Skip to main content

Architecture overview

TŒRN is a single Teensy sketch that behaves like a small OS for a sampler-sequencer: a mode machine drives the UI, a note grid is the musical source of truth, IntervalTimers advance playback, and the Teensy Audio library renders sound.

flowchart TB
subgraph inputs [Inputs]
ENC[Encoders + buttons]
TOUCH[Touch switches]
MIDI_IN[TRS MIDI]
SD[Micro SD]
end

subgraph core [Core]
MODE[currentMode]
GLOB[GLOB / SMP]
NOTE["note[x][y]"]
LOOP[loop]
ISR[playTimer ISR]
end

subgraph out [Outputs]
LED[LED grid: 16×16 or 32×16]
ENCLED[Encoder RGB]
AUDIO[Audio graph]
MIDI_OUT[MIDI out / clock]
end

ENC --> LOOP
TOUCH --> LOOP
MIDI_IN --> LOOP
SD --> LOOP
LOOP --> MODE
LOOP --> GLOB
LOOP --> NOTE
LOOP --> LED
LOOP --> ENCLED
ISR --> NOTE
ISR --> AUDIO
ISR --> MIDI_OUT
MODE --> LOOP
GLOB --> LOOP
NOTE --> ISR

Mental model in one paragraph​

You edit a 2D grid of Note cells (step × pitch/row). Playback walks the X axis on a timer interrupt and triggers sample or synth voices through the Audio graph. The UI never owns music data directly — it mutates note[][], GLOB, and SMP, then redraws LEDs to mirror that state. Modes (DRAW, FILTERMODE, MENU, …) only change which encoder axes mean what and what loop() draws.

Runtime pillars​

1. Mode machine​

Mode *currentMode points at a struct with name, encoder min/max/pos, and knob colors. Switching modes (switchMode) rebinds encoder hardware to those ranges. See Modes.

2. Pattern + session state​

  • note[x][y] — packed note events for the loaded pattern (in EXTMEM)
  • Device SMP — BPM, samplepack/paths, filter/synth params, mutes, song arrangement
  • GlobalVars GLOB — cursor, channel, page, velocity, copy state, …

See Data model.

3. Timing​

IntervalTimer playTimer calls playback logic in an ISR so the sequencer keeps running during SD/UI stalls. Heavy work (Serial, I2C, SD, FastLED) is deferred to loop() via flags. See Main loop.

4. Audio graph​

Declared in audioinit.h: sample players, synth oscillators, envelopes, bitcrushers, filters, freeverb, mixers → SGTL5000 and USB audio output. Parameters are applied from filter/synth setting arrays. See Audio graph.

Channel map (quick)​

ChannelsEngine
1–8Sample voices (AudioPlayArrayResmp)
113-voice poly synth
13–14Mono synths (LFO / arp capable)

Details: Channels.

Where to change things​

You want to…Start in…
Change what a knob does in a screenMode defs + handlers in toern.ino, UI in toern_ui.ino / toern_filterUI.ino
Change how notes playPlayback / playNote path in toern.ino
Change sound routing or FX orderaudioinit.h + toern_filter.ino / toern_parameters.ino
Change menu pagestoern_menu.ino
Change MIDI / clocktoern_midi.ino
Change sample load/browsetoern_sample.ino + toern_helpers.ino
Change LED drawing primitivestoern_ui.ino / toern_leds.ino