/*
**  PLAYLIB.C
**
**  Public domain for TC only by Lynn R. Lively
**  Modified by Bob Stout
*/

#include <dos.h>
#include <stdlib.h>
#include "sound.h"

#ifdef __ZTC__
 #include <int.h>
 #define interrupt
#else
 static void (interrupt far *n_oldtmint) (void);
#endif

#define TIMER_TICK_INTR 0x1c

static NOTE *     n_buff;
static unsigned   n_buff_sz;
static NOTE *     n_head;
static NOTE *     n_tail;
static unsigned   play_duration;
static unsigned   play_freq;

/*
** Add note to note buff. Return = 1 (note added), 0 (Out of note buff)
*/

int playb_note (unsigned freq, unsigned duration)
{
      if (++n_tail == (n_buff + n_buff_sz))
            n_tail = n_buff;

      if (n_tail == n_head)
      {
            --n_tail;
            return (0);
      }

      n_tail->freq     = freq;
      n_tail->duration = duration;

      return (1);
}

/*
** ISR for background music.
*/

#ifndef __ZTC__
 static void interrupt far play_intr (void)
#else
 static int play_intr (struct INT_DATA *idp)
#endif
{
      int_off ();

#ifndef __ZTC__
      (*n_oldtmint) ();                   /* Call Old timer interrupt.  */
#else
      int_prev(idp);
#endif

      if (play_duration == 0)
      {
            soundoff ();

            if (++n_head == (n_buff + n_buff_sz))
                  n_head = n_buff;

            if (n_head == n_tail)
            {
                  --n_head;
                  int_on ();
                  return;
            }

            play_duration = n_head->duration;
            if (0 != (play_freq = n_head->freq))
                  soundon();
            dosound (play_freq);
      }
      else  --play_duration;

      int_on ();

#ifdef __ZTC__
      return 1;                           /* Don't chain                */
#endif
}

/*
** Call this function to init background music. buff_sz is number of
** notes in the note buffer. Returns pointer to buff or NULL if
** out of heap space.
*/

NOTE * playb_open (unsigned buff_sz)
{
      n_buff =
      n_head =
      n_tail =  (NOTE *) calloc (buff_sz, sizeof (NOTE));

      if (n_buff != (NOTE *) NULL)
      {
            n_buff_sz     = buff_sz;

            play_duration =
            play_freq     = 0;
            
#ifdef __ZTC__
            int_intercept(TIMER_TICK_INTR, play_intr, 256);
#else
            n_oldtmint    = getvect (TIMER_TICK_INTR);
            setvect (TIMER_TICK_INTR, play_intr);
#endif
      }
      return (n_buff);
}

/*
** Return things to normal and free allocated space.
*/

void playb_close (void)
{
      soundoff ();
#ifndef __ZTC__
      setvect (TIMER_TICK_INTR, n_oldtmint);
#else
      int_restore(TIMER_TICK_INTR);
#endif
      free (n_buff);
}
