musa-dsl 0.23.5 → 0.23.10
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +2 -0
- data/lib/musa-dsl/generative/markov.rb +1 -1
- data/lib/musa-dsl/sequencer/base-sequencer-implementation-every.rb +2 -2
- data/lib/musa-dsl/sequencer/base-sequencer-implementation-move.rb +2 -2
- data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-timed.rb +39 -34
- data/lib/musa-dsl/sequencer/base-sequencer-implementation-play.rb +2 -2
- data/lib/musa-dsl/sequencer/base-sequencer-implementation.rb +2 -2
- data/lib/musa-dsl/series/base-series.rb +190 -71
- data/lib/musa-dsl/series/buffer-serie.rb +30 -17
- data/lib/musa-dsl/series/hash-or-array-serie-splitter.rb +13 -7
- data/lib/musa-dsl/series/main-serie-constructors.rb +44 -19
- data/lib/musa-dsl/series/main-serie-operations.rb +5 -7
- data/lib/musa-dsl/series/proxy-serie.rb +0 -4
- data/lib/musa-dsl/series/series-composer.rb +57 -7
- data/musa-dsl.gemspec +2 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 03b06753c72ecbea6d6b7b056996afa6defaa57e74edd389272728822c537e52
|
4
|
+
data.tar.gz: 6580590252818be5df7a5f42094a026897852e874ece2ce77e657a499255b2d1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 52a8bb01f12163cac1598946db6a60b10cb460894eac06952c82fb7b9eb32a76c6c05d1ff6b1c2133cd024253f3be5e100eec06c67afc6e0314d3bbbf2332bc2
|
7
|
+
data.tar.gz: a7eb355bb4d9e13523f4769d4f204f150d0eb59fb2adaf0ddc989750b42e3958f1422074d11d798df99d560990a5e005d748ad06d99205273af0bdf3cf12e5e2
|
data/Gemfile
CHANGED
@@ -9,7 +9,6 @@ module Musa
|
|
9
9
|
include Musa::Extension::SmartProcBinder
|
10
10
|
include Musa::Series::Serie.base
|
11
11
|
|
12
|
-
|
13
12
|
def initialize(transitions:, start:, finish: nil, random: nil)
|
14
13
|
@transitions = transitions.clone.freeze
|
15
14
|
|
@@ -21,6 +20,7 @@ module Musa
|
|
21
20
|
|
22
21
|
@procedure_binders = {}
|
23
22
|
|
23
|
+
mark_as_prototype!
|
24
24
|
init
|
25
25
|
end
|
26
26
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
module Musa
|
1
|
+
module Musa::Sequencer
|
2
2
|
class BaseSequencer
|
3
3
|
private def _every(interval, control, block_procedure_binder: nil, &block)
|
4
4
|
block ||= proc {}
|
@@ -84,4 +84,4 @@ module Musa; module Sequencer
|
|
84
84
|
|
85
85
|
private_constant :EveryControl
|
86
86
|
end
|
87
|
-
end
|
87
|
+
end
|
@@ -3,7 +3,7 @@ using Musa::Extension::Arrayfy
|
|
3
3
|
|
4
4
|
using Musa::Extension::InspectNice
|
5
5
|
|
6
|
-
module Musa
|
6
|
+
module Musa::Sequencer
|
7
7
|
class BaseSequencer
|
8
8
|
private def _move(every: nil,
|
9
9
|
from:, to: nil,
|
@@ -436,4 +436,4 @@ module Musa; module Sequencer
|
|
436
436
|
|
437
437
|
private_constant :MoveControl
|
438
438
|
end
|
439
|
-
end
|
439
|
+
end
|
@@ -3,11 +3,9 @@ using Musa::Extension::Arrayfy
|
|
3
3
|
|
4
4
|
using Musa::Extension::InspectNice
|
5
5
|
|
6
|
-
module Musa
|
6
|
+
module Musa::Sequencer
|
7
7
|
class BaseSequencer
|
8
|
-
private def _play_timed(timed_serie,
|
9
|
-
control,
|
10
|
-
&block)
|
8
|
+
private def _play_timed(timed_serie, control, &block)
|
11
9
|
|
12
10
|
if first_value_sample = timed_serie.peek_next_value
|
13
11
|
debug "_play_timed: first_value_sample #{first_value_sample}"
|
@@ -40,45 +38,52 @@ module Musa; module Sequencer
|
|
40
38
|
|
41
39
|
source_next_value = timed_serie.next_value
|
42
40
|
|
43
|
-
|
41
|
+
if source_next_value
|
42
|
+
affected_components = component_ids.select { |_| !source_next_value[:value][_].nil? }
|
44
43
|
|
45
|
-
|
46
|
-
|
44
|
+
if affected_components&.any?
|
45
|
+
time = source_next_value[:time]
|
47
46
|
|
48
|
-
|
49
|
-
|
50
|
-
|
47
|
+
values = hash_mode ? {} : []
|
48
|
+
extra_attributes = extra_attribute_names.collect { |_| [_, hash_mode ? {} : []] }.to_h
|
49
|
+
started_ago = hash_mode ? {} : []
|
51
50
|
|
52
|
-
|
53
|
-
|
51
|
+
affected_components.each do |component|
|
52
|
+
values[component] = source_next_value[:value][component]
|
54
53
|
|
55
|
-
|
56
|
-
|
54
|
+
extra_attribute_names.each do |attribute_name|
|
55
|
+
extra_attributes[attribute_name][component] = source_next_value[attribute_name][component]
|
56
|
+
end
|
57
|
+
|
58
|
+
last_positions[component] = _quantize_position(time, warn: false)
|
57
59
|
end
|
58
60
|
|
59
|
-
|
60
|
-
|
61
|
+
component_ids.each do |component|
|
62
|
+
if last_positions[component] && last_positions[component] != time
|
63
|
+
sa = _quantize_position(time, warn: false) - last_positions[component]
|
64
|
+
started_ago[component] = (sa == 0) ? nil : sa
|
65
|
+
end
|
66
|
+
end
|
61
67
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
68
|
+
_numeric_at _quantize_position(start_position + time, warn: true), control do
|
69
|
+
binder.call(values,
|
70
|
+
**extra_attributes,
|
71
|
+
time: start_position + time,
|
72
|
+
started_ago: started_ago,
|
73
|
+
control: control)
|
74
|
+
|
75
|
+
_play_timed_step(hash_mode,
|
76
|
+
component_ids, extra_attribute_names,
|
77
|
+
timed_serie,
|
78
|
+
start_position,
|
79
|
+
last_positions,
|
80
|
+
binder, control)
|
66
81
|
end
|
67
82
|
end
|
83
|
+
else
|
68
84
|
|
69
|
-
|
70
|
-
|
71
|
-
**extra_attributes,
|
72
|
-
time: start_position + time,
|
73
|
-
started_ago: started_ago,
|
74
|
-
control: control)
|
75
|
-
|
76
|
-
_play_timed_step(hash_mode,
|
77
|
-
component_ids, extra_attribute_names,
|
78
|
-
timed_serie,
|
79
|
-
start_position,
|
80
|
-
last_positions,
|
81
|
-
binder, control)
|
85
|
+
control.do_after.each do |do_after|
|
86
|
+
_numeric_at position + do_after[:bars], control, &do_after[:block]
|
82
87
|
end
|
83
88
|
end
|
84
89
|
end
|
@@ -107,5 +112,5 @@ module Musa; module Sequencer
|
|
107
112
|
|
108
113
|
private_constant :PlayTimedControl
|
109
114
|
end
|
110
|
-
end
|
115
|
+
end
|
111
116
|
|
@@ -5,7 +5,7 @@ using Musa::Extension::Arrayfy
|
|
5
5
|
|
6
6
|
using Musa::Extension::InspectNice
|
7
7
|
|
8
|
-
module Musa
|
8
|
+
module Musa::Sequencer
|
9
9
|
class BaseSequencer
|
10
10
|
private def _play(serie,
|
11
11
|
control,
|
@@ -175,4 +175,4 @@ module Musa; module Sequencer
|
|
175
175
|
|
176
176
|
private_constant :PlayControl
|
177
177
|
end
|
178
|
-
end
|
178
|
+
end
|
@@ -4,7 +4,7 @@ require_relative '../core-ext/smart-proc-binder'
|
|
4
4
|
using Musa::Extension::Arrayfy
|
5
5
|
using Musa::Extension::DeepCopy
|
6
6
|
|
7
|
-
module Musa
|
7
|
+
module Musa::Sequencer
|
8
8
|
class BaseSequencer
|
9
9
|
include Musa::Extension::SmartProcBinder
|
10
10
|
include Musa::Extension::DeepCopy
|
@@ -214,4 +214,4 @@ module Musa; module Sequencer
|
|
214
214
|
|
215
215
|
private_constant :EventHandler
|
216
216
|
end
|
217
|
-
end
|
217
|
+
end
|
@@ -12,24 +12,36 @@ module Musa
|
|
12
12
|
|
13
13
|
module Serie
|
14
14
|
def self.base
|
15
|
-
|
15
|
+
Module.new do
|
16
|
+
include SerieImplementation
|
17
|
+
|
18
|
+
def has_source; false; end
|
19
|
+
private def mandatory_source; false; end
|
20
|
+
|
21
|
+
def has_sources; false; end
|
22
|
+
private def mandatory_sources; false; end
|
23
|
+
end
|
16
24
|
end
|
17
25
|
|
18
26
|
def self.with(source: false,
|
19
27
|
source_as: nil,
|
20
28
|
private_source: nil,
|
29
|
+
mandatory_source: nil,
|
21
30
|
sources: false,
|
22
31
|
sources_as: nil,
|
23
32
|
private_sources: nil,
|
33
|
+
mandatory_sources: nil,
|
24
34
|
smart_block: false,
|
25
35
|
block: false,
|
26
36
|
block_as: nil)
|
27
37
|
|
28
38
|
source_as ||= :source
|
29
39
|
source_setter = (source_as.to_s + '=').to_sym
|
40
|
+
_mandatory_source = source if mandatory_source.nil?
|
30
41
|
|
31
42
|
sources_as ||= :sources
|
32
43
|
sources_setter = (sources_as.to_s + '=').to_sym
|
44
|
+
_mandatory_sources = sources if mandatory_sources.nil?
|
33
45
|
|
34
46
|
block_as ||= :proc
|
35
47
|
block_setter = (block_as.to_s + '=').to_sym
|
@@ -38,15 +50,19 @@ module Musa
|
|
38
50
|
include SerieImplementation
|
39
51
|
|
40
52
|
if source
|
53
|
+
private def has_source; true; end
|
54
|
+
define_method(:mandatory_source) { _mandatory_source }
|
55
|
+
private :mandatory_source
|
56
|
+
|
41
57
|
define_method source_as do
|
42
58
|
@source
|
43
59
|
end
|
44
60
|
|
45
61
|
define_method source_setter do |serie|
|
46
|
-
|
62
|
+
unless @source.nil? || @source.undefined? || serie.state == @source.state
|
63
|
+
raise ArgumentError, "New serie for #{source_as} should be a #{@state} instead of a #{serie.state}"
|
64
|
+
end
|
47
65
|
|
48
|
-
serie ||= Musa::Series::Constructors.NIL
|
49
|
-
@get = serie&.instance? ? :instance : :prototype
|
50
66
|
@source = serie
|
51
67
|
mark_regarding! @source
|
52
68
|
end
|
@@ -55,45 +71,49 @@ module Musa
|
|
55
71
|
private source_as
|
56
72
|
private source_setter
|
57
73
|
end
|
74
|
+
else
|
75
|
+
private def has_source; false; end
|
76
|
+
private def mandatory_source; false; end
|
58
77
|
end
|
59
78
|
|
60
79
|
if sources
|
61
|
-
|
80
|
+
private def has_sources; true; end
|
81
|
+
define_method(:mandatory_sources) { _mandatory_sources }
|
82
|
+
private :mandatory_source
|
83
|
+
|
84
|
+
define_method sources_as do
|
62
85
|
@sources
|
63
86
|
end
|
64
87
|
|
65
88
|
define_method sources_setter do |series|
|
66
|
-
|
67
|
-
|
68
|
-
getter = @get || ((series.first)&.instance? ? :instance : :prototype)
|
69
|
-
@sources = series.collect(&getter)
|
70
|
-
when Hash
|
71
|
-
getter = @get || ((series.values.first)&.instance? ? :instance : :prototype)
|
72
|
-
@sources = series.transform_values(&getter)
|
73
|
-
else
|
74
|
-
raise ArgumentError, "Only allowed Array or Hash"
|
89
|
+
unless series.is_a?(Hash) || series.is_a?(Array)
|
90
|
+
raise ArgumentError, "New series for #{sources_as} should be a Hash or an Array instead of a #{series.class.name}"
|
75
91
|
end
|
76
92
|
|
77
|
-
|
93
|
+
@sources = series
|
94
|
+
try_to_resolve_undefined_state_if_needed
|
78
95
|
end
|
79
96
|
|
80
97
|
if private_sources
|
81
98
|
private sources_as
|
82
99
|
private sources_setter
|
83
100
|
end
|
101
|
+
else
|
102
|
+
private def has_sources; false; end
|
103
|
+
private def mandatory_sources; false; end
|
84
104
|
end
|
85
105
|
|
86
106
|
if smart_block
|
87
107
|
define_method block_as do |&block|
|
88
108
|
if block
|
89
|
-
@block =
|
109
|
+
@block = Extension::SmartProcBinder::SmartProcBinder.new(block)
|
90
110
|
else
|
91
111
|
@block.proc
|
92
112
|
end
|
93
113
|
end
|
94
114
|
|
95
115
|
define_method block_setter do |block|
|
96
|
-
@block =
|
116
|
+
@block = Extension::SmartProcBinder::SmartProcBinder.new(block)
|
97
117
|
end
|
98
118
|
|
99
119
|
elsif block
|
@@ -113,35 +133,53 @@ module Musa
|
|
113
133
|
end
|
114
134
|
|
115
135
|
module Prototyping
|
136
|
+
def state
|
137
|
+
try_to_resolve_undefined_state_if_needed
|
138
|
+
@state || :undefined
|
139
|
+
end
|
140
|
+
|
116
141
|
def prototype?
|
117
|
-
|
142
|
+
try_to_resolve_undefined_state_if_needed
|
143
|
+
@state&.==(:prototype)
|
118
144
|
end
|
119
145
|
|
120
146
|
def instance?
|
121
|
-
|
147
|
+
try_to_resolve_undefined_state_if_needed
|
148
|
+
@state&.==(:instance)
|
149
|
+
end
|
150
|
+
|
151
|
+
def undefined?
|
152
|
+
try_to_resolve_undefined_state_if_needed
|
153
|
+
@state.nil? || @state == :undefined
|
154
|
+
end
|
155
|
+
|
156
|
+
def defined?
|
157
|
+
!undefined?
|
122
158
|
end
|
123
159
|
|
124
160
|
def prototype
|
125
|
-
|
126
|
-
if !@instance_of
|
127
|
-
@instance_of = clone
|
128
|
-
@instance_of._prototype!
|
129
|
-
@instance_of.mark_as_prototype!
|
130
|
-
@instance_of.init if @instance_of.respond_to?(:init)
|
131
|
-
end
|
161
|
+
try_to_resolve_undefined_state_if_needed
|
132
162
|
|
163
|
+
if prototype?
|
164
|
+
self
|
165
|
+
elsif instance?
|
166
|
+
# if the series has been directly created as an instance (i.e., because is an operation over an instance)
|
167
|
+
# the prototype doesn't exist.
|
168
|
+
#
|
133
169
|
@instance_of
|
134
170
|
else
|
135
|
-
|
171
|
+
raise PrototypingError, 'Can\'t get the prototype of an undefined serie'
|
136
172
|
end
|
137
173
|
end
|
138
174
|
|
139
175
|
alias_method :p, :prototype
|
140
176
|
|
141
177
|
def instance
|
142
|
-
|
178
|
+
try_to_resolve_undefined_state_if_needed
|
179
|
+
|
180
|
+
if instance?
|
143
181
|
self
|
144
|
-
|
182
|
+
elsif prototype?
|
145
183
|
new_instance = clone
|
146
184
|
|
147
185
|
new_instance._instance!
|
@@ -149,6 +187,8 @@ module Musa
|
|
149
187
|
new_instance.init if new_instance.respond_to?(:init)
|
150
188
|
|
151
189
|
new_instance
|
190
|
+
else
|
191
|
+
raise PrototypingError, 'Can\'t get an instance of an undefined serie'
|
152
192
|
end
|
153
193
|
end
|
154
194
|
|
@@ -163,61 +203,128 @@ module Musa
|
|
163
203
|
protected def _prototype!
|
164
204
|
@source = @source.prototype if @source
|
165
205
|
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
end
|
206
|
+
case @sources
|
207
|
+
when Array
|
208
|
+
@sources = @sources.collect(&:prototype)
|
209
|
+
when Hash
|
210
|
+
@sources = @sources.transform_values(&:prototype)
|
172
211
|
end
|
173
212
|
end
|
174
213
|
|
175
214
|
protected def _instance!
|
176
215
|
@source = @source.instance if @source
|
177
216
|
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
end
|
217
|
+
case @sources
|
218
|
+
when Array
|
219
|
+
@sources = @sources.collect(&:instance)
|
220
|
+
when Hash
|
221
|
+
@sources = @sources.transform_values(&:instance)
|
184
222
|
end
|
185
223
|
end
|
186
224
|
|
187
|
-
protected def mark_as!(
|
188
|
-
case
|
225
|
+
protected def mark_as!(state)
|
226
|
+
case state
|
227
|
+
when nil, :undefined
|
228
|
+
mark_as_undefined!
|
189
229
|
when :prototype
|
190
230
|
mark_as_prototype!
|
191
231
|
when :instance
|
192
232
|
mark_as_instance!
|
193
233
|
else
|
194
|
-
raise ArgumentError, "
|
234
|
+
raise ArgumentError, "Unexpected state #{state}. Only accepted nil, :undefined, :prototype or :instance."
|
195
235
|
end
|
196
236
|
end
|
197
237
|
|
198
238
|
protected def mark_regarding!(source)
|
199
|
-
if source.
|
239
|
+
if source.nil? || source.undefined?
|
240
|
+
mark_as_undefined!
|
241
|
+
elsif source.prototype?
|
200
242
|
mark_as_prototype!
|
201
|
-
|
243
|
+
elsif source.instance?
|
202
244
|
mark_as_instance!
|
203
245
|
end
|
204
246
|
end
|
205
247
|
|
248
|
+
protected def mark_as_undefined!
|
249
|
+
@state = :undefined
|
250
|
+
self
|
251
|
+
end
|
252
|
+
|
206
253
|
protected def mark_as_prototype!
|
207
|
-
|
254
|
+
notify = @state != :prototype
|
208
255
|
|
209
|
-
@
|
256
|
+
@state = :prototype
|
257
|
+
|
258
|
+
_sources_resolved if notify
|
210
259
|
self
|
211
260
|
end
|
212
261
|
|
213
262
|
protected def mark_as_instance!(prototype = nil)
|
214
|
-
|
263
|
+
notify = @state != :instance
|
215
264
|
|
265
|
+
@state = :instance
|
216
266
|
@instance_of = prototype
|
217
|
-
|
267
|
+
|
268
|
+
_sources_resolved if notify
|
218
269
|
self
|
219
270
|
end
|
220
271
|
|
272
|
+
protected def _sources_resolved; end
|
273
|
+
|
274
|
+
private def try_to_resolve_undefined_state_if_needed
|
275
|
+
|
276
|
+
return unless @state.nil? || @state == :undefined
|
277
|
+
|
278
|
+
states = []
|
279
|
+
|
280
|
+
if has_source
|
281
|
+
if mandatory_source
|
282
|
+
states << @source&.state || :undefined
|
283
|
+
elsif @source
|
284
|
+
states << @source.state
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
if has_sources
|
289
|
+
sources = case @sources
|
290
|
+
when Array
|
291
|
+
@sources
|
292
|
+
when Hash
|
293
|
+
@sources.values
|
294
|
+
when nil
|
295
|
+
[]
|
296
|
+
end
|
297
|
+
|
298
|
+
undefined_sources =
|
299
|
+
sources.empty? ||
|
300
|
+
sources.any?(&:undefined?) ||
|
301
|
+
sources.any?(&:instance?) && sources.any?(&:prototype?)
|
302
|
+
|
303
|
+
instance_sources = sources.all?(&:instance?) unless undefined_sources
|
304
|
+
|
305
|
+
sources_state = if undefined_sources
|
306
|
+
:undefined
|
307
|
+
elsif instance_sources
|
308
|
+
:instance
|
309
|
+
else
|
310
|
+
:prototype
|
311
|
+
end
|
312
|
+
|
313
|
+
if mandatory_sources
|
314
|
+
states << sources_state
|
315
|
+
elsif !(@sources.nil? || @sources.empty?)
|
316
|
+
states << sources_state
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
# in case of having source and sources, if both states are equal the final state is that one, else the final state is undefined
|
321
|
+
#
|
322
|
+
new_state = states.first if states.first == states.last
|
323
|
+
new_state ||= :undefined
|
324
|
+
|
325
|
+
mark_as!(new_state)
|
326
|
+
end
|
327
|
+
|
221
328
|
class PrototypingError < RuntimeError
|
222
329
|
def initialize(message = nil)
|
223
330
|
message ||= 'This serie is a prototype serie: cannot be consumed. To consume the serie use an instance serie via .instance method'
|
@@ -245,7 +352,7 @@ module Musa
|
|
245
352
|
private def _init; end
|
246
353
|
|
247
354
|
def restart(...)
|
248
|
-
|
355
|
+
check_state_permissions
|
249
356
|
init
|
250
357
|
_restart(...)
|
251
358
|
|
@@ -255,7 +362,7 @@ module Musa
|
|
255
362
|
private def _restart; end
|
256
363
|
|
257
364
|
def next_value
|
258
|
-
|
365
|
+
check_state_permissions
|
259
366
|
|
260
367
|
unless @_have_current_value && @_current_value.nil?
|
261
368
|
if @_have_peeked_next_value
|
@@ -274,7 +381,7 @@ module Musa
|
|
274
381
|
alias_method :v, :next_value
|
275
382
|
|
276
383
|
def peek_next_value
|
277
|
-
|
384
|
+
check_state_permissions
|
278
385
|
|
279
386
|
if !@_have_peeked_next_value
|
280
387
|
@_have_peeked_next_value = true
|
@@ -285,16 +392,20 @@ module Musa
|
|
285
392
|
end
|
286
393
|
|
287
394
|
def current_value
|
288
|
-
|
395
|
+
check_state_permissions
|
289
396
|
|
290
397
|
@_current_value
|
291
398
|
end
|
292
399
|
|
293
400
|
def infinite?
|
401
|
+
check_state_permissions(allows_prototype: true)
|
294
402
|
@source&.infinite? || false
|
295
403
|
end
|
296
404
|
|
297
405
|
def to_a(duplicate: nil, recursive: nil, restart: nil, dr: nil)
|
406
|
+
check_state_permissions(allows_prototype: true)
|
407
|
+
raise 'Cannot convert to array an infinite serie' if infinite?
|
408
|
+
|
298
409
|
recursive ||= false
|
299
410
|
|
300
411
|
dr = instance? if dr.nil?
|
@@ -302,8 +413,6 @@ module Musa
|
|
302
413
|
duplicate = dr if duplicate.nil?
|
303
414
|
restart = dr if restart.nil?
|
304
415
|
|
305
|
-
raise 'Cannot convert to array an infinite serie' if infinite?
|
306
|
-
|
307
416
|
array = []
|
308
417
|
|
309
418
|
serie = instance
|
@@ -324,12 +433,37 @@ module Musa
|
|
324
433
|
|
325
434
|
alias_method :a, :to_a
|
326
435
|
|
436
|
+
private def process_for_to_a(value)
|
437
|
+
case value
|
438
|
+
when Serie
|
439
|
+
value.to_a(recursive: true, restart: false, duplicate: false)
|
440
|
+
when Array
|
441
|
+
a = value.clone
|
442
|
+
a.collect! { |v| v.is_a?(Serie) ? v.to_a(recursive: true, restart: false, duplicate: false) : process_for_to_a(v) }
|
443
|
+
when Hash
|
444
|
+
h = value.clone
|
445
|
+
h.transform_values! { |v| v.is_a?(Serie) ? v.to_a(recursive: true, restart: false, duplicate: false) : process_for_to_a(v) }
|
446
|
+
else
|
447
|
+
value
|
448
|
+
end
|
449
|
+
end
|
450
|
+
|
327
451
|
def to_node(**attributes)
|
328
452
|
Nodificator.to_node(self, **attributes)
|
329
453
|
end
|
330
454
|
|
331
455
|
alias_method :node, :to_node
|
332
456
|
|
457
|
+
private def check_state_permissions(allows_prototype: nil)
|
458
|
+
try_to_resolve_undefined_state_if_needed
|
459
|
+
|
460
|
+
raise PrototypingError if !allows_prototype && prototype?
|
461
|
+
|
462
|
+
unless instance? || prototype?
|
463
|
+
raise PrototypingError, 'This serie is in undefined state: cannot be consumed. To consume the serie be sure the serie\'s sources are all in a defined state.'
|
464
|
+
end
|
465
|
+
end
|
466
|
+
|
333
467
|
class Nodificator
|
334
468
|
extend Musa::GenerativeGrammar
|
335
469
|
|
@@ -339,21 +473,6 @@ module Musa
|
|
339
473
|
end
|
340
474
|
|
341
475
|
private_constant :Nodificator
|
342
|
-
|
343
|
-
private def process_for_to_a(value)
|
344
|
-
case value
|
345
|
-
when Serie
|
346
|
-
value.to_a(recursive: true, restart: false, duplicate: false)
|
347
|
-
when Array
|
348
|
-
a = value.clone
|
349
|
-
a.collect! { |v| v.is_a?(Serie) ? v.to_a(recursive: true, restart: false, duplicate: false) : process_for_to_a(v) }
|
350
|
-
when Hash
|
351
|
-
h = value.clone
|
352
|
-
h.transform_values! { |v| v.is_a?(Serie) ? v.to_a(recursive: true, restart: false, duplicate: false) : process_for_to_a(v) }
|
353
|
-
else
|
354
|
-
value
|
355
|
-
end
|
356
|
-
end
|
357
476
|
end
|
358
477
|
|
359
478
|
private_constant :SerieImplementation
|
@@ -30,7 +30,7 @@ module Musa
|
|
30
30
|
|
31
31
|
def buffer
|
32
32
|
@buffer ||= Buffer.new(@history)
|
33
|
-
@buffer.send(
|
33
|
+
@buffer.send(state).tap { |_| @buffers << _ }
|
34
34
|
end
|
35
35
|
|
36
36
|
private def clear_old_history
|
@@ -51,6 +51,7 @@ module Musa
|
|
51
51
|
def initialize(history)
|
52
52
|
@history = history
|
53
53
|
@last_nil_index = -1
|
54
|
+
mark_as_prototype!
|
54
55
|
init
|
55
56
|
end
|
56
57
|
|
@@ -102,19 +103,31 @@ module Musa
|
|
102
103
|
@nils = [0]
|
103
104
|
@buffers = Set[]
|
104
105
|
|
105
|
-
@singleton = nil
|
106
106
|
@buffer = nil
|
107
107
|
|
108
108
|
init
|
109
109
|
end
|
110
110
|
|
111
|
-
def
|
112
|
-
|
111
|
+
def buffer
|
112
|
+
Buffer.new(self)
|
113
113
|
end
|
114
114
|
|
115
|
-
def
|
116
|
-
|
117
|
-
|
115
|
+
def _sources_resolved
|
116
|
+
(prototype || self).singleton = self if instance?
|
117
|
+
end
|
118
|
+
|
119
|
+
protected def singleton=(the_instance)
|
120
|
+
@singleton ||= the_instance
|
121
|
+
end
|
122
|
+
|
123
|
+
def singleton
|
124
|
+
if instance?
|
125
|
+
prototype.nil? ? @singleton : prototype.singleton
|
126
|
+
elsif prototype?
|
127
|
+
@singleton
|
128
|
+
else
|
129
|
+
raise "ES UNDEFINED!"
|
130
|
+
end
|
118
131
|
end
|
119
132
|
|
120
133
|
private def _restart(buffer)
|
@@ -163,9 +176,7 @@ module Musa
|
|
163
176
|
private def clear_old_history
|
164
177
|
min_last_nil_index = @buffers.collect(&:last_nil_index).min
|
165
178
|
|
166
|
-
if min_last_nil_index && min_last_nil_index >=0
|
167
|
-
|
168
|
-
pre_nils = @nils.clone
|
179
|
+
if min_last_nil_index && min_last_nil_index >= 0
|
169
180
|
@history = @history.drop(min_last_nil_index)
|
170
181
|
|
171
182
|
@nils.collect! { |_| _ - min_last_nil_index }
|
@@ -182,9 +193,6 @@ module Musa
|
|
182
193
|
|
183
194
|
def initialize(base)
|
184
195
|
self.source = base
|
185
|
-
|
186
|
-
mark_as_prototype! # necesario para que se creen instancias diferentes cada vez que se ejecute BufferSerie.buffer()
|
187
|
-
|
188
196
|
init
|
189
197
|
end
|
190
198
|
|
@@ -198,13 +206,18 @@ module Musa
|
|
198
206
|
@index -= offset
|
199
207
|
end
|
200
208
|
|
201
|
-
private def _init
|
202
|
-
|
209
|
+
# private def _init
|
210
|
+
# @source.prototype.singleton._register(self) if instance?
|
211
|
+
# @index = @last_nil_index
|
212
|
+
# end
|
213
|
+
#
|
214
|
+
private def _sources_resolved
|
215
|
+
@source.singleton._register(self) if instance?
|
203
216
|
@index = @last_nil_index
|
204
217
|
end
|
205
218
|
|
206
219
|
private def _restart
|
207
|
-
@source.restart(self)
|
220
|
+
@source.singleton.restart(self)
|
208
221
|
@needs_restart = false
|
209
222
|
end
|
210
223
|
|
@@ -216,7 +229,7 @@ module Musa
|
|
216
229
|
@index += 1
|
217
230
|
value = @history[@index]
|
218
231
|
else
|
219
|
-
value = _next_value unless @source.next_value.nil?
|
232
|
+
value = _next_value unless @source.singleton.next_value.nil?
|
220
233
|
end
|
221
234
|
|
222
235
|
if value.nil?
|
@@ -5,26 +5,30 @@ module Musa
|
|
5
5
|
end
|
6
6
|
|
7
7
|
class Splitter
|
8
|
+
include Series::Serie.with(source: true)
|
8
9
|
include Enumerable
|
9
|
-
|
10
|
+
|
11
|
+
private def has_source; true; end
|
12
|
+
private def has_sources; false; end
|
10
13
|
|
11
14
|
def initialize(source)
|
12
|
-
|
15
|
+
self.source = source
|
13
16
|
@series = {}
|
17
|
+
|
18
|
+
init
|
14
19
|
end
|
15
20
|
|
16
21
|
def source=(serie)
|
17
|
-
|
22
|
+
super
|
18
23
|
@proxy.source = @source if @proxy
|
19
24
|
end
|
20
25
|
|
21
|
-
|
22
|
-
super
|
26
|
+
def _sources_resolved
|
23
27
|
@proxy = SplitterProxy.new(@source)
|
24
28
|
end
|
25
29
|
|
26
30
|
def [](key_or_index)
|
27
|
-
raise "Can't get a component because Splitter is a prototype. To get a component you need a Splitter instance." unless
|
31
|
+
raise "Can't get a component because Splitter is a prototype. To get a component you need a Splitter instance." unless instance?
|
28
32
|
|
29
33
|
if @series.key?(key_or_index)
|
30
34
|
@series[key_or_index]
|
@@ -34,7 +38,7 @@ module Musa
|
|
34
38
|
end
|
35
39
|
|
36
40
|
def each
|
37
|
-
raise "Can't iterate because Splitter is
|
41
|
+
raise "Can't iterate because Splitter is in state '#{state}'. To iterate you need a Splitter in state 'instance'." unless instance?
|
38
42
|
|
39
43
|
if block_given?
|
40
44
|
if @proxy.hash_mode?
|
@@ -162,6 +166,8 @@ module Musa
|
|
162
166
|
end
|
163
167
|
end
|
164
168
|
|
169
|
+
private_constant :SplitterProxy
|
170
|
+
|
165
171
|
class Split
|
166
172
|
include Series::Serie.base
|
167
173
|
|
@@ -10,6 +10,10 @@ using Musa::Extension::ExplodeRanges
|
|
10
10
|
|
11
11
|
module Musa
|
12
12
|
module Series::Constructors
|
13
|
+
def UNDEFINED
|
14
|
+
UndefinedSerie.new
|
15
|
+
end
|
16
|
+
|
13
17
|
def NIL
|
14
18
|
NilSerie.new
|
15
19
|
end
|
@@ -44,10 +48,14 @@ module Musa
|
|
44
48
|
ForLoop.new from, to, step
|
45
49
|
end
|
46
50
|
|
47
|
-
def RND(*values, from: nil, to: nil, step: nil, random: nil)
|
51
|
+
def RND(*_values, values: nil, from: nil, to: nil, step: nil, random: nil)
|
52
|
+
raise ArgumentError, "Can't use both direct values #{_values} and values named parameter #{values} at the same time." if values && !_values.empty?
|
53
|
+
|
48
54
|
random = Random.new random if random.is_a?(Integer)
|
49
55
|
random ||= Random.new
|
50
56
|
|
57
|
+
values ||= _values
|
58
|
+
|
51
59
|
if !values.empty? && from.nil? && to.nil? && step.nil?
|
52
60
|
RandomValuesFromArray.new values.explode_ranges, random
|
53
61
|
elsif values.empty? && !to.nil?
|
@@ -63,10 +71,14 @@ module Musa
|
|
63
71
|
Sequence.new(series)
|
64
72
|
end
|
65
73
|
|
66
|
-
def RND1(*values, from: nil, to: nil, step: nil, random: nil)
|
74
|
+
def RND1(*_values, values: nil, from: nil, to: nil, step: nil, random: nil)
|
75
|
+
raise ArgumentError, "Can't use both direct values #{_values} and values named parameter #{values} at the same time." if values && !_values.empty?
|
76
|
+
|
67
77
|
random = Random.new random if random.is_a?(Integer)
|
68
78
|
random ||= Random.new
|
69
79
|
|
80
|
+
values ||= _values
|
81
|
+
|
70
82
|
if !values.empty? && from.nil? && to.nil? && step.nil?
|
71
83
|
RandomValueFromArray.new values.explode_ranges, random
|
72
84
|
elsif values.empty? && !to.nil?
|
@@ -99,8 +111,22 @@ module Musa
|
|
99
111
|
### Implementation
|
100
112
|
###
|
101
113
|
|
114
|
+
class UndefinedSerie
|
115
|
+
include Series::Serie.base
|
116
|
+
|
117
|
+
def initialize
|
118
|
+
mark_as_undefined!
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
private_constant :UndefinedSerie
|
123
|
+
|
102
124
|
class NilSerie
|
103
|
-
include
|
125
|
+
include Series::Serie.base
|
126
|
+
|
127
|
+
def initialize
|
128
|
+
mark_as_prototype!
|
129
|
+
end
|
104
130
|
|
105
131
|
def _next_value; nil; end
|
106
132
|
end
|
@@ -108,7 +134,7 @@ module Musa
|
|
108
134
|
private_constant :NilSerie
|
109
135
|
|
110
136
|
class FromArray
|
111
|
-
include
|
137
|
+
include Series::Serie.base
|
112
138
|
|
113
139
|
def initialize(values = nil, extends = nil)
|
114
140
|
@values = values
|
@@ -143,15 +169,14 @@ module Musa
|
|
143
169
|
# private_constant :FromArray
|
144
170
|
|
145
171
|
class Sequence
|
146
|
-
include
|
172
|
+
include Series::Serie.with(sources: true)
|
147
173
|
|
148
174
|
def initialize(series)
|
149
175
|
self.sources = series
|
150
|
-
|
151
176
|
init
|
152
177
|
end
|
153
178
|
|
154
|
-
|
179
|
+
attr_reader :sources
|
155
180
|
|
156
181
|
private def _init
|
157
182
|
@index = 0
|
@@ -189,9 +214,9 @@ module Musa
|
|
189
214
|
private_constant :Sequence
|
190
215
|
|
191
216
|
class FromEvalBlockWithParameters
|
192
|
-
include
|
217
|
+
include Series::Serie.with(smart_block: true)
|
193
218
|
|
194
|
-
using
|
219
|
+
using Extension::DeepCopy
|
195
220
|
|
196
221
|
def initialize(*parameters, **key_parameters, &block)
|
197
222
|
raise ArgumentError, 'Yield block is undefined' unless block
|
@@ -245,7 +270,7 @@ module Musa
|
|
245
270
|
private_constant :FromEvalBlockWithParameters
|
246
271
|
|
247
272
|
class ForLoop
|
248
|
-
include
|
273
|
+
include Series::Serie.base
|
249
274
|
|
250
275
|
def initialize(from, to, step)
|
251
276
|
@from = from
|
@@ -303,7 +328,7 @@ module Musa
|
|
303
328
|
private_constant :ForLoop
|
304
329
|
|
305
330
|
class RandomValueFromArray
|
306
|
-
include
|
331
|
+
include Series::Serie.base
|
307
332
|
|
308
333
|
def initialize(values, random)
|
309
334
|
@values = values
|
@@ -332,7 +357,7 @@ module Musa
|
|
332
357
|
private_constant :RandomValueFromArray
|
333
358
|
|
334
359
|
class RandomNumberFromRange
|
335
|
-
include
|
360
|
+
include Series::Serie.base
|
336
361
|
|
337
362
|
def initialize(from, to, step, random)
|
338
363
|
@from = from
|
@@ -392,7 +417,7 @@ module Musa
|
|
392
417
|
private_constant :RandomNumberFromRange
|
393
418
|
|
394
419
|
class RandomValuesFromArray
|
395
|
-
include
|
420
|
+
include Series::Serie.base
|
396
421
|
|
397
422
|
def initialize(values, random)
|
398
423
|
@values = values.clone.freeze
|
@@ -424,7 +449,7 @@ module Musa
|
|
424
449
|
private_constant :RandomValuesFromArray
|
425
450
|
|
426
451
|
class RandomNumbersFromRange
|
427
|
-
include
|
452
|
+
include Series::Serie.base
|
428
453
|
|
429
454
|
def initialize(from, to, step, random)
|
430
455
|
@from = from
|
@@ -486,7 +511,7 @@ module Musa
|
|
486
511
|
private_constant :RandomNumbersFromRange
|
487
512
|
|
488
513
|
class FromHashOfSeries
|
489
|
-
include
|
514
|
+
include Series::Serie.with(sources: true)
|
490
515
|
|
491
516
|
def initialize(hash_of_series, cycle_all_series)
|
492
517
|
self.sources = hash_of_series
|
@@ -545,7 +570,7 @@ module Musa
|
|
545
570
|
private_constant :FromHashOfSeries
|
546
571
|
|
547
572
|
class FromArrayOfSeries
|
548
|
-
include
|
573
|
+
include Series::Serie.with(sources: true)
|
549
574
|
|
550
575
|
def initialize(series_array, cycle_all_series)
|
551
576
|
self.sources = series_array
|
@@ -604,7 +629,7 @@ module Musa
|
|
604
629
|
private_constant :FromArrayOfSeries
|
605
630
|
|
606
631
|
class SinFunction
|
607
|
-
include
|
632
|
+
include Series::Serie.base
|
608
633
|
|
609
634
|
def initialize(start, steps, amplitude, center)
|
610
635
|
@start = start.to_f
|
@@ -679,7 +704,7 @@ module Musa
|
|
679
704
|
private_constant :SinFunction
|
680
705
|
|
681
706
|
class Fibonacci
|
682
|
-
include
|
707
|
+
include Series::Serie.base
|
683
708
|
|
684
709
|
def initialize
|
685
710
|
mark_as_prototype!
|
@@ -707,7 +732,7 @@ module Musa
|
|
707
732
|
private_constant :Fibonacci
|
708
733
|
|
709
734
|
class HarmonicNotes
|
710
|
-
include
|
735
|
+
include Series::Serie.base
|
711
736
|
|
712
737
|
def initialize(error, extended)
|
713
738
|
@error = error
|
@@ -125,7 +125,9 @@ module Musa
|
|
125
125
|
###
|
126
126
|
|
127
127
|
class ProcessWith
|
128
|
-
include Serie.with(source: true,
|
128
|
+
include Serie.with(source: true,
|
129
|
+
sources: true, sources_as: :with_sources, mandatory_sources: false,
|
130
|
+
smart_block: true)
|
129
131
|
|
130
132
|
def initialize(serie, with_series = nil, on_restart = nil, &block)
|
131
133
|
self.source = serie
|
@@ -800,12 +802,6 @@ module Musa
|
|
800
802
|
init
|
801
803
|
end
|
802
804
|
|
803
|
-
def source=(serie)
|
804
|
-
raise ArgumentError, "A serie to reverse can't be infinite" if serie.infinite?
|
805
|
-
super
|
806
|
-
init
|
807
|
-
end
|
808
|
-
|
809
805
|
private def _init
|
810
806
|
@reversed = nil
|
811
807
|
end
|
@@ -815,6 +811,8 @@ module Musa
|
|
815
811
|
end
|
816
812
|
|
817
813
|
private def _next_value
|
814
|
+
raise ArgumentError, "A serie to reverse can't be infinite" if @source.infinite?
|
815
|
+
|
818
816
|
@reversed ||= Constructors.S(*next_values_array_of(@source).reverse).instance
|
819
817
|
@reversed.next_value
|
820
818
|
end
|
@@ -6,7 +6,33 @@ module Musa
|
|
6
6
|
module Series
|
7
7
|
module Operations
|
8
8
|
def composer(&block)
|
9
|
-
|
9
|
+
ComposerAsOperationSerie.new(self, &block)
|
10
|
+
end
|
11
|
+
|
12
|
+
class ComposerAsOperationSerie
|
13
|
+
include Serie.with(source: true)
|
14
|
+
|
15
|
+
def initialize(serie, &block)
|
16
|
+
self.source = serie
|
17
|
+
@block = block
|
18
|
+
|
19
|
+
init
|
20
|
+
end
|
21
|
+
|
22
|
+
attr_reader :composer
|
23
|
+
|
24
|
+
private def _init
|
25
|
+
@composer = Composer::Composer.new(input: @source, &@block)
|
26
|
+
@output = @composer.output
|
27
|
+
end
|
28
|
+
|
29
|
+
private def _restart
|
30
|
+
@output.restart
|
31
|
+
end
|
32
|
+
|
33
|
+
private def _next_value
|
34
|
+
@output.next_value
|
35
|
+
end
|
10
36
|
end
|
11
37
|
end
|
12
38
|
|
@@ -14,9 +40,22 @@ module Musa
|
|
14
40
|
class Composer
|
15
41
|
using Musa::Extension::Arrayfy
|
16
42
|
|
17
|
-
def initialize(inputs: [:input], outputs: [:output], auto_commit: nil, &block)
|
43
|
+
def initialize(input: nil, inputs: [:input], outputs: [:output], auto_commit: nil, &block)
|
18
44
|
auto_commit = true if auto_commit.nil?
|
19
45
|
|
46
|
+
inputs = case inputs
|
47
|
+
when Array
|
48
|
+
inputs.collect { |_| [_, nil] }.to_h
|
49
|
+
when nil
|
50
|
+
{}
|
51
|
+
when Hash
|
52
|
+
inputs
|
53
|
+
else
|
54
|
+
raise ArgumentError, "inputs: expected a Hash with input names and source series { name: serie, ... } or an Array with names [name, ...] but received #{inputs}"
|
55
|
+
end
|
56
|
+
|
57
|
+
inputs[:input] = input if input
|
58
|
+
|
20
59
|
@pipelines = {}
|
21
60
|
|
22
61
|
def @pipelines.[]=(name, pipeline)
|
@@ -28,8 +67,9 @@ module Musa
|
|
28
67
|
@inputs = {}
|
29
68
|
@outputs = {}
|
30
69
|
|
31
|
-
inputs&.each do |input|
|
32
|
-
p = PROXY()
|
70
|
+
inputs.keys&.each do |input|
|
71
|
+
p = PROXY(inputs[input])
|
72
|
+
|
33
73
|
@inputs[input] = @pipelines[input] = Pipeline.new(input, input: p, output: p.buffered, pipelines: @pipelines)
|
34
74
|
|
35
75
|
@dsl.define_singleton_method(input) { input }
|
@@ -104,7 +144,8 @@ module Musa
|
|
104
144
|
end
|
105
145
|
|
106
146
|
def commit!
|
107
|
-
first_serie_operation = @first_proc&.call(
|
147
|
+
first_serie_operation = @first_proc&.call(UNDEFINED())
|
148
|
+
|
108
149
|
@input ||= first_serie_operation
|
109
150
|
|
110
151
|
@routes.each_value do |route|
|
@@ -241,9 +282,18 @@ module Musa
|
|
241
282
|
when Proc
|
242
283
|
call_constructor_according_to_last_and_parameter(last.call, constructor, parameter)
|
243
284
|
|
285
|
+
when UndefinedSerie
|
286
|
+
case parameter
|
287
|
+
when Hash
|
288
|
+
Musa::Series::Constructors.method(constructor).call(**parameter)
|
289
|
+
when Array
|
290
|
+
Musa::Series::Constructors.method(constructor).call(*parameter)
|
291
|
+
else
|
292
|
+
raise "Unexpected parameter #{parameter} for constructor #{constructor}"
|
293
|
+
end
|
294
|
+
|
244
295
|
when Serie
|
245
|
-
|
246
|
-
Musa::Series::Constructors.method(constructor).call(*parameter)
|
296
|
+
raise "Unexpected source serie #{last} for constructor #{constructor}"
|
247
297
|
|
248
298
|
when nil
|
249
299
|
Musa::Series::Constructors.method(constructor).call(*parameter)
|
data/musa-dsl.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'musa-dsl'
|
3
|
-
s.version = '0.23.
|
4
|
-
s.date = '2021-
|
3
|
+
s.version = '0.23.10'
|
4
|
+
s.date = '2021-08-05'
|
5
5
|
s.summary = 'A simple Ruby DSL for making complex music'
|
6
6
|
s.description = 'Musa-DSL: A Ruby framework and DSL for algorithmic sound and musical thinking and composition'
|
7
7
|
s.authors = ['Javier Sánchez Yeste']
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: musa-dsl
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.23.
|
4
|
+
version: 0.23.10
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Javier Sánchez Yeste
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-08-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: citrus
|