@elemaudio/offline-renderer
The official package for rendering Elementary applications offline, whether in Node.js or in the browser.
Often this is used for file-based processing (reading files, processing them, and writing them to disk), though
the actual encoding/decoding to and from file is not handled here, just the actual audio processing.
Note that, while the command line Node renderer currently requires the separate
Elementary command line binary, this renderer actually runs properly in Node.js itself.
This package will be used alongside @elemaudio/core
. Please see the full
documentation at https://www.elementary.audio/docs
Installation
npm install --save @elemaudio/offline-renderer
Example
import {el} from '@elemaudio/core';
import OfflineRenderer from '@elemaudio/offline-renderer';
(async function main() {
let core = new OfflineRenderer();
await core.initialize({
numInputChannels: 0,
numOutputChannels: 1,
sampleRate: 44100,
});
let inps = [];
let outs = [new Float32Array(44100 * 10)];
core.render(el.cycle(440));
core.process(inps, outs);
})();
Usage
import Offline from '@elemaudio/offline-renderer';
Constructor
let core = new OfflineRenderer();
No arguments provided; you can construct multiple OfflineRenderers and use them however you like,
even to generate buffers that will be loaded into other OfflineRenderers.
initialize
core.initialize(options: Object): Promise<void>
Initializes the Elementary offline runtime. In most other Elementary applications you'll rely on listening
for the "load" event to fire after initialization. With the OfflineRenderer you can be sure that after initialize
resolves, the runtime is ready to render.
The options object expects the following properties:
numInputChannels: number
– default 0numOutputChannels: number
– default 2sampleRate: number
– default 44100blockSize: number
– default 512virtualFileSystem: Object<string, Array<number>|Float32Array>
– default {}
render
core.render(...args: Array<NodeRepr_t | number>) : RenderStats;
Performs the reconciliation process for rendering your desired audio graph. This method expects one argument
for each available output channel. That is, if you want to render a stereo graph, you will invoke this method
with two arguments: core.render(leftOut, rightOut)
.
The RenderStats
object returned by this call provides some insight into what happened during the reconciliation
process: how many new nodes and edges were added to the graph, how long it took, etc.
updateVirtualFileSystem
core.updateVirtualFileSystem(Object<string, Array | Float32Array>);
Use this method to dynamically update the buffers available in the virtual file system after initialization. See the
Virtual File System section below for more details.
reset
core.reset();
Resets internal nodes and buffers back to their initial state.
Events
Each OfflineRenderer
instance is itself an event emitter with an API matching that of the Node.js Event Emitter
class.
The renderer will emit events from underlying audio processing graph for nodes such as el.meter
, el.snapshot
, etc. See
the reference documentation for each such node for details.
Virtual File System
When running offline, either in a web browser or in Node.js, the Elementary runtime has no access to your file system or network itself.
Therefore, when writing graphs which rely on sample data (such as with el.sample
, el.table
, or el.convolve
),
you must first load the sample data into the runtime using the virtual file system.
If you know your sample data ahead of time, you can load the virtual file system at initialization time using the
virtualFileSystem
property as follows.
await core.initialize(ctx, {
numInputChannels: 0,
numOutputChannels: 2,
virtualFileSystem: {
'/your/virtual/file.wav': (new Float32Array(512)).map(() => Math.random()),
}
});
After configuring the core processor this way, you may use el.sample
or any other node which
reads from file by referencing the corresponding virtual file path that you provided:
core.render(el.sample({path: '/your/virtual/path.wav'}, el.train(1)))
If you need to dynamically update the virtual file system after initialization, you may do so
using the updateVirtualFileSystem
method.
await core.initialize({
numInputChannels: 0,
numOutputChannels: 1,
});
let inps = [];
let outs = [new Float32Array(44100 * 10)];
core.render(el.cycle(440));
core.process(inps, outs);
core.updateVirtualFileSystem({
'/some/new/arbitrary/fileName.wav': myNewSampleData,
});
core.render(el.sample({path: '/some/new/arbitrary/fileName.wav'}, el.train(1)))
core.process(inps, outs);
Note: Each virtual file system entry maps to a single channel of audio data. To load multi-channel sample
data into the virtual file system, you should enumerate each channel as a differently named virtual file path.
MIDI
The OfflineRenderer does not include MIDI support itself.