


/*
#    Sfront, a SAOL to C translator    
#    This file: Included file in sfront runtime
#    Copyright (C) 1999  Regents of the University of California
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License (Version 2) as
#    published by the Free Software Foundation.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
#    Primary Author: John Lazzaro, lazzaro@cs.berkeley.edu
*/

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <unistd.h>

/********************************/
/* readabiliy-improving defines */
/********************************/

#define NV(x)   nstate->v[x].f
#define NVI(x)  nstate->v[x].i
#define NT(x)   nstate->t[x]
#define NTA(x)  nstate->t[nstate->v[x].i]
#define NG(x)   global[x].f
#define NGI(x)  global[x].i
#define TB(x)   bus[x]
#define ROUND(x) ( ((x) > 0.0F) ? ((int) ((x) + 0.5F)) :  ((int) ((x) - 0.5F)))
#define POS(x)   (((x) > 0.0F) ? x : 0.0F)

#define TOBEPLAYED 0
#define PLAYING 1
#define ALLDONE 2

#define NOTLAUNCHED 0
#define LAUNCHED 1

#define ASYS_DONE        0
#define ASYS_ERROR       1
#define ASYS_LOWLATENCY  0
#define ASYS_HIGHLATENCY 1

/* IPASS must be 0 */

#define IPASS 1
#define KPASS 2
#define APASS 3

/************************************/
/* externs for system functions     */
/************************************/

extern void epr(int, char *, char *, char *);

/************************************/
/*  union for a data stack element  */
/************************************/

typedef union {

long  i;
float f;

} dstack;

/************************************/
/* ntables: table entries for notes */
/************************************/

struct tableinfo {

int    len;                /* length of table */

int    start;              /* loop start position */
int    end;                /* loop end position */
float  sr;                 /* table sampling rate  */
float  base;               /* table base frequency */

                           /* precomputed constants       */
int tend;                  /* len -1 if end==0            */
float m;                   /* start/len                   */
float n;                   /* end/len, if end=0 1-(1/len) */
float dmult;               /* sr*atime                    */
float lmult;               /* (sr*atime)/basefreq         */
float diff;                /* n - m                       */

float  *t;                 /* pointer to table entries */
float stamp;               /* timestamp on table contents */
}; 

/********************/
/*  control lines   */
/********************/

struct scontrol_lines {

float t;                  /* trigger time */
int siptr;                /* score instr line to control */
struct instr_line *iline; /* pointer to score line */
int imptr;                /* position of variable in v[] */
float imval;              /* value to import into v[] */

};

/********************/
/*   tempo lines    */
/********************/

struct stempo_lines {

float t;          /* trigger time */
float newtempo;   /* new tempo */ 

};

/********************/
/*   table lines    */
/********************/

struct stable_lines {

float t;          /* trigger time */
void (*tmake) ();
};

/********************/
/* system variables */
/********************/

/* audio i/o */

short *asys_obuf = NULL;    /* pointer to output sample buffer */
long asys_osize = 0;             /* size of output buffer */
long obusidx = 0;

/* audio and control rates */

float globaltune = 440.0F;
float invglobaltune = 2.272727e-03F;
float scorebeats = 0.0F;              /* current score beat */
int kbase = 0;                       /* kcycle of last tempo change */
float scorebase = 0.0F;               /* scorebeat of last tempo change */


/* counters & bounds acycles and kcycles */

int endkcycle;
int kcycleidx,acycleidx;
int pass = IPASS;
int beginflag;

struct instr_line * sysidx;

int busidx;        /* counter for buses */
int nextstate = 0; /* counter for active instrument state */
int oldstate;      /* detects loops in nextstate updates */
int tstate;        /* flag for turnoff state machine */
int slips = 0;     /* number of k-periods that computation lags */


#define ARATE 32000.0F
#define ATIME 3.125000e-05F
#define KRATE 100.0F
#define KTIME 1.000000e-02F
#define KUTIME 10000L
#define ACYCLE 320L
#define ASLICE 80L
float tempo = 60.0F;
float scoremult = 1.000000e-02F;

#define BUS_output_bus 0
#define ENDBUS_output_bus 1
#define ENDBUS 1
float bus[ENDBUS] = {0.0F};

#define GBL_ENDVAR 0
dstack global[GBL_ENDVAR+1] = {0.0F};     /* global variables */

#define GBL_ENDTBL 0
struct tableinfo * gtables[GBL_ENDTBL+1] = {0};

#define MAXPFIELDS 1

struct instr_line { 

float starttime;            /* score start time of note */
float endtime;              /* actual end time of note */
float abstime;              /* absolute time extension */
float time;                 /* time of note start (absolute) */
float sdur;                 /* duration of note in score time*/

int released;               /* flag for turnoff*/
int turnoff;                /* flag for turnoff */
int noteon;                 /* TOBEPLAYED, PLAYING, ALLDONE */
int notestate;              /* index into state array */
int launch;                 /* only for dynamic instruments */
int numchan;                /* only for MIDI notes */
int preset;                 /* only for MIDI notes */
int notenum;                /* only for MIDI notes */
float p[MAXPFIELDS];        /* parameters */

struct ninstr_types * nstate; /* pointer into state array */

void (*ipass) (struct ninstr_types *); /* ipass function */
void (*kpass) (struct ninstr_types *); /* kpass function */
void (*apass) (struct ninstr_types *); /* apass function */
};

#define a0_a1 0
#define a0_a2 1
#define a0_a3 2
#define a0_ENDVAR 3

#define a0_ENDTBL 0


#define MAXVARSTATE 3
#define MAXTABLESTATE 1

void a0_ipass(struct ninstr_types *);
void a0_kpass(struct ninstr_types *);
void a0_apass(struct ninstr_types *);


float endtime = 4.500000e+00F;
#define MAXENDTIME 3.40282347e+38F

struct instr_line s_a0[1] = {
 2.500000e-01F, 3.40282347e+38F, 0.0F, 0.0F,  4.000000e+00F,  0, 0, 0, 0, 0, -1, 0, 0, 0.0F,  NULL, NULL, NULL, NULL };

struct instr_line * s_a0first = &s_a0[0];
struct instr_line * s_a0last = &s_a0[0];
struct instr_line * s_a0end = &s_a0[0];

struct scontrol_lines scontrol[1] = {
 0, 0, NULL, 0, 0
};
struct scontrol_lines * scontrolidx = NULL;
struct scontrol_lines * endscontrol = NULL;

struct stempo_lines stempo[1] = {
 0.0F, 0.0F };

int endstempo = -1;
int stempoidx = 0;

struct stable_lines stable[1] = {
 0.0F, NULL };

int endstable = -1;

int stableidx = 0;

#define MAXSTATE 2

/* ninstr: used for score, effects, */
/* and dynamic instruments          */

struct ninstr_types {

struct instr_line * iline; /* pointer to score line */
dstack v[MAXVARSTATE];     /* parameters and variables*/
struct tableinfo * t[MAXTABLESTATE]; /* tables */

} ninstr[MAXSTATE] = {0};



#define ASYS_OCHAN 1L

void ksync() {}

#define ASYS_HASOUTPUT


/*
#    Sfront, a SAOL to C translator    
#    This file: WAV audio driver for sfront
#    Copyright (C) 1999  Regents of the University of California
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License (Version 2) as
#    published by the Free Software Foundation.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
#    Maintainer: John Lazzaro, lazzaro@cs.berkeley.edu
*/


/****************************************************************/
/****************************************************************/
/*             wav file audio driver for sfront                 */ 
/****************************************************************/
        
#include <stdio.h>
#include <string.h>

#if defined(ASYS_HASOUTPUT)

/* default name for output audio file */
#define ASYSO_DEFAULTNAME "output.wav"

/* global variables, must start with asyso_ */

FILE * asyso_fd;     /* output file pointer */
char * asyso_name;   /* name of file  */        
long asyso_srate;    /* sampling rate */
long asyso_channels; /* number of channels */
long asyso_size;    /* number of samples in a buffer */
long asyso_nsamp;    /* total number of shorts written */
long asyso_doswap;   /* needs byteswap on write */
short * asyso_buf;   /* location for output buffer */ 
#endif

#if defined(ASYS_HASINPUT)

/* default name for input audio file */

#define ASYSI_DEFAULTNAME "input.wav"

/* only used for asysi_soundtypecheck */

#define ASYSI_MATCH  0
#define ASYSI_EOF 1
#define ASYSI_NOMATCH 2

/* global variables, must start with asysi_ */

FILE * asysi_fd;     /* input file pointer */
char * asysi_name;   /* name of file  */        
long asysi_srate;    /* sampling rate */
long asysi_channels; /* number of channels */
long asysi_size;    /* number of samples in a buffer */
long asysi_nsamp;    /* total number of shorts read */
long asysi_doswap;   /* needs byteswap on read */
short * asysi_buf;   /* location for input buffer */ 

#endif

#if defined(ASYS_HASOUTPUT)

/*********************************************************/
/*        writes next block of WAV/AIFF bytes            */
/*********************************************************/

int asyso_putbytes(unsigned char * c, int numbytes)

{
  if (fwrite(c, sizeof(char), numbytes, asyso_fd) != numbytes)
    return ASYS_ERROR;
  return ASYS_DONE;
}

/*********************************************************/
/*        writes unsigned long to a WAV files            */
/*********************************************************/

int asyso_putlong(unsigned long val, int numbytes)

{
  unsigned char c[4];

  if (numbytes > 4)
    return ASYS_ERROR;
  switch (numbytes) {
  case 4:
    c[0] = (unsigned char) (val&0x000000FF);
    c[1] = (unsigned char)((val >> 8)&0x000000FF);
    c[2] = (unsigned char)((val >> 16)&0x000000FF);
    c[3] = (unsigned char)((val >> 24)&0x000000FF);
    return asyso_putbytes(c, 4);
  case 3:
    c[0] = (unsigned char) (val&0x000000FF);
    c[1] = (unsigned char)((val >> 8)&0x000000FF);
    c[2] = (unsigned char)((val >> 16)&0x000000FF);
    return asyso_putbytes(c, 3);
  case 2:
    c[0] = (unsigned char) (val&0x000000FF);
    c[1] = (unsigned char)((val >> 8)&0x000000FF);
    return asyso_putbytes(c, 2);
  case 1:
    c[0] = (unsigned char) (val&0x000000FF);
    return asyso_putbytes(c,1);
  default:
    return ASYS_ERROR;
  }

}

/****************************************************************/
/*        core routine for audio output setup                   */
/****************************************************************/

int asyso_setup(long srate, long ochannels, long osize, char * name)


{
  short swaptest = 0x0100;
  
  asyso_doswap = *((char *)&swaptest);
  if (name == NULL)
    asyso_name = strdup(ASYSO_DEFAULTNAME);
  else
    asyso_name = strdup(name);
  asyso_fd = fopen(asyso_name,"wb");
  if (asyso_fd == NULL)
    return ASYS_ERROR;

  /* preamble for wav file */

  asyso_putbytes((unsigned char *) "RIFF",4);
  asyso_putlong(0,4);       /* patched later */
  asyso_putbytes((unsigned char *) "WAVEfmt ",8);
  asyso_putlong(16,4);
  asyso_putlong(1,2);                  /* PCM  */
  asyso_putlong(ochannels,2);          /* number of channels */
  asyso_putlong(srate,4);              /* srate */
  asyso_putlong(srate*ochannels*2,4);  /* bytes/sec */
  asyso_putlong(ochannels*2,2);        /* block align */
  asyso_putlong(16,2);                 /* 2 bytes per sample */
  asyso_putbytes((unsigned char *) "data",4);
  asyso_putlong(0,4);                  /* patched later */

  asyso_srate = srate;
  asyso_channels = ochannels;
  asyso_size = osize;
  asyso_nsamp = 0;
  asyso_buf = (short *)malloc(sizeof(short)*osize);
  return ASYS_DONE;
}

#endif

#if defined(ASYS_HASINPUT)

/*********************************************************/
/*            gets next block of WAV bytes               */
/*********************************************************/

int asysi_getbytes(unsigned char * c, int numbytes)

{
  if (fread(c, sizeof(char), numbytes, asysi_fd) != numbytes)
    return ASYS_ERROR;
  return ASYS_DONE;
}

/*********************************************************/
/*        flushes next block of WAV bytes                */
/*********************************************************/

int asysi_flushbytes(int numbytes)

{
  unsigned char c;

  while (numbytes > 0)
    {
      if (fread(&c, sizeof(char), 1, asysi_fd) != 1)
	return ASYS_ERROR;
      numbytes--;
    }
  return ASYS_DONE;

}

/*********************************************************/
/*     converts byte stream to an unsigned long          */
/*********************************************************/

long asysi_getlong(int numbytes, unsigned long * ret)

{
  unsigned char c[4];

  if (numbytes > 4)
    return ASYS_ERROR;
  if (ASYS_DONE != asysi_getbytes(&c[0],numbytes))
    return ASYS_ERROR;
  switch (numbytes) {
  case 4:
    *ret  =  (unsigned long)c[0];
    *ret |=  (unsigned long)c[1] << 8;
    *ret |=  (unsigned long)c[2] << 16;
    *ret |=  (unsigned long)c[3] << 24;
    return ASYS_DONE;
  case 3:
    *ret  =  (unsigned long)c[0];
    *ret |=  (unsigned long)c[1] << 8;
    *ret |=  (unsigned long)c[2] << 16;
    return ASYS_DONE;
  case 2:
    *ret  =  (unsigned long)c[0];
    *ret |=  (unsigned long)c[1] << 8;
    return ASYS_DONE;
  case 1:
    *ret = (unsigned long)c[0];
    return ASYS_DONE;
  default:
    return ASYS_ERROR;
  }

}
  
/***********************************************************/
/*  checks byte stream for AIFF/WAV cookie --              */
/***********************************************************/

int asysi_soundtypecheck(char * d)

{
  char c[4];

  if (fread(c, sizeof(char), 4, asysi_fd) != 4)
    return ASYSI_EOF;
  if (strncmp(c,d,4))
    return ASYSI_NOMATCH;
  return ASYSI_MATCH;
}
  
/****************************************************************/
/*        core routine for audio input setup                   */
/****************************************************************/

int asysi_setup(long srate, long ichannels, long isize, char * name)


{
  short swaptest = 0x0100;
  unsigned long i, cookie;
  long len;

  asysi_doswap = *((char *)&swaptest);
  if (name == NULL)
    asysi_name = strdup(ASYSI_DEFAULTNAME);
  else
    asysi_name = strdup(name);
  asysi_fd = fopen(asysi_name,"rb");
  if (asysi_fd == NULL)
    return ASYS_ERROR;

  if (asysi_soundtypecheck("RIFF")!= ASYSI_MATCH)
    return ASYS_ERROR;
  if (asysi_flushbytes(4)!= ASYS_DONE)
    return ASYS_ERROR;
  if (asysi_soundtypecheck("WAVE")!= ASYSI_MATCH)
    return ASYS_ERROR;
  while ((cookie = asysi_soundtypecheck("fmt "))!=ASYSI_MATCH)
    {
      if (cookie == ASYSI_EOF)
	return ASYS_ERROR;
      if (asysi_getlong(4, &i) != ASYS_DONE)
	return ASYS_ERROR;
      if (asysi_flushbytes(i)!= ASYS_DONE)
	return ASYS_ERROR;
    }
  if (asysi_getlong(4, &i) != ASYS_DONE)
    return ASYS_ERROR;
  len = i;
  if ((len -= 16) < 0)
    return ASYS_ERROR;
  if (asysi_getlong(2, &i) != ASYS_DONE)
    return ASYS_ERROR;
  if (i != 1)
    {
      fprintf(stderr,"Error: Can only handle PCM WAV files\n");
      return ASYS_ERROR;
    }
  if (asysi_getlong(2, &i) != ASYS_DONE)
    return ASYS_ERROR;
  if (i != ichannels)
    {
      fprintf(stderr,"Error: Inchannels doesn't match WAV file\n");
      return ASYS_ERROR;
    }
  if (asysi_getlong(4, &i) != ASYS_DONE)
    return ASYS_ERROR;
  if (srate != i)
    fprintf(stderr,"Warning: SAOL srate %i mismatches WAV file srate %i\n",
	    srate,i);
  asysi_flushbytes(6);
  if (asysi_getlong(2, &i) != ASYS_DONE)
    return ASYS_ERROR;
  if ((i < 9) || (i > 16))
    {
      fprintf(stderr,"Error: Can't handle %i bit data\n",i);
      return ASYS_ERROR;
    }
  asysi_flushbytes(len);
  while ((cookie = asysi_soundtypecheck("data"))!=ASYSI_MATCH)
    {
      if (cookie == ASYSI_EOF)
	return ASYS_ERROR;
      if (asysi_getlong(4, &i) != ASYS_DONE)
	return ASYS_ERROR;
      if (asysi_flushbytes(i)!= ASYS_DONE)
	return ASYS_ERROR;
    }
  if (asysi_getlong(4, &i) != ASYS_DONE)
    return ASYS_ERROR;
  asysi_nsamp = i/2;

  asysi_srate = srate;
  asysi_channels = ichannels;
  asysi_size = isize;
  asysi_buf = (short *)malloc(sizeof(short)*isize);
  return ASYS_DONE;
}

#endif

#if (defined(ASYS_HASOUTPUT) && !defined(ASYS_HASINPUT))

/****************************************************************/
/*        sets up audio output for a given srate/channels       */
/****************************************************************/

int asys_osetup(long srate, long ochannels, long osize, char * oname,
		long latency)

{
  return asyso_setup(srate, ochannels, osize, oname);
}

#endif


#if (!defined(ASYS_HASOUTPUT) && defined(ASYS_HASINPUT))

/****************************************************************/
/*        sets up audio input for a given srate/channels       */
/****************************************************************/

int asys_isetup(long srate, long ichannels, long isize, char * iname,
		long latency)

{
  return asysi_setup(srate, ichannels, isize, iname);
}

#endif


#if (defined(ASYS_HASOUTPUT) && defined(ASYS_HASINPUT))

/****************************************************************/
/*   sets up audio input and output for a given srate/channels  */
/****************************************************************/

int asys_iosetup(long srate, long ichannels, long ochannels,
		 long isize, long osize, char * iname,
		 char * oname, long latency)

{

  if (asysi_setup(srate, ichannels, isize, iname) != ASYS_DONE)
    return ASYS_ERROR;
  return asyso_setup(srate, ochannels, osize, oname);

}

#endif

#if defined(ASYS_HASOUTPUT)

/****************************************************************/
/*             shuts down audio output system                   */
/****************************************************************/

void asyso_shutdown(void)

{
  char name[1024];

  fclose(asyso_fd);
  asyso_fd = fopen(asyso_name,"r+b"); /* fill in actual lengths */
  fseek(asyso_fd, 4, SEEK_CUR);
  asyso_putlong(2*(unsigned long)asyso_nsamp+36,4);
  fseek(asyso_fd, 32, SEEK_CUR);
  asyso_putlong(2*(unsigned long)asyso_nsamp,4);
  fclose(asyso_fd);
}

#endif

#if defined(ASYS_HASINPUT)

/****************************************************************/
/*               shuts down audio input system                  */
/****************************************************************/

void asysi_shutdown(void)

{

  fclose(asysi_fd);
}

#endif


#if (defined(ASYS_HASOUTPUT)&&(!defined(ASYS_HASINPUT)))

/****************************************************************/
/*                    shuts down audio output                   */
/****************************************************************/

void asys_oshutdown(void)

{
  asyso_shutdown();
}

#endif

#if (!defined(ASYS_HASOUTPUT)&&(defined(ASYS_HASINPUT)))

/****************************************************************/
/*              shuts down audio input device                   */
/****************************************************************/

void asys_ishutdown(void)

{
  asysi_shutdown();
}

#endif

#if (defined(ASYS_HASOUTPUT)&&(defined(ASYS_HASINPUT)))

/****************************************************************/
/*              shuts down audio input and output device        */
/****************************************************************/

void asys_ioshutdown(void)

{
  asysi_shutdown();
  asyso_shutdown();
}

#endif


#if defined(ASYS_HASOUTPUT)

/****************************************************************/
/*               sends one frame of audio to output             */
/****************************************************************/

int asys_putbuf(short * asys_obuf[], long * osize)

{
  unsigned char * buf;
  unsigned char tmp;
  long i = 0;

  if (*asys_obuf == NULL)
    {
      *asys_obuf = asyso_buf;
      *osize = asyso_size;
      return ASYS_DONE;
    }
  if (asyso_doswap)
    {
      buf = (unsigned char *)(*asys_obuf);
      while (i < 2*(*osize))
	{
	  tmp = buf[i+1];
	  buf[i+1] = buf[i];
	  buf[i] = tmp;
	  i += 2;
	}
      if (fwrite(buf, sizeof(char), 2*(*osize), asyso_fd) != 2*(*osize))
	return ASYS_ERROR;
    }
  else
    if (fwrite(*asys_obuf, sizeof(short), *osize, asyso_fd) != *osize)
      return ASYS_ERROR;
  asyso_nsamp += *osize;
  *osize = asyso_size;
  return ASYS_DONE;
}

#endif

#if defined(ASYS_HASINPUT)

/****************************************************************/
/*               sends one frame of audio to output             */
/****************************************************************/

int asys_getbuf(short * asys_ibuf[], long * isize)

{
  unsigned char * buf;
  unsigned char tmp;
  long i = 0;

  if (*asys_ibuf == NULL)
    *asys_ibuf = asysi_buf;
  
  if (asysi_nsamp <= 0)
    {
      *isize = 0;
      return ASYS_DONE;
    }

  *isize = fread(*asys_ibuf, sizeof(short), asysi_size, asysi_fd);
  if (asysi_doswap)
    {
      buf = (unsigned char *)(*asys_ibuf);
      while (i < 2*(*isize))
	{
	  tmp = buf[i+1];
	  buf[i+1] = buf[i];
	  buf[i] = tmp;
	  i += 2;
	}
    }
  asysi_nsamp -= *isize;
  return ASYS_DONE;
}

#endif


void a0_ipass(struct ninstr_types * nstate)
{
   int i;

   for (i=0;i<a0_ENDVAR;i++)
      NV(i) = 0.0F;

}

void a0_kpass(struct ninstr_types * nstate)
{

   int i;


}

void a0_apass(struct ninstr_types * nstate)
{

 if  ( NV(a0_a3) ==  0.0F )
 { NV(a0_a3) =  1.0F ;
NV(a0_a1) =  5.000000e-01F ;
}
NV(a0_a1) = NV(a0_a1) -  1.963070e-01F  * NV(a0_a2);
NV(a0_a2) = NV(a0_a2) +  1.963070e-01F  * NV(a0_a1);
TB(BUS_output_bus + 0) += 
NV(a0_a2);
}


#undef NT
#define NT(x)  gtables[x]
#undef NV
#define NV(x)  global[x].f
#undef NVI
#define NVI(x)  global[x].i
#undef NTA
#define NTA(x) gtables[global[x].i]


#undef NT
#define NT(x)  nstate->t[x]
#undef NV
#define NV(x)  nstate->v[x].f
#undef NVI
#define NVI(x)  nstate->v[x].i
#undef NTA
#define NTA(x) nstate->t[nstate->v[x].i]


#undef NT
#define NT(x)  gtables[x]
#undef NV
#define NV(x)  global[x].f
#undef NVI
#define NVI(x)  global[x].i
#undef NTA
#define NTA(x) gtables[global[x].i]



void system_init(void)
{

   int i;
   struct ninstr_types * nstate = NULL;
   for (i=0;i<GBL_ENDVAR;i++)
      NV(i) = 0.0F;


#undef NT
#define NT(x)  nstate->t[x]
#undef NV
#define NV(x)  nstate->v[x].f
#undef NVI
#define NVI(x)  nstate->v[x].i
#undef NTA
#define NTA(x) nstate->t[nstate->v[x].i]

   for (busidx=0; busidx<ENDBUS;busidx++)
      bus[busidx]=0.0F;


}


#undef NT
#define NT(x)  gtables[x]
#undef NV
#define NV(x)  global[x].f
#undef NVI
#define NVI(x)  global[x].i
#undef NTA
#define NTA(x) gtables[global[x].i]



void effects_init(void)
{

   struct ninstr_types * nstate = NULL;


}


#undef NT
#define NT(x)  nstate->t[x]
#undef NV
#define NV(x)  nstate->v[x].f
#undef NVI
#define NVI(x)  nstate->v[x].i
#undef NTA
#define NTA(x) nstate->t[nstate->v[x].i]


#undef NT
#define NT(x)  gtables[x]
#undef NV
#define NV(x)  global[x].f
#undef NVI
#define NVI(x)  global[x].i
#undef NTA
#define NTA(x) gtables[global[x].i]



void shut_down(void)
   {

   asys_putbuf(&asys_obuf, &obusidx);
   asys_oshutdown();

   }

void main_apass(void)

{

 for (sysidx=s_a0first;sysidx<=s_a0last;sysidx++)
  if (sysidx->noteon == PLAYING)
   a0_apass(sysidx->nstate);

}

int main_kpass(void)

{

 for (sysidx=s_a0first;sysidx<=s_a0last;sysidx++)
  if (sysidx->noteon == PLAYING)
  {
   a0_kpass(sysidx->nstate);
  }

  return 0;
}

void main_ipass(void)

{

    sysidx = s_a0last;
    while ((sysidx <= s_a0end) && 
      (sysidx->starttime < scorebeats))
      {
       s_a0last = sysidx;
       sysidx++;
      }
  beginflag = 0;
 for (sysidx=s_a0first;sysidx<=s_a0last;sysidx++)
  {
  switch(sysidx->noteon) {
   case PLAYING:
   if (sysidx->released)
    {
     if (sysidx->turnoff)
      {
        sysidx->noteon = ALLDONE;
        sysidx->nstate->iline = NULL;
      }
     else
      {
        sysidx->abstime -= KTIME;
        if (sysidx->abstime < 0.0F)
         {
           sysidx->noteon = ALLDONE;
           sysidx->nstate->iline = NULL;
         }
        else
         sysidx->turnoff = sysidx->released = 0;
      }
    }
   else
    {
     if (sysidx->turnoff)
      {
       sysidx->released = 1;
       sysidx->endtime = scorebeats;
      }
     else
      {
        if (sysidx->endtime <= scorebeats)
         {
           if (sysidx->abstime <= 0.0F)
             sysidx->turnoff = sysidx->released = 1;
           else
           {
             sysidx->abstime -= KTIME;
             if (sysidx->abstime < 0.0F)
               sysidx->turnoff = sysidx->released = 1;
           }
         }
        else
          if ((sysidx->abstime < 0.0F) &&
           (1.666667e-2F*tempo*sysidx->abstime + 
               sysidx->endtime <= scorebeats))
            sysidx->turnoff = sysidx->released = 1;
      }
    }
   break;
   case TOBEPLAYED:
    if (sysidx->starttime < scorebeats)
     {
      sysidx->noteon = PLAYING;
      sysidx->notestate = nextstate;
      sysidx->nstate = &ninstr[nextstate];
      if (sysidx->sdur >= 0.0F)
        sysidx->endtime = scorebeats + sysidx->sdur;
      ninstr[nextstate].iline = sysidx;
      sysidx->time = kcycleidx*KTIME;
      a0_ipass(sysidx->nstate);
    oldstate = nextstate;
    nextstate = (nextstate+1) % MAXSTATE;
    while ((oldstate != nextstate) && 
           (ninstr[nextstate].iline != NULL))
      nextstate = (nextstate+1) % MAXSTATE;
    if (oldstate == nextstate)
    {      nextstate = (nextstate+1) % MAXSTATE;
      while ((oldstate != nextstate) && 
          (ninstr[nextstate].iline->time == 0.0F) &&
          (ninstr[nextstate].iline->noteon == PLAYING))
        nextstate = (nextstate+1) % MAXSTATE;
      ninstr[nextstate].iline->noteon = ALLDONE;
      ninstr[nextstate].iline = NULL;
    }    }
   break;
   default:
   break;
   }
   if ((!beginflag) && (sysidx->noteon == ALLDONE))
     s_a0first = sysidx+1;
   else
     beginflag = 1;
 }

}

void main_initpass(void)

{


   if (asys_osetup((int)ARATE, ASYS_OCHAN, ASYS_OCHAN*ASLICE, "output.wav",
ASYS_HIGHLATENCY) != ASYS_DONE)
   epr(0,NULL,NULL,"audio output device unavailable");
   if (asys_putbuf(&asys_obuf, &asys_osize))
   epr(0,NULL,NULL,"audio input device unavailable");

}



/*
#    Sfront, a SAOL to C translator    
#    This file: Main loop for runtime
#    Copyright (C) 1999  Regents of the University of California
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License (Version 2) as
#    published by the Free Software Foundation.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
#    Primary Author: John Lazzaro, lazzaro@cs.berkeley.edu
*/

void epr(int linenum, char * filename, char * token, char * message)

{

  fprintf(stderr, "\nRuntime Error.\n");
  if (filename != NULL)
    fprintf(stderr, "Location: File %s near line %i.\n",filename, linenum);
  if (token != NULL)
    fprintf(stderr, "While executing: %s.\n",token);
  if (message != NULL)
    fprintf(stderr, "Potential problem: %s.\n",message);
  fprintf(stderr, "Exiting program.\n\n");
  exit(-1);

}

void main_control(void)

{

  if (scontrolidx == NULL)
    return;

  while ((scontrolidx <=endscontrol)&&
	 (scontrolidx->t < scorebeats))
    {
      if (scontrolidx->siptr < 0)
	global[scontrolidx->imptr].f = scontrolidx->imval;
      else
	{
	  if ( (scontrolidx->iline != NULL) && 
	       (scontrolidx->iline->noteon == PLAYING) )
	    {
	      scontrolidx->iline->nstate->v[scontrolidx->imptr].f
		= scontrolidx->imval;
	    }
	}
      scontrolidx++;
    }

}


main(int argc, char *argv[])

{
  srand48(19753193L);
  system_init();
  effects_init();
  main_initpass();
  endkcycle = kbase + (int) (KRATE*(endtime - scorebase)*(60.0F/tempo));
  for (kcycleidx=0; kcycleidx<endkcycle; kcycleidx++)
    {
      pass = IPASS;
      scorebeats = scoremult*(kcycleidx - kbase) + scorebase;
      main_ipass();
      pass = KPASS;
      main_control();
      while ((stableidx <=endstable)&&
	     (stable[stableidx].t < scorebeats))
	{  
	  (*stable[stableidx].tmake) ();
	  stableidx++;
	}
      while ((stempoidx <=endstempo)&&
	     (stempo[stempoidx].t < scorebeats))
	{  
	  kbase = kcycleidx;
	  scorebase = scorebeats;
	  tempo = stempo[stempoidx].newtempo;
	  scoremult = 1.666667e-02F*KTIME*tempo;
	  endkcycle = kbase + (int)(KRATE*(endtime - scorebase)*(60.0F/tempo));
	  stempoidx++;
	}
      if (main_kpass())
	break;
      pass = APASS;
      for (acycleidx=0; acycleidx<ACYCLE; acycleidx++)
	{
	  for (busidx=0; busidx<ENDBUS;busidx++)
	    bus[busidx]=0.0F;
	  main_apass();
	  for (busidx=BUS_output_bus; busidx<ENDBUS_output_bus;busidx++)
	    {
	      bus[busidx] = (bus[busidx] >  1.0F) ?  1.0F : bus[busidx];
	      bus[busidx] = (bus[busidx] < -1.0F) ? -1.0F : bus[busidx];
	      asys_obuf[obusidx++] = (short) (32767.0F * bus[busidx]);
	    }
	  if (obusidx >= asys_osize)
	    {
	      obusidx = 0;
	      if (asys_putbuf(&asys_obuf, &asys_osize))
		{
		  fprintf(stderr,"Error: Audio output device problem\n");
		  kcycleidx = endkcycle;
		  break;
		}
	    }
	}
      ksync();
    }
  shut_down();
  return 0;
}





