#include <stdio.h>
#include "../H/ugens.h"
#include <signal.h>
#include <sys/soundfile.h>

#define NFILES 4
extern int NBYTES;           /* size of buffer to allocate */

extern int  sfd[NFILES];     /* soundfile descriptors */

extern int  pointer[NFILES]; /* to be used as pointer within sound buffer */
extern int  bufsize[NFILES]; /* word length of buffer */
extern char *buffer[NFILES]; /* address of buffer */
extern char *peak[NFILES];   /* array to store peak amplitude for nchannels */
extern char *ovpeak[NFILES];
extern struct SFDESC sfdesc[NFILES];

extern float SR;

int doit,input,output,stopit(),non,outch[4],inpch[4],opoint;
float amp,*pk,*ovpk,dur,enval;
long nsamps,loop;

int counter,skip;
int lineset = 0;
#define SIZE  512
float array[SIZE],tabs[2];
int RESET = 200;  /* times per sec to reinitialize envelope */

reset(p,n_args)
float *p;
{
	if(p[0]) RESET = p[0];
	fprintf(stderr,"Envelope calls set to %d times per sec\n",RESET);
}

mix(p,n_args)
float *p;
int n_args;
{
	int jj;
	input = 0; 
	output = 1;
	pk = (float *)peak[output];
/*	p[2] = (p[2] != 0.) ? p[2] : 
		((float)sfdesc[input].sf_bsize/(float)sfdesc[input].sf_class) /
		(sfdesc[input].sf_srate * (float)sfdesc[input].sf_chans);
printf(" endtime = %f\n",p[2]);   */
		/* if p2 == 0 it is reset to end of file */
	dur = (p[2] < 0) ? -p[2] : (p[2] - p[0]);
	ovpk = (float *)ovpeak[output];
	printf(" Overall peak to start is %e\n",*ovpk);

	if(!lineset) {
		for(jj=0; jj<SIZE; jj++) array[jj] = 1;
		fprintf(stderr,"Set phrase curve to all 1's\n");
		lineset = 1;
		}
	nsamps = setnot(p[0],dur,input);
		 setnot(p[1],dur,output);

	tableset(dur,SIZE,tabs);
	skip = SR/(float)RESET;  /* number of samples between reinits */
	counter = 0;  /* initialize counter */

	if(sflseek(sfd[output],(long)-NBYTES,1) < 0) {
		printf(" bad sflseek\n");
		sfclose();
		}
	amp = p[3];
	non=0;
	for(jj = 0; jj<sfdesc[input].sf_chans; jj++) {
		if(p[4+jj] >= 0) {
			if((outch[non] = p[4+jj]) >= sfdesc[output].sf_chans) {
				printf(" Wrong number of channels on output\n");
			closesf(); }
		inpch[non] = jj;
		non++;
		}
	}

	doit = 1;
	signal(SIGINT,SIG_DFL);
	signal(SIGINT,stopit);
	if(sfdesc[input].sf_class == INT) {
		if(sfdesc[output].sf_class == INT) {
			mixii(p);
			return;
		}
		if(sfdesc[output].sf_class == FLOAT) {
			mixif(p);
			return;
		}
	}
	else {
		if(sfdesc[output].sf_class == INT) {
			mixfi(p);
			return;
		}
		if(sfdesc[output].sf_class == FLOAT) {
			mixff(p);
			return;
		}
	}
}
mixii(p)
float *p;
{
	register jj,*ibuf,*obuf,ipoint;
	ibuf = (int *)buffer[input];
	obuf = (int *)buffer[output];
	for(loop=0; loop<nsamps; loop++) { 
		if(!counter--) {
			enval = tablei(loop,array,tabs) * amp;
			counter = skip;
			}
		if(!doit) break; 
		for(jj = 0,opoint=pointer[output],ipoint=pointer[input];
		             jj<non; jj++) 
			    if((*(obuf + opoint + outch[jj]) +=
			    enval * *(ibuf + ipoint + inpch[jj])) > 
			        *(pk + outch[jj])) 
				*(pk + outch[jj]) = 
				    *(obuf + opoint + outch[jj]);
		pointer[input] += sfdesc[input].sf_chans;
		pointer[output] += sfdesc[output].sf_chans;
		if(pointer[input] >= bufsize[input] ) {
			pointer[input] = 0;
			readit(input);
		}
		if(pointer[output] >= bufsize[output] ) {
			pointer[output] = 0;
			writeit(output);
			readit(output);
			if(sflseek(sfd[output],(long)-NBYTES,1) < 0) {
				printf(" bad sflseek\n");
				sfclose();
			}
		}
	}
	writeit(output); 
	endnot(output);
}
mixif(p)
float *p;
{
	register jj,*ibuf,ipoint;
	float *obuf;
	ibuf = (int *)buffer[input];
	obuf = (float *)buffer[output];
	for(loop=0; loop<nsamps; loop++) { 
		if(!counter--) {
			enval = tablei(loop,array,tabs) * amp;
			counter = skip;
			}
		if(!doit) break; 
		for(jj = 0,opoint=pointer[output],ipoint=pointer[input];
		             jj<non; jj++) 
			    if((*(obuf + opoint + outch[jj]) +=
			    enval * *(ibuf + ipoint + inpch[jj])) > 
			    *(pk + outch[jj])) 
				*(pk + outch[jj]) = 
				    *(obuf + opoint + outch[jj]);
		pointer[input] += sfdesc[input].sf_chans;
		pointer[output] += sfdesc[output].sf_chans;
		if(pointer[input] >= bufsize[input] ) {
			pointer[input] = 0;
			readit(input);
		}
		if(pointer[output] >= bufsize[output] ) {
			pointer[output] = 0;
			writeit(output);
			readit(output);
			if(sflseek(sfd[output],(long)-NBYTES,1) < 0) {
				printf(" bad sflseek\n");
				sfclose();
			}
		}
	}
	writeit(output);
	endnot(output);
}
mixfi(p)
float *p;
{
	register jj,*obuf,ipoint;
	float *ibuf;
	ibuf = (float *)buffer[input];
	obuf = (int *)buffer[output];
	for(loop=0; loop<nsamps; loop++) { 
		if(!counter--) {
			enval = tablei(loop,array,tabs) * amp;
			counter = skip;
			}
		if(!doit) break; 
		for(jj = 0,opoint=pointer[output],ipoint=pointer[input];
		             jj<non; jj++) 
			    if((*(obuf + opoint + outch[jj]) +=
			    enval * *(ibuf + ipoint + inpch[jj])) > 
			    *(pk + outch[jj])) 
				*(pk + outch[jj]) = 
				    *(obuf + opoint + outch[jj]);
		pointer[input] += sfdesc[input].sf_chans;
		pointer[output] += sfdesc[output].sf_chans;
		if(pointer[input] >= bufsize[input] ) {
			pointer[input] = 0;
			readit(input);
		}
		if(pointer[output] >= bufsize[output] ) {
			pointer[output] = 0;
			writeit(output);
			readit(output);
			if(sflseek(sfd[output],(long)-NBYTES,1) < 0) {
				printf(" bad sflseek\n");
				sfclose();
			}
		}
	}
	writeit(output);
	endnot(output);
}
mixff(p)
float *p;
{
	register jj,ipoint;
	float *ibuf,*obuf;
	ibuf = (float *)buffer[input];
	obuf = (float *)buffer[output];
	for(loop=0; loop<nsamps; loop++) { 
		if(!counter--) {
			enval = tablei(loop,array,tabs) * amp;
			counter = skip;
			}
		if(!doit) break; 
		for(jj = 0,opoint=pointer[output],ipoint=pointer[input];
		             jj<non; jj++) 
			    if((*(obuf + opoint + outch[jj]) +=
			    enval * *(ibuf + ipoint + inpch[jj])) > 
			    *(pk + outch[jj])) 
				*(pk + outch[jj]) = 
				    *(obuf + opoint + outch[jj]);
		pointer[input] += sfdesc[input].sf_chans;
		pointer[output] += sfdesc[output].sf_chans;
		if(pointer[input] >= bufsize[input] ) {
			pointer[input] = 0;
			readit(input);
		}
		if(pointer[output] >= bufsize[output] ) {
			pointer[output] = 0;
			writeit(output);
			readit(output);
			if(sflseek(sfd[output],(long)-NBYTES,1) < 0) {
				printf(" bad sflseek\n");
				sfclose();
			}
		}
	}
	writeit(output);
	endnot(output);
}
stopit() {
	doit =  0; 
}

setline(p,n_args)
float *p;
{
	double increm;
	int i,j,k,points;

	if((n_args % 2) != 0) {
		fprintf(stderr,"Something wrong with phrase, check args\n");
		closesf();
	}

	lineset = 1;   /* initialized array */
	increm = (double)(p[n_args - 2] - p[0])/(double)SIZE;
	for(j=0,i=0; j < (n_args-2); j += 2) {
		points = (int)((double)(p[j+2] - p[j]) / increm +.5);
		if(p[j+2] != p[j]) {
			if(points <= 0) points = 1;
			if((p[j+2] < p[j]) || (points > SIZE)) {
				fprintf(stderr," confusion on phrase card\n");
				closesf();
				}
			for(k=0; k < points; k++) {
				array[i++] = ((float)k/(float)points)
					* (p[j+3] - p[j+1]) + p[j+1];
			}
		}
		if(i == SIZE) return;
	}
	i--;
	while(i++ < SIZE) array[i] = array[i-1]; 
}
