Vocal2Midi is a Windows-first desktop tool and inference pipeline for turning vocal audio into lyric-aligned MIDI, USTX, and supporting editing artifacts.
The current runtime is ONNX-first:
llama.cpp is used for the Qwen decoder and runs on Vulkan or CPU.app_fluent.py.At a high level, the hybrid pipeline looks like this:
audio
-> optional RMVPE pitch curve
-> slicing
-> ASR
-> lyric matching / .lab generation
-> HubertFA forced alignment
-> GAME note extraction
-> quantization
-> export
There is also a no-lyrics path:
audio
-> optional RMVPE pitch curve
-> slicing
-> GAME pitch-only extraction
-> export
| Component | Current backend | Location |
|---|---|---|
| Qwen3-ASR | ONNX Runtime + llama.cpp |
inference/qwen3asr_dml/ |
| Japanese mora / romaji ASR | ONNX Runtime | inference/romaji_asr/ |
| HubertFA | ONNX Runtime | inference/HubertFA/ |
| GAME | ONNX Runtime | inference/game/ |
| RMVPE | ONNX Runtime | inference/API/rmvpe_api.py |
| Device normalization | DirectML / CPU helpers | inference/device_utils.py |
Some public function names still contain _torch for compatibility, but the active backend is ONNX-based.
application/ application-layer orchestration and config objects
docs/ architecture notes and supporting docs
experiments/ local model directories
gui/ PyQt5 + qfluentwidgets desktop UI
inference/ ASR, alignment, pitch extraction, slicing, quantization, export
scripts/ batch CLI and portable build helpers
tests/ automated tests
Use your preferred Python environment, then install:
pip install -r requirements.txt
The main runtime dependencies are:
onnxruntime-directmlPyQt5PyQt-Fluent-WidgetslibrosasoundfilemidopyopenjtalkAn environment.yml file is also included as a reference environment snapshot.
By default, the GUI expects models in these locations:
| Component | Default path |
|---|---|
| GAME | experiments/GAME-1.0.3-medium-onnx |
| HubertFA | experiments/1218_hfa_model_new_dict |
| Qwen3-ASR | experiments/Qwen3-ASR-1.7B-dml |
| Japanese mora ASR | experiments/romajiASR |
| RMVPE | experiments/RMVPE/rmvpe.onnx |
You can change these paths in the GUI settings panel.
For a normal developer environment:
python app_fluent.py
The GUI is the main way to use Vocal2Midi interactively. It lets you:
The application-layer job entrypoint is run_auto_lyric_job() in application/pipeline.py, which dispatches into the hybrid inference pipeline in inference/pipeline/auto_lyric_hybrid.py.
.lab content for HubertFA.In the main hybrid lyric pipeline:
romaji and kana lyric modes use the dedicated mora ASR pathromaji, the pipeline uses mora ASR output directlykana, the pipeline converts matched mora output to kana for displaypyopenjtalk, converted to kana mora tokens, then converted again to romaji mora tokens for matchingThis keeps Japanese lyric matching consistent with the mora-based ASR path instead of routing through the old phoneme-ASR forced-alignment branch.
Visible device options in the current UI are:
dmlcpuNotes:
dml is the default ONNX devicecuda values are still accepted by some public interfaces, but they are normalized to dmlllama.cpp remains CPU-based in the current designThe user-facing slice duration settings currently support:
0 to 60 seconds0 to 60 secondsCurrent defaults:
8.0 seconds22.0 secondsValidation rules:
slice_max_sec must be greater than 0slice_min_sec must be less than or equal to slice_max_secFor folder-based batch ASR processing:
python scripts/slice_asr_cli.py <input_dir> <output_dir> \
--asr-model experiments/Qwen3-ASR-1.7B-dml \
--device dml \
--language zh
This CLI is focused on:
.lab outputsSupported input extensions currently include:
.wav.m4a.mp3Useful options:
--no-slice bypass slicing and send the whole file to ASR
--asr-batch-size ASR batch size
--file-batch-size number of audio files per batch
--rmvpe-model enable RMVPE-assisted smart slicing
--rmvpe-batch-size RMVPE batch size
--keep-model keep the ASR runtime alive across the batch
--keep-rmvpe keep the RMVPE runtime alive across the batch
--save-json save slice timing and ASR outputs as JSON
--no-recursive scan only the top level
--no-skip-existing force reprocessing of existing outputs
Japanese whole-file example:
python scripts/slice_asr_cli.py input output \
--asr-model experiments/Qwen3-ASR-1.7B-dml \
--device dml \
--language ja \
--no-slice
The repository also includes Windows helper scripts:
These are useful for a smaller distribution model where the user downloads or initializes the runtime on first setup rather than receiving a fully bundled python/ folder.
Depending on the selected workflow, Vocal2Midi can export:
.mid.ustx.txt.csvTextGrid.wav files.labexperiments/ or another user-provided path.The overall Vocal2Midi repository is distributed under the Apache License 2.0. See LICENSE.
Third-party components, vendored code, model assets, dictionaries, and other embedded materials may also carry their own original licenses, notices, or attribution requirements. Those original notices remain applicable to the corresponding materials. See ACKNOWLEDGEMENTS.md and any embedded license files for details.
The repo includes a focused automated test suite under tests/.
Examples:
python -m pytest tests/test_auto_lyric_hybrid_pipeline.py
python -m pytest tests/test_asr_api.py tests/test_game_api.py tests/test_rmvpe_api.py
python -m pytest tests/test_device_selection.py tests/test_hubertfa_decoder.py
For architecture details, see docs/architecture.md.
app_fluent.py$ claude mcp add Vocal2Midi \
-- python -m otcore.mcp_server <graph>