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)

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.



74
75
76
77
78
79
80
# File 'lib/musa-dsl/transport/clock.rb', line 74

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:

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)



144
145
146
# File 'lib/musa-dsl/transport/clock.rb', line 144

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:

clock.on_start { puts "Clock started!" }

Yields:

  • Called when clock starts running.



112
113
114
# File 'lib/musa-dsl/transport/clock.rb', line 112

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:

clock.on_stop { puts "Clock stopped!" }

Yields:

  • Called when clock stops running.



125
126
127
# File 'lib/musa-dsl/transport/clock.rb', line 125

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.



164
165
166
# File 'lib/musa-dsl/transport/clock.rb', line 164

def run
  raise NotImplementedError
end

#running?Boolean

Checks if the clock is currently running.

Returns:

  • (Boolean)

    true if clock is running, false otherwise.



85
86
87
# File 'lib/musa-dsl/transport/clock.rb', line 85

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.



96
97
98
99
100
101
# File 'lib/musa-dsl/transport/clock.rb', line 96

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.



179
180
181
# File 'lib/musa-dsl/transport/clock.rb', line 179

def terminate
  raise NotImplementedError
end