Fixed-capacity, sample-accurate multi-lane linear step player. More...
#include <step_player.hpp>
Classes | |
| struct | Spec |
Public Member Functions | |
| constexpr | StepPlayer (Spec spec={}) noexcept |
| constexpr bool | valid () const noexcept |
| constexpr const Spec & | spec () const noexcept |
| constexpr StepPlayerError | set_step (std::size_t lane, std::size_t index, StepPlayerStep step) noexcept |
| constexpr const StepPlayerStep * | get_step (std::size_t lane, std::size_t index) const noexcept |
| constexpr void | clear_steps () noexcept |
| Authored-step edits are control-thread work; playback state is untouched so an in-flight note still receives its owned release. | |
| std::size_t | sounding_note_count () const noexcept |
| MidiUtilityProcessReport | process (const MidiBuffer &input, MidiBuffer &output, const StepPlayerBlock &block) noexcept |
| MidiUtilityProcessReport | flush_transport (MidiBuffer &output) noexcept |
| Release every owned note and resync lane clocks. | |
| MidiUtilityProcessReport | reset (MidiBuffer &output) noexcept |
| Release every owned note and discard all playback state. | |
| std::optional< StepPlayerCoordinate > | coordinate_at (std::size_t lane, timebase::TickPosition tick) const noexcept |
| The coordinate a lane's grid selects at tick. | |
| std::optional< StepPlayerCoordinate > | upcoming_coordinate (std::size_t lane) const noexcept |
| The coordinate a lane will fire next, or std::nullopt before the lane's clock has been placed by a transport block. | |
Static Public Member Functions | |
| static constexpr StepPlayerCapacityContract | contract () noexcept |
| static constexpr bool | valid_lane_spec (const StepPlayerLaneSpec &lane) noexcept |
| static constexpr bool | valid_spec (const Spec &spec) noexcept |
| static constexpr StepPlayerError | validate_step (const StepPlayerStep &step) noexcept |
Static Public Attributes | |
| static constexpr std::size_t | kMaximumCells = MaxLanes * MaxSteps |
| static constexpr std::size_t | kMaximumSoundingNotes = MaxLanes * (MaxRatchetHits + 1) |
| A lane can hold one ratchet burst plus one note kept overlapping by a slide, so the ledger never needs more than this to avoid stranding. | |
| static constexpr std::int32_t | kMaximumTimingOffsetTicks |
| A micro-timing nudge is bounded to one quarter note: far wider than any swing or groove needs, and narrow enough that a value which would reorder the grid wholesale is refused rather than silently honoured. | |
Fixed-capacity, sample-accurate multi-lane linear step player.
Each lane is an independent loop of up to MaxSteps authored steps over one shared transport: its own length, step duration, direction walk, and choke group. Lanes with different lengths or divisions realign at the common multiple of their grid ordinals, so polymeter falls out of the exact tick arithmetic rather than a dedicated mechanism.
The player is a generator: input passes through unchanged and generated notes are merged in sample order. Every emitted attack owns exactly one later release in the fixed sounding ledger; an attack that cannot secure a ledger slot is suppressed rather than stranded, and a release that cannot be emitted is retained as debt and retried. Step selection, probability, and random walks are pure functions of the grid coordinate, so the event stream is identical for any block partition of the same transport span. A transport discontinuity is a flush plus a resync: every owned note is released and every lane clock realigns to the grid at the new position.
|
inlineexplicitconstexprnoexcept |
|
inlineconstexprnoexcept |
Authored-step edits are control-thread work; playback state is untouched so an in-flight note still receives its owned release.
|
inlinestaticconstexprnoexcept |
|
inlinenoexcept |
The coordinate a lane's grid selects at tick.
Pure in the lane's authored spec and the tick: it consults no playback state and advances nothing, so a caller may ask ahead of process() which cell is about to speak. std::nullopt means the lane does not exist or carries no steps.
|
inlinenoexcept |
Release every owned note and resync lane clocks.
Use this for a transport stop, seek, or loop boundary handled outside process().
|
inlineconstexprnoexcept |
|
inlinenoexcept |
|
inlinenoexcept |
Release every owned note and discard all playback state.
|
inlineconstexprnoexcept |
|
inlinenoexcept |
|
inlineconstexprnoexcept |
|
inlinenoexcept |
The coordinate a lane will fire next, or std::nullopt before the lane's clock has been placed by a transport block.
|
inlineconstexprnoexcept |
|
inlinestaticconstexprnoexcept |
|
inlinestaticconstexprnoexcept |
|
inlinestaticconstexprnoexcept |
|
staticconstexpr |
|
staticconstexpr |
A lane can hold one ratchet burst plus one note kept overlapping by a slide, so the ledger never needs more than this to avoid stranding.
|
staticconstexpr |
A micro-timing nudge is bounded to one quarter note: far wider than any swing or groove needs, and narrow enough that a value which would reorder the grid wholesale is refused rather than silently honoured.
The field is 32-bit deliberately. A quarter is 705'600 ticks, so a 16-bit offset would cap at 32'767 — under a fifth of a single sixteenth step, which cannot express swing at all.