Audio Shared Features
Features common to all three audio cue types: audio, audioPool, and audioImpulse.
Fade Values
Fades can be specified in several formats. All three cue types support fade, fadeIn / fadein, and fadeOut / fadeout.
| Format | Example | Meaning |
|---|---|---|
| Seconds | fadeout:0.5 |
Fixed 0.5 second fade |
| Percentage | fadeout:"50%" |
50% of the file's duration |
| Random seconds | fadeout:rand(0.1, 0.5) |
Random value between 0.1 and 0.5 seconds |
| Random percentage | fadeout:rand("10%","60%") |
Random between 10% and 60% of duration |
Percentage fades adjust to each file's actual duration, accounting for speed changes. The fade shorthand applies the same value to both fadeIn and fadeOut. Explicit fadeIn / fadeOut values override the shorthand.
All gain fades use exponential ramps (exponentialRampToValueAtTime) for natural perceived-loudness curves. The target floor is 0.0001 (-80dB, effectively inaudible) since the Web Audio API cannot ramp exponentially to zero.
Random Expressions
Random values are evaluated fresh on every trigger or hit. They can be used for any numeric parameter.
amp:rand(0.2, 0.9) // continuous random float
pan:rand(-1, 1) // continuous random float
speed:rand(0.5, 2) // continuous random float
fadeout:rand(0.05, 0.3) // random fade in seconds
fadeout:rand("10%", "50%") // random fade as percentage of duration
For integer random values, use irand(a, b):
loop:irand(1, 4) // random integer between 1 and 4
Random expressions are objects in the parsed AST ({ type: "rand", min, max }) and are resolved at playback time by evalMaybeRandom().
Speed and Reverse Playback
All three cue types use the speed parameter to control playback rate. Negative values play audio in reverse.
| Value | Effect |
|---|---|
speed:1 |
Normal playback |
speed:0.5 |
Half speed (lower pitch) |
speed:2 |
Double speed (higher pitch) |
speed:-1 |
Reverse at normal speed |
speed:-0.5 |
Reverse at half speed |
Reverse Buffer
Web Audio API does not support negative playbackRate. Instead, Oscilla creates a sample-reversed copy of the audio buffer and plays it forward at the absolute speed value. Reversed buffers are cached by filename so the reversal only happens once per file.
Waveform Mirroring
When speed is negative, the waveform display mirrors horizontally via SVG transform. The base contour, all peak layers, and cursor direction all update to reflect the reversed playback. The cursor sweeps right-to-left.
In/Out Points
audio(...) supports in and out parameters to loop a subsection of a file:
audio(src:longfile, in:2, out:8, loop:0)
This plays only seconds 2--8 of the buffer. The segment is passed to the Web Audio BufferSource.start(when, offset, duration) call. In/out points work with both forward and reverse playback -- when speed is negative, the offset is flipped to the corresponding position in the reversed buffer.
Effects
All audio cue types support optional filter, delay, and reverb effects. Effects are applied in sequence after the main gain stage.
Filter
audio(src:pad.wav, filter:{type:lp, freq:800, q:2}, loop:0)
| Key | Default | Description |
|---|---|---|
type |
lp |
Filter type: lp (lowpass), hp (highpass), bp (bandpass), notch |
freq / cutoff |
1200 | Cutoff frequency in Hz (20--20000) |
q / resonance |
0.707 | Resonance / Q factor (0.0001--30) |
Delay
audio(src:vocal.wav, delay:{time:0.25, fb:0.4, mix:0.3})
| Key | Default | Description |
|---|---|---|
time |
0.25 | Delay time in seconds (0--5) |
fb |
0.25 | Feedback amount (0--0.95). Higher values = longer decay |
mix |
0.2 | Wet/dry mix (0--1). 0 = dry only, 1 = wet only |
Reverb
audio(src:strings.wav, reverb:{mix:0.3, time:2, damp:3000}, loop:0)
| Key | Default | Description |
|---|---|---|
mix |
0.3 | Wet/dry mix (0--1) |
time |
1.5 | Reverb time in seconds. Controls delay line length and feedback |
damp |
4000 | Damping lowpass frequency in Hz. Lower = darker reverb tail |
Combined Effects
Effects can be combined. When both delay and reverb are present, the signal flows through delay first, then reverb:
audio(
src:texture.wav,
filter:{type:lp, freq:2000, q:1.5},
delay:{time:0.3, fb:0.5, mix:0.25},
reverb:{mix:0.2, time:1.8, damp:2500},
loop:0
)
Signal Chain
source (BufferSource)
-> filter (optional, BiquadFilterNode)
-> gain (GainNode, envelope/amp target)
-> panner (optional, StereoPannerNode)
-> delay (optional, feedback delay)
-> reverb (optional, feedback reverb)
-> destination
Selection Modes
audioPool and audioImpulse both select files from a directory using the shared selectFromPool engine. The mode parameter controls selection behaviour:
| Mode | Behaviour |
|---|---|
shuffle (default) |
Walk through the pool without repeats. When all files have played, reshuffle and start over |
rand |
Pure random selection. Consecutive repeats are possible |
sequential |
Play files in directory order. Wrap around at the end without reshuffling |
The selection cursor is persistent and keyed by uid. Multiple cue elements sharing the same uid advance through the same sequence. This means scatter several audioPool rects across the score with the same uid and they collectively exhaust the pool before any file repeats.
Waveform Display
All three cue types render a waveform visualisation inside the cue element. The waveform parameter controls where:
| Value | Behaviour |
|---|---|
self (default) |
Render inside the cue element itself |
none |
Suppress waveform display entirely |
<element_id> |
Render inside a different SVG element by id |
Waveforms are preloaded at score load time during assignCues. They appear immediately, not only when the cue fires.
Per-Cue Behaviour
audio: A static waveform with a single cursor tracking playback. With poly:0 or poly:N, each voice adds its own coloured peak layer and independent cursor. Info text shows current filename and parameters.
audioPool: Waveform shape updates on each trigger to show whichever file was selected. Cursor tracks the current hit. Info text updates to reflect the newly selected file and its evaluated random parameters.
audioImpulse: A single base waveform rendered once. Each polyphonic hit adds its own peak layer and cursor (see Multi-Cursor Display below).
Info Text
A text line is rendered above the waveform peaks showing current parameter values: filename, amp, speed, pan, loop count, fades, and in/out points. This text updates in real time during live console parameter changes, reflecting the current state of the running voice. When src changes via hot-update, the info text refreshes after the new buffer loads.
Reverse Direction
When speed is negative, setWaveformDirection(handle, true) applies a horizontal mirror transform (scale(-1,1)) to the base contour and all peak layers. Cursors are not transformed -- instead, the cursor animation code computes right-to-left position directly from the negative speed value.
Waveform Reconnection
When a voice finishes and is later restarted from the live console (which has no cue element context), the new voice reconnects to the existing waveform SVG via getWaveform(uid). The waveform element persists in the score after cleanup, so the cursor and info text resume on the existing element.
Live Audio Rects
When audio cues are triggered from the live console or programmatically without a cue element, the system creates ephemeral SVG rects in the visible viewport to serve as waveform anchors. These rects are placed in a dedicated <g id="oscilla-live-audio-group"> appended to the score SVG.
Each unique uid gets its own rect. Multiple layers stack vertically from the screen center:
// Three independent layers with separate rects
audio(src:"noise/rain.wav", amp:0.6, loop:0, uid:layer1)
audio(src:"pads/drone.wav", amp:0.3, speed:0.5, uid:layer2)
audio(src:"perc/click.wav", amp:0.8, loop:0, uid:layer3)
To layer voices onto a single rect, use the same uid with poly:0:
// Three voices share one rect, each with colored peaks and cursor
audio(src:"drone.wav", loop:0, speed:1, uid:mix, poly:0)
audio(src:"drone.wav", loop:0, speed:0.5, uid:mix, poly:0)
audio(src:"drone.wav", loop:0, speed:0.25, uid:mix, poly:0)
Live rects are styled as translucent blue dashed outlines (400x120 SVG units). They are cleaned up by the global stop button, or individually via console:
removeLiveAudioRect("layer1") // remove one rect and its waveform
clearLiveAudioRects() // remove all live rects
Multi-Cursor Display (audio poly and audioImpulse)
audio (with poly:0 or poly:N) and audioImpulse both use a layered waveform display where each polyphonic voice gets its own visual representation.
Peak Layers
Each active voice draws a coloured waveform contour (upper and lower polylines) layered on top of the base waveform. Colours are assigned automatically from a 12-colour palette. Layers are added via addPeakLayer when a hit starts and removed when the voice completes.
If the waveform direction is currently reversed (negative speed), new peak layers are automatically given the same horizontal mirror transform as the base contour.
Preview Layers (audioImpulse only)
Before any live hits fire, three random files from the pool are rendered as preview peak layers at reduced opacity. This gives a visual sense of the pool content at score load time. Preview layers are cleared on the first live hit.
Cursors
Each voice gets an independent cursor line that sweeps across the waveform tracking playback position. Cursor colour matches its peak layer colour. Cursors auto-remove when their voice completes.
With poly:6, up to six cursors and six peak layers can be visible simultaneously, creating a dense visual representation of the stochastic texture.
Overlays
Audio cues display HTML overlay labels showing the cue type, filename, and parameter values. The overlay parameter controls detail level:
| Value | Meaning |
|---|---|
0 / off / none |
No overlay |
1 / brief |
Minimal: type and filename only |
2 / expanded (default) |
Full: type, filename, amp, pan, speed, fades |
audio: Overlay appears on trigger, shows filename and params.
audioPool: Overlay shows selected filename and evaluated random params. Auto-destroys after 1.5 seconds. Suppressed when waveform is active (since the waveform info text already shows the same information).
audioImpulse: Persistent overlay updates on every hit showing current filename and params. Destroys on region exit or stop.
Overlays are positioned at the top-left of the cue element and track its position as the score scrolls.
Live Console Hot-Update
Running audio cues can be modified in real time from the live console. Retrigger with the same uid to update parameters on a playing voice without restarting playback.
How It Works
When the audio handler detects that a voice with the given uid is already playing and has an update() method, it calls update(params) instead of stopping and restarting. The update method splits parameters into immediate and deferred categories.
Immediate (50ms ramp)
| Parameter | Behaviour |
|---|---|
amp |
gainNode.gain.exponentialRampToValueAtTime |
pan |
panNode.pan.linearRampToValueAtTime (creates StereoPannerNode on the fly if needed) |
speed |
srcNode.playbackRate.linearRampToValueAtTime (same direction only) |
Deferred (next loop iteration)
| Parameter | Behaviour |
|---|---|
fadeIn, fadeOut |
New envelope applied when playOne creates the next BufferSource |
in, out |
New segment boundaries passed to start(when, offset, duration) |
src |
Async fetch + decode of the new file; waveform peaks redraw when buffer is ready |
speed (direction change) |
Buffer swap between forward/reversed copy on next loop |
Loop Control
| Value | Effect |
|---|---|
loop:1 |
Finish after the current iteration |
loop:N |
Play N more iterations, with fadeOut on the final one |
loop:0 |
Switch to infinite looping |
The remaining counter is decremented on each onended event. When it reaches zero, the voice cleans up.
OSC Output
audioPool and audioImpulse can mirror each audio event as an OSC message to external software. Enable with osc:1.
Message Format
/oscilla/audio/pool sfffff filename amp pan speed fadeIn fadeOut
/oscilla/audio/impulse sfffff filename amp pan speed fadeIn fadeOut
/oscilla/audio/trigger sfi filename volume loop
Arguments: filename (string), then amp, pan, speed, fadeIn, fadeOut (all floats).
Custom Address
Use oscaddr to specify a custom path. The address is prefixed with /oscilla/:
audioImpulse(path:sfx, osc:1, oscaddr:"/myapp/texture/rain")
// sends to /oscilla/myapp/texture/rain
Signal Flow
audio handler -> sendOSC() -> WebSocket -> server.js -> osc-js UDP -> external
Pin to Playhead
All audio cues accept pin:N to keep the element visible at the playhead position for N seconds. This is especially useful for audioImpulse where the waveform and cursors would otherwise scroll off-screen while the process is still active.
audioImpulse(path:sfx/rain, rate:30, poly:6, lifetime:region, pin:30)
See pin for full details on the pin lifecycle.
Polyphony
All three audio cue types support the poly parameter to control voice overlap behaviour.
| Cue Type | Default | Behaviour when exceeded |
|---|---|---|
| audio | 1 | Retrigger hot-updates the running voice |
| audioPool | 1 | Previous sound stops before new one starts |
| audioImpulse | 6 | New hit skipped until a voice slot opens up |
With poly:0, there is no limit.
For audio(), poly:1 (default) enables the hot-update path where retriggering updates the running voice in place. Setting poly:0 or poly:N switches to layering mode where each trigger creates an independent voice with its own coloured peak layer and cursor.
Voice counting for audioImpulse is done by scanning window.activeAudioCues for keys matching the impulse uid prefix. When at the poly limit, the hit is skipped and the scheduling timer continues -- the next interval will try again once a voice has freed up.
Waveform cursors are also limited to the poly count. When at the cursor limit, the oldest cursor is evicted from the display.
Extent Handle Support
When cue elements use waveform-line or handle display modes, a draggable extent handle defines the right boundary of the active region. Audio cues with region-based behaviour (such as audioImpulse with lifetime:region) respect this extended boundary.
The playhead must exit past the extent handle position, not just the original element bounding box, before the region exit is triggered. This allows precise control over how long region-based audio processes remain active.
Extent handles are stored as world coordinates on the SVG element (_extentWorldX) and are converted to screen coordinates during region checking using the SVG's current transform matrix.
Stopping
Audio playback can be stopped by:
- Toggle mode:
audio(src:x, toggle:true)-- second trigger stops playback - Loop control:
audio(src:x, loop:1, uid:x)via live console -- finish after current iteration - Region exit: audioImpulse with
lifetime:regionstops on playhead exit (respects extent handles) - Transport: rewind or stop clears all active audio
- Programmatic:
stopAllAudio(),stopAudioImpulse(uid),stopAllAudioImpulses() - Live rects:
removeLiveAudioRect(uid)orclearLiveAudioRects()
On stop, all active voices fade out using exponential gain ramps, all waveform cursors are removed, and all peak layers are cleared.
See Also
- audio -- single file playback
- audioPool -- one-shot folder selection
- audioImpulse -- stochastic repeating process
- pin -- pin element to playhead
Tip: use ← → or ↑ ↓ to navigate the docs