Module: Musa::Sequencer::BaseSequencer::TickBasedTiming Private

Defined in:
lib/musa-dsl/sequencer/base-sequencer-tick-based.rb

Overview

This module is part of a private API. You should avoid using this module if possible, as it may be removed or be changed in the future.

Tick-based timing implementation for BaseSequencer.

TickBasedTiming provides quantized time progression where time advances in discrete tick increments. Musical time is divided into bars, beats, and ticks, with position rounded to the nearest tick boundary. This provides a traditional sequencer timing model similar to DAWs and MIDI sequencers.

Tick-Based Time Model

Time is quantized to a grid determined by:

  • beats_per_bar: Time signature numerator (e.g., 4 for 4/4)
  • ticks_per_beat: Subdivisions per beat (resolution)
  • ticks_per_bar: Total ticks = beats_per_bar × ticks_per_beat
  • tick_duration: 1 / ticks_per_bar (Rational)

Position always aligns to tick boundaries. Non-aligned positions are rounded with a warning.

Time Progression

  • Forward only: Position cannot decrease (enforced)
  • Tick advancement: #tick increments by tick_duration
  • Fast-forward: #position= jumps to future position
  • Quantization: All positions rounded to tick grid

Where time starts

A new sequencer sits one tick before bar 1, at 1r - tick_duration (plus offset), not at 1r. This is deliberate: #tick advances first and executes afterwards, so the first tick lands exactly on bar 1 and bar 1 gets its full complement of ticks. Nothing is scheduled at the starting position, which is why it is never observed in a piece.

It is observable from outside, though, and it is the reason a move or an every written directly in the sequencer body -- rather than inside an at 1 -- begins one tick early: it is being started at the position before bar 1.

Fast-Forward Mechanism

When jumping forward via position=:

  1. Triggers on_fast_forward callbacks with true
  2. Ticks forward until reaching target position
  3. Triggers on_fast_forward callbacks with false
  4. Allows event handlers to skip/optimize during jumps

Musical Applications

  • Traditional MIDI sequencing with quantized timing
  • Grid-aligned rhythmic patterns
  • Time signature-based composition (4/4, 3/4, etc.)
  • Tick-precise event scheduling

Rational vs Float

The sequencer internally encodes time as Rational. It is preferable to use Rational values for positions and durations, as using Float may cause precision issues in the conversion.

Examples:

Creating tick-based sequencer (4/4, 96 ticks per beat)

sequencer = BaseSequencer.new(4, 96)  # 4 beats, 96 ticks/beat
sequencer.ticks_per_bar  # => 384r
sequencer.tick_duration  # => 1/384r
sequencer.position       # => 383/384r  (one tick before bar 1)

Advancing time with tick

sequencer.tick      # the first tick lands on bar 1
sequencer.position  # => 1r
sequencer.tick
sequencer.position  # => 385/384r

Fast-forward to future position

sequencer.position = 2r  # Jump to bar 2
# Triggers on_fast_forward(true), ticks forward, on_fast_forward(false)

Quantization warning

sequencer.at(1.5001r) { puts "event" }
# WARN: rounding position 15001/10000 (1.5001) to tick precision: 3/2 (1.5)

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#positionRational

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Current playback position in bars (Rational).

Always aligned to tick boundaries. Bar 1 is position 1r; a sequencer that has not ticked yet is one tick short of it (see "Where time starts").

Returns:



96
97
98
# File 'lib/musa-dsl/sequencer/base-sequencer-tick-based.rb', line 96

def position
  @position
end

#tick_durationRational (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Duration of one tick in bars (1 / ticks_per_bar).

Returns:



106
107
108
# File 'lib/musa-dsl/sequencer/base-sequencer-tick-based.rb', line 106

def tick_duration
  @tick_duration
end

#ticks_per_barRational (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Total ticks per bar (beats_per_bar × ticks_per_beat).

Returns:



101
102
103
# File 'lib/musa-dsl/sequencer/base-sequencer-tick-based.rb', line 101

def ticks_per_bar
  @ticks_per_bar
end

Instance Method Details

#tickvoid

This method returns an undefined value.

Advances sequencer by one tick.

Increments position by tick_duration and executes all events scheduled at the new position. This is the primary time progression method for tick-based sequencers.

If ticks are held (during fast-forward), accumulates ticks in buffer without executing events until released.

Examples:

Normal tick progression

sequencer.position  # => 383/384r
sequencer.tick
sequencer.position  # => 1r
sequencer.tick
sequencer.position  # => 385/384r


127
128
129
130
131
132
133
# File 'lib/musa-dsl/sequencer/base-sequencer-tick-based.rb', line 127

def tick
  if @hold_public_ticks
    @hold_ticks += 1
  else
    _tick @position_mutex.synchronize { @position += @tick_duration }
  end
end