musa-dsl 0.21.1 → 0.22.1

Sign up to get free protection for your applications and to get access to all the features.
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
-