Module: Musa::Sequencer::BaseSequencer::TicklessBasedTiming Private

Defined in:
lib/musa-dsl/sequencer/base-sequencer-tickless-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.

Tickless (continuous) timing implementation for BaseSequencer.

TicklessBasedTiming provides continuous, non-quantized time progression where events can be scheduled at any Rational position without rounding to a tick grid. Time advances by jumping directly to the next scheduled event, enabling precise timing for complex musical structures and avoiding quantization artifacts.

Tickless Time Model

  • No quantization: Positions are exact Rational values
  • Event-driven: Time jumps to next scheduled event
  • Infinite resolution: ticks_per_bar = Float::INFINITY
  • Zero tick duration: tick_duration = 0r
  • Continuous time: No discrete grid or rounding

Time Progression

Unlike tick-based mode that advances in fixed increments, tickless mode advances position directly to the next scheduled event. If events are at positions [1r, 1.25r, 1.5r, 2r], calling #tick jumps through these exact positions without intermediate steps.

  • Forward only: Position cannot decrease (enforced)
  • Event jumping: #tick moves to next scheduled position
  • Fast-forward: #position= executes events up to target
  • No rounding: Positions preserved exactly

Comparison with Tick-Based Mode

Aspect Tick-Based Tickless
Time grid Quantized to ticks Continuous
Resolution ticks_per_beat Infinite (Rational)
Advancement Fixed tick_duration Jump to next event
Rounding Yes (with warning) No
Use case Traditional sequencing Complex timing, microtiming

Musical Applications

  • Complex polyrhythms without quantization loss
  • Precise microtiming and groove timing
  • Non-isochronous meters and irregular divisions
  • Algorithmic composition with exact ratios
  • Avoiding rounding errors in long sequences

Examples:

Creating tickless sequencer

sequencer = BaseSequencer.new  # No tick parameters
sequencer.ticks_per_bar   # => Float::INFINITY
sequencer.tick_duration   # => 0r
sequencer.position        # => nil
# nil, not a bar number: a tickless sequencer has no position of its
# own until it reaches the first scheduled event.

Precise timing without quantization

sequencer.at(1r) { puts "Event 1" }
sequencer.at(1 + 1/7r) { puts "Event 2" }  # Exact 1/7 division
sequencer.at(1 + 1/3r) { puts "Event 3" }  # Exact 1/3 division
sequencer.tick  # Jumps to 1r
sequencer.tick  # Jumps to 8/7r (1 + 1/7)
sequencer.tick  # Jumps to 4/3r (1 + 1/3)

Complex polyrhythm (5 against 7)

require 'musa-dsl'

sequencer = Musa::Sequencer::BaseSequencer.new  # Tickless mode

7.times { |i| sequencer.at(1 + Rational(i, 7)) { puts "Note A at #{sequencer.position}" } }
5.times { |i| sequencer.at(1 + Rational(i, 5)) { puts "Note B at #{sequencer.position}" } }

sequencer.run  # Events at exact rational positions

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 or nil).

Position is nil before first event, then becomes the exact Rational position of the current event. No quantization or rounding occurs.

Returns:

  • (Rational, nil)

    current position or nil before first event



85
86
87
# File 'lib/musa-dsl/sequencer/base-sequencer-tickless-based.rb', line 85

def position
  @position
end

Instance Method Details

#tickvoid

This method returns an undefined value.

Advances sequencer to next scheduled event.

Jumps position directly to the next event in the timeslots, skipping any intermediate positions. Executes all handlers scheduled at that position. This is the primary time progression method for tickless sequencers.

Unlike tick-based mode with fixed increments, tickless tick jumps to wherever the next event is scheduled, enabling precise event-driven timing without quantization.

Examples:

Event-driven progression

sequencer.at(1r) { puts "A" }
sequencer.at(1.5r) { puts "B" }
sequencer.at(2r) { puts "C" }

sequencer.tick  # position becomes 1r, prints "A"
sequencer.tick  # position becomes 1.5r, prints "B"
sequencer.tick  # position becomes 2r, prints "C"

Ticking a schedule that has run out does nothing

exhausted = Musa::Sequencer::BaseSequencer.new
exhausted.at(1r) { }
exhausted.tick

exhausted.tick
exhausted.position  # => 1r  (it stays where it was)


146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/musa-dsl/sequencer/base-sequencer-tickless-based.rb', line 146

def tick
  # `first_after` returns nil when the schedule is exhausted, which is
  # the END of time and not a position. Assigning it moved the position
  # back to nil -- the BEGINNING of time, the other thing nil means
  # here -- so a tick past the last event ran the clock backwards and
  # left the sequencer unmovable again (issue #76).
  #
  # A tick is "advance to the next event". With no next event there is
  # nothing to advance to and nobody to call.
  position_to_run = @position_mutex.synchronize do
    next_position = @timeslots.first_after(@position)
    @position = next_position if next_position

    next_position
  end

  _tick position_to_run if position_to_run
end

#tick_durationRational

Returns zero tick duration for tickless mode.

Indicates infinitesimal tick duration (continuous time).

Returns:



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

def tick_duration
  0r
end

#ticks_per_barFloat

Returns infinite ticks per bar for tickless mode.

Indicates unlimited timing resolution (no tick grid).

Returns:

  • (Float)

    Float::INFINITY



94
95
96
# File 'lib/musa-dsl/sequencer/base-sequencer-tickless-based.rb', line 94

def ticks_per_bar
  Float::INFINITY
end