Built-in Opcodes#

Whenever an Engine is created, some user-defined opcodes (UDO) are defined, which can be used from any code within this Engine.

Bus Opcodes#

These opcodes are present whenever a csound Engine is created with numAudioBuses > 0 or numControlBuses > 0 (enabled by default). They implement a pool of audio and control buses. The number of buses in the pool is determined by these variables and the default can be customized in the configuration (key num_audio_buses and num_control_buses).

Buses are reference counted: they stay alive as long as there are events using them. As soon as the last event usign a bus ends the bus is freed and returned to the pool. In order to keep a bus alive it can be created at the orchestra’s header (instr 0) or

An audio bus contains audio from the same performance cycle; all active buses are cleared at the end of the cycle so they cannot be used to implement feedback or pass audio to instrument instances with a lower priority. Control buses behave like global k-variables

A bus can be created in python via csoundengine.engine.Engine.assignBus() or directly in csound via busassign.

These user-defined-opcodes are also present for offline rendering


busin#

Receives audio/control data from a bus

Syntax

asig busin ibus
kvalue busin ibus

Example

from csoundengine import *
engine = Engine(numAudioBuses=64)
engine.compile(r'''
    instr mysynth
      ibus = p4
      kfreq = p5
      asig oscili 0.1, kfreq
      busout ibus, asig
    endin

    instr filter
      ibus = p4
      kcutoff = p5
      asig busin ibus
      asig moogladder2 asig, kcutoff, 0.9
      outch 1, asig
    endin
''')
bus = engine.assignBus('audio')
engine.sched('mysynth', dur=4, args=[bus, 220])
engine.sched('filter', dur=4, args=[bus, 1000])

busout#

Sends audio to a bus or sets a control bus to the given value. Audio already in the bus is replaced. In order to allow multiple sends to a bus use busmix.

Syntax

busout ibus, asig
busout ibus, kvalue
  • asig: the signal to output

  • ibus: the bus token as returned by busassign or from python by Engine.assignBus

Example

instr mysynth
  ibus = busassign("a")   ; "a" = audio; "k" = control
  kfreq = p4
  asig oscili 0.1, kfreq
  busout ibus, asig
  schedule "filt", 0, p3, ibus, 2000
endin

instr filt
  ibus = p4
  kcutoff = p5
  asig busin ibus
  asig moogladder2 asig, kcutoff, 0.9
  outch 1, asig
endin

Buses can also be used globally. NB: buses are cleared automatically at the end of a cycle, they do not need to be zeroed by the user.

gimasterL = busassign("a")
gimasterR = busassign("a")

instr mysynth
  kfreq = p4
  asig oscili 0.1, kfreq
  busout gimasterL, asig
endin

instr 999
  aL busin gimasterL
  aR busin gimasterR
  outch 1, aL, 2, aR
endin

schedule(999, 0, -1)

busassign#

Assigns an unused bus

Syntax

ibus busassign Skind
  • Skind: the kind of bus, “a” or “k”

  • ibus: the bus id of the newly assigned bus. This can be passed to busin or busout

gimasterL = busassign("a")
gimasterR = busassign("a")

instr mysynth
  kfreq = p4
  asig oscili 0.1, kfreq
  busout gimasterL, asig
endin

instr 999
  aL busin gimasterL
  aR busin gimasterR
  outch 1, aL, 2, aR
endin

schedule(999, 0, -1)

busmix#

Send audio to a bus, mixing it with other sends

The difference with busout is that here the audio of the bus is mixed with the new audio. NB: busmix is only available for audio buses

Syntax

busmix ibus, asig
  • ibus: the bus token as returned by busassign or from python by Engine.assignBus

  • asig: the audio signal to mix with the contents of the bus

Example

from csoundengine import *
e = Engine(numAudioBuses=64)
e.compile(r'''
  instr vco
    ibus = p4
    ifreq = p5
    asig vco2 0.1, ifreq
    busmix ibus, asig
  endin

  instr group
    ibus = p4
    asig busin ibus
    iatt, irel, ilook = 0.1, 0.2, 0.02
    asig compress2 asig, asig, -120, -40, -20, /*knee*/3, iatt, irel, ilook
    outch 1, asig
  endin
''')
bus = e.assignBus("audio")
freqs = [200, 210, 214]
for freq in freqs:
    e.sched('vco', dur=4, args=[bus, freq])
e.sched('master', dur=4, args=[bus])

Other opcodes#

sfloadonce#

Load a soundfont if needed

Like sfload, but can be used repeatedly. If a soundfont with the given path was already loaded, it will return the handle number of the loaded instance.

Syntax

ihandle sfloadonce "/path/to/soundfont.sf2"

sfPresetIndex#

Assigns an index to a soundfont program

This opcode loads the soundfont if not already loaded (like sfload) and assigns an index (like sfpassign) without the user needing to explicitely assign a number.

Syntax

ipresetIndex sfPresetIndex "/path/to/soundfont.sf2", ibank, ipresetnumber

Example

from csoundengine import *
e = Engine()
e.compile(r'''
  instr piano
    ivel, ipitch passign 4
    iamp = ivel/127
    inote = int(ipitch)
    ; assign an index to the program (bank=0, preset=1)
    ipresetidx sfPresetIndex "/path/to/piano.sf2", 0, 1
    aL, aR sfplay3 ivel, inote, iamp/16384, mtof:i(ipitch), ipresetidx, 1
    outch 1, aL, 2, aR
  endin
''')

Note

There will be a delay when playing a note using this opcode if the soundfont is read inside a note for the first time. To avoid this delay, load the soundfont beforehand, via sfloadonce. sfPresetIndex will detect this and use the loaded instance (this will not happen with sfload).

See Also: soundfontPreparePreset(), which does the same operation.