musa-dsl 0.21.5 → 0.22.4
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.
- checksums.yaml +4 -4
- data/lib/musa-dsl.rb +1 -1
- data/lib/musa-dsl/core-ext.rb +1 -0
- data/lib/musa-dsl/core-ext/arrayfy.rb +9 -9
- data/lib/musa-dsl/core-ext/hashify.rb +42 -0
- data/lib/musa-dsl/core-ext/inspect-nice.rb +6 -1
- data/lib/musa-dsl/datasets/e.rb +22 -5
- data/lib/musa-dsl/datasets/gdv.rb +0 -1
- data/lib/musa-dsl/datasets/p.rb +29 -36
- data/lib/musa-dsl/datasets/pdv.rb +0 -1
- data/lib/musa-dsl/datasets/ps.rb +10 -78
- data/lib/musa-dsl/logger/logger.rb +2 -2
- data/lib/musa-dsl/matrix/matrix.rb +9 -64
- data/lib/musa-dsl/sequencer/base-sequencer-implementation-every.rb +87 -0
- data/lib/musa-dsl/sequencer/base-sequencer-implementation-move.rb +439 -0
- data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-helper.rb +2 -2
- data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-timed.rb +219 -0
- data/lib/musa-dsl/sequencer/base-sequencer-implementation-play.rb +178 -0
- data/lib/musa-dsl/sequencer/base-sequencer-implementation.rb +150 -597
- data/lib/musa-dsl/sequencer/base-sequencer-tick-based.rb +6 -8
- data/lib/musa-dsl/sequencer/base-sequencer-tickless-based.rb +1 -5
- data/lib/musa-dsl/sequencer/{base-sequencer-public.rb → base-sequencer.rb} +63 -5
- data/lib/musa-dsl/sequencer/sequencer-dsl.rb +11 -2
- data/lib/musa-dsl/sequencer/sequencer.rb +1 -1
- data/lib/musa-dsl/series/base-series.rb +43 -78
- data/lib/musa-dsl/series/flattener-timed-serie.rb +61 -0
- data/lib/musa-dsl/series/hash-or-array-serie-splitter.rb +143 -0
- data/lib/musa-dsl/series/holder-serie.rb +1 -1
- data/lib/musa-dsl/series/main-serie-constructors.rb +32 -92
- data/lib/musa-dsl/series/main-serie-operations.rb +60 -215
- data/lib/musa-dsl/series/proxy-serie.rb +1 -1
- data/lib/musa-dsl/series/quantizer-serie.rb +558 -0
- data/lib/musa-dsl/series/queue-serie.rb +1 -1
- data/lib/musa-dsl/series/series.rb +8 -2
- data/lib/musa-dsl/series/union-timed-series.rb +109 -0
- data/musa-dsl.gemspec +2 -2
- metadata +12 -5
- data/lib/musa-dsl/sequencer/base-sequencer-implementation-control.rb +0 -216
- data/lib/musa-dsl/series/hash-serie-splitter.rb +0 -196
@@ -117,7 +117,7 @@ module Musa
|
|
117
117
|
|
118
118
|
@@id = 0
|
119
119
|
|
120
|
-
attr_reader :
|
120
|
+
attr_reader :neumalang_context
|
121
121
|
attr_reader :block_procedure_binder
|
122
122
|
|
123
123
|
def initialize(block_procedure_binder, decoder, nl_context, parent: nil)
|
@@ -166,7 +166,7 @@ module Musa
|
|
166
166
|
end
|
167
167
|
|
168
168
|
def eval_p(p)
|
169
|
-
p.to_ps_serie(@decoder.base_duration).instance
|
169
|
+
p.to_ps_serie(base_duration: @decoder.base_duration).instance
|
170
170
|
end
|
171
171
|
|
172
172
|
def eval_serie(serie)
|
@@ -0,0 +1,219 @@
|
|
1
|
+
using Musa::Extension::Hashify
|
2
|
+
using Musa::Extension::Arrayfy
|
3
|
+
|
4
|
+
using Musa::Extension::InspectNice
|
5
|
+
|
6
|
+
module Musa; module Sequencer
|
7
|
+
class BaseSequencer
|
8
|
+
private def _play_timed(timed_serie,
|
9
|
+
control,
|
10
|
+
reference: nil,
|
11
|
+
step: nil,
|
12
|
+
predictive: nil,
|
13
|
+
right_open: nil,
|
14
|
+
stops: nil,
|
15
|
+
&block)
|
16
|
+
|
17
|
+
reference ||= 0r
|
18
|
+
step ||= 1r
|
19
|
+
predictive ||= predictive
|
20
|
+
stops = stops.nil? ? true : stops
|
21
|
+
|
22
|
+
if first_value_sample = timed_serie.peek_next_value
|
23
|
+
|
24
|
+
debug "_play_timed: first_value_sample #{first_value_sample}"
|
25
|
+
|
26
|
+
hash_mode = first_value_sample[:value].is_a?(Hash)
|
27
|
+
|
28
|
+
if hash_mode
|
29
|
+
components = first_value_sample[:value].keys
|
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)
|
36
|
+
else
|
37
|
+
size = first_value_sample[:value].size
|
38
|
+
components = (0 .. size-1).to_a
|
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
|
58
|
+
end
|
59
|
+
|
60
|
+
last_positions = hash_mode ? {} : []
|
61
|
+
end
|
62
|
+
|
63
|
+
binder = SmartProcBinder.new(block)
|
64
|
+
|
65
|
+
_play_timed_step(hash_mode, components, quantized_series, position, last_positions, binder, control)
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
private def _play_timed_step(hash_mode, components, quantized_series, start_position, last_positions,
|
70
|
+
binder, control)
|
71
|
+
|
72
|
+
affected_components_by_time = {}
|
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]
|
79
|
+
|
80
|
+
affected_components_by_time[time] ||= []
|
81
|
+
affected_components_by_time[time] << component
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
if affected_components_by_time.any?
|
86
|
+
time = affected_components_by_time.keys.sort.first
|
87
|
+
|
88
|
+
values = hash_mode ? {} : []
|
89
|
+
next_values = hash_mode ? {} : []
|
90
|
+
durations = hash_mode ? {} : []
|
91
|
+
q_durations = hash_mode ? {} : []
|
92
|
+
started_ago = hash_mode ? {} : []
|
93
|
+
|
94
|
+
affected_components_by_time[time].each do |component|
|
95
|
+
value = quantized_series[component].next_value
|
96
|
+
|
97
|
+
values[component] = value[:value]
|
98
|
+
durations[component] = value[:duration]
|
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
|
106
|
+
|
107
|
+
last_positions[component] = _quantize_position(time, warn: false)
|
108
|
+
end
|
109
|
+
|
110
|
+
components.each do |component|
|
111
|
+
if last_positions[component] && last_positions[component] != time
|
112
|
+
sa = _quantize_position(time, warn: false) - last_positions[component]
|
113
|
+
started_ago[component] = (sa == 0) ? nil : sa
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
_numeric_at start_position + _quantize_position(time, warn: false), control do
|
118
|
+
debug "_play_timed_step: before binder.call: durations #{durations} q_durations #{q_durations}"
|
119
|
+
binder.call(values, next_values,
|
120
|
+
duration: durations,
|
121
|
+
quantized_duration: q_durations,
|
122
|
+
started_ago: started_ago,
|
123
|
+
control: control)
|
124
|
+
|
125
|
+
_play_timed_step(hash_mode, components, quantized_series, start_position, last_positions,
|
126
|
+
binder, control)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
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
|
+
class PlayTimedControl < EventHandler
|
195
|
+
attr_reader :do_on_stop, :do_after
|
196
|
+
|
197
|
+
def initialize(parent, on_stop: nil, after_bars: nil, after: nil)
|
198
|
+
super parent
|
199
|
+
@do_on_stop = []
|
200
|
+
@do_after = []
|
201
|
+
|
202
|
+
@do_on_stop << on_stop if on_stop
|
203
|
+
self.after after_bars, &after if after
|
204
|
+
end
|
205
|
+
|
206
|
+
def on_stop(&block)
|
207
|
+
@do_on_stop << block
|
208
|
+
end
|
209
|
+
|
210
|
+
def after(bars = nil, &block)
|
211
|
+
bars ||= 0
|
212
|
+
@do_after << { bars: bars.rationalize, block: block }
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
private_constant :PlayTimedControl
|
217
|
+
end
|
218
|
+
end; end
|
219
|
+
|
@@ -0,0 +1,178 @@
|
|
1
|
+
require_relative 'base-sequencer-implementation-play-helper'
|
2
|
+
|
3
|
+
using Musa::Extension::Hashify
|
4
|
+
using Musa::Extension::Arrayfy
|
5
|
+
|
6
|
+
using Musa::Extension::InspectNice
|
7
|
+
|
8
|
+
module Musa; module Sequencer
|
9
|
+
class BaseSequencer
|
10
|
+
private def _play(serie,
|
11
|
+
control,
|
12
|
+
neumalang_context = nil,
|
13
|
+
mode: nil,
|
14
|
+
decoder: nil,
|
15
|
+
__play_eval: nil,
|
16
|
+
**mode_args,
|
17
|
+
&block)
|
18
|
+
|
19
|
+
block ||= proc {}
|
20
|
+
|
21
|
+
__play_eval ||= PlayEval.create \
|
22
|
+
mode,
|
23
|
+
SmartProcBinder.new(block,
|
24
|
+
on_rescue: proc { |e| _rescue_error(e) }),
|
25
|
+
decoder,
|
26
|
+
neumalang_context
|
27
|
+
|
28
|
+
element = nil
|
29
|
+
|
30
|
+
if control.stopped?
|
31
|
+
# nothing to do
|
32
|
+
elsif control.paused?
|
33
|
+
control.store_continuation sequencer: self,
|
34
|
+
serie: serie,
|
35
|
+
neumalang_context: neumalang_context,
|
36
|
+
mode: mode,
|
37
|
+
decoder: decoder,
|
38
|
+
play_eval: __play_eval,
|
39
|
+
mode_args: mode_args
|
40
|
+
else
|
41
|
+
element = serie.next_value
|
42
|
+
end
|
43
|
+
|
44
|
+
if element
|
45
|
+
operation = __play_eval.run_operation element
|
46
|
+
|
47
|
+
case operation[:current_operation]
|
48
|
+
when :none
|
49
|
+
when :block
|
50
|
+
__play_eval.block_procedure_binder.call operation[:current_parameter], control: control
|
51
|
+
|
52
|
+
when :event
|
53
|
+
control._launch operation[:current_event],
|
54
|
+
operation[:current_value_parameters],
|
55
|
+
operation[:current_key_parameters]
|
56
|
+
|
57
|
+
when :play
|
58
|
+
control2 = PlayControl.new control
|
59
|
+
control3 = PlayControl.new control2
|
60
|
+
control3.after { control3.launch :sync }
|
61
|
+
|
62
|
+
_play operation[:current_parameter].instance,
|
63
|
+
control3,
|
64
|
+
__play_eval: __play_eval.subcontext,
|
65
|
+
**mode_args
|
66
|
+
|
67
|
+
control2.on :sync do
|
68
|
+
_play serie, control, __play_eval: __play_eval, **mode_args
|
69
|
+
end
|
70
|
+
|
71
|
+
when :no_eval_play
|
72
|
+
control2 = PlayControl.new control
|
73
|
+
control3 = PlayControl.new control2
|
74
|
+
control3.after { control3.launch :sync }
|
75
|
+
|
76
|
+
_play operation[:current_parameter].instance,
|
77
|
+
control3,
|
78
|
+
__play_eval: WaitModePlayEval.new(__play_eval.block_procedure_binder),
|
79
|
+
**mode_args
|
80
|
+
|
81
|
+
control2.on :sync do
|
82
|
+
_play serie, control, __play_eval: __play_eval, **mode_args
|
83
|
+
end
|
84
|
+
|
85
|
+
when :parallel_play
|
86
|
+
control2 = PlayControl.new control
|
87
|
+
|
88
|
+
operation[:current_parameter].each do |current_parameter|
|
89
|
+
control3 = PlayControl.new control2
|
90
|
+
control3.after { control3.launch :sync }
|
91
|
+
|
92
|
+
_play current_parameter.instance,
|
93
|
+
control3,
|
94
|
+
__play_eval: __play_eval.subcontext,
|
95
|
+
**mode_args
|
96
|
+
end
|
97
|
+
|
98
|
+
counter = operation[:current_parameter].size
|
99
|
+
|
100
|
+
control2.on :sync do
|
101
|
+
counter -= 1
|
102
|
+
_play serie, control, __play_eval: __play_eval, **mode_args if counter == 0
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
case operation[:continue_operation]
|
107
|
+
when :now
|
108
|
+
_numeric_at position, control do
|
109
|
+
_play serie, control, __play_eval: __play_eval, **mode_args
|
110
|
+
end
|
111
|
+
|
112
|
+
when :at
|
113
|
+
_numeric_at operation[:continue_parameter], control do
|
114
|
+
_play serie, control, __play_eval: __play_eval, **mode_args
|
115
|
+
end
|
116
|
+
|
117
|
+
when :wait
|
118
|
+
_numeric_at position + operation[:continue_parameter].rationalize, control do
|
119
|
+
_play serie, control, __play_eval: __play_eval, **mode_args
|
120
|
+
end
|
121
|
+
|
122
|
+
when :on
|
123
|
+
control.on operation[:continue_parameter], only_once: true do
|
124
|
+
_play serie, control, __play_eval: __play_eval, **mode_args
|
125
|
+
end
|
126
|
+
end
|
127
|
+
else
|
128
|
+
control2 = EventHandler.new control
|
129
|
+
|
130
|
+
control.do_after.each do |do_after|
|
131
|
+
_numeric_at position + do_after[:bars], control2, &do_after[:block]
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
nil
|
136
|
+
end
|
137
|
+
|
138
|
+
class PlayControl < EventHandler
|
139
|
+
attr_reader :do_after
|
140
|
+
|
141
|
+
def initialize(parent, after_bars: nil, after: nil)
|
142
|
+
super parent
|
143
|
+
|
144
|
+
@do_after = []
|
145
|
+
|
146
|
+
after(after_bars, &after) if after
|
147
|
+
end
|
148
|
+
|
149
|
+
def pause
|
150
|
+
@paused = true
|
151
|
+
end
|
152
|
+
|
153
|
+
def store_continuation(sequencer:, serie:, neumalang_context:, mode:, decoder:, play_eval:, mode_args:)
|
154
|
+
@continuation_sequencer = sequencer
|
155
|
+
@continuation_parameters = {
|
156
|
+
serie: serie,
|
157
|
+
control: self,
|
158
|
+
neumalang_context: neumalang_context,
|
159
|
+
mode: mode,
|
160
|
+
decoder: decoder,
|
161
|
+
play_eval: play_eval,
|
162
|
+
mode_args: mode_args }
|
163
|
+
end
|
164
|
+
|
165
|
+
def continue
|
166
|
+
super
|
167
|
+
@continuation_sequencer.continuation_play(@continuation_parameters) if @continuation_sequencer
|
168
|
+
end
|
169
|
+
|
170
|
+
def after(bars = nil, &block)
|
171
|
+
bars ||= 0
|
172
|
+
@do_after << { bars: bars.rationalize, block: block }
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
private_constant :PlayControl
|
177
|
+
end
|
178
|
+
end; end
|
@@ -1,678 +1,231 @@
|
|
1
1
|
require_relative '../core-ext/arrayfy'
|
2
2
|
require_relative '../core-ext/smart-proc-binder'
|
3
3
|
|
4
|
-
require_relative 'base-sequencer-implementation-control'
|
5
|
-
require_relative 'base-sequencer-implementation-play-helper'
|
6
|
-
|
7
4
|
using Musa::Extension::Arrayfy
|
8
5
|
using Musa::Extension::DeepCopy
|
9
6
|
|
10
|
-
module Musa
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
include Musa::Extension::DeepCopy
|
15
|
-
|
16
|
-
private
|
17
|
-
|
18
|
-
def _tick(position_to_run)
|
19
|
-
|
20
|
-
@before_tick.each { |block| block.call position_to_run }
|
7
|
+
module Musa; module Sequencer
|
8
|
+
class BaseSequencer
|
9
|
+
include Musa::Extension::SmartProcBinder
|
10
|
+
include Musa::Extension::DeepCopy
|
21
11
|
|
22
|
-
|
12
|
+
private def _tick(position_to_run)
|
13
|
+
@before_tick.each { |block| block.call position_to_run }
|
14
|
+
queue = @timeslots[position_to_run]
|
23
15
|
|
24
|
-
|
25
|
-
|
16
|
+
if queue
|
17
|
+
until queue.empty?
|
18
|
+
command = queue.shift
|
19
|
+
@timeslots.delete position_to_run if queue.empty?
|
26
20
|
|
27
|
-
|
28
|
-
@
|
21
|
+
if command.key?(:parent_control) && !command[:parent_control].stopped?
|
22
|
+
@event_handlers.push command[:parent_control]
|
29
23
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
@tick_mutex.synchronize do
|
34
|
-
command[:block].call *command[:value_parameters], **command[:key_parameters] if command[:block]
|
35
|
-
end
|
36
|
-
|
37
|
-
@event_handlers.pop
|
38
|
-
else
|
39
|
-
@tick_mutex.synchronize do
|
40
|
-
command[:block].call *command[:value_parameters], **command[:key_parameters] if command[:block]
|
41
|
-
end
|
24
|
+
@tick_mutex.synchronize do
|
25
|
+
command[:block].call *command[:value_parameters], **command[:key_parameters] if command[:block]
|
42
26
|
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
Thread.pass
|
47
|
-
end
|
48
|
-
|
49
|
-
def _raw_numeric_at(at_position, force_first: nil, &block)
|
50
|
-
force_first ||= false
|
51
|
-
|
52
|
-
if at_position == @position
|
53
|
-
begin
|
54
|
-
yield
|
55
|
-
rescue StandardError, ScriptError => e
|
56
|
-
_rescue_error e
|
57
|
-
end
|
58
|
-
|
59
|
-
elsif at_position > @position
|
60
|
-
@timeslots[at_position] ||= []
|
61
27
|
|
62
|
-
|
63
|
-
if force_first
|
64
|
-
@timeslots[at_position].insert 0, value
|
28
|
+
@event_handlers.pop
|
65
29
|
else
|
66
|
-
@
|
67
|
-
|
68
|
-
else
|
69
|
-
@logger.warn('BaseSequencer') { "._raw_numeric_at: ignoring past at command for #{at_position}" }
|
70
|
-
end
|
71
|
-
|
72
|
-
nil
|
73
|
-
end
|
74
|
-
|
75
|
-
def _numeric_at(at_position, control, with: nil, debug: nil, &block)
|
76
|
-
raise ArgumentError, "'at_position' parameter cannot be nil" if at_position.nil?
|
77
|
-
raise ArgumentError, 'Yield block is mandatory' unless block
|
78
|
-
|
79
|
-
at_position = _check_position(at_position)
|
80
|
-
|
81
|
-
value_parameters = []
|
82
|
-
value_parameters << with if !with.nil? && !with.is_a?(Hash)
|
83
|
-
|
84
|
-
block_key_parameters_binder =
|
85
|
-
SmartProcBinder.new block, on_rescue: proc { |e| _rescue_error(e) }
|
86
|
-
|
87
|
-
key_parameters = {}
|
88
|
-
key_parameters.merge! block_key_parameters_binder._apply(nil, with).last if with.is_a?(Hash)
|
89
|
-
|
90
|
-
key_parameters[:control] = control if block_key_parameters_binder.key?(:control)
|
91
|
-
|
92
|
-
if at_position == @position
|
93
|
-
@on_debug_at.each { |c| c.call } if @logger.sev_threshold >= ::Logger::Severity::DEBUG
|
94
|
-
|
95
|
-
begin
|
96
|
-
locked = @tick_mutex.try_lock
|
97
|
-
block_key_parameters_binder._call(value_parameters, key_parameters)
|
98
|
-
ensure
|
99
|
-
@tick_mutex.unlock if locked
|
100
|
-
end
|
101
|
-
|
102
|
-
elsif @position.nil? || at_position > @position
|
103
|
-
|
104
|
-
@timeslots[at_position] ||= []
|
105
|
-
|
106
|
-
if @logger.sev_threshold <= ::Logger::Severity::DEBUG
|
107
|
-
@on_debug_at.each do |block|
|
108
|
-
@timeslots[at_position] << { parent_control: control, block: block }
|
30
|
+
@tick_mutex.synchronize do
|
31
|
+
command[:block].call *command[:value_parameters], **command[:key_parameters] if command[:block]
|
109
32
|
end
|
110
33
|
end
|
111
|
-
|
112
|
-
@timeslots[at_position] << { parent_control: control, block: block_key_parameters_binder,
|
113
|
-
value_parameters: value_parameters,
|
114
|
-
key_parameters: key_parameters }
|
115
|
-
else
|
116
|
-
@logger.warn('BaseSequencer') { "._numeric_at: ignoring past 'at' command for #{at_position}" }
|
117
34
|
end
|
118
|
-
|
119
|
-
nil
|
120
35
|
end
|
121
36
|
|
122
|
-
|
123
|
-
|
124
|
-
bar_position = bar_position_serie.next_value
|
125
|
-
|
126
|
-
with_value = if with.respond_to? :next_value
|
127
|
-
with.next_value
|
128
|
-
else
|
129
|
-
with
|
130
|
-
end
|
37
|
+
Thread.pass
|
38
|
+
end
|
131
39
|
|
132
|
-
|
133
|
-
|
40
|
+
private def _raw_numeric_at(at_position, force_first: nil, &block)
|
41
|
+
force_first ||= false
|
134
42
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
43
|
+
if at_position == @position
|
44
|
+
begin
|
45
|
+
yield
|
46
|
+
rescue StandardError, ScriptError => e
|
47
|
+
_rescue_error e
|
140
48
|
end
|
141
49
|
|
142
|
-
|
143
|
-
|
50
|
+
elsif at_position > @position
|
51
|
+
@timeslots[at_position] ||= []
|
144
52
|
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
__play_eval ||= PlayEval.create \
|
150
|
-
mode,
|
151
|
-
SmartProcBinder.new(block,
|
152
|
-
on_rescue: proc { |e| _rescue_error(e) }),
|
153
|
-
decoder,
|
154
|
-
nl_context
|
155
|
-
|
156
|
-
element = nil
|
157
|
-
|
158
|
-
if control.stopped?
|
159
|
-
# nothing to do
|
160
|
-
elsif control.paused?
|
161
|
-
control.store_continuation sequencer: self,
|
162
|
-
serie: serie,
|
163
|
-
nl_context: nl_context,
|
164
|
-
mode: mode,
|
165
|
-
decoder: decoder,
|
166
|
-
play_eval: __play_eval,
|
167
|
-
mode_args: mode_args
|
53
|
+
value = { block: block, value_parameters: [], key_parameters: {} }
|
54
|
+
if force_first
|
55
|
+
@timeslots[at_position].insert 0, value
|
168
56
|
else
|
169
|
-
|
57
|
+
@timeslots[at_position] << value
|
170
58
|
end
|
171
|
-
|
172
|
-
|
173
|
-
operation = __play_eval.run_operation element
|
174
|
-
|
175
|
-
case operation[:current_operation]
|
176
|
-
|
177
|
-
when :none
|
178
|
-
|
179
|
-
when :block
|
180
|
-
|
181
|
-
__play_eval.block_procedure_binder.call operation[:current_parameter], control: control
|
182
|
-
|
183
|
-
when :event
|
184
|
-
|
185
|
-
control._launch operation[:current_event],
|
186
|
-
operation[:current_value_parameters],
|
187
|
-
operation[:current_key_parameters]
|
188
|
-
|
189
|
-
when :play
|
190
|
-
|
191
|
-
control2 = PlayControl.new control
|
192
|
-
control3 = PlayControl.new control2
|
193
|
-
control3.after { control3.launch :sync }
|
194
|
-
|
195
|
-
_play operation[:current_parameter].instance,
|
196
|
-
control3,
|
197
|
-
__play_eval: __play_eval.subcontext,
|
198
|
-
**mode_args
|
199
|
-
|
200
|
-
control2.on :sync do
|
201
|
-
_play serie, control, __play_eval: __play_eval, **mode_args
|
202
|
-
end
|
203
|
-
|
204
|
-
when :no_eval_play
|
205
|
-
|
206
|
-
control2 = PlayControl.new control
|
207
|
-
control3 = PlayControl.new control2
|
208
|
-
control3.after { control3.launch :sync }
|
209
|
-
|
210
|
-
_play operation[:current_parameter].instance,
|
211
|
-
control3,
|
212
|
-
__play_eval: WaitModePlayEval.new(__play_eval.block_procedure_binder),
|
213
|
-
**mode_args
|
214
|
-
|
215
|
-
control2.on :sync do
|
216
|
-
_play serie, control, __play_eval: __play_eval, **mode_args
|
217
|
-
end
|
218
|
-
|
219
|
-
when :parallel_play
|
220
|
-
|
221
|
-
control2 = PlayControl.new control
|
222
|
-
|
223
|
-
operation[:current_parameter].each do |current_parameter|
|
224
|
-
control3 = PlayControl.new control2
|
225
|
-
control3.after { control3.launch :sync }
|
226
|
-
|
227
|
-
_play current_parameter.instance,
|
228
|
-
control3,
|
229
|
-
__play_eval: __play_eval.subcontext,
|
230
|
-
**mode_args
|
231
|
-
end
|
232
|
-
|
233
|
-
counter = operation[:current_parameter].size
|
234
|
-
|
235
|
-
control2.on :sync do
|
236
|
-
counter -= 1
|
237
|
-
_play serie, control, __play_eval: __play_eval, **mode_args if counter == 0
|
238
|
-
end
|
239
|
-
end
|
240
|
-
|
241
|
-
case operation[:continue_operation]
|
242
|
-
when :now
|
243
|
-
_numeric_at position, control do
|
244
|
-
_play serie, control, __play_eval: __play_eval, **mode_args
|
245
|
-
end
|
246
|
-
|
247
|
-
when :at
|
248
|
-
_numeric_at operation[:continue_parameter], control do
|
249
|
-
_play serie, control, __play_eval: __play_eval, **mode_args
|
250
|
-
end
|
251
|
-
|
252
|
-
when :wait
|
253
|
-
_numeric_at position + operation[:continue_parameter].rationalize, control do
|
254
|
-
_play serie, control, __play_eval: __play_eval, **mode_args
|
255
|
-
end
|
256
|
-
|
257
|
-
when :on
|
258
|
-
control.on operation[:continue_parameter], only_once: true do
|
259
|
-
_play serie, control, __play_eval: __play_eval, **mode_args
|
260
|
-
end
|
261
|
-
end
|
262
|
-
else
|
263
|
-
control2 = EventHandler.new control
|
264
|
-
|
265
|
-
control.do_after.each do |do_after|
|
266
|
-
_numeric_at position, control2, &do_after
|
267
|
-
end
|
268
|
-
end
|
269
|
-
|
270
|
-
nil
|
59
|
+
else
|
60
|
+
@logger.warn('BaseSequencer') { "._raw_numeric_at: ignoring past at command for #{at_position}" }
|
271
61
|
end
|
272
62
|
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
block_procedure_binder ||= SmartProcBinder.new block, on_rescue: proc { |e| _rescue_error(e) }
|
277
|
-
|
278
|
-
_numeric_at position, control do
|
279
|
-
control._start_position ||= position
|
280
|
-
control._execution_counter ||= 0
|
63
|
+
nil
|
64
|
+
end
|
281
65
|
|
282
|
-
|
283
|
-
|
66
|
+
private def _numeric_at(at_position, control, with: nil, debug: nil, &block)
|
67
|
+
raise ArgumentError, "'at_position' parameter cannot be nil" if at_position.nil?
|
68
|
+
raise ArgumentError, 'Yield block is mandatory' unless block
|
284
69
|
|
285
|
-
|
70
|
+
at_position = _quantize_position(at_position)
|
286
71
|
|
287
|
-
|
72
|
+
value_parameters = []
|
73
|
+
value_parameters << with if !with.nil? && !with.is_a?(Hash)
|
288
74
|
|
289
|
-
|
290
|
-
|
291
|
-
control._execution_counter += 1
|
292
|
-
end
|
75
|
+
block_key_parameters_binder =
|
76
|
+
SmartProcBinder.new block, on_rescue: proc { |e| _rescue_error(e) }
|
293
77
|
|
78
|
+
key_parameters = {}
|
79
|
+
key_parameters.merge! block_key_parameters_binder._apply(nil, with).last if with.is_a?(Hash)
|
294
80
|
|
295
|
-
|
296
|
-
_numeric_at control._start_position + control._execution_counter * interval, control do
|
297
|
-
_every interval, control, block_procedure_binder: block_procedure_binder
|
298
|
-
end
|
81
|
+
key_parameters[:control] = control if block_key_parameters_binder.key?(:control)
|
299
82
|
|
300
|
-
|
301
|
-
|
83
|
+
if at_position == @position
|
84
|
+
@on_debug_at.each { |c| c.call } if @logger.sev_threshold >= ::Logger::Severity::DEBUG
|
302
85
|
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
86
|
+
begin
|
87
|
+
locked = @tick_mutex.try_lock
|
88
|
+
block_key_parameters_binder._call(value_parameters, key_parameters)
|
89
|
+
ensure
|
90
|
+
@tick_mutex.unlock if locked
|
307
91
|
end
|
308
92
|
|
309
|
-
|
310
|
-
end
|
311
|
-
|
312
|
-
def _move(every: nil,
|
313
|
-
from:, to: nil, step: nil,
|
314
|
-
duration: nil, till: nil,
|
315
|
-
function: nil,
|
316
|
-
right_open: nil,
|
317
|
-
on_stop: nil,
|
318
|
-
after_bars: nil, after: nil,
|
319
|
-
&block)
|
320
|
-
|
321
|
-
raise ArgumentError,
|
322
|
-
"Cannot use duration: #{duration} and till: #{till} parameters at the same time. " \
|
323
|
-
"Use only one of them." if till && duration
|
324
|
-
|
325
|
-
raise ArgumentError,
|
326
|
-
"Invalid use: 'function:' parameter is incompatible with 'step:' parameter" if function && step
|
327
|
-
raise ArgumentError,
|
328
|
-
"Invalid use: 'function:' parameter needs 'to:' parameter to be not nil" if function && !to
|
329
|
-
|
330
|
-
array_mode = from.is_a?(Array)
|
331
|
-
hash_mode = from.is_a?(Hash)
|
332
|
-
|
333
|
-
if array_mode
|
334
|
-
from = from.arrayfy
|
335
|
-
size = from.size
|
336
|
-
|
337
|
-
elsif hash_mode
|
338
|
-
hash_keys = from.keys
|
339
|
-
from = from.values
|
340
|
-
size = from.size
|
341
|
-
|
342
|
-
if every.is_a?(Hash)
|
343
|
-
every = hash_keys.collect { |k| every[k] }
|
344
|
-
raise ArgumentError,
|
345
|
-
"Invalid use: 'every:' parameter should contain the same keys as 'from:' Hash" \
|
346
|
-
unless every.all? { |_| _ }
|
347
|
-
end
|
348
|
-
|
349
|
-
if to.is_a?(Hash)
|
350
|
-
to = hash_keys.collect { |k| to[k] }
|
351
|
-
raise ArgumentError,
|
352
|
-
"Invalid use: 'to:' parameter should contain the same keys as 'from:' Hash" unless to.all? { |_| _ }
|
353
|
-
end
|
93
|
+
elsif @position.nil? || at_position > @position
|
354
94
|
|
355
|
-
|
356
|
-
step = hash_keys.collect { |k| step[k] }
|
357
|
-
end
|
95
|
+
@timeslots[at_position] ||= []
|
358
96
|
|
359
|
-
|
360
|
-
|
97
|
+
if @logger.sev_threshold <= ::Logger::Severity::DEBUG
|
98
|
+
@on_debug_at.each do |block|
|
99
|
+
@timeslots[at_position] << { parent_control: control, block: block }
|
361
100
|
end
|
362
|
-
|
363
|
-
else
|
364
|
-
from = from.arrayfy
|
365
|
-
size = from.size
|
366
101
|
end
|
367
102
|
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
# from, to, step, (duration | till)
|
375
|
-
# from, to, every, (duration | till)
|
376
|
-
# from, step, every, (duration | till)
|
377
|
-
|
378
|
-
block ||= proc {}
|
379
|
-
|
380
|
-
step.map!.with_index do |s, i|
|
381
|
-
(s && to[i] && ((s > 0 && to[i] < from[i]) || (s < 0 && from[i] < to[i]))) ? -s : s
|
382
|
-
end
|
383
|
-
|
384
|
-
right_open.map! { |v| v || false }
|
385
|
-
|
386
|
-
function ||= proc { |ratio| ratio }
|
387
|
-
function = function.arrayfy(size: size)
|
388
|
-
|
389
|
-
function_range = 1r.arrayfy(size: size)
|
390
|
-
function_offset = 0r.arrayfy(size: size)
|
391
|
-
|
392
|
-
start_position = position
|
393
|
-
|
394
|
-
if duration || till
|
395
|
-
effective_duration = duration || till - start_position
|
396
|
-
|
397
|
-
# Add 1 tick to arrive to final value in duration time (no need to add an extra tick)
|
398
|
-
right_open_offset = right_open.collect { |ro| ro ? 0 : 1 }
|
399
|
-
|
400
|
-
size.times do |i|
|
401
|
-
if to[i] && step[i] && !every[i]
|
402
|
-
|
403
|
-
steps = (to[i] - from[i]) / step[i]
|
404
|
-
|
405
|
-
# When to == from don't need to do any iteration with every
|
406
|
-
if steps + right_open_offset[i] > 0
|
407
|
-
every[i] = Rational(effective_duration, steps + right_open_offset[i])
|
408
|
-
else
|
409
|
-
every[i] = nil
|
410
|
-
end
|
411
|
-
|
412
|
-
elsif to[i] && !step[i] && !every[i]
|
413
|
-
|
414
|
-
if tick_duration > 0
|
415
|
-
function_range[i] = to[i] - from[i]
|
416
|
-
function_offset[i] = from[i]
|
417
|
-
|
418
|
-
from[i] = 0r
|
419
|
-
to[i] = 1r
|
420
|
-
|
421
|
-
step[i] = 1r / (effective_duration * ticks_per_bar - right_open_offset[i])
|
422
|
-
every[i] = tick_duration
|
423
|
-
else
|
424
|
-
raise ArgumentError, "Cannot use sequencer tickless mode without 'step' or 'every' parameter values"
|
425
|
-
end
|
426
|
-
|
427
|
-
elsif to[i] && !step[i] && every[i]
|
428
|
-
function_range[i] = to[i] - from[i]
|
429
|
-
function_offset[i] = from[i]
|
430
|
-
|
431
|
-
from[i] = 0r
|
432
|
-
to[i] = 1r
|
433
|
-
|
434
|
-
steps = effective_duration / every[i]
|
435
|
-
step[i] = 1r / (steps - right_open_offset[i])
|
436
|
-
|
437
|
-
elsif !to[i] && step[i] && every[i]
|
438
|
-
# ok
|
439
|
-
elsif !to[i] && !step[i] && every[i]
|
440
|
-
step[i] = 1r
|
103
|
+
@timeslots[at_position] << { parent_control: control, block: block_key_parameters_binder,
|
104
|
+
value_parameters: value_parameters,
|
105
|
+
key_parameters: key_parameters }
|
106
|
+
else
|
107
|
+
@logger.warn('BaseSequencer') { "._numeric_at: ignoring past 'at' command for #{at_position}" }
|
108
|
+
end
|
441
109
|
|
442
|
-
|
443
|
-
|
444
|
-
end
|
445
|
-
end
|
446
|
-
else
|
447
|
-
size.times do |i|
|
448
|
-
if to[i] && step[i] && every[i]
|
449
|
-
# ok
|
450
|
-
elsif to[i] && !step[i] && every[i]
|
451
|
-
size.times do |i|
|
452
|
-
step[i] = (to[i] <=> from[i]).to_r
|
453
|
-
end
|
454
|
-
else
|
455
|
-
raise ArgumentError, 'Cannot use this parameters combination'
|
456
|
-
end
|
457
|
-
end
|
458
|
-
end
|
110
|
+
nil
|
111
|
+
end
|
459
112
|
|
460
|
-
|
113
|
+
private def _serie_at(bar_position_serie, control, with: nil, debug: nil, &block)
|
114
|
+
bar_position = bar_position_serie.next_value
|
461
115
|
|
462
|
-
|
463
|
-
|
116
|
+
with_value = if with.respond_to? :next_value
|
117
|
+
with.next_value
|
118
|
+
else
|
119
|
+
with
|
120
|
+
end
|
464
121
|
|
465
|
-
|
466
|
-
|
467
|
-
position_jitters = Array.new(size)
|
468
|
-
duration_jitters = Array.new(size)
|
122
|
+
if bar_position
|
123
|
+
_numeric_at bar_position, control, with: with_value, debug: debug, &block
|
469
124
|
|
470
|
-
|
471
|
-
|
472
|
-
every_groups[every[i]] << i
|
473
|
-
group_counter[every[i]] = 0
|
125
|
+
_numeric_at bar_position, control, debug: false do
|
126
|
+
_serie_at bar_position_serie, control, with: with, debug: debug, &block
|
474
127
|
end
|
128
|
+
else
|
129
|
+
# serie finalizada
|
130
|
+
end
|
475
131
|
|
476
|
-
|
477
|
-
|
478
|
-
on_stop: on_stop, after_bars: after_bars, after: after)
|
132
|
+
nil
|
133
|
+
end
|
479
134
|
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
end
|
484
|
-
end
|
135
|
+
def _rescue_error(e)
|
136
|
+
@logger.error('BaseSequencer') { e.to_s }
|
137
|
+
@logger.error('BaseSequencer') { e.full_message(highlight: true, order: :top) }
|
485
138
|
|
486
|
-
|
139
|
+
@on_error.each do |block|
|
140
|
+
block.call e
|
141
|
+
end
|
142
|
+
end
|
487
143
|
|
488
|
-
|
489
|
-
|
144
|
+
class EventHandler
|
145
|
+
include Musa::Extension::SmartProcBinder
|
490
146
|
|
491
|
-
|
492
|
-
stop = Array.new(size, false)
|
493
|
-
last_position = Array.new(size)
|
147
|
+
attr_accessor :continue_parameters
|
494
148
|
|
495
|
-
|
496
|
-
process_indexes = []
|
149
|
+
@@counter = 0
|
497
150
|
|
498
|
-
|
499
|
-
|
151
|
+
def initialize(parent = nil)
|
152
|
+
@id = (@@counter += 1)
|
500
153
|
|
501
|
-
|
502
|
-
|
503
|
-
# This allow to round the irregularly timed positions due to every intervals not integer
|
504
|
-
# multiples of the tick_duration.
|
505
|
-
#
|
506
|
-
if tick_duration == 0 && group_position == position ||
|
507
|
-
group_position >= position - tick_duration && group_position < position + tick_duration
|
154
|
+
@parent = parent
|
155
|
+
@handlers = {}
|
508
156
|
|
509
|
-
|
157
|
+
@stop = false
|
158
|
+
end
|
510
159
|
|
511
|
-
|
160
|
+
def stop
|
161
|
+
@stop = true
|
162
|
+
end
|
512
163
|
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
else
|
517
|
-
effective_duration
|
518
|
-
end
|
164
|
+
def stopped?
|
165
|
+
@stop
|
166
|
+
end
|
519
167
|
|
520
|
-
|
168
|
+
def pause
|
169
|
+
raise NotImplementedError
|
170
|
+
end
|
521
171
|
|
522
|
-
|
523
|
-
|
524
|
-
|
172
|
+
def continue
|
173
|
+
@paused = false
|
174
|
+
end
|
525
175
|
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
end
|
530
|
-
end
|
176
|
+
def paused?
|
177
|
+
@paused
|
178
|
+
end
|
531
179
|
|
532
|
-
|
533
|
-
|
534
|
-
if process_indexes.any?
|
535
|
-
|
536
|
-
process_indexes.each do |i|
|
537
|
-
unless stop[i]
|
538
|
-
values[i] = next_values[i]
|
539
|
-
next_values[i] += step[i]
|
540
|
-
|
541
|
-
if to[i]
|
542
|
-
stop[i] = if right_open[i]
|
543
|
-
step[i].positive? ? next_values[i] >= to[i] : next_values[i] <= to[i]
|
544
|
-
else
|
545
|
-
step[i].positive? ? next_values[i] > to[i] : next_values[i] < to[i]
|
546
|
-
end
|
547
|
-
|
548
|
-
if stop[i]
|
549
|
-
if right_open[i]
|
550
|
-
next_values[i] = nil if values[i] == to[i]
|
551
|
-
else
|
552
|
-
next_values[i] = nil
|
553
|
-
end
|
554
|
-
end
|
555
|
-
end
|
556
|
-
end
|
557
|
-
end
|
558
|
-
|
559
|
-
control.stop if stop.all?
|
560
|
-
|
561
|
-
effective_values = from.clone(freeze: false).map!.with_index do |_, i|
|
562
|
-
function[i].call(values[i]) * function_range[i] + function_offset[i] unless values[i].nil?
|
563
|
-
end
|
564
|
-
|
565
|
-
effective_next_values = from.clone(freeze: false).map!.with_index do |_, i|
|
566
|
-
function[i].call(next_values[i]) * function_range[i] +
|
567
|
-
function_offset[i] unless next_values[i].nil?
|
568
|
-
end
|
569
|
-
|
570
|
-
# TODO add to values and next_values the modules of the original from and/or to objects.
|
571
|
-
|
572
|
-
value_parameters, key_parameters =
|
573
|
-
if array_mode
|
574
|
-
binder.apply(effective_values, effective_next_values,
|
575
|
-
control: control,
|
576
|
-
duration: _durations(every_groups, effective_duration),
|
577
|
-
quantized_duration: q_durations.dup,
|
578
|
-
started_ago: _started_ago(last_position, position, process_indexes),
|
579
|
-
position_jitter: position_jitters.dup,
|
580
|
-
duration_jitter: duration_jitters.dup,
|
581
|
-
right_open: right_open.dup)
|
582
|
-
elsif hash_mode
|
583
|
-
binder.apply(_hash_from_keys_and_values(hash_keys, effective_values),
|
584
|
-
_hash_from_keys_and_values(hash_keys, effective_next_values),
|
585
|
-
control: control,
|
586
|
-
duration: _hash_from_keys_and_values(
|
587
|
-
hash_keys,
|
588
|
-
_durations(every_groups, effective_duration)),
|
589
|
-
quantized_duration: _hash_from_keys_and_values(
|
590
|
-
hash_keys,
|
591
|
-
q_durations),
|
592
|
-
started_ago: _hash_from_keys_and_values(
|
593
|
-
hash_keys,
|
594
|
-
_started_ago(last_position, position, process_indexes)),
|
595
|
-
position_jitter: _hash_from_keys_and_values(
|
596
|
-
hash_keys,
|
597
|
-
position_jitters),
|
598
|
-
duration_jitter: _hash_from_keys_and_values(
|
599
|
-
hash_keys,
|
600
|
-
duration_jitters),
|
601
|
-
right_open: _hash_from_keys_and_values(hash_keys, right_open))
|
602
|
-
else
|
603
|
-
binder.apply(effective_values.first,
|
604
|
-
effective_next_values.first,
|
605
|
-
control: control,
|
606
|
-
duration: _durations(every_groups, effective_duration).first,
|
607
|
-
quantized_duration: q_durations.first,
|
608
|
-
position_jitter: position_jitters.first,
|
609
|
-
duration_jitter: duration_jitters.first,
|
610
|
-
started_ago: nil,
|
611
|
-
right_open: right_open.first)
|
612
|
-
end
|
613
|
-
|
614
|
-
yield *value_parameters, **key_parameters
|
615
|
-
|
616
|
-
process_indexes.each { |i| last_position[i] = position }
|
617
|
-
end
|
618
|
-
end
|
619
|
-
end
|
180
|
+
def on(event, name: nil, only_once: nil, &block)
|
181
|
+
only_once ||= false
|
620
182
|
|
621
|
-
@
|
183
|
+
@handlers[event] ||= {}
|
622
184
|
|
623
|
-
|
185
|
+
# TODO: add on_rescue: proc { |e| _rescue_block_error(e) } [this method is on Sequencer, not in EventHandler]
|
186
|
+
@handlers[event][name] = { block: SmartProcBinder.new(block), only_once: only_once }
|
624
187
|
end
|
625
188
|
|
626
|
-
def
|
627
|
-
|
628
|
-
last_positions.each_index do |i|
|
629
|
-
if last_positions[i] && !affected_indexes.include?(i)
|
630
|
-
a[i] = position - last_positions[i]
|
631
|
-
end
|
632
|
-
end
|
633
|
-
end
|
189
|
+
def launch(event, *value_parameters, **key_parameters)
|
190
|
+
_launch event, value_parameters, key_parameters
|
634
191
|
end
|
635
192
|
|
636
|
-
def
|
637
|
-
[]
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
193
|
+
def _launch(event, value_parameters = nil, key_parameters = nil)
|
194
|
+
value_parameters ||= []
|
195
|
+
key_parameters ||= {}
|
196
|
+
processed = false
|
197
|
+
|
198
|
+
if @handlers.key? event
|
199
|
+
@handlers[event].each do |name, handler|
|
200
|
+
handler[:block].call *value_parameters, **key_parameters
|
201
|
+
@handlers[event].delete name if handler[:only_once]
|
202
|
+
processed = true
|
646
203
|
end
|
647
204
|
end
|
648
|
-
end
|
649
205
|
|
650
|
-
|
651
|
-
{}.tap { |h| keys.each_index { |i| h[keys[i]] = values[i] } }
|
206
|
+
@parent._launch event, value_parameters, key_parameters if @parent && !processed
|
652
207
|
end
|
653
208
|
|
654
|
-
def
|
655
|
-
|
656
|
-
return nil if intervals.empty?
|
657
|
-
|
658
|
-
lcm_denominators = intervals.collect(&:denominator).reduce(1, :lcm)
|
659
|
-
numerators = intervals.collect { |i| i.numerator * lcm_denominators / i.denominator }
|
660
|
-
gcd_numerators = numerators.reduce(numerators.first, :gcd)
|
661
|
-
|
662
|
-
#intervals.reduce(1r, :*)
|
663
|
-
|
664
|
-
Rational(gcd_numerators, lcm_denominators)
|
209
|
+
def inspect
|
210
|
+
"EventHandler #{id}"
|
665
211
|
end
|
666
212
|
|
667
|
-
def
|
668
|
-
@
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
block.call e
|
213
|
+
def id
|
214
|
+
if @parent
|
215
|
+
"#{@parent.id}.#{self.class.name.split('::').last}-#{@id}"
|
216
|
+
else
|
217
|
+
"#{self.class.name.split('::').last}-#{@id.to_s}"
|
673
218
|
end
|
674
219
|
end
|
220
|
+
|
221
|
+
alias to_s inspect
|
675
222
|
end
|
223
|
+
|
224
|
+
private_constant :EventHandler
|
676
225
|
end
|
677
|
-
end
|
226
|
+
end; end
|
678
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'
|