Soundstage()

Import Soundstage.

import Soundstage from '/soundstage/build/module.js';

Create a new stage.

const stage = new Soundstage();

A stage is a graph of AudioNodes and a sequencer of events. It has the following properties and methods.

.label

A string name or title for this Soundstage document.

Graph

.createNode(type, settings)

Creates a new AudioNode in the Soundstage graph.

var wrap = stage.createNode('delay', {
    delayTime: 0.5
});

The type parameter is a string, and must be one of the node types either built-in or registered with Soundstage. The settings parameter is an object of settings specific to that node type.

The AudioNode is wrapped in an object with an id and label in the .nodes array. The wrapper object is returned.

.get(id)

Returns the AudioNode with id from the graph, or undefined.

var node = stage.get('0');

Sequencer

.startTime

The time at which playback is scheduled to start.

.stopTime

The time at which playback is scheduled to stop.

.rate

An AudioParam representing the rate of the transport clock in beats per second.

.time

The time of audio now leaving the device output. On browsers the have not yet implemented context.getOutputTimestamp() this value is estimated from currentTime and a guess at the output latency.

.rate

The rate of the transport clock in beats per second.

.tempo

The rate of the transport clock, expressed in bpm.

.sequences

An array of sequences that may be triggered by 'sequence' events stored in .events. See Sequences.

Audio

Nodes

Create a new node in the graph with a type string and a settings object:

stage.createNode('tick', {
    gain: 0.25,
    resonance: 1.1
});

A stage may be initialised with nodes by passing in an object with a nodes array to the Soundstage constructor:

const stage = new Soundstage({
    nodes: [{
        id: "1",
        type: "tick",
        node: {
            gain: 0.25,
            resonance: 1.1
        }
    }]
});

The available built-in node types and the settings they accept:

"input"

const input = stage.createNode('input', {
    channels: [1, 2]    // Device channels to use as input
});

.channels

An array of channel numbers. For stereo input this would typically be [1, 2].

"output"

const output = stage.createNode('output', {
    channels: [1, 2]    // Device channels to send output to
});

.channels

An array of channel numbers. For stereo output this would typically be [1, 2].

"compressor"

const compressor = stage.createNode('compressor');

Creates a standard CompressorNode.

"delay"

const delay = stage.createNode('delay');

Creates a standard DelayNode.

"eq"

const eq = stage.createNode('eq');

.nodes

An array of biquad-filter nodes.

"filter"

const filter = stage.createNode('filter');

Creates a filter node.

"flanger"

const flanger = stage.createNode('flanger', {
    delay:
    depth:
    feedback:
    frequency:
    type:
    dry:
    wet:
});

Creates a modulation delay effect, or ‘flanger’.

.feedback

Signal gain to feed back into the modulator.

.dry

AudioParam controlling dry gain.

.wet

AudioParam controlling effect gain.

"looper"

const looper = stage.createNode('looper', {
    [Todo]
});

Creates a node that records and loops audio.

.dry

An AudioParam controlling the direct signal (‘dry’) gain.

.wet

An AudioParam controlling the looper signal (‘wet’) gain.

.beats

The beat duration of the base loop.

.start(time)

Start playback of loops at time. If Soundstage’s transport is not running, it is set to run at the same rate as the looper and also started at time.

Returns `this`.

.startRecord(time)

Starts recording at time. The looper is continually buffering a signal, so time may be before context.currentTime (by up to 0.6s @44.1kHz or 0.3s @96kHz). This means recorded loops may be started in syncrounisation with audio already leaving the system’s output.

Returns `this`.

.stopRecord(time)

Stop recording at time. If the looper is not already playing, playback is started at the same time.

Returns `this`.

.records()

Returns an array of records, objects containing unsaved buffers. This method is called by Soundstage.records() when gathering records from all nodes.

"saturator"

const saturator = stage.createNode('saturator', {

});

"meter"

const meter = stage.createNode('meter');

.peaks

Peak level readout per channel.

"mix"

const mix = stage.createNode('mix', {
    gain: 1,
    pan: 0
});

.gain

AudioParam controlling gain.

.pan

AudioParam controlling stereo pan position.

"noise"

const noise = stage.createNode('noise', {
    type: 'sine',      // String 'white', 'pink', 'brown'
});

A noise object generates noise.

.type

One of the strings 'white', 'pink' or 'brown' describing the colour of noise to generate.

"sample"

const sample = stage.createNode('sample', {
    src: 'path/to/data',  // A path where the data for the sample set is kept
});

A sample object represents a set of audio buffers that are mapped to the playback of pitches. Mapping is defined in a JSON file.

.src

Path to a JSON file for sample set data. See [Todo:link] Sample Set Data.

.detune

An AudioParam that modifies the frequency in cents.

"tone"

const tone = stage.createNode('tone', {
    type: 'sine',      // String 'sine', 'square', 'sawtooth', 'triangle'
    frequency: 440,    // Frequency in Hz
    detune: 0,         // Deviation from frequency in cents
    gain: 1            // A float nominally in the range 0-1
});

A tone object is a simple wrapper for a standard oscillator node, but where an oscillator may only be started once, a tone can be started and stopped at will.

It is unusual to create tones directly, but they are an essential component for defining voices for instruments.

.type

A string. One of 'sine', 'square', 'sawtooth' or 'triangle'.

.detune

An AudioParam representing a deviation from frequency in cents.

.gain

A float, nominally in the range 0–1, that is read on calling .start() to set the gain of the tone. Changes to .gain during playback have no effect.

"tick"

const tick = stage.createNode('tick', {
    resonance:         // Todo
    decay:             // Todo
    gain: 1            // Output gain nominally in the range `0–1`
});

A tick object is a signal generator that emits a ‘tick’ sound on .start(). Used inside the metronome.

.gain

An AudioParam representing output gain.

.stop()

A noop method, provided to echo the interface of other generators.

"envelope"

const envelope = stage.createNode('envelope', {
    // An array of param events describing a attack curve
    attack: [
        [0.01, 'linear', 1]
    ],

    // An array of param events describing a release curve
    release: [
        [0, 'target', 0, 0.2]
    ],

    gain: 1,
    rate: 1
});

Take care not to connect an envelope directly to your outputs – expecially if you have expensive speakers attached. They are capable of producing DC signal.

.attack

An array of param events describing an arbitrary attack curve for the envelope. Param events have the form [time, type, value] (or if type is 'target', [time, type, value, duration]), where time is the time since the time passed to .start(time).

The default envelope value at time `0` is `0`.

.release

An array of param events describing the release curve of the envelope. Param events have the form [time, type, value] (or if type is 'target' [time, type, value, duration]), where time is the time since the time passed to .stop(time).

Values are scaled to the current value of the envelope – if the attack
envelope decays to a value of `0.5`, say, by the scheduled stop time, all
values in the release envelope are multiplied by `0.5`. The last event
should have a value of `0`, otherwise the envelope will never stop.

.gain

A float, nominally in the rage 0–1, that is read on .start() to determine the gain to apply to the curve.

.rate

A float that is read on .start() or .stop() to determine the rate of playback to apply to the curve.

"instrument"

const instrument = stage.createNode('instrument', {
    voice: {
        // Inherited from NodeGraph
        nodes: [...],
        connections: [...],
        properties: {...},
        output: 'id',

        // Start parameters
        __start: {
            filter: {
                frequency: {
                    1: { type: 'scale', scale: 1 }
                }
            }
        },
    }
});

An instrument is a polyphonic controller for multiple voice nodes. The voice property of an instrument describes an arbitrary node graph that is used to build and play a voice node each time instrument.start() is called.

The voice settings nodes, connections, properties and output are inherited from NodeGraph (see below).

The __start object defines transforms that determine how .start() parameters map to property and param values of the voice. In the example above start parameter 1 (note frequency) is scaled then used to set the frequency AudioParam of the child node 'filter'.

.start(time, note, velocity)

Creates a voice node from the data in .voice, then calls its .start() method with the same parameters.

Returns the voice node, enabling the pattern:

```
instrument
.start(startTime, note, velocity)
.stop(stopTime);
```

.stop(time, note)

Stops the first playing voice node found to match note. Provided as a convenience: normally voice nodes are stopped using their own .stop() method.

Returns this.

Connectors

Connect two nodes in the stage graph:

stage.createConnector(source, target);

A stage may be initialised with nodes connected by passing in an object with a connections array to the Soundstage constructor:

const stage = new Soundstage({
    nodes: [
        { type: "tick", id: "1" },
        { type: "output", id: "2" }
    ],

    connections: [
        { source: "1", target: "2" }
    ]
});

Sequences

A sequence is an object with an .events array. A stage itself is a sequence: it has an .events array. Events may be created in the stage events array by calling stage.createEvent():

stage.createEvent(0, 'rate', 1);

A stage may be initialised with events by passing them in the data object to the Soundstage constructor:

const stage = new Soundstage({
    events: [
        [0, 'rate', 1]
    ]
});

Events in the .events array are played when the sequencer is started:

stage.start();

Events

An event requires a beat, type and some data.

stage.createEvent(beat, type, data...);

Data parameters are dependent on the event type. The built-in events types and the data they expect are:

"meter"

[beat, "meter", numerator, denominator]

"note"

[beat, "note", name, velocity, duration]

"param"

[beat, "param", name, value, curve]

"rate"

[beat, "rate", rate, curve]

"sequence"

[beat, "sequence", sequence, target, duration]