musa-dsl 0.21.3 → 0.22.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) 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/repl/repl.rb +4 -8
  15. data/lib/musa-dsl/sequencer/base-sequencer-implementation-every.rb +87 -0
  16. data/lib/musa-dsl/sequencer/base-sequencer-implementation-move.rb +439 -0
  17. data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-helper.rb +3 -3
  18. data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-timed.rb +210 -0
  19. data/lib/musa-dsl/sequencer/base-sequencer-implementation-play.rb +178 -0
  20. data/lib/musa-dsl/sequencer/base-sequencer-implementation.rb +150 -595
  21. data/lib/musa-dsl/sequencer/base-sequencer-public.rb +58 -5
  22. data/lib/musa-dsl/sequencer/base-sequencer-tick-based.rb +5 -9
  23. data/lib/musa-dsl/sequencer/base-sequencer-tickless-based.rb +1 -5
  24. data/lib/musa-dsl/sequencer/sequencer-dsl.rb +11 -2
  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 +95 -0
  28. data/lib/musa-dsl/series/holder-serie.rb +1 -1
  29. data/lib/musa-dsl/series/main-serie-constructors.rb +29 -83
  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 +7 -2
  35. data/lib/musa-dsl/transport/input-midi-clock.rb +19 -12
  36. data/lib/musa-dsl/transport/transport.rb +6 -6
  37. data/musa-dsl.gemspec +2 -2
  38. metadata +10 -4
  39. data/lib/musa-dsl/sequencer/base-sequencer-implementation-control.rb +0 -216
  40. 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,14 @@ 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'
@@ -4,13 +4,20 @@ require 'nibbler'
4
4
  module Musa
5
5
  module Clock
6
6
  class InputMidiClock < Clock
7
- def initialize(input, do_log: nil)
7
+ def initialize(input, logger: nil, do_log: nil)
8
8
  do_log ||= false
9
9
 
10
10
  super()
11
11
 
12
12
  @input = input
13
- @do_log = do_log
13
+ @logger = logger
14
+
15
+ if logger
16
+ @logger = logger
17
+ else
18
+ @logger = Musa::Logger::Logger.new
19
+ @logger.debug! if do_log
20
+ end
14
21
 
15
22
  @nibbler = Nibbler.new
16
23
  end
@@ -52,7 +59,7 @@ module Musa
52
59
  messages[index + 1].name == 'Song Position Pointer' &&
53
60
  messages[index + 2].name == 'Continue'
54
61
 
55
- warn 'InputMidiClock: processing Stop + Song Position Pointer + Continue...' if @do_log
62
+ @logger.debug('InputMidiClock') { 'processing Stop + Song Position Pointer + Continue...' }
56
63
 
57
64
  process_start unless @started
58
65
 
@@ -62,7 +69,7 @@ module Musa
62
69
 
63
70
  index += 2
64
71
 
65
- warn 'InputMidiClock: processing Stop + Song Position Pointer + Continue... done' if @do_log
72
+ @logger.debug('InputMidiClock') { 'processing Stop + Song Position Pointer + Continue... done' }
66
73
 
67
74
  else
68
75
  process_message messages[index] do
@@ -84,12 +91,12 @@ module Musa
84
91
  private
85
92
 
86
93
  def process_start
87
- warn 'InputMidiClock: processing Start...' if @do_log
94
+ @logger.debug('InputMidiClock') { 'processing Start...' }
88
95
 
89
96
  @on_start.each(&:call)
90
97
  @started = true
91
98
 
92
- warn 'InputMidiClock: processing Start... done' if @do_log
99
+ @logger.debug('InputMidiClock') { 'processing Start... done' }
93
100
  end
94
101
 
95
102
  def process_message(m)
@@ -98,16 +105,16 @@ module Musa
98
105
  process_start
99
106
 
100
107
  when 'Stop'
101
- warn 'InputMidiClock: processing Stop...' if @do_log
108
+ @logger.debug('InputMidiClock') { 'processing Stop...' }
102
109
 
103
110
  @on_stop.each(&:call)
104
111
  @started = false
105
112
 
106
- warn 'InputMidiClock: processing Stop... done' if @do_log
113
+ @logger.debug('InputMidiClock') { 'processing Stop... done' }
107
114
 
108
115
  when 'Continue'
109
- warn 'InputMidiClock: processing Continue...' if @do_log
110
- warn 'InputMidiClock: processing Continue... done' if @do_log
116
+ @logger.debug('InputMidiClock') { 'processing Continue...' }
117
+ @logger.debug('InputMidiClock') { 'processing Continue... done' }
111
118
 
112
119
  when 'Clock'
113
120
  yield if block_given? && @started
@@ -116,9 +123,9 @@ module Musa
116
123
  new_position_in_midi_beats =
117
124
  m.data[0] & 0x7F | ((m.data[1] & 0x7F) << 7)
118
125
 
119
- warn "InputMidiClock: processing Song Position Pointer new_position_in_midi_beats #{new_position_in_midi_beats}..." if @do_log
126
+ @logger.debug('InputMidiClock') { "processing Song Position Pointer new_position_in_midi_beats #{new_position_in_midi_beats}..." }
120
127
  @on_change_position.each { |block| block.call midi_beats: new_position_in_midi_beats }
121
- warn "InputMidiClock: processing Song Position Pointer new_position_in_beats #{new_position_in_midi_beats}... done" if @do_log
128
+ @logger.debug('InputMidiClock') { "processing Song Position Pointer new_position_in_beats #{new_position_in_midi_beats}... done" }
122
129
  end
123
130
  end
124
131
  end
@@ -126,21 +126,21 @@ module Musa
126
126
  private
127
127
 
128
128
  def do_before_begin
129
- logger.debug('Transport') { 'doing before_begin initialization...' unless @before_begin.empty? }
129
+ logger.debug('Transport') { 'doing before_begin initialization...' } unless @before_begin.empty?
130
130
  @before_begin.each { |block| block.call @sequencer }
131
- logger.debug('Transport') { 'doing before_begin initialization... done' unless @before_begin.empty? }
131
+ logger.debug('Transport') { 'doing before_begin initialization... done' } unless @before_begin.empty?
132
132
  end
133
133
 
134
134
  def do_on_start
135
- logger.debug('Transport') { 'starting...' unless @on_start.empty? }
135
+ logger.debug('Transport') { 'starting...' } unless @on_start.empty?
136
136
  @on_start.each { |block| block.call @sequencer }
137
- logger.debug('Transport') { 'starting... done' unless @on_start.empty? }
137
+ logger.debug('Transport') { 'starting... done' } unless @on_start.empty?
138
138
  end
139
139
 
140
140
  def do_stop
141
- logger.debug('Transport') { 'stopping...' unless @after_stop.empty? }
141
+ logger.debug('Transport') { 'stopping...' } unless @after_stop.empty?
142
142
  @after_stop.each { |block| block.call @sequencer }
143
- logger.debug('Transport') { 'stopping... done' unless @after_stop.empty? }
143
+ logger.debug('Transport') { 'stopping... done' } unless @after_stop.empty?
144
144
 
145
145
  logger.debug('Transport') { 'resetting sequencer...' }
146
146
  @sequencer.reset
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'musa-dsl'
3
- s.version = '0.21.3'
4
- s.date = '2020-10-20'
3
+ s.version = '0.22.2'
4
+ s.date = '2020-11-11'
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.3
4
+ version: 0.22.2
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-20 00:00:00.000000000 Z
11
+ date: 2020-11-11 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,8 +164,11 @@ 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
173
  - lib/musa-dsl/sequencer/base-sequencer-public.rb
170
174
  - lib/musa-dsl/sequencer/base-sequencer-tick-based.rb
@@ -175,11 +179,13 @@ files:
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
185
191
  - lib/musa-dsl/transcription.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