OfflineRenderer

class maelzel.core.offline.OfflineRenderer(outfile='', sr=None, ksmps=None, numchannels=None, tail=0.0, verbose=None, endtime=0.0, session=None)[source]

Bases: Renderer

An OfflineRenderer is created to render musical objects to a soundfile

OfflineRenderer as context manager

The simplest way to render offline is to use an OfflineRenderer as a context manager (see also render()). Within this context any .play call will be collected and everything will be rendered when exiting the context (see example below)

Parameters:
  • outfile (str) – the path to the rendered soundfile. If not given, a path within the record path [1] is returned

  • sr (Optional[int]) – the sr of the render (config key: ‘rec.sr’)

  • ksmps (Optional[int]) – the ksmps used for the recording

  • numchannels (Optional[int]) – number of channels of this renderer. If not set, this will depend on the scheduled events and the final call to .render

  • verbose (Optional[bool]) – if True, debugging output is show. If None, defaults to config (key: ‘rec.verbose’)

  • endtime – used when the OfflineRenderer is called as a context manager

If rendering offline in tandem with audio samples and other csoundengine’s functionality, it is possible to access the underlying csoundengine’s Renderer via the .renderer attribute

(see recordPath())

Example

Render a chromatic scale in sync with a soundfile

>>> from maelzel.core import *
>>> import sndfileio
>>> notes = [Note(n, dur=0.5) for n in range(48, 72)]
>>> chain = Chain(notes)
>>> defPresetSoundfont('piano', sf2path='/path/to/piano.sf2')
>>> samples, sr = sndfileio.sndread('/path/to/soundfile')
>>> with render('scale.wav') as r:
...     chain.play(instr='piano')
...     # This allows access to the underlying csound renderer
...     r.renderer.playSample((samples, sr))

When exiting the context manager the file ‘scale.wav’ is rendered. During the context manager, all calls to .play are intersected and scheduled via the OfflineRenderer. This makes it easy to switch between realtime and offline rendering by simply changing from play to render()

Attributes Summary

scheduledEvents

The scheduled events

Methods Summary

assignBus([kind, value, persist])

Assign a bus of the given kind

definedInstrs()

Get all instruments available within this OfflineRenderer

getCsd()

Return the .csd as string

getInstr(instrname)

Get the csoundengine's Instr corresponding to instrname

getSession()

Return the Session associated with this OfflineRenderer, if any

getSynth(token)

Get a synth by token/synthid

includeFile(path)

Add an include clause to this renderer.

isInstrDefined(instrname)

Is an Instr with the given name defined?

isRealtime()

Is this a realtime renderer?

isRendering()

True if still rendering

lastOutfile()

Last rendered outfile, None if no soundfiles were rendered

lastRenderProc()

Last process (subprocess.Popen) used for rendering

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

Create a table in this renderer

openLastOutfile([timeout])

Open last rendered soundfile in an external app

play(obj, **kws)

Schedule the events generated by this obj to be renderer offline

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

Play a sample through this renderer

popLock()

Pop the lock of the audio engine (must be preceded by a pushLock)"

prepareEvent(event)

Prepare an event to be scheduled

prepareEvents(events[, sessionevents])

Prepare a series of events for scheduling

prepareInstr(instr, priority)

Reify an instance of instr at the given priority

preparePreset(presetdef, priority)

Prepare a preset to be used

prepareSessionEvent(sessionevent)

Prepare a session event

pushLock()

Lock the audio engine

readSoundfile(soundfile[, chan, skiptime])

Read a soundfile into the renderer

registerInstr(name, instrdef)

Register a csoundengine.Instr to be used with this OfflineRenderer

registerPreset(presetdef)

Register the given PresetDef with this renderer

releaseBus(busnum)

Signal that we no longer use the given bus

render([outfile, wait, verbose, ...])

Render the events scheduled until now.

renderedSample()

Returns the last rendered soundfile as a maelzel.snd.audiosample.Sample

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

Schedule a csound event

schedDummyEvent([dur])

Schedule a dummy synth

schedEvent(event)

Schedule a SynthEvent or a csound event

schedEvents(coreevents[, sessionevents, ...])

Schedule multiple events as returned by MObj.events()

show()

If inside jupyter, force a display of this OfflineRenderer

sync()

Block until the audio engine has processed its immediate events

timeRange()

The time range of the scheduled events

wait([timeout])

Wait until finished rendering

writeCsd([outfile])

Write the .csd which would render all events scheduled until now

Attributes Documentation

scheduledEvents

The scheduled events

Methods Documentation

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

Assign a bus of the given kind

Return type:

int

Returns:

the bus token. Can be used with any bus opcode (busin, busout, busmix, etc)

definedInstrs()[source]

Get all instruments available within this OfflineRenderer

All presets and all extra intruments registered at the active Session (as returned via getPlaySession) are available

Returns:

csoundengine.Instr} with all instruments available

Return type:

dict {instrname

getCsd()[source]

Return the .csd as string

Return type:

str

getInstr(instrname)[source]

Get the csoundengine’s Instr corresponding to instrname

Parameters:

instrname (str) – the name of the csoundengine’s Instr

Return type:

Instr | None

Returns:

If found, the csoundengine’s Instr

getSession()[source]

Return the Session associated with this OfflineRenderer, if any

Return type:

Session | None

getSynth(token)[source]

Get a synth by token/synthid

Return type:

SchedEvent | None

includeFile(path)[source]

Add an include clause to this renderer.

OfflineRenderer keeps track of includes so trying to include the same file multiple times will generate only one #include clause

Parameters:

path (str) – the path of the file to include

Return type:

None

isInstrDefined(instrname)

Is an Instr with the given name defined?

Return type:

bool

isRealtime()[source]

Is this a realtime renderer?

Return type:

bool

isRendering()[source]

True if still rendering

Return type:

bool

Returns:

True if rendering is still in course

lastOutfile()[source]

Last rendered outfile, None if no soundfiles were rendered

Return type:

str | None

Example

>>> r = OfflineRenderer(...)
>>> r._sched(...)
>>> r.render(wait=True)
>>> r.lastOutfile()
'~/.local/share/maelzel/recordings/tmpsasjdas.wav'
lastRenderProc()[source]

Last process (subprocess.Popen) used for rendering

Return type:

Popen | None

Example

>>> r = OfflineRenderer(...)
>>> r._sched(...)
>>> r.render("outfile.wav", wait=False)
>>> if (proc := r.lastRenderProc()) is not None:
...     proc.wait()
...     print(proc.stdout.read())
makeTable(data=None, size=0, sr=0, tabnum=0)[source]

Create a table in this renderer

Parameters:
  • data (Union[ndarray, list[float], None]) – if given, the table will be created with the given data

  • size (int) – if data is not given, an empty table of the given size is created. Otherwise, this parameter is ignored

  • sr (int) – the sample rate of the data, if applicable

  • tabnum (int) – leave it as 0 to let the renderer assign a table number

Return type:

int

Returns:

the assigned table number

openLastOutfile(timeout=None)[source]

Open last rendered soundfile in an external app

Will do nothing if there is no outfile. If the render is in progress this operation will block.

Parameters:

timeout – if the render is not finished this operation will block with the given timeout

Return type:

str

Returns:

the path of the soundfile or an empty string if no soundfile was rendered

play(obj, **kws)[source]

Schedule the events generated by this obj to be renderer offline

Parameters:
  • obj (MObj) – the object to be played offline

  • kws – any keyword passed to the .events method of the obj

Return type:

SchedEventGroup

Returns:

the offline score events

playSample(source, delay=0.0, dur=0, chan=1, gain=1.0, speed=1.0, loop=False, pos=0.5, skip=0.0, fade=None, crossfade=0.02)[source]

Play a sample through this renderer

Parameters:
  • source (int | str | TableProxy | tuple[np.ndarray, int] | audiosample.Sample) – a soundfile, a TableProxy, a tuple (samples, sr) or a maelzel.snd.audiosample.Sample

  • delay – when to play

  • dur – the duration. -1 to play until the end (will detect the end of the sample)

  • chan – the channel to output to

  • gain – a gain applied

  • speed – playback speed

  • loop – should the sample be looped?

  • pos – the panning position

  • skip – time to skip from the audio sample

  • fade (float | tuple[float, float] | None) – a fade applied to the playback

  • crossfade – a crossfade time when looping

Return type:

csoundengine.offline.SchedEvent

Returns:

a csoundengine.offline.SchedEvent

popLock()

Pop the lock of the audio engine (must be preceded by a pushLock)”

This only makes sense for realtime rendering and is a no-op when rendering offline

Return type:

None

prepareEvent(event)

Prepare an event to be scheduled

Parameters:

event (SynthEvent) – the event to schedule

Return type:

bool

Returns:

True if the operation performed some action on the audio engine

prepareEvents(events, sessionevents=None)

Prepare a series of events for scheduling

All init codes which need to be compiled are compiled and synched, then all presets are prepared for the given priority. This method minimizes the number of syncs needed.

Parameters:
  • events (list[SynthEvent]) – the core events to prepare

  • sessionevents (Optional[list[Event]]) – any session events

Return type:

bool

Returns:

True if the renderer needs to be synched. The called is resposible for calling the Renderer.sync() method

prepareInstr(instr, priority)[source]

Reify an instance of instr at the given priority

This method also prepares any resources and initialization that the given Instr might have

Parameters:
  • instr (Instr) – a csoundengine’s Instr

  • priority (int) – the priority to instantiate this instr with. Priorities start with 1

Return type:

bool

Returns:

False

preparePreset(presetdef, priority)

Prepare a preset to be used

Parameters:
  • presetdef (PresetDef) – the preset definition

  • priority (int) – the priority to use

Return type:

bool

Returns:

True if this operation performed some action on the audio engine. This can be used to sync the audio engine if needed.

prepareSessionEvent(sessionevent)[source]

Prepare a session event

Parameters:

sessionevent (Event) – the session event to prepare. This is mostly used internally

Return type:

None

pushLock()

Lock the audio engine

This only makes sense for realtime rendering and is a no-op when rendering offline

Return type:

None

readSoundfile(soundfile, chan=0, skiptime=0.0)[source]

Read a soundfile into the renderer

Parameters:
  • soundfile (str) – the soundfile to read

  • chan – the channel to read, 0 to read all channels

  • skiptime – start reading from this time

Return type:

int

registerInstr(name, instrdef)[source]

Register a csoundengine.Instr to be used with this OfflineRenderer

Note

All csoundengine.Instr defined in the play Session are available to be rendered offline without the need to be registered

Parameters:
  • name (str) – the name of this preset

  • instrdef (Instr) – the csoundengine.Instr instance

Return type:

None

registerPreset(presetdef)[source]

Register the given PresetDef with this renderer

Parameters:

presetdef (PresetDef) – the preset to register. Any global/init code declared by the preset will be made available to this renderer

Return type:

bool

Returns:

to adjust to the Renderer parent class we always return False since offline rendering does not need to sync

releaseBus(busnum)[source]

Signal that we no longer use the given bus

Parameters:

busnum (int) – the bus token as returned by OfflineRenderer.assignBus()

Return type:

None

render(outfile='', wait=None, verbose=None, openWhenDone=False, compressionBitrate=None, endtime=None, ksmps=None, tail=None)[source]

Render the events scheduled until now.

You can access the rendering subprocess (a subprocess.Popen object) via lastRenderProc()

Parameters:
  • outfile – the soundfile to generate. Use “?” to save via a GUI dialog, None will render to a temporary file

  • wait (Optional[bool]) – if True, wait until rendering is done

  • verbose (Optional[bool]) – if True, show output generated by csound itself (print statements and similar opcodes still produce output)

  • endtime (Optional[float]) – if given, crop rendering to this absolute time (in seconds)

  • compressionBitrate (Optional[int]) – the compression bit rate when rendering to .ogg (in kb/s, the default can be configured in config['.rec.compressionBitrate']

  • openWhenDone – if True, open the rendered soundfile in the default application

  • ksmps (Optional[int]) – the samples per cycle used when rendering

  • tail (Optional[float]) – an extra time at the end of the render to make room for long decaying sounds / reverbs. If given, overrides the tail parameter given at init.

Return type:

str

Returns:

the path of the rendered file

Example

>>> from maelzel.core import *
>>> scale = Chain([Note(n) for n in "4C 4D 4E 4F 4G".split()])
>>> playback.playSession().defInstr('reverb', r'''
... |kfeedback=0.6|
... amon1, amon2 monitor
... a1, a2 reverbsc amon1, amon2, kfeedback, 12000, sr, 0.6
... outch 1, a1-amon1, 2, a2-amon2
... ''')
>>> presetManager.defPresetSoundfont('piano', '/path/to/piano.sf2')
>>> renderer = playback.OfflineRenderer()
>>> renderer.schedEvents(scale.events(instr='piano'))
>>> renderer._sched('reverb', priority=2)
>>> renderer.render('outfile.wav')
renderedSample()[source]

Returns the last rendered soundfile as a maelzel.snd.audiosample.Sample

Return type:

Sample

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

Schedule a csound event

This method can be used to schedule non-preset based instruments when rendering offline (things like global effects, for example), similarly to how a user might schedule a non-preset based instrument in real-time.

If an OfflineRenderer is used as a context manager it is also possible to call the session’s ._sched method directly since its _sched callback is rerouted to call this OfflineRenderer instead

Parameters:
  • instrname (str) – the instr. name

  • delay – start time

  • dur – duration

  • priority – priority of the event

  • args (Union[list[float], dict[str, float], None]) – any pfields passed to the instr., starting at p5

  • whenfinished – this argument does nothing under this context. It is only present to make the signature compatible with the interface

  • relative – dummy argument, here to conform to the signature of csoundengine’s Session.sched, which is redirected to this method when an OfflineRenderer is used as a context manager

  • **kws – named pfields

Return type:

SchedEvent

Returns:

the offline.ScoreEvent, which can be used as a reference by other offline events

Example

Schedule a reverb at a higher priority to affect all notes played. Notice that the reverb instrument is declared at the play Session (see play.getPlaySession()). All instruments registered at this Session are immediately available for offline rendering.

>>> from maelzel.core import *
>>> scale = Chain([Note(n) for n in "4C 4D 4E 4F 4G".split()])
>>> playback.playSession().defInstr('reverb', r'''
... |kfeedback=0.6|
... amon1, amon2 monitor
... a1, a2 reverbsc amon1, amon2, kfeedback, 12000, sr, 0.6
... outch 1, a1-amon1, 2, a2-amon2
... ''')
>>> presetManager.defPresetSoundfont('piano', '/path/to/piano.sf2')
>>> with playback.OfflineRenderer() as r:
...     r._sched('reverb', priority=2)
...     scale.play('piano')
schedDummyEvent(dur=0.001)

Schedule a dummy synth

schedEvent(event)[source]

Schedule a SynthEvent or a csound event

Parameters:

event (SynthEvent | Event) – a SynthEvent

Return type:

SchedEvent

Returns:

a SchedEvent

schedEvents(coreevents, sessionevents=None, whenfinished=None)[source]

Schedule multiple events as returned by MObj.events()

Parameters:
  • coreevents (list[SynthEvent]) – the events to schedule

  • sessionevents (Optional[list[Event]]) – csound events as packed within a csoundengine.session.SessionEvent

  • whenfinished (Optional[Callable]) – dummy arg, here to conform to the signature of the parent. Only makes sense in realtime

Return type:

SchedEventGroup

Returns:

a csoundengine.offline.SchedEventGroup. This can be used to modify scheduled events via set(), automate() or stop

Example

>>> from maelzel.core import *
>>> scale = Chain([Note(m, 0.5) for m in range(60, 72)])
>>> renderer = OfflineRenderer()
>>> renderer.schedEvents(scale.events(instr='piano'))
>>> renderer.render('outfile.wav')
show()

If inside jupyter, force a display of this OfflineRenderer

Return type:

None

sync()

Block until the audio engine has processed its immediate events

Return type:

None

timeRange()[source]

The time range of the scheduled events

Return type:

tuple[float, float]

Returns:

a tuple (start, end)

wait(timeout=0)[source]

Wait until finished rendering

Parameters:

timeout – a timeout (0 to wait indefinitely)

Return type:

None

writeCsd(outfile='?')[source]

Write the .csd which would render all events scheduled until now

Parameters:

outfile (str) – the path of the saved .csd

Return type:

str

Returns:

the outfile