{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Ming-3.0-tts-0.5b Cookbook\n", "\n", "One runnable example per capability. Every cell calls the same entry point,\n", "`MingTTS.synthesize`, and differs only in the `task` and its controls.\n", "\n", "Capabilities new in 3.0 are marked **new**." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Run from the repository root so the local modules resolve.\n", "%cd /path/to/Ming-3.0-tts" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from IPython.display import Audio, display\n", "\n", "from ming_tts import MingTTS\n", "\n", "MODEL_PATH = \"inclusionAI/Ming-3.0-tts-0.5b\" # or a local checkpoint directory\n", "model = MingTTS(MODEL_PATH, device=\"cuda:0\")\n", "\n", "# A reference recording and its transcript, used by the cloning examples.\n", "PROMPT_WAV = \"data/voice_presets/voice_audio/lingguang.wav\"\n", "PROMPT_TEXT = \"诶,你今天有空吗?我们能不能聊聊这件事啊?\"\n", "\n", "\n", "def speak(**kwargs):\n", " waveform = model.synthesize(**kwargs)\n", " display(Audio(waveform.float().numpy(), rate=model.sample_rate))\n", " return waveform" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Zero-shot voice cloning\n", "\n", "Give one reference recording and its transcript. The transcript matters: the\n", "model conditions on the pair, so a wrong transcript degrades similarity." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "speak(\n", " task=\"TTS\",\n", " text=\"雨后的山谷很安静,远处亮起了一盏温暖的灯。\",\n", " prompt_wav_path=PROMPT_WAV,\n", " prompt_text=PROMPT_TEXT,\n", " use_spk_emb=True,\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Paralinguistic control **new**\n", "\n", "Tags go inline, anywhere in the sentence, in Chinese or English. They are\n", "routed around text normalization, so they survive intact.\n", "\n", "Available tags: `[Breathing]` `[Cough]` `[Sigh]` `[Laughter]` `[Surprise-ah]`\n", "`[Surprise-oh]` `[Dissatisfaction-hnn]` `[Uhm]` `[Confirmation-en]`\n", "`[Question-ei]` `[Question-ah]` `[Question-en]` `[Question-oh]` `[Question-huh]`" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "speak(\n", " task=\"TTS\",\n", " text=\"[Laughter] 你居然真的把那封信藏在旧钟后面了。\",\n", " prompt_wav_path=PROMPT_WAV,\n", " prompt_text=PROMPT_TEXT,\n", " use_spk_emb=True,\n", ")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Tags compose, and work mid-sentence in English too.\n", "speak(\n", " task=\"TTS\",\n", " text=\"I checked the drawer twice [Sigh] and it was empty [Uhm] again.\",\n", " language_id=\"en\",\n", " prompt_wav_path=PROMPT_WAV,\n", " prompt_text=PROMPT_TEXT,\n", " use_spk_emb=True,\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Multilingual **new**\n", "\n", "German, Spanish, French, Korean and Japanese join Chinese and English.\n", "`language_id` is required here — it both adds the target-language line to the\n", "prompt and keeps the text away from the Chinese/English normalizer, which\n", "would otherwise strip Japanese kana.\n", "\n", "The voice carries across languages, so a Chinese reference can speak Japanese." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "for language, sentence in [\n", " (\"ja\", \"あなた、ご自分のことばかりですのね。\"),\n", " (\"ko\", \"오늘 저녁에는 비가 올 것 같아요.\"),\n", " (\"de\", \"Der Garten bleibt bis Sonnenuntergang geöffnet.\"),\n", " (\"fr\", \"Le vieux phare veille encore sur la baie.\"),\n", " (\"es\", \"El jardín permanece abierto hasta el atardecer.\"),\n", "]:\n", " print(language, sentence)\n", " speak(\n", " task=\"MULTILINGUAL\",\n", " text=sentence,\n", " language_id=language,\n", " prompt_wav_path=PROMPT_WAV,\n", " prompt_text=PROMPT_TEXT,\n", " use_spk_emb=True,\n", " )" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Free-form instruction **new**\n", "\n", "Describe the delivery in one sentence. Reference-free generation is recommended for both models; adding a reference is not recommended. For 0.5B, `use_zero_spk_emb=True` supplies a zeroed speaker\n", "embedding and lets the instruction define the voice." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "speak(\n", " task=\"FREEFORM\",\n", " text=\"The old radio crackled softly as the storm approached.\",\n", " language_id=\"en\",\n", " instruction=\"Speak in a warm, intimate storytelling voice, with a gentle \"\n", " \"pace and a hint of nostalgia.\",\n", " use_zero_spk_emb=True,\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Voice design\n", "\n", "The same idea expressed as a voice description rather than a delivery\n", "instruction. Text is not split into fragments here, because the style applies\n", "to the utterance as a whole." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "speak(\n", " task=\"VOICE_DESIGN\",\n", " text=\"冰川在漫长岁月中缓缓移动,留下深刻的痕迹。\",\n", " controls={\"style\": \"成熟沉稳的男性纪录片旁白,吐字清晰,节奏舒缓。\"},\n", " use_zero_spk_emb=True,\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Basic attribute control\n", "\n", "`speed` is `慢速 / 中速 / 快速`; `pitch` and `volume` are `低 / 中 / 高`.\n", "The three move independently, so changing one does not drag the others." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "for speed in [\"慢速\", \"中速\", \"快速\"]:\n", " print(\"speed:\", speed)\n", " speak(\n", " task=\"BASIC\",\n", " text=\"今晚的观测将在云层散开后开始。\",\n", " controls={\"speed\": speed, \"pitch\": \"中\", \"volume\": \"中\"},\n", " prompt_wav_path=PROMPT_WAV,\n", " prompt_text=PROMPT_TEXT,\n", " use_spk_emb=True,\n", " )" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Emotion\n", "\n", "`高兴 / 悲伤 / 愤怒 / 恐惧 / 厌恶 / 惊讶 / 中性`." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "for emotion in [\"高兴\", \"悲伤\", \"愤怒\"]:\n", " print(\"emotion:\", emotion)\n", " speak(\n", " task=\"EMOTION\",\n", " text=\"所有的测试都通过了。\",\n", " controls={\"emotion\": emotion},\n", " prompt_wav_path=\"data/wavs/emotion_prompt.wav\",\n", " use_spk_emb=True,\n", " )" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Dialect\n", "\n", "`cantonese` or `chuanyu dialect`. This task takes no `language_id`: a dialect\n", "is selected through the control, not the target language. Passing one anyway\n", "raises a warning and is ignored." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "speak(\n", " task=\"DIALECT\",\n", " text=\"今日天气几好,我哋一齐去海边行下啦。\",\n", " controls={\"dialect\": \"cantonese\"},\n", " prompt_wav_path=\"data/wavs/yue_prompt.wav\",\n", " use_spk_emb=True,\n", ")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "speak(\n", " task=\"DIALECT\",\n", " text=\"今天天气巴适得很,我们一起出去转哈嘛。\",\n", " controls={\"dialect\": \"chuanyu dialect\"},\n", " prompt_wav_path=PROMPT_WAV,\n", " prompt_text=PROMPT_TEXT,\n", " use_spk_emb=True,\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Built-in premium voices\n", "\n", "No reference recording: five English voices and 479 Chinese voices.\n", "Recommended: **US_James**, **US_Stella**, **灵小柔**, **灵楷**.\n", "See the [full voice list](instructions.md#built-in-premium-voices)." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "for voice in [\"US_James\", \"US_Stella\", \"US_Emma\", \"UK_George\", \"UK_Charlotte\"]:\n", " print(\"voice:\", voice)\n", " speak(\n", " task=\"IP\",\n", " text=\"The garden will remain open until sunset, \"\n", " \"provided the weather stays clear.\",\n", " language_id=\"en\",\n", " controls={\"ip\": voice},\n", " use_zero_spk_emb=True,\n", " )" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Text normalization\n", "\n", "Numbers, dates, units and formulas are expanded before synthesis. This needs\n", "`pynini`; it is loaded lazily, so construct the model with\n", "`text_normalization=False` to skip it entirely." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "speak(\n", " task=\"TTS\",\n", " text=\"订单号 20250317,共 3 件商品,合计 ¥1,280.50,预计 3-5 天送达。\",\n", " prompt_wav_path=PROMPT_WAV,\n", " prompt_text=PROMPT_TEXT,\n", " use_spk_emb=True,\n", ")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Compare against the un-normalized reading.\n", "plain = MingTTS(MODEL_PATH, device=\"cuda:0\", text_normalization=False)\n", "waveform = plain.synthesize(\n", " task=\"TTS\",\n", " text=\"订单号 20250317,共 3 件商品,合计 ¥1,280.50,预计 3-5 天送达。\",\n", " prompt_wav_path=PROMPT_WAV,\n", " prompt_text=PROMPT_TEXT,\n", " use_spk_emb=True,\n", ")\n", "display(Audio(waveform.float().numpy(), rate=plain.sample_rate))" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "name": "python", "version": "3.10" } }, "nbformat": 4, "nbformat_minor": 5 }