music-dsl 2.0.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. music_dsl-2.0.3/LICENSE +21 -0
  2. music_dsl-2.0.3/MANIFEST.in +10 -0
  3. music_dsl-2.0.3/PKG-INFO +648 -0
  4. music_dsl-2.0.3/README.md +612 -0
  5. music_dsl-2.0.3/install.sh +69 -0
  6. music_dsl-2.0.3/music/__init__.py +6 -0
  7. music_dsl-2.0.3/music/__main__.py +2 -0
  8. music_dsl-2.0.3/music/_chords.py +62 -0
  9. music_dsl-2.0.3/music/_constants.py +22 -0
  10. music_dsl-2.0.3/music/_durations.py +19 -0
  11. music_dsl-2.0.3/music/_engine.py +91 -0
  12. music_dsl-2.0.3/music/_instruments.py +582 -0
  13. music_dsl-2.0.3/music/_keys.py +50 -0
  14. music_dsl-2.0.3/music/_midi.py +472 -0
  15. music_dsl-2.0.3/music/_pitch.py +25 -0
  16. music_dsl-2.0.3/music/_waveform.py +193 -0
  17. music_dsl-2.0.3/music/cli.py +90 -0
  18. music_dsl-2.0.3/music/models.py +834 -0
  19. music_dsl-2.0.3/music/parser.py +440 -0
  20. music_dsl-2.0.3/music/samples/chaos.music +119 -0
  21. music_dsl-2.0.3/music/samples/empire_fire.music +112 -0
  22. music_dsl-2.0.3/music/samples/fur_elise.mid +0 -0
  23. music_dsl-2.0.3/music/samples/iron_clash.music +167 -0
  24. music_dsl-2.0.3/music/samples/kavinsky-nightcall.mid +0 -0
  25. music_dsl-2.0.3/music/samples/last_stand.music +126 -0
  26. music_dsl-2.0.3/music/samples/machine.music +164 -0
  27. music_dsl-2.0.3/music/samples/neon1.music +356 -0
  28. music_dsl-2.0.3/music/samples/night_drive.music +149 -0
  29. music_dsl-2.0.3/music/samples/skybound.music +156 -0
  30. music_dsl-2.0.3/music/samples/tragedy.music +164 -0
  31. music_dsl-2.0.3/music_dsl.egg-info/PKG-INFO +648 -0
  32. music_dsl-2.0.3/music_dsl.egg-info/SOURCES.txt +36 -0
  33. music_dsl-2.0.3/music_dsl.egg-info/dependency_links.txt +1 -0
  34. music_dsl-2.0.3/music_dsl.egg-info/entry_points.txt +2 -0
  35. music_dsl-2.0.3/music_dsl.egg-info/requires.txt +10 -0
  36. music_dsl-2.0.3/music_dsl.egg-info/top_level.txt +1 -0
  37. music_dsl-2.0.3/pyproject.toml +64 -0
  38. music_dsl-2.0.3/setup.cfg +4 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Enginestein
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,10 @@
1
+ include LICENSE
2
+ include README.md
3
+ include install.sh
4
+ recursive-include music/samples *
5
+
6
+ global-exclude *.py[cod]
7
+ global-exclude *.so
8
+ prune build
9
+ prune dist
10
+ prune .git
@@ -0,0 +1,648 @@
1
+ Metadata-Version: 2.4
2
+ Name: music-dsl
3
+ Version: 2.0.3
4
+ Summary: A text-based music programming language: write songs in plain text and play or export them.
5
+ Author: Enginestein
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/enginestein/Music-DSL
8
+ Project-URL: Repository, https://github.com/enginestein/Music-DSL
9
+ Project-URL: Issues, https://github.com/enginestein/Music-DSL/issues
10
+ Keywords: music,dsl,audio,synthesis,synthesizer,midi,sequencer,tracker,wav,chiptune
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Intended Audience :: End Users/Desktop
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Topic :: Multimedia :: Sound/Audio :: Sound Synthesis
22
+ Classifier: Topic :: Multimedia :: Sound/Audio :: MIDI
23
+ Classifier: Topic :: Software Development :: Interpreters
24
+ Requires-Python: >=3.10
25
+ Description-Content-Type: text/markdown
26
+ License-File: LICENSE
27
+ Requires-Dist: numpy
28
+ Provides-Extra: playback
29
+ Requires-Dist: sounddevice; extra == "playback"
30
+ Provides-Extra: full
31
+ Requires-Dist: sounddevice; extra == "full"
32
+ Requires-Dist: pyaudio; extra == "full"
33
+ Requires-Dist: soundfile; extra == "full"
34
+ Requires-Dist: scipy; extra == "full"
35
+ Dynamic: license-file
36
+
37
+ # MUSIC — PROGRAM YOUR OWN MUSIC
38
+
39
+ **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.
40
+
41
+ ```
42
+ tempo: 120 name: My Song key: C
43
+
44
+ -- melody: organ 0.4 0.2 reverb:0.3 --
45
+ C4 q E4 q G4 q C5 q
46
+
47
+ -- bass: sawtooth 0.3 -0.3 filter:lp 400 --
48
+ C3 h F3 h G3 h C3 h
49
+ ```
50
+
51
+ ---
52
+
53
+ ## Installation
54
+
55
+ ### Prerequisites
56
+ - **Python 3.10+**
57
+ - **NumPy** (`pip install numpy`)
58
+ - **sounddevice** (optional, for playback): `pip install sounddevice`
59
+
60
+ ### Install
61
+
62
+ ```bash
63
+ cd music-dsl/
64
+ pip install .
65
+ pip install -e . # editable mode (development)
66
+ ```
67
+
68
+ ### System-wide install (Linux)
69
+
70
+ ```bash
71
+ sudo ./install.sh # creates venv at /opt/music, installs dependencies
72
+ ```
73
+
74
+ ### Verify
75
+
76
+ ```bash
77
+ music --help
78
+ music music/samples/night_drive.music # play a sample
79
+ python3 -m music --help # alternative invocation
80
+ ```
81
+
82
+ ---
83
+
84
+ ## Usage
85
+
86
+ ```
87
+ music song.music play a song
88
+ music --midi song.music out.mid export to MIDI
89
+ music --export song.music.wav export to WAV
90
+ music --import-midi file.mid import & play MIDI
91
+ music --import-midi file.mid out.music import MIDI → .music
92
+ music song.music --wave play with waveform visualizer
93
+ python3 -m music song.music alternative invocation
94
+ ```
95
+
96
+ ---
97
+
98
+ ## Python API
99
+
100
+ Use Music DSL programmatically from Python:
101
+
102
+ ```python
103
+ from music import load, Song, Track, Note, midi_to_song, song_to_text
104
+
105
+ # Parse a .music file
106
+ song = load("path/to/song.music")
107
+
108
+ # Play through speakers
109
+ song.play()
110
+
111
+ # Export
112
+ song.save("out.wav") # WAV file
113
+ song.to_midi("out.mid") # Standard MIDI File
114
+
115
+ # Inspect
116
+ song.show() # print track summary to stdout
117
+ print(song.total_beats()) # total duration in beats
118
+ text = song.to_text() # Song → .music DSL text (via MIDI roundtrip)
119
+ ```
120
+
121
+ ### Building a song in code
122
+
123
+ ```python
124
+ from music import Song, Track, Note
125
+
126
+ song = Song()
127
+ song.tempo = 120
128
+ song.name = "Code Song"
129
+
130
+ track = Track("melody", "piano", vol=0.5, pan=0.0)
131
+ track.line("C4 q E4 q G4 q C5 q", key_acc={})
132
+ song.add(track)
133
+
134
+ song.save("code_song.wav")
135
+ ```
136
+
137
+ ### Importing MIDI
138
+
139
+ ```python
140
+ from music import midi_to_song
141
+
142
+ song = midi_to_song("file.mid") # returns a Song object
143
+ song.play()
144
+ ```
145
+
146
+ ---
147
+
148
+ ## Language Reference
149
+
150
+ ### File-level directives
151
+
152
+ Place these at the top of a `.music` file:
153
+
154
+ ```
155
+ tempo: 120 # BPM (default 120)
156
+ name: My Song # title
157
+ key: C # major: C G D A E B F# C# F Bb Eb Ab Db Gb Cb
158
+ key: Am # minor: Am Em Bm F#m C#m Dm Gm Cm Fm Bbm
159
+ key: none # no key signature
160
+ time: 4/4 # time signature (default 4/4)
161
+ ```
162
+
163
+ ### Comments
164
+
165
+ ```
166
+ # This is a full-line comment
167
+ C4 q # This is an inline comment
168
+ ```
169
+
170
+ ### Tracks
171
+
172
+ A track has a name, instrument, volume, pan, and optional effects:
173
+
174
+ ```
175
+ -- name: instrument vol pan options --
176
+ -- melody: organ 0.4 0.2 reverb:0.3 --
177
+ -- bass: sawtooth 0.3 -0.3 swing:0.6 --
178
+ -- rhythm: noise 0.15 0.0 mute -- # silenced track
179
+ ```
180
+
181
+ Track header options:
182
+ | Option | Values | Description |
183
+ |--------|--------|-------------|
184
+ | `vol` | 0.0–1.0 | Volume |
185
+ | `pan` | -1.0–1.0 | Panning (left→right) |
186
+ | `reverb` | 0.0–1.0 | Reverb mix |
187
+ | `delay` | 0.0–1.0 | Delay mix |
188
+ | `swing` | 0.0–1.0 | Swing/shuffle amount |
189
+ | `mute` | — | Silences the track |
190
+
191
+ **Shorthand** — create a track with just an instrument name:
192
+
193
+ ```
194
+ inst: piano 0.5 0.0 # name=instrument, vol=0.5, pan=0.0
195
+ ```
196
+
197
+ Effect lines (placed inside the track body, one per line):
198
+
199
+ ```
200
+ reverb:0.3
201
+ delay:0.2
202
+ swing:0.5
203
+ adsr:0.01 0.05 0.8 0.1 # attack decay sustain release
204
+ filter:lp 800 0.7 # lowpass/highpass/bandpass + freq + Q
205
+ dist:0.3 # waveshaping distortion
206
+ lfo:filter 2 200 500 # LFO → filter (rate depth base)
207
+ humanize timing:0.02 vel:0.1 # random timing & velocity variation
208
+ ```
209
+
210
+ Effects are additive across lines (multiple `reverb:` lines sum, multiple `filter:` lines replace).
211
+
212
+ ### Notes
213
+
214
+ ```
215
+ C4 q D#4 e Bb3 h F4 w
216
+ ```
217
+
218
+ **Pitch:** `A B C D E F G` with optional `#`/`b` accidental, followed by an octave number (4 = middle C, range 0–9).
219
+
220
+ **Durations** (sticky — applies to subsequent notes until changed):
221
+
222
+ | Code | Beats | Code | Beats |
223
+ |------|-------|------|-------|
224
+ | `w` | 4 (whole) | `e` | 0.5 (eighth) |
225
+ | `h` | 2 (half) | `s` | 0.25 (sixteenth) |
226
+ | `q` | 1 (quarter) | `t` | 0.125 |
227
+ | | | `x` | 0.0625 (sixty-fourth) |
228
+
229
+ **Duration modifiers:**
230
+ ```
231
+ C4 q. # dotted (1.5x)
232
+ C4 q.. # double-dotted (1.75x)
233
+ C4 qt # triplet (2/3x)
234
+ C4 _1.5 # raw duration in beats
235
+ C4 _0.253 # fractional beats (e.g. from MIDI import)
236
+ ```
237
+
238
+ **Rests:**
239
+ ```
240
+ R q R e R _2 rest q _ q
241
+ ```
242
+
243
+ ### Bar lines
244
+
245
+ ```
246
+ | # bar line (warns if bar overflows)
247
+ || # double bar line
248
+ ```
249
+
250
+ ### Sections & Repeats
251
+
252
+ ```
253
+ [verse]
254
+ C4 q E4 q G4 q
255
+ @jump verse # repeat indefinitely
256
+
257
+ @done # stop playback here (rest of track ignored)
258
+ ```
259
+
260
+ `[label]` marks a position, `@jump label` jumps back to it. `@done` stops playback.
261
+
262
+ Repeat a block N times:
263
+ ```
264
+ [ C4 q E4 q G4 q ] x4
265
+ [ C4 e R e ] x32
266
+ ```
267
+
268
+ **Multi-line repeats:**
269
+ ```
270
+ [ C4 q E4 q
271
+ G4 q C5 q ] x3
272
+ ```
273
+
274
+ **Volta endings** (1st and 2nd endings):
275
+ ```
276
+ [1 C4 q D4 q E4 q] # play on first pass
277
+ [2 C4 q D4 q F4 q] # play on second pass
278
+ ```
279
+
280
+ ### Chords
281
+
282
+ **Simultaneous notes** (parenthesized group):
283
+ ```
284
+ (C4 E4 G4) q # C major chord
285
+ (C4 E4 G4 C5) h # add octave
286
+ ```
287
+
288
+ **Chord symbols** (shorthand):
289
+ ```
290
+ C q Cm q C7 q Cmaj7 q
291
+ ```
292
+
293
+ A letter alone (`C`) is a major triad. Chord type is appended directly (no space):
294
+
295
+ | Symbol | Type | Symbol | Type |
296
+ |--------|------|--------|------|
297
+ | (none) | Major | `m` / `min` | Minor |
298
+ | `maj7` / `M7` | Major 7th | `m7` | Minor 7th |
299
+ | `7` | Dominant 7th | `dim` | Diminished |
300
+ | `dim7` | Diminished 7th | `aug` | Augmented |
301
+ | `sus4` / `sus` | Suspended 4th | `sus2` | Suspended 2nd |
302
+ | `6` | Major 6th | `m6` | Minor 6th |
303
+ | `9` | Dominant 9th | `add9` | Add 9 |
304
+ | `m7b5` | Half-diminished | `m9` | Minor 9th |
305
+
306
+ Chord voicing starts at octave 4 by default. To specify octave, use the parenthesized form.
307
+
308
+ **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.
309
+
310
+ ### Ties & Articulations
311
+
312
+ ```
313
+ C4 w ~ C4 q # tie (sustain across barline)
314
+ C4~ q # legato (no gap between notes)
315
+ C4. q # staccato (50% duration)
316
+ ```
317
+
318
+ | Modifier | Effect |
319
+ |----------|--------|
320
+ | `.` after pitch | Staccato (shorten by 50%) |
321
+ | `~` after pitch | Legato (no gap before next) |
322
+ | `~` between notes | Tie (sustain through) |
323
+
324
+ ### Dynamics
325
+
326
+ ```
327
+ ppp pp p mp mf f ff fff sffz
328
+ ```
329
+
330
+ Set global dynamics for subsequent notes. `fp` starts loud then soft.
331
+
332
+ ```
333
+ ppp = 0.15 pp = 0.25 p = 0.35 mp = 0.50
334
+ mf = 0.70 f = 0.85 ff = 1.00 fff = 1.20
335
+ sffz = 1.30 fp = (1.00 → 0.35)
336
+ ```
337
+
338
+ ### Accent markings
339
+
340
+ ```
341
+ >C4 q ^D4 q +E4 q
342
+ ```
343
+
344
+ Apply directly before a pitch name. Boosts note velocity:
345
+
346
+ | Mark | Name | Velocity multiplier |
347
+ |------|------|-------------------|
348
+ | `>` | Accent | ×1.3 |
349
+ | `^` | Marcato | ×1.5 |
350
+ | `+` | Sforzando | ×1.8 |
351
+
352
+ ### Note velocity override
353
+
354
+ ```
355
+ C4 q @0.63 # set C4 velocity to 0.63 (overrides default 0.8)
356
+ ```
357
+
358
+ `@N` after a note sets its velocity directly (0.0–1.0).
359
+
360
+ ### Expression effects
361
+
362
+ ```
363
+ vibrato:5 # pitch LFO rate (Hz)
364
+ tremolo:3 # amplitude LFO rate (Hz)
365
+ portamento:0.15 # pitch slide duration (seconds)
366
+ ```
367
+
368
+ Set per-track. Values persist until changed.
369
+
370
+ ### Note probability
371
+
372
+ ```
373
+ C4 q ?0.5 D4 q E4 q # D4 has 50% chance of silence
374
+ ```
375
+
376
+ `?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`.
377
+
378
+ ### Crescendo & Diminuendo
379
+
380
+ ```
381
+ < C4 q D4 q E4 q > # notes get progressively louder
382
+ ```
383
+
384
+ `<` starts a velocity ramp (starting velocity → ×1.4), `>` ends it. All non-rest notes between receive linearly increasing velocity.
385
+
386
+ ### Inline tempo & time signature changes
387
+
388
+ ```
389
+ C4 q D4 q tempo:160 E4 q F4 q
390
+ C4 q D4 q time:3/4 C4 q D4 q E4 q
391
+ ```
392
+
393
+ `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.
394
+
395
+ ### Tuplets
396
+
397
+ ```
398
+ 3:2 {C4 D4 E4} # triplet (3 notes in the space of 2)
399
+ 5:4 {C4 D4 E4 F4 G4} # quintuplet (5 in the space of 4)
400
+ 6:4 {C4 D4 E4 F4 G4 A4} # sextuplet
401
+ ```
402
+
403
+ The first number is how many notes, the second is the base duration (in units of the current sticky duration). Grace notes:
404
+
405
+ ```
406
+ {C4 D4} E4 q # acciaccatura (grace notes, very short)
407
+ ```
408
+
409
+ ### Key signature
410
+
411
+ Key signatures apply accidentals automatically:
412
+
413
+ ```
414
+ key: D # F# and C# are raised
415
+ key: Bb # Bb and Eb
416
+ key: Fm # Bb, Eb, Ab, Db
417
+ ```
418
+
419
+ Use `key: none` or `key: C` for no accidentals. Accidentals on individual notes (`C#4`, `Bb3`) override the key signature.
420
+
421
+ ### Transpose
422
+
423
+ ```
424
+ @ transpose 2 # all subsequent notes up 2 semitones
425
+ @ transpose -12 # down one octave
426
+ ```
427
+
428
+ ### Voice assignment
429
+
430
+ ```
431
+ voice:2 # assign subsequent notes to MIDI voice 2
432
+ ```
433
+
434
+ Used for MIDI roundtrip fidelity when a channel contains multiple independent lines.
435
+
436
+ ### Patterns
437
+
438
+ Reusable note sequences:
439
+
440
+ **Single-line definition:**
441
+ ```
442
+ @pattern arp = C4 e E4 e G4 e C5 e
443
+ ```
444
+
445
+ **Multi-line definition:**
446
+ ```
447
+ @pattern bassline
448
+ C2 e G2 e C3 e G2 e
449
+ Ab1 e Eb2 e Ab2 e Eb2 e
450
+ @end
451
+ ```
452
+
453
+ **Invocation:**
454
+ ```
455
+ @arp
456
+ @bassline
457
+ ```
458
+
459
+ ### Step sequencer
460
+
461
+ ```
462
+ @steps 8 { C4 . D4 . E4 . F4 . }
463
+ ```
464
+
465
+ Each step gets `current_duration / nsteps` duration. Dots (`.`) or `R` produce rests within the step pattern.
466
+
467
+ ### Random / stochastic commands
468
+
469
+ ```
470
+ @coin C4 D4 E4 # 50% chance to play one random note
471
+ @coin 0.3 C4 D4 # 30% chance
472
+ @rand C4 D4 E4 F4 # always play one random note from the list
473
+ @choose C4 D4 E4 # play ALL notes, each shortened proportionally
474
+ @shuffle C4 D4 E4 F4 # play all notes in random order
475
+ ```
476
+
477
+ ### Include
478
+
479
+ ```
480
+ @include other_song.music # import tracks from another .music file
481
+ ```
482
+
483
+ Tracks from the included file are added to the current song using the current track's instrument.
484
+
485
+ ### Track mute
486
+
487
+ ```
488
+ -- rhythm: guitar 0.3 mute --
489
+ ```
490
+
491
+ Add `mute` anywhere in the track header to silence it during playback. Useful for arranging or A/B testing parts without deleting them.
492
+
493
+ ---
494
+
495
+ ## Instruments
496
+
497
+ 45 instruments organized by category. Each has a natural default ADSR envelope; override with `adsr:` in the track body.
498
+
499
+ ### Basic Waveforms
500
+
501
+ | Name | Aliases | Description |
502
+ |------|---------|-------------|
503
+ | `sine` | — | Pure sine wave |
504
+ | `square` | — | Square wave (polyBLEP anti-aliased) |
505
+ | `saw` | `sawtooth` | Saw wave (polyBLEP anti-aliased) |
506
+ | `tri` | `triangle` | Mellow triangle wave |
507
+ | `noise` | — | White noise |
508
+
509
+ ### Keyboard
510
+
511
+ | Name | Aliases | Description |
512
+ |------|---------|-------------|
513
+ | `piano` | — | Rich piano (inharmonic partials) |
514
+ | `organ` | — | Hammond-style drawbar organ with Leslie tremolo |
515
+ | `harpsichord` | — | Bright plucked keyboard (Karplus-Strong) |
516
+ | `clavinet` | — | Funky electric keyboard |
517
+ | `celesta` | — | Soft bell-like keyboard |
518
+
519
+ ### Plucked Strings
520
+
521
+ | Name | Aliases | Description |
522
+ |------|---------|-------------|
523
+ | `guitar` | — | Steel-string guitar (Karplus-Strong) |
524
+ | `nylon` | — | Nylon-string guitar (warmer KS) |
525
+ | `harp` | — | Warm resonant harp (KS, long decay) |
526
+ | `banjo` | — | Bright twangy banjo (KS, high brightness) |
527
+ | `sitar` | — | Buzzing Indian sitar (jawari + sympathetic resonance) |
528
+ | `kalimba` | — | Thumb piano (soft metallic pluck) |
529
+
530
+ ### Bowed / Sustained
531
+
532
+ | Name | Aliases | Description |
533
+ |------|---------|-------------|
534
+ | `strings` | `pad` | 3-voice detuned string ensemble |
535
+ | `bass` | — | Sub-oscillator bass with soft saturation |
536
+ | `choir` | — | Vocal ensemble with formant shaping |
537
+
538
+ ### Wind
539
+
540
+ | Name | Aliases | Description |
541
+ |------|---------|-------------|
542
+ | `flute` | — | Pure tone with breath noise |
543
+ | `brass` | — | Bright brass with attack blip |
544
+ | `reed` | `sax` | Nasal woodwind (even+odd harmonics + breath) |
545
+ | `accordion` | — | Free-reed with wet tuning tremolo |
546
+
547
+ ### Bells & Mallets
548
+
549
+ | Name | Aliases | Description |
550
+ |------|---------|-------------|
551
+ | `bell` | — | Inharmonic metallic bell |
552
+ | `pluck` | — | Percussive noise burst |
553
+ | `marimba` | — | Wooden bar (short inharmonic) |
554
+ | `xylophone` | — | Bright wooden bar (shorter than marimba) |
555
+ | `vibraphone` | — | Metal bar with motor tremolo |
556
+ | `steel_drums` | — | Metallic tropical steel pan |
557
+
558
+ ### Percussion
559
+
560
+ | Name | Aliases | Description |
561
+ |------|---------|-------------|
562
+ | `kick` | — | Bass drum (sine sweep + click) |
563
+ | `snare` | — | Snare drum (tone + filtered noise) |
564
+ | `hihat` | — | Closed hi-hat (short highpass noise) |
565
+ | `hihat_open` | — | Open hi-hat (longer decay) |
566
+ | `cymbal` | — | Crash cymbal (bright metallic noise) |
567
+ | `ride` | — | Ride cymbal (noise + tonal ping) |
568
+ | `tom` | — | Tom drum (pitched sine sweep) |
569
+ | `clap` | — | Hand clap (layered noise bursts) |
570
+ | `rimshot` | — | Rimshot (short click + tone) |
571
+ | `cowbell` | — | Cowbell (two-tone metallic) |
572
+ | `tambourine` | — | Tambourine (noise + metallic jingle) |
573
+ | `maracas` | — | Maracas (short highpass shake) |
574
+
575
+ ---
576
+
577
+ ## Sample Songs
578
+
579
+ Located in `music/samples/`:
580
+
581
+ ```
582
+ music music/samples/night_drive.music
583
+ ```
584
+
585
+ | File | Tempo | Duration | Style |
586
+ |------|-------|----------|-------|
587
+ | `night_drive.music` | 94 BPM | 165s | Synthwave / retrowave |
588
+ | `empire_fire.music` | 174 BPM | 66s | War march / orchestral |
589
+ | `chaos.music` | 178 BPM | — | Storm of iron / battle |
590
+ | `skybound.music` | — | — | Cinematic |
591
+ | `machine.music` | — | — | Industrial |
592
+ | `iron_clash.music` | — | — | Percussive |
593
+ | `last_stand.music` | 162 BPM | 95s | Epic finale |
594
+ | `tragedy.music` | — | — | Dark / melancholic |
595
+
596
+ ---
597
+
598
+ ## MIDI Import/Export
599
+
600
+ ### Import MIDI → play or convert
601
+
602
+ ```bash
603
+ music --import-midi song.mid # import & play
604
+ music --import-midi song.mid out.music # import → .music DSL file
605
+ ```
606
+
607
+ The importer maps General MIDI programs to the closest built-in instrument:
608
+
609
+ **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**
610
+
611
+ Percussion channel (GM ch10) maps to dedicated drum instruments: `kick`, `snare`, `hihat`, `hihat_open`, `cymbal`, `ride`, `tom`, `clap`, `rimshot`, `cowbell`, `tambourine`, `maracas`.
612
+
613
+ 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.
614
+
615
+ ### Export to MIDI / WAV
616
+
617
+ ```bash
618
+ music --midi song.music out.mid # export to Standard MIDI File
619
+ music --export song.music out.wav # export to WAV audio file
620
+ ```
621
+
622
+ ---
623
+
624
+ ## Audio Engine
625
+
626
+ ### Playback backends (auto-detected)
627
+ 1. **sounddevice** — preferred, low-latency
628
+ 2. **PyAudio** — fallback
629
+ 3. **aplay / paplay / pw-play** — system audio tools
630
+
631
+ ### Per-track effects chain
632
+ 1. Waveform synthesis (oscillator)
633
+ 2. ADSR envelope
634
+ 3. Staccato / legato articulation
635
+ 4. Vibrato, tremolo, portamento
636
+ 5. Volume & pan
637
+ 6. Filter (lowpass / highpass / bandpass)
638
+ 7. LFO-modulated filter
639
+ 8. Waveshaping distortion
640
+ 9. Reverb
641
+ 10. Delay
642
+ 11. Humanization (random timing & velocity)
643
+
644
+ ---
645
+
646
+ ## License
647
+
648
+ MIT — use it, tweak it, make music with it.