Skip to content

MAGDA DSL Reference

The MAGDA DSL is a functional scripting language for DAW operations. The AI Assistant translates natural language into DSL, and the DSL tab lets you write it directly.

Syntax

Commands are written one per line. Track statements return a context that can be extended with a method chain. Comments start with //.

// This is a comment
track(name="Bass", new=true)
  .clip.new(bar=1, length_bars=4)
  .notes.add_chord(root=C4, quality=major, beat=0, length=4)

Tracks

Creating & referencing tracks

Command Description
track() Create a new unnamed track
track(name="Bass") Reference existing track by name, or create if none exists
track(name="Bass", new=true) Always create a new track (even if name exists)
track(id=1) Reference track by 1-based index

Modifying tracks

track(name="Bass").track.set(name="Sub Bass", volume_db=-3, pan=0.5, mute=true, solo=true)
Parameter Type Description
name string Rename the track
volume_db number Volume in dB
pan number Pan position (-1.0 left to 1.0 right)
mute bool Mute the track
solo bool Solo the track

Other track operations

track(id=1).select()    // Select track in UI
track(id=1).delete()    // Delete track

Clips

Creating clips

track(name="Bass").clip.new(bar=1, length_bars=4)     // At specific bar
track(name="Bass").clip.new(length_bars=4)             // Auto-place after last clip
Parameter Type Default Description
bar number auto Bar position (omit to auto-place)
length_bars number 4 Clip length in bars

Managing clips

track(name="Bass").clip.rename(index=0, name="Intro")  // Rename clip at index
track(name="Bass").clip.rename(name="Part {i}")         // Rename selected clips (auto-number)
track(name="Bass").clip.delete(index=0)                 // Delete clip at index

Selecting clips

track(id=1).clips.select(clip.length_bars >= 2)
track(id=1).clips.select(clip.start_bar == 1)
Field Description
clip.length_bars Clip length in bars
clip.start_bar Clip start position in bars

Operators: ==, !=, >, >=, <, <=

Notes

Note operations require a selected clip. Chain them on a clip.new() call or use a track reference when a clip is already selected.

Adding notes

.notes.add(pitch=C4, beat=0, length=1, velocity=100)
Parameter Type Default Description
pitch note/number Note name (C4, F#3, Bb2) or MIDI number
beat number Beat position within the clip
length number 1 Duration in beats
velocity number 100 Velocity (0–127)

Tip

To add multiple notes to the same clip, chain .notes.add() calls on a single statement. Do not create a separate clip.new() for each note.

Adding chords

.notes.add_chord(root=C4, quality=major, beat=0, length=1, velocity=100, inversion=0)
Parameter Type Default Description
root note Root note
quality string Chord quality (see table below)
beat number 0 Beat position
length number 1 Duration in beats
velocity number 100 Velocity
inversion number 0 0 = root, 1 = first, 2 = second

Chord qualities:

Category Qualities
Triads major / maj, minor / min, dim, aug, sus2, sus4, power / 5
Sevenths dom7 / 7, maj7, min7, dim7, min7b5 / half_dim
Extended dom9 / 9, maj9, min9, dom11 / 11, min11, maj11, dom13 / 13, min13, maj13
Added tone add9, add11, add13, madd9
Sixth 6 / maj6, min6
Altered 7b5, 7sharp5, 7b9, 7sharp9

Adding arpeggios

.notes.add_arpeggio(root=C4, quality=major, beat=0, step=0.5,
                    note_length=0.5, velocity=100, inversion=0, pattern=up, fill=true)
Parameter Type Default Description
root note Root note
quality string Same chord qualities as add_chord
beat number 0 Start beat
step number Beat interval between notes
note_length number = step Duration of each note
velocity number 100 Velocity
inversion number 0 Chord inversion
pattern string up up, down, or updown
fill bool false Repeat pattern to fill the entire clip
beats number Fill a specific number of beats instead of the whole clip

Selecting notes

.notes.select(note.pitch == C4)
.notes.select(note.velocity > 100)
.notes.select(note.start_beat >= 4)
.notes.select(note.length_beats < 0.5)
Field Description
note.pitch Note pitch (note name or MIDI number)
note.velocity Note velocity
note.start_beat Note start position in beats
note.length_beats Note length in beats

Editing notes

All editing operations apply to currently selected notes.

.notes.delete()                    // Delete selected notes
.notes.transpose(semitones=5)      // Transpose (positive=up, negative=down)
.notes.set_pitch(pitch=F1)         // Set absolute pitch
.notes.set_velocity(value=80)      // Set velocity
.notes.quantize(grid=0.25)         // Quantize (0.25=16th, 0.5=8th, 1.0=quarter)
.notes.resize(length=0.5)          // Set note length in beats

Effects

track(name="Vocals").fx.add(name="reverb")
track(name="Vocals").fx.add(name="Pro-Q 3", format="VST3")
Parameter Type Description
name string Effect name
format string Optional: VST3, AU, or VST to disambiguate

Built-in effects: eq, compressor, reverb, delay, chorus, phaser, filter, utility, pitch shift, ir reverb

Third-party plugins are referenced by their scanned name. Use the @alias syntax in the AI chat to autocomplete plugin names.

Filter Operations

Bulk operations on tracks matching a condition.

filter(tracks, track.name == "Drums").track.set(mute=true)
filter(tracks, track.name == "Drums").delete()
filter(tracks, track.name == "Drums").select()
filter(tracks, track.name == "Drums").for_each(.clip.new(bar=1, length_bars=4))
filter(tracks, track.name == "Drums").for_each(.fx.add(name="reverb").track.set(volume_db=-6))

Groove / Swing

Groove templates control playback timing feel — they shift note positions at playback without modifying the source MIDI. These are not drum patterns.

In the AI chat, prefix your message with /groove to ensure the AI generates groove commands instead of note patterns.

Creating custom grooves

groove.new(name="Funky 16ths", notesPerBeat=4,
           shifts="0.0,0.15,-0.05,0.4,0.0,0.2,-0.1,0.35")
Parameter Type Default Description
name string Template name
notesPerBeat number 2 Grid resolution: 2 = 8th notes, 4 = 16th notes
shifts string Comma-separated lateness values (-1.0 to 1.0, 0 = on grid)
parameterized bool true Whether the strength slider scales the groove

The shifts string defines one value per grid position in a single beat. Positive values push notes late (behind the beat), negative values push notes early (ahead of the beat).

Extracting groove from audio

groove.extract(clip=0, resolution=16, name="Drum Loop Feel")
Parameter Type Default Description
clip number Clip index on the current track
resolution number 16 Grid resolution: 8 or 16
name string "Extracted Groove" Template name

Reads transient positions from an audio clip and computes timing deviations from the grid.

Applying groove to a clip

groove.set(template="Basic 8th Swing", strength=0.7)
Parameter Type Default Description
template string Groove template name
strength number Amount of groove to apply (0.01.0)

Applies to the currently selected MIDI clip.

Listing available grooves

groove.list()

Returns all available groove template names (built-in and custom).

Examples

Simple track with clip

track(name="Bass", new=true).clip.new(bar=1, length_bars=4)

Chord progression

track(name="Synth", new=true)
  .clip.new(bar=1, length_bars=4)
  .notes.add_chord(root=C4, quality=major, beat=0, length=4)
  .notes.add_chord(root=F4, quality=major, beat=4, length=4)
  .notes.add_chord(root=G4, quality=major, beat=8, length=4)
  .notes.add_chord(root=A3, quality=minor, beat=12, length=4)

Arpeggiated lead with swing

track(name="Lead", new=true)
  .clip.new(bar=1, length_bars=4)
  .notes.add_arpeggio(root=C4, quality=major, step=0.25, pattern=updown, fill=true)
track(name="Lead").fx.add(name="reverb").track.set(volume_db=-6)
groove.set(template="Basic 8th Swing", strength=0.6)

Split arpeggios across a clip

track(name="Arp", new=true)
  .clip.new(length_bars=4)
  .notes.add_arpeggio(root=E4, quality=min, beat=0, step=0.5, beats=8)
  .notes.add_arpeggio(root=C4, quality=major, beat=8, step=0.5, beats=8)

Bulk operations

// Mute all drum tracks
filter(tracks, track.name == "Drums").track.set(mute=true)

// Add compressor to every track named "Vocals"
filter(tracks, track.name == "Vocals").for_each(.fx.add(name="compressor"))

// Delete all tracks named "Scratch"
filter(tracks, track.name == "Scratch").delete()

Custom groove from scratch

groove.new(name="Lazy Swing", notesPerBeat=2, shifts="0.0,0.33")
groove.set(template="Lazy Swing", strength=0.8)