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.
- music_dsl-2.0.3/LICENSE +21 -0
- music_dsl-2.0.3/MANIFEST.in +10 -0
- music_dsl-2.0.3/PKG-INFO +648 -0
- music_dsl-2.0.3/README.md +612 -0
- music_dsl-2.0.3/install.sh +69 -0
- music_dsl-2.0.3/music/__init__.py +6 -0
- music_dsl-2.0.3/music/__main__.py +2 -0
- music_dsl-2.0.3/music/_chords.py +62 -0
- music_dsl-2.0.3/music/_constants.py +22 -0
- music_dsl-2.0.3/music/_durations.py +19 -0
- music_dsl-2.0.3/music/_engine.py +91 -0
- music_dsl-2.0.3/music/_instruments.py +582 -0
- music_dsl-2.0.3/music/_keys.py +50 -0
- music_dsl-2.0.3/music/_midi.py +472 -0
- music_dsl-2.0.3/music/_pitch.py +25 -0
- music_dsl-2.0.3/music/_waveform.py +193 -0
- music_dsl-2.0.3/music/cli.py +90 -0
- music_dsl-2.0.3/music/models.py +834 -0
- music_dsl-2.0.3/music/parser.py +440 -0
- music_dsl-2.0.3/music/samples/chaos.music +119 -0
- music_dsl-2.0.3/music/samples/empire_fire.music +112 -0
- music_dsl-2.0.3/music/samples/fur_elise.mid +0 -0
- music_dsl-2.0.3/music/samples/iron_clash.music +167 -0
- music_dsl-2.0.3/music/samples/kavinsky-nightcall.mid +0 -0
- music_dsl-2.0.3/music/samples/last_stand.music +126 -0
- music_dsl-2.0.3/music/samples/machine.music +164 -0
- music_dsl-2.0.3/music/samples/neon1.music +356 -0
- music_dsl-2.0.3/music/samples/night_drive.music +149 -0
- music_dsl-2.0.3/music/samples/skybound.music +156 -0
- music_dsl-2.0.3/music/samples/tragedy.music +164 -0
- music_dsl-2.0.3/music_dsl.egg-info/PKG-INFO +648 -0
- music_dsl-2.0.3/music_dsl.egg-info/SOURCES.txt +36 -0
- music_dsl-2.0.3/music_dsl.egg-info/dependency_links.txt +1 -0
- music_dsl-2.0.3/music_dsl.egg-info/entry_points.txt +2 -0
- music_dsl-2.0.3/music_dsl.egg-info/requires.txt +10 -0
- music_dsl-2.0.3/music_dsl.egg-info/top_level.txt +1 -0
- music_dsl-2.0.3/pyproject.toml +64 -0
- music_dsl-2.0.3/setup.cfg +4 -0
music_dsl-2.0.3/LICENSE
ADDED
|
@@ -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.
|
music_dsl-2.0.3/PKG-INFO
ADDED
|
@@ -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.
|