Repository navigation
Voice alloc fix opt in, firmware mapping doc, wave voice trace tool, - #6
xbraindance wants to merge 11 commits into
Conversation
The full panel is 2338 px wide, which is hard to fit on smaller screens. System > Tabbed Layout shows the panel as three tabs (Oscillator, Filter, Control) beside a fixed screen section, with the transport row, System Volume and the System menu always visible. The choice is remembered beside the panel-skin preference. Each tab is a list of original-SVG rectangles translated into a smaller view, so artwork, hit regions, LEDs and firmware wiring are reused unchanged; the classic layout is the identity mapping. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Keep the Waldorf-provided Sounds/System/Tools folders and their downloaded archives out of version control. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The 23 August note predated the firmware mapping. Replace it with the findings from mapping and running both OS 1.700 images (main OS and the WDV voice-board program) in a 68000 oracle: corrected hardware map, master-to-voice-board protocol, modulation-table facts, reproduced firmware bugs, remaining open questions and next steps. The full map, firmware and gates stay outside the repository. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
WaveVoiceTrace boots the real WDV.SYS in VoiceFirmwareRuntime from a small command script (poke, until_pc, scan, run, mark) and prints the logged ASIC/CV write stream with cycle stamps. The firmware repo's oracle/gate_e_wdv_note_trace.py runs the same script on the Musashi oracle and diffs the two: one note on voices 3 and 9 matches in order, value and cycle across all 11,146 checks. Both sides use the same 68000 core, so this checks bus decode, shared RAM and IRQ plumbing, not the ROM. The tool is EXCLUDE_FROM_ALL and needs no ROMs at build time. The research note's next-step checkbox is ticked with the result and the gaps found: the routing latch (0x8C0000) and board-control latch (0x800001) are neither logged nor decoded, and the engine's firmware register shadow is unused. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Wave RAM is at board 0x040000 (A) / 0x050000 (B) with a write-both alias at 0x060000, not 0x600000. The voice bus also fell through to master DRAM below 0x100000, so WDV wave-RAM stores landed in the master heap. The board now sees only its private 64 KB, the shared SRAM and its devices. The shared SRAM is 512 KB (0x100000-0x17FFFF); drop the 0x180000 extension decode on both buses so accesses above it count as unmapped. Verified: ctest passes (4/4) at this commit. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…esses Table 0x25E8 follows 8*n^2 except index 6 (-29912), 126 (31000) and 127 (32767). The oscillator asr.l #3 sites are 0xE14/0xECA, not 0xE34/0xEEA. Verified: ctest passes (4/4) at this commit. No test covers the table values. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A nonexistent firmware path fell back to its parent directory, so the recursive image search walked "/" and effectively never returned. Only step up to the parent when the path is an existing file. Verified: ctest passes (4/4) at this commit; the new WaveCoreTests case covers the missing-path load. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
OS 1.700's find_free_voice (0x2EAC) returns the lowest-level voice of any part when no voice is free, so the callers' steal passes never run and a fresh note steals a held note of its chord. A one-byte patch at 0x2EE2 (bcs -> bra) restores OS 1.680's allocation. It is applied only to an image whose surrounding bytes are the 1.700 ones, off by default, toggled from the System menu and saved in plugin state. Verified: ctest passes (4/4) at this commit. The 1.700 vs 1.680 allocation difference and the effect of the one-byte patch were checked against the 68000 oracle (gate_f_voice_alloc_1680_vs_1700.py, 12/12 checks: 1.680 steals no held note, 1.700 does, 1.700 with the patch does not). The oracle's voice-board side is a model, not hardware-validated. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
WDV writes the write-only routing latch (0x8C0000, 8 bytes per voice) but the voice board neither logged nor decoded it, so the emulator-vs-oracle diff could not cover it. VoiceFirmwareRuntime now queues those writes with the ASIC/CV writes (the engine still ignores them) through one queueHardwareWrite helper. WaveVoiceTrace takes an optional board argument (0-2) so the gate can run all three voice boards. The research note records the routing latch layout, the resolved board limit (3) and three emulator assumptions that disagree with the firmware map; none of those are changed here. Verified: ctest passes (4/4). gate_e_wdv_note_trace.py runs boards 0-2 against the Musashi oracle: 35,004 checks, 0 failures. Both sides use the same 68000 core, so this checks bus decode and plumbing, not the ROM or the hardware. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Both are local-only files that must not be committed. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The WDV image sends each oscillator level to the ASIC as three bits (ws level >> 4, written at 0x9B8/0xA58) and never to a CV channel. The engine's 7-bit level path is finer than that firmware contract. WaldorfEngine::setQuantiseWaveLevels keeps only those three bits, scaled back to 0..0x70. Off by default, no UI. The scaling is a hypothesis about the ASIC gain law; README's accuracy boundary says so and asks for an eight-step hardware level capture. Verified: ctest passes (4/4); a synthetic test covers the level mask. Not verified audibly or against hardware. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
The release I just published already fixed a fair few of these issues. Let me check through your work and see what you've done that I've missed. Thank you |
|
Thanks for putting this together. I’ve reviewed it against 0.1.12, and there are several useful additions here, particularly the firmware-path guard, voice-board memory-map corrections, modulation-table details and tracing tools. Before integrating anything, could you clarify a few points?
I also noticed The branch now conflicts with 0.1.12 in the README, editor and core tests. Would you be happy to split the firmware fixes/tracing and tabbed interface into separate PRs against current |
|
Thanks for the careful review. Answers in order: Voice allocation. No, we haven't shown an audible benefit and we won't claim one. The fix is a one-byte patch to find_free_voice (0x2EAC, byte 0x2EE2, 0x65→0x60). It removes the firmware-level steal bug, which the oracle script gate_f reproduces against OS 1.680. You're right that this emulator doesn't consume those writes, and that chooseVoice already prefers inactive and released voices over held ones. The patch is opt-in, off by default and hardware-unvalidated, and its only test checks that it applies and reverts. We're happy to drop it or keep it labelled experimental, whichever you prefer. Reconstruction test. Yes, the DSP change was omitted. The test landed in 7857e34 without the rewrite it was written for, which is why it fails on current main. The rewrite and scripts/derive_wvc_input_network.py are now in a separate PR: xbraindance/wave#6 · Model the WVC input network and…. On top of main, the build and all 4 test suites pass. The script derives the response from the p.47 component values and reproduces the test's +0.26, +3.66, −1.93 and −8.05 dB at 1, 8, 20 and 30 kHz. One caveat: the p.47 scan can't settle whether R4003 is 180K or 100K. The script uses 180K. At 100K the gains become +0.06, +5.19, +0.62 and −5.29 dB, so the 20/30 kHz values move by about 2.5–3 dB. A better scan or a measurement would settle it. Memory map. The changes are in the wave RAM and shared SRAM commits, with testVoiceBoardWaveRamDecode (about 35 lines in WaveCoreTests.cpp). Wave RAM A and B are at 0x040000 and 0x050000, with a write-both alias at 0x060000. The shared SRAM is 512 KB at 0x100000–0x17FFFF. The test checks that stores to wave RAM never reach master memory. The address references are in waldorf-wave-firmware-reverse-engineering.md, lines 53, 75 and 89–90. Research evidence. The full firmware map and the oracle scripts are built from the firmware binaries, so we can't publish them. The "not localised" wording was stale and is fixed in xbraindance/wave#5 · Merge WDV fixes and Audio Out…. Audio Out and Start modulation. The fix is in #5. Audio Out now reads part byte +0xC instead of +8, with 0 = Aux only, 1 = main and 2/3 = sub. testPerformanceAudioOutRouting checks that only value 1 reaches the main mix. The start modulation change has no test and is checked against the oracle only. Note the behaviour change: three parts in pg.set and ultimate.set have +0xC = 0 and now leave the main mix. Three-bit levels. No hardware capture supports it. What we have is static: the level words reach only the ASIC writer, and reg 4 carries 3 bits per level. The gain law of that 3-bit code is unknown and needs an 8-step capture of a real unit. The model stays opt-in until then. WaveVoiceTrace. Agreed, and fixed in #5 (e9fe4af). A script that can't be opened now prints an error and exits 2, instead of returning success with empty output. Splitting and conflicts. #5 has the firmware fixes and tracing, and #6 has the reconstruction change. Neither includes the tabbed interface, and we'll leave out the two ignore commits. Both PRs are against the current origin/main (f815546), which doesn't have 0.1.12 yet. Once 0.1.12 is pushed we'll rebase, and we expect the conflicts to be in the README, editor and core tests. |
|
Thanks for the clarification. That explains the reconstruction-test failure and helps separate the changes we should consider. I’d prefer to leave the firmware voice-allocation patch out of this integration, given that no audible benefit has been demonstrated with our current engine. Please keep the reconstruction/DAC changes separate too; we should resolve the R4003 value and verify the DAC interpretation before changing the released audio model. We’ve now independently investigated the three-bit levels by executing the authenticated WDV mixer and ASIC-writing routines across 9,600 input combinations:
So the eight-code encoding after modulation is confirmed by firmware execution. The remaining hardware question is the gain associated with each code. We also found a modulation-scaling discrepancy that the proposed mask alone doesn’t address. With base mixer level 2 (stored value 32), volume modulation amount +7 (stored value 120), and a positive half-scale source value of 16384:
Could you check this case against your oracle? It suggests we need to match the modulation scaling and integer rounding as well as the final quantization, including Noise. The memory-map corrections, missing-path guard, tracing improvements and Audio Out correction look useful. For Start modulation, please add focused tests covering free start, fixed phase, positive/negative modulation and clamping. We can use locally supplied firmware for reproducible checks without including firmware payloads. One repository clarification: 0.1.12 is already published and pushed. Our current Could you prepare clean branches against |
|
Thanks, all clear on scope. The firmware-fixes branch is based on c7b0b53 and contains only firmware-derived changes; the tabbed interface is a separate branch; the allocator patch and the reconstruction/DAC work are not included. Your 3-bit level case: confirmed, and I found where our model differs. On the oracle (WDV 0x10A6 with 0x246C and the 0x25E8 table), base stored 32, amount stored 120, source word 16384 gives an intermediate of 81 and ASIC code 5, identical for Wave 1, Wave 2 and Noise. Our model gives 75 because it works in normalised 0..112 units: the firmware's modulation word is ((src * table[amount]) >> 16) * 2, then >> 8, so a full-scale source swings the level by up to +/-127 steps, not +/-112. 32 + 0.7656 * 0.5 * 112 = 74.9 against 32 + 49 = 81 (factor 128/112). Rounding is also integer: arithmetic shift of the word (floor), 16-bit add, clamp 0..0x70, then >> 4. I wrote that as an integer model and swept it against the oracle: 18,576 combinations (Wave 1, Wave 2, Noise x 9 base levels x 43 amounts x 16 source words), 0 mismatches. So the final mask alone is not enough; the scaling and rounding need to match too. I have not changed the level model in this PR since you want the DAC/level interpretation settled first; happy to put the integer-exact version up as its own PR when you want it. Start modulation has tests as requested. While writing them I found the map's "clamped to 1-127" was wrong outside the nominal range: Wave 1 compares signed (8-bit wrap), Wave 2 compares unsigned (anything outside 1..126 becomes 127). The engine now uses the firmware's integer arithmetic for the phase code; one caveat remains in how the engine scales its float sources (controller words are CC << 8 in the firmware), details in the PR. |
Skip these:
Ignore the local service manual and header image
Ignore local Waldorf resources (Sounds, System, Tools and their zips)