;Written by Iain McCurdy, 2006

<CsoundSynthesizer>

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

<CsInstruments>

sr 	= 	44100  
ksmps 	= 	10
nchnls 	= 	2	

;FLTK INTERFACE CODE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
FLcolor	255, 255, 255, 0, 0, 0
;			LABEL     | WIDTH | HEIGHT | X | Y
		FLpanel	"gbuzz",     500,    200,    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

;NUMBER DISPLAY BOXES			WIDTH | HEIGHT | X | Y
idamp			FLvalue	" ",       80,    20,    5,  75
idmul			FLvalue	" ",       80,    20,    5, 125
idfreq			FLvalue	" ",       80,    20,    5, 175


;SLIDERS				     				MIN | MAX | EXP | TYPE | DISP | WIDTH | HEIGHT | X | Y
gkamp, ihamp		FLslider	"Amplitude",  			0,   10000,   0,   23,   idamp,  490,    25,     5,  50
gkmul, gihmul		FLslider	"Amplitude Multiplier CC#1",	0,       2,   0,   23,   idmul,  490,    25,     5, 100
gkfreq, ihfreq		FLslider	"Osc. Frequency",    		1,    2000,  -1,   23,  idfreq,  490,    25,     5, 150

;COUNTERS					MIN | MAX | STEP1 | STEP2 | TYPE | WIDTH | HEIGHT | X | Y | OPCODE
gkharm, ihharm 	FLcount  "No. of Harmonics",	-1,   100,    1,      1,      2,   120,      25,   380, 5,    -1
gklh, ihlh 	FLcount  "Lowest Harmonic",	1,    100,    1,      1,      2,   120,      25,   210, 5,    -1

;SET INITIAL VALUES		VALUE | HANDLE 
		FLsetVal_i	7000, 	ihamp
		FLsetVal_i	30, 	ihharm
		FLsetVal_i	0, 	ihlh
		FLsetVal_i	1, 	gihmul
		FLsetVal_i	100, 	ihfreq

		FLpanel_end	;END OF PANEL CONTENTS

;INSTRUCTIONS AND INFO PANEL
				FLpanel	" ", 500, 420, 512, 0
;TEXT BOXES												TYPE | FONT | SIZE | WIDTH | HEIGHT | X | Y
ih		 	FLbox  	"                Miscellaneous Waveforms : gbuzz              ", 	1,      5,     14,    490,    15,     5,  0
ih		 	FLbox  	"-------------------------------------------------------------", 	1,      5,     14,    490,    15,     5,  20
ih		 	FLbox  	"Gbuzz creates similar sounds to the buzz opcode by stacking  ", 	1,      5,     14,    490,    15,     5,  40
ih		 	FLbox  	"harmonically relates cosine waves but gbuzz offers some      ", 	1,      5,     14,    490,    15,     5,  60
ih		 	FLbox  	"additional possibilities.                                    ", 	1,      5,     14,    490,    15,     5,  80
ih		 	FLbox  	"In addition to allowing us to choose the number partials     ", 	1,      5,     14,    490,    15,     5, 100
ih		 	FLbox  	"above the fundemental that will be present gbuzz allows us to", 	1,      5,     14,    490,    15,     5, 120
ih	  	 	FLbox  	"choose what the lowest partial present will be.              ", 	1,      5,     14,    490,    15,     5, 140
ih		 	FLbox  	"The 'Amplitude Multiplier' control allows us to scale the    ", 	1,      5,     14,    490,    15,     5, 160
ih		 	FLbox  	"amplitudes of the sequence of partials. With a value of 1 all", 	1,      5,     14,    490,    15,     5, 180
ih		 	FLbox  	"amplitudes are equal, with values less than one the          ", 	1,      5,     14,    490,    15,     5, 200
ih		 	FLbox  	"amplitudes of higher partials are increasingly attenuated,   ", 	1,      5,     14,    490,    15,     5, 220
ih		 	FLbox  	"and with values greater than 1 the lower partials are        ", 	1,      5,     14,    490,    15,     5, 240
ih		 	FLbox  	"increasingly attenuated.                                     ", 	1,      5,     14,    490,    15,     5, 260
ih		 	FLbox  	"Gbuzz requires us to supply it with a cosine wave function   ", 	1,      5,     14,    490,    15,     5, 280
ih		 	FLbox  	"table. This is done using GEN 09.                            ", 	1,      5,     14,    490,    15,     5, 300
ih		 	FLbox  	"Gbuzz provides a useful source for subtractive synthesis.    ", 	1,      5,     14,    490,    15,     5, 320
ih		 	FLbox  	"This example can also be played from an external MIDI        ", 	1,      5,     14,    490,    15,     5, 340
ih		 	FLbox  	"keyboard. Pitch, note velocity and pitch bend and represented", 	1,      5,     14,    490,    15,     5, 360
ih		 	FLbox  	"appropriately. MIDI controller 1 (the modulation wheel) can  ", 	1,      5,     14,    490,    15,     5, 380
ih		 	FLbox  	"be used to modulate 'Amplitude Multiplier'.                  ", 	1,      5,     14,    490,    15,     5, 400
                                                           
				FLpanel_end

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

gicos	ftgen 0, 0, 65536, 9, 1, 1, 90		;FUNCTION TABLE THAT STORES A SINGLE CYCLE OF A COSINE WAVE

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
        kmul                    ctrl7           1,            1,      0,    1	;READ IN MIDI CONTROLLER
        ktrig                   changed         kmul    ;IF THE VARIABLE 'kptr' CHANGES FROM ITS PREVIOUS VALUE,
	kmul			scale		kmul, 2, 0	;RESCALE VARIABLE
                                                        ;I.E. IF THE MIDI SLIDER IS MOVED THEN THE VARIABLE ktrig WILL ASSUME THE VALUE '1', OTHERWISE IT WILL BE ZERO.
        ;                       OPCODE      |   TRIGGER | VALUE | HANDLE
                                FLsetVal        ktrig,     kmul,  gihmul	;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'...
		kamp = gkamp			;SET kamp TO FLTK SLIDER VALUE gkamp
		kfreq = gkfreq			;SET FUNDEMENTAL TO FLTK SLIDER gkfund
	else						;OTHERWISE...
		kfreq = p4				;SET FUNDEMENTAL TO RECEIVED p4 RECEIVED FROM INSTR 1. I.E. MIDI PITCH
		kamp = p5 * gkamp			;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(kfreq)
	kfreq	=	cpsoct(koct + kbend)
	;=====================================================================================================================================================================

	iporttime	=	0.05				;PORTAMENTO TIME VARIABLE
	kporttime	linseg	0,0.001,iporttime,1,iporttime	;CREATE A RAMPING UP FUNCTION TO REPRESENT PORTAMENTO TIME
	kmul		portk	gkmul, kporttime		;APPLY PORTAMENTO SMOOTHING

	;OUTPUT	OPCODE	AMPLITUDE | FREQUENCY | NO.OF_HARMONICS | LOWEST_HARMONIC | POWER | FUNCTION_TABLE
	asig	gbuzz 	gkamp,        kfreq,        gkharm,            gklh,       kmul,       gicos
	aenv	linsegr	0,0.01,1,0.01,0		;ANTI-CLICK ENVELOPE
	outs	asig * aenv, asig * aenv	;SEND AUDIO OUTPUT TO THE SPEAKERS
endin

</CsInstruments>

<CsScore>
f 0 3600		;DUMMY SCORE EVENT - ALLOW REALTIME PERFORMANCE FOR UP TO 1 HOUR 
</CsScore>

</CsoundSynthesizer>