SCNet Tran โ ONNX core for in-browser 4-stem separation
ONNX export of the core network of SCNet Tran
(SCNet with the separation network's bi-LSTM replaced by transformer layers), prepared for real-time-ish
music source separation inside a web browser via onnxruntime-web.
Stems: drums, bass, other, vocals.
This repository exists to host the weight file for a browser extension. It claims no new rights over the weights โ see Provenance and license.
Why "core"?
Two things had to change before this model could run under ONNX Runtime Web:
STFT / iSTFT are not in the graph.
torch.stft/torch.istfthave no stable ONNX equivalent โ ONNXDFTcannot setinverse=Trueandonesided=Trueat the same time. So the exported graph takes a spectrogram and returns a spectrogram; the consumer performs STFT/iSTFT itself.The internal FFT was replaced by matrix multiplication.
FeatureConversion, in the middle of the separation network, callstorch.fft.rfft/irfft. That is part of the model, not I/O, so it cannot be moved out. It was replaced with multiplication by precomputed DFT basis matrices:rfft(norm="ortho"): real = x @ C, C[t,k] = cos(2ฯkt/N)/โN imag = x @ S, S[t,k] = -sin(2ฯkt/N)/โN irfft(norm="ortho"): x = real @ Ci + imag @ Si Ci[k,t] = w_kยทcos(2ฯkt/N)/โN Si[k,t] = -w_kยทsin(2ฯkt/N)/โN, w_0 = w_{N/2} = 1, otherwise 2Substitution error against the original PyTorch model: max abs 1.04e-06.
Files
| File | Size | Notes |
|---|---|---|
scnet-tran-core-2.75s-v1.onnx |
47,200,340 B | opset 17, fp32, fixed 2.75 s chunk |
SHA-256: e2c6e2807e1deb937150c2c2d21db57b597388a67460706242e6f23a2d8f9c56
Interface
input spec (1, 4, 2049, 120) float32 โ view_as_real(stft) permuted/reshaped
output out (8, 2049, 120, 2) float32 โ pre-view_as_complex; 4 stems ร 2 channels
Stem order along the output's first axis: ['drums', 'bass', 'other', 'vocals'], each followed by its two
channels.
STFT convention (must match exactly)
Taken from the original scnet_tran.yaml plus torch.stft defaults. Getting any of these wrong still
produces audio โ it just produces wrong audio, so verify against reference tensors rather than by ear.
n_fft |
4096 (F = 2049) |
hop_length |
1024 |
win_length |
4096 |
| window | none (rectangular) โ the config has no window key, so torch.stft defaults to None, i.e. all ones. Not Hann. |
center |
true, with reflect padding of n_fft/2 = 2048 |
normalized |
true โ multiply by 1/โn_fft |
iSTFT is the exact inverse in torch.istft's order: undo normalization (รโn_fft) โ irfft per frame โ
overlap-add โ divide by the accumulated window-square envelope (with a rectangular window this is 4 in
the interior and 2โ3 at the edges โ dividing by a constant 4 corrupts the boundaries) โ strip the 2048-sample
center padding.
Chunking
chunk = 121275 samples (2.75 s @ 44100 Hz)
overlap = 2 โ step = 60637
fade = 12127 (chunk // 10, linear in/out for overlap-add)
Per chunk, pad to a multiple of hop_length such that the frame count is odd (121275 โ 121856, T = 120),
run the model, then drop the 581 padded samples. Reflect-pad the whole input by chunk - step at both ends
and crop afterwards. First chunk skips the fade-in; last chunk skips the fade-out.
Why 2.75 s and not the original 11 s: the 11 s chunk runs out of memory under onnxruntime-web's WASM
backend, and even on WebGPU the small chunk was faster in our measurements.
Measured performance
Chrome, Apple Silicon, onnxruntime-web, 2.75 s chunk:
| Backend | Per chunk | Realtime factor |
|---|---|---|
| WebGPU | 230 ms | 11.94ร |
| WASM, 8 threads | 1084 ms | 2.54ร |
A 5-minute song at 2ร overlap (221 chunks) takes roughly 50 s on WebGPU.
Agreement with the original PyTorch model: correlation 1.000000, max abs difference 6.43e-04.
Note that ONNX Runtime Web's WebGPU backend has no LSTM kernel, which is why the transformer variant (SCNet Tran) is used here rather than plain SCNet โ the LSTM variant silently falls back to CPU.
Conversion notes
- Exported with
torch.onnx.export,opset_version=17,dynamo=False. FeatureConversionmodules are swapped for matmul equivalents after observing the actual sequence length each one receives via forward pre-hooks โ the layers see differentTbecause of differing downsampling, so guessing the lengths does not work.- fp16 conversion was attempted and abandoned: intermediate activations exceed fp16 range and the converted graph produces NaNs.
Provenance and license
This file is a format conversion. The rights below belong to their respective holders, and nothing here grants rights that the upstream sources do not already grant.
| Layer | Source | Terms |
|---|---|---|
| Architecture / reference code | starrytong/SCNet | MIT |
| Training code and this variant | ZFTurbo/Music-Source-Separation-Training | MIT |
| Trained weights | ZFTurbo release checkpoint scnet_tran.ckpt |
distributed from the MIT-licensed repository above |
| Training data | MUSDB18-HQ | "provided for educational purposes only and the material contained in them should not be used for any commercial purpose without the express permission of the copyright holders" |
| This ONNX conversion | โ | conversion procedure released under MIT; no claim over the weights |
Because of the MUSDB18-HQ terms, treat this model as non-commercial. The extension it was prepared for is distributed free of charge with no advertising and no revenue.
If you are the rights holder of any layer above and want the hosting or the wording changed, please open a discussion on this repository.