The problem
The KORG DS-10 is an excellent virtual analogue synthesiser for the Nintendo DS, but this game console has a low-quality 8-bit audio output. KORG later released an improved version of the synthesiser, the DSN-12, for the new Nintendo 3DS games console with 16-bit audio. The problem, however, is that it is impossible to transfer save data from the old programme to the new one.
Research
It’s exactly the same story with the other KORG M01 synthesiser, but it turns out that a programmer recently figured out the file format and wrote a converter. I downloaded the source code, converted a few melodies for the M01, added a few DS-10 and DSN-12 format files, and decided to set the AI to search for common patterns. Both synthesisers were written by the same programmer, so I worked on the assumption that he had used similar data structures.
Fable vs Sonnet
Right at the start, I brought out the big guns – the Claude Fable 5 model. It was tasked with the first part of the plan: to compare the M01 and M01D formats using Mystievous’s source code, and then to get to grips with the DS-10 and DSN-12 containers. Claude Code broke down the DS-10 save file into slots and hashes, learnt how to unpack the LZ11-compressed DSN-12 melodies and repack them, described the field tree, and programmed the first version of the converter in Python. That used up my monthly limit (in half an hour!), so I had to switch to Claude Sonnet 5.
The hypothesis has been confirmed
The KORG DS file formats are not documented anywhere, so all the work involves controlled experiments. I prepared save files that differed by a single parameter, and took screenshots (of the DS-10 from the emulator, and the DSN-12 from the real hardware). Claude compared the files byte by byte and updated the format specification. As I had anticipated, the DS-10, M01 and DSN-12 turned out to have a great deal in common. The source code for the M01 converter helped AI quickly understand the purpose of many bytes and assign them meaningful names.
Hacking the checksum
The header of every DSN-12 melody contains a 32-bit checksum (CRC), and the converter must calculate it correctly. In M01, CRC is the simple arithmetic sum of the bytes, but in DSN-12, a change a byte by 1 resulted in a ‘random’ change to the checksum. Consequently, the checksum algorithm is more complex. Claude tried more than 10 standard algorithms, but none of them worked.
The difficulty lies in the fact that CRC has too many unknowns: the polynomial, the initial value, the final XOR, the bit order and even which bytes are taken into account. There are 2^64 combinations of initial values and final XORs – more than 18 quintillion, which cannot be found by brute force.
So, I created a special test pair of files in which only one byte differed by 1 (a note half a tone higher). CRC has a neat property: the difference between the checksums of two files of the same length is equal to the checksum of the difference between the files themselves. That’s how an initial value and a final XOR can be eliminated from this equation, leaving us to search through polynomials only. Claude wrote a script and found exactly one suitable option: 0x04C11DB7 – the same as in Ethernet and ZIP (only without bit mirroring).
The remaining constants were found by solving a system of linear equations based on two melodies of different lengths. The final XOR turned out to be the trivial 0xFFFFFFFF (simply an inversion). The initial values were determined as the characters ‘mfsd’ for the directory and ‘dxsd’ for the melodies.
AI makes mistakes
For some reason, Claude decided that the panorama values (left-right) in the mixer were encoded in reverse, contrary to all the other controls in the programme. This is very strange. To the AI’s credit, it did spot the anomaly itself and flagged it up. Testing on actual hardware revealed the error – there was no need to mirror anything.
Claude also wanted to round and quantise all variables so that the results would match the test melodies. I had to disable the rounding.
It seems a bug has come to light, introduced by the synthesiser’s developers: when a drum note was deleted from the score, the programme would clear the note’s parameters, but a bit indicating the note’s presence remained uncleared elsewhere. In this case, the KORG DS-10 would ignore the note, whilst the KORG DSN-12 would play it (using the default parameters). I had to add a clean-up function to the converter to deal with notes that hadn’t been completely removed. The AI’s mistake was that it failed to recognise the connection between the data and did not spot the inconsistency in the test file.
The DSN-12 synthesiser has more instrument parameters than DS-10, and the converter set the ‘unnecessary’ parameters to 0 without giving any thought to what they meant. Although the parameter names were displayed in the interface, and it’s possible to guessed that setting them to zero would result in no sound at all, I had to explain to AI which default values should be set.
Claude exaggerated the number of possible audio channels in the DS-10 simply because there was free space remaining at the end of the file, and this space was an exact multiple of the length of a channel recording. In reality, however, all save files simply have a fixed length of 256 kilobytes.
Result
Now my old 8-bit tunes are playing in 16-bit!
The bulk of the work was completed in a day. Another day was spent on fine-tuning: identifying discrepancies on real hardware, clarifying the format, addressing overlooked parameters, writing documentation and publishing it on GitHub. Plus this article.
I’ve done a lot of reverse engineering in the past, and from my own experience I can say that without AI, this sort of work would have taken 2-3 times as long.
The converter is available on GitHub (around 600 lines of Python code, with no dependencies).