musa-dsl 0.14.26 → 0.21.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +3 -1
- data/Gemfile +0 -1
- data/README.md +5 -1
- data/lib/musa-dsl.rb +54 -11
- data/lib/musa-dsl/core-ext.rb +7 -13
- data/lib/musa-dsl/core-ext/array-explode-ranges.rb +15 -23
- data/lib/musa-dsl/core-ext/arrayfy.rb +30 -12
- data/lib/musa-dsl/core-ext/attribute-builder.rb +194 -0
- data/lib/musa-dsl/core-ext/deep-copy.rb +185 -0
- data/lib/musa-dsl/core-ext/dynamic-proxy.rb +44 -40
- data/lib/musa-dsl/core-ext/inspect-nice.rb +40 -22
- data/lib/musa-dsl/core-ext/smart-proc-binder.rb +108 -0
- data/lib/musa-dsl/core-ext/with.rb +26 -0
- data/lib/musa-dsl/datasets.rb +8 -3
- data/lib/musa-dsl/datasets/dataset.rb +3 -0
- data/lib/musa-dsl/datasets/delta-d.rb +12 -0
- data/lib/musa-dsl/datasets/e.rb +61 -0
- data/lib/musa-dsl/datasets/gdv.rb +51 -411
- data/lib/musa-dsl/datasets/gdvd.rb +179 -0
- data/lib/musa-dsl/datasets/helper.rb +41 -0
- data/lib/musa-dsl/datasets/p.rb +68 -0
- data/lib/musa-dsl/datasets/packed-v.rb +19 -0
- data/lib/musa-dsl/datasets/pdv.rb +22 -15
- data/lib/musa-dsl/datasets/ps.rb +113 -0
- data/lib/musa-dsl/datasets/score.rb +210 -0
- data/lib/musa-dsl/datasets/score/queriable.rb +48 -0
- data/lib/musa-dsl/datasets/score/render.rb +31 -0
- data/lib/musa-dsl/datasets/score/to-mxml/process-pdv.rb +160 -0
- data/lib/musa-dsl/datasets/score/to-mxml/process-ps.rb +51 -0
- data/lib/musa-dsl/datasets/score/to-mxml/process-time.rb +153 -0
- data/lib/musa-dsl/datasets/score/to-mxml/to-mxml.rb +158 -0
- data/lib/musa-dsl/datasets/v.rb +23 -0
- data/lib/musa-dsl/generative.rb +5 -5
- data/lib/musa-dsl/generative/backboner.rb +274 -0
- data/lib/musa-dsl/generative/darwin.rb +102 -96
- data/lib/musa-dsl/generative/generative-grammar.rb +182 -187
- data/lib/musa-dsl/generative/markov.rb +56 -53
- data/lib/musa-dsl/generative/variatio.rb +234 -222
- data/lib/musa-dsl/logger.rb +1 -0
- data/lib/musa-dsl/logger/logger.rb +31 -0
- data/lib/musa-dsl/matrix.rb +1 -0
- data/lib/musa-dsl/matrix/matrix.rb +210 -0
- data/lib/musa-dsl/midi.rb +2 -2
- data/lib/musa-dsl/midi/midi-recorder.rb +54 -52
- data/lib/musa-dsl/midi/midi-voices.rb +183 -182
- data/lib/musa-dsl/music.rb +5 -5
- data/lib/musa-dsl/music/chord-definition.rb +54 -50
- data/lib/musa-dsl/music/chord-definitions.rb +13 -9
- data/lib/musa-dsl/music/chords.rb +236 -238
- data/lib/musa-dsl/music/equally-tempered-12-tone-scale-system.rb +187 -183
- data/lib/musa-dsl/music/scales.rb +331 -332
- data/lib/musa-dsl/musicxml.rb +1 -0
- data/lib/musa-dsl/musicxml/builder/attributes.rb +155 -0
- data/lib/musa-dsl/musicxml/builder/backup-forward.rb +45 -0
- data/lib/musa-dsl/musicxml/builder/direction.rb +322 -0
- data/lib/musa-dsl/musicxml/builder/helper.rb +90 -0
- data/lib/musa-dsl/musicxml/builder/measure.rb +137 -0
- data/lib/musa-dsl/musicxml/builder/note-complexities.rb +152 -0
- data/lib/musa-dsl/musicxml/builder/note.rb +577 -0
- data/lib/musa-dsl/musicxml/builder/part-group.rb +44 -0
- data/lib/musa-dsl/musicxml/builder/part.rb +67 -0
- data/lib/musa-dsl/musicxml/builder/pitched-note.rb +126 -0
- data/lib/musa-dsl/musicxml/builder/rest.rb +117 -0
- data/lib/musa-dsl/musicxml/builder/score-partwise.rb +120 -0
- data/lib/musa-dsl/musicxml/builder/typed-text.rb +43 -0
- data/lib/musa-dsl/musicxml/builder/unpitched-note.rb +112 -0
- data/lib/musa-dsl/neumalang.rb +1 -1
- data/lib/musa-dsl/neumalang/datatypes.citrus +79 -0
- data/lib/musa-dsl/neumalang/neuma.citrus +165 -0
- data/lib/musa-dsl/neumalang/neumalang.citrus +32 -242
- data/lib/musa-dsl/neumalang/neumalang.rb +373 -142
- data/lib/musa-dsl/neumalang/process.citrus +21 -0
- data/lib/musa-dsl/neumalang/terminals.citrus +67 -0
- data/lib/musa-dsl/neumalang/vectors.citrus +23 -0
- data/lib/musa-dsl/neumas.rb +5 -0
- data/lib/musa-dsl/neumas/array-to-neumas.rb +34 -0
- data/lib/musa-dsl/neumas/neuma-decoder.rb +63 -0
- data/lib/musa-dsl/neumas/neuma-gdv-decoder.rb +57 -0
- data/lib/musa-dsl/neumas/neuma-gdvd-decoder.rb +15 -0
- data/lib/musa-dsl/neumas/neumas.rb +37 -0
- data/lib/musa-dsl/neumas/string-to-neumas.rb +34 -0
- data/lib/musa-dsl/repl.rb +1 -1
- data/lib/musa-dsl/repl/repl.rb +105 -105
- data/lib/musa-dsl/sequencer.rb +1 -1
- data/lib/musa-dsl/sequencer/base-sequencer-implementation-control.rb +163 -136
- data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-helper.rb +301 -286
- data/lib/musa-dsl/sequencer/base-sequencer-implementation.rb +562 -270
- data/lib/musa-dsl/sequencer/base-sequencer-public.rb +199 -199
- data/lib/musa-dsl/sequencer/base-sequencer-tick-based.rb +77 -0
- data/lib/musa-dsl/sequencer/base-sequencer-tickless-based.rb +75 -0
- data/lib/musa-dsl/sequencer/sequencer-dsl.rb +105 -85
- data/lib/musa-dsl/sequencer/timeslots.rb +34 -0
- data/lib/musa-dsl/series.rb +1 -1
- data/lib/musa-dsl/{core-ext → series}/array-to-serie.rb +1 -1
- data/lib/musa-dsl/series/base-series.rb +171 -168
- data/lib/musa-dsl/series/hash-serie-splitter.rb +134 -132
- data/lib/musa-dsl/series/holder-serie.rb +1 -1
- data/lib/musa-dsl/series/main-serie-constructors.rb +6 -1
- data/lib/musa-dsl/series/main-serie-operations.rb +807 -797
- data/lib/musa-dsl/series/proxy-serie.rb +6 -6
- data/lib/musa-dsl/series/queue-serie.rb +5 -5
- data/lib/musa-dsl/series/series.rb +2 -0
- data/lib/musa-dsl/transcription.rb +4 -0
- data/lib/musa-dsl/transcription/from-gdv-to-midi.rb +227 -0
- data/lib/musa-dsl/transcription/from-gdv-to-musicxml.rb +36 -0
- data/lib/musa-dsl/transcription/from-gdv.rb +17 -0
- data/lib/musa-dsl/transcription/transcription.rb +55 -0
- data/lib/musa-dsl/transport.rb +6 -6
- data/lib/musa-dsl/transport/clock.rb +26 -26
- data/lib/musa-dsl/transport/dummy-clock.rb +32 -30
- data/lib/musa-dsl/transport/external-tick-clock.rb +21 -20
- data/lib/musa-dsl/transport/input-midi-clock.rb +82 -80
- data/lib/musa-dsl/transport/timer-clock.rb +72 -71
- data/lib/musa-dsl/transport/timer.rb +28 -26
- data/lib/musa-dsl/transport/transport.rb +99 -95
- data/musa-dsl.gemspec +3 -3
- metadata +73 -24
- data/lib/musa-dsl/core-ext/array-apply-get.rb +0 -18
- data/lib/musa-dsl/core-ext/array-to-neumas.rb +0 -28
- data/lib/musa-dsl/core-ext/as-context-run.rb +0 -44
- data/lib/musa-dsl/core-ext/duplicate.rb +0 -134
- data/lib/musa-dsl/core-ext/key-parameters-procedure-binder.rb +0 -85
- data/lib/musa-dsl/core-ext/proc-nice.rb +0 -13
- data/lib/musa-dsl/core-ext/send-nice.rb +0 -21
- data/lib/musa-dsl/core-ext/string-to-neumas.rb +0 -27
- data/lib/musa-dsl/datasets/gdv-decorators.rb +0 -221
- data/lib/musa-dsl/generative/rules.rb +0 -282
- data/lib/musa-dsl/neuma.rb +0 -1
- data/lib/musa-dsl/neuma/neuma.rb +0 -181
@@ -1,384 +1,676 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
require_relative '../core-ext/arrayfy'
|
2
|
+
require_relative '../core-ext/smart-proc-binder'
|
3
3
|
|
4
4
|
require_relative 'base-sequencer-implementation-control'
|
5
5
|
require_relative 'base-sequencer-implementation-play-helper'
|
6
6
|
|
7
|
-
|
8
|
-
|
7
|
+
using Musa::Extension::Arrayfy
|
8
|
+
using Musa::Extension::DeepCopy
|
9
9
|
|
10
|
-
|
11
|
-
|
10
|
+
module Musa
|
11
|
+
module Sequencer
|
12
|
+
class BaseSequencer
|
13
|
+
include Musa::Extension::SmartProcBinder
|
14
|
+
include Musa::Extension::DeepCopy
|
12
15
|
|
13
|
-
|
16
|
+
private
|
14
17
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
18
|
+
def _tick(position_to_run)
|
19
|
+
|
20
|
+
@before_tick.each { |block| block.call position_to_run }
|
21
|
+
|
22
|
+
queue = @timeslots[position_to_run]
|
23
|
+
|
24
|
+
if queue
|
25
|
+
until queue.empty?
|
21
26
|
|
22
|
-
|
23
|
-
|
27
|
+
command = queue.shift
|
28
|
+
@timeslots.delete position_to_run if queue.empty?
|
24
29
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
+
if command.key?(:parent_control) && !command[:parent_control].stopped?
|
31
|
+
@event_handlers.push command[:parent_control]
|
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
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
Thread.pass
|
30
47
|
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
48
|
|
35
|
-
|
36
|
-
|
49
|
+
def _raw_numeric_at(at_position, force_first: nil, &block)
|
50
|
+
force_first ||= false
|
37
51
|
|
38
|
-
|
39
|
-
|
52
|
+
if at_position == @position
|
53
|
+
begin
|
54
|
+
yield
|
55
|
+
rescue StandardError, ScriptError => e
|
56
|
+
_rescue_error e
|
57
|
+
end
|
40
58
|
|
41
|
-
|
59
|
+
elsif at_position > @position
|
60
|
+
@timeslots[at_position] ||= []
|
42
61
|
|
43
|
-
|
44
|
-
|
45
|
-
|
62
|
+
value = { block: block, value_parameters: [], key_parameters: {} }
|
63
|
+
if force_first
|
64
|
+
@timeslots[at_position].insert 0, value
|
65
|
+
else
|
66
|
+
@timeslots[at_position] << value
|
67
|
+
end
|
68
|
+
else
|
69
|
+
_log "BaseSequencer._raw_numeric_at: warning: ignoring past at command for #{at_position}" if @do_log
|
70
|
+
end
|
46
71
|
|
47
|
-
|
48
|
-
_log "BaseSequencer._numeric_at: warning: rounding position #{bar_position} (#{original_position}) "\
|
49
|
-
"to tick precision: #{position / @ticks_per_bar} (#{position})"
|
72
|
+
nil
|
50
73
|
end
|
51
|
-
end
|
52
74
|
|
53
|
-
|
54
|
-
|
75
|
+
def _numeric_at(at_position, control, with: nil, debug: nil, &block)
|
76
|
+
raise ArgumentError, "'at_position' parameter cannot be nil" if at_position.nil?
|
77
|
+
raise ArgumentError, 'Yield block is mandatory' unless block
|
55
78
|
|
56
|
-
|
57
|
-
block_key_parameters_binder =
|
58
|
-
KeyParametersProcedureBinder.new block, on_rescue: proc { |e| _rescue_block_error(e) }
|
79
|
+
at_position = _check_position(at_position)
|
59
80
|
|
60
|
-
|
61
|
-
|
81
|
+
value_parameters = []
|
82
|
+
value_parameters << with if !with.nil? && !with.is_a?(Hash)
|
62
83
|
|
63
|
-
|
84
|
+
block_key_parameters_binder =
|
85
|
+
SmartProcBinder.new block, on_rescue: proc { |e| _rescue_error(e) }
|
64
86
|
|
65
|
-
|
66
|
-
|
87
|
+
key_parameters = {}
|
88
|
+
key_parameters.merge! block_key_parameters_binder._apply(nil, with).last if with.is_a?(Hash)
|
67
89
|
|
68
|
-
|
69
|
-
locked = @@tick_mutex.try_lock
|
90
|
+
key_parameters[:control] = control if block_key_parameters_binder.key?(:control)
|
70
91
|
|
71
|
-
|
72
|
-
|
73
|
-
original_stderr = $stderr
|
92
|
+
if at_position == @position
|
93
|
+
@debug_at.call if debug && @debug_at
|
74
94
|
|
75
|
-
|
76
|
-
|
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
|
77
100
|
end
|
78
101
|
|
79
|
-
|
80
|
-
ensure
|
81
|
-
if locked
|
82
|
-
$stdout = original_stdout
|
83
|
-
$stderr = original_stderr
|
84
|
-
end
|
102
|
+
elsif @position.nil? || at_position > @position
|
85
103
|
|
86
|
-
|
87
|
-
|
104
|
+
@timeslots[at_position] ||= []
|
105
|
+
|
106
|
+
@timeslots[at_position] << { parent_control: control, block: @on_debug_at } if debug && @on_debug_at
|
88
107
|
|
89
|
-
|
90
|
-
|
108
|
+
@timeslots[at_position] << { parent_control: control, block: block_key_parameters_binder,
|
109
|
+
value_parameters: value_parameters,
|
110
|
+
key_parameters: key_parameters }
|
111
|
+
else
|
112
|
+
_log "BaseSequencer._numeric_at: warning: ignoring past 'at' command for #{at_position}" if @do_log
|
113
|
+
end
|
91
114
|
|
92
|
-
|
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
|
115
|
+
nil
|
96
116
|
end
|
97
|
-
end
|
98
117
|
|
99
|
-
|
100
|
-
end
|
118
|
+
def _serie_at(bar_position_serie, control, with: nil, debug: nil, &block)
|
101
119
|
|
102
|
-
|
120
|
+
bar_position = bar_position_serie.next_value
|
103
121
|
|
104
|
-
|
122
|
+
with_value = if with.respond_to? :next_value
|
123
|
+
with.next_value
|
124
|
+
else
|
125
|
+
with
|
126
|
+
end
|
105
127
|
|
106
|
-
|
107
|
-
|
108
|
-
else
|
109
|
-
with
|
110
|
-
end
|
128
|
+
if bar_position
|
129
|
+
_numeric_at bar_position, control, with: with_value, debug: debug, &block
|
111
130
|
|
112
|
-
|
113
|
-
|
131
|
+
_numeric_at bar_position, control, debug: false do
|
132
|
+
_serie_at bar_position_serie, control, with: with, debug: debug, &block
|
133
|
+
end
|
134
|
+
else
|
135
|
+
# serie finalizada
|
136
|
+
end
|
114
137
|
|
115
|
-
|
116
|
-
_serie_at bar_position_serie, control, with: with, debug: debug, &block
|
138
|
+
nil
|
117
139
|
end
|
118
|
-
else
|
119
|
-
# serie finalizada
|
120
|
-
end
|
121
140
|
|
122
|
-
|
123
|
-
|
141
|
+
def _play(serie, control, nl_context = nil, mode: nil, decoder: nil, __play_eval: nil, **mode_args, &block)
|
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
|
124
167
|
|
125
|
-
|
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
|
168
|
+
if element
|
169
|
+
operation = __play_eval.run_operation element
|
151
170
|
|
152
|
-
|
153
|
-
operation = __play_eval.run_operation element
|
171
|
+
case operation[:current_operation]
|
154
172
|
|
155
|
-
|
173
|
+
when :none
|
156
174
|
|
157
|
-
|
175
|
+
when :block
|
158
176
|
|
159
|
-
|
177
|
+
__play_eval.block_procedure_binder.call operation[:current_parameter], control: control
|
160
178
|
|
161
|
-
|
179
|
+
when :event
|
162
180
|
|
163
|
-
|
181
|
+
control._launch operation[:current_event],
|
182
|
+
operation[:current_value_parameters],
|
183
|
+
operation[:current_key_parameters]
|
164
184
|
|
165
|
-
|
166
|
-
operation[:current_value_parameters],
|
167
|
-
operation[:current_key_parameters]
|
185
|
+
when :play
|
168
186
|
|
169
|
-
|
187
|
+
control2 = PlayControl.new control
|
188
|
+
control3 = PlayControl.new control2
|
189
|
+
control3.after { control3.launch :sync }
|
170
190
|
|
171
|
-
|
172
|
-
|
173
|
-
|
191
|
+
_play operation[:current_parameter].instance,
|
192
|
+
control3,
|
193
|
+
__play_eval: __play_eval.subcontext,
|
194
|
+
**mode_args
|
174
195
|
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
**mode_args
|
196
|
+
control2.on :sync do
|
197
|
+
_play serie, control, __play_eval: __play_eval, **mode_args
|
198
|
+
end
|
179
199
|
|
180
|
-
|
181
|
-
_play serie, control, __play_eval: __play_eval, **mode_args
|
182
|
-
end
|
200
|
+
when :no_eval_play
|
183
201
|
|
184
|
-
|
202
|
+
control2 = PlayControl.new control
|
203
|
+
control3 = PlayControl.new control2
|
204
|
+
control3.after { control3.launch :sync }
|
185
205
|
|
186
|
-
|
187
|
-
|
188
|
-
|
206
|
+
_play operation[:current_parameter].instance,
|
207
|
+
control3,
|
208
|
+
__play_eval: WaitModePlayEval.new(__play_eval.block_procedure_binder),
|
209
|
+
**mode_args
|
189
210
|
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
**mode_args
|
211
|
+
control2.on :sync do
|
212
|
+
_play serie, control, __play_eval: __play_eval, **mode_args
|
213
|
+
end
|
194
214
|
|
195
|
-
|
196
|
-
_play serie, control, __play_eval: __play_eval, **mode_args
|
197
|
-
end
|
215
|
+
when :parallel_play
|
198
216
|
|
199
|
-
|
217
|
+
control2 = PlayControl.new control
|
200
218
|
|
201
|
-
|
219
|
+
operation[:current_parameter].each do |current_parameter|
|
220
|
+
control3 = PlayControl.new control2
|
221
|
+
control3.after { control3.launch :sync }
|
202
222
|
|
203
|
-
|
204
|
-
|
205
|
-
|
223
|
+
_play current_parameter.instance,
|
224
|
+
control3,
|
225
|
+
__play_eval: __play_eval.subcontext,
|
226
|
+
**mode_args
|
227
|
+
end
|
206
228
|
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
229
|
+
counter = operation[:current_parameter].size
|
230
|
+
|
231
|
+
control2.on :sync do
|
232
|
+
counter -= 1
|
233
|
+
_play serie, control, __play_eval: __play_eval, **mode_args if counter == 0
|
234
|
+
end
|
235
|
+
end
|
212
236
|
|
213
|
-
|
237
|
+
case operation[:continue_operation]
|
238
|
+
when :now
|
239
|
+
_numeric_at position, control do
|
240
|
+
_play serie, control, __play_eval: __play_eval, **mode_args
|
241
|
+
end
|
242
|
+
|
243
|
+
when :at
|
244
|
+
_numeric_at operation[:continue_parameter], control do
|
245
|
+
_play serie, control, __play_eval: __play_eval, **mode_args
|
246
|
+
end
|
247
|
+
|
248
|
+
when :wait
|
249
|
+
_numeric_at position + operation[:continue_parameter].rationalize, control do
|
250
|
+
_play serie, control, __play_eval: __play_eval, **mode_args
|
251
|
+
end
|
252
|
+
|
253
|
+
when :on
|
254
|
+
control.on operation[:continue_parameter], only_once: true do
|
255
|
+
_play serie, control, __play_eval: __play_eval, **mode_args
|
256
|
+
end
|
257
|
+
end
|
258
|
+
else
|
259
|
+
control2 = EventHandler.new control
|
214
260
|
|
215
|
-
|
216
|
-
|
217
|
-
|
261
|
+
control.do_after.each do |do_after|
|
262
|
+
_numeric_at position, control2, &do_after
|
263
|
+
end
|
218
264
|
end
|
265
|
+
|
266
|
+
nil
|
219
267
|
end
|
220
268
|
|
221
|
-
|
222
|
-
|
223
|
-
|
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
|
+
|
224
274
|
_numeric_at position, control do
|
225
|
-
|
226
|
-
|
275
|
+
control._start_position ||= position
|
276
|
+
control._execution_counter ||= 0
|
227
277
|
|
228
|
-
|
229
|
-
|
230
|
-
_numeric_at operation[:continue_parameter], control do
|
231
|
-
_play serie, control, __play_eval: __play_eval, **mode_args
|
232
|
-
end
|
278
|
+
duration_exceeded =
|
279
|
+
(control._start_position + control.duration_value - interval) <= position if interval && control.duration_value
|
233
280
|
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
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
|
+
|
290
|
+
|
291
|
+
unless control.stopped? || duration_exceeded || till_exceeded || condition_failed || interval.nil?
|
292
|
+
_numeric_at control._start_position + control._execution_counter * interval, control do
|
293
|
+
_every interval, control, block_procedure_binder: block_procedure_binder
|
294
|
+
end
|
239
295
|
|
240
|
-
|
241
|
-
|
242
|
-
|
296
|
+
else
|
297
|
+
control.do_on_stop.each(&:call)
|
298
|
+
|
299
|
+
control.do_after.each do |do_after|
|
300
|
+
_numeric_at position + (interval || 0) + do_after[:bars], control, &do_after[:block]
|
301
|
+
end
|
302
|
+
end
|
243
303
|
end
|
244
|
-
end
|
245
|
-
else
|
246
|
-
control2 = EventHandler.new control
|
247
304
|
|
248
|
-
|
249
|
-
_numeric_at position, control2, &do_after
|
305
|
+
nil
|
250
306
|
end
|
251
|
-
end
|
252
307
|
|
253
|
-
|
254
|
-
|
308
|
+
def _move(every: nil,
|
309
|
+
from:, to: nil, step: nil,
|
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
|
255
344
|
|
256
|
-
|
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
|
257
350
|
|
258
|
-
|
351
|
+
if step.is_a?(Hash)
|
352
|
+
step = hash_keys.collect { |k| step[k] }
|
353
|
+
end
|
259
354
|
|
260
|
-
|
355
|
+
if right_open.is_a?(Hash)
|
356
|
+
right_open = hash_keys.collect { |k| right_open[k] }
|
357
|
+
end
|
261
358
|
|
262
|
-
|
263
|
-
|
359
|
+
else
|
360
|
+
from = from.arrayfy
|
361
|
+
size = from.size
|
362
|
+
end
|
264
363
|
|
265
|
-
|
266
|
-
|
267
|
-
|
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)
|
268
368
|
|
269
|
-
|
369
|
+
# from, to, step, every
|
370
|
+
# from, to, step, (duration | till)
|
371
|
+
# from, to, every, (duration | till)
|
372
|
+
# from, step, every, (duration | till)
|
270
373
|
|
271
|
-
|
374
|
+
block ||= proc {}
|
272
375
|
|
273
|
-
|
274
|
-
|
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
|
275
378
|
end
|
276
|
-
else
|
277
|
-
control.do_on_stop.each(&:call)
|
278
379
|
|
279
|
-
|
280
|
-
_numeric_at position + binterval + do_after[:bars], control, &do_after[:block]
|
281
|
-
end
|
282
|
-
end
|
283
|
-
end
|
380
|
+
right_open.map! { |v| v || false }
|
284
381
|
|
285
|
-
|
286
|
-
|
382
|
+
function ||= proc { |ratio| ratio }
|
383
|
+
function = function.arrayfy(size: size)
|
287
384
|
|
288
|
-
|
385
|
+
function_range = 1r.arrayfy(size: size)
|
386
|
+
function_offset = 0r.arrayfy(size: size)
|
289
387
|
|
290
|
-
|
388
|
+
start_position = position
|
291
389
|
|
292
|
-
|
293
|
-
|
294
|
-
# from, to, every, (duration | till)
|
295
|
-
# from, step, every, (duration | till)
|
390
|
+
if duration || till
|
391
|
+
effective_duration = duration || till - start_position
|
296
392
|
|
297
|
-
|
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 }
|
298
395
|
|
299
|
-
|
300
|
-
|
396
|
+
size.times do |i|
|
397
|
+
if to[i] && step[i] && !every[i]
|
301
398
|
|
302
|
-
|
399
|
+
steps = (to[i] - from[i]) / step[i]
|
303
400
|
|
304
|
-
|
305
|
-
|
306
|
-
|
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
|
307
407
|
|
308
|
-
|
309
|
-
steps = (to - from) / step
|
310
|
-
every = Rational(effective_duration, steps + right_open_offset)
|
408
|
+
elsif to[i] && !step[i] && !every[i]
|
311
409
|
|
312
|
-
|
313
|
-
|
314
|
-
|
410
|
+
if tick_duration > 0
|
411
|
+
function_range[i] = to[i] - from[i]
|
412
|
+
function_offset[i] = from[i]
|
315
413
|
|
316
|
-
|
317
|
-
|
318
|
-
step = (to - from) / (steps - right_open_offset)
|
414
|
+
from[i] = 0r
|
415
|
+
to[i] = 1r
|
319
416
|
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
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
|
324
422
|
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
else
|
329
|
-
if to && step && every
|
330
|
-
# ok
|
331
|
-
elsif to && !step && every
|
332
|
-
step = (to <=> from).to_r
|
333
|
-
else
|
334
|
-
raise ArgumentError, 'Cannot use this parameters combination'
|
335
|
-
end
|
336
|
-
end
|
423
|
+
elsif to[i] && !step[i] && every[i]
|
424
|
+
function_range[i] = to[i] - from[i]
|
425
|
+
function_offset[i] = from[i]
|
337
426
|
|
427
|
+
from[i] = 0r
|
428
|
+
to[i] = 1r
|
338
429
|
|
339
|
-
|
430
|
+
steps = effective_duration / every[i]
|
431
|
+
step[i] = 1r / (steps - right_open_offset[i])
|
340
432
|
|
341
|
-
|
433
|
+
elsif !to[i] && step[i] && every[i]
|
434
|
+
# ok
|
435
|
+
elsif !to[i] && !step[i] && every[i]
|
436
|
+
step[i] = 1r
|
342
437
|
|
343
|
-
|
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
|
344
455
|
|
345
|
-
|
456
|
+
binder = SmartProcBinder.new(block)
|
346
457
|
|
347
|
-
|
348
|
-
|
458
|
+
every_groups = {}
|
459
|
+
group_counter = {}
|
349
460
|
|
350
|
-
|
461
|
+
positions = Array.new(size)
|
462
|
+
q_durations = Array.new(size)
|
463
|
+
position_jitters = Array.new(size)
|
464
|
+
duration_jitters = Array.new(size)
|
351
465
|
|
352
|
-
|
466
|
+
size.times.each do |i|
|
467
|
+
every_groups[every[i]] ||= []
|
468
|
+
every_groups[every[i]] << i
|
469
|
+
group_counter[every[i]] = 0
|
470
|
+
end
|
353
471
|
|
354
|
-
|
472
|
+
control = MoveControl.new(@event_handlers.last,
|
473
|
+
duration: duration, till: till,
|
474
|
+
on_stop: on_stop, after_bars: after_bars, after: after)
|
355
475
|
|
356
|
-
|
357
|
-
control.
|
358
|
-
|
359
|
-
|
476
|
+
control.on_stop do
|
477
|
+
control.do_after.each do |do_after|
|
478
|
+
_numeric_at position + do_after[:bars], control, &do_after[:block]
|
479
|
+
end
|
360
480
|
end
|
481
|
+
|
482
|
+
@event_handlers.push control
|
483
|
+
|
484
|
+
_numeric_at start_position, control do
|
485
|
+
next_values = from.dup
|
486
|
+
|
487
|
+
values = Array.new(size)
|
488
|
+
stop = Array.new(size, false)
|
489
|
+
last_position = Array.new(size)
|
490
|
+
|
491
|
+
_every _common_interval(every_groups.keys), control.every_control do
|
492
|
+
process_indexes = []
|
493
|
+
|
494
|
+
every_groups.each_pair do |group_interval, affected_indexes|
|
495
|
+
group_position = start_position + ((group_interval || 0) * group_counter[group_interval])
|
496
|
+
|
497
|
+
# We consider a position to be on current tick position when it is inside the interval of one tick
|
498
|
+
# centered on the current tick (current tick +- 1/2 tick duration).
|
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
|
504
|
+
|
505
|
+
process_indexes << affected_indexes
|
506
|
+
|
507
|
+
group_counter[group_interval] += 1
|
508
|
+
|
509
|
+
next_group_position = start_position +
|
510
|
+
if group_interval
|
511
|
+
(group_interval * group_counter[group_interval])
|
512
|
+
else
|
513
|
+
effective_duration
|
514
|
+
end
|
515
|
+
|
516
|
+
next_group_q_position = _quantize(next_group_position)
|
517
|
+
|
518
|
+
affected_indexes.each do |i|
|
519
|
+
positions[i] = group_position
|
520
|
+
q_durations[i] = next_group_q_position - position
|
521
|
+
|
522
|
+
position_jitters[i] = group_position - position
|
523
|
+
duration_jitters[i] = next_group_position - next_group_q_position
|
524
|
+
end
|
525
|
+
end
|
526
|
+
end
|
527
|
+
|
528
|
+
process_indexes.flatten!
|
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
|
616
|
+
|
617
|
+
@event_handlers.pop
|
618
|
+
|
619
|
+
control
|
361
620
|
end
|
362
|
-
end
|
363
621
|
|
364
|
-
|
622
|
+
def _started_ago(last_positions, position, affected_indexes)
|
623
|
+
Array.new(last_positions.size).tap do |a|
|
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
|
630
|
+
end
|
365
631
|
|
366
|
-
|
367
|
-
|
632
|
+
def _durations(every_groups, largest_duration)
|
633
|
+
[].tap do |a|
|
634
|
+
if every_groups.any?
|
635
|
+
every_groups.each_pair do |every_group, affected_indexes|
|
636
|
+
affected_indexes.each do |i|
|
637
|
+
a[i] = every_group || largest_duration
|
638
|
+
end
|
639
|
+
end
|
640
|
+
else
|
641
|
+
a << largest_duration
|
642
|
+
end
|
643
|
+
end
|
644
|
+
end
|
368
645
|
|
369
|
-
|
370
|
-
|
371
|
-
|
646
|
+
def _hash_from_keys_and_values(keys, values)
|
647
|
+
{}.tap { |h| keys.each_index { |i| h[keys[i]] = values[i] } }
|
648
|
+
end
|
372
649
|
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
650
|
+
def _common_interval(intervals)
|
651
|
+
intervals = intervals.compact
|
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)
|
661
|
+
end
|
377
662
|
|
378
|
-
|
379
|
-
|
380
|
-
|
663
|
+
def _rescue_error(e)
|
664
|
+
if @do_error_log
|
665
|
+
log e
|
666
|
+
log e.full_message(order: :top)
|
667
|
+
end
|
381
668
|
|
382
|
-
|
669
|
+
@on_error.each do |block|
|
670
|
+
block.call e
|
671
|
+
end
|
672
|
+
end
|
673
|
+
end
|
383
674
|
end
|
384
675
|
end
|
676
|
+
|