musa-dsl 0.14.32 → 0.21.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (129) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -1
  3. data/README.md +5 -1
  4. data/lib/musa-dsl.rb +54 -11
  5. data/lib/musa-dsl/core-ext.rb +7 -13
  6. data/lib/musa-dsl/core-ext/array-explode-ranges.rb +15 -23
  7. data/lib/musa-dsl/core-ext/arrayfy.rb +30 -12
  8. data/lib/musa-dsl/core-ext/attribute-builder.rb +194 -0
  9. data/lib/musa-dsl/core-ext/deep-copy.rb +185 -0
  10. data/lib/musa-dsl/core-ext/dynamic-proxy.rb +44 -40
  11. data/lib/musa-dsl/core-ext/inspect-nice.rb +40 -22
  12. data/lib/musa-dsl/core-ext/smart-proc-binder.rb +108 -0
  13. data/lib/musa-dsl/core-ext/with.rb +26 -0
  14. data/lib/musa-dsl/datasets.rb +8 -3
  15. data/lib/musa-dsl/datasets/dataset.rb +3 -0
  16. data/lib/musa-dsl/datasets/delta-d.rb +12 -0
  17. data/lib/musa-dsl/datasets/e.rb +61 -0
  18. data/lib/musa-dsl/datasets/gdv.rb +51 -411
  19. data/lib/musa-dsl/datasets/gdvd.rb +179 -0
  20. data/lib/musa-dsl/datasets/helper.rb +41 -0
  21. data/lib/musa-dsl/datasets/p.rb +68 -0
  22. data/lib/musa-dsl/datasets/packed-v.rb +19 -0
  23. data/lib/musa-dsl/datasets/pdv.rb +22 -15
  24. data/lib/musa-dsl/datasets/ps.rb +113 -0
  25. data/lib/musa-dsl/datasets/score.rb +210 -0
  26. data/lib/musa-dsl/datasets/score/queriable.rb +48 -0
  27. data/lib/musa-dsl/datasets/score/render.rb +31 -0
  28. data/lib/musa-dsl/datasets/score/to-mxml/process-pdv.rb +160 -0
  29. data/lib/musa-dsl/datasets/score/to-mxml/process-ps.rb +51 -0
  30. data/lib/musa-dsl/datasets/score/to-mxml/process-time.rb +153 -0
  31. data/lib/musa-dsl/datasets/score/to-mxml/to-mxml.rb +158 -0
  32. data/lib/musa-dsl/datasets/v.rb +23 -0
  33. data/lib/musa-dsl/generative.rb +5 -5
  34. data/lib/musa-dsl/generative/backboner.rb +274 -0
  35. data/lib/musa-dsl/generative/darwin.rb +102 -96
  36. data/lib/musa-dsl/generative/generative-grammar.rb +182 -187
  37. data/lib/musa-dsl/generative/markov.rb +56 -53
  38. data/lib/musa-dsl/generative/variatio.rb +234 -222
  39. data/lib/musa-dsl/logger.rb +1 -0
  40. data/lib/musa-dsl/logger/logger.rb +31 -0
  41. data/lib/musa-dsl/matrix.rb +1 -0
  42. data/lib/musa-dsl/matrix/matrix.rb +210 -0
  43. data/lib/musa-dsl/midi.rb +2 -2
  44. data/lib/musa-dsl/midi/midi-recorder.rb +54 -52
  45. data/lib/musa-dsl/midi/midi-voices.rb +183 -182
  46. data/lib/musa-dsl/music.rb +5 -5
  47. data/lib/musa-dsl/music/chord-definition.rb +54 -50
  48. data/lib/musa-dsl/music/chord-definitions.rb +13 -9
  49. data/lib/musa-dsl/music/chords.rb +236 -238
  50. data/lib/musa-dsl/music/equally-tempered-12-tone-scale-system.rb +187 -183
  51. data/lib/musa-dsl/music/scales.rb +331 -332
  52. data/lib/musa-dsl/musicxml.rb +1 -0
  53. data/lib/musa-dsl/musicxml/builder/attributes.rb +155 -0
  54. data/lib/musa-dsl/musicxml/builder/backup-forward.rb +45 -0
  55. data/lib/musa-dsl/musicxml/builder/direction.rb +322 -0
  56. data/lib/musa-dsl/musicxml/builder/helper.rb +90 -0
  57. data/lib/musa-dsl/musicxml/builder/measure.rb +137 -0
  58. data/lib/musa-dsl/musicxml/builder/note-complexities.rb +152 -0
  59. data/lib/musa-dsl/musicxml/builder/note.rb +577 -0
  60. data/lib/musa-dsl/musicxml/builder/part-group.rb +44 -0
  61. data/lib/musa-dsl/musicxml/builder/part.rb +67 -0
  62. data/lib/musa-dsl/musicxml/builder/pitched-note.rb +126 -0
  63. data/lib/musa-dsl/musicxml/builder/rest.rb +117 -0
  64. data/lib/musa-dsl/musicxml/builder/score-partwise.rb +120 -0
  65. data/lib/musa-dsl/musicxml/builder/typed-text.rb +43 -0
  66. data/lib/musa-dsl/musicxml/builder/unpitched-note.rb +112 -0
  67. data/lib/musa-dsl/neumalang.rb +1 -1
  68. data/lib/musa-dsl/neumalang/datatypes.citrus +79 -0
  69. data/lib/musa-dsl/neumalang/neuma.citrus +165 -0
  70. data/lib/musa-dsl/neumalang/neumalang.citrus +32 -242
  71. data/lib/musa-dsl/neumalang/neumalang.rb +373 -142
  72. data/lib/musa-dsl/neumalang/process.citrus +21 -0
  73. data/lib/musa-dsl/neumalang/terminals.citrus +67 -0
  74. data/lib/musa-dsl/neumalang/vectors.citrus +23 -0
  75. data/lib/musa-dsl/neumas.rb +5 -0
  76. data/lib/musa-dsl/neumas/array-to-neumas.rb +34 -0
  77. data/lib/musa-dsl/neumas/neuma-decoder.rb +63 -0
  78. data/lib/musa-dsl/neumas/neuma-gdv-decoder.rb +57 -0
  79. data/lib/musa-dsl/neumas/neuma-gdvd-decoder.rb +15 -0
  80. data/lib/musa-dsl/neumas/neumas.rb +37 -0
  81. data/lib/musa-dsl/neumas/string-to-neumas.rb +33 -0
  82. data/lib/musa-dsl/repl.rb +1 -1
  83. data/lib/musa-dsl/repl/repl.rb +103 -110
  84. data/lib/musa-dsl/sequencer.rb +1 -1
  85. data/lib/musa-dsl/sequencer/base-sequencer-implementation-control.rb +163 -136
  86. data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-helper.rb +301 -286
  87. data/lib/musa-dsl/sequencer/base-sequencer-implementation.rb +548 -321
  88. data/lib/musa-dsl/sequencer/base-sequencer-public.rb +198 -176
  89. data/lib/musa-dsl/sequencer/base-sequencer-tick-based.rb +77 -0
  90. data/lib/musa-dsl/sequencer/base-sequencer-tickless-based.rb +75 -0
  91. data/lib/musa-dsl/sequencer/sequencer-dsl.rb +105 -85
  92. data/lib/musa-dsl/sequencer/timeslots.rb +34 -0
  93. data/lib/musa-dsl/series.rb +1 -1
  94. data/lib/musa-dsl/{core-ext → series}/array-to-serie.rb +1 -1
  95. data/lib/musa-dsl/series/base-series.rb +171 -168
  96. data/lib/musa-dsl/series/hash-serie-splitter.rb +134 -132
  97. data/lib/musa-dsl/series/holder-serie.rb +1 -1
  98. data/lib/musa-dsl/series/main-serie-constructors.rb +6 -1
  99. data/lib/musa-dsl/series/main-serie-operations.rb +807 -797
  100. data/lib/musa-dsl/series/proxy-serie.rb +6 -6
  101. data/lib/musa-dsl/series/queue-serie.rb +5 -5
  102. data/lib/musa-dsl/series/series.rb +2 -0
  103. data/lib/musa-dsl/transcription.rb +4 -0
  104. data/lib/musa-dsl/transcription/from-gdv-to-midi.rb +227 -0
  105. data/lib/musa-dsl/transcription/from-gdv-to-musicxml.rb +36 -0
  106. data/lib/musa-dsl/transcription/from-gdv.rb +17 -0
  107. data/lib/musa-dsl/transcription/transcription.rb +55 -0
  108. data/lib/musa-dsl/transport.rb +6 -6
  109. data/lib/musa-dsl/transport/clock.rb +26 -26
  110. data/lib/musa-dsl/transport/dummy-clock.rb +32 -30
  111. data/lib/musa-dsl/transport/external-tick-clock.rb +21 -20
  112. data/lib/musa-dsl/transport/input-midi-clock.rb +82 -80
  113. data/lib/musa-dsl/transport/timer-clock.rb +72 -71
  114. data/lib/musa-dsl/transport/timer.rb +28 -26
  115. data/lib/musa-dsl/transport/transport.rb +100 -95
  116. data/musa-dsl.gemspec +3 -3
  117. metadata +73 -24
  118. data/lib/musa-dsl/core-ext/array-apply-get.rb +0 -18
  119. data/lib/musa-dsl/core-ext/array-to-neumas.rb +0 -28
  120. data/lib/musa-dsl/core-ext/as-context-run.rb +0 -44
  121. data/lib/musa-dsl/core-ext/duplicate.rb +0 -134
  122. data/lib/musa-dsl/core-ext/key-parameters-procedure-binder.rb +0 -85
  123. data/lib/musa-dsl/core-ext/proc-nice.rb +0 -13
  124. data/lib/musa-dsl/core-ext/send-nice.rb +0 -21
  125. data/lib/musa-dsl/core-ext/string-to-neumas.rb +0 -27
  126. data/lib/musa-dsl/datasets/gdv-decorators.rb +0 -221
  127. data/lib/musa-dsl/generative/rules.rb +0 -282
  128. data/lib/musa-dsl/neuma.rb +0 -1
  129. data/lib/musa-dsl/neuma/neuma.rb +0 -181
@@ -1,251 +1,273 @@
1
- require 'musa-dsl/core-ext/arrayfy'
2
- require 'musa-dsl/core-ext/key-parameters-procedure-binder'
1
+ require_relative '../core-ext/arrayfy'
2
+ require_relative '../core-ext/smart-proc-binder'
3
+ require_relative '../logger'
3
4
 
4
- require 'musa-dsl/series'
5
+ require_relative '../series'
5
6
 
6
- class Musa::BaseSequencer
7
- attr_reader :beats_per_bar, :ticks_per_beat, :ticks_per_bar, :tick_duration, :running_position
8
- attr_reader :everying, :playing, :moving
7
+ require_relative 'timeslots'
9
8
 
10
- @@tick_mutex = Mutex.new
9
+ require_relative 'base-sequencer-tick-based'
10
+ require_relative 'base-sequencer-tickless-based'
11
11
 
12
- def initialize(beats_per_bar, ticks_per_beat, do_log: nil)
13
- do_log ||= false
12
+ module Musa
13
+ module Sequencer
14
+ class BaseSequencer
15
+ attr_reader :beats_per_bar, :ticks_per_beat
16
+ attr_reader :running_position
17
+ attr_reader :everying, :playing, :moving
18
+ attr_reader :logger
14
19
 
15
- @on_debug_at = []
16
- @on_block_error = []
20
+ def initialize(beats_per_bar = nil, ticks_per_beat = nil, logger: nil, do_log: nil, do_error_log: nil, log_position_format: nil)
17
21
 
18
- @before_tick = []
19
- @on_fast_forward = []
22
+ raise ArgumentError,
23
+ "'beats_per_bar' and 'ticks_per_beat' parameters should be both nil or both have values" \
24
+ unless beats_per_bar && ticks_per_beat || beats_per_bar.nil? && ticks_per_beat.nil?
20
25
 
21
- @beats_per_bar = Rational(beats_per_bar)
22
- @ticks_per_beat = Rational(ticks_per_beat)
26
+ if logger
27
+ @logger = logger
28
+ else
29
+ @logger = Musa::Logger::Logger.new(sequencer: self, position_format: log_position_format)
23
30
 
24
- @ticks_per_bar = Rational(beats_per_bar * ticks_per_beat)
25
- @tick_duration = Rational(1, @ticks_per_bar)
31
+ @logger.error! if do_error_log || do_error_log.nil?
32
+ @logger.debug! if do_log
33
+ end
26
34
 
27
- @position_mutex = Mutex.new
28
- @hold_public_ticks = false
29
- @hold_ticks = 0
35
+ if beats_per_bar && ticks_per_beat
36
+ @beats_per_bar = Rational(beats_per_bar)
37
+ @ticks_per_beat = Rational(ticks_per_beat)
30
38
 
31
- @score = {}
39
+ self.singleton_class.include TickBasedTiming
40
+ else
41
+ self.singleton_class.include TicklessBasedTiming
42
+ end
32
43
 
33
- @everying = []
34
- @playing = []
35
- @moving = []
44
+ _init_timing
36
45
 
37
- @do_log = do_log
46
+ @on_debug_at = []
47
+ @on_error = []
38
48
 
39
- reset
40
- end
49
+ @before_tick = []
50
+ @on_fast_forward = []
41
51
 
42
- def reset
43
- @score.clear
44
- @everying.clear
45
- @playing.clear
46
- @moving.clear
52
+ @tick_mutex = Mutex.new
53
+ @position_mutex = Mutex.new
47
54
 
48
- @event_handlers = [EventHandler.new]
55
+ @timeslots = Timeslots.new
49
56
 
50
- @position = @position_mutex.synchronize { @ticks_per_bar - 1 }
51
- end
57
+ @everying = []
58
+ @playing = []
59
+ @moving = []
52
60
 
53
- def tick
54
- if @hold_public_ticks
55
- @hold_ticks += 1
56
- else
57
- _tick
58
- end
59
- end
61
+ reset
62
+ end
60
63
 
61
- def size
62
- @score.size
63
- end
64
+ def reset
65
+ @timeslots.clear
66
+ @everying.clear
67
+ @playing.clear
68
+ @moving.clear
64
69
 
65
- def empty?
66
- @score.empty?
67
- end
70
+ @event_handlers = [EventHandler.new]
68
71
 
69
- def round(bar)
70
- Rational((bar * @ticks_per_bar).round(0), @ticks_per_bar)
71
- end
72
+ _reset_timing
73
+ end
72
74
 
73
- def event_handler
74
- @event_handlers.last
75
- end
75
+ def size
76
+ @timeslots.values.sum(&:size)
77
+ end
76
78
 
77
- def on_debug_at(&block)
78
- @on_debug_at << KeyParametersProcedureBinder.new(block)
79
- end
79
+ def empty?
80
+ @timeslots.empty?
81
+ end
80
82
 
81
- def on_block_error(&block)
82
- @on_block_error << KeyParametersProcedureBinder.new(block)
83
- end
84
-
85
- def on_fast_forward(&block)
86
- @on_fast_forward << KeyParametersProcedureBinder.new(block)
87
- end
83
+ def run
84
+ tick until empty?
85
+ end
88
86
 
89
- def before_tick(&block)
90
- @before_tick << KeyParametersProcedureBinder.new(block)
91
- end
87
+ def event_handler
88
+ @event_handlers.last
89
+ end
92
90
 
93
- def position
94
- Rational(@position, @ticks_per_bar)
95
- end
91
+ def on_debug_at(&block)
92
+ @on_debug_at << SmartProcBinder.new(block)
93
+ end
96
94
 
97
- def position=(bposition)
98
- position = bposition * @ticks_per_bar
95
+ def on_error(&block)
96
+ @on_error << SmartProcBinder.new(block)
97
+ end
99
98
 
100
- raise ArgumentError, "Sequencer #{self}: cannot move back. current position: #{@position} new position: #{position}" if position < @position
99
+ def on_fast_forward(&block)
100
+ @on_fast_forward << SmartProcBinder.new(block)
101
+ end
101
102
 
102
- _hold_public_ticks
103
- @on_fast_forward.each { |block| block.call(true) }
103
+ def before_tick(&block)
104
+ @before_tick << SmartProcBinder.new(block)
105
+ end
104
106
 
105
- _tick while @position < position
107
+ def on(event, &block)
108
+ @event_handlers.last.on event, &block
109
+ end
106
110
 
107
- @on_fast_forward.each { |block| block.call(false) }
108
- _release_public_ticks
109
- end
111
+ def launch(event, *value_parameters, **key_parameters)
112
+ @event_handlers.last.launch event, *value_parameters, **key_parameters
113
+ end
110
114
 
111
- def on(event, &block)
112
- @event_handlers.last.on event, &block
113
- end
115
+ def wait(bars_delay, with: nil, debug: nil, &block)
116
+ debug ||= false
114
117
 
115
- def launch(event, *value_parameters, **key_parameters)
116
- @event_handlers.last.launch event, *value_parameters, **key_parameters
117
- end
118
+ control = EventHandler.new @event_handlers.last
119
+ @event_handlers.push control
118
120
 
119
- def wait(bars_delay, with: nil, debug: nil, &block)
120
- debug ||= false
121
+ if bars_delay.is_a? Numeric
122
+ _numeric_at position + bars_delay.rationalize, control, with: with, debug: debug, &block
123
+ else
124
+ bars_delay = Series::S(*bars_delay) if bars_delay.is_a?(Array)
125
+ bars_delay = bars_delay.instance if bars_delay
121
126
 
122
- control = EventHandler.new @event_handlers.last, capture_stdout: true
123
- @event_handlers.push control
127
+ with = Series::S(*with).repeat if with.is_a?(Array)
128
+ with = with.instance if with
124
129
 
125
- if bars_delay.is_a? Numeric
126
- _numeric_at position + bars_delay.rationalize, control, with: with, debug: debug, &block
127
- else
128
- bars_delay = Series::S(*bars_delay) if bars_delay.is_a? Array
129
- bars_delay = bars_delay.instance if bars_delay
130
+ _serie_at bars_delay.eval { |delay| position + delay }, control, with: with, debug: debug, &block
131
+ end
130
132
 
131
- with = Series::S(*with).repeat if with.is_a? Array
132
- with = with.instance if with
133
+ @event_handlers.pop
133
134
 
134
- _serie_at bars_delay.eval { |delay| position + delay }, control, with: with, debug: debug, &block
135
- end
135
+ control
136
+ end
136
137
 
137
- @event_handlers.pop
138
+ def now(with: nil, &block)
139
+ control = EventHandler.new @event_handlers.last
140
+ @event_handlers.push control
138
141
 
139
- control
140
- end
142
+ _numeric_at position, control, with: with, &block
141
143
 
142
- def now(with: nil, &block)
143
- control = EventHandler.new @event_handlers.last, capture_stdout: true
144
- @event_handlers.push control
144
+ @event_handlers.pop
145
145
 
146
- _numeric_at position, control, with: with, &block
146
+ control
147
+ end
147
148
 
148
- @event_handlers.pop
149
+ def raw_at(bar_position, force_first: nil, &block)
150
+ _raw_numeric_at bar_position.rationalize, force_first: force_first, &block
149
151
 
150
- control
151
- end
152
+ nil
153
+ end
152
154
 
153
- def raw_at(bar_position, force_first: nil, &block)
154
- _raw_numeric_at bar_position, force_first: force_first, &block
155
+ def at(bar_position, with: nil, debug: nil, &block)
156
+ debug ||= false
155
157
 
156
- nil
157
- end
158
+ control = EventHandler.new @event_handlers.last
159
+ @event_handlers.push control
158
160
 
159
- def at(bar_position, with: nil, debug: nil, &block)
160
- debug ||= false
161
+ if bar_position.is_a? Numeric
162
+ _numeric_at bar_position.rationalize, control, with: with, debug: debug, &block
163
+ else
164
+ bar_position = Series::S(*bar_position) if bar_position.is_a? Array
165
+ bar_position = bar_position.instance if bar_position
161
166
 
162
- control = EventHandler.new @event_handlers.last, capture_stdout: true
163
- @event_handlers.push control
167
+ with = Series::S(*with).repeat if with.is_a? Array
168
+ with = with.instance if with
164
169
 
165
- if bar_position.is_a? Numeric
166
- _numeric_at bar_position, control, with: with, debug: debug, &block
167
- else
168
- bar_position = Series::S(*bar_position) if bar_position.is_a? Array
169
- bar_position = bar_position.instance if bar_position
170
+ _serie_at bar_position, control, with: with, debug: debug, &block
171
+ end
170
172
 
171
- with = Series::S(*with).repeat if with.is_a? Array
172
- with = with.instance if with
173
+ @event_handlers.pop
173
174
 
174
- _serie_at bar_position, control, with: with, debug: debug, &block
175
- end
175
+ control
176
+ end
176
177
 
177
- @event_handlers.pop
178
+ def play(serie, mode: nil, parameter: nil, after: nil, context: nil, **mode_args, &block)
179
+ mode ||= :wait
178
180
 
179
- control
180
- end
181
+ control = PlayControl.new @event_handlers.last, after: after
182
+ @event_handlers.push control
181
183
 
182
- def play(serie, mode: nil, parameter: nil, after: nil, context: nil, **mode_args, &block)
183
- mode ||= :wait
184
+ _play serie.instance, control, context, mode: mode, parameter: parameter, **mode_args, &block
184
185
 
185
- control = PlayControl.new @event_handlers.last, after: after, capture_stdout: true
186
- @event_handlers.push control
186
+ @event_handlers.pop
187
187
 
188
- _play serie.instance, control, context, mode: mode, parameter: parameter, **mode_args, &block
188
+ @playing << control
189
189
 
190
- @event_handlers.pop
190
+ control.after do
191
+ @playing.delete control
192
+ end
191
193
 
192
- @playing << control
194
+ control
195
+ end
193
196
 
194
- control.after do
195
- @playing.delete control
196
- end
197
+ def continuation_play(parameters)
198
+ _play parameters[:serie],
199
+ parameters[:control],
200
+ parameters[:nl_context],
201
+ mode: parameters[:mode],
202
+ decoder: parameters[:decoder],
203
+ __play_eval: parameters[:play_eval],
204
+ **parameters[:mode_args]
205
+ end
197
206
 
198
- control
199
- end
207
+ def every(interval, duration: nil, till: nil, condition: nil, on_stop: nil, after_bars: nil, after: nil, &block)
208
+ # nil interval means 'only once'
209
+ interval = interval.rationalize unless interval.nil?
200
210
 
201
- def continuation_play(parameters)
202
- _play parameters[:serie],
203
- parameters[:control],
204
- parameters[:nl_context],
205
- mode: parameters[:mode],
206
- decoder: parameters[:decoder],
207
- __play_eval: parameters[:play_eval],
208
- **parameters[:mode_args]
209
- end
211
+ control = EveryControl.new @event_handlers.last,
212
+ duration: duration,
213
+ till: till,
214
+ condition: condition,
215
+ on_stop: on_stop,
216
+ after_bars: after_bars,
217
+ after: after
210
218
 
211
- def every(binterval, duration: nil, till: nil, condition: nil, on_stop: nil, after_bars: nil, after: nil, &block)
212
- binterval = binterval.rationalize
219
+ @event_handlers.push control
213
220
 
214
- control = EveryControl.new @event_handlers.last, capture_stdout: true, duration: duration, till: till, condition: condition, on_stop: on_stop, after_bars: after_bars, after: after
215
- @event_handlers.push control
221
+ _every interval, control, &block
216
222
 
217
- _every binterval, control, &block
223
+ @event_handlers.pop
218
224
 
219
- @event_handlers.pop
225
+ @everying << control
220
226
 
221
- @everying << control
227
+ control.after do
228
+ @everying.delete control
229
+ end
222
230
 
223
- control.after do
224
- @everying.delete control
225
- end
231
+ control
232
+ end
226
233
 
227
- control
228
- end
234
+ def move(every: nil,
235
+ from: nil, to: nil, step: nil,
236
+ duration: nil, till: nil,
237
+ function: nil,
238
+ right_open: nil,
239
+ on_stop: nil,
240
+ after_bars: nil,
241
+ after: nil,
242
+ &block)
229
243
 
230
- def move(every: nil, from: nil, to: nil, step: nil, duration: nil, till: nil, function: nil, right_open: nil, on_stop: nil, after_bars: nil, after: nil, &block)
231
- control = _move every: every, from: from, to: to, step: step, duration: duration, till: till, function: function, right_open: right_open, on_stop: on_stop, after_bars: after_bars, after: after, &block
244
+ control = _move every: every,
245
+ from: from, to: to, step: step,
246
+ duration: duration, till: till,
247
+ function: function,
248
+ right_open: right_open,
249
+ on_stop: on_stop,
250
+ after_bars: after_bars,
251
+ after: after,
252
+ &block
232
253
 
233
- @moving << control
254
+ @moving << control
234
255
 
235
- control.after do
236
- @moving.delete control
237
- end
256
+ control.after do
257
+ @moving.delete control
258
+ end
238
259
 
239
- control
240
- end
260
+ control
261
+ end
241
262
 
242
- def log(msg = nil)
243
- _log msg
244
- end
263
+ def debug(msg = nil)
264
+ @logger.debug { msg || '...' }
265
+ end
245
266
 
246
- def inspect
247
- super + ": position=#{position}"
267
+ def to_s
268
+ super + ": position=#{position}"
269
+ end
270
+ end
248
271
  end
249
-
250
- alias to_s inspect
251
272
  end
273
+
@@ -0,0 +1,77 @@
1
+ module Musa
2
+ module Sequencer
3
+ class BaseSequencer
4
+ module TickBasedTiming
5
+
6
+ attr_reader :position, :ticks_per_bar, :tick_duration
7
+
8
+ def tick
9
+ if @hold_public_ticks
10
+ @hold_ticks += 1
11
+ else
12
+ _tick @position_mutex.synchronize { @position += @tick_duration }
13
+ end
14
+ end
15
+
16
+ def position=(new_position)
17
+ raise ArgumentError,
18
+ "Sequencer #{self}: cannot move back. current position: #{@position} new position: #{new_position}" \
19
+ if new_position < position
20
+
21
+ _hold_public_ticks
22
+ @on_fast_forward.each { |block| block.call(true) }
23
+
24
+ _tick(@position_mutex.synchronize { @position += @tick_duration }) while @position < new_position
25
+
26
+ @on_fast_forward.each { |block| block.call(false) }
27
+ _release_public_ticks
28
+ end
29
+
30
+ private
31
+
32
+ def _init_timing
33
+ @ticks_per_bar = Rational(beats_per_bar * ticks_per_beat)
34
+ @tick_duration = Rational(1, @ticks_per_bar)
35
+
36
+ @hold_public_ticks = false
37
+ @hold_ticks = 0
38
+ end
39
+
40
+ def _reset_timing
41
+ @position = @position_mutex.synchronize { 1r - @tick_duration }
42
+ end
43
+
44
+ def _check_position(position)
45
+ ticks_position = position / @tick_duration
46
+
47
+ if ticks_position.round != ticks_position
48
+ original_position = position
49
+ position = ticks_position.round * @tick_duration
50
+
51
+ if @do_log
52
+ _log "BaseSequencer._numeric_at: warning: rounding "\
53
+ "position #{position} (#{original_position.to_f.round(5)}) "\
54
+ "to tick precision: #{position} (#{position.to_f.round(5)})"
55
+ end
56
+ end
57
+
58
+ position
59
+ end
60
+
61
+ def _quantize(position)
62
+ (position / @tick_duration).round * @tick_duration
63
+ end
64
+
65
+ def _hold_public_ticks
66
+ @hold_public_ticks = true
67
+ end
68
+
69
+ def _release_public_ticks
70
+ @hold_ticks.times { _tick(@position_mutex.synchronize { @position += @tick_duration }) }
71
+ @hold_ticks = 0
72
+ @hold_public_ticks = false
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end