musa-dsl 0.14.16
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 +7 -0
- data/.gitignore +10 -0
- data/Gemfile +20 -0
- data/LICENSE.md +157 -0
- data/README.md +8 -0
- data/lib/musa-dsl/core-ext/array-apply-get.rb +18 -0
- data/lib/musa-dsl/core-ext/array-explode-ranges.rb +29 -0
- data/lib/musa-dsl/core-ext/array-to-neumas.rb +28 -0
- data/lib/musa-dsl/core-ext/array-to-serie.rb +20 -0
- data/lib/musa-dsl/core-ext/arrayfy.rb +15 -0
- data/lib/musa-dsl/core-ext/as-context-run.rb +44 -0
- data/lib/musa-dsl/core-ext/duplicate.rb +134 -0
- data/lib/musa-dsl/core-ext/dynamic-proxy.rb +55 -0
- data/lib/musa-dsl/core-ext/inspect-nice.rb +28 -0
- data/lib/musa-dsl/core-ext/key-parameters-procedure-binder.rb +85 -0
- data/lib/musa-dsl/core-ext/proc-nice.rb +13 -0
- data/lib/musa-dsl/core-ext/send-nice.rb +21 -0
- data/lib/musa-dsl/core-ext/string-to-neumas.rb +27 -0
- data/lib/musa-dsl/core-ext.rb +13 -0
- data/lib/musa-dsl/datasets/gdv-decorators.rb +221 -0
- data/lib/musa-dsl/datasets/gdv.rb +499 -0
- data/lib/musa-dsl/datasets/pdv.rb +44 -0
- data/lib/musa-dsl/datasets.rb +5 -0
- data/lib/musa-dsl/generative/darwin.rb +145 -0
- data/lib/musa-dsl/generative/generative-grammar.rb +294 -0
- data/lib/musa-dsl/generative/markov.rb +78 -0
- data/lib/musa-dsl/generative/rules.rb +282 -0
- data/lib/musa-dsl/generative/variatio.rb +331 -0
- data/lib/musa-dsl/generative.rb +5 -0
- data/lib/musa-dsl/midi/midi-recorder.rb +83 -0
- data/lib/musa-dsl/midi/midi-voices.rb +274 -0
- data/lib/musa-dsl/midi.rb +2 -0
- data/lib/musa-dsl/music/chord-definition.rb +99 -0
- data/lib/musa-dsl/music/chord-definitions.rb +13 -0
- data/lib/musa-dsl/music/chords.rb +326 -0
- data/lib/musa-dsl/music/equally-tempered-12-tone-scale-system.rb +204 -0
- data/lib/musa-dsl/music/scales.rb +584 -0
- data/lib/musa-dsl/music.rb +6 -0
- data/lib/musa-dsl/neuma/neuma.rb +181 -0
- data/lib/musa-dsl/neuma.rb +1 -0
- data/lib/musa-dsl/neumalang/neumalang.citrus +294 -0
- data/lib/musa-dsl/neumalang/neumalang.rb +179 -0
- data/lib/musa-dsl/neumalang.rb +3 -0
- data/lib/musa-dsl/repl/repl.rb +143 -0
- data/lib/musa-dsl/repl.rb +1 -0
- data/lib/musa-dsl/sequencer/base-sequencer-implementation-control.rb +189 -0
- data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-helper.rb +354 -0
- data/lib/musa-dsl/sequencer/base-sequencer-implementation.rb +382 -0
- data/lib/musa-dsl/sequencer/base-sequencer-public.rb +261 -0
- data/lib/musa-dsl/sequencer/sequencer-dsl.rb +94 -0
- data/lib/musa-dsl/sequencer/sequencer.rb +3 -0
- data/lib/musa-dsl/sequencer.rb +1 -0
- data/lib/musa-dsl/series/base-series.rb +245 -0
- data/lib/musa-dsl/series/hash-serie-splitter.rb +194 -0
- data/lib/musa-dsl/series/holder-serie.rb +87 -0
- data/lib/musa-dsl/series/main-serie-constructors.rb +726 -0
- data/lib/musa-dsl/series/main-serie-operations.rb +1151 -0
- data/lib/musa-dsl/series/proxy-serie.rb +69 -0
- data/lib/musa-dsl/series/queue-serie.rb +94 -0
- data/lib/musa-dsl/series/series.rb +8 -0
- data/lib/musa-dsl/series.rb +1 -0
- data/lib/musa-dsl/transport/clock.rb +36 -0
- data/lib/musa-dsl/transport/dummy-clock.rb +47 -0
- data/lib/musa-dsl/transport/external-tick-clock.rb +31 -0
- data/lib/musa-dsl/transport/input-midi-clock.rb +124 -0
- data/lib/musa-dsl/transport/timer-clock.rb +102 -0
- data/lib/musa-dsl/transport/timer.rb +40 -0
- data/lib/musa-dsl/transport/transport.rb +137 -0
- data/lib/musa-dsl/transport.rb +9 -0
- data/lib/musa-dsl.rb +17 -0
- data/musa-dsl.gemspec +17 -0
- metadata +174 -0
@@ -0,0 +1,382 @@
|
|
1
|
+
require 'musa-dsl/core-ext/arrayfy'
|
2
|
+
require 'musa-dsl/core-ext/key-parameters-procedure-binder'
|
3
|
+
|
4
|
+
require_relative 'base-sequencer-implementation-control'
|
5
|
+
require_relative 'base-sequencer-implementation-play-helper'
|
6
|
+
|
7
|
+
class Musa::BaseSequencer
|
8
|
+
private
|
9
|
+
|
10
|
+
def _raw_numeric_at(bar_position, force_first: nil, &block)
|
11
|
+
force_first ||= false
|
12
|
+
|
13
|
+
position = bar_position.rationalize * @ticks_per_bar
|
14
|
+
|
15
|
+
if position == @position
|
16
|
+
begin
|
17
|
+
yield
|
18
|
+
rescue StandardError, ScriptError => e
|
19
|
+
_rescue_block_error e
|
20
|
+
end
|
21
|
+
|
22
|
+
elsif position > @position
|
23
|
+
@score[position] = [] unless @score[position]
|
24
|
+
|
25
|
+
value = { block: block, value_parameters: [], key_parameters: {} }
|
26
|
+
if force_first
|
27
|
+
@score[position].insert 0, value
|
28
|
+
else
|
29
|
+
@score[position] << value
|
30
|
+
end
|
31
|
+
else
|
32
|
+
_log "BaseSequencer._raw_numeric_at: warning: ignoring past at command for #{Rational(position, @ticks_per_bar)}" if @do_log
|
33
|
+
end
|
34
|
+
|
35
|
+
nil
|
36
|
+
end
|
37
|
+
|
38
|
+
def _numeric_at(bar_position, control, with: nil, debug: nil, &block)
|
39
|
+
raise ArgumentError, 'Block is mandatory' unless block
|
40
|
+
|
41
|
+
position = bar_position.rationalize * @ticks_per_bar
|
42
|
+
|
43
|
+
if position != position.round
|
44
|
+
original_position = position
|
45
|
+
position = position.round.rationalize
|
46
|
+
|
47
|
+
if @do_log
|
48
|
+
_log "BaseSequencer._numeric_at: warning: rounding position #{bar_position} (#{original_position}) "\
|
49
|
+
"to tick precision: #{position / @ticks_per_bar} (#{position})"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
value_parameters = []
|
54
|
+
value_parameters << with if !with.nil? && !with.is_a?(Hash)
|
55
|
+
|
56
|
+
if block_given?
|
57
|
+
block_key_parameters_binder =
|
58
|
+
KeyParametersProcedureBinder.new block, on_rescue: proc { |e| _rescue_block_error(e) }
|
59
|
+
|
60
|
+
key_parameters = {}
|
61
|
+
key_parameters.merge! block_key_parameters_binder.apply with if with.is_a? Hash
|
62
|
+
|
63
|
+
key_parameters[:control] = control if block_key_parameters_binder.key?(:control)
|
64
|
+
|
65
|
+
if position == @position
|
66
|
+
@debug_at.call if debug && @debug_at
|
67
|
+
|
68
|
+
begin
|
69
|
+
locked = @@tick_mutex.try_lock
|
70
|
+
|
71
|
+
if locked
|
72
|
+
original_stdout = $stdout
|
73
|
+
original_stderr = $stderr
|
74
|
+
|
75
|
+
$stdout = control.stdout
|
76
|
+
$stderr = control.stderr
|
77
|
+
end
|
78
|
+
|
79
|
+
block_key_parameters_binder._call value_parameters, key_parameters
|
80
|
+
ensure
|
81
|
+
if locked
|
82
|
+
$stdout = original_stdout
|
83
|
+
$stderr = original_stderr
|
84
|
+
end
|
85
|
+
|
86
|
+
@@tick_mutex.unlock if locked
|
87
|
+
end
|
88
|
+
|
89
|
+
elsif position > @position
|
90
|
+
@score[position] = [] unless @score[position]
|
91
|
+
|
92
|
+
@score[position] << { parent_control: control, block: @on_debug_at } if debug && @on_debug_at
|
93
|
+
@score[position] << { parent_control: control, block: block_key_parameters_binder, value_parameters: value_parameters, key_parameters: key_parameters }
|
94
|
+
else
|
95
|
+
_log "BaseSequencer._numeric_at: warning: ignoring past at command for #{Rational(position, @ticks_per_bar)}" if @do_log
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
nil
|
100
|
+
end
|
101
|
+
|
102
|
+
def _serie_at(bar_position_serie, control, with: nil, debug: nil, &block)
|
103
|
+
|
104
|
+
bar_position = bar_position_serie.next_value
|
105
|
+
|
106
|
+
with_value = if with.respond_to? :next_value
|
107
|
+
with.next_value
|
108
|
+
else
|
109
|
+
with
|
110
|
+
end
|
111
|
+
|
112
|
+
if bar_position
|
113
|
+
_numeric_at bar_position, control, with: with_value, debug: debug, &block
|
114
|
+
|
115
|
+
_numeric_at bar_position, control, debug: false do
|
116
|
+
_serie_at bar_position_serie, control, with: with, debug: debug, &block
|
117
|
+
end
|
118
|
+
else
|
119
|
+
# serie finalizada
|
120
|
+
end
|
121
|
+
|
122
|
+
nil
|
123
|
+
end
|
124
|
+
|
125
|
+
def _play(serie, control, nl_context = nil, mode: nil, decoder: nil, __play_eval: nil, **mode_args, &block)
|
126
|
+
|
127
|
+
block ||= proc {}
|
128
|
+
|
129
|
+
__play_eval ||= PlayEval.create \
|
130
|
+
mode,
|
131
|
+
KeyParametersProcedureBinder.new(block,
|
132
|
+
on_rescue: proc { |e| _rescue_block_error(e) }),
|
133
|
+
decoder,
|
134
|
+
nl_context
|
135
|
+
|
136
|
+
element = nil
|
137
|
+
|
138
|
+
if control.stopped?
|
139
|
+
# nothing to do
|
140
|
+
elsif control.paused?
|
141
|
+
control.store_continuation sequencer: self,
|
142
|
+
serie: serie,
|
143
|
+
nl_context: nl_context,
|
144
|
+
mode: mode,
|
145
|
+
decoder: decoder,
|
146
|
+
play_eval: __play_eval,
|
147
|
+
mode_args: mode_args
|
148
|
+
else
|
149
|
+
element = serie.next_value
|
150
|
+
end
|
151
|
+
|
152
|
+
if element
|
153
|
+
operation = __play_eval.run_operation element
|
154
|
+
|
155
|
+
case operation[:current_operation]
|
156
|
+
|
157
|
+
when :none
|
158
|
+
|
159
|
+
when :block
|
160
|
+
|
161
|
+
__play_eval.block_procedure_binder.call operation[:current_parameter], control: control
|
162
|
+
|
163
|
+
when :event
|
164
|
+
|
165
|
+
control._launch operation[:current_event],
|
166
|
+
operation[:current_value_parameters],
|
167
|
+
operation[:current_key_parameters]
|
168
|
+
|
169
|
+
when :play
|
170
|
+
|
171
|
+
control2 = PlayControl.new control
|
172
|
+
control3 = PlayControl.new control2
|
173
|
+
control3.after { control3.launch :sync }
|
174
|
+
|
175
|
+
_play operation[:current_parameter].instance,
|
176
|
+
control3,
|
177
|
+
__play_eval: __play_eval.subcontext,
|
178
|
+
**mode_args
|
179
|
+
|
180
|
+
control2.on :sync do
|
181
|
+
_play serie, control, __play_eval: __play_eval, **mode_args
|
182
|
+
end
|
183
|
+
|
184
|
+
when :no_eval_play
|
185
|
+
|
186
|
+
control2 = PlayControl.new control
|
187
|
+
control3 = PlayControl.new control2
|
188
|
+
control3.after { control3.launch :sync }
|
189
|
+
|
190
|
+
_play operation[:current_parameter].instance,
|
191
|
+
control3,
|
192
|
+
__play_eval: WaitModePlayEval.new(__play_eval.block_procedure_binder),
|
193
|
+
**mode_args
|
194
|
+
|
195
|
+
control2.on :sync do
|
196
|
+
_play serie, control, __play_eval: __play_eval, **mode_args
|
197
|
+
end
|
198
|
+
|
199
|
+
when :parallel_play
|
200
|
+
|
201
|
+
control2 = PlayControl.new control
|
202
|
+
|
203
|
+
operation[:current_parameter].each do |current_parameter|
|
204
|
+
control3 = PlayControl.new control2
|
205
|
+
control3.after { control3.launch :sync }
|
206
|
+
|
207
|
+
_play current_parameter.instance,
|
208
|
+
control3,
|
209
|
+
__play_eval: __play_eval.subcontext,
|
210
|
+
**mode_args
|
211
|
+
end
|
212
|
+
|
213
|
+
counter = operation[:current_parameter].size
|
214
|
+
|
215
|
+
control2.on :sync do
|
216
|
+
counter -= 1
|
217
|
+
_play serie, control, __play_eval: __play_eval, **mode_args if counter == 0
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
case operation[:continue_operation]
|
222
|
+
when :now
|
223
|
+
#now do
|
224
|
+
_numeric_at position, control do
|
225
|
+
_play serie, control, __play_eval: __play_eval, **mode_args
|
226
|
+
end
|
227
|
+
|
228
|
+
when :at
|
229
|
+
#at operation[:continue_parameter] do
|
230
|
+
_numeric_at operation[:continue_parameter], control do
|
231
|
+
_play serie, control, __play_eval: __play_eval, **mode_args
|
232
|
+
end
|
233
|
+
|
234
|
+
when :wait
|
235
|
+
#wait operation[:continue_parameter] do
|
236
|
+
_numeric_at position + operation[:continue_parameter].rationalize, control do
|
237
|
+
_play serie, control, __play_eval: __play_eval, **mode_args
|
238
|
+
end
|
239
|
+
|
240
|
+
when :on
|
241
|
+
control.on operation[:continue_parameter], only_once: true do
|
242
|
+
_play serie, control, __play_eval: __play_eval, **mode_args
|
243
|
+
end
|
244
|
+
end
|
245
|
+
else
|
246
|
+
control2 = EventHandler.new control
|
247
|
+
|
248
|
+
control.do_after.each do |do_after|
|
249
|
+
_numeric_at position, control2, &do_after
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
nil
|
254
|
+
end
|
255
|
+
|
256
|
+
def _every(binterval, control, block_procedure_binder: nil, &block)
|
257
|
+
|
258
|
+
block ||= proc {}
|
259
|
+
|
260
|
+
block_procedure_binder ||= KeyParametersProcedureBinder.new block, on_rescue: proc { |e| _rescue_block_error(e) }
|
261
|
+
|
262
|
+
_numeric_at position, control do
|
263
|
+
control._start ||= position
|
264
|
+
|
265
|
+
duration_exceeded = (control._start + control.duration_value - binterval) <= position if control.duration_value
|
266
|
+
till_exceeded = control.till_value - binterval <= position if control.till_value
|
267
|
+
condition_failed = !instance_eval(&control.condition) if control.condition
|
268
|
+
|
269
|
+
block_procedure_binder.call(control: control) unless control.stopped?
|
270
|
+
|
271
|
+
if !control.stopped? && !duration_exceeded && !till_exceeded && !condition_failed
|
272
|
+
|
273
|
+
_numeric_at position + binterval, control do
|
274
|
+
_every binterval, control, block_procedure_binder: block_procedure_binder
|
275
|
+
end
|
276
|
+
else
|
277
|
+
control.do_on_stop.each(&:call)
|
278
|
+
|
279
|
+
control.do_after.each do |do_after|
|
280
|
+
_numeric_at position + binterval + do_after[:bars], control, &do_after[:block]
|
281
|
+
end
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
nil
|
286
|
+
end
|
287
|
+
|
288
|
+
def _move(every: nil, from:, to: nil, step: nil, duration: nil, till: nil, on_stop: nil, after_bars: nil, after: nil, &block)
|
289
|
+
|
290
|
+
raise ArgumentError, "Cannot use duration: #{duration} and till: #{till} parameters at the same time. Use only one of them." if till && duration
|
291
|
+
|
292
|
+
# from, to, step, every
|
293
|
+
# from, to, step, (duration | till)
|
294
|
+
# from, to, every, (duration | till)
|
295
|
+
# from, step, every, (duration | till)
|
296
|
+
|
297
|
+
block ||= proc {}
|
298
|
+
|
299
|
+
step = -step if step && to && ((step > 0 && to < from) || (step < 0 && from < to))
|
300
|
+
|
301
|
+
start_position = position
|
302
|
+
|
303
|
+
if duration || till
|
304
|
+
effective_duration = duration || till - start_position
|
305
|
+
|
306
|
+
if to && step && !every
|
307
|
+
steps = (to - from) / step
|
308
|
+
every = Rational(effective_duration, steps)
|
309
|
+
|
310
|
+
elsif to && !step && !every
|
311
|
+
step = (to <=> from).to_r
|
312
|
+
every = Rational(effective_duration, (to - from).abs)
|
313
|
+
|
314
|
+
elsif to && !step && every
|
315
|
+
steps = (to - from) / every
|
316
|
+
step = (to - from) / steps
|
317
|
+
|
318
|
+
elsif !to && step && every
|
319
|
+
# ok
|
320
|
+
elsif !to && !step && every
|
321
|
+
step = 1r
|
322
|
+
|
323
|
+
else
|
324
|
+
raise ArgumentError, 'Cannot use this parameters combination'
|
325
|
+
end
|
326
|
+
else
|
327
|
+
if to && step && every
|
328
|
+
# ok
|
329
|
+
elsif to && !step && every
|
330
|
+
step = (to <=> from).to_r
|
331
|
+
else
|
332
|
+
raise ArgumentError, 'Cannot use this parameters combination'
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
|
337
|
+
binder = KeyParametersProcedureBinder.new(block)
|
338
|
+
|
339
|
+
every_control = EveryControl.new(@event_handlers.last, capture_stdout: true, duration: duration, till: till, on_stop: on_stop, after_bars: after_bars, after: after)
|
340
|
+
|
341
|
+
control = MoveControl.new(every_control)
|
342
|
+
|
343
|
+
@event_handlers.push control
|
344
|
+
|
345
|
+
_numeric_at start_position, control do
|
346
|
+
value = from
|
347
|
+
|
348
|
+
_every every, every_control do
|
349
|
+
|
350
|
+
parameters = binder.apply(control: control)
|
351
|
+
|
352
|
+
yield value, **parameters
|
353
|
+
|
354
|
+
if to && (value >= to && step.positive? || value <= to && step.negative?)
|
355
|
+
control.stop
|
356
|
+
else
|
357
|
+
value += step
|
358
|
+
end
|
359
|
+
end
|
360
|
+
end
|
361
|
+
|
362
|
+
@event_handlers.pop
|
363
|
+
|
364
|
+
control
|
365
|
+
end
|
366
|
+
|
367
|
+
def _rescue_block_error(e)
|
368
|
+
_log e
|
369
|
+
_log e.full_message(order: :top)
|
370
|
+
|
371
|
+
@on_block_error.each do |block|
|
372
|
+
block.call e
|
373
|
+
end
|
374
|
+
end
|
375
|
+
|
376
|
+
def _log(msg = nil)
|
377
|
+
m = '...' unless msg
|
378
|
+
m = ": #{msg}" if msg
|
379
|
+
|
380
|
+
warn "#{position.to_f.round(3)} [#{position}]#{m}"
|
381
|
+
end
|
382
|
+
end
|
@@ -0,0 +1,261 @@
|
|
1
|
+
require 'musa-dsl/core-ext/arrayfy'
|
2
|
+
require 'musa-dsl/core-ext/key-parameters-procedure-binder'
|
3
|
+
|
4
|
+
require 'musa-dsl/series'
|
5
|
+
|
6
|
+
class Musa::BaseSequencer
|
7
|
+
attr_reader :ticks_per_bar, :running_position
|
8
|
+
attr_reader :everying, :playing, :moving
|
9
|
+
|
10
|
+
@@tick_mutex = Mutex.new
|
11
|
+
|
12
|
+
def initialize(beats_per_bar, ticks_per_beat, do_log: nil)
|
13
|
+
do_log ||= false
|
14
|
+
|
15
|
+
@on_debug_at = []
|
16
|
+
@on_fast_forward = []
|
17
|
+
@on_block_error = []
|
18
|
+
|
19
|
+
@ticks_per_bar = Rational(beats_per_bar * ticks_per_beat)
|
20
|
+
|
21
|
+
@score = {}
|
22
|
+
|
23
|
+
@everying = []
|
24
|
+
@playing = []
|
25
|
+
@moving = []
|
26
|
+
|
27
|
+
@do_log = do_log
|
28
|
+
|
29
|
+
reset
|
30
|
+
end
|
31
|
+
|
32
|
+
def reset
|
33
|
+
@score.clear
|
34
|
+
@everying.clear
|
35
|
+
@playing.clear
|
36
|
+
@moving.clear
|
37
|
+
|
38
|
+
@event_handlers = [EventHandler.new]
|
39
|
+
|
40
|
+
@position = @ticks_per_bar - 1
|
41
|
+
end
|
42
|
+
|
43
|
+
def tick
|
44
|
+
position_to_run = (@position += 1)
|
45
|
+
|
46
|
+
if @score[position_to_run]
|
47
|
+
@score[position_to_run].each do |command|
|
48
|
+
|
49
|
+
if command.key?(:parent_control) && !command[:parent_control].stopped?
|
50
|
+
@event_handlers.push command[:parent_control]
|
51
|
+
|
52
|
+
@@tick_mutex.synchronize do
|
53
|
+
original_stdout = $stdout
|
54
|
+
original_stderr = $stderr
|
55
|
+
|
56
|
+
$stdout = command[:parent_control].stdout
|
57
|
+
$stderr = command[:parent_control].stderr
|
58
|
+
|
59
|
+
command[:block]._call command[:value_parameters], command[:key_parameters] if command[:block]
|
60
|
+
|
61
|
+
$stdout = original_stdout
|
62
|
+
$stderr = original_stderr
|
63
|
+
end
|
64
|
+
|
65
|
+
@event_handlers.pop
|
66
|
+
else
|
67
|
+
@@tick_mutex.synchronize do
|
68
|
+
command[:block]._call command[:value_parameters], command[:key_parameters] if command[:block]
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
@score.delete position_to_run
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def size
|
78
|
+
@score.size
|
79
|
+
end
|
80
|
+
|
81
|
+
def empty?
|
82
|
+
@score.empty?
|
83
|
+
end
|
84
|
+
|
85
|
+
def round(bar)
|
86
|
+
Rational((bar * @ticks_per_bar).round(0), @ticks_per_bar)
|
87
|
+
end
|
88
|
+
|
89
|
+
def event_handler
|
90
|
+
@event_handlers.last
|
91
|
+
end
|
92
|
+
|
93
|
+
def on_debug_at(&block)
|
94
|
+
@on_debug_at << block
|
95
|
+
end
|
96
|
+
|
97
|
+
def on_block_error(&block)
|
98
|
+
@on_block_error << block
|
99
|
+
end
|
100
|
+
|
101
|
+
def on_fast_forward(&block)
|
102
|
+
@on_fast_forward << block
|
103
|
+
end
|
104
|
+
|
105
|
+
def position
|
106
|
+
Rational(@position, @ticks_per_bar)
|
107
|
+
end
|
108
|
+
|
109
|
+
def position=(bposition)
|
110
|
+
position = bposition * @ticks_per_bar
|
111
|
+
|
112
|
+
raise ArgumentError, "Sequencer #{self}: cannot move back. current position: #{@position} new position: #{position}" if position < @position
|
113
|
+
|
114
|
+
@on_fast_forward.each { |block| block.call(true) }
|
115
|
+
|
116
|
+
tick while @position < position
|
117
|
+
|
118
|
+
@on_fast_forward.each { |block| block.call(false) }
|
119
|
+
end
|
120
|
+
|
121
|
+
def on(event, &block)
|
122
|
+
@event_handlers.last.on event, &block
|
123
|
+
end
|
124
|
+
|
125
|
+
def launch(event, *value_parameters, **key_parameters)
|
126
|
+
@event_handlers.last.launch event, *value_parameters, **key_parameters
|
127
|
+
end
|
128
|
+
|
129
|
+
def wait(bars_delay, with: nil, debug: nil, &block)
|
130
|
+
debug ||= false
|
131
|
+
|
132
|
+
control = EventHandler.new @event_handlers.last, capture_stdout: true
|
133
|
+
@event_handlers.push control
|
134
|
+
|
135
|
+
if bars_delay.is_a? Numeric
|
136
|
+
_numeric_at position + bars_delay.rationalize, control, with: with, debug: debug, &block
|
137
|
+
else
|
138
|
+
bars_delay = Series::S(*bars_delay) if bars_delay.is_a? Array
|
139
|
+
bars_delay = bars_delay.instance if bars_delay
|
140
|
+
|
141
|
+
with = Series::S(*with).repeat if with.is_a? Array
|
142
|
+
with = with.instance if with
|
143
|
+
|
144
|
+
_serie_at bars_delay.eval { |delay| position + delay }, control, with: with, debug: debug, &block
|
145
|
+
end
|
146
|
+
|
147
|
+
@event_handlers.pop
|
148
|
+
|
149
|
+
control
|
150
|
+
end
|
151
|
+
|
152
|
+
def now(with: nil, &block)
|
153
|
+
control = EventHandler.new @event_handlers.last, capture_stdout: true
|
154
|
+
@event_handlers.push control
|
155
|
+
|
156
|
+
_numeric_at position, control, with: with, &block
|
157
|
+
|
158
|
+
@event_handlers.pop
|
159
|
+
|
160
|
+
control
|
161
|
+
end
|
162
|
+
|
163
|
+
def raw_at(bar_position, force_first: nil, &block)
|
164
|
+
_raw_numeric_at bar_position, force_first: force_first, &block
|
165
|
+
|
166
|
+
nil
|
167
|
+
end
|
168
|
+
|
169
|
+
def at(bar_position, with: nil, debug: nil, &block)
|
170
|
+
debug ||= false
|
171
|
+
|
172
|
+
control = EventHandler.new @event_handlers.last, capture_stdout: true
|
173
|
+
@event_handlers.push control
|
174
|
+
|
175
|
+
if bar_position.is_a? Numeric
|
176
|
+
_numeric_at bar_position, control, with: with, debug: debug, &block
|
177
|
+
else
|
178
|
+
bar_position = Series::S(*bar_position) if bar_position.is_a? Array
|
179
|
+
bar_position = bar_position.instance if bar_position
|
180
|
+
|
181
|
+
with = Series::S(*with).repeat if with.is_a? Array
|
182
|
+
with = with.instance if with
|
183
|
+
|
184
|
+
_serie_at bar_position, control, with: with, debug: debug, &block
|
185
|
+
end
|
186
|
+
|
187
|
+
@event_handlers.pop
|
188
|
+
|
189
|
+
control
|
190
|
+
end
|
191
|
+
|
192
|
+
def play(serie, mode: nil, parameter: nil, after: nil, context: nil, **mode_args, &block)
|
193
|
+
mode ||= :wait
|
194
|
+
|
195
|
+
control = PlayControl.new @event_handlers.last, after: after, capture_stdout: true
|
196
|
+
@event_handlers.push control
|
197
|
+
|
198
|
+
_play serie.instance, control, context, mode: mode, parameter: parameter, **mode_args, &block
|
199
|
+
|
200
|
+
@event_handlers.pop
|
201
|
+
|
202
|
+
@playing << control
|
203
|
+
|
204
|
+
control.after do
|
205
|
+
@playing.delete control
|
206
|
+
end
|
207
|
+
|
208
|
+
control
|
209
|
+
end
|
210
|
+
|
211
|
+
def continuation_play(parameters)
|
212
|
+
_play parameters[:serie],
|
213
|
+
parameters[:control],
|
214
|
+
parameters[:nl_context],
|
215
|
+
mode: parameters[:mode],
|
216
|
+
decoder: parameters[:decoder],
|
217
|
+
__play_eval: parameters[:play_eval],
|
218
|
+
**parameters[:mode_args]
|
219
|
+
end
|
220
|
+
|
221
|
+
def every(binterval, duration: nil, till: nil, condition: nil, on_stop: nil, after_bars: nil, after: nil, &block)
|
222
|
+
binterval = binterval.rationalize
|
223
|
+
|
224
|
+
control = EveryControl.new @event_handlers.last, capture_stdout: true, duration: duration, till: till, condition: condition, on_stop: on_stop, after_bars: after_bars, after: after
|
225
|
+
@event_handlers.push control
|
226
|
+
|
227
|
+
_every binterval, control, &block
|
228
|
+
|
229
|
+
@event_handlers.pop
|
230
|
+
|
231
|
+
@everying << control
|
232
|
+
|
233
|
+
control.after do
|
234
|
+
@everying.delete control
|
235
|
+
end
|
236
|
+
|
237
|
+
control
|
238
|
+
end
|
239
|
+
|
240
|
+
def move(every: nil, from: nil, to: nil, step: nil, duration: nil, till: nil, on_stop: nil, after_bars: nil, after: nil, &block)
|
241
|
+
control = _move every: every, from: from, to: to, step: step, duration: duration, till: till, on_stop: on_stop, after_bars: after_bars, after: after, &block
|
242
|
+
|
243
|
+
@moving << control
|
244
|
+
|
245
|
+
control.after do
|
246
|
+
@moving.delete control
|
247
|
+
end
|
248
|
+
|
249
|
+
control
|
250
|
+
end
|
251
|
+
|
252
|
+
def log(msg = nil)
|
253
|
+
_log msg
|
254
|
+
end
|
255
|
+
|
256
|
+
def inspect
|
257
|
+
super + ": position=#{position}"
|
258
|
+
end
|
259
|
+
|
260
|
+
alias to_s inspect
|
261
|
+
end
|