;Written by Iain McCurdy

<CsoundSynthesizer>

<CsOptions>
-odevaudio -M0 -b100
</CsOptions>

<CsInstruments>

sr 		= 	44100
kr 		= 	441
ksmps 		= 	100
nchnls 		= 	2
0dbfs		=	1	;MAXIMUM AMPLITUDE REGARDLESS OF BIT DEPTH

;FLTK INTERFACE CODE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
FLcolor	255, 255, 255, 100, 200, 200
;			LABEL                        | WIDTH | HEIGHT | X | Y
	FLpanel	"Basic Monophonic MIDI Synthesizer",    500,     60,    0,  0

;VALUE DISPLAY BOXES					WIDTH | HEIGHT | X |  Y
idporttime			FLvalue	" ",     	60,       18,    5,   35

;SLIDERS				            				MIN  |   MAX | EXP | TYPE |   DISP     | WIDTH | HEIGHT | X | Y
gkporttime,ihporttime		FLslider 	"Portamento Time",		0,        1,    0,    25,  idporttime,    490,    25,     5, 10


;SET INITIAL VALUES			VALUE | HANDLE
			FLsetVal_i	 .01,	ihporttime

			FLpanel_end

;INSTRUCTIONS AND INFO PANEL
				FLpanel	" ", 515, 620, 512, 0
;TEXT BOXES												TYPE | FONT | SIZE | WIDTH | HEIGHT | X | Y
ih		 	FLbox  	"         Basic Monophonic MIDI controlled Synthesizer        ", 	1,      5,     14,    490,    20,     5,  0
ih		 	FLbox  	"-------------------------------------------------------------", 	1,      5,     14,    490,    20,     5,  20
ih		 	FLbox  	"You will need to have a midi keyboard connected to the       ", 	1,      5,     14,    490,    20,     5,  40
ih		 	FLbox  	"computer for this to work.                                   ", 	1,      5,     14,    490,    20,     5,  60
ih		 	FLbox  	"Monosynths can be implemented using 2 separate instruments   ", 	1,      5,     14,    490,    20,     5,  80
ih		 	FLbox  	"and the schedkwhen opcode. The instrument containing the     ", 	1,      5,     14,    490,    20,     5, 100
ih		 	FLbox  	"schedkwhen is midi triggered the schedkwhen opcode triggers a", 	1,      5,     14,    490,    20,     5, 120
ih	  	 	FLbox  	"second instrument which is the one that actually produces the", 	1,      5,     14,    490,    20,     5, 140
ih		 	FLbox  	"sound. Crucially the imaxnum parameter (maximum number of    ", 	1,      5,     14,    490,    20,     5, 160
ih		 	FLbox  	"simultaneous notes allowed) in the schedkwhen opcode line is ", 	1,      5,     14,    490,    20,     5, 180
ih		 	FLbox  	"set to 1.                                                    ", 	1,      5,     14,    490,    20,     5, 200
ih		 	FLbox  	"The active opcode is used (in instr 2) to sense how many     ", 	1,      5,     14,    490,    20,     5, 220
ih		 	FLbox  	"notes instr 1 is playing. If instr 1 isn't playing any notes ", 	1,      5,     14,    490,    20,     5, 240
ih		 	FLbox  	"then instr 2 turns itself off.                               ", 	1,      5,     14,    490,    20,     5, 260
ih		 	FLbox  	"Pitch variables are passed from the first instrument to the  ", 	1,      5,     14,    490,    20,     5, 280
ih		 	FLbox  	"second using global variables.                               ", 	1,      5,     14,    490,    20,     5, 300
ih		 	FLbox  	"Portamento (portk) is used to implement glisandi between     ", 	1,      5,     14,    490,    20,     5, 320
ih		 	FLbox  	"overlapping notes.                                           ", 	1,      5,     14,    490,    20,     5, 340
ih		 	FLbox  	"There are two ways in which envelopes can be triggered in    ", 	1,      5,     14,    490,    20,     5, 360
ih		 	FLbox  	"monophonic synths:                                           ", 	1,      5,     14,    490,    20,     5, 380
ih		 	FLbox  	"1 - triggered only once, at the beginning of a sequence of   ", 	1,      5,     14,    490,    20,     5, 400
ih		 	FLbox  	"overlapping notes.                                           ", 	1,      5,     14,    490,    20,     5, 420
ih		 	FLbox  	"2 - triggered with each new new that is pressed whether      ", 	1,      5,     14,    490,    20,     5, 440
ih		 	FLbox  	"overlapping or not.                                          ", 	1,      5,     14,    490,    20,     5, 460
ih		 	FLbox  	"Two different envelopes which illustrate these two           ", 	1,      5,     14,    490,    20,     5, 480
ih		 	FLbox  	"situations have been implemented in this example:            ", 	1,      5,     14,    490,    20,     5, 500
ih		 	FLbox  	"1 - a filter envelope is put in instrument 2 so that it will ", 	1,      5,     14,    490,    20,     5, 520
ih		 	FLbox  	"only trigger with the first of a series of overlapping notes.", 	1,      5,     14,    490,    20,     5, 540
ih		 	FLbox  	"2 - a vibrato function (with an vibrato depth envelope) is   ", 	1,      5,     14,    490,    20,     5, 560
ih		 	FLbox  	"placed in instr 1 so that it will trigger each time a new    ", 	1,      5,     14,    490,    20,     5, 580
ih		 	FLbox  	"note is is pressed whether legato or not.                    ", 	1,      5,     14,    490,    20,     5, 600

				FLpanel_end

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

gkamp		init	0	;INITIALISE GLOBAL VARIABLES
gkcps		init	0       ;INITIALISE GLOBAL VARIABLES
gkNumInstr1	init	0       ;INITIALISE GLOBAL VARIABLES
gkvib		init	0       ;INITIALISE GLOBAL VARIABLES

instr	1
	;READ VALUES FOR FREQUENCY FROM A MIDI KEYBOARD 
	icps		cpsmidi
	;CREATE A K-RATE GLOBAL VARIABLE FROM MIDI FREQ. VALUES
	gkcps		=	icps
	
	;CREATE A VIBRATO FUNCTION - THIS ENVELOPE WILL BE TRIGGERED WITH EACH NEW NEW THAT IS PRESSED WHETHER LEGATO OR NOT
	ivibamp		=	.1
	ivibdelayTim	=	.3
	ivibRiseTim	=	1
	kvibenv		expseg	.001, (ivibdelayTim), .001, (ivibRiseTim), ivibamp, (1), ivibamp
	kvibfreq	=	6
	ivibwave	=	1
	kvib		oscil	kvibenv, kvibfreq, ivibwave
	gkvib		=	kvib+1
	
	;INSTR 2 IS INSTRUCTED TO PLAY A VERY LONG NOTE - ONLY ONE NOTE AT A TIME IS ALLOWED
	;				KTRIGGER, KMINTIM, KMAXNUM, KINSNUM, KWHEN, KDUR 
			schedkwhen      1,           0,       1,       2,      0,   3600
endin
			
instr	2
	kreleaseflag	release
	gkNumInstr1 	active 		1	;SENSE THE NUMBER OF NOTES ARE BEING PLAYED BY INSTR 1
	if		gkNumInstr1!=0||kreleaseflag=1	kgoto	KEEP_PLAYING	;IF INSTR 1 IS PLAYING AT LEAST ONE NOTE THEN INSTR 2 MUSTN'T TURN ITSELF OFF
								;I.E. SKIP THE NEXT LINE...
	turnoff		;INSTR 2 TURNS ITSELF OFF
	KEEP_PLAYING:						;SKIP TO HERE IF INSTR 1 IS STILL PLAYING
	
	;CREATE PORTAMENTO ON PITCH PARAMETER
	kporttime	linseg	0, (.01), 1, (1), 1
	kporttime	=	kporttime * gkporttime
	kcps		portk	gkcps, kporttime
	
	;CREATE AN OSILLATOR USING THE vco OPCODE
	iwave		=	1
	kpw		=	.5
	ifn		=	1
	imaxd		=	1
	ileak		=	0
	inyx		=	.5
	asig		vco 	0.3, kcps*gkvib, iwave, kpw, ifn, imaxd, ileak, inyx
	
	;FILTER ENVELOPE - ALL LEVELS ARE GIVEN IN OCT FORMAT
	iFAttTim	=	.1	;ATTACK TIME
	iFAttLev	=	7	;ATTACK LEVEL
	iFDecTim	=	.1	;DECAY TIME
	iFSusLev	=	5	;SUSTAIN LEVEL
	iFRelTim	=	0.01	;RELEASE TIME
	;CREATE AN ENVELOPE WITH A MIDI RELEASE SEGMENT TO INFLUENCE THE FILTER CUTOFF
	kFEnv		linsegr	0, iFAttTim, iFAttLev, iFDecTim, iFSusLev, iFRelTim, 0
	kCFOct		=	6	;BASE LEVEL OF THE FILTER (BEFORE THE ENVELOPE IS ADDED)
	kCFcps		=	cpsoct(kCFOct+kFEnv)	;FINAL FILTER CUTOFF VALUE (IN CPS) INCORPORATING THE FILTER ENVELOPE AND THE FILTER BASE LEVEL
	kres		=	.5	;RESOSNANCE
	iscale 		= 	1
	;CREATE A FILTERED VERSION OF THE OSCILLATOR SIGNAL
	aFilt		moogvcf	asig, kCFcps, kres ,iscale
	;SEND FILTERED SIGNAL TO OUTPUT
	aenv		linsegr	0,0.001,1,0.01,0	;ANTI CLICK ENVELOPE
			outs	aFilt * aenv, aFilt * aenv
endin

</CsInstruments>

<CsScore>
f1 0 131072 10 1  ;A SINE WAVE - USED BY BOTH THE VIBRATO AND THE vco

f 0 3600	;DUMMY SCORE EVENT - REAL TIME PERFORMANCE FOR 1 HOUR
</CsScore>

</CsoundSynthesizer>