//||
//||	`rhybag' - Rhythmic BinAural Generator
//||
//||	(c) 1999 Jim Peters <jim@aguazul.demon.co.uk>.  All Rights Reserved.
//||	For latest version see <http://www.aguazul.demon.co.uk/bagen/>.
//||	Released under the GNU GPL.  Use at your own risk.
//||
//||	" This program is free software; you can redistribute it and/or modify
//||	  it under the terms of the GNU General Public License as published by
//||	  the Free Software Foundation, version 2.
//||
//||	  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. "
//||
//||	If you really don't have a copy of the GNU GPL, I'll send you one.
//||	

//
//	All the bits together
//

#define VERSION "0.1.1"
char *program_name= "rhybag";


#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/soundcard.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <ctype.h>
#include <sys/mman.h>
#include <math.h>


#define uint unsigned int

#include "data.c"
#include "proto.h"
#include "util.c"
#include "compile.c"
#include "play.c"
#include "render.c"

#define NL "\n"
void
usage(void) {
  error("Rhythmic Binaural Generator, version " VERSION
	NL "Copyright (c) 1999 Jim Peters, released under the GNU GPL"
	NL
	NL "Usage: rhybag [options] sequence-file [sequence]"
	NL "   Defaults to playing `main' sequence if none specified"
	NL "Options:"
	NL " -o file      Output raw data to a file instead of to /dev/dsp"
	NL " -o file.wav  Output WAV-format data to a file"
	NL " -O           Output raw data to standard output"
	NL ""
	NL " -r rate      Manually select an output rate (Hz, default is 44100Hz)"
	NL " -S fade_ms   Set the time over which to fade sudden volume changes (def 5ms)"
	NL " -A vol       Set master volume to given %age of maximum possible, calculated"
	NL "                automatically (default is 95%)"
	NL " -M vol       Manually set master volume level (%age, 100 == as written)"
	NL " -D           Generate debugging dump of notes and sequences"
	NL " -DD          Also generate debugging dump of rendering events"
	);
}

int argc;
char **argv;
char *in_file= 0;
char *in_seq= 0;
char *out_file;

int 
main(int ac, char **av) {
  argc= ac-1; argv= av+1;
  setupTables();

  out_file= StrDup("/dev/dsp");
  rate= 44100; 
  fade_ms= 5;
  bfreq= 440;		//@@@@
  o_mvol= -0.95;
  addOptions(0, 0);

  if (!in_file) usage();
  process(in_file, in_seq ? in_seq : "main", out_file);

  return 0;
}

//
//	Process options - processes the given options, then the
//	original command line options once again.  This means that
//	command line options always override any options specified in
//	the file.
//	

void 
addOptions(int ac, char **av) {
  o_dump= 0;			// This gets incremented rather than set, so have to clear it
  processOptions(ac, av, 0);
  processOptions(argc, argv, 1);

  // Values calculated from options
  fade_period= rate * fade_ms / 1000;
  delta_period= rate/1000;
  if (delta_period < 32) delta_period= 32;
}

void 
processOptions(int ac, char **av, int f_main) {
  while (ac > 0) {	
    if (av[0][0] == '-' && av[0][1]) {
      int val; char dmy; double dval;
      char *p= *av++ + 1; ac--;
      while (*p) switch (*p++) {
       case 'o':
	 if (ac-- < 1) usage();
	 Free(out_file); out_file= StrDup(*av++);
	 break;
       case 'O':
	 Free(out_file); out_file= 0;
	 break;
       case 'r':
	 if (ac-- < 1 || 1 != sscanf(*av++, "%d %c", &val, &dmy)) usage();
	 rate= val; break;
       case 'A':
	 if (ac-- < 1 || 1 != sscanf(*av++, "%lg %c", &dval, &dmy)) usage();
	 o_mvol= -dval/100; break;
       case 'M':
	 if (ac-- < 1 || 1 != sscanf(*av++, "%lg %c", &dval, &dmy)) usage();
	 o_mvol= dval/100; break;
       case 'D':
	 o_dump++; break;
       case 'S':
	 if (ac-- < 1 || 1 != sscanf(*av++, "%d %c", &val, &dmy)) usage();
	 fade_ms= val < 0 ? 0 : val; break;
       default:
	 warn("Unknown option `%c'%s\n", p[-1], f_main ? "" : " in `opt' directive");
	 usage();
      }
    }
    else if (!f_main) {
      warn("Invalid option `%s' specified in `opt' directive\n", av[0]);
      usage();
    }
    else if (!av[0][0]) {	// Null entry - we've already processed it, probably
      av++; ac--;
    }
    else {
      char *p= *av++; ac--;
      if (!in_file) in_file= StrDup(p);
      else if (!in_seq) in_seq= StrDup(p);
      else usage();
      av[-1]= "";
    }
  }
}

// END //
