discover · compare · collections · requirements · contribute · feed · watching · stats · help with your tokens
OnjLouis/syxg100-hybrid · source
Snapshot 0 · 2026-11-04T12:47:28Z · C++ · MIT
Content fingerprint
8d37ca3c3f3c1ba8f7459ffc125e084a2148864337c1bddc82455cda51e0b8f0GitHub description at capture
Modern Windows VST2 preservation wrapper for Yamaha S-YXG100 VL/PVL and SG synthesis
README at capture
# S-YXG100 Hybrid ## Version 0.1.9: Reset-Free MIDI Drums Files without a GM, GS or XG reset now retain the normal channel-10 drum default when sending bank-zero selections. Startup no longer assumes that an XG reset has already arrived. Explicit XG resets still permit melodic channel 10; explicit part modes, other resets, gains and effects are unchanged. The fix applies generally, not only to the reported DirectX diagnostic MIDI. ## Native Linux Updater 1.2.0 Run `sh ./Update-YamahaHybrids.sh` with its Python script and product/key JSON alongside it. Python 3.9+ and OpenSSL are required; PowerShell and Wine are not needed for updating. See [Linux-Updater.html](Linux-Updater.html). This separate updater release leaves synth audio and version unchanged. It supports the stable signed updates of all three hybrid families and preserves unrelated files. ## Version 0.1.8: Preserve Native VL Voice Edits Late-starting VL/PVL workers now replay bank/program selection and native voice edits in their original order, then restore current controllers without reloading the preset. This fixes Timeless's ending: Volume Expression Mode is no longer erased, so CC11 fades do not revert to breath-controlled timbre or jump in level. Intentional later program changes still reload normally. Full-volume gain, master-volume handling, SG and effects are unchanged. Setup history remains bounded; capacity exhaustion uses the existing current voice snapshot fallback. This does not correct a host that omits SysEx. The separate Falcosoft fade report was traced to its intentional master-volume filtering option. Disable Use Sysex for Volume/Balance for VST output when preserving MIDI-file fades; keep file SysEx enabled and restart playback. ## Version 0.1.7: Master-Volume Fades XG and Universal Real-Time Master Volume now affect the external VL/PVL audio at the correct MIDI event time. FatPizz's closing plucked lead fades with the backing instead of remaining prominent. SG already handles master volume internally and is not attenuated twice. Full-volume gain is unchanged, and effects retain their natural decay. The external fade uses a power-law envelope, not a bit-exact reconstruction of Yamaha's quantized voice-volume curve. Intermediate-level hardware parity is not claimed. GM/GM2/GS/XG resets restore the external master envelope. Existing insertion-effect limitations and host-headroom requirements remain. ## Version 0.1.6: Voice Mapping and Independent Insertions Independent MU Effect 2 distortion (49/00) and overdrive (4A/00) can be translated for external VL/PVL audio and a single routed SG part using separate voice-free software XG DSP instances. Normal XG reverb, chorus and variation, including system delay, are retained; MU DSP is not substituted. Private insertion connection preserves the requested Dry/Wet balance. Its own system sends are disabled; the processed output feeds the song's sends once. No additional gain trim is applied to imitate MU levels. This is an experimental compatibility feature, not hardware-equivalent MU effects. Distortion increases peaks and may require more host headroom. Converted AWM/2006LE insertion processing, other algorithms, effect-controller modulation, chained assignments and inseparable multi-part SG routes are not implemented. Pan/send proportions use the existing 128-frame DSP quantum. This release restores converted MU-exclusive MSB 48 sub-banks, including Anathema, and preserves SFX drum bank 126 under explicit rhythm assignments. The sub-banks require the matching extended converted engine. These changes are included in the complete package and signed update. See the HTML guide for limitations. ## Version 0.1.5: MU-Derived Sound Set Current complete packages use MU1000-derived AWM sounds converted with [NightFright2k19's SXG-Create-NF](https://github.com/NightFright2k19/SXG-Create-NF), a fork of Soundshock's SXG-Create. The table and converted waves are embedded in `syxg50-engine.bin`; VL/PVL, SG, and the software XG effects path remain. MU Native is the default map. MU Voice Map Select also switches the converted engine's Native/Basic map without affecting legacy engines lacking that feature. This is a software-engine conversion, not MU hardware emulation. Some three/four-element voices are folded to two elements, unsupported effect types use approximations, and some sample loops retain conversion limitations. Existing songs can sound different. Use original S-YXG50 for its original voices, or Mu2026 for its separate firmware-emulation effects path. Updated QWS and REAPER definitions accompany complete packages. The GitHub repository remains source-only: no Yamaha binaries, ROMs, tables, or demonstration MIDI are included. See the HTML manual for conversion credits and the BSD-3-Clause notice. Upstream revision: `596e23209cf9d08fb199769be8a9a2adf8b1e822`. ## Version 0.1.4 Corrects an SG startup memory error that could crash the singing worker under Wine. The legacy one-slot setup now supplies the one-based slot number expected by Yamaha's native helpers. The loaded image is checked before this correction is applied, and the Yamaha file on disk remains unchanged. ## Version 0.1.3 Prepares the eight VL helpers and the SG helper in a serialized, below-normal- priority background phase when the host activates the plug-in. This removes process creation and Yamaha-engine initialization from first-note MIDI processing. A single active plug-in instance reserves approximately 60-70 MB for its ready helpers; hosts that prebuffer more than one instance multiply that figure. ## Version 0.1.2 Adds an accessible native editor and handles complete Yamaha model `0x64` Plug-in Voice bulk transactions. Songs can now load and change their embedded VL voices during playback, including the associated bank, program, volume, mono/poly, pitch-bend range, portamento, reverb, and chorus settings. For the user-facing overview, runtime layout, current compatibility notes, and real-time host instructions, see [`README.html`](README.html). This source-only project combines a user-supplied 32-bit Yamaha S-YXG50 VST with separately recovered VL/PVL synthesis; current complete packages use a MU-derived conversion of that AWM engine. This repository does not contain or distribute Yamaha executables, tables, presets, demo files, or firmware. S-YXG100 Hybrid brings the discontinued Windows 9x VL/PVL and SG engines into a modern Windows VST2 host while retaining S-YXG50 for ordinary XG synthesis and Yamaha effects. The recovered engines run as isolated worker processes so their legacy generated-code state cannot corrupt the host or one another. ## Accessible editor The plug-in editor opens a native Windows dashboard with three pages: live status, under-the-hood routing, and the original Yamaha editor. Status uses standard named controls and a 16-channel report list that exposes engine, bank, program, note activity, controllers, pitch bend, and effect sends to screen readers. Its small engine activity graphic is supplemental; the same values are always present in the selected-channel text. Use `Alt+S`, `Alt+U`, or `Alt+Y` for the three pages, `F5` or `Alt+R` to refresh, and `Alt+C` to copy a complete text report. Tab and Shift+Tab move through the controls, and arrow keys switch among the page buttons. Live updates change rows in place without rebuilding the list or moving focus. The status page describes the live plug-in instance owned by its host. VSTHost therefore exposes current channel activity. Foobar2000 MIDI Player may render a MIDI file ahead of playback and later open the editor on a new, idle instance; in that host the status page can consequently show defaults while Foobar2000 is playing its already-rendered audio. The wrapper keeps S-YXG50 as the proven AWM and effects engine. It routes MIDI bank MSBs 33, 81, and 97 to a native PVL engine and leaves ordinary XG parts on S-YXG50. Returning a channel from a VL bank to an ordinary bank clears the VL part and forwards the transition to XG. GM1, GM2, GS, and XG system reset messages reset the remembered routing state. Before any system reset is received, GM-style defaults preserve channel 10 as drums even when a file sends ordinary bank-zero selections. Channel 10 retains the normal rhythm default after a reset. In XG mode, a later bank MSB changes that implicit mode: melodic banks release channel 10 from rhythm operation, while bank 127 selects drums. GM1 and GS bank selections do not override their channel-10 drum default; their original bank, program, and drum-note layout pass through to S-YXG50 unchanged. GM2 follows its standard bank 120 rhythm and bank 121 melodic selections. An explicit Yamaha part-mode SysEx remains authoritative and is not overridden by subsequent bank changes. Note ownership is retained across bank changes in both directions. If a note, sustain pedal, or all-notes-off transaction begins under one engine and its channel changes between XG and VL before release, the required release reaches both engines. Ordinary events remain routed only to their current owner. VL/PVL runs as native 32-bit code in a pool of eight one-voice worker processes prepared in the background when the host activates the plug-in. Legacy VL files without Yamaha voice-assignment SysEx retain their original source channel and the monophonic behaviour of S-YXG100LE. Japanese PVL files explicitly assign native voice slots; only that mode maps workers onto Yamaha's canonical first VL part and enables up to eight-note polyphony. Notes retain exact voice ownership across overlapping and repeated pitches; a ninth simultaneous note steals the oldest active voice. A compact per-channel snapshot restores bank, program, controllers, RPN/NRPN state, pressure, and pitch bend when a worker changes channels. XG/PVL part SysEx is filtered and remapped in the same way while global SysEx remains unchanged. Process isolation prevents the legacy Yamaha engines from overwriting shared generated-callback state. Yamaha model `0x5D` SysEx routes singing data to a separately prepared native SG worker. The wrapper replays bounded pre-activation setup with its original timing, preserves MIDI and SysEx order and block offsets, queries the SG route mask, and suppresses only note-on/off events that SG accepts. SG never shares an address space with XG50 or PVL. Workers use inherited anonymous handles and shared memory; they do not use network access, temporary files, Python, or CPU emulation. Timed MIDI and audio are batched once per render block: all active VL workers run concurrently, then the wrapper waits and mixes their completed buses. The callback-stack keeper is suspended while idle, avoiding one busy-spinning thread per worker. If a worker or VxD is absent or fails, native routing falls back without taking down XG. Both recovered renderers provide four signed 16-bit stereo planes. Controlled CC91, CC93, and CC94 impulse tests identify them as dry plus unprocessed reverb, chorus, and variation send buses. A signature-checked bridge inserts all four native planes between XG50 voice synthesis and its original effects stage, converting native normalized samples to XG50's internal sample-unit scale. XG50 bus probes confirm dry at buses 0/1, reverb at 2/3, chorus at 4/5, and variation at 6/7. Reverb and chorus then use the same Yamaha processing as XG parts; variation still depends on XG50's effect configuration and connection mode. If that exact XG50 build is unavailable or the bridge signature does not match, the wrapper mixes the native dry plane directly instead. A calibrated native gain of 3.5 is applied in either path. MIDI events retain their VST block offsets, including the first VL note. PVL exposes its generated renderer only after an initial native trigger. The wrapper retains a bounded setup history, uses the first positive VL note to warm the native path, replays setup because warm-up consumes that state, and retriggers the note at its original block offset. Audio rendering remains dormant until then. The pre-activation setup history preserves every short MIDI message in exact arrival order. This is required for stateful RPN and NRPN transactions: treating CC101, CC100, and Data Entry as independent replaceable controller values can turn a valid pitch-bend-range sequence into an ineffective RPN-null sequence. The first worker consumes that ordered history directly without appending a redundant channel snapshot. This also preserves custom model `0x57` VL voice uploads, which can be replaced if bank and program selection are sent again after the upload. Workers created later still receive the current snapshot. The retained history remains fixed at 1,024 events and never allocates in the audio callback. PVL uses Yamaha's genuine gate-zero software renderer through dispatcher service 7. Every native render uses a fixed 256-frame cadence, independent of the host block size. The older generated hardware-transport path remains available only for diagnostic comparison with `SYXG100_VL_RENDER_PATH=transport`; it is not the default. SG uses its recovered 256-frame native host bridge. Render buffers, event queues, and IPC storage are fixed in size. VL and SG always run at their proven native rate of 44,100 Hz. At a different host rate, a preallocated streaming adapter converts all eight native dry and effect-send buses while retaining fractional position and unused source samples across callbacks. Absolute MIDI positions are converted onto the same native timeline, avoiding per-block rounding drift. The 44.1 kHz path bypasses the adapter and remains sample-identical to the accepted build. Complete VL and SG trace renders have also passed at 48 kHz. Real-time playback at 48 kHz has been confirmed in Foobar2000 without the former worker stall or crash. ## Runtime Layout The packaged tester archive groups these files in its `VST` folder. Keep them beside one another in that one runtime directory: ```text syxg100-hybrid.dll built by this project syxg100-vl-worker.exe built by this project syxg100-sg-worker.exe built by this project syxg50-engine.bin user-supplied S-YXG50 VST binary Sxgpvknl.vxd user-supplied original PVL VxD sxgsgknl.vxd user-supplied original SG VxD syxg100-hybrid.version.json updater product/version marker ``` The user-supplied Yamaha files do not belong in this repository or a distributed source or binary package. ## Wine compatibility The 32-bit plug-in and its separate native VL/SG workers can run under Wine, but the workers require Wine's newer WoW64 process arrangement. A user reported that an incompatible prefix let ordinary XG play while the VL worker faulted as soon as a VL note sounded, causing the part to fall back to piano. For Wine 11, use a 64-bit prefix and force the newer WoW64 mode when launching the 32-bit VST host, for example: ```sh WINEPREFIX="$HOME/.wine-syxg" WINEARCH=win64 wineboot WINEPREFIX="$HOME/.wine-syxg" WINEARCH=wow64 wine /path/to/vst-host.exe ``` `WINEARCH=wow64` requires a prefix that was created as 64-bit, which is Wine's default. It cannot convert a pure `WINEARCH=win32` prefix; create a separate 64-bit prefix instead. This workaround was reported in [issue 4](https://github.com/OnjLouis/syxg100-hybrid/issues/4) and agrees with [Wine 11's documented new-WoW64 behaviour](https://list.winehq.org/hyperkitty/list/wine-releases%40list.winehq.org/thread/UL6L2GJ55VYUJ5KUMBZ3TZSXRFJ52QG6/). Wine remains community-tested rather than a primary supported platform. ## Updater `Update Yamaha Hybrids.cmd` launches the shared PowerShell updater. The pair may be placed in this product folder or in a common parent containing both hybrids. It searches at most two folder levels, detects existing installations by their unique wrapper DLLs, and never installs a missing synth. Stable GitHub release metadata is signed with a product-specific RSA key. The manifest restricts replacement to an allowlist, identifies the exact product, and supplies SHA-256 hashes for the externally hosted runtime ZIP and every managed file. The updater stages and verifies the complete package before changing the live folder. It displays release notes and requires confirmation unless explicitly invoked for unattended installation. Before replacement, managed files are stored in one rollback ZIP beneath `%LOCALAPPDATA%\Onj Research\Yamaha Hybrid Updater\syxg100-hybrid\backups`. Only the newest rollback and two bounded logs are retained. Rollback DLLs are never left loose in a VST search path, unrelated files are preserved, and a partial replacement is restored automatically. Audio hosts must be closed so they do not lock the runtime files. ## Portability and macOS The repository is intentionally public so the preservation work can be studied, verified, and extended. The MIDI routing, ordered setup history, voice allocator, effects-bus mapping, LE image loader, native-engine interfaces, and behavioural tests provide a concrete starting point for another platform. The current runtime is not directly portable: it loads original 32-bit Windows PE/LE code and depends on Win32 process, shared-memory, event, and VST2 APIs. A native macOS port would need replacements for that hosting layer and either a compatible execution environment for the entitled legacy runtime or a clean reimplementation of the recovered synthesis interfaces. Yamaha binaries and demonstration files are not licensed by this project and must not be committed to a fork or redistributed with a build. ## Build Build output must remain outside this source directory. The wrapper and worker target 32-bit Windows because the original engines are 32-bit. ```text cmake -S . -B <build-directory> -G Ninja \ -DCMAKE_C_COMPILER=<i686-clang> \ -DCMAKE_CXX_COMPILER=<i686-clang++> cmake --build <build-directory> ctest --test-dir <build-directory> --output-on-failure ``` ## Verification Tools `HybridHostProbe.exe <wrapper.dll>` verifies the normal XG path. Supplying a captured event trace also exercises VL routing and mixing: ```text HybridHostProbe <wrapper.dll> [events.pvte.txt] ``` `HYBRID_PROBE_BLOCKS` controls the number of post-event render blocks. `HYBRID_PROBE_NOTE_DELTA` assigns a block offset to trace note events for timing checks. Event traces and Yamaha-derived test data are private research inputs and are not included here. The wrapper has also been exercised in 32-bit VSTHost with its real-time audio engine. Load the wrapper from an isolated runtime directory, then use VSTHost's MIDI player or a virtual MIDI input to send complete songs. Confirm that no more than eight VL voice workers exist, SG owns one separate worker, playback time advances normally, and all workers exit when the host closes. A virtual MIDI loop is required when testing from an external sequencer such as QWS. For native-render diagnostics, `SYXG100_VL_GENERATED_HEAP=restore` retains the current deterministic heap-cursor behaviour. Setting it to `advance` allows the generated data heap to advance naturally with the generated code ring. This is an experimental comparison switch, not a release setting. `SYXG100_VL_GENERATED_JITTER=zero` retains the deterministic timestamp patch; `native` preserves Yamaha's original timestamp-derived allocator advance. The latter can vary between worker launches and is also diagnostic-only. `NativeProbe` validates the in-process engine independently of S-YXG50: ```text VlNativeProbe <Sxgpvknl.vxd> <events.pvte.txt> ``` `SgNativeProbe` independently validates a user-supplied original SG kernel, including multi-object LE loading, initialization, bounded rendering, MIDI/SysEx transport, native host mixing, and clean shutdown. ```text SgNativeProbe <sxgsgknl.vxd> [events.sgte.txt] [output.wav] ``` The reference 2,048-frame render is deterministic and remains comfortably faster than real time. The older 64-bit Unicorn worker remains only as a research oracle; it is not part of the wrapper's runtime path. Set `SYXG100_DISABLE_XG_EFFECTS=1` only to compare the direct dry fallback. `SYXG100_NATIVE_GAIN` overrides the calibrated default native gain of `3.5` for diagnostic comparisons; accepted values are `0.1` through `8.0`. XG50 can emit floating-point samples above unity even with all native channels muted, so a host or lossless test renderer must preserve headroom before final conversion. `SYXG100_HYBRID_LOG` enables bounded wrapper diagnostics, and `SYXG100_SG_WORKER_LOG` writes one end-of-run SG worker summary. None of these diagnostic settings is required for normal use.