- Rust 99%
- Nix 1%
Savvas #
A small LPC singing-voice synthesizer. Uses a source-filter model, Rosenberg glottal pulse train/band-limited noise driving LPC. This implementation is a test to see how closely this style of LPC voice synthesis matches the Teenage Engineering Choir for later use in a project with the same algorithm running on an ESP32.
Vowels and melody #
cargo run --release -- sing --melody "A4:0.45:a C5:0.45:e E5:0.9:i" --out demo.wav
cargo run --release -- sing --voice take.wav --melody "C4:0.6:o E4:0.6:o G4:0.9:o" --out out.wav
Melody notes are NOTE:DUR[:VOWEL]; r:DUR is a rest, #/b for accidentals.
Consonants and text #
--phonemes takes explicit X-SAMPA phones; --text runs a crude English
letter-to-sound front end. Both split into syllables and take one melody
note per syllable; without --melody the syllables get a plain chant.
cargo run --release -- sing --text "hello world" --out hello.wav
cargo run --release -- phonemes --text "the quick brown fox"
cargo run --release -- sing --phonemes "h V l oU | w 3: l d" --melody "A3:0.5 A3:0.4 E3:0.9" --out out.wav
Pieces #
song renders a score file, which is made of tracks with explicitly defined musical parts.
A vocal track entry is TIME NOTE DUR PHONES (phones dash separated), and a piano track
entry is TIME NOTES DUR AMP where NOTES is a chord joined by +. A vocal track header can cast
a singer: preset=bass|baritone|tenor|alto|mezzo|soprano|child sets the whole vocal quality, and
individual settings (formant=, cluster=, tilt=, vibrato=, vibrato_rate=, glide=,
breath=) override it. The singer's formant cluster moves with the tract length, so a bass and a
soprano differ above 2 kHz as well as below; cluster= scales it further. Score-level lines
reverb <0..1> and humanize <ms> set the wet mix and the timing drift, so a piece renders the
same way without flags; the command line overrides them.
cargo run --release -- song --file songs/daisy.song --out daisy.wav
cargo run --release -- song --file songs/chorale.song --out chorale.wav
cargo run --release -- song --file songs/chorale_four.song --out chorale_four.wav
songs/daisy.song is the chorus of Daisy Bell (Harry Dacre, 1892) with a simple piano part.
songs/chorale.song is Bach's O Haupt voll Blut und Wunden (BWV 244/74) in four voices.
songs/chorale_four.song is Bach's Ach Gott, vom Himmel sieh darein (BWV 153), also in four voices.
install #
flake.nix packages the binary and exports an overlay, so it can be a system command rather than
something you build yourself.
nix profile install . # or: nix run . -- song --file songs/daisy.song --out x.wav
On NixOS, take it as an input and apply the overlay:
{
inputs.savvas.url = "path:/mnt/hdd0/Code/savvas";
outputs = { self, nixpkgs, savvas }: {
nixosConfigurations.host = nixpkgs.lib.nixosSystem {
modules = [{
nixpkgs.overlays = [ savvas.overlays.default ];
environment.systemPackages = [ pkgs.savvas ];
}];
};
};
}
The build runs the test suite in the sandbox.
The phone inventory is X-SAMPA and covers the IPA chart: 112 phones, including the German set (x, C, y, Y, 2, 9, 6, R, p_f, t_s), the pulmonic consonants, the cardinal vowels, and ejectives, implosives and clicks. savvas phonemes --all lists them.
A track may set pan=-1..1; a song with any pan set renders stereo.