MOSS-TTS-Nano

Streaming speech synthesis and voice cloning with CoreML, 48 kHz stereo audio and 80 ms chunks.

Apache-2.0 · aufklarer/MOSS-TTS-Nano-100M-CoreML

CLI

speech speak "Hello world." --engine moss-nano -o hello.wav
speech speak "The weather is nice today." --engine moss-nano \
  --voice-sample reference.wav --moss-nano-seed 1 -o cloned.wav
speech speak "Hello world." --engine moss-nano --stream --play -o streamed.wav

Use --voice-sample for voice cloning; no reference transcript is needed. Mono references are duplicated to stereo, resampled to 48 kHz and padded to an 80 ms boundary. Encode a reference once and reuse its codes across requests.

--moss-nano-modelaufklarer/MOSS-TTS-Nano-100M-CoreMLModel repository or local directory
--moss-nano-compute-unitscpucpu or gpu
--moss-nano-max-frames300Maximum 80 ms frames; natural EOS required
--moss-nano-seed0Reproducible Swift sampling seed

Swift API

import AudioCommon
import MossTTSNano

let model = try await MossTTSNanoModel.fromPretrained()
let reference = try await model.encodeReference(url: referenceURL)
let result = try await model.synthesize(
    text: "The weather is nice today.", reference: reference,
    options: MossTTSNanoOptions(maxFrames: 300, seed: 1))
try WAVWriter.writeStereo(left: result.left, right: result.right,
    sampleRate: 48000, to: outputURL)

MossTTSNanoModel serializes requests and creates fresh CoreML state for each utterance. synthesize and synthesizeStream preserve stereo; SpeechGenerationModel returns a mono downmix. Pass language: nil. Streams end with an empty final marker.

Limits and measurements

macOS 15+ / iOS 18+; four compiled graphs total 367.6 MB. Prompt, reference and requested frames share a 1,024-row context. The runtime rejects overflow and raises an error if maxFrames is reached before natural end-of-speech. CPU is the default; gpu permits CPU+GPU execution. PCG64 sampling uses NumPy-compatible seeds; backend numerical differences can still change output.

Python/CoreML on an M5 Pro, 48 GB, macOS 26.6.2; separate fresh processes, five warm requests per case. Cloning uses a 2.72-second reference. First/warm include reference reading, encoder loading and encoding; cached reuses reference codes. Synthesis model loading is excluded. RSS includes the full Python worker, without PyTorch or ASR. These are not Swift or iPhone measurements and do not measure speaker similarity.

BackendPeak RSSFirst token: first / warm / cachedFirst audio: first / warm / cached
CPU779 MiB542 / 203 / 52 ms563 / 216 / 65 ms
CPU+GPU731 MiB649 / 225 / 24 ms741 / 245 / 48 ms

Swift · Release

Native Swift release CLI on the same M5 Pro: one request per fresh process, with the same reference, text and seed. Reference preparation is included; synthesis-model loading is excluded. RSS covers the whole CLI without ASR weights. Dashes mean unmeasured warm/cache cases. Both outputs passed independent ASR with the exact requested sentence.

BackendPeak RSSFirst token: first / warm / cachedFirst audio: first / warm / cached
CPU670.7 MiB537 / — / — ms560 / — / — ms
CPU+GPU602.5 MiB570 / — / — ms645 / — / — ms

MossTTSNano · OpenMOSS