;Written by Iain McCurdy, 2006

<CsoundSynthesizer>

<CsOptions>
-odevaudio -b400 -M0 -+rtmidi=virtual
</CsOptions>

<CsInstruments>

sr 	= 	44100  
ksmps 	= 	10
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	"VCO with PWM LFO and Moog Low Pass Filter",     500,    550,    0,  0

;				FLBUTBANK 	TYPE | NUMX | NUMY | WIDTH | HEIGHT | X | Y | IOPCODE | P1 | P2 | P3
gkFLTK_MIDI, ihFLTK_MIDI	FLbutBank	4,      1,     2,     20,      40,    5,  5,     0,     2,    0, 3600
;TEXT BOXES					TYPE | FONT | SIZE | WIDTH | HEIGHT | X | Y
ih		 	FLbox  	"MIDI", 	1,      6,     17,     50,     20,   23,   4
ih		 	FLbox  	"FLTK", 	1,      6,     17,     50,     20,   23,  24

;VALUE DISPLAY BOXES			WIDTH | HEIGHT | X | Y
idcps			FLvalue	" ",      70,     20,    5, 125
idleak			FLvalue	" ",      70,     20,    5, 175
idnyx			FLvalue	" ",      70,     20,    5, 225
idpw			FLvalue	" ",      70,     20,    5, 275
idPWMamt		FLvalue	" ",      70,     20,    5, 325
idPWMspd		FLvalue	" ",      70,     20,    5, 375
idMVCFcf		FLvalue	" ",      70,     20,    5, 425
idMVCFres		FLvalue	" ",      70,     20,    5, 475
idgain			FLvalue	" ",      70,     20,    5, 525

;SLIDERS				     					MIN | MAX | EXP | TYPE | DISP    | WIDTH | HEIGHT | X | Y
gkcps, ihcps		FLslider	"Frequency",  				2,   10000,  -1,   23,   idcps,      490,    25,     5, 100
gkleak, ihleak		FLslider	"Integrator Leak",			0,       1,   0,   23,   idleak,     490,    25,     5, 150
gknyx, ihnyx		FLslider	"Number of Harmonics",			0,       1,   0,   23,   idnyx,      490,    25,     5, 200
gkpw, ihpw		FLslider	"Pulse Width",    			0,       1,   0,   23,   idpw,       490,    25,     5, 250
gkPWMamt, ihPWMamt	FLslider	"PWM Amount",				0,       1,   0,   23,   idPWMamt,   490,    25,     5, 300
gkPWMspd, ihPWMspd	FLslider	"PWM Speed",				0.001,  10,   0,   23,   idPWMspd,   490,    25,     5, 350
gkMVCFcf, gihMVCFcf	FLslider	"Moog VCF Cutoff Frequency (CC#1)",	4,      14,   0,   23,   idMVCFcf,   490,    25,     5, 400
gkMVCFres, ihMVCFres	FLslider	"Moog VCF Resonance",			0,      .9,   0,   23,   idMVCFres,  490,    25,     5, 450
gkgain, ihgain		FLslider	"Output Gain",				0,       1,   0,   23,   idgain,     490,    25,     5, 500

;COUNTERS						MIN | MAX | STEP1 | STEP2 | TYPE | WIDTH | HEIGHT | X | Y | OPCODE
gkwave,ihwave 		FLcount  "Waveform", 		1,      3,   1,       1,      2,   140,     25,    175, 5,    -1
gkPWMwave,ihPWMwave	FLcount  "PWM LFO Waveform", 	0,      5,   1,       1,      2,   140,     25,    350, 5,    -1

;TEXT BOXES									TYPE | FONT | SIZE | WIDTH | HEIGHT | X | Y
ih		 	FLbox  	"1=Saw 2=Square/PWM 3=Triangle/Saw/Ramp", 	1,      5,     12,    150,    15,    175, 55

;SET INITIAL VALUES		VALUE | HANDLE 
		FLsetVal_i	100, 	ihcps
		FLsetVal_i	2, 	ihwave
		FLsetVal_i	0, 	ihleak
		FLsetVal_i	.5, 	ihnyx
		FLsetVal_i	0.5, 	ihpw
		FLsetVal_i	1, 	ihPWMamt
		FLsetVal_i	0.15, 	ihPWMspd
		FLsetVal_i	12, 	gihMVCFcf
		FLsetVal_i	0.4, 	ihMVCFres
		FLsetVal_i	0.5, 	ihgain

		FLpanel_end	;END OF PANEL CONTENTS

;INSTRUCTIONS AND INFO PANEL
				FLpanel	" ", 500, 320, 512, 0
;TEXT BOXES												TYPE | FONT | SIZE | WIDTH | HEIGHT | X | Y
ih		 	FLbox  	"           VCO with PWM LFO and Moog Low Pass Filter         ", 	1,      5,     14,    490,    15,     5,  0
ih		 	FLbox  	"-------------------------------------------------------------", 	1,      5,     14,    490,    15,     5,  20
ih		 	FLbox  	"This example adds a number of features onto a basic VCO audio", 	1,      5,     14,    490,    15,     5,  40
ih		 	FLbox  	"oscillator. For an explanation of the 'vco' opcode please    ", 	1,      5,     14,    490,    15,     5,  60
ih		 	FLbox  	"look at the previous example.                                ", 	1,      5,     14,    490,    15,     5,  80
ih		 	FLbox  	"As well as being able to modulate the pulse width manually   ", 	1,      5,     14,    490,    15,     5, 100
ih		 	FLbox  	"with a single slider, an LFO (low frequency oscillator) has  ", 	1,      5,     14,    490,    15,     5, 120
ih	  	 	FLbox  	"added which allows this task to be automated. This is a      ", 	1,      5,     14,    490,    15,     5, 140
ih		 	FLbox  	"common arrangement on analogue synthesizers.                 ", 	1,      5,     14,    490,    15,     5, 160
ih		 	FLbox  	"A Moog-style resonant lowpass filter has also been added to  ", 	1,      5,     14,    490,    15,     5, 180
ih		 	FLbox  	"allow the user to explore the timbral possibilities from the ", 	1,      5,     14,    490,    15,     5, 200
ih		 	FLbox  	"vco opcode.                                                  ", 	1,      5,     14,    490,    15,     5, 220
ih		 	FLbox  	"This example can also be played from an external MIDI        ", 	1,      5,     14,    490,    20,     5, 240
ih		 	FLbox  	"keyboard. Pitch, note velocity and pitch bend and represented", 	1,      5,     14,    490,    20,     5, 260
ih		 	FLbox  	"appropriately. MIDI controller 1 (the modulation wheel) can  ", 	1,      5,     14,    490,    20,     5, 280
ih		 	FLbox  	"be used to modulate 'Moog VCF Cutoff Frequency'.             ", 	1,      5,     14,    490,    20,     5, 300
                                                           
				FLpanel_end

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

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
	iamp	ampmidi	1		;READ IN A NOTE VELOCITY VALUE FROM THE MIDI INPUT
	;				P1 | P4 | P5
	aoutL, aoutR	subinstr	2,  icps, iamp	;ACTIVATE A SUB-INSTRUMENT
		outs	aoutL, aoutR	;SEND AUDIO TO SPEAKERS
endin

instr	2		;GBUZZ INSTRUMENT
	;MIDI INPUT============================================================================================================================================================
        ;OUTPUT                 OPCODE          CHANNEL | CC.NUMBER | MIN | MAX
        kMVCFcf                 ctrl7           1,            1,      0,    1	;READ IN MIDI CONTROLLER
        ktrig                   changed         kMVCFcf    ;IF THE VARIABLE 'kptr' CHANGES FROM ITS PREVIOUS VALUE,
                                                        ;I.E. IF THE MIDI SLIDER IS MOVED THEN THE VARIABLE ktrig WILL ASSUME THE VALUE '1', OTHERWISE IT WILL BE ZERO.
	kMVCFcf			scale		kMVCFcf, 14, 4	;RESCALE VARIABLE
        ;                       OPCODE      |   TRIGGER | VALUE | HANDLE
                                FLsetVal        ktrig,     kMVCFcf,  gihMVCFcf	;UPDATE WIDGET WHEN A TRIGGER IS RECEIVED
        ;======================================================================================================================================================================

	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
		kcps = gkcps			;SET FUNDEMENTAL TO FLTK SLIDER gkfund
	else						;OTHERWISE...
		kcps = 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

	;PITCH BEND===========================================================================================================================================================
	iSemitoneBendRange = 2		;PITCH BEND RANGE IN SEMITONES (WILL BE DEFINED FURTHER LATER) - SUGGESTION - THIS COULD BE CONTROLLED BY AN FLTK COUNTER
	imin = 0			;EQUILIBRIUM POSITION
	imax = iSemitoneBendRange * .0833333	;MAX PITCH DISPLACEMENT (IN oct FORMAT)
	kbend	pchbend	imin, imax	;PITCH BEND VARIABLE (IN oct FORMAT)
	koct	=	octcps(kcps)
	kcps	=	cpsoct(koct + kbend)
	;=====================================================================================================================================================================

	iporttime	=	0.03
	kporttime	linseg	0,(.001),iporttime,(1),iporttime
	
	kpw		portk	gkpw, kporttime
	kcps		portk	kcps, kporttime
	kMVCFcf		portk	gkMVCFcf, kporttime
	
	ifn	=	1
	imaxd	=	1
	kSwitch		changed	gkleak, gknyx, gkwave, gkPWMwave
	if	kSwitch=1	then		;IF I-RATE VARIABLE CHANGE TRIGGER IS '1'...
		reinit	UPDATE			;BEGIN A REINITIALISATION PASS FROM LABEL 'UPDATE'
	endif
	UPDATE:
	kPWMmod	lfo	gkPWMamt, gkPWMspd, i(gkPWMwave)
	kpw	mirror	kpw+((kPWMmod+gkPWMamt)*.5), 0, 1	;REFLECT OUT OF RANGE VALUES
	aenv	linsegr	0,0.01,1,0.01,0		;ANTI-CLICK ENVELOPE
	asig	vco 	gkgain*aenv, kcps, i(gkwave), kpw, ifn, imaxd, i(gkleak), i(gknyx);, 0, 0
	rireturn	;RETURN FROM REINITIALISATION PASS TO PERFORMANCE TIME PASSES
	iscale 		= 	1
	asig		moogvcf	asig, cpsoct(kMVCFcf), gkMVCFres, iscale
		outs	asig, asig
endin

</CsInstruments>


<CsScore>
f1 0 131072 10 1  ; audio function
f 0 3600	;DUMMY SCORE EVENT - ALLOWS REAL-TIME PERFORMANCE FOR 1 HOUR
</CsScore>

</CsoundSynthesizer>