Introduction

Norwegian makers just got a fresh Piper voice with a serious teacher pedigree: rasmusjs/nb_NO-vox-medium (created 2026-11-07T22:35:21Z). It is a Norwegian bokmål VITS distilled from the open OpenBMB VoxCPM2 teacher into a 63.5 MB ONNX student — small enough for a Raspberry Pi, Home Assistant, or plain piper-tts.

The lineage starts from the NbAiLab/nb-tts-norwegian-piper-trimmed / talesyntese base (epoch 3459), then fine-tunes on synthetic VoxCPM2 audio so you keep Piper’s edge footprint while borrowing much of the teacher’s prosody.

What Shipped

  • Vendor / product: nb_NO-vox-medium — Piper bokmål voice (rasmusjs)
  • Modality: open-weight single-speaker Norwegian bokmål TTS (Piper VITS, medium quality)
  • Open vs closed: weights CC0-1.0; base talesyntese data CC0; teacher VoxCPM2 Apache-2.0; training text not redistributed
  • Runnable today: pip install piper-tts (tested 1.8.0), then load the ONNX + JSON config; Home Assistant drop-in by copying into the Piper voice directory
  • Concrete fact: fine-tune from epoch 3459 → 3744 (+285) on 10,333 synthetic clips (~13.9 h); output 22.05 kHz mono

Distillation Pipeline

  1. Corpus: 12,097 modern sentences (Wikipedia, NDLA, Alpaca sets, Språkrådet Q&A, name/city/date drills) — archaic public-domain book lines were generated then skipped
  2. Teacher synth: VoxCPM2 read every line with a fixed synthetic speaker (“vox8”)
  3. Verify: NB-Whisper + espeak-ng phoneme compare; 10,336 passed (~85%), three pathological clips dropped → 10,333 for training
  4. Prep: trim, -23 LUFS normalize, -0.95 dBFS peak ceiling, resample to 22.05 kHz, align to the base phoneme map
  5. Select: rank by validation loss, then pick the final checkpoint by WER on a held-out set (not by val loss alone)

Pro Tip

Checkpoint choice was WER-first: among four exports, epoch 3744 won at 12.5% mean WER versus 14.5% / 13.2% / 13.7% on earlier candidates — trust the listening judge when distillation gaps are small.

How to Run It

pip install piper-tts

piper \
  --model nb_NO-vox-medium.onnx \
  --config nb_NO-vox-medium.onnx.json \
  --output_file out.wav \
  -- "Værmelding for Vestlandet: Regn og frisk bris fra sjøen hele dagen."

import wave
from piper import PiperVoice

voice = PiperVoice.load("nb_NO-vox-medium.onnx")
with wave.open("out.wav", "wb") as wf:
    voice.synthesize_wav("Hei! Dette er en norsk stemme laget lokalt.", wf)

For Home Assistant, copy the ONNX and JSON into the Piper voice directory and select the voice in the UI.

Quality Snapshot and Limits

On 100 held-out Norwegian Wikipedia sentences (NbAiLab/nb-whisper-large judge, normalized):

  • This model: mean WER 12.5%, median 9.1%, 31/100 perfect clips
  • VoxCPM2 teacher (2B, GPU, 48 kHz): mean 11.2%, median 7.4%, 40/100 perfect

Targeted 16-sentence drills (none of the date/name lines in training text): dates/years 10.1% WER, Norwegian names 6.0%. Remaining gap to the teacher is mostly espeak-ng nb frontend + rare foreign names. Limits: bokmål only (nynorsk untested), medium quality not studio, flatter prosody than the teacher, and unusual numeric formats should be expanded before synth.

Where It Fits

  • Edge Norwegian assistants, Home Assistant announce, and offline read-aloud where a 2B GPU teacher is overkill
  • Distinct from shipping VoxCPM2 itself: this is the distilled Piper student you can run on a Pi
  • Fully synthetic voice (not derived from an identifiable person); do not use for impersonation or disinformation
  • Training text keeps its own licences; only the CC0 weights are published

Conclusion

If you wanted VoxCPM2’s Norwegian feel without the GPU bill, nb_NO-vox-medium is the zero-day Piper drop to pull. CC0 weights, 63.5 MB ONNX, and a WER gap of roughly one point versus the teacher on the wiki set — that is a distillation win worth cloning for local bokmål.

—Anabel ♡