首页 语音合成
文章
取消

语音合成

语音合成

下载vits模型文件

如果你有能力可以自己炼丹出个模型,具体可以参考这个

或者可以白嫖点大佬训练的模型,比如这个这个

代码取自这位大佬,然后进行魔改了一番,没有自己造轮子,好多都看不懂,慢慢啃。

speaking.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import subprocess
import argparse
import torch
import time
from torch import no_grad, LongTensor
import asyncio
import utils
from models import SynthesizerTrn
from text import text_to_sequence
import commons
from scipy.io import wavfile
import pygame

#noise_scale(控制感情变化程度)
vitsNoiseScale = 0.6
#noise_scale_w(控制音素发音长度)
vitsNoiseScaleW = 0.668
#length_scale(控制整体语速)
vitsLengthScale = 1.0
_init_vits_model = False

hps_ms = None
device = None
net_g_ms = None

def play_audio(audio_file_name):
    # 初始化pygame
    pygame.init()
    # 设置音频文件
    pygame.mixer.music.load(audio_file_name)
    # 播放音频
    pygame.mixer.music.play()
    # 等待音频播放完毕
    while pygame.mixer.music.get_busy():
        pygame.time.Clock().tick(10)
    # 退出pygame
    pygame.quit()
# def play_audio(audio_file_name):
#     command = f'mpv.exe -vo null {audio_file_name}'
#     subprocess.run(command, shell=True)

def init_vits_model():
    # 全局变量引入
    global hps_ms, device, net_g_ms

    # 创建参数解析器
    parser = argparse.ArgumentParser()
    parser.add_argument('--device', type=str, default='cpu')
    parser.add_argument('--api', action="store_true", default=False)
    parser.add_argument("--share", action="store_true", default=False, help="share gradio app")
    parser.add_argument("--colab", action="store_true", default=False, help="share gradio app")
    args = parser.parse_args()
    device = torch.device(args.device)
    # 从文件中获取VITS模型的参数
    hps_ms = utils.get_hparams_from_file('config.json')
    # 创建VITS模型
    net_g_ms = SynthesizerTrn(
        len(hps_ms.symbols),
        hps_ms.data.filter_length // 2 + 1,
        hps_ms.train.segment_size // hps_ms.data.hop_length,
        n_speakers=hps_ms.data.n_speakers,
        **hps_ms.model)
    # 将VITS模型设置为评估模式,并移动到指定设备
    _ = net_g_ms.eval().to(device)
    # 获取说话者信息
    speakers = hps_ms.speakers
    # 加载模型和优化器
    model, optimizer, learning_rate, epochs = utils.load_checkpoint('G_953000.pth', net_g_ms, None)
    # 标记VITS模型已初始化
    _init_vits_model = True

def get_text(text, hps):
    # 使用text_to_sequence将输入文本转换为模型可用的格式
    text_norm, clean_text = text_to_sequence(text, hps.symbols, hps.data.text_cleaners)
    # 如果需要在文本中添加空白符,则在文本序列中插入0(代表空白符)
    if hps.data.add_blank:
        text_norm = commons.intersperse(text_norm, 0)
    # 将文本序列转换为LongTensor(长整数)格式
    text_norm = LongTensor(text_norm)
    return text_norm, clean_text

def vits(text, language, speaker_id, noise_scale, noise_scale_w, length_scale):
    global over
    # 记录生成开始时间
    start = time.perf_counter()
    # 处理输入文本
    if not len(text):
        return "输入文本不能为空!", None, None
    text = text.replace('\n', ' ').replace('\r', '').replace(" ", "")
    if len(text) > 200:
        return f"输入文字过长!{len(text)}>100", None, None
    # 根据语言类型添加标记
    if language == 0:
        text = f"[ZH]{text}[ZH]"
    elif language == 1:
        text = f"[JA]{text}[JA]"
    else:
        text = f"{text}"
    # 调用get_text将文本转换为模型可用的格式
    stn_tst, clean_text = get_text(text, hps_ms)
    # 使用VITS模型生成音频
    with no_grad():
        x_tst = stn_tst.unsqueeze(0).to(device)
        x_tst_lengths = LongTensor([stn_tst.size(0)]).to(device)
        speaker_id = LongTensor([speaker_id]).to(device)
        audio = net_g_ms.infer(x_tst, x_tst_lengths, sid=speaker_id, noise_scale=noise_scale, noise_scale_w=noise_scale_w,
                               length_scale=length_scale)[0][0, 0].data.cpu().float().numpy()
    # 返回生成成功信息、音频信息以及生成耗时
    return "生成成功!", (22050, audio), f"生成耗时 {round(time.perf_counter()-start, 2)} s"

async def start():
    while True:
        print("请输入 >")
        input_str = await asyncio.get_event_loop().run_in_executor(None, input, '')
        if "关闭AI" in input_str:
            return
        result = input_str
        status, audios, time = vits(result, 0, 124, vitsNoiseScale, vitsNoiseScaleW, vitsLengthScale)
        print("VITS : ", status, time)
        wavfile.write("output.wav", audios[0], audios[1])
        play_audio("output.wav")

async def main():
    if not _init_vits_model:
        init_vits_model()
    await asyncio.gather(start(),)

asyncio.run(main())
  • 导入库:代码导入了必要的Python库,例如time、os、scipy.io.wavfile、asyncio、subprocess、requests、json、argparse,以及自定义模块utils、models、text和commons中的各种函数和类。
  • 变量定义和配置:
    • 定义了一些全局变量,用于配置GPT-3.5模型的访问信息、VITS模型的参数等。
    • 初始化了一些VITS模型的相关参数,并加载了模型。
  • 函数定义:
    • send_chatgpt_request(send_msg):用于向GPT-3.5模型发送请求并获取生成的文本回复。
    • play_audio(audio_file_name):用于播放音频文件。
    • init_vits_model():用于初始化VITS模型。
    • get_text(text, hps):用于处理输入文本,将其转换成模型可用的格式。
    • vits(text, language, speaker_id, noise_scale, noise_scale_w, length_scale):用于生成语音。
  • 异步事件处理:
    • start():从用户输入中获取文本,发送给GPT-3.5模型获取回复,并使用VITS模型生成对应的语音。
    • main():主要函数,协调调用start()函数以实现异步处理。
  • 程序入口:
    • 使用asyncio.run(main())调用主函数,启动程序运行。

###get_text()函数 get_text函数的目的是将输入文本转换为VITS模型可用的格式,它接受两个参数:text(输入的文本)和hps(VITS模型的参数)。 在get_text函数中,主要有以下步骤:

  1. 调用text_to_sequence函数:
    • text_to_sequence函数用于将文本转换为符号序列,该序列是模型可接受的输入格式。
    • 这个函数的调用将输入文本转换成两部分:text_norm和clean_text。
    • text_norm是转换后的文本序列,使用VITS模型参数中的符号表和文本清理器处理得到。
    • clean_text是原始文本的清理版本。
  2. 添加空白符(如果需要):
    • 根据模型参数中的add_blank标志,决定是否需要在文本序列中插入0作为空白符。
  3. 将文本序列转换为LongTensor:
    • 最终将处理后的文本序列转换为PyTorch的LongTensor格式,以便模型可以接受它作为输入。
1
2
3
4
5
6
7
8
9
10
11
def get_text(text, hps):
    # 使用text_to_sequence将输入文本转换为模型可用的格式
    text_norm, clean_text = text_to_sequence(text, hps.symbols, hps.data.text_cleaners)
    
    # 如果需要在文本中添加空白符,则在文本序列中插入0(代表空白符)
    if hps.data.add_blank:
        text_norm = commons.intersperse(text_norm, 0)
    
    # 将文本序列转换为LongTensor(长整数)格式
    text_norm = LongTensor(text_norm)
    return text_norm, clean_text

###text_to_sequence函数 text_to_sequence函数的目的是将文本转换为符号序列,它接受三个参数:text(输入文本)、symbols(符号表)和cleaners(文本清理器)。

在text_to_sequence函数中,主要有以下步骤:

  1. 文本清理:
    • 调用clean_text函数对输入文本进行清理,去除多余的空格、特殊字符等。
  2. 文本转换为符号序列:
    • 遍历清理后的文本,将每个字符转换为对应的符号在符号表中的索引。
    • 如果字符不在符号表中,将其转换为未知符号的索引。 总的来说,get_text函数使用了text_to_sequence函数将输入文本转换为模型可用的符号序列,并可以选择是否添加空白符。 ``` cpp def text_to_sequence(text, symbols, cleaners): # 文本清理,例如去除多余的空格、特殊字符等 cleaned_text = clean_text(text, cleaners)
1
2
3
4
5
6
7
8
9
# 将文本转换为符号序列
symbols = symbols + ['[UNK]']  # 符号表增加未知符号
sequence = []
for s in cleaned_text:
    if s in symbols:
        sequence.append(symbols.index(s))
    else:
        sequence.append(symbols.index('[UNK]'))
return sequence, cleaned_text
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
###异步事件处理:

- start():从用户输入中获取文本,发送给GPT-3.5模型获取回复,并使用VITS模型生成对应的语音。
- main():主要函数,协调调用start()函数以实现异步处理。

1. async 和 await 关键字
- async: async关键字用于定义一个异步函数,即一个函数的执行可能会被中断,然后在稍后的某个时刻继续执行。异步函数在遇到await时可能会暂停执行,等待另一个异步操作完成。
- await: await关键字用于等待一个异步操作完成。它只能在异步函数内部使用,并且通常与async一起使用。
2. asyncio 模块
asyncio 是 Python 标准库中的模块,用于支持异步编程。它提供了一种事件循环机制,用于管理异步任务和异步函数。

在异步编程中,我们将任务添加到事件循环中,然后让事件循环负责调度这些任务的执行。asyncio 通过事件循环来驱动异步程序的执行,处理异步函数的调用和结果的返回。

3. 异步事件处理流程
现在,让我们来理解代码中的异步事件处理流程:

- start() 函数:

  - 这是一个异步函数,用于处理用户输入。它等待用户的输入,然后将输入文本发送给 GPT-3.5 模型获取回复,并使用 VITS 模型生成对应的语音。这里的 await 用于等待异步操作完成,例如等待用户输入。
- main() 函数:

  - 这是程序的主要函数,也是一个异步函数。它协调调用 start() 函数以实现异步处理。在这里,await start() 用于等待 start() 函数执行完成,然后结束程序。
- 程序入口:
  - 最后,在程序的入口处,我们使用 asyncio.run(main()) 调用主函数 main(),启动整个程序的异步执行。asyncio.run() 是用于运行异步程序的简便方法。
总结一下,异步编程通过使用 async 和 await 关键字以及 asyncio 模块,使程序能够在等待一些耗时的操作时不阻塞,从而提高了程序的效率和响应性。

###关键代码
``` cpp
audio = net_g_ms.infer(x_tst, x_tst_lengths, sid=speaker_id, noise_scale=noise_scale, noise_scale_w=noise_scale_w,
                       length_scale=length_scale)[0][0, 0].data.cpu().float().numpy()

这行代码调用了 net_g_ms 对象(一个 VITS 模型)的 infer 方法来生成音频,然后将结果赋给 audio 变量。

逐步解释:

  1. net_g_ms: 这是 VITS 模型对象,用于语音合成。

  2. infer: 这是 VITS 模型的推理方法,用于生成音频。

  3. x_tst: 这是输入的文本序列的 PyTorch tensor,表示待合成的文本。

  4. x_tst_lengths: 这是输入文本的长度,以 PyTorch tensor 表示。

  5. sid=speaker_id: 这是说话者 ID,用于指定生成音频的说话者。

  6. noise_scale, noise_scale_w, length_scale: 这些是控制语音生成的参数,影响生成音频的特征,包括感情变化程度、音素发音长度和整体语速。

  7. [0][0, 0]: 这是对生成的音频结果进行索引操作,从生成的音频结果中提取特定部分。具体来说,它提取了生成的音频的第一个样本(可能是第一个批次的第一个样本)的第一个通道的数据。

  8. .data.cpu().float().numpy(): 这一系列操作将音频数据从 GPU(如果在 GPU 上)转移到 CPU,并转换为 NumPy 数组,以便后续处理或保存为音频文件。

这行代码调用 VITS 模型的推理方法生成音频,并对生成的音频结果进行一系列处理,最终得到可以播放或保存的音频数据。

本文由作者按照 CC BY 4.0 进行授权