Last updated: 2026-07-18
These notes capture the read-only IDA investigation needed to add real vocal
audio rendering to the MCP server. Addresses are for the exact binaries listed
below and must not be treated as stable API addresses. The planned bridge will
resolve exported decorated names dynamically with GetProcAddress.
- Path:
D:\Vocaloid\Vocaloid3FE\DSCL3.dll - Architecture: PE32 / Intel 80386
- Image base:
0x10000000 - Image size:
0x7c000 - File size:
0x68f60 - SHA-256:
9bcdc8b8424849f18975af47ceaad984222239ddad57d1554e75b2478fb5f789
- Path:
D:\Vocaloid\Vocaloid3FE\DSE3.dll - Architecture: PE32 / Intel 80386
- Image base:
0x10000000 - Image size:
0x802000 - File size: 7,970,144 bytes
- SHA-256:
f251e7105eee2c8ceb8e632bf22ff50655cb7b87b7e892b6116b3b17c6a4ee5f
The useful path is the exported C++ wrapper in DSCL3.dll, not direct calls to
the raw DSE functions:
- Load a VSQX with
CVSVsqManagerIFfromVsq3.dll. - Obtain an
IVSMusicalPartplus a sequence time map. - Construct
CxDaisyMidiFileand callEncodeMusicalPart. - Construct
CRtSynthesis, configure DB paths/voices, and callOpenSynthesizer. - Pass the resulting
CDaisyMidiBufferand aCWaveFiletoDoSynthesis. - Close/destruct all objects in reverse order.
This keeps phonemes, singer selection, pitch curves, dynamics, vibrato, and other VOCALOID-specific data. It is not a MIDI-only workaround.
- Export:
?OpenSynthesizer@CRtSynthesis@@QAEHPB_WN@Z - IDA address:
0x1002f220 - Effective signature:
int __thiscall OpenSynthesizer(const wchar_t* dseDll, double apiVersion) - The version guard requires
apiVersion == 20008017.0(epsilon0.00001). - A null DLL path loads
DSE.dll; the bridge must pass the fullDSE3.dllpath. - Resolves these DSE exports:
DSEGetVersion,DSECreate,DSEDelete,DSESetStaticSetting,DSESetDynamicSetting,DSEDoStepSynthesis,DSEStart,DSEStop,DSEReset,DSESetDBMPath,DSESetVVoiceTable,DSEBeginExport, andDSEEndExport. - Calls
CreateDSEonce as a capability/voice-table probe and deletes that temporary DSE before returning success.
- Export:
?CreateDSE@CRtSynthesis@@IAEHPAPAE@Z - IDA address:
0x1002eeb0 - Calls
DSEGetVersionusing engine-version token20012012.0. - Calls
SendVVoiceTableToDse,DSECreate, thenDSESetStaticSetting. - Static settings observed in the wrapper include the configured sample rate, frame size 256, DBM path, mono output, and optional returned voice table.
- Failure sentinel:
-2.
- Export:
?DoSynthesis@CRtSynthesis@@QAEHPAVCDaisyMidiBuffer@@PAVCWaveFile@@KK_NPBD2MM@Z - IDA address:
0x1002f450 - Effective parameters:
(CDaisyMidiBuffer*, CWaveFile*, sampleRate, progressIntervalMs, exportMode, exportPath, exportFormat, float, float). - Creates a new DSE, optionally surrounds synthesis with
DSEBeginExport/DSEEndExport, invokes the internal renderer, deletes the DSE, and returns the renderer status.
- Export:
?DoSynthesis@CRtSynthesis@@IAEHPAUHWND__@@HPAVCWaveFile@@PAVCDaisyMidiBuffer@@K@Z - IDA address:
0x1002a230 - Calls
PrepareWavFile, seeks the Daisy buffer, starts DSE, and renders in 256-sample frames throughDSEDoStepSynthesis. - Daisy events are passed as arrays of compact timestamp/event blocks.
- Generated mono 16-bit samples are appended to
CWaveFile. - Calls
DSEStopand returns success/failure.
- Constructor:
??0CRtSynthesis@@QAE@XZat0x1002c370. The object touches at least 1,040 bytes; allocate using the same MSVC runtime or a conservatively sized zeroed block before invoking the constructor. - Destructor:
??1CRtSynthesis@@UAE@XZ. ?SetDBMPath@CRtSynthesis@@QAEHPBD0@Z.?SetDseVVoiceTable@CRtSynthesis@@QAEXABV?$vector@UtagDSEVVoiceSetting@@V?$allocator@UtagDSEVVoiceSetting@@@std@@@std@@@Z.?PrepareWavFile@CRtSynthesis@@QAEHPAVCWaveFile@@KH@Z.?WriteWavFile@CRtSynthesis@@QAEH_J0PAVCWaveFile@@1@Z.?CloseSynthesizer@CRtSynthesis@@QAEHXZ.
- Export:
?EncodeMusicalPart@CxDaisyMidiFile@@QAEPAVCDaisyMidiBuffer@@PAUtagDaisyMidiV3EncodeStruct@@@Z - IDA address:
0x10014ee0. - The encode-struct's first two observed fields are:
IVSMusicalPart* musicalParttagSequenceTimeMap* sequenceTimeMap
- Allocates and constructs a
CDaisyMidiBufferof0x5cbytes. - Calls
CDaisyMidiBuffer::Create(1, eventInterval, outputMode). - Calls
WriteMusicalPartDaisyMidiTrack(part, timeMap). - Stores the musical part start time in Daisy buffer field 20.
- The caller owns the returned
CDaisyMidiBufferand must invoke its virtual deleting destructor.
- Export:
??0CxDaisyMidiFile@@QAE@XZat0x10012a00. - Object size used by observed fields is at least
0x60bytes. - Default event interval is 2000; accepted range is 50..5000.
The Vsq3 investigation recovered:
CVSVsqManagerIFconstructor/destructor andsysInitializepolicy layout.fileLoadVsqFileownership and error behavior.- Root/track/part interface vtable methods needed to enumerate
IVSMusicalPartobjects. - Voice-library initialization requirements.
The x86 helper must remain isolated from the stdio MCP server, validate every path, enforce timeouts, and return structured render diagnostics. It must never silently claim a WAV was rendered; it must verify RIFF/WAVE headers, sample rate, channel count, sample count, and non-silent peak/RMS before success.
- Path:
D:\Vocaloid\Vocaloid3FE\Vsq3.dll - PE32 / Intel 80386, image base
0x10000000, image size0xb6000 - File size:
0xa4d60 - SHA-256:
236b4be5c09d17f77e5f9c9a7455817edba01664e760908635157eef2dce7256
CVSVsqManagerIFis a four-byte wrapper around an internal0x100-byte implementation object.sysInitializevalidates aVSVsqManagementPolicycontaining 12 scalar words followed by a native VC9std::wstring.- Observed scalar constraints: field 0 is
-1or positive; field 1 is 1..16; fields 3/4/6 are booleans; fields 2/5/7/10 are at least-1; field 8 is-1or at least the field-9 timeout (minimum 60); field 11 is-1or at least 60. - The trailing string must be non-empty. The standalone helper constructs,
assigns, and destroys it with the already-loaded VC9
MSVCP90.dllABI. The Vocaloid runtime directory works as its value.
fileLoadVsqFilereturns the primaryIVSVsqRoot*interface.- Concrete objects use primary interface at offset 0 and the generic
IVSVsqObjectinterface at offset+4. - Generic vtable slot 6 enumerates child objects into a VC9 pointer vector.
- The VC9 vector layout is six pointers/words: iterator proxy, two reserved
words, begin, end, capacity. Vsq3's internal constructor is at RVA
0x725b0for the pinned binary. - Primary vtable RVAs identify important types:
- root:
0x85258 - musical part:
0x85ac4 - VS track:
0x85d1c
- root:
- Therefore a generic child with primary vtable
0x85ac4converts to theIVSMusicalPart*expected by DSCL by subtracting four bytes.
native/vsq_probe.c plus scripts/build-native.sh builds a statically linked
32-bit Windows probe. Against the real Creative/GHOST V4 project it loaded the
project with Yamaha's own Vsq3 implementation and enumerated 20,402 native
objects, six VS tracks, and six musical parts. Against the MCP-generated smoke
project it enumerated 83 objects, one VS track, and one musical part.
This native validation also exposed XML-compatibility requirements that XSD validation alone missed:
- VOCALOID phoneme elements contain raw symbols such as
aork a. - Every generated note needs the standard note-style attributes (including
vibLenandvibType), and string-bearing fields should use CDATA like editor-produced VSQX files.
Important correction: the earlier probe iteration incorrectly blamed 4 a
for a load failure. 4 is an official Japanese flap/tap phoneme (for example
4 a for ら). The local manual's Japanese phonetic table and bundled
KanaNote.lua both confirm it. A fresh generated VSQ3 containing 4 a, note
style, vibrato sequences, and DYN points loaded successfully through the native
probe (77 objects, one track, one musical part). The numeric-prefix rejection
was removed and replaced by a regression test.
The probe now has an optional render mode:
vsq_probe.exe <Vocaloid3FE-dir> <project.vsqx> [output.wav VoiceDB-dir]
For the MCP-generated, Vsq3-valid smoke project it successfully completed all
pre-synthesis stages: loaded the VSQX, selected the first musical part, created
the sequence-time map, encoded the part as Daisy MIDI, loaded DSCL3.dll, and
loaded DSE3.dll. OpenSynthesizer resolved the expected DSE entry points.
The first actual render stopped at database initialization:
DSESetDBMPath result=-100
DoSynthesis failed
render_status=71
The attempted arguments were the Vocaloid runtime directory and
D:\Vocaloid\VoiceDB. No output file is written for this failure, and the
probe also refuses to report success for silent PCM.
Offline inspection of the pinned DSE3.dll shows that DSESetDBMPath calls
two internal initialization routines and references the relative database
names DATABASE\\VOICE3 and DATABASE\\VOICE2. The exact meaning of its two
path arguments and the source of error -100 still need live decompilation in
IDA. The next target is DSE3.dll; the investigation must use legitimate
installed/registered voice databases and must not patch or bypass activation.
Live decompilation of the pinned DSE3 build corrected the interpretation of
DSESetDBMPath:
- Its first argument is a registry-key format string, not a filesystem path.
The editor passes
SOFTWARE\\VCLDASGN3\\%s. - Internal RVA
0x5520formats that string withCOMMONand checks the installed system/activation state. - Internal RVA
0x8180enumeratesHKLM\\SOFTWARE\\VCLDASGN3\\DATABASE\\VOICE2andVOICE3, checking values includingINSTALLED,TIME,ORGID, andKEYS. - The 32-bit registry contains legitimate installed IA and IA_ROCKS entries.
Direct diagnostics currently return
VOICE2=0andVOICE3=-100; the latter remains the blocker for direct DSCL/DSE rendering. DSESetVVoiceTablerequires version token0x13000202and copies a table of 64-byte voice-setting entries. The exact entry layout is still pending.
No activation checks are bypassed or patched.
The generated native-vsqx-smoke-style.vsqx was opened by the original
VOCALOID3 Editor. The UI displayed the generated notes and IA_ROCKS part,
playback advanced normally, and manual Export Wave succeeded. Win32 menu
enumeration identified File > Export > Wave... as command ID 33299; helper
scripts for menu/UI discovery and bounded WM_COMMAND dispatch live under
scripts/. Future automation must launch minimized, use a single bounded
export operation, validate the resulting RIFF/WAVE, and close the editor so it
does not interrupt the user.
Separately, Codex CLI was configured with only the local Vocaloid MCP and told
not to use shell/XML. It created
artifacts/evals/codex-agent-from-zero-tuned.vsqx from an abstract brief:
- VSQ3, IA_ROCKS, 132 BPM, 4/4, eight measures
- 41 original notes and locked Japanese phonemes
- 34 DYN, 6 PBS, and 22 PIT points
- expressive note styles plus three selected long-note vibratos with editable depth/rate envelopes
- XSD/structural validation: valid, no diagnostics
- Yamaha
Vsq3.dllnative load: 351 objects, one track, one musical part
This proves the current project writer does not require an input VSQX. The real corpus project was used only as a format/behavior oracle and validation fixture.
The first export-helper prototype established the two-stage UI contract:
- VOCALOID's
Export Wave Fileoptions dialog (master/current/selected/ separate tracks, sample rate, channel mode). - Windows'
Export to Wave Filecommon Save dialog.
A non-interactive Windows desktop prevented visible UI, but the common dialog
did not create its normal shell filename controls without an Explorer shell.
The replacement helper starts the editor minimized on the normal desktop and
uses an out-of-context EVENT_OBJECT_SHOW guard to move dialogs offscreen.
One diagnostic run enumerated the Save dialog before its asynchronously created filename control existed, then attempted to exit the disabled MFC owner while the modal dialog was still active. VOCALOID3.exe raised an access violation during teardown. This was an automation cleanup bug, not a VSQX or synthesis failure. The helper now:
- waits for both filename and Save controls until the bounded deadline;
- cancels every known modal dialog before touching the owner;
- waits for the owner to become enabled before sending Exit;
- terminates the helper-owned process directly if the modal cannot be unwound, instead of sending Exit/Close into an invalid UI state;
- hooks only
EVENT_OBJECT_SHOW, not partially constructed windows.
No VOCALOID or exporter process remained after the failed run. After explicit user confirmation, the hardened helper completed both integration exports with no forced termination or residual process:
- Japanese
4 asmoke: 13.657 s helper runtime; 44.1 kHz, 16-bit stereo; 10.008 s audio; peak -18.47 dBFS; RMS -38.46 dBFS; non-silent. - Codex-created
雨のあとで: 14.641 s helper runtime; 44.1 kHz, 16-bit stereo; 16.370 s audio; peak -7.92 dBFS; RMS -23.01 dBFS; non-silent.
The helper also treats Editor's singer-substitution warning as a provenance
failure. It matches the exact dialog text, reports singer_unavailable, and
does not click through to render with an unknown default singer. VVD metadata
on disk is therefore advertised separately from Editor registration/licensing;
only a successful render proves current synthesis availability.
The workflow is now exposed as vocaloid_render_wav. It validates the VSQX,
renders to a temporary sibling path, parses RIFF/WAVE chunks and sample data,
rejects silent output, then atomically renames the validated WAV. Existing
outputs require an explicit overwrite and receive a timestamped backup.
The single-part writer has been retained for compatibility and a separate
vocaloid_create_song workflow now models long-form arrangements directly:
- zero-based measure/beat/tick positions after the VSQX pre-measure count-in;
- ordered tempo and time-signature maps;
- up to 16 vocal tracks, each with its own singer slot and mixer unit;
- multiple named, non-overlapping musical parts per track;
- absolute song positions for notes and control curves, converted to each part's relative ticks by the server;
- explicit lead/double/harmony/countermelody tracks for simultaneous voices;
- native V3
seTrack/karaokeTrackand V4monoTrack/stTrackWAV parts.
WAV parts are not accepted on metadata trust alone. The server parses the RIFF
header and sample data, enforces the VOCALOID3 manual's 16-bit PCM plus
44.1/48/96 kHz sample-rate and mono/stereo channel
constraints, converts the readable WSL path to a Windows path for the Editor,
and derives playTime from audio duration across the song's tempo map. Project
inspection reports the resulting audio-part metadata and stored file path.
Both V3 and V4 structured fixtures pass their Yamaha XSDs. A native V3 Editor integration test then combined two simultaneous IA vocal tracks (lead and a third/fourth harmony in a separate track) with a stereo 44.1 kHz/16-bit backing part. Master export completed without forced termination or residual process:
- project: 2 vocal tracks, 2 musical parts, 6 notes, 4 DYN points, 1 WAV part;
- helper runtime: 16.313 seconds;
- output: 6.014 seconds, 44.1 kHz, 16-bit stereo, non-silent;
- peak: -13.26 dBFS; RMS: -25.32 dBFS.
This closes the structural and native-render path for harmony plus real audio accompaniment. It does not yet generate instrumental stems or make perceptual mix decisions; those require higher-level composition, listening analysis, and mix/master tools on top of this deterministic VSQX layer.
FluidSynth 2.3.4 and the FluidR3 GM SoundFont provide the first replaceable
instrumental renderer backend. vocaloid_render_accompaniment accepts the same
measure/beat/tick timeline as the structured VSQX writer, up to 15 melodic GM
tracks plus channel-10 percussion, per-track volume/pan, tempo/meter changes,
and a requested song end. It writes a temporary format-1 SMF only as the
bounded synth process input, deletes it after rendering, verifies the resulting
16-bit stereo PCM, rejects silence, and atomically commits the WAV. The MCP
also exposes the full 128-program and standard percussion map. This default
SoundFont is intentionally described as draft quality; a compatible custom SF2
can replace it without changing the composition model.
An ephemeral local Codex CLI session was restricted by instruction to the Vocaloid MCP and given an abstract 16-measure Japanese pop-rock brief. It used the tools rather than shell/XML and recovered from two schema mistakes (signed pan and an out-of-range send level) without leaving partial outputs. The final artifacts were created from zero:
- form: 2-bar instrumental intro, 6-bar verse, 2-bar pre-chorus, 6-bar chorus;
- tempo: 128 BPM, rising to 132 BPM at the chorus;
- accompaniment: four GM tracks, 176 pitched notes, 127 drum hits (303 events);
- vocal: IA_ROCKS lead with 56 notes/17 controls and chorus harmony with 12 notes/6 controls, on two independent tracks;
- VSQ3: two musical parts, 68 notes, 23 controls, one stereo WAV part;
- validation: Yamaha XSD and structural diagnostics both clean;
- backing: 38.368 seconds, peak -4.45 dBFS, RMS -24.15 dBFS;
- original-Editor Master: 40.263 seconds, 44.1 kHz/16-bit stereo, non-silent, 26.344-second helper runtime, no forced termination or residual process.
The eval also exposed the next real quality gate. Independent FFmpeg EBU R128 analysis measured the Master at -9.0 LUFS integrated, 13.5 LU LRA, and +0.3 dBFS true peak; the basic PCM analyzer likewise reported a 0 dBFS sample peak. The workflow is therefore complete as a composition/render loop but this output is not claimed as mastered. The next tools must expose clipping/true-peak and loudness analysis, adjustable audio/mixer gain, stem replacement, and a bounded revision/mastering pass with explicit headroom targets.
The MCP now separates audio inspection from mutation. vocaloid_analyze_wav
combines exact PCM sample-domain analysis with FFmpeg EBU R128 metrics, while
vocaloid_master_wav performs two-pass loudnorm into a distinct output and
accepts the file only after a second independent quality measurement. The old
16-measure Master contained 9,844 full-scale sample values (about 0.277% of all
sample values), measured -9.0 LUFS and +0.3 dBTP. Its descriptively named
revision hoshikuzu-letter-master-v1.wav measures -13.8 LUFS, -1.0 dBTP and
zero full-scale samples. The result reports sourceClipped=true: normalization
can prevent further clipping but cannot reconstruct source transients, so the
proper artistic revision remains a lower-level re-render.
The phrase compiler is grounded in both the local VOCALOID3 manual and installed
VSQX corpus behavior. The editor exposes quantization through 1/64 plus triplets,
and a note may contain multiple phoneme symbols. Real projects use lyric - and
phoneme - for a note that continues the previous syllable, and also split
composite pronunciations across successive notes. The MCP therefore offers two
high-level allocation modes: sequential lyric consumption for rapid syllabic
runs and explicit lyric indices for melisma, with automatic native continuation
events. It also supports rests, gates, dotted values, tuplets, cell overrides,
note expression, and vibrato. The low-level VSQX representation is unchanged.
Accompaniment patterns and placements make long structures compact without flattening their musical intent. A test arrangement uses eight source events and two placements to expand 96 measures into 192 shamisen notes plus 384 drum hits. Placements can repeat, transpose, or scale velocity, so intro, verse, pre-chorus, chorus, bridge, and outro may use different grooves over one tempo/meter map. FluidR3 preset inspection verified bank/program access to Shakuhachi (0/0/77), Shamisen (0/0/106), Koto (0/0/107), Taisho Koto (0/8/107), Taiko Drum (0/0/116), Timpani, Woodblock, and Shanai. These are draft composition colors, not a claim of realistic Japanese-instrument production quality.
A fresh Codex CLI session was restricted to the Vocaloid MCP and asked to write
a named Japanese long-form song without reading or copying any source project.
It created 月影疾走 (tsukikage-shissou) with the following structure:
- 96 measures and 172.408 seconds of Editor-exported audio;
- intro, verse 1, pre-chorus, chorus 1, interlude, verse 2, bridge, final chorus, and outro;
- ten tempo events from 96 to 156 BPM and a 4/4 to 6/8 to 4/4 meter map;
- Shamisen, Koto, Shakuhachi, Taiko, pick bass, distortion guitar, synth strings, piano, and channel-10 drums;
- 81 patterns and 81 placements expanded into 3,128 pitched accompaniment notes plus 861 drum hits;
- IA_ROCKS lead (311 notes) and an independent harmony/counterline (85 notes), all locked phonemes, with 1/16 and 1/32 lyrics, triplets, pickups, rests, syncopation, four explicit melismas, selective vibrato, and 41 controls;
- clean Yamaha XSD and structural validation with no overlaps or out-of-range events.
The first render revealed a semantic MCP failure that aggregate loudness did not catch. The stereo backing was balanced within 0.17 dB, but the VSQX vocal units used pan 0 and 10 because the agent treated zero as center. VOCALOID pan actually uses 0=hard left, 64=center, and 127=hard right. The resulting mix differed by 17.196 dB RMS between channels. This was audible even though the WAV header said stereo and its aggregate loudness/clipping checks passed.
The MCP now exposes read-only mixer inspection, atomic mixer updates, per-channel
peak/RMS/clipping, signed L-minus-R RMS balance, and a review flag above 3 dB.
A second MCP-only agent inspected the evidence and chose lead pan 64 plus harmony
pan 96. The derived tsukikage-shissou-v2.vsqx remained XSD-valid. Its original
Editor mix measures L/R RMS -28.627/-28.044 dBFS (0.583 dB toward the right),
-21.4 LUFS, -6.0 dBTP, and zero clipped samples. The named v2 master measures
L/R RMS -19.596/-19.114 dBFS (0.482 dB toward the right), -14.2 LUFS, -1.0 dBTP,
and zero clipped samples. Its 12.6 LU loudness range does not meet the requested
9 LU target; the tool now reports that separately rather than equating LUFS and
true-peak success with full dynamic-range success.
This eval also exercised failure honesty: the first v2 render attempt saw the Editor exit during synthesis and produced no committed WAV or fake master. A single bounded retry succeeded with normal Editor cleanup. The generated VSQX revisions are retained as evaluation fixtures; WAV files remain ignored build artifacts with descriptive song/version names.