musa-dsl 0.22.3 → 0.23.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +3 -1
  3. data/lib/musa-dsl.rb +14 -8
  4. data/lib/musa-dsl/core-ext/deep-copy.rb +12 -1
  5. data/lib/musa-dsl/core-ext/inspect-nice.rb +1 -2
  6. data/lib/musa-dsl/core-ext/smart-proc-binder.rb +13 -11
  7. data/lib/musa-dsl/datasets/p.rb +41 -16
  8. data/lib/musa-dsl/datasets/score/to-mxml/process-pdv.rb +14 -12
  9. data/lib/musa-dsl/datasets/score/to-mxml/process-ps.rb +32 -6
  10. data/lib/musa-dsl/datasets/score/to-mxml/to-mxml.rb +24 -10
  11. data/lib/musa-dsl/generative/backboner.rb +6 -11
  12. data/lib/musa-dsl/generative/generative-grammar.rb +1 -3
  13. data/lib/musa-dsl/generative/markov.rb +10 -6
  14. data/lib/musa-dsl/logger/logger.rb +6 -1
  15. data/lib/musa-dsl/matrix/matrix.rb +9 -7
  16. data/lib/musa-dsl/midi/midi-voices.rb +8 -7
  17. data/lib/musa-dsl/music/scales.rb +1 -1
  18. data/lib/musa-dsl/neumalang/neumalang.rb +1 -1
  19. data/lib/musa-dsl/neumas/array-to-neumas.rb +1 -1
  20. data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-helper.rb +9 -4
  21. data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-timed.rb +30 -129
  22. data/lib/musa-dsl/sequencer/base-sequencer-implementation.rb +10 -24
  23. data/lib/musa-dsl/sequencer/base-sequencer-tick-based.rb +9 -9
  24. data/lib/musa-dsl/sequencer/base-sequencer-tickless-based.rb +3 -5
  25. data/lib/musa-dsl/sequencer/base-sequencer.rb +14 -23
  26. data/lib/musa-dsl/sequencer/sequencer-dsl.rb +9 -7
  27. data/lib/musa-dsl/sequencer/sequencer.rb +7 -0
  28. data/lib/musa-dsl/series/base-series.rb +293 -144
  29. data/lib/musa-dsl/series/buffer-serie.rb +237 -0
  30. data/lib/musa-dsl/series/hash-or-array-serie-splitter.rb +136 -105
  31. data/lib/musa-dsl/series/main-serie-constructors.rb +251 -156
  32. data/lib/musa-dsl/series/main-serie-operations.rb +308 -303
  33. data/lib/musa-dsl/series/proxy-serie.rb +21 -41
  34. data/lib/musa-dsl/series/quantizer-serie.rb +44 -46
  35. data/lib/musa-dsl/series/queue-serie.rb +39 -43
  36. data/lib/musa-dsl/series/series-composer.rb +149 -0
  37. data/lib/musa-dsl/series/series.rb +6 -3
  38. data/lib/musa-dsl/series/timed-serie.rb +343 -0
  39. data/musa-dsl.gemspec +13 -3
  40. metadata +10 -11
  41. data/lib/musa-dsl/series/flattener-timed-serie.rb +0 -61
  42. data/lib/musa-dsl/series/holder-serie.rb +0 -87
  43. data/lib/musa-dsl/series/union-timed-series.rb +0 -109
@@ -3,13 +3,8 @@ require_relative '../core-ext/with'
3
3
 
4
4
  using Musa::Extension::Arrayfy
5
5
 
6
- # incluir With -> hecho
7
- # eliminar method_missing
8
- # crear rama tb debe recibir la serie de la history -> ya lo hace
9
- # crear rama puede repetirse (hasta terminar según ended_when) -> no
10
- #
11
- # hacer que pueda funcionar en tiempo real? le vas suministrando seeds y le vas diciendo qué opción has elegido (p.ej. para hacer un armonizador en tiempo real)
12
- # esto mismo sería aplicable en otros generadores? variatio/darwin? generative-grammar? markov?
6
+ # TODO hacer que pueda funcionar en tiempo real? le vas suministrando seeds y le vas diciendo qué opción has elegido (p.ej. para hacer un armonizador en tiempo real)
7
+ # TODO esto mismo sería aplicable en otros generadores? variatio/darwin? generative-grammar? markov?
13
8
 
14
9
  module Musa
15
10
  module Backboner
@@ -17,12 +12,12 @@ module Musa
17
12
  include Musa::Extension::With
18
13
 
19
14
  def initialize(&block)
20
- @context = RulesEvalContext.new(&block)
15
+ @dsl = RulesEvalContext.new(&block)
21
16
  end
22
17
 
23
18
  def generate_possibilities(object, confirmed_node = nil, node = nil, grow_rules = nil)
24
19
  node ||= Node.new
25
- grow_rules ||= @context._grow_rules
20
+ grow_rules ||= @dsl._grow_rules
26
21
 
27
22
  history = confirmed_node.history if confirmed_node
28
23
  history ||= []
@@ -33,9 +28,9 @@ module Musa
33
28
  if grow_rule
34
29
  grow_rule.generate_possibilities(object, history).each do |new_object|
35
30
  new_node = Node.new new_object, node
36
- new_node.mark_as_ended! if @context._ended? new_object
31
+ new_node.mark_as_ended! if @dsl._ended? new_object
37
32
 
38
- rejection = @context._cut_rules.find { |cut_rule| cut_rule.rejects?(new_object, history) }
33
+ rejection = @dsl._cut_rules.find { |cut_rule| cut_rule.rejects?(new_object, history) }
39
34
  # TODO: include rejection secondary reasons in rejection message
40
35
 
41
36
  new_node.reject! rejection if rejection
@@ -100,9 +100,7 @@ module Musa
100
100
  options[index].to_serie.to_node
101
101
  end
102
102
 
103
- def to_serie(flatten: nil, &condition)
104
- flatten ||= true
105
-
103
+ def to_serie(flatten: true, &condition)
106
104
  serie = _options(&condition).collect { |o| o.collect(&:content) }.to_serie(of_series: true).merge
107
105
  serie = serie.flatten if flatten
108
106
 
@@ -7,9 +7,8 @@ module Musa
7
7
  module Markov
8
8
  class Markov
9
9
  include Musa::Extension::SmartProcBinder
10
- include Musa::Series::Serie
10
+ include Musa::Series::Serie.base
11
11
 
12
- attr_accessor :start, :finish, :random, :transitions
13
12
 
14
13
  def initialize(transitions:, start:, finish: nil, random: nil)
15
14
  @transitions = transitions.clone.freeze
@@ -22,23 +21,28 @@ module Musa
22
21
 
23
22
  @procedure_binders = {}
24
23
 
25
- _restart
24
+ init
26
25
  end
27
26
 
28
- def _restart
27
+ attr_accessor :start
28
+ attr_accessor :finish
29
+ attr_accessor :random
30
+ attr_accessor :transitions
31
+
32
+ private def _init
29
33
  @current = nil
30
34
  @finished = false
31
35
  @history = []
32
36
  end
33
37
 
34
- def _next_value
38
+ private def _next_value
35
39
  if @finished
36
40
  @current = nil
37
41
  else
38
42
  if @current.nil?
39
43
  @current = @start
40
44
  else
41
- if @transitions.has_key? @current
45
+ if @transitions.has_key?(@current)
42
46
  options = @transitions[@current]
43
47
 
44
48
  case options
@@ -1,7 +1,12 @@
1
1
  require 'logger'
2
2
 
3
+ require_relative '../core-ext/inspect-nice'
4
+
5
+
3
6
  module Musa; module Logger
4
7
  class Logger < ::Logger
8
+ using Musa::Extension::InspectNice
9
+
5
10
  def initialize(sequencer: nil, position_format: nil)
6
11
  super STDERR, level: WARN
7
12
 
@@ -22,7 +27,7 @@ module Musa; module Logger
22
27
 
23
28
  progname = "[#{progname}]" if progname
24
29
 
25
- "#{position}#{level}#{progname} #{msg}\n"
30
+ "#{position}#{level}#{progname}#{' ' if position || level || progname}#{msg}\n"
26
31
  else
27
32
  "\n"
28
33
  end
@@ -22,8 +22,8 @@ module Musa
22
22
  indexes
23
23
  end
24
24
 
25
- def to_p(time_dimension, keep_time: nil)
26
- condensed_matrices.collect { |m| m.to_p(time_dimension, keep_time: keep_time) }
25
+ def to_p(time_dimension:, keep_time: nil)
26
+ condensed_matrices.collect { |m| m.to_p(time_dimension: time_dimension, keep_time: keep_time) }
27
27
  end
28
28
 
29
29
  def condensed_matrices
@@ -69,14 +69,14 @@ module Musa
69
69
  refine ::Matrix do
70
70
  include Musa::Datasets
71
71
 
72
- def to_p(time_dimension, keep_time: nil)
72
+ def to_p(time_dimension:, keep_time: nil)
73
73
  decompose(self.to_a, time_dimension).collect do |points|
74
74
  line = []
75
75
 
76
76
  start_point = points[0]
77
77
  start_time = start_point[time_dimension]
78
78
 
79
- line << start_point.tap { |_| _.delete_at(time_dimension) unless keep_time; _ }.extend(Datasets::V)
79
+ line << start_point.clone.tap { |_| _.delete_at(time_dimension) unless keep_time; _ }.extend(Datasets::V)
80
80
 
81
81
  (1..points.size-1).each do |i|
82
82
  end_point = points[i]
@@ -84,7 +84,7 @@ module Musa
84
84
  end_time = end_point[time_dimension]
85
85
 
86
86
  line << end_time - start_time
87
- line << end_point.tap { |_| _.delete_at(time_dimension) unless keep_time; _ }.extend(Datasets::V)
87
+ line << end_point.clone.tap { |_| _.delete_at(time_dimension) unless keep_time; _ }.extend(Datasets::V)
88
88
 
89
89
  start_time = end_time
90
90
  end
@@ -107,8 +107,9 @@ module Musa
107
107
 
108
108
  x_dim_values_indexes.keys.sort.each do |value|
109
109
  x_dim_values_indexes[value].each do |index|
110
+ #
110
111
  # hacia un lado
111
-
112
+ #
112
113
  unless used_indexes.include?(index)
113
114
  i = index
114
115
  xx = array[i][time_dimension]
@@ -125,8 +126,9 @@ module Musa
125
126
 
126
127
  directional_segments << a if a.size > 1
127
128
 
129
+ #
128
130
  # y hacia el otro
129
-
131
+ #
130
132
  i = index
131
133
  xx = array[i][time_dimension]
132
134
 
@@ -10,7 +10,7 @@ using Musa::Extension::ExplodeRanges
10
10
  module Musa
11
11
  module MIDIVoices
12
12
  class MIDIVoices
13
- attr_accessor :log
13
+ attr_accessor :do_log
14
14
 
15
15
  def initialize(sequencer:, output:, channels:, do_log: nil)
16
16
  do_log ||= false
@@ -24,7 +24,7 @@ module Musa
24
24
  end
25
25
 
26
26
  def reset
27
- @voices = @channels.collect { |channel| MIDIVoice.new sequencer: @sequencer, output: @output, channel: channel, log: @do_log }.freeze
27
+ @voices = @channels.collect { |channel| MIDIVoice.new(sequencer: @sequencer, output: @output, channel: channel, do_log: @do_log) }.freeze
28
28
  end
29
29
 
30
30
  attr_reader :voices
@@ -48,14 +48,14 @@ module Musa
48
48
  attr_accessor :name, :do_log
49
49
  attr_reader :sequencer, :output, :channel, :active_pitches, :tick_duration
50
50
 
51
- def initialize(sequencer:, output:, channel:, name: nil, log: nil)
52
- log ||= false
51
+ def initialize(sequencer:, output:, channel:, name: nil, do_log: nil)
52
+ do_log ||= false
53
53
 
54
54
  @sequencer = sequencer
55
55
  @output = output
56
56
  @channel = channel
57
57
  @name = name
58
- @do_log = log
58
+ @do_log = do_log
59
59
 
60
60
  @tick_duration = Rational(1, @sequencer.ticks_per_bar)
61
61
 
@@ -64,7 +64,7 @@ module Musa
64
64
  @active_pitches = []
65
65
  fill_active_pitches @active_pitches
66
66
 
67
- log 'Warning: voice without output' unless @output
67
+ @sequencer.logger.warn 'voice without output' unless @output
68
68
 
69
69
  self
70
70
  end
@@ -118,7 +118,7 @@ module Musa
118
118
  end
119
119
 
120
120
  def log(msg)
121
- @sequencer.log "voice #{name || @channel}: #{msg}" if @do_log
121
+ @sequencer.logger.info('MIDIVoice') { "voice #{name || @channel}: #{msg}" } if @do_log
122
122
  end
123
123
 
124
124
  def to_s
@@ -169,6 +169,7 @@ module Musa
169
169
  private_constant :ControllersControl
170
170
 
171
171
  class NoteControl
172
+ attr_reader :voice, :pitch, :velocity, :velocity_off, :duration
172
173
  attr_reader :start_position, :end_position
173
174
 
174
175
  def initialize(voice, pitch:, velocity: nil, duration: nil, velocity_off: nil)
@@ -303,7 +303,7 @@ module Musa
303
303
 
304
304
  def [](grade_or_symbol)
305
305
 
306
- raise ArgumentError, "grade_or_symbol '#{grade_or_symbol}' should be a Numeric, String or Symbol" unless grade_or_symbol.is_a?(Symbol) || grade_or_symbol.is_a?(String) || grade_or_symbol.is_a?(Integer)
306
+ raise ArgumentError, "grade_or_symbol '#{grade_or_symbol}' should be a Integer, String or Symbol" unless grade_or_symbol.is_a?(Symbol) || grade_or_symbol.is_a?(String) || grade_or_symbol.is_a?(Integer)
307
307
 
308
308
  wide_grade, sharps = grade_of(grade_or_symbol)
309
309
 
@@ -15,7 +15,7 @@ module Musa
15
15
  include Musa::Neumas
16
16
 
17
17
  def value
18
- _SE(captures(:expression).collect(&:value), extends: Neuma::Serie)
18
+ S(*captures(:expression).collect(&:value)).extend(Neuma::Serie)
19
19
  end
20
20
  end
21
21
 
@@ -21,7 +21,7 @@ module Musa
21
21
  def convert_to_neumas(e)
22
22
  case e
23
23
  when Musa::Neumas::Neuma::Serie then e
24
- when Musa::Neumas::Neuma::Parallel then _SE([e], extends: Musa::Neumas::Neuma::Serie)
24
+ when Musa::Neumas::Neuma::Parallel then S(e).extend(Musa::Neumas::Neuma::Serie)
25
25
  when String then e.to_neumas
26
26
  else
27
27
  raise ArgumentError, "Don't know how to convert to neumas #{e}"
@@ -262,11 +262,11 @@ module Musa
262
262
 
263
263
  when Musa::Series::Serie
264
264
  { current_operation: :play,
265
- current_parameter: element.restart }
265
+ current_parameter: element.instance.restart }
266
266
 
267
267
  when Parallel
268
268
  { current_operation: :parallel_play,
269
- current_parameter: element.tap { |e| e.each(&:restart) } }
269
+ current_parameter: element.instance.tap { |e| e.each(&:restart) } }
270
270
 
271
271
  when Array
272
272
  { current_operation: :no_eval_play,
@@ -324,8 +324,13 @@ module Musa
324
324
  run_operation eval_use_variable(element[:use_variable])
325
325
 
326
326
  when :event
327
- value_parameters = element[:value_parameters] ? element[:value_parameters].collect { |e| subcontext.eval_element(e) } : []
328
- key_parameters = element[:key_parameters] ? element[:key_parameters].collect { |k, e| [k, subcontext.eval_element(e)] }.to_h : {}
327
+ value_parameters = element[:value_parameters] ?
328
+ element[:value_parameters].collect { |e| subcontext.eval_element(e) } :
329
+ []
330
+
331
+ key_parameters = element[:key_parameters] ?
332
+ element[:key_parameters].collect { |k, e| [k, subcontext.eval_element(e)] }.to_h :
333
+ {}
329
334
 
330
335
  { current_operation: :event,
331
336
  current_event: element[:event],
@@ -7,181 +7,82 @@ module Musa; module Sequencer
7
7
  class BaseSequencer
8
8
  private def _play_timed(timed_serie,
9
9
  control,
10
- reference: nil,
11
- step: nil,
12
- right_open: nil,
13
10
  &block)
14
11
 
15
- reference ||= 0r
16
- step ||= 1r
17
-
18
12
  if first_value_sample = timed_serie.peek_next_value
19
-
20
13
  debug "_play_timed: first_value_sample #{first_value_sample}"
21
14
 
22
15
  hash_mode = first_value_sample[:value].is_a?(Hash)
23
16
 
24
17
  if hash_mode
25
- components = first_value_sample[:value].keys
26
-
27
- reference = reference.hashify(keys: components)
28
- step = step.hashify(keys: components)
29
- right_open = right_open.hashify(keys:components)
18
+ component_ids = first_value_sample[:value].keys
30
19
  else
31
20
  size = first_value_sample[:value].size
32
- components = (0 .. size-1).to_a
33
-
34
- reference = reference.arrayfy(size: size)
35
- step = step.arrayfy(size: size)
36
- right_open = right_open.arrayfy(size: size)
37
- end
38
-
39
- split = timed_serie.flatten_timed.split
40
- quantized_series = hash_mode ? {} : []
41
-
42
- components.each do |component|
43
- quantized_series[component] =
44
- QUANTIZE(split[component],
45
- reference: reference[component],
46
- step: step[component],
47
- right_open: right_open[component],
48
- stops: true).instance
21
+ component_ids = (0 .. size-1).to_a
49
22
  end
23
+ extra_attribute_names = Set[*(first_value_sample.keys - [:time, :value])]
50
24
 
51
25
  last_positions = hash_mode ? {} : []
52
26
  end
53
27
 
54
28
  binder = SmartProcBinder.new(block)
55
29
 
56
- _play_timed_step(hash_mode, components, quantized_series, position, last_positions, binder, control)
30
+ _play_timed_step(hash_mode, component_ids, extra_attribute_names, timed_serie,
31
+ position, last_positions, binder, control)
57
32
  end
58
33
 
59
-
60
- private def _play_timed_step(hash_mode, components, quantized_series, start_position, last_positions,
34
+ private def _play_timed_step(hash_mode,
35
+ component_ids, extra_attribute_names,
36
+ timed_serie,
37
+ start_position,
38
+ last_positions,
61
39
  binder, control)
62
40
 
63
- affected_components_by_time = {}
64
-
65
- components.each do |component|
66
- if v = quantized_series[component].peek_next_value
41
+ source_next_value = timed_serie.next_value
67
42
 
68
- debug "_play_timed_step: quantized_series[#{component}].peek_next_value #{v}"
69
- time = v[:time]
70
-
71
- affected_components_by_time[time] ||= []
72
- affected_components_by_time[time] << component
73
- end
74
- end
43
+ affected_components = component_ids.select { |_| !source_next_value[:value][_].nil? } if source_next_value
75
44
 
76
- if affected_components_by_time.any?
77
- time = affected_components_by_time.keys.sort.first
45
+ if affected_components && affected_components.any?
46
+ time = source_next_value[:time]
78
47
 
79
48
  values = hash_mode ? {} : []
80
- next_values = hash_mode ? {} : []
81
- durations = hash_mode ? {} : []
82
- q_durations = hash_mode ? {} : []
49
+ extra_attributes = extra_attribute_names.collect { |_| [_, hash_mode ? {} : []] }.to_h
83
50
  started_ago = hash_mode ? {} : []
84
51
 
85
- affected_components_by_time[time].each do |component|
86
- value = quantized_series[component].next_value
87
-
88
- values[component] = value[:value]
89
- durations[component] = value[:duration]
90
-
91
- q_durations[component] =
92
- _quantize_position(time + durations[component], warn: false) -
93
- _quantize_position(time, warn: false)
52
+ affected_components.each do |component|
53
+ values[component] = source_next_value[:value][component]
94
54
 
95
- nv = quantized_series[component].peek_next_value
96
- next_values[component] = (nv && nv[:value] != values[component]) ? nv[:value] : nil
55
+ extra_attribute_names.each do |attribute_name|
56
+ extra_attributes[attribute_name][component] = source_next_value[attribute_name][component]
57
+ end
97
58
 
98
59
  last_positions[component] = _quantize_position(time, warn: false)
99
60
  end
100
61
 
101
- components.each do |component|
62
+ component_ids.each do |component|
102
63
  if last_positions[component] && last_positions[component] != time
103
64
  sa = _quantize_position(time, warn: false) - last_positions[component]
104
65
  started_ago[component] = (sa == 0) ? nil : sa
105
66
  end
106
67
  end
107
68
 
108
- _numeric_at start_position + _quantize_position(time, warn: false), control do
109
- debug "_play_timed_step: before binder.call: durations #{durations} q_durations #{q_durations}"
110
- binder.call(values, next_values,
111
- duration: durations,
112
- quantized_duration: q_durations,
69
+ _numeric_at _quantize_position(start_position + time, warn: true), control do
70
+ binder.call(values,
71
+ **extra_attributes,
72
+ time: start_position + time,
113
73
  started_ago: started_ago,
114
74
  control: control)
115
75
 
116
- _play_timed_step(hash_mode, components, quantized_series, start_position, last_positions,
76
+ _play_timed_step(hash_mode,
77
+ component_ids, extra_attribute_names,
78
+ timed_serie,
79
+ start_position,
80
+ last_positions,
117
81
  binder, control)
118
82
  end
119
83
  end
120
84
  end
121
85
 
122
- # TODO implement this alternative play method as another mode
123
- # Este es un modo muy interesante pero que implica un procesamiento diferente en el yield_block que no me
124
- # sirve para el código de samples/multidim_sample, puesto que en este el next_values es literal,
125
- # mientras que samples/multidim_sample necesita que el next_value sea nil si el valor no cambia durante el periodo.
126
- #
127
- private def _play_timed_step_b(hash_mode, components, quantized_series, start_position, last_positions,
128
- binder, control)
129
-
130
- affected_components_by_time = {}
131
-
132
- components.each do |component|
133
- if v = quantized_series[component].peek_next_value
134
- time = v[:time]
135
-
136
- affected_components_by_time[time] ||= []
137
- affected_components_by_time[time] << component
138
- end
139
- end
140
-
141
- if !affected_components_by_time.empty?
142
- time = affected_components_by_time.keys.sort.first
143
-
144
- values = hash_mode ? {} : []
145
- next_values = hash_mode ? {} : []
146
- durations = hash_mode ? {} : []
147
- q_durations = hash_mode ? {} : []
148
- started_ago = hash_mode ? {} : []
149
-
150
- affected_components_by_time[time].each do |component|
151
- value = quantized_series[component].next_value
152
-
153
- values[component] = value[:value]
154
- durations[component] = value[:duration]
155
-
156
- q_durations[component] =
157
- _quantize_position(time + durations[component], warn: false) -
158
- _quantize_position(time, warn: false)
159
-
160
- last_positions[component] = _quantize_position(time, warn: false)
161
- end
162
-
163
- components.each do |component|
164
- nv = quantized_series[component].peek_next_value
165
- next_values[component] = nv[:value] if nv
166
-
167
- if last_positions[component] && last_positions[component] != time
168
- started_ago[component] = _quantize_position(time, warn: false) - last_positions[component]
169
- end
170
- end
171
-
172
- _numeric_at start_position + _quantize_position(time, warn: false), control do
173
- binder.call(values, next_values,
174
- duration: durations,
175
- quantized_duration: q_durations,
176
- started_ago: started_ago,
177
- control: control)
178
-
179
- _play_timed_step_b(hash_mode, components, quantized_series, start_position, last_positions,
180
- binder, control)
181
- end
182
- end
183
- end
184
-
185
86
  class PlayTimedControl < EventHandler
186
87
  attr_reader :do_on_stop, :do_after
187
88