/* Syntring, a string synthesizer program.
 *
 * (c) 2007 Karel 'Clock' Kulhavy of Twibright Labs
 * This program is free software released under the GNU Public License version
 * 3 or later. */

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

#define PI 3.141592653589793238462643383279502884 /* M_PI is unreliable. Sometimes defined sometimes not. */

// #define CONSOLE_SOUND 
// 8-bit square wave sound - instead of sine waves,
// square waves are generated.

#define EXCITE_SAMPLES 140 /* How many individual excitation events should
			       occur. They occure every sample. */
// #define SHIFT_90
#define NOVERT 50 /* Number of overtones */

#define MIDDLE_A 440.0 /* You can bend the tuning here */
#define SAMPLE_RATE 44100 /* Must be an integer */

#define RETUNE_TIME 0.03
#define RETUNE_DAMP 850 /* Decibels per second. Sign is ignored. */
#define DISTORT_GAIN 0.00001

#define MULTIMODE_MODES 2
#define MULTIMODE_DETUNE 1.01 /* A constant slightly above 1 produces what normally
                                  multimodes do - decreased frequency. But slightly
                                  under 1 can be used too, to create increased
                                  frequencies. */
#define MULTIMODE_DECAY 0.7 /* This allows the modes became weaker (decay
			       exponentially ) so there is not a total AM but just
                               a partial one. */

#define ALMOST_ZERO 1e-9
#define PLUCK_DELAY 0.06 /* Must be more than RETUNE_TIME otherwise we are
			    plucking a string being damped and don't get much
			    sound */
#define STRUM_DELAY 0.03
#define STRUM_END 0.09


struct overtone{
	float f; /* relative frequency to the assigned tone */
	float a; /* Amplitude relative to the tone amplitude */
};

struct osc{
	double x,y; /* State space coordinates.*/
	double rot_x, rot_y; /* Has to be a unit circle vector. Has to be a
				double otherwise it does a runaway in some
				common situation */
	float rot_angle;
	double rot_step_x, rot_step_y; /* Also has to be a double because of
					  runaway */
	float rot_step_angle;
	int excite_counter; /* If zero, no excitation occurs. If nonzero,
			     excitation occurs and the timer is decremented. */
	float exciter_x, exciter_y; /* Set to 1,0 at the start of excitation
				       and is stepped with the oscillator. */
	int retune_counter; /* If this is >0, returning is in progress
			       (including damping): rot_x, rot_y is multiplied
			       with
			     rot_step_x,rot_step_y and retune_counter
			     is decremented. */
	double decay; /* A number by which the sample is multiplied every
			 sample when decaying. */
	char blocked; /* suspended because of bad frequency */
	char silent; /* silence because of low amplitude */
};

struct string{
	int tuning; /* 48 is middle C */
	float loudness; /* String loudness. linear, not dB */
	unsigned char distort_export; /* If this is set, the sum of notes is
					exported into the distorter with given
					parameters. */
	float distort_gain; /* Distorted input gain */
	float volume_left; /* Mixer gain */
	float volume_right; /* Mixer gain */
	int fret; /* How the string is currently fretted. 0=open, 1=1st
		     fret etc. */
	int pluck_timer; /* Goes down and when it switches from 1 to 0 then
			    it plucks */
	float pluck_strength; /* For pluck_timer */
	float reflection_loss; /* Cutoff frequency in Hz for the RC filter */
	float bend_loss;
	struct overtone overtones[NOVERT];
};

/* 48 (4*12, 4 octaves) is middle C (C4) */
static const unsigned char common_guitar_tuning[6]={
	40, /* E */
	45, /* A */
	38, /* D */
	43, /* G */
	47, /* H */
	52  /* e */
};

struct string *strings;

unsigned char *tune;
unsigned char *tune_end;
struct osc *oscillators;
unsigned retune_steps;
unsigned n_strings=16;
char oscillators_allocated;
char strings_allocated;
#define TAPE_GRAN 4096 /* Must be a power of two. Tape allocation granularity
			  counted in float numbers, not bytes. */
float *tape=NULL; /* Stereo tape, each sample is a pair of floats */
unsigned long tape_len; /* Number of *floats* (not samples) the tape is allocated
			   to */

/* Variables for runout monitoring */
unsigned strings_waiting_for_pluck; /* Used to detect the end of the song */
unsigned oscs_running; /*                    -||-                  */
float total_energy; /* Total energy stored in the oscillators */

float beat_period=60.0/130; /* 130bpm Rock default */
float beat_leftover; /* In seconds. Should be reset to 0 on every bpm change to
			prevent the sampling imprecision leftover to be
			amplified by the new/old bpm ratio. */
float inharmonicity=0.001; /* Default inharmonicity */
float retune_damp; /* The oscillator is multiplied by this every sample during
		      the retuning. It simulates the damping caused by the
		      string being lifted and the finger touching it. */

/* Normalizes from 0 to 1 */
float normalize_angle(float a)
{
	a-=floor(a);
	return a;
}

/* Angles are from 0 to 1 */
float sum_angles(float a1, float a2)
{
	float ret;

	a1=normalize_angle(a1);
	a2=normalize_angle(a2);

	if (fabs(a1-a2)>0.5) ret=(a1+a2+1)/2; /* Span more than 180 deg */
	else ret=(a1+a2)/2;
	return ret;
}
/* 0=bridge, 1=where the string is fretted down. pickup, pluck are positions
 * where the pickup is and the string is plucked.
 * Returns in the 0...2*PI range. */
float overtone_phase(double pickup, double pluck, int overtone)
{
	float a1, a2, a3, a4;

	/* Angles as seen by the fundamental */
	a1=(pickup+pluck)/2;
	a2=(pickup+pluck)/-2;
	a3=(1+pickup+pluck)/2;
	a4=(1-pickup-pluck)/2;

#ifdef SHIFT_90
	/* We don't need this anymore because we have a soft start. Actually,
	 * it limits the sharpness of the attack we can achieve. */
	/* Shift by quarter string roundtrip in time. That doesn't change
	 * the waveform, just shifts it. That's to place the cut point not
	 * on the peak but right between them - to avoid nasty clicks! */
	a1+=0.25;
	a2+=0.25;
	a3+=0.25;
	a4+=0.25;
#endif /* SHIFT_90 */

	/* Angles as seen by the overtone */
	a1*=overtone;
	a2*=overtone;
	a3*=overtone;
	a4*=overtone;
	return 2*PI*sum_angles(sum_angles(a1,a2),sum_angles(a3,a4));
}

/* Does one step, one sample. Returns the oscillator value before the step.
 * Depending on the state variables of the oscillator, it does a
 * decay step. Regarding frequency, it either does a retuning step or
 * a normal one. */
float osc_step(struct osc *o)
{
	double newx, newy;
	float retval;
#ifdef CONSOLE_SOUND
	float retval_imag;
#endif

	if (!o->silent){
		retval=o->x;
#ifdef CONSOLE_SOUND
		retval_imag=o->y;
#endif
	} else {
		retval=0;
#ifdef CONSOLE_SOUND
		retval_imag=0;
#endif
	}

	/* Handles frequency retuning */
	if (o->retune_counter){
		newx=o->rot_x*o->rot_step_x
			-o->rot_y*o->rot_step_y;
		newy=o->rot_x*o->rot_step_y
			+o->rot_step_x*o->rot_y;
		o->rot_x=newx;
		o->rot_y=newy;
		o->rot_angle+=o->rot_step_angle;
		o->retune_counter--;

		/* Damp */
		o->x*=retune_damp;
		o->y*=retune_damp;
	}

	if (o->excite_counter) o->silent=0;

	if (!o->silent){
		if (!o->blocked){
			/* Push the oscillator forward in it's oscillation */
			newx=o->x*o->rot_x-o->y*o->rot_y;
			newy=o->y*o->rot_x+o->x*o->rot_y;

			if (o->excite_counter){
				/* We should excite the oscillator */
				float enewx, enewy; /* Exciter */

				/* The excitation itself */
				newx+=o->exciter_x;
				newy+=o->exciter_y;

				/* Rotate the exciter */
				enewx=o->exciter_x*o->rot_x
					-o->exciter_y*o->rot_y;
				enewy=o->exciter_y*o->rot_x
					+o->exciter_x*o->rot_y;

				/* Save the rotated exciter */
				o->exciter_x=enewx;
				o->exciter_y=enewy;

				/* At zero, it doesn't excite anymore. */
				o->excite_counter--;
			}
		}else{
			newx=o->x;
			newy=o->y;
		}
		/* Let the amplitude decay */
		o->x=newx*o->decay;
		o->y=newy*o->decay;
		{
			float energy=o->x*o->x+o->y*o->y;
			total_energy+=energy;
			if (fabs(energy)<ALMOST_ZERO) o->silent=1;
		}

	}

	if (!o->silent) oscs_running++;
#ifdef CONSOLE_SOUND
	return (retval<0?-1:1)*sqrt(retval*retval+retval_imag*retval_imag);
#else
	return retval;
#endif
}

/* Halftone 0 means middle A (440Hz or whatever it's initialized to) */

void normalize_vector(float *x, float *y, float target_len)
{
	float len=sqrt(*x**x+*y**y);

	if (!len){
		*x=target_len;
		*y=0;
	}else{
		*x*=target_len/len;
		*y*=target_len/len;
	}
}

float getfreq(int halftone)
{
	return MIDDLE_A*pow(2, (halftone-9-4*12)/12.0);
}

/* Frequency is in Hertz */
void osc_retune(struct osc *o, float freq, double decay)
{
	if (freq>=SAMPLE_RATE/2){
		o->blocked=1;
		return;
	}
	o->blocked=0;
	o->decay=decay;
	/* freq in cycles/sec. now */
	freq/=SAMPLE_RATE;
	/* freq is cycles/sample now */
	freq*=2*PI;
	/* freq in radians/sample now */
	freq-=o->rot_angle;

	o->rot_x=cos(o->rot_angle);
	o->rot_y=sin(o->rot_angle);
	/* Make sure the vector doesn't drift from unit vector at given
	 * angle through time ! */

	o->rot_step_angle=freq/retune_steps;
	o->rot_step_x=cos(o->rot_step_angle);
	o->rot_step_y=sin(o->rot_step_angle);
	o->retune_counter=retune_steps;
}

void output_header(unsigned long samples)
{
	unsigned long bytes=samples*4; /* 16 bit stereo */

static unsigned char wav_header[]={'R','I','F','F',
	0xff, 0xff, 0xff, 0xff,
	'W','A','V','E',

	'f','m','t',' ',
	16, 0, 0, 0, /* 16 for PCM */
	1, 0, /* uncompressed PCM */
	2, 0, /* stereo */
	SAMPLE_RATE&0xff, (SAMPLE_RATE>>8)&0xff, (SAMPLE_RATE>>16)&0xff, (SAMPLE_RATE>>24)&0xff,
		/* samplerate */
	(SAMPLE_RATE<<1)&0xff, (SAMPLE_RATE>>7)&0xff,
	(SAMPLE_RATE>>15)&0xff, (SAMPLE_RATE>>23)&0xff,
		/* byterate */
	4, 0, /* blockalign */
	16, 0, /* bits per sample */

	'd','a','t','a',
	0xff, 0xff, 0xff, 0xff
};
	wav_header[sizeof wav_header-1]=(bytes>>24)&0xff;
	wav_header[sizeof wav_header-2]=(bytes>>16)&0xff;
	wav_header[sizeof wav_header-3]=(bytes>>8)&0xff;
	wav_header[sizeof wav_header-4]=bytes&0xff;
	fwrite(wav_header, sizeof wav_header, 1, stdout);
}

static void osc_init(struct osc *o)
{
	o->x=0;
	o->y=0;
	o->rot_x=1;
	o->rot_y=0;
	o->rot_angle=0;
	o->retune_counter=0; /* This invalidates the rot_step_? */
	o->decay=0;
}

float distort(float x)
{
	return x;

	x*=DISTORT_GAIN;
	x+=2;
	if (x<0) x=0;
	x*=x;
	x/=4;
	x-=1;
	return x;
}

void dump_halftone(unsigned halftone)
{
	putc('0'+halftone/12, stderr);
	halftone=halftone%12;
	if (halftone>=10) putc ('a'+halftone-10, stderr);
	else putc ('0'+halftone, stderr);
}

/* Sets the decay times for the overtones, their frequencies to zero and
 * their loudness to 0 */
void init_instrument(struct osc* i)
{
	int h;

	for (h=0;h<NOVERT*MULTIMODE_MODES; h++, i++)
		osc_init(i);
}

/* Attack time is in seconds */
void pluck_string(int string_no, float strength)
{
	int overtone,chorus_copy;
	struct osc *oscptr;
	oscptr=oscillators+string_no*MULTIMODE_MODES*NOVERT;

	for (overtone=0;overtone<NOVERT; overtone++)
		for (chorus_copy=0; chorus_copy<MULTIMODE_MODES; chorus_copy++){

			float phase, amplitude;
			float shortening; /* >1 means the string is shortened,
					     <1 means lenghtened (never happens)
					     */

			shortening=pow(2,strings[string_no].fret/12.0);

			phase=overtone_phase(0.058*shortening, 0.142*shortening,
				floor(strings[string_no].overtones[overtone].f+0.5));
			amplitude=strength*strings[string_no].overtones[overtone].a
				*pow(MULTIMODE_DECAY, chorus_copy);


			oscptr->excite_counter=EXCITE_SAMPLES;
			oscptr->exciter_x=amplitude*cos(phase)
				/oscptr->excite_counter;
			oscptr->exciter_y=amplitude*sin(phase)
				/oscptr->excite_counter;
			oscptr++;
		}
}

/* Turns an overtone theoretical relative frequency into the more real one */
float inharmonize(float perfect)
{
	return perfect+inharmonicity*perfect*(perfect-1);
}

void retune_string(struct osc *i, int halftone, float bend_loss, float
		reflection_loss, int string)
{
	int overtone, c;
	float freq=getfreq(halftone);

	for (c=0;c<MULTIMODE_MODES;c++)
	for (overtone=0;overtone<NOVERT; overtone++){
		float overtone_freq=freq
			*inharmonize(strings[string].overtones[overtone].f);

		double decay=exp((overtone_freq*log1p(-bend_loss)
			+freq*log1p(-reflection_loss))/SAMPLE_RATE);

		osc_retune(i, overtone_freq
			/pow(MULTIMODE_DETUNE,c)
			, decay);
		i++;
		}
}

float step_instrument(struct osc *i)
{
	int h;
	float result=0;

	for (h=0;h<NOVERT*MULTIMODE_MODES; h++)
		result+=osc_step(i+h);
	return result;
}

/* Automatically skips in case of match */
int begins(unsigned char **tab, unsigned char *pattern){
	unsigned plen=strlen((char *)pattern);

	if (*tab+plen>tune_end) return 0;
	if (!memcmp(*tab, pattern, plen)){ /* Match */
		*tab+=plen;
		return 1;
	}else return 0;

}

void *mem_alloc(size_t size){
	void *ret;
	ret=malloc(size);
	if (!ret&&size){
		fprintf(stderr,"Error: can't allocate any more "
			"memory.\n");
		exit(1);
	}
	return ret;
}

/* Initializes the string descriptors so parameters like tuning, loudness,
 * etc. can be set. */
void init_strings(void)
{
	int string;
	unsigned long nbytes;

	if (!n_strings){
		fprintf(stderr,"Before the first string setup command you "
			"have to first specify the number of oscillators.\n");
		exit(1);
	}
	nbytes=n_strings*MULTIMODE_MODES*NOVERT*sizeof *strings;
	strings=mem_alloc(nbytes);
	strings_allocated=1;
	memset(strings, 0, nbytes);

	for (string=0;string<n_strings;string++){
		strings[string].tuning=common_guitar_tuning[string%6]; 
		/* Default guitar tuning. */
		strings[string].loudness=1; /* Default unit loudness */

		/* Default to 6-string guitars */
		strings[string].distort_export=(string%6==5);
		if (string==n_strings-1) strings[string].distort_export=1;

		strings[string].distort_gain=1;
		strings[string].volume_left=(string/6)&1?0.25:0.75;
		strings[string].volume_right=(string/6)&1?0.75:0.25;
		strings[string].fret=0;
		strings[string].pluck_timer=0;
		strings[string].reflection_loss=0.002;
		strings[string].bend_loss=0.009;
		memset(strings[string].overtones, 0,
				sizeof(strings[string].overtones));
	}

	/* Calculate damping in decibels per sample and then translate
	 * to a multiplier */
	retune_damp=pow(10, -fabs((double)RETUNE_DAMP)/SAMPLE_RATE/20);
	fprintf(stderr,"retune_damp=%G\n", retune_damp);
}

void init_oscillators(void)
{
	unsigned long nbytes;
	int string;

	if (!strings_allocated){
		init_strings();
	}
	nbytes=n_strings*MULTIMODE_MODES*NOVERT*sizeof *oscillators;
	oscillators=mem_alloc(nbytes);
	oscillators_allocated=1;
	memset(oscillators, 0, nbytes);

	for (string=0;string<n_strings;string++){
		init_instrument(oscillators+string*MULTIMODE_MODES*NOVERT);
	}
}

/* Give the first char after the underscore. Returns first char after the
 * terminating newline. */
unsigned char * parse_tab(unsigned char *tab){
	int string=0;

	if (tab>=tune_end) return tune_end;
	if (!oscillators_allocated) init_oscillators();
	putc('_', stderr);
	for (;*tab!='\n';tab++){
		if (tab>=tune_end) return tune_end;
		putc(*tab, stderr);
		if (*tab==' '||*tab=='\t') continue;
		if (*tab>='0'&&*tab<='9'&&string<n_strings){
			int fret=*tab-'0';
			retune_string(oscillators+string*MULTIMODE_MODES*NOVERT,
				strings[string].tuning+fret, strings[string].
				bend_loss, strings[string].reflection_loss,
				string);
			strings[string].fret=fret;
			if (string>=6&&string<12){
				strings[string].pluck_timer
					=SAMPLE_RATE*(STRUM_DELAY+
					(STRUM_END-STRUM_DELAY)
					*(string-6)/5);
			}else
			strings[string].pluck_timer=PLUCK_DELAY*SAMPLE_RATE;
			strings[string].pluck_strength
				=strings[string].loudness;
		}
		string++;
	}
	putc('\n', stderr);
	return tab+1; /* Skip the \n */
}

unsigned char *find_skip_newline(unsigned char *ptr)
{
	while(ptr<tune_end&&(*ptr!='\n')) ptr++;
	if (ptr>=tune_end) return ptr; /* End of file */
	else return ptr+1; /* Skip the newline */
}

/* 1=char was found and skipped, 0=not found, nothing done */
int skip_char(unsigned char **ptr, unsigned char c)
{
	if (**ptr==c){
		(*ptr)++;
		return 1;
	}
	return 0;
}

/* Skips whitespace except newlines. */
unsigned char *skip_whitespace(unsigned char *ptr)
{
	while(ptr<tune_end&&(*ptr==' '||*ptr=='\t')) ptr++;
	return ptr;
}

/* Skips whitespace at the beginning */
unsigned char *get_decimal(int *dest, unsigned char *txt)
{
	unsigned val=0;

	txt=skip_whitespace(txt);
	for (;*txt>='0'&&*txt<='9'&&txt<tune_end;txt++){
		val*=10;
		val+=*txt-'0';
	}
	*dest=val;
	return txt;

}

/* C2, d#4, Gb etc. format. */
unsigned char *get_note(int *output, unsigned char *ptr)
{
	int semitone;
	int octave;
	static unsigned char semitones[8]={
		9,11,0,2,4,5,7,11};

	ptr=skip_whitespace(ptr);
	if (ptr>=tune_end){
		fprintf(stderr,"Error: expecting a note, got an end of"
				" file.\n");
		exit(1);
	}
	semitone=*ptr;
	if (semitone>'Z') semitone-='z'-'Z'; /* To uppercase */
	if (semitone<'A'||semitone>'H'){
		fprintf(stderr,"Error: nonsensical note: %c\n", *ptr);
		exit(1);
	}
	ptr++;
	semitone=semitones[semitone-'A'];
	if (skip_char(&ptr,'#')) /* Sharp */ semitone++;
	else if (skip_char(&ptr,'b')) /* Flat */ semitone--;
	ptr=get_decimal(&octave, ptr);
	*output=semitone+12*octave;
	return ptr;
}

/* Skips whitespace at the beginning. Also allocates. */
int get_string(unsigned char **ptr)
{
	int string;

	if (!strings_allocated) init_strings();

	*ptr=get_decimal(&string, *ptr);
	if (string>n_strings){
		fprintf(stderr,"Error: string number %d too high\n",
				string);
		exit(1);
	}
	return string;
}

/* Returns the char after the newline. */
unsigned char * parse_tuning(unsigned char *tab){
	int string;
	int semitone;

	string=get_string(&tab);
	tab=get_note(&semitone, tab);
	fprintf(stderr,"Tuning string %d to %d semitones above C0\n"
		, string, semitone);
	strings[string].tuning=semitone;

	return find_skip_newline(tab);
}

unsigned char *get_float(float *dst, unsigned char *ptr)
{
	unsigned char *temp;
	unsigned char *begin;

	ptr=skip_whitespace(ptr);
	begin=ptr;
	while(*ptr=='-'||*ptr=='.'||(*ptr>='0'&&*ptr<='9')) ptr++;
	temp=mem_alloc(ptr-begin+1);
	memcpy(temp, begin, ptr-begin);
	temp[ptr-begin]=0;
	*dst=atof((char *)temp);
	free(temp);
	return ptr;
}

/* Skips whitespace at the beginning too. Never puts bigger number into string
 * than string2. */
unsigned char *get_string_range(int *string, int *string2, unsigned char *tab)
{
	*string=get_string(&tab);
	tab=skip_whitespace(tab);
	if (skip_char(&tab, '/')) *string2=get_string(&tab);
	else *string2=*string;
	return tab;
}

unsigned char *parse_volume(unsigned char *tab){
	int string, string2;
	float volume;

	tab=get_string_range(&string, &string2, tab);
	tab=get_float(&volume, tab);
	for (;string<=string2;string++){
		fprintf(stderr,"Setting string %d to volume %G dB.\n"
			,string, volume);
		strings[string].loudness=pow(10, volume/20);
	}
	tab=find_skip_newline(tab);
	return tab;
}

unsigned char *parse_reflection_loss(unsigned char *tab)
{
	int string, string2;
	float reflection_loss;

	if (!strings_allocated) init_strings();

	tab=get_string_range(&string, &string2, tab);
	tab=get_float(&reflection_loss, tab);
	for (;string<=string2;string++){
		fprintf(stderr,"Setting reflection loss of string "
				"%d to %G.\n"
			,string, reflection_loss);
		strings[string].reflection_loss=reflection_loss;
	}
	tab=find_skip_newline(tab);
	return tab;
}

unsigned char *parse_overtone(unsigned char *tab)
{
	int string, string2;
	int index;
	float freq;
	float dB;

	tab=get_string_range(&string, &string2, tab);
	tab=get_decimal(&index, tab);
	tab=get_float(&freq, tab);
	tab=get_float(&dB, tab);
	dB=pow(10,-dB/20);
	if (index>=NOVERT){
		fprintf(stderr,"Error: overtone index %d out of range\n",
				index);
		exit(1);
	}
	for (;string<=string2;string++){
		fprintf(stderr,"Setting overtone %d of string "
				"%d to freq. %G amplitude %G.\n"
			, index, string, freq, dB);
		strings[string].overtones[index].f=freq;
		strings[string].overtones[index].a=dB;
	}
	tab=find_skip_newline(tab);
	return tab;
}

unsigned char *parse_bend_loss(unsigned char *tab)
{
	int string, string2;
	float bend_loss;

	tab=get_string_range(&string, &string2, tab);
	tab=get_float(&bend_loss, tab);
	for (;string<=string2;string++){
		fprintf(stderr,"Setting reflection loss of string "
				"%d to %G.\n"
			,string, bend_loss);
		strings[string].bend_loss=bend_loss;
	}
	tab=find_skip_newline(tab);
	return tab;
}

unsigned char *parse_bpm(unsigned char *tab){
	float bpm;

	tab=get_float(&bpm, tab);
	fprintf(stderr,"Setting tempo to %G BPM.\n" ,bpm);
	beat_period=60/bpm;
	beat_leftover=0; /* See the global def why */
	tab=find_skip_newline(tab);
	return tab;
}

unsigned char *parse_inharmonicity(unsigned char *tab){

	tab=get_float(&inharmonicity, tab);
	fprintf(stderr,"Setting inharmonicity to %G.\n" ,inharmonicity);
	tab=find_skip_newline(tab);
	return tab;
}

/* Parses file until it reads one tab line. The input pointer can be one
 * after the end of tune. */
unsigned char *parse_line(unsigned char *tab)
{
another_line:
	tab=skip_whitespace(tab); /* Skip whitespace at the beginning
		of a line */
	if (tab>=tune_end) return tune_end;
	if (begins(&tab,(unsigned char *)"_")){
		return parse_tab(tab);
	}else if(begins(&tab, (unsigned char *)"tuning")){
		tab=parse_tuning(tab);
	}else if(begins(&tab,(unsigned char *)"volume")){
		tab=parse_volume(tab);
	}else if(begins(&tab,(unsigned char *)"reflection_loss")){
		tab=parse_reflection_loss(tab);
	}else if(begins(&tab,(unsigned char *)"bend_loss")){
		tab=parse_bend_loss(tab);
#if 0
		/* Not implemented yet */
	}else if(begins(&tab,"retune_damping")){
		tab=parse_retune_damping(tab);
#endif
	}else if(begins(&tab,(unsigned char *)"overtone")){
		tab=parse_overtone(tab);
	}else if(begins(&tab,(unsigned char *)"bpm")){
		tab=parse_bpm(tab);
	}else if(begins(&tab,(unsigned char *)"inharmonicity")){
		tab=parse_inharmonicity(tab);
	}else tab=find_skip_newline(tab);
	goto another_line;
}

/* Make sure the excursion with tone strength 1 never reaches out of range */
void prepare(void)
{
	fprintf(stderr,"%u oscillators, each %u overtones, each %u chorus "
			"copies\n", n_strings, NOVERT, MULTIMODE_MODES);

	retune_steps=SAMPLE_RATE*RETUNE_TIME+1;
}

void load_tune(unsigned char *fname)
{
	FILE *f;
	unsigned long len;

	f=fopen((char *)fname,"r");
	if (!f){
		fprintf(stderr,"Cannot open %s\n", fname);
		exit(1);
	}
	fseek(f, 0, SEEK_END);
	len=ftell(f);
	fseek(f,0,SEEK_SET);
	tune=mem_alloc(len);
	if (!tune){
		fprintf(stderr,"Malloc failed.\n");
		exit(1);
	}
	tune_end=tune+len;
	fread(tune, len, 1, f);
	fclose(f);
}

/* Makes the DC average 0. Then scales to maximum volume so that there is
 * no clipping or overflow. Doesn't scale channels individually but together. */
void output_tape(unsigned long output_samples)
{
	int slot;
	float left_avg=0, right_avg=0;
	float left_max=0, right_max=0;
	int out_int;

	/* Calculate averages */
	for (slot=0;slot<2*output_samples;slot+=2){
		left_avg+=tape[slot+0];
		right_avg+=tape[slot+1];
	}
	left_avg/=output_samples;
	right_avg/=output_samples;

	/* Subtract averages */
	for (slot=0;slot<2*output_samples;slot+=2){
		tape[slot+0]-=left_avg;
		tape[slot+1]-=right_avg;

		if (fabs(tape[slot+0])>left_max) left_max=fabs(tape[slot+0]);
		if (fabs(tape[slot+1])>right_max) right_max=fabs(tape[slot+1]);
	}

	/* Make sure you don't change the relative loudness of the channels */
	if (left_max>right_max) right_max=left_max; else left_max=right_max;

	left_max=32767.0/left_max; /* Now holds mul. coefficients */
	right_max=32767.0/right_max;

	for (slot=0;slot<2*output_samples;slot+=2){
		tape[slot]*=left_max;
		tape[slot+1]*=right_max;
	}

	/* Output the file */
	output_header(output_samples);
	for (slot=0;slot<2*output_samples;slot++){
		out_int=floor(tape[slot]);
		putchar(out_int&255);
		putchar((out_int>>8)&255);
	}
}


void step_string(int string)
{
	if (strings[string].pluck_timer){
		strings_waiting_for_pluck++;
		strings[string].pluck_timer--;
		if (!strings[string].pluck_timer)
			pluck_string(string, strings[string].pluck_strength);
	}
}

void write_tape(unsigned long pos, float val, float strength)
{
	if (pos>=tape_len){
		unsigned long newlen;

		newlen=(pos|(TAPE_GRAN-1))+1;
		tape=realloc(tape,newlen*sizeof(*tape));
		/* tape_len is updated below */

		if (!tape){
			fprintf(stderr,"syntring: error: out of memory\n");
			exit(1);
		}

		/* Clear the remainder */
		for (;tape_len<newlen;tape_len++)tape[tape_len]=0;

	}
	tape[pos]+=val*strength;
}

/* Sample says where to save the result */
void step_strings(unsigned long sample)
{
	float l=0,r=0;
	/* float l2, r2; */
	int string;

	for (string=0;string<(n_strings>>1);string++){
		step_string(string);
		l+=step_instrument(oscillators+string*MULTIMODE_MODES*NOVERT);
	}
	for (;string<n_strings;string++){
		step_string(string);
		r+=step_instrument(oscillators+string*MULTIMODE_MODES*NOVERT);
	}
	l=distort(l);
	r=distort(r);
	/*
	 * I don't know or remember for what it was.
	l2=0.75*(l+r/3);
	r2=0.75*(r+l/3);
	*/
	write_tape(sample*2, l, 1);
	write_tape(sample*2+1, r, 1);
}

int main(int argc, char **argv)
{
	int sample;
	unsigned char *tuneptr;

	if (argc<2){
		fprintf(stderr,"Usage: syntring <tabfile>\n");
		exit(1);
	}
	load_tune((unsigned char *)argv[1]);
	prepare();

	tuneptr=parse_line(tune); 
	/* Do the first step and init everything if the
				file contains at least one tab line */
	if (!oscillators_allocated){
		fprintf(stderr,"Error: no tab - no music!\n");
		exit(1);
	}
	for (sample=0;tuneptr<tune_end||oscs_running
		 ||strings_waiting_for_pluck;sample++){

		/* Take care of the beat */
		if (beat_leftover>beat_period){
			beat_leftover-=beat_period;
			tuneptr=parse_line(tuneptr);
		}
		beat_leftover+=1.0/SAMPLE_RATE;

		strings_waiting_for_pluck=0;
		oscs_running=0;
		total_energy=0;
		step_strings(sample);
		if (tuneptr==tune_end&&!(sample%(SAMPLE_RATE*10))){
			/* Multiple of 10 seconds */
			fprintf(stderr,"%u sec., %u oscs running, level %f dB"
					", %u strings "
				"waiting for a pluck\n", sample/SAMPLE_RATE
				,oscs_running
				,10*log10(total_energy)
				,strings_waiting_for_pluck);
		}
	}
	fprintf(stderr,"The song is %f seconds long.\n"
		, (float)sample/SAMPLE_RATE);
	output_tape(sample);

	return 0;
}
