musa-dsl 0.21.5 → 0.22.4

Sign up to get free protection for your applications and to get access to all the features.
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 +29 -36
  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 +2 -2
  13. data/lib/musa-dsl/matrix/matrix.rb +9 -64
  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 +219 -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} +63 -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: rounding "\
52
- "position #{original_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,61 @@ 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
+ predictive: nil,
222
+ stops: nil,
223
+ right_open: nil,
224
+ on_stop: nil,
225
+ after_bars: nil, after: nil,
226
+ &block)
227
+
228
+ control = PlayTimedControl.new(@event_handlers.last,
229
+ on_stop: on_stop, after_bars: after_bars, after: after)
230
+
231
+ control.on_stop do
232
+ control.do_after.each do |do_after|
233
+ _numeric_at position + do_after[:bars], control, &do_after[:block]
234
+ end
235
+ end
236
+
237
+ @event_handlers.push control
238
+
239
+ _play_timed(timed_serie.instance,
240
+ control,
241
+ reference: reference,
242
+ step: step,
243
+ predictive: predictive,
244
+ stops: stops,
245
+ right_open: right_open,
246
+ &block)
247
+
248
+ @event_handlers.pop
249
+
250
+ @playing << control
251
+
252
+ control.after do
253
+ @playing.delete control
254
+ end
255
+
256
+ control
257
+ end
258
+
259
+ def every(interval,
260
+ duration: nil, till: nil,
261
+ condition: nil,
262
+ on_stop: nil,
263
+ after_bars: nil, after: nil,
264
+ &block)
265
+
208
266
  # nil interval means 'only once'
209
267
  interval = interval.rationalize unless interval.nil?
210
268
 
@@ -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