Cabbage Logo
Back to Cabbage Site

In which circumstances to use event, subinstr, UDO

Hello,
Csound proposes many ways to call one instrument from another.
The following opcodes are available (as far as I can understand) :

  • event “i”,…
    -subinstr
    -opcode XXXX
    -schedule family
    -channels on running instrument (chnmix,chnget,…)

How to choose one from these ? and why ?. Somehow, it seems that the called instrument (i.e. reverb) doesn’t react the same way relatively to audio signal (beeps, pops,) depending on the opcode used for callint it . Is there any preferable opcode from these or is it a question of personal preference (like the choice of a desktop manager under linux)?

Could this be a good topic for a tuto ?

Thank you for your help.

I’m not sure it warrants a tutorial, but I’ll try to answer this as best I can. First things first, the event and schedule family of opcoes are used to trigger score events. UDOs and sub instruments provide a running abstracted or standalone code within an instrument.

event
The event family of opcodes are used to trigger score events. event_i is used to trigger events at i-time, meaning it will only be called at the very start of an instrument’s lifetime. event on the other hand is called on every k cycle meaning it will be called continuously over the life-time of an instrument. In Cabbage, one usually uses event opcodes with a changed opcode, i.e,

kButton chnget "button1"
if changed:k(kButton) == 1 then
   event "i", 100, 0, 10
endif

schedule
The schedule family of opcodes offer more or less the same functionality, only the the k versions also offer a trigger parameter. This eliminates the needs for an if statement:

kButton chnget "but1"
schedkwhen changed:k(kButton), 0, 100, 2, 0, 1

The schedule family of opcodes also provide streamlined management of instruments by letting the user decide how many instances of an instrument can run at the same time. There will be times when this is important.

UDOs
UDOs, which are created using opcode provide users with a way of abstracting functionality into self-contained user defined opcodes. They were added to Csound so that users could write their own custom opcodes in Csound. Before they existed, the only way to create custom opcodes was using a lower level language like C. UDO definitions can use all or any opcodes. There are no limitations. They can also be recursive, meaning they can call themselves. Spend some time trying to get your head around this recursive vocoder!

You can also keep all your UDOs in a separate file and include them using an #include statement:

#include "MyUDOs.whatever"

subinstr
subinstr was a precursor to the UDO construct. It’s not used that often today, but works in a similar kind of way. Instead of defined an custom opcode, you create an instrument for a specific task. You then call this instrument within another one. Since UDOs became a thing, subinstr has gone the way of the dodo. It can still be useful as a pedagogic tool, but I find I rarely use it all these days.

channels
Channels are used to send signals around a Csound orchestra. Host applications can tap into Csound’s channels and send information to then. Cabbage does this all the time. But channels are not just for host application. Csound can use channels to send audio or k-rate signal from one instrument to another. chnget recieves data while chnset sends data. chnmix is a very useful opcode for accumulating signal. Consider the following example:

instr 1
	a1 oscil .25, 100
	chnset a1, "instr1"
endin

instr 2
	a1 oscil .25, 200
	chnset a1, "instr2"
endin

instr 3
	a1 oscil .25, 300
	chnset a1, "instr3"
endin

instr 4
	a1 oscil .25, 400
	chnset a1, "instr4"
endin

instr 5
   	a1 chnget "instr1"
   	a2 chnget "instr2"
   	a3 chnget "instr3"
   	a4 chnget "instr4"
  	outs a1+a2+a3+a4, a1+a2+a3+a4
endin

We send the output of the each instrument to channel called “instrN”. In instrument 5 we pick up the signals sent to those channels using a chnget. We then mix the signals and send it to the output. Using a chnmix would make things a little simpler:

instr 1
	a1 oscil .25, 100
	chnset a1, "instr"
endin

instr 2
	a1 oscil .25, 200
	chnmix a1, "instr"
endin

instr 3
	a1 oscil .25, 300
	chnmix a1, "instr"
endin

instr 4
	a1 oscil .25, 400
	chnmix a1, "instr"
endin

instr 5
	a1 chnget "instr"
	outs a1, a1
endin

In particular instrument 5, In this case we only need to grab the signal from a single channel. Note that instrument 1 uses a chnset and not chnmix. This is purposely used to clear the contents of the channel on each k-cycle. If i used a chnmix instead the signal would accumulate over time and start to distort. In cases where this is likely to occur, you can use a chnclear to clear the contents of the channel.

p.s. I’m not sure this is quite tutorial stuff, it’s good info, but I may move it to the cabbage stew section?

1 Like

ive been trying this method because it seems really good for organize my big code, and didnt work. So i took the example above, and it didnt work. So next, i just use this reduced code:

<Cabbage>
form caption("Untitled") size(400, 300), colour(58, 110, 182), pluginid("def1")
keyboard bounds(8, 158, 381, 95)
</Cabbage>
<CsoundSynthesizer>
<CsOptions>
-n -d -+rtmidi=NULL -M0 -m0d --midi-key-cps=4 --midi-velocity-amp=5
</CsOptions>
<CsInstruments>
; Initialize the global variables. 
ksmps = 32
nchnls = 2
0dbfs = 1

;instrument will be triggered by keyboard widget
instr 1
	a1 oscil .25, 100
	chnset a1, "instr"
endin

instr 2
	a1 chnget "instr"
	outs a1, a1
endin

</CsInstruments>
<CsScore>
;causes Csound to run for about 7000 years...
f0 z
</CsScore>
</CsoundSynthesizer>

And still not working. Why? Whats the problem? Im sure your code was right!!

Plleeeeaaassseee format your code. When you don’t it’s impossible to read it correctly. I’m not quite sure what you’re trying to do here, but you don’t start instrument 2 at all. However, it does sound like you are trying to achieve something similar to @Retornz in this thread. Or?

Yeah, i am looking for more or less the same objective as @TONITORM. I’ve tried the example you gave him of the reverb effect, and it works well for me, but the problem comes when i mix 2 or more instruments with its respectively oscilli opcode. When i try to mix 3 instruments, the program just reproduce the soundwave generated in the instr 1. Here I gave you an easy example. The code in what im working on is very more complex, but if we resolve the problem in this small example, my complex code will work too because is the same fact with the chanmix op code.

Simpleexample.csd (1012 Bytes)

This example doesn’t make much sense because instruments 2 and 3 never make any sound, because p5 and p4 are 0. Only instrument 1 will get triggered via the keyboard, and there is no need to use an i-statement in the score to enable it. If you replace the p4 and p5 s in those instruments with actual value it should work fine.

Did you figure it out?

yeahhhhhh, i understand what you mean. Didnt know p2 and p3 never make any sound. Thank you!! :smiley: