;WRITTEN BY IAIN MCCURDY 2010

<CsoundSynthesizer>

<CsOptions>
-odevaudio -b400 -d -m0
</CsOptions>

<CsInstruments>
sr 	=	44100
ksmps 	=	1
nchnls 	=	2
0dbfs	=	1	;MAXIMUM AMPLITUDE REGARDLESS OF BIT DEPTH

;FLTK INTERFACE CODE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
FLcolor	255, 255, 255, 0, 0, 0
;			LABEL           | WIDTH | HEIGHT | X | Y
	FLpanel	"Shuffle Table Contents",  500,    100,    0,  0

;SWITCHES                                			ON | OFF | TYPE | WIDTH | HEIGHT | X | Y | OPCODE | INS | STARTTIM | DUR
gkShuffle,ihShuffle		FLbutton	"Shuffle",	1,    0,    21,    120,     30,    5,  5,     0,      1,      0,      0.1
gkRetrograde,ihRetrograde	FLbutton	"Retrograde",	1,    0,    21,    120,     30,  130,  5,     0,      5,      0,      0.1
gkPlay,ihPlay			FLbutton	"Play",		1,    0,    21,    120,     30,  255,  5,     0,      3,      0,      0.1

;TEXT BOXES			MIN | MAX | STEP | TYPE | WIDTH | HEIGHT | X  | Y
gk1,  gih1	FLtext	"1", 	8,     9,    0,     1,      35,     20,   50,  50
gk2,  gih2	FLtext	"2", 	8,     9,    0,     1,      35,     20,   85,  50
gk3,  gih3	FLtext	"3", 	8,     9,    0,     1,      35,     20,  120,  50
gk4,  gih4	FLtext	"4", 	8,     9,    0,     1,      35,     20,  155,  50
gk5,  gih5	FLtext	"5", 	8,     9,    0,     1,      35,     20,  190,  50
gk6,  gih6	FLtext	"6", 	8,     9,    0,     1,      35,     20,  225,  50
gk7,  gih7	FLtext	"7", 	8,     9,    0,     1,      35,     20,  260,  50
gk8,  gih8	FLtext	"8", 	8,     9,    0,     1,      35,     20,  295,  50
gk9,  gih9	FLtext	"9", 	8,     9,    0,     1,      35,     20,  330,  50
gk10, gih10	FLtext	"10", 	8,     9,    0,     1,      35,     20,  365,  50
gk11, gih11	FLtext	"11", 	8,     9,    0,     1,      35,     20,  400,  50
gk12, gih12	FLtext	"12", 	8,     9,    0,     1,      35,     20,  435,  50

;TEXT BOXES					TYPE | FONT | SIZE | WIDTH | HEIGHT | X |  Y
ih		 	FLbox  	"Items", 	1,       5,    14,     50,     20,    0,   50

FLpanel_end

;INSTRUCTIONS AND INFO PANEL
				FLpanel	" ", 512, 540, 510, 0
				FLscroll     512, 540, 0, 0
;TEXT BOXES												TYPE | FONT | SIZE | WIDTH | HEIGHT | X | Y
ih		 	FLbox  	"                 Shuffle Table Contents                      ", 	1,      5,     14,    490,    20,     5,   0
ih		 	FLbox  	"-------------------------------------------------------------", 	1,      5,     14,    490,    20,     5,  20
ih		 	FLbox  	"This example shuffles the contents of a function table in a  ", 	1,      5,     14,    490,    20,     5,  40
ih		 	FLbox  	"fashion similar to shuffling a deck of cards.                ", 	1,      5,     14,    490,    20,     5,  60
ih		 	FLbox  	"The table's contents in this example are the notes of a      ", 	1,      5,     14,    490,    20,     5,  80
ih		 	FLbox  	"chromatic scale in pch format. Each time the 'Shuffle' button", 	1,      5,     14,    490,    20,     5, 100
ih		 	FLbox  	"is clicked the order of these twelve items is changed. The   ", 	1,      5,     14,    490,    20,     5, 120
ih		 	FLbox  	"new table is printed to the terminal and to the FL boxes and ", 	1,      5,     14,    490,    20,     5, 140
ih		 	FLbox  	"can be played as a note row by clicking 'Play'.              ", 	1,      5,     14,    490,    20,     5, 160
ih		 	FLbox  	"Table shuffling is achieved by generating a random number to ", 	1,      5,     14,    490,    20,     5, 180
ih		 	FLbox  	"be used as a table index. The value at this table index is   ", 	1,      5,     14,    490,    20,     5, 200
ih		 	FLbox  	"read. Values are written into a buffer table but before this ", 	1,      5,     14,    490,    20,     5, 220
ih		 	FLbox  	"is done a checking procedure is executed that checks whether ", 	1,      5,     14,    490,    20,     5, 240
ih		 	FLbox  	"this value has already been chosen (this ensures that each   ", 	1,      5,     14,    490,    20,     5, 260
ih		 	FLbox  	"item occurs in the new table only once). Once a value has    ", 	1,      5,     14,    490,    20,     5, 280
ih		 	FLbox  	"been accepted and written into the buffer table. The process ", 	1,      5,     14,    490,    20,     5, 300
ih		 	FLbox  	"is repeated to find the next value for the buffer table. To  ", 	1,      5,     14,    490,    20,     5, 320
ih		 	FLbox  	"carry out the entire process a number of k-rate loops are    ", 	1,      5,     14,    490,    20,     5, 340
ih		 	FLbox  	"employed with counter varibles being used to check when the  ", 	1,      5,     14,    490,    20,     5, 360
ih		 	FLbox  	"various iterative procedures are complete.                   ", 	1,      5,     14,    490,    20,     5, 380
ih		 	FLbox  	"To allow the use of items of the same value in the table the ", 	1,      5,     14,    490,    20,     5, 400
ih		 	FLbox  	"process is actually carried out on a table of indices (1, 2, ", 	1,      5,     14,    490,    20,     5, 420
ih		 	FLbox  	"3...) so that the checking procedure described above can     ", 	1,      5,     14,    490,    20,     5, 440
ih		 	FLbox  	"still be carried out. A buffer table of the new arrangement  ", 	1,      5,     14,    490,    20,     5, 460
ih		 	FLbox  	"of items is created from this table of jumbled indices and   ", 	1,      5,     14,    490,    20,     5, 480
ih		 	FLbox  	"finally written over the original table.                     ", 	1,      5,     14,    490,    20,     5, 500
ih		 	FLbox  	"As an additional feature the user can perform a retrograde on", 	1,      5,     14,    490,    20,     5, 520
ih		 	FLbox  	"the table's contents which reverses their order.             ", 	1,      5,     14,    490,    20,     5, 540

FLscroll_end
FLpanel_end                                                                                       

FLrun	;RUN THE FLTK WIDGET THREAD
;END OF FLTK INTERFACE CODE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

giTable		ftgen	0,0,-12,-2, 8.00, 8.01, 8.02, 8.03, 8.04, 8.05, 8.06, 8.07, 8.08, 8.09, 8.10, 8.11	;CHROMATIC SCALE - 12 ITEMS - NEGATIVE TABLE SIZE PERMITS THE USE OF NON-ZERO TABLE SIZE
gisine		ftgen	0, 0, 4096, 10, 1	;A SINE WAVE

instr	1	;SHUFFLE TABLE CONTENTS
	iNumItems	=	ftlen(giTable)		;DERIVE THE NUMBER OF ITEMS IN THE FUNCTION TABLE
	iIndices	ftgen	0,0,-12,-2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12	;TABLE OF INDEX VALUES (+1) - SHOULD CORRESPOND TO THE NUMBER OF ITEMS IN THE ORIGINAL TABLE
	iIndicesBuffer	ftgen	0,0,-12,-2, 0						;BUFFER TABLE FOR JUMBLED UP INDICES
	iTableBuffer	ftgen	0,0,-12,-2, 0		;BUFFER TABLE INITIALLY CONSISTING OF ZEROES
	kcount 		init 	1	;INITIALISE COUNTER
	begin:				;LABEL
	kfn	random	0,iNumItems	;RANDOM TABLE ITEM INDEX
	kfn	=	int(kfn)	;CONVERT TO INTEGER (THIS STEP IS NOT ACTUALLY REQUIRED)
	krandval	table	kfn, iIndices	;READ THE VALUE AT THE RANDOMLY CHOSEN INDEX LOCATION
			;CHECK IF RANDOMLY CHOSEN ITEM HAS ALREADY BEEN CHOSEN AND INSERTED INTO NEW TABLE
			kcheckcount	=	1					;COUNTER USED THROUGHOUT CHECKING PROCESS
			checkbegin:							;LABEL - START OF CHECKING PROCESS
				kcheckval	table	kcheckcount-1, iIndicesBuffer	;READ VALUE FROM TABLE ACCORDING TO CURRENT checkcount CYCLE 
				if	(kcheckval=krandval)	kgoto	begin		;IF VALUE ALREADY EXISTS, REDO THE RANDOMIZATION PROCESS
				kcheckcount	=	kcheckcount + 1			;INCREMENT CHECK COUNTER
			if (kcheckcount < kcount) kgoto checkbegin			;UNTIL ALL VALUES HAVE BEEN TESTED REPEAT CHECK FOR NEXT VALUE
		tablew	krandval, kcount-1, iIndicesBuffer				;ONCE VALUE HAS BEEN VERIFIED WRITE TO TABLE 
	kcount = kcount + 1								;INCREMENT MAIN COUNTER
	if (kcount <= iNumItems) goto begin						;UNTIL TABLE IS FILLED REPEAT CYCLE
	
		;CREATE NEW TABLE IN THE BUFFER TABLE ACCORDING TO NEW ARRANGEMENT OF INDICES
	kcount	=	1								;SET COUNTER TO '1'
	begin2:										;BEGINNING OF LOOP LABEL
		kndx	table	kcount-1, iIndicesBuffer				;READ INDEX VALUE FROM TABLE OF INDICES BUFFER
		kval	table	kndx-1, giTable						;READ ITEM VALUE AT CURRENT INDEX LOCATION
		tablew	kval, kcount-1, iTableBuffer					;WRITE READ ITEM INTO TABLE BUFFER
		kcount = kcount + 1							;INCREMENT COUNTER
		if (kcount <= iNumItems) goto begin2					;UNTIL TABLE IS COMPLETELY WRITTEN REPEAT CYCLE
			
	tablecopy	giTable, iTableBuffer 						;REPLACE ORIGINAL TABLE WITH BUFFER (SHUFFLED) TABLE
	event	"i", 2, 0, 0.1								;PRINT TABLE VALUES
	turnoff										;WHEN DONE, TURN OFF THIS INSTRUMENT
endin

instr	2	;PRINT TABLE VALUES TO COMMAND LINE AND FL BOXES
	iNumItems	=	ftlen(giTable)		;DERIVE THE NUMBER OF ITEMS IN THE FUNCTION TABLE
	prints "\\n"					;NEWLINE
	icount	init	1				;INITIALIZE COUNTER
	BEGIN:						;LABEL
		ival	table	icount-1, giTable       ;READ VALUE FROM TABLE
		print	ival				;PRINT READ VALUE
		icount	=	icount + 1		;INCREMENT COUNTER
		if	icount<=iNumItems goto BEGIN	;CHECK IF WE ARE AT THE LAST VALUE OF TABLE, IF NOT, REPEAT PRINT TASK

	;FLTK UPDATE
	;CREATE A MACRO TO REDUCE CODE REPETITION
#define	FLPRINT(N)
	#
	ipch$N	table	$N-1, giTable	;READ PITCH VALUES FROM TABLE
	FLsetVal_i	ipch$N, gih$N	;WRITE PITCH VALUES TO FL_TEXT BOXES
	#
	;EXECUTE MACRO MULTIPLE TIMES
	$FLPRINT(1)
	$FLPRINT(2)
	$FLPRINT(3)
	$FLPRINT(4)
	$FLPRINT(5)
	$FLPRINT(6)
	$FLPRINT(7)
	$FLPRINT(8)
	$FLPRINT(9)
	$FLPRINT(10)
	$FLPRINT(11)
	$FLPRINT(12)
	
	turnoff		;TURN THIS INSTRUMENT OFF
endin

instr	3	;TRIGGER NOTES IN SOUND GENERATING INSTRUMENT
	iNumItems	=	ftlen(giTable)		;DERIVE THE NUMBER OF ITEMS IN THE FUNCTION TABLE
	icount	init	1
	igap	init	0.2
	iwhen	init	0	
	PLAYBEGIN:
		ipch	table	icount-1, giTable		;READ PITCH (pch FORMAT) FROM TABLE ACCORDING TO WHERE WE ARE IN THE SEQUENCE
		event_i		"i",4, iwhen, 0.6, ipch		;CREATE A NOTE EVENT TO BE PLAYED BY INSTR 3
		iwhen	=	iwhen + igap			;CREATE THE TIME THE NEXT NOTE WILL BE PLAYED
		igap	=	igap * 1.05			;GAP BETWEEN NOTES INCREASES AS WE PROGRESS RESULT IN A RALLENTANDO (SLOWING DOWN) AS THE SEQUENCE IS PLAYED
		icount = icount + 1
		if icount<=iNumItems goto PLAYBEGIN		;CHECK IF WE ARE AT THE LAST VALUE OF TABLE, IF NOT, REPEAT PRINT TASK
	
	turnoff		;TURN THIS INSTRUMENT OFF
endin

instr	4	;SOUND GENERATING INSTRUMENT
	aenv	line	0.2, p3, 0			;CREATE AN AMPLITUDE ENVELOPE
	a1	oscili	aenv, cpspch(p4), gisine	;GENERATE AN AUDIO SIGNAL (PITCH RECEIVED FROM INSTR 2 VIA p4)
	outs	a1, a1					;SEND AUDIO TO OUTPUTS
endin

instr	5	;PERFORM RETROGRADE
	iTableBuffer	ftgen	0,0,-12,-2, 0		;BUFFER TABLE INITIALLY CONSISTING OF ZEROES
	iNumItems	=	ftlen(giTable)		;DERIVE THE NUMBER OF ITEMS IN THE FUNCTION TABLE
	iTableBuffer	ftgen	0,0,-iNumItems,-2, 0		;BUFFER TABLE INITIALLY CONSISTING OF ZEROES
	kcount 		init 	1	;INITIALISE COUNTER
	begin:				;LABEL
		kval	table	iNumItems - kcount, giTable
		tablew	kval, kcount-1, iTableBuffer
	kcount = kcount + 1								;INCREMENT MAIN COUNTER
	if (kcount <= iNumItems) goto begin						;UNTIL TABLE IS FILLED REPEAT CYCLE
			
	tablecopy	giTable, iTableBuffer 						;REPLACE ORIGINAL TABLE WITH BUFFER (SHUFFLED) TABLE
	event	"i", 2, 0, 0.1								;PRINT TABLE VALUES
	turnoff										;WHEN DONE, TURN OFF THIS INSTRUMENT
endin

</CsInstruments>

<CsScore>
i 2 0 0.001
f 0 3600
</CsScore>

</CsoundSynthesizer>