Arpeggiator.csd
Written by Iain McCurdy, 2012

<CsoundSynthesizer>

<CsOptions>
;VIRTUAL MIDI
-odac -M0 -+rtmidi=virtual -dm0 -b1024

;EXTERNAL MIDI
;-odac -Ma -dm0 -b1024
</CsOptions>

<CsInstruments>

sr 		= 	44100
ksmps 		= 	4
nchnls 		= 	2
0dbfs		=	1	;MAXIMUM AMPLITUDE
massign 0,0 	;USING MASSIGN WITH THESE ARGUMENTS DISABLES CSOUND'S DEFAULT INSTRUMENT TRIGGERING

;FLTK INTERFACE CODE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
FLcolor	255, 255, 255, 100, 200, 200

;INSTRUCTIONS AND INFO PANEL
				FLpanel	"info", 515, 540, 512, 0
				FLscroll     515, 540, 0, 0
;TEXT BOXES												TYPE | FONT | SIZE | WIDTH | HEIGHT | X | Y
ih		 	FLbox  	"                         Arpeggiator                         ", 	1,      6,     14,    490,    20,     5,   0
ih		 	FLbox  	"-------------------------------------------------------------", 	1,      6,     14,    490,    20,     5,  20
ih		 	FLbox  	"This example implements a simple arpeggiator effect, such as ", 	1,      5,     14,    490,    20,     5,  40
ih		 	FLbox  	"is often found on hardware synthesizers.                     ", 	1,      5,     14,    490,    20,     5,  60
ih		 	FLbox  	"The notes generated by the arpeggiator are played by a simple", 	1,      5,     14,    490,    20,     5,  80
ih		 	FLbox  	"synthesizer and echoed by a multi-mode delay.                ", 	1,      5,     14,    490,    20,     5, 100
ih		 	FLbox  	"                                                             ", 	1,      5,     14,    490,    20,     5, 120 
ih		 	FLbox  	" Arpeggiator Section                                         ", 	1,      8,     14,    490,    20,     5, 140 
ih		 	FLbox  	"The speed or rate of the arpeggio can be defined one of two  ", 	1,      5,     14,    490,    20,     5, 160
ih		 	FLbox  	"ways depending on the choice made for 'Rate Mode'. In 'Free' ", 	1,      5,     14,    490,    20,     5, 180
ih		 	FLbox  	"mode the tempo is freely adjustable in hertz using the 'Rate'", 	1,      5,     14,    490,    20,     5, 200
ih		 	FLbox  	"knob. In 'Tempo' mode the rate of the metronome driving the  ", 	1,      5,     14,    490,    20,     5, 220
ih		 	FLbox  	"arpeggiator is defined in BPM (beats per minute). Each       ", 	1,      5,     14,    490,    20,     5, 240
ih		 	FLbox  	"arpeggio note is assumed to be a quaver/eighth note so a     ", 	1,      5,     14,    490,    20,     5, 260
ih		 	FLbox  	"tempo of 120 BPM will result in 240 notes being played per   ", 	1,      5,     14,    490,    20,     5, 280
ih		 	FLbox  	"minute, assuming beats are in crotchets/quarter notes.       ", 	1,      5,     14,    490,    20,     5, 300
ih		 	FLbox  	"In 'Tempo' mode there are also 8 'multiplier' presets which  ", 	1,      5,     14,    490,    20,     5, 320 
ih		 	FLbox  	"scale the tempo using simple ratios.                         ", 	1,      5,     14,    490,    20,     5, 340 
ih		 	FLbox  	"There are six modes of movement: 'Up', 'Down', and 'Up and   ", 	1,      5,     14,    490,    20,     5, 360
ih		 	FLbox  	"Down' are as would be expected. 'Random Direction' randomly  ", 	1,      5,     14,    490,    20,     5, 380
ih		 	FLbox  	"moves up or down from the current pitch to the next pitch in ", 	1,      5,     14,    490,    20,     5, 400
ih		 	FLbox  	"the arpeggio. 'Random Pick' chooses any other note within the", 	1,      5,     14,    490,    20,     5, 420
ih		 	FLbox  	"arpeggio each time a new note is required. 'Seq. Play' plays ", 	1,      5,     14,    490,    20,     5, 440
ih		 	FLbox  	"through the sequence of notes in the order in which they were", 	1,      5,     14,    490,    20,     5, 460
ih		 	FLbox  	"pressed.                                                     ", 	1,      5,     14,    490,    20,     5, 480
ih		 	FLbox  	"'Cycles' will add repeats of the entire arpeggio transposed  ", 	1,      5,     14,    490,    20,     5, 500
ih		 	FLbox  	"sequentially by the number of semitones defined by 'Intvl'.  ", 	1,      5,     14,    490,    20,     5, 520
ih		 	FLbox  	"'Cycles' will have no effect if 'Intvl' is zero therefore its", 	1,      5,     14,    490,    20,     5, 540 
ih		 	FLbox  	"widget only appears if 'Intvl' is non-zero. If 'Intvl' is    ", 	1,      5,     14,    490,    20,     5, 560 
ih		 	FLbox  	"negative subsequent cycles of the arpeggio will be lower than", 	1,      5,     14,    490,    20,     5, 580 
ih		 	FLbox  	"the first. If 'Up+Down' is activated the transposition steps ", 	1,      5,     14,    490,    20,     5, 600 
ih		 	FLbox  	"will go up and then back down (or vice versa if 'Intvl' is   ", 	1,      5,     14,    490,    20,     5, 620
ih		 	FLbox  	"negative) rather than just up. This option is ignored in     ", 	1,      5,     14,    490,    20,     5, 640
ih		 	FLbox  	"'Random Dir.' mode which instead implements a kind of        ", 	1,      5,     14,    490,    20,     5, 660
ih		 	FLbox  	"'Drunken Walk'. Note that 'Up+Down' only becomes relevant    ", 	1,      5,     14,    490,    20,     5, 680
ih		 	FLbox  	"(and visible) if 'Cycles' is '2' or more.                    ", 	1,      5,     14,    490,    20,     5, 700 
ih		 	FLbox  	"'Hold' imitates the action of a keyboard's sustain pedal.    ", 	1,      5,     14,    490,    20,     5, 720
ih		 	FLbox  	"This function is also referred to as 'latch' in arpeggiators.", 	1,      5,     14,    490,    20,     5, 740 
ih		 	FLbox  	"'Swing' warps the rhythm of each pair of arpeggiator notes.  ", 	1,      5,     14,    490,    20,     5, 760
ih		 	FLbox  	"The rhythm is warped continuously from quaver:quaver at its  ", 	1,      5,     14,    490,    20,     5, 780
ih		 	FLbox  	"minimum setting to dotted-quaver:semiquaver at its maximum.  ", 	1,      5,     14,    490,    20,     5, 800
ih		 	FLbox  	"At its midway point the rhythm is triplet-crotchet, triplet- ", 	1,      5,     14,    490,    20,     5, 820
ih		 	FLbox  	"quaver.                                                      ", 	1,      5,     14,    490,    20,     5, 840
ih		 	FLbox  	"                                                             ", 	1,      5,     14,    490,    20,     5, 860
ih		 	FLbox  	" Synthesizer Section                                         ", 	1,      8,     14,    490,    20,     5, 880
ih		 	FLbox  	"Single oscillator synthesizer with four waveform choices, an ", 	1,      5,     14,    490,    20,     5, 900
ih		 	FLbox  	"amplitude envelope, a filter envelope and an LFO influencing ", 	1,      5,     14,    490,    20,     5, 920
ih		 	FLbox  	"the filter cutoff frequency. Use the radio buttons to select ", 	1,      5,     14,    490,    20,     5, 940 
ih		 	FLbox  	"either the amplitude, filter envelope or LFO for editing.    ", 	1,      5,     14,    490,    20,     5, 960
ih		 	FLbox  	"The filter envelope can be defined as a static repeating     ", 	1,      5,     14,    490,    20,     5, 980
ih		 	FLbox  	"function ('Kybd.Track' off) or one that describes a frequency", 	1,      5,     14,    490,    20,     5,1000
ih		 	FLbox  	"function relative to the currently playing pitch ('Kybd.-    ", 	1,      5,     14,    490,    20,     5,1020
ih		 	FLbox  	"-Track' on). The filter can be either resonant lowpass or    ", 	1,      5,     14,    490,    20,     5,1040
ih		 	FLbox  	"bandpass. 'Port.' applies a sliding portamento between pitch ", 	1,      5,     14,    490,    20,     5,1060
ih		 	FLbox  	"changes.                                                     ", 	1,      5,     14,    490,    20,     5,1080
ih		 	FLbox  	"                                                             ", 	1,      5,     14,    490,    20,     5,1100
ih		 	FLbox  	" Delay Section                                               ", 	1,      8,     14,    490,    20,     5,1120
ih		 	FLbox  	"The delay can be either a simple delay or a ping-pong delay, ", 	1,      5,     14,    490,    20,     5,1140
ih		 	FLbox  	"in which case the echoes alternate between the left and right", 	1,      5,     14,    490,    20,     5,1160
ih		 	FLbox  	"speakers. Delay time can be expressed either freely using the", 	1,      5,     14,    490,    20,     5,1180
ih		 	FLbox  	"'Time' knob, when 'Free' mode is selected, or as a rhythmic  ", 	1,      5,     14,    490,    20,     5,1200
ih		 	FLbox  	"value, with respect to the arpeggiator rate, when 'Rhythm'   ", 	1,      5,     14,    490,    20,     5,1220
ih		 	FLbox  	"is selected. Each arpeggiator note duration is assumed to be ", 	1,      5,     14,    490,    20,     5,1240
ih		 	FLbox  	"a quaver/eighth note so a setting of 1/8 here will invoke a  ", 	1,      5,     14,    490,    20,     5,1260
ih		 	FLbox  	"delay time equal to the duration of each arpeggiator note.   ", 	1,      5,     14,    490,    20,     5,1280
ih		 	FLbox  	"'Port.' controls the degree to which delay time change are   ", 	1,      5,     14,    490,    20,     5,1300
ih		 	FLbox  	"damped, causing pitch glides whenever delay time is changed. ", 	1,      5,     14,    490,    20,     5,1320
ih		 	FLbox  	"Note that several controls influence delay time: 'Delay Time ", 	1,      5,     14,    490,    20,     5,1340
ih		 	FLbox  	"Mode', 'Time' knob, 'Rhy. Val.' and arpeggiator rate/tempo   ", 	1,      5,     14,    490,    20,     5,1360
ih		 	FLbox  	"(when rhythm mode is selected).                              ", 	1,      5,     14,    490,    20,     5,1380
ih		 	FLbox  	"                                                             ", 	1,      5,     14,    490,    20,     5,1400
ih		 	FLbox  	" Technical                                                   ", 	1,      8,     14,    490,    20,     5,1420
ih		 	FLbox  	"Whenever a new note is played its note number is written into", 	1,      5,     14,    490,    20,     5,1440
ih		 	FLbox  	"two different function tables: in the first table, note      ", 	1,      5,     14,    490,    20,     5,1460
ih		 	FLbox  	"numbers are written sequentially in the order in which they  ", 	1,      5,     14,    490,    20,     5,1480
ih		 	FLbox  	"were played. (NB. if a note is removed its note number is    ", 	1,      5,     14,    490,    20,     5,1500
ih		 	FLbox  	"removed from this table and any notes following it in the    ", 	1,      5,     14,    490,    20,     5,1520
ih	  	 	FLbox  	"table are shunted back one place so as to not leave any      ", 	1,      5,     14,    490,    20,     5,1540
ih	  	 	FLbox  	"gaps.) This table is used by the 'Seq. Play' and 'Random     ", 	1,      5,     14,    490,    20,     5,1560
ih	  	 	FLbox  	"Pick' arpeggiator modes. A second table is created (and      ", 	1,      5,     14,    490,    20,     5,1580
ih	  	 	FLbox  	"updated any time a new note is added or removed) in which all", 	1,      5,     14,    490,    20,     5,1580
ih	  	 	FLbox  	"notes currently being held are sorted into ascending order.  ", 	1,      5,     14,    490,    20,     5,1580
ih	  	 	FLbox  	"This table is used by all other arpeggiator modes.           ", 	1,      5,     14,    490,    20,     5,1600
ih	  	 	FLbox  	"A third table is used to store the on/off status of each     ", 	1,      5,     14,    490,    20,     5,1620
ih	  	 	FLbox  	"note. A value of '1' in this table denote 'note on' and '0'  ", 	1,      5,     14,    490,    20,     5,1640
ih	  	 	FLbox  	"denotes 'note off'. For example if middle C (note number 60) ", 	1,      5,     14,    490,    20,     5,1660
ih	  	 	FLbox  	"is pressed, the 61st table item with index number 60 will be ", 	1,      5,     14,    490,    20,     5,1680
ih	  	 	FLbox  	"'1'. This is needed to check for active notes and prevent the", 	1,      5,     14,    490,    20,     5,1700
ih	  	 	FLbox  	"same note appearing twice in a note row. This would otherwise", 	1,      5,     14,    490,    20,     5,1720
ih	  	 	FLbox  	"be possible when 'hold' is active. This function could be    ", 	1,      5,     14,    490,    20,     5,1740
ih	  	 	FLbox  	"deactivated if you wanted to define arpeggios with repeated  ", 	1,      5,     14,    490,    20,     5,1760
ih	  	 	FLbox  	"notes.                                                       ", 	1,      5,     14,    490,    20,     5,1780
				FLscroll_end                                                                                                      
				FLpanel_end

				
				
;		LABEL          | WIDTH | HEIGHT | X | Y
	FLpanel	"Arpeggiator",    500,    460,    0,  0

;BORDERS						TYPE | FONT | SIZE | WIDTH | HEIGHT | X | Y
ih		 	FLbox  	" ", 			6,        9,    15,    498,   135,    1,  1	;ARPEGGIATOR
ih		 	FLbox  	" ", 			6,        9,    15,    498,   170,    1, 140	;SYNTH
ih		 	FLbox  	" ", 			6,        9,    15,    498,   145,    1, 315	;DELAY
;PANEL LABELS
ih		 	FLbox  	"Arpeggiator", 		1,       12,    14,     88,    15,    5,   5
ih		 	FLbox  	"Synth", 		1,       12,    14,     48,    15,    5, 144
ih		 	FLbox  	"Delay",		1,       12,    14,     48,    15,    5, 319

;VALUE DISPLAY BOXES				WIDTH | HEIGHT | X |  Y
gidrate			FLvalue	" ",     	50,       18,   205,  82

;COUNTERS					MIN | MAX | STEP1 | STEP2 | TYPE | WIDTH | HEIGHT | X | Y | OPCODE
gkintvl,   ihintvl 	FLcount  "Intvl.", 	-36,   36,    1,     12,     1,     80,      20,   10,  42,   -1
gkcycles,   gihcycles 	FLcount  "Cycles", 	0,     32,    1,     12,     2,     80,      20,   10,  78,   -1
gktempo,   gihtempo 	FLcount  "Tempo", 	1,    500,   1,     10,     1,     80,      20,  200,  30,   -1
gkRhyNum,   gihRhyNum 	FLcount  "", 		  1,   32,    1,     12,     2,     50,      20,  355, 380,   -1
gkRhyDen,   gihRhyDen 	FLcount  "", 		  1,   16,    1,     12,     2,     50,      20,  355, 400,   -1
FLsetTextSize	11,ihintvl
FLsetTextSize	11,gihcycles

;SWITCHES                        	             		ON | OFF | TYPE | WIDTH | HEIGHT | X  | Y | OPCODE
gkhold,ihhold			FLbutton	"Hold",		1,    0,    22,     60,     18,   150, 108,   -1
gkKybdTrk,ihKybdTrk		FLbutton	"Track",	1,    0,    22,     50,     15,   280, 240,   -1
gkDelOnOff,ihDelOnOff		FLbutton	"On/Off",	1,    0,    22,     70,     18,    10, 340,   -1
gkCyUpDn,gihCyUpDn		FLbutton	"Up+Down",	1,    0,    22,     80,     18,    10, 112,   -1
FLsetColor2	255,255,50,ihhold
FLsetColor2	255,255,50,ihKybdTrk
FLsetColor2	255,255,50,ihDelOnOff
FLsetColor2	255,255,50,gihCyUpDn
FLsetTextSize	12,gihCyUpDn
FLsetTextSize	11,ihKybdTrk
;GENERAL_TEXT_SETTINGS			SIZE | FONT |  ALIGN | RED | GREEN | BLUE
			FLlabel		13,      1,      3,    255,   255,   255		;LABELS MADE INVISIBLE (I.E. SAME COLOR AS PANEL)

;BUTTON BANKS					TYPE | NUMX | NUMY | WIDTH | HEIGHT | X | Y | OPCODE | INS | STARTTIM | DUR
gkmode, ihmode			FLbutBank	11,     1,     6,     18,    6*15,   395, 30,  -1
gkwave, ihwave			FLbutBank	11,     1,     4,     18,    4*15,   165,215,  -1
gkFiltType, gihFiltType		FLbutBank	11,     1,     2,     18,    2*15,   330,225,  -1
gkDelType, ihDelType		FLbutBank	11,     1,     2,     18,      30,   125,335,  -1
gkDelTimMode, ihDelTimMode	FLbutBank	11,     1,     2,     18,      30,   357,335,  -1
gkRateMode, ihRateMode		FLbutBank	11,     1,     2,     18,      30,   135, 20,  -1
gkTempoMlt, gihTempoMlt		FLbutBank	11,     1,     8,     18,    8*15,   280,  5,  -1
gkModView, ihModView		FLbutBank	11,     1,     3,     18,      45,     5,175,  -1
gkOctTrans, ihOctTrans		FLbutBank	11,     7,     1,   7*15,      15,    25,240,  -1
gkSemiTrans, ihSemiTrans	FLbutBank	11,     23,     1,  23*15,     15,     5,280,  -1
FLsetVal_i	1,ihOctTrans
FLsetVal_i	11,ihSemiTrans
;GENERAL_TEXT_SETTINGS			SIZE | FONT |  ALIGN | RED | GREEN | BLUE
			FLlabel		13,      1,      3,     0,     0,     0			;LABELS MADE VISIBLE AGAIN

;TEXT BOXES							TYPE | FONT | SIZE | WIDTH | HEIGHT | X |  Y
ih		 	FLbox  	"Mode:", 			1,       6,    12,     40,      15, 355,  30
ih		 	FLbox  	"Up         ",			1,       5,    12,     80,      15, 415,  30
ih		 	FLbox  	"Down       ",			1,       5,    12,     80,      15, 415,  45
ih		 	FLbox  	"Up<->Down  ",			1,       5,    12,     80,      15, 415,  60
ih		 	FLbox  	"Random Dir.",			1,       5,    12,     80,      15, 415,  75
ih		 	FLbox  	"Random Pick",			1,       5,    12,     80,      15, 415,  90
ih		 	FLbox  	"Seq. Play  ",			1,       5,    12,     80,      15, 415, 105
ih		 	FLbox  	"Octave", 			1,       6,    12,     48,      15,  55, 225
ih		 	FLbox  	"-3", 				1,       5,    11,     15,      12,  25, 255
ih		 	FLbox  	"-2", 				1,       5,    11,     15,      12,  40, 255
ih		 	FLbox  	"-1", 				1,       5,    11,     15,      12,  55, 255
ih		 	FLbox  	"0", 				1,       5,    11,     15,      12,  70, 255
ih		 	FLbox  	"+1", 				1,       5,    11,     15,      12,  85, 255
ih		 	FLbox  	"+2", 				1,       5,    11,     15,      12, 100, 255
ih		 	FLbox  	"+3", 				1,       5,    11,     15,      12, 115, 255

ih		 	FLbox  	"Semitone", 			1,       6,    12,     55,      15,  55, 265
ih		 	FLbox  	"-11", 				1,       6,     9,     15,      12,   5, 295
ih		 	FLbox  	"-10", 				1,       6,     9,     15,      12,  20, 295
ih		 	FLbox  	"-9", 				1,       6,     9,     15,      12,  35, 295
ih		 	FLbox  	"-8", 				1,       6,     9,     15,      12,  50, 295
ih		 	FLbox  	"-7", 				1,       6,     9,     15,      12,  65, 295
ih		 	FLbox  	"-6", 				1,       6,     9,     15,      12,  80, 295
ih		 	FLbox  	"-5", 				1,       6,     9,     15,      12,  95, 295
ih		 	FLbox  	"-4", 				1,       6,     9,     15,      12, 110, 295
ih		 	FLbox  	"-3", 				1,       6,     9,     15,      12, 125, 295
ih		 	FLbox  	"-2", 				1,       6,     9,     15,      12, 140, 295
ih		 	FLbox  	"-1", 				1,       6,     9,     15,      12, 155, 295
ih		 	FLbox  	"0", 				1,       6,     9,     15,      12, 170, 295
ih		 	FLbox  	"+1", 				1,       6,     9,     15,      12, 185, 295
ih		 	FLbox  	"+2", 				1,       6,     9,     15,      12, 200, 295
ih		 	FLbox  	"+3", 				1,       6,     9,     15,      12, 215, 295
ih		 	FLbox  	"+4", 				1,       6,     9,     15,      12, 230, 295
ih		 	FLbox  	"+5", 				1,       6,     9,     15,      12, 245, 295
ih		 	FLbox  	"+6", 				1,       6,     9,     15,      12, 260, 295
ih		 	FLbox  	"+7", 				1,       6,     9,     15,      12, 275, 295
ih		 	FLbox  	"+8", 				1,       6,     9,     15,      12, 290, 295
ih		 	FLbox  	"+9", 				1,       6,     9,     15,      12, 305, 295
ih		 	FLbox  	"+10", 				1,       6,     9,     15,      12, 320, 295
ih		 	FLbox  	"+11", 				1,       6,     9,     15,      12, 335, 295


ih		 	FLbox  	"Wave:", 			1,       6,    12,     50,      15, 115, 215                                                     
ih		 	FLbox  	"Tri.", 			1,       5,    11,     35,      15, 185, 215
ih		 	FLbox  	"Sq. ", 			1,       5,    11,     35,      15, 185, 230
ih		 	FLbox  	"Saw ", 			1,       5,    11,     35,      15, 185, 245
ih		 	FLbox  	"Nse.", 			1,       5,    11,     35,      15, 185, 260
ih		 	FLbox  	"Filter:", 			1,       6,    12,     50,      15, 280, 225
ih		 	FLbox  	"Lowpass ", 			1,       5,    11,     60,      15, 350, 225
ih		 	FLbox  	"Bandpass", 			1,       5,    11,     60,      15, 350, 240
ih		 	FLbox  	"Type:", 			1,       6,    12,     40,      15,  85, 335
ih		 	FLbox  	"Simple   ", 			1,       5,    12,     65,      15, 145, 335
ih		 	FLbox  	"Ping-Pong", 			1,       5,    12,     65,      15, 145, 350
ih		 	FLbox  	"Delay Time Mode:", 		1,       6,    12,     70,      30, 285, 335
ih		 	FLbox  	"Free  ", 			1,       5,    12,     50,      15, 375, 335
ih		 	FLbox  	"Rhythm", 			1,       5,    12,     50,      15, 375, 350
gihRhyLabel	 	FLbox  	"Rhy. Val.", 			1,       6,    12,     65,      15, 290, 380
ih		 	FLbox  	"Rate Mode:", 			1,       6,    12,     75,      15,  60,  20
ih		 	FLbox  	"Free ", 			1,       5,    11,     45,      15, 155,  20
ih		 	FLbox  	"Tempo", 			1,       5,    11,     45,      15, 155,  35
ih		 	FLbox  	"Mod:", 			1,       6,    12,     30,      15,   5, 160
ih		 	FLbox  	"Amp ", 			1,       5,    11,     30,      15,  25, 175
ih		 	FLbox  	"Filt", 			1,       5,    11,     30,      15,  25, 190
ih		 	FLbox  	"LFO ", 			1,       5,    11,     30,      15,  25, 205
gih1		 	FLbox  	"x 1/4", 			1,       5,    11,     40,      15, 300,   5
gih2		 	FLbox  	"x 1/3", 			1,       5,    11,     40,      15, 300,  20
gih3		 	FLbox  	"x 1/2", 			1,       5,    11,     40,      15, 300,  35
gih4		 	FLbox  	"x 1  ", 			1,       5,    11,     40,      15, 300,  50
gih5		 	FLbox  	"x 3/2", 			1,       5,    11,     40,      15, 300,  65
gih6		 	FLbox  	"x 2  ", 			1,       5,    11,     40,      15, 300,  80
gih7		 	FLbox  	"x 3  ", 			1,       5,    11,     40,      15, 300,  95
gih8		 	FLbox  	"x 4  ", 			1,       5,    11,     40,      15, 300, 110
gilog	ftgen	0,0,1024,16,0,1024,-2,1
giexp	ftgen	0,0,1024,16,0,1024, 2,1
;KNOBS								MIN | MAX | EXP | TYPE | DISP | WIDTH | X | Y
gkrate, gihrate			FLknob 		"Rate", 	0.25, 32,   -1,    1,gidrate,     60, 200,   5
gkswing, ihswing		FLknob 		"Swing", 	0,     1,    0,    1,     -1,     40, 102,  70
gkEnvAmt, gihEnvAmt		FLknob 		"Env.Amt.", 	0,     1,    0,    1,     -1,     60,  60, 150
gkatt, gihatt			FLknob 		"Att.", 	0.001, 2,   -1,    1,     -1,     50, 130, 150
gkdec, gihdec			FLknob 		"Dec", 		0.001, 2,   -1,    1,     -1,     50, 185, 150
gksus, gihsus			FLknob 		"Sus", 		0,     1,    0,    1,     -1,     50, 240, 150
gkrel, gihrel			FLknob 		"Rel.", 	0.001, 2,   -1,    1,     -1,     50, 295, 150
gkAatt, gihAatt			FLknob 		"Att.", 	0.001, 2,   -1,    1,     -1,     50, 130, 150
gkAdec, gihAdec			FLknob 		"Dec", 		0.001, 2,   -1,    1,     -1,     50, 185, 150
gkAsus, gihAsus			FLknob 		"Sus", 		0,     1,    0,    1,     -1,     50, 240, 150
gkArel, gihArel			FLknob 		"Rel.", 	0.001, 2,   -1,    1,     -1,     50, 295, 150
gkLFOdep, gihLFOdep		FLknob 		"Depth", 	0,   0.5,    0,    1,     -1,     50, 130, 150
gkLFOrate, gihLFOrate		FLknob 		"Rate", 	0.001, 5,   -1,    1,     -1,     50, 185, 150
gkres, gihres			FLknob 		"Res.", 	0,     1,    0,    1,     -1,     60, 355, 150
gkdist, gihdist			FLknob 		"Dist", 	0,     1,    0,    1,     -1,     60, 425, 150
gkSynLev, ihSynLev		FLknob 		"Level", 	0,     1,    0,    1,     -1,     60, 425, 230
gkNotePort, ihNotePort		FLknob 		"Port.", 	0,     1,giexp,    1,     -1,     40, 220, 220
gkFBamt, ihFBamt		FLknob 		"F.Back", 	0,  0.99,    0,    1,     -1,     60,  15, 375
gkDryWet, ihDryWet		FLknob 		"Dry/Wet", 	0,     1,    0,    1,     -1,     60,  85, 375
gkDelTimPort, ihDelTimPort	FLknob 		"Port.", 	0,     1,    0,    1,     -1,     60, 155, 375
gkDelTone, ihDelTone		FLknob 		"Tone", 	7,    13,    0,    1,     -1,     60, 225, 375
gkDelTim, gihDelTim		FLknob 		"Time", 	0.01,  2,   -1,    1,     -1,     60, 365, 375
FLhide	gihDelTim
FLhide	gihAatt
FLhide	gihAdec
FLhide	gihAsus
FLhide	gihArel
FLhide	gihLFOdep 
FLhide	gihLFOrate
FLhide	gihrate
;CREATE A FLTK VIRTUAL KEYBOARD WITHIN THIS WINDOW
;;FLvkeybd "", 500, 90, 0, 480	;'ADD INTERVAL' DOESN'T SEEM TO WORK WHEN THIS VIRTUAL KEYBOARD IS SELECTED!

;SET INITIAL VALUES			VALUE | HANDLE
			FLsetVal_i	 8,	gihrate
			FLsetVal_i	 120,	gihtempo
			FLsetVal_i	 0.001,	gihatt
			FLsetVal_i	 0.5,	gihdec
			FLsetVal_i	 0.5,	gihsus
			FLsetVal_i	 0.1,	gihrel
			FLsetVal_i	 0.5,	gihres
			FLsetVal_i	 0.5,	gihEnvAmt
			FLsetVal_i	 0.001,	gihAatt
			FLsetVal_i	 0.001,	gihAdec
			FLsetVal_i	 1,	gihAsus
			FLsetVal_i	 0.001,	gihArel
			FLsetVal_i	 0.5,	gihDelTim
			FLsetVal_i	 0.2,	ihFBamt
			FLsetVal_i	 0.1,	ihDryWet
			FLsetVal_i	 1,	ihDelTimMode
			FLsetVal_i	 1,	ihKybdTrk
			FLsetVal_i	 2,	ihwave
			FLsetVal_i	 0,	ihDelTimPort
			FLsetVal_i	 1,	ihDelType
			FLsetVal_i	 13,	ihDelTone
			FLsetVal_i	 5,	gihTempoMlt
			FLsetVal_i	 0.3,	ihSynLev
			FLsetVal_i	 5,	ihmode
			FLsetVal_i	7,	ihintvl
			FLsetVal_i	5,	gihcycles
			FLsetVal_i	8,	gihRhyNum
			FLsetVal_i	16,	gihRhyDen
			FLsetVal_i	1,	ihDelOnOff
			FLsetVal_i	0.15,	gihLFOdep
			FLsetVal_i	0.07,	gihLFOrate
			FLsetVal_i	1,	ihModView
			FLsetVal_i	1,	ihRateMode
			FLsetVal_i	1,	gihCyUpDn
			FLsetVal_i	1,	ihhold
			FLpanel_end

			
				FLpanel	"XY Panels", 500, 530, 512, 0			
;XY PANELS												MINX | MAXX | MINY | MAXY | EXPX | EXPY | DISPX | DISPY | WIDTH | HEIGHT | X | Y
gkatt, gkdec, ihatt2, ihdec2				FLjoy	"Filter: X - Attack  Y - Decay",	0.001,  2,   0.001,   2,    -1,     -1,     -1,     -1,    240,    240,    5,  5
gkEnvAmt, gkres, ihEnvAmt2, ihres2			FLjoy	"Filter X - Env.Amt.  Y - Res.",	0,      1,       0,   1,     0,      0,     -1,     -1,    240,    240,  255,  5
gkwave, gkdist, ihwave2, ihdist2			FLjoy	"Synth: X - Wave  Y - Distortion",	0,      3,       0,   1,     0,      0,     -1,     -1,    240,    240,    5,270
gkFBamt, gkDelTone, ihFBamt2, ihDelTone2		FLjoy	"Delay: X - Feedback  Y - Tone",	0,    0.99,      7,  13,     0,      0,     -1,     -1,    240,    240,  255,270
;gkDelTim, gkDelTimPort, ihDelTim2, ihDelTimPort2	FLjoy	"Delay: X - Time  Y - Portamento",	0,       1,      7,  13,     0,      0,     -1,     -1,    240,    240,  255,270
;SET INITIAL VALUES			VALUE | HANDLE
			FLsetVal_i	 0.001,	ihatt2
			FLsetVal_i	 0.5,	ihdec2
			FLsetVal_i	 0.5,	ihEnvAmt2
			FLsetVal_i	 0.5,	ihres2
			FLsetVal_i	 2,	ihwave2
			FLsetVal_i	 0,	ihdist2
;			FLsetVal_i	 0.2,	ihFBamt2
;			FLsetVal_i	 13,	ihDelTone2
;			FLsetVal_i	 0.2,	ihDelTim2
;			FLsetVal_i	 0,	ihDelTimPort2

FLpanelEnd


				FLrun	;RUN THE FLTK WIDGET THREAD
;END OF FLTK INTERFACE CODE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

giseqorder	ftgen	0,0,1024,-2,0	;ORDERED ROW OF NOTES (IN THE ORDER IN WHICH THEY WERE PLAYED)
giseqascend	ftgen	0,0,1024,-2,0	;ORDERED ROW OF NOTES (IN ASCENDING ORDER)
ginoteactive	ftgen	0,0,128,-2,0	;TABLE OF NOTE ON STATUSES 1=ON 0=OFF
giblank		ftgen	0,0,128,-2,0	;BLANK TABLE

giFletcherMunsonCurve	ftgen	0,0,-20000,-16,1,4000,-8,0.15, 20000-4000,0,0.15

giTempoMlt	ftgen	0,0,-8,-2,1/4,1/3,1/2,1,3/2,2,3,4	;TABLE OF TEMPO MULTIPLIERS - USED TO SCALE THE ARPEGGIO RATE WHEN IN TEMPO MODE
gasendL,gasendR	init	0					;GLOBAL VARIABLES USED TO SEND SIGNAL TO THE DELAY EFFECT

;UDO THAT SORTS A TABLE OF NUMBERS INTO ASCENDING ORDER
opcode	tabsort_ascnd2,0,ii
	iNumItems,ifn	xin
	iTabLen		=		ftlen(ifn)
	imax		table		0,ifn
	icount		=		1
	loop1:
	  ival		table		icount,ifn
	  imax 		= 		(ival>=imax?ival:imax)
	  		loop_lt		icount,1,iNumItems,loop1
	iTableBuffer	ftgentmp	0,0,iTabLen,-2, 0
	icount1		=		0
	loop2:
	  icount2	=		0
	  imin		=		imax
	  loop3:
	    ival	table		icount2,ifn
	    if ival<=imin then			
	      imin 	= 		ival
	      iloc 	= 		icount2 
	    endif
	    		loop_lt		icount2,1,iNumItems,loop3
			tableiw		imin,icount1,iTableBuffer
			tableiw		imax,iloc,ifn
			loop_lt		icount1,1,iNumItems,loop2
	icount		=		0
	loop4:
	ival		table		icount,iTableBuffer
			tableiw		ival,icount,ifn
			loop_lt		icount,1,iNumItems,loop4
endop

instr	NoteLayer				;THIS INSTRUMENT IS TRIGGERED FOR EACH NOTE PLAYED ON THE KEYBOARD
	inum	=	p4			;READ IN MIDI NOTE NUMBER		
	tableiw	1,inum,ginoteactive
	iNNotes	active	"NoteLayer"		;SENSE THE NUMBER INSTANCES OF THIS INSTRUMENT (I.E. MIDI NOTES) ARE BEING HELD AT I-TIME.
	print	iNNotes
	tableiw	inum,iNNotes-1,giseqorder	;WRITE THE NOTE NUMBER OF THIS NOTE TO THE NEXT LOCATION IN THE ORDERED ROW OF NOTES (giseqorder)
	tableicopy	giseqascend,giseqorder	;COPY THE LIST OF NOTES (IN THE ORDER IN WHICH THEY WERE PLAYED) INTO THE TABLE OF NOTES TO BE SORTED INTO ASCENDING ORDER
	tabsort_ascnd2	iNNotes,giseqascend	;UDO CALLED THAT ORDERS THE LIST OF NOTES INTO ASCENDING ORDER
	
	krelease	release			;SENSE WHEN THIS NOTE HAS BEEN RELEASED
	if krelease==1 then			;IF THIS NOTE HAS BEEN RELEASED (FINAL K-RATE CYCLE)...
	 tablew	0,inum,ginoteactive
	 ;AS THIS NOTE HAS BEEN RELEASED IT WILL HAVE TO BE REMOVED FROM THE ORDERED ROW OF NOTE (giseqorder). ALL NOTES *AFTER* IT IN THE ROW WILL HAVE TO BE SHUNTED BACK ONE PLACE.
	 kShuntNdx	=	iNNotes		;INITIAL SHUNT INDEX (THE LOCATION TO WHICH THE NOTE NUMBER FOR THIS NOTE WAS WRITTEN)
	 kNNotes	active	"NoteLayer"	;FIND THE NUMBER OF INSTANCES OF THIS INSTRUMENT (I.E. NOTES BEING HELD) NOW
	 SHUNT_ROW:				;A LABEL. THE SHUNTING PROCEDURE LOOPS FROM HERE.
	 kval	table	kShuntNdx, giseqorder	;READ THE NOTE NUMBER JUST AFTER THIS ONE IN THE SEQUENCE ROW...
	 	tablew	kval, kShuntNdx-1, giseqorder	;AND MOVE IT BACK ONE PLACE
	 loop_lt	kShuntNdx,1,kNNotes,SHUNT_ROW	;LOOP BACK AND REPEAT THE SHUNTING PROCEDURE UNTIL THE NEW ROW IS COMPLETE
	endif
	
	kHoldOff	trigger	gkhold,0.5,1	;IF HOLD GOES FROM '1'/'ON' TO '0'/'OFF' GENERATE A TRIGGER IMPULSE
	if kHoldOff==1 then			;IF HOLD GOES FROM 'ON' TO 'OFF'... 
	 turnoff				;TURN THIS (AND ALL OTHER) NOTES OFF
	endif					;END OF CONDITIONAL BRANCH

	if iNNotes==1 then			;IF THIS IS THE FIRST NOTE OF AN ARPEGGIO TO BE PLAYED...
	 event_i "i","Arpeggiator",0,-1		;START ARPEGGIATOR INSTRUMENT WITH A 'HELD' NOTE. SEND IT THE MIDI NOTE NUMBER.
	endif					;END OF CONDITIONAL BRANCH
endin


instr	Arpeggiator
	krelease	release				;SENSE END OF NOTE (1)

	ktrans		init	((i(gkOctTrans)-3)*12)+(i(gkSemiTrans)-11)

	kHoldOff	trigger	gkhold,0.5,1		;IF HOLD GOES FROM '1'/'ON' TO '0'/'OFF' GENERATE A TRIGGER IMPULSE
	if kHoldOff==1 then				;IF HOLD GOES FROM 'ON' TO 'OFF'... 
	 tablecopy	ginoteactive,giblank		;ERASE NOTE STATUSES TABLE
	 turnoff					;TURN THIS INSTRUMENT OFF
	endif						;END OF CONDITIONAL BRANCH

	kNNotes	active	"NoteLayer"			;NUMBER OF INSTR 1 (MIDI NOTES) BEING HELD. SPECIFICALLY WE ARE INTERESTED IN WHETHER ALL NOTES HAVE BEEN RELEASED
	prints	"\n"
	;printk2	kNNotes
	
	
	if kNNotes==0&&gkhold==0 then			;IF ALL MIDI KEYBOARD NOTES HAVE BEEN RELEASED...
	 turnoff					;...TURN THIS INSTRUMENT OFF
	endif						;END OF CONDITIONAL BRANCH

	kswingval1	scale	gkswing,1/1.5,1	;=	(gkswing*0.5) + 1	;
	kswingval2	scale	gkswing,1/0.5,1	;=	1-(gkswing*0.5)		;
	kswingstep	init	0
	kswingval	init	(i(gkswing)*0.5) + 1
	
	ktrig	changed	gkTempoMlt
	if ktrig==1 then
	 kTempoMlt	table	gkTempoMlt,giTempoMlt
	endif
	
	if i(gkRateMode)==1 then
	 gkrate	=	(gktempo*2*kTempoMlt)/60
	endif
	
	ktrigger	metro	gkrate*kswingval;,ksmps/sr		;METRONOME TO TRIGGER NOTES OF THE ARPEGGIO. PHASE OFFSET (P2) PREVENTS A SEARCH FOR A NEW NOTE WHEN THE FIRST NOTE OF AN ARPEGGIO HAS BEEN PLAYED

	;SET REQUIRED INITIAL SETTINGS DEPENDING ON ARPEGGIATOR MODE
	ktrig	changed	gkmode
	if ktrig==1 then
	 reinit	RESET_START_VALS
	endif
	RESET_START_VALS:
	kcount1	init	0
	kcount2	init	0
	kndx	init	0
	kcycle	init	0
	kCycleDir	init	0
	if i(gkmode)==0 then				;IF UP MODE...
	 kcount1	init	0
	 kcount2	init	0
	 kndx	init	0
	 kdir	init	1
	elseif i(gkmode)==1 then			;IF DOWN MODE...
	 kcount1	init	0
	 kcount2	init	0
	 kndx	init	i(kNNotes)-1
	 kdir	init	-1
	elseif i(gkmode)==2 then			;IF UP AND DOWN MODE...
	 kdir	init	1
	 kcount1	init	0
	 kcount2	init	0
	 kndx	init	0
	elseif i(gkmode)==3 then			;RANDOM DIRECTION MODE...
	 kdir	init	1
	 kcount1	init	0
	 kcount2	init	0
	 kndx	init	0
	elseif i(gkmode)==4 then			;RANDOM PICK MODE...
	 kcount1	init	0
	 kcount2	init	0
	 kndx	init	0
	elseif i(gkmode)==5 then			;SEQUENCE PLAY MODE...
	 kcount1	init	0
	 kcount2	init	0
	 kndx	init	0
	 kdir	init	1
	endif
	rireturn
	
	if ktrigger==1&&krelease!=1 then		;IF A TRIGGER FOR A NEW NOTE HAS BEEN ISSUED AND WE ARE NOT IN A RELEASE STAGE...

 	 ktrans		=	((gkOctTrans-3)*12)+(gkSemiTrans-11)

 	if gkRateMode==1 then
	 gkrate	=	(gktempo*2*kTempoMlt)/60
	endif

	 kswingstep	=	abs(kswingstep-1)
	 kswingval	=	(kswingstep=0?kswingval1:kswingval2)
	
	 ;UP
	 if gkmode==0 then				;IF 'UP' DIRECTION MODE IS SELECTED...
	  knum		table	kndx,giseqascend	;READ NOTE NUMBER
	  knum		=	knum+(gkintvl*kcycle)
	  kcount1	=	kcount1 + 1
	  ktrig		changed	kNNotes
	  if ktrig==1 then				;IF NOTES ARE ADDED OR TAKEN AWAY FROM THE ROW SINCE THE LAST ITERATION
	   kcount1	=	kndx+1
	  endif	  
	  if kndx==kNNotes-1 then
	   kcount2	=	kcount2+1
	   if gkCyUpDn==0 then
	    kcycle	wrap	kcount2,0,gkcycles+1
	   else
	    kcycle	mirror	kcount2,0,gkcycles
	   endif	    
	  endif	  
	  kndx		wrap	kcount1,-0.5,kNNotes-0.5  
	  


	 ;DOWN
	 elseif gkmode==1 then				;IF 'DOWN' DIRECTION MODE IS SELECTED...
	  knum		table	kndx,giseqascend	;READ NOTE NUMBER
	  knum		=	knum+(gkintvl*kcycle)
	  if kndx==0 then
	   kcount2	=	kcount2+1
	   if gkCyUpDn==0 then
	    kcycle	wrap	kcount2,0,gkcycles+1
	   else
	    kcycle	mirror	kcount2,0,gkcycles
	   endif	    
	  endif	  
	  kcount1	=	kcount1 - 1
	  ktrig		changed	kNNotes
	  if ktrig==1 then				;IF NOTES ARE ADDED OR TAKEN AWAY FROM THE ROW SINCE THE LAST ITERATION
	   kcount1	=	kndx-1
	  endif	  
	  kndx		wrap	kcount1,-0.5,kNNotes-0.5  



	
	 ;UP-DOWN
	 elseif gkmode==2 then				;IF 'UP<->DOWN' DIRECTION MODE IS SELECTED...
	  if gkcycles==0 then
	   if kNNotes==1 then
	    kdir	=	0
	   elseif kndx=0 then				;OR IF... THE INDEX IS POINTING TO THE FIRST NOTE IN THE LIST, WE NEED TO CHANGE DIRECTION TO UP FOR THE NEXT NOTE AFTER THIS ONE
	    kdir	=	1			;CHANGE DIRECTION TO UP
	   elseif kndx=(kNNotes-1) then			;IF THE INDEX IS POINTING TO THE LAST NOTE IN THE LIST, WE NEED TO CHANGE DIRECTION TO DOWN FOR THE NEXT NOTE AFTER THIS ONE
	    kdir	=	-1			;CHANGE DIRECTION TO DOWN
	   endif					;END OF CONDITIONAL
	   kndx	=	kndx + kdir
	   knum		table	kndx,giseqascend	;READ NOTE NUMBER
	   kgoto PLAY_A_NOTE				;GO STRAIGHT TO PLAYING THIS NEW NOTE

	  else
	   kndx		limit	kndx,0,kNNotes-1
	   knum		table	kndx,giseqascend	;READ NOTE NUMBER
	   knum		=	knum+(gkintvl*kcycle)
	   kcount	init	i(kndx)
	   kcount	=	kcount + 1
	   kndx		mirror	kcount,0,kNNotes-1
	   if kndx==0 then
	    kcount2	init	i(kcycle)
	    kcount2	=	kcount2+1	    
	    if gkCyUpDn==0 then
	     kcycle	wrap	kcount2,0,gkcycles+1
	    else
	     kcycle	mirror	kcount2,0,gkcycles
	    endif	    
	   endif
	   
	   kgoto PLAY_A_NOTE				;GO STRAIGHT TO PLAYING THIS NEW NOTE
	  endif
	 
	 
	 
	 
	 
	 
	 
	 
	 
	 
	 
	 
	 
	 ;RANDOM DIRECTION
	 elseif gkmode==3 then
	  if kndx==(kNNotes-1) then			;IF THE INDEX IS POINTING TO THE LAST NOTE IN THE LIST, WE NEED TO CHANGE DIRECTION TO DOWN FOR THE NEXT NOTE AFTER THIS ONE
	   kdir	=	-1				;CHANGE DIRECTION TO DOWN
	  elseif kndx==0 then				;OR IF... THE INDEX IS POINTING TO THE FIRST NOTE IN THE LIST, WE NEED TO CHANGE DIRECTION TO UP FOR THE NEXT NOTE AFTER THIS ONE
	   kdir	=	1				;CHANGE DIRECTION TO UP
	  endif						;END OF CONDITIONAL
	  knum		table	kndx,giseqascend	;READ NOTE NUMBER	
	  if gkcycles>0 then
	   knum	=	knum+(gkintvl*kcycle)
	  endif	
	  if kndx==(kNNotes-1) then
	   kcycle	wrap	kcycle+1,0,gkcycles+1
	  elseif kndx==0 then	
	   kcycle	wrap	kcycle-1,0,gkcycles+1
	  endif
	  kndx	=	kndx+kdir			;INCREMENT INDEX FOR THE NEXT NOTE AFTER THIS ONE
	  kgoto PLAY_A_NOTE				;GO STRAIGHT TO PLAYING THIS NEW NOTE


	 
	 ;RANDOM PICK (RANDOMLY CHOOSE ANY NOTE CURRENTLY BEING HELD)
	 elseif gkmode==4 then
	  kRndNdx	random	0,kNNotes		;CREATE RANDOM INDEX
	  knum		table	kRndNdx,giseqorder	;READ NOTE FROM NOTE LIST USING RANDOM INDEX
	  knum	=	knum+(gkintvl*kcycle)
	  if kndx==kNNotes-1 then
	   kcount2	=	kcount2 + 1
	   if gkCyUpDn==0 then
	    kcycle	wrap	kcount2,0,gkcycles+1
	   else
	    kcycle	mirror	kcount2,0,gkcycles
	   endif
	  endif
	  kndx	wrap	kndx+1,0,kNNotes		;INCREMENT THE COUNTER BUT WRAP IT AROUND IF IT STRAYS BEYOND THE VALUE CORRESPONDING TO THE NUMBER OF NOTES BEING HELD (I.E. THE LENGTH OF THE SEQUENCE)
	  kgoto	PLAY_A_NOTE				;GO STRAIGHT TO PLAYING THIS NEW NOTE


	
	 ;SEQUENCE PLAY (PLAYS NOTES IN THE ORDER IN WHICH THEY WERE ORIGINALLY PLAYED)
	 else
	  knum	table	kndx,giseqorder			;READ NOTE VALUE FROM TABLE
	  if gkcycles!=0 then
	   knum	=	knum+(gkintvl*kcycle)
	  endif	
	  if kndx==kNNotes-1 then
	   kcount2	=	kcount2 + 1
	   if gkCyUpDn==0 then
	    kcycle	wrap	kcount2,0,gkcycles+1
	   else
	    kcycle	mirror	kcount2,0,gkcycles
	   endif
	  endif
	  kndx	wrap	kndx+1,0,kNNotes		;INCREMENT THE COUNTER BUT WRAP IT AROUND IF IT STRAYS BEYOND THE VALUE CORRESPONDING TO THE NUMBER OF NOTES BEING HELD (I.E. THE LENGTH OF THE SEQUENCE) 
	  kgoto PLAY_A_NOTE				;GO STRAIGHT TO PLAYING THIS NEW NOTE
	 endif
	endif
	
	
	
	
	
	PLAY_A_NOTE:
	if gkmode==3&&ktrigger==1 then			;IF RANDOM DIRECTION MODE HAS BEEN CHOSEN, CHOOSE A NEW RANDOM DIRECTION FOR THE NEXT STEP 
	 kdir	random	0,1.999999			;
	 kdir	=	(int(kdir)*2)-1			;kdir WILL BE EITHER -1 OR 1
	endif

	;PORTAMENTO ADDED TO NOTE NUMBER CHANGES
	kporttime	linseg	0,0.001,0.1
	knum2		portk	knum+ktrans,kporttime*gkNotePort
	kcps		limit	cpsmidinn(knum2),0,10000
	kAmpScale	table	kcps,giFletcherMunsonCurve
	
	a1	vco2	gkSynLev*kAmpScale,kcps,4,0.5		;TRIANGLE WAVE OSCILLATOR
	a2	vco2	gkSynLev*kAmpScale,kcps,2,0.5		;SQUARE WAVE OSCILLATOR
	a3	vco2	gkSynLev*kAmpScale,kcps,0,0.5		;SAWTOOTH WAVE OSCILLATOR
  	a4	pinkish	gkSynLev				;PINK NOISE
	
	ifadecurve	ftgenonce	0,0,1024,20,2		;HANNING WINDOW USED FOR THE CROSSFADING CURVES
	kamp1	table	((gkwave/3)*1.5)+0.5,ifadecurve,1	;TRIANGLE WAVE AMPLITUDE CONTROL EACH OF THE AMPLITUDES ARE OFFSET WITH RESPECT TO EACH OTHER. NOTE THAT IF INDEX IS LESS THAN 0 IT WILL ACTUALLY HOLD READING AT ZERO IF ITS GREATER THAN '1' IT WILL HOLD AT 1
	kamp2	table	((gkwave/3)*1.5),ifadecurve,1		;SQUARE WAVE AMPLITUDE CONTROL
	kamp3	table	((gkwave/3)*1.5)-0.5,ifadecurve,1	;SAW WAVE AMPLITUDE CONTROL
	kamp4	table	((gkwave/3)*1.5)-1,ifadecurve,1		;PINK NOISE AMPLITUDE CONTROL
	aamp1	interp	kamp1
	aamp2	interp	kamp2
	aamp3	interp	kamp3
	aamp4	interp	kamp4
	a1	sum	a1*aamp1,a2*aamp2,a3*aamp3,a4*aamp4
	
	if ktrigger==1 then
	 reinit RETRIGGER_ENVELOPES
	endif
	RETRIGGER_ENVELOPES:
	;FILTER ENVELOPE
	iatt	=	i(gkatt)
	idec	=	i(gkdec)
	isus	=	i(gksus)
	irel	=	i(gkrel)
	isustim	=	abs((1/i(gkrate))-iatt-irel)+0.0001	;DERIVE SUSTAIN TIME FROM ARPEGGIATOR RATE AND THE OTHER ENVELOPE SEGMENT DURATIONS
	kfenv	linsegr	0,iatt,1,idec,0,isustim,0,irel,0	;FILTER ENVELOPE
	kfenv	=	(kfenv*(1-gksus))+gksus
	;AMPLITUDE ENVELOPE
	if gkAatt+gkAdec=0.002&&gkAsus==1 kgoto SKIP_AMP_ENV	;IF ATTACK AND/OR DECAY TIME ARE AT THEIR MINIMUM SETTINGS AND SUSTAIN LEVEL IS MAXIMUM IGNORE AMPLITUDE ENVELOPE CREATION AND IMPLEMENTATION - I.E. WE WIL HAVE SIMPLY A SUSTAINING INSTRUMENT  
	iAatt	=	i(gkAatt)
	iAdec	=	i(gkAdec)
	iAsus	=	i(gkAsus)
	iArel	=	i(gkArel)	
	iAsustim	=	abs((1/i(gkrate))-iAatt-iArel)+0.0001	;DERIVE SUSTAIN TIME FROM ARPEGGIATOR RATE AND THE OTHER ENVELOPE SEGMENT DURATIONS
	kAenv	linsegr	0,iAatt,1,iAdec,i(gkAsus),iAsustim,i(gkAsus),iArel,0	;AMPLITUDE ENVELOPE
	a1	=	a1*kAenv
	SKIP_AMP_ENV:
	rireturn
	
	kLFO	lfo	gkLFOdep,gkLFOrate,0			;CREATE AN LFO. SINE WAVE SHAPE  
	kEnvAmt	portk	gkEnvAmt,kporttime
	kEnvAmt	limit	kEnvAmt+kLFO,0,1			;ADD LFO TO ENVELOPE AMOUNT VARIABLE AND LIMIT THE RESULT TO LIE WITHIN 0 AND 1
	
	if gkKybdTrk=0 then					;IF KEYBOARD TRACKING IS OFF...
	 ;NON-KEYBOARD TRACKING FILTER
	 kcfoct	=	((kfenv*8)+6)*(kEnvAmt^0.25)
	else							;OTHERWISE (KEYBOARD TRACKING IS OFF
	 ;KEYBOARD TRACKING FILTER
	 kcfoct	=	octcps(kcps)+((kfenv*7*(kEnvAmt^0.75))-2)	;KEYBOARD TRACKING
	endif
	
	kcf	limit	cpsoct(kcfoct),20,sr/3			;PROTECT AGAINST OUT OF RANGE FILTER VALUES	 

	kres	portk	gkres,kporttime				;SMOOTH CHANGES MADE TO RESONANCE SETTING
	if gkFiltType==0 then					;CHOOSE FILTER TYPE
	 kdist	portk	gkdist,kporttime			;SMOOTH CHANGES MADE TO DISTORTION SETTING
	 a1	lpf18	a1,kcf,kres*0.98, (kdist^2)*10		;LOWPASS
	 kdmp	scale	kdist^0.2,0.06,1			;CREATE A FUNCTION THAT WILL DAMPEN SIGNAL AMPLITUDE WHEN LOWPASS FILTER DISTORTION IS INCREASED
	 a1	=	a1*kdmp					;
	else
	 ;aflt	butbp	a1,kcf,kcf * (2-((kres^0.5)*1.9))	;BANDPASS
	 kcf	limit	kcf,20,sr*0.4
	 kbw	limit	(kcf*(kres^8))*0.7, 1, sr/4
	 aflt	rbjeq	a1,kcf,1,kbw,1,4;BANDPASS

	 a1	balance	aflt,a1/4,1				;EVEN OUT LEVEL OF FILTER OUTPUT SIGNAL TO COMPENSATE FOR SIGNAL POWER LOSS WHEN BANDWIDTH ('q') IS NARROW
	endif
	
	aenv	linsegr	0,0.001,1,0.005,0			;ANTI-CLICK ENVELOPE
	a1	=	a1*aenv					;APPLY ENVELOPE
	
	;EFFECT WET/DRY MIX CONSTRUCTION
	iWet	ftgentmp	0,0,512,-7,0,256,1,256,1	;RESCALING FUNCTION FOR WET LEVEL CONTROL
	iDry	ftgentmp	0,0,512,-7,1,256,1,256,0	;RESCALING FUNCTION FOR DRY LEVEL CONTROL
	kWet	table	gkDryWet, iWet, 1			;RESCALE WET LEVEL CONTROL ACCORDING TO FUNCTION TABLE iWet
	kDry	table	gkDryWet, iDry, 1			;RESCALE DRY LEVEL CONTROL ACCORDING TO FUNCTION TABLE iWet	
	gasendL	=	gasendL+a1*kWet
	gasendR	=	gasendR+a1*kWet
	if gkDelOnOff=1 then
	 a1	=	a1*kDry
	endif
	 	outs	a1,a1
	
endin


instr	ScanMIDI
	insno 	nstrnum "NoteLayer"
	kstatus, kchan, kdata1, kdata2  midiin; read in midi
	if kstatus==144 then
	 if kdata2>0 then					;IF VELOCITY IS GREATER THAN 0 (I.E. FOR SOME KEYBOARDS VELOCITY ZERO IS A NOTE OFF)
	  kAlreadyActiveStatus	table	kdata1,ginoteactive	;CHECK IF THIS NOTE IS ALREADY ACTIVE (POSSIBLE IF HOLD IS ON).
	  if kAlreadyActiveStatus==0 then			;IF THIS NOTE IS NOT ALREADY ACTIVE...
	   event "i",insno+(kdata1*0.001),0,3600,kdata1	;
	  endif
	 else
	  if gkhold==0 then
	   turnoff2	1+(kdata1*0.001),4,1
	  endif
	 endif
	elseif kstatus==128&&gkhold==0 then		;IF MIDI KEYBOARD USES NOTE OFF STATUS BYTE
	 turnoff2	1+(kdata1*0.001),4,1
	endif
	
endin


instr	MultiModeDelay
	iMaxRhyVal	=	32/1	;LONGEST POSSIBLE RHYTHMIC VALUE
	iMinRate	=	0.25	;MINIMUM POSSIBLE ARPEGGIATOR RATE
	iArpRhyVal	=	1/8	;VALUE OF ARPEGGIATOR DIVISION (1/8 = QUAVER/EIGHTH NOTE)
	iMaxDelay	=	(iMaxRhyVal*iArpRhyVal)/iMinRate

	kporttime	linseg	0,0.001,0.05
	;kcf	portk	cpsoct(gkDelTone),kporttime
	kcf	=	cpsoct(gkDelTone)
	kFBamt	portk	gkFBamt,kporttime
	
	if gkDelOnOff==0 kgoto SKIP		;IF DELAY ON/OFF BUTTON IS OFF SKIP ALL OF THE DELAY CODE 
	kptime	linseg	0,0.001,0.4		;CREATE A FUNCTION THAT RISES QUICKLY FROM ZERO TO A STEADY VALUE. THIS WILL BE USED FOR PORTAMENTO TIME
	if gkDelTimMode==1 then			;IF RHYTHMIC DELAY TIME MODE HAS BEEN CHOSEN...
	 kDelTim	=	(gkRhyNum)/(gkrate*gkRhyDen*iArpRhyVal)	;
	 kDelTim	limit	kDelTim,0,iMaxDelay	;PROTECT AGAINST OUT OF RANGE DELAY TIMES
	else
	 kDelTim	=	gkDelTim 	
	 kDelTim	limit	kDelTim,0,iMaxDelay
	endif
	
	kDelTim	portk	kDelTim,0.0001+kptime*gkDelTimPort
	aDelTim	interp	kDelTim
	
	if gkDelType==0 then	;SIMPLE STEREO DELAY
	 abuffer	delayr	iMaxDelay	;ESTABLISH LEFT CHANNEL BUFFER
	 aTapL	deltapi	aDelTim			;TAP LEFT CHANNEL BUFFER
	 aTapL	tone	aTapL,kcf		;LOWPASS FILTER
	 	delayw	gasendL+aTapL*kFBamt	;WRITE INTO LEFT CHANNEL BUFFER
	 abuffer	delayr	iMaxDelay       ;ESTABLISH RIGHT CHANNEL BUFFER 
	 aTapR	deltapi	aDelTim                 ;TAP RIGHT CHANNEL BUFFER       
	 aTapR	tone	aTapR,kcf               ;LOWPASS FILTER                
	 	delayw	gasendR+aTapR*kFBamt    ;WRITE INTO RIGHT CHANNEL BUFFER
	 	outs	aTapL,aTapR		;SEND LEFT AND RIGHT CHANNEL TAPS TO AUDIO OUTPUT
	
	else					;PING PONG DELAY
	 ;LEFT CHANNEL OFFSET / FIRST ECHO (NO FEEDBACK)
	 aL	vdelay	gasendL,aDelTim*1000,iMaxDelay*1000
	 aL	tone	aL,kcf			;LOWPASS FILTER
	 
	 abuffer	delayr	iMaxDelay*2	;ESTABLISH LEFT CHANNEL BUFFER
	 aTapL	deltapi	aDelTim * 2		;TAP LEFT CHANNEL BUFFER
 	 aTapL	tone	aTapL,kcf		;LOWPASS FILTER
	 	delayw	aL+aTapL*kFBamt		;WRITE INTO LEFT CHANNEL BUFFER
         
	 abuffer	delayr	iMaxDelay*2	;ESTABLISH RIGHT CHANNEL BUFFER
	 aTapR	deltapi	aDelTim * 2		;TAP RIGHT CHANNEL BUFFER
	 aTapR	tone	aTapR,kcf		;LOWPASS FILTER
	 	delayw	gasendR+aTapR*kFBamt	;WRITE INTO RIGHT CHANNEL BUFFER
	 	outs	aTapL+aL,aTapR		;SEND LEFT AND RIGHT CHANNEL TAPS AND LEFT CHANNEL INITIAL TAP TO AUDIO OUTPUT
	endif
	SKIP:
		clear	gasendL,gasendR		;CLEAR GLOBAL SEND AUDIO VARIABLES
endin

instr	ModifyGUI
	;DELAY TIME MODE SELECTION GUI MODIFICATIONS
	ktrig	changed	gkDelTimMode
	if ktrig==1 then
	 reinit update
	 update:
	 if i(gkDelTimMode)==0 then
	  FLhide gihRhyNum
	  FLhide gihRhyDen
	  FLhide gihRhyLabel
	  FLshow gihDelTim
	 else
	  FLhide gihDelTim
	  FLshow gihRhyNum
	  FLshow gihRhyDen
	  FLshow gihRhyLabel
	 endif
	 rireturn
	endif 	

	;FILTER TYPE SELECTION GUI MODIFICATIONS
	ktrig	changed	gkFiltType
	if ktrig==1 then
	 reinit update2
	 update2:
	 if i(gkFiltType)==0 then
	  FLsetText "     ", gihres
	  FLsetText "Res.", gihres
	  FLshow gihdist
	 else
	  FLhide gihdist
	  FLsetText "     ", gihres
	  FLsetText "Q", gihres
	 endif
	 rireturn
	endif 	

	;ARPEGGIO RATE MODE SELECTION GUI MODIFICATIONS
	ktrig	changed	gkRateMode
	if ktrig==1 then
	 reinit update3
	 update3:
	 if i(gkRateMode)==0 then
	  FLshow gihrate
	  FLshow gidrate
	  FLhide gihtempo
	  FLhide gihTempoMlt
	  FLhide gih1
	  FLhide gih2
	  FLhide gih3
	  FLhide gih4
	  FLhide gih5
	  FLhide gih6
	  FLhide gih7
	  FLhide gih8
	 else
	  FLshow gihtempo
	  FLshow gihTempoMlt
	  FLshow gih1
	  FLshow gih2
	  FLshow gih3
	  FLshow gih4
	  FLshow gih5
	  FLshow gih6
	  FLshow gih7
	  FLshow gih8
	  FLhide gihrate
	  FLhide gidrate
	 endif
	 rireturn
	endif 	


	;MODULATION VIEW CHANGES
	ktrig	changed	gkModView
	if ktrig==1 then
	 reinit update4
	 update4:
	 if i(gkModView)==0 then
	  FLhide gihEnvAmt
	  FLhide gihatt
	  FLhide gihdec
	  FLhide gihsus
	  FLhide gihrel
	  FLhide gihres
	  FLhide gihdist
	  FLhide gihLFOdep
	  FLhide gihLFOrate
	  FLshow gihAatt
	  FLshow gihAdec
	  FLshow gihAsus
	  FLshow gihArel
	 elseif i(gkModView)==1 then
	  FLhide gihAatt
	  FLhide gihAdec
	  FLhide gihAsus
	  FLhide gihArel
	  FLhide gihLFOdep
	  FLhide gihLFOrate
	  FLshow gihEnvAmt
	  FLshow gihatt
	  FLshow gihdec
	  FLshow gihsus
	  FLshow gihrel
	  FLshow gihres
	  if i(gkFiltType)==0 then
	   FLshow gihdist
	  endif
	 else
	  FLhide gihEnvAmt
	  FLhide gihatt
	  FLhide gihdec
	  FLhide gihsus
	  FLhide gihrel
	  FLhide gihres
	  FLhide gihdist
	  FLhide gihAatt
	  FLhide gihAdec
	  FLhide gihAsus
	  FLhide gihArel
	  FLshow gihLFOdep
	  FLshow gihLFOrate	  
	 endif
	 rireturn
	endif

	ktrig	changed	gkintvl
	if ktrig==1 then
	 reinit update5
	 update5:
	 if i(gkintvl)==0 then
	  FLhide gihcycles
	 else
	  FLshow gihcycles
	 endif
	 rireturn
	endif

	ktrig	changed	gkmode
	if ktrig==1 then
	 reinit update7
	 update7:
	 if i(gkmode)==3 then
	  FLhide gihCyUpDn
	 else
	  FLshow gihCyUpDn
	 endif
	 rireturn
	endif

	ktrig	changed	gkintvl,gkcycles
	if ktrig==1 then
	 reinit update6
	 update6:
	 if i(gkintvl)==0||i(gkcycles)<2 then
	  FLhide gihCyUpDn
	 elseif gkcycles>1 then
	  FLshow gihCyUpDn
	 endif
	 rireturn
	endif


endin     



</CsInstruments>

<CsScore>
i "ScanMIDI" 0 3600		;SCANS FOR MIDI NOTE EVENTS
i "MultiModeDelay" 0 3600	;DELAY INSTRUMENT PLAYS A LONG NOTE AND KEEPS PERFORMANCE GOING
i "ModifyGUI" 0 3600		;INSTRUMENT THAT MODIFYS GUI WHENEVER CERTAIN OPTIONS ARE CHOSEN USING GUI BUTTON BANKS 
</CsScore>

</CsoundSynthesizer>