delayCompletedPitchShifter.csd
Written by Iain McCurdy, 2006

<CsoundSynthesizer>

<CsOptions>
-iadc -odac -M0 -+rtmidi=virtual -+raw_controller_mode=1 -dm0
</CsOptions>

<CsInstruments>

sr 		= 	44100	;SAMPLE RATE
ksmps 		= 	1	;NUMBER OF AUDIO SAMPLES IN EACH CONTROL CYCLE (MAY NEED TO BE LOW WHEN WORKING WITH SHORT DELAY TIMES DEFINED INITIALLY AT KRATE)
nchnls 		= 	2	;NUMBER OF CHANNELS (2=STEREO)
0dbfs		=	1	;MAXIMUM AMPLITUDE

;FLTK INTERFACE CODE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
FLcolor	255, 255, 255, 0, 0, 0	;SETUP BASIC COLOURS
;			LABEL             | WIDTH | HEIGHT | X | Y
	FLpanel	"Completed Pitch Shifter",   500,    200,    0,  0

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

;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
gkinput, ihinput	FLbutBank	14,     1,     2,     18,      40,  165,  0,   -1

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

;TEXT BOXES						TYPE | FONT | SIZE | WIDTH | HEIGHT | X |  Y
ih		 	FLbox  	"Source:",		1,       6,    12,    40,      18,   120,  0
ih		 	FLbox  	"Soundfile", 		1,       5,    12,    60,      20,   190,  0
ih		 	FLbox  	"Live     ", 		1,       5,    12,    60,      20,   190, 20

;VALUE_DISPLAY_BOXES		WIDTH | HEIGHT | X | Y
idtrans		FLvalue   " ",	88,       20,    5,   75
iddlt		FLvalue   " ",	88,       20,    5,  125
idFB		FLvalue   " ",	88,       20,    5,  175

;SLIDERS					            			MIN | MAX | EXP | TYPE |   DISP    | WIDTH | HEIGHT | X | Y
gkGain,ihGain			FLslider 	"Gain",				0,      1,    0,    23,   -1,         230,     20,  265,   5
gktrans,gihtrans		FLslider 	"Transposition (semitones)",	-24,   24,    0,    23,   idtrans,    490,     25,    5,  50
gkdlt,gihdlt			FLslider 	"Delay Time (CC#1)",		0.01,   2,   -1,    23,   iddlt,      490,     25,    5, 100
gkFB,gihFB			FLslider	"Feedback (CC#2)",  		0,      1,    0,    23,   idFB,       490,     25,    5, 150

;SET_INITIAL_VALUES		VALUE | HANDLE
		FLsetVal_i	0.5, 	ihGain
		FLsetVal_i   	0, 	gihtrans
		FLsetVal_i   	0.05, 	gihdlt
		FLsetVal_i   	0, 	gihFB

		FLpanel_end	;END OF PANEL CONTENTS

;INSTRUCTIONS AND INFO PANEL
				FLpanel	" ", 500, 640, 512, 0
;TEXT BOXES												TYPE | FONT | SIZE | WIDTH | HEIGHT | X | Y
ih		 	FLbox  	"               delay - completed pitch shifter               ", 	1,      5,     14,    490,    20,     5,  0
ih		 	FLbox  	"-------------------------------------------------------------", 	1,      5,     14,    490,    20,     5,  20
ih		 	FLbox  	"This example is an refinement of the 'Delay: Simple Pitch    ", 	1,      5,     14,    490,    20,     5,  40
ih		 	FLbox  	"Shifter' example in that amplitude enveloping is employed to ", 	1,      5,     14,    490,    20,     5,  60
ih		 	FLbox  	"prevent glitching in the sound output whenever the sawtooth  ", 	1,      5,     14,    490,    20,     5,  80
ih		 	FLbox  	"LFO waveform that modulates delay time instantaneously jumps ", 	1,      5,     14,    490,    20,     5, 100
ih		 	FLbox  	"from a maximum to a minimum (or vice versa).                 ", 	1,      5,     14,    490,    20,     5, 120
ih		 	FLbox  	"Two modulated delay taps (180 degrees out of phase with each ", 	1,      5,     14,    490,    20,     5, 140
ih		 	FLbox  	"other) are employed and are enveloped individually.          ", 	1,      5,     14,    490,    20,     5, 160
ih		 	FLbox  	"The outputs of the two delay taps are mixed to create an - as", 	1,      5,     14,    490,    20,     5, 180
ih		 	FLbox  	"smooth as possible - pitch shifted output.                   ", 	1,      5,     14,    490,    20,     5, 200
ih		 	FLbox  	"Pitch shifting effects can also be produced using any of the ", 	1,      5,     14,    490,    20,     5, 220
ih		 	FLbox  	"granular synthesis opcodes but this method has the advantage ", 	1,      5,     14,    490,    20,     5, 240
ih		 	FLbox  	"that it can be applied to a streamed live audio input or a   ", 	1,      5,     14,    490,    20,     5, 260
ih		 	FLbox  	"signal generated within Csound and it does not rely upon a   ", 	1,      5,     14,    490,    20,     5, 280
ih		 	FLbox  	"stored function table.                                       ", 	1,      5,     14,    490,    20,     5, 300
ih		 	FLbox  	"Some experimentation with the setting for 'Delay Time' can   ", 	1,      5,     14,    490,    20,     5, 320
ih		 	FLbox  	"enhance the resultant sound quality. An appropriate setting  ", 	1,      5,     14,    490,    20,     5, 340
ih		 	FLbox  	"for 'Delay Time' is partially dependent upon the type of     ", 	1,      5,     14,    490,    20,     5, 360
ih		 	FLbox  	"sound material being processed. Most hardware implementations", 	1,      5,     14,    490,    20,     5, 380
ih		 	FLbox  	"of pitch shifters do not include this parameter.             ", 	1,      5,     14,    490,    20,     5, 400
ih		 	FLbox  	"Large values for 'Delay Time' tend to temporally smear the   ", 	1,      5,     14,    490,    20,     5, 420
ih		 	FLbox  	"processed sound whereas excessively small values for 'Delay  ", 	1,      5,     14,    490,    20,     5, 440
ih		 	FLbox  	"Time' tend to distort the harmonic content of the original   ", 	1,      5,     14,    490,    20,     5, 460
ih		 	FLbox  	"sound.                                                       ", 	1,      5,     14,    490,    20,     5, 480
ih		 	FLbox  	"The 'Feedback' control allows some of the pitch shifted      ", 	1,      5,     14,    490,    20,     5, 500
ih		 	FLbox  	"output to be fed back into the input thus allowing the       ", 	1,      5,     14,    490,    20,     5, 520
ih		 	FLbox  	"creation of arpeggiation effects.                            ", 	1,      5,     14,    490,    20,     5, 540
ih		 	FLbox  	"MIDI can be used to control 'Transposition', 'Delay Time' and", 	1,      5,     14,    490,    20,     5, 560
ih		 	FLbox  	"'Feedback'. MIDI notes played shift the transposition slider ", 	1,      5,     14,    490,    20,     5, 580
ih		 	FLbox  	"in semitone steps, middle C represents zero transposition.   ", 	1,      5,     14,    490,    20,     5, 600
ih		 	FLbox  	"CC#1 controls 'Delay Time' and CC#2 controls 'Feedback'.     ", 	1,      5,     14,    490,    20,     5, 620

				FLpanel_end

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

gihalfsine	ftgen	0, 0, 1025, 9, 0.5, 1, 0	;HALF SINE  WINDOW FUNCTION USED FOR AMPLITUDE ENVELOPING

instr	1	;MIDI INPUT - TRANSFER NOTE INPUT INFORMATION TO TRANSPOSITION FLTK SLIDER
	inotnum	notnum				;READ IN MIDI NOTE NUMBER
	inotnum	limit	inotnum - 60, -24, 24	;SHIFT NOTE NUMBER (-60) AND LIMIT RANGE
						;MIDDLE C WILL REPRESENT NO TRANSPOSITION AND TRANSPOSITION WILL BE POSSIBLE UP OR DOWN 2 OCTAVES FROM THIS POINT
	FLsetVal_i	inotnum, gihtrans	;SEND NOTE NUMBER DERIVED INFORMATION TO TRANSPOSITION SLIDER
endin

instr	2	;READ IN MIDI CONTINUOUS CONTROLLER INFORMATION AND TRANFER TO FLTK SLIDERS
	;CC#1(DELAY TIME)===============================================================================================================
	kcc1	ctrl7	1, 1, 0, 1		;READ IN MIDI CC 1 (CHANNEL 1)
	ktrig1	changed	kcc1			;GENERATE A TRIGGER IF CONTROLLER CHANGES
	kcc1	pow	kcc1, 4			;RAISE TO THE POWER OF 4 (TO BETTER MATCH RESPONSE OF FLTK SLIDER)
	kcc1	scale	kcc1, 2, 0.01		;RESCALE WITHIN THE RANGE 0.01 AND 2
	FLsetVal	ktrig1, kcc1, gihdlt	;SEND VALUE TO FLTK SLIDER
	;CC#2(FEEDBACK)=================================================================================================================
	kcc2	ctrl7	1, 2, 0, 1		;READ IN MIDI CC 2 (CHANNEL 1)
	ktrig2	changed	kcc2			;GENERATE A TRIGGER IF CONTROLLER CHANGES
	FLsetVal	ktrig2, kcc2, gihFB	;SEND VALUE TO FLTK SLIDER
	;===============================================================================================================================
endin

instr	3	;PLAYS FILE
	if gkOnOff=0	then	;SENSE FLTK ON/OFF SWITCH
			turnoff	;TURN THIS INSTRUMENT OFF IMMEDIATELY
	endif			;END OF CONDITIONAL BRANCHING
	if	gkinput=0	then
		;OUTPUT		OPCODE	FILE           | SPEED | INSKIP | LOOPING (0=OFF 1=ON)
		asigL		diskin2	"AndItsAll.wav",     1,       0,        1
		asigR		=	asigL	;ASSIGN aR (RIGHT CHANNEL) TO BE THE SAME AS aL (LEFT CHANNEL)
	else
		asigL, asigR	ins
	endif
	aenv	linsegr	0,0.01,1,0.01,0	;ANTI CLICK ENVELOPE WITH RELEASE STAGE
	gasigL		=	asigL * gkGain * aenv	;RESCALE AUDIO SIGNAL WITH ON-SCREEN GAIN SLIDER
	gasigR		=	asigR * gkGain * aenv	;RESCALE AUDIO SIGNAL WITH ON-SCREEN GAIN SLIDER
endin

instr	4	;PITCH SHIFTER
	kporttime	linseg	0,0.001,0.005,1,0.005	;CREATE A VARIABLE FUNCTION THAT RAPIDLY RAMPS UP TO A SET VALUE
	ktrans		portk	gktrans, kporttime	;SMOOTH CHANGES IN SLIDER VARIABLE
	kdlt		portk	gkdlt, kporttime*100	;SMOOTH CHANGES IN SLIDER VARIABLE
	koctfract	=	ktrans/12		;TRANSPOSITION AS FRACTION OF AN OCTAVE
	kratio		=	octave(koctfract)	;RATIO TO PRODUCE PITCH SHIFT
	krate		=	(kratio-1)/kdlt		;SUBTRACT 1/1 SPEED
	
	aphase1		phasor	-krate				;MOVING PHASE 1-0
	aphase2		phasor	-krate, .5			;MOVING PHASE 1-0 - PHASE OFFSET BY 180 DEGREES (.5 RADIANS)
	
	agate1		tablei	aphase1, gihalfsine, 1, 0, 1	;WINDOW FUNC =HALF SINE
	agate2		tablei	aphase2, gihalfsine, 1, 0, 1	;WINDOW FUNC =HALF SINE

	;LEFT CHANNEL===========================================================================================================================================================
	aignore		delayr	2				;DECLARE DELAY BUFFER
	adelsig1L	deltap3	aphase1 * kdlt			;VARIABLE TAP
	aGatedSig1L	=	adelsig1L * agate1
			delayw	gasigL + (aGatedSig1L*gkFB)	;WRITE AUDIO TO THE BEGINNING OF THE DELAY BUFFER, MIX IN FEEDBACK SIGNAL - PROPORTION DEFINED BY gkFB
	
	aignore		delayr	2				;DECLARE DELAY BUFFER
	adelsig2L	deltap3	aphase2 * kdlt			;VARIABLE TAP
	aGatedSig2L	=	adelsig2L * agate2
			delayw	gasigL + (aGatedSig2L*gkFB)	;WRITE AUDIO TO THE BEGINNING OF THE DELAY BUFFER, MIX IN FEEDBACK SIGNAL - PROPORTION DEFINED BY gkFB
	;=======================================================================================================================================================================


	;RIGHT CHANNEL==========================================================================================================================================================
	aignore		delayr	2				;DECLARE DELAY BUFFER
	adelsig1R	deltap3	aphase1 * kdlt			;VARIABLE TAP
	aGatedSig1R	=	adelsig1R * agate1
			delayw	gasigR + (aGatedSig1R*gkFB)	;WRITE AUDIO TO THE BEGINNING OF THE DELAY BUFFER, MIX IN FEEDBACK SIGNAL - PROPORTION DEFINED BY gkFB
	
	aignore		delayr	2				;DECLARE DELAY BUFFER
	adelsig2R	deltap3	aphase2 * kdlt			;VARIABLE TAP
	aGatedSig2R	=	adelsig2R * agate2
			delayw	gasigR + (aGatedSig2R*gkFB)	;WRITE AUDIO TO THE BEGINNING OF THE DELAY BUFFER, MIX IN FEEDBACK SIGNAL - PROPORTION DEFINED BY gkFB
	;=======================================================================================================================================================================
			
	aGatedMixL	=	(aGatedSig1L + aGatedSig2L) * .5;SUM AND RESCALE PITCH SHIFTER OUTPUTS (LEFT CHANNEL)
	aGatedMixR	=	(aGatedSig1R + aGatedSig2R) * .5;SUM AND RESCALE PITCH SHIFTER OUTPUTS (RIGHT CHANNEL)
			outs	aGatedMixL, aGatedMixR		;SEND AUDIO TO OUTPUTS
			clear	gasigL, gasigR			;CLEAR GLOBAL AUDIO VARIABLES
endin

</CsInstruments>

<CsScore>
;INSTR | START | DURATION
i  2       0      3600	;INSTRUMENT 2 READS IN CONTINUOUS CONTROLLER INFORMATION AND SENDS IT TO FLTK SLIDERS
i  4       0      3600	;INSTRUMENT 3 (THE PITCH SHIFTER) PLAYS A HELD NOTE
</CsScore>

</CsoundSynthesizer>
