musa-dsl 0.43.1 → 0.47.2
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.
Potentially problematic release.
This version of musa-dsl might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/README.md +31 -160
- data/docs/README.md +6 -5
- data/docs/api-reference.md +1 -1
- data/docs/{getting-started/tutorial.md → examples/neuma-notation.md} +6 -3
- data/docs/{getting-started/quick-start.md → examples/sequencer-dsl-voices.md} +2 -2
- data/docs/idioms.md +326 -0
- data/docs/subsystems/generative.md +0 -160
- data/docs/subsystems/repl.md +6 -27
- data/docs/subsystems/series.md +1 -1
- data/lib/musa-dsl/core-ext/attribute-builder.rb +7 -4
- data/lib/musa-dsl/core-ext/deep-copy.rb +81 -24
- data/lib/musa-dsl/core-ext/dynamic-proxy.rb +4 -4
- data/lib/musa-dsl/core-ext/hashify.rb +6 -1
- data/lib/musa-dsl/core-ext/inspect-nice.rb +1 -1
- data/lib/musa-dsl/core-ext/smart-proc-binder.rb +20 -8
- data/lib/musa-dsl/core-ext/with.rb +10 -7
- data/lib/musa-dsl/datasets/dataset.rb +6 -5
- data/lib/musa-dsl/datasets/delta-d.rb +11 -11
- data/lib/musa-dsl/datasets/e.rb +69 -18
- data/lib/musa-dsl/datasets/gdv.rb +118 -86
- data/lib/musa-dsl/datasets/gdvd.rb +45 -21
- data/lib/musa-dsl/datasets/helper.rb +40 -10
- data/lib/musa-dsl/datasets/p.rb +16 -11
- data/lib/musa-dsl/datasets/pdv.rb +82 -16
- data/lib/musa-dsl/datasets/ps.rb +3 -4
- data/lib/musa-dsl/datasets/score/queriable.rb +9 -0
- data/lib/musa-dsl/datasets/score/to-mxml/process-pdv.rb +287 -263
- data/lib/musa-dsl/datasets/score/to-mxml/process-ps.rb +139 -128
- data/lib/musa-dsl/datasets/score/to-mxml/process-time.rb +342 -324
- data/lib/musa-dsl/datasets/score/to-mxml/to-mxml.rb +61 -10
- data/lib/musa-dsl/datasets/score.rb +26 -19
- data/lib/musa-dsl/generative/darwin.rb +35 -28
- data/lib/musa-dsl/generative/generative-grammar.rb +41 -16
- data/lib/musa-dsl/generative/markov.rb +35 -7
- data/lib/musa-dsl/generative.rb +0 -1
- data/lib/musa-dsl/matrix/matrix.rb +28 -11
- data/lib/musa-dsl/midi/midi-recorder.rb +31 -12
- data/lib/musa-dsl/midi/midi-voices.rb +139 -19
- data/lib/musa-dsl/music/chord-definition.rb +16 -7
- data/lib/musa-dsl/music/chords.rb +59 -24
- data/lib/musa-dsl/music/scale_systems/equally_tempered_12_tone_scale_system.rb +3 -3
- data/lib/musa-dsl/music/scale_systems/twelve_semitones_scale_system.rb +2 -2
- data/lib/musa-dsl/music/scales.rb +122 -54
- data/lib/musa-dsl/musicxml/builder/attributes.rb +103 -47
- data/lib/musa-dsl/musicxml/builder/backup-forward.rb +7 -0
- data/lib/musa-dsl/musicxml/builder/direction.rb +26 -19
- data/lib/musa-dsl/musicxml/builder/helper.rb +7 -4
- data/lib/musa-dsl/musicxml/builder/measure.rb +7 -3
- data/lib/musa-dsl/musicxml/builder/part.rb +4 -0
- data/lib/musa-dsl/musicxml/builder/pitched-note.rb +1 -0
- data/lib/musa-dsl/musicxml/builder/score-partwise.rb +4 -0
- data/lib/musa-dsl/musicxml/builder/typed-text.rb +4 -4
- data/lib/musa-dsl/neumalang/neumalang.rb +25 -15
- data/lib/musa-dsl/neumas/array-to-neumas.rb +17 -17
- data/lib/musa-dsl/neumas/neuma-decoder.rb +3 -3
- data/lib/musa-dsl/neumas/neuma-gdv-decoder.rb +4 -2
- data/lib/musa-dsl/neumas/neuma-gdvd-decoder.rb +19 -14
- data/lib/musa-dsl/neumas/neumas.rb +25 -17
- data/lib/musa-dsl/neumas/string-to-neumas.rb +25 -18
- data/lib/musa-dsl/repl/repl.rb +98 -89
- data/lib/musa-dsl/sequencer/base-sequencer-implementation-every.rb +4 -0
- data/lib/musa-dsl/sequencer/base-sequencer-implementation-move.rb +4 -0
- data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-helper.rb +55 -34
- data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-timed.rb +8 -1
- data/lib/musa-dsl/sequencer/base-sequencer-implementation-play.rb +65 -9
- data/lib/musa-dsl/sequencer/base-sequencer-implementation.rb +39 -7
- data/lib/musa-dsl/sequencer/base-sequencer-tick-based.rb +31 -13
- data/lib/musa-dsl/sequencer/base-sequencer-tickless-based.rb +76 -21
- data/lib/musa-dsl/sequencer/base-sequencer.rb +47 -21
- data/lib/musa-dsl/series/base-series.rb +91 -13
- data/lib/musa-dsl/series/main-serie-constructors.rb +170 -47
- data/lib/musa-dsl/series/main-serie-operations.rb +36 -13
- data/lib/musa-dsl/series/proxy-serie.rb +156 -12
- data/lib/musa-dsl/series/quantizer-serie.rb +6 -3
- data/lib/musa-dsl/series/queue-serie.rb +33 -8
- data/lib/musa-dsl/series/series-composer.rb +94 -40
- data/lib/musa-dsl/series/timed-serie.rb +1 -1
- data/lib/musa-dsl/transcription/from-gdv-to-midi.rb +82 -9
- data/lib/musa-dsl/transcription/from-gdv.rb +1 -1
- data/lib/musa-dsl/transcription/transcription.rb +19 -10
- data/lib/musa-dsl/transport/clock.rb +8 -3
- data/lib/musa-dsl/transport/dummy-clock.rb +6 -3
- data/lib/musa-dsl/transport/external-tick-clock.rb +9 -7
- data/lib/musa-dsl/transport/input-midi-clock.rb +3 -2
- data/lib/musa-dsl/transport/timer-clock.rb +3 -3
- data/lib/musa-dsl/transport/timer.rb +6 -4
- data/lib/musa-dsl/transport/transport.rb +26 -14
- data/lib/musa-dsl/version.rb +1 -1
- data/lib/musa-dsl.rb +9 -6
- data/tools/doc-examples.rb +499 -0
- metadata +5 -4
- data/lib/musa-dsl/generative/rules.rb +0 -590
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f8a1f6bc6c231c4b43a8ad4dcfe5db56a0da9de25de6392cc077dba95dc41648
|
|
4
|
+
data.tar.gz: a725d6365bcb16d52dd86de6c6d64d56f72e4eab197d8129fdfd1125570a9212
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2219dc7c259c72a81f8b1a14640313af2537dcb47d24746b8f17c3221df1ff49c34551e520873d4102df32c9a2429939b08c4c3f5f2b6a75d8258e2e062e28b0
|
|
7
|
+
data.tar.gz: 8f77c647934c2024b75529feb983cb45c2ad45e1d5083279f339133cd65c5eb057ca0033c60cdae992408d4a58b704cc6f5a067953b5cade6726f72312327e90
|
data/README.md
CHANGED
|
@@ -23,7 +23,7 @@ Musa-DSL is a programming language DSL (Domain-Specific Language) based on Ruby
|
|
|
23
23
|
- **Transport & Timing** - Multiple clock sources (internal, MIDI, external) with microsecond precision
|
|
24
24
|
- **Audio Engine Independent** - Works with any MIDI-capable, OSC-capable or any other output hardware or software system
|
|
25
25
|
- **Series-Based Composition** - Flexible sequence generators for pitches, rhythms, dynamics, and any musical parameter
|
|
26
|
-
- **Generative Tools** - Markov chains, combinatorial variations (Variatio),
|
|
26
|
+
- **Generative Tools** - Markov chains, combinatorial variations (Variatio), formal grammars (GenerativeGrammar), and genetic algorithms (Darwin)
|
|
27
27
|
- **Matrix Operations** - Mathematical transformations for musical structures
|
|
28
28
|
- **Scale System** - Comprehensive support for scales, tuning systems, and chord structures
|
|
29
29
|
- **Neumalang Notation** - Intuitive text-based and customizable musical (or sound) notation
|
|
@@ -39,7 +39,7 @@ Musa-DSL is a programming language DSL (Domain-Specific Language) based on Ruby
|
|
|
39
39
|
- [Non-commercial use](https://www.jetbrains.com/non-commercial/) — for learning, hobbies, open-source, content creation
|
|
40
40
|
- [Students](https://www.jetbrains.com/academy/student-pack/) and [Teachers/Researchers](https://www.jetbrains.com/academy/teacher-pack/) — with institutional email
|
|
41
41
|
|
|
42
|
-
VSCode with the Ruby LSP extension also works well, though Ruby autocomplete and hover documentation are less complete.
|
|
42
|
+
[VSCode](https://code.visualstudio.com/) with the Ruby LSP extension also works well, though Ruby autocomplete and hover documentation are less complete.
|
|
43
43
|
|
|
44
44
|
### Framework Installation
|
|
45
45
|
|
|
@@ -58,24 +58,19 @@ gem install musa-dsl
|
|
|
58
58
|
**Requirements:**
|
|
59
59
|
- Ruby ~> 3.4
|
|
60
60
|
|
|
61
|
-
##
|
|
61
|
+
## Examples
|
|
62
62
|
|
|
63
|
-
|
|
63
|
+
Two complete, runnable examples included here. Pedagogical learning is covered separately in the [musadsl-demo](https://github.com/javier-sy/musadsl-demo) repository.
|
|
64
64
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
## Tutorial
|
|
68
|
-
|
|
69
|
-
Detailed tutorial showing the Neuma notation system for composing melodies with grade-based notation.
|
|
70
|
-
|
|
71
|
-
**📖 [Complete Tutorial](docs/getting-started/tutorial.md)**
|
|
65
|
+
- **[Sequencer DSL with interacting voices](docs/examples/sequencer-dsl-voices.md)** — multiple voice lines coordinated through shared state, demonstrating the sequencer DSL and timing primitives.
|
|
66
|
+
- **[Neuma notation](docs/examples/neuma-notation.md)** — composing melodies with grade-based Neuma notation and the parser.
|
|
72
67
|
|
|
73
68
|
## Demo Projects
|
|
74
69
|
|
|
75
70
|
A collection of 22+ working demo projects covering the full spectrum of Musa DSL capabilities:
|
|
76
71
|
|
|
77
72
|
- **Basic concepts**: Setup, series, neumas, canon
|
|
78
|
-
- **Generative tools**: Markov chains, Variatio, Darwin, Grammar,
|
|
73
|
+
- **Generative tools**: Markov chains, Variatio, Darwin, Grammar, Matrix
|
|
79
74
|
- **DAW integration**: MIDI sync, live coding, clock modes
|
|
80
75
|
- **External protocols**: OSC with SuperCollider and Max/MSP
|
|
81
76
|
- **Advanced patterns**: Event architecture, parameter automation, multi-phase compositions
|
|
@@ -84,12 +79,10 @@ Each demo is a complete, runnable project with documentation explaining the conc
|
|
|
84
79
|
|
|
85
80
|
**📦 [musadsl-demo Repository](https://github.com/javier-sy/musadsl-demo)**
|
|
86
81
|
|
|
87
|
-
##
|
|
82
|
+
## MusaDSL Ecosystem
|
|
88
83
|
|
|
89
84
|
MusaDSL is a comprehensive ecosystem consisting of a core framework (musa-dsl) and associated projects for communication, development, and integration.
|
|
90
85
|
|
|
91
|
-
### MusaDSL Ecosystem
|
|
92
|
-
|
|
93
86
|
**Core Framework:**
|
|
94
87
|
- [**musa-dsl**](https://github.com/javier-sy/musa-dsl) - Main DSL framework for algorithmic composition and musical thinking
|
|
95
88
|
|
|
@@ -99,159 +92,37 @@ MusaDSL is a comprehensive ecosystem consisting of a core framework (musa-dsl) a
|
|
|
99
92
|
- [**midi-communications**](https://github.com/javier-sy/midi-communications) - Cross-platform MIDI I/O abstraction layer
|
|
100
93
|
- [**midi-communications-macos**](https://github.com/javier-sy/midi-communications-macos) - macOS-specific MIDI native implementation
|
|
101
94
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
The musa-dsl framework is organized in modular layers:
|
|
105
|
-
|
|
106
|
-
#### 1. Foundation Layer
|
|
107
|
-
- **core-ext** - Ruby core extensions (refinements for enhanced syntax)
|
|
108
|
-
- **logger** - Structured logging system with severity levels
|
|
109
|
-
|
|
110
|
-
#### 2. Temporal & Scheduling Layer
|
|
111
|
-
- **sequencer** - Event scheduling engine with microsecond precision
|
|
112
|
-
- Tick-based (quantized) and tickless (continuous) timing modes
|
|
113
|
-
- Series playback with automatic duration management
|
|
114
|
-
- Support for polyrhythms and polytemporal structures
|
|
115
|
-
- **transport** - High-level playback control with clock synchronization
|
|
116
|
-
- BPM management and tempo changes
|
|
117
|
-
- Start/stop/pause/continue controls
|
|
118
|
-
- Multiple clock source support (internal, MIDI, external)
|
|
119
|
-
|
|
120
|
-
#### 3. Notation & Parsing Layer
|
|
121
|
-
- **neumas** - Text-based musical notation system
|
|
122
|
-
- **neumalang** - Parser and interpreter for neuma notation with DSL support
|
|
123
|
-
|
|
124
|
-
#### 4. Generation & Transformation Layer
|
|
125
|
-
- **series** - Lazy sequence generators with functional operations
|
|
126
|
-
- Map, filter, transpose, repeat, and combination operations
|
|
127
|
-
- Infinite and finite series support
|
|
128
|
-
- **generative** - Algorithmic composition tools
|
|
129
|
-
- **Markov chains**: Probabilistic sequence generation
|
|
130
|
-
- **Variatio**: Cartesian product parameter variations
|
|
131
|
-
- **Rules**: L-system-like production systems with growth/pruning
|
|
132
|
-
- **GenerativeGrammar**: Formal grammar-based generation
|
|
133
|
-
- **Darwin**: Genetic algorithms for evolutionary composition
|
|
134
|
-
- **matrix** - Matrix operations for musical gestures
|
|
135
|
-
- Matrix-to-P (point sequence) conversion
|
|
136
|
-
- Gesture condensation and transformation
|
|
137
|
-
|
|
138
|
-
#### 5. Output & Communication Layer
|
|
139
|
-
- **transcription** - Musical event transformation system
|
|
140
|
-
- Ornament expansion (trills, mordents, turns)
|
|
141
|
-
- GDV to MIDI/MusicXML conversion
|
|
142
|
-
- Dynamic articulation rendering
|
|
143
|
-
- **musicxml** - MusicXML score generation
|
|
144
|
-
- Multi-part score creation
|
|
145
|
-
- Notation directives (dynamics, tempo, articulations)
|
|
146
|
-
- Standard MusicXML 3.0 output
|
|
147
|
-
- **midi** - MIDI voice management
|
|
148
|
-
- Polyphonic voice allocation
|
|
149
|
-
- Channel management
|
|
150
|
-
- Note-on/note-off scheduling
|
|
151
|
-
|
|
152
|
-
#### 6. Musical Knowledge Layer
|
|
153
|
-
- **music** - Scales, tuning systems, intervals, and chord structures
|
|
154
|
-
- Equal temperament and just intonation support
|
|
155
|
-
- Modal scales (major, minor, chromatic, etc.)
|
|
156
|
-
- Chord definitions and harmonic analysis
|
|
157
|
-
- **datasets** - Musical data structures (GDV, PDV, Score)
|
|
158
|
-
- GDV (Grade-Duration-Velocity): Scale-relative representation
|
|
159
|
-
- PDV (Pitch-Duration-Velocity): Absolute pitch representation
|
|
160
|
-
- Score: Timeline-based multi-track composition structure
|
|
161
|
-
|
|
162
|
-
#### 7. Development & Interaction Layer
|
|
163
|
-
- **repl** - Interactive Read-Eval-Print Loop for live composition
|
|
164
|
-
|
|
165
|
-
## Core Subsystems
|
|
166
|
-
|
|
167
|
-
### MIDI - Voice Management & Recording
|
|
168
|
-
|
|
169
|
-
Polyphonic voice management for MIDI output with automatic note tracking, and MIDI input recording with precise timestamping.
|
|
170
|
-
|
|
171
|
-
**📖 [Complete Documentation](docs/subsystems/midi.md)**
|
|
172
|
-
|
|
173
|
-
### Sequencer - Temporal Engine
|
|
174
|
-
|
|
175
|
-
Event scheduling engine with musical time (bars/beats), precise tick-based timing, and DSL for temporal composition.
|
|
176
|
-
|
|
177
|
-
**📖 [Complete Documentation](docs/subsystems/sequencer.md)**
|
|
178
|
-
|
|
179
|
-
### Transport - Timing & Clocks
|
|
180
|
-
|
|
181
|
-
Comprehensive timing infrastructure connecting clock sources to the sequencer. Supports multiple clock types (TimerClock, InputMidiClock, ExternalTickClock, DummyClock) and manages playback lifecycle with precise timing control.
|
|
182
|
-
|
|
183
|
-
**📖 [Complete Transport Documentation](docs/subsystems/transport.md)**
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
### Series - Sequence Generators
|
|
187
|
-
|
|
188
|
-
Lazy functional sequence generators with map/filter operations, numeric generators, buffering, quantization, and timed merging.
|
|
189
|
-
|
|
190
|
-
**📖 [Complete Documentation](docs/subsystems/series.md)**
|
|
191
|
-
|
|
192
|
-
### Neumas & Neumalang - Musical Notation
|
|
193
|
-
|
|
194
|
-
Compact text-based musical notation system with parser for converting notation to structured musical data.
|
|
195
|
-
|
|
196
|
-
**📖 [Complete Documentation](docs/subsystems/neumas.md)**
|
|
197
|
-
|
|
198
|
-
### Datasets - Sonic Data Structures
|
|
199
|
-
|
|
200
|
-
Type-safe musical event representations (GDV, PDV, PS, P, V) with conversions, validation, Score container, and advanced queries.
|
|
201
|
-
|
|
202
|
-
**📖 [Complete Documentation](docs/subsystems/datasets.md)**
|
|
203
|
-
|
|
204
|
-
### Matrix - Sonic Gesture Conversion
|
|
205
|
-
|
|
206
|
-
Convert matrix representations to point sequences for sequencer playback, treating sonic gestures as geometric objects.
|
|
207
|
-
|
|
208
|
-
**📖 [Complete Documentation](docs/subsystems/matrix.md)**
|
|
209
|
-
|
|
210
|
-
### Transcription - MIDI & MusicXML Output
|
|
211
|
-
|
|
212
|
-
Convert between representations with ornament expansion for MIDI or preservation as notation symbols for MusicXML.
|
|
213
|
-
|
|
214
|
-
**📖 [Complete Documentation](docs/subsystems/transcription.md)**
|
|
215
|
-
|
|
216
|
-
### Music - Scales & Chords
|
|
217
|
-
|
|
218
|
-
Comprehensive scale and chord systems with equal temperament, custom tunings, chord navigation, and extensible definitions.
|
|
219
|
-
|
|
220
|
-
**📖 [Complete Documentation](docs/subsystems/music.md)**
|
|
221
|
-
|
|
222
|
-
### Generative - Algorithmic Composition
|
|
223
|
-
|
|
224
|
-
Algorithmic composition tools: Markov chains, Variatio, Rules (L-systems), GenerativeGrammar, and Darwin (genetic algorithms).
|
|
225
|
-
|
|
226
|
-
**📖 [Complete Documentation](docs/subsystems/generative.md)**
|
|
227
|
-
|
|
228
|
-
### MusicXML Builder - Music Notation Export
|
|
229
|
-
|
|
230
|
-
Comprehensive MusicXML score generation with hierarchical structure, multiple voices, articulations, and dynamics.
|
|
231
|
-
|
|
232
|
-
**📖 [Complete Documentation](docs/subsystems/musicxml-builder.md)**
|
|
233
|
-
|
|
234
|
-
### REPL - Live Coding Infrastructure
|
|
95
|
+
## MusaDSL Architecture
|
|
235
96
|
|
|
236
|
-
|
|
97
|
+
The musa-dsl framework is organized in modular layers. Each component has its own detailed documentation.
|
|
237
98
|
|
|
238
|
-
|
|
99
|
+
### 1. Foundation Layer
|
|
100
|
+
- [**core-ext**](docs/subsystems/core-extensions.md) - Ruby refinements and metaprogramming utilities: Arrayfy, Hashify, ExplodeRanges, DeepCopy, DynamicProxy, AttributeBuilder.
|
|
101
|
+
- **logger** - Structured logging system with severity levels.
|
|
239
102
|
|
|
240
|
-
###
|
|
103
|
+
### 2. Temporal & Scheduling Layer
|
|
104
|
+
- [**sequencer**](docs/subsystems/sequencer.md) - Event scheduling engine with musical time (bars/beats), microsecond-precise tick-based timing, and a DSL for temporal composition. Tick-based (quantized) and tickless (continuous) modes; series playback with automatic duration management; polyrhythms and polytemporal structures.
|
|
105
|
+
- [**transport**](docs/subsystems/transport.md) - Comprehensive timing infrastructure connecting clock sources to the sequencer. Supports multiple clock types (TimerClock, InputMidiClock, ExternalTickClock, DummyClock), BPM management, tempo changes, and the start/stop/pause/continue playback lifecycle.
|
|
241
106
|
|
|
242
|
-
|
|
107
|
+
### 3. Notation & Parsing Layer
|
|
108
|
+
- [**neumas + neumalang**](docs/subsystems/neumas.md) - Compact text-based musical notation system with parser and interpreter for converting notation to structured musical data, with DSL support.
|
|
243
109
|
|
|
244
|
-
|
|
110
|
+
### 4. Generation & Transformation Layer
|
|
111
|
+
- [**series**](docs/subsystems/series.md) - Lazy functional sequence generators with map/filter operations, numeric generators, buffering, quantization, and timed merging. Transpose, repeat, and combination operations; infinite and finite series support.
|
|
112
|
+
- [**generative**](docs/subsystems/generative.md) - Algorithmic composition tools: Markov chains (probabilistic sequence generation), Variatio (Cartesian product parameter variations), GenerativeGrammar (formal grammar-based generation), and Darwin (genetic algorithms for evolutionary composition).
|
|
113
|
+
- [**matrix**](docs/subsystems/matrix.md) - Matrix operations for musical gestures: matrix-to-P (point sequence) conversion for sequencer playback, gesture condensation and transformation. Treats sonic gestures as geometric objects.
|
|
245
114
|
|
|
246
|
-
|
|
115
|
+
### 5. Output & Communication Layer
|
|
116
|
+
- [**transcription**](docs/subsystems/transcription.md) - Musical event transformation system with ornament expansion (trills, mordents, turns), GDV to MIDI/MusicXML conversion, and dynamic articulation rendering. Expansion for MIDI or preservation as notation symbols for MusicXML.
|
|
117
|
+
- [**musicxml**](docs/subsystems/musicxml-builder.md) - MusicXML score generation. Hierarchical structure, multiple voices, multi-part scores, articulations, dynamics, tempo, and notation directives. Standard MusicXML 3.0 output.
|
|
118
|
+
- [**midi**](docs/subsystems/midi.md) - MIDI voice management with polyphonic voice allocation, channel management, note-on/note-off scheduling, automatic note tracking, and MIDI input recording with precise timestamping.
|
|
247
119
|
|
|
248
|
-
|
|
249
|
-
- [
|
|
250
|
-
- [
|
|
251
|
-
- **Pulso** — Stream Deck plugin for MusaLCE Surface controls *(upcoming)*.
|
|
252
|
-
- **VST3 plugins** — collection of audio plugins for mixing and mastering *(upcoming)*.
|
|
120
|
+
### 6. Musical Knowledge Layer
|
|
121
|
+
- [**music**](docs/subsystems/music.md) - Scales, tuning systems, intervals, and chord structures. Equal temperament and just intonation support; modal scales (major, minor, chromatic, etc.); chord definitions, harmonic analysis, and chord navigation.
|
|
122
|
+
- [**datasets**](docs/subsystems/datasets.md) - Type-safe musical event representations: GDV (Grade-Duration-Velocity, scale-relative), PDV (Pitch-Duration-Velocity, absolute), PS, P, V. Conversions, validation, Score container (timeline-based multi-track composition), and advanced queries.
|
|
253
123
|
|
|
254
|
-
|
|
124
|
+
### 7. Development & Interaction Layer
|
|
125
|
+
- [**repl**](docs/subsystems/repl.md) - Interactive Read-Eval-Print Loop for live composition. TCP-based server for real-time code evaluation and error handling. Consumed by external REPL clients (editor extensions, custom evaluators).
|
|
255
126
|
|
|
256
127
|
## Author
|
|
257
128
|
|
data/docs/README.md
CHANGED
|
@@ -5,9 +5,10 @@ Complete documentation for the Musa DSL framework for algorithmic sound and musi
|
|
|
5
5
|
## 📚 Documentation Structure
|
|
6
6
|
|
|
7
7
|
### Getting Started
|
|
8
|
-
- **[Installation](../README.md#
|
|
9
|
-
- **[
|
|
10
|
-
-
|
|
8
|
+
- **[Installation](../README.md#getting-started)** - Set up Musa DSL
|
|
9
|
+
- **[Examples](../README.md#examples)** - Two runnable examples:
|
|
10
|
+
- [Sequencer DSL with interacting voices](examples/sequencer-dsl-voices.md)
|
|
11
|
+
- [Neuma notation](examples/neuma-notation.md)
|
|
11
12
|
|
|
12
13
|
### Core Subsystems
|
|
13
14
|
|
|
@@ -39,8 +40,8 @@ For users extending the DSL or integrating deeply:
|
|
|
39
40
|
## 🎯 Learning Paths
|
|
40
41
|
|
|
41
42
|
### New to Musa DSL?
|
|
42
|
-
1. Start with [
|
|
43
|
-
2. Read [
|
|
43
|
+
1. Start with one of the [Examples](../README.md#examples)
|
|
44
|
+
2. Read [MusaDSL Architecture](../README.md#musadsl-architecture)
|
|
44
45
|
3. Explore subsystems in this order:
|
|
45
46
|
- [MIDI](subsystems/midi.md) - Output basics
|
|
46
47
|
- [Sequencer](subsystems/sequencer.md) - Temporal control
|
data/docs/api-reference.md
CHANGED
|
@@ -82,5 +82,5 @@ yard stats --list-undoc
|
|
|
82
82
|
## See Also
|
|
83
83
|
|
|
84
84
|
- **Conceptual Documentation**: [subsystems/](subsystems/) - Guides and tutorials for each subsystem
|
|
85
|
-
- **
|
|
85
|
+
- **Examples**: [examples/](examples/) - Runnable code examples
|
|
86
86
|
- **Main Documentation**: [README.md](README.md) - Documentation hub
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Neuma notation
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A more detailed example showing the Neuma notation system:
|
|
4
4
|
|
|
5
5
|
```ruby
|
|
6
6
|
require 'musa-dsl'
|
|
@@ -20,7 +20,10 @@ decoder = Decoders::NeumaDecoder.new(
|
|
|
20
20
|
|
|
21
21
|
# Define a melody using neuma notation with duration and velocity
|
|
22
22
|
# Format: (grade duration velocity)
|
|
23
|
-
# Durations
|
|
23
|
+
# Durations are multiples of base_duration, which here is 1r -- a bar. So the
|
|
24
|
+
# numbers below are fractions of a bar: 1/4 of a bar, 1/2 of a bar, a whole
|
|
25
|
+
# bar. In 4/4 those are a quarter, a half and a whole note; in another meter
|
|
26
|
+
# they are not, because a bar and a whole note are only the same in 4/4.
|
|
24
27
|
# Velocities: pp, p, mp, mf, f, ff
|
|
25
28
|
melody = "(0 1/4 p) (+2 1/4 mp) (+2 1/4 mf) (-1 1/2 f) " \
|
|
26
29
|
"(0 1/4 mf) (+4 1/4 mp) (+5 1/2 f) (+7 1/4 ff) " \
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Sequencer DSL with interacting voices
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A complete example showcasing the sequencer DSL with multiple melodic lines that interact with each other:
|
|
4
4
|
|
|
5
5
|
```ruby
|
|
6
6
|
require 'musa-dsl'
|
data/docs/idioms.md
ADDED
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
# Idioms — choosing the MusaDSL form
|
|
2
|
+
|
|
3
|
+
Every entry below names a **reflex**: something a competent programmer writes
|
|
4
|
+
when they have not yet asked what MusaDSL calls it. The reflex always works.
|
|
5
|
+
That is the problem — it produces code that runs, sounds right, passes every
|
|
6
|
+
test, and is foreign to the framework.
|
|
7
|
+
|
|
8
|
+
This document is the answer to one question, asked at the moment of writing:
|
|
9
|
+
|
|
10
|
+
> *What I have to do here — how would it be expressed most beautifully in
|
|
11
|
+
> MusaDSL?*
|
|
12
|
+
|
|
13
|
+
It is organised by **the shape of the data and of the problem**, not by
|
|
14
|
+
subsystem, because the shape is what you can see when you are about to make the
|
|
15
|
+
mistake. The subsystem is what you can only see afterwards.
|
|
16
|
+
|
|
17
|
+
Read it from the symptom.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## The root principle
|
|
22
|
+
|
|
23
|
+
> **The shape of the data decides the idiom.**
|
|
24
|
+
|
|
25
|
+
The generalist reflex is not committed when the loop is written. It is committed
|
|
26
|
+
earlier, when the plan is modelled. Hold absolute positions and a loop of `at`
|
|
27
|
+
is already inevitable; hold durations and `play` is already natural. No guard
|
|
28
|
+
placed later can rescue a plan modelled in the wrong coordinates.
|
|
29
|
+
|
|
30
|
+
Two corollaries used throughout this document:
|
|
31
|
+
|
|
32
|
+
- **Model plans as durations, not as positions.**
|
|
33
|
+
- **Keep the musical layer musical**: grades, proportional durations and
|
|
34
|
+
dynamic marks travel as far as the sink; pitches, seconds and integers appear
|
|
35
|
+
only where the sound is actually produced.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## 1. Events placed in time
|
|
40
|
+
|
|
41
|
+
**Reflex** — precompute absolute positions, then iterate:
|
|
42
|
+
|
|
43
|
+
```ruby
|
|
44
|
+
plan.each_with_index do |(start, duration), i|
|
|
45
|
+
at 1 + start do ... end
|
|
46
|
+
end
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**Idiom** — a serie whose elements carry `duration:` (and, when the sounding
|
|
50
|
+
length differs from the step, `note_duration:` and `forward_duration:`),
|
|
51
|
+
consumed by `play`, which walks time itself:
|
|
52
|
+
|
|
53
|
+
```ruby
|
|
54
|
+
play plan_serie do |duration:, order:, ...|
|
|
55
|
+
...
|
|
56
|
+
end
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
**What is gained** — the plan stays *data*: sliceable (`.cut`, `.max_size`),
|
|
60
|
+
composable (`MERGE`, `H`, `HC`), reusable across voices (`.buffered`). Temporal
|
|
61
|
+
arithmetic disappears from the code. And `play` returns a control, so the ending
|
|
62
|
+
is a handle (`control.after { ... }`) instead of a computed final position.
|
|
63
|
+
|
|
64
|
+
**Detectable** — `at` inside `each`/`times`/`while`, or `at` whose position
|
|
65
|
+
contains a loop variable.
|
|
66
|
+
|
|
67
|
+
**When the reflex is right** — a genuine one-off landmark: the start, a single
|
|
68
|
+
structural mark, the end.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## 2. Sequences of anything
|
|
73
|
+
|
|
74
|
+
**Reflex** — an array, iterated, indexed, or consumed with `.next_value` by
|
|
75
|
+
hand.
|
|
76
|
+
|
|
77
|
+
**Idiom** — `S(...)` and the operations: `.map`, `.select`, `.remove`,
|
|
78
|
+
`.reverse`, `.shift`, `.randomize`, `.repeat`, `.max_size`, `.cut`, `.with`,
|
|
79
|
+
`MERGE`, `H`/`HC`. Numeric contours have constructors of their own: `FOR`,
|
|
80
|
+
`SIN`, `FIBO`, `HARMO`, `RND`.
|
|
81
|
+
|
|
82
|
+
**What is gained** — laziness (infinite generators, no cost until consumed) and
|
|
83
|
+
composition (a complex line is an expression, not a built list). The
|
|
84
|
+
prototype/instance split (`.i`) lets the same definition be read independently
|
|
85
|
+
by several voices; `.buffered` + `.buffer.i` lets them read the *same* progress
|
|
86
|
+
at different speeds, which is what a canon is.
|
|
87
|
+
|
|
88
|
+
**Detectable** — `.i.to_a` followed by Array operations followed by `S(*...)`.
|
|
89
|
+
|
|
90
|
+
**When the reflex is right** — materialising a finite, already-computed plan
|
|
91
|
+
into `S(*plan)` is legitimate: generators feed series. The smell is when every
|
|
92
|
+
intermediate step was expressible as a serie operation.
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## 3. Pitch
|
|
97
|
+
|
|
98
|
+
**Reflex** — arithmetic on MIDI note numbers: `pitch + 7`, `% 12`, a table of
|
|
99
|
+
semitones, an array called `pitches`.
|
|
100
|
+
|
|
101
|
+
**Idiom** — `scale[grade]`, `note.at_octave`, `.sharp` / `.flat`, `chord_on`,
|
|
102
|
+
`chord.with_quality` / `.with_move`, `chord.search_in_scales`,
|
|
103
|
+
`scale.degree_of_chord`.
|
|
104
|
+
|
|
105
|
+
**What is gained** — this is not decoration. A piece written in MIDI integers is
|
|
106
|
+
welded to one tuning and one tonic; written in grades, transposing, modulating
|
|
107
|
+
or re-temperament is *rebinding the scale*. And the material stays navigable:
|
|
108
|
+
you can ask a chord for its degree, a scale for its chords.
|
|
109
|
+
|
|
110
|
+
**Detectable** — literals in the 48–84 range combined with `+`/`-`/`% 12`.
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## 4. Layers: musical intent vs. realization
|
|
115
|
+
|
|
116
|
+
**Reflex** — compute MIDI pitches and durations in seconds where the material is
|
|
117
|
+
defined.
|
|
118
|
+
|
|
119
|
+
**Idiom** — GDV (grade, duration as a multiple of `base_duration`, velocity as a
|
|
120
|
+
dynamic mark) all the way to the edge; `to_pdv(scale)` and the conversion to
|
|
121
|
+
seconds only in the sink.
|
|
122
|
+
|
|
123
|
+
**What is gained** — the same material renders to MIDI, to a synthesis server or
|
|
124
|
+
to MusicXML by changing the sink, not the piece.
|
|
125
|
+
|
|
126
|
+
**Detectable** — `60.0 / bpm`, `* beat` or integer velocities appearing in the
|
|
127
|
+
*material* (constants, series, plans) rather than in the block that finally
|
|
128
|
+
emits sound. Converting inside the emitting call is correct and is not a smell.
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## 5. Recurrences and hand-made state
|
|
133
|
+
|
|
134
|
+
**Reflex** — `a, b = b, a + b`, accumulators inside `loop`, a small class whose
|
|
135
|
+
core is a recurrence.
|
|
136
|
+
|
|
137
|
+
**Idiom** — `FIBO(first, second)`, whose seeds are its first two values, so
|
|
138
|
+
`FIBO(1, 2)` and `FIBO(2, 1)` are relatives of Fibonacci and not delayed echoes
|
|
139
|
+
of it; `E(*seeds) { |last_value:, caller:| ... }` when the recurrence is not
|
|
140
|
+
Fibonacci at all (`caller.parameters` carries the state); `.repeat` for cycles.
|
|
141
|
+
|
|
142
|
+
**What is gained** — the recurrence becomes a serie, so it composes with
|
|
143
|
+
everything else: `.map`, `.select`, feeding `play` directly.
|
|
144
|
+
|
|
145
|
+
**Detectable** — the swap `a, b = b, a + b` is a literal grep.
|
|
146
|
+
|
|
147
|
+
**When the reflex is right** — when the object needs to be *inspected*, not just
|
|
148
|
+
consumed. A serie is a flow: you cannot ask it for its period, its reachable
|
|
149
|
+
states or its cycle. A grid that must answer "when does my state repeat?" is a
|
|
150
|
+
domain object and deserves a class. What is never right is writing the
|
|
151
|
+
recurrence four times instead of extracting it.
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## 6. Randomness
|
|
156
|
+
|
|
157
|
+
**Reflex** — `rand` with a ladder of `if p < 0.3`.
|
|
158
|
+
|
|
159
|
+
**Idiom** — `RND(values, random: Random.new(seed))` — a *shuffle*: each value is
|
|
160
|
+
drawn once and the serie ends. `.repeat` reshuffles on every pass and is what
|
|
161
|
+
gives a die. Constrained with
|
|
162
|
+
`.remove { |value, history| ... }`; Markov when the tendency has memory. Note
|
|
163
|
+
that `Markov` **is a serie** — it can feed `play` directly and be chained with
|
|
164
|
+
`.map`.
|
|
165
|
+
|
|
166
|
+
**What is gained** — reproducibility (an explicit seed makes the piece the same
|
|
167
|
+
piece), tendencies as a *mutable table* (blend two tables to evolve behaviour
|
|
168
|
+
while the chain keeps its state), and constraints declared rather than filtered
|
|
169
|
+
ad hoc.
|
|
170
|
+
|
|
171
|
+
**Detectable** — `rand` not derived from a seeded `Random`; thresholds in a
|
|
172
|
+
chain of `if`.
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## 7. Combinatorics and search
|
|
177
|
+
|
|
178
|
+
**Reflex** — nested loops, `Array#product`, `permutation` followed by filters.
|
|
179
|
+
|
|
180
|
+
**Idiom** — **Variatio** (fields + `constructor`, re-constrained at runtime with
|
|
181
|
+
`.on()`), **GenerativeGrammar** (`|` alternative, `+` sequence, `.repeat`,
|
|
182
|
+
`.limit`), **Darwin** (score candidates by measures and weights, select the
|
|
183
|
+
fittest).
|
|
184
|
+
|
|
185
|
+
**What is gained** — the exploration space becomes an object: re-restrictable,
|
|
186
|
+
filterable, and prunable *during* growth instead of generate-then-filter. The
|
|
187
|
+
constraints are declared where they are conceived.
|
|
188
|
+
|
|
189
|
+
**Detectable** — `product` / `permutation` / `combination`, or three nested
|
|
190
|
+
loops filling an array of candidates.
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## 8. Musical material as text
|
|
195
|
+
|
|
196
|
+
**Reflex** — literal arrays of `{ grade:, duration:, velocity: }`.
|
|
197
|
+
|
|
198
|
+
**Idiom** — neumas: `'(0 1 mf) (+2 1/2 f tr)'.to_neumas`, `|` for polyphony,
|
|
199
|
+
`.neu` files.
|
|
200
|
+
|
|
201
|
+
**What is gained** — material readable *as a score*, relative encoding
|
|
202
|
+
(invariant under transposition), access to ornaments, and the route to MusicXML.
|
|
203
|
+
|
|
204
|
+
**Detectable** — hash literals with those three keys, repeated.
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## 9. Articulation and ornament
|
|
209
|
+
|
|
210
|
+
**Reflex** — schedule a grace note plus the real note; multiply a duration by
|
|
211
|
+
`0.5` for staccato.
|
|
212
|
+
|
|
213
|
+
**Idiom** — a `Transcriptor` with the appropriate transcription set; the
|
|
214
|
+
distinction between `duration`, `note_duration` and `forward_duration`.
|
|
215
|
+
|
|
216
|
+
**What is gained** — articulation as annotation instead of arithmetic, and the
|
|
217
|
+
same GDV rendering expanded MIDI or symbolic MusicXML by changing the set.
|
|
218
|
+
|
|
219
|
+
**Detectable** — `* 0.5` on durations; pairs of notes with a small fixed offset.
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## 10. Parameters that change over time
|
|
224
|
+
|
|
225
|
+
**Reflex** — `every` plus a variable nudged towards a target.
|
|
226
|
+
|
|
227
|
+
**Idiom** — `move from:, to:, duration:, every:, function:` (scalar and hash
|
|
228
|
+
forms); `SIN()` for cyclic contours; `.quantize` for stepped output.
|
|
229
|
+
|
|
230
|
+
**What is gained** — the *shape* (a proc from `[0..1]` to `[0..1]`) is separated
|
|
231
|
+
from the *clock*, so one movement can rise and fall, and the shape can be
|
|
232
|
+
reasoned about, plotted and reused.
|
|
233
|
+
|
|
234
|
+
**Detectable** — `every` whose body mutates a variable towards a target.
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
## 11. Several layers of events in time
|
|
239
|
+
|
|
240
|
+
**Reflex** — arrays of `[time, ...]` sorted and traversed with indices.
|
|
241
|
+
|
|
242
|
+
**Idiom** — AbsTimed series and `TIMED_UNION` (array and hash forms),
|
|
243
|
+
`.flatten_timed`, `.compact_timed`, consumed with `play_timed`, whose block
|
|
244
|
+
receives `time:` and `started_ago:`.
|
|
245
|
+
|
|
246
|
+
**What is gained** — merging layers becomes algebra, with components addressable
|
|
247
|
+
by name.
|
|
248
|
+
|
|
249
|
+
**Detectable** — `sort_by { |e| e[:time] }` followed by pointer traversal.
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
## 12. Macro form
|
|
254
|
+
|
|
255
|
+
**Reflex** — constants chained by addition (`SECTION_2 = SECTION_1 + LENGTH`),
|
|
256
|
+
boolean flags, a counter deciding what happens.
|
|
257
|
+
|
|
258
|
+
**Idiom** — `on` / `launch` for sections; `control.after` for natural
|
|
259
|
+
completion; `control.on_stop` for cleanup; `every` with `duration:`, `till:` or
|
|
260
|
+
`condition:`.
|
|
261
|
+
|
|
262
|
+
**What is gained** — form as a graph of events rather than arithmetic; material
|
|
263
|
+
recalculated at each entry rather than precomputed; and the distinction between
|
|
264
|
+
*finishing* and *being stopped*, which position arithmetic cannot express at
|
|
265
|
+
all. `after` fires only on natural completion — never rely on it for cleanup.
|
|
266
|
+
|
|
267
|
+
**Detectable** — position constants defined in terms of other position
|
|
268
|
+
constants.
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
## 13. Multiparametric gesture
|
|
273
|
+
|
|
274
|
+
**Reflex** — tables of parameters traversed by loops.
|
|
275
|
+
|
|
276
|
+
**Idiom** — `Matrix#to_p(time_dimension:)` → `to_ps_serie` / `to_timed_serie` →
|
|
277
|
+
`play_timed`; `condensed_matrices` for the reduction.
|
|
278
|
+
|
|
279
|
+
**What is gained** — a trajectory drawn in several dimensions at once becomes a
|
|
280
|
+
single object, interpolated and consumed as one gesture.
|
|
281
|
+
|
|
282
|
+
**Detectable** — low. This is territory for *suggestion*, not for lint: the
|
|
283
|
+
user will rarely ask for it by name. When someone describes "a trajectory that
|
|
284
|
+
is drawn", the matrix is the honest answer.
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
## 14. Event lists for querying or export
|
|
289
|
+
|
|
290
|
+
**Reflex** — hand-rolled arrays of events, then hand-rolled queries over them.
|
|
291
|
+
|
|
292
|
+
**Idiom** — `Datasets::Score` (`at`, `between`, `changes_between`, `subset`,
|
|
293
|
+
`values_of`) and the MusicXML builder.
|
|
294
|
+
|
|
295
|
+
**What is gained** — the piece becomes queryable, and exportable, without a
|
|
296
|
+
second representation.
|
|
297
|
+
|
|
298
|
+
---
|
|
299
|
+
|
|
300
|
+
## 15. Clocks
|
|
301
|
+
|
|
302
|
+
**Reflex** — always the real clock, even for tests and offline rendering.
|
|
303
|
+
|
|
304
|
+
**Idiom** — `DummyClock` for tests and fast rendering, `ExternalTickClock` when
|
|
305
|
+
another source owns time, tickless mode when events are not on a grid,
|
|
306
|
+
`change_position_to` to jump.
|
|
307
|
+
|
|
308
|
+
**What is gained** — a piece that can be rendered faster than real time, and
|
|
309
|
+
tested at all.
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
313
|
+
## Using this document
|
|
314
|
+
|
|
315
|
+
For each layer or material of a piece, before writing code, name:
|
|
316
|
+
|
|
317
|
+
1. **the shape of the data** — serie? neumas? generator output? timed serie? a
|
|
318
|
+
class of its own, and if so why the framework does not have it;
|
|
319
|
+
2. **the verb that consumes it** — `play`, `play_timed`, `move`, `every`,
|
|
320
|
+
`on` + `launch`, `at`;
|
|
321
|
+
3. **why not the neighbouring verb**.
|
|
322
|
+
|
|
323
|
+
`at` with a computed position, and a bespoke class, are the two answers that
|
|
324
|
+
always require an explicit justification. Neither is forbidden — sometimes a
|
|
325
|
+
class modelling an inspectable structure *is* the honest answer. What is not
|
|
326
|
+
acceptable is that the choice was never argued against the framework.
|