Since the OP-1 is using the APPL
AIFF chunk we have to figure out how to read the data out of it. Thankfully it seems that the OP-1 is writing a contiguous blob of JSON within this chunk. In a hex editor you will see the following (whether or not you're looking at a drum patch or a synth patch)
If you load your patches into an app like Hex Fiend this is what you'll see.
When we read the first 4 bytes (after the APPL
) we'll get a big endian int of the remaining size of the chunk. This will pull out the following string:
op-1{"adsr":[8768,16320,10240,4160,8192,8896,4000,4000],"fx_active":true,"fx_params":[8000,10624,8328,10168,0,0,0,0],"fx_type":"delay","knobs":[5576,0,32767,32767,23255,0,0,15743],"lfo_active":true,"lfo_params":[4912,8265,2000,2000,0,0,0,0],"lfo_type":"element","name":"20181230_0340","octave":2,"synth_version":2,"type":"dsynth"}
So at this point we can check the first 4 bytes of this string to ensure they start with op-1
and if so, strip them off, trim any control characters that might be present on the end of the string, and send it into any standard JSON parser.
{
"adsr": [8768, 16320, 10240, 4160, 8192, 8896, 4000, 4000],
"fx_active": true,
"fx_params": [8000, 10624, 8328, 10168, 0, 0, 0, 0],
"fx_type": "delay",
"knobs": [5576, 0, 32767, 32767, 23255, 0, 0, 15743],
"lfo_active": true,
"lfo_params": [4912, 8265, 2000, 2000, 0, 0, 0, 0],
"lfo_type": "element",
"name": "20181230_0340",
"octave": 2,
"synth_version": 2,
"type": "dsynth"
}
To the right is a sample drum header pulled out of a file made with the OP-1 Drum Utility.
I've tried to break out the data type and calculation formula for each of these values where I could figure things out.
Some are still a mystery that may have to be deduced through trial and error.
{
"drum_version": 1,
"type": "drum",
"name": "user",
"octave": 0,
"pitch": [6144, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"start": [0, 35186754, 73270908, 193926863, 262863847, 282963028, 327734734, 374604417, 422374972, 456892160, 477153660, 548131809, 570661720, 597144106, 696446963, 726788489, 830413096, 918041142, 955370511, 1001935845, 1053265249, 1053265249, 1053265249, 1053265249],
"end": [35182696, 73266850, 193922805, 262859789, 282958970, 327730676, 374600359, 422370914, 456888102, 477149602, 548127751, 570657662, 597140048, 696442905, 726784431, 830409038, 918037084, 955366453, 1001931787, 1053261191, 1153253906, 1153253906, 1153253906, 1153253906],
"playmode": [8192, 16384, 8192, 8192, 8192, 8000, 8192, 8192, 16384, 8000, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192],
"reverse": [8192, 16384, 8192, 8192, 8192, 16384, 8192, 8192, 8192, 8192, 16384, 8192, 8192, 8192, 8192, 8192, 8192, 16384, 8192, 8192, 8192, 8192, 8192, 8192],
"volume": [9195, 8192, 5190, 8192, 8192, 4969, 8192, 8192, 16384, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192],
"dyna_env": [0, 8192, 0, 8192, 0, 0, 0, 0],
"fx_active": false,
"fx_type": "delay",
"fx_params": [8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000],
"lfo_active": false,
"lfo_type": "tremolo",
"lfo_params": [16000, 16000, 16000, 16000, 0, 0, 0, 0]
}
If you want to debug an AIFF file to see these chunks for yourself, I've documented this script that I used to start digging into these here as a Swift script that could easily be pulled into a project or something if you wanted to have some more fun.