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.
Files changed (130) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -1
  3. data/Gemfile +0 -1
  4. data/README.md +5 -1
  5. data/lib/musa-dsl.rb +54 -11
  6. data/lib/musa-dsl/core-ext.rb +7 -13
  7. data/lib/musa-dsl/core-ext/array-explode-ranges.rb +15 -23
  8. data/lib/musa-dsl/core-ext/arrayfy.rb +30 -12
  9. data/lib/musa-dsl/core-ext/attribute-builder.rb +194 -0
  10. data/lib/musa-dsl/core-ext/deep-copy.rb +185 -0
  11. data/lib/musa-dsl/core-ext/dynamic-proxy.rb +44 -40
  12. data/lib/musa-dsl/core-ext/inspect-nice.rb +40 -22
  13. data/lib/musa-dsl/core-ext/smart-proc-binder.rb +108 -0
  14. data/lib/musa-dsl/core-ext/with.rb +26 -0
  15. data/lib/musa-dsl/datasets.rb +8 -3
  16. data/lib/musa-dsl/datasets/dataset.rb +3 -0
  17. data/lib/musa-dsl/datasets/delta-d.rb +12 -0
  18. data/lib/musa-dsl/datasets/e.rb +61 -0
  19. data/lib/musa-dsl/datasets/gdv.rb +51 -411
  20. data/lib/musa-dsl/datasets/gdvd.rb +179 -0
  21. data/lib/musa-dsl/datasets/helper.rb +41 -0
  22. data/lib/musa-dsl/datasets/p.rb +68 -0
  23. data/lib/musa-dsl/datasets/packed-v.rb +19 -0
  24. data/lib/musa-dsl/datasets/pdv.rb +22 -15
  25. data/lib/musa-dsl/datasets/ps.rb +113 -0
  26. data/lib/musa-dsl/datasets/score.rb +210 -0
  27. data/lib/musa-dsl/datasets/score/queriable.rb +48 -0
  28. data/lib/musa-dsl/datasets/score/render.rb +31 -0
  29. data/lib/musa-dsl/datasets/score/to-mxml/process-pdv.rb +160 -0
  30. data/lib/musa-dsl/datasets/score/to-mxml/process-ps.rb +51 -0
  31. data/lib/musa-dsl/datasets/score/to-mxml/process-time.rb +153 -0
  32. data/lib/musa-dsl/datasets/score/to-mxml/to-mxml.rb +158 -0
  33. data/lib/musa-dsl/datasets/v.rb +23 -0
  34. data/lib/musa-dsl/generative.rb +5 -5
  35. data/lib/musa-dsl/generative/backboner.rb +274 -0
  36. data/lib/musa-dsl/generative/darwin.rb +102 -96
  37. data/lib/musa-dsl/generative/generative-grammar.rb +182 -187
  38. data/lib/musa-dsl/generative/markov.rb +56 -53
  39. data/lib/musa-dsl/generative/variatio.rb +234 -222
  40. data/lib/musa-dsl/logger.rb +1 -0
  41. data/lib/musa-dsl/logger/logger.rb +31 -0
  42. data/lib/musa-dsl/matrix.rb +1 -0
  43. data/lib/musa-dsl/matrix/matrix.rb +210 -0
  44. data/lib/musa-dsl/midi.rb +2 -2
  45. data/lib/musa-dsl/midi/midi-recorder.rb +54 -52
  46. data/lib/musa-dsl/midi/midi-voices.rb +183 -182
  47. data/lib/musa-dsl/music.rb +5 -5
  48. data/lib/musa-dsl/music/chord-definition.rb +54 -50
  49. data/lib/musa-dsl/music/chord-definitions.rb +13 -9
  50. data/lib/musa-dsl/music/chords.rb +236 -238
  51. data/lib/musa-dsl/music/equally-tempered-12-tone-scale-system.rb +187 -183
  52. data/lib/musa-dsl/music/scales.rb +331 -332
  53. data/lib/musa-dsl/musicxml.rb +1 -0
  54. data/lib/musa-dsl/musicxml/builder/attributes.rb +155 -0
  55. data/lib/musa-dsl/musicxml/builder/backup-forward.rb +45 -0
  56. data/lib/musa-dsl/musicxml/builder/direction.rb +322 -0
  57. data/lib/musa-dsl/musicxml/builder/helper.rb +90 -0
  58. data/lib/musa-dsl/musicxml/builder/measure.rb +137 -0
  59. data/lib/musa-dsl/musicxml/builder/note-complexities.rb +152 -0
  60. data/lib/musa-dsl/musicxml/builder/note.rb +577 -0
  61. data/lib/musa-dsl/musicxml/builder/part-group.rb +44 -0
  62. data/lib/musa-dsl/musicxml/builder/part.rb +67 -0
  63. data/lib/musa-dsl/musicxml/builder/pitched-note.rb +126 -0
  64. data/lib/musa-dsl/musicxml/builder/rest.rb +117 -0
  65. data/lib/musa-dsl/musicxml/builder/score-partwise.rb +120 -0
  66. data/lib/musa-dsl/musicxml/builder/typed-text.rb +43 -0
  67. data/lib/musa-dsl/musicxml/builder/unpitched-note.rb +112 -0
  68. data/lib/musa-dsl/neumalang.rb +1 -1
  69. data/lib/musa-dsl/neumalang/datatypes.citrus +79 -0
  70. data/lib/musa-dsl/neumalang/neuma.citrus +165 -0
  71. data/lib/musa-dsl/neumalang/neumalang.citrus +32 -242
  72. data/lib/musa-dsl/neumalang/neumalang.rb +373 -142
  73. data/lib/musa-dsl/neumalang/process.citrus +21 -0
  74. data/lib/musa-dsl/neumalang/terminals.citrus +67 -0
  75. data/lib/musa-dsl/neumalang/vectors.citrus +23 -0
  76. data/lib/musa-dsl/neumas.rb +5 -0
  77. data/lib/musa-dsl/neumas/array-to-neumas.rb +34 -0
  78. data/lib/musa-dsl/neumas/neuma-decoder.rb +63 -0
  79. data/lib/musa-dsl/neumas/neuma-gdv-decoder.rb +57 -0
  80. data/lib/musa-dsl/neumas/neuma-gdvd-decoder.rb +15 -0
  81. data/lib/musa-dsl/neumas/neumas.rb +37 -0
  82. data/lib/musa-dsl/neumas/string-to-neumas.rb +34 -0
  83. data/lib/musa-dsl/repl.rb +1 -1
  84. data/lib/musa-dsl/repl/repl.rb +105 -105
  85. data/lib/musa-dsl/sequencer.rb +1 -1
  86. data/lib/musa-dsl/sequencer/base-sequencer-implementation-control.rb +163 -136
  87. data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-helper.rb +301 -286
  88. data/lib/musa-dsl/sequencer/base-sequencer-implementation.rb +562 -270
  89. data/lib/musa-dsl/sequencer/base-sequencer-public.rb +199 -199
  90. data/lib/musa-dsl/sequencer/base-sequencer-tick-based.rb +77 -0
  91. data/lib/musa-dsl/sequencer/base-sequencer-tickless-based.rb +75 -0
  92. data/lib/musa-dsl/sequencer/sequencer-dsl.rb +105 -85
  93. data/lib/musa-dsl/sequencer/timeslots.rb +34 -0
  94. data/lib/musa-dsl/series.rb +1 -1
  95. data/lib/musa-dsl/{core-ext → series}/array-to-serie.rb +1 -1
  96. data/lib/musa-dsl/series/base-series.rb +171 -168
  97. data/lib/musa-dsl/series/hash-serie-splitter.rb +134 -132
  98. data/lib/musa-dsl/series/holder-serie.rb +1 -1
  99. data/lib/musa-dsl/series/main-serie-constructors.rb +6 -1
  100. data/lib/musa-dsl/series/main-serie-operations.rb +807 -797
  101. data/lib/musa-dsl/series/proxy-serie.rb +6 -6
  102. data/lib/musa-dsl/series/queue-serie.rb +5 -5
  103. data/lib/musa-dsl/series/series.rb +2 -0
  104. data/lib/musa-dsl/transcription.rb +4 -0
  105. data/lib/musa-dsl/transcription/from-gdv-to-midi.rb +227 -0
  106. data/lib/musa-dsl/transcription/from-gdv-to-musicxml.rb +36 -0
  107. data/lib/musa-dsl/transcription/from-gdv.rb +17 -0
  108. data/lib/musa-dsl/transcription/transcription.rb +55 -0
  109. data/lib/musa-dsl/transport.rb +6 -6
  110. data/lib/musa-dsl/transport/clock.rb +26 -26
  111. data/lib/musa-dsl/transport/dummy-clock.rb +32 -30
  112. data/lib/musa-dsl/transport/external-tick-clock.rb +21 -20
  113. data/lib/musa-dsl/transport/input-midi-clock.rb +82 -80
  114. data/lib/musa-dsl/transport/timer-clock.rb +72 -71
  115. data/lib/musa-dsl/transport/timer.rb +28 -26
  116. data/lib/musa-dsl/transport/transport.rb +99 -95
  117. data/musa-dsl.gemspec +3 -3
  118. metadata +73 -24
  119. data/lib/musa-dsl/core-ext/array-apply-get.rb +0 -18
  120. data/lib/musa-dsl/core-ext/array-to-neumas.rb +0 -28
  121. data/lib/musa-dsl/core-ext/as-context-run.rb +0 -44
  122. data/lib/musa-dsl/core-ext/duplicate.rb +0 -134
  123. data/lib/musa-dsl/core-ext/key-parameters-procedure-binder.rb +0 -85
  124. data/lib/musa-dsl/core-ext/proc-nice.rb +0 -13
  125. data/lib/musa-dsl/core-ext/send-nice.rb +0 -21
  126. data/lib/musa-dsl/core-ext/string-to-neumas.rb +0 -27
  127. data/lib/musa-dsl/datasets/gdv-decorators.rb +0 -221
  128. data/lib/musa-dsl/generative/rules.rb +0 -282
  129. data/lib/musa-dsl/neuma.rb +0 -1
  130. data/lib/musa-dsl/neuma/neuma.rb +0 -181
@@ -1,384 +1,676 @@
1
- require 'musa-dsl/core-ext/arrayfy'
2
- require 'musa-dsl/core-ext/key-parameters-procedure-binder'
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
- class Musa::BaseSequencer
8
- private
7
+ using Musa::Extension::Arrayfy
8
+ using Musa::Extension::DeepCopy
9
9
 
10
- def _raw_numeric_at(bar_position, force_first: nil, &block)
11
- force_first ||= false
10
+ module Musa
11
+ module Sequencer
12
+ class BaseSequencer
13
+ include Musa::Extension::SmartProcBinder
14
+ include Musa::Extension::DeepCopy
12
15
 
13
- position = bar_position.rationalize * @ticks_per_bar
16
+ private
14
17
 
15
- if position == @position
16
- begin
17
- yield
18
- rescue StandardError, ScriptError => e
19
- _rescue_block_error e
20
- end
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
- elsif position > @position
23
- @score[position] = [] unless @score[position]
27
+ command = queue.shift
28
+ @timeslots.delete position_to_run if queue.empty?
24
29
 
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
+ 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
- nil
36
- end
49
+ def _raw_numeric_at(at_position, force_first: nil, &block)
50
+ force_first ||= false
37
51
 
38
- def _numeric_at(bar_position, control, with: nil, debug: nil, &block)
39
- raise ArgumentError, 'Block is mandatory' unless block
52
+ if at_position == @position
53
+ begin
54
+ yield
55
+ rescue StandardError, ScriptError => e
56
+ _rescue_error e
57
+ end
40
58
 
41
- position = bar_position.rationalize * @ticks_per_bar
59
+ elsif at_position > @position
60
+ @timeslots[at_position] ||= []
42
61
 
43
- if position != position.round
44
- original_position = position
45
- position = position.round.rationalize
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
- if @do_log
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
- value_parameters = []
54
- value_parameters << with if !with.nil? && !with.is_a?(Hash)
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
- if block_given?
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
- key_parameters = {}
61
- key_parameters.merge! block_key_parameters_binder.apply with if with.is_a? Hash
81
+ value_parameters = []
82
+ value_parameters << with if !with.nil? && !with.is_a?(Hash)
62
83
 
63
- key_parameters[:control] = control if block_key_parameters_binder.key?(:control)
84
+ block_key_parameters_binder =
85
+ SmartProcBinder.new block, on_rescue: proc { |e| _rescue_error(e) }
64
86
 
65
- if position == @position
66
- @debug_at.call if debug && @debug_at
87
+ key_parameters = {}
88
+ key_parameters.merge! block_key_parameters_binder._apply(nil, with).last if with.is_a?(Hash)
67
89
 
68
- begin
69
- locked = @@tick_mutex.try_lock
90
+ key_parameters[:control] = control if block_key_parameters_binder.key?(:control)
70
91
 
71
- if locked
72
- original_stdout = $stdout
73
- original_stderr = $stderr
92
+ if at_position == @position
93
+ @debug_at.call if debug && @debug_at
74
94
 
75
- $stdout = control.stdout
76
- $stderr = control.stderr
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
- block_key_parameters_binder._call value_parameters, key_parameters
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
- @@tick_mutex.unlock if locked
87
- end
104
+ @timeslots[at_position] ||= []
105
+
106
+ @timeslots[at_position] << { parent_control: control, block: @on_debug_at } if debug && @on_debug_at
88
107
 
89
- elsif position > @position
90
- @score[position] = [] unless @score[position]
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
- @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
115
+ nil
96
116
  end
97
- end
98
117
 
99
- nil
100
- end
118
+ def _serie_at(bar_position_serie, control, with: nil, debug: nil, &block)
101
119
 
102
- def _serie_at(bar_position_serie, control, with: nil, debug: nil, &block)
120
+ bar_position = bar_position_serie.next_value
103
121
 
104
- bar_position = bar_position_serie.next_value
122
+ with_value = if with.respond_to? :next_value
123
+ with.next_value
124
+ else
125
+ with
126
+ end
105
127
 
106
- with_value = if with.respond_to? :next_value
107
- with.next_value
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
- if bar_position
113
- _numeric_at bar_position, control, with: with_value, debug: debug, &block
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
- _numeric_at bar_position, control, debug: false do
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
- nil
123
- end
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
- 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
168
+ if element
169
+ operation = __play_eval.run_operation element
151
170
 
152
- if element
153
- operation = __play_eval.run_operation element
171
+ case operation[:current_operation]
154
172
 
155
- case operation[:current_operation]
173
+ when :none
156
174
 
157
- when :none
175
+ when :block
158
176
 
159
- when :block
177
+ __play_eval.block_procedure_binder.call operation[:current_parameter], control: control
160
178
 
161
- __play_eval.block_procedure_binder.call operation[:current_parameter], control: control
179
+ when :event
162
180
 
163
- when :event
181
+ control._launch operation[:current_event],
182
+ operation[:current_value_parameters],
183
+ operation[:current_key_parameters]
164
184
 
165
- control._launch operation[:current_event],
166
- operation[:current_value_parameters],
167
- operation[:current_key_parameters]
185
+ when :play
168
186
 
169
- when :play
187
+ control2 = PlayControl.new control
188
+ control3 = PlayControl.new control2
189
+ control3.after { control3.launch :sync }
170
190
 
171
- control2 = PlayControl.new control
172
- control3 = PlayControl.new control2
173
- control3.after { control3.launch :sync }
191
+ _play operation[:current_parameter].instance,
192
+ control3,
193
+ __play_eval: __play_eval.subcontext,
194
+ **mode_args
174
195
 
175
- _play operation[:current_parameter].instance,
176
- control3,
177
- __play_eval: __play_eval.subcontext,
178
- **mode_args
196
+ control2.on :sync do
197
+ _play serie, control, __play_eval: __play_eval, **mode_args
198
+ end
179
199
 
180
- control2.on :sync do
181
- _play serie, control, __play_eval: __play_eval, **mode_args
182
- end
200
+ when :no_eval_play
183
201
 
184
- when :no_eval_play
202
+ control2 = PlayControl.new control
203
+ control3 = PlayControl.new control2
204
+ control3.after { control3.launch :sync }
185
205
 
186
- control2 = PlayControl.new control
187
- control3 = PlayControl.new control2
188
- control3.after { control3.launch :sync }
206
+ _play operation[:current_parameter].instance,
207
+ control3,
208
+ __play_eval: WaitModePlayEval.new(__play_eval.block_procedure_binder),
209
+ **mode_args
189
210
 
190
- _play operation[:current_parameter].instance,
191
- control3,
192
- __play_eval: WaitModePlayEval.new(__play_eval.block_procedure_binder),
193
- **mode_args
211
+ control2.on :sync do
212
+ _play serie, control, __play_eval: __play_eval, **mode_args
213
+ end
194
214
 
195
- control2.on :sync do
196
- _play serie, control, __play_eval: __play_eval, **mode_args
197
- end
215
+ when :parallel_play
198
216
 
199
- when :parallel_play
217
+ control2 = PlayControl.new control
200
218
 
201
- control2 = PlayControl.new control
219
+ operation[:current_parameter].each do |current_parameter|
220
+ control3 = PlayControl.new control2
221
+ control3.after { control3.launch :sync }
202
222
 
203
- operation[:current_parameter].each do |current_parameter|
204
- control3 = PlayControl.new control2
205
- control3.after { control3.launch :sync }
223
+ _play current_parameter.instance,
224
+ control3,
225
+ __play_eval: __play_eval.subcontext,
226
+ **mode_args
227
+ end
206
228
 
207
- _play current_parameter.instance,
208
- control3,
209
- __play_eval: __play_eval.subcontext,
210
- **mode_args
211
- end
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
- counter = operation[:current_parameter].size
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
- control2.on :sync do
216
- counter -= 1
217
- _play serie, control, __play_eval: __play_eval, **mode_args if counter == 0
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
- case operation[:continue_operation]
222
- when :now
223
- #now do
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
- _play serie, control, __play_eval: __play_eval, **mode_args
226
- end
275
+ control._start_position ||= position
276
+ control._execution_counter ||= 0
227
277
 
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
278
+ duration_exceeded =
279
+ (control._start_position + control.duration_value - interval) <= position if interval && control.duration_value
233
280
 
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
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
- when :on
241
- control.on operation[:continue_parameter], only_once: true do
242
- _play serie, control, __play_eval: __play_eval, **mode_args
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
- control.do_after.each do |do_after|
249
- _numeric_at position, control2, &do_after
305
+ nil
250
306
  end
251
- end
252
307
 
253
- nil
254
- end
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
- def _every(binterval, control, block_procedure_binder: nil, &block)
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
- block ||= proc {}
351
+ if step.is_a?(Hash)
352
+ step = hash_keys.collect { |k| step[k] }
353
+ end
259
354
 
260
- block_procedure_binder ||= KeyParametersProcedureBinder.new block, on_rescue: proc { |e| _rescue_block_error(e) }
355
+ if right_open.is_a?(Hash)
356
+ right_open = hash_keys.collect { |k| right_open[k] }
357
+ end
261
358
 
262
- _numeric_at position, control do
263
- control._start ||= position
359
+ else
360
+ from = from.arrayfy
361
+ size = from.size
362
+ end
264
363
 
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
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
- block_procedure_binder.call(control: control) unless control.stopped?
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
- if !control.stopped? && !duration_exceeded && !till_exceeded && !condition_failed
374
+ block ||= proc {}
272
375
 
273
- _numeric_at position + binterval, control do
274
- _every binterval, control, block_procedure_binder: block_procedure_binder
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
- 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
380
+ right_open.map! { |v| v || false }
284
381
 
285
- nil
286
- end
382
+ function ||= proc { |ratio| ratio }
383
+ function = function.arrayfy(size: size)
287
384
 
288
- def _move(every: nil, from:, to: nil, step: nil, duration: nil, till: nil, right_open: nil, on_stop: nil, after_bars: nil, after: nil, &block)
385
+ function_range = 1r.arrayfy(size: size)
386
+ function_offset = 0r.arrayfy(size: size)
289
387
 
290
- raise ArgumentError, "Cannot use duration: #{duration} and till: #{till} parameters at the same time. Use only one of them." if till && duration
388
+ start_position = position
291
389
 
292
- # from, to, step, every
293
- # from, to, step, (duration | till)
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
- block ||= proc {}
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
- step = -step if step && to && ((step > 0 && to < from) || (step < 0 && from < to))
300
- right_open ||= false
396
+ size.times do |i|
397
+ if to[i] && step[i] && !every[i]
301
398
 
302
- start_position = position
399
+ steps = (to[i] - from[i]) / step[i]
303
400
 
304
- if duration || till
305
- effective_duration = duration || till - start_position
306
- 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)
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
- if to && step && !every
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
- elsif to && !step && !every
313
- step = (to - from) / (effective_duration * @ticks_per_bar - right_open_offset)
314
- every = @tick_duration
410
+ if tick_duration > 0
411
+ function_range[i] = to[i] - from[i]
412
+ function_offset[i] = from[i]
315
413
 
316
- elsif to && !step && every
317
- steps = effective_duration / every
318
- step = (to - from) / (steps - right_open_offset)
414
+ from[i] = 0r
415
+ to[i] = 1r
319
416
 
320
- elsif !to && step && every
321
- # ok
322
- elsif !to && !step && every
323
- step = 1r
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
- else
326
- raise ArgumentError, 'Cannot use this parameters combination'
327
- end
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
- binder = KeyParametersProcedureBinder.new(block)
430
+ steps = effective_duration / every[i]
431
+ step[i] = 1r / (steps - right_open_offset[i])
340
432
 
341
- every_control = EveryControl.new(@event_handlers.last, capture_stdout: true, duration: duration, till: till, on_stop: on_stop, after_bars: after_bars, after: after)
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
- control = MoveControl.new(every_control)
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
- @event_handlers.push control
456
+ binder = SmartProcBinder.new(block)
346
457
 
347
- _numeric_at start_position, control do
348
- value = from
458
+ every_groups = {}
459
+ group_counter = {}
349
460
 
350
- _every every, every_control do
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
- parameters = binder.apply(control: control)
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
- yield value, **parameters
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
- if to && (value >= to && step.positive? || value <= to && step.negative?)
357
- control.stop
358
- else
359
- value += step
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
- @event_handlers.pop
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
- control
367
- end
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
- def _rescue_block_error(e)
370
- _log e
371
- _log e.full_message(order: :top)
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
- @on_block_error.each do |block|
374
- block.call e
375
- end
376
- end
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
- def _log(msg = nil)
379
- m = '...' unless msg
380
- m = ": #{msg}" if msg
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
- warn "#{position.to_f.round(3)} [#{position}]#{m}"
669
+ @on_error.each do |block|
670
+ block.call e
671
+ end
672
+ end
673
+ end
383
674
  end
384
675
  end
676
+