Instrument-Asset: Graph mit Notes-Node und Sample-Node #331

Closed
opened 2026-10-06 07:02:12 +02:00 by meleki · 2 comments
Owner

Teil von #330. Ein Instrument macht aus einer Note einen Klang. Es ist das, was ein Pattern (#333) spielt, und es ersetzt die Idee eines einzelnen Generator-Assets aus #329.

Aufbau

Ein Instrument hat einen Graph wie ein Sound FX (src/core/soundfx). Statt Input gibt es:

  • Notes (Vorschlag für den Namen, siehe Rückfragen): bringt die Noten herein. Mehrere Notes-Nodes sind erlaubt.
  • Quellen, die einen Klang erzeugen: Sample (spielt ein Sound-Asset) und später die Chip-Nodes aus #329.
  • Die FX-Nodes des Sound FX (Gain, Pitch, EQ, Mix und was #318 ff. dazubringen) formen den Klang.
  • Output ist, was man hört.

Der Notes-Node

  • Einstellungen: from und to, die tiefste und die höchste Note, zum Beispiel C2 bis B4. Für jede Note in diesem Bereich bekommt der Node einen Ausgang mit ihrem Namen (C2, C#2, D2 …). Ändert sich der Bereich, ändern sich die Ausgänge.
  • Weitere Ausgänge:
    • any: jede Note im Bereich. Das ist der Normalfall für ein melodisches Instrument, bei dem ein Sample oder Oszillator alle Noten spielt.
    • note (Zahl): die Nummer der gespielten Note.
    • frequency (Zahl, Hz): ihre Frequenz.
    • velocity (Zahl, 0 bis 1): wie stark sie angeschlagen ist.
  • Mehrere Notes-Nodes teilen die Tastatur in Zonen, zum Beispiel ein Bass-Sample für C1–B2 und ein anderes ab C3. Überlappen sich zwei Bereiche, klingen beide (Layer).
  • Drum-Kit: Ein Notes-Node mit dem Bereich C1–B1, an jedem Noten-Ausgang ein anderes Sample (C1 Kick, D1 Snare, F#1 Hi-Hat …). Ein Pattern spielt dann das ganze Schlagzeug mit einem Instrument.

Sind die Noten-Ausgänge „Flows“?

Von der Bedeutung her ja: Ein Noten-Ausgang ist nur aktiv, wenn genau diese Note kommt. Technisch würde ich ihn aber nicht als exec-Port der Behaviors bauen, sondern als eigenen Port-Typ (Arbeitsname trigger) mit eigener Farbe:

  • Ein Sound-Graph läuft nicht Frame für Frame. Er wird kompiliert, und eine Note startet auf der Audio-Uhr, nicht in einem Behavior-Tick.
  • Ein trigger-Ausgang lässt sich nur an den trigger-Eingang einer Quelle stecken. So kann nichts aus den Behaviors hineinrutschen.
  • Kompiliert wird pro Note: Für die Note F4 gilt nur der Ausgang F4 als aktiv, dazu any, wenn F4 im Bereich liegt. Quellen an anderen Ausgängen fallen weg, ein Mix mit einer leeren Seite wird zur anderen Seite. Spielt für eine Note gar nichts, ist das Stille und kein Fehler.
  • Das Ergebnis ist ein Plan wie heute beim Sound FX (FxPlan in src/core/soundfx/nodes.ts), nur mit Quellen an den Blättern. Er wird pro Instrument und Note gecacht, wie soundFxBuildFor.
  • note, frequency und velocity bleiben im Plan offen und werden je Stimme gefüllt. Das ist derselbe Weg wie heute die Parameter des Input (#311).

Nummer oder Hertz?

Beides, als getrennte Ausgänge. Die Nummer ist der Kern:

  • Patterns speichern ganze Nummern. Transponieren ist eine Addition (+12 ist eine Oktave), und der Pitch-Node rechnet schon in Halbtönen.
  • Ein Sample braucht nur den Abstand zu seinem Grundton: note - root Halbtöne.
  • Hertz braucht der Oszillator. frequency wird aus der Nummer gerechnet: 440 * 2^((note - 69) / 12).
  • Nummerierung wie MIDI: 0 ist die tiefste Note, 60 das mittlere C, 69 das A mit 440 Hz, 127 die höchste. Damit hat die tiefste Note die Nummer 0, und es ist die Zählung, die jedes Musikprogramm kennt.

Der Sample-Node

  • Eingang trigger, Einstellung Sound (ein Sound-Asset) und Root: die Note, auf der das Sample unverändert klingt, Standard C4 (60).
  • Follow note (an/aus): An transponiert das Sample um note - root Halbtöne, ohne die Länge zu ändern (#317). Aus spielt es immer gleich, das ist der Drum-Fall.
  • Mode: One-shot spielt das Sample ganz durch, egal wie lang die Note ist (Drums). Gate hört am Ende der Note auf, mit kurzem Ausblenden gegen das Knacken. Ein Release über das Notenende hinaus kommt mit #335.
  • Loop für gehaltene Töne, optional mit Loop-Start und -Ende.

Im Editor

  • Ein Tab wie beim Sound FX, dazu eine Tastatur zum Vorhören. Ein Klick auf eine Taste spielt die Note, solange die Maus gedrückt bleibt.
  • Spielen mit der Computer-Tastatur wie in Trackern: zwei Tastenreihen ergeben knapp zwei Oktaven, zwei Tasten schalten die Oktave. Gelesen wird KeyboardEvent.code, also die Lage der Taste und nicht der Buchstabe. So passt es auf QWERTZ und QWERTY gleich.
  • Die Tastatur zeigt die Zonen der Notes-Nodes. Tasten ohne Klang sind ausgegraut.

Haken

  • Viele Ausgänge: Ein Bereich über 7 Oktaven sind 84 Ausgänge, der Node wird sehr lang. Für melodische Instrumente reicht any, die Einzelausgänge sind vor allem für Drum-Kits da.
  • Das Sound FX darf sich nicht ändern. compileSoundFx und FxPlan bekommen Quellen dazu. Ein Sound FX bleibt dabei, was es ist: ein Graph mit dem gespielten Sound als einziger Quelle.
  • Ohne #317 ginge beim Sample nur der Drum-Fall oder ein Pitch über die Geschwindigkeit, der die Länge ändert.
  • Tests: Das Kompilieren pro Note ist eine reine Funktion und in Node testbar. Im e2e-Browser ist der Ton stumm. Prüfen lässt sich, welche Quellen eine Stimme bekommt, und mit einem OfflineAudioContext die Frequenz.

Rückfragen

  • Name des Nodes: Notes ist mein Vorschlag. Keys läge nahe, aber „Key“ heißt in den Behaviors schon eine Taste der Computer-Tastatur (Key is down, Key was pressed). Andere Möglichkeiten: Key zone, Note in.
  • Notennamen: Das mittlere C als C4 (= 60, wie in den meisten Programmen) oder als C3 (Yamaha, Ableton)? Mit C4 heißt die tiefste Note C-1. Mit Bindestrich wie im Tracker (C-4) würde daraus C--1, deshalb würde ich ohne schreiben: C4, C#4.
  • Nur C#, oder wahlweise auch Db?
  • Sollen Noten-Ausgänge einen eigenen Namen bekommen können (Kick, Snare)? Die Piano Roll (#333) könnte ihn dann in der Zeile zeigen, wie eine Drum-Map.
  • Soll man die Einzelausgänge abschalten können, damit ein melodischer Notes-Node nur any, note, frequency und velocity zeigt?
  • Soll Play sound auch ein Instrument spielen können, mit den Eingängen note, velocity und duration? Dann ginge ein 8-bit-Effekt im Spiel auch ohne Song.
  • Soll ein Instrument eigene Parameter erklären können wie das Sound FX am Input (zum Beispiel Brightness)? Die könnte ein Song dann automatisieren (#337).
  • Soll es einen Node geben, der ein bestehendes Sound-FX-Asset im Instrument benutzt, statt dessen Nodes nachzubauen?
  • Velocity: Wirkt sie immer als Lautstärke, oder nur, wenn man velocity selbst an einen Gain steckt?
Teil von #330. Ein Instrument macht aus einer Note einen Klang. Es ist das, was ein Pattern (#333) spielt, und es ersetzt die Idee eines einzelnen Generator-Assets aus #329. ## Aufbau Ein Instrument hat einen Graph wie ein Sound FX (`src/core/soundfx`). Statt *Input* gibt es: - **Notes** (Vorschlag für den Namen, siehe Rückfragen): bringt die Noten herein. Mehrere *Notes*-Nodes sind erlaubt. - **Quellen**, die einen Klang erzeugen: *Sample* (spielt ein Sound-Asset) und später die Chip-Nodes aus #329. - **Die FX-Nodes** des Sound FX (Gain, Pitch, EQ, Mix und was #318 ff. dazubringen) formen den Klang. - **Output** ist, was man hört. ## Der Notes-Node - **Einstellungen:** `from` und `to`, die tiefste und die höchste Note, zum Beispiel C2 bis B4. Für jede Note in diesem Bereich bekommt der Node einen Ausgang mit ihrem Namen (`C2`, `C#2`, `D2` …). Ändert sich der Bereich, ändern sich die Ausgänge. - **Weitere Ausgänge:** - `any`: jede Note im Bereich. Das ist der Normalfall für ein melodisches Instrument, bei dem ein Sample oder Oszillator alle Noten spielt. - `note` (Zahl): die Nummer der gespielten Note. - `frequency` (Zahl, Hz): ihre Frequenz. - `velocity` (Zahl, 0 bis 1): wie stark sie angeschlagen ist. - **Mehrere Notes-Nodes** teilen die Tastatur in Zonen, zum Beispiel ein Bass-Sample für C1–B2 und ein anderes ab C3. Überlappen sich zwei Bereiche, klingen beide (Layer). - **Drum-Kit:** Ein Notes-Node mit dem Bereich C1–B1, an jedem Noten-Ausgang ein anderes Sample (C1 Kick, D1 Snare, F#1 Hi-Hat …). Ein Pattern spielt dann das ganze Schlagzeug mit einem Instrument. ### Sind die Noten-Ausgänge „Flows“? Von der Bedeutung her ja: Ein Noten-Ausgang ist nur aktiv, wenn genau diese Note kommt. Technisch würde ich ihn aber **nicht** als `exec`-Port der Behaviors bauen, sondern als eigenen Port-Typ (Arbeitsname `trigger`) mit eigener Farbe: - Ein Sound-Graph läuft nicht Frame für Frame. Er wird kompiliert, und eine Note startet auf der Audio-Uhr, nicht in einem Behavior-Tick. - Ein `trigger`-Ausgang lässt sich nur an den `trigger`-Eingang einer Quelle stecken. So kann nichts aus den Behaviors hineinrutschen. - **Kompiliert wird pro Note:** Für die Note F4 gilt nur der Ausgang `F4` als aktiv, dazu `any`, wenn F4 im Bereich liegt. Quellen an anderen Ausgängen fallen weg, ein Mix mit einer leeren Seite wird zur anderen Seite. Spielt für eine Note gar nichts, ist das Stille und kein Fehler. - Das Ergebnis ist ein Plan wie heute beim Sound FX (`FxPlan` in `src/core/soundfx/nodes.ts`), nur mit Quellen an den Blättern. Er wird pro Instrument und Note gecacht, wie `soundFxBuildFor`. - `note`, `frequency` und `velocity` bleiben im Plan offen und werden je Stimme gefüllt. Das ist derselbe Weg wie heute die Parameter des *Input* (#311). ### Nummer oder Hertz? Beides, als getrennte Ausgänge. Die **Nummer** ist der Kern: - Patterns speichern ganze Nummern. Transponieren ist eine Addition (+12 ist eine Oktave), und der Pitch-Node rechnet schon in Halbtönen. - Ein Sample braucht nur den Abstand zu seinem Grundton: `note - root` Halbtöne. - **Hertz** braucht der Oszillator. `frequency` wird aus der Nummer gerechnet: `440 * 2^((note - 69) / 12)`. - **Nummerierung wie MIDI:** 0 ist die tiefste Note, 60 das mittlere C, 69 das A mit 440 Hz, 127 die höchste. Damit hat die tiefste Note die Nummer 0, und es ist die Zählung, die jedes Musikprogramm kennt. ## Der Sample-Node - Eingang `trigger`, Einstellung *Sound* (ein Sound-Asset) und *Root*: die Note, auf der das Sample unverändert klingt, Standard C4 (60). - *Follow note* (an/aus): An transponiert das Sample um `note - root` Halbtöne, **ohne die Länge zu ändern** (#317). Aus spielt es immer gleich, das ist der Drum-Fall. - *Mode*: *One-shot* spielt das Sample ganz durch, egal wie lang die Note ist (Drums). *Gate* hört am Ende der Note auf, mit kurzem Ausblenden gegen das Knacken. Ein Release über das Notenende hinaus kommt mit #335. - *Loop* für gehaltene Töne, optional mit Loop-Start und -Ende. ## Im Editor - **Ein Tab wie beim Sound FX**, dazu eine **Tastatur zum Vorhören**. Ein Klick auf eine Taste spielt die Note, solange die Maus gedrückt bleibt. - **Spielen mit der Computer-Tastatur** wie in Trackern: zwei Tastenreihen ergeben knapp zwei Oktaven, zwei Tasten schalten die Oktave. Gelesen wird `KeyboardEvent.code`, also die Lage der Taste und nicht der Buchstabe. So passt es auf QWERTZ und QWERTY gleich. - Die Tastatur zeigt die Zonen der Notes-Nodes. Tasten ohne Klang sind ausgegraut. ## Haken - **Viele Ausgänge:** Ein Bereich über 7 Oktaven sind 84 Ausgänge, der Node wird sehr lang. Für melodische Instrumente reicht `any`, die Einzelausgänge sind vor allem für Drum-Kits da. - **Das Sound FX darf sich nicht ändern.** `compileSoundFx` und `FxPlan` bekommen Quellen dazu. Ein Sound FX bleibt dabei, was es ist: ein Graph mit dem gespielten Sound als einziger Quelle. - **Ohne #317** ginge beim Sample nur der Drum-Fall oder ein Pitch über die Geschwindigkeit, der die Länge ändert. - **Tests:** Das Kompilieren pro Note ist eine reine Funktion und in Node testbar. Im e2e-Browser ist der Ton stumm. Prüfen lässt sich, welche Quellen eine Stimme bekommt, und mit einem `OfflineAudioContext` die Frequenz. ## Rückfragen - **Name des Nodes:** *Notes* ist mein Vorschlag. *Keys* läge nahe, aber „Key“ heißt in den Behaviors schon eine Taste der Computer-Tastatur (*Key is down*, *Key was pressed*). Andere Möglichkeiten: *Key zone*, *Note in*. - **Notennamen:** Das mittlere C als **C4** (= 60, wie in den meisten Programmen) oder als C3 (Yamaha, Ableton)? Mit C4 heißt die tiefste Note C-1. Mit Bindestrich wie im Tracker (`C-4`) würde daraus `C--1`, deshalb würde ich ohne schreiben: `C4`, `C#4`. - Nur `C#`, oder wahlweise auch `Db`? - Sollen Noten-Ausgänge einen eigenen Namen bekommen können (*Kick*, *Snare*)? Die Piano Roll (#333) könnte ihn dann in der Zeile zeigen, wie eine Drum-Map. - Soll man die Einzelausgänge abschalten können, damit ein melodischer Notes-Node nur `any`, `note`, `frequency` und `velocity` zeigt? - Soll *Play sound* auch ein Instrument spielen können, mit den Eingängen `note`, `velocity` und `duration`? Dann ginge ein 8-bit-Effekt im Spiel auch ohne Song. - Soll ein Instrument eigene Parameter erklären können wie das Sound FX am *Input* (zum Beispiel *Brightness*)? Die könnte ein Song dann automatisieren (#337). - Soll es einen Node geben, der ein bestehendes Sound-FX-Asset im Instrument benutzt, statt dessen Nodes nachzubauen? - **Velocity:** Wirkt sie immer als Lautstärke, oder nur, wenn man `velocity` selbst an einen Gain steckt?
meleki added the new label 2026-10-06 07:02:12 +02:00
Author
Owner

Umgesetzt in 8a4e4a6, Doku im Wiki auf der neuen Seite Instruments (Wiki-Commit fb136da).

Deine Entscheidungen

# Frage Antwort
1 Name des Noten-Nodes Notes
2 Notennamen C4 = 60 wie MIDI, nur Kreuze (C#4), die tiefste Note heißt C-1
3 Eigene Namen pro Note jetzt schon, am Notes-Node (Name of C2 …), sie gehören zum Instrument
4 Einzelausgänge Schalter Single notes, neu aus, Bereich neu C4–B4
5 Velocity wirkt immer als Lautstärke, der Ausgang velocity zusätzlich
6 Im Spiel eigener Node Play note (note, velocity, volume, duration, detached, params), gibt voice aus
7 Eigene Parameter jetzt, über den Node Parameters im Instrument, gesetzt mit Instrument parameters
8 Sound-FX-Asset im Instrument jetzt, Node Sound FX, seine Parameter als Eingänge, offen gilt der Standardwert des FX
9 Ort im Projektbaum Gruppe Music

Was jetzt gilt

  • Port-Typ trigger (lime), passt nur in den trigger einer Quelle. Eingänge können jetzt beliebig viele Kanten nehmen (PortDef.many): der trigger einer Quelle (eine Kante an reicht) und der Output (alles darin klingt zusammen, das sind die Layer).
  • Kompiliert wird pro Note und gecacht, bis sich der Graph oder ein benutzter Sound oder Sound FX ändert. Eine Quelle mit aus-Trigger ist Stille, ein Mix mit einer stillen Seite ist die andere Seite. Spielt für eine Note nichts, ist das kein Fehler: die Taste ist grau, Play note gibt voice 0.
  • Sample: Follow note verschiebt um note - root über das Pitch-Worklet aus #317, die Länge bleibt. Gate blendet am Notenende in 10 ms aus, One-shot spielt durch, Loop mit Start und Ende in Sekunden (auch im Worklet).
  • Eine Note ist eine Stimme mit mehreren Layern, jeder Weg mit eigener Datei und Lautstärke. Set sound FX parameters und Stop sound (mit voice, auch Let ring) erreichen sie wie einen Sound.
  • Tab: Graph, darunter alle 128 Tasten, ohne Klang grau. Halten mit der Maus spielt, Ziehen über die Tasten wechselt die Note. Mit Fokus spielt die Computer-Tastatur wie im Tracker nach KeyboardEvent.code (Z S X D C … ab C3, Q 2 W 3 E … eine Oktave höher), ←/→ verschieben die Oktave. Im Header ein Feld pro Parameter und Stop.

Abweichungen und Grenzen

  • Die Sound-FX-Eingänge am Node sind eigene Werte des Instruments: offen gilt der Standardwert des FX als feste Zahl. Soll ein Wert beim Spielen kommen, steckt man einen Parameter des Instruments hinein.
  • Ein Mix im eingesetzten FX spielt den Sound zweimal, eine Quelle pro Weg (wie im Sound FX selbst).
  • Eine Note weit weg vom Root klingt so rau wie jeder Phase-Vocoder-Pitch (#317). Auf dem Root spielt sie ohne Worklet.
  • Kein Release über das Notenende hinaus (#335), keine Oszillatoren (#329).

Fund in CI

Task 523 (Suite zu cf6799a) hatte zwei rote Checks in e2e 34, die Audio mit der Uhr der Seite gemessen haben: ein Nachklang von 2,95 s war nach 1 s weg, Quad in war weiter als 0,7 s erlauben. Die Audio-Uhr lief in diesem Lauf der Seite voraus. Beide Checks messen jetzt auf der Audio-Uhr (__gm.sound.clock()).

Tests

instrument.test.ts (neu)          → 22 Tests, grün
sound-library / pitch-player       → +7 / +2 Tests, grün
node-catalog                       → +4 Fälle, grün
e2e 4 und 34 (melektaus-atx)       → ALL PASSED, 34 mit 44 Checks (+7)
Gate (melektaus-atx)               → CHECK EXIT 0, 243 Testdateien, 3750 Tests
  • Gegenproben: any immer an, Release beendet auch One-shots, Eingänge des Sound-FX-Nodes ignoriert, Loop-Bereich ignoriert. Es fallen 3, 2, 1 und 1 Tests.
  • Browser-Probe auf stein2 mit Screenshots angesehen: Tasten mit Zonen, gehaltene Taste, Namen der Einzelnoten im Inspector, Header.
  • Den CI-Lauf zu 8a4e4a6 habe ich beim Schließen noch nicht gelesen.

Gehört hat niemand etwas, der Browser im Test ist stumm. In Firefox lief nichts.

Umgesetzt in 8a4e4a6, Doku im Wiki auf der neuen Seite [Instruments](https://git.nockal.com/meleki/game-maker/wiki/Instruments) (Wiki-Commit fb136da). ## Deine Entscheidungen | # | Frage | Antwort | |---|---|---| | 1 | Name des Noten-Nodes | **Notes** | | 2 | Notennamen | C4 = 60 wie MIDI, nur Kreuze (`C#4`), die tiefste Note heißt C-1 | | 3 | Eigene Namen pro Note | jetzt schon, am Notes-Node (*Name of C2* …), sie gehören zum Instrument | | 4 | Einzelausgänge | Schalter *Single notes*, neu aus, Bereich neu C4–B4 | | 5 | Velocity | wirkt immer als Lautstärke, der Ausgang `velocity` zusätzlich | | 6 | Im Spiel | eigener Node **Play note** (`note`, `velocity`, `volume`, `duration`, `detached`, `params`), gibt `voice` aus | | 7 | Eigene Parameter | jetzt, über den Node **Parameters** im Instrument, gesetzt mit **Instrument parameters** | | 8 | Sound-FX-Asset im Instrument | jetzt, Node **Sound FX**, seine Parameter als Eingänge, offen gilt der Standardwert des FX | | 9 | Ort im Projektbaum | Gruppe **Music** | ## Was jetzt gilt - **Port-Typ `trigger`** (lime), passt nur in den `trigger` einer Quelle. Eingänge können jetzt beliebig viele Kanten nehmen (`PortDef.many`): der `trigger` einer Quelle (eine Kante an reicht) und der **Output** (alles darin klingt zusammen, das sind die Layer). - **Kompiliert wird pro Note** und gecacht, bis sich der Graph oder ein benutzter Sound oder Sound FX ändert. Eine Quelle mit aus-Trigger ist Stille, ein Mix mit einer stillen Seite ist die andere Seite. Spielt für eine Note nichts, ist das kein Fehler: die Taste ist grau, `Play note` gibt `voice` 0. - **Sample**: *Follow note* verschiebt um `note - root` über das Pitch-Worklet aus #317, die Länge bleibt. *Gate* blendet am Notenende in 10 ms aus, *One-shot* spielt durch, *Loop* mit Start und Ende in Sekunden (auch im Worklet). - **Eine Note ist eine Stimme** mit mehreren Layern, jeder Weg mit eigener Datei und Lautstärke. `Set sound FX parameters` und `Stop sound` (mit `voice`, auch *Let ring*) erreichen sie wie einen Sound. - **Tab**: Graph, darunter alle 128 Tasten, ohne Klang grau. Halten mit der Maus spielt, Ziehen über die Tasten wechselt die Note. Mit Fokus spielt die Computer-Tastatur wie im Tracker nach `KeyboardEvent.code` (`Z S X D C …` ab C3, `Q 2 W 3 E …` eine Oktave höher), `←`/`→` verschieben die Oktave. Im Header ein Feld pro Parameter und *Stop*. ## Abweichungen und Grenzen - Die Sound-FX-Eingänge am Node sind **eigene Werte des Instruments**: offen gilt der Standardwert des FX als feste Zahl. Soll ein Wert beim Spielen kommen, steckt man einen Parameter des Instruments hinein. - Ein Mix im eingesetzten FX spielt den Sound zweimal, eine Quelle pro Weg (wie im Sound FX selbst). - Eine Note weit weg vom Root klingt so rau wie jeder Phase-Vocoder-Pitch (#317). Auf dem Root spielt sie ohne Worklet. - Kein Release über das Notenende hinaus (#335), keine Oszillatoren (#329). ## Fund in CI Task 523 (Suite zu `cf6799a`) hatte zwei rote Checks in e2e 34, die Audio mit der Uhr der Seite gemessen haben: ein Nachklang von 2,95 s war nach 1 s weg, Quad in war weiter als 0,7 s erlauben. Die Audio-Uhr lief in diesem Lauf der Seite voraus. Beide Checks messen jetzt auf der Audio-Uhr (`__gm.sound.clock()`). ## Tests ``` instrument.test.ts (neu) → 22 Tests, grün sound-library / pitch-player → +7 / +2 Tests, grün node-catalog → +4 Fälle, grün e2e 4 und 34 (melektaus-atx) → ALL PASSED, 34 mit 44 Checks (+7) Gate (melektaus-atx) → CHECK EXIT 0, 243 Testdateien, 3750 Tests ``` - **Gegenproben:** `any` immer an, Release beendet auch One-shots, Eingänge des Sound-FX-Nodes ignoriert, Loop-Bereich ignoriert. Es fallen 3, 2, 1 und 1 Tests. - **Browser-Probe auf stein2** mit Screenshots angesehen: Tasten mit Zonen, gehaltene Taste, Namen der Einzelnoten im Inspector, Header. - Den CI-Lauf zu 8a4e4a6 habe ich beim Schließen noch nicht gelesen. Gehört hat niemand etwas, der Browser im Test ist stumm. In Firefox lief nichts.
Author
Owner

Nachtrag: ein Sound am Output, Mix mit Kurve

Zwei Änderungen nach dem Abschluss, beide auf Wunsch des Users.

076c564 Der Output nimmt nur noch einen Sound

  • Bisher hat der Output beliebig viele Kanten zusammengezählt (Layer). Eine Note war dabei immer eine Stimme, der Graph hat das aber nicht gezeigt.
  • Jetzt nimmt der Output einen Sound wie jeder andere Sound-Eingang, eine zweite Kante ersetzt die erste. Mehrere Sounds kommen über einen Mix zusammen.
  • Ein altes Instrument mit mehreren Kanten behält sie, kompiliert aber nicht: Takes one sound: put a Mix in front of it to play several. In den gespeicherten Projekten gibt es keinen solchen Fall.
  • Ein leerer Output wird als Problem gemeldet.

fb4d65a Mix mit Einstellung Curve

mix Crossfade (Standard) a / b Both at center a / b
0 1 / 0 1 / 0
0.25 0.75 / 0.25 1 / 0.5
0.5 0.5 / 0.5 1 / 1
0.75 0.25 / 0.75 0.5 / 1
1 0 / 1 0 / 1
  • Gilt im Sound FX und im Instrument, auch für einen Mix in einem eingebundenen Sound FX.
  • mix bleibt über Parameter und Set sound FX parameters steuerbar. Ein Gleiten folgt der Kurve: Eine ConstantSourceNode trägt mix auf dem Audio-Thread, zwei WaveShaperNodes machen daraus die Anteile. Zwei getrennte Rampen wären in der Mitte auf je 0,5 eingebrochen.
  • Bei 0,5 werden beide Sounds voll addiert, bis zu +6 dB, wenn beide gleichzeitig laut sind. Das entspricht dem früheren Verhalten mehrerer Kanten am Output.
  • Bestehende Mixe bleiben Crossfade und klingen wie bisher.

Nebenbei: CI zu 23bdc3f war rot

Task 529, e2e 34: Der Step-Check hat den Sprung ab dem Start der Stimme gemessen. Eine zeitgesteuerte Änderung läuft aber ab ihrem Eintreffen, und das kam in der CI 80 ms später. Die Tonhöhe hielt also zu Recht bis 2,08 s. stats() meldet jetzt tunedAt (Audio-Uhr der letzten Änderung, die eine Stimme bewegt hat), und der Check misst ab dort.

Tests

Unit (sound-library, soundfx, instrument) → grün, 5 neu
e2e 34 (melektaus-atx)                    → ALL PASSED – 48 Checks (+1)
Gate (melektaus-atx)                      → CHECK EXIT 0, 244 Dateien, 3793 Tests
  • Offline in Chrome gerendert kommen a/b bei mix 0 bis 1 genau wie in der Tabelle, auch während eines Gleitens von 0 nach 1. Der Step-Sprung lag 2,04 s nach der Änderung.
  • Gegenproben: Kurve im eingebundenen Sound FX verworfen, Treiber beim Ende nicht gestoppt. Jedes Mal fällt der neue Test.
  • Nicht geprüft: gehört hat niemand etwas, Firefox lief nicht.

Wiki: f2a3834 (Sounds → The curve of a Mix, Instruments, Architecture).

## Nachtrag: ein Sound am Output, Mix mit Kurve Zwei Änderungen nach dem Abschluss, beide auf Wunsch des Users. ### `076c564` Der Output nimmt nur noch einen Sound - Bisher hat der Output beliebig viele Kanten zusammengezählt (Layer). Eine Note war dabei immer **eine** Stimme, der Graph hat das aber nicht gezeigt. - Jetzt nimmt der Output einen Sound wie jeder andere Sound-Eingang, eine zweite Kante ersetzt die erste. Mehrere Sounds kommen über einen **Mix** zusammen. - Ein altes Instrument mit mehreren Kanten behält sie, kompiliert aber nicht: *Takes one sound: put a Mix in front of it to play several*. In den gespeicherten Projekten gibt es keinen solchen Fall. - Ein leerer Output wird als Problem gemeldet. ### `fb4d65a` Mix mit Einstellung *Curve* | `mix` | *Crossfade* (Standard) a / b | *Both at center* a / b | |---|---|---| | 0 | 1 / 0 | 1 / 0 | | 0.25 | 0.75 / 0.25 | 1 / 0.5 | | 0.5 | 0.5 / 0.5 | 1 / 1 | | 0.75 | 0.25 / 0.75 | 0.5 / 1 | | 1 | 0 / 1 | 0 / 1 | - Gilt im Sound FX und im Instrument, auch für einen Mix in einem eingebundenen Sound FX. - `mix` bleibt über Parameter und *Set sound FX parameters* steuerbar. **Ein Gleiten folgt der Kurve:** Eine `ConstantSourceNode` trägt `mix` auf dem Audio-Thread, zwei `WaveShaperNode`s machen daraus die Anteile. Zwei getrennte Rampen wären in der Mitte auf je 0,5 eingebrochen. - Bei 0,5 werden beide Sounds voll addiert, bis zu +6 dB, wenn beide gleichzeitig laut sind. Das entspricht dem früheren Verhalten mehrerer Kanten am Output. - Bestehende Mixe bleiben *Crossfade* und klingen wie bisher. ### Nebenbei: CI zu `23bdc3f` war rot Task 529, e2e 34: Der Step-Check hat den Sprung ab dem Start der Stimme gemessen. Eine zeitgesteuerte Änderung läuft aber ab ihrem Eintreffen, und das kam in der CI 80 ms später. Die Tonhöhe hielt also zu Recht bis 2,08 s. `stats()` meldet jetzt `tunedAt` (Audio-Uhr der letzten Änderung, die eine Stimme bewegt hat), und der Check misst ab dort. ### Tests ``` Unit (sound-library, soundfx, instrument) → grün, 5 neu e2e 34 (melektaus-atx) → ALL PASSED – 48 Checks (+1) Gate (melektaus-atx) → CHECK EXIT 0, 244 Dateien, 3793 Tests ``` - Offline in Chrome gerendert kommen a/b bei `mix` 0 bis 1 genau wie in der Tabelle, auch während eines Gleitens von 0 nach 1. Der Step-Sprung lag 2,04 s nach der Änderung. - Gegenproben: Kurve im eingebundenen Sound FX verworfen, Treiber beim Ende nicht gestoppt. Jedes Mal fällt der neue Test. - Nicht geprüft: gehört hat niemand etwas, Firefox lief nicht. Wiki: `f2a3834` (*Sounds* → *The curve of a Mix*, *Instruments*, *Architecture*).
admin added this to the Development project 2026-10-06 15:42:50 +02:00
admin removed the new label 2026-10-06 15:43:01 +02:00
admin moved this to Next in Development on 2026-10-06 15:43:10 +02:00
admin moved this to Done in Development on 2026-10-06 15:43:17 +02:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: meleki/feuerwerk#331