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