This document summarizes the current reverse-engineering and integration status of gedx8musicdrv.dll and the DirectMusic playback path used by the project.
The main playback path is working.
The following steps are currently confirmed by ASM review and runtime behavior:
+0x08creates the driver instance+0x10initializes the synthesizer using the 12-byte init structure+0x20loads a cached object and returns the created wrapper+0x34creates an audiopath object+0x38activates an audiopath object+0x3Cis currently used as the normal audiopath state / volume-style call and is exposed asSetVolumeOfAudiopath(...)+0x54starts segment playback using the loaded segment wrapper+0x5Cqueries playback state using the loaded segment wrapper
In practical terms, the project can now:
- load
.sgtsegments - create and activate an audiopath
- start segment playback
- play music successfully in stable runs
The biggest remaining issue was not the basic playback path itself, but native timing / settling.
The driver can report success for:
- segment loading
- audiopath creation
- audiopath activation
- playback start
while the final audio output is still not fully ready.
Without extra settling time, this led to inconsistent behavior such as:
- no audible sound
- wrong instruments
- playback state reporting
0while sound was already audible - playback state reporting
1while the final output was still incorrect
Playback became stable after introducing explicit settling time at key transition points:
- wait after
geLoadCachedObject - wait after
geActivateAudiopath - poll playback state longer after
geStartSegmentPlayback
These waits are currently required for stable playback and should be treated as part of the practical integration, not as arbitrary hacks.
The currently reliable synthesizer init path is the fixed legacy mapping:
- mode
0->44100,0x40 - mode
1->22050,0x10 - mode
2->11025,0x08
Although the DLL accepts a sample rate through the 12-byte init structure, the known-good runtime path currently remains the fixed legacy mapping above.
The normal playback path should currently do the following:
- create the audiopath
- activate the audiopath
- normalize the audiopath state with:
SetVolumeOfAudiopath(audiopath, 0, 0);- wait for the native pipeline to settle
- start segment playback
- poll playback state long enough for the native graph to stabilize
A few parts are still only partially understood.
+0x58 is a real segment-wrapper method, but it is not part of the reliable normal startup sequence.
Calling it at the wrong point can push playback back into a non-running state, so it should not be inserted into the standard start path without a clearly confirmed reason.
Additional wrappers exist around:
+0x40+0x44+0x48
These appear to belong to an audiopath property / dispatcher layer, but their exact semantics are still not fully confirmed.
They are not required for the currently working playback path and should be treated as future reverse-engineering targets rather than mandatory startup calls.
The loaded segment wrapper currently behaves consistently enough to rule out a simple pointer-corruption explanation.
Observed stable fields:
wrapper + 0x04 = 0wrapper + 0x08 = 2wrapper + 0x0C = native payload pointer used by the start / reset / state wrappers
Differences in wrapper addresses such as ...0700 vs ...0788 are not, by themselves, evidence of corruption. They are more likely normal allocation differences or different internal native states.
The core playback chain is now understood well enough to work.
The remaining fragility was mainly caused by the fact that successful native return values do not mean the entire DirectMusic playback graph is already fully ready.
The current practical solution is therefore:
- keep the known-good fixed synth init path
- keep
SetVolumeOfAudiopath(audiopath, 0, 0)in the normal path - keep the timing delays and longer playback-state polling
- document the waits clearly in code comments as required native settling behavior
Recommended future work:
- clean up the timing constants and centralize them
- document the stable startup sequence directly in code
- continue reverse-engineering
+0x40 / +0x44 / +0x48 - further investigate instrument / dependency binding behavior for full determinism