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.
Files changed (72) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/Gemfile +20 -0
  4. data/LICENSE.md +157 -0
  5. data/README.md +8 -0
  6. data/lib/musa-dsl/core-ext/array-apply-get.rb +18 -0
  7. data/lib/musa-dsl/core-ext/array-explode-ranges.rb +29 -0
  8. data/lib/musa-dsl/core-ext/array-to-neumas.rb +28 -0
  9. data/lib/musa-dsl/core-ext/array-to-serie.rb +20 -0
  10. data/lib/musa-dsl/core-ext/arrayfy.rb +15 -0
  11. data/lib/musa-dsl/core-ext/as-context-run.rb +44 -0
  12. data/lib/musa-dsl/core-ext/duplicate.rb +134 -0
  13. data/lib/musa-dsl/core-ext/dynamic-proxy.rb +55 -0
  14. data/lib/musa-dsl/core-ext/inspect-nice.rb +28 -0
  15. data/lib/musa-dsl/core-ext/key-parameters-procedure-binder.rb +85 -0
  16. data/lib/musa-dsl/core-ext/proc-nice.rb +13 -0
  17. data/lib/musa-dsl/core-ext/send-nice.rb +21 -0
  18. data/lib/musa-dsl/core-ext/string-to-neumas.rb +27 -0
  19. data/lib/musa-dsl/core-ext.rb +13 -0
  20. data/lib/musa-dsl/datasets/gdv-decorators.rb +221 -0
  21. data/lib/musa-dsl/datasets/gdv.rb +499 -0
  22. data/lib/musa-dsl/datasets/pdv.rb +44 -0
  23. data/lib/musa-dsl/datasets.rb +5 -0
  24. data/lib/musa-dsl/generative/darwin.rb +145 -0
  25. data/lib/musa-dsl/generative/generative-grammar.rb +294 -0
  26. data/lib/musa-dsl/generative/markov.rb +78 -0
  27. data/lib/musa-dsl/generative/rules.rb +282 -0
  28. data/lib/musa-dsl/generative/variatio.rb +331 -0
  29. data/lib/musa-dsl/generative.rb +5 -0
  30. data/lib/musa-dsl/midi/midi-recorder.rb +83 -0
  31. data/lib/musa-dsl/midi/midi-voices.rb +274 -0
  32. data/lib/musa-dsl/midi.rb +2 -0
  33. data/lib/musa-dsl/music/chord-definition.rb +99 -0
  34. data/lib/musa-dsl/music/chord-definitions.rb +13 -0
  35. data/lib/musa-dsl/music/chords.rb +326 -0
  36. data/lib/musa-dsl/music/equally-tempered-12-tone-scale-system.rb +204 -0
  37. data/lib/musa-dsl/music/scales.rb +584 -0
  38. data/lib/musa-dsl/music.rb +6 -0
  39. data/lib/musa-dsl/neuma/neuma.rb +181 -0
  40. data/lib/musa-dsl/neuma.rb +1 -0
  41. data/lib/musa-dsl/neumalang/neumalang.citrus +294 -0
  42. data/lib/musa-dsl/neumalang/neumalang.rb +179 -0
  43. data/lib/musa-dsl/neumalang.rb +3 -0
  44. data/lib/musa-dsl/repl/repl.rb +143 -0
  45. data/lib/musa-dsl/repl.rb +1 -0
  46. data/lib/musa-dsl/sequencer/base-sequencer-implementation-control.rb +189 -0
  47. data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-helper.rb +354 -0
  48. data/lib/musa-dsl/sequencer/base-sequencer-implementation.rb +382 -0
  49. data/lib/musa-dsl/sequencer/base-sequencer-public.rb +261 -0
  50. data/lib/musa-dsl/sequencer/sequencer-dsl.rb +94 -0
  51. data/lib/musa-dsl/sequencer/sequencer.rb +3 -0
  52. data/lib/musa-dsl/sequencer.rb +1 -0
  53. data/lib/musa-dsl/series/base-series.rb +245 -0
  54. data/lib/musa-dsl/series/hash-serie-splitter.rb +194 -0
  55. data/lib/musa-dsl/series/holder-serie.rb +87 -0
  56. data/lib/musa-dsl/series/main-serie-constructors.rb +726 -0
  57. data/lib/musa-dsl/series/main-serie-operations.rb +1151 -0
  58. data/lib/musa-dsl/series/proxy-serie.rb +69 -0
  59. data/lib/musa-dsl/series/queue-serie.rb +94 -0
  60. data/lib/musa-dsl/series/series.rb +8 -0
  61. data/lib/musa-dsl/series.rb +1 -0
  62. data/lib/musa-dsl/transport/clock.rb +36 -0
  63. data/lib/musa-dsl/transport/dummy-clock.rb +47 -0
  64. data/lib/musa-dsl/transport/external-tick-clock.rb +31 -0
  65. data/lib/musa-dsl/transport/input-midi-clock.rb +124 -0
  66. data/lib/musa-dsl/transport/timer-clock.rb +102 -0
  67. data/lib/musa-dsl/transport/timer.rb +40 -0
  68. data/lib/musa-dsl/transport/transport.rb +137 -0
  69. data/lib/musa-dsl/transport.rb +9 -0
  70. data/lib/musa-dsl.rb +17 -0
  71. data/musa-dsl.gemspec +17 -0
  72. 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