;Written by Iain McCurdy, 2007

<CsoundSynthesizer>

<CsOptions>
-idevaudio -odevaudio -b200 -Ma -+rtmidi=virtual
;DISABLE VIRTUAL MIDI FOR EXTERNAL MIDI CONTROL
</CsOptions>

<CsInstruments>

sr	= 	44100
ksmps	= 	100
nchnls	= 	2
0dbfs	=	1	;MAXIMUM SOUND INTENSITY LEVEL REGARDLESS OF BIT DEPTH

;FLTK INTERFACE CODE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
FLcolor	255, 255, 255, 0, 0, 0
;		LABEL     | WIDTH | HEIGHT | X | Y
	FLpanel	"pvscale",   500,    420,    0,  0

;BORDERS				TYPE | FONT | SIZE | WIDTH | HEIGHT | X | Y
ih		 	FLbox  	" ", 	6,      9,     15,    490,    130,    5, 280	;BORDER AROUND FFT ATTRIBUTES

;SWITCHES                                            			ON | OFF | TYPE | WIDTH | HEIGHT | X  | Y | OPCODE | INS | STARTTIM | DUR	p4	p5	p6	p7	p8	p9	p10	p11	p12	p13	p14	p15	p16	p17	p18	p19	p20	p21	p22	p23	p24	p25	p26	p27	p28	p29	p30	p31	p32	p33
gkFLTK_MIDI,ihFLTK_MIDI		FLbutton	"FLTK/MIDI",		1,    0,    22,    120,     25,    5,    5,    0,     2,      0,      3600
FLsetColor2	255, 255, 50, ihFLTK_MIDI	;SET SECONDARY COLOUR TO YELLOW

;VALUE DISPLAY BOXES		LABEL | WIDTH | HEIGHT | X | Y
idscal			FLvalue	" ",	 80,      20,    5, 125
idgain			FLvalue	" ",	 80,      20,    5, 175

;SLIDERS				            		MIN   | MAX | EXP | TYPE |  DISP   | WIDTH | HEIGHT | X  | Y
gkscal, ihscal		FLslider 	"Frequency Rescale",	.125,    8,   -1,    23,   idscal,    490,     25,    5,  100
gkgain, ihgain		FLslider 	"Gain Rescale",		0,      20,    0,    23,   idgain,    490,     25,    5,  150

;GENERAL_TEXT_SETTINGS			SIZE | FONT |  ALIGN | RED | GREEN | BLUE
			FLlabel		13,      1,       1,   255,   255,   255		;NUMBERS MADE INVISIBLE

;BUTTON BANKS			   			TYPE | NUMX | NUMY | WIDTH | HEIGHT | X  | Y | OPCODE
gkkeepform,   ihkeepform		FLbutBank	14,     1,     3,     18,      60,   200,   0,   -1
gkinput,   ihinput			FLbutBank	14,     1,     3,     30,      75,     5, 202,   -1
gkFFTattributes, ihFFTattributes	FLbutBank	14,     1,     4,     18,      78,   120, 320,   -1

;GENERAL_TEXT_SETTINGS			SIZE | FONT |  ALIGN | RED | GREEN | BLUE
			FLlabel		13,      5,      4,     0,     0,     0			;LABELS MADE VISIBLE AGAIN

;TEXT BOXES										TYPE | FONT | SIZE | WIDTH | HEIGHT | X |  Y
ih		 	FLbox  	"Live Input", 						1,       5,    11,    70,      25,   32,  202
ih		 	FLbox  	"Voice     ", 						1,       5,    11,    70,      25,   32,  227
ih		 	FLbox  	"Drum Loop ", 						1,       5,    11,    70,      25,   32,  252
ih		 	FLbox  	"FFT Attributes",       				1,       4,    14,   100,      25,   15,  285
ih		 	FLbox  	"FFT Size - Overlap - Window Size - Window Type",	1,       5,    11,    340,      20,  140,  300
ih		 	FLbox  	"  512        256        1024            1     ",	1,       5,    11,    340,      20,  140,  318
ih		 	FLbox  	" 1024        256        1024            1     ",	1,       5,    11,    340,      20,  140,  338
ih		 	FLbox  	" 2048        128        2048            1     ",	1,       5,    11,    340,      20,  140,  358
ih		 	FLbox  	" 4096        128        4096            1     ",	1,       5,    11,    340,      20,  140,  378
ih		 	FLbox  	"Do not preserve formants       ",			1,       5,    12,    230,      20,  220,    0
ih		 	FLbox  	"Impose original amplitudes     ",			1,       5,    12,    230,      20,  220,   20
ih		 	FLbox  	"Keep original spectral envelope",			1,       5,    12,    230,      20,  220,   40

;SET INITIAL VALUES FOR SLIDERS 	|VALUE | HANDLE
			FLsetVal_i	1, 	ihscal
			FLsetVal_i	1, 	ihgain
			FLsetVal_i	0, 	ihkeepform
			FLsetVal_i	1, 	ihinput
			FLsetVal_i	1, 	ihFFTattributes

			FLpanel_end

;INSTRUCTIONS AND INFO PANEL                 WIDTH | HEIGHT | X | Y
				FLpanel	" ", 500,     500,   512, 0
;TEXT BOXES												TYPE | FONT | SIZE | WIDTH | HEIGHT | X | Y
ih		 	FLbox  	"                           pvscale                           ", 	1,      5,     14,    490,    15,     5,  0
ih		 	FLbox  	"-------------------------------------------------------------", 	1,      5,     14,    490,    15,     5,  20
ih		 	FLbox  	"The opcode pvscale performs rescaling of the frequency values", 	1,      5,     14,    490,    15,     5,  40
ih		 	FLbox  	"of an f-signal. If the 'Frequency Rescale' slider is given a ", 	1,      5,     14,    490,    15,     5,  60
ih		 	FLbox  	"value of 2, frequency values will be transposed up by one    ", 	1,      5,     14,    490,    15,     5,  80
ih		 	FLbox  	"octave, if it is given a value of .5, frequency values will  ", 	1,      5,     14,    490,    15,     5, 100
ih		 	FLbox  	"be transposed down 1 octave and so on.                       ", 	1,      5,     14,    490,    15,     5, 120
ih		 	FLbox  	"Pvscale also offers three transposition modes of dealing with", 	1,      5,     14,    490,    15,     5, 140
ih		 	FLbox  	"formants of the original spectrum. This is an optional       ", 	1,      5,     14,    490,    15,     5, 160
ih		 	FLbox  	"argument and it defaults to 0. In mode 0 no attempt is made  ", 	1,      5,     14,    490,    15,     5, 180
ih		 	FLbox  	"to retain formants. In mode 1 formants are retained by       ", 	1,      5,     14,    490,    15,     5, 200
ih		 	FLbox  	"imposing the original amplitude values. In mode 2 formants   ", 	1,      5,     14,    490,    15,     5, 220
ih		 	FLbox  	"are retained through filtering the output according to the   ", 	1,      5,     14,    490,    15,     5, 240
ih		 	FLbox  	"spectral envelope of the original signal.                    ", 	1,      5,     14,    490,    15,     5, 260
ih		 	FLbox  	"A variety of combination of FFT analysis attributes are      ", 	1,      5,     14,    490,    15,     5, 280
ih		 	FLbox  	"selectable using radio button selectors. It can be observed  ", 	1,      5,     14,    490,    15,     5, 300
ih		 	FLbox  	"that smaller FFT size and window sizes results in less time  ", 	1,      5,     14,    490,    15,     5, 320
ih		 	FLbox  	"smearing but greater harmonic distortion whereas larger FFT  ", 	1,      5,     14,    490,    15,     5, 340
ih		 	FLbox  	"sizes and window sizes results in greater time smearing but  ", 	1,      5,     14,    490,    15,     5, 360
ih		 	FLbox  	"less harmonic distortion.                                    ", 	1,      5,     14,    490,    15,     5, 380
ih		 	FLbox  	"This example can also be activated from a MIDI keyboard (if  ", 	1,      5,     14,    490,    15,     5, 400
ih		 	FLbox  	"the 'FLTK/MIDI' switch is set to off (MIDI). In this mode    ", 	1,      5,     14,    490,    15,     5, 420
ih		 	FLbox  	"frequency rescaling values are derived from notes played on  ", 	1,      5,     14,    490,    15,     5, 440
ih		 	FLbox  	"the keyboard. Each MIDI note pressed begins another          ", 	1,      5,     14,    490,    15,     5, 460
ih		 	FLbox  	"frequency rescaling voice thus permitting polyphony.         ", 	1,      5,     14,    490,    15,     5, 480

				FLpanel_end

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

giFFTattributes0	ftgen	1, 0, 4, -2,  512, 256, 1024, 1
giFFTattributes1	ftgen	2, 0, 4, -2, 1024, 256, 1024, 1
giFFTattributes2	ftgen	3, 0, 4, -2, 2048, 128, 2048, 1
giFFTattributes3	ftgen	4, 0, 4, -2, 4096, 128, 4096, 1

instr	1	;MIDI INPUT INSTRUMENT
	if	gkFLTK_MIDI=1	then	;IF FLTK/MIDI SWITCH IS SET TO 'FLTK'...
		turnoff			;TURN THIS INSTRUMENT OFF
	endif				;END OF CONDITIONAL BRANCHING
	icps	cpsmidi			;READ CYCLES PER SECOND VALUE FROM MIDI INPUT
	iscal	=	icps/cpsoct(8)	;CREATE FREQUENCY SCALING VARIABLE
	iamp	ampmidi	1		;READ IN A NOTE VELOCITY VALUE FROM THE MIDI INPUT
	;				P1 | P4  | P5
	aoutL, aoutR	subinstr	2,  iscal, iamp	;ACTIVATE A SUB-INSTRUMENT
		outs	aoutL, aoutR	;SEND AUDIO TO SPEAKERS
endin

instr	2	;SOUND PRODUCING AND TRANSFORMING INSTRUMENT
	kactive1	active	1	;SENSE NUMBER OF ACTIVE INSTANCES OF INSTRUMENT 1 (I.E. MIDI ACTIVATED INSTRUMENT) 
	if	gkFLTK_MIDI=0&&kactive1=0	then	;IF FLTK/MIDI SWITCH IS SET TO 'MIDI' AND NO MIDI NOTES ARE ACTIVE...
		turnoff					;TURN THIS INSTRUMENT
	endif						;END OF CONDITIONAL BRANCHING
	if	gkFLTK_MIDI = 1	then			;IF FLTK/MIDI SWITCH IS SET TO 'FLTK'...
		kgain=gkgain				;SET kamp TO FLTK SLIDER VALUE gkamp
		kscal=gkscal				;SET FUNDEMENTAL TO FLTK SLIDER gkfund
	else						;OTHERWISE...
		kscal = p4				;SET FUNDEMENTAL TO RECEIVED p4 RECEIVED FROM INSTR 1. I.E. MIDI PITCH
		kgain = p5 * gkgain			;SET AMPLITUDE TO RECEIVED p5 RECEIVED FROM INSTR 1 (I.E. MIDI VELOCITY) MULTIPLIED BY FLTK SLIDER gkamp.
	endif						;END OF CONDITIONAL BRANCHING
	
	if		gkinput=0	then			;IF 'INPUT' SWITCH IS SET TO 'Live Input' THEN IMPLEMENT THE NEXT LINE OF CODE
		asig		inch		1				;READ AUDIO FROM THE COMPUTER'S LIVE INPUT CHANNEL 1 (LEFT)
	elseif		gkinput=1 	then			;IF 'INPUT' SWITCH IS SET TO 'Voice' THEN IMPLEMENT THE NEXT LINE OF CODE
		;OUTPUT		OPCODE		FILE_PATH       | SPEED | INSKIP | WRAPAROUND (1=ON)
		asig		diskin2		"AndItsAll.wav",    1,      0,        1			;READ A STORED AUDIO FILE FROM THE HARD DRIVE
	else						;IF 'INPUT' SWITCH IS NOT SET TO 'STORED FILE' THEN IMPLEMENT THE NEXT LINE OF CODE
		;OUTPUT		OPCODE		FILE_PATH       | SPEED | INSKIP | WRAPAROUND (1=ON)
		asig		diskin2		"808loopMono.wav",    1,      0,        1			;READ A STORED AUDIO FILE FROM THE HARD DRIVE
	endif						;END OF 'IF'...'THEN' BRANCHING

	kSwitch		changed		gkgain, gkkeepform, gkFFTattributes	;GENERATE A MOMENTARY '1' PULSE IN OUTPUT 'kSwitch' IF ANY OF THE SCANNED INPUT VARIABLES CHANGE. (OUTPUT 'kSwitch' IS NORMALLY ZERO)
	if	kSwitch=1	then		;IF I-RATE VARIABLE CHANGE TRIGGER IS '1'...
		reinit	START			;BEGIN A REINITIALISATION PASS FROM LABEL 'START'
	endif
	START:
	iFFTsize	table	0, i(gkFFTattributes)+1
	ioverlap	table	1, i(gkFFTattributes)+1
	iwinsize	table	2, i(gkFFTattributes)+1
	iwintype	table	3, i(gkFFTattributes)+1	
	fsig1  		pvsanal		asig, iFFTsize, ioverlap, iwinsize, iwintype		;ANALYSE THE AUDIO SIGNAL THAT WAS CREATED IN INSTRUMENT 1. OUTPUT AN F-SIGNAL.
	;OUTPUT		OPCODE		INPUT | RESCALE_VALUE | FORMANT_MODE |   GAIN
	fsig2 		pvscale 	fsig1,      kscal,     i(gkkeepform), i(gkgain)	;RESCALE THE FREQUENCY VALUES ACCORDING TO THE INPUT ARGUMENT gkscal.
	rireturn	;RETURN FROM REINITIALISATION PASS TO PERFORMANCE TIME PASSES
	;OUTPUT		OPCODE		INPUT
	aresyn 		pvsynth  	fsig2                      		;RESYNTHESIZE THE f-SIGNAL AS AN AUDIO SIGNAL
	aenv		linsegr		0,0.01,1,0.02,0				;ANTI CLICK ENVELOPE WITH AMIDI SENSING RELEASE SEGMENT
			outs		aresyn*aenv, aresyn*aenv		;SEND THE RESCALED, RESYNTHESIZED SIGNAL TO THE AUDIO OUTPUTS AND RESCALE AMPLITUDE WITH ENVELOPE aenv
endin

</CsInstruments>

<CsScore>
f 0 3600	;DUMMY SCORE EVENT KEEPS PERFORMANCE GOING FOR 1 HOUR
</CsScore>

</CsoundSynthesizer>