The 2-D (Cartesian) sequencer. More...
#include <cartesian_walk.hpp>
Classes | |
| struct | Frame |
Public Member Functions | |
| void | prepare (double sample_rate) |
| void | set_size (int w, int h) |
| int | width () const |
| int | height () const |
| void | set_value (int x, int y, SampleType volts) |
| SampleType | value (int x, int y) const |
| void | set_access (CartesianAccess mode) |
| CartesianAccess | access () const |
| void | set_offsets (int x_cv, int y_cv) |
| Integer CV offsets added to each axis counter. | |
| void | apply_reset_edge () |
| Verb 2: both counters home, gate low, output CV held. | |
| void | reset () |
| int | x () const |
| int | y () const |
| int | cell_x () const |
| int | cell_y () const |
| bool | gate () const |
| SampleType | cv () const |
| Frame | process (bool run_high, bool reset_edge, bool x_clock_edge, bool y_clock_edge) |
Static Public Member Functions | |
| static constexpr int | latency_samples () |
Static Public Attributes | |
| static constexpr int | kMaxDim = 8 |
| Grid cap. | |
| static constexpr int | kDefaultDim = 4 |
| static constexpr int | kMaxOffset = 1000000 |
| Bound on an axis offset. | |
The 2-D (Cartesian) sequencer.
(lineage — informative) Make Noise René (2009) is documented as "the world's first Cartesian sequencer for music synthesizers": sixteen locations in a 4×4 grid with the X and Y axes clocked independently, plus CV offset inputs added to each axis counter — "a control signal at the X-CV input… is added to the number generated by the X-Axis counter to create the X coordinate" [Make Noise, René Manual]. Cited for concept and topology only; the 8×8 cap is ours.
Two independent clocks over a grid is a genuinely different topology from a linear sequencer, and the reason is arithmetic: clock only X on a 4×4 and you loop four values; add a Y clock at four times the period and the sequence is sixteen; make the two periods coprime and the walk visits cells in an order with a super-cycle of lcm of the two — long sequences out of two cheap dividers and no memory.
The gate is a one-sample trigger, not a level, and fires on any clock edge that changes the output coordinate (a simultaneous X and Y edge is one gate). This block has no gate modes to give a gate a length, so inventing one would be inventing a tempo; a caller who wants a gate of a stated length puts a GateGenT (kit) downstream, which is also where a gate length belongs.
USE. Evolving pads — slow Y, fast X: the melody re-colours row by row. Two-hand performance — drive X-clock and Y-clock from two ClockDividerT (kit) taps at different divisions for hands-free polyrhythm. Chord tables — a chord's notes across each row: walk X for arpeggios, tap Y to change chord, with a QuantizeScaleT downstream to keep arbitrary grid values in key.
RT contract: as the header.
|
inline |
|
inline |
Verb 2: both counters home, gate low, output CV held.
The next clock lands on the home cell rather than one past it, so "reset then run" plays from the top on both sequencers in this header.
|
inline |
|
inline |
|
inline |
|
inline |
|
inline |
|
inlinestaticconstexpr |
|
inline |
|
inline |
|
inline |
|
inline |
|
inline |
Integer CV offsets added to each axis counter.
Read at clock time only, never continuously — a continuously-read offset would zipper the output between cells whenever the offset crossed an integer.
|
inline |
|
inline |
|
inline |
|
inline |
|
inline |
|
inline |
|
staticconstexpr |
|
staticconstexpr |
Grid cap.
4×4 is the cited hardware; 8×8 is ours. [design parameter] default 4×4, range 1×1 .. 8×8.
|
staticconstexpr |
Bound on an axis offset.
Any offset is equivalent to itself modulo the axis length, so a bound loses nothing musically; it exists so counter + offset cannot overflow on a runaway CV. [design parameter] default ±1,000,000, range ±(kMaxDim) .. ±2^24.