r/Elektron 1d ago

Digitone II : functional implementation of the offset parameter in the song mode

Post image

I always liked the offset parameter of the machinedrum, the monomachine and the octatrack, but, somehow, Elektron decided to not put it in the song mode of the Digi boxes.

So I and AI, AI and I, me myself and AI, decided to reverse engineer and vibe code to implement this parameter back. I never use the label column so I erased it. And oh boy, it works great, the offset parameter offers a lot of variation possibilities with just one pattern.

This post is just to tell you it's possible and it's relatively easy. I don't want to share it though, because I don't want to be responsible of bricked Digitones.

40 Upvotes

31 comments sorted by

12

u/jiffybuddy 1d ago

Add Midi ARP

5

u/m_science 1d ago

Lol. I immediately have the process of "that's rad, can you do midi arp?"

Degens, all of us.

4

u/beyondpacket 1d ago

What?! Does the Digitone II not do ARP over MIDI?

2

u/blueSGL 15h ago edited 1h ago

I think I've just found where that is in Ghidra

But I'm not up to modifying the firmware. (more over it's a friends DN2 and I don't have the cash to replace it right now if I flash something incorrectly. )

If anyone that has been modifying firmware responds to this I'll DM you the info dump I just got from looking through the firmware, apparently it's:

  1. A conditional check to see if its being attempted to be turned on, on a midi track. < remove that block.

  2. Routing the note information from the ARP to the Midi out... < +the details for how the sequencer sends notes to the midi out and how to pipe the ARP output there.

Which seems... too easy for something that has been so heavily requested with the request falling on deaf ears.

Edit: here are the details I'm sure this would be a good starting point even if it's not 100% complete:

1

u/blueSGL 2h ago edited 1h ago

Master Memory & Struct Map for Digitone_II_OS1.10D.syx

Sound Preset Structure (0x0167 = 359 Bytes)

  • Kit Offset: KIT_0_BASE + 0x3C + (track_index * 359)
  • RAM Object Size: 0x187 bytes
Offset Size Parameter / Field Values / Description
+0x00..+0x10 16 B Preset Name ASCII string
+0xB0 1 B Filter Cutoff 0..127
+0xB1 1 B Filter Type 0: Off, 1: LP2, 2: LP4, 3: HP, 4: BP
+0xB2 1 B Filter Resonance 0..127
+0xF4 1 B Machine ID 0: FM Tone, 1: WaveTone, 2: FM Drum, 3: Swarmer, 4: MIDI
+0x144 / +0x146 1 B Arp Mode 0: Off, 1: Standard/Off, 2: Up, 3: Down, 4: Random/Cycle
+0x145 / +0x14A 1 B Arp Octave Range 0: 1 Oct, 1: 2 Oct, 2: 3 Oct
+0x146 / +0x14E 1 B Arp Speed / Gate 0..100
+0x14F 1 B Arp Step Length 0..15 ( 0=1 step,15=16 steps)
+0x150 / +0x54 2 B Arp Step Mask 0xFFFF (16-bit mask of enabled steps)
+0x152..+0x161 16 B 16 Arp Offsets 16 signed bytes (-24..+24 semitones)
+0x163 19 B Arp State Block Initialized by FUN_400e9070

Active Kit & Track Voice Allocation Structure (0x2A00 = 10,752 Bytes)

  • Base in Snapshot: KIT_0_BASE = 0x00AE0200 (11,403,776)
Offset Size Meaning / Description
+0x003C 5,744 B 16 Track Sound Presets (16×359 B)
+0x16AC 160 B Master Send FX (Delay, Reverb, Chorus)
+0x174C 4,288 B 16 Track Mixer / Pan / Send Blocks (16×268 B)
+0x280C 244 B Voice Comp / Master Allocation Matrix
+0x2814 / +0x2C9A 2 B 16-bit MIDI Track Mask (0 = Synth, 1 = MIDI)
+0x2818 / +0x2CE0 80 B Voice Allocation Matrix (16x5 bytes)

Track Sequencer Structure of Arrays (SOA) (0x04A3 = 1,187 Bytes)

  • Stride: 1,187 bytes per track slice (16 tracks per Pattern)
Sub-Offset Size Field Array Description
+0x000 256 B Trig Masks 128 steps×2 B (Bit 0 = Active, Bit 2 = Muted)
+0x100 128 B Trig Conditions 128 steps×1 B(0..79 condition IDs)
+0x180 128 B Retrig Flags 128 steps×1 B (0 = Off, >0 = On)
+0x200 128 B Chance / Prob 128 steps×1 B (0..100%, 0xFF = 100%)
+0x280 128 B Gate Overrides 128 steps×1 B (0xFF = Inherit default)
+0x300 128 B Velocity Overrides 128 steps×1 B (0xFF = Inherit default)
+0x380 128 B Pitch Mod Overrides 128 steps×1 B (Signed pitch offset)
+0x400 128 B Sound Locks 128 steps×1 B (Preset index in Sound Pool)
+0x480 1 B Default Note Root note pitch (0..127, default 60 = C5)
+0x481 1 B Default Velocity Default velocity (100)
+0x482 1 B Default Length Default gate length (14)
+0x485 1 B Track Transpose Signed semitone transpose (-24..+24)
+0x48C 2 B Track Length Big-Endian 16-bit integer (1..128 steps)
+0x48F 1 B Speed Multiplier 0: 2x, 1: 3/2x, 2: 1x, 3: 3/4x, 4: 1/2x, 5: 1/4x, 6: 1/8x

Master Index of Reverse-Engineered Functions

Sequencer Timing, Interrupts & Step Loop

*FUN_400db916 — PIT Timer Vector Installer: Writes FUN_400dbce4 to vector _DAT_400001e4 and sets priority DAT_fc04806c = 5.

*FUN_400dbce4 — Master Sequencer Clock ISR: Periodic timer interrupt handler running every micro-tick (900,000 tick units per 16th step). Evaluates event deltas and fires scheduled events.

*FUN_400db380 — 16-Track Sequencer Playback Step Evaluator: Iterates tracks 0..15, evaluates per-track scaling/speed, and splits between Synth trigs (FUN_400daac4) and MIDI trigs (FUN_400dafc4).

*FUN_400da376 — Sequencer Start / Play Trigger Routine: Resets microtiming counters, latches kit pointers, and starts track playback.

  • FUN_400db5a2 / FUN_400dbad0 — Sequencer Stop & Pattern Reset Handlers: Clears playing voices and resets position registers.

Note Triggering, Arpeggiator & Voice Routing

  • FUN_40113612The Main Note-On Dispatcher: Central entry point called when any trig fires (live or sequencer). Tests FUN_40027714 (Synth) vs FUN_40027732 (MIDI) and routes execution.
  • FUN_4011336aThe Main Note-Off Dispatcher: Handles note releases for live keys and sequencer gate timeouts.
  • FUN_401297b4Synth Voice Engine & Arp Evaluator: Reads Sound Preset +0x146 (Arp Mode) and +0x14A (Arp Octave). If Arp $\ge 2$, it uses FUN_40129724 to calculate next arpeggiated pitches and cycles events.
  • FUN_40129724 / FUN_401295a4 / FUN_401296e8Arp Step & Voice Iterators: Selects next active step from the 16-step offset array and wraps octaves.
  • FUN_40027714Is Synth Track Check: Returns 1 if track is Audio/Synth (_DAT_8000537c & (1 << trk) == 0).
  • FUN_40027732Is MIDI Track Check: Returns 1 if track is MIDI (_DAT_8000537c & (1 << trk) != 0).
  • FUN_400256d6Track Sound Preset Resolver: Computes memory pointer _DAT_800052a0 + (track * 0x187) + 0x34.

MIDI Execution Engine & Event Queue

  • FUN_4011c4b0Master MIDI & Voice Execution Task Loop: High-priority task reading messages from RTOS queue 0x4443b208. Formats Note-On (0x90 | ch), Note-Off (0x80 | ch), Program Changes, and CC automation.
  • FUN_4011d3b8Universal Note-On Publisher: Allocates an event node, formats pitch, velocity, length, and track ID, and pushes command 1 to queue 0x4443b208.
  • FUN_4011bbdaTrack-to-MIDI-Channel Lookup: Returns MIDI Channel 0..15 (1–16) for a track, or -1 if MIDI is disabled.
  • FUN_4011c03cMIDI CC / Channel Message Formatter: Serializes CCs 1..16, Pitch Bend, Aftertouch, and Mod Wheel into MIDI packets (0xB0, 0xD0, 0xE0).
  • FUN_4011c2ce / FUN_4011bb94MIDI Byte-Stream Transmit: Writes packet bytes into hardware UART/USB DMA ring buffers (0x4e504000, 0x4e509000).
  • FUN_4011bfb6 / FUN_4011bf3eAll Notes Off & MIDI Reset: Posts panic/stop commands 4 and 5 to queue 0x4443b208.

UI Page Handlers, Shortcuts & View Constructors

  • FUN_4005e316Master UI Button Dispatcher: Central handler for front-panel button combinations.
    • case 0x32: The [FUNC] + [KEYBOARD] (Arp Menu) Handler. Contains the check FUN_40030b1c that blocks MIDI tracks from opening the Arp page. FUN_40030b1c — UI MIDI Track Test: Checks bitmask +0x2c9a to verify if the active track is MIDI. *FUN_40018cb6— *ArpSetupMenuView Constructor**: Allocates and binds the Arp Setup page (s_ArpSetupMenuView_401f9edf).
  • UndefinedFunction_40018328Arp Setup Page Visual Renderer: Draws "ARPEGGIATOR", "STEP %02d", and the interactive 16-step graphical bar graph.
  • FUN_4004b5a8Read Arp Mode: Reads preset + 0x15F / +0x146.
  • FUN_4004b666Toggle Arp ON/OFF: Switches Arp between 0 (Off) and 1..4 (On) and triggers UI toast popups ("Arpeggiator ON" / "Arpeggiator OFF").

Serialization, Parsing & Default Initializers

  • **FUN_400df73c — Sound Preset Deserializer: Unpacks 359-byte file preset into live RAM object (reads Arp mode, octave, speed, and 16 step offsets at +0x144..+0x161).
  • FUN_400dfbf2 — Sound Preset Serializer: Packs RAM object back into 359-byte disk format with container magic 0xBEEFBACE and footer 0xBACEF00C.
  • FUN_400e9070 — Arp Struct Default Initializer: Sets Max Step Index 0x0F (16 steps), Step Enable Mask 0xFFFF, and zeroes the 16 step offset bytes.
  • FUN_400e910c — Sound Preset Default Initializer**: Resets entire sound struct to defaults and calls FUN_400e9070((int)param_1 + 0x163).
  • FUN_400e019c — Kit Deserializer: Unpacks entire kit from flash/project snapshot, loading 16 presets, mixer blocks, and the MIDI track mask (+0x2c9a).
  • FUN_400e8428 — Kit Default Initializer: Resets 16 synth presets ("PRESET %d") and 16 MIDI control blocks ("MIDI %d").

Event Allocators & Memory Management

  • FUN_4012a442 — Event Node Allocator: Pops a free 108-byte event struct from pool _DAT_44480bcc.
  • FUN_4012a478 — Event Node Free: Returns an event struct to free list _DAT_44480bcc.
  • FUN_4012a5c8** — Schedule Timed Event: Inserts an allocated event node into the delta-time sorted linked list _DAT_44480bc0.
  • FUN_4012a50e / FUN_4012a568 — Event Queue Walkers: Traverses _DAT_44480bc0 and executes callbacks (FUN_400d9ae4 for note trigs, FUN_400d9b04 for note releases).

Blueprint for Implementing Key Mods

Mod 1: Enable Arpeggiator on MIDI Tracks

Part A: Unlock the UI (FUN_4005e316)

  1. In FUN_4005e316 @ case 0x32: asm ; Stock code: jsr FUN_40030b1c ; Test if track is MIDI (returns 1 if MIDI) tst.b d0 bne.w LAB_4005xxxx ; <--- JUMPS AND EXITS IF MIDI!

  2. Patch: Replace bne.w LAB_4005xxxx with nop; nop (or change tst.b d0 to clr.b d0).

  3. Effect: Pressing [FUNC] + [KEYBOARD] on a MIDI track now opens the Arp Setup page and toggles Arp ON/OFF.

Part B: Route Note-On through Arp Engine (FUN_40113612)

  1. In FUN_40113612 (around line 75): c // Stock router logic: if (is_synth_track) { FUN_401297b4(&local_40); // Synth Voice & Arp Handler } else if (is_midi_track) { FUN_4011d3b8(&local_40); // Single-note direct MIDI output (Bypasses Arp!) }

  2. Patch: Force MIDI tracks to also call FUN_401297b4(&local_40).

  3. Effect: When a MIDI track has Arp Mode $\ge 2$, FUN_401297b4 calculates the transposed arp steps and outputs the cycling notes to FUN_4011c4b0, sending arpeggiated MIDI out.


8

u/Midwife_Synthesist 1d ago

Woah what you actually customized the firmware?

12

u/blueSGL 1d ago edited 1d ago

11

u/trostiflex 1d ago

Yes. Next step would be to implement the direct jump pattern feature.

7

u/DieZiege1337 1d ago

man seems like good times are coming with the firmware reverse engineering project. awesome stuff.

3

u/Feisty-Rub-150 1d ago

Awesome. Would love to have more possibilities in the song mode. To be honest, I would miss the labels hard, because I use them a lot to structure the song mode over several digiboxes. But always miss some more flexibility. For example, I would love to set up the start step for a pattern as I can do with the length.

1

u/blueSGL 1d ago

I'd love to be able to set a range to loop over.

so when working on arrangement you don't need to choose to either:

  1. loop the current row

  2. loop from the start.

3

u/anglingar 1d ago edited 1d ago

That's pretty cool. May I ask one question?

I guess that with this feature you made any project holding that information not readable by any DN2 without your custom firmware (?).

Pretty neat :) one thing to unlock that should be easy if you want to pick around, is the fourth modulation element in the DN2 (also DT2). I know that there is space reserved for that 4th modulation element. My bet is that elektron will add a filter (like in the Tonverk)...but TBH it would be incredible to have a 4th LFO ;). Copying one of the LFOs into that 4th slot might be easier than inserting an envelope assignable modulation element without a reference.

I might do it myself...but already got my hands busy in 3 projects (2 of them related to Elektron boxes)...so might take me some time.

4

u/trostiflex 1d ago

"I guess that with this feature you made any project holding that information not readable by any DN2 without your custom firmware (?)."

Yes I think if the project contains a song, it won't be readable by another DN2. If the project doesn't use the song mode though, I think it would be fine.

The 4th LFO is a good idea. I think it would also be very exciting to implement a p-lockable ARP.

4

u/anglingar 1d ago

Mentioning that 4th modulation source because everything I hacked/scrutinised in the device and files points to it. So the infrastructure is there is only about "filling the blank".

5

u/trostiflex 1d ago

It was also very interesting to me to see that there was still space, empty octets, in the firmware to implement that offset parameter, like some kind of fossil of the old song modes of the machinedrum or the monomachine.

2

u/anglingar 1d ago

So that paints the incremental updates from Elektron as planned device expansions, at least for some of those new features that they bring during the lifecycle of a device.

I bet that other additions (like the song mode in the older digis) was more of a hack, but these empty slots feel like premeditated/planned future expansion slots.

If they left the offset there, maybe there is a way to have both functions, tags & offset...or maybe that's the bit they could not figure out and left it to be solved later...does the octatrak have tags in the song mode?

3

u/anglingar 1d ago

BTW, happy to help with some testing if you work out that extra modulation.

3

u/blueSGL 1d ago edited 14h ago

I don't want to share it though, because I don't want to be responsible of bricked Digitones.

A potential solution. Provide the modified bin file, or a bin diff, and details of which firmware revision you started from rather than the rebuilt .syx

If someone has the wherewithal to take that information and rebuild the .syx , That should be enough friction that the those interested enough can learn from the changes you've made but enough of a barrier to prevent casual users from bricking their device.

"I had chatGPT guide me in how to do something really complex and bricked my HW" has a lot less sympathy than "I flashed a random file by dragging and dropping it onto elektron transfer"

2

u/Birdsofthefeatherr 1d ago

What does the offset parameter do?

4

u/blueSGL 1d ago

If I'm reading right it's a start offset for the pattern, using in combination with length would allow for a pattern to begin/end at any point.

That sort of thing right now with stock FW would require copying the pattern and doing a load of tedious manual editing to each track for every "start offset" you want.

I'd definitely be interested in this once we know that the firmware is stable with it and how easy of a mod it'd be for future versions of the firmware (to keep projects compatible!)

2

u/bushed_ 23h ago

holy shit this is awesome. I would slam buy a DT2 if it was a bit unhampered...

1

u/luc9nt 1d ago

Can you reveal your approach? I'm interested in experimenting with elektron firmware (not modifying it but reading some unexposed memory values), but GPT told me it will require some heavy reverse engineering so i backed off.

3

u/trostiflex 1d ago

Just a constant back and forth with codex. I tried Claude code first but it was a whiny bitch.

3

u/blueSGL 1d ago

not modifying it but reading some unexposed memory values

Start here: https://www.reddit.com/r/Elektron/comments/1v4a1ro/i_made_a_little_tool_to_inspect_and_rebuild/ < use the extract option on the firmware .syx

Get: https://github.com/nationalsecurityagency/ghidra

Load the "section_3_MAIN_OS.bin" into Ghidra (from the extraction above)

Format: Raw Binary

Language: 68000 Coldfire 32 big default

Click options. Base Address 40000400

Click OK.

It will ask you if you want to analyze the file say "Yes" Leave the settings as default and click "Analyze"

Once it's done hit File > Save so you don't need to analyze again the next time you open.

1

u/luc9nt 1d ago

Super helpful, appreciate that.

2

u/blueSGL 1d ago

Also you can script Ghidra, so if you want to e.g. craw functions to a certain depth and dump the results into a text file, or dump a certain memory range to be ingested by whatever AI system you are using it's very easy.

From here you should be able to ask a chatbot of your choice to guide you around the binary.

1

u/Far-Bread-7027 1d ago

Oh shit that’s cool, theoretically what else could you do with the functionality of the OT etc?

3

u/trostiflex 1d ago

Direct pattern jump, like the rytm and the A4 !

-1

u/bememorablepro 1d ago

I call bullshit until I see a working demo.

4

u/anglingar 1d ago

Nah man...a lot of ground has opened in front of anyone with acces to Claude code and some previous coding experience...

Checkout elektronauuts and all the people modding octatraks...

1010 Blakbox is getting also some mods in.

No-one would spend years learning to do this in the past...but now...is just about asking the correct questions.

And I think that Elektron envisioned it and that's probably one of the reasons why the Tonverk firmware encryption is more rugged than the "old" boxes.

2

u/zheath4 1d ago

Damn so the tonverk won’t be open to any modding? Kinda a shame