musa-dsl 0.30.2 → 0.40.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 (123) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -1
  3. data/.version +6 -0
  4. data/.yardopts +7 -0
  5. data/README.md +227 -6
  6. data/docs/README.md +83 -0
  7. data/docs/api-reference.md +86 -0
  8. data/docs/getting-started/quick-start.md +93 -0
  9. data/docs/getting-started/tutorial.md +58 -0
  10. data/docs/subsystems/core-extensions.md +316 -0
  11. data/docs/subsystems/datasets.md +465 -0
  12. data/docs/subsystems/generative.md +290 -0
  13. data/docs/subsystems/matrix.md +63 -0
  14. data/docs/subsystems/midi.md +123 -0
  15. data/docs/subsystems/music.md +233 -0
  16. data/docs/subsystems/musicxml-builder.md +264 -0
  17. data/docs/subsystems/neumas.md +71 -0
  18. data/docs/subsystems/repl.md +135 -0
  19. data/docs/subsystems/sequencer.md +98 -0
  20. data/docs/subsystems/series.md +302 -0
  21. data/docs/subsystems/transcription.md +152 -0
  22. data/docs/subsystems/transport.md +177 -0
  23. data/lib/musa-dsl/core-ext/array-explode-ranges.rb +68 -0
  24. data/lib/musa-dsl/core-ext/arrayfy.rb +110 -0
  25. data/lib/musa-dsl/core-ext/attribute-builder.rb +91 -30
  26. data/lib/musa-dsl/core-ext/deep-copy.rb +125 -2
  27. data/lib/musa-dsl/core-ext/dynamic-proxy.rb +78 -0
  28. data/lib/musa-dsl/core-ext/extension.rb +53 -0
  29. data/lib/musa-dsl/core-ext/hashify.rb +162 -1
  30. data/lib/musa-dsl/core-ext/inspect-nice.rb +154 -0
  31. data/lib/musa-dsl/core-ext/smart-proc-binder.rb +117 -0
  32. data/lib/musa-dsl/core-ext/with.rb +114 -0
  33. data/lib/musa-dsl/datasets/dataset.rb +109 -0
  34. data/lib/musa-dsl/datasets/delta-d.rb +78 -0
  35. data/lib/musa-dsl/datasets/e.rb +186 -2
  36. data/lib/musa-dsl/datasets/gdv.rb +279 -2
  37. data/lib/musa-dsl/datasets/gdvd.rb +201 -0
  38. data/lib/musa-dsl/datasets/helper.rb +75 -0
  39. data/lib/musa-dsl/datasets/p.rb +177 -2
  40. data/lib/musa-dsl/datasets/packed-v.rb +91 -0
  41. data/lib/musa-dsl/datasets/pdv.rb +136 -1
  42. data/lib/musa-dsl/datasets/ps.rb +134 -4
  43. data/lib/musa-dsl/datasets/score/queriable.rb +143 -1
  44. data/lib/musa-dsl/datasets/score/render.rb +105 -1
  45. data/lib/musa-dsl/datasets/score/to-mxml/process-pdv.rb +138 -1
  46. data/lib/musa-dsl/datasets/score/to-mxml/process-ps.rb +111 -0
  47. data/lib/musa-dsl/datasets/score/to-mxml/process-time.rb +200 -1
  48. data/lib/musa-dsl/datasets/score/to-mxml/to-mxml.rb +145 -1
  49. data/lib/musa-dsl/datasets/score.rb +279 -0
  50. data/lib/musa-dsl/datasets/v.rb +88 -0
  51. data/lib/musa-dsl/generative/darwin.rb +180 -1
  52. data/lib/musa-dsl/generative/generative-grammar.rb +359 -0
  53. data/lib/musa-dsl/generative/markov.rb +133 -3
  54. data/lib/musa-dsl/generative/rules.rb +258 -4
  55. data/lib/musa-dsl/generative/variatio.rb +217 -2
  56. data/lib/musa-dsl/logger/logger.rb +267 -2
  57. data/lib/musa-dsl/matrix/matrix.rb +256 -10
  58. data/lib/musa-dsl/midi/midi-recorder.rb +108 -1
  59. data/lib/musa-dsl/midi/midi-voices.rb +265 -4
  60. data/lib/musa-dsl/music/chord-definition.rb +233 -1
  61. data/lib/musa-dsl/music/chord-definitions.rb +33 -6
  62. data/lib/musa-dsl/music/chords.rb +308 -2
  63. data/lib/musa-dsl/music/equally-tempered-12-tone-scale-system.rb +315 -0
  64. data/lib/musa-dsl/music/scales.rb +957 -40
  65. data/lib/musa-dsl/musicxml/builder/attributes.rb +483 -3
  66. data/lib/musa-dsl/musicxml/builder/backup-forward.rb +166 -1
  67. data/lib/musa-dsl/musicxml/builder/direction.rb +243 -0
  68. data/lib/musa-dsl/musicxml/builder/helper.rb +240 -0
  69. data/lib/musa-dsl/musicxml/builder/measure.rb +284 -0
  70. data/lib/musa-dsl/musicxml/builder/note-complexities.rb +324 -8
  71. data/lib/musa-dsl/musicxml/builder/note.rb +285 -0
  72. data/lib/musa-dsl/musicxml/builder/part-group.rb +108 -1
  73. data/lib/musa-dsl/musicxml/builder/part.rb +139 -0
  74. data/lib/musa-dsl/musicxml/builder/pitched-note.rb +124 -0
  75. data/lib/musa-dsl/musicxml/builder/rest.rb +93 -0
  76. data/lib/musa-dsl/musicxml/builder/score-partwise.rb +276 -0
  77. data/lib/musa-dsl/musicxml/builder/typed-text.rb +62 -1
  78. data/lib/musa-dsl/musicxml/builder/unpitched-note.rb +83 -0
  79. data/lib/musa-dsl/neumalang/neumalang.rb +675 -0
  80. data/lib/musa-dsl/neumas/array-to-neumas.rb +149 -0
  81. data/lib/musa-dsl/neumas/neuma-decoder.rb +253 -0
  82. data/lib/musa-dsl/neumas/neuma-gdv-decoder.rb +142 -2
  83. data/lib/musa-dsl/neumas/neuma-gdvd-decoder.rb +82 -0
  84. data/lib/musa-dsl/neumas/neumas.rb +67 -0
  85. data/lib/musa-dsl/neumas/string-to-neumas.rb +233 -1
  86. data/lib/musa-dsl/repl/repl.rb +550 -0
  87. data/lib/musa-dsl/sequencer/base-sequencer-implementation-every.rb +118 -2
  88. data/lib/musa-dsl/sequencer/base-sequencer-implementation-move.rb +149 -2
  89. data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-helper.rb +296 -0
  90. data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-timed.rb +88 -2
  91. data/lib/musa-dsl/sequencer/base-sequencer-implementation-play.rb +161 -0
  92. data/lib/musa-dsl/sequencer/base-sequencer-implementation.rb +263 -0
  93. data/lib/musa-dsl/sequencer/base-sequencer-tick-based.rb +173 -1
  94. data/lib/musa-dsl/sequencer/base-sequencer-tickless-based.rb +177 -0
  95. data/lib/musa-dsl/sequencer/base-sequencer.rb +710 -10
  96. data/lib/musa-dsl/sequencer/sequencer-dsl.rb +210 -0
  97. data/lib/musa-dsl/sequencer/timeslots.rb +79 -0
  98. data/lib/musa-dsl/series/array-to-serie.rb +37 -1
  99. data/lib/musa-dsl/series/base-series.rb +843 -5
  100. data/lib/musa-dsl/series/buffer-serie.rb +48 -0
  101. data/lib/musa-dsl/series/hash-or-array-serie-splitter.rb +41 -0
  102. data/lib/musa-dsl/series/main-serie-constructors.rb +398 -2
  103. data/lib/musa-dsl/series/main-serie-operations.rb +538 -16
  104. data/lib/musa-dsl/series/proxy-serie.rb +67 -0
  105. data/lib/musa-dsl/series/quantizer-serie.rb +45 -7
  106. data/lib/musa-dsl/series/queue-serie.rb +65 -0
  107. data/lib/musa-dsl/series/series-composer.rb +701 -0
  108. data/lib/musa-dsl/series/timed-serie.rb +473 -28
  109. data/lib/musa-dsl/transcription/from-gdv-to-midi.rb +404 -1
  110. data/lib/musa-dsl/transcription/from-gdv-to-musicxml.rb +118 -0
  111. data/lib/musa-dsl/transcription/from-gdv.rb +84 -1
  112. data/lib/musa-dsl/transcription/transcription.rb +265 -0
  113. data/lib/musa-dsl/transport/clock.rb +125 -0
  114. data/lib/musa-dsl/transport/dummy-clock.rb +89 -2
  115. data/lib/musa-dsl/transport/external-tick-clock.rb +91 -0
  116. data/lib/musa-dsl/transport/input-midi-clock.rb +133 -1
  117. data/lib/musa-dsl/transport/timer-clock.rb +183 -1
  118. data/lib/musa-dsl/transport/timer.rb +83 -0
  119. data/lib/musa-dsl/transport/transport.rb +318 -0
  120. data/lib/musa-dsl/version.rb +1 -1
  121. data/lib/musa-dsl.rb +132 -25
  122. data/musa-dsl.gemspec +12 -10
  123. metadata +87 -8
@@ -1,5 +1,53 @@
1
1
  module Musa
2
2
  module Series::Operations
3
+ # Creates a buffered serie allowing multiple independent iterations over same source.
4
+ #
5
+ # Provides buffering mechanism enabling multiple "readers" to independently
6
+ # iterate over the same serie source without interfering with each other.
7
+ #
8
+ # ## Buffering Modes
9
+ #
10
+ # - **Async (default)**: Buffers fill independently, each progresses at own pace
11
+ # - **Sync**: All buffers synchronized, restart affects all
12
+ #
13
+ # ## Use Cases
14
+ #
15
+ # - Multiple voices reading same melodic sequence at different speeds
16
+ # - Polyphonic playback from single source
17
+ # - Canonic structures (rounds, fugues)
18
+ # - Independent transformations of same base material
19
+ #
20
+ # ## Memory Management
21
+ #
22
+ # History is automatically cleaned when all buffers have progressed past
23
+ # old values, preventing unbounded memory growth.
24
+ #
25
+ # @param sync [Boolean] synchronized mode (default: false)
26
+ #
27
+ # @return [BufferSerie, SyncBufferSerie] buffered serie
28
+ #
29
+ # @example Create buffered serie
30
+ # buffered = S(1, 2, 3, 4).buffered
31
+ # reader1 = buffered.buffer.i
32
+ # reader2 = buffered.buffer.i
33
+ #
34
+ # @example Multiple independent readers
35
+ # source = S(1, 2, 3, 4).buffered
36
+ # reader1 = source.buffer.i
37
+ # reader2 = source.buffer.i
38
+ #
39
+ # reader1.next_value # => 1
40
+ # reader2.next_value # => 1 (independent)
41
+ # reader1.next_value # => 2
42
+ # reader2.next_value # => 2
43
+ #
44
+ # @example Canon structure
45
+ # melody = S(60, 64, 67, 72).buffered
46
+ # voice1 = melody.buffer
47
+ # voice2 = melody.buffer
48
+ # # Play voice2 delayed by N beats
49
+ #
50
+ # @api public
3
51
  def buffered(sync: false)
4
52
  if sync
5
53
  SyncBufferSerie.new(self)
@@ -1,5 +1,46 @@
1
1
  module Musa
2
2
  module Series::Operations
3
+
4
+ # Serie splitter for decomposing hash/array values into component series.
5
+ #
6
+ # Splits series of hash or array values into individual component series,
7
+ # enabling independent access to each component.
8
+ #
9
+ # ## Splitting Modes
10
+ #
11
+ # - **Hash mode**: Split `{pitch: 60, velocity: 96}` into separate series
12
+ # for `:pitch` and `:velocity`
13
+ # - **Array mode**: Split `[60, 96]` into separate series for indices 0, 1
14
+ #
15
+ # ## Component Access
16
+ #
17
+ # - **Hash**: `splitter[:pitch]`, `splitter[:velocity]`
18
+ # - **Array**: `splitter[0]`, `splitter[1]`
19
+ # - **Enumerable**: `splitter.each { |component| ... }`
20
+ #
21
+ # ## Use Cases
22
+ #
23
+ # - Separate polyphonic voices from single source
24
+ # - Independent processing of musical parameters
25
+ # - Extract specific components (pitch, duration, velocity, etc.)
26
+ # - Multi-track decomposition
27
+ #
28
+ # @example Split hash values
29
+ # notes = S({pitch: 60, vel: 96}, {pitch: 64, vel: 80})
30
+ # splitter = notes.split.i
31
+ #
32
+ # pitches = splitter[:pitch]
33
+ # velocities = splitter[:vel]
34
+ #
35
+ # pitches.next_value # => 60
36
+ # velocities.next_value # => 96
37
+ #
38
+ # @example Split array values
39
+ # pairs = S([1, 10], [2, 20], [3, 30]).split.i
40
+ # first = pairs[0]
41
+ # second = pairs[1]
42
+ #
43
+ # @api public
3
44
  def split
4
45
  Splitter.new(self)
5
46
  end
@@ -3,50 +3,314 @@ require_relative '../core-ext/smart-proc-binder'
3
3
 
4
4
  require_relative 'base-series'
5
5
 
6
- # TODO: añadir en for: steps: (nº de pasos en los que repartir el incremento)
7
-
8
6
  module Musa
7
+ # Series constructor methods for creating series from various sources.
8
+ #
9
+ # Provides factory methods for common serie types:
10
+ #
11
+ # ## Basic Constructors
12
+ #
13
+ # - **UNDEFINED** - Undefined serie (unresolved state)
14
+ # - **NIL** - Serie that always returns nil
15
+ # - **S** - Serie from array of values
16
+ # - **E** - Serie from evaluation block
17
+ #
18
+ # ## Collection Constructors
19
+ #
20
+ # - **H/HC** - Hash of series (hash/combined mode)
21
+ # - **A/AC** - Array of series (array/combined mode)
22
+ # - **MERGE** - Sequential merge of multiple series
23
+ #
24
+ # ## Numeric Generators
25
+ #
26
+ # - **FOR** - For-loop style numeric sequence
27
+ # - **RND** - Random values (from array or range)
28
+ # - **RND1** - Single random value
29
+ # - **SIN** - Sine wave function
30
+ # - **FIBO** - Fibonacci sequence
31
+ #
32
+ # ## Musical Generators
33
+ #
34
+ # - **HARMO** - Harmonic note series
35
+ #
36
+ # ## Usage Patterns
37
+ #
38
+ # ### Array Serie
39
+ #
40
+ # ```ruby
41
+ # notes = S(60, 64, 67, 72)
42
+ # notes.i.next_value # => 60
43
+ # ```
44
+ #
45
+ # ### Evaluation Block
46
+ #
47
+ # ```ruby
48
+ # counter = E(1) { |v, last_value:| last_value + 1 unless last_value == 10 }
49
+ # counter.i.to_a # => [1, 2, 3, ..., 10]
50
+ # ```
51
+ #
52
+ # ### Random Values
53
+ #
54
+ # ```ruby
55
+ # dice = RND(1, 2, 3, 4, 5, 6)
56
+ # dice.i.next_value # => random 1-6
57
+ # ```
58
+ #
59
+ # ### Numeric Sequences
60
+ #
61
+ # ```ruby
62
+ # sequence = FOR(from: 0, to: 10, step: 2)
63
+ # sequence.i.to_a # => [0, 2, 4, 6, 8, 10]
64
+ # ```
65
+ #
66
+ # ### Combining Series
67
+ #
68
+ # ```ruby
69
+ # melody = MERGE(S(60, 64), S(67, 72))
70
+ # melody.i.to_a # => [60, 64, 67, 72]
71
+ # ```
72
+ #
73
+ # @see Musa::Series::Operations Serie transformation operations
74
+ #
75
+ # @api public
9
76
  module Series::Constructors
10
77
  using Musa::Extension::ExplodeRanges
11
78
 
79
+ # Creates undefined serie.
80
+ #
81
+ # Returns serie in undefined state. Useful as placeholder that will
82
+ # be resolved later (e.g., in PROXY).
83
+ #
84
+ # @return [UndefinedSerie] serie in undefined state
85
+ #
86
+ # @example Undefined placeholder
87
+ # proxy = PROXY() # Uses UNDEFINED internally
88
+ # proxy.undefined? # => true
89
+ #
90
+ # @api public
12
91
  def UNDEFINED
13
92
  UndefinedSerie.new
14
93
  end
15
94
 
95
+ # Creates serie that always returns nil.
96
+ #
97
+ # Returns nil on every next_value call. Useful for padding or as
98
+ # placeholder in composite structures.
99
+ #
100
+ # @return [NilSerie] serie returning nil
101
+ #
102
+ # @example Nil serie
103
+ # s = NIL().i
104
+ # s.next_value # => nil
105
+ # s.next_value # => nil
106
+ #
107
+ # @api public
16
108
  def NIL
17
109
  NilSerie.new
18
110
  end
19
111
 
112
+ # Creates serie from array of values.
113
+ #
114
+ # Most common constructor. Values can include ranges which will be
115
+ # expanded automatically via ExplodeRanges extension.
116
+ #
117
+ # @param values [Array] values to iterate (supports ranges)
118
+ #
119
+ # @return [FromArray] serie from array
120
+ #
121
+ # @example Basic array
122
+ # notes = S(60, 64, 67, 72)
123
+ # notes.i.to_a # => [60, 64, 67, 72]
124
+ #
125
+ # @example With ranges
126
+ # scale = S(60..67)
127
+ # scale.i.to_a # => [60, 61, 62, 63, 64, 65, 66, 67]
128
+ #
129
+ # @api public
20
130
  def S(*values)
21
131
  FromArray.new values.explode_ranges
22
132
  end
23
133
 
134
+ # Creates hash-mode serie from hash of series.
135
+ #
136
+ # Combines multiple series into hash-structured values. Returns hash
137
+ # with same keys, values from respective series. Stops when first
138
+ # serie exhausts.
139
+ #
140
+ # @param series_hash [Hash] hash of series (key => serie)
141
+ #
142
+ # @return [FromHashOfSeries] combined hash serie
143
+ #
144
+ # @example Hash of series
145
+ # h = H(pitch: S(60, 64, 67), velocity: S(96, 80, 64))
146
+ # h.i.next_value # => {pitch: 60, velocity: 96}
147
+ # h.i.next_value # => {pitch: 64, velocity: 80}
148
+ #
149
+ # @api public
24
150
  def H(**series_hash)
25
151
  FromHashOfSeries.new series_hash, false
26
152
  end
27
153
 
154
+ # Creates hash-mode combined serie from hash of series.
155
+ #
156
+ # Like H but cycles all series. When a serie exhausts, it restarts from
157
+ # the beginning, continuing until all series complete their cycles.
158
+ #
159
+ # @param series_hash [Hash] hash of series (key => serie)
160
+ #
161
+ # @return [FromHashOfSeries] combined hash serie that cycles all series
162
+ #
163
+ # @example Combined cycling all series
164
+ # hc = HC(a: S(1, 2), b: S(10, 20, 30))
165
+ # hc.max_size(6).i.to_a # => [{a:1, b:10}, {a:2, b:20}, {a:1, b:30},
166
+ # # {a:2, b:10}, {a:1, b:20}, {a:2, b:30}]
167
+ #
168
+ # @api public
28
169
  def HC(**series_hash)
29
170
  FromHashOfSeries.new series_hash, true
30
171
  end
31
172
 
173
+ # Creates array-mode serie from array of series.
174
+ #
175
+ # Combines multiple series into array-structured values. Returns array
176
+ # of values from respective series. Stops when first serie exhausts.
177
+ #
178
+ # @param series [Array] array of series
179
+ #
180
+ # @return [FromArrayOfSeries] combined array serie
181
+ #
182
+ # @example Array of series
183
+ # a = A(S(1, 2, 3), S(10, 20, 30))
184
+ # a.i.next_value # => [1, 10]
185
+ # a.i.next_value # => [2, 20]
186
+ #
187
+ # @api public
32
188
  def A(*series)
33
189
  FromArrayOfSeries.new series, false
34
190
  end
35
191
 
192
+ # Creates array-mode combined serie from array of series.
193
+ #
194
+ # Like A but cycles all series. When a serie exhausts, it restarts from
195
+ # the beginning, continuing until all series complete their cycles.
196
+ #
197
+ # @param series [Array] array of series
198
+ #
199
+ # @return [FromArrayOfSeries] combined array serie that cycles all series
200
+ #
201
+ # @example Combined cycling all series
202
+ # ac = AC(S(1, 2), S(10, 20, 30))
203
+ # ac.max_size(6).i.to_a # => [[1, 10], [2, 20], [1, 30],
204
+ # # [2, 10], [1, 20], [2, 30]]
205
+ #
206
+ # @api public
36
207
  def AC(*series)
37
208
  FromArrayOfSeries.new series, true
38
209
  end
39
210
 
211
+ # Creates serie from evaluation block.
212
+ #
213
+ # Calls block repeatedly with parameters and last_value. Block returns
214
+ # next value or nil to stop. Enables stateful generators and algorithms.
215
+ #
216
+ # ## Block Parameters
217
+ #
218
+ # - **value_args**: Initial positional parameters
219
+ # - **last_value**: Previous return value (nil on first call)
220
+ # - **caller**: Serie instance (access to parameters attribute)
221
+ # - **key_args**: Initial keyword parameters
222
+ #
223
+ # @param value_args [Array] initial positional parameters
224
+ # @param key_args [Hash] initial keyword parameters
225
+ # @yield block called for each value
226
+ # @yieldparam value_args [Array] current positional parameters
227
+ # @yieldparam last_value [Object, nil] previous return value
228
+ # @yieldparam caller [FromEvalBlockWithParameters] serie instance
229
+ # @yieldparam key_args [Hash] current keyword parameters
230
+ # @yieldreturn [Object, nil] next value or nil to stop
231
+ #
232
+ # @return [FromEvalBlockWithParameters] evaluation-based serie
233
+ #
234
+ # @example Counter
235
+ # counter = E(1) { |v, last_value:| last_value + 1 unless last_value == 5 }
236
+ # counter.i.to_a # => [1, 2, 3, 4, 5]
237
+ #
238
+ # @example Fibonacci
239
+ # fib = E { |last_value:, caller:|
240
+ # a, b = caller.parameters
241
+ # caller.parameters = [b, a + b]
242
+ # a
243
+ # }
244
+ # fib.parameters = [0, 1]
245
+ # fib.i.to_a(limit: 10) # => [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
246
+ #
247
+ # @api public
40
248
  def E(*value_args, **key_args, &block)
41
249
  FromEvalBlockWithParameters.new *value_args, **key_args, &block
42
250
  end
43
251
 
252
+ # Creates for-loop style numeric sequence.
253
+ #
254
+ # Generates sequence from `from` to `to` (inclusive) with `step` increment.
255
+ # Automatically adjusts step sign based on from/to relationship.
256
+ #
257
+ # @param from [Numeric, nil] starting value (default: 0)
258
+ # @param to [Numeric, nil] ending value (nil for infinite)
259
+ # @param step [Numeric, nil] increment (default: 1, sign auto-adjusted)
260
+ #
261
+ # @return [ForLoop] numeric sequence serie
262
+ #
263
+ # @example Ascending sequence
264
+ # s = FOR(from: 0, to: 10, step: 2)
265
+ # s.i.to_a # => [0, 2, 4, 6, 8, 10]
266
+ #
267
+ # @example Descending sequence
268
+ # s = FOR(from: 10, to: 0, step: 2)
269
+ # s.i.to_a # => [10, 8, 6, 4, 2, 0]
270
+ #
271
+ # @example Infinite sequence
272
+ # s = FOR(from: 0, step: 1) # to: nil
273
+ # s.infinite? # => true
274
+ #
275
+ # @api public
44
276
  def FOR(from: nil, to: nil, step: nil)
45
277
  from ||= 0
46
278
  step ||= 1
47
279
  ForLoop.new from, to, step
48
280
  end
49
281
 
282
+ # Creates random value serie from array or range.
283
+ #
284
+ # Two modes:
285
+ # - **Array mode**: Random values from provided array
286
+ # - **Range mode**: Random numbers from range (from, to, step)
287
+ #
288
+ # Infinite serie - never exhausts.
289
+ #
290
+ # @param _values [Array] values to choose from (positional)
291
+ # @param values [Array, nil] values to choose from (named)
292
+ # @param from [Numeric, nil] range start (range mode)
293
+ # @param to [Numeric, nil] range end (range mode, required)
294
+ # @param step [Numeric, nil] range step (default: 1)
295
+ # @param random [Random, Integer, nil] Random instance or seed
296
+ #
297
+ # @return [RandomValuesFromArray, RandomNumbersFromRange] random serie
298
+ #
299
+ # @raise [ArgumentError] if using both positional and named values
300
+ # @raise [ArgumentError] if mixing array and range parameters
301
+ #
302
+ # @example Random from array
303
+ # dice = RND(1, 2, 3, 4, 5, 6)
304
+ # dice.i.next_value # => random 1-6
305
+ #
306
+ # @example Random from range
307
+ # rand = RND(from: 0, to: 100, step: 10)
308
+ # rand.i.next_value # => random 0, 10, 20, ..., 100
309
+ #
310
+ # @example With seed
311
+ # rnd = RND(1, 2, 3, random: 42) # Reproducible
312
+ #
313
+ # @api public
50
314
  def RND(*_values, values: nil, from: nil, to: nil, step: nil, random: nil)
51
315
  raise ArgumentError, "Can't use both direct values #{_values} and values named parameter #{values} at the same time." if values && !_values.empty?
52
316
 
@@ -66,10 +330,55 @@ module Musa
66
330
  end
67
331
  end
68
332
 
333
+ # Merges multiple series sequentially.
334
+ #
335
+ # Plays series in sequence: first serie until exhausted, then second,
336
+ # etc. Restarts each serie (except first) before playing.
337
+ #
338
+ # @param series [Array<Serie>] series to merge sequentially
339
+ #
340
+ # @return [Sequence] sequential merge serie
341
+ #
342
+ # @example Merge sequences
343
+ # merged = MERGE(S(1, 2, 3), S(10, 20, 30))
344
+ # merged.i.to_a # => [1, 2, 3, 10, 20, 30]
345
+ #
346
+ # @example Melodic phrases
347
+ # phrase1 = S(60, 64, 67)
348
+ # phrase2 = S(72, 69, 65)
349
+ # melody = MERGE(phrase1, phrase2)
350
+ #
351
+ # @api public
69
352
  def MERGE(*series)
70
353
  Sequence.new(series)
71
354
  end
72
355
 
356
+ # Creates single random value serie from array or range.
357
+ #
358
+ # Like RND but returns only one random value then exhausts.
359
+ # Two modes: array mode and range mode.
360
+ #
361
+ # @param _values [Array] values to choose from (positional)
362
+ # @param values [Array, nil] values to choose from (named)
363
+ # @param from [Numeric, nil] range start (range mode)
364
+ # @param to [Numeric, nil] range end (range mode, required)
365
+ # @param step [Numeric, nil] range step (default: 1)
366
+ # @param random [Random, Integer, nil] Random instance or seed
367
+ #
368
+ # @return [RandomValueFromArray, RandomNumberFromRange] single random value serie
369
+ #
370
+ # @raise [ArgumentError] if using both positional and named values
371
+ # @raise [ArgumentError] if mixing array and range parameters
372
+ #
373
+ # @example Single random value
374
+ # rnd = RND1(1, 2, 3, 4, 5)
375
+ # rnd.i.next_value # => random 1-5
376
+ # rnd.i.next_value # => nil (exhausted)
377
+ #
378
+ # @example Random seed selection
379
+ # seed = RND1(10, 20, 30, random: 42)
380
+ #
381
+ # @api public
73
382
  def RND1(*_values, values: nil, from: nil, to: nil, step: nil, random: nil)
74
383
  raise ArgumentError, "Can't use both direct values #{_values} and values named parameter #{values} at the same time." if values && !_values.empty?
75
384
 
@@ -89,6 +398,36 @@ module Musa
89
398
  end
90
399
  end
91
400
 
401
+ # Creates sine wave function serie.
402
+ #
403
+ # Generates values following sine curve. Useful for smooth oscillations,
404
+ # LFO-style modulation, and periodic variations.
405
+ #
406
+ # ## Wave Parameters
407
+ #
408
+ # - **start_value**: Initial value (default: center)
409
+ # - **steps**: Period in steps (nil for continuous)
410
+ # - **amplitude**: Wave amplitude (default: 1.0)
411
+ # - **center**: Center/offset value (default: 0.0)
412
+ #
413
+ # Wave equation: `center + amplitude * sin(progress)`
414
+ #
415
+ # @param start_value [Numeric, nil] initial value
416
+ # @param steps [Numeric, nil] full period in steps
417
+ # @param amplitude [Numeric, nil] wave amplitude (default: 1.0)
418
+ # @param center [Numeric, nil] center offset (default: 0.0)
419
+ #
420
+ # @return [SinFunction] sine wave serie
421
+ #
422
+ # @example Basic sine wave
423
+ # wave = SIN(steps: 8, amplitude: 10, center: 50)
424
+ # wave.i.to_a # => oscillates around 50 ± 10
425
+ #
426
+ # @example LFO modulation
427
+ # lfo = SIN(steps: 16, amplitude: 0.5, center: 0.5)
428
+ # # Use for amplitude modulation
429
+ #
430
+ # @api public
92
431
  def SIN(start_value: nil, steps: nil, amplitude: nil, center: nil)
93
432
  amplitude ||= 1.0
94
433
  center ||= 0.0
@@ -96,10 +435,53 @@ module Musa
96
435
  SinFunction.new start_value, steps, amplitude, center
97
436
  end
98
437
 
438
+ # Creates Fibonacci sequence serie.
439
+ #
440
+ # Generates classic Fibonacci sequence: 0, 1, 1, 2, 3, 5, 8, 13, 21, ...
441
+ # Infinite serie.
442
+ #
443
+ # @return [Fibonacci] Fibonacci sequence serie
444
+ #
445
+ # @example Fibonacci numbers
446
+ # fib = FIBO()
447
+ # fib.infinite? # => true
448
+ # inst = fib.i
449
+ # 10.times.map { inst.next_value }
450
+ # # => [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
451
+ #
452
+ # @example Rhythmic proportions
453
+ # durations = FIBO().i.map { |n| Rational(n, 16) }
454
+ #
455
+ # @api public
99
456
  def FIBO()
100
457
  Fibonacci.new
101
458
  end
102
459
 
460
+ # Creates harmonic notes serie from fundamental.
461
+ #
462
+ # Generates MIDI note numbers for harmonic series based on listened
463
+ # fundamental. Approximates harmonics to nearest semitone within error
464
+ # tolerance.
465
+ #
466
+ # ## Parameters
467
+ #
468
+ # - **error**: Maximum cents deviation to accept harmonic (default: 0.5)
469
+ # - **extended**: Include extended harmonics beyond audible range
470
+ #
471
+ # @param error [Numeric, nil] maximum deviation in semitones (default: 0.5)
472
+ # @param extended [Boolean, nil] include extended harmonics (default: false)
473
+ #
474
+ # @return [HarmonicNotes] harmonic series serie
475
+ #
476
+ # @example Harmonic series
477
+ # # Listen to fundamental, serie returns harmonic notes
478
+ # harmonics = HARMO(error: 0.5)
479
+ # harmonics.i # Waits for fundamental input
480
+ #
481
+ # @example Extended harmonics
482
+ # harm = HARMO(error: 0.3, extended: true)
483
+ #
484
+ # @api public
103
485
  def HARMO(error: nil, extended: nil)
104
486
  error ||= 0.5
105
487
  extended ||= false
@@ -133,6 +515,20 @@ module Musa
133
515
 
134
516
  private_constant :NilSerie
135
517
 
518
+ # Serie constructor that creates a serie from an array of values.
519
+ #
520
+ # Iterates through array elements, returning nil when exhausted.
521
+ # Supports optional module extensions for enhanced functionality.
522
+ #
523
+ # @example Basic array serie
524
+ # serie = FromArray.new([1, 2, 3, 4, 5])
525
+ # serie.next_value # => 1
526
+ # serie.next_value # => 2
527
+ #
528
+ # @example With extensions
529
+ # serie = FromArray.new([60, 62, 64], [SomeExtension])
530
+ #
531
+ # @api private
136
532
  class FromArray
137
533
  include Series::Serie.base
138
534