;Written by Iain McCurdy, 2009

<CsoundSynthesizer>

<CsOptions>
-odevaudio -b400
</CsOptions>

<CsInstruments>

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

;FLTK INTERFACE CODE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
FLcolor	255, 255, 255, 0, 0, 0	;SET INTERFACE COLOURS
;					LABEL    | WIDTH | HEIGHT | X | Y
				FLpanel	"resony",   500,    440,    0,  0

;SWITCHES                       			ON | OFF | TYPE | WIDTH | HEIGHT | X | Y | OPCODE | INS | STARTTIM | IDUR
gkOnOff,ihOnOff		FLbutton	"On/Off",	1,    0,    22,    140,     25,    5,  5,    0,      1,      0,      3600
FLsetColor2	255, 255, 50, ihOnOff		;SET SECONDARY COLOUR TO YELLOW

;VALUE DISPLAY BOXES			LABEL     | WIDTH | HEIGHT | X | Y
idbf				FLvalue	" ",          80,     20,    5,  75
idbw				FLvalue	" ",          80,     20,    5, 125
idamp				FLvalue	" ",          80,     20,    5, 270
gidsep				FLvalue	"octaves",    80,     20,    5, 405

;COUNTERS								MIN | MAX | STEP1 | STEP2 | TYPE | WIDTH | HEIGHT |  X  | Y | OPCODE | INS | STARTTIM | IDUR
gkscl, ihscl 			FLcount  "Scaling Mode", 		0,      2,    1,      1,      2,    150,     25,    175, 155,     -1
gkskip, ihskip 			FLcount  "Initialisation 0-On 1-Off", 	0,      1,    1,      1,      2,    150,     25,    345,   5,     -1
gknum, ihnum 			FLcount  "Number of Filters", 		1,     80,    1,      1,      2,    150,     25,      5, 300,     -1

;SLIDERS					            			MIN | MAX | EXP | TYPE |  DISP | WIDTH | HEIGHT | X   | Y
gkbf,ihbf			FLslider 	"Base Frequency",		20,  20000, -1,    23,   idbf,    490,     25,    5,    50
gkbw,ihbw			FLslider 	"Bandwidth",			.01, 10000, -1,    23,   idbw,    490,     25,    5,   100
gkgain,ihgain			FLslider 	"Output Gain",			0,       5,  0,    23,   idamp,   490,     25,    5,   245
gksep,ihsep			FLslider 	"Separation",	        	-11,    11,  0,    23,     -1,    490,     25,    5,   380

;BORDERS				ITYPE, IFONT, ISIZE, IWIDTH, IHEIGHT, IX, IY
ih		 	FLbox  	" ", 	6,        9,    15,    230,    60,   250, 295

;GENERAL_TEXT_SETTINGS			SIZE | FONT |  ALIGN | RED | GREEN | BLUE
			FLlabel		13,      4,      1,    255,   255,   255		;LABELS MADE INVISIBLE (I.E. SAME COLOR AS PANEL)

;BUTTON BANKS			 	TYPE | NUMX | NUMY | WIDTH | HEIGHT | X | Y | OPCODE
gksepmode,   ihsepmode	FLbutBank	13,     1,     2,     18,     50,   390, 300,   -1

;GENERAL_TEXT_SETTINGS			SIZE | FONT |  ALIGN | RED | GREEN | BLUE
			FLlabel		13,      4,      1,     0,     0,     0			;LABELS MADE VISIBLE AGAIN

;TEXT BOXES						TYPE | FONT | SIZE | WIDTH | HEIGHT | X |  Y
ih		 	FLbox  	"Separation Mode:",	1,       6,    12,   120,      25,   270,  300
ih		 	FLbox  	"octaves ", 		1,       5,    12,    20,      25,   430,  299
ih		 	FLbox  	"hertz   ", 		1,       5,    12,    20,      25,   430,  324

;SET INITIAL VALUES OF FLTK VALUATORS		VALUE | HANDLE
				FLsetVal_i	1000, 	ihbf
				FLsetVal_i	30, 	ihbw
				FLsetVal_i	1, 	ihscl
				FLsetVal_i	1, 	ihgain
				FLsetVal_i	10, 	ihnum
				FLsetVal_i	2.7, 	ihsep

;TEXT BOXES																ITYPE, IFONT, ISIZE, IWIDTH, IHEIGHT, IX, IY
ih		 	FLbox  	"Scaling Modes:    0-None    1-Peak Response Factor of 1    2-Overall RMS Response Factor equals 1", 	1,        9,    12,    500,    10,     0, 203
			
				FLpanel_end

;INSTRUCTIONS AND INFO PANEL
				FLpanel	" ", 	500, 700, 512, 0
				FLscroll	500, 700, 0,   0
;TEXT BOXES												TYPE | FONT | SIZE | WIDTH | HEIGHT | X | Y
ih		 	FLbox  	"                          resony                             ", 	1,      5,     14,    490,    20,     5,  0
ih		 	FLbox  	"-------------------------------------------------------------", 	1,      5,     14,    490,    20,     5,  20
ih		 	FLbox  	"Resony is an implementation of a stack of second-order band- ", 	1,      5,     14,    490,    20,     5,  40
ih		 	FLbox  	"-pass filters whose centre frequencies are arithmetically    ", 	1,      5,     14,    490,    20,     5,  60
ih		 	FLbox  	"related.                                                     ", 	1,      5,     14,    490,    20,     5,  80
ih		 	FLbox  	"The 'bandwidth', 'scaling mode' and 'skip initialisation'    ", 	1,      5,     14,    490,    20,     5, 100
ih		 	FLbox  	"parameters are as they are in the reson opcode.              ", 	1,      5,     14,    490,    20,     5, 120
ih		 	FLbox  	"'inum' (number of filters) defines the number of filters in  ", 	1,      5,     14,    490,    20,     5, 140
ih		 	FLbox  	"the stack.                                                   ", 	1,      5,     14,    490,    20,     5, 160
ih		 	FLbox  	"'ksep' (separation) defines the separation between the lowest", 	1,      5,     14,    490,    20,     5, 180
ih		 	FLbox  	"and highest filter in the stack in octaves. How this relates ", 	1,      5,     14,    490,    20,     5, 200
ih		 	FLbox  	"to what the actual centre frequencies of filters differs     ", 	1,      5,     14,    490,    20,     5, 220
ih		 	FLbox  	"depending upon which separation mode has been selected and   ", 	1,      5,     14,    490,    20,     5, 240
ih		 	FLbox  	"is explained below.                                          ", 	1,      5,     14,    490,    20,     5, 260
ih		 	FLbox  	"'kbf' (base frequency) defines the centre frequency of the   ", 	1,      5,     14,    490,    20,     5, 280
ih		 	FLbox  	"lowest filter.                                               ", 	1,      5,     14,    490,    20,     5, 300
ih		 	FLbox  	"In 'octave' separation mode the pitch interval between the   ", 	1,      5,     14,    490,    20,     5, 320
ih		 	FLbox  	"base frequency and (base frequency + separation) is divided  ", 	1,      5,     14,    490,    20,     5, 340
ih		 	FLbox  	"into equal intervals according to the number of filters that ", 	1,      5,     14,    490,    20,     5, 360
ih		 	FLbox  	"have been selected. Note that no filter is created at the    ", 	1,      5,     14,    490,    20,     5, 380
ih		 	FLbox  	"frequency of (base frequency + separation). For example: if  ", 	1,      5,     14,    490,    20,     5, 400
ih		 	FLbox  	"separation=1 and num.filters=2 filters will be created at    ", 	1,      5,     14,    490,    20,     5, 420
ih		 	FLbox  	"the base frequency and a tritone above the base frequency    ", 	1,      5,     14,    490,    20,     5, 440
ih		 	FLbox  	"(i.e. a interval of 1/2 and octave).                         ", 	1,      5,     14,    490,    20,     5, 460
ih		 	FLbox  	"If 'hertz' separation mode is selected behaviour is somewhat ", 	1,      5,     14,    490,    20,     5, 480
ih		 	FLbox  	"curious. A filter is never created at the base frequency,    ", 	1,      5,     14,    490,    20,     5, 500
ih		 	FLbox  	"this is probably a bug but a simple workaround would be to   ", 	1,      5,     14,    490,    20,     5, 520
ih		 	FLbox  	"create a filter separately using a single instance of the    ", 	1,      5,     14,    490,    20,     5, 540
ih		 	FLbox  	"reson opcode. Therefore if num.filters=1 no filters are      ", 	1,      5,     14,    490,    20,     5, 560
ih		 	FLbox  	"actually created! num.filters=2 creates a single filter and  ", 	1,      5,     14,    490,    20,     5, 580
ih		 	FLbox  	"so on. The frequency relationship between filters in the     ", 	1,      5,     14,    490,    20,     5, 600
ih		 	FLbox  	"stack always follows the harmonic series. num.filters defines", 	1,      5,     14,    490,    20,     5, 620
ih		 	FLbox  	"how many stages up the harmonic series are created - remember", 	1,      5,     14,    490,    20,     5, 640
ih		 	FLbox  	"the fundemental will always be absent! In 'hertz' mode,      ", 	1,      5,     14,    490,    20,     5, 660
ih		 	FLbox  	"'base frequency' and 'separation' have the same effect of    ", 	1,      5,     14,    490,    20,     5, 680
ih		 	FLbox  	"moving the entire stack of filters up and down the frequency ", 	1,      5,     14,    490,    20,     5, 700
ih		 	FLbox  	"domain.                                                      ", 	1,      5,     14,    490,    20,     5, 720
ih		 	FLbox  	"Negative values for 'separation' are allowed whenever        ", 	1,      5,     14,    490,    20,     5, 740
ih		 	FLbox  	"'separation mode' is 'octaves' (if this is the case, the     ", 	1,      5,     14,    490,    20,     5, 760
ih		 	FLbox  	"stack of frequencies will extend below the base frequency).  ", 	1,      5,     14,    490,    20,     5, 780
ih		 	FLbox  	"Negative values for 'separation' when 'separation mode' is   ", 	1,      5,     14,    490,    20,     5, 800
ih		 	FLbox  	"'hertz' will cause filters to 'explode'. The code in this    ", 	1,      5,     14,    490,    20,     5, 820
ih		 	FLbox  	"example allows negative values for 'separation' whenever     ", 	1,      5,     14,    490,    20,     5, 840
ih		 	FLbox  	"'separation mode' is 'octaves' but prevents them whenever    ", 	1,      5,     14,    490,    20,     5, 860
ih		 	FLbox  	"'separation mode' is 'hertz'.                                ", 	1,      5,     14,    490,    20,     5, 880

				FLscroll_end
				FLpanel_end

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

instr	1
	if	gkOnOff=0	then	;IF On/Off SWITCH IS SET TO 'OFF'...
		turnoff			;TURN THIS INSTRUMENT OFF
	endif				;END OF CONDITIONAL BRANCHING
	kporttime	linseg	0,0.001,0.005,1,0.005	;CREATE A VARIABLE FUNCTION THAT RAPIDLY RAMPS UP TO A SET VALUE	
	kbf	portk	gkbf, kporttime	;SMOOTH MOVEMENT OF SLIDER VARIABLE
	;OUTPUTS	OPCODE	FILE           | SPEED | INSKIP | LOOPING (0=OFF 1=ON)
	asigL, asigR	diskin2	"Seashore.wav",    1,       0,         1	;GENERATE 2 AUDIO SIGNALS FROM A STEREO SOUND FILE (NOTE THE USE OF GLOBAL VARIABLES)
	kSwitch		changed	gkscl, gkskip, gknum, gksepmode		;GENERATE A MOMENTARY '1' PULSE IN OUTPUT 'kSwitch' IF ANY OF THE SCANNED INPUT VARIABLES CHANGE. (OUTPUT 'kSwitch' IS NORMALLY ZERO)
	if	kSwitch=1	then		;IF I-RATE VARIABLE CHANGE TRIGGER IS '1'...
		reinit	START			;BEGIN A REINITIALISATION PASS FROM LABEL 'START'
	endif
	START:
	;IF SEPARATION MODE IS 'HERTZ' THEN SEPARATION SHOULD NOT BE LESS THAT 1, THE FOLLOWING 5 LINES OF CODE PROTECT AGAINST THIS 
	if	gksepmode==1	then		;IF gksepmode IS 'HERTZ'...
		ksep	=	abs(gksep)      ;...FINAL SEPARATION VALUE IS AN ABSOLUTE VERSION OF gksep (I.E. CANNOT BE NEGATIVE)
	else                                    ;IF gksepmode IS OCTAVES...
		ksep	=	gksep           ;
	endif                                   ;END OF CONDITIONAL BRANCHING
	ksep	lineto	ksep, 0.05	;SMOOTH MOVEMENT OF SLIDER VARIABLE
	aresL 		resony 	asigL, kbf, gkbw, i(gknum), ksep , i(gksepmode), i(gkscl), i(gkskip)
	aresR 		resony 	asigR, kbf, gkbw, i(gknum), ksep , i(gksepmode), i(gkscl), i(gkskip)
	rireturn	;RETURN FROM REINITIALISATION PASS TO PERFORMANCE TIME PASSES
	outs	aresL * gkgain, aresR * gkgain	;SEND FILTER OUTPUT TO THE AUDIO OUTPUTS AND SCALE USING THE FLTK SLIDER VARIABLE gkgain
endin

instr	2	;UPDATE SEPARATION VALUE DISPLAY BOX DEPENDING UPON CHOSEN MODE
	if	gksepmode==1	then		;IF gksepmode IS 'HERTZ'...
		ksep	=	abs(gksep)      ;...FINAL SEPARATION VALUE IS AN ABSOLUTE VERSION OF gksep (I.E. CANNOT BE NEGATIVE)
		FLprintk2	ksep, gidsep	;UPDATE SEPARATION DISPLAY BOX IF VALUE HAS CHANGED
	else                                    ;IF gksepmode IS OCTAVES...
		ksep	=	gksep           ;
		FLprintk2	ksep, gidsep	;UPDATE SEPARATION DISPLAY BOX IF VALUE HAS CHANGED
	endif                                   ;END OF CONDITIONAL BRANCHING
endin

</CsInstruments>

<CsScore>
i 2 0 3600	;UPDATE SEPARATION DISPLAY BOX
</CsScore>

</CsoundSynthesizer>