musa-dsl 0.21.4 → 0.22.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/musa-dsl.rb +1 -1
- data/lib/musa-dsl/core-ext.rb +1 -0
- data/lib/musa-dsl/core-ext/arrayfy.rb +9 -9
- data/lib/musa-dsl/core-ext/hashify.rb +42 -0
- data/lib/musa-dsl/core-ext/inspect-nice.rb +6 -1
- data/lib/musa-dsl/datasets/e.rb +22 -5
- data/lib/musa-dsl/datasets/gdv.rb +0 -1
- data/lib/musa-dsl/datasets/p.rb +28 -37
- data/lib/musa-dsl/datasets/pdv.rb +0 -1
- data/lib/musa-dsl/datasets/ps.rb +10 -78
- data/lib/musa-dsl/logger/logger.rb +4 -3
- data/lib/musa-dsl/matrix/matrix.rb +0 -57
- data/lib/musa-dsl/sequencer/base-sequencer-implementation-every.rb +87 -0
- data/lib/musa-dsl/sequencer/base-sequencer-implementation-move.rb +439 -0
- data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-helper.rb +2 -2
- data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-timed.rb +210 -0
- data/lib/musa-dsl/sequencer/base-sequencer-implementation-play.rb +178 -0
- data/lib/musa-dsl/sequencer/base-sequencer-implementation.rb +150 -597
- data/lib/musa-dsl/sequencer/base-sequencer-tick-based.rb +6 -8
- data/lib/musa-dsl/sequencer/base-sequencer-tickless-based.rb +1 -5
- data/lib/musa-dsl/sequencer/{base-sequencer-public.rb → base-sequencer.rb} +59 -5
- data/lib/musa-dsl/sequencer/sequencer-dsl.rb +11 -2
- data/lib/musa-dsl/sequencer/sequencer.rb +1 -1
- data/lib/musa-dsl/series/base-series.rb +43 -78
- data/lib/musa-dsl/series/flattener-timed-serie.rb +61 -0
- data/lib/musa-dsl/series/hash-or-array-serie-splitter.rb +143 -0
- data/lib/musa-dsl/series/holder-serie.rb +1 -1
- data/lib/musa-dsl/series/main-serie-constructors.rb +32 -92
- data/lib/musa-dsl/series/main-serie-operations.rb +60 -215
- data/lib/musa-dsl/series/proxy-serie.rb +1 -1
- data/lib/musa-dsl/series/quantizer-serie.rb +558 -0
- data/lib/musa-dsl/series/queue-serie.rb +1 -1
- data/lib/musa-dsl/series/series.rb +8 -2
- data/lib/musa-dsl/series/union-timed-series.rb +109 -0
- data/musa-dsl.gemspec +2 -2
- metadata +12 -5
- data/lib/musa-dsl/sequencer/base-sequencer-implementation-control.rb +0 -216
- data/lib/musa-dsl/series/hash-serie-splitter.rb +0 -196
@@ -41,25 +41,23 @@ module Musa
|
|
41
41
|
@position = @position_mutex.synchronize { 1r - @tick_duration }
|
42
42
|
end
|
43
43
|
|
44
|
-
def
|
44
|
+
def _quantize_position(position, warn: true)
|
45
45
|
ticks_position = position / @tick_duration
|
46
46
|
|
47
47
|
if ticks_position.round != ticks_position
|
48
48
|
original_position = position
|
49
49
|
position = ticks_position.round * @tick_duration
|
50
50
|
|
51
|
-
|
52
|
-
|
53
|
-
|
51
|
+
if warn
|
52
|
+
@logger.warn('BaseSequencer') { "_check_position: rounding "\
|
53
|
+
"position #{original_position} (#{original_position.to_f.round(5)}) "\
|
54
|
+
"to tick precision: #{position} (#{position.to_f.round(5)})" }
|
55
|
+
end
|
54
56
|
end
|
55
57
|
|
56
58
|
position
|
57
59
|
end
|
58
60
|
|
59
|
-
def _quantize(position)
|
60
|
-
(position / @tick_duration).round * @tick_duration
|
61
|
-
end
|
62
|
-
|
63
61
|
def _hold_public_ticks
|
64
62
|
@hold_public_ticks = true
|
65
63
|
end
|
@@ -17,7 +17,9 @@ module Musa
|
|
17
17
|
attr_reader :everying, :playing, :moving
|
18
18
|
attr_reader :logger
|
19
19
|
|
20
|
-
def initialize(beats_per_bar = nil, ticks_per_beat = nil,
|
20
|
+
def initialize(beats_per_bar = nil, ticks_per_beat = nil,
|
21
|
+
logger: nil,
|
22
|
+
do_log: nil, do_error_log: nil, log_position_format: nil)
|
21
23
|
|
22
24
|
raise ArgumentError,
|
23
25
|
"'beats_per_bar' and 'ticks_per_beat' parameters should be both nil or both have values" \
|
@@ -28,6 +30,7 @@ module Musa
|
|
28
30
|
else
|
29
31
|
@logger = Musa::Logger::Logger.new(sequencer: self, position_format: log_position_format)
|
30
32
|
|
33
|
+
@logger.fatal!
|
31
34
|
@logger.error! if do_error_log || do_error_log.nil?
|
32
35
|
@logger.debug! if do_log
|
33
36
|
end
|
@@ -175,10 +178,18 @@ module Musa
|
|
175
178
|
control
|
176
179
|
end
|
177
180
|
|
178
|
-
def play(serie,
|
181
|
+
def play(serie,
|
182
|
+
mode: nil,
|
183
|
+
parameter: nil,
|
184
|
+
after_bars: nil,
|
185
|
+
after: nil,
|
186
|
+
context: nil,
|
187
|
+
**mode_args,
|
188
|
+
&block)
|
189
|
+
|
179
190
|
mode ||= :wait
|
180
191
|
|
181
|
-
control = PlayControl.new @event_handlers.last, after: after
|
192
|
+
control = PlayControl.new @event_handlers.last, after_bars: after_bars, after: after
|
182
193
|
@event_handlers.push control
|
183
194
|
|
184
195
|
_play serie.instance, control, context, mode: mode, parameter: parameter, **mode_args, &block
|
@@ -197,14 +208,57 @@ module Musa
|
|
197
208
|
def continuation_play(parameters)
|
198
209
|
_play parameters[:serie],
|
199
210
|
parameters[:control],
|
200
|
-
parameters[:
|
211
|
+
parameters[:neumalang_context],
|
201
212
|
mode: parameters[:mode],
|
202
213
|
decoder: parameters[:decoder],
|
203
214
|
__play_eval: parameters[:play_eval],
|
204
215
|
**parameters[:mode_args]
|
205
216
|
end
|
206
217
|
|
207
|
-
def
|
218
|
+
def play_timed(timed_serie,
|
219
|
+
reference: nil,
|
220
|
+
step: nil,
|
221
|
+
right_open: nil,
|
222
|
+
on_stop: nil,
|
223
|
+
after_bars: nil, after: nil,
|
224
|
+
&block)
|
225
|
+
|
226
|
+
control = PlayTimedControl.new(@event_handlers.last,
|
227
|
+
on_stop: on_stop, after_bars: after_bars, after: after)
|
228
|
+
|
229
|
+
control.on_stop do
|
230
|
+
control.do_after.each do |do_after|
|
231
|
+
_numeric_at position + do_after[:bars], control, &do_after[:block]
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
@event_handlers.push control
|
236
|
+
|
237
|
+
_play_timed(timed_serie.instance,
|
238
|
+
control,
|
239
|
+
reference: reference,
|
240
|
+
step: step,
|
241
|
+
right_open: right_open,
|
242
|
+
&block)
|
243
|
+
|
244
|
+
@event_handlers.pop
|
245
|
+
|
246
|
+
@playing << control
|
247
|
+
|
248
|
+
control.after do
|
249
|
+
@playing.delete control
|
250
|
+
end
|
251
|
+
|
252
|
+
control
|
253
|
+
end
|
254
|
+
|
255
|
+
def every(interval,
|
256
|
+
duration: nil, till: nil,
|
257
|
+
condition: nil,
|
258
|
+
on_stop: nil,
|
259
|
+
after_bars: nil, after: nil,
|
260
|
+
&block)
|
261
|
+
|
208
262
|
# nil interval means 'only once'
|
209
263
|
interval = interval.rationalize unless interval.nil?
|
210
264
|
|
@@ -18,12 +18,13 @@ module Musa
|
|
18
18
|
:event_handler
|
19
19
|
|
20
20
|
def_delegators :@context, :position, :logger, :debug
|
21
|
-
def_delegators :@context, :with, :now, :at, :wait, :play, :every, :move
|
21
|
+
def_delegators :@context, :with, :now, :at, :wait, :play, :play_timed, :every, :move
|
22
22
|
def_delegators :@context, :everying, :playing, :moving
|
23
23
|
def_delegators :@context, :launch, :on
|
24
24
|
def_delegators :@context, :run
|
25
25
|
|
26
|
-
def initialize(beats_per_bar
|
26
|
+
def initialize(beats_per_bar = nil,
|
27
|
+
ticks_per_beat = nil,
|
27
28
|
sequencer: nil,
|
28
29
|
logger: nil,
|
29
30
|
do_log: nil, do_error_log: nil, log_position_format: nil,
|
@@ -89,6 +90,14 @@ module Musa
|
|
89
90
|
end
|
90
91
|
end
|
91
92
|
|
93
|
+
def play_timed(*value_parameters, **key_parameters, &block)
|
94
|
+
block ||= proc {}
|
95
|
+
|
96
|
+
@sequencer.play_timed *value_parameters, **key_parameters do |*value_args, **key_args|
|
97
|
+
with *value_args, **key_args, &block
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
92
101
|
def every(*value_parameters, **key_parameters, &block)
|
93
102
|
block ||= proc {}
|
94
103
|
|
@@ -18,57 +18,73 @@ module Musa
|
|
18
18
|
|
19
19
|
def prototype
|
20
20
|
if @is_instance
|
21
|
-
@instance_of || (@instance_of = clone.tap(&:_prototype).mark_as_prototype!)
|
21
|
+
@instance_of || (@instance_of = self.clone.tap(&:_prototype!).mark_as_prototype!)
|
22
22
|
else
|
23
23
|
self
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
-
def _prototype
|
28
|
-
nil
|
29
|
-
end
|
30
|
-
|
31
27
|
alias_method :p, :prototype
|
32
28
|
|
33
|
-
def
|
34
|
-
@is_instance
|
35
|
-
|
29
|
+
def instance
|
30
|
+
if @is_instance
|
31
|
+
self
|
32
|
+
else
|
33
|
+
clone(freeze: false).tap(&:_instance!).mark_as_instance!(self)
|
34
|
+
end
|
36
35
|
end
|
37
36
|
|
38
|
-
|
37
|
+
alias_method :i, :instance
|
39
38
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
39
|
+
# By default, if there is a @source attribute that contains the source of the serie, SeriePrototyping will
|
40
|
+
# handle prototyping/instancing automatically.
|
41
|
+
# If there is a @sources attribute with the eventual several sources, SeriePrototyping will handle them by
|
42
|
+
# default.
|
43
|
+
# If needed the subclasses can override this behaviour to accomodate to real subclass specificities.
|
44
|
+
#
|
45
|
+
protected def _prototype!
|
46
|
+
@source = @source.prototype if @source
|
47
|
+
|
48
|
+
if @sources
|
49
|
+
if @sources.is_a?(Array)
|
50
|
+
@sources = @sources.collect(&:prototype).freeze
|
51
|
+
elsif @sources.is_a?(Hash)
|
52
|
+
@sources = @sources.transform_values(&:prototype).freeze
|
53
|
+
end
|
45
54
|
end
|
46
55
|
end
|
47
56
|
|
48
|
-
protected
|
57
|
+
protected def _instance!
|
58
|
+
@source = @source.instance if @source
|
49
59
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
60
|
+
if @sources
|
61
|
+
if @sources.is_a?(Array)
|
62
|
+
@sources = @sources.collect(&:instance)
|
63
|
+
elsif @sources.is_a?(Hash)
|
64
|
+
@sources = @sources.transform_values(&:instance)
|
65
|
+
end
|
55
66
|
end
|
56
67
|
end
|
57
68
|
|
58
|
-
|
69
|
+
protected def mark_regarding!(source)
|
70
|
+
if source.prototype?
|
71
|
+
mark_as_prototype!
|
72
|
+
else
|
73
|
+
mark_as_instance!
|
74
|
+
end
|
75
|
+
end
|
59
76
|
|
60
|
-
def
|
61
|
-
nil
|
77
|
+
protected def mark_as_prototype!
|
78
|
+
@is_instance = nil
|
79
|
+
freeze
|
62
80
|
end
|
63
81
|
|
64
|
-
def mark_as_instance!(prototype = nil)
|
82
|
+
protected def mark_as_instance!(prototype = nil)
|
65
83
|
@instance_of = prototype
|
66
84
|
@is_instance = true
|
67
85
|
self
|
68
86
|
end
|
69
87
|
|
70
|
-
protected :_instance, :mark_as_instance!
|
71
|
-
|
72
88
|
class PrototypingSerieError < RuntimeError
|
73
89
|
def initialize(message = nil)
|
74
90
|
message ||= 'This serie is a prototype serie: cannot be consumed. To consume the serie use an instance serie via .instance method'
|
@@ -106,8 +122,6 @@ module Musa
|
|
106
122
|
end
|
107
123
|
end
|
108
124
|
|
109
|
-
propagate_value @_current_value
|
110
|
-
|
111
125
|
@_current_value
|
112
126
|
end
|
113
127
|
|
@@ -180,15 +194,7 @@ module Musa
|
|
180
194
|
|
181
195
|
private_constant :Nodificator
|
182
196
|
|
183
|
-
|
184
|
-
|
185
|
-
def propagate_value(value)
|
186
|
-
@_slaves.each { |s| s.push_next_value value } if @_slaves
|
187
|
-
end
|
188
|
-
|
189
|
-
private
|
190
|
-
|
191
|
-
def process_for_to_a(value)
|
197
|
+
private def process_for_to_a(value)
|
192
198
|
case value
|
193
199
|
when Serie
|
194
200
|
value.to_a(recursive: true, restart: false, duplicate: false)
|
@@ -203,46 +209,5 @@ module Musa
|
|
203
209
|
end
|
204
210
|
end
|
205
211
|
end
|
206
|
-
|
207
|
-
class Slave
|
208
|
-
include Serie
|
209
|
-
|
210
|
-
attr_reader :master
|
211
|
-
|
212
|
-
def initialize(master)
|
213
|
-
@master = master
|
214
|
-
@next_value = []
|
215
|
-
end
|
216
|
-
|
217
|
-
def _restart
|
218
|
-
throw OperationNotAllowedError, "SlaveSerie #{self}: slave series cannot be restarted"
|
219
|
-
end
|
220
|
-
|
221
|
-
def next_value
|
222
|
-
value = @next_value.shift
|
223
|
-
|
224
|
-
raise "Warning: slave serie #{self} has lost sync with his master serie #{@master}" if value.nil? && !@master.peek_next_value.nil?
|
225
|
-
|
226
|
-
propagate_value value
|
227
|
-
|
228
|
-
value
|
229
|
-
end
|
230
|
-
|
231
|
-
def peek_next_value
|
232
|
-
value = @next_value.first
|
233
|
-
|
234
|
-
raise "Warning: slave serie #{self} has lost sync with his master serie #{@master}" if value.nil? && !@master.peek_next_value.nil?
|
235
|
-
|
236
|
-
value
|
237
|
-
end
|
238
|
-
|
239
|
-
def infinite?
|
240
|
-
@master.infinite?
|
241
|
-
end
|
242
|
-
|
243
|
-
def push_next_value(value)
|
244
|
-
@next_value << value
|
245
|
-
end
|
246
|
-
end
|
247
212
|
end
|
248
213
|
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require_relative '../datasets/e'
|
2
|
+
|
3
|
+
module Musa
|
4
|
+
module Series
|
5
|
+
|
6
|
+
module SerieOperations
|
7
|
+
def flatten_timed
|
8
|
+
TimedFlattener.new(self)
|
9
|
+
end
|
10
|
+
|
11
|
+
class TimedFlattener
|
12
|
+
include Serie
|
13
|
+
|
14
|
+
attr_reader :source
|
15
|
+
|
16
|
+
def initialize(serie)
|
17
|
+
@source = serie
|
18
|
+
mark_regarding! @source
|
19
|
+
end
|
20
|
+
|
21
|
+
def _restart
|
22
|
+
@source.restart
|
23
|
+
end
|
24
|
+
|
25
|
+
def _next_value
|
26
|
+
source_value = @source.next_value
|
27
|
+
|
28
|
+
if !source_value.nil?
|
29
|
+
time = source_value[:time]
|
30
|
+
source_value_value = source_value[:value]
|
31
|
+
|
32
|
+
case source_value_value
|
33
|
+
when Hash
|
34
|
+
result = {}
|
35
|
+
source_value_value.each_pair do |key, value|
|
36
|
+
result[key] = { time: time, value: value }.extend(Musa::Datasets::AbsTimed)
|
37
|
+
end
|
38
|
+
when Array
|
39
|
+
result = []
|
40
|
+
source_value_value.each_index do |index|
|
41
|
+
result[index] = { time: time, value: source_value_value[index] }.extend(Musa::Datasets::AbsTimed)
|
42
|
+
end
|
43
|
+
else
|
44
|
+
raise RuntimeError, "Don't know how to handle #{source_value_value}"
|
45
|
+
end
|
46
|
+
|
47
|
+
result
|
48
|
+
else
|
49
|
+
nil
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def infinite?
|
54
|
+
@source.infinite?
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
private_constant :TimedFlattener
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
module Musa
|
2
|
+
module Series
|
3
|
+
module SerieOperations
|
4
|
+
def split
|
5
|
+
Splitter.new(Splitter::BufferedProxy.new(self))
|
6
|
+
end
|
7
|
+
|
8
|
+
class Splitter
|
9
|
+
include Enumerable
|
10
|
+
|
11
|
+
def initialize(proxy)
|
12
|
+
@proxy = proxy
|
13
|
+
@series = {}
|
14
|
+
end
|
15
|
+
|
16
|
+
def [](key_or_index)
|
17
|
+
if @series.has_key?(key_or_index)
|
18
|
+
@series[key_or_index]
|
19
|
+
else
|
20
|
+
@series[key_or_index] = Split.new(@proxy, key_or_index)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def each
|
25
|
+
if block_given?
|
26
|
+
if @proxy.hash_mode?
|
27
|
+
@proxy.components.each do |key|
|
28
|
+
yield [key, self[key]]
|
29
|
+
end
|
30
|
+
elsif @proxy.array_mode?
|
31
|
+
@proxy.components.each do |index|
|
32
|
+
yield self[index]
|
33
|
+
end
|
34
|
+
else
|
35
|
+
# do nothing
|
36
|
+
end
|
37
|
+
else
|
38
|
+
if @proxy.hash_mode?
|
39
|
+
@proxy.components.collect { |key| [key, self[key]] }.each
|
40
|
+
elsif @proxy.array_mode?
|
41
|
+
@proxy.components.collect { |index| self[index] }.each
|
42
|
+
else
|
43
|
+
[].each
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class BufferedProxy
|
49
|
+
include SeriePrototyping
|
50
|
+
|
51
|
+
def initialize(hash_or_array_serie)
|
52
|
+
@source = hash_or_array_serie
|
53
|
+
restart restart_source: false
|
54
|
+
|
55
|
+
mark_regarding! @source
|
56
|
+
end
|
57
|
+
|
58
|
+
attr_reader :components
|
59
|
+
|
60
|
+
def hash_mode?; @hash_mode; end
|
61
|
+
def array_mode?; @array_mode; end
|
62
|
+
|
63
|
+
protected def _instance!
|
64
|
+
super
|
65
|
+
restart
|
66
|
+
end
|
67
|
+
|
68
|
+
def restart(restart_source: true)
|
69
|
+
@source.restart if restart_source
|
70
|
+
|
71
|
+
source = @source.instance
|
72
|
+
sample = source.current_value || source.peek_next_value
|
73
|
+
|
74
|
+
case sample
|
75
|
+
when Array
|
76
|
+
@components = (0..sample.size-1).to_a
|
77
|
+
@values = []
|
78
|
+
@array_mode = true
|
79
|
+
@hash_mode = false
|
80
|
+
when Hash
|
81
|
+
@components = sample.keys.clone
|
82
|
+
@values = {}
|
83
|
+
@array_mode = false
|
84
|
+
@hash_mode = true
|
85
|
+
else
|
86
|
+
@components = []
|
87
|
+
@values = nil
|
88
|
+
@array_mode = @hash_mode = false
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def next_value(key_or_index)
|
93
|
+
if @values[key_or_index].nil? || @values[key_or_index].empty?
|
94
|
+
hash_or_array_value = @source.next_value
|
95
|
+
|
96
|
+
case hash_or_array_value
|
97
|
+
when Hash
|
98
|
+
hash_or_array_value.each do |k, v|
|
99
|
+
@values[k] ||= []
|
100
|
+
@values[k] << v
|
101
|
+
end
|
102
|
+
when Array
|
103
|
+
hash_or_array_value.each_index do |i|
|
104
|
+
@values[i] ||= []
|
105
|
+
@values[i] << hash_or_array_value[i]
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
if @values && !@values[key_or_index].nil?
|
111
|
+
@values[key_or_index].shift
|
112
|
+
else
|
113
|
+
nil
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
class Split
|
119
|
+
include Serie
|
120
|
+
|
121
|
+
def initialize(proxy, key_or_index)
|
122
|
+
@source = proxy
|
123
|
+
@key_or_index = key_or_index
|
124
|
+
|
125
|
+
mark_regarding! @source
|
126
|
+
end
|
127
|
+
|
128
|
+
def _restart
|
129
|
+
@source.restart
|
130
|
+
end
|
131
|
+
|
132
|
+
def _next_value
|
133
|
+
@source.next_value(@key_or_index)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
private_constant :Split
|
138
|
+
end
|
139
|
+
|
140
|
+
private_constant :Splitter
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|