musa-dsl 0.21.4 → 0.22.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|