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.
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/musa-dsl/transport/timer-clock.rb', line 91 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.
128 129 130 |
# File 'lib/musa-dsl/transport/timer-clock.rb', line 128 def bpm @bpm end |
#period ⇒ Rational
Current tick period in seconds.
118 119 120 |
# File 'lib/musa-dsl/transport/timer-clock.rb', line 118 def period @period end |
#ticks_per_beat ⇒ Rational
Number of ticks per beat.
123 124 125 |
# File 'lib/musa-dsl/transport/timer-clock.rb', line 123 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.
273 274 275 276 277 278 |
# File 'lib/musa-dsl/transport/timer-clock.rb', line 273 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.
258 259 260 261 262 263 |
# File 'lib/musa-dsl/transport/timer-clock.rb', line 258 def pause if @started && !@paused @timer.stop @paused = true end end |
#paused? ⇒ Boolean
Checks if the clock is paused.
181 182 183 |
# File 'lib/musa-dsl/transport/timer-clock.rb', line 181 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.
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
# File 'lib/musa-dsl/transport/timer-clock.rb', line 196 def run @run = true 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.
222 223 224 225 226 227 228 229 |
# File 'lib/musa-dsl/transport/timer-clock.rb', line 222 def start unless @started @on_start.each(&:call) @started = true @paused = false @timer.continue end end |
#started? ⇒ Boolean
Checks if the clock has been started.
174 175 176 |
# File 'lib/musa-dsl/transport/timer-clock.rb', line 174 def started? @started end |
#stop ⇒ void
Calls registered on_stop callbacks
Different from #pause: stop resets to initial state
This method returns an undefined value.
Stops the clock and resets to initial state.
Triggers @on_stop callbacks and marks clock as not started. Has no effect if not currently started.
240 241 242 243 244 245 246 247 |
# File 'lib/musa-dsl/transport/timer-clock.rb', line 240 def stop if @started @timer.stop @started = false @paused = false @on_stop.each(&:call) end end |