
/*********************************************************************************
 **	Chordian -- a program to mix tunes of a sample into a chord		**
 ** 										**
 ** 	Released to the public domain by Andreas Fredriksson (dep@canit.se)	**
 **										**
 **	If you use this program or the source code in any way, mention my name.	**
 **										**
 *********************************************************************************/

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

float diffs[]={ 1.0000, 1.0594, 1.1225, 1.1892,
		1.2600, 1.3348, 1.4142, 1.4983,
		1.5874, 1.6818, 1.7817, 1.8878 };

char infoline[]={"Chordian v1.0 -- copyright (c)1996 by Andreas Fredriksson (dep@canit.se)\n"};

char usage[]={"
Usage:\n
Chordian <sample> <output> [i] n1 n2 [n3..]\n
<sample>	the sample you wish to make a chord from
<output>	the chord sample to create
i		use interpolation
the n values are tones relative to the basenote
values n1,n2 are required but up to 4 may be given\n
example:
	Chordian organ.raw organchord i 0 3 7\n
This would create a minor chord from the sample 'organ.raw' and
place the result in the file 'organchord'.\n\n"};


long filesize(FILE *f)
	{
	long s;
	fseek(f,0,2); s=ftell(f); rewind(f);
	return(s);
	}


/*  cut(): not needed anymore but kept if I want to change the smp-size someday */

/*
void cut(float *f,long s)
	{
	if(*f>=s) *f=s-1;
	}
*/



/* macro to get the fractional part from a float */

#define frac(a) (a-floor(a))

int main(int argc, char *argv[])
	{
	FILE *in,*out;
	int x;
	long csize,size=0;
	char interpolate=0, num, *sample, *chord;
	char numnotes=-1, notes[4]={0,0,0,0}, *tmp;

	float pos1=0,pos2=0,pos3=0,pos4=0,tmpfloat,v1,v2,v3,v4;
	float step1=0,step2=0,step3=0,step4=0;

	if(argc<5) { printf("%s%s",infoline,usage); exit(0); }

	printf("%s",infoline);

	/* open files needed */
	if(!(in=fopen(argv[1],"rb"))) { printf("Couldn't open file '%s'.\n",argv[1]); exit(0); }
	if(!(out=fopen(argv[2],"wb"))) { printf("Couldn't create file '%s'.\n",argv[2]); fclose(in); exit(0);}

	/* check for 'i' flag */
	if(*argv[3]=='i' || *argv[3]=='I')
		{
		interpolate=1;
		num=4;
		puts("Interpolation enabled.");
		}
	else num=3;

	/* read the notes */
	tmp=notes;	/* set up a pointer */
	while(num<=argc && numnotes<4)
		{
		*tmp++=atoi(argv[num]);
		numnotes++;
		num++;
		}

	/* print some info */
	printf("Mixing sample '%s' to '%s'.\n",argv[1],argv[2]);
	printf("Notes in use (%d) :",numnotes);

	for(x=0;x<numnotes;x++)
		{
		printf(" %d",notes[x]);
		}
	printf("\n");



	/* allocate memory and read the sample */

	size=filesize(in);

	sample=(char *)malloc(size);
	chord=(char *)malloc(size);

	if( (!(sample)) || (!(chord)) )
		{
		fclose(in); fclose(out);
		puts("Error: Out of memory.");
		exit(0);
		}

	fread(sample,1,size,in);

	/* do the mixing */

	step1=diffs[notes[0]];	/* get stepvalues */
	step2=diffs[notes[1]];
	step3=diffs[notes[2]];
	step4=diffs[notes[3]];

	/* find biggest stepvalue, divide size with it to get chord size */

	tmpfloat=-10;
	if(step1>tmpfloat) tmpfloat=step1;
	if(step2>tmpfloat) tmpfloat=step2;
	if(step3>tmpfloat) tmpfloat=step3;
	if(step4>tmpfloat) tmpfloat=step4;

	csize=size/tmpfloat;

	printf("Sample size: %d\n",size);
	printf(" Chord size: %d (based on highest note)\n",csize);

	tmp=chord;	/* set up a pointer */

	if(interpolate)
		{
		switch(numnotes)
			{
			case 2:
				for(x=0;x<size;x++)
					{
					v1=sample[(int)pos1]*(1-frac(pos1))+
					  +sample[(int)pos1+1]*(frac(pos1));
					v2=sample[(int)pos2]*(1-frac(pos2))+
					  +sample[(int)pos2+1]*(frac(pos2));
					*tmp++=(v1+v2)/2;
					pos1+=step1;
					pos2+=step2;
					}
				break;

			case 3:
				for(x=0;x<size;x++)
					{
					v1=sample[(int)pos1]*(1-frac(pos1))+
					  +sample[(int)pos1+1]*(frac(pos1));
					v2=sample[(int)pos2]*(1-frac(pos2))+
					  +sample[(int)pos2+1]*(frac(pos2));
					v3=sample[(int)pos3]*(1-frac(pos3))+
					  +sample[(int)pos3+1]*(frac(pos3));
					*tmp++=(v1+v2+v3)/3;
					pos1+=step1;
					pos2+=step2;
					pos3+=step3;
					}
				break;

			case 4:
				for(x=0;x<size;x++)
					{
					v1=sample[(int)pos1]*(1-frac(pos1))+
					  +sample[(int)pos1+1]*(frac(pos1));
					v2=sample[(int)pos2]*(1-frac(pos2))+
					  +sample[(int)pos2+1]*(frac(pos2));
					v3=sample[(int)pos3]*(1-frac(pos3))+
					  +sample[(int)pos3+1]*(frac(pos3));
					v4=sample[(int)pos4]*(1-frac(pos4))+
					  +sample[(int)pos4+1]*(frac(pos4));
					*tmp++=(v1+v2+v3+v4)/4;
					pos1+=step1;
					pos2+=step2;
					pos3+=step3;
					pos4+=step4;
					}
				break;
			}
		}
	else
		{
		switch(numnotes)
			{
			case 2:
				for(x=0;x<csize;x++)
					{
					/*cut(&pos1,size); cut(&pos2,size);*/
					*tmp++= (sample[(int)pos1]
						+sample[(int)pos2])/2;
					pos1+=step1;
					pos2+=step2;
					}
				break;


			case 3:
				for(x=0;x<csize;x++)
					{
					/*cut(&pos1,size); cut(&pos2,size); cut(&pos3,size);*/
					*tmp++= (sample[(int)pos1]
						+sample[(int)pos2]
						+sample[(int)pos3])/3;
					pos1+=step1;
					pos2+=step2;
					pos3+=step3;
					}
				break;


			case 4:
				for(x=0;x<csize;x++)
					{
					/*cut(&pos1,size); cut(&pos2,size); cut(&pos3,size); cut(&pos4,size);*/
					*tmp++= (sample[(int)pos1]
						+sample[(int)pos2]
						+sample[(int)pos3]
						+sample[(int)pos4])/4;
					pos1+=step1;
					pos2+=step2;
					pos3+=step3;
					pos4+=step4;
					}
				break;
			}
		}

	/* save data to disk */

	printf("Saving data.. ");
	fwrite(chord,1,csize,out);
	printf("done.\n");

	/* close files & free memory */

	free(sample);
	free(chord);
	fclose(in);
	fclose(out);
	}
