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