CsoundIsListening.csd
WRITTEN BY IAIN MCCURDY, 2011

This example exemplifies the technique of opcode iteration using UDOs to create a mass of oscillators using a small amount of code.
This technique is introduced and explained in detail by Steven Yi in his article 'Control Flow - Part II' in the summer 2006 issue of the Csound Journal (http://www.csounds.com/journal/2006summer/controlFlow_part2.html).

In this example 100 vco2 oscillators are created but you can change this number in instrument 1 if you like, increasing it if your system permits it in realtime.
Each oscillator exhibits its own unique behaviour in terms of its pitch, pulse width and panning.
The entire mass morphs from a state in which the oscillator pitches slowly glide about randomly to a state in which they hold a fixed pitch across a range of octaves.

Some commercial synthesizers offer oscillators called 'mega-saws' or something similar. These are normally just clusters of detuned sawtooth waveforms so this is the way in which this could be emulated in Csound.

The example emulates a familiar sound ident. It is for educational purposes and no breach of copyright is intended.

<CsoundSynthesizer>

<CsOptions>
-odac -dm0
</CsOptions>

<CsInstruments>
sr = 44100
ksmps = 64
nchnls = 2
0dbfs = 1	;MAXIMUM AMPLITUDE
zakinit 3,3	;INITIALISE ZAK VARIABLE STORAGE SPACE

;INITIALISE REVERB SEND VARIABLES
gasendL	init	0
gasendR	init	0

;DEFINE A UDO FOR AN OSCILLATOR VOICE
opcode	vcomodule, 0, ii										;DEFINE OPCODE FORMAT
	icount,inum  xin										;DEFINE NAMES FOR INPUT ARGUMENTS
	kvar	jspline	15,0.1,0.2									;RANDOM JITTERING OF PITCH
	kpw	rspline	0.05,0.5,0.4,0.8								;RANDOM MOVEMENT OF PULSE WIDTH FOR vco2
	imorphtime	random	5.5,6.5									;TIME TO MORPH FROM GLIDING PITCHES TO STATIC PITCHES WILL DIFFER SLIGHTLY FROM VOICE TO VOICE
	kxfade	linseg	0,7, 0,imorphtime, 0.999,2, 0.999						;FUNCTION DEFINING MORPH FROM GLIDING TO STATIC VOICES IS CREATED				
	ioct	wrap	icount,0,8									;BASIC OCTAVE FOR EACH VOICE IS DERIVED FROM VOICE COUNT NUMBER (WRAPPED BETWEEN 0 AND 8 TO PREVENT RIDICULOUSLY HIGH TONES)
	iinitoct	random	0,2									;DEFINES THE SPREAD OF VOICES DURING THE GLIDING VOICES SECTION
	kcps	ntrpol	200*semitone(kvar)*octave(iinitoct),cpsoct(3+ioct+octpch(0.025)),kxfade		;PITCH (IN CPS) OF EACH VOICE - MORPHING BETWEEN A RANDOMLY GLIDING STAGE AND A STATIC STAGE
	koct	=	octcps(kcps)									;PITCH CONVERTED TO OCT FORMAT
	kdb	=	(5-koct)*4									;DECIBEL VALUE DERIVED FROM OCT VALUE - THIS WILL BE USED FOR 'AMPLITUDE SCALING' TO PREVENT EMPHASIS OF HIGHER PITCHED TONES
	a1	vco2	ampdb(kdb)*0.12,kcps,4,kpw,0							;THE OSCILLATOR IS CREATED
	kPanDep	linseg	0,5,0,6,0.5									;RANDOM PANNING DEPTH WILL MOVE FROM ZERO (MONOPHONIC) TO FULL STEREO AT THE END OF THE NOTE
	kpan	rspline 0.5+kPanDep,0.5-kPanDep,0.3,0.5							;RANDOM PANNING FUNCTION
	aL,aR	pan2	a1,kpan										;MONO OSCILLATOR IS RANDOMLY PANNED IN A SMOOTH GLIDING MANNER
	zawm	aL,0											;LEFT CHANNEL MIXED INTO ZAK VARIABLE
	zawm	aR,1											;RIGHT CHANNEL MIXED INTO ZAK VARIABLE
	icount	=	icount + 1									;INCREMENT VOICE COUNT COUNTER
	if	icount <= inum	then									;IF TOTAL VOICE LIMIT HAS NOT YET BEEN REACHED...
		vcomodule	icount, inum								;...CALL THE UDO AGAIN (WITH THE INCREMENTED COUNTER)
	endif												;END OF THIS CONDITIONAL BRANCH
endop

instr	1
	prints	"See .csd for explanation..."
	inum	=		100								;NUMBER OF VOICES
	icount	init		0								;INITIALISE VOICE COUNTER
		vcomodule	icount,inum							;CALL vcomodule UDO (SUBSEQUENT CALLS WILL BE MADE WITHIN THE UDO ITSELF)
	aoutL	zar		0								;READ ZAK CHANNEL (MIX OF ALL VOICES LEFT CHANNEL)
	aoutR	zar		1								;READ ZAK CHANNEL (MIX OF ALL VOICES RIGHT CHANNEL)
		aoutL	dcblock	aoutL								;REMOVE DC OFFSET FROM AUDIO (LEFT CHANNEL)
		aoutR	dcblock	aoutR								;REMOVE DC OFFSET FROM AUDIO (RIGHT CHANNEL)
		kenv		linseg	-90,(1), -50,(6), -20,(6), 0,(p3-16),  0,(3), -90	;AMPLITUDE ENVELOPE THAT WILL BE APPLIED TO THE MIX OF ALL VOICES
		aoutL	=	aoutL*ampdb(kenv)						;APPLY ENVELOPE (LEFT CHANNEL)
		aoutR	=	aoutR*ampdb(kenv)						;APPLY ENVELOPE (RIGHT CHANNEL)
		outs		aoutL,aoutR							;SEND AUDIO TO OUTPUTS
		zacl		0,3								;CLEAR ZAK AUDIO VARIABLES
		gasendL	=	gasendL+(aoutL*0.5)						;MIX SOME AUDIO INTO THE REVERB SEND VARIABLE (LEFT CHANNEL)
		gasendR	=	gasendR+(aoutR*0.5)						;MIX SOME AUDIO INTO THE REVERB SEND VARIABLE (RIGHT CHANNEL)
endin

instr	2	;REVERB INSTRUMENT
	aRvbL,aRvbR	reverbsc	gasendL,gasendR,0.82,10000
	outs	aRvbL,aRvbR
	clear	gasendL,gasendR
endin
</CsInstruments>

<CsScore>
i 1 0 20	;SYNTH VOICES GENERATING INSTRUMENT
i 2 0 25	;REVERB INSTRUMENT
</CsScore>

</CsoundSynthesizer>
