Skip to main content

MUSIC — PROGRAM YOUR OWN MUSIC

Music DSL is a text-based music programming language. Write songs in a plain text file, play them instantly through your speakers, or export to WAV/MIDI. No instruments, DAWs, or audio editing required.

tempo: 120   name: My Song   key: C

-- melody: organ 0.4 0.2 reverb:0.3 --
C4 q  E4 q  G4 q  C5 q

-- bass: sawtooth 0.3 -0.3 filter:lp 400 --
C3 h  F3 h  G3 h  C3 h

Installation

Prerequisites

  • Python 3.10+
  • NumPy (pip install numpy)
  • sounddevice (optional, for playback): pip install sounddevice

Install

cd music-dsl/
pip install .
pip install -e .        # editable mode (development)

System-wide install (Linux)

sudo ./install.sh       # creates venv at /opt/music, installs dependencies

Verify

music --help
music music/samples/night_drive.music   # play a sample
python3 -m music --help                 # alternative invocation

Usage

music song.music                 play a song
music --midi song.music out.mid  export to MIDI
music --export song.music.wav    export to WAV
music --import-midi file.mid     import & play MIDI
music --import-midi file.mid out.music  import MIDI → .music
music song.music --wave          play with waveform visualizer
python3 -m music song.music      alternative invocation

Python API

Use Music DSL programmatically from Python:

from music import load, Song, Track, Note, midi_to_song, song_to_text

# Parse a .music file
song = load("path/to/song.music")

# Play through speakers
song.play()

# Export
song.save("out.wav")              # WAV file
song.to_midi("out.mid")           # Standard MIDI File

# Inspect
song.show()                       # print track summary to stdout
print(song.total_beats())         # total duration in beats
text = song.to_text()             # Song → .music DSL text (via MIDI roundtrip)

Building a song in code

from music import Song, Track, Note

song = Song()
song.tempo = 120
song.name = "Code Song"

track = Track("melody", "piano", vol=0.5, pan=0.0)
track.line("C4 q E4 q G4 q C5 q", key_acc={})
song.add(track)

song.save("code_song.wav")

Importing MIDI

from music import midi_to_song

song = midi_to_song("file.mid")   # returns a Song object
song.play()

Language Reference

File-level directives

Place these at the top of a .music file:

tempo: 120          # BPM (default 120)
name: My Song       # title
key: C              # major: C G D A E B F# C# F Bb Eb Ab Db Gb Cb
key: Am             # minor: Am Em Bm F#m C#m Dm Gm Cm Fm Bbm
key: none           # no key signature
time: 4/4           # time signature (default 4/4)

Comments

# This is a full-line comment
C4 q  # This is an inline comment

Tracks

A track has a name, instrument, volume, pan, and optional effects:

-- name: instrument vol pan options --
-- melody: organ 0.4 0.2 reverb:0.3 --
-- bass: sawtooth 0.3 -0.3 swing:0.6 --
-- rhythm: noise 0.15 0.0 mute --    # silenced track

Track header options:

Option Values Description
vol 0.0–1.0 Volume
pan -1.0–1.0 Panning (left→right)
reverb 0.0–1.0 Reverb mix
delay 0.0–1.0 Delay mix
swing 0.0–1.0 Swing/shuffle amount
mute — Silences the track

Shorthand — create a track with just an instrument name:

inst: piano 0.5 0.0     # name=instrument, vol=0.5, pan=0.0

Effect lines (placed inside the track body, one per line):

reverb:0.3
delay:0.2
swing:0.5
adsr:0.01 0.05 0.8 0.1   # attack decay sustain release
filter:lp 800 0.7         # lowpass/highpass/bandpass + freq + Q
dist:0.3                  # waveshaping distortion
lfo:filter 2 200 500      # LFO → filter (rate depth base)
humanize timing:0.02 vel:0.1  # random timing & velocity variation

Effects are additive across lines (multiple reverb: lines sum, multiple filter: lines replace).

Notes

C4 q    D#4 e    Bb3 h    F4 w

Pitch: A B C D E F G with optional #/b accidental, followed by an octave number (4 = middle C, range 0–9).

Durations (sticky — applies to subsequent notes until changed):

Code Beats Code Beats
w 4 (whole) e 0.5 (eighth)
h 2 (half) s 0.25 (sixteenth)
q 1 (quarter) t 0.125
x 0.0625 (sixty-fourth)

Duration modifiers:

C4 q.           # dotted (1.5x)
C4 q..          # double-dotted (1.75x)
C4 qt           # triplet (2/3x)
C4 _1.5         # raw duration in beats
C4 _0.253       # fractional beats (e.g. from MIDI import)

Rests:

R q    R e    R _2    rest q    _ q

Bar lines

|             # bar line (warns if bar overflows)
||            # double bar line

Sections & Repeats

[verse]
C4 q  E4 q  G4 q
@jump verse       # repeat indefinitely

@done              # stop playback here (rest of track ignored)

[label] marks a position, @jump label jumps back to it. @done stops playback.

Repeat a block N times:

[ C4 q E4 q G4 q ] x4
[ C4 e R e ] x32

Multi-line repeats:

[ C4 q E4 q
  G4 q C5 q ] x3

Volta endings (1st and 2nd endings):

[1 C4 q D4 q E4 q]      # play on first pass
[2 C4 q D4 q F4 q]      # play on second pass

Chords

Simultaneous notes (parenthesized group):

(C4 E4 G4) q        # C major chord
(C4 E4 G4 C5) h     # add octave

Chord symbols (shorthand):

C  q    Cm  q    C7  q    Cmaj7  q

A letter alone (C) is a major triad. Chord type is appended directly (no space):

Symbol Type Symbol Type
(none) Major m / min Minor
maj7 / M7 Major 7th m7 Minor 7th
7 Dominant 7th dim Diminished
dim7 Diminished 7th aug Augmented
sus4 / sus Suspended 4th sus2 Suspended 2nd
6 Major 6th m6 Minor 6th
9 Dominant 9th add9 Add 9
m7b5 Half-diminished m9 Minor 9th

Chord voicing starts at octave 4 by default. To specify octave, use the parenthesized form.

Note: Pitch names ending in a digit (C7, F#7, Bb9) are parsed as single notes, not chord symbols. Use G7 for the note G at octave 7; use (G B D F) q for a G7 chord.

Ties & Articulations

C4 w ~ C4 q          # tie (sustain across barline)
C4~ q                # legato (no gap between notes)
C4. q                # staccato (50% duration)
Modifier Effect
. after pitch Staccato (shorten by 50%)
~ after pitch Legato (no gap before next)
~ between notes Tie (sustain through)

Dynamics

ppp  pp  p  mp  mf  f  ff  fff  sffz

Set global dynamics for subsequent notes. fp starts loud then soft.

ppp = 0.15   pp = 0.25   p = 0.35   mp = 0.50
mf = 0.70    f = 0.85    ff = 1.00  fff = 1.20
sffz = 1.30  fp = (1.00 → 0.35)

Accent markings

>C4 q    ^D4 q    +E4 q

Apply directly before a pitch name. Boosts note velocity:

Mark Name Velocity multiplier
> Accent ×1.3
^ Marcato ×1.5
+ Sforzando ×1.8

Note velocity override

C4 q @0.63     # set C4 velocity to 0.63 (overrides default 0.8)

@N after a note sets its velocity directly (0.0–1.0).

Expression effects

vibrato:5            # pitch LFO rate (Hz)
tremolo:3            # amplitude LFO rate (Hz)
portamento:0.15      # pitch slide duration (seconds)

Set per-track. Values persist until changed.

Note probability

C4 q ?0.5 D4 q E4 q   # D4 has 50% chance of silence

?N sets the probability (0.0–1.0) for all subsequent notes in that track. Notes roll against the probability each time they play; skipped notes become rests of equal duration. Reset with ?1.0.

Crescendo & Diminuendo

< C4 q D4 q E4 q >   # notes get progressively louder

< starts a velocity ramp (starting velocity → ×1.4), > ends it. All non-rest notes between receive linearly increasing velocity.

Inline tempo & time signature changes

C4 q D4 q tempo:160 E4 q F4 q
C4 q D4 q time:3/4 C4 q D4 q E4 q

tempo:BPM and time:N/D can appear inside a note sequence to change tempo or time signature mid-song. Also work as file-level directives.

Tuplets

3:2 {C4 D4 E4}           # triplet (3 notes in the space of 2)
5:4 {C4 D4 E4 F4 G4}    # quintuplet (5 in the space of 4)
6:4 {C4 D4 E4 F4 G4 A4} # sextuplet

The first number is how many notes, the second is the base duration (in units of the current sticky duration). Grace notes:

{C4 D4} E4 q    # acciaccatura (grace notes, very short)

Key signature

Key signatures apply accidentals automatically:

key: D             # F# and C# are raised
key: Bb            # Bb and Eb
key: Fm            # Bb, Eb, Ab, Db

Use key: none or key: C for no accidentals. Accidentals on individual notes (C#4, Bb3) override the key signature.

Transpose

@ transpose 2     # all subsequent notes up 2 semitones
@ transpose -12   # down one octave

Voice assignment

voice:2           # assign subsequent notes to MIDI voice 2

Used for MIDI roundtrip fidelity when a channel contains multiple independent lines.

Patterns

Reusable note sequences:

Single-line definition:

@pattern arp = C4 e E4 e G4 e C5 e

Multi-line definition:

@pattern bassline
C2 e G2 e C3 e G2 e
Ab1 e Eb2 e Ab2 e Eb2 e
@end

Invocation:

@arp
@bassline

Step sequencer

@steps 8 { C4 . D4 . E4 . F4 . }

Each step gets current_duration / nsteps duration. Dots (.) or R produce rests within the step pattern.

Random / stochastic commands

@coin C4 D4 E4          # 50% chance to play one random note
@coin 0.3 C4 D4         # 30% chance
@rand C4 D4 E4 F4       # always play one random note from the list
@choose C4 D4 E4        # play ALL notes, each shortened proportionally
@shuffle C4 D4 E4 F4    # play all notes in random order

Include

@include other_song.music    # import tracks from another .music file

Tracks from the included file are added to the current song using the current track's instrument.

Track mute

-- rhythm: guitar 0.3 mute --

Add mute anywhere in the track header to silence it during playback. Useful for arranging or A/B testing parts without deleting them.


Instruments

45 instruments organized by category. Each has a natural default ADSR envelope; override with adsr: in the track body.

Basic Waveforms

Name Aliases Description
sine — Pure sine wave
square — Square wave (polyBLEP anti-aliased)
saw sawtooth Saw wave (polyBLEP anti-aliased)
tri triangle Mellow triangle wave
noise — White noise

Keyboard

Name Aliases Description
piano — Rich piano (inharmonic partials)
organ — Hammond-style drawbar organ with Leslie tremolo
harpsichord — Bright plucked keyboard (Karplus-Strong)
clavinet — Funky electric keyboard
celesta — Soft bell-like keyboard

Plucked Strings

Name Aliases Description
guitar — Steel-string guitar (Karplus-Strong)
nylon — Nylon-string guitar (warmer KS)
harp — Warm resonant harp (KS, long decay)
banjo — Bright twangy banjo (KS, high brightness)
sitar — Buzzing Indian sitar (jawari + sympathetic resonance)
kalimba — Thumb piano (soft metallic pluck)

Bowed / Sustained

Name Aliases Description
strings pad 3-voice detuned string ensemble
bass — Sub-oscillator bass with soft saturation
choir — Vocal ensemble with formant shaping

Wind

Name Aliases Description
flute — Pure tone with breath noise
brass — Bright brass with attack blip
reed sax Nasal woodwind (even+odd harmonics + breath)
accordion — Free-reed with wet tuning tremolo

Bells & Mallets

Name Aliases Description
bell — Inharmonic metallic bell
pluck — Percussive noise burst
marimba — Wooden bar (short inharmonic)
xylophone — Bright wooden bar (shorter than marimba)
vibraphone — Metal bar with motor tremolo
steel_drums — Metallic tropical steel pan

Percussion

Name Aliases Description
kick — Bass drum (sine sweep + click)
snare — Snare drum (tone + filtered noise)
hihat — Closed hi-hat (short highpass noise)
hihat_open — Open hi-hat (longer decay)
cymbal — Crash cymbal (bright metallic noise)
ride — Ride cymbal (noise + tonal ping)
tom — Tom drum (pitched sine sweep)
clap — Hand clap (layered noise bursts)
rimshot — Rimshot (short click + tone)
cowbell — Cowbell (two-tone metallic)
tambourine — Tambourine (noise + metallic jingle)
maracas — Maracas (short highpass shake)

Sample Songs

Located in music/samples/:

music music/samples/night_drive.music
File Tempo Duration Style
night_drive.music 94 BPM 165s Synthwave / retrowave
empire_fire.music 174 BPM 66s War march / orchestral
chaos.music 178 BPM — Storm of iron / battle
skybound.music — — Cinematic
machine.music — — Industrial
iron_clash.music — — Percussive
last_stand.music 162 BPM 95s Epic finale
tragedy.music — — Dark / melancholic

MIDI Import/Export

Import MIDI → play or convert

music --import-midi song.mid              # import & play
music --import-midi song.mid out.music    # import → .music DSL file

The importer maps General MIDI programs to the closest built-in instrument:

Piano/Keys→piano,harpsichord,clavinet,celesta Guitar→guitar,nylon Bass→bass Strings→strings Pad→pad Organ→organ Accordion→accordion Brass→brass Woodwinds→reed,sax Flute→flute Choir→choir Mallets→marimba,xylophone,vibraphone,celesta Plucked→harp,banjo,sitar,kalimba,steel_drums Leads→saw,square,sine

Percussion channel (GM ch10) maps to dedicated drum instruments: kick, snare, hihat, hihat_open, cymbal, ride, tom, clap, rimshot, cowbell, tambourine, maracas.

Polyphonic voices within a MIDI channel are automatically split into separate tracks. Duration codes use the raw _N.NNN format to preserve exact MIDI timing.

Export to MIDI / WAV

music --midi song.music out.mid    # export to Standard MIDI File
music --export song.music out.wav  # export to WAV audio file

Audio Engine

Playback backends (auto-detected)

  1. sounddevice — preferred, low-latency
  2. PyAudio — fallback
  3. aplay / paplay / pw-play — system audio tools

Per-track effects chain

  1. Waveform synthesis (oscillator)
  2. ADSR envelope
  3. Staccato / legato articulation
  4. Vibrato, tremolo, portamento
  5. Volume & pan
  6. Filter (lowpass / highpass / bandpass)
  7. LFO-modulated filter
  8. Waveshaping distortion
  9. Reverb
  10. Delay
  11. Humanization (random timing & velocity)

License

MIT — use it, tweak it, make music with it.

Metadata

Release files for music-dsl 2.0.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for music-dsl 2.0.3
File Size Uploaded
music_dsl-2.0.3.tar.gz 62.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for music-dsl 2.0.3
File Interpreter ABI Platform
music_dsl-2.0.3-py3-none-any.whl Python 3 none any Details

Total release size: 121.6 kB

Release files / music_dsl-2.0.3.tar.gz

Download URL music_dsl-2.0.3.tar.gz
Size 62.5 kB
Tags Source
SHA-256 checksum
How to use checksums
1ee4d7cafd32147831d804eb30f6ca542b08c16654f09dff4ac4eb3655d5eb02
BLAKE2b-256 checksum
How to use checksums
d0acc019730a63668487967c936dae04c92065212424c3011e25113c85ba6edb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.10.12

Release files / music_dsl-2.0.3-py3-none-any.whl

Download URL music_dsl-2.0.3-py3-none-any.whl
Size 59.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5fbcdb83f497080043bbf8a0ade1de3e6e4e34bd0e44e86c24d5831402dedd30
BLAKE2b-256 checksum
How to use checksums
cd4bcc2fd169bd7a7a325e8f331dd8c62ee2b68d8f8f8405a50565db49bfb96d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.10.12

Release history Release notifications | RSS feed

This release

2.0.3 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page