Class: Musa::Clock::Clock Abstract

Inherits:
Object show all
Defined in:
lib/musa-dsl/transport/clock.rb

Overview

This class is abstract.

Subclass and implement #run and #terminate

Abstract base class for all clock implementations.

This class defines the interface and callback infrastructure that all concrete clock implementations must follow. Subclasses must implement the run and terminate methods.

Callback System

Clocks maintain three callback collections:

  • on_start: Called when clock starts running
  • on_stop: Called when clock stops
  • on_change_position: Called when position changes (seek/jump)

Subclass Responsibilities

Concrete clocks must:

  1. Implement run(&block) - Start generating ticks, yield for each tick
  2. Override stop if additional cleanup is needed (call super)
  3. Override terminate to call stop then exit the run loop
  4. Manage @run state properly
  5. Reset @stopped = false at the start of run (and in start if applicable)

The per-method examples below are written against a clock that does not need hardware or real time:

clock = Musa::Clock::DummyClock.new(4)

Examples:

Creating a simple clock subclass

class SimpleClock < Clock
  def run
    @stopped = false
    @run = true
    @on_start.each(&:call)

    while @run
      yield if block_given?  # Generate tick
      sleep 0.1
    end

    stop  # Fires on_stop callbacks (idempotent)
  end

  def terminate
    stop         # Ensures on_stop callbacks fire
    @run = false # Exits the run loop
  end
end

Instance Method Summary collapse

Constructor Details

#initializeClock

Initializes the clock with empty callback collections.



79
80
81
82
83
84
85
# File 'lib/musa-dsl/transport/clock.rb', line 79

def initialize
  @run = nil
  @stopped = false
  @on_start = []
  @on_stop = []
  @on_change_position = []
end

Instance Method Details

#on_change_position {|bars, beats, midi_beats| ... } ⇒ void

This method returns an undefined value.

Registers a callback to be called when playback position changes.

This is typically used for handling seek/jump operations where the transport position changes non-linearly.

Examples:

on_change_position callback

clock.on_change_position do |bars:, beats:, midi_beats:|
  puts "Position changed to bar #{bars}"
end

Yields:

  • (bars, beats, midi_beats)

    Position change information

Yield Parameters:

  • bars (Rational, nil)

    new position in bars

  • beats (Rational, nil)

    new position in beats

  • midi_beats (Integer, nil)

    new position in MIDI beats (for MIDI Clock)



149
150
151
# File 'lib/musa-dsl/transport/clock.rb', line 149

def on_change_position(&block)
  @on_change_position << block
end

#on_start { ... } ⇒ void

This method returns an undefined value.

Registers a callback to be called when the clock starts.

Multiple callbacks can be registered and will be called in order.

Examples:

on_start callback

clock.on_start { puts "Clock started!" }

Yields:

  • Called when clock starts running.



117
118
119
# File 'lib/musa-dsl/transport/clock.rb', line 117

def on_start(&block)
  @on_start << block
end

#on_stop { ... } ⇒ void

This method returns an undefined value.

Registers a callback to be called when the clock stops.

Multiple callbacks can be registered and will be called in order.

Examples:

on_stop callback

clock.on_stop { puts "Clock stopped!" }

Yields:

  • Called when clock stops running.



130
131
132
# File 'lib/musa-dsl/transport/clock.rb', line 130

def on_stop(&block)
  @on_stop << block
end

#run { ... } ⇒ void

Note:

This method typically runs in a loop until #terminate is called.

Note:

Subclasses should call @on_start callbacks when starting.

Note:

Subclasses should call #stop (not @on_stop directly) when stopping.

This method returns an undefined value.

Starts the clock running and generates ticks.

This method should block and yield once per tick. Subclasses must implement this method.

Subclasses should reset @stopped = false at the start of run to allow stop/start cycles.

Yields:

  • Called once per tick to advance the sequencer.

Raises:

  • (NotImplementedError)

    if not overridden by subclass.



169
170
171
# File 'lib/musa-dsl/transport/clock.rb', line 169

def run
  raise NotImplementedError
end

#running?Boolean

Checks if the clock is currently running.

Returns:

  • (Boolean)

    true if clock is running, false otherwise.



90
91
92
# File 'lib/musa-dsl/transport/clock.rb', line 90

def running?
  @run
end

#stopvoid

This method returns an undefined value.

Stops the clock and fires on_stop callbacks.

Idempotent: calling stop multiple times only fires callbacks once. Subclasses that need additional stop logic (e.g., pausing a timer) should override and call super.



101
102
103
104
105
106
# File 'lib/musa-dsl/transport/clock.rb', line 101

def stop
  return if @stopped

  @stopped = true
  @on_stop.each(&:call)
end

#terminatevoid

Note:

After calling this, #run should exit.

Note:

Must call #stop to guarantee on_stop callbacks fire.

This method returns an undefined value.

Stops the clock and terminates the run loop.

Calls #stop to ensure on_stop callbacks fire, then exits the run loop. Subclasses must implement this method.

Raises:

  • (NotImplementedError)

    if not overridden by subclass.



184
185
186
# File 'lib/musa-dsl/transport/clock.rb', line 184

def terminate
  raise NotImplementedError
end