- Rust 81%
- Python 19%
sublimit #
a cross-platform, dependency-free utau resampler written in rust
sublimit uses time-domain psola on pitch marks placed on the source's glottal pulses. a yin f0 track finds them and cross-correlation snaps them, then they are re-laid at the target period. the periodic part isn't resampled (similar to tips/macres, more on that in provenance), so formants remain intact and the excitation stays phase-coherent (..most of the time)
basically it sounds really niceys okay. it doesnt have a lot of flags IM SORRY
provenance #
sublimit is not a clean-room design. it was developed by reverse-engineering the behaviour of tips by rendering the original and comparing measurements and sound. no tips code or binary is redistributed in this repo
build #
cargo build --release # -> target/release/sublimit
cargo test --release # unit + integration tests
cargo clippy --all-targets # lints
cargo fmt is not enforced. prefer --release for tests; the debug build is much slower on
multi-second samples.
version stamp #
sublimit --version (or -V) prints the crate version and the git revision it was built from, for
example sublimit 0.2.1 (a1b2c3d4e5). a -dirty suffix means the working tree had uncommitted
changes.
install into openutau #
copy sublimit (or sublimit.exe) and sublimit.yaml into openutau's resamplers folder, then
select it under preferences > rendering. usual locations:
- macOS:
~/Library/OpenUtau/Resamplers/ - Windows:
%APPDATA%\OpenUtau\Resamplers\ - Linux:
~/.local/share/OpenUtau/Resamplers/
use the install's own resamplers folder if it differs. sublimit.yaml must sit beside the binary and
share its name or its (very few) renderer flags wont show up
usage #
sublimit <in.wav> <out.wav> <note> <velocity> [flags] [offset] [length]
[consonant] [cutoff] [volume] [modulation] [tempo] [pitchbend]
every argument after <out.wav> is optional and positional. anything omitted or unparseable falls
back to its default
| Argument | Meaning | Default |
|---|---|---|
in.wav / out.wav |
input / output paths. input may be mono or multichannel, 8/16/24/32-bit pcm or 32-bit float, but output is 16-bit pcm mono at the input sample rate | required |
note |
target note, e.g. C4, F#3, Bb5, or a midi note number |
A4 |
velocity |
utau velocity; the fixed consonant scales by 2^(1 - velocity/100), so 100 is neutral and higher is faster |
100 |
flags |
combined flag string, see below | none |
offset |
source start, ms | 0 |
length |
output length, ms; 0 uses the source window length |
0 |
consonant |
fixed consonant length, ms | 0 |
cutoff |
oto "right blank", ms. if >= 0, source end = wav end - cutoff; if < 0, source end = offset + abs(cutoff) |
0 |
volume |
output volume, percent | 100 |
modulation |
vibrato depth, percent; used only when no pitch bend is given | 0 |
tempo |
bpm, used to step the pitch bend | 100 |
pitchbend |
utau base64 rle pitch data | none |
flags are concatenated with no separators, e.g. g-20P86t+15R:
| Flag | Name | Range | Default |
|---|---|---|---|
g |
formant shift. positive is deeper, negative is brighter | -100..100 | 0 |
P |
peak compressor strength | 0..100 | 86 |
R |
remove dc offset (subtracts the mean) | on/off | off |
t |
pitch offset, cents | any | 0 |
target/release/sublimit in.wav out.wav C4 100 "g-20P86" 0 1000 0 0 100 0 "!120" "AA"
behaviour #
- output length is capped at 600000 ms (ten minutes); anything longer is an error
- a 5 ms fade is applied at both ends
- writing the output path
nul(any case) exits successfully without writing, which is what utau asks for on a silent render - unsupported wav encodings (adpcm, mu-law, a-law) and malformed headers exit non-zero
debug output #
two environment variables dump internals to stderr:
SUBLIMIT_DEBUG_MARKS=1: the f0 track (one value per hop,-for unvoiced) and the mark spacings of the analysed sliceSUBLIMIT_DEBUG_SYNTH=1: one line per synthesis grain (time, source position, mark, period)
tests #
cargo test --release
this runs the unit tests plus the integration suite in tests/:
synthetic.rsneeds no voicebank and runs everywhere. it exercises the full command line, the analysis/synthesis chain and the wav I/O the binary usesvoicebank.rsandvcv.rsrun against a local voicebank and check duration, level, pitch tracking and formant independencecanary.rsis a high-pitch canary against a second local bank
the bank-dependent tests skip cleanly (and print a skip message) when the bank is not installed. point them at banks outside the repo, with:
SUBLIMIT_TEST_VBANK=/path/to/bank cargo test --release
SUBLIMIT_TEST_VBANK2=/path/to/second-bank cargo test --release
the test fixtures in tests/fixtures/ are synthetic and generated by
tools/make_fixtures.py
corpus sweep #
tests/sweep.rs is a bug-discovery sweep over a voicebank, ignored by default:
cargo test --release --test sweep -- --ignored --nocapture
it renders oto entries from the bank and reports the worst offenders for f0, per-cycle correlation, phantom band and hollowed H1. useful knobs:
| Variable | Effect |
|---|---|
SUBLIMIT_TEST_VBANK |
bank root |
SUBLIMIT_SWEEP_BANK2=1 |
sweep SUBLIMIT_TEST_VBANK2 instead |
SUBLIMIT_SWEEP_FOLDERS |
substring filter on folder names |
SUBLIMIT_SWEEP_ALIAS |
substring filter on aliases |
SUBLIMIT_SWEEP_LIMIT |
max entries rendered, evenly strided (default 80, 0 = all) |
SUBLIMIT_SWEEP_SHIFT |
semitones above/below the folder pitch |
SUBLIMIT_SWEEP_LEN |
output length, ms (default 700) |
SUBLIMIT_SWEEP_FLAGS |
resampler flags, e.g. g-20 |
SUBLIMIT_SWEEP_CSV |
also write every row to this csv path |
SUBLIMIT_SWEEP_STRICT=1 |
fail if any entry trips a threshold |
tools/onset_sweep.py and tools/onset_split.py are numpy-only instruments for consonant-onset
glitches; tools/make_refs.py and tools/worldline_ref.py build cached worldline references for the
sweep. each file's docstring has its own usage