Soundio is a Graph Object Model for Web Audio processing graphs. It provides an API for creating, manipulating and observing graphs, and a JSONify-able structure for exporting and importing them.
Soundio is the library that powers sound.io.
Soundio is in development. It is currently dependent on three repos that can be installed as git submodules:
- github.com/cruncher/collection
- github.com/soundio/audio-object
- github.com/soundio/clock (optional)
- github.com/soundio/midi (optional)
Install with submodules:
git clone https://github.com/soundio/soundio.git
cd soundio
git submodule update --init
Tests use Karma. To run tests:
npm install
karma start
Soundio data
is an object that looks something like this:
var data = {
objects: [
{ id: 0, type: "input" },
{ id: 1, type: "flange", frequency: 0.33, feedback: 0.9, delay: 0.16 },
{ id: 2, type: "output" }
],
connections: [
{ source: 0, destination: 1 },
{ source: 1, destination: 2 }
],
midi: [
{ message: [176, 8], object: 1, property: "frequency" }
]
};
It contains three arrays, objects
, connections
and
midi
. objects
is a collection of
audio objects (an audio
object is a wrapper for one or more Web Audio nodes). Audio objects must have an
id
and type
, while other properties depend on the
type. connections
is a collection of objects defining connections
between the audio objects, and midi
defines routes for incoming
MIDI messages.
Call Soundio with this data to set it up as an audio graph:
var soundio = Soundio(data);
Turn your volume down a bit, enable the mic when prompted by the browser, and you will hear your voice being flanged. Changes to object properties are reflected 'live' in the Web Audio graph.
The resulting object, soundio
, has the same structure as
data
, so the graph can be converted back to data with:
JSON.stringify(soundio);
This means you can export an audio graph you have made at, say,
sound.io – open the console and run this line –
and import it into your own web page – call Soundio()
with
the data.
Soundio also accepts an options
object with one option. Where you
have an existing AudioContext, pass it in to avoid creating a new one:
var soundio = Soundio(data, {
audio: AudioContext
});
Create objects from data. As with Soundio(data)
, but
soundio.create(data)
adds objects, connections and midi routes to
the existing graph.
Remove and destroy all objects and connections.
Removes and destroys all objects and connections, disconnects any media inputs from soundio's input, and disconnects soundio's output from audio destination.
A collecton of audio objects.
An audio object controls one or more audio nodes. In soundio, audio objects have
an id
and a type
. name
is optional. Other
properties depend on the type.
var flanger = soundio.objects.find(1);
{
id: 7,
type: "flange",
frequency: 256
}
Changes to flanger.frequency
are reflected immediately in the
Web Audio graph.
flanger.frequency = 480;
// flanger.automate(name, value, time, curve)
flanger.automate('frequency', 2400, audio.currentTime + 0.8, 'exponential');
For more about audio objects see github.com/soundio/audio-object.
Create an audio object.
type
is a string.
These audio objects connect to the sound card input and output respectively:
- "input"
- "output"
These audio objects wrap sub-graphs of audio nodes and are kind of equivalent to plugins in a DAW:
- "compress"
- "filter"
- "flange"
- "loop"
- "saturate"
- "send"
These audio objects wrap single Web Audio nodes and can be useful for testing:
- "biquad filter"
- "compressor"
- "convolver"
- "delay"
- "oscillator"
- "waveshaper"
settings
depend on the type of audio object being created.
Returns the created audio object. Created objects can also be found in
soundio.objects
, as well as in soundio.inputs
and
soundio.outputs
if they are of type "input"
or
"output"
respectively.
Destroy an audio object in the graph. Both the object and any connections to or from the object are destroyed.
A collection of connections between the audio objects in the graph. A connection
has a source
and a destination
that point to
id
s of objects in soundio.objects
:
{
source: 7,
destination: 12
}
In addition a connection can define a named output node on the source object and/or a named input node on the destination object:
{
source: 7,
output: "send",
destination: 12,
input: "default"
}
Connect two objects. data
must have source
and
destination
defined. Naming an output
or
input
is optional. They will default to "default"
.
soundio.connections.create({
source: 7,
output: "send",
destination: 12
});
Removes all connections whose properties are equal to the properties defined in
the query
object. For example, disconnect all connections to
object with id 3
:
soundio.connections.query({ destination: 3 });
Returns an array of all objects in connections
whose properties
are equal to the properties defined in the query
object. For
example, get all connections from object with id 6
:
soundio.connections.query({ source: 6 });
An instance of Clock
,
which requires the repo github.com/soundio/clock.
If Clock
is not found, soundio.clock
is undefined
.
soundio.clock
is a Collection of tempo data that maps a
beat
clock against the audio context's time
clock. It
is a library of properties and methods for scheduling function calls. It is also
an AudioObject with two
output nodes, "rate"
and "duration"
, for syncing Web
Audio parameters to the tempo.
The current time. Gets audio.currentTime
. Read-only.
The current beat. Gets clock.beatAtTime(audio.currentTime)
. Read-only.
The current rate, in beats per second.
Returns the audio context time at beat
.
Returns the beat at time
.
// Move to 120bpm in 2.5 seconds
clock.automate('rate', 2, clock.time + 2.5);
Inherited from AudioObject.
Creates a tempo change at a time given by beat
. If beat is not
defined, the clock creates a tempo change at the current beat
.
Returns tempo change found at beat
or undefined
.
Removes tempo change found at beat
.
Shorthand for clock.cue(beat, fn, 0)
, calls fn
at the beat specified (0
ms lookahead).
Cue a function to be called just before beat
.
fn
is called with the argument time
, which can used to
accurately schedule Web Audio changes.
clock.cue(42, function(time) {
gainParam.setValueAtTime(time, 0.25);
bufferSourceNode.start(time);
});
Pass in a third parameter lookahead
to override the default
(0.05
s) lookahead:
clock.cue(44, function(time) {
gainParam.setValueAtTime(time, 1);
bufferSourceNode.stop(time);
}, 0.08);
Removes fn
at beat
from the timer queue.
Either, neither or both beat
and fn
can be given.
Remove all cues from the timer queue:
clock.uncue();
Remove cues at beat
from the timer queue:
clock.uncue(beat);
Remove cues to fire fn
from the timer queue:
clock.uncue(fn);
Remove cues at beat
to fire fn
from the timer queue:
clock.uncue(beat, fn)
Removes fn
after beat
from the timer queue.
fn
is optional.
Remove all cues after beat
from the timer queue:
clock.uncueAfter(beat);
Remove all cues after beat
to fire fn
from the timer queue:
clock.uncueAfter(beat, fn)
Shorthand for clock.cueTime(time, fn, 0)
, calls fn
at the time specified (0
ms lookahead).
Cue a function to be called just before time
. fn
is
called with the argument time
, which can used to accurately
schedule changes to Web Audio parameters:
clock.cue(42, function(time) {
gainParam.setValueAtTime(time, 0.25);
bufferSourceNode.start(time);
});
Pass in a third parameter lookahead
to override the default
(0.05
s) lookahead:
clock.cue(44, fn, 0.08);
Removes fn
at time
from the timer cues.
Either, neither or both time
and fn
can be given.
Remove all cues from the timer queue:
clock.uncueTime();
Remove cues at time
from the timer queue:
clock.uncueTime(time);
Remove cues to fire fn
from the timer queue:
clock.uncueTime(fn);
Remove cues at time
to fire fn
from the timer queue:
clock.uncueTime(time, fn)
Removes fn
after time
from the timer queue.
fn
is optional.
Remove all cues after time
from the timer queue:
clock.uncueAfterTime(time);
Remove all cues after time
for fn
from the timer queue:
clock.uncueAfterTime(time, fn)
A collection of MIDI routes that make object properties controllable via incoming MIDI events. A midi route looks like this:
{
message: [191, 0],
object: AudioObject,
property: "gain",
transform: "linear",
min: 0,
max: 1
}
Create a MIDI route from data:
soundio.midi.create({
message: [191, 0],
object: 1,
property: "gain",
transform: "cubic",
min: 0,
max: 2
});
The properties transform
, min
and max
are
optional. They default to different values depending on the type of the object.
Removes all MIDI routes whose properties are equal to the properties defined in
the query
object. For example, disconnect all routes to gain
properties:
soundio.midi.query({ property: "gain" });
Returns an array of all objects in soundio.midi
whose properties
are equal to the properties defined in the query
object. For
example, get all connections from object with id 6
:
soundio.connections.query({ object: 6 });
Register an audio object factory function for creating audio objects of type
type
.
Soundio.register('gain', function(audio, data) {
var gainNode = audio.createGain();
gainNode.gain.value = settings.gain;
return AudioObject(audio, gain, gain, {
gain: gainNode.gain
});
});
data
is an object that comes directly from data passed to
soundio.objects.create(type, data)
or Soundio(data)
.
You should make sure the registered audio object correctly initialises itself
from data
, and JSON.stringify
s back to
data
.
Soundio comes with the following audio object factories registered:
// Single node audio objects
'biquad filter'
'compressor'
'convolver'
'delay'
'oscillator'
'waveshaper'
// Multi node audio objects
'compress'
'flange'
'loop'
'filter'
'saturate'
'send'
Returns true
where value
is not undefined
or null
.