📝 Originally published (in Japanese) at forge.workstyle.tech.
We are creating voice models for different roles: narrator, call center, sales, and MC. Each role should have a distinct speaking style.
Initially, we thought, "We only need to train the model once, and we can adjust speech rate and intonation during synthesis." The synthesis API had a parameter that seemed to control speech rate.
However, it didn’t work when we tested it.
Parameters Being Ignored
We measured the speech rate using the same model and text, changing only the speech rate parameter.
for kw in [{}, {"length": 1.15}, {"length": 1.35}, {"length": 0.85}]:
wav = synth(model_id=MID, text=T, style="Neutral", **kw)
sec, lvl, f0, rng = acoustics(wav)
print(f"{kw} 発話{sec:.1f}s 話速{mora(T)/sec:.1f}")
{} 発話3.9s 話速5.3
{'length': 1.15} 発話4.0s 話速5.2
{'length': 1.35} 発話4.1s 話速5.1
{'length': 0.85} 発話4.0s 話速5.2
Whether set to 1.35 (slower) or 0.85 (faster), the speech rate remained between 5.1 and 5.3. This variation falls within the range of natural fluctuations during synthesis, not due to the parameter's effect.
The API accepts the parameter, returns no errors, and generates audio normally. It receives the parameter but doesn’t use it. The server-side implementation wasn’t passing the parameter to the synthesizer.
"Can pass" and "takes effect" are different. Even if a parameter is documented, you need to test it to confirm its functionality.
What Gets "Baked In"
If parameters can’t modify these traits, they must be determined during training. Indeed, many elements are influenced by the training corpus.
Speech rate: If the corpus is spoken slowly, the model will speak slowly.
Intonation habits: If the corpus includes clips with elongated endings, the model will elongate endings even if the script doesn’t specify it. We’ve seen models turn "こんにちは" (hello) into "こんにちわぁ".
Emotional styles: If the corpus contains material like screaming or laughter, those styles will be created. If not, they won’t exist.
Sentence structure habits: If the corpus scripts are mostly polite ("〜です", "〜ます"), the model will lean toward a formal style. If casual ("〜だよ", "〜じゃん"), it will lean casual.
This means use cases must be finalized at creation time. We redesigned the entire system based on this premise.
Defining Speech Profiles
We defined "speech profiles" (conv_style) for each use case, switching script sets and quality gate strictness. There are 14 profiles.
_CONV_STYLE_PATHS = {
"news": _SAMPLES / "conversational_news_texts.txt",
"narration": _SAMPLES / "conversational_narration_texts.txt",
"support": _SAMPLES / "conversational_support_texts.txt",
"presentation": _SAMPLES / "conversational_presentation_texts.txt",
"sales": _SAMPLES / "conversational_sales_texts.txt",
"counseling": _SAMPLES / "conversational_counseling_texts.txt",
"guidance": _SAMPLES / "conversational_guidance_texts.txt", # IVR・館内
"compliance": _SAMPLES / "conversational_compliance_texts.txt", # 重要事項説明
"guide": _SAMPLES / "conversational_guide_texts.txt", # 観光・展示
"mc": _SAMPLES / "conversational_mc_texts.txt",
"secretary": _SAMPLES / "conversational_secretary_texts.txt",
}
# Add polite (reception), casual (VTuber/streaming), and mixed (general/default) for 14 total
The script content reflects the use case. For call centers, phrases like "Thank you for calling. This is the support center." For narrators, "Since our founding, we’ve been committed to quality."
Omitting Extreme Material for Business Use
Another decision was whether to include extreme acting material (screaming/laughter).
# Business styles: exclude extreme acting material (screaming/laughter)
BUSINESS_CONV_STYLES = {"polite", "news", "narration", "support",
"presentation", "sales", "counseling",
"guidance", "compliance", "guide", "secretary"}
# Note: mc (event MC/commentator) includes extreme material = not in business set
def build_corpus_plan(conv_style=None):
per_cat = int(os.getenv("EXTREME_PER_CAT", "8"))
if (conv_style or "").lower() in BUSINESS_CONV_STYLES:
per_cat = 0 # Exclude all extreme material
...
This affects the number of styles a model has.
Business = 12 styles
Neutral, Joy, Excitement, Pride, Relief, Surprise,
Fear, Sadness, Shame, Anger, Contempt, Disgust
Casual/Mixed/MC = 17 styles
Above 12 + Scream, Laugh, Cry, JoyBurst, Shock
This wasn’t about audio quality but accident prevention. The runtime has a "react enthusiastically when excited" feature triggered by "Scream" in styles. Only voices with the Scream style react fully.
If a call center voice suddenly laughed, "Ahahahaha!", it would be problematic. We designed the system to prevent accidents at the configuration stage, regardless of runtime logic, by not including the Scream style.
⚠️ Business-Like Profiles with Extreme Material
In the code above, mc is excluded from BUSINESS_CONV_STYLES. Event MCs need to hype the crowd, so screams and laughter are appropriate.
However, MC voices appear business-like. "Event MC" is a customer-facing role, so it could be mistakenly assigned to a support desk. Since it has 17 styles (including Scream), full reactions would be triggered.
We confirmed this through testing.
| Profile | Styles | Has Scream |
|---|---|---|
| Counseling / Sales / Support / Presentation / Narration / News | 12 | No |
| MC | 17 | Yes |
We documented this exception and added a constraint to voice assignment systems: "Do not assign MC voices to support desks." "Business-like appearance" and "extreme material presence" don’t align, so it can’t be inferred from the name.
Baking in Different Use Cases for the Same Voice
If profiles can’t be changed, we must bake in different use cases. However, this was lighter than expected.
A voice’s identity is determined by (caption, seed), independent of its profile ([[deterministic-voice-gacha-and-design-ledger|Voice Gacha Design]]). Thus, we can bake in a different profile for the same voice.
INSERT INTO voice_design_jobs (name, caption, seed, progress) VALUES
('Shiori (Narration)', 'Calm, intellectual adult female voice...', 1042,
'{"params":{"conv_style":"narration"}}'),
('Shiori (Call Center)', 'Calm, intellectual adult female voice...', 1042,
'{"params":{"conv_style":"support"}}');
The caption and seed are identical; only the profile differs. Each variant takes 1–2 hours to bake, so we can add them as needed.
One character has two variants: "Streaming (Casual, 17 styles)" and "Business (Polite, 12 styles)."
Accepting "can’t change" shifts the approach to "can add." We couldn’t reach this design while assuming runtime adjustments.
Ripple Effect: Impact on Voice Selection
Since profiles are baked into the corpus, voice selectors need to know the profile.
For a request like "Give me a call center voice," we return voices with conv_style = 'support'. Older models without recorded profiles aren’t considered.
When we audited the catalog, only 19 out of 76 entries had recorded profiles ([[four-registration-paths-one-exit|4 registration paths, 0 management screens]]). The rest were pre-profile models or reference audio registered via other paths, with conv_style as NULL.
We considered retroactively adding profiles but decided not to. conv_style records which script corpus was used for training, not how the model behaves. Labeling old models with narration would misrepresent their training data. This would fix a label-reality mismatch in the DB.
We explicitly mark them as "Profile Unknown" and exclude them from automated selection. The UI displays "Use Case Unrecorded." We treat this as a fact, not a deficiency.
Summary
- Parameters being "received" and "effective" are different. Test critical parameters like speech rate.
- Identify what gets baked into the corpus: speech rate, intonation habits, available styles, sentence structure.
- Prevent accidents through configuration, not runtime logic. Without the Scream style, full reactions won’t trigger.
- Exceptions can’t be inferred from names. MCs seem business-like but have extreme material. Document and add machine-readable constraints.
- Accepting "can’t change" shifts to "can add." We can bake in different profiles for the same voice.
- Don’t add labels that can’t be verified later. Mismatched records harm automation decisions.
Series: Mass-Producing Practical Voices from Diffusion TTS
This series documents designing voices from captions, creating training corpora, and mass-producing role-specific practical voices. This article is Part 2: Manufacturing.
← Previous: [[quality-gate-selection-bias-flat-takes|The stricter the quality gate, the more monotone voices survive]]
→ Next: [[tts-changes-recording-room-every-time|TTS changes "recording location" every generation]]
All 18 Articles
- [[diffusion-tts-too-slow-for-conversation|The TTS chosen for quality was too slow for conversation]]
- [[deterministic-voice-gacha-and-design-ledger|Voice Gacha Design]]
- [[screening-voices-by-metrics-not-ears|Letting a machine select "narrator-like voices" from 24 candidates]]
- [[quality-gate-selection-bias-flat-takes|The stricter the quality gate, the more monotone voices survive]] 5. [[speaking-style-is-baked-into-the-corpus|Speech rate can’t be changed after training]] ← You are here
- [[tts-changes-recording-room-every-time|TTS changes "recording location" every generation]]
- [[one-rough-clip-ruins-the-whole-style|One rough clip ruins the entire style]]
- [[where-did-the-elongated-ending-come-from|Where did the AI’s habit of elongating "こんにちわー" come from?]]
- [[the-character-that-broke-the-tts-input|"少々" becoming "しょも" — Permitted character lists were cutting Japanese]]
- [[hallucination-guard-that-never-fired|Hallucination guard code only ran when there was no hallucination]]
- [[three-chars-became-a-verbal-tic|Three characters permitted by the quality gate became the model’s verbal tic]]
- [[measuring-factory-defects-as-product-traits|We were rejecting candidates over fixable defects]]
- [[defects-invisible-to-transcription|Some defects can’t be found through transcription]]
- [[70-minutes-lost-to-a-network-blink|70 minutes of training material lost to a network blink]]
- [[ja-vs-JP-babbling-model|From "ja" to "JP": Creating a babbling model]]
- [[four-registration-paths-one-exit|4 registration paths, 0 management screens]]
- [[who-is-rolling-back-whom|Each deployment was overwriting the other’s work]]
- [[chasing-unmeasured-targets-with-thresholds|Chasing unmeasured targets with thresholds always fails]]
The insights are compiled in [[Mass-Producing Practical Voices from Diffusion TTS Manufacturing Pipeline]].
Top comments (0)