📖 What Pearson does

Chapter 11 is the second-biggest chapter in the book, after Chapter 3. Pearson teaches you to build step sequencers — circuits that play a sequence of notes in a loop. The chapter introduces:

  • The 4051 multiplexer. A chip that selects one of 8 inputs based on a 3-bit address. Used as the heart of an 8-step sequencer.
  • Boolean logic. AND, OR, NOT — the basics of how digital circuits “decide” things.
  • Binary and the 4051. How to set the 3 address bits using binary counting.

Projects (in increasing complexity):

  • The Disco Boole (Part I). A 2-step sequencer using a 4017 decade counter.
  • The Disco Boole (Part II). Adding LEDs to the previous so you can see which step is active.
  • The Standard Eight-Step Sequencer. The canonical project. Eight steps, each with a pitch knob and a trigger.
  • A Pattern-Changing Sequencer. A sequencer that switches between two patterns based on an external input.
  • A First-Order Reset Harmonization Sequencer. A sequencer that auto-resets based on the output of another sequencer.
  • A Second-Order Reset Harmonization Sequencer. Like the above, but the cascaded resets create complex interlocking patterns.

🎓 Background: our sequencer, end to end

Our firmware has a sequencer that does almost everything Pearson’s circuits do, plus more. It is implemented in main/sequencer/sequencer.c and main/sequencer/pattern.{c,h}. The key data structures:

#define PATTERN_COUNT  16
#define STEP_COUNT     16
#define SLOT_COUNT     16
#define CHAIN_LENGTH   128

typedef struct {
    uint8_t slot;            // which slot to play on this step
    uint8_t note;            // MIDI note number, 0..127 (0 = step off)
    uint8_t fx;              // punch-in effect for this step
    uint8_t fx_p1, fx_p2;    // effect params
    uint8_t filter_cutoff;   // tweak-filter cutoff, 0..255
    uint8_t filter_resonance;// tweak-filter resonance, 0..255
} pattern_step_t;

struct pattern_t {
    pattern_step_t steps[STEP_COUNT];
};

struct pattern_t patterns[PATTERN_COUNT];
uint8_t chain[CHAIN_LENGTH];
uint8_t chain_len;

When the sequencer ticks, it:

  1. Looks up the current step in the active pattern.
  2. If note == 0, the step is empty — do nothing.
  3. Otherwise, call amy_bridge_play_note(step.slot, step.note, step.fx, step.fx_p1, step.fx_p2, step.filter_cutoff, step.filter_resonance).
  4. AMY plays the slot at the given pitch with the given effect and filter.
  5. Advance to the next step. If we’ve gone past step 16, jump back to step 1 (or move to the next pattern in the chain).

This is Pearson’s Standard Eight-Step Sequencer, with 16 steps instead of 8, no knob per step (we have UART verbs instead), and a chain instead of a single loop.

🔧 Try it on the device

This chapter has the most exercises. Take your time — the sequencer is the heart of the device.

Exercise 1: the Standard Sixteen-Step Sequencer.

Clear pattern 1 and put four notes on steps 1, 5, 9, 13:

> pattern_clear 1
> step_set 1 1 9 60    ; step 1 plays slot 9 at MIDI 60 (C4)
> step_set 1 5 9 64    ; step 5 plays slot 9 at MIDI 64 (E4)
> step_set 1 9 9 67    ; step 9 plays slot 9 at MIDI 67 (G4)
> step_set 1 13 9 72   ; step 13 plays slot 9 at MIDI 72 (C5)
> bpm 120
> play

You should hear a 4-note pattern: C, rest, E, rest, G, rest, C, rest, repeat. That is the Standard Sixteen-Step Sequencer — 16 steps, each with a slot and a pitch.

If you don’t have a recorded slot 9, you can still play — AMY’s default synth will provide a patch on the fly.

Exercise 2: the Pattern-Changing Sequencer.

Add another pattern with different pitches:

> pattern_clear 2
> step_set 2 1 9 67
> step_set 2 5 9 72
> step_set 2 9 9 76
> step_set 2 13 9 79

Append both patterns to the chain:

> chain_clear
> chain_append 1
> chain_append 2
> chain_show

The chain now reads [1, 2]. When you press play, pattern 1 plays once, then pattern 2 plays once, then the chain wraps back to pattern 1. That is Pearson’s Pattern-Changing Sequencer — the hardware version uses an external input to switch patterns; ours uses a chain.

Exercise 3: chained reorder (live re-ordering).

While the sequencer is playing, swap the two patterns in the chain:

> chain_swap 0 1

You should hear the order reverse immediately. That is Pearson’s “live re-arrangement” — possible in hardware only by physically moving wires; possible in our firmware via two keystrokes.

Exercise 4: the First-Order Reset Sequencer (chain auto-reset).

If you build a chain of patterns where the last pattern is the “reset trigger” pattern, the chain wraps back to pattern 1 after the last. That is the simplest form of Pearson’s auto-reset sequencer. Our firmware does this automatically:

> chain_clear
> chain_append 1
> chain_append 2
> chain_append 1   ; explicitly loop back
> chain_append 2
> play

Plays 1, 2, 1, 2 forever. Or use the loop_chain option (if your firmware version supports it) to auto-loop without explicit appends.

Exercise 5: the Disco Boole (binary counter).

The Disco Boole is a sequencer that uses a binary counter to choose the step. Our firmware does this implicitly — the sequencer walks through steps 1, 2, 3, … which is just a binary counter that increments on each clock tick. No special verb needed.

Exercise 6: cascade (Second-Order Reset Harmonization).

Two chains, one driving the other. We don’t expose this directly, but you can approximate it with a long chain of alternating patterns:

> chain_clear
> chain_append 1
> chain_append 2
> chain_append 1
> chain_append 2
> chain_append 1
> chain_append 2

The pattern 1 and 2 will play alternately, creating a “harmonized” effect because they share the same step data but at different pitches.

🛠 Code reference

  • The pattern data structure — main/sequencer/pattern.h. pattern_step_t and pattern_t. About 50 lines of declarations.
  • The sequencer tick — main/sequencer/sequencer.c, sequencer_tick(). About 60 lines. Pulls the current step from the active pattern, calls amy_bridge_play_note(), advances the step counter.
  • The chain — main/sequencer/sequencer.c. chain[], chain_len, chain_append(), chain_remove(), chain_swap(), chain_insert().
  • The UART verbs — main/main.c. Each shell command (cmd_chain_append, cmd_chain_swap, etc.) is about 15 lines.

🚫 What we can’t simulate

  • The 4051 multiplexer chip. It’s a piece of silicon that selects one of 8 inputs based on a 3-bit address. Our firmware has no analog; the sequencer just walks an array index.
  • Boolean logic gates. Pearson uses discrete logic gates to decide “should this step fire?” Our firmware uses C if statements, which compile to conditional branches on the CPU. Same thing.