musa-dsl 0.21.1 → 0.22.1

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 (41) 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/midi/midi-voices.rb +4 -0
  15. data/lib/musa-dsl/repl/repl.rb +30 -11
  16. data/lib/musa-dsl/sequencer/base-sequencer-implementation-every.rb +87 -0
  17. data/lib/musa-dsl/sequencer/base-sequencer-implementation-move.rb +439 -0
  18. data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-helper.rb +3 -3
  19. data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-timed.rb +210 -0
  20. data/lib/musa-dsl/sequencer/base-sequencer-implementation-play.rb +178 -0
  21. data/lib/musa-dsl/sequencer/base-sequencer-implementation.rb +150 -595
  22. data/lib/musa-dsl/sequencer/base-sequencer-public.rb +58 -5
  23. data/lib/musa-dsl/sequencer/base-sequencer-tick-based.rb +5 -9
  24. data/lib/musa-dsl/sequencer/base-sequencer-tickless-based.rb +1 -5
  25. data/lib/musa-dsl/sequencer/sequencer-dsl.rb +8 -0
  26. data/lib/musa-dsl/series/base-series.rb +43 -78
  27. data/lib/musa-dsl/series/flattener-timed-serie.rb +61 -0
  28. data/lib/musa-dsl/series/hash-or-array-serie-splitter.rb +95 -0
  29. data/lib/musa-dsl/series/holder-serie.rb +1 -1
  30. data/lib/musa-dsl/series/main-serie-constructors.rb +29 -83
  31. data/lib/musa-dsl/series/main-serie-operations.rb +60 -215
  32. data/lib/musa-dsl/series/proxy-serie.rb +1 -1
  33. data/lib/musa-dsl/series/quantizer-serie.rb +546 -0
  34. data/lib/musa-dsl/series/queue-serie.rb +1 -1
  35. data/lib/musa-dsl/series/series.rb +7 -2
  36. data/lib/musa-dsl/transport/input-midi-clock.rb +19 -12
  37. data/lib/musa-dsl/transport/transport.rb +25 -12
  38. data/musa-dsl.gemspec +2 -2
  39. metadata +10 -4
  40. data/lib/musa-dsl/sequencer/base-sequencer-implementation-control.rb +0 -216
  41. 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
@@ -1,6 +1,9 @@
1
1
  require_relative '../core-ext/smart-proc-binder'
2
+ require_relative '../core-ext/inspect-nice'
2
3
  require_relative '../sequencer'
3
4
 
5
+ using Musa::Extension::InspectNice
6
+
4
7
  module Musa
5
8
  module Transport
6
9
  class Transport
@@ -15,6 +18,7 @@ module Musa
15
18
  on_start: nil,
16
19
  after_stop: nil,
17
20
  on_position_change: nil,
21
+ logger: nil,
18
22
  do_log: nil)
19
23
 
20
24
  beats_per_bar ||= 4
@@ -37,7 +41,7 @@ module Musa
37
41
 
38
42
  @do_log = do_log
39
43
 
40
- @sequencer = Sequencer::Sequencer.new beats_per_bar, ticks_per_beat, do_log: @do_log
44
+ @sequencer = Sequencer::Sequencer.new beats_per_bar, ticks_per_beat, logger: logger, do_log: @do_log
41
45
 
42
46
  @clock.on_start do
43
47
  do_on_start
@@ -78,15 +82,20 @@ module Musa
78
82
  end
79
83
 
80
84
  def change_position_to(bars: nil, beats: nil, midi_beats: nil)
81
- warn "Transport: asked to change position to #{"#{bars} bars " if bars}#{"#{beats} beats " if beats}#{"#{midi_beats} midi beats " if midi_beats}" if @do_log
85
+ logger.debug('Transport') do
86
+ "asked to change position to #{"#{bars} bars " if bars}#{"#{beats} beats " if beats}" \
87
+ "#{"#{midi_beats} midi beats " if midi_beats}"
88
+ end
82
89
 
83
90
  position = bars&.rationalize || 1r
84
91
  position += Rational(midi_beats, 4 * @sequencer.beats_per_bar) if midi_beats
85
92
  position += Rational(beats, @sequencer.beats_per_bar) if beats
86
93
 
94
+ position -= @sequencer.tick_duration
95
+
87
96
  raise ArgumentError, "undefined new position" unless position
88
97
 
89
- warn "Transport: received message position change to #{position}" if @do_log
98
+ logger.debug('Transport') { "received message position change to #{position.inspect}" }
90
99
 
91
100
  start_again_later = false
92
101
 
@@ -95,7 +104,7 @@ module Musa
95
104
  start_again_later = true
96
105
  end
97
106
 
98
- warn "Transport: setting sequencer position #{position}" if @do_log
107
+ logger.debug('Transport') { "setting sequencer position #{position.inspect}" }
99
108
 
100
109
  @sequencer.raw_at position, force_first: true do
101
110
  @on_change_position.each { |block| block.call @sequencer }
@@ -110,28 +119,32 @@ module Musa
110
119
  @clock.terminate
111
120
  end
112
121
 
122
+ def logger
123
+ @sequencer.logger
124
+ end
125
+
113
126
  private
114
127
 
115
128
  def do_before_begin
116
- warn 'Transport: doing before_begin initialization...' unless @before_begin.empty? || !@do_log
129
+ logger.debug('Transport') { 'doing before_begin initialization...' } unless @before_begin.empty?
117
130
  @before_begin.each { |block| block.call @sequencer }
118
- warn 'Transport: doing before_begin initialization... done' unless @before_begin.empty? || !@do_log
131
+ logger.debug('Transport') { 'doing before_begin initialization... done' } unless @before_begin.empty?
119
132
  end
120
133
 
121
134
  def do_on_start
122
- warn 'Transport: starting...' unless @on_start.empty? || !@do_log
135
+ logger.debug('Transport') { 'starting...' } unless @on_start.empty?
123
136
  @on_start.each { |block| block.call @sequencer }
124
- warn 'Transport: starting... done' unless @on_start.empty? || !@do_log
137
+ logger.debug('Transport') { 'starting... done' } unless @on_start.empty?
125
138
  end
126
139
 
127
140
  def do_stop
128
- warn 'Transport: stoping...' unless @after_stop.empty? || !@do_log
141
+ logger.debug('Transport') { 'stopping...' } unless @after_stop.empty?
129
142
  @after_stop.each { |block| block.call @sequencer }
130
- warn 'Transport: stoping... done' unless @after_stop.empty? || !@do_log
143
+ logger.debug('Transport') { 'stopping... done' } unless @after_stop.empty?
131
144
 
132
- warn 'Transport: resetting sequencer...' if @do_log
145
+ logger.debug('Transport') { 'resetting sequencer...' }
133
146
  @sequencer.reset
134
- warn 'Transport: resetting sequencer... done' if @do_log
147
+ logger.debug('Transport') { 'resetting sequencer... done' }
135
148
 
136
149
  do_before_begin
137
150
  @before_begin_already_done = true
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'musa-dsl'
3
- s.version = '0.21.1'
4
- s.date = '2020-10-09'
3
+ s.version = '0.22.1'
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.1
4
+ version: 0.22.1
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-09 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
-