/* Generated by Interface Builder */

#include <libc.h>
#include <strings.h>

#import "Looching.h"
#import <appkit/Form.h>
#import <appkit/Slider.h>
#import <musickit/musickit.h>
#import <musickit/synthpatches/synthpatches.h>

#import "LoochPerformer.h"
#import "Bark.h"
#import "RandomIzer.h"
#import "LoochWaves.h"

#define	NWAVES	7
#define FADELO	10
#define FADEHI	20
#define AMPLO	0.05
#define AMPHI	0.1
#define DURSHORT	5.0
#define	DURLONG		20.0
#define SLEEPLO	2
#define	SLEEPHI	10

extern int Pid;

@implementation Looching

/* these are the global vars */
static int IsLooching = 0;
static int ToneRow = 0;
static int TimbreSet = 0;
static int fds[2];
static int isPiped = 0;
double VibWide;
double VibRate;
double FreqSpread;
double Headroom;

- setInVibRate:anObject
{
    inVibRate = anObject;
    [inVibRate setDoubleValue:0.5];
    VibRate = 0.5; /* initialize the variable */    
    return self;
}

- setInVibWidth:anObject
{
    inVibWidth = anObject;
    [inVibWidth setDoubleValue:1.0];
    VibWide = 1.0; /* initialize the variable */
    return self;
}

- setInSpread:anObject
{
    inSpread = anObject;
    [inSpread setDoubleValue:1.0];
    FreqSpread = 1.0; /* initialize the variable */
    return self;
}

- setInHeadroom:anObject
{
    inHeadroom = anObject;
    [inHeadroom setDoubleValue:2.36];
    Headroom = 2.36; /* initialize the variable */    
    return self;
}

- setOutVibRate:anObject
{
    outVibRate = anObject;
    [outVibRate setDoubleValue:0.5];
    return self;
}

- setOutVibWidth:anObject
{
    outVibWidth = anObject;
    [outVibWidth setDoubleValue:1.0 ];
    return self;
}

- setOutSpread:anObject
{
    outSpread = anObject;
    [outSpread setDoubleValue:1.0 ];
    return self;
}

- setOutHeadroom:anObject
{
    outHeadroom = anObject;
    [outHeadroom setDoubleValue:2.36 ];
    return self;
}

- displayVibWidth:sender
{
    double val;

    val = [inVibWidth doubleValue];
    [outVibWidth setDoubleValue:val ];
    return self;
}

- displayVibRate:sender
{
    double val;

    val = [inVibRate doubleValue];
    [outVibRate setDoubleValue:val ];
    return self;
}

- displaySpread:sender
{
    double val;

    val = [inSpread doubleValue];
    [outSpread setDoubleValue:val ];
    return self;
}

- displayHeadroom:sender
{
    double val;

    val = ([inHeadroom doubleValue] - 2.0) / 2.0;
    [outHeadroom setDoubleValue:val ];
    return self;
}

- setParams:sender
{
    FreqSpread = [inSpread doubleValue];
    VibWide = [inVibWidth doubleValue];
    VibRate = [inVibRate doubleValue];
    Headroom = ([inHeadroom doubleValue] - 2.0) / 2.0;
    
    if (isPiped == 1) {
    	write(fds[1], (char *) &FreqSpread, sizeof(double));
   	write(fds[1], (char *) &VibWide, sizeof(double));
   	write(fds[1], (char *) &VibRate, sizeof(double));
   	write(fds[1], (char *) &ToneRow, sizeof(int));

	}
	
    return self;
}

- StartAndStop:sender
{
    FreqSpread = [inSpread doubleValue];
    VibWide = [inVibWidth doubleValue];
    VibRate = [inVibRate doubleValue];
    Headroom = ([inHeadroom doubleValue] - 2.0) / 2.0;
	
    if (IsLooching == 0) {
	IsLooching = 1;

	if (!isPiped) {
		pipe(fds); /* set up communications with the child process */
		isPiped = 1;
		}

	Pid = fork();

	if (Pid == 0) { /* child does the playing */
		int i,j,n;
		int sleeptime;
		int nfound = 0;
		double fade,coin;
		int isPlaying[4] = {0, 0, 0, 0};
		double durations[4] = {0.0, 0.0, 0.0, 0.0};
		double val,sval,fval;
    		id aLoochPerformer[4],theOrch;
    		SynthInstrument *anIns[4];
		id RanNum;
		id aPartials[NWAVES];
		double *LWfreqptr,*LWampptr;
		fd_set rfds,wfds;
		struct timeval ttt;

		RanNum = [RandomIzer new];
		[RanNum setit];

		/* Create the Partials objects. */
		for (i = 0; i < NWAVES; i++) { 
			aPartials[i] = [Partials new];
			LWfreqptr = freqs[TimbreSet][i];
			LWampptr = amps[TimbreSet][i];

			/* Fill the object with data. */ 
			[aPartials[i] setPartialCount:7 
					freqRatios:LWfreqptr 
					ampRatios:LWampptr 
					phases:NULL 
					orDefaultPhase:0.0];
    			}
			
		/* Create the Orchestra which manages all DSP activity. */
    		theOrch = [Orchestra new];
    		if (![theOrch open]) {
			fprintf(stderr, "Can't open the DSP!\n");
			Pid = 0;
			exit(-1);
    			}
		[theOrch setSamplingRate:22050.0];
		[theOrch setHeadroom:Headroom];
 				
		for(i = 0; i < 4; i++) {	
			/* make performers */
			aLoochPerformer[i] = [LoochPerformer new];
	
			/* create instruments */                  
			anIns[i] = [SynthInstrument new];      
			/* Assign the class of SynthPatch. */
			[anIns[i] setSynthPatchClass:[Bark class]];
	
			/* set up the performer--instrument connection
						and get ready to roll */
			[[aLoochPerformer[i] noteSender] connect:[anIns[i]
							noteReceiver]];
			[aLoochPerformer[i] activate];
			[aLoochPerformer[i] pause];   /* Start paused */
			}
				
		[theOrch run];	/* Start the DSP. */

		sleeptime = 0.0;
		while(1) {
			for(j = 0; j < 4; j++) {
				if (isPlaying[j]) {
					durations[j] -= sleeptime;
					if (durations[j] <= 0) {
						/* choose the fadeout dur */
						fade = [RanNum
							GetNumberRangeHi:FADEHI
								Lo:FADELO];
						[aLoochPerformer[j]
							setdecay:fade];
						[aLoochPerformer[j] stopNote];
						[theOrch flushTimedMessages];
						durations[j] += fade;
						isPlaying[j] = 0;
						}
					}
				else {
					durations[j] -= sleeptime;
					if (durations[j] > 0) {
						;
						}
					else {
						/* play a new note? */
						coin = [RanNum GetNumber];
						if (coin < 0.5) {

/* set the waveform */
n = [RanNum GetIndex:(NWAVES-1)];
[aLoochPerformer[j] setwave:aPartials[n]];

/* set the frequency */
n = [RanNum GetIndex:toneindex[ToneRow]];
fval = pitches[ToneRow][n];
sval = ( ([RanNum GetNumber:FreqSpread]) / 100.0 ) * fval;
[aLoochPerformer[j] setfreq:fval spread:sval];

/* set the amplitude */
val = [RanNum GetNumberRangeHi:AMPHI Lo:AMPLO];
[aLoochPerformer[j] setamp:val];

/* set vibrato0 */
val = [RanNum GetNumber:VibRate];
[aLoochPerformer[j] setvibfreq0:val];

/* set amp0 */
val = ( ([RanNum GetNumber:VibWide]) / 100.0 ) * fval;
[aLoochPerformer[j] setvibamp0:val];

/* set vibrato1 */
val = [RanNum GetNumber:VibRate];
[aLoochPerformer[j] setvibfreq1:val];

/* set amp1 */
val = ( ([RanNum GetNumber:VibWide]) / 100.0 ) *fval;
[aLoochPerformer[j] setvibamp1:val];

/* set attack time */
fade = [RanNum GetNumberRangeHi:FADEHI Lo:FADELO];
[aLoochPerformer[j] setattack:fade];

/* set note duration */
durations[j] = [RanNum GetNumberRangeHi:DURLONG Lo:DURSHORT];
[theOrch flushTimedMessages];

[aLoochPerformer[j] startNote];
[theOrch flushTimedMessages];
isPlaying[j] = 1;

							}
						}
					}
				}
			sleeptime = [RanNum GetIndexRangeHi:SLEEPHI
								Lo:SLEEPLO];
			ttt.tv_sec = sleeptime;
			ttt.tv_usec = 0;
			FD_ZERO(&rfds);
			FD_SET(fds[0],&rfds);

			nfound = select(5, &rfds, 0, 0, &ttt);
			if ( (nfound > 0) && (FD_ISSET(fds[0], &rfds)) ) {
				read(fds[0], (char *) &FreqSpread,
							sizeof(double));
				read(fds[0], (char *) &VibWide,
							sizeof(double));
				read(fds[0], (char *) &VibRate,
							sizeof(double));
				read(fds[0], (char *) &ToneRow,
							sizeof(int));

				}
			}
		}
	}

    else {
	char s[10] = "kill ";
	char num[10];

	sprintf(num,"%d",Pid);
	strcat(s,num);
	system(s);
	IsLooching = 0;
	Pid = 0;
	}

    return self;
}

- trArnie:sender
{
    ToneRow = 3;
    TimbreSet = 2;
    return self;
}

- trBach:sender
{
    ToneRow = 4;
    TimbreSet = 0;
    return self;
}

- trDrone:sender
{
    ToneRow = 2;
    TimbreSet = 1;
    return self;
}

- trMorning:sender
{
    ToneRow = 1;
    TimbreSet = 1;
    return self;
}

- trOriginal:sender
{
    ToneRow = 0;
    TimbreSet = 0;
    return self;
}


@end
