/* $Id: sa_encode.cpp,v 1.3 1997/11/20 18:32:14 eds Exp $ */
/* $Log: sa_encode.cpp,v $
// Revision 1.3  1997/11/20  18:32:14  eds
// Added SASBF block.
// Changed many direct actual parameters to pointer-passing.
// Bug fixes.
//
 * Revision 1.2  1997/11/15 00:43:01  luked
 * This is the result of the manual merge from the vendor branch for the
 * release tagged Fribourg_after_integration. I (brian) have probably lost
 * some history, but oh well.
 *
 * This contains the integration work by Eric Scheirer (MIT).
 *
// Revision 1.1  1997/11/10  22:55:37  eds
// Initial revision
// */

/*********************************************************************

This software module was originally developed by

Eric D. Scheirer (MIT Media Laboratory)

in the course of development of the MPEG-2 NBC/MPEG-4 Audio standard
ISO/IEC 13818-7, 14496-1,2 and 3. This software module is an
implementation of a part of one or more MPEG-2 NBC/MPEG-4 Audio tools
as specified by the MPEG-2 NBC/MPEG-4 Audio standard.  ISO/IEC gives
users of the MPEG-2 NBC/MPEG-4 Audio standards free license to this
software module or modifications thereof for use in hardware or
software products claiming conformance to the MPEG-2 NBC/ MPEG-4 Audio
standards. Those intending to use this software module in hardware or
software products are advised that this use may infringe existing
patents. The original developer of this software module and his/her
company, the subsequent editors and their companies, and ISO/IEC have
no liability for use of this software module or modifications thereof
in an implementation.

This software module is hereby released into the public domain.

***********************************************************************/

extern "C"
{
#include "aifif.h"
#include "saol.h"
extern char *getline(FILE *fp);
extern int split(char *s, char ***words);
extern FILE *yyin;
yylex(void); 
extern char yytext[];
}
#include "bitstream.h"
#include "sa_bitstream.h"
#include "y.tab.h"
#include "saol_tok_table.h"

orc_file *parse_saol(Bitstream *);
sa_symtable symtab;
sa_symbol doSample(char *,Bitstream *);
void doScore(char *,Bitstream *);
struct cmdinfo cmd;

main(int argc, char *argv[]) {
  int done = 0,type;
  FILE *fp;
  Bitstream *out;
  char s[100];
  orc_file *orc;
  soundfont *SBF;

  if (argc < 2) {
    printf("Usage: encoder [file]\n");
    exit(1);
  }

  out = new Bitstream(argv[1],BS_OUTPUT);
  out->putbits(0x0,10);  /* magic number */
  
  while (!done) {
    printf("Chunk types: 1=SAOL 2=SASL 3=sample 4=MIDI 5=SASBF (0=done)\n");
    printf("Type, name: ");
    scanf("%d",&type);

    switch (type) {
    case 0:
      done = 1;
      break;
    case 1: /* SAOL */
      scanf("%s",s);
      if (!(fp = fopen(s,"r"))) {
	printf("Couldn't open file.\n");
      } else {
	yyin = fp;
	orc = parse_saol(out);
        out->putbits(1,1);  /* more_data */
	out->putbits(0,3); /* orc_file */
	orc->put(*out);
      }
      break;
    case 2: /* SASL */
      scanf("%s",s);
      out->putbits(1,1);
      out->putbits(1,3);
      doScore(s,out);
      break;
    case 3: /* sample */
      scanf("%s",s);
      doSample(s,out);
      break;

    case 5: /* SASBF */
      scanf("%s",s);
      if (!(fp = fopen(s,"r"))) {
	printf("Couldn't open file.\n");
      } else {
	out->putbits(1,1);
	out->putbits(4,3);
	SBF = new soundfont;
	while (!feof(fp))
	  SBF->data[SBF->size++] = getc(fp);
	fclose(fp);
	printf("Read %d bytes.\n",SBF->size);
	SBF->put(*out);
      }
      break;
    default:
      printf("Not done yet.\n");
    }
  }
  printf("Include sa_symbol table? ");
  scanf("%s",s);
  if (s[0] == 'y') {
    out->putbits(1,1);
    out->putbits(5,3);
    symtab.put(*out);
  }
  out->putbits(0,1); /* no more bits */
  out->flushbits();
}

void flerror(char *s) {
  printf(s);
  exit(1);
}

double bufval(char *buf, int nchan, int nbits, int frame, int chan) {
  /* get the value of frame #frame, chan #chan, from the buffer, which
     corresponds to input #input of the current decode process */
  
  if (nbits == 16)
    return((double)*(short *)&buf[frame * nchan * 2 + chan * 2]);
  
  if (nbits == 32)
    return((double)*(int *)&buf[frame * nchan * 2 + chan * 2]);
  
  if (nbits == 8)
    return((double)*(char *)&buf[frame * nchan *2 + chan * 2]);

  return 0;
}

orc_file *parse_saol(Bitstream *out) {
  int lexel;
  orch_token t;
  int ct,i;
  orc_file *o;
  char s[20];

  o = new orc_file;
  
  while (lexel = yylex()) {
    if (lexel > STRCONST)
      t.token = lexel_map(lexel);
    if (lexel == IDENT) {
      if (is_builtin(yytext) != -1)
	t.token = is_builtin(yytext);
      else { /* sa_symbol */
	t.token = TOK_SYMBOL;
	t.sym = symtab.add(yytext);
	/*	printf("Sa_Symbol '%s' = %d.\n",yytext,t.sym.sym); */
      }
    }
    if (lexel == NUMBER) {
      t.token = TOK_NUMBER;
      t.val = atof(yytext);
    }
    if (lexel == INTGR) {
      t.token = TOK_INT;
      t.ival = atoi(yytext);
    }
    if (lexel == STRCONST) {
      /* Must be a sound file */
      printf("Incorporate sound file '%s'? ",&yytext[1]);
      scanf("%s",s);
      if (s[0] == 'y') {
	t.token = TOK_SYMBOL;
	t.sym = doSample(yytext,out);
      }
    }

    o->add(t);
  }

  return o;
}

void doScore(char *name, Bitstream *out) {
  FILE *fp;
  char *s,**words;
  int ct,num,i;
  score_file *sf;
  score_line *sl;

  sf = new score_file;

  if (!(fp = fopen(name,"r")))
    printf("Couldn't open file.\n");
  else {
    while (!feof(fp)) {
      sl = new score_line;
      ct++;
      s = getline(fp);
      num = split(s,&words);
      if (!num) break;
      if (num > 2 && (!strcmp(words[1],"control") || !strcmp(words[2],"control"))) {
	control_event *ctrl = new control_event;
	sl->type = 1;
	sl->time = atof(words[0]);
	
	if (!strcmp(words[2],"control")) {
	  ctrl->has_label = 1;
	  ctrl->label = symtab.add(words[1]);
	  ctrl->varsym = symtab.add(words[3]);
	  ctrl->value = atof(words[4]);
	}
	else {
	  ctrl->has_label = 0;
	  ctrl->varsym = symtab.add(words[2]);
	  ctrl->value = atof(words[3]);
	}
	sl->control = *ctrl;
      }
      else if (!strcmp(words[1],"tempo")) {
	sl->type = 3;
	tempo_event *tempo = new tempo_event;
	sl->time = atof(words[0]);
	tempo->tempo = atof(words[2]);
	sl->tempo = *tempo;
      }
      else if (!strcmp(words[1],"table")) {
	/* still need to get samples in */
	table_event *table = new table_event;
	sl->type = 2;
	sl->time = atof(words[0]);
	table->tname = symtab.add(words[2]);
	table->num_pf = num-3;
	for (i=3;i!=num;i++)
	  table->pf[i-3] = atof(words[i]);
	sl->table = *table;
      }
      else if (!strcmp(words[1],"end")) {
	sl->type = 4;
	sl->time = atof(words[0]);
	end_event *end = new end_event;
	sl->end = *end;
      }
      else { /* must be an instrument event */
	instr_event *instr = new instr_event;
	sl->type = 0;
	
	if (words[0][strlen(words[0])-1] == ':') { /* label */
	  instr->has_label = 1;
	  words[0][strlen(words[0])-1] = '\0';
	  instr->label = symtab.add(words[0]);
	  sl->time = atof(words[1]);
	  instr->iname_sym = symtab.add(words[2]);
	  instr->dur = atof(words[3]);
	  instr->num_pf =  num-4;
	  for (i=4;i!=num;i++)
	    instr->pf[i-4] = atof(words[i]);
	} else {
	  instr->has_label = 0;
	  sl->time = atof(words[0]);
	  instr->iname_sym = symtab.add(words[1]);
	  instr->dur = atof(words[2]);
	  instr->num_pf =  num-3;
	  for (i=3;i!=num;i++)
	    instr->pf[i-3] = atof(words[i]);

	}
	sl->inst = *instr;
      }
      sf->add(sl);
    }
  }
  sf->put(*out);
}

sa_symbol doSample(char *yytext,Bitstream *out) {
  AIF_STRUCT *aif;
  char buf[65536];
  float fdata[4][1024],scale;
  short data[4][1024];
  long pvb[16];
  long nchan, nbits, srate;
  sample *s;
  char name[20];
  int usechan,ct,tot=0,done=0,i,j;
  static int count = 0;
  
  aif = aifNew();
  
  if (aifOpenRead(aif,&yytext[1]))
    printf("Couldn't open file.\n");
  else {
    s = new sample;
    sprintf(name,"_sym_samp_%d",count++);
    s->sample_name_sym = symtab.add(name);
    pvb[0] = AIF_P_CHANNELS;
    pvb[2] = AIF_P_SAMPSIZE;
    pvb[4] = AIF_P_SAMPRATE;
    aifGetParams(aif,pvb,6);
    nchan = pvb[1]; nbits = pvb[3]; srate = (int)*(float *)&pvb[5];
    s->has_srate = 1;
    if (nchan > 1) {
      printf("Sample has %d channels->  Use which channel (0 = mean)? ",nchan);
      scanf("%d",&usechan);
    } else usechan = 1;
    s->srate = srate;
    s->has_loop = 0;
    s->has_base = 0;
    
     while (!done) {
      ct = aifReadFrames(aif,buf,1024);
      if (ct < 1024) done = 1;
      if (nbits == 32) {
	scale = (double)(2 << (nbits-2));
	 
	s->float_sample = 1;
	for (i=0;i!=nchan;i++)
	  for (j=0;j!=ct;j++)
	    fdata[i][j] = (float)bufval(buf,nchan,nbits,j,i) / scale;
	for (j=0;j!=ct;j++)
	  if (!usechan) {
	    s->fs_data[tot+j] = 0;
	    for (i=0;i!=nchan;i++)
	      s->fs_data[tot+j] += fdata[i][j];
	    s->fs_data[tot+j] /= nchan;
	  }
	  else s->fs_data[tot+j] = fdata[usechan-1][j];
      } else {
	double val;
	
	s->float_sample = 0;
	for (i=0;i!=nchan;i++)
	  for (j=0;j!=ct;j++) {
	    data[i][j] = (short)bufval(buf,nchan,nbits,j,i);
	  }
	for (j=0;j!=ct;j++) {
	  if (!usechan) {
	    val = 0;
	    for (i=0;i!=nchan;i++)
	      val += data[i][j];
	    s->s_data[tot+j] = (short)(val / nchan);
	  }
	  else s->s_data[tot+j] = data[usechan-1][j];
	}
      }
      tot += ct;
    }
    s->length = tot;
    printf("Read %d samples->\n",tot); 
  } 
  out->putbits(1,1);  /* more bits */
  out->putbits(3,3); /* sample */
  s->put(*out);

  return s->sample_name_sym;
}

extern "C" {
void runtime(char *s) {
  printf(s);
  exit(1);
}

void schedule_event() { }
}
