The pulse-count stage sequencer. More...
#include <stage_sequencer.hpp>
Classes | |
| struct | Frame |
| One sample of sequencer output. More... | |
Public Member Functions | |
| StageSeqT () | |
| void | prepare (double sample_rate) |
| void | set_num_stages (int n) |
| int | num_stages () const |
| void | set_direction (SeqDirection d) |
| SeqDirection | direction () const |
| void | set_stage_pitch (int s, SampleType volts) |
| SampleType | stage_pitch (int s) const |
| void | set_stage_pulse_count (int s, int count) |
| int | stage_pulse_count (int s) const |
| void | set_stage_gate_mode (int s, StageGateMode m) |
| StageGateMode | stage_gate_mode (int s) const |
| void | set_stage_slide (int s, bool on) |
| bool | stage_slide (int s) const |
| void | set_stage_skip (int s, bool on) |
| bool | stage_skip (int s) const |
| void | set_slide_ms (double ms) |
| double | slide_ms () const |
| void | set_repeat_duty (double duty) |
| double | repeat_duty () const |
| void | set_seed (std::uint32_t seed) |
| void | apply_reset_edge () |
| The modular reset jack (verb 2): position to the top of the pattern, gate low, pitch CV held, RNG untouched. | |
| void | reset () |
| The lifecycle verb (verb 1): everything apply_reset_edge() does, plus held outputs to zero, the clock-period measurement forgotten, and the RNG rewound to its seed. | |
| bool | gate () const |
| SampleType | pitch_v () const |
| int | stage () const |
| int | pulse () const |
| 0-based pulse index inside the current stage. | |
| bool | started () const |
| True once the first clock after a reset has landed. | |
| Frame | process (bool run_high, bool reset_edge, bool clock_edge) |
| Advances one sample. See the header's order-of-operations rule. | |
Static Public Member Functions | |
| static constexpr int | latency_samples () |
Static Public Attributes | |
| static constexpr int | kMaxStages = 16 |
| Stage capacity. | |
| static constexpr int | kDefaultStages = 8 |
| static constexpr int | kMinPulseCount = 1 |
| Pulse count per stage. The 1–8 range is the cited hardware's. | |
| static constexpr int | kMaxPulseCount = 8 |
| static constexpr double | kRepeatDuty = 0.5 |
| High fraction of each pulse in repeat mode. | |
| static constexpr double | kSlideMs = 30.0 |
| Constant-time portamento duration — "a constant time portamento very
similar to the Roland TB-303" [Intellijel Metropolis Manual v1.30]. | |
| static constexpr std::uint32_t | kRandomSeed = 0x2A3Bu |
| Seed for SeqDirection::random. | |
| static constexpr int | kRandomDrawAttempts = 64 |
| Attempts a random draw makes before falling back to a deterministic forward scan. | |
| static constexpr double | kMaxPeriodMs = 4000.0 |
| Longest clock period the repeat duty tracker will believe, in ms. | |
| static constexpr double | kMaxSlideMs = 60000.0 |
| Ceiling on the slide time. | |
The pulse-count stage sequencer.
(lineage — informative) The Roland-System-100M-format Ryk M-185 and its Eurorack descendant the Intellijel Metropolis are stage sequencers rather than step sequencers: a small number of stages, each carrying a pitch, a pulse count (how many clocks that stage lasts) and a gate mode governing the gate across those pulses [Intellijel, Metropolis Manual v1.30, 2020 — "eight STAGES, each with its own assignable gate mode, pulse count, ratchet count, and pitch value"; "PULSE COUNT sets the number of repetitions from 1 to 8"]. Cited for concepts and topology only.
The pulse count is what makes this different from a step sequencer with a length knob: a stage that lasts three clocks is one musical event with a duration, so rest at pulse count 3 is three clocks of silence you can hear the shape of, and hold at pulse count 8 is a tied note. A step sequencer spells those with three or eight steps you then have to keep in sync when you edit the pattern.
USE. Acid basslines — eight stages, mostly single, one or two with slide, pulse counts of 1–2, into a TB-303-style voice: the interplay of slide and pulse count is the genre. Generative melody — random direction, a few rest stages, a QuantizeScaleT downstream: never repeating but always in key. Polymeter against drums — set N to 5 or 7 with repeat gates while a 4/4 drum clock runs, and the sequence drifts in and out of phase with the beat (the M-185 party trick). Long tension builds — one stage at pulse count 8 in hold: a note held for eight clocks, then release.
Ratchets are not baked in. The hardware's per-stage ratchet is a ClockMultT (kit) upstream of the clock input, or repeat mode. Duplicating the kit inside a sequencer is how two definitions of a subdivision end up in one library.
RT contract: as the header. Fixed-capacity arrays, no allocation anywhere.
|
inline |
|
inline |
The modular reset jack (verb 2): position to the top of the pattern, gate low, pitch CV held, RNG untouched.
The playhead is placed on stage 0, or on the first non-skipped stage at or after 0 if stage 0 is skipped, so "the first clock after a reset lands on the first playable stage's first pulse" holds under any skip pattern. The measured clock period survives, because it is a property of the incoming clock rather than a position in the pattern.
|
inline |
|
inline |
|
inlinestaticconstexpr |
|
inline |
|
inline |
|
inline |
|
inline |
Advances one sample. See the header's order-of-operations rule.
|
inline |
0-based pulse index inside the current stage.
|
inline |
|
inline |
The lifecycle verb (verb 1): everything apply_reset_edge() does, plus held outputs to zero, the clock-period measurement forgotten, and the RNG rewound to its seed.
|
inline |
|
inline |
|
inline |
|
inline |
|
inline |
|
inline |
|
inline |
|
inline |
|
inline |
|
inline |
|
inline |
|
inline |
|
inline |
|
inline |
|
inline |
|
inline |
|
inline |
|
inline |
True once the first clock after a reset has landed.
|
staticconstexpr |
|
staticconstexpr |
Longest clock period the repeat duty tracker will believe, in ms.
Beyond it the clock is treated as stopped rather than as very slow, the same reasoning ClockMultT documents. [design parameter] default 4000 ms, range 250 .. 30000 ms.
|
staticconstexpr |
|
staticconstexpr |
Ceiling on the slide time.
Two orders past the documented 1–500 ms range — a minute-long portamento is already musically absurd — so it only ever catches a nonsense value on its way into a sample-count conversion. [design parameter] default 60000 ms ceiling, range 1000 .. 600000 ms.
|
staticconstexpr |
Stage capacity.
Eight mirrors the cited hardware; the wider cap is ours. [design parameter] default 8 stages, range 1 .. 16.
|
staticconstexpr |
Pulse count per stage. The 1–8 range is the cited hardware's.
|
staticconstexpr |
Attempts a random draw makes before falling back to a deterministic forward scan.
Rejection sampling has no worst-case bound, and an audio thread cannot have an unbounded loop; the fallback keeps the block RT-safe and still fully deterministic. Only reachable when nearly every stage is skipped (at 15 of 16 skipped the fallback fires on ~1.6 % of advances). [design parameter] default 64, range 8 .. 1024.
|
staticconstexpr |
Seed for SeqDirection::random.
A config value, never automatable (series law 2). [design parameter] default 0x2A3B, range 0 .. 2^31 − 1.
|
staticconstexpr |
High fraction of each pulse in repeat mode.
[design parameter] default 0.5, range 0.1 .. 0.9.
|
staticconstexpr |
Constant-time portamento duration — "a constant time portamento very similar to the Roland TB-303" [Intellijel Metropolis Manual v1.30].
[design parameter] default 30 ms, range 1 .. 500 ms.