ShengChang: Import a Novel Chapter, Get a Mixed Radio-Drama Episode

2026-11-03来源 dev.toEnglish

Text-to-speech is basically solved for reading text out loud. Turning a story into something that sounds like a radio drama is not. Once you try it, you notice that the voice model is the easy part. The hard part is everything around it: working out who says each line, keeping every character's voice the same across scenes, directing the delivery, and mixing dialogue with ambience and music so the result doesn't sound like a screen reader.

ShengChang (声场) is my attempt at that whole job. It's a personal AI radio-drama workbench: import a novel chapter as a .txt file, get a directed, mixed episode. It runs on your own machine, it's MIT-licensed, and each character keeps one voice from the first scene to the last.

The reason is a bit personal. I'm a heavy audiobook fan, and at one point I wanted to do voice acting on the side. My own voice was never going to get me there, so the idea just sat. Over the last couple of years, voice models got good enough to clone a voice and take direction on emotion and pacing, and it clicked: if I can't perform the parts, maybe I can direct them.

The name comes from acoustics. 声场 (shēngchǎng) means "sound field": how sound fills a space. In a good radio drama you can close your eyes and still tell who's standing where, how far away they are, and whether you're in a forest or a palace hall. That's the job I want this tool to do. Its own tagline puts it as 「让故事,有声有场」, roughly "give a story its voices, and the space they live in."

What it does

The pipeline looks like this:

scene/line breakdown → per-character voice mapping → directed TTS → FFmpeg mix desk with sidechain ducking → loudness-normalized MP3

The stack is plain on purpose: React + Vite for the desktop-first UI, Node.js + Express on the server, the built-in node:sqlite module for storage, and FFmpeg/ffprobe for rendering. One thing to know up front: the UI and the sample content are Chinese only, and English support isn't on my plan yet.

It's for:

  • people who want to turn a story they like into a multi-voice audio episode;
  • developers who want to see a complete text-to-audio production pipeline, not just a TTS demo;
  • anyone who'd rather keep manuscripts, voices, and API keys on their own machine.

Features

One-click episode. One button runs five checkpointed stages: breakdown → preset voice mapping → batch generation → audio health check → episode export. Before it starts, you get an estimate (line count, characters, predicted cache hits). If a stage fails, you retry from that checkpoint. Re-runs only re-voice the lines you actually changed (text, emotion, speed, or locked voice). Everything else is reused.

Direction, not just text. Every line can carry subtext, emotion, intensity, speed, and distance. ShengChang folds those into one voice instruction for the engine. For Breeze, ShengChang writes the instruction itself (emotion level + speed + subtext, max 300 characters). If a line has no direction at all, it sends an empty instruction, so you get a plain voice clone.

Direction Lab. Pick a line and render it three ways side by side in the Inspector. Takes are cached by their direction parameters, so when you apply the one you like and regenerate, it's an instant cache hit.

Voices that stay put. With a local Breeze server, you can clone a voice from a 5–30 second reference clip (10–30 s recommended), or design one from a text description, audition it, and lock it.

A real mix desk. Each scene gets its own timeline. Dialogue is sequenced automatically when you don't set in-points, and background beds can loop. Music and ambience duck under dialogue through FFmpeg sidechain compression. The master chain normalizes to a target loudness (−16 LUFS by default) with a −1 dBTP ceiling, and exports 48 kHz stereo MP3 at 192 kbps.

Sound assets with provenance. The app ships with 20 CC0 assets (ambience, foley, music beds) and recommends matches from each sound event's description, all computed locally. You can also plug in an AI SFX service or import your own files. Each export comes with a source list that groups every asset as built-in, AI-generated, or imported.

Zero-key first run. A fresh install seeds a sample project: an adapted excerpt from chapter 27 of Journey to the West (public domain), condensed to 19 fully directed lines. It defaults to an offline demo engine, so the whole one-click pipeline runs end to end with no API key, no signup, and no cost. The idea is simple: the plumbing is real, and only the voice is a placeholder.

Quick start

Requirements: Node.js 22.5+, with FFmpeg and ffprobe on your PATH.

npm install npm run dev # workbench on http://127.0.0.1:4173 

This starts the web UI on 127.0.0.1:4173 and a local model gateway on 127.0.0.1:4174. Then:

  1. Open the sample project 「西游记 · 三打白骨精」.
  2. Go to 制作中心 (Production) → 一键成片 (one-click episode) and confirm the estimate.
  3. Come back to a mixed episode MP3 (with demo-engine tones).

For real voices, run the bundled Breeze TTS service. It currently needs an Apple Silicon Mac:

cd breeze uv venv --python 3.12 .venv uv pip install --python .venv/bin/python -r requirements.txt .venv/bin/hf download mlx-community/Breeze-TTS-2-mlx --local-dir models/Breeze-TTS-2-mlx ./start.sh curl -s http://127.0.0.1:4180/health 

Then open Settings, choose the local Breeze-TTS-2 engine, and set the address to http://127.0.0.1:4180. To import your own novel (a .txt file), first add any OpenAI-compatible text model (base URL, key, model name) and click 测试连接 ("Test connection"). The import button stays locked until that test passes.

You can also use Docker. The image includes Node 22 and FFmpeg, runs as a non-root user, and serves everything on one port, 4174:

docker build -t shengchang . docker run -p 4174:4174 \ -v shengchang-runtime:/app/.runtime \ -v shengchang-config:/home/node/.shengchang \ shengchang 

Design decisions worth calling out

Loopback only. The server binds to 127.0.0.1, and /api rejects any non-loopback Host or Origin header, which blocks cross-site form posts and DNS rebinding. Credentials live in ~/.shengchang/config.json with mode 0600. The browser never sees a key in plaintext; the UI shows only the last three characters. If you change an endpoint, the saved key is not sent to the new address.

No default provider. The text model can be any OpenAI Chat Completions–compatible endpoint: a hosted API like DeepSeek or OpenAI, or a local server like Ollama, LM Studio, vLLM, or llama.cpp. You do need one to import your own novel, though: the current UI blocks the import until the connection test passes. (The server still has a rule-based breakdown fallback, but the current import flow doesn't reach it.)

No silent engine switching. If Breeze is unreachable, the UI tells you and offers a retry or a link to Settings. It never falls back to another engine, and never to a paid one. There's a dedicated test for this. I'd rather stop the pipeline than spend someone's money without asking.

Production plumbing. Breakdown, generation, and export all run as persistent, resumable tasks in SQLite with stage checkpoints, so unfinished work goes back in the queue after a restart. Audio is cached by content: the same model, voice, text, and direction always reuse the same file. When the cache passes its size limit (50 GB by default), the least recently used entries are evicted, but files still referenced by a project are never deleted. When you edit a line, its old audio is marked stale instead of being quietly removed.

Tests that exercise the real chain. Besides unit tests, npm run test:e2e starts the actual server and runs generation and the one-click pipeline end to end. The mix tests render real timelines through FFmpeg and check duration and format with ffprobe. Both suites run in GitHub Actions.

Where it stands

This is an early project, and I'd rather say so up front:

  • The version is v0.1.0, the license is MIT, and CI is passing.
  • The local Breeze voice path, now the main engine, was merged in late October 2026.
  • breeze/requirements.txt was pinned from a working environment but hasn't been tested on a clean machine. The 8-bit Breeze weights should save memory, but their quality and stability are untested.
  • A real-voice demo episode isn't published yet. What runs today out of the box is the demo-engine version with placeholder tones.

What's next isn't a long feature list. The focus is output quality: more accurate breakdowns, more natural delivery, and episodes that sound more like real radio drama.

Trade-offs and limits

  • Real voices need Apple Silicon for now. The Breeze service runs on MLX and the Metal GPU. Intel Macs, Linux, and Windows are untested and probably won't work.
  • The hardware bar is real. The bf16 weights are about a 7.1 GB download. A full episode peaks around 12 GB of memory, so 24 GB+ is recommended (16 GB is untested). My test machine was an M4 Pro with 48 GB.
  • The Breeze weights aren't open source. They use the BreezeBlue Research and Non-Commercial License. ShengChang's code is MIT, but that doesn't cover the weights. The repo doesn't ship or redistribute them; you download them yourself.
  • For commercial use, there's an optional cloud engine (Doubao TTS from Volcengine) and a custom HTTP adapter for your own TTS service.
  • Breakdown needs a model with enough output room. Each request asks for 8,192 output tokens. If your model's limit is lower, the output gets truncated, so pick a bigger model or import one chapter at a time.
  • Importing your own novel needs a text model. Zero-key mode only covers the bundled sample project.
  • The Breeze address is part of the cache key. Change it, even just the port, and every line voiced by Breeze gets marked for regeneration.

Try it

If you want to hear a book you love as a radio drama, or you just want to see how a text-to-episode audio pipeline holds together, clone the repo and run the sample project. It takes no keys and a couple of commands.

👉 https://github.com/yanjiliang/shengchang-ai-studio

If it's useful, a star helps. Issues, Discussions, and PRs are all welcome.

原文:https://www.a8q9.cn/en/article/shengchang-import-a-novel-chapter-get-a-mixed-radio-drama-episode-5182f1.html

相关文章