flavio
(Flavio)
February 2, 2025, 11:14pm
#1
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?
rory
(Rory Walsh)
February 2, 2025, 11:17pm
#2
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
flavio
(Flavio)
February 16, 2025, 2:12pm
#4
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
rory
(Rory Walsh)
February 17, 2025, 9:12am
#5
Thanks for sharing the solution. Btw, in Csound 7 it will be possible to do this kind of thing without a recursive UDO.
flavio
(Flavio)
February 17, 2025, 11:05am
#6
And how will it be done? What change are you referring to?
rory
(Rory Walsh)
February 17, 2025, 11:48am
#7
You can read about it here - ( I’m still not 100% on how it will work )
csound:develop
← csound:feature/instancetype
opened 11:07AM - 27 Nov 24 UTC
This PR introduces an instance ref type, some overloads, and new opcodes.
Ins… tance ref type
----
Following on from the introduction of the instrument definition ref type, we know have an instance ref type that can be used to manipulate instances running in Csound. The type name is `Instr`.
- it takes over from the use of plain k- and i-rate variables to hold instances,
- it allows new operations on instances.
The use of MYFLT to hold instance pointers was always problematic because these types do not have enough size to accommodate a pointer in some situations (e.g. floats version running in 64bit architectures). Compounding the problem, the code in 6.x only used the mantissa bytes to hold the pointer and so that was problematic also in doubles version running on 64bit systems. Since the use of this was limited to two opcodes (`nstance` and `turnoff`), we can now deprecate the i-/k- versions.
Instance chains
-----------
Csound maintains lists (chains) of instances so the performance order can be established and memory can be managed. There are two important chains:
- active list: instances on this list are performed in the order they have been linked into. The standard order is by ascending p1.
- free instance list: instances on this list are free to be inserted into the active list. Csound uses this list to manage memory allocation.
With the instance reference type we can manage instances in those lists and also run instances that are not in either of them.
Overloads of existing opcodes
-------
We overload the schedule opcode so it can return an instance
```
var:Instr schedule ...
```
We overload turnoff so it can act on an instance
```
turnoff Instr // i-time
turnoff Instr, koff //k-rate with off trigger
```
New Opcodes
--------
A set of standard and more experimental opcodes are put forward
```
var:Instr play InstrDef[,p4, ...]
```
creates, inits, and performs an instance indefinitely (i-time) and immediately. It adds the instance to the end of the active list, regardless of instr number, so it preserves the instantiation order.
```
pause Instr, koff
```
pauses an instance if `koff = 1` (perf-time)
```
setp Instr, n, val
```
sets an instance parameter n to val (perf-time)
```
var:Instr create InstrDef
```
creates an instance (i-time), but does not add it to the free instance or active chains (so `orcompact()` etc are not aware of it). We can later add opcodes that will insert this instance at specific places in the active list.
```
err:i init Instr[,p4, ...]
```
runs an init pass on an instance (i-time), it sets the instrument active flag but does not add it to the active chain.
```
err:k perf Instr
```
runs a perf pass on an instance (perf-time).
```
delete Instr
```
deletes instance (deinit-time). If instance is active, it turns it off. If it has been linked into the free instance chain, do not delete it so it can be reused. The instance is also unlinked from the active list.
These last four opcodes allow us to run a create-init-perf-delete cycle inside an instrument. They also pave the way for us to start offering means of setting arbitrary performance orders. For example,
```
instr 1
// run at i-time
myInstr:InstrDef create {{
out linenr(oscili(p4,k(p5)),0.1,0.1,0.01)
}}
myInstance:Instr create myInstr
err1:i init myInstance,0.5,440
// run at perf-time
err2:k perf myInstance
glid:k expon 440, p3, 880
setp myInstance, 5, glid
// run at deinit time
delete myInstance
delete myInstr
endin
```
NB: having a `create` for `Instr` also seems to make it logical to overload it for `InstrDef` and remove `createinstr` which was never ideal.
1 Like