Skip to main content

Firmware edits

The sketch is one program. A new on-screen setting touches several files. GAIN (menu id 53) is the recent example: defines in toern.ino, EEPROM bytes, draw, encoder handling, startNew(), and the handbook.

Build with PlatformIO (pio run from the repo root). See Build setup. UI functions are marked FLASHMEM so they stay out of ITCM. Keep an eye on the ITCM line in the build output; it has to stay under 256 KB. Large buffers go in EXTMEM or DMAMEM — see Memory.

Add a menu page​

Pages are MenuPage rows near the top of toern_menu.ino. Each row has a 4-character name and an integer mainSetting. That integer is the case label in the draw and input switches. Pick one that is not already in menuPages, lookPages, recsPages, midiPages, volPages, or etcPages.

  1. Add the row and bump the matching *_PAGES_COUNT.
  2. Draw it in drawMainSettingStatus.
  3. If an encoder changes a value, handle it in handleAdditionalFeatureControls. Reset encoder min/max when leaving the page, the same way ids 50 and 53 do.
  4. If a knob click does something, handle it in switchMenu and in the button match inside checkMode (toern.ino), so the click is not treated as a generic menu action.
  5. If the value must survive reboot, add an EEPROM offset as below, write the default in both the virgin-EEPROM path of loadMenuFromEEPROM and in startNew() (toern_helpers.ino), and apply it from applyAudioSettingsFromGlobals when it affects audio.
  6. If a player can see it, update the handbook page for that menu.

EEPROM bytes​

Settings live at absolute address EEPROM_DATA_START + offset with EEPROM_DATA_START = 43. A magic byte 0x5A sits at absolute address 42. Sample-pack 0 flags sit at absolute address 200 (EEPROM_SP0_STATE_ADDR), outside this table.

SETTINGS_EEPROM_BLOCK_LEN is 55, so offsets 0 through 54 are copied to the SD settings backup. Offset 50 is the IMG migrate marker 0xA5. Offset 51 is MIDI → TRIG (sidechain voice). Offset 52 is BPM EXT analog vs MIDI clock in. Offset 53 is MIDI → CIN: bits 0–2 PPQN index, bits 3–7 hold-off ms − 1. Offset 54 is MIDI → OVWR (0 = keep occupied cells, 1 = overwrite). Inserting a byte in the middle shifts every saved unit. A shorter backup leaves the missing bytes at 0; offset 42 absent means VMOD off, offset 43 absent means FIRE off. Offset 44 absent or out of 1–25 loads as count 8. Offset 45 absent loads as size 1. Offset 46 absent loads as gravity 0. Offset 47 absent loads as colour 8. Offset 48 absent means IMG off. Offset 49 absent or out of 0–3 loads as EYES 1MIN. Offset 51 absent or invalid loads as voice 1. Offset 53 defaults to byte 2 (4 PPQN, 1 ms hold-off). Offset 54 absent or >1 loads as OVWR OFF.

Offsets 32–33 and 34–35 are uint16 values (EEPROM.put). Offset 33 is also written as a single format byte. Leave 32–35 alone.

OffsetWhat
0recMode
1clockMode
2transportMode
3patternMode
4voiceSelect
5fastRecMode
6recChannelClear
7previewVol
8flowMode
9micGain
10PPQN pulse packed byte
11simpleNotesView
12loopLength
13ledMode
14ctrlMode
15lineOutLevelSetting
16lineInLevel
17headphone volume (GLOB.vol)
18cursorType
19showChannelNr
20previewTriggerMode
21drawMode
22colorScheme
23stereoChannel
24midiSendMode
25ledStripEnabled
26ledBrightness
27spkrEnabled
28midiNoteReceive
29transportSendDelayMs
30PPQN pulse width, ms
31transportRcveDelayMs
32–33codecHfCut (uint16)
34–35draw-R mute mask (uint16)
36childLockEnabled
37MIDI pitch clamp
38mixGain14
39mixGain58
40mixGainSynth
41mixGainMaster
42voiceMode (VMOD), 0 = off, 1 = on
43fireVoice (ETC → ADV → FIRE), 0 = off, 15 = all voices, else voice 1–8, 11, 13, or 14
44fireLevel (ETC → ADV → FIRE), particle count 1–25. Encoder 2. Out of range loads as 8
45fireSize (ETC → ADV → FIRE), particle size 1–4. Encoder 1. Out of range loads as 1
46fireGravity (ETC → ADV → FIRE), 0–8. 0 keeps drifting sideways. Higher pulls toward the playhead. Encoder 3 after one click. Above 8 loads as 0
47fireColor (ETC → ADV → FIRE), 0–8. 0 white, 8 voice colour. Encoder 3 after a second click. Above 8 loads as 8
48imageMode (MODE → IMG), 0 = off, 1 = on
49eyesMode (ETC → ADV → EYES), 0 = OFF, 1 = 1MIN, 2 = 5MIN, 3 = 15MIN. Out of range loads as 1
50IMG one-time migrate marker (0xA5)
51sidechainVoice (MIDI → TRIG), 0 = OFF, else voice 1–8, 11, 13, or 14. Invalid loads as 1
52analogExtClock (BPM encoder-3 click in EXT), 0 = MIDI clock in, 1 = analog CLK-IN (J26)
53MIDI → CIN. Bits 0–2: PPQN index 0..7 = 1/2/4/8/12/16/24/32. Bits 3–7: hold-off ms − 1 (1–32 ms). Default 2 (4 PPQN, 1 ms)
54MIDI → OVWR, 0 = OFF (do not overwrite occupied cells), 1 = ON. Absent or >1 loads as 0

Named constants for 38–41 are EEPROM_MIX_GAIN_* in toern.ino. Offsets 42 through 49 are raw bytes at EEPROM_DATA_START + offset.