Building a Synth Patch Library with Claude (Part 2: The Generator)
Part 1 covered getting the actual patch data right: correcting .ins files, cataloguing 2,172 patches across 6 synths, and building a reference library. That part was mostly Claude doing data extraction and reconciliation work.
Once the library existed, the next problem was obvious: browsing a markdown file is not a workflow. I wanted something that could generate a starting patch combination for a track based on feel, let me pick which synth covers which role, and export directly into Reaper. So that's what we built.
This part is different. This is writing software. I suck at writing software...
...but I'm good at getting computers to do what I want them to do.
The Generator Tool
What It Does:
- Generates random patch combinations for starting new tracks
- Filters by feel (Chill, Aggressive, Minimal)
- Lets you specify which synth for each part (Bass from Phatty, Lead from MicroKORG, etc.)
- Has a separate Orchestra mode for symphonic stuff
- Works 100% offline, just double-click the HTML file
Session 1: Nothing Worked
First version shipped with a bug that broke everything. No buttons responded at all.
Root cause: a 246KB single-line JSON blob was breaking JavaScript parsing. The PATCHES constant was improperly formatted, causing all event handlers to fail silently. No errors in console, just nothing happening.
Fix:
- Used Python's
json.dump()with proper separators to format the data correctly - Separated HTML structure from data injection to prevent syntax collisions
- Rebuilt all JavaScript event handlers cleanly
The lesson here applies broadly: when you embed a large data structure directly in a JavaScript file, formatting matters. A single-line 246KB string will choke parsers in ways that are hard to debug because the failure is silent.
Session 2: Stack Mode
The next request was the most architecturally interesting: allow stacking multiple patches per category, but respect the voice limitations of each synth.
A Moog Little Phatty is monophonic. You can't stack three Phatty patches simultaneously. There's only one voice. A Yamaha PSR-730 is multitimbral. You can stack it multiple times in the same category. The generator needed to know the difference.
Synth classification:
const MULTI = ['Yamaha PSR-730', 'Alesis Micron'];
const SINGLE = ['Moog Little Phatty', 'Modal Argon8', 'Dave Smith Poly Evolver', 'Korg microKORG'];
Validation function:
function canStack(synth, usedLayers) {
return MULTI.includes(synth) || !usedLayers.some(l => l.synth === synth);
}
Multi-voice synths can appear multiple times per category. Single-voice synths can only appear once. This prevents generating a combination that's physically impossible to play.
Stack controls use HTML range inputs (1-3 layers per category), real-time display updates, and per-layer edit/delete/regenerate controls.
The Cyberpunk Aesthetic
I had a previous killer electric blue logo from previous music projects. I uploaded that, had Claude extract the data points on colors, and built the whole interface around that with a cyberpunk/hacker theme. Pure black background, electric blue and purple glows, and when you hover over the logo it glitches out with this lightning effect. The language is all system-themed: "EXECUTE SYSTEM PROTOCOL", "Bass Protocol", "Lead Algorithm". Very underground industrial.
Sessions 3-5: The Reaper Export (The Interesting Part)
This is where it got genuinely complex.
The first attempt at a Reaper export created new tracks from scratch. That approach had an immediate problem: the user already had a Reaper session with MIDI routing configured for each synth: specific MIDI channels, effects chains, audio routing, everything. Creating new tracks from scratch threw all of that away. It was useless.
The second attempt broke the buttons again. A function was inserted mid-declaration block, breaking JavaScript scope. Same symptom as Session 1, different cause. Solution: complete file rebuild using a Python script to regenerate the entire HTML with proper structure rather than patching.
The third approach was the right one. The user uploaded their actual Reaper session template, a 954-line .RPP file. The instruction was simple: use that template, don't create new tracks. Just update the track names with the patch info.
What that required:
Reverse-engineering the .RPP format to find the relevant pieces:
- Track structure:
<TRACK {GUID}> - Track names:
NAME "track name here" - MIDI routing:
MIDIOUTvalues - Each synth already had a named track with routing pre-configured
Synth-to-track mapping extracted from the template:
const SYNTH_TRACK = {
'Modal Argon8': 'Argon8 Midi',
'Moog Little Phatty': 'Midi To Moog',
'Yamaha PSR-730': 'MidiKeyz',
'Alesis Micron': 'Midi To Micron',
'Dave Smith Poly Evolver':'Midi to DSI',
'Korg microKORG': 'Midi To MKorg'
};
The export logic:
Object.entries(synthPatches).forEach(([synth, patches]) => {
const trackName = SYNTH_TRACK[synth];
const patchList = patches.join(' | ');
const newName = trackName + ' :: ' + patchList;
rpp = rpp.split('NAME "' + trackName + '"').join('NAME "' + newName + '"');
});
The entire 954-line template was base64-encoded and embedded in the HTML (38KB encoded). On export, it decodes client-side, updates only the track names, and downloads as a .RPP file ready to open.
The result: exported sessions preserve all MIDI routing, all audio tracks, all effects chains, all session settings. Track names get updated with the generated patch combination. Nothing else changes.
When multiple patches stack to the same synth, they appear together in one track name:
Midi To Moog :: BASS: Thick Bass 909 | PAD: Dark Atmosphere
Sessions 6-7: Preset Fixes and Logo Animation
Preset bug: The Chill and Aggressive presets were generating 2 pads every time regardless of settings. Hardcoded stack counts in the preset functions were overriding user selections and skipping categories. Fixed by making each preset generate all 4 categories with appropriate stack emphasis. Aggressive gets heavy bass and lead stacks, Chill gets pad emphasis, etc.
Logo animation: The glitch effect on hover uses layered CSS keyframe animation with multi-color drop shadows cycling through electric blue and purple:
@keyframes glitch {
0% { transform: translate(0); }
20% { transform: translate(-3px, 3px);
filter: drop-shadow(0 0 30px #00d4ff) drop-shadow(0 0 50px #7b2ff7); }
40% { transform: translate(-3px, -3px);
filter: drop-shadow(0 0 35px #a0c4ff) drop-shadow(0 0 55px #b794f6); }
60% { transform: translate(3px, 3px);
filter: drop-shadow(0 0 40px #00d4ff) drop-shadow(0 0 60px #7b2ff7); }
80% { transform: translate(3px, -3px);
filter: drop-shadow(0 0 45px #a0c4ff) drop-shadow(0 0 65px #b794f6); }
100% { transform: translate(0); }
}
Chromatic aberration effect via alternating blue/purple shadow layers at different radii.
Iterative Design
The generator evolved through multiple iterations based on real usage:
- Started with just random combos
- Added keyword filtering
- Added per-category synth selection
- Added orchestra mode
- Added regenerate buttons for individual patches
- Refined the aesthetic multiple times (settled on pure black background because the glows pop better)
Conclusion
This silly little project helped me organize all my sounds across 6 synths, along with allowing my DAW to accurately display, communicate, and manage my external synthesizers. It took less than a week to create, spending maybe 30 minutes an evening (including listening to patches in meatspace). I used the free version of Claude just to see what the feedback loop would be like, so I could have probably got it done significantly faster if I was paying for credits.
It also helps with two crucial workflow components when writing music with hardware synthesizers:
- Having to dig through your menus looking for an instrument type (especially when looking across multiple synths).
- Coming up with sounds from scratch for a new song in a certain style without menu diving.
Using AI was a force multiplier, and turned what would have been weeks of manual effort into a fast feedback loop, dramatically cutting the time to the result, and let me focus on design decisions, ideas, and features, instead of busywork. That leverage compounds fast without sacrificing intent or quality.
Give it a try with my patches loaded:
A note on the file structure: the original version of this tool was one large HTML file with everything embedded. That was a bad design decision. It has since been refactored into a modular structure with separate JS, CSS, and data files. That took about 15 minutes in a follow-up session with Claude. I only had to coach it on how I wanted things organized.