Skip to content

fix(korg): Step-Record-Layout korrigiert — Note @1, Velocity @2 (v3.306.0) - #36

Merged
GeorgDub merged 5 commits into
mainfrom
fix/e2-step-layout
Jul 31, 2026
Merged

GeorgDub merged 5 commits into
mainfrom
fix/e2-step-layout

Conversation

@GeorgDub

@GeorgDub GeorgDub commented Jul 31, 2026 •

Copy link
Copy Markdown
Owner

Der Import las die Velocity von Byte 1 und zeigte deshalb für jeden Step die 72 an — das ist 0x48, die Vorgabe-Note C5.

Zwei unabhängige Belege

Am Gerät gemessen (2026-07-30). Der Nutzer setzte auf einem Part vier Steps mit deutlich unterschiedlicher Betonung (laut/leise/laut/leise). Im per Sysex zurückgeholten Pattern stand:

Step  1: 01 48 7f 01 3d …      Step  5: 01 48 08 01 3d …
Step  9: 01 48 7f 01 3d …      Step 13: 01 48 19 01 3d …
inaktiv: 00 48 60 00 00 …

Byte 1 konstant 0x48, Byte 2 folgt exakt der Betonung (127 / 8 / 127 / 25).

Werksdatei 245_BodyTalk1.e2spat, über die ganze Datei gezählt: Byte 1 trägt musikalische Tonhöhen (C5 dominant, dazu B2/D2/C#3/F2) plus 98× 0xFF für „kein neuer Ton"; Byte 2 trägt 96 (299×) mit 127 (14×) als Akzent; Byte 4 streut über 32..80 wie eine Gate-Länge.

e2sExport.ts beschrieb das Layout von Anfang an richtig — die beiden Pfade widersprachen sich.

Warum daraus ein Umbau wurde

Parser und electribePatternBuilder bilden ein positionstreues Paar, dessen Byte-Treue 13 Tests gegen echte Dateien prüfen. Nur den Parser zu korrigieren bricht die Symmetrie; beide zu korrigieren ließ Byte 4 seinen Rückweg verlieren, weil E2StepInput kein Gate-Längen-Feld hatte — gemessen stieg die Abweichung gegen Init181 von unter 200 auf 1188 Bytes.

Gelöst, indem ParsedPartStep und E2StepInput um note, gate und gateLength erweitert wurden: der Parser füllt sie, der Builder schreibt sie zurück. Beide Drift-Tests sind wieder grün.

Zwei Funde nebenbei

  • Der Builder schrieb inaktiven Steps 0x00 aufs Noten-Byte. Unter dem alten Layout war das richtig (Byte 4 ist dort 0x00), unter dem korrigierten falsch: echte Dateien tragen auch bei inaktiven Steps die Vorgabe 0x48 — Init181 hat 1020× 00 48 60 00 00. Das allein erzeugte rund 1020 abweichende Bytes.
  • Der 0xFF-Sentinel gehört zum Noten-Byte („kein neuer Ton"), nicht zur Velocity. Der Builder schreibt ihn nicht mehr als Velocity, und das Noten-Byte reicht ihn unverändert durch statt auf 127 zu klemmen.

Eine Selbstkorrektur, die im Code dokumentiert ist

Ich hatte diesen Fix zunächst gebaut und dann wegen eines vermeintlichen Widerspruchs zur Werksdatei zurückgenommen. Den Widerspruch gab es nicht — ich hatte Byte 4 nur in den ersten Steps eines Parts angesehen und daraus „konstant 0x48, also die Note" geschlossen. Über die ganze Datei gerechnet löst er sich auf. Die Lehre steht im Prüfprotokoll: bei Byte-Semantik über die ganze Datei zählen, nicht über eine Handvoll Records.

Tests

Neuer Regressionstest e2-step-layout-device.test.ts hält die Gerätemessung wörtlich fest — die gemessenen Bytes stehen als Konstanten drin. Fällt er, ist die Zuordnung wieder verrutscht, und zwar gegen echte Hardware statt gegen eine Annahme.

Nachgezogen: synthetische Fixtures, der BodyTalk-Sentinel-Test (dessen Prämisse das falsche Byte las) und 9 × toEqual → toMatchObject, weil der Parser jetzt drei Felder mehr liefert.

tsc clean, 11431 grün. Der eine lokale Failer (Pan-Histogramm über e2s-2016.e2sallpat) ist vorbestehend und skippt auf CI.

🤖 Generated with Claude Code


Nachgelagerte Commits auf diesem Branch (Update 2026-07-31)

Der Branch ist über den ursprünglichen Layout-Fix hinausgewachsen — vier Versionen, die aufeinander aufbauen:

  • v3.307.0 (74adc55) — Bank-Builder gegen die verifizierte Werksbank e2s-2016.e2sallpat geprüft: drei Fixes (sampleId-Clamp 0xFFFF→999, 0xFF-Tie-Durchreichung statt Klemmen auf 127, Velocity min. 1) + neuer Validator verifyE2AllpatBank, der vor jedem Bank-Save läuft. Die Werksbank dient als Ground Truth im Test.
  • v3.308.0 (d8ac50b) — Chord-Noten (Step-Bytes 5..7 = Noten 2..4) durch die gesamte Pattern-Pipeline: chordNotes in ParsedPartStep/E2StepInput, Parser füllt, beide Builder schreiben zurück, Stock-Roundtrip byte-genau. Die e2Sysex-„motion"-Bytes sind damit teilentschlüsselt (5..7 Chord, 8..11 Reserved-0).
  • v3.309.0 (8cd982e) — Chord-Noten im Step-Editor sichtbar: ♫-Indikator auf der Step-Zelle, Akkord-Chips mit Notennamen + Entfernen im StepInspector, beide Import-Pfade (Bank + „Von Korg"-Sysex) verdrahtet, Re-Export verlustfrei. Dabei gefundener Bugfix: NOTE_NAMES fehlte „G#" — alle Pitch-Labels oberhalb von G waren einen Halbton verrutscht.

Stand: tsc clean, Vollsuite 11460 grün / 37 skipped.

GeorgDub and others added 5 commits July 31, 2026 07:03
…06.0)

Der Import las Velocity von Byte 1 und zeigte deshalb fuer JEDEN Step die 72
an — das ist 0x48, die Vorgabe-Note C5.

Zwei unabhaengige Belege:
- Am Geraet gemessen: der Nutzer setzte vier Steps mit deutlich
  unterschiedlicher Betonung; im per Sysex geholten Pattern stand Byte 1
  konstant 0x48, Byte 2 folgte exakt der Betonung (127/8/127/25).
- Werksdatei 245_BodyTalk1: Byte 1 traegt Tonhoehen (C5 dominant, dazu
  B2/D2/C#3/F2) plus 98x 0xFF ("kein neuer Ton"), Byte 2 die Velocity
  (96 mit 127 als Akzent), Byte 4 streuende Gate-Laengen.

Der Umbau war noetig, weil Parser und Legacy-Builder ein positionstreues Paar
bilden, dessen Byte-Treue 13 Tests gegen echte Dateien pruefen: nur den Parser
zu korrigieren bricht die Symmetrie, beide zu korrigieren liess Byte 4 seinen
Rueckweg verlieren (Init181-Abweichung 200 -> 1188 B). Geloest, indem
ParsedPartStep und E2StepInput um note/gate/gateLength erweitert wurden.

Zusatzfund: der Builder schrieb inaktiven Steps 0x00 aufs Noten-Byte — unter
dem alten Layout richtig, jetzt falsch; echte Dateien tragen dort 0x48
(Init181: 1020x "00 48 60 00 00"). Und der 0xFF-Sentinel gehoert zum
Noten-Byte, nicht zur Velocity.

Neuer Regressionstest haelt die Geraetemessung woertlich fest.
tsc clean, 11431 gruen.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ator (v3.307.0)

Differenzielle Analyse der verifiziert korrekten Werksbank e2s-2016.e2sallpat
(250 Factory-Patterns): Prefix und GLST-Block sind byte-identisch zu unserem
Output, das Init-Template verletzt keine der 9869 bank-weiten Byte-Invarianten.
Der Template-Overlay-Ansatz ist damit gegen Werksdaten bestaetigt — aber drei
Overlay-Felder schrieben falsche Werte:

- sampleId-Clamp 0xFFFF -> 999: Geraete-Slots enden bei 999 (Stock max. 419);
  ein Part mit zu grosser ID bekam eine Referenz ins Leere.
- 0xFF-Tie-Sentinel wurde auf 127 geclampt — Ties (15 177 aktive Stock-Steps)
  gingen bei jedem Re-Export verloren. Jetzt Durchreichung.
- Velocity min 1 (Stock kennt keine 0) und gate/gateLength aus dem Input
  statt Konstante 0x3D (Roundtrip-Verlust).

Neuer stock-verifizierter Struktur-Validator verifyE2AllpatBank haengt VOR dem
Save in beiden Bank-Export-Pfaden (DrumMachine, esxToE2sBank): Prefix-Marker,
PTST/PTED, BPM<=3000, StepLen in {0,1,3}, Sample-Ref<=999, Note<=127|0xFF,
Reserved-Bytes. Eine strukturell kaputte Bank verlaesst SynthStudio nicht mehr.

Doku-Korrektur aus den Stock-Zahlen: Gate-Flag (Byte 3) ist kein Pflicht-Bit
(38% aktive Stock-Steps haben 0); Bytes 5..7 sind Chord-Noten, 8..11 immer 0.

16 neue Tests (Werksbank als Ground Truth + 8 Korruptions-Szenarien); den
vorbestehend roten Pan-Histogramm-Test auf die korrekte Pan-Semantik gehoben
(seine Zahlen beschrieben das falsche Byte +0x22). Vollsuite 11448 gruen.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…(v3.308.0)

Semantik aus der Werksbank e2s-2016 abgeleitet: 4 392 aktive Stock-Steps
tragen in den Bytes 5..7 Zusatznoten 2..4 (0 = unbenutzt, nie >127), die
Bytes 8..11 sind in allen 256 000 Records 0. Vorher gingen Akkorde bei jedem
Parse->Build-Roundtrip verloren — nur der Patch-Pfad writePatternBodyIntoAllpat
war verlustfrei.

- ParsedPartStep + E2StepInput: neues Feld chordNotes?: number[]
- Parser fuellt es (nur wenn belegt); electribePatternBuilder.writeStepRecord
  und e2sExport.buildE2PatternBody schreiben es zurueck (Clamp 0..127)
- e2Sysex: 'motion'-Bytes teilentschluesselt, Doku korrigiert, neuer Helper
  stepChordNotes(); Feldname bleibt fuer API-Kompatibilitaet
- veraltete Step-Record-Doku in electribeImport.ts auf das korrigierte
  Layout gehoben (stand noch auf Velocity@1/Note@4)

2 neue Tests: synthetischer Chord-Write inkl. Clamp + Stock-Ground-Truth-
Roundtrip (5 akkordtragende Werks-Patterns, Chord-Bytes byte-genau identisch,
Parser sieht >4000 Chord-Steps). Vollsuite 11450 gruen, tsc clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…v3.309.0)

Schliesst das offene v3.308-Item "UI zeigt Chord-Noten noch nirgends an":

- StepData.chordNotes (AudioEngine) + Store-Action setStepChordNotes. Die
  Engine spielt Akkorde bewusst NICHT ab — Anzeige + verlustfreier Re-Export.
- Import verdrahtet auf beiden Wegen: Bank-/Datei-Import fuehrt chords
  index-aligned durch convertParsedPatternToSynthstudio, der Sysex-Pfad
  ("Von Korg") nutzt stepChordNotes(). Beide setzen auch undefined, damit
  Akkorde eines frueheren Imports abgeraeumt werden (setPartSteps spreadet
  alte Step-Props weiter).
- Export: convertStepToE2 reicht chordNotes (gefiltert 1..127, max 3 Slots)
  in E2StepInput durch — Bytes 5..7 kommen byte-genau an.
- UI: Chord-Indikator auf der Step-Zelle (ChannelStrip, inkl. aria-label und
  Tooltip), Akkord-Chips mit Notennamen + Entfernen-Button im StepInspector.

BUGFIX dabei gefunden: NOTE_NAMES fehlte "G#" — alle Pitch-Labels oberhalb
von G waren einen Halbton verrutscht, NOTE_NAMES[11] war undefined. Neu:
midiNoteLabel() (E2-Konvention 60=C4) + chordNotesLabel(), mit Regression.

10 neue Tests (e2-chord-step-editor.test.ts) inkl. Werksbank-Sichtbarkeit
(>3000 Chord-Steps nach Konvertierung). tsc clean, 11460 gruen / 37 skipped.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…setzt

Die Datei war ein lokales Regenerat, kein Teil von v3.309: pretest/precheck
rufen gen:sandbox auf, und auf einem CRLF-Checkout (Windows, core.autocrlf)
hasht sandbox-runtime.ts anders (d1c3cd64) als auf dem LF-Checkout der CI
(fdd7fcee). Der Output-Hash war identisch — nur der Quell-Hash wich ab und
liess den Staleness-Check fehlschlagen.

Merke: das lokale Regenerat dieser Datei nie mitcommitten, solange der
Checkout CRLF traegt.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@GeorgDub
GeorgDub merged commit 7bf8e88 into main Jul 31, 2026
2 of 3 checks passed
@GeorgDub
GeorgDub deleted the fix/e2-step-layout branch July 31, 2026 15:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant