Session – High-level interface#

Overview#

  • A Session uses instrument templates (Instr), which enable an instrument to be instantiated at any place in the evaluation chain.

  • An instrument template within a Session can also declare default values for pfields

  • Session instruments can declare named controls. These are dynamic parameters which can be modified and automated over the lifetime of an event (Synth.set, Synth.automate)

1. Instrument Templates#

In csound there is a direct mapping between an instrument declaration and its order of evaluation. Within a Session, on the other hand, it is possible to declare an instrument ( Instr) and instantiated it at any order, making it possibe to create chains of processing units.

s = Engine().session()
# Notice: the filter is declared before the generator. If these were
# normal csound instruments, the filter would receive an instr number
# lower and thus could never process audio generated by `myvco`
Instr('filt', r'''
    Schan strget p5
    kcutoff = p6
    a0 chnget Schan
    a0 moogladder2 a0, kcutoff, 0.9
    outch 1, a0
    chnclear Schan
''').register(s)

# The same can be achieved via Session.defInstr:

s.defInstr('myvco', r'''
    kfreq = p5
    kamp = p6
    Schan strget p7
    a0 = vco2:a(kamp, kfreq)
    chnset a0, Schan
''')
synth = s.sched('myvco', kfreq=440, kamp=0.1, Schan="chan1")

# The filter is instantiated with a priority higher than the generator and
# thus is evaluated later in the chain.
filt = s.sched('filt', priority=synth.priority+1, kcutoff=1000, Schan="chan1")

2. Named pfields with default values#

An Instr (also declared via defInstr()) can define default values for its pfields via the pset opcode (http://www.csounds.com/manual/html/pset.html). When scheduling an event the user only needs to fill the values for those pfields which differ from the given default. Notice that p4 is reserved and cannot be used

s = Engine().session()
s.defInstr('sine', r'''
    pset p1, p2, p3, 0, 0.1, 1000
    iamp = p5
    kfreq = p6
    a0 = oscili:a(iamp, kfreq)
    outch 1, a0
''')
# We schedule an event of sine, iamp will take the default (0.1)
synth = s.sched('sine', kfreq=440)
# pfields assigned to k-variables can be modified by name
synth.set(kamp=0.5)

3. Dynamic Controls#

An Instr can define a number of named controls, similar to pfields. These controls must have a valid csound name (starting with ‘k’) and can define a default value. They provide a more efficient way of controlling dynamic parameters and are the default method to communicate with a running event.

Note

Dynamic controls are implemented in two different ways. One is by using regular pfields and having direct access to thses pfields via the pwrite opcode; another method is by reading from a control table. In the latter case, each time an instr with dynamic controls is scheduled, it is assigned a slice within that table (the slice number is passed as p4). On the python side that table can be accesses directly, making it very efficient to set it from python without needing to call csound at all.

The same instr as above can be defined using dynamic controls as follows:

s = Engine().session()
s.defInstr('sine', r'''
outch 1, oscili:a(kamp, kfreq)
''',
args={'kamp': 0.1, 'kfreq': 1000})

synth = s.sched('sine', kfreq=800)
# Dynamic controls can also be modified via set
synth.set(kfreq=1000)
# Automation can be applied with 'automate'
synth.automate('freq', (0, 0, 2, 440, 3, 880), overtake=True)

csoundengine generates the needed code to access the table slots:

i__slicestart__ = p4
i__tabnum__ chnget ".dynargsTabnum"
kamp  tab i__slicestart__ + 0, i__tabnum__
kfreq tab i__slicestart__ + 1, i__tabnum__

4. Inline arguments#

An Instr can set arguments (both init args and dynamic args) as an inline declaration:

s = Engine().session()
s.defInstr('sine', r'''
    |iamp=0.1, kfreq=1000|
    a0 = oscili:a(kamp, kfreq)
    outch 1, a0
''')

Notice that the generated code used pfields for init-time parameters and dynamic controls for k-time arguments.

iamp = p5
i__tabnum__ chnget ".dynargsTabnum"
kfreq tab i__slicestart__ + 0, i__tabnum__
a0 = oscili:a(iamp, kfreq)
outch 1, a0

All dynamic (k-rate) parameters can be modulated after the note has started (see :meth:~maelzel.synth.Synth.set). Also notice that parameters start with p5: p4 is reserved: declaring an Instr which uses p4 will raise an exception.

5. User Interface#

A Synth can be modified interactively via an auto-generated user-interface. Depending on the running context this results in either a gui dialog (within a terminal) or an embedded user-interface in jupyter.

_images/synthui.png

UI generated when using the terminal:

_images/ui2.png

Session Class#

class csoundengine.session.Session(engine=None, priorities=None, maxControlsPerInstr=None, numControlSlots=None, **enginekws)[source]#

A Session is associated (exclusively) to a running Engine and manages instrument declarations and scheduled events. An Engine can be thought of as a low-level interface for managing a csound instance, whereas a Session allows a higher-level control

A user normally does not create a Session manually: the normal way to create a Session for a given Engine is to call session() (see example below)

Once a Session is created for an existing Engine, calling session() again will always return the same Session object.

Example

In order to add an instrument to a Session, an Instr is created and registered with the Session. Alternatively, the shortcut defInstr() can be used to create and register an Instr at once.

s = Engine().session()
s.defInstr('sine', r'''
    |kfreq=440, kamp=0.1|
    a0 = oscili:a(kamp, kfreq)
    outch 1, a0
''')
synth = s.sched('sine', kfreq=500)
synth.stop()

An Instr can define default values for any of parameters. By default, any dynamic argument (any argument starting with ‘k’) will be implemented as a dynamic control and not as a pfield. On the contrary, any init-time argument will be implemented as a pfield.

s = Engine().session()
s.defInstr('sine', args={'kamp': 0.1, 'kfreq': 1000}, body=r'''
    a0 = oscili:a(kamp, kfreq)
    outch 1, a0
''')
# We schedule an event of sine, kamp will take the default (0.1)
synth = s.sched('sine', kfreq=440)
synth.stop()

An inline args declaration can set both parameter name and default value:

s = Engine().session()
Intr('sine', r'''
    |kamp=0.1, kfreq=1000|
    a0 = oscili:a(kamp, kfreq)
    outch 1, a0
''').register(s)
synth = s.sched('sine', kfreq=440)
synth.stop()

To force usage of pfields for dynamic args you need to use manual declaration:

s.defInstr('sine', r'''
;                     p5   p6
pset p1, p2, p3, 0,   0.1, 1000
kamp = p5
kfreq = p6
outch 1, oscili:a(kamp, kfreq)
''')
synth = s.sched('sine', kfreq=440)

Methods:

__init__([engine, priorities, ...])

A Session controls a csound Engine

isRendering()

Is an offline renderer attached to this session?

hasHandler()

Does this session have a handler to redirect actions? :rtype: bool

stop()

Stop this session and the underlying engine

hasBusSupport()

Does the underlying engine have bus support?

automate(event, param, pairs[, mode, delay, ...])

Automate any named parameter of this Synth

renderMode()

The render mode of this Renderer

setHandler(handler)

Set a SessionHandler for this session

defInstr(name, body[, args, init, priority, ...])

Create an Instr and register it at this session

registeredInstrs()

Returns a dict (instrname: Instr) with all registered Instrs

isInstrRegistered(instr)

Returns True if instr is already registered in this Session

registerInstr(instr)

Register the given Instr in this session.

getInstr(instrname)

Returns the Instr defined under name

prepareSched(instr[, priority, block])

Prepare an instrument template for being scheduled

instrnum(instrname[, priority])

Return the instr number for the given Instr at the given priority

assignBus([kind, value, persist])

Creates a bus in the engine

schedEvents(events)

Schedule multiple events

schedEvent(event)

Schedule an event

lockedClock(latency)

context manager to ensure sync :rtype: Session

rendering([outfile, sr, nchnls, ksmps, ...])

A context-manager for offline rendering

generateInstrBody(instr)

Generate the actual body for a given instr

sched(instrname[, delay, dur, priority, ...])

Schedule an instance of an instrument

activeSynths([sortby])

Returns a list of playing synths

scheduledSynths()

Returns all scheduled synths (both active and future)

unsched(event[, delay])

Stop a scheduled instance.

unschedAll([future])

Unschedule all playing synths

includeFile(path)

Include a file

readSoundfile([path, chan, skiptime, delay, ...])

Read a soundfile, store its metadata in a TableProxy

makeTable([data, size, tabnum, sr, delay, ...])

Create a table with given data or an empty table of the given size

freeTable(table[, delay])

Free the given table

testAudio([dur, mode, period, gain])

Schedule a test synth to test the engine/session

playPartials(source[, delay, dur, speed, ...])

Play a packed spectrum

playSample(source[, delay, dur, chan, gain, ...])

Play a sample.

makeRenderer([sr, nchnls, ksmps, addTables, ...])

Create a Renderer (to render offline) with the instruments defined in this Session

Attributes:

engine

The Engine corresponding to this Session

name

The name of this Session/Engine

instrs

maps instr name to Instr

numPriorities

Number of priorities in this Session

maxDynamicArgs

The max.

__init__(engine=None, priorities=None, maxControlsPerInstr=None, numControlSlots=None, **enginekws)[source]#

A Session controls a csound Engine

Normally a user does not create a Session directly, but calls the Engine.session() <csoundengine.engine.Engine.session>`() method

Parameters:
  • engine (str | Engine | None) – the parent engine. If no engine is given, an engine with default parameters will be created. To customize the engine, the canonical way of creating a session is to use session = Engine(...).session()

  • priorities (int | None) – the max. number of priorities for scheduled instrs

  • maxControlsPerInstr (int | None) – the max. number of named controls per instr

  • numControlSlots (int | None) – the total number of slots allocated for dynamic parameters. Each synth which declares named controls is assigned a slot, used to hold all its named controls. This is also the max. number of simultaneous events with named controls.

  • enginekws – any keywords are used to create an Engine, if no engine has been provided. See docs for Engine for available keywords.

Example

>>> from csoundengine import *
>>> session = Engine(nchnls=4, nchnls_i=2).session()

This is the same as

>>> engine = Engine(nchnls=4, nchnls_i=2)
>>> session = Session(engine=engine)
engine: Engine#

The Engine corresponding to this Session

name: str#

The name of this Session/Engine

instrs: dict[str, Instr]#

maps instr name to Instr

numPriorities: int#

Number of priorities in this Session

maxDynamicArgs#

The max. number of dynamic parameters per instr

isRendering()[source]#

Is an offline renderer attached to this session?

Return type:

bool

hasHandler()[source]#

Does this session have a handler to redirect actions? :rtype: bool

stop()[source]#

Stop this session and the underlying engine

Return type:

None

hasBusSupport()[source]#

Does the underlying engine have bus support?

Return type:

bool

automate(event, param, pairs, mode='linear', delay=0.0, overtake=False)[source]#

Automate any named parameter of this Synth

Raises KeyError if the parameter is unknown

Parameters:
  • event (SchedEvent) – the event to automate

  • param (str) – the name of the parameter to automate

  • pairs (Union[Sequence[float], ndarray, tuple[ndarray, ndarray]]) – automation data as a flat array with the form [time0, value0, time1, value1, …]

  • mode – one of ‘linear’, ‘cos’. Determines the curve between values

  • delay – when to start the automation

  • overtake – if True, do not use the first value in pairs but overtake the current value

Return type:

float

Returns:

the eventid of the automation event.

renderMode()[source]#

The render mode of this Renderer

Return type:

str

setHandler(handler)[source]#

Set a SessionHandler for this session

This is used internally to delegate actions to an offline renderer when this session is rendering.

Return type:

SessionHandler | None

defInstr(name, body, args=None, init='', priority=None, doc='', includes=None, aliases=None, useDynamicPfields=None, **kws)[source]#

Create an Instr and register it at this session

Any init code given is compiled and executed at this point

Parameters:
  • name (str) – the name of the created instr

  • body (str) – the body of the instrument. It can have named pfields (see example) or a table declaration

  • args (dict[str, float | str] | None) – pfields with their default values

  • init – init (global) code needed by this instr (read soundfiles, load soundfonts, etc)

  • priority (int | None) – if given, the instrument is prepared to be executed at this priority

  • doc – documentation describing what this instr does

  • includes (list[str] | None) – list of files to be included in order for this instr to work

  • aliases (dict[str, str] | None) – a dict mapping arg names to real argument names. It enables to define named args for an instrument using any kind of name instead of following csound name

  • useDynamicPfields (bool | None) – if True, use pfields to implement dynamic arguments (arguments given as k-variables). Otherwise dynamic args are implemented as named controls, using a big global table

  • kws – any keywords are passed on to the Instr constructor. See the documentation of Instr for more information.

Return type:

Instr

Returns:

the created Instr. If needed, this instr can be registered at any other running Session via session.registerInstr(instr)

Note

An instr is not compiled at the moment of definition: only when an instr is actually scheduled to be run at a given priority the code is compiled. There might be a small delay the first time an instr is scheduled at a given priority. To prevent this a user can give a default priority when calling Session.defInstr(), or call Session.prepareSched() to explicitely compile the instr

Example

>>> session = Engine().session()
# An Instr with named parameters
>>> session.defInstr('filter', r'''
... a0 = busin(kbus)
... a0 = moogladder2(a0, kcutoff, kresonance)
... outch 1, a0
... ''', args=dict(kbus=0, kcutoff=1000, kresonance=0.9))
# Parameters can be given inline. Parameters do not necessarily need
# to define defaults
>>> session.defInstr('synth', r'''
... |ibus, kamp=0.5, kmidi=60|
... kfreq = mtof:k(lag:k(kmidi, 1))
... a0 vco2 kamp, kfreq
... a0 *= linsegr:a(0, 0.1, 1, 0.1, 0)
... busout ibus, a0
... ''')
>>> bus = session.engine.assignBus()
# Named params can be given as keyword arguments
>>> synth = session.sched('sine', 0, dur=10, ibus=bus, kmidi=67)
>>> synth.set(kmidi=60, delay=2)
>>> filt = session.sched('filter', 0, dur=synth.dur, priority=synth.priority+1,
...                      args={'kbus': bus, 'kcutoff': 1000})
>>> filt.automate('kcutoff', [3, 1000, 6, 200, 10, 4000])

See also

sched()

registeredInstrs()[source]#

Returns a dict (instrname: Instr) with all registered Instrs

Return type:

dict[str, Instr]

isInstrRegistered(instr)[source]#

Returns True if instr is already registered in this Session

To check that a given instrument name is defined, use session.getInstr(instrname) is not None :rtype: bool

registerInstr(instr)[source]#

Register the given Instr in this session.

It evaluates any init code, if necessary

Parameters:

instr (Instr) – the Instr to register

Return type:

bool

Returns:

True if the action was performed, False if this instr was already defined in its current form

See also

defInstr()

getInstr(instrname)[source]#

Returns the Instr defined under name

Returns None if no Instr is defined with the given name

Parameters:

instrname (str) – the name of the Instr - use “?” to select interactively

Return type:

Instr | None

See also

defInstr()

prepareSched(instr, priority=1, block=False)[source]#

Prepare an instrument template for being scheduled

The only use case to call this method explicitely is when the user is certain to need the given instrument at the specified priority and wants to avoid the delay needed for the first time an instr is called, since this first call implies compiling the code in csound.

Parameters:
  • instr (str | Instr) – the name of the instrument to send to the csound engine or the Instr itself

  • priority (int) – the priority of the instr

  • block – if True, this method will block until csound is ready to schedule the given instr at the given priority

Returns:

bool)

Return type:

a tuple (_ReifiedInstr, needssync

instrnum(instrname, priority=1)[source]#

Return the instr number for the given Instr at the given priority

For a defined Instr (identified by instrname) and a priority, return the concrete instrument number for this instrument.

This returned instrument number will not be a unique (fractional) instance number.

Parameters:
  • instrname (str) – the name of a defined Instr

  • priority (int) – the priority at which an instance of this Instr should be scheduled. An instance with a higher priority is evaluated later in the chain. This is relevant when an instrument performs some task on data generated by a previous instrument.

Return type:

int

Returns:

the actual (integer) instrument number inside csound

See also

defInstr()

assignBus(kind='', value=None, persist=False)[source]#

Creates a bus in the engine

This is a wrapper around Engine.assignBus(). Instead of returning a raw bus token it returns a Bus, which can be used to write, read or automate a bus. To pass the bus to an instrument expecting a bus, use its token attribute.

Within csound a bus is reference counted and is kept alive as long as there are events using it via any of the builtin bus opcdodes: busin, busout, busmix. A Bus can hold itself a reference to the bus if called with persist=True, which means that the csound bus will be kept alive as long as python holds a reference to the Bus object.

For more information on the bus-opcodes, see Bus Opcodes

Parameters:
  • kind – the kind of bus, “audio” or “control”. If left unset and value is not given it defaults to an audio bus. Otherwise, if value is given a control bus is created. Explicitely asking for an audio bus and setting an initial value will raise an expection

  • value (float | None) – for control buses it is possible to set an initial value for the bus. If a value is given the bus is created as a control bus. For audio buses this should be left as None

  • persist – if True, the bus is valid until manually released or until the returned Bus object is freed.

Return type:

Bus

Returns:

a Bus, representing the bus created. The returned object can be used to modify/read/automate the bus

Example

from csoundengine import *

s = Engine().session()

s.defInstr('sender', r'''
ibus = p5
ifreqbus = p6
kfreq = busin:k(ifreqbus)
asig vco2 0.1, kfreq
busout(ibus, asig)
''')

s.defInstr('receiver', r'''
ibus  = p5
kgain = p6
asig = busin:a(ibus)
asig *= a(kgain)
outch 1, asig
''')

bus = s.assignBus('audio')
freqbus = s.assignBus(value=880)

# The receiver needs to have a higher priority in order to
# receive the audio of the sender
chain = [s.sched('sender', ibus=bus.token, ifreqbus=freqbus.token),
         s.sched('receiver', priority=2, ibus=bus.token, kgain=0.5)]

# Make a glissando
freqbus.automate((0, 880, 5, 440))
schedEvents(events)[source]#

Schedule multiple events

Parameters:

events (Sequence[Event]) – the events to schedule

Return type:

SynthGroup

Returns:

a SynthGroup with the synths corresponding to the given events

schedEvent(event)[source]#

Schedule an event

An Event can be generated to store a Synth’s data.

Parameters:

event (Event) – the event to schedule. An csoundengine.event.Event represents an unscheduled event.

Return type:

Synth

Returns:

the generated Synth

Example

>>> from csoundengine import *
>>> s = Engine().session()
>>> s.defInstr('simplesine', r'''
... |ifreq=440, iamp=0.1, iattack=0.2|
... asig vco2 0.1, ifreq
... asig *= linsegr:a(0, iattack, 1, 0.1, 0)
... outch 1, asig
... ''')
>>> event = Event('simplesine', args=dict(ifreq=1000, iamp=0.2, iattack=0.2))
>>> synth = s.schedEvent(event)
...
>>> synth.stop()
lockedClock(latency)[source]#

context manager to ensure sync :rtype: Session

rendering(outfile='', sr=0, nchnls=None, ksmps=0, encoding='', starttime=0.0, endtime=0.0, tail=0.0, openWhenDone=False, verbose=None)[source]#

A context-manager for offline rendering

All scheduled events are rendered to outfile when exiting the context. The Renderer returned by the context manager has the same interface as a Session and can be used as a drop-in replacement. Any instrument or resource declared within this Session is available for offline rendering.

Parameters:
  • outfile – the soundfile to generate after exiting the context

  • sr – the samplerate. If not given, the samplerate of the session will be used

  • nchnls (int | None) – the number of channels. If not given, the number of channels of the session will be used

  • ksmps – samples per cycle to use for rendering

  • encoding – the sample encoding of the rendered file, given as ‘pcmXX’ or ‘floatXX’, where XX represent the bit-depth (‘pcm16’, ‘float32’, etc.). If no encoding is given a suitable default for the sample format is chosen

  • starttime – start rendering at the given time. Any event ending previous to this time will not be rendered and any event between starttime and endtime will be cropped

  • endtime – stop rendering at the given time. This will either extend or crop the rendering.

  • tail – extra render time at the end, to accomodate extended releases

  • openWhenDone – open the file in the default application after rendering.

  • verbose (bool | None) – if True, output rendering information. If None uses the value specified in the config (config['rec_suppress_output'])

Return type:

Renderer

Returns:

a csoundengine.offline.Renderer

Example

>>> from csoundengine import *
>>> s = Engine().session()
>>> s.defInstr('simplesine', r'''
... |kfreq=440, kgain=0.1, iattack=0.05|
... asig vco2 1, ifreq
... asig *= linsegr:a(0, iattack, 1, 0.1, 0)
... asing *= kgain
... outch 1, asig
... ''')
>>> with s.rendering('out.wav') as r:
...     r.sched('simplesine', 0, dur=2, kfreq=1000)
...     r.sched('simplesine', 0.5, dur=1.5, kfreq=1004)
>>> # Generate the corresponding csd
>>> r.writeCsd('out.csd')

See also

Renderer

generateInstrBody(instr)[source]#

Generate the actual body for a given instr

This task is done by a Session/Renderer because the actual body might be different if we are rendering in realtime, as is the case of a session, or if its offline

Parameters:

instr (Instr) – the Instr for which to generate the instr body

Return type:

str

Returns:

the generated body. This is the text which must be wrapped between instr/endin

sched(instrname, delay=0.0, dur=-1.0, priority=1, args=None, whenfinished=None, relative=True, syncifneeded=True, **kwargs)[source]#

Schedule an instance of an instrument

Parameters:
  • instrname (str) – the name of the instrument, as defined via defInstr. Use “?” to select an instrument interactively

  • delay – time offset of the scheduled instrument

  • dur – duration (-1 = forever)

  • priority (int) – the priority (1 to 10)

  • args (Union[Sequence[float | str], dict[str, float], None]) – arguments passed to the instrument, a dict of the form {‘argname’: value}, where argname can be any px string or the name of the variable (for example, if the instrument has a line ‘kfreq = p5’, then ‘kfreq’ can be used as key here). Alternatively, a list of positional arguments, starting with p5

  • whenfinished (Optional[Callable]) – a function of the form f(synthid) -> None if given, it will be called when this instance stops

  • relative – if True, delay is relative to the current time. Otherwise delay is interpreted as an absolute time from the start time of the Engine.

  • syncifneeded – if True, a .sync call is performed if the instrument needs to be synched in order to ensure that compilation has been performed

  • kwargs – keyword arguments are interpreted as named parameters. This is needed when passing positional and named arguments at the same time

Return type:

Synth

Returns:

a synth,Synth, which is a handle to the instance (can be stopped, etc.)

Example

>>> from csoundengine import *
>>> s = Engine().session()
>>> s.defInstr('simplesine', r'''
... pset 0, 0, 0, 440, 0.1, 0.05
... ifreq = p5
... iamp = p6
... iattack = p7
... asig vco2 0.1, ifreq
... asig *= linsegr:a(0, iattack, 1, 0.1, 0)
... outch 1, asig
... ''')
# NB: in a Session, pfields start at p5 since p4 is reserved
>>> synth = s.sched('simplesine', args=[1000, 0.2], iattack=0.2)
...
>>> synth.stop()

See also

stop()

activeSynths(sortby='start')[source]#

Returns a list of playing synths

Parameters:

sortby – either “start” (sort by start time) or None (unsorted)

Return type:

list[Synth]

Returns:

a list of active Synths

scheduledSynths()[source]#

Returns all scheduled synths (both active and future)

Return type:

list[Synth]

unsched(event, delay=0.0)[source]#

Stop a scheduled instance.

This will stop an already playing synth or a synth which has been scheduled in the future

Normally the user should not call unsched(). This method is called by a Synth when stop() is called.

Parameters:
  • event (int | float | SchedEvent) – the event to stop, either a Synth or the p1

  • delay – how long to wait before stopping them

Return type:

None

unschedAll(future=False)[source]#

Unschedule all playing synths

Parameters:

future – if True, cancel also synths which are already scheduled but have not started playing yet

Return type:

None

includeFile(path)[source]#

Include a file

Parameters:

path (str) – the path to the include file

Return type:

None

readSoundfile(path='?', chan=0, skiptime=0.0, delay=0.0, force=False, block=False)[source]#

Read a soundfile, store its metadata in a TableProxy

The life-time of the returned TableProxy object is not bound to the csound table. If the user needs to free the table, this needs to be done manually by calling csoundengine.tableproxy.TableProxy.free()

Parameters:
  • path – the path to a soundfile. “?” to open file via a gui dialog

  • chan – the channel to read, or 0 to read all channels into a multichannel table. Within a multichannel table, samples are interleaved

  • force – if True, the soundfile will be read and added to the session even if the same path has already been read before.#

  • delay – when to read the soundfile (0=now)

  • skiptime – start playback from this time instead of the beginning

  • block – block execution while reading the soundfile

Return type:

TableProxy

Returns:

a TableProxy, holding information like .source: the table number .path: the path you just passed .nchnls: the number of channels in the output .sr: the sample rate of the output

Example

>>> import csoundengine as ce
>>> session = ce.Engine().session()
>>> table = session.readSoundfile("path/to/soundfile.flac")
>>> table
TableProxy(source=100, sr=44100, nchnls=2,
           numframes=88200, path='path/to/soundfile.flac',
           freeself=False)
>>> table.duration()
2.0
>>> session.playSample(table)
makeTable(data=None, size=0, tabnum=0, sr=0, delay=0.0, unique=True, freeself=False, block=False, callback=None)[source]#

Create a table with given data or an empty table of the given size

Parameters:
  • data (ndarray | list[float] | None) – the data of the table. Use None if the table should be empty

  • size (int | tuple[int, int]) – if not data is given, sets the size of the empty table created. Either a size as int or a tuple (numchannels: int, numframes: int). In the latter case, the actual size of the table is numchannels * numframes.

  • tabnum (int) – 0 to let csound determine a table number, -1 to self assign a value

  • block – if True, wait until the operation has been finished

  • callback – function called when the table is fully created

  • sr (int) – the samplerate of the data, if applicable.

  • freeself – if True, the underlying csound table will be freed whenever the returned TableProxy ceases to exist.

  • unique – if False, do not create a table if there is a table with the same data

  • delay (float) – when to allocate the table. This has little use in realtime but is here to comply to the signature.

Return type:

TableProxy

Returns:

a TableProxy object

freeTable(table, delay=0.0)[source]#

Free the given table

Parameters:
  • table (int | TableProxy) – the table to free (a table number / a TableProxy)

  • delay (float) – when to free it (0=now)

Return type:

None

testAudio(dur=20, mode='noise', period=1, gain=0.1)[source]#

Schedule a test synth to test the engine/session

The test iterates over each channel outputing audio to the channel for a specific time period

Parameters:
  • dur – the duration of the test synth

  • mode – the test mode, one of ‘noise’, ‘sine’

  • period – the duration of each iteration

  • gain – the gain of the output

playPartials(source, delay=0.0, dur=-1, speed=1.0, freqscale=1.0, gain=1.0, bwscale=1.0, loop=False, chan=1, start=0.0, stop=0.0, minfreq=0, maxfreq=0, maxpolyphony=50, gaussian=False, interpfreq=True, interposcil=True, position=0.0, freqoffset=0.0, minbw=0.0, maxbw=1.0, minamp=0.0)[source]#

Play a packed spectrum

A packed spectrum is a 2D numpy array representing a fixed set of oscillators. After partial tracking analysis, all partials are arranged into such a matrix where each row represents the state of all oscillators over time.

The loristrck package is needed for both partial-tracking analysis and packing. It can be installed via pip install loristrck (see gesellkammer/loristrck). This is an optional dependency

Parameters:
  • source (int | TableProxy | str | ndarray) – a table number, TableProxy, path to a .mtx or .sdif file, or a numpy array containing the partials data

  • delay – when to start the playback

  • dur – duration of the synth (-1 will play indefinitely if looping or until the end of the last partial or the end of the selection

  • speed – speed of playback (does not affect pitch)

  • loop – if True, loop the selection or the entire spectrum

  • chan – channel to send the output to

  • start – start of the time selection

  • stop – stop of the time selection (0 to play until the end)

  • minfreq – lowest frequency to play

  • maxfreq – highest frequency to play

  • gaussian – if True, use gaussian noise for residual resynthesis

  • interpfreq – if True, interpolate frequency between cycles

  • interposcil – if True, use linear interpolation for the oscillators

  • maxpolyphony – if a sdif is passed, compress the partials to max. this number of simultaneous oscillators

  • position – pan position

  • freqscale – frequency scaling factor

  • gain – playback gain

  • bwscale – bandwidth scaling factor

  • minbw – breakpoints with bw less than this value are not played

  • maxbw – breakpoints with bw higher than this value are not played

  • freqoffset – an offset to add to all frequencies, shifting them by a fixed amount. Notice that this will make a harmonic spectrum inharmonic

  • minamp – exclude breanpoints with an amplitude less than this value

Return type:

Synth

Returns:

the playing Synth

Example

>>> import loristrck as lt
>>> import csoundengine as ce
>>> samples, sr = lt.util.sndread("/path/to/soundfile")
>>> partials = lt.analyze(samples, sr, resolution=50)
>>> lt.util.partials_save_matrix(partials, outfile='packed.mtx')
>>> session = ce.Engine().session()
>>> session.playPartials(source='packed.mtx', speed=0.5)
playSample(source, delay=0.0, dur=0.0, chan=1, gain=1.0, speed=1.0, loop=False, pan=0.5, skip=0.0, fade=None, crossfade=0.02, blockread=True)[source]#

Play a sample.

This method ensures that the sample is played at the original pitch, independent of the current samplerate. The source can be a table, a soundfile or a TableProxy. If a path to a soundfile is given, the ‘diskin2’ opcode is used by default

Parameters:
  • source (int | TableProxy | str | tuple[ndarray, int]) – table number, a path to a sample or a TableProxy, or a tuple (numpy array, samplerate).

  • dur – the duration of playback (-1 to play until the end of the sample or indefinitely if loop==True).

  • chan – the channel to play the sample to. In the case of multichannel samples, this is the first channel

  • pan – a value between 0-1. -1 means default, which is 0 for mono, 0.5 for stereo. For multichannel (3+) samples, panning is not taken into account

  • gain – gain factor.

  • speed – speed of playback. Pitch will be changed as well.

  • loop – True/False or -1 to loop as defined in the file itself (not all file formats define loop points)

  • delay – time to wait before playback starts

  • skip – the starting playback time (0=play from beginning)

  • fade (float | tuple[float, float] | None) – fade in/out in secods. None=default. Either a fade value or a tuple (fadein, fadeout)

  • crossfade – if looping, this indicates the length of the crossfade

  • blockread – block while reading the source (if needed) before playback is scheduled

Returns:

kgain, kspeed, kchan, kpan

Return type:

A Synth with the following mutable parameters

makeRenderer(sr=0, nchnls=None, ksmps=0, addTables=True, addIncludes=True)[source]#

Create a Renderer (to render offline) with the instruments defined in this Session

To schedule events, use the sched() method of the renderer

Parameters:
  • sr – the samplerate (see config[‘rec_sr’])

  • ksmps – ksmps used for rendering (see also config[‘rec_ksmps’]). 0 uses the default defined in the config

  • nchnls (int | None) – the number of output channels. If not given, nchnls is taken from the session

  • addTables – if True, any soundfile read via readSoundFile will be made available to the renderer. The TableProxy corresponding to that soundfile can be queried via csoundengine.offline.Renderer.soundfileRegistry. Notice that data tables will not be exported to the renderer

  • addIncludes – add any #include file declared in this session to the created renderer

Return type:

Renderer

Returns:

a Renderer

Example

>>> from csoundengine import *
>>> s = Engine().session()
>>> s.defInstr('sine', r'''
... |kamp=0.1, kfreq=1000|
... outch 1, oscili:ar(kamp, freq)
... ''')
>>> renderer = s.makeRenderer()
>>> event = renderer.sched('sine', 0, dur=4, args=[0.1, 440])
>>> event.set(delay=2, kfreq=880)
>>> renderer.render("out.wav")

Bus Class#

class csoundengine.busproxy.Bus(kind, token, renderer, bound=True)[source]#

A wrapper around a raw bus

Note

A user never creates a Bus directly. A Bus is created by a Session through the method assignBus().

Parameters:
  • kind (str) – the bus kind, one of ‘audio’, ‘control’

  • token (int) – the token as returned via csoundengine.engine.Engine.assignBus()

  • renderer (AbstractRenderer) – the renderer to which this Bus belongs

  • bound – if True, the Bus object uses itself a reference. This means that the bus will stay alive at least as long as this object is kept alive. The bus might still survive the object if it is still being used by any instrument

Attributes:

renderer

The parent renderer

token

Token as returned via csoundengine.engine.Engine.assignBus()

kind

Bus kind, one of 'audio', 'control'

bound

Bind the bus lifetime to this object.

Methods:

set(value[, delay])

Set the value of this bus

get()

Get the value of the bus

automate(pairs[, mode, delay, overtake])

Automate this bus

release()

Manually release the bus

renderer#

The parent renderer

token#

Token as returned via csoundengine.engine.Engine.assignBus()

kind#

Bus kind, one of ‘audio’, ‘control’

bound#

Bind the bus lifetime to this object.

set(value, delay=0.0)[source]#

Set the value of this bus

This is only valid for scalar (control) buses

Parameters:
  • value (float) – the new value

  • delay – when to set the value

Return type:

None

Example

>>> from csoundengine import *
>>> s = Engine().session()
>>> s.defInstr('vco', r'''
... |ifreqbus|
... kfreq = busin:k(ifreqbus)
... outch 1, vco2:a(0.1, kfreq)
... ''')
>>> freqbus = s.assignBus(value=1000)
>>> s.sched('vco', 0, 4, ifreqbus=freqbus)
>>> freqbus.set(500, delay=0.5)
get()[source]#

Get the value of the bus

Return type:

float

Example

>>> from csoundengine import *
>>> s = Engine().session()
>>> s.defInstr('rms', r'''
... |irmsbus|
... asig inch 1
... krms = rms:k(asig)
... busout irmsout, krms
... ''')
>>> rmsbus = s.assignBus('control')
>>> synth = s.sched('rms', irmsbus=rmsbus.token)
>>> while True:
...     rmsvalue = rmsbus.get()
...     print(f"Rms value: {rmsvalue}")
...     time.sleep(0.1)
automate(pairs, mode='linear', delay=0.0, overtake=False)[source]#

Automate this bus

This operation is only valid for control buses. The automation is performed within csound and is thus assured to stay in sync

Parameters:
  • pairs (Union[Sequence[float], tuple[Sequence[float], Sequence[float]]]) – the automation data as a flat sequence (t0, value0, t1, value1, …) Times are relative to the start of the automation event

  • mode – interpolation mode, one of ‘linear’, ‘expon(xx)’, ‘cos’, ‘smooth’. See the csound opcode ‘interp1d’ for mode information (https://csound-plugins.github.io/csound-plugins/opcodes/interp1d.html)

  • delay – when to start the automation

  • overtake – if True, the first value of pairs is replaced with the current value of the bus. The same effect can be achieved if the first value of the automation line is a nan

See also

Engine.assignBus(), Engine.writeBus(), Engine.automatep()

Example

>>> from csoundengine import *
>>> s = Engine().session()
>>> s.defInstr('sine', r'''
... |ifreqbus|
... kfreq = busin:k(ifreqbus)
... outch 1, oscili:a(0.1, kfreq)
... ''')
>>> freqbus = s.assignBus(value=440)
>>> synth = s.sched('sine', ifreqbus=freqbus)
>>> freqbus.automate([0, float('nan'), 3, 200, 5, 200])
release()[source]#

Manually release the bus

Normally this operation is done automatically when the object is deleted.

Return type:

None


See Also#