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.

Files changed (93) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +31 -160
  3. data/docs/README.md +6 -5
  4. data/docs/api-reference.md +1 -1
  5. data/docs/{getting-started/tutorial.md → examples/neuma-notation.md} +6 -3
  6. data/docs/{getting-started/quick-start.md → examples/sequencer-dsl-voices.md} +2 -2
  7. data/docs/idioms.md +326 -0
  8. data/docs/subsystems/generative.md +0 -160
  9. data/docs/subsystems/repl.md +6 -27
  10. data/docs/subsystems/series.md +1 -1
  11. data/lib/musa-dsl/core-ext/attribute-builder.rb +7 -4
  12. data/lib/musa-dsl/core-ext/deep-copy.rb +81 -24
  13. data/lib/musa-dsl/core-ext/dynamic-proxy.rb +4 -4
  14. data/lib/musa-dsl/core-ext/hashify.rb +6 -1
  15. data/lib/musa-dsl/core-ext/inspect-nice.rb +1 -1
  16. data/lib/musa-dsl/core-ext/smart-proc-binder.rb +20 -8
  17. data/lib/musa-dsl/core-ext/with.rb +10 -7
  18. data/lib/musa-dsl/datasets/dataset.rb +6 -5
  19. data/lib/musa-dsl/datasets/delta-d.rb +11 -11
  20. data/lib/musa-dsl/datasets/e.rb +69 -18
  21. data/lib/musa-dsl/datasets/gdv.rb +118 -86
  22. data/lib/musa-dsl/datasets/gdvd.rb +45 -21
  23. data/lib/musa-dsl/datasets/helper.rb +40 -10
  24. data/lib/musa-dsl/datasets/p.rb +16 -11
  25. data/lib/musa-dsl/datasets/pdv.rb +82 -16
  26. data/lib/musa-dsl/datasets/ps.rb +3 -4
  27. data/lib/musa-dsl/datasets/score/queriable.rb +9 -0
  28. data/lib/musa-dsl/datasets/score/to-mxml/process-pdv.rb +287 -263
  29. data/lib/musa-dsl/datasets/score/to-mxml/process-ps.rb +139 -128
  30. data/lib/musa-dsl/datasets/score/to-mxml/process-time.rb +342 -324
  31. data/lib/musa-dsl/datasets/score/to-mxml/to-mxml.rb +61 -10
  32. data/lib/musa-dsl/datasets/score.rb +26 -19
  33. data/lib/musa-dsl/generative/darwin.rb +35 -28
  34. data/lib/musa-dsl/generative/generative-grammar.rb +41 -16
  35. data/lib/musa-dsl/generative/markov.rb +35 -7
  36. data/lib/musa-dsl/generative.rb +0 -1
  37. data/lib/musa-dsl/matrix/matrix.rb +28 -11
  38. data/lib/musa-dsl/midi/midi-recorder.rb +31 -12
  39. data/lib/musa-dsl/midi/midi-voices.rb +139 -19
  40. data/lib/musa-dsl/music/chord-definition.rb +16 -7
  41. data/lib/musa-dsl/music/chords.rb +59 -24
  42. data/lib/musa-dsl/music/scale_systems/equally_tempered_12_tone_scale_system.rb +3 -3
  43. data/lib/musa-dsl/music/scale_systems/twelve_semitones_scale_system.rb +2 -2
  44. data/lib/musa-dsl/music/scales.rb +122 -54
  45. data/lib/musa-dsl/musicxml/builder/attributes.rb +103 -47
  46. data/lib/musa-dsl/musicxml/builder/backup-forward.rb +7 -0
  47. data/lib/musa-dsl/musicxml/builder/direction.rb +26 -19
  48. data/lib/musa-dsl/musicxml/builder/helper.rb +7 -4
  49. data/lib/musa-dsl/musicxml/builder/measure.rb +7 -3
  50. data/lib/musa-dsl/musicxml/builder/part.rb +4 -0
  51. data/lib/musa-dsl/musicxml/builder/pitched-note.rb +1 -0
  52. data/lib/musa-dsl/musicxml/builder/score-partwise.rb +4 -0
  53. data/lib/musa-dsl/musicxml/builder/typed-text.rb +4 -4
  54. data/lib/musa-dsl/neumalang/neumalang.rb +25 -15
  55. data/lib/musa-dsl/neumas/array-to-neumas.rb +17 -17
  56. data/lib/musa-dsl/neumas/neuma-decoder.rb +3 -3
  57. data/lib/musa-dsl/neumas/neuma-gdv-decoder.rb +4 -2
  58. data/lib/musa-dsl/neumas/neuma-gdvd-decoder.rb +19 -14
  59. data/lib/musa-dsl/neumas/neumas.rb +25 -17
  60. data/lib/musa-dsl/neumas/string-to-neumas.rb +25 -18
  61. data/lib/musa-dsl/repl/repl.rb +98 -89
  62. data/lib/musa-dsl/sequencer/base-sequencer-implementation-every.rb +4 -0
  63. data/lib/musa-dsl/sequencer/base-sequencer-implementation-move.rb +4 -0
  64. data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-helper.rb +55 -34
  65. data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-timed.rb +8 -1
  66. data/lib/musa-dsl/sequencer/base-sequencer-implementation-play.rb +65 -9
  67. data/lib/musa-dsl/sequencer/base-sequencer-implementation.rb +39 -7
  68. data/lib/musa-dsl/sequencer/base-sequencer-tick-based.rb +31 -13
  69. data/lib/musa-dsl/sequencer/base-sequencer-tickless-based.rb +76 -21
  70. data/lib/musa-dsl/sequencer/base-sequencer.rb +47 -21
  71. data/lib/musa-dsl/series/base-series.rb +91 -13
  72. data/lib/musa-dsl/series/main-serie-constructors.rb +170 -47
  73. data/lib/musa-dsl/series/main-serie-operations.rb +36 -13
  74. data/lib/musa-dsl/series/proxy-serie.rb +156 -12
  75. data/lib/musa-dsl/series/quantizer-serie.rb +6 -3
  76. data/lib/musa-dsl/series/queue-serie.rb +33 -8
  77. data/lib/musa-dsl/series/series-composer.rb +94 -40
  78. data/lib/musa-dsl/series/timed-serie.rb +1 -1
  79. data/lib/musa-dsl/transcription/from-gdv-to-midi.rb +82 -9
  80. data/lib/musa-dsl/transcription/from-gdv.rb +1 -1
  81. data/lib/musa-dsl/transcription/transcription.rb +19 -10
  82. data/lib/musa-dsl/transport/clock.rb +8 -3
  83. data/lib/musa-dsl/transport/dummy-clock.rb +6 -3
  84. data/lib/musa-dsl/transport/external-tick-clock.rb +9 -7
  85. data/lib/musa-dsl/transport/input-midi-clock.rb +3 -2
  86. data/lib/musa-dsl/transport/timer-clock.rb +3 -3
  87. data/lib/musa-dsl/transport/timer.rb +6 -4
  88. data/lib/musa-dsl/transport/transport.rb +26 -14
  89. data/lib/musa-dsl/version.rb +1 -1
  90. data/lib/musa-dsl.rb +9 -6
  91. data/tools/doc-examples.rb +499 -0
  92. metadata +5 -4
  93. data/lib/musa-dsl/generative/rules.rb +0 -590
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d4255273d1d071bd791ad11b5da8cd3e452442c2ec5bc78aed0f594968589a79
4
- data.tar.gz: 8814fbd0fa803dd30f1aaad76a0b4843f008065db1533bef87872fccf1cf8e9c
3
+ metadata.gz: f8a1f6bc6c231c4b43a8ad4dcfe5db56a0da9de25de6392cc077dba95dc41648
4
+ data.tar.gz: a725d6365bcb16d52dd86de6c6d64d56f72e4eab197d8129fdfd1125570a9212
5
5
  SHA512:
6
- metadata.gz: 61b3eb793d334844822636e2d8597c86dee2f353170d215328bf6dfc1be4aa24fdbe96c830584de377d99472d2259ef75a804f3c564fa5785f2430a14c1805a2
7
- data.tar.gz: 7616c2dd4e24bf46714a64d48690d81989fa8ed41d99972f7c0aa2164607c8e72bf7fcd57b20963eed38d56420e889cd3421135d79df11d35464f2b2b1637005
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), rule-based production systems (Rules), formal grammars (GenerativeGrammar), and genetic algorithms (Darwin)
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
- ## Quick Start
61
+ ## Examples
62
62
 
63
- A complete working example with multiple interacting voice lines, demonstrating sequencer DSL, timing control, and shared state.
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
- **📖 [Complete Quick Start Guide](docs/getting-started/quick-start.md)**
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, Rules, Matrix
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
- ## System Architecture
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
- ### musa-dsl Internal Architecture
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
- TCP-based server for live coding real-time code evaluation and error handling. Consumed by external REPL clients (editor extensions, custom evaluators).
97
+ The musa-dsl framework is organized in modular layers. Each component has its own detailed documentation.
237
98
 
238
- **📖 [Complete Documentation](docs/subsystems/repl.md)**
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
- ### Core Extensions - Advanced Metaprogramming
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
- Ruby refinements and metaprogramming utilities: Arrayfy, Hashify, ExplodeRanges, DeepCopy, DynamicProxy, AttributeBuilder, Logger.
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
- **📖 [Complete Documentation](docs/subsystems/core-extensions.md)**
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
- ## More from the MusaDSL ecosystem
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
- - [MusaDSL](https://musadsl.yeste.studio) Ruby framework for algorithmic sound and musical composition.
249
- - [MusaLCE](https://musalce.yeste.studio) live coding environment for Ableton Live and Bitwig Studio.
250
- - [Nota](https://nota.yeste.studio) Claude Code plugin for AI-assisted MusaDSL composition.
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
- For the full map descriptions, how they relate, which one to pick for what — see [musa-ecosystem.yeste.studio](https://musa-ecosystem.yeste.studio).
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#installation)** - Set up Musa DSL
9
- - **[Quick Start](../README.md#quick-start)** - 5-minute introduction
10
- - **[Not So Quick Start](../README.md#not-so-quick-start)** - Comprehensive tutorial
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 [Quick Start](../README.md#quick-start)
43
- 2. Read [System Architecture](../README.md#system-architecture)
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
@@ -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
- - **Getting Started**: [getting-started/](getting-started/) - Quick start and tutorials
85
+ - **Examples**: [examples/](examples/) - Runnable code examples
86
86
  - **Main Documentation**: [README.md](README.md) - Documentation hub
@@ -1,6 +1,6 @@
1
- # Tutorial: Not So Quick Start
1
+ # Neuma notation
2
2
 
3
- Here's a more detailed example showing the Neuma notation system:
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: 1/4 = quarter, 1/2 = half, 1 = whole
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
- # Quick Start
1
+ # Sequencer DSL with interacting voices
2
2
 
3
- Here's a complete example showcasing the sequencer DSL with multiple melodic lines that interact with each other:
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.