forked from bradbrok/BrokModular-DaisyGPT
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpatch-evolver.js
More file actions
202 lines (172 loc) · 5.58 KB
/
Copy pathpatch-evolver.js
File metadata and controls
202 lines (172 loc) · 5.58 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
// Patch Evolver — genetic algorithm-style patch evolution through AI-guided mutation.
// Manages variant slots, generation tracking, and user selection.
/**
* PatchEvolver manages the evolution workflow:
* 1. User starts from a base patch
* 2. AI generates N variants with musically-intelligent mutations
* 3. User picks favorites
* 4. AI breeds next generation from favorites
*/
export class PatchEvolver {
constructor() {
this.active = false;
this.generation = 0;
this.basePatch = null;
this.variants = []; // Array of { code, label, compiled, wasmBytes, selected }
this.maxVariants = 4;
this.history = []; // Previous generations for undo
}
/**
* Start evolution from a base patch.
* @param {string} code - The starting C++ code
*/
start(code) {
this.active = true;
this.generation = 0;
this.basePatch = code;
this.variants = [];
this.history = [];
}
/**
* Stop evolution and return to normal mode.
*/
stop() {
this.active = false;
this.variants = [];
this.history = [];
}
/**
* Set variants for the current generation (called after LLM response).
* @param {Array<{code: string, label: string}>} newVariants
*/
setVariants(newVariants) {
this.generation++;
this.variants = newVariants.map((v, i) => ({
code: v.code,
label: v.label || `Variant ${String.fromCharCode(65 + i)}`,
compiled: false,
wasmBytes: null,
selected: false,
slot: i,
}));
}
/**
* Toggle selection of a variant for breeding.
*/
toggleSelection(index) {
if (index >= 0 && index < this.variants.length) {
this.variants[index].selected = !this.variants[index].selected;
}
}
/**
* Get selected variants for the next breeding round.
*/
getSelectedVariants() {
return this.variants.filter(v => v.selected);
}
/**
* Get the number of selected variants.
*/
get selectionCount() {
return this.variants.filter(v => v.selected).length;
}
/**
* Mark a variant as compiled with its WASM bytes.
*/
markCompiled(index, wasmBytes) {
if (index >= 0 && index < this.variants.length) {
this.variants[index].compiled = true;
this.variants[index].wasmBytes = wasmBytes;
}
}
/**
* Build the LLM prompt for generating initial variants.
*/
buildEvolvePrompt() {
return `EVOLVE MODE: Generate exactly 4 variations of the current patch.
For each variation, make musically-interesting changes to parameters. Good mutations include:
- Shift frequencies (octave up/down, detune, harmonic ratios)
- Change waveforms (saw→square, sine→triangle, etc.)
- Alter filter cutoff/resonance ranges
- Modify envelope times (snappy vs. slow)
- Adjust mix levels and effects sends
- Change modulation depths and rates
- Swap DSP modules (SVF→MoogLadder, Chorus→Flanger)
Keep each variation COMPILABLE and COMPLETE. Don't break the core structure.
Return your response as a \`\`\`variants block with exactly 4 variations:
\`\`\`variants
--- Variant A: [short description of changes]
[complete C++ code]
--- Variant B: [short description of changes]
[complete C++ code]
--- Variant C: [short description of changes]
[complete C++ code]
--- Variant D: [short description of changes]
[complete C++ code]
\`\`\`
Make each variant distinctly different but musically coherent.`;
}
/**
* Build the LLM prompt for breeding selected variants.
*/
buildBreedPrompt() {
const selected = this.getSelectedVariants();
if (selected.length === 0) return null;
let prompt = `EVOLVE MODE — BREED Generation ${this.generation + 1}:
The user selected ${selected.length} favorite(s) from the previous generation.
Breed 4 new variations that combine and mutate the best traits of the selected patches.
SELECTED PATCHES:\n\n`;
for (const v of selected) {
prompt += `--- ${v.label}\n\`\`\`cpp\n${v.code}\n\`\`\`\n\n`;
}
prompt += `Generate 4 new variations that:
- Combine interesting elements from the selected patches
- Introduce new mutations for further exploration
- Keep the overall character while pushing boundaries
Return as a \`\`\`variants block (same format as before).`;
return prompt;
}
/**
* Parse a ```variants block from the LLM response.
* @param {string} text - Full LLM response
* @returns {Array<{code: string, label: string}>|null}
*/
static parseVariantsBlock(text) {
const match = text.match(/```variants\s*\n([\s\S]*?)```/);
if (!match) return null;
const content = match[1];
const variants = [];
// Split by --- Variant headers
const sections = content.split(/^---\s*Variant\s*[A-Z]:\s*/m);
for (let i = 1; i < sections.length; i++) {
const section = sections[i].trim();
if (!section) continue;
// First line is the description, rest is code
const lines = section.split('\n');
const label = `Variant ${String.fromCharCode(64 + i)}: ${lines[0].trim()}`;
// Extract code — might be in a cpp fence or just raw
const codeMatch = section.match(/```(?:cpp)?\s*\n([\s\S]*?)```/);
const code = codeMatch ? codeMatch[1].trim() : lines.slice(1).join('\n').trim();
if (code) {
variants.push({ code, label });
}
}
return variants.length > 0 ? variants : null;
}
/**
* Get evolution state for display.
*/
getState() {
return {
active: this.active,
generation: this.generation,
variants: this.variants.map(v => ({
label: v.label,
compiled: v.compiled,
selected: v.selected,
slot: v.slot,
})),
selectionCount: this.selectionCount,
};
}
}