TTS语音合成:让数字人开口说话

这篇文章帮你理解语音合成

数字人除了要”长得好看”,还得”会说话”。TTS(Text-to-Speech)就是让电脑把文字变成语音的技术。读完这篇,你会了解各种TTS方案的优缺点,知道怎么给自己的数字人配上好听的声音,以及怎么做声音克隆。

先搞清楚:什么是TTS?

TTS(Text-to-Speech)就是把文字转成语音的技术。比如你输入一段文字”今天天气很好”,TTS系统就会生成对应的语音音频文件。

TTS的应用场景

场景说明
数字人配音让数字人说话
语音导航GPS导航的语音播报
智能客服AI接听电话
有声书自动生成书籍朗读
无障碍辅助屏幕阅读器

TTS技术的发展历程

时代技术效果代表
早期波形拼接机械感强PSOLA
中期参数合成稍有改善HTS
深度学习神经网络自然流畅WaveNet
当前端到端非常自然GPT-SoVITS, Fish-Speech

1. 主流TTS方案对比

1.1 在线服务 vs 开源方案

类型优点缺点适合场景
在线服务效果好、使用简单需要付费、数据上传快速上线、生产环境
开源方案免费、可本地部署需要配置、效果参差学习研究、自建系统

1.2 在线TTS服务推荐

服务商中文效果价格推荐指数
Azure TTS⭐⭐⭐⭐中等⭐⭐⭐⭐⭐
火山引擎⭐⭐⭐⭐⭐便宜⭐⭐⭐⭐⭐
阿里云⭐⭐⭐⭐⭐便宜⭐⭐⭐⭐
腾讯云⭐⭐⭐⭐便宜⭐⭐⭐⭐

1.3 开源TTS方案推荐

项目中文支持声音克隆推荐指数
Fish-Speech⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
Coqui TTS⭐⭐⭐⭐⭐⭐⭐⭐
VITS⭐⭐⭐⭐⭐⭐⭐⭐
GPT-SoVITS⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐

2. Fish-Speech:最好的中文开源TTS

2.1 Fish-Speech是什么?

Fish-Speech是国产开源的TTS项目,专为中文优化,效果非常好,而且完全免费可商用。

主要特点

  • 对中文支持极佳
  • 支持声音克隆(只需10秒音频)
  • 支持多说话人
  • 完全开源免费
  • 训练推理效率高

2.2 安装Fish-Speech

# 克隆仓库
git clone https://github.com/fishaudio/fish-speech.git
cd fish-speech
 
# 方法1:使用Docker(推荐)
docker compose up -d
 
# 方法2:手动安装
# 创建虚拟环境
python -m venv fish_env
source fish_env/bin/activate  # Windows: fish_env\Scripts\activate
 
# 安装依赖
pip install -r requirements.txt
 
# 下载模型
# 模型会自动下载,首次使用时会提示

2.3 使用Fish-Speech进行语音合成

方式一:命令行使用

# 基础使用
python tools/tts_service.py --text "你好,这是一段测试语音"
 
# 指定声音
python tools/tts_service.py \
    --text "你好,欢迎使用Fish-Speech" \
    --speaker "default"
 
# 指定语速和音调
python tools/tts_service.py \
    --text "今天天气真不错" \
    --speed 1.2 \
    --pitch 1.0
 
# 输出到文件
python tools/tts_service.py \
    --text "你好,世界" \
    --output "output.wav"

方式二:网页界面

# 启动网页界面
python tools/webui.py
 
# 然后打开浏览器访问 http://127.0.0.1:7860

2.4 Fish-Speech Python API

"""
Fish-Speech Python API使用示例
"""
import requests
import base64
import json
 
class FishSpeechTTS:
    """Fish-Speech TTS封装"""
    
    def __init__(self, api_url="http://localhost:8080"):
        self.api_url = api_url
    
    def synthesize(self, text, speaker="default", speed=1.0):
        """
        文字转语音
        
        Args:
            text: 要转换的文字
            speaker: 说话人ID
            speed: 语速 (0.5-2.0)
        
        Returns:
            bytes: WAV格式音频数据
        """
        response = requests.post(
            f"{self.api_url}/v1/tts",
            json={
                "text": text,
                "speaker": speaker,
                "speed": speed
            }
        )
        
        if response.status_code == 200:
            return response.content
        else:
            raise Exception(f"TTS failed: {response.text}")
    
    def synthesize_to_file(self, text, output_path, **kwargs):
        """
        文字转语音并保存文件
        
        Args:
            text: 要转换的文字
            output_path: 输出文件路径
            **kwargs: 其他参数
        """
        audio_data = self.synthesize(text, **kwargs)
        
        with open(output_path, 'wb') as f:
            f.write(audio_data)
        
        print(f"音频已保存到: {output_path}")
 
# 使用示例
if __name__ == "__main__":
    tts = FishSpeechTTS()
    
    # 生成语音
    audio = tts.synthesize("你好,这是一个测试。")
    
    # 保存到文件
    tts.synthesize_to_file(
        "今天天气真不错,适合出门散步。",
        "output.wav"
    )

2.5 声音克隆教程

Fish-Speech支持声音克隆,只需要10-30秒的音频样本。

准备工作

  1. 准备一段干净的语音(最好是无背景音乐的人声)
  2. 时长10秒-30秒最佳
  3. 音频格式最好是WAV或MP3

训练自己的声音模型

# 1. 准备训练数据
# 将音频文件放到 data/your_voice/ 目录下
# 命名格式: audio_001.wav, audio_002.wav, ...
 
# 2. 准备训练文本
# 创建一个文本文件 audio_transcripts.txt:
# audio_001.wav|今天天气很好
# audio_002.wav|我们一起去公园吧
 
# 3. 开始训练
python tools/train.py \
    --data_dir ./data/your_voice \
    --output_dir ./checkpoints/your_voice \
    --max_epochs 100 \
    --batch_size 16
 
# 4. 训练完成后,使用你的声音
python tools/tts_service.py \
    --text "你好,这是我的声音" \
    --speaker your_voice

3. GPT-SoVITS:新一代声音克隆

3.1 GPT-SoVITS是什么?

GPT-SoVITS是2024年新出的声音克隆技术,只需要1分钟的训练数据就能达到很好的效果。

优势

  • 训练数据需求少(1分钟即可)
  • 克隆效果好
  • 支持多语言
  • 推理速度快

3.2 安装GPT-SoVITS

# 克隆仓库
git clone https://github.com/RVC-Boss/GPT-SoVITS.git
cd GPT-SoVITS
 
# 安装依赖
pip install -r requirements.txt
 
# 下载预训练模型
# 需要从HuggingFace下载:
# - GPT-SoVITS-base.pth
# - v2权重

3.3 GPT-SoVITS使用教程

"""
GPT-SoVITS使用示例
"""
import torch
from GPT_SoVITS.download import get_hf_download
from GPT_SoVITS.inference import GPT_SoVITS
 
# 加载模型
gpt_sovits = GPT_SoVITS.from_pretrained(
    "GPT_SoVITS/SoVITS.pth",
    "GPT_SoVITS/GPT.pth"
)
 
def clone_and_speak(audio_sample, text):
    """
    克隆声音并合成语音
    
    Args:
        audio_sample: 参考音频路径
        text: 要说的话
    """
    # 克隆声音特征
    voice_embedding = gpt_sovits.extract_voice(audio_sample)
    
    # 生成语音
    audio = gpt_sovits.generate(
        text=text,
        ref_audio=voice_embedding,
        language="auto"  # 自动检测语言
    )
    
    return audio
 
# 使用示例
if __name__ == "__main__":
    # 用3秒音频克隆声音
    audio = clone_and_speak(
        audio_sample="my_voice.wav",
        text="你好,这是用我自己的声音合成的。"
    )
    
    # 保存
    import soundfile as sf
    sf.write("cloned_voice.wav", audio, 24000)

4. Coqui TTS:老牌开源TTS

4.1 Coqui TTS介绍

Coqui TTS是发展比较成熟的开源TTS项目,支持多种语言和声音克隆。

4.2 安装Coqui TTS

# 安装
pip install TTS
 
# 验证安装
tts --version

4.3 Coqui TTS基础使用

"""
Coqui TTS使用示例
"""
from TTS.api import TTS
 
# 初始化(使用默认模型)
tts = TTS(model_name="tts_models/zh-CN/baker/tacotron2-DDC-GST")
 
# 基础合成
tts.tts_to_file(
    text="你好,这是一个测试。",
    file_path="output.wav"
)
 
# 指定说话人
tts.tts_to_file(
    text="你好,这是一个测试。",
    speaker="female_1",  # 指定说话人
    file_path="output2.wav"
)
 
# 使用参考音频(声音克隆)
tts.tts_with_vc_to_file(
    speaker_wav="reference_voice.wav",
    text="用这个声音说话。",
    file_path="output3.wav"
)

4.4 Coqui TTS进阶:训练自定义声音

"""
Coqui TTS训练自定义声音
"""
from TTS.trainer import Trainer
from TTS.config import load_config
from TTS.tts.datasets import load_tts_samples
 
# 1. 准备数据
# 创建dataset_config.json:
# {
#     "datasets": [
#         {
#             "name": "my_voice",
#             "path": "./data/my_voice",
#             "meta_file_train": "metadata.csv",
#             "audio_config": {
#                 "sample_rate": 22050
#             }
#         }
#     ]
# }
 
# 2. 创建metadata.csv:
# wav_file,duration,text
# audio_001.wav,3.5,你好世界
# audio_002.wav,4.2,今天天气很好
 
# 3. 开始训练
# 加载配置
config = load_config("train_config.json")
 
# 创建数据集
train_samples, eval_samples = load_tts_samples(
    config.datasets,
    eval_split=True
)
 
# 训练
trainer = Trainer(
    config=config,
    output_path="./output",
    train_samples=train_samples,
    eval_samples=eval_samples
)
 
trainer.fit()

5. Azure TTS:企业级云服务

5.1 Azure TTS优势

Azure TTS是微软的云端TTS服务,优点是:

  • 效果非常好,接近真人
  • 神经网络语音非常自然
  • 支持情感控制
  • 全球70+语言
  • 稳定可靠

5.2 Azure TTS安装和使用

# 安装SDK
pip install azure-cognitiveservices-speech
"""
Azure TTS使用示例
"""
import azure.cognitiveservices.speech as speechsdk
import os
 
class AzureTTS:
    """Azure TTS封装"""
    
    def __init__(self, subscription_key, region="eastus"):
        self.speech_config = speechsdk.SpeechConfig(
            subscription=subscription_key,
            region=region
        )
    
    def synthesize(self, text, voice="zh-CN-XiaoxiaoNeural", 
                  output_file="output.wav"):
        """
        文字转语音
        
        Args:
            text: 要转换的文字
            voice: 语音名称
            output_file: 输出文件路径
        """
        self.speech_config.speech_synthesis_voice_name = voice
        
        audio_config = speechsdk.audio.AudioOutputConfig(
            filename=output_file
        )
        
        synthesizer = speechsdk.SpeechSynthesizer(
            speech_config=self.speech_config,
            audio_config=audio_config
        )
        
        result = synthesizer.speak_text_async(text).get()
        
        if result.reason == speechsdk.ResultReason.SynthesizingAudioCompleted:
            print(f"音频已保存到: {output_file}")
        else:
            print(f"合成失败: {result.error_details}")
    
    def synthesize_with_emotion(self, text, emotion, 
                                output_file="output.wav"):
        """
        带情感的语音合成(使用SSML)
        
        Args:
            text: 要转换的文字
            emotion: 情感类型 (cheerful/sad/angry/etc.)
            output_file: 输出文件路径
        """
        # 构建SSML
        ssml = f"""
<speak version='1.0' xmlns='https://www.w3.org/2001/10/synthesis' 
       xml:lang='zh-CN'>
    <voice name='zh-CN-XiaoxiaoNeural'>
        <mstts:express-as style='{emotion}'>
            {text}
        </mstts:express-as>
    </voice>
</speak>
"""
        
        audio_config = speechsdk.audio.AudioOutputConfig(
            filename=output_file
        )
        
        synthesizer = speechsdk.SpeechSynthesizer(
            speech_config=self.speech_config,
            audio_config=audio_config
        )
        
        result = synthesizer.speak_ssml_async(ssml).get()
        
        return result.reason == speechsdk.ResultReason.SynthesizingAudioCompleted
 
# 使用示例
if __name__ == "__main__":
    # 初始化(需要设置环境变量或直接传入key)
    subscription_key = os.getenv("AZURE_SPEECH_KEY")
    region = "eastus"
    
    tts = AzureTTS(subscription_key, region)
    
    # 基础合成
    tts.synthesize(
        text="你好,欢迎使用Azure语音合成服务。",
        voice="zh-CN-XiaoxiaoNeural",
        output_file="azure_basic.wav"
    )
    
    # 带情感合成
    tts.synthesize_with_emotion(
        text="太棒了!我们成功了!",
        emotion="cheerful",
        output_file="azure_happy.wav"
    )
    
    tts.synthesize_with_emotion(
        text="我感到有点难过。",
        emotion="sad",
        output_file="azure_sad.wav"
    )

5.3 Azure TTS情感控制

Azure支持多种情感样式:

情感使用场景效果
cheerful开心、兴奋语气上扬
sad悲伤、沮丧语气下沉
angry生气、愤怒语气强硬
afraid害怕、紧张语速加快
excited兴奋、激动语气夸张
friendly友好、亲切语气温和
hopeful希望、期待语气上扬
terrified恐惧、害怕语速极快

6. XTTS:高质量声音克隆

6.1 XTTS是什么?

XTTS是Coqui推出的新一代声音克隆模型,可以只用短音频就能克隆声音。

6.2 XTTS使用

"""
XTTS声音克隆示例
"""
from TTS.api import TTS
 
# 初始化
tts = TTS(model_name="tts_models/multilingual/multi-dataset/xtts")
 
# 使用参考音频克隆声音
tts.tts_to_file(
    text="这是用你的声音合成的语音。",
    speaker_wav="my_voice.wav",  # 参考音频
    language="zh",
    file_path="cloned_output.wav"
)
 
# 多语言支持
tts.tts_to_file(
    text="Hello, this is a test.",
    speaker_wav="english_voice.wav",
    language="en",
    file_path="english_output.wav"
)

7. 火山引擎TTS:国产好选择

7.1 火山引擎TTS

火山引擎是字节跳动旗下的AI服务平台,TTS效果很好,价格便宜。

"""
火山引擎TTS示例
"""
import requests
import hashlib
import time
import base64
 
class VolcanoTTS:
    """火山引擎TTS封装"""
    
    def __init__(self, app_id, access_token, cluster="volcengine_streaming_common"):
        self.app_id = app_id
        self.access_token = access_token
        self.cluster = cluster
        self.base_url = "https://openspeech.bytedance.com/api/v1/tts"
    
    def synthesize(self, text, voice="zh_female_qingxin", 
                  speed=1.0, pitch=1.0, volume=1.0):
        """
        文字转语音
        
        Args:
            text: 要转换的文字
            voice: 语音名称
            speed: 语速 (0.5-2.0)
            pitch: 音调 (0.5-2.0)
            volume: 音量 (0.5-2.0)
        
        Returns:
            bytes: WAV格式音频数据
        """
        headers = {
            "Content-Type": "application/json",
            "Authorization": f"Bearer;{self.access_token}",
            "Aid": self.app_id
        }
        
        payload = {
            "app": {
                "appid": self.app_id,
                "token": self.access_token,
                "cluster": self.cluster
            },
            "user": {
                "uid": "12345"
            },
            "audio": {
                "voice": voice,
                "encoding": "wav",
                "speed_ratio": speed,
                "volume_ratio": volume,
                "pitch_ratio": pitch,
                "sample_rate": 16000
            },
            "request": {
                "reqid": str(int(time.time() * 1000)),
                "text": text,
                "text_type": "plain",
                "operation": "submit"
            }
        }
        
        response = requests.post(
            self.base_url,
            json=payload,
            headers=headers
        )
        
        if response.status_code == 200:
            return response.content
        else:
            raise Exception(f"TTS failed: {response.text}")
    
    def synthesize_to_file(self, text, output_path, **kwargs):
        """保存到文件"""
        audio_data = self.synthesize(text, **kwargs)
        
        with open(output_path, 'wb') as f:
            f.write(audio_data)
        
        print(f"音频已保存到: {output_path}")
 
# 使用示例
if __name__ == "__main__":
    tts = VolcanoTTS(
        app_id="your_app_id",
        access_token="your_access_token"
    )
    
    tts.synthesize_to_file(
        text="你好,欢迎使用火山引擎语音合成服务。",
        voice="zh_female_qingxin",
        output_path="volcano_output.wav"
    )

8. 实时TTS流式输出

8.1 什么是流式TTS?

流式TTS就是”边生成边播放”,不需要等整段语音生成完毕才能听。这对数字人实时对话非常重要。

8.2 流式TTS实现

"""
流式TTS实现
"""
import asyncio
import websockets
import base64
import numpy as np
 
class StreamingTTS:
    """流式TTS客户端"""
    
    def __init__(self, tts_service):
        self.tts = tts_service
        self.sample_rate = 24000
    
    async def stream_synthesize(self, text, websocket_url):
        """
        流式合成并发送到WebSocket
        
        Args:
            text: 要转换的文字
            websocket_url: WebSocket服务器地址
        """
        async with websockets.connect(websocket_url) as ws:
            # 发送文本
            await ws.send(json.dumps({
                "type": "text",
                "text": text
            }))
            
            # 接收流式音频
            buffer = bytearray()
            
            while True:
                message = await ws.recv()
                
                if isinstance(message, bytes):
                    # 音频数据
                    buffer.extend(message)
                    
                    # 可以在这里播放音频
                    # play_audio_chunk(message)
                else:
                    # JSON消息
                    data = json.loads(message)
                    if data.get("type") == "done":
                        break
            
            return bytes(buffer)
    
    async def synthesize_and_play(self, text):
        """
        合成并直接播放
        """
        # 这里需要结合音频播放库
        # 比如使用pyaudio或sounddevice
        pass
 
# WebSocket服务端示例
"""
from fastapi import WebSocket
from fastapi import FastAPI
import asyncio
 
app = FastAPI()
 
@app.websocket("/ws/tts")
async def tts_websocket(ws: WebSocket):
    await ws.accept()
    
    try:
        while True:
            # 接收文本
            data = await ws.receive_json()
            text = data.get("text", "")
            
            # 流式合成并发送
            tts = TTSEngine()
            async for chunk in tts.stream_synthesize(text):
                await ws.send_bytes(chunk)
            
            # 发送完成信号
            await ws.send_json({"type": "done"})
    
    except Exception as e:
        print(f"Error: {e}")
    finally:
        await ws.close()
"""

9. 情感语音合成

9.1 什么是情感TTS?

情感TTS可以合成带有不同情感的语音,比如开心的、悲伤的、愤怒的等。

9.2 实现情感控制

"""
情感TTS控制示例
"""
from enum import Enum
from typing import Dict
 
class Emotion(Enum):
    """情感枚举"""
    NEUTRAL = "neutral"
    HAPPY = "happy"
    SAD = "sad"
    ANGRY = "angry"
    EXCITED = "excited"
    SCARED = "scared"
 
class EmotionalTTS:
    """情感TTS"""
    
    def __init__(self, tts_engine):
        self.tts = tts_engine
        
        # 情感对应的语音参数调整
        self.emotion_params: Dict[Emotion, Dict] = {
            Emotion.NEUTRAL: {"pitch": 1.0, "speed": 1.0, "volume": 1.0},
            Emotion.HAPPY: {"pitch": 1.1, "speed": 1.1, "volume": 1.0},
            Emotion.SAD: {"pitch": 0.9, "speed": 0.9, "volume": 0.9},
            Emotion.ANGRY: {"pitch": 1.0, "speed": 1.2, "volume": 1.2},
            Emotion.EXCITED: {"pitch": 1.2, "speed": 1.15, "volume": 1.1},
            Emotion.SCARED: {"pitch": 1.15, "speed": 1.1, "volume": 1.0}
        }
    
    def synthesize_emotional(self, text, emotion: Emotion):
        """情感合成"""
        params = self.emotion_params.get(emotion, self.emotion_params[Emotion.NEUTRAL])
        
        return self.tts.synthesize(
            text=text,
            pitch=params["pitch"],
            speed=params["speed"],
            volume=params["volume"]
        )
 
# 使用示例
if __name__ == "__main__":
    tts = TTSEngine()  # 初始化你的TTS引擎
    emotional_tts = EmotionalTTS(tts)
    
    # 根据对话内容选择情感
    dialogues = [
        ("我们成功了!太棒了!", Emotion.HAPPY),
        ("对不起,让你失望了。", Emotion.SAD),
        ("你说什么?!", Emotion.ANGRY),
        ("哇,太不可思议了!", Emotion.EXCITED),
    ]
    
    for text, emotion in dialogues:
        audio = emotional_tts.synthesize_emotional(text, emotion)
        # 保存或播放
        print(f"合成情感语音: {emotion.value}")

10. 常见问题与解决方案

Q1: 合成的语音听起来机械?

原因:模型质量问题

解决

  1. 使用更高级的模型(如GPT-SoVITS、Fish-Speech)
  2. 调整语速参数,不要太快
  3. 使用带情感控制的语音

Q2: 中文发音不准确?

原因:发音人问题

解决

  1. 选择中文优化的模型(如Fish-Speech)
  2. 使用SSML标记特殊发音
  3. 检查输入文字是否有错别字

Q3: 声音克隆效果差?

原因:训练数据问题

解决

  1. 使用更清晰的音频
  2. 增加训练数据量
  3. 确保音频无背景噪音
  4. 增加训练轮数

Q4: 实时合成延迟太高?

解决

  1. 使用流式输出
  2. 预加载模型到内存
  3. 使用GPU加速
  4. 选择更轻量的模型

11. 工具链推荐

11.1 快速上线方案

场景推荐说明
快速体验Azure TTS效果好,5分钟接入
预算有限火山引擎便宜,效果不错
中文为主Fish-Speech免费,中文最好

11.2 声音克隆方案

场景推荐说明
快速克隆GPT-SoVITS1分钟数据,效果好
高质量克隆Fish-Speech需要更多数据,效果顶级
精确控制Coqui + 训练工作量大,但最可控

11.3 企业级方案

场景推荐说明
稳定可靠Azure + 自建核心用Azure,边缘自建
大规模自建GPT-SoVITS集群成本最低,弹性扩展

相关文档


更新日志

日期版本修改内容
2026-04-18v1.0初版完成
2026-04-24v1.1深度改写,增加开源方案实操