Mix audio array into a single audio signal

Hi all, I’m trying to develop an oscillator bank UDO with a parametrizable oscillator count. I’m using multiple vco2 in a loop and put their audio output in an audio array:

opcode oscillators, a, iii
  setksmps 1
  iFreq, iDetune, iOscilCount xin
  iIndexOffset = (iOscilCount - 1) / 2
  aOuts[] init iOscilCount
  kIndex = 0
  while kIndex < iOscilCount do
    aOuts[kIndex] vco2 1, iFreq + iDetune * (kIndex - iIndexOffset)
    kIndex += 1
  od
  xout [aOuts as a single audio value]
endop

How to do it?

You can’t do it like this as vco2 had internal state. To do this, modify your UDO so it’s recursive. Then each instance of vco2 will be unique.

1 Like

Thanks for the tip.

Here’s my working oscillator bank implemented with a recursive UDO. Thanks again Rory.

opcode vco2Bank, a, kkioOo
  kFreq, kDetune, iCount, iMode, kPulseWidth, iIndex xin
  iFactor = 1 / (iCount - 1) * iIndex
  iDetuneFactor = iFactor * 2 - 1
  kOscFreq = kFreq + kDetune * iDetuneFactor
  aSig vco2 0dbfs / iCount, kOscFreq, iMode, kPulseWidth
  if iIndex < iCount - 1 then
    aSig2 vco2Bank kFreq, kDetune, iCount, iMode, kPulseWidth, iIndex + 1
    aSig += aSig2
  endif
  xout aSig
endop

Thanks for sharing the solution. Btw, in Csound 7 it will be possible to do this kind of thing without a recursive UDO. :+1:

And how will it be done? What change are you referring to?

You can read about it here - ( I’m still not 100% on how it will work )

1 Like

Hi Rory

Still trying to wrap my head around this new Csound 7 stuff.

Is it related to this? What's New in Csound 7 - Csound 7 Manual

I can’t see how to translate the following udo into the new Cs7 opcode references…or is this unrelated? Do we just do this in Instr now?

:laughing: :confounded:

opcode FlooperOverlap(amp:k, freq:k, nvoices:i, idx:i):(a)
	sig:a = poscil(amp/nvoices, freq) 
	if idx < nvoices then
		sig += FlooperOverlap(amp, freq+random(-50,50), nvoices, idx+1)	
	endif
	xout(sig)
endop

I think the section on Opcode Reference and Opcode Types outlines how this can be done within an instrument. flooper has internal state which is why we must run it in a recursive UDO. But in Csound7 it looks like you can create an instance of an opcode, and then create a bank of that opcode. I haven’t done this myself yet, but let me reach out Victor and ask him for an example. :+1:

Victor just sent me this example of calling opcodes in parallel within an instrument. The run opcode isn’t document yet, but the first parameter is the opcode reference and the next parameters are those you would send to the opcode itself. By using arrays you don’t need any loops.

// parallel connection
instr 6
   freq:i[] fillarray p5*0.75, p5, p5*1.333, p5*1.666
   obj:Opcode[] create reson, lenarray(freq)
   src:a rand linenr(p4,0.1,0.1,0.01)
   sig:a[] run obj, src, freq, freq/p6, 2
   out sumarray(sig)/lenarray(sig)
endin

Your opcode should work just as fast because UDOs in Csound 7 work with references, not copies. So it comes down to personal preference. :+1:

1 Like

This is a fascinating example!
Quite incredible, what Csound7 can do.
tarmo

Kontakt Rory Walsh via The Csound Community (<noreply@forum.csound.com>) kirjutas kuupäeval N, 2. oktoober 2025 kell 19:14:

Woowz thanks for this! something new to unpick here…powerful stuff

…Separately I’m having an issue with a Cs7 udo, but I’ll start a new topic for that

cheers Rory!