;WRITTEN BY IAIN MCCURDY, 2006

<CsoundSynthesizer>

<CsOptions>
-idevaudio -odevaudio -Ma -+rtmidi=virtual -b400 
</CsOptions>

<CsInstruments>

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

;FLTK INTERFACE CODE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;			LABEL		WIDTH | HEIGHT | X | Y
	FLpanel		"pvscross", 	500,      670,   0,  0

;BORDERS				TYPE | FONT | SIZE | WIDTH | HEIGHT | X | Y
ih		 	FLbox  	" ", 	6,      9,     15,    496,    240,    3, 70
ih		 	FLbox  	" ", 	6,      9,     15,    496,    140,    3,320
ih		 	FLbox  	" ", 	6,      9,     15,    496,    140,    3,470

;TEXT BOXES							TYPE | FONT | SIZE | WIDTH | HEIGHT | X |  Y
ih		 	FLbox  	"Signal Generator",		1,      10,    16,    150,     25,    10, 72
ih		 	FLbox  	"Source Signal",		1,      10,    16,    150,     25,    10,322
ih		 	FLbox  	"Pvcross Cross Synthesizer",	1,      10,    16,    200,     25,    10,472

;SWITCHES	  	                  		       			ON | OFF | TYPE | WIDTH | HEIGHT | X | Y | OPCODE | INS | STARTTIM | DUR
gkSigGen, gihSigGen		FLbutton	"On/Off (Use if No MIDI)",	1,    0,    22,    170,     19,  320, 76,    0,      2,      0,       -1
gkGate, ihGate			FLbutton	"Amplitude Gate",		1,    0,    22,    170,     19,  320,476,    0,      2,      0,       -1
gkSpeedToZero, ihSpeedToZero	FLbutton	"Speed To Zero",		1,    0,    21,    120,     19,  370,425,    0,      4,      0,      0.01

;VALUE DISPLAY BOXES		LABEL | WIDTH | HEIGHT | X | Y
idcps			FLvalue	" ",	 80,      20,   10, 125
idptr			FLvalue	" ",	 80,      20,   10, 375
idspd			FLvalue	" ",	 80,      20,   10, 425
idamp1			FLvalue	" ",	 80,      20,   10, 525
idamp2			FLvalue	" ",	 80,      20,   10, 575

;SLIDERS				            						MIN   | MAX | EXP | TYPE |  DISP   | WIDTH | HEIGHT | X  | Y
gkcps, ihcps		FLslider 	"CPS (No MIDI)",					20,    2000,  -1,    23,    idcps,     480,    25,    10,  100
gkptr, gihptr		FLslider 	"File Pointer",						0,       1,    0,     1,    idptr,     480,    25,    10,  350
gkspd, gihspd		FLslider 	"Speed",						-2,      2,    0,    23,    idspd,     480,    25,    10,  400
gkamp1, ihamp1		FLslider 	"Excitation Signal Amplitude",				0,       1,    0,    23,    idamp1,    480,    25,    10,  500
gkamp2, ihamp2		FLslider 	"Cross Synthesis Amplitude",				0,       1,    0,    23,    idamp2,    480,    25,    10,  550

;GENERAL_TEXT_SETTINGS			SIZE | FONT |  ALIGN | RED | GREEN | BLUE
			FLlabel		13,      1,      1,    190,   190,   190	;LABELS MADE INVISIBLE

;			FLBUTBANK 	TYPE | NUMX | NUMY | WIDTH | HEIGHT | X | Y | OPCODE
gkinput, ihinput	FLbutBank	12,     1,     3,     30,    60,      0,  0,   -1
gkwave, ihwave		FLbutBank	12,     1,     5,     30,   100,     10,170,   0, 2, 0, -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,    12,    100,      20,   30,  0
ih		 	FLbox  	"Vocal Sample", 	1,       5,    12,    100,      20,   30, 20
ih		 	FLbox  	"Drum Loop   ", 	1,       5,    12,    100,      20,   30, 40
ih		 	FLbox  	"Sine    ", 		1,       5,    12,     70,      20,   40,170
ih		 	FLbox  	"Sawtooth", 		1,       5,    12,     70,      20,   40,190
ih		 	FLbox  	"Square  ", 		1,       5,    12,     70,      20,   40,210
ih		 	FLbox  	"Triangle", 		1,       5,    12,     70,      20,   40,230
ih		 	FLbox  	"Noise   ", 		1,       5,    12,     70,      20,   40,250

;SET INITIAL VALUES FOR SLIDERS 	|VALUE | HANDLE
			FLsetVal_i	200,	ihcps
			FLsetVal_i	0, 	ihamp1
			FLsetVal_i	.5, 	ihamp2
			FLsetVal_i	.1,	gihptr
			FLsetVal_i	1,	gihspd
			FLsetVal_i	1, 	ihinput
			FLsetVal_i	0, 	gihSigGen
			FLsetVal_i	1, 	ihGate
			FLsetVal_i	1, 	ihwave

			FLpanel_end

;INSTRUCTIONS AND INFO PANEL                 WIDTH | HEIGHT | X | Y
				FLpanel	" ", 500,      540,  512, 0
;TEXT BOXES												TYPE | FONT | SIZE | WIDTH | HEIGHT | X | Y
ih		 	FLbox  	"                            pvcross                          ", 	1,      5,     14,    490,    15,     5,  0
ih		 	FLbox  	"-------------------------------------------------------------", 	1,      5,     14,    490,    15,     5,  20
ih		 	FLbox  	"Pvscross combines the spectral envelope of one signal        ", 	1,      5,     14,    490,    15,     5,  40
ih		 	FLbox  	"(referred to as the input signal) with the frequencies of    ", 	1,      5,     14,    490,    15,     5,  60
ih		 	FLbox  	"another signal (referred to as the excitation signal).       ", 	1,      5,     14,    490,    15,     5,  80
ih		 	FLbox  	"This capability can be used to imitate the functioning of the", 	1,      5,     14,    490,    15,     5, 100
ih		 	FLbox  	"traditional vocoder. This is what has been implemented in    ", 	1,      5,     14,    490,    15,     5, 120
ih		 	FLbox  	"this example. An input signal of either a stored analysis    ", 	1,      5,     14,    490,    15,     5, 140
ih		 	FLbox  	"file (voice or drum loop) or a live input can be combined    ", 	1,      5,     14,    490,    15,     5, 160
ih		 	FLbox  	"with a variety of synthesized timbres. This signal generator ", 	1,      5,     14,    490,    15,     5, 180
ih		 	FLbox  	"can also be triggered from a connected MIDI keyboard thus    ", 	1,      5,     14,    490,    15,     5, 200
ih		 	FLbox  	"allowing the playing of chords of excitation signals. When   ", 	1,      5,     14,    490,    15,     5, 220
ih		 	FLbox  	"playing from a MIDI keyboard the 'Signal Generator' switch   ", 	1,      5,     14,    490,    15,     5, 240
ih		 	FLbox  	"should be deactivated. Pitch bend is also implemented.       ", 	1,      5,     14,    490,    15,     5, 260
ih		 	FLbox  	"The 'Gate Amplitude' switch forces the output sound to follow", 	1,      5,     14,    490,    15,     5, 280
ih		 	FLbox  	"the amplitude of the excitation sound.                       ", 	1,      5,     14,    490,    15,     5, 300
ih		 	FLbox  	"The user can mix between the excitation signal and the       ", 	1,      5,     14,    490,    15,     5, 320
ih		 	FLbox  	"cross-synthesized signal using the 'Excitation Signal        ", 	1,      5,     14,    490,    15,     5, 340
ih		 	FLbox  	"Amplitude' and 'Cross Synthesis Amplitude' controls.         ", 	1,      5,     14,    490,    15,     5, 360
ih		 	FLbox  	"When using a stored analysis file (either voice or drums) as ", 	1,      5,     14,    490,    15,     5, 380
ih		 	FLbox  	"input the speed of playback can be varied using the 'Speed'  ", 	1,      5,     14,    490,    15,     5, 400
ih		 	FLbox  	"slider. A value of 1 represents normal playback speed, 2     ", 	1,      5,     14,    490,    15,     5, 420
ih		 	FLbox  	"represents double speed and so on. File pointer movement is  ", 	1,      5,     14,    490,    15,     5, 440
ih		 	FLbox  	"monitored by the 'File Pointer' slider. Manual file pointer  ", 	1,      5,     14,    490,    15,     5, 460
ih		 	FLbox  	"adjustment is possible by first reducing 'Speed' to zero by  ", 	1,      5,     14,    490,    15,     5, 480
ih		 	FLbox  	"clicking the 'Speed to Zero' button and then using the 'File ", 	1,      5,     14,    490,    15,     5, 500
ih		 	FLbox  	"Pointer' slider.                                             ", 	1,      5,     14,    490,    15,     5, 520

				FLpanel_end

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

gasrc	init	0	;INITIALISE GLOBAL AUDIO VARIABLE TO ZERO 

instr 1		;SIGNAL GENERATOR (MIDI)
	iporttime	=	.01					;CREATE A RAMPING UP VALUE THAT WILL BE USED FOR PORTAMENTO TIME
	kporttime	linseg	0, .001, iporttime, 1, iporttime	;CREATE A RAMPING UP VALUE THAT WILL BE USED FOR PORTAMENTO TIME
	ioct		octmidi		;READ MIDI PITCH INFORMATION FROM A MIDI KEYBOARD
	;PITCH BEND INFORMATION IS READ
	iSemitoneBendRange = 2		;PITCH BEND RANGE IN SEMITONES (WILL BE DEFINED FURTHER LATER)
	imin = 0			;EQUILIBRIUM POSITION
	imax = iSemitoneBendRange * .0833333	;MAX PITCH DISPLACEMENT (IN oct FORMAT)
	kbend	pchbend	imin, imax	;PITCH BEND VARIABLE (IN oct FORMAT)
	kenv		linsegr	0, .1, 1, .01, 0	;CREATE AN AMPLITUDE ENVELOPE TO PREVENT CLICK THAT INCLUDES A MIDI-RELEASE STAGE
	if	gkwave=0	then
		asine		oscili	kenv, cpsoct(ioct + kbend), 1 
		gasrc		=	gasrc + asine	;ADD SINE TONE TO THE GLOBAL AUDIO VARIABLE gasrc. THIS MECHANISM FACILITATES MIDI POLYPHONY
	elseif	gkwave<=3&&gkwave>0	then
		avco		vco 	kenv, cpsoct(ioct + kbend), i(gkwave), 0.5, 1, 1, 0, 22054/sr, 0	;SAWTOOTH WAVEFORM
		gasrc		=	gasrc + avco	;ADD VCO TONE TO THE GLOBAL AUDIO VARIABLE gasrc. THIS MECHANISM FACILITATES MIDI POLYPHONY
	else
		anoise	noise	kenv, 0
		gasrc		=	gasrc + anoise	;ADD NOISE SIGNAL TO THE GLOBAL AUDIO VARIABLE gasrc. THIS MECHANISM FACILITATES MIDI POLYPHONY
	endif
endin

instr	2	;SIGNAL GENERATOR (NO MIDI)
	if	gkSigGen=0	then	;IF Sig.Gen. SWITCH IS SET TO 'OFF'...
		turnoff			;TURN THIS INSTRUMENT OFF
	endif				;END OF CONDITIONAL BRANCHING
	iporttime	=	.01					;CREATE A RAMPING UP VALUE THAT WILL BE USED FOR PORTAMENTO TIME
	kporttime	linseg	0, .001, iporttime, 1, iporttime	;CREATE A RAMPING UP VALUE THAT WILL BE USED FOR PORTAMENTO TIME
	kcps		portk	gkcps, kporttime			;APPLY PORTAMENTO TO gkcps
	kenv		linsegr	0, .01, 1, .01, 0	;CREATE AN AMPLITUDE ENVELOPE TO PREVENT CLICKS. INCLUDES A MIDI-RELEASE STAGE
	if	gkwave=0	then
		asine		oscili	kenv, kcps, 1 
		gasrc		=	gasrc + asine	;ADD SINE TONE TO THE GLOBAL AUDIO VARIABLE gaexc
	elseif	gkwave<=3&&gkwave>0	then
	avco		vco 	kenv, kcps, i(gkwave), 0.5, 1, 1, 0, 22054/sr, 0	;SAWTOOTH WAVEFORM
	gasrc		=	gasrc + avco				;ADD TONE TO THE GLOBAL AUDIO VARIABLE gaexc
	else
		anoise	noise	kenv, 0
		gasrc		=	gasrc + anoise	;ADD NOISE SIGNAL TO THE GLOBAL AUDIO VARIABLE gaSRC.
	endif
endin

instr	3
		if		gkinput>=1 then		;IF 'INPUT' SWITCH IS SET TO 'STORED FILE' THEN IMPLEMENT THE NEXT LINE OF CODE
		if		gkinput!=1 kgoto	SKIP1
#define		ANALYSISFILE	#"AndItsAll.pvx"#	;CREATE A TEXT MACRO OF THE CHOSEN ANALYSIS FILE NAME (TO SAVE US HAVING TO WRITE IT OUT TWICE!)
							;IF YOU WISH TO USE A DIFFERENT ANALYSIS FILE YOU ONLY NEED TO CHANGE THE REFERENCE HERE
	ilen1		filelen		$ANALYSISFILE		;DERIVE THE FILE LENGTH (IN SECONDS) OF THE CHOSEN ANALYSIS FILE	
	;OUTPUT		OPCODE		FREQUENCY
	kptr		phasor		gkspd/ilen1		;CREATE A MOVING PHASE VALUE (0-1) THAT WILL BE USED AS A FILE POINTER. FREQUENCY OF PHASOR WILL BE DIRECTLY PROPORTIONAL TO SPEED SLIDER AND INVERSELY PROPORTIONAL TO THE LENGTH OF THE ANALYSIS FILE
	ktrig		changed		kptr			;CREATE A TRIGGER (MOMENTARY 1 VALUE) EACH TIME VARIABLE kptr CHANGES
	;		OPCODE		TRIGGER | VALUE | HANDLE
			FLsetVal	ktrig,     kptr,  gihptr	;UPDATE 'Pointer' SLIDER WHENEVER TRIGGER IS '1' USING VALUE HELD IN THE 'VALUE' COLUMN 
	;OUTPUT		OPCODE		POINTER     |   FILE
	fdest  		pvsfread	gkptr * ilen1, $ANALYSISFILE	;READ AN ANALYSIS FILE FROM THE HARD DRIVE ACCORDING TO THE GIVEN FILE POINTER LOCATION. OUTPUT AN F-SIGNAL.
			kgoto		SKIP2
	SKIP1:
#define		ANALYSISFILE	#"808loopmono.pvx"#	;CREATE A TEXT MACRO OF THE CHOSEN ANALYSIS FILE NAME (TO SAVE US HAVING TO WRITE IT OUT TWICE!)
							;IF YOU WISH TO USE A DIFFERENT ANALYSIS FILE YOU ONLY NEED TO CHANGE THE REFERENCE HERE
	ilen2		filelen		$ANALYSISFILE		;DERIVE THE FILE LENGTH (IN SECONDS) OF THE CHOSEN ANALYSIS FILE	
	;OUTPUT		OPCODE		FREQUENCY
	kptr		phasor		gkspd/ilen2		;CREATE A MOVING PHASE VALUE (0-1) THAT WILL BE USED AS A FILE POINTER. FREQUENCY OF PHASOR WILL BE DIRECTLY PROPORTIONAL TO SPEED SLIDER AND INVERSELY PROPORTIONAL TO THE LENGTH OF THE ANALYSIS FILE
	ktrig		changed		kptr			;CREATE A TRIGGER (MOMENTARY 1 VALUE) EACH TIME VARIABLE kptr CHANGES
	;		OPCODE		TRIGGER | VALUE | HANDLE
			FLsetVal	ktrig,     kptr,  gihptr	;UPDATE 'Pointer' SLIDER WHENEVER TRIGGER IS '1' USING VALUE HELD IN THE 'VALUE' COLUMN 
	;OUTPUT		OPCODE		POINTER     |   FILE
	fdest  		pvsfread	gkptr * ilen2, $ANALYSISFILE	;READ AN ANALYSIS FILE FROM THE HARD DRIVE ACCORDING TO THE GIVEN FILE POINTER LOCATION. OUTPUT AN F-SIGNAL.
	SKIP2:
			else						;IF 'INPUT' SWITCH IS NOT SET TO 'STORED FILE' THEN IMPLEMENT THE NEXT LINE OF CODE
	adest, aignore	ins						;READ AUDIO FROM THE COMPUTER'S LIVE INPUT (LEFT INPUT ONLY IS READ, RIGHT CHANNEL IS IGNORED IN SUBSEQUENT CODE. A STEREO VERSION COULD EASILY BE BUILT BUT THIS WOULD DOUBLE CPU DEMANDS!) 
	;OUTPUT		OPCODE		INPUT | FFTSIZE | OVERLAP | WINSIZE | WINTYPE [, IFORMAT] [, IINIT]
	fdest  		pvsanal		adest,    1024,      256,     1024,       1	;ANALYSE THE AUDIO SIGNAL
			endif						;END OF 'IF'...'THEN' BRANCHING
	
	fsrc  	pvsanal		gasrc*32768, 1024, 256, 1024, 1	;ANALYSE THE EXCITATION AUDIO SIGNAL
	
	fsig 	pvscross 	fsrc, fdest, gkamp1, gkamp2
	
	aresyn 	pvsynth fsig					;RESYNTHESIZE THE NEW F-SIGNAL INTO AN AUDIO SIGNAL
	
	if	gkGate=1	then
		afollow	follow2 gasrc, 0.1, 0.1			;CREATE AN AMPLITUDE FOLLOWING SIGNAL THAT FOLLOWS THE DYNAMIC ENVELOPE OF THE EXCITATION SIGNAL - THIS WILL BE USED TO GATE THE CROSS SYNTHESISED SIGNAL
		aresyn	= aresyn*afollow
	endif
		outs	aresyn, aresyn				;SEND THE RESYNTHESIZED AUDIO SIGNAL TO THE OUTPUTS 
	gasrc	=	0					;RESET THE GLOBAL AUDIO SIGNAL TO ZERO - THIS PREVENTS A STUCK, NON-ZERO VALUE FOR gaexc IN THE SITUATION WHERE NO EXCITATION SIGNAL IS PLAYING
		endin
	
	instr	4	;SET SPEED SLIDER TO ZERO
		FLsetVal_i	0, gihspd
endin

</CsInstruments>

<CsScore>
f 1 0 65536 10 1		;SINE WAVE
i 3 0 3600 		;ACTIVATE INSTRUMENT 3 FOR 1 HOUR - ALSO SUSTAINS REALTIME PERFORMANCE
</CsScore>

</CsoundSynthesizer>