Using Cabbage 3
ARA Support
Audio Random Access (ARA) is an extension to the standard audio plugin format that gives a plugin direct, offline access to a host’s audio material—without having to process it in real time. Cabbage 3 supports ARA through a consolidated opcode API that provides access to the host’s audio tracks.
In an ARA document, you’ll find references to several key entities:
- Audio Sources (
AudioSource): Provide the low-level PCM data and properties for any audio asset loaded into a DAW session. Note: audio sources have their own regions — don’t confuse these with the higher-level PlaybackRegions listed below. - Playback Regions (
PlaybackRegion): Represent how an audio source is mapped onto the DAW timeline as a clip. It contains information about the region’s duration, its start time on the DAW timeline, and its internal start time/offset relative to the raw audio file. Cropping the start or end of an audio clip in the DAW will modify thisPlaybackRegionstructure. Note that duplicating an audio source across multiple tracks will increase the number of regions, but not the number of audio sources. - Region Sequences (
RegionSequence): Represent a collection of playback regions grouped together, typically mapping to tracks, lanes, or channels in the host. Each region sequence belongs to a musical context. - Musical Contexts (
MusicalContext): Describe the rhythmic and harmonic structure of the music, including tempo, bar signatures, key signatures, and tuning. - Audio Modifications (
AudioModification): Contain the edits applied to an audio source. Each modification belongs to an audio source and can contain multiple playback regions. - View Selection (
ViewSelection): Provides real-time information about the host’s current user selection, which can include specific playback regions, region sequences, and/or a distinct time range.
Exporting an ARA plugin
Section titled “Exporting an ARA plugin”ARA support is only available in dedicated ARA build targets. When exporting your plugin from the Cabbage extension, you must choose one of the ARA-specific export commands:
- Export as VST3 Effect (ARA)
- Export as VST3 Synth (ARA)
These commands are available from the VS Code Command Palette (Cmd+Shift+P on macOS, Ctrl+Shift+P on Windows/Linux). Exporting with a standard VST3 or CLAP target will produce a plugin that does not include ARA support.
How it works
Section titled “How it works”When an ARA-capable host loads a Cabbage plugin, it grants the plugin direct access to the audio material on each track. Cabbage reads this audio data directly from the host, stores it in an internal data pool, and makes it available to your Csound instrument through the cabbageAraGet opcode.
All Cabbage ARA plugin instances in a project share one document model. That model can contain many audio sources (for example, across multiple tracks). Cabbage provides opcodes to query source metadata, read audio samples, and detect when the model is updated.
Querying source metadata
Section titled “Querying source metadata”Use cabbageAraGet to query information about the available audio sources. Top-level properties (like currentIndex and audioSourceCount) are queried without an index. Per-source metadata (like audioSource.name, audioSource.channels, and audioSource.duration) takes a source index argument.
instr 1 idx:i = cabbageAraGet("currentIndex") count:i = cabbageAraGet("audioSourceCount") name:S = cabbageAraGet("audioSource.name", idx) channels:i = cabbageAraGet("audioSource.channels", idx) numSamples:i = cabbageAraGet("audioSource.sampleCount", idx) sampleRate:i = cabbageAraGet("audioSource.sampleRate", idx) duration:i = cabbageAraGet("audioSource.duration", idx)
prints("Source '%s': %d ch, %d samples, %d Hz, %.2f sec\n", name, channels, numSamples, sampleRate, duration)endinReading audio data
Section titled “Reading audio data”Use cabbageAraGetSourceSamples to read raw PCM data from a source. It supports audio-rate, k-rate, and array output. To read the contents of the track the plugin is currently loaded onto, do this:
instr 1 ; Query the pool index for this instance's source idx:i = cabbageAraGet("currentIndex")
; Query structural asset parameters via the consolidated opcode name:S = cabbageAraGet("audioSource.name", idx) sampleRate:i = cabbageAraGet("audioSource.sampleRate", idx) channels:i = cabbageAraGet("audioSource.channels", idx) trig:k = cabbageAraGetUpdate()
; Detect new ARA lifecycle events (already a 1-k-cycle trigger, no changed() needed) if trig == 1 then ; Query region properties (crop position within source file) regionStart:i = cabbageAraGet("audioSource.region.startInSamples", idx) regionDuration:i = cabbageAraGet("audioSource.region.durationInSamples", idx) printf("Asset: %s [SR: %d, Chans: %d]\n", trig, name, sampleRate, channels) endif
; Read raw audio samples at audio-rate position ; audioSignal:a = cabbageAraGetSourceSamples(position, 0, idx) ; Apply normalization: gain:k = targetLevel / peak ; normalizedSignal:a = audioSignal * gainendinDetecting updates
Section titled “Detecting updates”cabbageAraGetUpdate returns a k-rate trigger that fires 1 for a single k-cycle whenever the ARA model data changes. Use it directly as a trigger to re-read source metadata (no changed() needed — wrapping it in changed() would double-fire on both edges). This fires whenever changes are made to the session — timeline edits, new clips added, clips resized, tracks hidden, etc.
instr 1 updated:k = cabbageAraGetUpdate() if updated == 1 then event "i", "ReadAraData", 0, 3600 endifendin
instr ReadAraData iIdx cabbageAraGet "currentIndex" iCnt cabbageAraGet "audioSourceCount" SLast cabbageAraGet "lastEvent" prints("Update [%s]: source %d of %d\n", SLast, iIdx, iCnt)endinAudioSource Playback regions
Section titled “AudioSource Playback regions”ARA hosts define audio source playback regions that specify which portion of a source is active. Use the region properties to query these:
instr 1 iIdx cabbageAraGet "currentIndex" iStart cabbageAraGet "audioSource.region.startInSamples", iIdx iCount cabbageAraGet "audioSource.region.durationInSamples", iIdx iDur cabbageAraGet "audioSource.duration", iIdx
prints("Region: sample %d, %d samples (%.2f sec)\n", iStart, iCount, iDur)endinAll playback regions in the session
Section titled “All playback regions in the session”List all clips in the document (not just the selected ones), using the playbackRegionCount property and per-index playbackRegion.* properties. This gives you access to every clip on the timeline, including its crop offset within the source and its arrangement position:
instr 1 kTrig cabbageAraGetUpdate if kTrig == 1 then event "i", "ShowAllClips", 0, 1 endifendin
instr ShowAllClips iCnt cabbageAraGet "playbackRegionCount" prints("%d clips in session:\n", iCnt) idx = 0 while idx < iCnt do SName cabbageAraGet "playbackRegion.name", idx STrack cabbageAraGet "playbackRegion.sequenceName", idx iStart cabbageAraGet "playbackRegion.startInSamples", idx iDur cabbageAraGet "playbackRegion.durationInSamples", idx iPbStart cabbageAraGet "playbackRegion.start", idx iPbDur cabbageAraGet "playbackRegion.duration", idx iSrcIdx cabbageAraGet "playbackRegion.sourceIndex", idx prints(" [%d] '%s' on '%s': src#%d crop=%d-%d pb=%.3f-%.3f\n", idx, SName, STrack, iSrcIdx, iStart, iStart+iDur, iPbStart, iPbStart+iPbDur) idx += 1 odendinThe playback region array is automatically maintained via ARA lifecycle callbacks — clips are added when playbackRegionAddedToRegionSequence fires and removed when playbackRegionRemovedFromRegionSequence or playbackRegionWillDestroy fires.
EditorView selection
Section titled “EditorView selection”When the user selects tracks or regions in the host, the plugin is notified via the EditorView. Selection data is accessible through indexed properties — use editorView.selectedPlaybackRegionCount to get the number of selected playback regions (clips), then query each by index:
instr 1 kTrig cabbageAraGetUpdate if kTrig == 1 then event "i", "ShowSelection", 0, 1 endifendin
instr ShowSelection iCnt cabbageAraGet "editorView.selectedPlaybackRegionCount" iHidden cabbageAraGet "editorView.hiddenSequenceCount" prints("%d regions selected (%d tracks hidden):\n", iCnt, iHidden) idx = 0 while idx < iCnt do SName cabbageAraGet "editorView.selectedRegion.name", idx iStart cabbageAraGet "editorView.selectedRegion.startInSamples", idx iDurSec cabbageAraGet "editorView.selectedRegion.duration", idx iDurSamp cabbageAraGet "editorView.selectedRegion.durationInSamples", idx prints(" [%d] '%s' start=%d dur=%.3fs (%d samples)\n", idx, SName, iStart, iDurSec, iDurSamp) idx += 1 odendinThe "lastEvent" property will be "notifySelection" when the selection changes, or "notifyHideRegionSequences" when tracks are hidden or shown. Selection index is separate from source pool index — the first selected region is always index 0 regardless of which source it belongs to.
Musical contexts and region sequences
Section titled “Musical contexts and region sequences”Musical contexts describe the rhythmic and harmonic structure of the music. Region sequences represent tracks or lanes in the host. Use the musicalContextCount and regionSequenceCount properties to iterate over these entities:
instr 1 kTrig cabbageAraGetUpdate if kTrig == 1 then event "i", "ShowTracks", 0, 1 endifendin
instr ShowTracks ; Show musical contexts iMcCnt cabbageAraGet "musicalContextCount" prints("%d musical contexts:\n", iMcCnt) idx = 0 while idx < iMcCnt do SName cabbageAraGet "musicalContext.name", idx iOrder cabbageAraGet "musicalContext.orderIndex", idx iColR cabbageAraGet "musicalContext.color.r", idx iColG cabbageAraGet "musicalContext.color.g", idx iColB cabbageAraGet "musicalContext.color.b", idx prints(" [%d] '%s' order=%d colour=(%.2f, %.2f, %.2f)\n", idx, SName, iOrder, iColR, iColG, iColB) idx += 1 od
; Show region sequences (tracks) iRsCnt cabbageAraGet "regionSequenceCount" prints("%d region sequences:\n", iRsCnt) idx = 0 while idx < iRsCnt do SName cabbageAraGet "regionSequence.name", idx iOrder cabbageAraGet "regionSequence.orderIndex", idx iMcIdx cabbageAraGet "regionSequence.musicalContextIndex", idx iColR cabbageAraGet "regionSequence.color.r", idx iColG cabbageAraGet "regionSequence.color.g", idx iColB cabbageAraGet "regionSequence.color.b", idx prints(" [%d] '%s' order=%d context=#%d colour=(%.2f, %.2f, %.2f)\n", idx, SName, iOrder, iMcIdx, iColR, iColG, iColB) idx += 1 odendinAudio modifications
Section titled “Audio modifications”Audio modifications represent edits applied to an audio source. Each modification has a name and a persistent ID used for archiving:
instr ShowModifications iCnt cabbageAraGet "audioModificationCount" prints("%d audio modifications:\n", iCnt) idx = 0 while idx < iCnt do SName cabbageAraGet "audioModification.name", idx SId cabbageAraGet "audioModification.persistentId", idx prints(" [%d] '%s' id='%s'\n", idx, SName, SId) idx += 1 odendinTesting without a DAW (CabbageApp)
Section titled “Testing without a DAW (CabbageApp)”During development, you can test ARA instruments without an ARA-capable host by using CabbageApp’s standalone mode. There are two ways to provide audio files for testing:
VS Code extension prompt: When the VS Code extension launches a standalone ARA instrument, it will prompt you to select an audio file (WAV, FLAC, Ogg, or MP3).
Widget JSON property: You can pre-specify test files in the widget JSON so they load automatically without a prompt:
{ "ara": { "testFiles": ["guitar.wav", "drums.wav"] }}Relative paths are resolved from the CSD file’s directory. The audio is loaded on a background thread and made available through the same ARA opcodes, making it straightforward to develop and debug without leaving your normal Cabbage workflow.
Current limitations
Section titled “Current limitations”The ARA implementation is still in its early stages. The following table represents the current implementation status.
| ARA Entity | Status | Notes |
|---|---|---|
| AudioSource | Supported | Name, channels, sample count, sample rate, duration, region crop |
| PlaybackRegion | Supported | Name, track name, crop offset, arrangement position, source index, colour |
| EditorView selection | Supported | Selected region/track data, time range, hidden tracks |
| MusicalContext | Supported | Name, order index, colour |
| RegionSequence | Supported | Name, order index, parent musical context, colour |
| AudioModification | Supported | Name, persistent ID |
This will be expanded in future versions as the ARA integration matures. Musical context content (tempo map, bar signatures, key signatures, tuning, chords) will be added in a future release.
See the ARA Opcodes reference for the full list of available opcodes.