Class: Musa::Clock::TimerClock
- Defined in:
- lib/musa-dsl/transport/timer-clock.rb
Overview
Internal timer-based clock for standalone operation.
TimerClock uses a high-precision Timer to generate ticks at a configurable rate. Unlike DummyClock, TimerClock requires external activation and is designed for scenarios where timing control comes from outside (e.g., live coding clients, interactive systems).
Activation Model
IMPORTANT: TimerClock starts in a paused state. After calling
transport.start (which blocks), you must call clock.start() from
another thread to begin generating ticks.
This activation model is appropriate for:
- Live coding: Client controls when to start/stop
- Interactive systems: External controller manages playback
- Testing with control: Precise control over when ticks begin
Configuration Methods
The clock can be configured in three equivalent ways:
- BPM + ticks_per_beat: Musical tempo-based (most common)
- Period: Direct tick period in seconds
- Any combination: Changes one parameter, others auto-calculate
Relationship Between Parameters
period = 60 / (bpm * ticks_per_beat)
Example: 120 BPM, 24 ticks/beat → period = 60/(120*24) = 0.02083s
States
- Not started: Clock created but not running
- Started: Clock running, generating ticks
- Paused: Clock started but temporarily stopped
Instance Attribute Summary collapse
-
#bpm ⇒ Rational
Current tempo in beats per minute.
-
#period ⇒ Rational
Current tick period in seconds.
-
#ticks_per_beat ⇒ Rational
Number of ticks per beat.
Instance Method Summary collapse
-
#continue ⇒ void
Resumes the clock from paused state.
-
#initialize(period = nil, ticks_per_beat: nil, bpm: nil, correction: nil, delayed_ticks_error: nil, logger: nil, do_log: nil) ⇒ TimerClock
constructor
Creates a new timer-based clock.
-
#pause ⇒ void
Pauses the clock without stopping it.
-
#paused? ⇒ Boolean
Checks if the clock is paused.
-
#run { ... } ⇒ void
Starts the clock's run loop.
-
#start ⇒ void
Starts the clock from paused state.
-
#started? ⇒ Boolean
Checks if the clock has been started.
-
#stop ⇒ void
Stops the clock and resets to initial state.
-
#terminate ⇒ void
Terminates the clock's run loop.
Constructor Details
#initialize(period = nil, ticks_per_beat: nil, bpm: nil, correction: nil, delayed_ticks_error: nil, logger: nil, do_log: nil) ⇒ TimerClock
Creates a new timer-based clock.
At least one timing parameter must be provided (period, bpm, or ticks_per_beat). Missing parameters use defaults: bpm=120, ticks_per_beat=24.
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
# File 'lib/musa-dsl/transport/timer-clock.rb', line 116 def initialize(period = nil, ticks_per_beat: nil, bpm: nil, correction: nil, delayed_ticks_error: nil, logger: nil, do_log: nil) do_log ||= false super() @correction = correction # Set parameters in any combination self.period = period if period self.ticks_per_beat = ticks_per_beat if ticks_per_beat self.bpm = bpm if bpm # Apply defaults self.bpm ||= 120 self.ticks_per_beat ||= 24 @started = false @paused = false @delayed_ticks_error = delayed_ticks_error @logger = logger @do_log = do_log end |
Instance Attribute Details
#bpm ⇒ Rational
Current tempo in beats per minute.
153 154 155 |
# File 'lib/musa-dsl/transport/timer-clock.rb', line 153 def bpm @bpm end |
#period ⇒ Rational
Current tick period in seconds.
143 144 145 |
# File 'lib/musa-dsl/transport/timer-clock.rb', line 143 def period @period end |
#ticks_per_beat ⇒ Rational
Number of ticks per beat.
148 149 150 |
# File 'lib/musa-dsl/transport/timer-clock.rb', line 148 def ticks_per_beat @ticks_per_beat end |
Instance Method Details
#continue ⇒ void
No effect if not started or not paused
This method returns an undefined value.
Resumes the clock from paused state.
Continues generating ticks. Has no effect if not paused.
308 309 310 311 312 313 |
# File 'lib/musa-dsl/transport/timer-clock.rb', line 308 def continue if @started && @paused @paused = false @timer.continue end end |
#pause ⇒ void
No effect if not started or already paused
This method returns an undefined value.
Pauses the clock without stopping it.
Ticks stop but clock remains in started state. Use #continue to resume.
293 294 295 296 297 298 |
# File 'lib/musa-dsl/transport/timer-clock.rb', line 293 def pause if @started && !@paused @timer.stop @paused = true end end |
#paused? ⇒ Boolean
Checks if the clock is paused.
215 216 217 |
# File 'lib/musa-dsl/transport/timer-clock.rb', line 215 def paused? @paused end |
#run { ... } ⇒ void
This method blocks until #terminate is called
Clock begins paused; call #start to begin ticking
This method returns an undefined value.
Starts the clock's run loop.
This method blocks and runs the timer loop, yielding for each tick. The clock starts in a paused state and must be explicitly started via #start.
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 |
# File 'lib/musa-dsl/transport/timer-clock.rb', line 230 def run @run = true @stopped = false while @run @timer = Timer.new(@period, correction: @correction, stop: true, delayed_ticks_error: @delayed_ticks_error, logger: @logger, do_log: @do_log) @timer.run do yield if block_given? end end end |
#start ⇒ void
Must call #run first to start the run loop
Calls registered on_start callbacks
This method returns an undefined value.
Starts the clock from paused state.
Triggers @on_start callbacks and begins generating ticks. Has no effect if already started.
257 258 259 260 261 262 263 264 265 |
# File 'lib/musa-dsl/transport/timer-clock.rb', line 257 def start unless @started @stopped = false @on_start.each(&:call) @started = true @paused = false @timer.continue end end |
#started? ⇒ Boolean
Checks if the clock has been started.
208 209 210 |
# File 'lib/musa-dsl/transport/timer-clock.rb', line 208 def started? @started end |
#stop ⇒ void
Different from #pause: stop resets to initial state
This method returns an undefined value.
Stops the clock and resets to initial state.
Stops the internal timer, resets state flags, and fires on_stop callbacks via super (idempotent).
275 276 277 278 279 280 281 282 |
# File 'lib/musa-dsl/transport/timer-clock.rb', line 275 def stop if @started @timer.stop @started = false @paused = false end super end |
#terminate ⇒ void
After calling this, #run will exit and Transport::Transport#start will return
This method returns an undefined value.
Terminates the clock's run loop.
Calls #stop to ensure on_stop callbacks fire, then exits the run loop by terminating the internal timer.
323 324 325 326 327 |
# File 'lib/musa-dsl/transport/timer-clock.rb', line 323 def terminate stop @run = false @timer&.terminate end |