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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/lib/musa-dsl.rb +1 -1
  3. data/lib/musa-dsl/core-ext.rb +1 -0
  4. data/lib/musa-dsl/core-ext/arrayfy.rb +9 -9
  5. data/lib/musa-dsl/core-ext/hashify.rb +42 -0
  6. data/lib/musa-dsl/core-ext/inspect-nice.rb +6 -1
  7. data/lib/musa-dsl/datasets/e.rb +22 -5
  8. data/lib/musa-dsl/datasets/gdv.rb +0 -1
  9. data/lib/musa-dsl/datasets/p.rb +28 -37
  10. data/lib/musa-dsl/datasets/pdv.rb +0 -1
  11. data/lib/musa-dsl/datasets/ps.rb +10 -78
  12. data/lib/musa-dsl/logger/logger.rb +4 -3
  13. data/lib/musa-dsl/matrix/matrix.rb +0 -57
  14. data/lib/musa-dsl/sequencer/base-sequencer-implementation-every.rb +87 -0
  15. data/lib/musa-dsl/sequencer/base-sequencer-implementation-move.rb +439 -0
  16. data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-helper.rb +2 -2
  17. data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-timed.rb +210 -0
  18. data/lib/musa-dsl/sequencer/base-sequencer-implementation-play.rb +178 -0
  19. data/lib/musa-dsl/sequencer/base-sequencer-implementation.rb +150 -597
  20. data/lib/musa-dsl/sequencer/base-sequencer-tick-based.rb +6 -8
  21. data/lib/musa-dsl/sequencer/base-sequencer-tickless-based.rb +1 -5
  22. data/lib/musa-dsl/sequencer/{base-sequencer-public.rb → base-sequencer.rb} +59 -5
  23. data/lib/musa-dsl/sequencer/sequencer-dsl.rb +11 -2
  24. data/lib/musa-dsl/sequencer/sequencer.rb +1 -1
  25. data/lib/musa-dsl/series/base-series.rb +43 -78
  26. data/lib/musa-dsl/series/flattener-timed-serie.rb +61 -0
  27. data/lib/musa-dsl/series/hash-or-array-serie-splitter.rb +143 -0
  28. data/lib/musa-dsl/series/holder-serie.rb +1 -1
  29. data/lib/musa-dsl/series/main-serie-constructors.rb +32 -92
  30. data/lib/musa-dsl/series/main-serie-operations.rb +60 -215
  31. data/lib/musa-dsl/series/proxy-serie.rb +1 -1
  32. data/lib/musa-dsl/series/quantizer-serie.rb +558 -0
  33. data/lib/musa-dsl/series/queue-serie.rb +1 -1
  34. data/lib/musa-dsl/series/series.rb +8 -2
  35. data/lib/musa-dsl/series/union-timed-series.rb +109 -0
  36. data/musa-dsl.gemspec +2 -2
  37. metadata +12 -5
  38. data/lib/musa-dsl/sequencer/base-sequencer-implementation-control.rb +0 -216
  39. 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 _check_position(position)
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
- @logger.warn('BaseSequencer') { "._numeric_at: warning: rounding "\
52
- "position #{position} (#{original_position.to_f.round(5)}) "\
53
- "to tick precision: #{position} (#{position.to_f.round(5)})" }
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
@@ -62,11 +62,7 @@ module Musa
62
62
  @position = nil
63
63
  end
64
64
 
65
- def _check_position(position)
66
- position
67
- end
68
-
69
- def _quantize(position)
65
+ def _quantize_position(position, warn: false)
70
66
  position
71
67
  end
72
68
  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, logger: nil, do_log: nil, do_error_log: nil, log_position_format: 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, mode: nil, parameter: nil, after: nil, context: nil, **mode_args, &block)
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[:nl_context],
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 every(interval, duration: nil, till: nil, condition: nil, on_stop: nil, after_bars: nil, after: nil, &block)
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, ticks_per_beat,
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
 
@@ -1,3 +1,3 @@
1
- require_relative 'base-sequencer-public'
1
+ require_relative 'base-sequencer'
2
2
  require_relative 'base-sequencer-implementation'
3
3
  require_relative 'sequencer-dsl'
@@ -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 mark_as_prototype!
34
- @is_instance = nil
35
- freeze
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
- protected :_prototype, :mark_as_prototype!
37
+ alias_method :i, :instance
39
38
 
40
- def mark_regarding!(source)
41
- if source.prototype?
42
- mark_as_prototype!
43
- else
44
- mark_as_instance!
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 :mark_regarding!
57
+ protected def _instance!
58
+ @source = @source.instance if @source
49
59
 
50
- def instance
51
- if @is_instance
52
- self
53
- else
54
- clone(freeze: false).tap(&:_instance).mark_as_instance!(self)
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
- alias_method :i, :instance
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 _instance
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
- protected
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