synth() -- Web Audio Synth Cue
Oscilla "Native WebAudio Utility Synth"
The synth() cue creates a lightweight Web Audio sound source inside Oscilla. It is intended for reference tones, drones, textures, chords, and simple patterned sound processes, integrated directly into the score timeline.
The design prioritises deterministic, cue-scoped behaviour; readable parameter syntax; low default amplitudes and click-free envelopes; optional pattern sequencing; optional OSC mirroring; and real-time parameter binding from animation and control sources.
The synth is not intended as a full synthesiser environment. For full electroacoustic work, Oscilla is designed to operate in conjunction with external audio systems via OSC (e.g. SuperCollider, Pure Data, Max). The built-in synth provides a bounded, score-aligned sound source intended for rehearsal contexts away from a complete setup, as well as for simple tone cues, drones, and basic animation- or pattern-driven sound sequences embedded directly in the score.
Basic Usage
synth(uid:refA, wave:sine, freq:440, amp:0.1)
Pitch may be specified as Hz or note name:
synth(uid:tuning, wave:sine, freq:A4, amp:0.08)
Parameters
| Key | Default | Description |
|---|---|---|
uid |
auto | Unique voice identity. Auto-generated from element id if omitted |
wave |
sine |
Waveform type |
freq |
440 | Frequency: Hz, note name, array (chord), pattern, rand(), or signal ref |
amp |
0.08 | Amplitude 0--0.25. Accepts rand() or signal ref |
pan |
0 | Stereo position -1 (left) to 1 (right). Accepts rand() or signal ref |
env |
{a:0.02, d:0, s:1, r:0.1} |
ADSR envelope object |
envPerStep |
false | Retrigger envelope on each sequence step (articulated notes) |
dur |
-- | Step duration for patterns, or voice lifetime if no step engine. Omit for gate mode |
filter |
-- | Filter object {type, freq, q} |
delay |
-- | Delay object {time, fb, mix} |
reverb |
-- | Reverb object {mix, time, damp} |
glide |
0.02 | Frequency interpolation time in seconds |
interp |
smooth |
Interpolation mode: smooth or step |
poly |
0 | Polyphony: 0=mono (retrigger updates), N=overlapping voices |
lifetime |
region |
region (stop on playhead exit) or process (until explicit stop) |
waveform |
self |
Scope display target: self, none, or element id |
overlay |
2 | Overlay detail: 0/off, 1/brief, 2/full |
osc |
0 | Enable OSC mirroring (1=on) |
oscAddr |
-- | Custom OSC address |
rel |
env.r | Override release time for synthStop |
Wave Types
sine
square
saw
triangle
noise
Oscillator waveforms map directly to standard Web Audio oscillator types. noise produces a broadband noise source generated from a looping audio buffer.
Frequency and Pitch
Frequency accepts several formats:
| Format | Example | Description |
|---|---|---|
| Hz | freq:440 |
Direct frequency in Hertz |
| Note name | freq:A4 |
Standard pitch notation (A0--C8) |
| MIDI number | freq:69 |
MIDI note number (auto-detected above 127 as Hz) |
| Chord array | freq:[440, 550, 660] |
Multiple oscillators summed |
| Random | freq:rand(200, 800) |
Random Hz per trigger |
| Pattern | freq:Pseq(220, 330, 440) |
Sequenced values |
| Signal ref | freq:fader.t[200,2000] |
Real-time binding from control source |
Chords
When freq is an array, multiple oscillators are created and summed. All voices share the same envelope and effects chain. A mixer gain node scales amplitude by 1 / sqrt(N) to prevent clipping.
synth(
uid:pad3,
wave:sine,
freq:[440, 477, 644, 777],
env:{a:1.5},
amp:0.12
)
Chord arrays can contain rand() expressions. Each element is evaluated independently at voice creation time:
synth(
uid:cluster,
wave:triangle,
freq:[rand(200, 400), rand(300, 600), rand(400, 800)],
env:{a:3, r:2},
amp:0.1
)
Retriggering from the live console re-evaluates all rand() calls, producing a new chord voicing each time.
Chord frequencies can be updated live. Existing oscillators ramp to new pitches, excess oscillators stop, and new oscillators start as needed.
Amplitude Envelope (ADSR)
synth(
uid:env1,
wave:saw,
freq:220,
amp:0.12,
env:{a:0.5, d:0.2, s:0.7, r:1.2}
)
Envelope parameters:
| Key | Default | Description |
|---|---|---|
a |
0.02 | Attack time in seconds (ramp from 0 to peak) |
d |
0 | Decay time in seconds (ramp from peak to sustain) |
s |
1 | Sustain level as fraction of peak amplitude (0--1) |
r |
0.1 | Release time in seconds (ramp to silence on stop) |
The envelope uses linearRampToValueAtTime for the attack and decay stages. Sustain holds indefinitely until the voice is stopped (by explicit synthStop, dur timeout, or region exit), at which point the release ramp begins from the current gain value.
When both env and dur are specified, dur controls voice lifetime: the voice auto-stops after dur seconds, triggering the release envelope. This allows self-terminating voices with shaped envelopes:
synth(uid:swell, wave:sine, freq:220, env:{a:6, r:4}, amp:0.12, dur:12)
This voice fades in over 6 seconds, sustains, then stops at 12 seconds and fades out over 4 seconds.
Per-Step Envelope (envPerStep)
By default, pitch sequences glide smoothly between notes with the envelope applied only at the start and end of the entire sequence. For articulated sequences where each note should have its own attack-decay-sustain-release cycle, enable envPerStep:
synth(
uid:melody,
wave:triangle,
freq:Pseq(C4, E4, G4, C5),
dur:0.5,
env:{a:0.05, d:0.1, s:0.6, r:0.15},
envPerStep:true,
amp:0.1
)
With envPerStep:true, each pitch step triggers a complete ADSR cycle:
- Attack ramps gain from 0 to peak
- Decay ramps from peak to sustain level
- Sustain holds until release begins
- Release ramps to silence, timed to complete as the next step starts
Envelope Compression
If the step duration is shorter than the total envelope time (attack + decay + release), the envelope phases are compressed proportionally to fit within the step. This ensures smooth transitions even at fast tempos.
Comparison
| Mode | Behaviour |
|---|---|
envPerStep:false (default) |
Legato: pitches glide smoothly, envelope only at start/end |
envPerStep:true |
Articulate: each pitch gets full ADSR, distinct note attacks |
Polyphony
The poly parameter controls how retriggers with the same uid behave.
| Value | Behaviour |
|---|---|
poly:0 (default) |
Mono mode. Retrigger updates the running voice in place |
poly:N |
Up to N overlapping voices. Oldest voice is stopped when count exceeds N |
In mono mode, retriggering with the same uid calls updateSynthVoice -- parameters change smoothly without restarting playback or envelope. This is the default and is suitable for live console tweaking.
In poly mode, each trigger creates an independent sub-voice with its own oscillator(s), envelope, and effects chain. Sub-voices are internally named uid__0, uid__1, etc. The dur parameter and rand() expressions are especially useful in poly mode, since each voice evaluates its own random values and manages its own lifetime.
Example: Overlapping Swells
synth(
uid:swell,
wave:triangle,
freq:[rand(33, 333), rand(33, 533), rand(33, 1333)],
env:{a:6, r:4},
amp:0.12,
dur:12,
poly:12
)
Each trigger creates a new 3-oscillator chord with random frequencies, fading in over 6 seconds. Up to 12 can overlap. The 13th trigger stops the oldest voice (with its release envelope). All poly voices share a single scope display rect in the GUI.
Stopping Poly Voices
synthStop(uid:swell) stops all sub-voices in the group. Each voice fades out independently using its own release time.
Patterned Parameters
The following parameters accept static values, arrays, or pattern functions. When patterns are present, a step engine advances through values at the rate specified by dur.
| Parameter | Description |
|---|---|
freq |
Pitch sequence |
amp |
Amplitude sequence |
dur |
Step duration sequence |
filter.freq |
Filter cutoff sequence |
filter.q |
Filter resonance sequence |
pan |
Stereo position sequence |
Frequency Sequence
synth(
uid:seq1,
wave:triangle,
freq:Pseq(220, 330, 440),
dur:Pseq(1, 1, 2),
amp:0.08
)
Patterned Chord Progression
synth(
uid:chordSeq,
wave:saw,
freq:Pseq(
[220, 330, 440],
[247, 370, 494],
[196, 294, 392]
),
dur:1.5,
amp:0.1
)
Random Pitch Selection
synth(
uid:randFreq,
wave:square,
freq:Prand(200, 400, 600),
dur:0.8,
amp:0.09
)
Available Patterns
| Pattern | Behaviour |
|---|---|
Pseq(...) |
Sequential, loops forever |
Prand(...) |
Random selection per step |
Pxrand(...) |
Random without consecutive repeats |
Pshuf(...) |
Shuffle, then repeat the shuffled order |
Random Expressions
rand(min, max) and irand(min, max) can be used for any numeric parameter. They are evaluated at voice creation time for static params.
synth(uid:x, wave:sine, freq:rand(200, 2000), amp:rand(0.02, 0.12))
rand() returns a continuous float. irand() returns an integer. Both work inside chord arrays, filter configs, and anywhere a numeric value is expected.
For patterned parameters, random values evaluate once when the pattern is built. For per-step randomness, use Prand(...).
Random Expressions in Chords
rand() expressions inside freq arrays are evaluated individually per oscillator per trigger:
synth(uid:x, wave:sine, freq:[rand(100, 500), rand(200, 800), rand(300, 1200)])
Each trigger produces three oscillators at different random frequencies. Retriggering from the live console rolls new values each time.
Filters
synth(
uid:filterSeq,
wave:saw,
freq:330,
filter:{type:lp, freq:Pseq(400, 800, 1600, 800), q:0.7},
dur:0.5,
amp:0.08
)
Filter parameters:
| Key | Default | Description |
|---|---|---|
type |
lp |
Filter type: lp, hp, bp, notch |
freq / cutoff |
1200 | Cutoff frequency. Accepts rand() or signal ref |
q / resonance |
1 | Resonance. Accepts rand() or signal ref |
Delay
synth(
uid:delayLead,
wave:square,
freq:550,
delay:{time:0.25, fb:0.35, mix:0.2},
amp:0.12
)
| Key | Default | Description |
|---|---|---|
time |
0.3 | Delay time in seconds |
fb |
0.3 | Feedback amount 0--0.95 |
mix |
0.3 | Wet/dry mix 0--1 |
Reverb
synth(
uid:revDrone,
wave:sine,
freq:110,
reverb:{mix:0.3, time:2, damp:3000},
amp:0.07
)
| Key | Default | Description |
|---|---|---|
mix |
0.3 | Wet/dry mix 0--1 |
time |
1.5 | Reverb time (controls delay line lengths) |
damp |
4000 | Damping lowpass frequency in Hz |
Glide
synth(
uid:glide1,
wave:sine,
freq:Pseq(220, 330, 440),
glide:0.1,
dur:1,
amp:0.1
)
glide specifies the time in seconds used to interpolate frequency changes between steps. It applies only to pitch. Default is 0.02 (near-instant). Set higher values for audible portamento.
Interpolation Mode
synth(
uid:stepSeq,
wave:triangle,
freq:Pshuf(300, 450, 600),
interp:step,
dur:1,
amp:0.08
)
| Value | Behaviour |
|---|---|
smooth (default) |
Ramps between values using setTargetAtTime |
step |
Immediate value changes using setValueAtTime |
Pan
synth(uid:panTest, wave:sine, freq:440, pan:-0.6, amp:0.09)
Pan accepts static values, rand() expressions, patterns, or signal references. Range is -1 (left) to 1 (right).
Lifetime and Duration
Gate Mode (default)
When no dur is specified, the synth operates in gate mode: it plays while the playhead is inside the cue element's region and releases when the playhead exits. This is ideal for sustained tones that follow the score timeline.
synth(uid:regionTone, wave:sine, freq:220, amp:0.06)
The synth starts on playhead entry, sustains indefinitely, and triggers its release envelope on playhead exit. If the cue element has an extent handle (for waveform-line or handle display modes), the region boundary extends to that handle position.
Explicit duration
synth(uid:fixedDur, wave:sine, freq:220, dur:5, amp:0.07)
The synth auto-stops after 5 seconds. If an envelope is specified, the release ramp begins at the stop point. This switches lifetime to process mode internally.
Process lifetime
synth(uid:persist, wave:saw, freq:110, lifetime:process, amp:0.05)
The synth continues until explicitly stopped with synthStop(uid:persist).
Extent Handle Support
When using waveform-line or handle display modes, the cue element has a draggable extent handle that defines the right boundary of the region. Synths with region-based lifetime (gate mode) respect this extended boundary -- they continue playing until the playhead exits past the extent handle, not just the original element bounding box.
Parent Group Extent (SVG-Authored Cues)
For SVG-authored cues where the synth DSL is placed directly in an element's id attribute (authored in Inkscape or another SVG editor), the extent region can be defined by a parent group. If the synth element is placed inside a group (<g>) that contains an extent path or line, the playhead uses the group's bounding box rather than just the synth element's box.
This enables workflows where the synth rect and an extent line are grouped together in the SVG editor, with the group defining the active region:
<g id="g20">
<rect id="synth(wave:sine, freq:440, amp:0.1)" ... />
<path d="m 100,50 h 500" /> <!-- extent line -->
</g>
The synth remains active until the playhead exits the group's combined bounding box.
Duration vs. Step Engine
When pattern parameters are present (making _hasStepEngine true), dur controls step timing rather than voice lifetime. Use stopAfter or lifeDur to set an explicit voice lifetime independently of step duration:
synth(uid:seq, wave:saw, freq:Pseq(220, 330, 440), dur:0.5, stopAfter:10, amp:0.08)
This steps through frequencies every 0.5 seconds and stops the entire voice after 10 seconds.
Signal Binding (Control Plane)
Synth parameters can be bound to real-time signal sources such as controlXY faders, o2p animations, rotate, and scale cues. Bound parameters update continuously at audio rate.
Syntax
param:source.channel[min,max]
The source is the uid of a publishing cue, and the channel specifies which signal dimension to follow. The optional [min,max] range maps the 0--1 signal to the specified output range.
Bindable Parameters
| Parameter | Default Range | Description |
|---|---|---|
freq |
20--20000 | Oscillator frequency |
amp |
0--0.5 | Output amplitude |
pan |
-1 to 1 | Stereo position |
cutoff / filterFreq |
20--20000 | Filter cutoff frequency |
q / resonance |
0.1--30 | Filter resonance |
Examples
synth(uid:pad, freq:myFader.t[200,800], amp:0.15)
synth(uid:drone, freq:220, amp:slider.y[0,0.25], pan:slider.x[-1,1])
synth(uid:filter1, wave:saw, freq:440, filter:{type:lp, freq:knob.t[200,8000], q:2})
When a signal ref is used for freq, chord mode is disabled (binding applies to a single oscillator). Static values work alongside bound values: you can bind freq while keeping amp static, or vice versa.
Bindings are automatically cleaned up when the voice stops.
Oscilloscope Display
Each synth voice renders a real-time oscilloscope trace driven by a Web Audio AnalyserNode. The scope shows the time-domain waveform shape updating at display framerate.
Display Modes
waveform value |
Behaviour |
|---|---|
self (default) |
Render scope inside the cue element |
none |
Suppress scope display |
<element_id> |
Render inside a different SVG element by id |
Scope Stacking
Multiple synths can share a single display area. When waveform points to another synth's uid, the scope renders into that synth's rect with a distinct colour:
synth(uid:pad1, wave:sine, freq:[740, 477, 644], amp:0.12)
synth(uid:pad2, wave:square, freq:880, waveform:pad1, amp:0.1)
pad2's scope stacks into pad1's display element with a different colour from the 12-colour palette.
Poly Scope Display
All poly voices for a given uid share a single display rect. The rect is created when the first voice triggers and persists across group recreation. Each voice gets its own scope trace in a distinct colour, and traces are cleaned up when their voice stops.
Info Text
A text line above the scope shows the voice's current parameters: uid, waveform type, frequency/chord voicing, amplitude, and any active effects. This text updates when parameters change via live console.
Live Console Scopes
When synth cues are triggered from the live console without a score element, an ephemeral SVG rect is created in the viewport as a scope anchor. These rects stack vertically and can be dragged and resized. They persist until the global stop button clears them.
OSC Mirroring
synth(
uid:oscLead,
osc:1,
oscAddr:/synth/lead,
wave:saw,
freq:440,
amp:0.1
)
When osc:1 is enabled, synth state changes (start, stop, parameter updates) are sent as OSC messages to external software via the Oscilla server.
Stopping
synthStop(uid:seq1, rel:0.5)
The rel parameter overrides the envelope release time. Without it, the voice's env.r value is used.
Voices can also be stopped by:
- Region exit (lifetime:region)
- Duration timeout (
durorstopAfter) - Transport stop/rewind (stops all voices)
stopSynth(uid)from JavaScript- Click-to-toggle (clicking a playing synth stops it)
Click-to-Trigger
Synth cues are click-triggerable. Clicking the synth element in the score starts the synth immediately, regardless of playhead position.
By default, clicking an already-playing synth stops it (toggle behaviour). This can be controlled with the toggle parameter:
toggle value |
Behaviour |
|---|---|
| (omitted) | Toggle on click, retrigger on playhead |
toggle:true |
Always toggle (click and playhead) |
toggle:false |
Never toggle, always retrigger |
synth(wave:sine, freq:440, amp:0.1, toggle:false)
This synth will layer multiple instances on repeated clicks instead of toggling.
For poly voices, synthStop(uid:X) stops all sub-voices in the group. Each voice fades out independently using its own release time.
Live Console
Hot-Update (Mono Mode)
In mono mode (default, poly:0), retriggering a synth from the live console with the same uid updates the running voice without restarting it. The following parameters update immediately:
| Parameter | Behaviour |
|---|---|
amp |
Gain ramp via setTargetAtTime |
pan |
Pan ramp on StereoPannerNode |
wave |
Oscillator type change (instant) |
freq (single) |
Frequency ramp with glide |
freq (chord) |
Ramp existing oscs, stop excess, create new |
filter.freq |
Cutoff ramp |
filter.q |
Resonance ramp |
lifetime |
Switch between region/process |
Pattern parameters (Pseq, Prand, etc.) are rebuilt on update. Duration and stop-after timers are reset.
Poly Mode from Console
With poly:N, each execution from the live console creates a new overlapping voice. The rand() expressions re-evaluate on each trigger, so repeated execution of the same line produces different results:
synth(uid:cloud, wave:sine, freq:[rand(100,2000), rand(100,2000)], env:{a:4, r:6}, dur:8, poly:20)
Execute this line repeatedly to build up a cloud of overlapping two-note chords, each with random pitches, each fading in over 4 seconds and releasing over 6 seconds after the 8-second lifetime.
Signal Chain
The internal audio graph for each voice is:
source (oscillator or noise buffer)
-> filter (optional, BiquadFilterNode)
-> gain (GainNode, envelope target)
-> panner (optional, StereoPannerNode)
-> delay (optional, feedback delay)
-> reverb (optional, multi-tap reverb)
-> analyser (AnalyserNode for scope display)
-> destination
For chords, all oscillators feed through a shared mixer gain node (scaled by 1/sqrt(N)) before the filter stage.
Examples
// Simple reference tone
synth(uid:ref, wave:sine, freq:A4, amp:0.08)
// Drone with slow attack
synth(uid:drone, wave:saw, freq:55, env:{a:3, s:0.6, r:2}, amp:0.1)
// Chord with envelope
synth(uid:pad, wave:sine, freq:[440, 550, 660], env:{a:2, d:0.5, s:0.7, r:3}, amp:0.12)
// Filtered sequence
synth(uid:bass, wave:square, freq:Pseq(55, 82, 110), dur:0.5,
filter:{type:lp, freq:Pseq(200, 800, 1600), q:2}, amp:0.1)
// Random chord cloud (poly, from live console)
synth(uid:cloud, wave:triangle,
freq:[rand(100, 1000), rand(200, 1500), rand(300, 2000)],
env:{a:5, r:3}, dur:10, amp:0.08, poly:16)
// Signal-bound drone (controlled by fader)
synth(uid:ctrlDrone, wave:saw, freq:fader1.t[80,800],
amp:fader1.y[0,0.2], filter:{type:lp, freq:knob1.t[200,4000]})
// Noise burst with delay
synth(uid:noiseBurst, wave:noise, dur:0.1,
delay:{time:0.15, fb:0.6, mix:0.4}, amp:0.15)
// Patterned pan movement
synth(uid:ping, wave:sine, freq:1200, dur:0.3,
pan:Pseq(-1, -0.5, 0, 0.5, 1), amp:0.06)
// Self-terminating swell with long envelope
synth(uid:swell, wave:sine, freq:rand(100, 400),
env:{a:8, r:6}, dur:15, amp:0.1)
Summary
The synth() cue provides a bounded, score-aligned sound source suitable for reference tones, drones, chords, patterned textures, and signal-controlled processes. All behaviour is deterministic and cue-scoped. Polyphony enables overlapping voices with independent envelopes and random parameters. The oscilloscope display provides real-time visual feedback. Signal binding connects synth parameters to Oscilla's control plane for continuous modulation from faders, animations, and other score elements.
See Also
- audio -- file-based audio playback
- audioPool -- one-shot selection from a folder
- audioImpulse -- stochastic repeating process
- Control and Modulation -- signal binding reference
Tip: use ← → or ↑ ↓ to navigate the docs