Aus der Planung von #329 (Gespräch 2026-10-06), dort bewusst ausgeklammert.
Einen Klang als WAV-Datei herausrechnen („Bounce“): ein Instrument auf einer Note, ein Sound mit seiner FX-Kette, später vielleicht ein Pattern oder ein Song.
Vorschlag zur Technik:
Den vorhandenen Weg in einem OfflineAudioContext laufen lassen. AudioWorklets (Pitch #317, Chip #329, Bitcrusher #322) laufen dort auch.
Das Ergebnis als 16-bit-PCM-WAV kodieren und herunterladen.
Rückfragen:
Was soll exportierbar sein? Nur ein Instrument mit einer Note, oder auch Sound, Pattern und Song?
Nur herunterladen, oder auch als neuer Datei-Sound ins Projekt legen? Das Zweite friert einen Chip-Klang ein und spart Rechenzeit im Spiel.
Länge: bis zum Ende des Envelope (Sustain 0) bzw. des Songs, oder eine feste Länge zum Eintippen?
Aus der Planung von #329 (Gespräch 2026-10-06), dort bewusst ausgeklammert.
Einen Klang als WAV-Datei herausrechnen („Bounce“): ein Instrument auf einer Note, ein Sound mit seiner FX-Kette, später vielleicht ein Pattern oder ein Song.
Vorschlag zur Technik:
- Den vorhandenen Weg in einem `OfflineAudioContext` laufen lassen. AudioWorklets (Pitch #317, Chip #329, Bitcrusher #322) laufen dort auch.
- Das Ergebnis als 16-bit-PCM-WAV kodieren und herunterladen.
Rückfragen:
- **Was soll exportierbar sein?** Nur ein Instrument mit einer Note, oder auch Sound, Pattern und Song?
- **Nur herunterladen, oder auch als neuer Datei-Sound ins Projekt legen?** Das Zweite friert einen Chip-Klang ein und spart Rechenzeit im Spiel.
- **Länge:** bis zum Ende des Envelope (Sustain 0) bzw. des Songs, oder eine feste Länge zum Eintippen?
meleki
added the new label 2026-10-06 20:04:09 +02:00
Es betrifft nur Pattern und Song (nicht Instrument). Also: Nennen wir es nicht zwingend "Export" sondern eher "Bake". Man kann bei Pattern oder Song auf Bake klicken, dann wird es als WAV exportiert und gilt als gebaked. Wenn man im Pattern oder Song etwas ändert soll der Bake wieder verschwinden. Herunterladen nicht notwendig, auch nicht als Datei in Projekt legen. Länge ist einfach die von Pattern und Song - falls es einen Ausklang (z.B. Delay) gibt, dann muss man es als User selbst verlängern (z.b. leeres Pattern einfügen im Song)
Frage die noch übrig bleibt: Die gebakte Version müsste dann eigentlich bei "Play sound" abgespielt werden oder wird diese dann automatisch verwendet bei "Play pattern" / "Play song"?
Es betrifft nur Pattern und Song (nicht Instrument). Also: Nennen wir es nicht zwingend "Export" sondern eher "Bake". Man kann bei Pattern oder Song auf Bake klicken, dann wird es als WAV exportiert und gilt als gebaked. Wenn man im Pattern oder Song etwas ändert soll der Bake wieder verschwinden. Herunterladen nicht notwendig, auch nicht als Datei in Projekt legen. Länge ist einfach die von Pattern und Song - falls es einen Ausklang (z.B. Delay) gibt, dann muss man es als User selbst verlängern (z.b. leeres Pattern einfügen im Song)
Frage die noch übrig bleibt: Die gebakte Version müsste dann eigentlich bei "Play sound" abgespielt werden oder wird diese dann automatisch verwendet bei "Play pattern" / "Play song"?
admin
added the held-back label 2026-10-07 20:18:39 +02:00
admin
moved this to Held back in Development on 2026-10-07 20:18:48 +02:00
Überarbeitet am 09.10. nach deinen Ergänzungen im Chat:
Format: Opus in Ogg statt WAV, im Browser kodiert. Damit ist die Datei rund ein Zehntel so groß.
Clips und Sounds einzeln: Ein Clip lässt sich auch baken, ein Sound nur umwandeln. Beides gehört zum Streamen und steht deshalb in #349. Fingerabdruck, Ablage und Kodierung baue ich hier so, dass #349 sie mitbenutzt.
Ziel ist Chrome. Firefox und Safari prüfe ich nicht.
Die Fragen 1 bis 4 sind gleich geblieben.
Grundlage ist dein Vorschlag aus dem Kommentar oben: nur Pattern und Song, kein Download, keine eigene Datei im Projekt, Länge = Länge von Pattern bzw. Song. Ausklang verlängert man selbst.
Deine offene Frage: Play sound oder automatisch?
Meine Empfehlung: automatisch bei Play pattern und Play song. Ein Bake ist nur eine schnellere Art, dasselbe abzuspielen. Die Nodes bleiben, wie sie sind, und kein Behavior muss sich ändern. Wo der Bake nicht passt (verändert, Datei fehlt), spielt der Node live wie heute. Play sound kennt den Bake nicht.
Was im Bake steckt und was live bleibt
Im Bake: alles bis zum Ausgang von Pattern oder Song. Beim Pattern sind das die Noten durchs Instrument samt dessen Sound FX. Beim Song sind es Spuren, Clips, Pattern-Items, Spur-FX, Song-Routing, Mute und Solo.
Live bleibt alles danach: die Sound FX des Patterns oder Songs (bzw. die am Node gewählte), fx params und Set sound FX parameters, volume, fade in, bus, das Master routing und Stop mit Fade. Damit verhalten sich die Nodes mit Bake genau wie ohne.
Gemessen im Code: Ein Spiel erreicht zur Laufzeit nur Busse des Projekts (reachedBus), keine Spur eines Songs. Durch den Bake geht heute also nichts verloren, was ein Spiel steuern könnte.
Technik
Rechnen: eine zweite SoundLibrary auf einem OfflineAudioContext (48 kHz, Stereo), mit demselben Code wie live. Der Scheduler bekommt die Uhr des Offline-Kontexts und plant schrittweise über suspend(). Das Rechnen läuft schneller als Echtzeit und zeigt einen Fortschritt. Das Worklet (Pitch, Chip, Bitcrusher, Phaser …) wird in den Offline-Kontext geladen. Größter Umbau: Die SoundLibrary hängt heute fest an einem AudioContext, sie muss einen übergeben bekommen können.
Loop nahtlos: Live klingt das Ende einer Runde in den Anfang der nächsten hinein (Release, Delay). Deshalb rechne ich einmal ganz durch und hänge dann die Schleife als zweite Runde an, mit dem Nachklang der ersten darin. Abgespielt wird der Anfang bis zum Loop-Ende und danach diese zweite Runde im Kreis, sample-genau. Beim Pattern ist die Schleife das ganze Pattern, beim Song die auf dem Lineal. Ohne loop spielt nur der erste Teil.
Format: Opus in Ogg, kodiert im Browser über WebCodecs (AudioEncoder), 160 kbit/s Stereo bzw. 96 kbit/s Mono. Sind beide Kanäle gleich, wird es Mono.
Die Ogg-Seiten schreibe ich selbst, ohne Bibliothek. Der Upload nimmt OggS schon heute an (api/lib/SoundStore.php).
Der Ogg-Kopf hält den Vorlauf des Encoders (pre-skip) und die genaue Länge fest. Dekodiert ist der Bake damit sample-genau, und die Loop-Stellen bleiben exakt. MP3 scheidet deshalb aus, dort entsteht durch das Füllmaterial des Encoders eine Lücke.
Vor dem Kodieren wird auf die Spitze normalisiert. Der Faktor wird mitgespeichert und beim Abspielen wieder angewandt, so übersteuert nichts.
Ein Bake wird immer neu aus der Quelle gerechnet. Es gibt also keine Verluste durch mehrfaches Kodieren.
Ablage: Upload über ?r=sounds in deinen Ordner, wie jede hochgeladene Datei (#344). Am Pattern oder Song steht dann ein Eintrag bake mit Datei, Fingerabdruck, Faktor und Loop-Stellen. Das ist kein Sound-Asset und taucht in keiner Liste auf. Bei einem neuen Bake wird die alte Datei gelöscht, außer ein Snapshot hält sie noch (409).
Kein Undo-Schritt, wie der Zoom im EQ (#376). Strg+Z nimmt also keinen Bake zurück.
Größe: 1,2 MB pro Minute als Datei. Ein 3-Minuten-Song mit 1-Minuten-Schleife sind rund 4,8 MB Upload statt 46 MB als WAV.
Speicher: Kompression spart keinen Arbeitsspeicher, solange dekodiert wird. Dann liegen wieder 23 MB pro Minute im Speicher, beim Beispiel also rund 92 MB. Bis #349 fertig ist, wird ein Bake beim Laden dekodiert wie jeder Sound. Danach streamt er (siehe #349).
Wann der Bake verschwindet
Der Fingerabdruck wird aus dem gerechneten Plan gebildet, nicht aus den Feldern des Assets: Noten und Clips, Tempo, Länge, Loop, Spuren mit Pegel, Pan und FX, und die Bauten der Instrumente und Sound FX samt Dateinamen. Ein Bake gilt nur, solange der Plan gleich ist.
Eine Änderung im Pattern oder Song macht ihn ungültig. Umbenennen ändert den Klang nicht und lässt ihn stehen. Ob auch Änderungen am Instrument usw. zählen, ist Frage 1.
Ein Undo zurück auf den gebakten Stand macht ihn wieder gültig, ohne neu zu rechnen.
Ungültig heißt: Der Tab zeigt „nicht gebakt“, und das Spiel spielt live. Der alte Eintrag bleibt liegen, bis neu gebakt oder entfernt wird.
Fingerabdruck, Ablage und Kodierung sind allgemein gebaut. #349 benutzt sie für gebakte Clips und für die Opus-Kopie eines Sounds.
Im Editor
Pattern- und Song-Tab: Knopf Bake in der Leiste. Während des Rechnens Fortschritt und Cancel. Danach steht „Baked“ mit Länge und Größe, dazu Remove bake. Wird während des Rechnens etwas geändert, wird das Ergebnis verworfen, und der Tab sagt das.
Der Tab selbst spielt immer live (siehe Frage 3). Den Bake hört man im Play-Modus und im Spiel.
Tests
Unit: Ogg-Seiten schreiben und wieder lesen (Prüfsumme, Granule-Positionen, pre-skip), Normalisieren und Mono. Fingerabdruck: gleich nach Umbenennen, anders nach einer Änderung am Instrument, wieder gleich nach Undo. Aufbau der Datei mit Loop.
e2e (Song- bzw. Pattern-Modul): Ein kurzes Pattern aus dem Seed baken. Prüfen, dass Play pattern im Play-Modus genau eine Stimme aus der Bake-Datei startet und keine Noten plant. Pegel live und gebakt über eine Aufnahme vergleichen (RMS je 100 ms, Abweichung unter 1 dB). Nach einer Änderung plant es wieder Noten.
Gegenproben: Fingerabdruck ohne Instrument-Bau, Loop ohne zweite Runde (Knack an der Naht im RMS), pre-skip ignoriert (Versatz am Anfang), Bake ignoriert.
Deine Entscheidungen
#
Frage
Meine Empfehlung
1
Was macht den Bake ungültig: nur Änderungen im Pattern/Song selbst, oder alles, was den Klang ändert (auch Instrument, Sound, Sound FX, die es benutzt)?
Alles, was den Klang ändert. Sonst spielt das Spiel nach einer Änderung am Instrument still weiter den alten Klang.
2
Ein Pattern im Song: dessen eigener Bake, oder live?
Live. Der Bake des Songs deckt es ab, und im Song hat das Item eigene FX, Pegel und Länge.
3
Was spielt der Pattern- bzw. Song-Tab?
Immer live. Dort wird bearbeitet, und jede Änderung macht den Bake ohnehin ungültig. Kein eigener Knopf zum Anhören des Bakes.
4
Stop pattern mit let ring bei einem gebakten Pattern: Live klingen die Noten in ihrem Release aus, das trennt ein Bake nicht mehr.
0,3 s ausblenden. Live wechseln geht mitten im Spiel nicht.
Probe vor dem Bau
Im Test-Chrome auf melektaus-atx prüfe ich vorab:
ob die Worklets im OfflineAudioContext laufen
wie schnell ein Song rechnet
ob volume am Node live nach den FX der Note wirkt. Sonst klänge ein leiser gestelltes Pattern mit Verzerrung gebakt anders.
ob AudioEncoder dort Opus kodiert, und wie schnell
ob der Bake nach dem Dekodieren sample-genau auf der Quelle liegt und der Loop ohne Lücke ist
Fällt etwas davon durch, melde ich mich vor dem Bau.
## Plan: Bake für Pattern und Song
> **Überarbeitet am 09.10.** nach deinen Ergänzungen im Chat:
> - **Format:** Opus in Ogg statt WAV, im Browser kodiert. Damit ist die Datei rund ein Zehntel so groß.
> - **Clips und Sounds einzeln:** Ein Clip lässt sich auch baken, ein Sound nur umwandeln. Beides gehört zum Streamen und steht deshalb in #349. Fingerabdruck, Ablage und Kodierung baue ich hier so, dass #349 sie mitbenutzt.
> - **Ziel ist Chrome.** Firefox und Safari prüfe ich nicht.
> - Die Fragen 1 bis 4 sind gleich geblieben.
Grundlage ist dein Vorschlag aus dem Kommentar oben: nur Pattern und Song, kein Download, keine eigene Datei im Projekt, Länge = Länge von Pattern bzw. Song. Ausklang verlängert man selbst.
### Deine offene Frage: Play sound oder automatisch?
**Meine Empfehlung: automatisch bei *Play pattern* und *Play song*.** Ein Bake ist nur eine schnellere Art, dasselbe abzuspielen. Die Nodes bleiben, wie sie sind, und kein Behavior muss sich ändern. Wo der Bake nicht passt (verändert, Datei fehlt), spielt der Node live wie heute. *Play sound* kennt den Bake nicht.
### Was im Bake steckt und was live bleibt
- **Im Bake:** alles bis zum Ausgang von Pattern oder Song. Beim Pattern sind das die Noten durchs Instrument samt dessen Sound FX. Beim Song sind es Spuren, Clips, Pattern-Items, Spur-FX, Song-Routing, Mute und Solo.
- **Live bleibt alles danach:** die Sound FX des Patterns oder Songs (bzw. die am Node gewählte), *fx params* und *Set sound FX parameters*, `volume`, `fade in`, `bus`, das Master routing und Stop mit Fade. Damit verhalten sich die Nodes mit Bake genau wie ohne.
- Gemessen im Code: Ein Spiel erreicht zur Laufzeit nur Busse des Projekts (`reachedBus`), keine Spur eines Songs. Durch den Bake geht heute also nichts verloren, was ein Spiel steuern könnte.
### Technik
- **Rechnen:** eine zweite `SoundLibrary` auf einem `OfflineAudioContext` (48 kHz, Stereo), mit demselben Code wie live. Der `Scheduler` bekommt die Uhr des Offline-Kontexts und plant schrittweise über `suspend()`. Das Rechnen läuft schneller als Echtzeit und zeigt einen Fortschritt. Das Worklet (Pitch, Chip, Bitcrusher, Phaser …) wird in den Offline-Kontext geladen. Größter Umbau: Die `SoundLibrary` hängt heute fest an einem `AudioContext`, sie muss einen übergeben bekommen können.
- **Loop nahtlos:** Live klingt das Ende einer Runde in den Anfang der nächsten hinein (Release, Delay). Deshalb rechne ich einmal ganz durch und hänge dann die Schleife als **zweite Runde** an, mit dem Nachklang der ersten darin. Abgespielt wird der Anfang bis zum Loop-Ende und danach diese zweite Runde im Kreis, sample-genau. Beim Pattern ist die Schleife das ganze Pattern, beim Song die auf dem Lineal. Ohne `loop` spielt nur der erste Teil.
- **Format: Opus in Ogg**, kodiert im Browser über WebCodecs (`AudioEncoder`), 160 kbit/s Stereo bzw. 96 kbit/s Mono. Sind beide Kanäle gleich, wird es Mono.
- Die Ogg-Seiten schreibe ich selbst, ohne Bibliothek. Der Upload nimmt `OggS` schon heute an (`api/lib/SoundStore.php`).
- Der Ogg-Kopf hält den Vorlauf des Encoders (`pre-skip`) und die genaue Länge fest. Dekodiert ist der Bake damit sample-genau, und die Loop-Stellen bleiben exakt. MP3 scheidet deshalb aus, dort entsteht durch das Füllmaterial des Encoders eine Lücke.
- Vor dem Kodieren wird auf die Spitze normalisiert. Der Faktor wird mitgespeichert und beim Abspielen wieder angewandt, so übersteuert nichts.
- Ein Bake wird immer neu aus der Quelle gerechnet. Es gibt also keine Verluste durch mehrfaches Kodieren.
- **Ablage:** Upload über `?r=sounds` in deinen Ordner, wie jede hochgeladene Datei (#344). Am Pattern oder Song steht dann ein Eintrag `bake` mit Datei, Fingerabdruck, Faktor und Loop-Stellen. Das ist kein Sound-Asset und taucht in keiner Liste auf. Bei einem neuen Bake wird die alte Datei gelöscht, außer ein Snapshot hält sie noch (409).
- **Kein Undo-Schritt**, wie der Zoom im EQ (#376). Strg+Z nimmt also keinen Bake zurück.
- **Größe:** 1,2 MB pro Minute als Datei. Ein 3-Minuten-Song mit 1-Minuten-Schleife sind rund 4,8 MB Upload statt 46 MB als WAV.
- **Speicher:** Kompression spart keinen Arbeitsspeicher, solange dekodiert wird. Dann liegen wieder 23 MB pro Minute im Speicher, beim Beispiel also rund 92 MB. Bis #349 fertig ist, wird ein Bake beim Laden dekodiert wie jeder Sound. Danach streamt er (siehe #349).
### Wann der Bake verschwindet
Der Fingerabdruck wird aus dem **gerechneten Plan** gebildet, nicht aus den Feldern des Assets: Noten und Clips, Tempo, Länge, Loop, Spuren mit Pegel, Pan und FX, und die Bauten der Instrumente und Sound FX samt Dateinamen. Ein Bake gilt nur, solange der Plan gleich ist.
- Eine Änderung im Pattern oder Song macht ihn ungültig. Umbenennen ändert den Klang nicht und lässt ihn stehen. Ob auch Änderungen am Instrument usw. zählen, ist Frage 1.
- Ein Undo zurück auf den gebakten Stand macht ihn wieder gültig, ohne neu zu rechnen.
- Ungültig heißt: Der Tab zeigt „nicht gebakt“, und das Spiel spielt live. Der alte Eintrag bleibt liegen, bis neu gebakt oder entfernt wird.
- Fingerabdruck, Ablage und Kodierung sind allgemein gebaut. #349 benutzt sie für gebakte Clips und für die Opus-Kopie eines Sounds.
### Im Editor
- **Pattern- und Song-Tab:** Knopf *Bake* in der Leiste. Während des Rechnens Fortschritt und *Cancel*. Danach steht „Baked“ mit Länge und Größe, dazu *Remove bake*. Wird während des Rechnens etwas geändert, wird das Ergebnis verworfen, und der Tab sagt das.
- **Der Tab selbst spielt immer live** (siehe Frage 3). Den Bake hört man im Play-Modus und im Spiel.
### Tests
- **Unit:** Ogg-Seiten schreiben und wieder lesen (Prüfsumme, Granule-Positionen, `pre-skip`), Normalisieren und Mono. Fingerabdruck: gleich nach Umbenennen, anders nach einer Änderung am Instrument, wieder gleich nach Undo. Aufbau der Datei mit Loop.
- **e2e (Song- bzw. Pattern-Modul):** Ein kurzes Pattern aus dem Seed baken. Prüfen, dass *Play pattern* im Play-Modus genau eine Stimme aus der Bake-Datei startet und keine Noten plant. Pegel live und gebakt über eine Aufnahme vergleichen (RMS je 100 ms, Abweichung unter 1 dB). Nach einer Änderung plant es wieder Noten.
- **Gegenproben:** Fingerabdruck ohne Instrument-Bau, Loop ohne zweite Runde (Knack an der Naht im RMS), `pre-skip` ignoriert (Versatz am Anfang), Bake ignoriert.
### Deine Entscheidungen
| # | Frage | Meine Empfehlung |
|---|---|---|
| 1 | Was macht den Bake ungültig: nur Änderungen im Pattern/Song selbst, oder alles, was den Klang ändert (auch Instrument, Sound, Sound FX, die es benutzt)? | **Alles, was den Klang ändert.** Sonst spielt das Spiel nach einer Änderung am Instrument still weiter den alten Klang. |
| 2 | Ein Pattern im Song: dessen eigener Bake, oder live? | **Live.** Der Bake des Songs deckt es ab, und im Song hat das Item eigene FX, Pegel und Länge. |
| 3 | Was spielt der Pattern- bzw. Song-Tab? | **Immer live.** Dort wird bearbeitet, und jede Änderung macht den Bake ohnehin ungültig. Kein eigener Knopf zum Anhören des Bakes. |
| 4 | *Stop pattern* mit *let ring* bei einem gebakten Pattern: Live klingen die Noten in ihrem Release aus, das trennt ein Bake nicht mehr. | **0,3 s ausblenden.** Live wechseln geht mitten im Spiel nicht. |
### Probe vor dem Bau
Im Test-Chrome auf `melektaus-atx` prüfe ich vorab:
- ob die Worklets im `OfflineAudioContext` laufen
- wie schnell ein Song rechnet
- ob `volume` am Node live nach den FX der Note wirkt. Sonst klänge ein leiser gestelltes Pattern mit Verzerrung gebakt anders.
- ob `AudioEncoder` dort Opus kodiert, und wie schnell
- ob der Bake nach dem Dekodieren sample-genau auf der Quelle liegt und der Loop ohne Lücke ist
Fällt etwas davon durch, melde ich mich vor dem Bau.
Umgesetzt in 84cd36f, Wiki in 26f23de (Songs → Baking).
So funktioniert es
Knopf Bake (Icon) in der Kopfzeile des Pattern- und des Song-Tabs. Ein Klick bakt, während des Rechnens bricht ein Klick ab, gebakt bietet er Bake again und Remove bake. Den Fortschritt zeigt die Werkzeugleiste. Solange der Bake gilt, leuchtet der Knopf, und der Info-Text sagt „baked“, sonst „bake outdated“.
Im Spiel spielen Play pattern und Play song den Bake als eine einzige Stimme. Die Sound FX des Nodes, fx params, volume, fade in, Bus, Master routing und Stop mit Fade bleiben live. Die Tabs spielen immer live (Frage 3).
Gültigkeit (Frage 1): Der Fingerabdruck kommt aus dem gerechneten Plan: Noten und Clips, Tempo, Länge, Loop, Spuren, der Bau jedes Instruments je Note, Sound FX, Dateien, Schnitte und Pegel. Umbenennen ändert nichts. Strg+Z zurück auf den gebakten Stand macht den Bake wieder gültig.
Datei: Opus in Ogg, 160 kbit/s Stereo bzw. 96 kbit/s, wenn am Ausgang nur Mono ankommt. Auf die Spitze normalisiert, der Faktor wird mitgespeichert. Hochgeladen als „[bake] Name“, der Sound-Picker blendet das aus. Die alte Datei wird gelöscht, sobald das Projekt ohne sie gespeichert ist.
Loop: Die Datei enthält den geraden Durchlauf und eine zweite Runde der Schleife mit dem Nachklang der ersten. Geloopt spielt der Bake bis zum Loop-Ende und dann diese Runde, sample-genau.
Stop (Frage 4): Einmal gespielt blendet der Bake in den letzten 10 ms aus. Mit let ring blendet er über 0,3 s aus.
Pattern im Song (Frage 2): spielt live, der Bake des Songs deckt es ab.
Probe vorab (Test-Chrome)
Beide Worklets laufen im OfflineAudioContext.
60 s Klang sind in 0,3 s gerechnet, mit vielen Pitch-Stimmen in 2,1 s. Kodieren nach Opus: 0,6 s.
AudioEncoder lehnt opus.format: 'ogg' ab, liefert aber mit 'opus' den OpusHead samt pre-skip (312). Die Ogg-Seiten schreibe ich selbst.
Zurück dekodiert stimmt die Länge aufs Sample, die Loop-Naht ist sauber. Bei 44,1 kHz verlor die Schleife ein Sample pro Runde, deshalb werden Ogg-Dateien mit 48 kHz dekodiert.
Abweichung vom Plan
Icon statt Textknopf: Die Kopfzeile des Song-Tabs ist bei 1280 px voll, ein Knopf mit Text hat Fit hinausgeschoben (e2e 65 brach daran ab).
Clips einzeln baken ist wie im überarbeiteten Plan nicht hier drin, sondern kommt mit #349. Clips auf einer Song-Spur stecken aber im Bake des Songs, und eine Änderung am Clip macht ihn ungültig.
Live gegen gebakt, offline über 4 s mit zwei Loop-Nähten: höchstens 0,06 dB Unterschied in 114 hörbaren 20-ms-Fenstern.
Gegenproben, alle greifen: Fingerabdruck ohne Instrument-Bauten, Fingerabdruck mit der Datei des Sounds statt dem Schnitt des Clips, Runde aus dem ersten Durchlauf, Bake-Stimme ohne Loop-Quelle, Play pattern bzw. Play song ohne Bake, pre-skip 0 (im e2e dann 4,8 dB Abweichung).
Nicht geprüft:
ein gebakter Song im Browser (nur Unit-Test), lange Songs (Rechenzeit, Speicher)
wie es klingt (CI ist stumm)
Cancel per Klick, das Ausblenden im Sound-Picker im Browser
Löschen, wenn ein Snapshot die Datei hält
e2e 65 nach der letzten kleinen Änderung am Auffrischen des Tabs (das fängt CI)
Umgesetzt in 84cd36f, Wiki in 26f23de (*Songs → Baking*).
## So funktioniert es
- **Knopf *Bake*** (Icon) in der Kopfzeile des Pattern- und des Song-Tabs. Ein Klick bakt, während des Rechnens bricht ein Klick ab, gebakt bietet er *Bake again* und *Remove bake*. Den Fortschritt zeigt die Werkzeugleiste. Solange der Bake gilt, leuchtet der Knopf, und der Info-Text sagt „baked“, sonst „bake outdated“.
- **Im Spiel** spielen *Play pattern* und *Play song* den Bake als eine einzige Stimme. Die Sound FX des Nodes, *fx params*, `volume`, `fade in`, Bus, Master routing und Stop mit Fade bleiben live. Die Tabs spielen immer live (Frage 3).
- **Gültigkeit (Frage 1):** Der Fingerabdruck kommt aus dem gerechneten Plan: Noten und Clips, Tempo, Länge, Loop, Spuren, der Bau jedes Instruments je Note, Sound FX, Dateien, Schnitte und Pegel. Umbenennen ändert nichts. Strg+Z zurück auf den gebakten Stand macht den Bake wieder gültig.
- **Datei:** Opus in Ogg, 160 kbit/s Stereo bzw. 96 kbit/s, wenn am Ausgang nur Mono ankommt. Auf die Spitze normalisiert, der Faktor wird mitgespeichert. Hochgeladen als „[bake] Name“, der Sound-Picker blendet das aus. Die alte Datei wird gelöscht, sobald das Projekt ohne sie gespeichert ist.
- **Loop:** Die Datei enthält den geraden Durchlauf und eine zweite Runde der Schleife mit dem Nachklang der ersten. Geloopt spielt der Bake bis zum Loop-Ende und dann diese Runde, sample-genau.
- **Stop (Frage 4):** Einmal gespielt blendet der Bake in den letzten 10 ms aus. Mit *let ring* blendet er über 0,3 s aus.
- **Pattern im Song (Frage 2):** spielt live, der Bake des Songs deckt es ab.
## Probe vorab (Test-Chrome)
- Beide Worklets laufen im `OfflineAudioContext`.
- 60 s Klang sind in 0,3 s gerechnet, mit vielen Pitch-Stimmen in 2,1 s. Kodieren nach Opus: 0,6 s.
- `AudioEncoder` lehnt `opus.format: 'ogg'` ab, liefert aber mit `'opus'` den `OpusHead` samt `pre-skip` (312). Die Ogg-Seiten schreibe ich selbst.
- Zurück dekodiert stimmt die Länge aufs Sample, die Loop-Naht ist sauber. Bei 44,1 kHz verlor die Schleife ein Sample pro Runde, deshalb werden Ogg-Dateien mit 48 kHz dekodiert.
## Abweichung vom Plan
- **Icon statt Textknopf:** Die Kopfzeile des Song-Tabs ist bei 1280 px voll, ein Knopf mit Text hat *Fit* hinausgeschoben (e2e 65 brach daran ab).
- **Clips einzeln baken** ist wie im überarbeiteten Plan nicht hier drin, sondern kommt mit #349. Clips auf einer Song-Spur stecken aber im Bake des Songs, und eine Änderung am Clip macht ihn ungültig.
## Tests
```
Unit → ogg 6, bake 16, sound-library +4, song-play +1
e2e 64 (melektaus-atx) → ALL PASSED, 36 Checks (6 neu)
Gate (melektaus-atx) → CHECK EXIT 0, 277 Dateien, 4281 Tests
```
- **Live gegen gebakt**, offline über 4 s mit zwei Loop-Nähten: höchstens 0,06 dB Unterschied in 114 hörbaren 20-ms-Fenstern.
- **Gegenproben, alle greifen:** Fingerabdruck ohne Instrument-Bauten, Fingerabdruck mit der Datei des Sounds statt dem Schnitt des Clips, Runde aus dem ersten Durchlauf, Bake-Stimme ohne Loop-Quelle, *Play pattern* bzw. *Play song* ohne Bake, `pre-skip` 0 (im e2e dann 4,8 dB Abweichung).
**Nicht geprüft:**
- ein gebakter Song im Browser (nur Unit-Test), lange Songs (Rechenzeit, Speicher)
- wie es klingt (CI ist stumm)
- *Cancel* per Klick, das Ausblenden im Sound-Picker im Browser
- Löschen, wenn ein Snapshot die Datei hält
- e2e 65 nach der letzten kleinen Änderung am Auffrischen des Tabs (das fängt CI)
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Aus der Planung von #329 (Gespräch 2026-10-06), dort bewusst ausgeklammert.
Einen Klang als WAV-Datei herausrechnen („Bounce“): ein Instrument auf einer Note, ein Sound mit seiner FX-Kette, später vielleicht ein Pattern oder ein Song.
Vorschlag zur Technik:
OfflineAudioContextlaufen lassen. AudioWorklets (Pitch #317, Chip #329, Bitcrusher #322) laufen dort auch.Rückfragen:
Es betrifft nur Pattern und Song (nicht Instrument). Also: Nennen wir es nicht zwingend "Export" sondern eher "Bake". Man kann bei Pattern oder Song auf Bake klicken, dann wird es als WAV exportiert und gilt als gebaked. Wenn man im Pattern oder Song etwas ändert soll der Bake wieder verschwinden. Herunterladen nicht notwendig, auch nicht als Datei in Projekt legen. Länge ist einfach die von Pattern und Song - falls es einen Ausklang (z.B. Delay) gibt, dann muss man es als User selbst verlängern (z.b. leeres Pattern einfügen im Song)
Frage die noch übrig bleibt: Die gebakte Version müsste dann eigentlich bei "Play sound" abgespielt werden oder wird diese dann automatisch verwendet bei "Play pattern" / "Play song"?
Plan: Bake für Pattern und Song
Grundlage ist dein Vorschlag aus dem Kommentar oben: nur Pattern und Song, kein Download, keine eigene Datei im Projekt, Länge = Länge von Pattern bzw. Song. Ausklang verlängert man selbst.
Deine offene Frage: Play sound oder automatisch?
Meine Empfehlung: automatisch bei Play pattern und Play song. Ein Bake ist nur eine schnellere Art, dasselbe abzuspielen. Die Nodes bleiben, wie sie sind, und kein Behavior muss sich ändern. Wo der Bake nicht passt (verändert, Datei fehlt), spielt der Node live wie heute. Play sound kennt den Bake nicht.
Was im Bake steckt und was live bleibt
volume,fade in,bus, das Master routing und Stop mit Fade. Damit verhalten sich die Nodes mit Bake genau wie ohne.reachedBus), keine Spur eines Songs. Durch den Bake geht heute also nichts verloren, was ein Spiel steuern könnte.Technik
SoundLibraryauf einemOfflineAudioContext(48 kHz, Stereo), mit demselben Code wie live. DerSchedulerbekommt die Uhr des Offline-Kontexts und plant schrittweise übersuspend(). Das Rechnen läuft schneller als Echtzeit und zeigt einen Fortschritt. Das Worklet (Pitch, Chip, Bitcrusher, Phaser …) wird in den Offline-Kontext geladen. Größter Umbau: DieSoundLibraryhängt heute fest an einemAudioContext, sie muss einen übergeben bekommen können.loopspielt nur der erste Teil.AudioEncoder), 160 kbit/s Stereo bzw. 96 kbit/s Mono. Sind beide Kanäle gleich, wird es Mono.OggSschon heute an (api/lib/SoundStore.php).pre-skip) und die genaue Länge fest. Dekodiert ist der Bake damit sample-genau, und die Loop-Stellen bleiben exakt. MP3 scheidet deshalb aus, dort entsteht durch das Füllmaterial des Encoders eine Lücke.?r=soundsin deinen Ordner, wie jede hochgeladene Datei (#344). Am Pattern oder Song steht dann ein Eintragbakemit Datei, Fingerabdruck, Faktor und Loop-Stellen. Das ist kein Sound-Asset und taucht in keiner Liste auf. Bei einem neuen Bake wird die alte Datei gelöscht, außer ein Snapshot hält sie noch (409).Wann der Bake verschwindet
Der Fingerabdruck wird aus dem gerechneten Plan gebildet, nicht aus den Feldern des Assets: Noten und Clips, Tempo, Länge, Loop, Spuren mit Pegel, Pan und FX, und die Bauten der Instrumente und Sound FX samt Dateinamen. Ein Bake gilt nur, solange der Plan gleich ist.
Im Editor
Tests
pre-skip), Normalisieren und Mono. Fingerabdruck: gleich nach Umbenennen, anders nach einer Änderung am Instrument, wieder gleich nach Undo. Aufbau der Datei mit Loop.pre-skipignoriert (Versatz am Anfang), Bake ignoriert.Deine Entscheidungen
Probe vor dem Bau
Im Test-Chrome auf
melektaus-atxprüfe ich vorab:OfflineAudioContextlaufenvolumeam Node live nach den FX der Note wirkt. Sonst klänge ein leiser gestelltes Pattern mit Verzerrung gebakt anders.AudioEncoderdort Opus kodiert, und wie schnellFällt etwas davon durch, melde ich mich vor dem Bau.
Umgesetzt in
84cd36f, Wiki in 26f23de (Songs → Baking).So funktioniert es
volume,fade in, Bus, Master routing und Stop mit Fade bleiben live. Die Tabs spielen immer live (Frage 3).Probe vorab (Test-Chrome)
OfflineAudioContext.AudioEncoderlehntopus.format: 'ogg'ab, liefert aber mit'opus'denOpusHeadsamtpre-skip(312). Die Ogg-Seiten schreibe ich selbst.Abweichung vom Plan
Tests
pre-skip0 (im e2e dann 4,8 dB Abweichung).Nicht geprüft: