;Written by Iain McCurdy, 2009

<CsoundSynthesizer>

<CsOptions>
;COMMENT/UNCOMMENT AS REQUIRED
;-odevaudio -idevaudio -M0 -b400				;EXTERNAL MIDI CONTROL
-odevaudio -idevaudio -M0 -+rtmidi=virtual -b400	;VIRTUAL MIDI CONTROL
;-odevaudio -idevaudio -b400				;NO MIDI
</CsOptions>

<CsInstruments>

sr 		= 	44100	;SAMPLE RATE
kr 		= 	4410	;CONTROL RATE
ksmps 		= 	10	;NUMBER OF AUDIO SAMPLES IN EACH CONTROL CYCLE
nchnls 		= 	2	;NUMBER OF CHANNELS (2=STEREO)

;FLTK INTERFACE CODE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
FLcolor	255, 255, 255, 0, 0, 0	;SET INTERFACE COLOURS
;					LABEL   | WIDTH | HEIGHT | X | Y
				FLpanel	"sndloop",   500,  250,    0,  0

;BUTTONS						ON | OFF | TYPE | WIDTH | HEIGHT | X | Y | OPCODE | INS | STARTTIM | IDUR
gktrig,ihtrig	FLbutton	"Rec-Play/Stop",	1,   0,     22,    140,     25,     5,  5,    0,      2,     0,       0.01
gkmute,ihmute	FLbutton	"Mute Live Input",	1,   0,     22,    140,     25,   150,  5,    -1
gkrec,gihrec	FLbutton	"RECORDING",		1,   0,      1,     90,     25,   405,  5,    -1
FLsetColor2	255, 255, 50, ihtrig	;SET SECONDARY COLOUR TO YELLOW
FLsetColor2	255, 255, 50, ihmute	;SET SECONDARY COLOUR TO YELLOW
;		RED | GREEN | BLUE | HANDLE
FLsetColor2	255,     0,     0,   gihrec	;SET SELECTION COLOUR OF WIDGET. IN THIS CASE 'RED'
;		RED | BLUE | GREEN | HANDLE
FLsetTextColor	255,   255,   255,   gihrec	;SET COLOUR OF WIDGET LABEL. IN THIS CASE 'WHITE' - THE SAME COLOUR AS THE WIDGET AND THEREFORE INVISIBLE

;VALUE DISPLAY BOXES			LABEL  | WIDTH | HEIGHT | X | Y
iddur				FLvalue	" ",       70,    15,     5,  75
idpitch				FLvalue	" ",      100,    20,     5, 125
idfad				FLvalue	" ",      100,    20,     5, 175
idInGain			FLvalue	" ",      100,    20,     5, 225

;SLIDERS					            				MIN | MAX | EXP | TYPE |    DISP | WIDTH | HEIGHT | X | Y
gkdur, ihdur			FLslider 	"Duration of Recording (seconds)",	0,     10,   0,    23,     iddur,   490,     25,    0,  50
gkpitch, gihpitch		FLslider 	"Pitch (ratio)",			-4,     4,   0,    23,   idpitch,   490,     25,    0, 100
gkfad, ihfad			FLslider 	"Crossfade (seconds)",			0,      5,   0,    23,     idfad,   490,     25,    0, 150
gkInGain, ihInGain		FLslider 	"Input Gain",				0,      1,   0,    23,  idInGain,   490,     25,    0, 200

;SET INITIAL VALUES OF FLTK VALUATORS		VALUE | HANDLE
				FLsetVal_i	3, 	ihdur
				FLsetVal_i	1, 	gihpitch
				FLsetVal_i	0, 	ihfad
				FLsetVal_i	1, 	ihmute
				FLsetVal_i	0.5, 	ihInGain

				FLpanel_end

;INSTRUCTIONS AND INFO PANEL
				FLpanel	" ", 500, 480, 512, 0
;TEXT BOXES												TYPE | FONT | SIZE | WIDTH | HEIGHT | X | Y
ih		 	FLbox  	"                          sndloop                            ", 	1,      5,     14,    490,    15,     5,   0
ih		 	FLbox  	"-------------------------------------------------------------", 	1,      5,     14,    490,    15,     5,  20
ih		 	FLbox  	"'sndloop' is an opcode that offers a straightforward method  ", 	1,      5,     14,    490,    15,     5,  40
ih		 	FLbox  	"of sampling some live audio and immediately playing it back  ", 	1,      5,     14,    490,    15,     5,  60
ih		 	FLbox  	"in a loop with pitch control.                                ", 	1,      5,     14,    490,    15,     5,  80
ih		 	FLbox  	"The duration of the recording to be undertaken must be       ", 	1,      5,     14,    490,    15,     5, 100
ih		 	FLbox  	"defined before recording is activated.                       ", 	1,      5,     14,    490,    15,     5, 120
ih		 	FLbox  	"A crossfade time can be defined which will create a crossfade", 	1,      5,     14,    490,    15,     5, 140
ih		 	FLbox  	"between the end and the beginning of the loop which may      ", 	1,      5,     14,    490,    15,     5, 160
ih		 	FLbox  	"smooth the transition between the end and the beginning of   ", 	1,      5,     14,    490,    15,     5, 180
ih		 	FLbox  	"the loop and therefore prevent clicks.                       ", 	1,      5,     14,    490,    15,     5, 200
ih		 	FLbox  	"In addition to the audio output from the opcode there is a   ", 	1,      5,     14,    490,    15,     5, 220
ih		 	FLbox  	"k-rate switch which indicates when recording has begun and   ", 	1,      5,     14,    490,    15,     5, 240
ih		 	FLbox  	"then when playback begins. In this example, this variable is ", 	1,      5,     14,    490,    15,     5, 260
ih		 	FLbox  	"used to activate the red 'RECORDING' indicator.              ", 	1,      5,     14,    490,    15,     5, 280
ih		 	FLbox  	"Negative values for 'Pitch' result in reverse playback.      ", 	1,      5,     14,    490,    15,     5, 300
ih		 	FLbox  	"This instrument also allows the user to shift the pitch of   ", 	1,      5,     14,    490,    15,     5, 320
ih		 	FLbox  	"the loop by playing keys on a connected MIDI keyboard.       ", 	1,      5,     14,    490,    15,     5, 340
ih		 	FLbox  	"The 'Input Gain' control controls the level of audio reaching", 	1,      5,     14,    490,    15,     5, 360
ih		 	FLbox  	"the sndloop opcode therefore must be greater than zero.      ", 	1,      5,     14,    490,    15,     5, 380
ih		 	FLbox  	"When not in playback mode after recording the sndloop opcode ", 	1,      5,     14,    490,    15,     5, 400
ih		 	FLbox  	"normally outputs the audio reaching its input, if you wish to", 	1,      5,     14,    490,    15,     5, 420
ih		 	FLbox  	"mute live audio while recording (and also before recording   ", 	1,      5,     14,    490,    15,     5, 440
ih		 	FLbox  	"has first taken place) activate the 'Mute Live Input' button.", 	1,      5,     14,    490,    15,     5, 460

				FLpanel_end

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

instr	1	;MIDI ACTIVATED INSTRUMENT - READS MIDI NOTE VALUES
	icps	cpsmidi		;READ PITCH VALUES (IN HERTZ) FROM A CONNECTED MIDI KEYBOARD
	ifreqratio	=	icps/261.626	;DERIVE A FREQUENCY RATI0 (BASE FREQUENCY IS MIDDLE C)
	FLsetVal_i	ifreqratio, gihpitch	;SEND FRQUENCY RATIO VALUE TO 'Pitch' FADER.
	gkpitch	init	ifreqratio	;SET gkpitch TO ifreqratio.
endin

instr	2	;RESTARTS INSTR 2 WHEN RECORD-PLAY/STOP IS PRESSED
	turnon	3
endin

instr	3	;SOUND PRODUCING INSTRUMENT
	krecflag	init	0
	ain	inch	1	;READ AUDIO FROM LIVE INPUT CHANNEL 1
	asig, krec sndloop ain*gkInGain, gkpitch, gktrig, i(gkdur), i(gkfad)
	kupdate	changed	krec	;IF krec CHANGES, (I.E. STATE CHANGES FROM RECORDING TO PLAYBACK), kupdate WILL BE MOMENTARILY 1 
	FLsetVal	kupdate, krec, gihrec	;UPDATE 'RECORDING' INDICATOR
	krecflag	max	krec, krecflag
	if	gkmute=1 then
		if	krecflag=1&&krec=0	then
			outs	asig, asig	;SEND AUDIO TO OUTPUT
		endif
	else
		outs	asig, asig	;SEND AUDIO TO OUTPUT
	endif
endin

</CsInstruments>                         
                                         
<CsScore>
;INSTR | START | DURATION                
i  2       0      3600	;INSTRUMENT PLAYS FOR 1 HOUR (AND SUSTAINS REALTIME PERFORMANCE)                    
</CsScore>                               
                                         
</CsoundSynthesizer>