The Multi-Phasor Gate (MultiPhasorGateInternal in private/src/MultiPhasorGate.hpp) decides, per voice, whether to emit a trigger – the gate that starts a note and drives the AHD envelope and the rest of the voice chain. The Nonagon feeds it from the Theory of Time, LameJuis, and index arp, then the Multi-Phasor Gate combines phasor-based gate timing with trigger logic so that only one condition (or the right combination) actually fires a note.
m_gate[i]) and an AHD control (m_ahdControl[i]). The downstream synth uses m_ahdControl[i].m_trig as “this voice should start a note this frame.”NonagonTrigLogic) – Builds a boolean m_trigs[i] and m_newTrigCanStart[i] per voice from LameJuis triggers, index-arp “triggered,” mutes, and interrupt rules.Process – Combines those with phasor-based timing and mute to set m_ahdControl[i].m_trig and m_gate[i], and to turn the gate off after half a voice-period.The Nonagon sets these before calling SetInput (in SetMultiPhasorGateInputs):
input.m_running (transport running). Must be true for any new trigger to be allowed.m_lameJuis.m_lanes[trio].m_trigger[voiceInTrio]).NonagonTrigLogic::SetInput fills the Multi-Phasor Gate input for all 9 voices.
For each voice i:
trioId = i / 3. The “logical” voice used for trigger sources is ixToCheck = (m_unisonMaster[trioId] == -1) ? i : m_unisonMaster[trioId] (unison master or self).input.m_trigs[i] = (m_trigOnSubTrigger[trioId] && m_subTrigger[ixToCheck]) || (m_trigOnPitchChanged[trioId] && m_pitchChanged[ixToCheck])input.m_trigs[i] &= !m_earlyMuted[ixToCheck]. Reserved for future mute logic; currently always false. When true, blocks triggers.input.m_newTrigCanStart[i] = m_running && !m_earlyMuted[ixToCheck]. A new note is allowed only when the transport is running and the voice is not early-muted.input.m_mute[i] = m_mute[i] (per-voice mute).m_interrupt[trioId][jTrioId] is true and voice j has a trigger this frame and is not muted (input.m_trigs[j] && !input.m_mute[j]), then set input.m_trigs[i] = false. So a lower-index voice with a trigger can cancel the trigger for voice i when interrupt is enabled between their trios.Result: m_trigs[i] is true only when the chosen trigger source (pitch-changed or sub-trigger) fired, the note is not early-muted, and no lower-index voice “interrupts” it. m_newTrigCanStart[i] is true when running and not early-muted.
MultiPhasorGateInternal::Process runs once per frame with that input.
Timing inputs (set by the Nonagon after SetInput):
m_theoryOfTime supplies absolute modulated global phase at slot 0.m_globalPeriodSamples is the current global period in samples.m_voiceCycleRatio[i] is the positive signed 64-bit LCM of the selected clock loop ratio and all read lens loop ratios, starting at one when no clock is selected. Neither contribution is doubled. It determines the voice gate period.m_phaseRatio is the envelope source/global ratio, currently taken from loop 0. It is distinct from the voice gate ratio.A trigger is emitted when requested, allowed, and unmuted. Accepted trigger bounds capture global phase, voice cycle ratio, and global period. The gate closes when abs(globalPhase - startGlobalPhase) * capturedVoiceCycleRatio >= 0.5. Existing bounds do not adopt later topology changes. A retrigger captures fresh bounds. This 0.5 note-duration cutoff remains intentional; Theory of Time rhythm steps span complete loop cycles and do not change that cutoff or the clock frequency.
The envelope period sent in AHDControl is the captured global period divided by the captured voice cycle ratio. AHD captures that period and the source phase ratio when it receives the trigger and evaluates its own elapsed position from global phase. There is no elapsed-sample relay or circle-distance tracker.
Mute and interrupt decisions retain their existing behavior. Muted accepted requests still establish internal bounds; they do not emit an envelope trigger. Once the half-period ends, a muted voice or one that cannot start a new trigger receives release. m_anyGate reports whether any voice gate remains high.
m_gate controls note-off and the UI. Envelopes receive AHDControl (m_trig, m_release, m_phaseRatio, m_envelopePeriodSamples) rather than following the boolean gate directly.