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
@@ -32,7 +32,7 @@ module Musa
32
32
  self
33
33
  end
34
34
 
35
- def _prototype
35
+ def _prototype!
36
36
  raise PrototypingSerieError, 'Cannot get prototype of a proxy serie'
37
37
  end
38
38
 
@@ -2,9 +2,15 @@ require_relative 'base-series'
2
2
 
3
3
  require_relative 'main-serie-constructors'
4
4
  require_relative 'main-serie-operations'
5
- require_relative 'hash-serie-splitter'
5
+
6
+ require_relative 'array-to-serie'
7
+
6
8
  require_relative 'holder-serie'
7
9
  require_relative 'proxy-serie'
8
10
  require_relative 'queue-serie'
9
11
 
10
- require_relative 'array-to-serie'
12
+ require_relative 'hash-or-array-serie-splitter'
13
+
14
+ require_relative 'quantizer-serie'
15
+ require_relative 'flattener-timed-serie'
16
+ require_relative 'union-timed-series'
@@ -0,0 +1,109 @@
1
+ require_relative '../datasets/e'
2
+
3
+ module Musa
4
+ module Series
5
+
6
+ extend self
7
+
8
+ def TIMED_UNION(*timed_series)
9
+ TimedUnion.new(timed_series)
10
+ end
11
+
12
+ class TimedUnion
13
+ include Serie
14
+
15
+ attr_reader :sources
16
+
17
+ def initialize(series)
18
+ @sources = if series[0].prototype?
19
+ series.collect(&:prototype).freeze
20
+ else
21
+ series.collect(&:instance)
22
+ end
23
+
24
+ _restart false
25
+
26
+ mark_regarding! series[0]
27
+ end
28
+
29
+ private def _restart(restart_sources = true)
30
+ @sources.each { |serie| serie.restart } if restart_sources
31
+ @sources_next_values = Array.new(@sources.size)
32
+
33
+ @components = nil
34
+ @hash_mode = @array_mode = nil
35
+ end
36
+
37
+ private def _next_value
38
+ sources_values = @sources_next_values.each_index.collect do |i|
39
+ @sources_next_values[i] || (@sources_next_values[i] = @sources[i].next_value)
40
+ end
41
+
42
+ infer_components(sources_values) if !@components
43
+
44
+ time = sources_values.collect { |_| _&.[](:time) }.compact.min
45
+
46
+ if time
47
+ selected_values = sources_values.collect { |_| _ if _&.[](:time) == time }
48
+
49
+ @sources_next_values.each_index do |i|
50
+ if @sources_next_values[i]&.[](:time) == time
51
+ @sources_next_values[i] = nil
52
+ end
53
+ end
54
+
55
+ if @hash_mode
56
+ result = {}
57
+ elsif @array_mode
58
+ result = []
59
+ else # value mode
60
+ result = []
61
+ end
62
+
63
+ @components.each do |target_key_or_index, source_placement|
64
+ result[target_key_or_index] = selected_values.dig(*source_placement)
65
+ end
66
+
67
+ { time: time,
68
+ value: result }
69
+ else
70
+ nil
71
+ end
72
+ end
73
+
74
+ def infinite?
75
+ !!@sources.find(&:infinite?)
76
+ end
77
+ end
78
+
79
+ private def infer_components(sources_values)
80
+ @components = {}
81
+ target_index = 0
82
+
83
+ sources_values.each_with_index do |source_value, i|
84
+ case source_value[:value]
85
+ when Hash
86
+ @hash_mode = true
87
+
88
+ source_value[:value].keys.each do |key|
89
+ @components[key] = [i, :value, key]
90
+ end
91
+ when Array
92
+ @array_mode = true
93
+
94
+ (0..source_value[:value].size - 1).each do |index|
95
+ @components[target_index] = [i, :value, index]
96
+ target_index += 1
97
+ end
98
+ else
99
+ @components[target_index] = [i, :value]
100
+ target_index += 1
101
+ end
102
+ end
103
+
104
+ raise RuntimeError, "source series values are of incompatible type (can't combine Hash and Array values)" if @array_mode && @hash_mode
105
+ end
106
+
107
+ private_constant :TimedUnion
108
+ end
109
+ end
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'musa-dsl'
3
- s.version = '0.21.5'
4
- s.date = '2020-10-21'
3
+ s.version = '0.22.4'
4
+ s.date = '2020-11-14'
5
5
  s.summary = 'A simple Ruby DSL for making complex music'
6
6
  s.description = 'Musa-DSL: A Ruby DSL for algorithmic music composition, device language neutral (MIDI, OSC, etc)'
7
7
  s.authors = ['Javier Sánchez Yeste']
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: musa-dsl
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.21.5
4
+ version: 0.22.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Javier Sánchez Yeste
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-10-21 00:00:00.000000000 Z
11
+ date: 2020-11-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: citrus
@@ -89,6 +89,7 @@ files:
89
89
  - lib/musa-dsl/core-ext/attribute-builder.rb
90
90
  - lib/musa-dsl/core-ext/deep-copy.rb
91
91
  - lib/musa-dsl/core-ext/dynamic-proxy.rb
92
+ - lib/musa-dsl/core-ext/hashify.rb
92
93
  - lib/musa-dsl/core-ext/inspect-nice.rb
93
94
  - lib/musa-dsl/core-ext/smart-proc-binder.rb
94
95
  - lib/musa-dsl/core-ext/with.rb
@@ -163,25 +164,31 @@ files:
163
164
  - lib/musa-dsl/repl.rb
164
165
  - lib/musa-dsl/repl/repl.rb
165
166
  - lib/musa-dsl/sequencer.rb
166
- - lib/musa-dsl/sequencer/base-sequencer-implementation-control.rb
167
+ - lib/musa-dsl/sequencer/base-sequencer-implementation-every.rb
168
+ - lib/musa-dsl/sequencer/base-sequencer-implementation-move.rb
167
169
  - lib/musa-dsl/sequencer/base-sequencer-implementation-play-helper.rb
170
+ - lib/musa-dsl/sequencer/base-sequencer-implementation-play-timed.rb
171
+ - lib/musa-dsl/sequencer/base-sequencer-implementation-play.rb
168
172
  - lib/musa-dsl/sequencer/base-sequencer-implementation.rb
169
- - lib/musa-dsl/sequencer/base-sequencer-public.rb
170
173
  - lib/musa-dsl/sequencer/base-sequencer-tick-based.rb
171
174
  - lib/musa-dsl/sequencer/base-sequencer-tickless-based.rb
175
+ - lib/musa-dsl/sequencer/base-sequencer.rb
172
176
  - lib/musa-dsl/sequencer/sequencer-dsl.rb
173
177
  - lib/musa-dsl/sequencer/sequencer.rb
174
178
  - lib/musa-dsl/sequencer/timeslots.rb
175
179
  - lib/musa-dsl/series.rb
176
180
  - lib/musa-dsl/series/array-to-serie.rb
177
181
  - lib/musa-dsl/series/base-series.rb
178
- - lib/musa-dsl/series/hash-serie-splitter.rb
182
+ - lib/musa-dsl/series/flattener-timed-serie.rb
183
+ - lib/musa-dsl/series/hash-or-array-serie-splitter.rb
179
184
  - lib/musa-dsl/series/holder-serie.rb
180
185
  - lib/musa-dsl/series/main-serie-constructors.rb
181
186
  - lib/musa-dsl/series/main-serie-operations.rb
182
187
  - lib/musa-dsl/series/proxy-serie.rb
188
+ - lib/musa-dsl/series/quantizer-serie.rb
183
189
  - lib/musa-dsl/series/queue-serie.rb
184
190
  - lib/musa-dsl/series/series.rb
191
+ - lib/musa-dsl/series/union-timed-series.rb
185
192
  - lib/musa-dsl/transcription.rb
186
193
  - lib/musa-dsl/transcription/from-gdv-to-midi.rb
187
194
  - lib/musa-dsl/transcription/from-gdv-to-musicxml.rb
@@ -1,216 +0,0 @@
1
- require 'forwardable'
2
-
3
- module Musa
4
- module Sequencer
5
- class BaseSequencer
6
- class EventHandler
7
- include Musa::Extension::SmartProcBinder
8
-
9
- attr_accessor :continue_parameters
10
-
11
- @@counter = 0
12
-
13
- def initialize(parent = nil)
14
- @id = (@@counter += 1)
15
-
16
- @parent = parent
17
- @handlers = {}
18
-
19
- @stop = false
20
- end
21
-
22
- def stop
23
- @stop = true
24
- end
25
-
26
- def stopped?
27
- @stop
28
- end
29
-
30
- def pause
31
- raise NotImplementedError
32
- end
33
-
34
- def continue
35
- @paused = false
36
- end
37
-
38
- def paused?
39
- @paused
40
- end
41
-
42
- def on(event, name: nil, only_once: nil, &block)
43
- only_once ||= false
44
-
45
- @handlers[event] ||= {}
46
-
47
- # TODO: add on_rescue: proc { |e| _rescue_block_error(e) } [this method is on Sequencer, not in EventHandler]
48
- @handlers[event][name] = {block: SmartProcBinder.new(block), only_once: only_once }
49
- end
50
-
51
- def launch(event, *value_parameters, **key_parameters)
52
- _launch event, value_parameters, key_parameters
53
- end
54
-
55
- def _launch(event, value_parameters = nil, key_parameters = nil)
56
- value_parameters ||= []
57
- key_parameters ||= {}
58
- processed = false
59
-
60
- if @handlers.key? event
61
- @handlers[event].each do |name, handler|
62
- handler[:block].call *value_parameters, **key_parameters
63
- @handlers[event].delete name if handler[:only_once]
64
- processed = true
65
- end
66
- end
67
-
68
- @parent._launch event, value_parameters, key_parameters if @parent && !processed
69
- end
70
-
71
- def inspect
72
- "EventHandler #{id}"
73
- end
74
-
75
- def id
76
- if @parent
77
- "#{@parent.id}.#{self.class.name.split('::').last}-#{@id}"
78
- else
79
- "#{self.class.name.split('::').last}-#{@id.to_s}"
80
- end
81
- end
82
-
83
- alias to_s inspect
84
- end
85
-
86
- private_constant :EventHandler
87
-
88
- class PlayControl < EventHandler
89
- attr_reader :do_after
90
-
91
- def initialize(parent, after: nil)
92
- super parent
93
-
94
- @do_after = []
95
-
96
- self.after &after if after
97
- end
98
-
99
- def pause
100
- @paused = true
101
- end
102
-
103
- def store_continuation(sequencer:, serie:, nl_context:, mode:, decoder:, play_eval:, mode_args:)
104
- @continuation_sequencer = sequencer
105
- @continuation_parameters = {
106
- serie: serie,
107
- control: self,
108
- nl_context: nl_context,
109
- mode: mode,
110
- decoder: decoder,
111
- play_eval: play_eval,
112
- mode_args: mode_args
113
- }
114
- end
115
-
116
- def continue
117
- super
118
- @continuation_sequencer.continuation_play(@continuation_parameters) if @continuation_sequencer
119
- end
120
-
121
- def after(_bars = nil, &block)
122
- # TODO implementar parámetro _bars (?)
123
- @do_after << block
124
- end
125
- end
126
-
127
- private_constant :PlayControl
128
-
129
- class EveryControl < EventHandler
130
- attr_reader :duration_value, :till_value, :condition_block, :do_on_stop, :do_after
131
-
132
- attr_accessor :_start_position
133
- attr_accessor :_execution_counter
134
-
135
- def initialize(parent, duration: nil, till: nil, condition: nil, on_stop: nil, after_bars: nil, after: nil)
136
- super parent
137
-
138
- @duration_value = duration
139
- @till_value = till
140
- @condition_block = condition
141
-
142
- @do_on_stop = []
143
- @do_after = []
144
-
145
- @do_on_stop << on_stop if on_stop
146
-
147
- self.after after_bars, &after if after
148
- end
149
-
150
- def duration(value)
151
- @duration_value = value.rationalize
152
- end
153
-
154
- def till(value)
155
- @till_value = value.rationalize
156
- end
157
-
158
- def condition(&block)
159
- @condition_block = block
160
- end
161
-
162
- def on_stop(&block)
163
- @do_on_stop << block
164
- end
165
-
166
- def after(bars = nil, &block)
167
- bars ||= 0
168
- @do_after << { bars: bars.rationalize, block: block }
169
- end
170
- end
171
-
172
- private_constant :EveryControl
173
-
174
- class MoveControl < EventHandler
175
- attr_reader :every_control, :do_on_stop, :do_after
176
-
177
- def initialize(parent, duration: nil, till: nil, on_stop: nil, after_bars: nil, after: nil)
178
- super parent
179
-
180
- @every_control = EveryControl.new(self, duration: duration, till: till)
181
-
182
- @do_on_stop = []
183
- @do_after = []
184
-
185
- @do_on_stop << on_stop if on_stop
186
- self.after after_bars, &after if after
187
-
188
- @every_control.on_stop do
189
- @stop = true
190
- @do_on_stop.each(&:call)
191
- end
192
- end
193
-
194
- def on_stop(&block)
195
- @do_on_stop << block
196
- end
197
-
198
- def after(bars = nil, &block)
199
- bars ||= 0
200
- @do_after << { bars: bars.rationalize, block: block }
201
- end
202
-
203
- def stop
204
- @every_control.stop
205
- end
206
-
207
- def stopped?
208
- @stop
209
- end
210
- end
211
-
212
- private_constant :MoveControl
213
- end
214
- end
215
- end
216
-
@@ -1,196 +0,0 @@
1
- module Musa
2
- # TODO: adapt to series prototyping
3
- # TODO: full test cases
4
-
5
- module Series
6
- module SerieOperations
7
- def split(buffered: nil, master: nil)
8
- buffered ||= false
9
-
10
- return HashSplitter.new HashSplitter::KeyProxy.new(self) if master.nil? && !buffered
11
- return HashSplitter.new HashSplitter::MasterSlaveKeyProxy.new(self, master) if !master.nil? && !buffered
12
- return HashSplitter.new HashSplitter::BufferedKeyProxy.new(self) if buffered
13
- end
14
-
15
- class HashSplitter
16
- def initialize(proxy)
17
- @proxy = proxy
18
- @series = {}
19
- end
20
-
21
- def [](key)
22
- serie = if @series.key? key
23
- @series[key]
24
- else
25
- @series[key] = Splitted.new(@proxy, key: key)
26
- end
27
- end
28
-
29
- class KeyProxy
30
- def initialize(hash_serie)
31
- @serie = hash_serie.instance
32
- @values = {}
33
- end
34
-
35
- def restart
36
- @serie.restart
37
- @values = {}
38
- end
39
-
40
- def next_value(key)
41
- return nil unless @values
42
-
43
- value = @values[key]
44
-
45
- if value.nil?
46
- before_values = @values.collect { |k, v| [k, v] unless v.nil? }.compact.to_h
47
-
48
- @values = @serie.next_value
49
- value = @values[key] if @values
50
-
51
- warn "Warning: splitted serie #{@serie} values #{before_values} are being lost" if !value.nil? && !before_values.empty?
52
- end
53
-
54
- @values[key] = nil if @values
55
-
56
- value
57
- end
58
-
59
- def peek_next_value(key)
60
- value = @values[key]
61
-
62
- if value.nil?
63
- peek_values = @serie.peek_next_value
64
- value = peek_values[key] if peek_values
65
- end
66
-
67
- value
68
- end
69
- end
70
-
71
- class BufferedKeyProxy
72
- def initialize(hash_serie)
73
- @serie = hash_serie.instance
74
- @values = {}
75
- end
76
-
77
- def restart
78
- @serie.restart
79
- @values = {}
80
- end
81
-
82
- def next_value(key)
83
- value = nil
84
-
85
- if @values[key].nil? || @values[key].empty?
86
- hash_value = @serie.next_value
87
-
88
- if hash_value
89
- hash_value.each do |k, v|
90
- @values[k] = [] if @values[k].nil?
91
- @values[k] << v
92
- end
93
- end
94
- end
95
-
96
- value = @values[key].shift if @values[key]
97
-
98
- value
99
- end
100
-
101
- def peek_next_value(key)
102
- value = nil
103
-
104
- if @values[key] && !@values[key].empty?
105
- value = @values[key].first
106
- else
107
- peek_values = @serie.peek_next_value
108
- value = peek_values[key] if peek_values
109
- end
110
-
111
- value
112
- end
113
- end
114
-
115
- class MasterSlaveKeyProxy
116
- def initialize(hash_serie, master)
117
- @serie = hash_serie.instance
118
- @master = master
119
- @values = {}
120
- @values_counter = {}
121
- end
122
-
123
- def restart
124
- @serie.restart
125
- @values = {}
126
- @values_counter = {}
127
- end
128
-
129
- def next_value(key)
130
- return nil unless @values
131
-
132
- value = @values[key]
133
-
134
- if value.nil?
135
- @values = @serie.next_value
136
-
137
- value = @values[key] if @values
138
-
139
- # warn "Info: splitted serie #{@serie} use count on next_value: #{@values_counter}"
140
- @values_counter = {}
141
- end
142
-
143
- @values_counter[key] ||= 0
144
- @values_counter[key] += 1
145
-
146
- @values[key] = nil if key == @master && @values
147
-
148
- value
149
- end
150
-
151
- def peek_next_value(key)
152
- return nil unless @values
153
-
154
- value = @values[key]
155
-
156
- if value.nil?
157
- peek_values = @serie.peek_next_value
158
- value = peek_values[key] if peek_values
159
- end
160
-
161
- value
162
- end
163
- end
164
-
165
- class Splitted
166
- include Serie
167
-
168
- def initialize(proxy, key:)
169
- @proxy = proxy
170
- @key = key
171
-
172
- mark_as_instance!
173
- end
174
-
175
- def _prototype
176
- raise PrototypingSerieError, 'Cannot get prototype of a splitted serie'
177
- end
178
-
179
- def _restart
180
- @proxy.restart
181
- end
182
-
183
- def next_value
184
- @proxy.next_value(@key)
185
- end
186
-
187
- def peek_next_value
188
- @proxy.peek_next_value(@key)
189
- end
190
- end
191
- end
192
-
193
- private_constant :HashSplitter
194
- end
195
- end
196
- end