Teaching Claude to use my Novation Circuit Tracks - Part 2
Reverse engineering a binary file format and MIDI SysEx protocol so an AI can write music directly to hardware.
In Part 1, we got Claude talking to the Novation Circuit Tracks over MIDI — but we hit a wall. To actually create and load projects, we’d need to reverse engineer the proprietary ncs binary format and the SysEx transfer protocol.
TLDR: We did it. And it was a lot of fun.
Table of Contents
- Reverse Engineering the NCS format
- Reverse Engineering the SysEx message protocol for writing/reading projects
- Wrapping up
1. Reverse Engineering the NCS format
Doing this has been both tedious and fun/exciting. I have to admit that having Claude Code help for this task made it possible. I think I’d have otherwise been too lazy to even start doing this.
As we already know, the ncs format (Novation Circuit [Storage|System|Song|Something]?) is a binary format that contains all the information related to a project. Some examples
so you get an idea:
- Global settings like Tempo, Swing, selected effects, etc.
- Pattern information: steps sequenced, pattern chaining, scenes, etc.
- Mixer settings: mute states, levels, panning etc.
- Track information: selected synths and selected drums
- Synth patches: I didn’t expect this, but the project also contains a full definition of the 2 patches selected.
Combining a few different approaches, Claude and I were able to almost fully decode the format. This makes the MCP server capable of writing projects to the Circuit. Let’s dive into it!
Researching existing knowledge
First of all, I started checking if there was already someone out there who tried to make this happen. We found a few resources that are worth mentioning:
- userx14’s Circuit Tracks Reverse Engineering repository is inspiring. It’s more focused on reverse engineering the Hardware and the Firmware.
- This GIST also started from userx14. We can find a comment there by Ondrysak that
shows how reversing the WASM is helpful. They even created a tool to partially decode
ncsfiles.
Thanks to all these resources, we didn’t start from scratch. Claude had already some first good information and assumptions that we used to start the core of the reverse engineering process. Let’s take a look.
Claude: There's a WASM validator from Novation Components that reveals
the file structure. Let me check that firmware RE gist for more
details.
[analyzes WASM string table]
This is the complete data model! The WASM validator contains
string literals with every field name — swing, scaleType,
scaleRoot, delayPreset, reverbPreset...
We didn't even need more example files. The field names from
the validator strings let us correctly identify everything.
Reverse Engineering Well-Known NCS files
The idea is simple: let’s create sample NCS files, and tell Claude to take a look at the binaries and do diffs between them to find where the different settings and parameters are. We started with an empty project file as the base, and then we went feature by feature, comparing the empty file against them.
Me: Okay, i want to reverse engineer the ncs format. In the folder
there are 2 files. Both are Novation Circuit Tracks projects with
the same presets selected, etc. The only difference is that the
"2 notes.ncs" has a note in the first step of the sequence for
synth1 and synth2.
My goal is to understand the format and be able to eventually
write projects into the circuit.
Claude: Both files are exactly 157KB. Let me find all the differences
between them.
Only 3 differences:
1. Name at offset 0x10: "Empty" vs "2 notes"
2. Offset 0x2E4: 00 07 00 00 00 00 00 60
→ 01 07 00 00 3c 06 00 62 (synth1 note)
3. Offset 0x6824: 00 07 00 00 00 00 00 60
→ 01 07 00 00 54 06 00 3e (synth2 note)
The flow we used was:
- I create a project, and do something (change tempo, change swing, set up patterns, etc.)
- I download the project using Novation Components
- I feed Claude Code with the project, and explain what I did.
- Claude Code - using tools they created - diffs against the empty project, and finds in which bytes this information lies
- Claude writes code to parse NCS files and vice versa, all backed with automated tests that check the 2 ways and for exact byte matching.
- Repeat
After a few rounds of doing this, we were able to decode the majority of features. The NCS files are structured, so whenever we decode the pattern structure for let’s say Synth 1, we could easily derive where patterns for Synth 2 and all the other tracks were defined.
As said before: this is clearly a task I would have been waaaaay too lazy to do without using any AI Assisted coding. Doing it with Claude Code was fun and felt like a constant progress and discovery, even though my role was mostly to test the results in the Circuit Tracks and give feedback to Claude about what was wrong. But I also learned a lot!
Claude: Here's what I'd need — grouped by the minimum number of test
.ncs files:
File 1: "ScaleAndFX.ncs" — Change these from an empty project:
- Scale to Major (instead of Natural Minor)
- Root note to G (instead of C)
- Reverb preset to preset 5 (Hall)
- Delay preset to preset 8 (16th Ping Pong Swung)
File 2: "MixerAndSends.ncs" — Change from empty:
- Synth 1 level to something non-default
- Add some reverb send on synth 1
- Add some delay send on drum 1
- Mute synth 2
Me: I've added the project to the example-projects-ncs folder,
have fun!
Claude: All 5 files! Let me diff them all against Empty to map every
unknown field.
| Field | Offset | Source File | Value |
|--------------|----------|---------------|--------------------|
| scaleType | 0x26D0D | ScaleAndFX | 1 = Major |
| scaleRoot | 0x26D0E | ScaleAndFX | 7 = G |
| delayPreset | 0x26D0C | ScaleAndFX | 7 = delay 8 (0-ix) |
| reverbPreset | 0x26D0F | ScaleAndFX | 4 = reverb 5 |
| Reverb sends | 0x26FE8+ | MixerAndSends | 8 bytes, per track |
| Delay sends | 0x26FFA+ | MixerAndSends | 8 bytes, per track |
2. Reverse Engineering the MIDI SysEx message protocol for writing/reading projects
So now we have a way to create projects from a prompt:
Me: Let's create a progressive and deep ambient song
After that, Claude Code would use the MCP to create an NCS file that I still needed to manually upload to Novation Components and send to my Circuit Tracks. We had to close the loop: our MCP server needed a way to write and read projects from the Circuit Tracks directly.
Aside: what is MIDI SysEx?
As you know, we are using MIDI-over-USB to connect to the Circuit Tracks and interact with it. But, what is MIDI? MIDI stands for Musical Instrument Digital Interface and we can say it is just a communication protocol standard developed by America and Japan. The most common usage is to send notes from a device (e.g. a keyboard) to another (e.g. a synthesizer) to make it sound. But there is much more to it. The MIDI protocol specifies multiple message types. A few of them are:
- Note Messages: to send note information (number, velocity, channel). In the example above, the external keyboard basically sends Note ON messages when a key is pressed, and Note OFF messages when the key is released.
- Control Messages: as the name says, these are messages that are generally sent from a device to control parameters of the target device. This could be for example to control parameters of the synthesizer’s engine, the cutoff of a filter, etc.
- Midi SysEx: they stand for System Exclusive Messages. As the name indicates, this type of messages are meant to be used by product manufacturers. For instance, our Circuit Tracks uses SysEx for many functions, mostly everything related to transferring files, but not only that.
If MIDI were a language, Note and Control messages would be the shared vocabulary — words every speaker understands. SysEx messages are more like a private dialect that only one manufacturer speaks.
Cracking the SysEx Transfer Protocol
I asked Claude to take a look at this problem. If Novation Components can do it, we should be able to do it as well!
Me: We are able to generate .ncs files for the Novation Circuit
Tracks. Now I want to find a way to send those files to the
circuit, analog to how the Novation Components app does it.
The first approach was to use MIDI Monitor. I set it up and then used the Novation Components software to transfer a project to the Circuit Tracks.
But that felt too manual, there had to be a better way. Novation Components is a web app. I gave Claude Code access to Chrome and asked them to figure out the protocol by watching the traffic directly. What happened next was amazing. Claude navigated to the Novation Components site and injected a JavaScript snippet using DevTools to intercept all WebMIDI SysEx messages. Then, they asked me to help them trigger a project transfer to the Circuit Tracks and they captured the entire exchange.
Claude: [intercepts WebMIDI traffic via Chrome DevTools JS injection]
This is incredibly valuable data! The protocol is completely
different from the firmware update gist — it's a file
management protocol.
It's MSB interleave encoding, not bitstream packing! The first
byte 0x00 is the MSB header for the next 7 bytes, and since
all of "USER" have MSB=0, it's just 0x00 followed by raw ASCII.
Everything matches now. The protocol uses:
1. MSB interleave v2 — bit 0 of MSB byte = MSB of first
data byte (ascending bit order)
2. Standard zlib CRC32 (reflected) — not the non-reflected
variant from the firmware gist
The checksum 0x2D9CB759 matches exactly with zlib.crc32().
This is much simpler than expected.
Seeing Claude using my browser directly felt crazy — what a time to be alive! Later on, I’d use this approach to also decode reading projects from the device with almost no manual intervention.
3. Wrapping up
We now fully worked around the main problem we had since part 1: the AI is able to load a project from the Circuit Tracks, modify it and send it back to the device. But don’t just take my word for it. I want you to see (and listen, of course). So, it’s showtime!
Me: Let's make an ambient drone based short song on my Circuit Tracks!
I'm working on Project 5 (slot index 4). Let's make something that
uses all tracks, sets up macros for live playing using the standard
macro layout, uses p-locks controlling the macro knobs and other
parameters, etc., this is a demo to show off! Don't play it in the
internal sequencer, save it directly to the Circuit Tracks in one go.
<!-- Claude loads parameter references for patches, macros,
mod matrix, and lookup tables in parallel — getting exact
waveform names, filter types, LFO shapes, macro destination
indices, and mod matrix source/dest names -->
Claude: [scans MIDI ports, finds "Circuit Tracks MIDI", connects]
Connected to Circuit Tracks MIDI.
drum_samples_scanned: 64
Now let me build and load the full ambient drone song. This will
be a 4-pattern song called "Ethereal Drift" with rich patches,
mod matrix routing, standard macro layout, p-lock automation,
and lush FX.
<!-- Claude designs two synth patches from scratch. Base parameter
values are set LOW for anything macros should sweep upward,
because macros ADD to the base — they don't replace it. -->
Synth 1 — "Abyss Pad":
Sine table + triangle oscillators with subtle detuning.
LP24 filter starting at 20 so macros can sweep the full range.
Long attack (80) and release (90) for drone character.
6-slot mod matrix:
LFO 1+/- → filter frequency (depth 25)
LFO 2+/- → osc 1 & 2 pitch (depth 5, subtle vibrato)
env 3 → osc 1 pulse width (depth 30)
LFO 1+ → osc 2 level (depth 15, crossfade effect)
LFO 2+ → noise level (depth 10, breath)
env filt → filter resonance (depth 12)
Chorus for stereo width, valve drive at 10 for warmth.
Synth 2 — "Crystal Shim":
Digital vocal 3 + random collection waveforms for texture.
Osc2 tuned +12 semitones for octave shimmer.
Bandpass 6/6 filter — ethereal, not boomy.
Ring mod at 20 for metallic harmonics.
6-slot mod matrix with alt-waveform LFO for organic movement.
Standard 8-macro layout on both synths:
1. Oscillator — wave interpolate morphing
2. OscMod — density & detune
3. AmpEnv — attack & release
4. FilterEnv — attack & decay
5. FilterFreq — filter sweep
6. Resonance — resonance sweep
7. Modulation — LFO rate + chorus depth
8. FX — chorus level + distortion
<!-- Claude constructs the entire song as a single load_song call —
two synth patches with full param sets, four drum track configs,
four 32-step patterns with per-step macro automation, FX routing,
mixer config, mod matrix, sidechain compression, and an 8-scene
song arrangement. All patterns use 32 steps for smooth p-lock
automation. -->
The "apex" pattern has per-step macro automation on every step
for macro 5 (filter), creating a smooth triangle sweep:
macros.5: {
"0": 50, "1": 53, "2": 56, "3": 60, "4": 64,
"5": 68, "6": 72, "7": 76, "8": 80, "9": 83,
"10": 86, "11": 89, "12": 92, "13": 95, "14": 98,
"15": 100, "16": 100, "17": 97, "18": 94, "19": 91,
"20": 88, "21": 85, "22": 82, "23": 79, "24": 76,
"25": 73, "26": 70, "27": 67, "28": 64, "29": 60,
"30": 56, "31": 52
}
32 individual automation values for a single macro on a single
track. The full song has track-level macro automation on macros
1, 2, 5, 6, 7, 8 across multiple patterns and both synth tracks.
Drums use the "params" key for pitch, decay, distortion, and
pan automation.
8-scene arrangement at 65 BPM in D natural minor:
1-2. "Emergence" — sparse drone intro, filter slowly opening
3-4. "Drift" — minor chord pads, melodic synth2 fragments
5-6. "Apex" — full density, heavy automation, arpeggiated shimmer
7. "Drift" — reprise
8. "Dissolve" — filter closing, washing into reverb
FX: Heavy reverb (preset 7, long decay), tempo-synced delay with
wide stereo, gentle sidechain from drum1 pumping both synths.
<!-- load_song validates the entire structure, then
export_song_to_project converts it to binary NCS and
transfers via SysEx -->
[calls export_song_to_project with slot=4]
status: ok
slot: 4
name: "Ethereal Drift"
bytes_sent: 160780
blocks: 20
crc32: 0xC30D9763
160KB of binary NCS project data sent via SysEx — two custom
synth patches, four drum configs, four 32-step patterns with
hundreds of p-lock automation points, full FX routing, mixer
settings, sidechain compression, and an 8-scene song arrangement.
One prompt. One transfer. Zero manual programming.
And just like that, we closed the loop.
This effectively makes human-AI music making collaboration using external gear possible. I’ve also learned a lot, had lots of fun and expanded my AI Assisted Development skills further. I also achieved the goals I had with this side project and even more:
- My music gear is now with me, sitting on my desk, accessible at any time. I play it from time to time, and I love it!
- I worked on a tech side project that turned out to be multiple ones at once: the Novation Circuit MCP Tracks, my personal website, etc.
- I started writing a blog, something I wanted to try since long ago!
I’ll be releasing everything I’ve been doing soon so everyone that’s interested can use it and have some fun with it!
See you in the next one!
Responses
Loading...