Cabbage Logo
Back to Cabbage Site

Advice on reusable code

Hi there

Sorry more of a conceptual Csound query really, rather than Cabbage specifically. I’m sure this have been done to death, but I’m trying to come up with a standard way of creating re-usable modular code for my patches. For example, below is an instr definition for a reverb that I can #include, that takes either p-fields or if supplied with a string, creates a k-rate chnget so that it can be controlled externally:

	ilen strlen $CHNID
	if ilen > 0 then 
		$VAR chnget $CHNID
	 	$VAR = $PARAM

instr $NUM
prints {{
B_IN: %s
B_OUT: %s
SIZE: %s, {float} [0..1]
DAMP: %s, {float} [0.. israte/2]
MIX: %s, {float} [0..1]
PTCHMOD: %f, {float} [0..10]
}}, $B_IN, $B_OUT, $K_SIZE, $K_DAMP, $K_MIX, p7

	ainl chnget strcat($B_IN, "L")
	ainr chnget strcat($B_IN, "R")

	iptchmod = p7

	aRevL, aRevR	reverbsc ainl, ainr, ksize, kdamp, sr, iptchmod, 0
	aMixL  	ntrpol ainl, aRevL, kmix
	aMixR   ntrpol ainr, aRevR, kmix
	outs aMixL, aMixR
	chnclear strcat($B_IN, "L"), strcat($B_IN, "R")


and it’s called in the main orchestra as:

$REVERBSC_ALT(VerbAlt ' "Verb" ' "" ' "Size" ' "Damp" ' "Mix")
schedule("VerbAlt", 0, -1, .95, 5000, 0.5, .2)

The empty string denotes whether a channel needs to be used, or can be skipped to use a p-field instead (SET_CTL_TYPE macro handles all this). The prints stuff is to document inputs/outputs so I don’t have to open the src file, as I’m a bit lazy!

I did try a udo for the $SET_CTL_TYPE bit to use inline, but I wasn’t having much success with it. I think a macro was the way to go anyhow.

So, what are your thoughts, is this way over engineered? - am I overlooking something obvious, like a better way to achieve my aim of drop in re-usability? (sidenote, I’m inspired by Pd’s abstraction system when I say reusability).


Personally I avoid macros at all costs, and just use UDOs. They can be included using #include statements. I also find them easier to read and maintain. I think UDOs are the closest to Pd abstractions we have in Csound.

Hi Rory

huh interesting…how would you encapsulate a whole instrument like the above? It might be a poor example given that it wraps a reverbsc and adds a ntrpol for crossfading (mix parameter). But with something more complex say, like one of the grain3 examples, you’d still be doing:

#include "mygrain3opcode.udo"

instr Grain3Example
kp1 chnget p4
kp2 chnget p5
aout mygrain3opcode kp1, kp2, ...

It’s all the boilerplate of integrating I’m trying to minimise really. Ideally I’d throw a few strings at a schedule for the control channels…Perhaps I need to rethink this :upside_down_face:

Yes, you still need instruments, but you could do:

instr GrainExample
    aOut = myGainOpcodes:a("param1", "param2", "param3")
    outs:a(aOut, aOut)

Sure that works, I’m not that lazy that I couldn’t type instr haha.

I’m wondering tho, can udos have smart (overloaded) inputs , as in if it’s marked as a S type, then could it accept an i type if no string is present. In other words, if I didn’t want a external channel controlling the parameter, then I could feed it a p-field? ( like what $SET_CTL_TYPE macro is doing)

Yes. You can do something like this:

opcode MyOpcode, i, kSk


opcode MyOpcodes, i, kii


Oh of course, yes

thanks again