;Written by Iain McCurdy, 2008

<CsoundSynthesizer>

<CsOptions>
-odac4 -d -m0 -M0 -b20
</CsOptions>

<CsInstruments>

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


;FLTK INTERFACE CODE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
FLcolor	255, 255, 255, 50, 0, 0
		FLpanel	"Live Quantize", 300, 150, 0, 0

;BUTTONS                                     			ON | OFF | TYPE | WIDTH | HEIGHT | X | Y | OPCODE | I | STARTTIM | IDUR
gkLiveQuantize,ihLiveQuantize	FLbutton	"On/Off",	1,    0,    22,    100,     25,    5,  5,   0,      2,     0,      3600
FLsetColor2	255, 255, 50, ihLiveQuantize	;SET SECONDARY COLOUR TO YELLOW

;COUNTERS						MIN | MAX | STEP1 | STEP2 | TYPE | WIDTH | HEIGHT | POS_X | POS_Y | IOPCODE
gkTempo,ihTempo 	FLcount		"Tempo",	1,    999,    1,     10,     21,   100,     20,      10,     50,      -1
gkNoteVal,ihNoteVal 	FLcount		"Beat Subdiv.",	1,      4,    1,     10,      2,   100,     20,     120,     50,      -1

;SLIDERS								MIN | MAX | EXP | TYPE |   DISP   | WIDTH | HEIGHT | X   | Y
gkMetroGain, ihMetroGain	FLslider	"Metronone Vol.",	0,     1,  0,       5,     -1,      280,     20,    10,   100


;GENERAL_TEXT_SETTINGS			isize, ifont, ialign, ired, igreen, iblue
			FLlabel		13,      1,       1,   255,  255,   255		;NUMBERS MADE INVISIBLE
;		FLBUTBANK 	TYPE | NUMX | NUMY | WIDTH | HEIGHT | X | Y | IOPCODE | P1 | P2 | P3
gkbar, gihbar	FLbutBank	4,     4,     1,     100,      20,   150, 10,   -1
;GENERAL_TEXT_SETTINGS			isize, ifont, ialign, ired, igreen, iblue
			FLlabel		13,      5,      4,   0,      0,     0		;LABELS MADE VISIBLE AGAIN

		FLsetVal_i	70, 	ihTempo
		FLsetVal_i	 1, 	ihNoteVal
		FLsetVal_i	 1, 	ihMetroGain

		FLpanel_end	;END OF PANEL CONTENTS

;INSTRUCTIONS AND INFO PANEL
				FLpanel	" ", 515, 380, 312, 0
;TEXT BOXES												TYPE | FONT | SIZE | WIDTH | HEIGHT | X | Y
ih		 	FLbox  	"                       Live Quantize                         ", 	1,      5,     14,    490,    20,     5,  0
ih		 	FLbox  	"-------------------------------------------------------------", 	1,      5,     14,    490,    20,     5,  20
ih		 	FLbox  	"This example quantizes an incoming stream of MIDI notes      ", 	1,      5,     14,    490,    20,     5,  40
ih		 	FLbox  	"according to an internal metronone.                          ", 	1,      5,     14,    490,    20,     5,  60
ih		 	FLbox  	"If a MIDI note-on is received the orchestra calculates how   ", 	1,      5,     14,    490,    20,     5,  80
ih		 	FLbox  	"much time will elapse until the next beat and then delays the", 	1,      5,     14,    490,    20,     5, 100
ih		 	FLbox  	"onset of the note by that amount.                            ", 	1,      5,     14,    490,    20,     5, 120
ih		 	FLbox  	"To provide the user with the frame of reference used by the  ", 	1,      5,     14,    490,    20,     5, 140
ih		 	FLbox  	"orchestra, a metronome sounds the beats of a 4/4 bar as well ", 	1,      5,     14,    490,    20,     5, 160
ih		 	FLbox  	"as this being indicated visually with flashing dots.         ", 	1,      5,     14,    490,    20,     5, 180
ih		 	FLbox  	"'Beat Subdiv' defines how the quantizing grid relates to the ", 	1,      5,     14,    490,    20,     5, 200
ih		 	FLbox  	"beats outlined by the metronome. Giving this a value of '1'  ", 	1,      5,     14,    490,    20,     5, 220
ih		 	FLbox  	"will cause each note-on to be moved to the next beat, giving ", 	1,      5,     14,    490,    20,     5, 240
ih		 	FLbox  	"it a value of '4' will cause it to move each note-on to the  ", 	1,      5,     14,    490,    20,     5, 260
ih		 	FLbox  	"next quarter of a beat.                                      ", 	1,      5,     14,    490,    20,     5, 280
ih		 	FLbox  	"Note onset delay is implemented by passing the duty of       ", 	1,      5,     14,    490,    20,     5, 300
ih		 	FLbox  	"sounding the note onto another instrument through the        ", 	1,      5,     14,    490,    20,     5, 320
ih		 	FLbox  	"'schedkwhen' opcode. The 'start time' of the scheduled note  ", 	1,      5,     14,    490,    20,     5, 340
ih		 	FLbox  	"is given the value of the derived delay time.                ", 	1,      5,     14,    490,    20,     5, 360
				FLpanel_end
		FLrun		;RUN THE WIDGET THREAD!

gisine		ftgen	0,0,65537,10,1	;A SINE WAVE

giSubDiv	=	1000	;SUBDIVISION OF THE BEAT (ESSENTIALLY THIS WILL DETERMINE THE PRECISION OF THE QUANTIZING EFFECT
;maxalloc	4,1		;POLYPHONY CONTROL FOR THE SOUND PREODUCING INSTRUMENT
gkTempoClock	init	0	;INITIALISE VARIABLE FOR MAIN CLOCK	


instr	2	;TURNS ON THE QUANTISER
	gkTempoClock	init	0	;INITIALISE VARIABLE FOR MAIN CLOCK	
	if	gkLiveQuantize!=0	goto	CONTINUE
	turnoff
	CONTINUE:
	kTrigger	metro	(gkTempo*giSubDiv*gkNoteVal)/60
	schedkwhen	kTrigger, 0, 0, p1+1, 0, 0.001

	kMetronome	metro	gkTempo/240
	kbeat		=	240/gkTempo
	schedkwhen	kMetronome, 0, 0, 5, 0,         .05, 600, 0
	schedkwhen	kMetronome, 0, 0, 5, kbeat*.25, .05, 300, 1
	schedkwhen	kMetronome, 0, 0, 5, kbeat*.50, .05, 300, 2
	schedkwhen	kMetronome, 0, 0, 5, kbeat*.75, .05, 300, 3	
endin

instr	3	;INCREMENT THE CLOCK BY 1 SUBDIVISION
	kTempoClock	=	gkTempoClock + (1/giSubDiv)
	gkTempoClock	=	kTempoClock
	turnoff	
endin

instr	1	;MIDI TRIGGERED INSTRUMENT
	icps		cpsmidi
	iamp		veloc	0,0.2
	idelay		=	frac(i(gkTempoClock))
	idelay		=	(1-idelay)*(60/(i(gkTempo)*i(gkNoteVal)))
	event_i	"i", p1+3, idelay, 1, icps, iamp
endin

instr	4	;SOUND PRODUCING INSTRMENT
	aenv	expseg	0.0001, 0.01, 1, p3-0.01, 0.0001
	a1	oscili	aenv*p5, p4, gisine
	outs	a1, a1
endin


instr	5	;METRONOME SOUND GENERATOR
	if	gkLiveQuantize=0	then
		turnoff
	endif
	aenv	linseg	0,0.001,1,p3-0.001,0
	asig	oscili	0.2*aenv*i(gkMetroGain),p4,gisine
	outs	asig, asig
	FLsetVal_i	p5, gihbar
endin

</CsInstruments>

<CsScore>
f 0 3600
</CsScore>

</CsoundSynthesizer>