Sopro v2 turbo on LiteRT (CompiledModel)

Waveform and 100-band log-mel of a sentence synthesized by the converted model

Sample from the converted model (plain fp16 weights + int8 AR, streaming vocoder) cloning a CC0 volunteer voice from kyutai/tts-voices (voice-donations/0a67): assets/hero_sample.wav — “The morning light fell across the garden while a small bird sang beside the open window.” Source and license of the reference voice: assets/ATTRIBUTION.md.

What it is

These classic .tflite graphs convert Samuel Vitorino's Sopro v2 turbo, a reference-conditioned text-to-speech model for English, European Portuguese, French and German, to the LiteRT CompiledModel API. The package provides fp32 reference graphs, plain weight-only fp16 graphs and a native-int8 merged AR alternative. It produces 24 kHz audio and includes a streaming vocoder, while resampling, spectral DSP, token sampling and the acoustic solver loop stay on the host. The upstream model and source are Apache-2.0; the included LICENSE is retained verbatim. Conversion used sopro==2.2.0 and upstream model revision f747f9edfb7b0233a3b7105af3a75603a7213d26.

Files

The file sizes below are exact bytes. There are fourteen fp32 graph files, fourteen plain wfp16 graph files and one native-int8 merged AR file. The Android variants add eight fp32, seven wfp16 and one int8 graph file (rows marked "Android variant"), plus the app source under android/. Separate AR prefill/step files and merged alternatives are included so callers can choose one form without loading both. This table covers the executable artifacts, host assets and conversion sources.

File Bytes SHA256 Dtype Purpose
LICENSE 11357 c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4 metadata / source Verbatim upstream Apache-2.0 license
contract.json 98047 e4ea40c95fd2d3bbc937377e5f3734b89771b3c55fe4f778821a4d77a8442a6f metadata / source Static shapes, signatures and host limits
conversion/acoustic_graphs.py 3856 bda1b4426b23c2770d76e0af84b9f81f8411a1a97c94217c6287ba2c4ad3c86a metadata / source Portable conversion / host / verification code
conversion/acoustic_host.py 4050 c7248ea9567b01a08990770dcb978cc7ddf9ca012c8ccf79d3d194f63843c5b2 metadata / source Portable conversion / host / verification code
conversion/alias_probe.py 2056 41a9f31e4e8fcee8995823daa8118c2bd68462c1ca767e3d1d79804dc030ded8 metadata / source Portable conversion / host / verification code
conversion/ar_graphs.py 4345 ab23a34559b82af3ee4f65ec4263e0cedb951d074b3603f7ef490e506b767152 metadata / source Portable conversion / host / verification code
conversion/ar_host.py 4374 2af8283e5234070e509f48e833b2cda83d5f4f4145f799afc0d17d6f89a3a77c metadata / source Portable conversion / host / verification code
conversion/common.py 3803 0eb12811cf8873c1571ad7385fab1bf83987841ce3f6735293b94b3927e99009 metadata / source Portable conversion / host / verification code
conversion/convert.py 10903 c2328d3a3e497c739809c15de1ebb7dcba5e0b1785b6d003b470a84f512f54f0 metadata / source Portable conversion / host / verification code
conversion/env.sh 937 63eaadbce97e6e550ee8c0a22854f354462f6a63daceb8ee22cd9156c4c1950b metadata / source Portable conversion / host / verification code
conversion/graphs.py 2685 573e37bbd1cd2c4360b943fdcdbdaca02158453f394d43fa1bfbf0c2d025e4aa metadata / source Portable conversion / host / verification code
conversion/host_dsp.py 4193 725b72c350d1ce13996697075d29f1e36bb6d325bf751b4d55b5121f800e5dd7 metadata / source Portable conversion / host / verification code
conversion/host_postprocess.py 3333 5fe4424616862a47db9345e58ccc01d7bebe16b830798823d8f60e1fcb265b5d metadata / source Portable conversion / host / verification code
conversion/host_sampler.py 4653 8cb47d226d0dbdf4e2157b1f23f986d7b6051da80d88c50c153ad5a7bf1c44c3 metadata / source Portable conversion / host / verification code
conversion/host_stream_istft.py 4316 6f60c5df3175ffad796e5ab10805ef55efb04b378c8466dff2f927665548d7e3 metadata / source Portable conversion / host / verification code
conversion/inference.py 12525 b331379226d7c104cbd1c73cf7b477a4764043be57f4732b7f0543f7393b7a28 metadata / source Portable conversion / host / verification code
conversion/litert_utils.py 8335 285738f0315020700dfd6d226858f42b58481b138fa2912192a47ae921bf8733 metadata / source Portable conversion / host / verification code
conversion/oracle.py 10516 8dc41a8563611113717b6c7cd2b883eb19f4ea585b34e6dc95c7990e58e47b96 metadata / source Portable conversion / host / verification code
conversion/parity.py 7158 56fe4adbfccd79bf16a2061fd507a43c91bb9b60f441c232d752fc6cb42089c1 metadata / source Portable conversion / host / verification code
conversion/perceptual_proxies.py 2235 56a170f791e45bc88c7265b8177db945bfc4e0d2ef2820734f57c3ccef1755f5 metadata / source Portable conversion / host / verification code
conversion/quality.py 5004 7f9058dc16bf0e96be879573f43ad3cbb8f909a1ccbc34a2b488306f314ea370 metadata / source Portable conversion / host / verification code
conversion/requirements.txt 1364 d6c81211dbb482532f32c3e941df3c7306f0b8a04b8e0fa3d8558372a2ef5ffc metadata / source Portable conversion / host / verification code
conversion/semantic_graph.py 3012 c585e0f05ed1b1468b06387a9e85f1d07114a5e3e0a7c8e976d43e73d21d462c metadata / source Portable conversion / host / verification code
conversion/source.py 1801 1caad8a5d4c729521166c08e70fd1245bf89906f523dc074249ce64c6c71adc4 metadata / source Portable conversion / host / verification code
conversion/vocoder_stream_graphs.py 1815 8a266c2a6472f206816fb4d6af6bf2433f147c25bd136ccd7c6c0b89f889d46d metadata / source Portable conversion / host / verification code
fp32/sopro_acoustic_condition_fp32.tflite 101598868 f60849c565fc056a76badcc640d2f8c564b44c23ca09fad73ccd5b80fd146e6b fp32 weights / float32 or int32 I/O acoustic condition
fp32/sopro_acoustic_condition_t4096_fp32.tflite 101598868 414975cffdb3c9d9a3ac2596d4e6132087710a87ce6b750c0fe021d3e06d7e07 fp32 weights / float32 or int32 I/O acoustic condition t4096
fp32/sopro_acoustic_velocity_fp32.tflite 127775972 c9d7821502613595828fc7699d92e43a47c542d9f885dbdbd4592bbf67f57a5a fp32 weights / float32 or int32 I/O acoustic velocity
fp32/sopro_acoustic_velocity_t4096_fp32.tflite 128824548 7901c9f4af3537275e345a0fa6bd33be34cfac622ba8f7b827485edc30490749 fp32 weights / float32 or int32 I/O acoustic velocity t4096
fp32/sopro_ar_merged_fp32.tflite 223457648 4cf522669f55f0bc93087e473c6c03df116f0086c922903b8f5688db52cb35ae fp32 weights / float32 or int32 I/O ar merged
fp32/sopro_ar_prefill_fp32.tflite 210678772 a5fbff1f345cfa17795fd33ddf488773d3cfc117d059e4fbe4b8d15ea342a84a fp32 weights / float32 or int32 I/O ar prefill
fp32/sopro_ar_step_fp32.tflite 210563980 b508e7512a55cb0d2105e7fc6927cddee500affd9121eba4dc9db6c59e8ea36c fp32 weights / float32 or int32 I/O ar step
fp32/sopro_semantic_encoder_fp32.tflite 80479220 c1d67fc72b953a6805690910f59d5fe68f2e47a15013ec27b6f979c1869f1ef9 fp32 weights / float32 or int32 I/O semantic encoder
fp32/sopro_speaker_encoder_fp32.tflite 12613536 f7e5f8302821fa9917c50656f64e81007201fa9ebc0a973f29f65eb7890e6d57 fp32 weights / float32 or int32 I/O speaker encoder
fp32/sopro_style_prefix_fp32.tflite 3191224 78e5c8aed42c5ec23da2224fd2ed3bb3368b6a49b8b1b450118759829c075ec5 fp32 weights / float32 or int32 I/O style prefix
fp32/sopro_vocoder_fp32.tflite 54145312 52fd19478ba13a6ffaae324d67c33ad7c3bbfd5eb28fd20a51d2fd93fba6dfc7 fp32 weights / float32 or int32 I/O vocoder
fp32/sopro_vocoder_stream_flush_fp32.tflite 54177908 10271f9c9f2a83872b9fd88760faa59f68dffe13634596d39fef2de9532e3c02 fp32 weights / float32 or int32 I/O vocoder stream flush
fp32/sopro_vocoder_stream_start_fp32.tflite 54181584 3a64a0e437caac9ee9637d1d73115ccfe8cff5a24f1665b4ab181a4483737da1 fp32 weights / float32 or int32 I/O vocoder stream start
fp32/sopro_vocoder_stream_step_fp32.tflite 54178996 51701381131b45fe9afff4cbbff8ef881c2e0254b7333cbcb34d216cc1931282 fp32 weights / float32 or int32 I/O vocoder stream step
host_assets/ar_tables_fp16.bin 12870788 feda5bf963e8034c89edcd7d16721087072941eae5d41e591828faa88d93574d little-endian fp16 + int32 metadata Packed embedding tables; un-gated fp16 storage option
host_assets/config.json 4482 b8593ff96b2976215ff64e58e784f4d667f4f0f205ae8686b57e78c10f42d6d7 metadata / source Upstream configuration
host_assets/dsp_constants_fp32.bin 446224 d52b5b6dacba6ba21a6e0d44578575211f13d0711bbebeb5c06e0c6656ede574 little-endian fp32 + int32 metadata Packed host frontend / FFT constants
host_assets/host_assets.json 6665 68e37b921b8a91d578ef157092427a4bd691354e543f82c40dee91efae3ac16e metadata / source Little-endian tensor offsets and shapes
host_assets/sopro_ar_tables_fp32.npz 25742598 a8e4c7e415c6978ad06b12919311b301544910f11da696cbc2b18ef4ca2559a9 original array dtypes Original fp32 tables used by measured pipeline
host_assets/sopro_dsp_constants_fp32.npz 448952 d2c8aeafd550b84e9ea9d2fa59d9683f9c28c4f5ac7ca393dd707af3a1d9ed45 original array dtypes Original host DSP arrays
host_assets/tokenizer.model 370821 2d76e7a4e8dbd0a4d2137c13200ac9710ad3fd93fad20a61f71102ab7bae754d metadata / source Upstream SentencePiece tokenizer
int8/sopro_ar_merged_i8native.tflite 55217000 4c9a54699f2e1b0ca6e777970b440bf5666e8399ea1342dce7d2dea6c5ad86fb int8 weights / float32 or int32 I/O ar merged
wfp16/sopro_acoustic_condition_t4096_wfp16.tflite 50822224 23c8c7ce01a1488911b86ffce5133f55029a53b47a2a55c6f6bd8c11a6be947b fp16 weights / float32 or int32 I/O acoustic condition t4096
wfp16/sopro_acoustic_condition_wfp16.tflite 50822224 9fa5e75f006bb3c8f291f0bf2393e20bff22baea6a70b7443eb4ee1a61d92bdd fp16 weights / float32 or int32 I/O acoustic condition
wfp16/sopro_acoustic_velocity_t4096_wfp16.tflite 65672144 35db79991879a313d3fbffcf8b5e05394c8ad3122e564fe8937f39a45928e07e fp16 weights / float32 or int32 I/O acoustic velocity t4096
wfp16/sopro_acoustic_velocity_wfp16.tflite 64623568 1dfc3d21128e1cae50ccab4147a3126157bfaf5d753d4934063b35e13f76ae79 fp16 weights / float32 or int32 I/O acoustic velocity
wfp16/sopro_ar_merged_wfp16.tflite 112038416 c5401ec8a55c6c51c4fb07979d469320d8886ab7a1bbbc14a1ed410597b85137 fp16 weights / float32 or int32 I/O ar merged
wfp16/sopro_ar_prefill_wfp16.tflite 105544496 560814c267ab096b04c8982031a55057c5128207edb524794fcd175cce520114 fp16 weights / float32 or int32 I/O ar prefill
wfp16/sopro_ar_step_wfp16.tflite 105426896 934e951d2237ff2ff4621108724d712a8199c127c0ae93d87886784c87426fb1 fp16 weights / float32 or int32 I/O ar step
wfp16/sopro_semantic_encoder_wfp16.tflite 40895552 a68d0d8fc5ee867716e7d556f3e0561ae618c0810f186d1c5bb2d55a7742af9b fp16 weights / float32 or int32 I/O semantic encoder
wfp16/sopro_speaker_encoder_wfp16.tflite 6516144 39f46f2b66bc6c3f73b48f69faf7e480efc72d3a20a5a0cca8b4ee325ecabd0e fp16 weights / float32 or int32 I/O speaker encoder
wfp16/sopro_style_prefix_wfp16.tflite 1618800 ab56621a5c9bf880656ad517c4219b3db4d1da3f75f9a9ae929d7dbe9a1ae8c9 fp16 weights / float32 or int32 I/O style prefix
wfp16/sopro_vocoder_stream_flush_wfp16.tflite 27246640 adb45a266fc98e69d3731cd2ebf8db47ff692feaf1fda35b4cc53a18e4e9e4d3 fp16 weights / float32 or int32 I/O vocoder stream flush
wfp16/sopro_vocoder_stream_start_wfp16.tflite 27250512 5da076e8414f62db2bf99357495be848c87fe5921608b32ff38e39e59811d65f fp16 weights / float32 or int32 I/O vocoder stream start
wfp16/sopro_vocoder_stream_step_wfp16.tflite 27247488 8657d179710ffba7d0a5dec3227226c93c8b7868bc51cd34ae19d8eb9ecf634a fp16 weights / float32 or int32 I/O vocoder stream step
wfp16/sopro_vocoder_wfp16.tflite 27158496 ef807881576945d7f2415990ffbf0f6a22626a8b2ecf3cd826e4707d0bbf2ee4 fp16 weights / float32 or int32 I/O vocoder
fp32/sopro_acoustic_velocity_r6_fp32.tflite 127810560 bbd1ca24238167d7bbfb75b9c5c01113ee408d3135ef36962a57982263d84740 fp32 weights / float32 or int32 I/O acoustic velocity r6 fp32 (Android variant)
wfp16/sopro_acoustic_velocity_r6_wfp16.tflite 64655616 8b78862126487e49fffefbfa1aed5b28c4f9eb45384f224023706514352f6a7b fp16 weights / float32 or int32 I/O acoustic velocity r6 wfp16 (Android variant)
fp32/sopro_acoustic_velocity_t4096_r6_fp32.tflite 128867328 f47c3fbf103e2d3f2d250362f71b46ccbbe9baccb5a4ad5e773155942793088d fp32 weights / float32 or int32 I/O acoustic velocity t4096 r6 fp32 (Android variant)
wfp16/sopro_acoustic_velocity_t4096_r6_wfp16.tflite 65712384 51aa464fbca8240b906621ba334d8891835d12c51ccc95a76b4ec6a2775e54c6 fp16 weights / float32 or int32 I/O acoustic velocity t4096 r6 wfp16 (Android variant)
fp32/sopro_ar_merged_r6_fp32.tflite 223489200 1cf7373f5c7a05659c00738a5883aabea1cfb4e9c4c67e1b3c83f0eff1a13f39 fp32 weights / float32 or int32 I/O ar merged r6 fp32 (Android variant)
wfp16/sopro_ar_merged_r6_wfp16.tflite 112061680 7d66f29a5b64111ba5914abcfbdbcaff9c910f4ccbac1e8835e8da58ca4a7c75 fp16 weights / float32 or int32 I/O ar merged r6 wfp16 (Android variant)
int8/sopro_ar_merged_r6_int8.tflite 55249192 3d80c19472006c6e6602977629f6419c33903fd12a12924c65407b03cf941f2e int8 weights / float32 or int32 I/O ar merged r6 int8 (Android variant)
fp32/sopro_acoustic_condition_r6_fp32.tflite 101596592 60568d9fcd9f0dba6722a442a75c6e24dce4aeb1cdd3b6cd30784c38e52838fa fp32 weights / float32 or int32 I/O acoustic condition r6 fp32 (Android variant)
wfp16/sopro_acoustic_condition_r6_wfp16.tflite 50820160 ad5ef423f523dc903e5909b2310bd82311f4a972b82c4a0c145d255999eb7d0e fp16 weights / float32 or int32 I/O acoustic condition r6 wfp16 (Android variant)
fp32/sopro_acoustic_condition_t4096_r6_fp32.tflite 101596592 9dbb9ec867fe6eeb1855ab7687fb97ea351cf3e9b7aef753a6a1fbcabd6d262f fp32 weights / float32 or int32 I/O acoustic condition t4096 r6 fp32 (Android variant)
wfp16/sopro_acoustic_condition_t4096_r6_wfp16.tflite 50820160 23e6866a3f1c0f016999e21f288481e31574ee0da1ce3cf2336ffb0c87550add fp16 weights / float32 or int32 I/O acoustic condition t4096 r6 wfp16 (Android variant)
fp32/sopro_semantic_encoder_r6_fp32.tflite 81424792 16230b386eb1b10c3a749997a4aad492e1472c0e6a101aa98e3a2bf63243c957 fp32 weights / float32 or int32 I/O semantic encoder r6 fp32 (Android variant)
wfp16/sopro_semantic_encoder_r6_wfp16.tflite 41371840 0b1af43d356f225b3707746364b23187b18fcdb59318c0369a5596482d431484 fp16 weights / float32 or int32 I/O semantic encoder r6 wfp16 (Android variant)
fp32/sopro_style_prefix_r6_fp32.tflite 3193560 63ca99524d37134460af37f769a9bfb9896446841069cb013c9219a6897deb35 fp32 weights / float32 or int32 I/O style prefix r6 fp32 (Android variant)
wfp16/sopro_style_prefix_r6_wfp16.tflite 1621024 95791de76282b699122aa575f78d155878b1be333430223377d36404d4e45285 fp16 weights / float32 or int32 I/O style prefix r6 wfp16 (Android variant)
fp32/sopro_style_prefix_r9_fp32.tflite 3193116 5dbe43a551015ab2a03451a015918dfeaa550e9456f0d277a7646db92769eaf5 fp32 weights / float32 or int32 I/O style prefix r9 fp32 (Android variant)
host_assets/ar_tables_fp32.bin 25741312 9c6c89d2af9efffbf3c0a486acbd1f708c610b5cd0d67ab338abce0841f3b88a little-endian fp32 Raw fp32 embedding tables for the Android app (little-endian)
host_assets/ar_tables_fp32.json 801 9b42a5f8923891627a6c36b151ebc0c9153221939f01a5c46bf1a57282f8349f metadata / source Offsets and shapes of ar_tables_fp32.bin
contract_r6.json 93961 6fbc6bb3e96ba84d8a0e0ebb11668e15062cf9c76d56dde13f5ac12665bd4820 metadata / source Android variant signatures (round-6 rewrites)
contract_r9.json 2383 ac8d892dac48d546ebe36220fee693e176bef78437bb32f91b33ed486321abbe metadata / source Android variant signatures (fp32 style)
android/ — see android/README.md Kotlin source Android sample app (Compose, LiteRT CompiledModel), 37 source files

The wfp16/ files use plain FLOAT_CASTING: the final vocoder head is also stored as fp16, with float32 public I/O and CPU computation. The native-int8 AR uses per-channel int8 weights with dynamic activation quantization inside its CPU kernels. No speaker, acoustic or vocoder int8 candidate is included.

Raw host bins are little-endian; host_assets/host_assets.json gives each tensor's shape, dtype, byte offset and byte size. The measured pipeline used the original fp32 NPZ embedding tables. The requested fp16 raw embedding tables are a storage option, not an independently quality-gated host change. The original NPZs remain available for the validated path.

Graph contract

Batch size is one. Float inputs and outputs are float32 for every weight variant; token IDs, gather indices and last_index are int32. Bind actual signature names and buffer order from contract.json, not inferred tensor-index order. The ordinary signature is serving_default; merged AR exposes prefill and step with the same corresponding I/O contracts.

Graph Inputs, in exported argument order Outputs
Speaker encoder speaker mel [1,80,1001] id [1,192], style [1,128], control [1,8], condition [1,512]
Semantic encoder Whisper mel [1,80,1002] reference tokens [1,235] int32
Style prefix semantic embeddings [1,160,512] prefix [1,8,512]
AR prefill embeddings [1,256,512], additive bias [1,1,256,256], last index [1] logits [1,4377], K and V [1,96,256,64] each
AR step embedding [1,1,512], cos and sin [1,1,1,64] each, bias [1,1,1,1024], K and V [1,96,1024,64] each logits [1,4377], new K and V [1,96,1,64] each
Acoustic condition tokens [1,N], token mask [1,1,N], frame-to-token [T] mu [1,100,T]
Acoustic velocity x [1,100,T], time [1], mu [1,100,T], condition [1,512], condition mel [1,100,T], condition mask [1,1,T], key bias [1,1,1,T] velocity [1,100,T]
Offline vocoder denormalized mel [1,100,1024], frame mask [1,1,1024] iSTFT features [1,1024,1026]
Vocoder stream start mel [1,100,64] features [1,37,1026], embed state [1,100,6], convolution state [8,1,512,6], pending state [8,1,512,3]
Vocoder stream step mel [1,100,64] and the three states in that order features [1,64,1026] and updated states
Vocoder stream flush the three states features [1,27,1026]; discard neural state

Acoustic (T,N) is (2048,512) or (4096,1024). The _t4096 pair is the second bucket. The semantic encoder follows the installed package's 500-position crop before its fixed interpolation to 235 tokens. The fixed prefix uses eight style vectors, 120 prompt tokens and BOS, leaving at most 127 text tokens in the 256-position bucket; reject or segment a longer prefix before inference. Source activation functions are retained: semantic/vocoder erf-GELU and the acoustic DiT's native tanh-GELU.

The Android variants (_r6 / _r9 files) keep these computations and change only inputs the GPU delegate could not lower: AR prefill takes last_onehot [1,256] instead of last_index; acoustic condition takes token_onehot [1,N,4377] and frame_onehot [T,N] instead of semantic_tokens and frame_to_token; the semantic encoder returns digit_logits [1,235,27] and the host takes the argmax; the style prefix is shipped as fp32. Their signatures are listed in contract.json under android_contract_deltas, and their Mac CPU outputs equal the originals (maximum difference 0.0).

Host-side steps

  • Load mono audio, resample and apply the upstream reference normalization. Compute separate speaker, Whisper and acoustic mel frontends, including the speaker frame LayerNorm and Whisper's zero append, logarithmic floor and dynamic-range clamp. Normalize the acoustic reference mel with the supplied mean and standard deviation.
  • Tokenize with the language tag, gather text and semantic embedding tables, build the style/text/prompt/BOS prefix, and create RoPE tables and runtime additive masks. Keep packed K/V on the host; each step returns only its new slice. Attention includes the current key/value and masks invalid cache slots with −10,000.
  • Sample at temperature 0.8, top-k 25 and top-p 0.9, using the probability-below-kth rule, shifted top-p removal and 1e-8 normalization clamps. BOS is always masked; EOS is enabled from prediction ten. Use one uniform draw and inverse CDF. The evaluated free-running seed rule was NumPy default_rng(2000+i).
  • Construct frame-to-token indices from the actual token/frame lengths. Run the two Euler steps on the sway grid [0,0.29289323,1], using the same initial noise when measuring parity, and re-mask the reference prompt after each step with sigma_min 1e-6.
  • Denormalize the solved mel, retain 32 reference-context frames before generated frames, run the vocoder, split its head output into log-magnitude and phase, apply exp/clamp and complex phase, and perform host iSTFT with FFT 1024, hop 256 and periodic Hann. Overlap-add, window-envelope division and center cropping remain host operations.
  • Remove reference-context samples and apply output_gain, leading/trailing trim, single-segment join, soft_limit, then an 80 ms fade-out without fade-in. Streaming iSTFT state is ola, env, tail_start, processed_frames, and emitted_samples.

fp32 FFT contract: the acoustic mel mirror explicitly selects NumPy's fp32 FFT path with an exact power-of-two normalization and scale restoration. A mathematically equivalent implementation that dispatches to fp64 changes fp32 rounding. Preserve the implementation in conversion/host_dsp.py when reproducing these measurements; another FFT library needs its own parity check.

Reference contract

The static host input is exactly 10 seconds at 24 kHz, or 240,000 samples, resampled to 160,000 samples at 16 kHz for the encoders. Longer references are cropped; deterministic zero-padding of shorter inputs is the host's fixed-shape option. Short-reference padding was not evaluated: both measured references were at least ten seconds, and normalization preceded cropping. This differs from upstream crop_on_pause, which can append random room tone and is bypassed here. Upstream describes voice cloning from 5–20 seconds of reference audio; that guidance is not a measurement of this fixed bucket.

Buckets and limits

Component Static limit Meaning
Acoustic primary T=2048, N=512 Up to about 11.8 seconds of generated speech after the ten-second reference
Acoustic long T=4096, N=1024 Up to about 33.7 seconds by shape capacity; the sampler remains capped at 30 seconds
AR 256 prefix positions; cache 1024 At most 704 generated tokens; worst contract occupancy 960 positions
Offline vocoder 1024 mel frames About 10.9 seconds total mel coverage; reference context consumes part of that bucket
Streaming vocoder 64-frame calls No fixed upper utterance-length bucket; current tail-replay helper needs at least 128 real mel frames including context

Streaming start emits 37 feature frames, ordinary steps emit 64, and flush emits 27. For a partial final chunk, the host replays the last 128 real mel frames through a separate start/step, keeps only the remainder from that step, then flushes that replay state. This is the measured exact tail strategy; it does not cover arbitrarily short inputs. The acoustic solver itself is still offline.

The long fixtures generated 16.416–17.824 seconds of raw audio, using 385–418 tokens and at most 635 cache positions. All four used the long bucket and streaming vocoder. These are measured long-utterance tests, not thirty-second saturation tests; the thirty-second bound is established separately by the static capacity arithmetic.

Android

The android/ directory holds a Kotlin sample app (Compose, LiteRT CompiledModel) that runs the whole pipeline on the phone: the three mel front-ends with an fp32 FFT, the 24→16 kHz resampler, the SentencePiece tokenizer with the language tag, the packed-KV AR loop with the sampler, the two-step acoustic solver, the streaming vocoder with a host iSTFT, and the post-processing chain, then plays the audio through AudioTrack while it is being decoded. Every host step was gated on the JVM against the Python dumps before the device (worst tensor difference 2e-5 on the mels, 2.4e-7 on the iSTFT, sampler picks 2,920/2,920, tokenizer 1,214/1,214) and again on the phone, where the device chains reproduce the Mac results (fp32 teacher-forced raw waveform corr ≥ 0.9999993, 24/24).

Five graphs were re-exported without any numerical change so that the GPU delegate accepts them; the new files carry the _r6/_r9 suffix in their directories and supersede the originals on Android (Mac CPU parity against the originals: maximum difference 0.0). sopro_ar_merged: the prefill's last-row gather became a one-hot float input last_onehot [1,256]. sopro_acoustic_condition: the token-embedding lookup and the frame gather became one-hot float selections (token_onehot [1,N,4377], frame_onehot [T,N]). sopro_acoustic_velocity: the BROADCAST_TO lowering was removed. sopro_semantic_encoder: the graph returns the FSQ digit logits [1,235,27] and the host takes the argmax and forms the token (bases 1, 7, 35, 175, 875). sopro_style_prefix: shipped as fp32 (3.2 MB). Signatures and buffer order are in contract.json.

Measured placement on a Galaxy S26 (SM-S942Q, Adreno), LiteRT 2.2.0, release build, screen on, the phone held by the test alone, battery 39–43 °C. Warm latency is the synchronized run + read time of one call, median over the streaming suite.

Graph Storage Accelerator Gate Warm ms
speaker encoder wfp16 GPU, precision FP32 id max diff 2e-7; default precision returns non-finite output 16.3
semantic encoder wfp16 GPU, precision FP32 tokens 235/235 ×2; default precision flips 93–100 of 235 50.6
style prefix fp32 CPU the delegate rejects its batched matmul (non-constant tensor) 1.0
AR merged prefill / step int8 CPU GPU FP32 is exact (2,920/2,920) but a step costs 22 ms against 9.5 ms on CPU: the 50 MB packed KV crosses the bus every step 47.5 / 9.5
acoustic condition wfp16 GPU, default precision solved-mel corr ≥ 0.9997 32.5
acoustic velocity wfp16 GPU, default precision solved-mel corr ≥ 0.9996, chain log-mel corr ≥ 0.9975, HNR change ≤ 0.2 dB 177.2
vocoder stream start / step / flush wfp16 CPU GPU output is not speech in either precision (raw waveform corr ≈ 0, HNR change 5.7 dB); a rank-4 rewrite did not change it 7.5 / 7.4 / 4.1

Streaming on that placement, 36 utterances (the two private references and the CC0 demo voice × the 12 test sentences), release build:

Placement Time to first audio, median [min, max] Real-time factor, median [min, max] Ready after a cold launch First tap after Ready
shipped (GPU acoustic + encoders, CPU AR + vocoder) 2.07 s [1.13, 3.77] 0.41 [0.25, 0.79] 3.5 s (five GPU compilations) 1.8–2.9 s
all CPU 3.34 s [1.77, 4.06] 0.64 [0.36, 0.78] 0.6 s 3.1 s

Time to first audio is the tap-to-first-PCM-chunk time; the AR loop and the two velocity calls precede the first vocoder chunk. Quality on the shipped placement: Whisper-turbo WER 0.56 % / 3.70 % / 0 % and speaker cosine 0.939 / 0.916 / 0.777 for reference one / reference two / the demo voice (the demo voice's own PyTorch baseline is 0.781; its clip is a plain volunteer recording). Playback applies the output gain and soft limit per chunk; the saved WAV goes through the full offline post-processing.

Pixel 8a (Mali): not measured yet.

What is not included

Mac CPU numbers and Galaxy S26 Android numbers are included; the Pixel 8a (Mali) column is not measured yet. No streaming acoustic graphs, NPU verification or private reference voices are included. A macOS ai-edge-litert 2.2.0 GPU-only CompiledModel ends the process with SIGSEGV on a trivial Linear-plus-ReLU graph at creation; the 2.1.6 wheel runs the same file on Metal, so no Mac GPU numbers are given here. Private LibriSpeech reference readers and their generated audio are excluded from this package.

Gates and results

All execution measurements in this section used Apple M4 Max CPU, four threads, ai-edge-litert 2.2.0 CompiledModel, with float32 public tensors and the weight dtype named by the table. Source checks used PyTorch 2.11.0 / torchaudio 2.11.0 / Sopro 2.2.0 in float32. The machine was shared; timings are contended. The short suite contains two private reference voices and twelve sentences, giving 24 utterances in English, Portuguese, French and German. Four additional long utterances cover English and German. This is a small conversion-gate suite, not broad model-quality coverage.

For fp32 per-graph floats, the measured rule is finite values, correlation at least 0.9999, norm ratio within 1±0.001, and max error at most max(0.001,0.0001×reference_absmax) on valid positions. Integer output agreement is checked separately. Reduced-precision acoustic graphs are judged in solved-mel and output log-mel space; vocoders are judged in waveform space. Absolute phase-channel tensor errors do not determine audible parity.

fp32 reference set

Gate / measured domain Coverage Result
Speaker embeddings Both references id max error 2.98023e-7; other outputs at most 1.75089e-6; minimum correlation 0.999999999998
Semantic tokens / diagnostic digit logits Both references 235/235 tokens exact each; digit-logit max error 1.75476e-4
AR prefill and step 24 prefixes; 2,896 replay steps Step greedy agreement 100%; worst step-logit error 3.29018e-5
Acoustic mu / velocity / solved mel 24 utterances; two velocity calls each Maximum errors 6.86646e-5 / 5.50747e-5 / 1.46389e-4
Offline vocoder waveform 24 mels Minimum correlation 0.999999998368; maximum error 1.38946e-4
Full teacher-forced raw / final waveform 24 utterances, oracle tokens and noise Minimum correlations 0.999999470531 / 0.999999426261; max errors 0.00471610 / 0.00564674; final trim lengths exact
Streaming vocoder waveform against source offline 24 mels Minimum correlation 0.999999994171; maximum error 3.94199e-4
Long full chain, raw waveform Four utterances Minimum correlation 0.999997804111; maximum error 0.01242098

The source's own fp32 streaming/offline difference reached 2.15493e-4; its fp64 waveform check reached 4.96575e-13. This source summation-order difference was accepted without changing the graphs.

Plain wfp16 set

Gate / measured domain Coverage Result
Semantic token agreement with fp32 graph Both references 234/235 and 235/235 exact
AR greedy replay with fp32 graph 2,920 predictions including prefills Prefill-only swap: 2,919/2,920; sole disagreement gap 9.72748e-5; style, step and merged swaps: 2,920/2,920
Acoustic condition single swap, solved mel / output log-mel 24 utterances Minimum correlations 0.999999984985 / 0.999931426392; solved-mel max error 0.00727928
Acoustic velocity single swap, solved mel / output log-mel 24 utterances Minimum correlations 0.999999922480 / 0.999944061523; solved-mel max error 0.01574764
Plain offline vocoder single swap, waveform 24 utterances Minimum correlation 0.999938064242; max error 0.05010722
Plain stream start / step / flush single swaps, waveform 24 utterances each Minimum correlations 0.999999530346 / 0.999968632447 / 0.999999902165
All plain-wfp16 vocoder streaming, identical input mel 24 utterances Minimum waveform correlation 0.999967892482; max error 0.02738303
Full reduced teacher-forced chain, output log-mel 24 utterances Minimum correlation 0.999905133195; PASS by acoustic mel-domain rule
Full reduced teacher-forced perceptual proxies, same tokens/noise as fp32 chain 24 utterances Maximum HNR change 0.011127 dB; maximum high-band ratio change 0.021581 dB; limits 1.0 / 1.5 dB
Long reduced full chain, output log-mel Four utterances Minimum correlation 0.999970696744

The full reduced chain uses the wfp16 neural stages and native-int8 merged AR, with original fp32 host tables. Teacher forcing fixes the reference/generated token sequence and initial noise, so AR precision does not select a different downstream sequence in that test. The all-wfp16 AR alternative was also executed on the same teacher path. Its minimum raw-waveform correlation was 0.977468237158 on one Portuguese utterance; that value is informational under the acoustic mel-domain rule, not omitted or treated as waveform equivalence. HNR uses 25 ms autocorrelation frames with 10 ms hop and the fp32 output's HNR>0 dB voiced mask; energy ratio compares 4–12 kHz with 0–4 kHz.

Native-int8 merged AR

Gate / measured domain Coverage Result
Oracle-path greedy replay, fp32 AR comparison 2,920 predictions 2,834 agreements, 97.0548%; informational, no bit-exact claim
Single-swap teacher-forced downstream waveform 24 utterances, fixed tokens/noise Minimum correlation 0.999999470531; max error 0.00471610
Free-running with other graphs fp32 24 utterances Mean WER 1.306168%; speaker cosine mean 0.925210, minimum 0.868675
Exact packaged pipeline configuration 24 utterances Quality shown below; wfp16 graphs plus native-int8 merged AR and fp32 host tables

WER and speaker similarity

ASR: openai-whisper turbo / large-v3-turbo, package 20250625, float32 CPU, four threads; language forced per utterance, 16 kHz float32 array input, no ffmpeg. WER uses jiwer 4.0.0, Whisper EnglishTextNormalizer for English and BasicTextNormalizer for Portuguese/French/German. Values are the unweighted mean of per-utterance WER, in percent. Speaker cosine uses the source float32 speaker encoder on each output and its reference embedding. Hardware/runtime and contended conditions are those stated above; these are quality comparisons, not speed comparisons.

Output configuration Mean WER % Mean speaker cosine Minimum speaker cosine
PyTorch source oracle, seeds 1000+i 1.113591 0.925923 0.856220
All-fp32 LiteRT free-running, seeds 2000+i 2.058483 0.922257 0.869553
Packaged reduced configuration, seeds 2000+i 1.259872 0.925939 0.853079
Language Utterances Source-oracle mean WER % Reduced-pipeline mean WER % Reduced-pipeline mean speaker cosine
en 12 0.595238 1.011029 0.937780
pt 4 3.333333 1.666667 0.931149
fr 4 1.562500 1.388889 0.919935
de 4 0.000000 1.470588 0.891210

All 24 reduced-pipeline final waveforms were finite, with RMS above 0.001 and peak at most 1.0; measured durations were 4.4693–6.0053 seconds. The quality gate required mean speaker cosine no more than 0.03 below the oracle, minimum cosine at least 0.80, and mean WER no more than three percentage points above the oracle.

Contended CPU timing

Apple M4 Max CPU; ai-edge-litert 2.2.0 CompiledModel; four threads; contended. The graph table includes input-buffer writes, synchronous execution and output-buffer reads, with two warmups followed by eight timed calls on recorded real inputs. Each row names its weight format; public I/O is float32 or the declared int32 indices. Model load is excluded. Other workloads shared the machine, so these are observed latencies, not latency guarantees or phone estimates.

Graph / signature Weight format Median ms p90 ms
speaker_encoder / serving_default wfp16 10.541 11.901
semantic_encoder / serving_default wfp16 27.515 29.755
style_prefix / serving_default wfp16 0.820 0.908
ar_prefill / serving_default wfp16 36.131 38.471
ar_step / serving_default wfp16 11.807 13.194
acoustic_condition / serving_default wfp16 33.968 35.781
acoustic_velocity / serving_default wfp16 208.691 219.439
vocoder / serving_default wfp16 21.440 24.355
vocoder_stream_start / serving_default wfp16 5.100 5.410
vocoder_stream_step / serving_default wfp16 6.828 7.412
vocoder_stream_flush / serving_default wfp16 5.855 7.450
ar_merged / prefill wfp16 40.042 44.715
ar_merged / step wfp16 13.672 21.533
ar_merged / prefill i8native 37.693 43.195
ar_merged / step i8native 12.956 14.991

The reduced free-running pipeline, including reference processing, AR, acoustic solving, streaming vocoder and host DSP/post-processing, had RTF 0.442386 median and 0.600927 maximum over 24 utterances under the same contended four-thread CPU conditions. Model loading and audio-file serialization were excluded. RTF is pipeline wall seconds divided by final audio seconds. The timed configuration uses native-int8 merged AR, wfp16 remaining graphs and the original fp32 host tables.

Minimal usage

These examples call only the speaker graph. The Python block uses zero-valued host mel as a runnable tensor-I/O smoke input; replace it with the normalized speaker log-mel [1,80,1001] from your own reference frontend for real use. Run from the repository root after installing the pinned environment in REPRODUCE.md.

from pathlib import Path
import numpy as np
from ai_edge_litert.compiled_model import (
    CompiledModel, Options, CpuOptions, HardwareAccelerator,
)

path = Path("fp32/sopro_speaker_encoder_fp32.tflite")
model = CompiledModel.from_file(str(path), options=Options(
    hardware_accelerators=HardwareAccelerator.CPU,
    cpu_options=CpuOptions(num_threads=4),
))
inputs = model.create_input_buffers(0)
outputs = model.create_output_buffers(0)
speaker_mel = np.zeros((1, 80, 1001), dtype=np.float32)
try:
    inputs[0].write(speaker_mel.ravel())  # args_0
    model.run_by_index(0, inputs, outputs)
    id_emb = np.array(outputs[0].read(192, np.float32)).reshape(1, 192)
    print(id_emb.shape, float(np.linalg.norm(id_emb)))  # output_0
finally:
    for buffer in inputs + outputs:
        buffer.destroy()
    model.close()

The Kotlin example follows the LiteRT Kotlin CompiledModel/TensorBuffer API shape. It is a design example, not an Android execution result; modelPath points to the downloaded fp32 speaker file, and hostMel is channel-major float32 speaker log-mel.

import com.google.ai.edge.litert.Accelerator
import com.google.ai.edge.litert.CompiledModel

fun speakerEmbedding(modelPath: String, hostMel: FloatArray): FloatArray {
    require(hostMel.size == 80 * 1001)
    val model = CompiledModel.create(
        modelPath, CompiledModel.Options(Accelerator.CPU), null
    )
    val inputs = model.createInputBuffers()
    val outputs = model.createOutputBuffers()
    try {
        inputs[0].writeFloat(hostMel) // args_0: [1,80,1001]
        model.run(inputs, outputs)
        return outputs[0].readFloat().also { // output_0: id_emb
            require(it.size == 192)
        }
    } finally {
        inputs.forEach { it.close() }
        outputs.forEach { it.close() }
        model.close()
    }
}

Text examples and use

These plain-word sentences were used in the private test suite and contain no personal names or trademarks:

  • English: “The morning light fell across the garden while a small bird sang beside the open window.”
  • Portuguese: “A luz da manhã entrou pela janela e iluminou as flores que estavam sobre a mesa da cozinha.”
  • French: “Après la pluie, nous avons suivi le petit chemin qui descend vers le lac au milieu des arbres.”
  • German: “Nach dem Regen gingen wir den schmalen Weg entlang und hörten den Wind in den hohen Bäumen.”

Upstream disclaimer: “Please use the model for good: do not impersonate people.”

Conversion and verification code is included under conversion/. Supply your own authorized reference audio to reproduce speaker or full-pipeline checks. No private fixtures, reference audio, transcripts, oracle dumps or generated samples are included.

Downloads last month
374
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Model tree for litert-community/sopro-v2-turbo

Finetuned
(1)
this model