Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
pulp::signal::StageSeqT< SampleType > Class Template Reference

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.

Detailed Description

template<typename SampleType = float>
class pulp::signal::StageSeqT< SampleType >

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.

Constructor & Destructor Documentation

◆ StageSeqT()

template<typename SampleType = float>
pulp::signal::StageSeqT< SampleType >::StageSeqT ( )
inline

Member Function Documentation

◆ apply_reset_edge()

template<typename SampleType = float>
void pulp::signal::StageSeqT< SampleType >::apply_reset_edge ( )
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.

◆ direction()

template<typename SampleType = float>
SeqDirection pulp::signal::StageSeqT< SampleType >::direction ( ) const
inline

◆ gate()

template<typename SampleType = float>
bool pulp::signal::StageSeqT< SampleType >::gate ( ) const
inline

◆ latency_samples()

template<typename SampleType = float>
constexpr int pulp::signal::StageSeqT< SampleType >::latency_samples ( )
inlinestaticconstexpr

◆ num_stages()

template<typename SampleType = float>
int pulp::signal::StageSeqT< SampleType >::num_stages ( ) const
inline

◆ pitch_v()

template<typename SampleType = float>
SampleType pulp::signal::StageSeqT< SampleType >::pitch_v ( ) const
inline

◆ prepare()

template<typename SampleType = float>
void pulp::signal::StageSeqT< SampleType >::prepare ( double sample_rate)
inline

◆ process()

template<typename SampleType = float>
Frame pulp::signal::StageSeqT< SampleType >::process ( bool run_high,
bool reset_edge,
bool clock_edge )
inline

Advances one sample. See the header's order-of-operations rule.

◆ pulse()

template<typename SampleType = float>
int pulp::signal::StageSeqT< SampleType >::pulse ( ) const
inline

0-based pulse index inside the current stage.

◆ repeat_duty()

template<typename SampleType = float>
double pulp::signal::StageSeqT< SampleType >::repeat_duty ( ) const
inline

◆ reset()

template<typename SampleType = float>
void pulp::signal::StageSeqT< SampleType >::reset ( )
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.

◆ set_direction()

template<typename SampleType = float>
void pulp::signal::StageSeqT< SampleType >::set_direction ( SeqDirection d)
inline

◆ set_num_stages()

template<typename SampleType = float>
void pulp::signal::StageSeqT< SampleType >::set_num_stages ( int n)
inline

◆ set_repeat_duty()

template<typename SampleType = float>
void pulp::signal::StageSeqT< SampleType >::set_repeat_duty ( double duty)
inline

◆ set_seed()

template<typename SampleType = float>
void pulp::signal::StageSeqT< SampleType >::set_seed ( std::uint32_t seed)
inline

◆ set_slide_ms()

template<typename SampleType = float>
void pulp::signal::StageSeqT< SampleType >::set_slide_ms ( double ms)
inline

◆ set_stage_gate_mode()

template<typename SampleType = float>
void pulp::signal::StageSeqT< SampleType >::set_stage_gate_mode ( int s,
StageGateMode m )
inline

◆ set_stage_pitch()

template<typename SampleType = float>
void pulp::signal::StageSeqT< SampleType >::set_stage_pitch ( int s,
SampleType volts )
inline

◆ set_stage_pulse_count()

template<typename SampleType = float>
void pulp::signal::StageSeqT< SampleType >::set_stage_pulse_count ( int s,
int count )
inline

◆ set_stage_skip()

template<typename SampleType = float>
void pulp::signal::StageSeqT< SampleType >::set_stage_skip ( int s,
bool on )
inline

◆ set_stage_slide()

template<typename SampleType = float>
void pulp::signal::StageSeqT< SampleType >::set_stage_slide ( int s,
bool on )
inline

◆ slide_ms()

template<typename SampleType = float>
double pulp::signal::StageSeqT< SampleType >::slide_ms ( ) const
inline

◆ stage()

template<typename SampleType = float>
int pulp::signal::StageSeqT< SampleType >::stage ( ) const
inline

◆ stage_gate_mode()

template<typename SampleType = float>
StageGateMode pulp::signal::StageSeqT< SampleType >::stage_gate_mode ( int s) const
inline

◆ stage_pitch()

template<typename SampleType = float>
SampleType pulp::signal::StageSeqT< SampleType >::stage_pitch ( int s) const
inline

◆ stage_pulse_count()

template<typename SampleType = float>
int pulp::signal::StageSeqT< SampleType >::stage_pulse_count ( int s) const
inline

◆ stage_skip()

template<typename SampleType = float>
bool pulp::signal::StageSeqT< SampleType >::stage_skip ( int s) const
inline

◆ stage_slide()

template<typename SampleType = float>
bool pulp::signal::StageSeqT< SampleType >::stage_slide ( int s) const
inline

◆ started()

template<typename SampleType = float>
bool pulp::signal::StageSeqT< SampleType >::started ( ) const
inline

True once the first clock after a reset has landed.

Member Data Documentation

◆ kDefaultStages

template<typename SampleType = float>
int pulp::signal::StageSeqT< SampleType >::kDefaultStages = 8
staticconstexpr

◆ kMaxPeriodMs

template<typename SampleType = float>
double pulp::signal::StageSeqT< SampleType >::kMaxPeriodMs = 4000.0
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.

◆ kMaxPulseCount

template<typename SampleType = float>
int pulp::signal::StageSeqT< SampleType >::kMaxPulseCount = 8
staticconstexpr

◆ kMaxSlideMs

template<typename SampleType = float>
double pulp::signal::StageSeqT< SampleType >::kMaxSlideMs = 60000.0
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.

◆ kMaxStages

template<typename SampleType = float>
int pulp::signal::StageSeqT< SampleType >::kMaxStages = 16
staticconstexpr

Stage capacity.

Eight mirrors the cited hardware; the wider cap is ours. [design parameter] default 8 stages, range 1 .. 16.

◆ kMinPulseCount

template<typename SampleType = float>
int pulp::signal::StageSeqT< SampleType >::kMinPulseCount = 1
staticconstexpr

Pulse count per stage. The 1–8 range is the cited hardware's.

◆ kRandomDrawAttempts

template<typename SampleType = float>
int pulp::signal::StageSeqT< SampleType >::kRandomDrawAttempts = 64
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.

◆ kRandomSeed

template<typename SampleType = float>
std::uint32_t pulp::signal::StageSeqT< SampleType >::kRandomSeed = 0x2A3Bu
staticconstexpr

Seed for SeqDirection::random.

A config value, never automatable (series law 2). [design parameter] default 0x2A3B, range 0 .. 2^31 − 1.

◆ kRepeatDuty

template<typename SampleType = float>
double pulp::signal::StageSeqT< SampleType >::kRepeatDuty = 0.5
staticconstexpr

High fraction of each pulse in repeat mode.

[design parameter] default 0.5, range 0.1 .. 0.9.

◆ kSlideMs

template<typename SampleType = float>
double pulp::signal::StageSeqT< SampleType >::kSlideMs = 30.0
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.


The documentation for this class was generated from the following file: