musa-dsl 0.30.2 → 0.41.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (158) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +5 -1
  3. data/.version +6 -0
  4. data/.yardopts +7 -0
  5. data/Gemfile +0 -1
  6. data/README.md +227 -6
  7. data/docs/README.md +83 -0
  8. data/docs/api-reference.md +86 -0
  9. data/docs/getting-started/quick-start.md +93 -0
  10. data/docs/getting-started/tutorial.md +58 -0
  11. data/docs/subsystems/core-extensions.md +316 -0
  12. data/docs/subsystems/datasets.md +465 -0
  13. data/docs/subsystems/generative.md +290 -0
  14. data/docs/subsystems/matrix.md +63 -0
  15. data/docs/subsystems/midi.md +123 -0
  16. data/docs/subsystems/music.md +544 -0
  17. data/docs/subsystems/musicxml-builder.md +264 -0
  18. data/docs/subsystems/neumas.md +71 -0
  19. data/docs/subsystems/repl.md +135 -0
  20. data/docs/subsystems/sequencer.md +98 -0
  21. data/docs/subsystems/series.md +302 -0
  22. data/docs/subsystems/transcription.md +152 -0
  23. data/docs/subsystems/transport.md +177 -0
  24. data/lib/musa-dsl/core-ext/array-explode-ranges.rb +68 -0
  25. data/lib/musa-dsl/core-ext/arrayfy.rb +110 -0
  26. data/lib/musa-dsl/core-ext/attribute-builder.rb +91 -30
  27. data/lib/musa-dsl/core-ext/deep-copy.rb +125 -2
  28. data/lib/musa-dsl/core-ext/dynamic-proxy.rb +78 -0
  29. data/lib/musa-dsl/core-ext/extension.rb +53 -0
  30. data/lib/musa-dsl/core-ext/hashify.rb +162 -1
  31. data/lib/musa-dsl/core-ext/inspect-nice.rb +154 -0
  32. data/lib/musa-dsl/core-ext/smart-proc-binder.rb +117 -0
  33. data/lib/musa-dsl/core-ext/with.rb +114 -0
  34. data/lib/musa-dsl/datasets/dataset.rb +109 -0
  35. data/lib/musa-dsl/datasets/delta-d.rb +78 -0
  36. data/lib/musa-dsl/datasets/e.rb +186 -2
  37. data/lib/musa-dsl/datasets/gdv.rb +279 -2
  38. data/lib/musa-dsl/datasets/gdvd.rb +201 -0
  39. data/lib/musa-dsl/datasets/helper.rb +75 -0
  40. data/lib/musa-dsl/datasets/p.rb +177 -2
  41. data/lib/musa-dsl/datasets/packed-v.rb +91 -0
  42. data/lib/musa-dsl/datasets/pdv.rb +136 -1
  43. data/lib/musa-dsl/datasets/ps.rb +134 -4
  44. data/lib/musa-dsl/datasets/score/queriable.rb +143 -1
  45. data/lib/musa-dsl/datasets/score/render.rb +105 -1
  46. data/lib/musa-dsl/datasets/score/to-mxml/process-pdv.rb +138 -1
  47. data/lib/musa-dsl/datasets/score/to-mxml/process-ps.rb +111 -0
  48. data/lib/musa-dsl/datasets/score/to-mxml/process-time.rb +200 -1
  49. data/lib/musa-dsl/datasets/score/to-mxml/to-mxml.rb +145 -1
  50. data/lib/musa-dsl/datasets/score.rb +279 -0
  51. data/lib/musa-dsl/datasets/v.rb +88 -0
  52. data/lib/musa-dsl/generative/darwin.rb +215 -1
  53. data/lib/musa-dsl/generative/generative-grammar.rb +387 -0
  54. data/lib/musa-dsl/generative/markov.rb +135 -3
  55. data/lib/musa-dsl/generative/rules.rb +312 -4
  56. data/lib/musa-dsl/generative/variatio.rb +286 -2
  57. data/lib/musa-dsl/logger/logger.rb +267 -2
  58. data/lib/musa-dsl/matrix/matrix.rb +256 -10
  59. data/lib/musa-dsl/midi/midi-recorder.rb +113 -2
  60. data/lib/musa-dsl/midi/midi-voices.rb +275 -4
  61. data/lib/musa-dsl/music/chord-definition.rb +233 -1
  62. data/lib/musa-dsl/music/chord-definitions.rb +33 -6
  63. data/lib/musa-dsl/music/chords.rb +353 -2
  64. data/lib/musa-dsl/music/equally-tempered-12-tone-scale-system.rb +70 -206
  65. data/lib/musa-dsl/music/scale_kinds/bebop/bebop_dominant_scale_kind.rb +110 -0
  66. data/lib/musa-dsl/music/scale_kinds/bebop/bebop_major_scale_kind.rb +110 -0
  67. data/lib/musa-dsl/music/scale_kinds/bebop/bebop_minor_scale_kind.rb +110 -0
  68. data/lib/musa-dsl/music/scale_kinds/blues/blues_major_scale_kind.rb +100 -0
  69. data/lib/musa-dsl/music/scale_kinds/blues/blues_scale_kind.rb +99 -0
  70. data/lib/musa-dsl/music/scale_kinds/chromatic_scale_kind.rb +79 -0
  71. data/lib/musa-dsl/music/scale_kinds/ethnic/double_harmonic_scale_kind.rb +102 -0
  72. data/lib/musa-dsl/music/scale_kinds/ethnic/hungarian_minor_scale_kind.rb +102 -0
  73. data/lib/musa-dsl/music/scale_kinds/ethnic/neapolitan_major_scale_kind.rb +102 -0
  74. data/lib/musa-dsl/music/scale_kinds/ethnic/neapolitan_minor_scale_kind.rb +101 -0
  75. data/lib/musa-dsl/music/scale_kinds/ethnic/phrygian_dominant_scale_kind.rb +103 -0
  76. data/lib/musa-dsl/music/scale_kinds/harmonic_major/harmonic_major_scale_kind.rb +104 -0
  77. data/lib/musa-dsl/music/scale_kinds/major_scale_kind.rb +110 -0
  78. data/lib/musa-dsl/music/scale_kinds/melodic_minor/altered_scale_kind.rb +106 -0
  79. data/lib/musa-dsl/music/scale_kinds/melodic_minor/dorian_b2_scale_kind.rb +104 -0
  80. data/lib/musa-dsl/music/scale_kinds/melodic_minor/locrian_sharp2_scale_kind.rb +103 -0
  81. data/lib/musa-dsl/music/scale_kinds/melodic_minor/lydian_augmented_scale_kind.rb +103 -0
  82. data/lib/musa-dsl/music/scale_kinds/melodic_minor/lydian_dominant_scale_kind.rb +106 -0
  83. data/lib/musa-dsl/music/scale_kinds/melodic_minor/melodic_minor_scale_kind.rb +104 -0
  84. data/lib/musa-dsl/music/scale_kinds/melodic_minor/mixolydian_b6_scale_kind.rb +103 -0
  85. data/lib/musa-dsl/music/scale_kinds/minor_harmonic_scale_kind.rb +125 -0
  86. data/lib/musa-dsl/music/scale_kinds/minor_natural_scale_kind.rb +123 -0
  87. data/lib/musa-dsl/music/scale_kinds/modes/dorian_scale_kind.rb +111 -0
  88. data/lib/musa-dsl/music/scale_kinds/modes/locrian_scale_kind.rb +114 -0
  89. data/lib/musa-dsl/music/scale_kinds/modes/lydian_scale_kind.rb +111 -0
  90. data/lib/musa-dsl/music/scale_kinds/modes/mixolydian_scale_kind.rb +111 -0
  91. data/lib/musa-dsl/music/scale_kinds/modes/phrygian_scale_kind.rb +111 -0
  92. data/lib/musa-dsl/music/scale_kinds/pentatonic/pentatonic_major_scale_kind.rb +93 -0
  93. data/lib/musa-dsl/music/scale_kinds/pentatonic/pentatonic_minor_scale_kind.rb +99 -0
  94. data/lib/musa-dsl/music/scale_kinds/symmetric/diminished_hw_scale_kind.rb +110 -0
  95. data/lib/musa-dsl/music/scale_kinds/symmetric/diminished_wh_scale_kind.rb +110 -0
  96. data/lib/musa-dsl/music/scale_kinds/symmetric/whole_tone_scale_kind.rb +99 -0
  97. data/lib/musa-dsl/music/scale_systems/equally_tempered_12_tone_scale_system.rb +80 -0
  98. data/lib/musa-dsl/music/scale_systems/twelve_semitones_scale_system.rb +60 -0
  99. data/lib/musa-dsl/music/scales.rb +1384 -40
  100. data/lib/musa-dsl/musicxml/builder/attributes.rb +483 -3
  101. data/lib/musa-dsl/musicxml/builder/backup-forward.rb +166 -1
  102. data/lib/musa-dsl/musicxml/builder/direction.rb +243 -0
  103. data/lib/musa-dsl/musicxml/builder/helper.rb +240 -0
  104. data/lib/musa-dsl/musicxml/builder/measure.rb +284 -0
  105. data/lib/musa-dsl/musicxml/builder/note-complexities.rb +324 -8
  106. data/lib/musa-dsl/musicxml/builder/note.rb +285 -0
  107. data/lib/musa-dsl/musicxml/builder/part-group.rb +108 -1
  108. data/lib/musa-dsl/musicxml/builder/part.rb +139 -0
  109. data/lib/musa-dsl/musicxml/builder/pitched-note.rb +124 -0
  110. data/lib/musa-dsl/musicxml/builder/rest.rb +93 -0
  111. data/lib/musa-dsl/musicxml/builder/score-partwise.rb +276 -0
  112. data/lib/musa-dsl/musicxml/builder/typed-text.rb +62 -1
  113. data/lib/musa-dsl/musicxml/builder/unpitched-note.rb +83 -0
  114. data/lib/musa-dsl/neumalang/neumalang.rb +675 -0
  115. data/lib/musa-dsl/neumas/array-to-neumas.rb +149 -0
  116. data/lib/musa-dsl/neumas/neuma-decoder.rb +253 -0
  117. data/lib/musa-dsl/neumas/neuma-gdv-decoder.rb +142 -2
  118. data/lib/musa-dsl/neumas/neuma-gdvd-decoder.rb +82 -0
  119. data/lib/musa-dsl/neumas/neumas.rb +67 -0
  120. data/lib/musa-dsl/neumas/string-to-neumas.rb +233 -1
  121. data/lib/musa-dsl/repl/repl.rb +550 -0
  122. data/lib/musa-dsl/sequencer/base-sequencer-implementation-every.rb +118 -2
  123. data/lib/musa-dsl/sequencer/base-sequencer-implementation-move.rb +149 -2
  124. data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-helper.rb +296 -0
  125. data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-timed.rb +88 -2
  126. data/lib/musa-dsl/sequencer/base-sequencer-implementation-play.rb +161 -0
  127. data/lib/musa-dsl/sequencer/base-sequencer-implementation.rb +263 -0
  128. data/lib/musa-dsl/sequencer/base-sequencer-tick-based.rb +173 -1
  129. data/lib/musa-dsl/sequencer/base-sequencer-tickless-based.rb +177 -0
  130. data/lib/musa-dsl/sequencer/base-sequencer.rb +710 -10
  131. data/lib/musa-dsl/sequencer/sequencer-dsl.rb +210 -0
  132. data/lib/musa-dsl/sequencer/timeslots.rb +79 -0
  133. data/lib/musa-dsl/series/array-to-serie.rb +37 -1
  134. data/lib/musa-dsl/series/base-series.rb +843 -5
  135. data/lib/musa-dsl/series/buffer-serie.rb +54 -0
  136. data/lib/musa-dsl/series/hash-or-array-serie-splitter.rb +64 -0
  137. data/lib/musa-dsl/series/main-serie-constructors.rb +398 -2
  138. data/lib/musa-dsl/series/main-serie-operations.rb +538 -16
  139. data/lib/musa-dsl/series/proxy-serie.rb +67 -0
  140. data/lib/musa-dsl/series/quantizer-serie.rb +57 -7
  141. data/lib/musa-dsl/series/queue-serie.rb +78 -0
  142. data/lib/musa-dsl/series/series-composer.rb +701 -0
  143. data/lib/musa-dsl/series/timed-serie.rb +473 -28
  144. data/lib/musa-dsl/transcription/from-gdv-to-midi.rb +404 -1
  145. data/lib/musa-dsl/transcription/from-gdv-to-musicxml.rb +118 -0
  146. data/lib/musa-dsl/transcription/from-gdv.rb +84 -1
  147. data/lib/musa-dsl/transcription/transcription.rb +265 -0
  148. data/lib/musa-dsl/transport/clock.rb +125 -0
  149. data/lib/musa-dsl/transport/dummy-clock.rb +89 -2
  150. data/lib/musa-dsl/transport/external-tick-clock.rb +91 -0
  151. data/lib/musa-dsl/transport/input-midi-clock.rb +133 -1
  152. data/lib/musa-dsl/transport/timer-clock.rb +183 -1
  153. data/lib/musa-dsl/transport/timer.rb +83 -0
  154. data/lib/musa-dsl/transport/transport.rb +318 -0
  155. data/lib/musa-dsl/version.rb +2 -1
  156. data/lib/musa-dsl.rb +132 -25
  157. data/musa-dsl.gemspec +25 -18
  158. metadata +158 -16
@@ -0,0 +1,264 @@
1
+ # MusicXML Builder - Music Notation Export
2
+
3
+ Comprehensive builder for generating MusicXML 3.0 files compatible with music notation software (Finale, Sibelius, MuseScore, Dorico, etc.). MusicXML is the standard open format for exchanging digital sheet music between applications.
4
+
5
+ ## Root Class: ScorePartwise
6
+
7
+ The entry point for creating MusicXML documents is `Musa::MusicXML::Builder::ScorePartwise`, which represents the `<score-partwise>` root element. It organizes music by parts (instruments/voices) and measures.
8
+
9
+ **Structure:**
10
+ - **Metadata**: work info, movement info, creators, rights, encoding date
11
+ - **Part List**: part definitions with names and abbreviations
12
+ - **Parts**: musical content organized by measures
13
+
14
+ ## Key Features
15
+
16
+ **Multiple staves:**
17
+ Use `staff:` parameter to specify which staff (1, 2, etc.) for grand staff notation (piano, harp, organ, etc.).
18
+ ```ruby
19
+ pitch 'C', octave: 3, staff: 2 # Note in staff 2 (bass clef)
20
+ ```
21
+
22
+ **Multiple voices:**
23
+ Use `voice:` parameter for polyphonic notation within a single staff (independent melodic lines).
24
+ ```ruby
25
+ pitch 'C', octave: 4, voice: 1 # Voice 1
26
+ pitch 'E', octave: 3, voice: 2 # Voice 2 (simultaneous)
27
+ ```
28
+
29
+ **Backup/Forward:**
30
+ Navigate timeline within measures to layer voices. `backup(duration)` returns to an earlier point, `forward(duration)` skips ahead.
31
+ ```ruby
32
+ pitch 'C', octave: 4, duration: 4
33
+ backup 4 # Return to beginning
34
+ pitch 'E', octave: 3, duration: 4 # Play simultaneously
35
+ ```
36
+
37
+ **Divisions:**
38
+ Set rhythmic precision as divisions per quarter note in measure attributes. Higher values allow smaller note values.
39
+ ```ruby
40
+ attributes do
41
+ divisions 4 # 4 divisions per quarter (allows 16th notes)
42
+ end
43
+ ```
44
+
45
+ **Alterations:**
46
+ Use `alter:` parameter for accidentals: `-1` for flat, `1` for sharp, `2` for double sharp, etc.
47
+ ```ruby
48
+ pitch 'F', octave: 4, alter: 1 # F# (sharp)
49
+ pitch 'B', octave: 4, alter: -1 # Bb (flat)
50
+ ```
51
+
52
+ **Articulations:**
53
+ Add slurs, dots, and other articulations via parameters.
54
+ ```ruby
55
+ pitch 'C', octave: 4, slur: 'start' # Begin slur
56
+ pitch 'D', octave: 4, slur: 'stop' # End slur
57
+ pitch 'E', octave: 4, dots: 1 # Dotted note
58
+ ```
59
+
60
+ **Dynamics:**
61
+ Add dynamic markings using `direction` blocks with `dynamics` method. Supported: `pp`, `p`, `mp`, `mf`, `f`, `ff`, `fff`, etc.
62
+ ```ruby
63
+ direction do
64
+ dynamics 'f' # Forte
65
+ end
66
+ ```
67
+
68
+ **Wedges:**
69
+ Add crescendo/diminuendo markings with `wedge` in direction blocks.
70
+ ```ruby
71
+ direction do
72
+ wedge 'crescendo' # Start crescendo
73
+ end
74
+ # ... notes ...
75
+ direction wedge: 'stop' # End crescendo
76
+ ```
77
+
78
+ **Metronome:**
79
+ Add tempo markings with `metronome` in measures.
80
+ ```ruby
81
+ metronome beat_unit: 'quarter', per_minute: 120
82
+ ```
83
+
84
+ **Rests:**
85
+ Use `rest` method instead of `pitch` for rest notation.
86
+ ```ruby
87
+ rest duration: 2, type: 'quarter'
88
+ ```
89
+
90
+ ## Two Usage Modes
91
+
92
+ **Constructor Style (Method Calls):**
93
+
94
+ Use constructor parameters and `add_*` methods for programmatic building:
95
+
96
+ ```ruby
97
+ require 'musa-dsl'
98
+
99
+ # Create score with metadata
100
+ score = Musa::MusicXML::Builder::ScorePartwise.new(
101
+ work_title: "Piano Piece",
102
+ creators: { composer: "Your Name" },
103
+ encoding_date: DateTime.new(2024, 1, 1)
104
+ )
105
+
106
+ # Add parts using add_* methods
107
+ part = score.add_part(:p1, name: "Piano", abbreviation: "Pno.")
108
+
109
+ # Add measures and attributes
110
+ measure = part.add_measure(divisions: 4)
111
+
112
+ # Add attributes (key, time, clef, etc.)
113
+ measure.attributes.last.add_key(1, fifths: 0) # C major
114
+ measure.attributes.last.add_time(1, beats: 4, beat_type: 4)
115
+ measure.attributes.last.add_clef(1, sign: 'G', line: 2)
116
+
117
+ # Add notes
118
+ measure.add_pitch(step: 'C', octave: 4, duration: 4, type: 'quarter')
119
+ measure.add_pitch(step: 'E', octave: 4, duration: 4, type: 'quarter')
120
+ measure.add_pitch(step: 'G', octave: 4, duration: 4, type: 'quarter')
121
+ measure.add_pitch(step: 'C', octave: 5, duration: 4, type: 'quarter')
122
+
123
+ # Export to file
124
+ File.write("score.musicxml", score.to_xml.string)
125
+ ```
126
+
127
+ **DSL Style (Blocks):**
128
+
129
+ Use blocks with method names as setters/builders for more readable, declarative code:
130
+
131
+ ```ruby
132
+ require 'musa-dsl'
133
+
134
+ score = Musa::MusicXML::Builder::ScorePartwise.new do
135
+ work_title "Piano Piece"
136
+ creators composer: "Your Name"
137
+ encoding_date DateTime.new(2024, 1, 1)
138
+
139
+ part :p1, name: "Piano", abbreviation: "Pno." do
140
+ measure do
141
+ attributes do
142
+ divisions 4
143
+ key 1, fifths: 0 # C major
144
+ time 1, beats: 4, beat_type: 4
145
+ clef 1, sign: 'G', line: 2
146
+ end
147
+
148
+ pitch 'C', octave: 4, duration: 4, type: 'quarter'
149
+ pitch 'E', octave: 4, duration: 4, type: 'quarter'
150
+ pitch 'G', octave: 4, duration: 4, type: 'quarter'
151
+ pitch 'C', octave: 5, duration: 4, type: 'quarter'
152
+ end
153
+ end
154
+ end
155
+
156
+ File.write("score.musicxml", score.to_xml.string)
157
+ ```
158
+
159
+ **Sophisticated Example - Piano Score with Multiple Features:**
160
+
161
+ ```ruby
162
+ require 'musa-dsl'
163
+
164
+ score = Musa::MusicXML::Builder::ScorePartwise.new do
165
+ work_title "Étude in D Major"
166
+ work_number 1
167
+ creators composer: "Example Composer"
168
+ encoding_date DateTime.now
169
+
170
+ part :p1, name: "Piano" do
171
+ # Measure 1 - Setup and opening with two staves
172
+ measure do
173
+ attributes do
174
+ divisions 2 # 2 divisions per quarter note
175
+
176
+ # Treble clef (staff 1)
177
+ key 1, fifths: 2 # D major (2 sharps)
178
+ clef 1, sign: 'G', line: 2
179
+ time 1, beats: 4, beat_type: 4
180
+
181
+ # Bass clef (staff 2)
182
+ key 2, fifths: 2
183
+ clef 2, sign: 'F', line: 4
184
+ time 2, beats: 4, beat_type: 4
185
+ end
186
+
187
+ # Tempo marking
188
+ metronome beat_unit: 'quarter', per_minute: 120
189
+
190
+ # Right hand melody (staff 1)
191
+ pitch 'D', octave: 4, duration: 4, type: 'half', slur: 'start'
192
+ pitch 'E', octave: 4, duration: 4, type: 'half', slur: 'stop'
193
+
194
+ # Return to beginning for left hand (staff 2)
195
+ backup 8
196
+
197
+ # Left hand accompaniment (staff 2)
198
+ pitch 'D', octave: 3, duration: 8, type: 'whole', staff: 2
199
+ end
200
+
201
+ # Measure 2 - Two voices in treble clef
202
+ measure do
203
+ # Voice 1
204
+ pitch 'F#', octave: 4, duration: 2, type: 'quarter', alter: 1, voice: 1
205
+ pitch 'G', octave: 4, duration: 2, type: 'quarter', voice: 1
206
+ pitch 'A', octave: 4, duration: 2, type: 'quarter', voice: 1
207
+ pitch 'B', octave: 4, duration: 2, type: 'quarter', voice: 1
208
+
209
+ # Return to beginning for voice 2
210
+ backup 8
211
+
212
+ # Voice 2 (inner voice)
213
+ pitch 'A', octave: 3, duration: 3, type: 'quarter', dots: 1, voice: 2
214
+ pitch 'B', octave: 3, duration: 1, type: 'eighth', voice: 2
215
+ pitch 'C#', octave: 4, duration: 3, type: 'quarter', dots: 1, alter: 1, voice: 2
216
+ pitch 'D', octave: 4, duration: 1, type: 'eighth', voice: 2
217
+
218
+ # Return for left hand
219
+ backup 8
220
+
221
+ # Left hand (staff 2)
222
+ pitch 'A', octave: 2, duration: 8, type: 'whole', staff: 2
223
+ end
224
+
225
+ # Measure 3 - Dynamics and articulations
226
+ measure do
227
+ # Dynamic marking
228
+ direction do
229
+ dynamics 'pp'
230
+ wedge 'crescendo'
231
+ end
232
+
233
+ # Notes with crescendo
234
+ pitch 'C#', octave: 5, duration: 1, type: 'eighth', alter: 1
235
+ pitch 'D', octave: 5, duration: 1, type: 'eighth'
236
+ pitch 'E', octave: 5, duration: 1, type: 'eighth'
237
+ pitch 'F#', octave: 5, duration: 1, type: 'eighth', alter: 1
238
+
239
+ pitch 'G', octave: 5, duration: 1, type: 'eighth'
240
+ pitch 'A', octave: 5, duration: 1, type: 'eighth'
241
+ pitch 'B', octave: 5, duration: 1, type: 'eighth'
242
+ pitch 'C#', octave: 6, duration: 1, type: 'eighth', alter: 1
243
+
244
+ # End of crescendo, forte
245
+ direction wedge: 'stop', dynamics: 'f'
246
+ end
247
+ end
248
+ end
249
+
250
+ # Export to file
251
+ File.write("etude.musicxml", score.to_xml.string)
252
+
253
+ # Or write directly to IO
254
+ File.open("etude.musicxml", 'w') { |f| score.to_xml(f) }
255
+ ```
256
+
257
+ ## API Reference
258
+
259
+ **Complete API documentation:**
260
+ - [Musa::MusicXML::Builder](https://rubydoc.info/gems/musa-dsl/Musa/MusicXML/Builder) - MusicXML score generation
261
+
262
+ **Source code:** `lib/musicxml/builder/`
263
+
264
+
@@ -0,0 +1,71 @@
1
+ # Neumas & Neumalang - Musical Notation
2
+
3
+ Neumas provide a compact text-based notation system for musical composition. Neumalang is the parser that converts this notation to structured musical data.
4
+
5
+ ```ruby
6
+ require 'musa-dsl'
7
+ require 'midi-communications'
8
+
9
+ # To play the song, decode neumas to GDV and convert to PDV
10
+ include Musa::All
11
+
12
+ using Musa::Extension::Neumas
13
+
14
+ # Neuma notation requires parentheses around each neuma element
15
+ # Parsed using Musa::Neumalang::Neumalang.parse()
16
+
17
+ # Complete example with durations and dynamics (parallel voices using |)
18
+ song = "(0 1 mf) (+2 1 mp) (+4 2 p) (+5 1/2 mf) (+7 1 f)" | # Voice 1: melody with varied dynamics
19
+ "(+7 2 p) (+5 1 mp) (+7 1 mf) (+9 1/2 f) (+12 2 ff)" # Voice 2: harmony with crescendo
20
+
21
+ # Wrap parallel structure in serie
22
+ song_serie = S(song)
23
+
24
+ # Create decoder with a scale
25
+ scale = Scales.et12[440.0].major[60]
26
+ decoder = Decoders::NeumaDecoder.new(scale, base_duration: 1r)
27
+
28
+ # Setup sequencer with clock and transport
29
+ output = MIDICommunications::Output.gets
30
+
31
+ clock = TimerClock.new(bpm: 120, ticks_per_beat: 24)
32
+ transport = Transport.new(clock, 4, 24)
33
+
34
+ voices = MIDIVoices.new(sequencer: transport.sequencer, output: output, channels: [0, 1])
35
+
36
+ # Play both voices simultaneously - sequencer handles parallel structure automatically
37
+ transport.sequencer.with do
38
+ at 1 do
39
+ play song_serie, decoder: decoder, mode: :neumalang do |gdv|
40
+ # Convert GDV to PDV for MIDI output
41
+ pdv = gdv.to_pdv(scale)
42
+
43
+ # Use voice based on channel assignment (sequencer maintains voice separation)
44
+ voice_index = gdv[:channel] || 0
45
+ voices.voices[voice_index].note pitch: pdv[:pitch],
46
+ velocity: pdv[:velocity],
47
+ duration: pdv[:duration]
48
+ end
49
+ end
50
+ end
51
+
52
+ transport.start
53
+ ```
54
+
55
+ **Notation syntax:**
56
+ - `(0)`, `(+2)`, `(-1)` - Absolute/relative pitch steps (in parentheses)
57
+ - `o0`, `o1`, `o-1` - Octave specification
58
+ - `1`, `2`, `1/2`, `1/4` - Duration (whole, double, half, quarter)
59
+ - `ppp`, `pp`, `p`, `mp`, `mf`, `f`, `ff`, `fff` - Dynamics (velocity)
60
+ - `+f`, `+ff`, `-p`, `-pp` - Relative dynamics (louder/softer)
61
+ - `|` operator - Parallel voices (polyphonic structure)
62
+
63
+ ## API Reference
64
+
65
+ **Complete API documentation:**
66
+ - [Musa::Neumas](https://rubydoc.info/gems/musa-dsl/Musa/Neumas) - Musical notation data structures
67
+ - [Musa::Neumalang](https://rubydoc.info/gems/musa-dsl/Musa/Neumalang) - Notation parser and interpreter
68
+
69
+ **Source code:** `lib/neumas/` and `lib/neumalang/`
70
+
71
+
@@ -0,0 +1,135 @@
1
+ # REPL - Live Coding Infrastructure
2
+
3
+ The REPL (Read-Eval-Print Loop) provides a TCP-based server for live coding, enabling real-time code evaluation and interactive composition. It acts as a bridge between code editors (via MusaLCE clients) and the running Musa DSL environment.
4
+
5
+ **Architecture:**
6
+ ```
7
+ Editor → MusaLCE Client → TCP (port 1327) → REPL Server → DSL Context
8
+
9
+ Results/Errors
10
+ ```
11
+
12
+ **Available MusaLCE Clients:**
13
+ - **MusaLCEClientForVSCode**: Visual Studio Code extension
14
+ - **MusaLCEClientForAtom**: Atom editor plugin
15
+ - **MusaLCEforBitwig**: Bitwig Studio integration
16
+ - **MusaLCEforLive**: Ableton Live integration
17
+
18
+ ## Communication Protocol
19
+
20
+ The REPL uses a line-based protocol over TCP (default port: 1327).
21
+
22
+ **Client to Server:**
23
+ - `#path` - Start path block (optional, to inject file path context)
24
+ - *file path* - Path to the user's file being edited
25
+ - `#begin` - Start code block
26
+ - *code lines* - Ruby code to execute
27
+ - `#end` - Execute accumulated code block
28
+
29
+ **Server to Client:**
30
+ - `//echo` - Start echo block (code about to be executed)
31
+ - `//error` - Start error block
32
+ - `//backtrace` - Start backtrace section within error block
33
+ - `//end` - End current block
34
+ - *regular lines* - Output from code execution (puts, etc.)
35
+
36
+ **Example Session:**
37
+ ```
38
+ Client → Server:
39
+ #path
40
+ /Users/me/composition.rb
41
+ #begin
42
+ puts "Starting composition..."
43
+ at 1 do
44
+ note pitch: 60, duration: 1r
45
+ end
46
+ #end
47
+
48
+ Server → Client:
49
+ //echo
50
+ puts "Starting composition..."
51
+ at 1 do
52
+ note pitch: 60, duration: 1r
53
+ end
54
+ //end
55
+ Starting composition...
56
+ ```
57
+
58
+ ## Server Setup
59
+
60
+ **Basic REPL Server:**
61
+
62
+ ```ruby
63
+ require 'musa-dsl'
64
+ include Musa::All
65
+
66
+ # Create sequencer and transport
67
+ clock = TimerClock.new(bpm: 120, ticks_per_beat: 24)
68
+ transport = Transport.new(clock, 4, 24)
69
+
70
+ # Start REPL server bound to sequencer context
71
+ # The REPL will execute code in the sequencer's DSL context
72
+ transport.sequencer.with do
73
+ # DSL methods available in REPL
74
+ def note(pitch:, duration:)
75
+ puts "Playing pitch #{pitch} for #{duration} bars"
76
+ end
77
+
78
+ # Create REPL server (port 1327 by default)
79
+ @repl = Musa::REPL::REPL.new(binding)
80
+ end
81
+
82
+ # Start playback (REPL runs in background thread)
83
+ transport.start
84
+ ```
85
+
86
+ **File Path Injection:**
87
+
88
+ When a client sends a file path via `#path`, the REPL injects it as `@user_pathname` (Pathname object). This enables relative requires based on the editor's current file location:
89
+
90
+ ```ruby
91
+ # In REPL context, clients can use:
92
+ require_relative @user_pathname.dirname / 'my_helpers'
93
+ ```
94
+
95
+ ## Integration with Sequencer
96
+
97
+ The REPL automatically hooks into sequencer error handling to report async errors during playback:
98
+
99
+ ```ruby
100
+ require 'musa-dsl'
101
+ include Musa::All
102
+
103
+ clock = TimerClock.new(bpm: 120, ticks_per_beat: 24)
104
+ transport = Transport.new(clock, 4, 24)
105
+
106
+ transport.sequencer.with do
107
+ # If an error occurs during sequencer execution,
108
+ # REPL clients receive formatted error messages
109
+
110
+ at 1 do
111
+ raise "This error will be sent to REPL client"
112
+ end
113
+
114
+ @repl = Musa::REPL::REPL.new(binding)
115
+ end
116
+
117
+ transport.start
118
+ ```
119
+
120
+ ## Use Cases
121
+
122
+ - **Live coding performances**: Real-time code evaluation during performances
123
+ - **Interactive composition**: Develop compositions interactively with immediate feedback
124
+ - **DAW synchronization**: Control Musa DSL from within Bitwig or Ableton Live
125
+ - **Remote composition control**: Send commands to running compositions over network
126
+ - **Educational workshops**: Live demonstrations with instant code execution
127
+
128
+ ## API Reference
129
+
130
+ **Complete API documentation:**
131
+ - [Musa::REPL](https://rubydoc.info/gems/musa-dsl/Musa/REPL) - Live coding server and protocol
132
+
133
+ **Source code:** `lib/repl/`
134
+
135
+
@@ -0,0 +1,98 @@
1
+ # Sequencer - Temporal Engine
2
+
3
+ The Sequencer manages time-based event scheduling with microsecond precision, supporting complex polyrhythmic and polytemporal structures.
4
+
5
+ ```ruby
6
+ require 'musa-dsl'
7
+ include Musa::All
8
+
9
+ # Setup: Create clock and transport (for real-time execution)
10
+ clock = TimerClock.new(bpm: 120, ticks_per_beat: 24)
11
+ transport = Transport.new(clock, 4, 24) # 4 beats per bar, 24 ticks per beat
12
+
13
+ # Define series outside DSL block (Series constructors not available in DSL context)
14
+ melody = S({ note: 60, duration: 1/2r }, { note: 62, duration: 1/2r },
15
+ { note: 64, duration: 1/2r }, { note: 65, duration: 1/2r },
16
+ { note: 67, duration: 1/2r }, { note: 65, duration: 1/2r },
17
+ { note: 64, duration: 1/2r }, { note: 62, duration: 1/2r })
18
+
19
+ # Program sequencer using DSL
20
+ transport.sequencer.with do
21
+ # Custom event handlers (on/launch)
22
+ on :section_change do |name|
23
+ puts "Section: #{name}"
24
+ end
25
+
26
+ # Immediate event (now)
27
+ now do
28
+ launch :section_change, "Start"
29
+ end
30
+
31
+ # Absolute positioning (at): event at bar 1
32
+ at 1 do
33
+ puts "Bar 1: position #{position}"
34
+ end
35
+
36
+ # Relative positioning (wait): event 2 bars later
37
+ wait 2 do
38
+ puts "Bar 3: position #{position}"
39
+ end
40
+
41
+ # Play series (play): reproduces series with automatic timing
42
+ at 5 do
43
+ play melody do |note:, duration:, control:|
44
+ puts "Playing note: #{note}, duration: #{duration}"
45
+ end
46
+ end
47
+
48
+ # Recurring event (every) with stop control
49
+ beat_loop = nil
50
+ at 10 do
51
+ # Store control object to stop it later
52
+ beat_loop = every 2, duration: 10 do
53
+ puts "Beat at position #{position}"
54
+ end
55
+ end
56
+
57
+ # Stop the beat loop at bar 18
58
+ at 18 do
59
+ beat_loop.stop if beat_loop
60
+ puts "Beat loop stopped"
61
+ end
62
+
63
+ # Animated value (move) from 0 to 10 over 4 bars
64
+ at 20 do
65
+ move from: 0, to: 10, duration: 4, every: 1/2r do |value|
66
+ puts "Value: #{value.round(2)}"
67
+ end
68
+ end
69
+
70
+ # Multi-parameter animation (move with hash)
71
+ at 25 do
72
+ move from: { pitch: 60, vel: 60 },
73
+ to: { pitch: 72, vel: 100 },
74
+ duration: 2,
75
+ every: 1/4r do |values|
76
+ puts "Pitch: #{values[:pitch].round}, Velocity: #{values[:vel].round}"
77
+ end
78
+ end
79
+
80
+ # Final event
81
+ at 30 do
82
+ launch :section_change, "End"
83
+ puts "Finished at position #{position}"
84
+ end
85
+ end
86
+
87
+ # Start real-time playback
88
+ transport.start
89
+ ```
90
+
91
+ ## API Reference
92
+
93
+ **Complete API documentation:**
94
+ - [Musa::Sequencer](https://rubydoc.info/gems/musa-dsl/Musa/Sequencer) - Main sequencer class and DSL
95
+
96
+ **Source code:** `lib/sequencer/`
97
+
98
+