theallelectricsmartgrid

The Nonagon (Sequencer)

The Nonagon (TheNonagonInternal in private/src/TheNonagon.hpp) is the core sequencer logic class. It wires together the Theory of Time, LameJuis, index arp, and Multi-Phasor Gate into a single unified polyphonic sequence generator.


1. Overview

The Nonagon is responsible for:

It manages 9 voices arranged in 3 trios.


2. Process Flow

For every micro block, the Theory of Time computes all samples in that block plus the first sample of the next block. Slot 8 holds the first sample of the next micro block (computed in the current block). At the start of each micro block, RolloverMicroblockBuffer copies slot 8 into slot 0—the first sample of this block was computed in the previous block. The Nonagon then runs at that sample (sequencer logic, outputs), and Process(j) for j=1..8 computes the rest of this block and the first sample of the next. This ensures that interpolation anywhere inside a micro block always has accurate boundary samples.

During a control frame, Process executes the following steps:

  1. Rollover and Theory of Time (sample 0):
    • SetTheoryOfTimeInput(input) prepares the global clock inputs.
    • m_theoryOfTime.RolloverMicroblockBuffer() copies slot 8 into slot 0 (sample 0 of this block was computed in the previous block).
    • If the master loop wraps (m_topIndependent), it records a start index in the note writer.
  2. Index Arp and LameJuis (Only on change):
    • If the Theory of Time had any integer position change in the micro block (m_theoryOfTime.AnyChangeInMicroBlock()), the sequencer state must be updated.
    • SetIndexArpInputs(input) calculates m_totalIndex (monodromy) and clock/read gates.
    • m_indexArp.Process(input.m_arpInput) runs the arpeggiators to find the point in the range.
    • SetLameJuisInput(input) feeds the Theory of Time gates and the index arp outputs (as m_choiceArg for the chosen strategy) into LameJuis.
    • m_lameJuis.Process(input.m_lameJuisInput) evaluates the logic matrix and sheaf to produce pitches and extra timbres.
  3. Multi-Phasor Gate (Only when running):
    • If the transport is running (m_theoryOfTime.m_running), SetMultiPhasorGateInputs(input) evaluates trigger logic (pitch-changed, sub-trigger, mutes, interrupts).
    • m_multiPhasorGate.Process(input.m_multiPhasorGateInput) determines which voices emit a trigger and tracks their gate lengths based on the master phasor.
  4. Outputs and Note Writer:
    • SetOutputs(input) gathers the results.
    • For each voice, if a trigger was emitted (m_ahdControl[i].m_trig), it:
      • Sets m_output.m_gate[i] = true.
      • Applies the trio octave switch to the LameJuis pitch (Octavize).
      • Records a note-on event (m_noteWriter.RecordNote).
    • If a voice’s gate turns off (!m_multiPhasorGate.m_gate[i]), it clears m_output.m_gate[i] and records a note-off (m_noteWriter.RecordNoteEnd).
    • It slews the 3 extra timbre modulators from LameJuis (m_extraTimbreSlew) to prevent clicks.
    • It outputs the Theory of Time phasors (m_totPhasors) for downstream LFOs.
  5. Theory of Time (samples 1–8):
    • m_theoryOfTime.Process(j, input.m_theoryOfTimeInput) is called for j = 1 through 8 to compute the rest of this micro block (samples 1–7) and the first sample of the next block (slot 8).

3. Trio Octave Switches

The Nonagon applies an octave shift per trio via TrioOctaveSwitches. The raw pitch from LameJuis is passed through Octavize(preOctave, i), which adds or subtracts octaves based on the UI state before being sent to the DSP.


4. Note Writer

The NonagonNoteWriter acts as a bridge between the core sequencer logic and the outside world (like MIDI out or UI piano rolls). It records EventData containing the voice index, pitch, start position, and extra timbres.