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.
UI generated when using the terminal:
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 controlA 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
, anInstr
is created and registered with the Session. Alternatively, the shortcutdefInstr()
can be used to create and register anInstr
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
Is an offline renderer attached to this session?
Does this session have a handler to redirect actions? :rtype:
bool
stop
()Stop this session and the underlying engine
Does the underlying engine have bus support?
automate
(event, param, pairs[, mode, delay, ...])Automate any named parameter of this Synth
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 sessionReturns 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 nameprepareSched
(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
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 SessionAttributes:
The Engine corresponding to this Session
The name of this Session/Engine
maps instr name to Instr
Number of priorities in this Session
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 usesession = Engine(...).session()
priorities (
int
|None
) – the max. number of priorities for scheduled instrsmaxControlsPerInstr (
int
|None
) – the max. number of named controls per instrnumControlSlots (
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)
-
name:
str
# The name of this Session/Engine
-
numPriorities:
int
# Number of priorities in this Session
- maxDynamicArgs#
The max. number of dynamic parameters per instr
- 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 automateparam (
str
) – the name of the parameter to automatepairs (
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.
- 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 sessionAny 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 valuesinit – 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 prioritydoc – documentation describing what this instr does
includes (
list
[str
] |None
) – list of files to be included in order for this instr to workaliases (
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 nameuseDynamicPfields (
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 tablekws – any keywords are passed on to the Instr constructor. See the documentation of Instr for more information.
- Return type:
- 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 callSession.prepareSched()
to explicitely compile the instrExample
>>> 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
- 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
See also
- 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
- getInstr(instrname)[source]#
Returns the
Instr
defined under nameReturns 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
- 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 itselfpriority (
int
) – the priority of the instrblock – 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 Instrpriority (
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
- 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 aBus
, which can be used to write, read or automate a bus. To pass the bus to an instrument expecting a bus, use itstoken
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 withpersist=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 Nonepersist – if True, the bus is valid until manually released or until the returned Bus object is freed.
- Return type:
- 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:
- 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. Ancsoundengine.event.Event
represents an unscheduled event.- Return type:
- 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()
- 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 aSession
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 usedksmps – 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:
- Returns:
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
- 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 interactivelydelay – 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 p5whenfinished (
Optional
[Callable
]) – a function of the form f(synthid) -> None if given, it will be called when this instance stopsrelative – 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:
- 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
- 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 aSynth
whenstop()
is called.- Parameters:
event (
int
|float
|SchedEvent
) – the event to stop, either a Synth or the p1delay – 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:
- 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 emptysize (
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 valueblock – 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:
- 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 / aTableProxy
)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 datadelay – 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:
- 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 SessionTo 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 sessionaddTables – 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 rendereraddIncludes – add any
#include
file declared in this session to the created renderer
- Return type:
- 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 methodassignBus()
.- Parameters:
kind (
str
) – the bus kind, one of ‘audio’, ‘control’token (
int
) – the token as returned viacsoundengine.engine.Engine.assignBus()
renderer (
AbstractRenderer
) – the renderer to which this Bus belongsbound – 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:
The parent renderer
Token as returned via
csoundengine.engine.Engine.assignBus()
Bus kind, one of 'audio', 'control'
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 valuedelay – 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 eventmode – 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])