musa-dsl 0.21.1 → 0.22.1
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 +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'
|