
/* Generated by Interface Builder */

#import <objc/Object.h>
#import "Reicher.h"

@implementation Reicher:Object

#import <appkit/appkit.h>
#import <appkit/Panel.h>	// For the NXAlert panel
#import <soundkit/soundkit.h>
#import <musickit/musickit.h>
#import <musickit/Conductor.h>
#import <musickit/Performer.h>
#import "FluteIns.h"
#import <math.h>
#import "RandomIzer.h"

// all the defined values, etc. are in this file
#include "Reichvals.h"

static Orchestra *theOrch;
static SynthInstrument *theIns[NUMFLUTES];
static id theRand;
static int going = 0;

static Note *theNote[NUMFLUTES];
static Note *theNoteOn[LBREATH*NUMFLUTES][ARRNOTES][NCYCS];
static Note *theNoteOff[LBREATH*NUMFLUTES][ARRNOTES][NCYCS];
static Note *theNoteRun[NUMFLUTES][ARRNOTES][RUNNOTES];
static Note *theNoteUpdate[NUMFLUTES];

static int PITCH[ARRNOTES];
static double AMP[ARRNOTES];
static double DUR[ARRNOTES];

int perform_switch = 0;
int numflutes = NUMFLUTES;

- setup
{
	int MY_outAmp = [[Note class] parName: "MY_outAmp"];
	int MY_dLineLength = [[Note class] parName: "MY_dLineLength"];
	int MY_delay2Length = [[Note class] parName: "MY_delay2Length"];

	double D1,D2;
	double panval,pan_incr;
	int j;
	
	if (going == 0) {
		theRand = [RandomIzer new];
		[theRand setit];
		
		theOrch = [Orchestra new];
	    if (![theOrch open]) {               
			NXRunAlertPanel("Shoot Fire...", "Can't open the DSP", "darn.", NULL, NULL, "is it clear?");
			exit(1);
	    	}
				              
	    [theOrch setSamplingRate: 22050.0];	
	    MKSetDeltaT(.01) ;           
	    [Orchestra setFastResponse:YES]; 
	    [Orchestra setTimed:NO];
	    [Conductor setFinishWhenEmpty:NO];
	    [Conductor useSeparateThread:YES];
	    [Conductor setThreadPriority:1.0];    
		[theOrch run];				
	    [Conductor startPerformance];
		    
	    [Conductor lockPerformance];

		// doesn't matter which notes here, will get updated later
		D1 = MAXLENGTH;
		D2 = MAXD2LENGTH;

		panval = -45.0;
		pan_incr = 90.0/(numflutes-1);
		for(j = 0; j < numflutes; j++) {
			theIns[j] = [SynthInstrument new];
	    	[theIns[j] setSynthPatchClass:[FluteIns class]];   
	    	[theIns[j] setSynthPatchCount:1];
			theNote[j] = [Note new];
			[theNote[j] setNoteType:MK_noteOn]; 	
			[theNote[j] setNoteTag:MKNoteTag()];
    		[theNote[j] setPar:MK_amp0 toDouble:0.0];	    	    	    
    		[theNote[j] setPar:MK_amp1 toDouble:0.0];	    	    	    
			[theNote[j] setPar:MY_outAmp toDouble:0.3];
			[theNote[j] setPar:MK_bearing toDouble:panval];
			panval += pan_incr;
			[theNote[j] setPar:MY_dLineLength toDouble: (MINLENGTH + (MAXLENGTH - MINLENGTH) * D1)];	
			[theNote[j] setPar:MY_delay2Length toDouble: (MAXD2LENGTH * D2)];
			[[theIns[j] noteReceiver] receiveNote:theNote[j]];
			}

		[Conductor unlockPerformance];
		}
		
	return(self);
}

- StartAndStop:sender
{
	int i;
	int MY_outAmp = [[Note class] parName: "MY_outAmp"];
	
	if (going == 0) {
		[self setup];
		switch (perform_switch) {
			case 0:
				[self doPulsing];
				break;
			case 1:
				[self doCanon];
				break;
			case 2:
				[self doPhasing];
				break;
			case 3:
				[self doInterlock];
				break;
			}
		going = 1;
		}
	else {
		[Conductor lockPerformance];
		for (i = 0; i < NUMFLUTES; i++) {
			theNoteOff[i][0][0] = [Note new];
			[theNoteOff[i][0][0] setNoteType:MK_noteOff]; 	
			[theNoteOff[i][0][0] setNoteTag:[theNote[i] noteTag]];
    		[theNoteOff[i][0][0] setPar:MK_amp0 toDouble:0.0];	    	    	    
    		[theNoteOff[i][0][0] setPar:MK_amp1 toDouble:0.0];	    	    	    
			[theNoteOff[i][0][0] setPar:MY_outAmp toDouble:0.0];
			[[theIns[i] noteReceiver] receiveAndFreeNote:theNoteOff[i][0][0]];
			
			[theIns[i] free];
			}
		[Conductor unlockPerformance];

		[Conductor finishPerformance];
		
		[theOrch flushTimedMessages];
		[theOrch free];

		going = 0;
		}

	return(self);
}


- doPulsing;
{
	int MY_dLineLength = [[Note class] parName: "MY_dLineLength"];
	int MY_noiseVolume = [[Note class] parName: "MY_noiseVolume"];
	int MY_delay2Length = [[Note class] parName: "MY_delay2Length"];
	int MY_envelopeSlew = [[Note class] parName: "MY_envelopeSlew"];
	
	double playspeed = 0.23;
	double notedur = 0.17;
	double AMP1,AMP1incr;
	double D1,D2;
	int numpulses,halfway;
	int Reichons[NUMNOTES];
	int i,j;
	int val_int;
	int turnflag;
	double val_double;
	double playtime;
	
		    
	[Conductor lockPerformance];	     /* Prepare to send MK message */

	// choose notes
	// first of all, clear out the placeholder array (for dups)
	for (j = 0; j < NUMNOTES; j++) Reichons[j] = 0;

	// now choose a unique note value for each flute
	for(j = 0; j < NUMFLUTES; j++) {
		do {
			val_int = [theRand GetIndex:NUMNOTES-1];
			}
		while (Reichons[val_int] == 1);
		
		Reichons[val_int] = 1;
		
		D1 = Reichnotes[val_int][0];
		D2 = Reichnotes[val_int][1];

// set up a Note with this note info and send it out --
// assumption here is that the -play method is queued to be called
// at the correct time to start a new chord

		theNoteUpdate[j] = [Note new];
		[theNoteUpdate[j] setNoteType:MK_noteUpdate]; 
		[theNoteUpdate[j] setNoteTag:[theNote[j] noteTag]];
		[theNoteUpdate[j] setPar:MY_dLineLength toDouble: (MINLENGTH + (MAXLENGTH - MINLENGTH) * D1)];	
		[theNoteUpdate[j] setPar:MY_delay2Length toDouble: (MAXD2LENGTH * D2)];
		[theNoteUpdate[j] setPar:MK_amp1 toDouble:0.0];
		[[theIns[j] noteReceiver] receiveAndFreeNote:theNoteUpdate[j]];

		}

// at this point, the flutes all are set to the correct note
// now to decide the breath for each flute, and then set up the
// phrase

	for (j = 0; j < NUMFLUTES; j++) {
		// choose the number of pulses
		numpulses = [theRand GetIndexRangeHi:LBREATH Lo:SBREATH];
		halfway = numpulses/2;
		turnflag = 0;			
		playtime = playspeed;
		AMP1 = 0.4;
		val_double = [theRand GetNumberRangeHi:0.9 Lo:0.8];
		AMP1incr = (val_double - AMP1)/(double)numpulses;

		for (i = 0; i < numpulses; i++) {
			theNoteOn[j][0][0] = [Note new];
			[theNoteOn[j][0][0] setNoteType:MK_noteUpdate]; 
			[theNoteOn[j][0][0] setNoteTag:[theNote[j] noteTag]]; 
			[theNoteOn[j][0][0] setPar:MK_amp1 toDouble:AMP1];
			[theNoteOn[j][0][0] setPar:MY_envelopeSlew toDouble:0.001];	    
			[theNoteOn[j][0][0] setPar:MY_noiseVolume toDouble:0.007];
			[[theIns[j] noteReceiver] receiveAndFreeNote:theNoteOn[j][0][0] withDelay:playtime];

			theNoteOff[j][0][0] = [Note new];
			[theNoteOff[j][0][0] setNoteType:MK_noteUpdate]; 
			[theNoteOff[j][0][0] setNoteTag:[theNote[j] noteTag]]; 	    	    	    
			[theNoteOff[j][0][0] setPar:MK_amp1 toDouble:0.0];
			[theNoteOff[j][0][0] setPar:MY_envelopeSlew toDouble:1.0];	    
			[theNoteOff[j][0][0] setPar:MY_noiseVolume toDouble:0.001];	    
			[[theIns[j] noteReceiver] receiveAndFreeNote:theNoteOff[j][0][0] withDelay:playtime+notedur];
			
		playtime = playtime + (playspeed + [theRand GetNumber:0.01]);
		if ((i > halfway) && (turnflag == 0)) {
			AMP1incr *= -1.0;
			turnflag = 1;
			}
		AMP1 = AMP1 + AMP1incr;	    	    
		}
	}

	[[Conductor defaultConductor] sel:@selector(doPulsing) to:self withDelay:playtime argCount:0];
	 	    	    
	[Conductor unlockPerformance];

    return self;
}


- doCanon
{
	int MY_dLineLength = [[Note class] parName: "MY_dLineLength"];
	int MY_noiseVolume = [[Note class] parName: "MY_noiseVolume"];
	int MY_delay2Length = [[Note class] parName: "MY_delay2Length"];
	int MY_envelopeSlew = [[Note class] parName: "MY_envelopeSlew"];

    int i,j,k;
    int nrunnotes;
	double D1,D2;
    double playtime,canon_delay;
	static int long_incr;
	static float longdur_mult;
	static int reg_incr, reg_hi, reg_lo;
	static float run_prob, runprob_incr, run_direction;
	static float rest_prob, restprob_incr;
	static float amp_hi, amphi_incr, amp_lo, amplo_incr;
	double noiseval;
		    
	[Conductor lockPerformance];
	
	// set up:
	if (going == 0) {			
		// set up some initial flags
		long_incr = LONGSTART;
		longdur_mult = (float)[theRand GetIndexRangeHi:10 Lo:6];
		reg_incr = REGSTART;
		reg_hi = 4;
		reg_lo = 0;
		runprob_incr = RUNPROBINCR;
		run_prob = 0.0;
		run_direction = UP;
		restprob_incr = 0.0 - RESTPROBINCR;
		rest_prob = 0.4;
		amphi_incr = AMPHIINCR;
		amp_hi = 0.8;
		amplo_incr = AMPLOINCR;
		amp_lo = 0.5;
		}

		
	// load up the PITCH, AMP, and DUR arrays with values:
	for (j = 0; j < ARRNOTES; j++) {
		// select pitch indices
		if (reg_incr < REGSECTDUR) {
			PITCH[j] = [theRand GetIndexRangeHi:reg_hi Lo:reg_lo];
			if (reg_incr < 0) {
				reg_incr = REGSTART;
				if ([theRand GetNumber] < 0.5) {
					reg_hi = 4;
					reg_lo = 0;
					}
				else {
					reg_hi = 16;
					reg_lo = 11;
					}
				}
			}
		else {
			PITCH[j] = [theRand GetIndex:16];
			}
		AMP[j] = [theRand GetNumberRangeHi:amp_hi Lo:amp_lo];
		if ([theRand GetNumber] < rest_prob) {
			AMP[j] = 0.0;
			}
		DUR[j] = Beats[ [theRand GetIndex:3] ];
		if (long_incr < LONGSECTDUR) {
			DUR[j] *= longdur_mult;
			if (long_incr < 0) {
				long_incr = LONGSTART;
				longdur_mult = (float)[theRand GetIndexRangeHi:10 Lo:6];
				}
			}
		}

	reg_incr--;
	long_incr--;	
	run_prob += runprob_incr;
	if ( (run_prob > 1.0) || (run_prob < 0.0) )
		runprob_incr = 0.0 - runprob_incr;
	rest_prob += restprob_incr;
	if ( (rest_prob > 0.4) || (rest_prob < 0.0) )
		restprob_incr = 0.0 -restprob_incr;
	amp_hi += amphi_incr;
	if ( (amp_hi > 0.95) || (amp_hi < 0.75) )
		amphi_incr = 0.0 - amphi_incr;
	amp_lo += amplo_incr;
	if ( (amp_lo > 0.65) || (amp_lo < 0.4) )
		amplo_incr = 0.0 - amplo_incr;

	playtime = 0.0;
	for (j = 0; j < ARRNOTES; j++) {
		// test and possibly do a short run here
		if ( [theRand GetNumber] < run_prob ) {
			// choose the number of notes in the run
			nrunnotes = [theRand GetIndexRangeHi:RUNNOTES Lo:1];
			// choose the run-note duration
			if ( [theRand GetNumber] > 0.9 ) {
				DUR[j] = SIXTEENTH;
				}
			else {
				DUR[j] = EIGHTH;
				}

			// choose the run direction
			if (run_prob < 0.9) {
				if ( [theRand GetNumber] > 0.5 ) {
					run_direction = UP;
					}
				else {
					run_direction = DOWN;
					}
				}
			else {		// I like the sound of this
				DUR[j] = SIXTEENTH;
				nrunnotes = 4;
				}							
					
			// now make the runs!
			for (k = 0; k < nrunnotes; k++) {
				if (run_direction == UP) {					
					if (PITCH[j] > 12) PITCH[j] = [theRand GetIndex:12];
					D1 = Reichnotes[PITCH[j]+k][0];
					D2 = Reichnotes[PITCH[j]+k][1];
					}
				else {
					if (PITCH[j] < 5) PITCH[j] = [theRand GetIndexRangeHi:16 Lo:5];
					D1 = Reichnotes[PITCH[j]-k][0];
					D2 = Reichnotes[PITCH[j]-k][1];
					}
				
				canon_delay = 0.0;						
				for (i = 0; i < NUMFLUTES; i++) {
					theNoteRun[i][j][k] = [Note new];
	    			[theNoteRun[i][j][k] setNoteType:MK_noteUpdate]; 
	    			[theNoteRun[i][j][k] setNoteTag:[theNote[i] noteTag]]; 	    
    	    		[theNoteRun[i][j][k] setPar:MK_amp1 toDouble:AMP[j]];
    	    		[theNoteRun[i][j][k] setPar:MY_envelopeSlew toDouble:0.001];
					noiseval = [theRand GetNumberRangeHi:0.035 Lo:0.015];	    
    	    		[theNoteRun[i][j][k] setPar:MY_noiseVolume toDouble:noiseval];
					
					D1 += [theRand GetPlusMinus:0.0001];	
					D2 += [theRand GetPlusMinus:0.0001];	

					[theNoteRun[i][j][k] setPar:MY_dLineLength toDouble: (MINLENGTH + (MAXLENGTH - MINLENGTH) * D1)];	
					[theNoteRun[i][j][k] setPar:MY_delay2Length toDouble: (MAXD2LENGTH * D2)];
	    			[[theIns[i] noteReceiver] receiveAndFreeNote:theNoteRun[i][j][k] withDelay:playtime+canon_delay];
					canon_delay += (CANONPT + [theRand GetNumber:0.001]);
					}
				playtime += DUR[j];
				}
			}

		// play a "normal" note
		else {
			canon_delay = 0.0;
			for (i = 0; i < NUMFLUTES; i++) {
				theNoteOn[i][j][0] = [Note new];
	    		[theNoteOn[i][j][0] setNoteType:MK_noteUpdate]; 
	    		[theNoteOn[i][j][0] setNoteTag:[theNote[i] noteTag]]; 	    
    	    	[theNoteOn[i][j][0] setPar:MK_amp1 toDouble:AMP[j]];
    	    	[theNoteOn[i][j][0] setPar:MY_envelopeSlew toDouble:0.001];	    
				noiseval = [theRand GetNumberRangeHi:0.035 Lo:0.015];	    
    	    	[theNoteOn[i][j][0] setPar:MY_noiseVolume toDouble:noiseval];

				D1 = Reichnotes[PITCH[j]][0];
				D2 = Reichnotes[PITCH[j]][1];
					
				D1 += [theRand GetPlusMinus:0.0001];	
				D2 += [theRand GetPlusMinus:0.0001];	

				[theNoteOn[i][j][0] setPar:MY_dLineLength toDouble: (MINLENGTH + (MAXLENGTH - MINLENGTH) * D1)];	
				[theNoteOn[i][j][0] setPar:MY_delay2Length toDouble: (MAXD2LENGTH * D2)];
	    		[[theIns[i] noteReceiver] receiveAndFreeNote:theNoteOn[i][j][0] withDelay:playtime+canon_delay];

				theNoteOff[i][j][0] = [Note new];
	    		[theNoteOff[i][j][0] setNoteType:MK_noteUpdate]; 
	    		[theNoteOff[i][j][0] setNoteTag:[theNote[i] noteTag]]; 				    	    	    
    	    	[theNoteOff[i][j][0] setPar:MK_amp1 toDouble:0.0];
    	    	[theNoteOff[i][j][0] setPar:MY_envelopeSlew toDouble:0.001];	    
    	    	[theNoteOff[i][j][0] setPar:MY_noiseVolume toDouble:0.0];
		    
	    		[[theIns[i] noteReceiver] receiveAndFreeNote:theNoteOff[i][j][0] withDelay:playtime+canon_delay+DUR[j]];
				canon_delay += (CANONPT + [theRand GetNumber:0.001]);
				}
			playtime = 0.2 + playtime + (DUR[j] + [theRand GetNumber:0.01]);
	    	}
		}

	[[Conductor defaultConductor] sel:@selector(doCanon) to:self withDelay:playtime argCount:0];
	 	    	    
	[Conductor unlockPerformance];

    return self;
}


- doPhasing
{
	int MY_dLineLength = [[Note class] parName: "MY_dLineLength"];
	int MY_noiseVolume = [[Note class] parName: "MY_noiseVolume"];
	int MY_delay2Length = [[Note class] parName: "MY_delay2Length"];
	int MY_envelopeSlew = [[Note class] parName: "MY_envelopeSlew"];

	double D1,D2;
    int i,j;
    double playtime;
	static double phase_delay;
	static int slurflags[ARRNOTES];
	float noiseval;

	[Conductor lockPerformance];

	if (going == 0) {			
		// load up the PITCH, AMP, slurflags, and DUR arrays with values:
		for (j = 0; j < ARRNOTES; j++) {
			// select pitch indices from all the notes
			PITCH[j] = [theRand GetIndex:17];
			AMP[j] = [theRand GetNumberRangeHi:0.99 Lo:0.7];
			if (PITCH[j] > 15) {
				PITCH[j] = 0;
				AMP[j] = 0.0;
				}
			DUR[j] = Beats[ [theRand GetIndex:3] ];
			
			slurflags[j] = 0;
			if ( [theRand GetNumber] < SLURPROB) slurflags[j] = 1;
			}
		phase_delay = 0.0;
		}
		
	// queue up the notes for the two flutes
	playtime = 0.0;
	for (j = 0; j < ARRNOTES; j++) {
		for (i = 0; i < numflutes; i++) {
			theNoteOn[i][j][0] = [Note new];
	    	[theNoteOn[i][j][0] setNoteType:MK_noteUpdate]; 
	    	[theNoteOn[i][j][0] setNoteTag:[theNote[i] noteTag]]; 	    
    	    [theNoteOn[i][j][0] setPar:MK_amp1 toDouble:AMP[j]];
    	    [theNoteOn[i][j][0] setPar:MY_envelopeSlew toDouble:0.001];	    
			noiseval = [theRand GetNumberRangeHi:0.035 Lo:0.015];	    
    	    [theNoteOn[i][j][0] setPar:MY_noiseVolume toDouble:noiseval];

			D1 = Reichnotes[PITCH[j]][0];
			D2 = Reichnotes[PITCH[j]][1];
					
			D1 += [theRand GetPlusMinus:0.0001];	
			D2 += [theRand GetPlusMinus:0.0001];	
				
			[theNoteOn[i][j][0] setPar:MY_dLineLength toDouble: (MINLENGTH + (MAXLENGTH - MINLENGTH) * D1)];	
			[theNoteOn[i][j][0] setPar:MY_delay2Length toDouble: (MAXD2LENGTH * D2)];
	    	[[theIns[i] noteReceiver] receiveAndFreeNote:theNoteOn[i][j][0] withDelay:playtime + ((float)i * phase_delay)];


			if (slurflags[j] == 0) {
				theNoteOff[i][j][0] = [Note new];
	    		[theNoteOff[i][j][0] setNoteType:MK_noteUpdate]; 
	    		[theNoteOff[i][j][0] setNoteTag:[theNote[i] noteTag]]; 				    	    	    
    	    	[theNoteOff[i][j][0] setPar:MK_amp1 toDouble:0.0];
    	    	[theNoteOff[i][j][0] setPar:MY_envelopeSlew toDouble:0.001];	    
    	    	[theNoteOff[i][j][0] setPar:MY_noiseVolume toDouble:0.0];
		    
	    		[[theIns[i] noteReceiver] receiveAndFreeNote:theNoteOff[i][j][0] withDelay:playtime+ ((float)i * phase_delay) + DUR[j]];
				}
			}
		playtime = 0.2 + playtime + (DUR[j] + [theRand GetNumber:0.01]);
	    }
			
	phase_delay += (PHASEINCR + [theRand GetNumber:0.001]);

	[[Conductor defaultConductor] sel:@selector(doPhasing) to:self withDelay:playtime argCount:0];
	 	    	    
	[Conductor unlockPerformance];

    return self;
}


-doInterlock
{
	int MY_dLineLength = [[Note class] parName: "MY_dLineLength"];
	int MY_noiseVolume = [[Note class] parName: "MY_noiseVolume"];
	int MY_delay2Length = [[Note class] parName: "MY_delay2Length"];
	int MY_envelopeSlew = [[Note class] parName: "MY_envelopeSlew"];

    int i,j,k;
    double playtime;
	static int reg_incr, reg_hi, reg_lo;
	static float amp_hi, amphi_incr, amp_lo, amplo_incr;
	float noiseval;
	double D1,D2;
	int cycles;
	float cycle_delay;

	[Conductor lockPerformance];

	if (going == 0) {
		// set up some initial flags
		reg_incr = REGSTART;
		reg_hi = 4;
		reg_lo = 0;
		amphi_incr = AMPHIINCR;
		amp_hi = 0.8;
		amplo_incr = AMPLOINCR;
		amp_lo = 0.5;
		}
		
	for (i = 0; i < NUMFLUTES; i++) {
		// load up the PITCH, AMP, and DUR arrays with new values:
		for (j = 0; j < CYCARRNOTES; j++) {
			// select pitch indices
			if (reg_incr < REGSECTDUR) {
				PITCH[j] = [theRand GetIndexRangeHi:reg_hi Lo:reg_lo];
				if (reg_incr < 0) {
					reg_incr = REGSTART;
					if ([theRand GetNumber] < 0.5) {
						reg_hi = 4;
						reg_lo = 0;
						}
					else {
						reg_hi = 16;
						reg_lo = 12;
						}
					}
				}
			else {
				PITCH[j] = [theRand GetIndex:16];
				}
			AMP[j] = [theRand GetNumberRangeHi:amp_hi Lo:amp_lo];
			DUR[j] = Beats[ [theRand GetIndex:3] ];
			}

		cycles = [theRand GetIndexRangeHi:NCYCS Lo:3];
		cycle_delay = (CYCMEASURE * (float)(i * 4)) + (QUARTER * (float)i);
		for (k = 0; k < cycles; k++) {
			playtime = 0.0;
			for (j = 0; j < CYCARRNOTES; j++) {
				theNoteOn[i][j][k] = [Note new];
	    		[theNoteOn[i][j][k] setNoteType:MK_noteUpdate]; 
	    		[theNoteOn[i][j][k] setNoteTag:[theNote[i] noteTag]]; 	    
    	   		[theNoteOn[i][j][k] setPar:MK_amp1 toDouble:AMP[j]];
    	   		[theNoteOn[i][j][k] setPar:MY_envelopeSlew toDouble:0.001];	    
				noiseval = [theRand GetNumberRangeHi:0.035 Lo:0.015];	    
    	   		[theNoteOn[i][j][k] setPar:MY_noiseVolume toDouble:noiseval];

				D1 = Reichnotes[PITCH[j]][0];
				D2 = Reichnotes[PITCH[j]][1];
					
				D1 += [theRand GetPlusMinus:0.0001];	
				D2 += [theRand GetPlusMinus:0.0001];	
				
				[theNoteOn[i][j][k] setPar:MY_dLineLength toDouble: (MINLENGTH + (MAXLENGTH - MINLENGTH) * D1)];	
				[theNoteOn[i][j][k] setPar:MY_delay2Length toDouble: (MAXD2LENGTH * D2)];
	    		[[theIns[i] noteReceiver] receiveAndFreeNote:theNoteOn[i][j][k] withDelay:playtime+cycle_delay];

				theNoteOff[i][j][k] = [Note new];
	    		[theNoteOff[i][j][k] setNoteType:MK_noteUpdate]; 
	    		[theNoteOff[i][j][k] setNoteTag:[theNote[i] noteTag]]; 				    	    	    
    	    	[theNoteOff[i][j][k] setPar:MK_amp1 toDouble:0.0];
    	    	[theNoteOff[i][j][k] setPar:MY_envelopeSlew toDouble:0.001];	    
    	    	[theNoteOff[i][j][k] setPar:MY_noiseVolume toDouble:0.0];
		   
	    		[[theIns[i] noteReceiver] receiveAndFreeNote:theNoteOff[i][j][k] withDelay:playtime+cycle_delay+DUR[j]];
				playtime = playtime + (DUR[j] + [theRand GetNumber:0.01]);
				}
					
			cycle_delay += (CYCMEASURE + [theRand GetNumber:0.001]);
			}
	    }				

	reg_incr--;
	amp_hi += amphi_incr;
	if ( (amp_hi > 0.95) || (amp_hi < 0.75) )
		amphi_incr = 0.0 - amphi_incr;
	amp_lo += amplo_incr;
	if ( (amp_lo > 0.65) || (amp_lo < 0.4) )
		amplo_incr = 0.0 - amplo_incr;

	[[Conductor defaultConductor] sel:@selector(doInterlock) to:self withDelay:(CYCMEASURE * 7) argCount:0];
	 	    	    
	[Conductor unlockPerformance];

    return self;
}


- setPulsing:sender
{
	perform_switch = 0;
	numflutes = NUMFLUTES;
	
	return(self);
}


- setCanon:sender
{
	perform_switch = 1;
	numflutes = NUMFLUTES;
	
	return(self);
}


- setPhasing:sender
{
	perform_switch = 2;
	numflutes = 2;
	
	return(self);
}


- setInterlock:sender
{
	perform_switch = 3;
	numflutes = NUMFLUTES;
	
	return(self);
}


@end
