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
@@ -1,11 +1,78 @@
1
+ #
2
+ # @api public
1
3
  require_relative 'base-series'
2
4
 
3
5
  module Musa
4
6
  module Series::Constructors
7
+ # Creates a proxy serie with optional initial source.
8
+ #
9
+ # Proxy series enable late binding - creating a serie placeholder that will
10
+ # be resolved later. Useful for:
11
+ #
12
+ # ## Use Cases
13
+ #
14
+ # - **Forward references**: Reference series before definition
15
+ # - **Circular structures**: Self-referential or mutually referential series
16
+ # - **Dependency injection**: Define structure, inject source later
17
+ # - **Dynamic routing**: Change source serie at runtime
18
+ #
19
+ # ## Method Delegation
20
+ #
21
+ # Proxy delegates all methods to underlying source via method_missing,
22
+ # making it transparent proxy for most operations.
23
+ #
24
+ # ## State Resolution
25
+ #
26
+ # Proxy starts in :undefined state, becomes :prototype/:instance when
27
+ # source is set and resolved.
28
+ #
29
+ # @param serie [Serie, nil] initial source serie (default: nil)
30
+ #
31
+ # @return [ProxySerie] proxy serie
32
+ #
33
+ # @example Forward reference
34
+ # proxy = PROXY()
35
+ # proxy.undefined? # => true
36
+ #
37
+ # # Define later
38
+ # proxy.proxy_source = S(1, 2, 3)
39
+ # proxy.prototype? # => true
40
+ #
41
+ # @example Circular structure
42
+ # loop_serie = PROXY()
43
+ # sequence = S(1, 2, 3).after(loop_serie)
44
+ # loop_serie.proxy_source = sequence
45
+ # # Creates infinite loop: 1, 2, 3, 1, 2, 3, ...
46
+ #
47
+ # @example With initial source
48
+ # proxy = PROXY(S(1, 2, 3))
49
+ #
50
+ # @api public
5
51
  def PROXY(serie = nil)
6
52
  ProxySerie.new(serie)
7
53
  end
8
54
 
55
+ # Proxy/wrapper serie that delegates to another serie.
56
+ #
57
+ # Acts as transparent proxy forwarding all method calls to the wrapped
58
+ # serie. Useful for lazy evaluation, conditional serie switching, or
59
+ # adding indirection layer.
60
+ #
61
+ # The proxy can be reassigned to a different serie dynamically by
62
+ # changing the `proxy_source` attribute.
63
+ #
64
+ # @example Basic proxy
65
+ # original = FromArray.new([1, 2, 3])
66
+ # proxy = ProxySerie.new(original)
67
+ # proxy.next_value # => 1 (delegates to original)
68
+ #
69
+ # @example Dynamic serie switching
70
+ # proxy = ProxySerie.new(serie_a)
71
+ # proxy.next_value # Uses serie_a
72
+ # proxy.proxy_source = serie_b
73
+ # proxy.next_value # Now uses serie_b
74
+ #
75
+ # @api private
9
76
  class ProxySerie
10
77
  include Series::Serie.with(source: true, source_as: :proxy_source)
11
78
 
@@ -3,16 +3,54 @@ require_relative '../core-ext/inspect-nice'
3
3
 
4
4
  require_relative 'base-series'
5
5
 
6
- # TODO remove debugging puts, intermediate hash comments on :info and InspectNice
7
6
  module Musa
8
7
  module Series::Operations
8
+ # Quantizes time-value serie to discrete steps.
9
+ #
10
+ # ## Quantization Modes
11
+ #
12
+ # - **Raw**: Rounds values to nearest step, interpolates between points
13
+ # - **Predictive**: Predicts crossings of quantization boundaries
14
+ #
15
+ # ## Applications
16
+ #
17
+ # - Quantize MIDI controller data to discrete values
18
+ # - Convert continuous pitch bends to semitones
19
+ # - Snap timing to grid
20
+ # - Generate stepped automation curves
21
+ # - Convert analog input to digital steps
22
+ #
23
+ # @param reference [Numeric, nil] quantization reference (default: 0)
24
+ # @param step [Numeric, nil] step size (default: 1)
25
+ # @param value_attribute [Symbol, nil] attribute to quantize (default: :value)
26
+ # @param stops [Boolean, nil] include stop points (default: false)
27
+ # @param predictive [Boolean, nil] use predictive mode (default: false)
28
+ # @param left_open [Boolean, nil] left boundary open (raw mode)
29
+ # @param right_open [Boolean, nil] right boundary open (raw mode)
30
+ #
31
+ # @return [RawQuantizer, PredictiveQuantizer] quantized serie
32
+ #
33
+ # @example Basic quantization
34
+ # # Quantize to semitones (12 steps per octave)
35
+ # pitch_bend = S({time: 0r, value: 60.3}, {time: 1r, value: 61.8})
36
+ # quantized = pitch_bend.quantize(step: 1)
37
+ # quantized.i.to_a # => [{time: 0, value: 60, duration: 1}, ...]
38
+ #
39
+ # @example Predictive quantization
40
+ # continuous = S({time: 0r, value: 0}, {time: 4r, value: 10})
41
+ # pred = continuous.quantize(step: 2, predictive: true)
42
+ # # Generates crossing points at values 0, 2, 4, 6, 8, 10
43
+ #
44
+ # @api public
9
45
  def quantize(reference: nil, step: nil,
10
- value_attribute: nil,
11
- stops: nil,
12
- predictive: nil,
13
- left_open: nil,
14
- right_open: nil)
15
-
46
+ value_attribute: nil,
47
+ stops: nil,
48
+ predictive: nil,
49
+ left_open: nil,
50
+ right_open: nil)
51
+
52
+ # TODO remove debugging puts, intermediate hash comments on :info and InspectNice
53
+
16
54
  Series::Constructors.QUANTIZE(self,
17
55
  reference: reference,
18
56
  step: step,
@@ -25,6 +63,18 @@ module Musa
25
63
  end
26
64
 
27
65
  module Series::Constructors
66
+ # Quantizes time-value serie to discrete steps.
67
+ #
68
+ # @param time_value_serie [Serie] source timed serie
69
+ # @param reference [Numeric, nil] quantization reference
70
+ # @param step [Numeric, nil] step size
71
+ # @param value_attribute [Symbol, nil] attribute to quantize
72
+ # @param stops [Boolean, nil] include stop points
73
+ # @param predictive [Boolean, nil] use predictive mode
74
+ # @param left_open [Boolean, nil] left boundary open
75
+ # @param right_open [Boolean, nil] right boundary open
76
+ #
77
+ # @return [RawQuantizer, PredictiveQuantizer] quantized serie
28
78
  def QUANTIZE(time_value_serie,
29
79
  reference: nil, step: nil,
30
80
  value_attribute: nil,
@@ -1,11 +1,76 @@
1
+ # Queue serie for dynamic series concatenation.
2
+ #
3
+ #
4
+ # @api public
1
5
  require_relative 'base-series'
2
6
 
3
7
  module Musa
4
8
  module Series::Constructors
9
+ # Creates queue serie from initial series.
10
+ #
11
+ # Queue allows adding series dynamically during playback, creating flexible
12
+ # sequential playback with runtime modification.
13
+ #
14
+ # ## Features
15
+ #
16
+ # - **Dynamic addition**: Add series with `<<` during playback
17
+ # - **Sequential playback**: Plays series in queue order
18
+ # - **Method delegation**: Delegates methods to current serie
19
+ # - **Clear**: Can clear queue and reset
20
+ #
21
+ # ## Use Cases
22
+ #
23
+ # - Interactive sequencing with user input
24
+ # - Dynamic phrase assembly
25
+ # - Playlist-style serie management
26
+ # - Reactive composition systems
27
+ # - Live coding pattern queuing
28
+ #
29
+ # @param series [Array<Serie>] initial series in queue
30
+ #
31
+ # @return [QueueSerie] queue serie
32
+ #
33
+ # @example Basic queue
34
+ # queue = QUEUE(S(1, 2, 3)).i
35
+ # queue.next_value # => 1
36
+ # queue << S(4, 5, 6).i # Add dynamically
37
+ # queue.to_a # => [2, 3, 4, 5, 6]
38
+ #
39
+ # @example Dynamic playlist
40
+ # queue = QUEUE().i
41
+ # queue << melody1.i
42
+ # queue << melody2.i
43
+ # # Plays melody1 then melody2
44
+ #
45
+ # @api public
5
46
  def QUEUE(*series)
6
47
  QueueSerie.new(series)
7
48
  end
8
49
 
50
+ # Serie that processes multiple source series in queue/sequence fashion.
51
+ #
52
+ # Combines multiple series by playing them sequentially - when one
53
+ # series exhausts, moves to the next. New series can be added dynamically
54
+ # with `<<` operator.
55
+ #
56
+ # All queued series must be instances (not prototypes). The queue can
57
+ # be cleared with `clear` method.
58
+ #
59
+ # @example Sequential series playback
60
+ # serie_a = FromArray.new([1, 2, 3]).instance
61
+ # serie_b = FromArray.new([4, 5, 6]).instance
62
+ # queue = QueueSerie.new([serie_a, serie_b])
63
+ # queue.next_value # => 1
64
+ # queue.next_value # => 2
65
+ # queue.next_value # => 3
66
+ # queue.next_value # => 4 (switches to serie_b)
67
+ #
68
+ # @example Dynamic queueing
69
+ # queue = QueueSerie.new([serie_a]).instance
70
+ # queue << serie_b # Add series on the fly
71
+ # queue.clear # Empty the queue
72
+ #
73
+ # @api private
9
74
  class QueueSerie
10
75
  include Series::Serie.with(sources: true)
11
76
 
@@ -14,6 +79,13 @@ module Musa
14
79
  init
15
80
  end
16
81
 
82
+ # Adds serie to queue.
83
+ #
84
+ # @param serie [Serie] instance serie to add
85
+ #
86
+ # @return [self] for chaining
87
+ #
88
+ # @raise [ArgumentError] if serie is not an instance
17
89
  def <<(serie)
18
90
  # when queue is a prototype it is also frozen so no serie can be added (it would raise an Exception if tried).
19
91
  # when queue is an instance the added serie should also be an instance (raise an Exception otherwise)
@@ -26,6 +98,9 @@ module Musa
26
98
  self
27
99
  end
28
100
 
101
+ # Clears all series from queue.
102
+ #
103
+ # @return [self] for chaining
29
104
  def clear
30
105
  @sources.clear
31
106
  init
@@ -83,6 +158,9 @@ module Musa
83
158
  end
84
159
 
85
160
  module Series::Operations
161
+ # Wraps this serie in a queue.
162
+ #
163
+ # @return [QueueSerie] queue containing this serie
86
164
  def queued
87
165
  Series::Constructors.QUEUE(self)
88
166
  end