Neufassung (Zielbild A, settings-first) — Design¶
Datum: 2026-06-04
Status: Ratifiziert (Brainstorming-Session), Implementierung autonom freigegeben
Datei: synthwave_surfer.html (single-file)
Vorgänger-Kontext: Phase 1.5 (Melodie-/Bass-Engine, Genre-Voicing, Stratos retired) abgeschlossen.
1. Problem & Ziel¶
Problem: Die 6 Factory-Presets sind eingefrorenes fixedSwmd (hand-geschriebenes Multi-Phase-Notenmaterial). Sie erben keine Engine-Verbesserungen — verbessere ich Melodie-, Bass- oder Voicing-Engine, bleiben die Presets stale. Außerdem teilen sich zwei kompositorisch unterschiedliche Identitäten (Blade Runner = atmosphärisches Noir, Carpenter = Horror-Ostinato) dieselbe noir-Engine und unterscheiden sich nur in Instrumenten — sie fühlen sich nicht eigenständig an.
Ziel (Zielbild A, settings-first):
- Genre = Engine + Default-Voicing. Engine = reine Komposition (ALGORITHMS); Default-Voicing = kanonische Instrumente+FX pro Engine.
- Preset = benannter Seed im Genre + Voicing-Deltas. Kein fixedSwmd mehr → Presets sind generativ, deterministisch über mulberry32(seed) reproduzierbar, und erben Engine- und Voicing-Verbesserungen automatisch.
- Carpenter wird eine eigene Engine (Horror-Ostinato in 4/4), getrennt vom atmosphärischen noir.
Erfolgskriterium: Eine Engine-Verbesserung wirkt automatisch auf alle Presets dieser Engine. Carpenter und Blade Runner klingen hörbar kompositorisch verschieden. Jedes der 6 Presets ist ein per Ohr kuratierter Seed, der gut klingt.
2. Ratifizierte Entscheidungen¶
| # | Entscheidung | Begründung |
|---|---|---|
| D1 | Einphasig jetzt, Schema phasen-erweiterbar | Mehrphasigkeit (Song-Bogen) ist Phase 3. Der eingebaute 16-Takt-Bogen (Intro/Build/Drop via drumStartBar, padStartBar, Lead A@4 / B@10) reicht vorerst. Schema soll ein späteres phases[] natürlich andocken lassen, ohne es jetzt zu bauen. |
| D2 | Carpenter = eigene Engine in 4/4 | Carpenter-Charakter (karg, Ostinato, Halbton-/Tritonus-Spannung) ist Komposition, nicht Voicing. Echtes 5/4-Halloween (Scheduler-Umbau) ist eine spätere Verfeinerung. |
| D3 | 2-Schicht-Modell (Engine-Default-Voicing + sparse Preset-Deltas) | Die separate „benannte Voicing"-Zwischenschicht ist YAGNI, seit Carpenter/Blade Runner auf Engine-Ebene getrennt sind. Sparse Deltas realisieren „Presets erben Voicing-Verbesserungen" wörtlich. |
| D4 | Migration = frische, lebendige Interpretation | Presets reproduzieren NICHT die alten eingefrorenen Noten. Jedes Preset = kuratierter Seed; Identität aus Engine+Voicing+Mood. |
| D5 | Codec bleibt, repositioniert | .swmd-Codec wird nicht fallengelassen: (1) Import authored Files → fixed-Modus; (2) „Freeze"/Export der generativen Ausgabe → .swmd zum Editieren in Obsidian. Der fixed/generative-Toggle bleibt bedeutsam. |
3. Engines (4) + Default-Voicings¶
ENGINE_VOICINGS[engine] = { bass, lead, pad, master } ersetzt das alte GENRE_REF (das auf ein Preset zeigte) durch eine kanonische Voicing pro Engine. GENRE_BASS entfällt (geht in ENGINE_VOICINGS[*].bass.model auf).
| Engine | Charakter | Default-Voicing (Quelle/Richtung) | BPM · Mode |
|---|---|---|---|
outrun |
treibend, klassisch | alkali Bass / crystal Lead / vapor Pad (≈ heutige Miami-Nights-Voicing) | 120 · aeolian |
noir |
atmosphärisch (Blade Runner) | warmer Sub / CS-80-artiger Lead / breiter Pad (≈ heutige Blade-Runner-Voicing) | 80 · aeolian |
dreamwave |
hazy / warm | weicher Bass / soft Lead / vapor-Pad (≈ heutige VHS-Sunset-Voicing) | 100 · aeolian |
carpenter (NEU) |
karg, Horror-Ostinato | dunkler Pulse-Bass / spärliches hohes Motiv / Drone-Pad | 92 · phrygian |
Hinweis Apply-Flow: Die Default-Voicing muss die durch
applyAllToGraph/applyTrackParamseffektiv gehörten Parameter setzen (Preset-Master-Block + Per-Track-Param-Tabellen), nicht nur Konstruktor-Defaults. Siehe Memoryproject_audio_apply_flow.
4. Datenmodell¶
4.1 Preset-Schema (neu)¶
'Miami Nights': {
engine: 'outrun', // Pflicht: ALGORITHMS-Key
seed: 1986, // Pflicht: kuratierter Seed
bpm: 120, // optional: Override von ALGORITHMS[engine].defaultBpm
mode: 'aeolian', // optional: Override von ALGORITHMS[engine].defaultMode
tag: 'Outrun · classic', // UI-Label
voicing: { // optional, SPARSE: nur Abweichungen von ENGINE_VOICINGS[engine]
bass: { /* Partial */ },
lead: { /* Partial */ },
pad: { /* Partial */ },
master: { /* Partial */ },
},
// KEIN fixedSwmd mehr
}
Phasen-Erweiterbarkeit (D1): Ein künftiges optionales phases: [{ seed, voicing }] kann ergänzt werden; fehlt es, gilt die einphasige Form { seed, voicing }. Jetzt NICHT implementieren — nur nicht verbauen.
4.2 mergeVoicing(defaultVoicing, deltas) → { trackParams, masterState }¶
Reine Funktion (headless-testbar). Tiefe Merge je Spur:
für track in ['bass','lead','pad']:
result[track] = { ...clone(defaultVoicing[track]), ...(deltas?.[track] || {}) }
masterState = { ...clone(defaultVoicing.master), ...(deltas?.master || {}) }
4.3 applyPreset(name) (ersetzt applyFactoryPreset)¶
const p = FACTORY_PRESETS[name]; if (!p) return;
setEngine(p.engine); // Radio + Algo-Card aktiv
const v = mergeVoicing(ENGINE_VOICINGS[p.engine], p.voicing);
Object.assign(trackParams.bass, v.trackParams.bass);
Object.assign(trackParams.lead, v.trackParams.lead);
Object.assign(trackParams.pad, v.trackParams.pad);
Object.assign(masterState, v.masterState);
$('bpm').value = p.bpm ?? ALGORITHMS[p.engine].defaultBpm;
$('mode').value = p.mode ?? ALGORITHMS[p.engine].defaultMode;
$('seed').value = p.seed;
patternMode = 'generative'; // Presets sind generativ
syncTrackUI('bass'|'lead'|'pad'); syncMasterUI(); syncPatternToggle();
if (liveSynths) { setTrackModel ×3; applyAllToGraph(liveSynths); } // live re-voice
generate(); // Engine erzeugt Noten
d787004) bleibt erhalten und greift weiter, falls eine Voicing lfoTarget:'pwm' auf nicht-Stratos trägt.
5. Carpenter-Engine¶
5.1 ALGORITHMS.carpenter¶
carpenter: {
totalBars: 16, buildForm: buildCarpenterForm,
riffGen: (rng, sl) => generateRiff(rng, sl, BASS_PROFILES.carpenter),
leadGenA: (rng, sl, ctx) => generateMelody(rng, sl, 4, { ...ctx, profile: MELODY_PROFILES.carpenter, startBar: 6 }),
leadGenB: (rng, sl, ctx) => generateMelody(rng, sl, 4, { ...ctx, profile: MELODY_PROFILES.carpenter, startBar: 12 }),
padProg: [[0,2,4], [-1,1,3]], // langsam, 1–2 Akkorde, phrygische Färbung
padStartBar: 0, padEndBar: 16, padRoot: 60,
drumStartBar: 4, drumEndBar: 16, drumIntenseFrom: 999, drumBreakFrom: 999, drumBreakTo: 0,
drumPattern: 'carpenter', // neue, minimale Pattern-Variante
swing: 0, sidechain: false,
defaultBpm: 92, defaultMode: 'phrygian',
}
5.2 Musikalische Bausteine¶
- Bass-Ostinato (
BASS_PROFILES.carpenter): unerbittliches 8tel-Pattern auf dem Akkord-Root, gelegentlicher Halbton-Obernachbar — das Signature-Element. Wenig rhythmische Variation, Determinismus erhalten. - Motiv (
MELODY_PROFILES.carpenter): enger Ambitus, Halbton-/Tritonus-Lean, hohe Pausen-Rate (spärlich, hoch). Nutzt die bestehenden Entwicklungs-Operatoren. - Pad: minimal — gehaltener dunkler Drone; sehr langsame Akkordwechsel.
- Drums (
drumPattern: 'carpenter'): Kick auf schwere Zählzeiten, gelegentlicher Rim, keine Hi-Hat-Betriebsamkeit — Spannung aus dem Raum. - Harmonie:
phrygian(b2 liefert die Halbton-Düsternis). Pad-Root 60, Bass lockt viachordMapauf Akkord-Roots wie in den anderen Engines.
5.3 buildCarpenterForm(rng, material, ctx)¶
Analog zu buildNoirForm, aber: Bass-Ostinato läuft durchgehend (kein Aussetzen), Lead-Motiv erst spät und spärlich, Pad-Drone von Takt 0. chordMap aus ctx für Root-Lock (wie bestehende Form-Builder, rootOffset = chordMap[b].root).
5.4 Phrygian-Scale¶
Falls SCALES.phrygian fehlt: ergänzen ([0,1,3,5,7,8,10]).
6. Preset → Engine-Remap¶
| Preset | bisher | neu |
|---|---|---|
| Miami Nights | outrun | outrun |
| Highway Cruise | outrun | outrun |
| Blade Runner Rain | noir | noir |
| Carpenter Synth | noir | carpenter |
| Mall Bliss | dreamwave | dreamwave |
| VHS Sunset | dreamwave | dreamwave |
Voicing-Deltas pro Preset = Differenz zwischen heutiger Preset-Voicing und der neuen ENGINE_VOICINGS-Default. Seeds werden in der Kuratierungs-Phase (§9) per Ohr final gesperrt; bis dahin Platzhalter = heutiger Preset-Seed.
7. Codec / Fixed-Modus¶
patternMode:generative(Engine) |fixed(importiertes/authored.swmdverbatim).- Factory-Presets sind alle
generative(keinfixedSwmd). - Import:
.swmd/.mdparsen →fixed. Unverändert. - Freeze/Export: aktuelle generative Ausgabe →
.swmdserialisieren (existiert viaswmdSerialize; als bewusstes „Freeze"-Feature dokumentieren/anbieten). - Der
fixed/generative-Toggle bleibt; beim Laden eines Presets schaltet er aufgenerative.
8. Tests¶
- Raus: Assertions, die Frozen-Preset-
fixedSwmd-Roundtrip-Inhalt prüfen (Presets tragen keinfixedSwmdmehr). - Bleibt: Codec-Roundtrip-Tests (User-File-Import/-Export).
- Neu (headless, Sentinel-Pattern
// <<…_START/END>>, via Node): ENGINE_VOICINGS-Vollständigkeit: alle 4 Engines haben komplettebass/lead/pad/mastermit allen Pflichtfeldern.mergeVoicing: Default ohne Deltas = Default; Deltas überschreiben punktuell; Quelle wird nicht mutiert (Clone).applyPreset(soweit ohne DOM testbar): erzeugte trackParams sind valide / Modelle existieren.- Carpenter-Generatoren:
generateRiff(.,.,BASS_PROFILES.carpenter)deterministisch & Groove-Summe = 16;MELODY_PROFILES.carpenterForm-Constraints; Ambitus eng. SCALES.phrygiankorrekt.- Headless-Verify-Harness erweitern (extrahiert Funktionen zwischen Sentinels, führt mit
nodeaus).
9. Kuratierungs-Phase (braucht Ohr → User)¶
Nach Implementierung, pro Preset mit gelockter Engine+Voicing:
1. HTTP-Server (python3 -m http.server), App im generative-Modus.
2. Eine Handvoll Seeds durchhören (z.B. 5–8 Kandidaten).
3. Besten Seed in FACTORY_PRESETS[name].seed sperren.
4. Carpenter zuerst (neue Engine), dann die fünf migrierten Presets.
Diese Phase ist nicht autonom — Claude liefert die Kandidaten-Infrastruktur, Johannes wählt per Ohr.
10. Touch-Liste (Dateien/Bereiche in synthwave_surfer.html)¶
SCALES— ggf.phrygianergänzen.- Melodie-Engine-Block (Sentinels ~505–718) —
MELODY_PROFILES.carpenter,BASS_PROFILES.carpenter. - Form-Builder —
buildCarpenterForm. - Drum-Pattern-Logik —
'carpenter'-Variante. ALGORITHMS(~1120) —carpenter-Eintrag.ENGINE_VOICINGS(neu) — ersetztGENRE_REF/GENRE_BASS(~3274).applyGenreVoicing(~3276) — aufENGINE_VOICINGSumstellen.FACTORY_PRESETS(~2210) — 6 Presets aufs neue Schema,fixedSwmdraus.applyFactoryPreset(~3118) →applyPresetmitmergeVoicing.- UI: 4. Algo-Card
carpenter(~HTML 210), Preset-Liste, Boot-Default. mergeVoicing(neu, reine Funktion in Sentinel-Block für Headless-Test).- Test-Harness (~3641–4133) — anpassen/erweitern.
11. Risiken¶
- Carpenter-„Feel" in 4/4 ist kreative Iteration — die Ostinato-/Motiv-Balance muss per Ohr stimmen (Kuratierung).
- Voicing-Default-Ableitung: Die
ENGINE_VOICINGS-Defaults müssen die gehörten (apply-flow-effektiven) Werte treffen, sonst klingen Presets anders als erwartet. - Multi-Phase-Verlust (akzeptiert, D1): migrierte Presets sind einphasig; Song-Bogen folgt in Phase 3.
- Seed-Kuratierung ist manuelle Ohr-Arbeit (User-abhängig).
12. Nicht-Ziele (YAGNI)¶
- Kein 5/4-/Meter-Umbau (Carpenter bleibt 4/4).
- Keine Song-Bogen-/Phasen-Engine (Phase 3).
- Keine benannte „Voicing"-Zwischenschicht (D3).
- Kein Match des alten eingefrorenen Klangs (D4).