musa-dsl 0.22.4 → 0.22.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/musa-dsl.rb +1 -1
- data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-helper.rb +7 -2
- data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-timed.rb +28 -137
- data/lib/musa-dsl/sequencer/base-sequencer-implementation.rb +8 -24
- data/lib/musa-dsl/sequencer/base-sequencer-tick-based.rb +5 -7
- data/lib/musa-dsl/sequencer/base-sequencer-tickless-based.rb +3 -5
- data/lib/musa-dsl/sequencer/base-sequencer.rb +14 -27
- data/lib/musa-dsl/sequencer/sequencer-dsl.rb +4 -2
- data/lib/musa-dsl/sequencer/sequencer.rb +7 -0
- data/lib/musa-dsl/series/base-series.rb +2 -2
- data/lib/musa-dsl/series/hash-or-array-serie-splitter.rb +16 -0
- data/lib/musa-dsl/series/main-serie-constructors.rb +4 -2
- data/lib/musa-dsl/series/main-serie-operations.rb +39 -4
- data/lib/musa-dsl/series/quantizer-serie.rb +6 -8
- data/lib/musa-dsl/series/series.rb +1 -2
- data/lib/musa-dsl/series/timed-serie.rb +354 -0
- data/musa-dsl.gemspec +2 -2
- metadata +3 -4
- data/lib/musa-dsl/series/flattener-timed-serie.rb +0 -61
- data/lib/musa-dsl/series/union-timed-series.rb +0 -109
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 77d95cd844364ae8dce08779712a34fdb0e8e349336717ffc7e49580c293b647
|
4
|
+
data.tar.gz: 16b7d33203bdd273acd5f235189025fa15797e7d09a1bee498151d521c0109d3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bad2f753e7c62c93276dd5a019f57ff8eb2b5c23c38a20989e4dcc5f7a3a4365dfdd1532750da0cbb8dbe0a08c459fb02f8f62b0fd1246f1a5f8da8c755c49c5
|
7
|
+
data.tar.gz: a7a7e3d32b7a723c206ec098585cbbad76d2ef377ad55007a722537ef0b1070a9a43a4a18740758db82167193b55e1b524e7bb7f3bdf5251e7beba1c2effd6d5
|
data/lib/musa-dsl.rb
CHANGED
@@ -324,8 +324,13 @@ module Musa
|
|
324
324
|
run_operation eval_use_variable(element[:use_variable])
|
325
325
|
|
326
326
|
when :event
|
327
|
-
value_parameters = element[:value_parameters] ?
|
328
|
-
|
327
|
+
value_parameters = element[:value_parameters] ?
|
328
|
+
element[:value_parameters].collect { |e| subcontext.eval_element(e) } :
|
329
|
+
[]
|
330
|
+
|
331
|
+
key_parameters = element[:key_parameters] ?
|
332
|
+
element[:key_parameters].collect { |k, e| [k, subcontext.eval_element(e)] }.to_h :
|
333
|
+
{}
|
329
334
|
|
330
335
|
{ current_operation: :event,
|
331
336
|
current_event: element[:event],
|
@@ -7,107 +7,59 @@ module Musa; module Sequencer
|
|
7
7
|
class BaseSequencer
|
8
8
|
private def _play_timed(timed_serie,
|
9
9
|
control,
|
10
|
-
reference: nil,
|
11
|
-
step: nil,
|
12
|
-
predictive: nil,
|
13
|
-
right_open: nil,
|
14
|
-
stops: nil,
|
15
10
|
&block)
|
16
11
|
|
17
|
-
reference ||= 0r
|
18
|
-
step ||= 1r
|
19
|
-
predictive ||= predictive
|
20
|
-
stops = stops.nil? ? true : stops
|
21
|
-
|
22
12
|
if first_value_sample = timed_serie.peek_next_value
|
23
|
-
|
24
13
|
debug "_play_timed: first_value_sample #{first_value_sample}"
|
25
14
|
|
26
15
|
hash_mode = first_value_sample[:value].is_a?(Hash)
|
27
16
|
|
28
17
|
if hash_mode
|
29
|
-
|
30
|
-
|
31
|
-
reference = reference.hashify(keys: components)
|
32
|
-
step = step.hashify(keys: components)
|
33
|
-
predictive = predictive.hashify(keys:components)
|
34
|
-
stops = stops.hashify(keys:components)
|
35
|
-
right_open = right_open.hashify(keys:components)
|
18
|
+
component_ids = first_value_sample[:value].keys
|
36
19
|
else
|
37
20
|
size = first_value_sample[:value].size
|
38
|
-
|
39
|
-
|
40
|
-
reference = reference.arrayfy(size: size)
|
41
|
-
step = step.arrayfy(size: size)
|
42
|
-
predictive = predictive.arrayfy(size: size)
|
43
|
-
stops = stops.arrayfy(size: size)
|
44
|
-
right_open = right_open.arrayfy(size: size)
|
45
|
-
end
|
46
|
-
|
47
|
-
split = timed_serie.flatten_timed.split
|
48
|
-
quantized_series = hash_mode ? {} : []
|
49
|
-
|
50
|
-
components.each do |component|
|
51
|
-
quantized_series[component] =
|
52
|
-
QUANTIZE(split[component],
|
53
|
-
reference: reference[component],
|
54
|
-
step: step[component],
|
55
|
-
predictive: predictive[component],
|
56
|
-
right_open: right_open[component],
|
57
|
-
stops: stops[component]).instance
|
21
|
+
component_ids = (0 .. size-1).to_a
|
58
22
|
end
|
23
|
+
extra_attribute_names = Set[*(first_value_sample.keys - [:time, :value])]
|
59
24
|
|
60
25
|
last_positions = hash_mode ? {} : []
|
61
26
|
end
|
62
27
|
|
63
28
|
binder = SmartProcBinder.new(block)
|
64
29
|
|
65
|
-
_play_timed_step(hash_mode,
|
30
|
+
_play_timed_step(hash_mode, component_ids, extra_attribute_names, timed_serie,
|
31
|
+
position, last_positions, binder, control)
|
66
32
|
end
|
67
33
|
|
68
|
-
|
69
|
-
|
34
|
+
private def _play_timed_step(hash_mode,
|
35
|
+
component_ids, extra_attribute_names,
|
36
|
+
timed_serie,
|
37
|
+
start_position,
|
38
|
+
last_positions,
|
70
39
|
binder, control)
|
71
40
|
|
72
|
-
|
73
|
-
|
74
|
-
components.each do |component|
|
75
|
-
if v = quantized_series[component].peek_next_value
|
76
|
-
|
77
|
-
debug "_play_timed_step: quantized_series[#{component}].peek_next_value #{v}"
|
78
|
-
time = v[:time]
|
41
|
+
source_next_value = timed_serie.next_value
|
79
42
|
|
80
|
-
|
81
|
-
affected_components_by_time[time] << component
|
82
|
-
end
|
83
|
-
end
|
43
|
+
affected_components = component_ids.select { |_| !source_next_value[:value][_].nil? } if source_next_value
|
84
44
|
|
85
|
-
if
|
86
|
-
time =
|
45
|
+
if affected_components && affected_components.any?
|
46
|
+
time = source_next_value[:time]
|
87
47
|
|
88
48
|
values = hash_mode ? {} : []
|
89
|
-
|
90
|
-
durations = hash_mode ? {} : []
|
91
|
-
q_durations = hash_mode ? {} : []
|
49
|
+
extra_attributes = extra_attribute_names.collect { |_| [_, hash_mode ? {} : []] }.to_h
|
92
50
|
started_ago = hash_mode ? {} : []
|
93
51
|
|
94
|
-
|
95
|
-
|
52
|
+
affected_components.each do |component|
|
53
|
+
values[component] = source_next_value[:value][component]
|
96
54
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
q_durations[component] =
|
101
|
-
_quantize_position(time + durations[component], warn: false) -
|
102
|
-
_quantize_position(time, warn: false)
|
103
|
-
|
104
|
-
nv = quantized_series[component].peek_next_value
|
105
|
-
next_values[component] = (nv && nv[:value] != values[component]) ? nv[:value] : nil
|
55
|
+
extra_attribute_names.each do |attribute_name|
|
56
|
+
extra_attributes[attribute_name][component] = source_next_value[attribute_name][component]
|
57
|
+
end
|
106
58
|
|
107
59
|
last_positions[component] = _quantize_position(time, warn: false)
|
108
60
|
end
|
109
61
|
|
110
|
-
|
62
|
+
component_ids.each do |component|
|
111
63
|
if last_positions[component] && last_positions[component] != time
|
112
64
|
sa = _quantize_position(time, warn: false) - last_positions[component]
|
113
65
|
started_ago[component] = (sa == 0) ? nil : sa
|
@@ -115,82 +67,21 @@ module Musa; module Sequencer
|
|
115
67
|
end
|
116
68
|
|
117
69
|
_numeric_at start_position + _quantize_position(time, warn: false), control do
|
118
|
-
|
119
|
-
|
120
|
-
duration: durations,
|
121
|
-
quantized_duration: q_durations,
|
70
|
+
binder.call(values,
|
71
|
+
**extra_attributes,
|
122
72
|
started_ago: started_ago,
|
123
73
|
control: control)
|
124
74
|
|
125
|
-
_play_timed_step(hash_mode,
|
75
|
+
_play_timed_step(hash_mode,
|
76
|
+
component_ids, extra_attribute_names,
|
77
|
+
timed_serie,
|
78
|
+
start_position,
|
79
|
+
last_positions,
|
126
80
|
binder, control)
|
127
81
|
end
|
128
82
|
end
|
129
83
|
end
|
130
84
|
|
131
|
-
# TODO implement this alternative play method as another mode
|
132
|
-
# Este es un modo muy interesante pero que implica un procesamiento diferente en el yield_block que no me
|
133
|
-
# sirve para el código de samples/multidim_sample, puesto que en este el next_values es literal,
|
134
|
-
# mientras que samples/multidim_sample necesita que el next_value sea nil si el valor no cambia durante el periodo.
|
135
|
-
#
|
136
|
-
private def _play_timed_step_b(hash_mode, components, quantized_series, start_position, last_positions,
|
137
|
-
binder, control)
|
138
|
-
|
139
|
-
affected_components_by_time = {}
|
140
|
-
|
141
|
-
components.each do |component|
|
142
|
-
if v = quantized_series[component].peek_next_value
|
143
|
-
time = v[:time]
|
144
|
-
|
145
|
-
affected_components_by_time[time] ||= []
|
146
|
-
affected_components_by_time[time] << component
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
|
-
if !affected_components_by_time.empty?
|
151
|
-
time = affected_components_by_time.keys.sort.first
|
152
|
-
|
153
|
-
values = hash_mode ? {} : []
|
154
|
-
next_values = hash_mode ? {} : []
|
155
|
-
durations = hash_mode ? {} : []
|
156
|
-
q_durations = hash_mode ? {} : []
|
157
|
-
started_ago = hash_mode ? {} : []
|
158
|
-
|
159
|
-
affected_components_by_time[time].each do |component|
|
160
|
-
value = quantized_series[component].next_value
|
161
|
-
|
162
|
-
values[component] = value[:value]
|
163
|
-
durations[component] = value[:duration]
|
164
|
-
|
165
|
-
q_durations[component] =
|
166
|
-
_quantize_position(time + durations[component], warn: false) -
|
167
|
-
_quantize_position(time, warn: false)
|
168
|
-
|
169
|
-
last_positions[component] = _quantize_position(time, warn: false)
|
170
|
-
end
|
171
|
-
|
172
|
-
components.each do |component|
|
173
|
-
nv = quantized_series[component].peek_next_value
|
174
|
-
next_values[component] = nv[:value] if nv
|
175
|
-
|
176
|
-
if last_positions[component] && last_positions[component] != time
|
177
|
-
started_ago[component] = _quantize_position(time, warn: false) - last_positions[component]
|
178
|
-
end
|
179
|
-
end
|
180
|
-
|
181
|
-
_numeric_at start_position + _quantize_position(time, warn: false), control do
|
182
|
-
binder.call(values, next_values,
|
183
|
-
duration: durations,
|
184
|
-
quantized_duration: q_durations,
|
185
|
-
started_ago: started_ago,
|
186
|
-
control: control)
|
187
|
-
|
188
|
-
_play_timed_step_b(hash_mode, components, quantized_series, start_position, last_positions,
|
189
|
-
binder, control)
|
190
|
-
end
|
191
|
-
end
|
192
|
-
end
|
193
|
-
|
194
85
|
class PlayTimedControl < EventHandler
|
195
86
|
attr_reader :do_on_stop, :do_after
|
196
87
|
|
@@ -63,21 +63,16 @@ module Musa; module Sequencer
|
|
63
63
|
nil
|
64
64
|
end
|
65
65
|
|
66
|
-
private def _numeric_at(at_position, control,
|
66
|
+
private def _numeric_at(at_position, control, debug: nil, &block)
|
67
67
|
raise ArgumentError, "'at_position' parameter cannot be nil" if at_position.nil?
|
68
68
|
raise ArgumentError, 'Yield block is mandatory' unless block
|
69
69
|
|
70
70
|
at_position = _quantize_position(at_position)
|
71
71
|
|
72
|
-
value_parameters = []
|
73
|
-
value_parameters << with if !with.nil? && !with.is_a?(Hash)
|
74
|
-
|
75
72
|
block_key_parameters_binder =
|
76
73
|
SmartProcBinder.new block, on_rescue: proc { |e| _rescue_error(e) }
|
77
74
|
|
78
75
|
key_parameters = {}
|
79
|
-
key_parameters.merge! block_key_parameters_binder._apply(nil, with).last if with.is_a?(Hash)
|
80
|
-
|
81
76
|
key_parameters[:control] = control if block_key_parameters_binder.key?(:control)
|
82
77
|
|
83
78
|
if at_position == @position
|
@@ -85,7 +80,7 @@ module Musa; module Sequencer
|
|
85
80
|
|
86
81
|
begin
|
87
82
|
locked = @tick_mutex.try_lock
|
88
|
-
block_key_parameters_binder._call(
|
83
|
+
block_key_parameters_binder._call(nil, key_parameters)
|
89
84
|
ensure
|
90
85
|
@tick_mutex.unlock if locked
|
91
86
|
end
|
@@ -100,8 +95,8 @@ module Musa; module Sequencer
|
|
100
95
|
end
|
101
96
|
end
|
102
97
|
|
103
|
-
@timeslots[at_position] << { parent_control: control,
|
104
|
-
|
98
|
+
@timeslots[at_position] << { parent_control: control,
|
99
|
+
block: block_key_parameters_binder,
|
105
100
|
key_parameters: key_parameters }
|
106
101
|
else
|
107
102
|
@logger.warn('BaseSequencer') { "._numeric_at: ignoring past 'at' command for #{at_position}" }
|
@@ -110,20 +105,14 @@ module Musa; module Sequencer
|
|
110
105
|
nil
|
111
106
|
end
|
112
107
|
|
113
|
-
private def _serie_at(
|
114
|
-
bar_position =
|
115
|
-
|
116
|
-
with_value = if with.respond_to? :next_value
|
117
|
-
with.next_value
|
118
|
-
else
|
119
|
-
with
|
120
|
-
end
|
108
|
+
private def _serie_at(position_or_serie, control, debug: nil, &block)
|
109
|
+
bar_position = position_or_serie.next_value
|
121
110
|
|
122
111
|
if bar_position
|
123
|
-
_numeric_at bar_position, control,
|
112
|
+
_numeric_at bar_position, control, debug: debug, &block
|
124
113
|
|
125
114
|
_numeric_at bar_position, control, debug: false do
|
126
|
-
_serie_at
|
115
|
+
_serie_at position_or_serie, control, debug: debug, &block
|
127
116
|
end
|
128
117
|
else
|
129
118
|
# serie finalizada
|
@@ -224,8 +213,3 @@ module Musa; module Sequencer
|
|
224
213
|
private_constant :EventHandler
|
225
214
|
end
|
226
215
|
end; end
|
227
|
-
|
228
|
-
require_relative 'base-sequencer-implementation-every'
|
229
|
-
require_relative 'base-sequencer-implementation-move'
|
230
|
-
require_relative 'base-sequencer-implementation-play'
|
231
|
-
require_relative 'base-sequencer-implementation-play-timed'
|
@@ -27,9 +27,7 @@ module Musa
|
|
27
27
|
_release_public_ticks
|
28
28
|
end
|
29
29
|
|
30
|
-
private
|
31
|
-
|
32
|
-
def _init_timing
|
30
|
+
private def _init_timing
|
33
31
|
@ticks_per_bar = Rational(beats_per_bar * ticks_per_beat)
|
34
32
|
@tick_duration = Rational(1, @ticks_per_bar)
|
35
33
|
|
@@ -37,11 +35,11 @@ module Musa
|
|
37
35
|
@hold_ticks = 0
|
38
36
|
end
|
39
37
|
|
40
|
-
def _reset_timing
|
38
|
+
private def _reset_timing
|
41
39
|
@position = @position_mutex.synchronize { 1r - @tick_duration }
|
42
40
|
end
|
43
41
|
|
44
|
-
def _quantize_position(position, warn: true)
|
42
|
+
private def _quantize_position(position, warn: true)
|
45
43
|
ticks_position = position / @tick_duration
|
46
44
|
|
47
45
|
if ticks_position.round != ticks_position
|
@@ -58,11 +56,11 @@ module Musa
|
|
58
56
|
position
|
59
57
|
end
|
60
58
|
|
61
|
-
def _hold_public_ticks
|
59
|
+
private def _hold_public_ticks
|
62
60
|
@hold_public_ticks = true
|
63
61
|
end
|
64
62
|
|
65
|
-
def _release_public_ticks
|
63
|
+
private def _release_public_ticks
|
66
64
|
@hold_ticks.times { _tick(@position_mutex.synchronize { @position += @tick_duration }) }
|
67
65
|
@hold_ticks = 0
|
68
66
|
@hold_public_ticks = false
|
@@ -53,16 +53,14 @@ module Musa
|
|
53
53
|
@on_fast_forward.each { |block| block.call(false) }
|
54
54
|
end
|
55
55
|
|
56
|
-
private
|
57
|
-
|
58
|
-
def _init_timing
|
56
|
+
private def _init_timing
|
59
57
|
end
|
60
58
|
|
61
|
-
def _reset_timing
|
59
|
+
private def _reset_timing
|
62
60
|
@position = nil
|
63
61
|
end
|
64
62
|
|
65
|
-
def _quantize_position(position, warn: false)
|
63
|
+
private def _quantize_position(position, warn: false)
|
66
64
|
position
|
67
65
|
end
|
68
66
|
end
|
@@ -83,6 +83,11 @@ module Musa
|
|
83
83
|
@timeslots.empty?
|
84
84
|
end
|
85
85
|
|
86
|
+
def quantize_position(position, warn: nil)
|
87
|
+
warn ||= false
|
88
|
+
_quantize_position(position, warn: warn)
|
89
|
+
end
|
90
|
+
|
86
91
|
def run
|
87
92
|
tick until empty?
|
88
93
|
end
|
@@ -115,22 +120,19 @@ module Musa
|
|
115
120
|
@event_handlers.last.launch event, *value_parameters, **key_parameters
|
116
121
|
end
|
117
122
|
|
118
|
-
def wait(bars_delay,
|
123
|
+
def wait(bars_delay, debug: nil, &block)
|
119
124
|
debug ||= false
|
120
125
|
|
121
126
|
control = EventHandler.new @event_handlers.last
|
122
127
|
@event_handlers.push control
|
123
128
|
|
124
129
|
if bars_delay.is_a? Numeric
|
125
|
-
_numeric_at position + bars_delay.rationalize, control,
|
130
|
+
_numeric_at position + bars_delay.rationalize, control, debug: debug, &block
|
126
131
|
else
|
127
132
|
bars_delay = Series::S(*bars_delay) if bars_delay.is_a?(Array)
|
128
133
|
bars_delay = bars_delay.instance if bars_delay
|
129
134
|
|
130
|
-
|
131
|
-
with = with.instance if with
|
132
|
-
|
133
|
-
_serie_at bars_delay.eval { |delay| position + delay }, control, with: with, debug: debug, &block
|
135
|
+
_serie_at bars_delay.eval { |delay| position + delay }, control, debug: debug, &block
|
134
136
|
end
|
135
137
|
|
136
138
|
@event_handlers.pop
|
@@ -138,11 +140,11 @@ module Musa
|
|
138
140
|
control
|
139
141
|
end
|
140
142
|
|
141
|
-
def now(
|
143
|
+
def now(&block)
|
142
144
|
control = EventHandler.new @event_handlers.last
|
143
145
|
@event_handlers.push control
|
144
146
|
|
145
|
-
_numeric_at position, control,
|
147
|
+
_numeric_at position, control, &block
|
146
148
|
|
147
149
|
@event_handlers.pop
|
148
150
|
|
@@ -155,22 +157,19 @@ module Musa
|
|
155
157
|
nil
|
156
158
|
end
|
157
159
|
|
158
|
-
def at(bar_position,
|
160
|
+
def at(bar_position, debug: nil, &block)
|
159
161
|
debug ||= false
|
160
162
|
|
161
163
|
control = EventHandler.new @event_handlers.last
|
162
164
|
@event_handlers.push control
|
163
165
|
|
164
166
|
if bar_position.is_a? Numeric
|
165
|
-
_numeric_at bar_position.rationalize, control,
|
167
|
+
_numeric_at bar_position.rationalize, control, debug: debug, &block
|
166
168
|
else
|
167
169
|
bar_position = Series::S(*bar_position) if bar_position.is_a? Array
|
168
170
|
bar_position = bar_position.instance if bar_position
|
169
171
|
|
170
|
-
|
171
|
-
with = with.instance if with
|
172
|
-
|
173
|
-
_serie_at bar_position, control, with: with, debug: debug, &block
|
172
|
+
_serie_at bar_position, control, debug: debug, &block
|
174
173
|
end
|
175
174
|
|
176
175
|
@event_handlers.pop
|
@@ -216,11 +215,6 @@ module Musa
|
|
216
215
|
end
|
217
216
|
|
218
217
|
def play_timed(timed_serie,
|
219
|
-
reference: nil,
|
220
|
-
step: nil,
|
221
|
-
predictive: nil,
|
222
|
-
stops: nil,
|
223
|
-
right_open: nil,
|
224
218
|
on_stop: nil,
|
225
219
|
after_bars: nil, after: nil,
|
226
220
|
&block)
|
@@ -236,14 +230,7 @@ module Musa
|
|
236
230
|
|
237
231
|
@event_handlers.push control
|
238
232
|
|
239
|
-
_play_timed(timed_serie.instance,
|
240
|
-
control,
|
241
|
-
reference: reference,
|
242
|
-
step: step,
|
243
|
-
predictive: predictive,
|
244
|
-
stops: stops,
|
245
|
-
right_open: right_open,
|
246
|
-
&block)
|
233
|
+
_play_timed(timed_serie.instance, control, &block)
|
247
234
|
|
248
235
|
@event_handlers.pop
|
249
236
|
|
@@ -17,7 +17,7 @@ module Musa
|
|
17
17
|
:position=,
|
18
18
|
:event_handler
|
19
19
|
|
20
|
-
def_delegators :@context, :position, :logger, :debug
|
20
|
+
def_delegators :@context, :position, :quantize_position, :logger, :debug
|
21
21
|
def_delegators :@context, :with, :now, :at, :wait, :play, :play_timed, :every, :move
|
22
22
|
def_delegators :@context, :everying, :playing, :moving
|
23
23
|
def_delegators :@context, :launch, :on
|
@@ -51,7 +51,9 @@ module Musa
|
|
51
51
|
|
52
52
|
def_delegators :@sequencer,
|
53
53
|
:launch, :on,
|
54
|
-
:position, :
|
54
|
+
:position, :quantize_position,
|
55
|
+
:size,
|
56
|
+
:everying, :playing, :moving,
|
55
57
|
:ticks_per_bar, :logger, :debug, :inspect,
|
56
58
|
:run
|
57
59
|
|
@@ -1,3 +1,10 @@
|
|
1
1
|
require_relative 'base-sequencer'
|
2
|
+
|
2
3
|
require_relative 'base-sequencer-implementation'
|
4
|
+
|
5
|
+
require_relative 'base-sequencer-implementation-every'
|
6
|
+
require_relative 'base-sequencer-implementation-move'
|
7
|
+
require_relative 'base-sequencer-implementation-play'
|
8
|
+
require_relative 'base-sequencer-implementation-play-timed'
|
9
|
+
|
3
10
|
require_relative 'sequencer-dsl'
|
@@ -30,7 +30,7 @@ module Musa
|
|
30
30
|
if @is_instance
|
31
31
|
self
|
32
32
|
else
|
33
|
-
clone(freeze: false).tap(&:_instance!).mark_as_instance!(self)
|
33
|
+
clone(freeze: false).tap(&:_instance!).mark_as_instance!(self).tap(&:restart)
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
@@ -40,7 +40,7 @@ module Musa
|
|
40
40
|
# handle prototyping/instancing automatically.
|
41
41
|
# If there is a @sources attribute with the eventual several sources, SeriePrototyping will handle them by
|
42
42
|
# default.
|
43
|
-
# If needed the subclasses can override this behaviour to
|
43
|
+
# If needed the subclasses can override this behaviour to accommodate to real subclass specificities.
|
44
44
|
#
|
45
45
|
protected def _prototype!
|
46
46
|
@source = @source.prototype if @source
|
@@ -45,6 +45,22 @@ module Musa
|
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
48
|
+
def to_hash
|
49
|
+
if @proxy.hash_mode?
|
50
|
+
@proxy.components.collect { |key| [key, self[key]] }.to_h
|
51
|
+
else
|
52
|
+
raise RuntimeError, 'Splitter is not based on Hash: can\'t convert to Hash'
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def to_array
|
57
|
+
if @proxy.array_mode?
|
58
|
+
[].tap { |_| @proxy.components.each { |i| _[i] = self[i] } }
|
59
|
+
else
|
60
|
+
raise RuntimeError, 'Splitter is not based on Array: can\'t convert to Array'
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
48
64
|
class BufferedProxy
|
49
65
|
include SeriePrototyping
|
50
66
|
|
@@ -192,6 +192,8 @@ module Musa
|
|
192
192
|
private_constant :Sequence
|
193
193
|
|
194
194
|
class FromEvalBlockWithParameters
|
195
|
+
using Musa::Extension::DeepCopy
|
196
|
+
|
195
197
|
include Serie
|
196
198
|
include Musa::Extension::SmartProcBinder
|
197
199
|
|
@@ -211,8 +213,8 @@ module Musa
|
|
211
213
|
end
|
212
214
|
|
213
215
|
def _restart
|
214
|
-
@value_parameters = @original_value_parameters.
|
215
|
-
@key_parameters = @original_key_parameters.
|
216
|
+
@value_parameters = @original_value_parameters.clone(deep: true)
|
217
|
+
@key_parameters = @original_key_parameters.clone(deep: true)
|
216
218
|
|
217
219
|
@first = true
|
218
220
|
@value = nil
|
@@ -112,6 +112,10 @@ module Musa
|
|
112
112
|
ProcessWith.new self, &yield_block
|
113
113
|
end
|
114
114
|
|
115
|
+
def anticipate(&yield_block)
|
116
|
+
Anticipate.new self, &yield_block
|
117
|
+
end
|
118
|
+
|
115
119
|
###
|
116
120
|
### Implementation
|
117
121
|
###
|
@@ -130,7 +134,7 @@ module Musa
|
|
130
134
|
@block = SmartProcBinder.new(block) if block_given?
|
131
135
|
|
132
136
|
if @source.prototype?
|
133
|
-
@sources = @sources.transform_values { |s| s.prototype }
|
137
|
+
@sources = @sources.transform_values { |s| s.prototype }.freeze
|
134
138
|
else
|
135
139
|
@sources = @sources.transform_values { |s| s.instance }
|
136
140
|
end
|
@@ -168,6 +172,37 @@ module Musa
|
|
168
172
|
|
169
173
|
private_constant :ProcessWith
|
170
174
|
|
175
|
+
class Anticipate
|
176
|
+
include Musa::Extension::SmartProcBinder
|
177
|
+
include Serie
|
178
|
+
|
179
|
+
attr_reader :source, :block
|
180
|
+
|
181
|
+
def initialize(serie, &block)
|
182
|
+
@source = serie
|
183
|
+
@block = block
|
184
|
+
|
185
|
+
mark_regarding! @source
|
186
|
+
end
|
187
|
+
|
188
|
+
def _restart
|
189
|
+
@source.restart
|
190
|
+
end
|
191
|
+
|
192
|
+
def _next_value
|
193
|
+
value = @source.next_value
|
194
|
+
peek_next_value = @source.peek_next_value
|
195
|
+
|
196
|
+
@block.call(value, peek_next_value)
|
197
|
+
end
|
198
|
+
|
199
|
+
def infinite?
|
200
|
+
@source.infinite?
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
private_constant :Anticipate
|
205
|
+
|
171
206
|
class Switcher
|
172
207
|
include Serie
|
173
208
|
|
@@ -185,7 +220,7 @@ module Musa
|
|
185
220
|
@sources = hash_series.clone.transform_values(&get)
|
186
221
|
end
|
187
222
|
|
188
|
-
if get == :
|
223
|
+
if get == :prototype!
|
189
224
|
@sources.freeze
|
190
225
|
end
|
191
226
|
|
@@ -236,7 +271,7 @@ module Musa
|
|
236
271
|
|
237
272
|
_restart false
|
238
273
|
|
239
|
-
if get == :
|
274
|
+
if get == :prototype
|
240
275
|
@sources.freeze
|
241
276
|
end
|
242
277
|
|
@@ -293,7 +328,7 @@ module Musa
|
|
293
328
|
@sources = hash_series.clone.transform_values(&get)
|
294
329
|
end
|
295
330
|
|
296
|
-
if get == :
|
331
|
+
if get == :prototype
|
297
332
|
@sources.freeze
|
298
333
|
end
|
299
334
|
|
@@ -87,8 +87,6 @@ module Musa
|
|
87
87
|
|
88
88
|
attr_reader :source
|
89
89
|
|
90
|
-
attr_reader :points_history
|
91
|
-
|
92
90
|
def initialize(reference, step, source, value_attribute, stops, left_open, right_open)
|
93
91
|
@reference = reference
|
94
92
|
@step_size = step.abs
|
@@ -218,13 +216,13 @@ module Musa
|
|
218
216
|
if @segments.last && @segments.last[:time] == from_time
|
219
217
|
|
220
218
|
@segments.last[:duration] = to_time - from_time
|
221
|
-
@segments.last[:info] +=
|
219
|
+
@segments.last[:info] += '; edited on a as start'
|
222
220
|
|
223
221
|
else
|
224
222
|
@segments << { time: from_time,
|
225
223
|
value: from_value,
|
226
224
|
duration: to_time - from_time,
|
227
|
-
info:
|
225
|
+
info: 'added on a as start' }
|
228
226
|
|
229
227
|
end
|
230
228
|
|
@@ -233,7 +231,7 @@ module Musa
|
|
233
231
|
value: from_value,
|
234
232
|
duration: 0,
|
235
233
|
stop: true,
|
236
|
-
info:
|
234
|
+
info: 'added on a as end stop' }
|
237
235
|
end
|
238
236
|
else
|
239
237
|
time_increment = to_time - from_time
|
@@ -268,7 +266,7 @@ module Musa
|
|
268
266
|
@segments.last[:value] == value
|
269
267
|
|
270
268
|
@segments.last[:duration] = step_time_increment
|
271
|
-
@segments.last[:info] +=
|
269
|
+
@segments.last[:info] += '; edited on b'
|
272
270
|
|
273
271
|
# puts "process2: editing #{@segments.last}"
|
274
272
|
|
@@ -276,7 +274,7 @@ module Musa
|
|
276
274
|
@segments << v = { time: intermediate_point_time,
|
277
275
|
value: value,
|
278
276
|
duration: step_time_increment,
|
279
|
-
info:
|
277
|
+
info: 'added on b' }
|
280
278
|
|
281
279
|
# puts "process2: adding #{v.inspect}"
|
282
280
|
end
|
@@ -297,7 +295,7 @@ module Musa
|
|
297
295
|
|
298
296
|
private def process(time, value, last_time_value)
|
299
297
|
if time && value
|
300
|
-
raise RuntimeError,
|
298
|
+
raise RuntimeError, 'time only can go forward' if @last_processed_time && time <= @last_processed_time
|
301
299
|
|
302
300
|
q_value = round_quantize(value)
|
303
301
|
|
@@ -0,0 +1,354 @@
|
|
1
|
+
require_relative '../datasets/e'
|
2
|
+
|
3
|
+
module Musa
|
4
|
+
module Series
|
5
|
+
extend self
|
6
|
+
|
7
|
+
def TIMED_UNION(*array_of_timed_series, **hash_of_timed_series)
|
8
|
+
raise ArgumentError, 'Can\'t union an array of series with a hash of series' if array_of_timed_series.any? && hash_of_timed_series.any?
|
9
|
+
|
10
|
+
if array_of_timed_series.any?
|
11
|
+
TimedUnionOfArrayOfSeries.new(array_of_timed_series)
|
12
|
+
elsif hash_of_timed_series.any?
|
13
|
+
TimedUnionOfHashOfSeries.new(hash_of_timed_series)
|
14
|
+
else
|
15
|
+
raise ArgumentError, 'Missing argument series'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class TimedUnionOfArrayOfSeries
|
20
|
+
include Serie
|
21
|
+
|
22
|
+
attr_reader :sources
|
23
|
+
|
24
|
+
def initialize(series)
|
25
|
+
@sources = if series[0].prototype?
|
26
|
+
series.collect(&:prototype).freeze
|
27
|
+
else
|
28
|
+
series.collect(&:instance)
|
29
|
+
end
|
30
|
+
|
31
|
+
_restart false
|
32
|
+
|
33
|
+
mark_regarding! series[0]
|
34
|
+
end
|
35
|
+
|
36
|
+
private def _restart(restart_sources = true)
|
37
|
+
@sources.each { |serie| serie.restart } if restart_sources
|
38
|
+
@sources_next_values = Array.new(@sources.size)
|
39
|
+
|
40
|
+
@components = nil
|
41
|
+
end
|
42
|
+
|
43
|
+
private def _next_value
|
44
|
+
sources_values = @sources_next_values.each_index.collect do |i|
|
45
|
+
@sources_next_values[i] || (@sources_next_values[i] = @sources[i].next_value)
|
46
|
+
end
|
47
|
+
|
48
|
+
@components, @hash_mode, @array_mode = infer_components(sources_values) unless @components
|
49
|
+
|
50
|
+
time = sources_values.collect { |_| _&.[](:time) }.compact.min
|
51
|
+
|
52
|
+
if time
|
53
|
+
selected_values = sources_values.collect { |_| _ if _&.[](:time) == time }
|
54
|
+
|
55
|
+
@sources_next_values.each_index do |i|
|
56
|
+
if @sources_next_values[i]&.[](:time) == time
|
57
|
+
@sources_next_values[i] = nil
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
result = { time: time }
|
62
|
+
|
63
|
+
@components.each do |attribute_name, components|
|
64
|
+
if @hash_mode
|
65
|
+
result[attribute_name] = {}
|
66
|
+
elsif @array_mode
|
67
|
+
result[attribute_name] = []
|
68
|
+
else # value mode
|
69
|
+
result[attribute_name] = []
|
70
|
+
end
|
71
|
+
|
72
|
+
components.each do |target_key_or_index, source_placement|
|
73
|
+
result[attribute_name][target_key_or_index] = selected_values.dig(*source_placement)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
result
|
78
|
+
else
|
79
|
+
nil
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def infinite?
|
84
|
+
!!@sources.find(&:infinite?)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
private def infer_components(sources_values)
|
89
|
+
other_attributes = Set[]
|
90
|
+
|
91
|
+
sources_values.each do |source_value|
|
92
|
+
(source_value.keys - [:time, :value]).each { |_| other_attributes << _ }
|
93
|
+
end
|
94
|
+
|
95
|
+
components = {}
|
96
|
+
components[:value] = {}
|
97
|
+
|
98
|
+
hash_mode = array_mode = nil
|
99
|
+
|
100
|
+
other_attributes.each do |attribute_name|
|
101
|
+
components[attribute_name] = {}
|
102
|
+
end
|
103
|
+
|
104
|
+
target_index = 0
|
105
|
+
|
106
|
+
sources_values.each_with_index do |source_value, i|
|
107
|
+
case source_value[:value]
|
108
|
+
when Hash
|
109
|
+
hash_mode = true
|
110
|
+
|
111
|
+
source_value[:value].keys.each do |key|
|
112
|
+
raise RuntimeError, "Value: key #{key} already used" unless components[:value][key].nil?
|
113
|
+
|
114
|
+
components[:value][key] = [i, :value, key]
|
115
|
+
|
116
|
+
other_attributes.each do |attribute_name|
|
117
|
+
raise RuntimeError, "Attribute #{attribute_name}: key #{key} already used" unless components[attribute_name][key].nil?
|
118
|
+
components[attribute_name][key] = [i, attribute_name, key]
|
119
|
+
end
|
120
|
+
end
|
121
|
+
when Array
|
122
|
+
array_mode = true
|
123
|
+
|
124
|
+
(0..source_value[:value].size - 1).each do |index|
|
125
|
+
components[:value][target_index] = [i, :value, index]
|
126
|
+
|
127
|
+
other_attributes.each do |attribute_name|
|
128
|
+
components[attribute_name][target_index] = [i, attribute_name, index]
|
129
|
+
end
|
130
|
+
|
131
|
+
target_index += 1
|
132
|
+
end
|
133
|
+
else
|
134
|
+
components[:value][target_index] = [i, :value]
|
135
|
+
|
136
|
+
other_attributes.each do |attribute_name|
|
137
|
+
components[attribute_name][target_index] = [i, attribute_name]
|
138
|
+
end
|
139
|
+
|
140
|
+
target_index += 1
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
raise RuntimeError, "source series values are of incompatible type (can't combine Hash and Array values)" if array_mode && hash_mode
|
145
|
+
|
146
|
+
return components, hash_mode, array_mode
|
147
|
+
end
|
148
|
+
|
149
|
+
private_constant :TimedUnionOfArrayOfSeries
|
150
|
+
|
151
|
+
class TimedUnionOfHashOfSeries
|
152
|
+
include Serie
|
153
|
+
|
154
|
+
attr_reader :sources
|
155
|
+
|
156
|
+
def initialize(series)
|
157
|
+
@components = series.keys
|
158
|
+
|
159
|
+
@sources = if series.values.first.prototype?
|
160
|
+
series.transform_values(&:prototype).freeze
|
161
|
+
else
|
162
|
+
series.transform_values(&:instance)
|
163
|
+
end
|
164
|
+
|
165
|
+
_restart false
|
166
|
+
|
167
|
+
mark_regarding! series.values.first
|
168
|
+
end
|
169
|
+
|
170
|
+
private def _restart(restart_sources = true)
|
171
|
+
@sources.each_value { |serie| serie.restart } if restart_sources
|
172
|
+
@sources_next_values = @components.collect { |k| [k, nil] }.to_h
|
173
|
+
@other_attributes = nil
|
174
|
+
end
|
175
|
+
|
176
|
+
private def _next_value
|
177
|
+
sources_values = @sources_next_values.collect do |key, _|
|
178
|
+
[key, @sources_next_values[key] || (@sources_next_values[key] = @sources[key].next_value)]
|
179
|
+
end.to_h
|
180
|
+
|
181
|
+
@other_attributes = infer_other_attributes(sources_values) unless @other_attributes
|
182
|
+
|
183
|
+
time = sources_values.values.collect { |_| _&.[](:time) }.compact.min
|
184
|
+
|
185
|
+
if time
|
186
|
+
selected_values = sources_values.transform_values { |_| _ if _&.[](:time) == time }
|
187
|
+
|
188
|
+
@sources_next_values.each_key do |key|
|
189
|
+
if @sources_next_values[key]&.[](:time) == time
|
190
|
+
@sources_next_values[key] = nil
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
result = { time: time, value: {} }
|
195
|
+
|
196
|
+
@other_attributes.each do |attribute_name|
|
197
|
+
result[attribute_name] = {}
|
198
|
+
end
|
199
|
+
|
200
|
+
@components.each do |component|
|
201
|
+
result[:value][component] = selected_values[component]&.[](:value)
|
202
|
+
|
203
|
+
@other_attributes.each do |attribute_name|
|
204
|
+
result[attribute_name][component] = selected_values[component]&.[](attribute_name)
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
result
|
209
|
+
else
|
210
|
+
nil
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
def infinite?
|
215
|
+
!!@sources.find(&:infinite?)
|
216
|
+
end
|
217
|
+
|
218
|
+
private def infer_other_attributes(sources_values)
|
219
|
+
other_attributes = Set[]
|
220
|
+
|
221
|
+
sources_values.each_value do |source_value|
|
222
|
+
(source_value.keys - [:time, :value]).each do |attribute_name|
|
223
|
+
other_attributes << attribute_name
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
other_attributes
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
private_constant :TimedUnionOfHashOfSeries
|
232
|
+
|
233
|
+
module SerieOperations
|
234
|
+
def flatten_timed
|
235
|
+
TimedFlattener.new(self)
|
236
|
+
end
|
237
|
+
|
238
|
+
def compact_timed
|
239
|
+
TimedCompacter.new(self)
|
240
|
+
end
|
241
|
+
|
242
|
+
def union_timed(*other_timed_series, key: nil, **other_key_timed_series)
|
243
|
+
if key && other_key_timed_series.any?
|
244
|
+
Series::TIMED_UNION(key => self, **other_key_timed_series)
|
245
|
+
|
246
|
+
elsif other_timed_series.any? && other_key_timed_series.empty?
|
247
|
+
Series::TIMED_UNION(self, *other_timed_series)
|
248
|
+
|
249
|
+
else
|
250
|
+
raise ArgumentError, 'Can\'t union an array of series with a hash of series'
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
class TimedFlattener
|
255
|
+
include Serie
|
256
|
+
|
257
|
+
attr_reader :source
|
258
|
+
|
259
|
+
def initialize(serie)
|
260
|
+
@source = serie
|
261
|
+
mark_regarding! @source
|
262
|
+
end
|
263
|
+
|
264
|
+
def _restart
|
265
|
+
@source.restart
|
266
|
+
end
|
267
|
+
|
268
|
+
def _next_value
|
269
|
+
source_value = @source.next_value
|
270
|
+
|
271
|
+
if !source_value.nil?
|
272
|
+
time = source_value[:time]
|
273
|
+
source_value_value = source_value[:value]
|
274
|
+
|
275
|
+
source_value_extra = (source_value.keys - [:time, :value]).collect do |attribute_name|
|
276
|
+
[attribute_name, source_value[attribute_name]]
|
277
|
+
end.to_h
|
278
|
+
|
279
|
+
case source_value_value
|
280
|
+
when Hash
|
281
|
+
result = {}
|
282
|
+
source_value_value.each_pair do |key, value|
|
283
|
+
result[key] = { time: time, value: value }.extend(Musa::Datasets::AbsTimed)
|
284
|
+
|
285
|
+
source_value_extra.each do |attribute_name, attribute_value|
|
286
|
+
result[key][attribute_name] = attribute_value[key]
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
when Array
|
291
|
+
result = []
|
292
|
+
source_value_value.each_index do |index|
|
293
|
+
result[index] = { time: time, value: source_value_value[index] }.extend(Musa::Datasets::AbsTimed)
|
294
|
+
|
295
|
+
source_value_extra.each do |attribute_name, attribute_value|
|
296
|
+
result[index][attribute_name] = attribute_value[index]
|
297
|
+
end
|
298
|
+
end
|
299
|
+
else
|
300
|
+
result = source_value.clone.extend(Musa::Datasets::AbsTimed)
|
301
|
+
end
|
302
|
+
|
303
|
+
result
|
304
|
+
else
|
305
|
+
nil
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
def infinite?
|
310
|
+
@source.infinite?
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
private_constant :TimedFlattener
|
315
|
+
end
|
316
|
+
|
317
|
+
class TimedCompacter
|
318
|
+
include Serie
|
319
|
+
|
320
|
+
attr_reader :source
|
321
|
+
|
322
|
+
def initialize(serie)
|
323
|
+
@source = serie
|
324
|
+
mark_regarding! @source
|
325
|
+
end
|
326
|
+
|
327
|
+
def _restart
|
328
|
+
@source.restart
|
329
|
+
end
|
330
|
+
|
331
|
+
def _next_value
|
332
|
+
while (source_value = @source.next_value) && skip_value?(source_value[:value]); end
|
333
|
+
source_value
|
334
|
+
end
|
335
|
+
|
336
|
+
def infinite?
|
337
|
+
@source.infinite?
|
338
|
+
end
|
339
|
+
|
340
|
+
private def skip_value?(timed_value)
|
341
|
+
case timed_value
|
342
|
+
when Hash
|
343
|
+
timed_value.all? { |_, v| v.nil? }
|
344
|
+
when Array
|
345
|
+
timed_value.all?(&:nil?)
|
346
|
+
else
|
347
|
+
timed_value.nil?
|
348
|
+
end
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
352
|
+
private_constant :TimedCompacter
|
353
|
+
end
|
354
|
+
end
|
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.22.
|
4
|
-
s.date = '2020-11-
|
3
|
+
s.version = '0.22.5'
|
4
|
+
s.date = '2020-11-18'
|
5
5
|
s.summary = 'A simple Ruby DSL for making complex music'
|
6
6
|
s.description = 'Musa-DSL: A Ruby DSL for algorithmic music composition, device language neutral (MIDI, OSC, etc)'
|
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.22.
|
4
|
+
version: 0.22.5
|
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: 2020-11-
|
11
|
+
date: 2020-11-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: citrus
|
@@ -179,7 +179,6 @@ files:
|
|
179
179
|
- lib/musa-dsl/series.rb
|
180
180
|
- lib/musa-dsl/series/array-to-serie.rb
|
181
181
|
- lib/musa-dsl/series/base-series.rb
|
182
|
-
- lib/musa-dsl/series/flattener-timed-serie.rb
|
183
182
|
- lib/musa-dsl/series/hash-or-array-serie-splitter.rb
|
184
183
|
- lib/musa-dsl/series/holder-serie.rb
|
185
184
|
- lib/musa-dsl/series/main-serie-constructors.rb
|
@@ -188,7 +187,7 @@ files:
|
|
188
187
|
- lib/musa-dsl/series/quantizer-serie.rb
|
189
188
|
- lib/musa-dsl/series/queue-serie.rb
|
190
189
|
- lib/musa-dsl/series/series.rb
|
191
|
-
- lib/musa-dsl/series/
|
190
|
+
- lib/musa-dsl/series/timed-serie.rb
|
192
191
|
- lib/musa-dsl/transcription.rb
|
193
192
|
- lib/musa-dsl/transcription/from-gdv-to-midi.rb
|
194
193
|
- lib/musa-dsl/transcription/from-gdv-to-musicxml.rb
|
@@ -1,61 +0,0 @@
|
|
1
|
-
require_relative '../datasets/e'
|
2
|
-
|
3
|
-
module Musa
|
4
|
-
module Series
|
5
|
-
|
6
|
-
module SerieOperations
|
7
|
-
def flatten_timed
|
8
|
-
TimedFlattener.new(self)
|
9
|
-
end
|
10
|
-
|
11
|
-
class TimedFlattener
|
12
|
-
include Serie
|
13
|
-
|
14
|
-
attr_reader :source
|
15
|
-
|
16
|
-
def initialize(serie)
|
17
|
-
@source = serie
|
18
|
-
mark_regarding! @source
|
19
|
-
end
|
20
|
-
|
21
|
-
def _restart
|
22
|
-
@source.restart
|
23
|
-
end
|
24
|
-
|
25
|
-
def _next_value
|
26
|
-
source_value = @source.next_value
|
27
|
-
|
28
|
-
if !source_value.nil?
|
29
|
-
time = source_value[:time]
|
30
|
-
source_value_value = source_value[:value]
|
31
|
-
|
32
|
-
case source_value_value
|
33
|
-
when Hash
|
34
|
-
result = {}
|
35
|
-
source_value_value.each_pair do |key, value|
|
36
|
-
result[key] = { time: time, value: value }.extend(Musa::Datasets::AbsTimed)
|
37
|
-
end
|
38
|
-
when Array
|
39
|
-
result = []
|
40
|
-
source_value_value.each_index do |index|
|
41
|
-
result[index] = { time: time, value: source_value_value[index] }.extend(Musa::Datasets::AbsTimed)
|
42
|
-
end
|
43
|
-
else
|
44
|
-
raise RuntimeError, "Don't know how to handle #{source_value_value}"
|
45
|
-
end
|
46
|
-
|
47
|
-
result
|
48
|
-
else
|
49
|
-
nil
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
def infinite?
|
54
|
-
@source.infinite?
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
private_constant :TimedFlattener
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
@@ -1,109 +0,0 @@
|
|
1
|
-
require_relative '../datasets/e'
|
2
|
-
|
3
|
-
module Musa
|
4
|
-
module Series
|
5
|
-
|
6
|
-
extend self
|
7
|
-
|
8
|
-
def TIMED_UNION(*timed_series)
|
9
|
-
TimedUnion.new(timed_series)
|
10
|
-
end
|
11
|
-
|
12
|
-
class TimedUnion
|
13
|
-
include Serie
|
14
|
-
|
15
|
-
attr_reader :sources
|
16
|
-
|
17
|
-
def initialize(series)
|
18
|
-
@sources = if series[0].prototype?
|
19
|
-
series.collect(&:prototype).freeze
|
20
|
-
else
|
21
|
-
series.collect(&:instance)
|
22
|
-
end
|
23
|
-
|
24
|
-
_restart false
|
25
|
-
|
26
|
-
mark_regarding! series[0]
|
27
|
-
end
|
28
|
-
|
29
|
-
private def _restart(restart_sources = true)
|
30
|
-
@sources.each { |serie| serie.restart } if restart_sources
|
31
|
-
@sources_next_values = Array.new(@sources.size)
|
32
|
-
|
33
|
-
@components = nil
|
34
|
-
@hash_mode = @array_mode = nil
|
35
|
-
end
|
36
|
-
|
37
|
-
private def _next_value
|
38
|
-
sources_values = @sources_next_values.each_index.collect do |i|
|
39
|
-
@sources_next_values[i] || (@sources_next_values[i] = @sources[i].next_value)
|
40
|
-
end
|
41
|
-
|
42
|
-
infer_components(sources_values) if !@components
|
43
|
-
|
44
|
-
time = sources_values.collect { |_| _&.[](:time) }.compact.min
|
45
|
-
|
46
|
-
if time
|
47
|
-
selected_values = sources_values.collect { |_| _ if _&.[](:time) == time }
|
48
|
-
|
49
|
-
@sources_next_values.each_index do |i|
|
50
|
-
if @sources_next_values[i]&.[](:time) == time
|
51
|
-
@sources_next_values[i] = nil
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
if @hash_mode
|
56
|
-
result = {}
|
57
|
-
elsif @array_mode
|
58
|
-
result = []
|
59
|
-
else # value mode
|
60
|
-
result = []
|
61
|
-
end
|
62
|
-
|
63
|
-
@components.each do |target_key_or_index, source_placement|
|
64
|
-
result[target_key_or_index] = selected_values.dig(*source_placement)
|
65
|
-
end
|
66
|
-
|
67
|
-
{ time: time,
|
68
|
-
value: result }
|
69
|
-
else
|
70
|
-
nil
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
def infinite?
|
75
|
-
!!@sources.find(&:infinite?)
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
private def infer_components(sources_values)
|
80
|
-
@components = {}
|
81
|
-
target_index = 0
|
82
|
-
|
83
|
-
sources_values.each_with_index do |source_value, i|
|
84
|
-
case source_value[:value]
|
85
|
-
when Hash
|
86
|
-
@hash_mode = true
|
87
|
-
|
88
|
-
source_value[:value].keys.each do |key|
|
89
|
-
@components[key] = [i, :value, key]
|
90
|
-
end
|
91
|
-
when Array
|
92
|
-
@array_mode = true
|
93
|
-
|
94
|
-
(0..source_value[:value].size - 1).each do |index|
|
95
|
-
@components[target_index] = [i, :value, index]
|
96
|
-
target_index += 1
|
97
|
-
end
|
98
|
-
else
|
99
|
-
@components[target_index] = [i, :value]
|
100
|
-
target_index += 1
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
raise RuntimeError, "source series values are of incompatible type (can't combine Hash and Array values)" if @array_mode && @hash_mode
|
105
|
-
end
|
106
|
-
|
107
|
-
private_constant :TimedUnion
|
108
|
-
end
|
109
|
-
end
|