minicpmo-utils 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (148) hide show
  1. cosyvoice/__init__.py +17 -0
  2. cosyvoice/bin/average_model.py +93 -0
  3. cosyvoice/bin/export_jit.py +103 -0
  4. cosyvoice/bin/export_onnx.py +120 -0
  5. cosyvoice/bin/inference_deprecated.py +126 -0
  6. cosyvoice/bin/train.py +195 -0
  7. cosyvoice/cli/__init__.py +0 -0
  8. cosyvoice/cli/cosyvoice.py +209 -0
  9. cosyvoice/cli/frontend.py +238 -0
  10. cosyvoice/cli/model.py +386 -0
  11. cosyvoice/dataset/__init__.py +0 -0
  12. cosyvoice/dataset/dataset.py +151 -0
  13. cosyvoice/dataset/processor.py +434 -0
  14. cosyvoice/flow/decoder.py +494 -0
  15. cosyvoice/flow/flow.py +281 -0
  16. cosyvoice/flow/flow_matching.py +227 -0
  17. cosyvoice/flow/length_regulator.py +70 -0
  18. cosyvoice/hifigan/discriminator.py +230 -0
  19. cosyvoice/hifigan/f0_predictor.py +58 -0
  20. cosyvoice/hifigan/generator.py +582 -0
  21. cosyvoice/hifigan/hifigan.py +67 -0
  22. cosyvoice/llm/llm.py +610 -0
  23. cosyvoice/tokenizer/assets/multilingual_zh_ja_yue_char_del.tiktoken +58836 -0
  24. cosyvoice/tokenizer/tokenizer.py +279 -0
  25. cosyvoice/transformer/__init__.py +0 -0
  26. cosyvoice/transformer/activation.py +84 -0
  27. cosyvoice/transformer/attention.py +330 -0
  28. cosyvoice/transformer/convolution.py +145 -0
  29. cosyvoice/transformer/decoder.py +396 -0
  30. cosyvoice/transformer/decoder_layer.py +132 -0
  31. cosyvoice/transformer/embedding.py +302 -0
  32. cosyvoice/transformer/encoder.py +474 -0
  33. cosyvoice/transformer/encoder_layer.py +236 -0
  34. cosyvoice/transformer/label_smoothing_loss.py +96 -0
  35. cosyvoice/transformer/positionwise_feed_forward.py +115 -0
  36. cosyvoice/transformer/subsampling.py +383 -0
  37. cosyvoice/transformer/upsample_encoder.py +320 -0
  38. cosyvoice/utils/__init__.py +0 -0
  39. cosyvoice/utils/class_utils.py +83 -0
  40. cosyvoice/utils/common.py +186 -0
  41. cosyvoice/utils/executor.py +176 -0
  42. cosyvoice/utils/file_utils.py +129 -0
  43. cosyvoice/utils/frontend_utils.py +136 -0
  44. cosyvoice/utils/losses.py +57 -0
  45. cosyvoice/utils/mask.py +265 -0
  46. cosyvoice/utils/scheduler.py +738 -0
  47. cosyvoice/utils/train_utils.py +367 -0
  48. cosyvoice/vllm/cosyvoice2.py +103 -0
  49. matcha/__init__.py +0 -0
  50. matcha/app.py +357 -0
  51. matcha/cli.py +418 -0
  52. matcha/hifigan/__init__.py +0 -0
  53. matcha/hifigan/config.py +28 -0
  54. matcha/hifigan/denoiser.py +64 -0
  55. matcha/hifigan/env.py +17 -0
  56. matcha/hifigan/meldataset.py +217 -0
  57. matcha/hifigan/models.py +368 -0
  58. matcha/hifigan/xutils.py +60 -0
  59. matcha/models/__init__.py +0 -0
  60. matcha/models/baselightningmodule.py +209 -0
  61. matcha/models/components/__init__.py +0 -0
  62. matcha/models/components/decoder.py +443 -0
  63. matcha/models/components/flow_matching.py +132 -0
  64. matcha/models/components/text_encoder.py +410 -0
  65. matcha/models/components/transformer.py +316 -0
  66. matcha/models/matcha_tts.py +239 -0
  67. matcha/onnx/__init__.py +0 -0
  68. matcha/onnx/export.py +181 -0
  69. matcha/onnx/infer.py +168 -0
  70. matcha/text/__init__.py +53 -0
  71. matcha/text/cleaners.py +116 -0
  72. matcha/text/numbers.py +71 -0
  73. matcha/text/symbols.py +17 -0
  74. matcha/train.py +122 -0
  75. matcha/utils/__init__.py +5 -0
  76. matcha/utils/audio.py +82 -0
  77. matcha/utils/generate_data_statistics.py +111 -0
  78. matcha/utils/instantiators.py +56 -0
  79. matcha/utils/logging_utils.py +53 -0
  80. matcha/utils/model.py +90 -0
  81. matcha/utils/monotonic_align/__init__.py +22 -0
  82. matcha/utils/monotonic_align/setup.py +7 -0
  83. matcha/utils/pylogger.py +21 -0
  84. matcha/utils/rich_utils.py +101 -0
  85. matcha/utils/utils.py +219 -0
  86. minicpmo/__init__.py +24 -0
  87. minicpmo/utils.py +636 -0
  88. minicpmo/version.py +2 -0
  89. minicpmo_utils-0.1.0.dist-info/METADATA +72 -0
  90. minicpmo_utils-0.1.0.dist-info/RECORD +148 -0
  91. minicpmo_utils-0.1.0.dist-info/WHEEL +5 -0
  92. minicpmo_utils-0.1.0.dist-info/top_level.txt +5 -0
  93. s3tokenizer/__init__.py +153 -0
  94. s3tokenizer/assets/BAC009S0764W0121.wav +0 -0
  95. s3tokenizer/assets/BAC009S0764W0122.wav +0 -0
  96. s3tokenizer/assets/mel_filters.npz +0 -0
  97. s3tokenizer/cli.py +183 -0
  98. s3tokenizer/model.py +546 -0
  99. s3tokenizer/model_v2.py +605 -0
  100. s3tokenizer/utils.py +390 -0
  101. stepaudio2/__init__.py +40 -0
  102. stepaudio2/cosyvoice2/__init__.py +1 -0
  103. stepaudio2/cosyvoice2/flow/__init__.py +0 -0
  104. stepaudio2/cosyvoice2/flow/decoder_dit.py +585 -0
  105. stepaudio2/cosyvoice2/flow/flow.py +230 -0
  106. stepaudio2/cosyvoice2/flow/flow_matching.py +205 -0
  107. stepaudio2/cosyvoice2/transformer/__init__.py +0 -0
  108. stepaudio2/cosyvoice2/transformer/attention.py +328 -0
  109. stepaudio2/cosyvoice2/transformer/embedding.py +119 -0
  110. stepaudio2/cosyvoice2/transformer/encoder_layer.py +163 -0
  111. stepaudio2/cosyvoice2/transformer/positionwise_feed_forward.py +56 -0
  112. stepaudio2/cosyvoice2/transformer/subsampling.py +79 -0
  113. stepaudio2/cosyvoice2/transformer/upsample_encoder_v2.py +483 -0
  114. stepaudio2/cosyvoice2/utils/__init__.py +1 -0
  115. stepaudio2/cosyvoice2/utils/class_utils.py +41 -0
  116. stepaudio2/cosyvoice2/utils/common.py +101 -0
  117. stepaudio2/cosyvoice2/utils/mask.py +49 -0
  118. stepaudio2/flashcosyvoice/__init__.py +0 -0
  119. stepaudio2/flashcosyvoice/cli.py +424 -0
  120. stepaudio2/flashcosyvoice/config.py +80 -0
  121. stepaudio2/flashcosyvoice/cosyvoice2.py +160 -0
  122. stepaudio2/flashcosyvoice/cosyvoice3.py +1 -0
  123. stepaudio2/flashcosyvoice/engine/__init__.py +0 -0
  124. stepaudio2/flashcosyvoice/engine/block_manager.py +114 -0
  125. stepaudio2/flashcosyvoice/engine/llm_engine.py +125 -0
  126. stepaudio2/flashcosyvoice/engine/model_runner.py +310 -0
  127. stepaudio2/flashcosyvoice/engine/scheduler.py +77 -0
  128. stepaudio2/flashcosyvoice/engine/sequence.py +90 -0
  129. stepaudio2/flashcosyvoice/modules/__init__.py +0 -0
  130. stepaudio2/flashcosyvoice/modules/flow.py +198 -0
  131. stepaudio2/flashcosyvoice/modules/flow_components/__init__.py +0 -0
  132. stepaudio2/flashcosyvoice/modules/flow_components/estimator.py +974 -0
  133. stepaudio2/flashcosyvoice/modules/flow_components/upsample_encoder.py +998 -0
  134. stepaudio2/flashcosyvoice/modules/hifigan.py +249 -0
  135. stepaudio2/flashcosyvoice/modules/hifigan_components/__init__.py +0 -0
  136. stepaudio2/flashcosyvoice/modules/hifigan_components/layers.py +433 -0
  137. stepaudio2/flashcosyvoice/modules/qwen2.py +92 -0
  138. stepaudio2/flashcosyvoice/modules/qwen2_components/__init__.py +0 -0
  139. stepaudio2/flashcosyvoice/modules/qwen2_components/layers.py +616 -0
  140. stepaudio2/flashcosyvoice/modules/sampler.py +231 -0
  141. stepaudio2/flashcosyvoice/utils/__init__.py +0 -0
  142. stepaudio2/flashcosyvoice/utils/audio.py +77 -0
  143. stepaudio2/flashcosyvoice/utils/context.py +28 -0
  144. stepaudio2/flashcosyvoice/utils/loader.py +116 -0
  145. stepaudio2/flashcosyvoice/utils/memory.py +19 -0
  146. stepaudio2/stepaudio2.py +204 -0
  147. stepaudio2/token2wav.py +248 -0
  148. stepaudio2/utils.py +91 -0
matcha/cli.py ADDED
@@ -0,0 +1,418 @@
1
+ import argparse
2
+ import datetime as dt
3
+ import os
4
+ import warnings
5
+ from pathlib import Path
6
+
7
+ import matplotlib.pyplot as plt
8
+ import numpy as np
9
+ import soundfile as sf
10
+ import torch
11
+
12
+ from matcha.hifigan.config import v1
13
+ from matcha.hifigan.denoiser import Denoiser
14
+ from matcha.hifigan.env import AttrDict
15
+ from matcha.hifigan.models import Generator as HiFiGAN
16
+ from matcha.models.matcha_tts import MatchaTTS
17
+ from matcha.text import sequence_to_text, text_to_sequence
18
+ from matcha.utils.utils import assert_model_downloaded, get_user_data_dir, intersperse
19
+
20
+ MATCHA_URLS = {
21
+ "matcha_ljspeech": "https://github.com/shivammehta25/Matcha-TTS-checkpoints/releases/download/v1.0/matcha_ljspeech.ckpt",
22
+ "matcha_vctk": "https://github.com/shivammehta25/Matcha-TTS-checkpoints/releases/download/v1.0/matcha_vctk.ckpt",
23
+ }
24
+
25
+ VOCODER_URLS = {
26
+ "hifigan_T2_v1": "https://github.com/shivammehta25/Matcha-TTS-checkpoints/releases/download/v1.0/generator_v1", # Old url: https://drive.google.com/file/d/14NENd4equCBLyyCSke114Mv6YR_j_uFs/view?usp=drive_link
27
+ "hifigan_univ_v1": "https://github.com/shivammehta25/Matcha-TTS-checkpoints/releases/download/v1.0/g_02500000", # Old url: https://drive.google.com/file/d/1qpgI41wNXFcH-iKq1Y42JlBC9j0je8PW/view?usp=drive_link
28
+ }
29
+
30
+ MULTISPEAKER_MODEL = {
31
+ "matcha_vctk": {"vocoder": "hifigan_univ_v1", "speaking_rate": 0.85, "spk": 0, "spk_range": (0, 107)}
32
+ }
33
+
34
+ SINGLESPEAKER_MODEL = {"matcha_ljspeech": {"vocoder": "hifigan_T2_v1", "speaking_rate": 0.95, "spk": None}}
35
+
36
+
37
+ def plot_spectrogram_to_numpy(spectrogram, filename):
38
+ fig, ax = plt.subplots(figsize=(12, 3))
39
+ im = ax.imshow(spectrogram, aspect="auto", origin="lower", interpolation="none")
40
+ plt.colorbar(im, ax=ax)
41
+ plt.xlabel("Frames")
42
+ plt.ylabel("Channels")
43
+ plt.title("Synthesised Mel-Spectrogram")
44
+ fig.canvas.draw()
45
+ plt.savefig(filename)
46
+
47
+
48
+ def process_text(i: int, text: str, device: torch.device):
49
+ print(f"[{i}] - Input text: {text}")
50
+ x = torch.tensor(
51
+ intersperse(text_to_sequence(text, ["english_cleaners2"]), 0),
52
+ dtype=torch.long,
53
+ device=device,
54
+ )[None]
55
+ x_lengths = torch.tensor([x.shape[-1]], dtype=torch.long, device=device)
56
+ x_phones = sequence_to_text(x.squeeze(0).tolist())
57
+ print(f"[{i}] - Phonetised text: {x_phones[1::2]}")
58
+
59
+ return {"x_orig": text, "x": x, "x_lengths": x_lengths, "x_phones": x_phones}
60
+
61
+
62
+ def get_texts(args):
63
+ if args.text:
64
+ texts = [args.text]
65
+ else:
66
+ with open(args.file, encoding="utf-8") as f:
67
+ texts = f.readlines()
68
+ return texts
69
+
70
+
71
+ def assert_required_models_available(args):
72
+ save_dir = get_user_data_dir()
73
+ if not hasattr(args, "checkpoint_path") and args.checkpoint_path is None:
74
+ model_path = args.checkpoint_path
75
+ else:
76
+ model_path = save_dir / f"{args.model}.ckpt"
77
+ assert_model_downloaded(model_path, MATCHA_URLS[args.model])
78
+
79
+ vocoder_path = save_dir / f"{args.vocoder}"
80
+ assert_model_downloaded(vocoder_path, VOCODER_URLS[args.vocoder])
81
+ return {"matcha": model_path, "vocoder": vocoder_path}
82
+
83
+
84
+ def load_hifigan(checkpoint_path, device):
85
+ h = AttrDict(v1)
86
+ hifigan = HiFiGAN(h).to(device)
87
+ hifigan.load_state_dict(torch.load(checkpoint_path, map_location=device)["generator"])
88
+ _ = hifigan.eval()
89
+ hifigan.remove_weight_norm()
90
+ return hifigan
91
+
92
+
93
+ def load_vocoder(vocoder_name, checkpoint_path, device):
94
+ print(f"[!] Loading {vocoder_name}!")
95
+ vocoder = None
96
+ if vocoder_name in ("hifigan_T2_v1", "hifigan_univ_v1"):
97
+ vocoder = load_hifigan(checkpoint_path, device)
98
+ else:
99
+ raise NotImplementedError(
100
+ f"Vocoder {vocoder_name} not implemented! define a load_<<vocoder_name>> method for it"
101
+ )
102
+
103
+ denoiser = Denoiser(vocoder, mode="zeros")
104
+ print(f"[+] {vocoder_name} loaded!")
105
+ return vocoder, denoiser
106
+
107
+
108
+ def load_matcha(model_name, checkpoint_path, device):
109
+ print(f"[!] Loading {model_name}!")
110
+ model = MatchaTTS.load_from_checkpoint(checkpoint_path, map_location=device)
111
+ _ = model.eval()
112
+
113
+ print(f"[+] {model_name} loaded!")
114
+ return model
115
+
116
+
117
+ def to_waveform(mel, vocoder, denoiser=None):
118
+ audio = vocoder(mel).clamp(-1, 1)
119
+ if denoiser is not None:
120
+ audio = denoiser(audio.squeeze(), strength=0.00025).cpu().squeeze()
121
+
122
+ return audio.cpu().squeeze()
123
+
124
+
125
+ def save_to_folder(filename: str, output: dict, folder: str):
126
+ folder = Path(folder)
127
+ folder.mkdir(exist_ok=True, parents=True)
128
+ plot_spectrogram_to_numpy(np.array(output["mel"].squeeze().float().cpu()), f"{filename}.png")
129
+ np.save(folder / f"{filename}", output["mel"].cpu().numpy())
130
+ sf.write(folder / f"{filename}.wav", output["waveform"], 22050, "PCM_24")
131
+ return folder.resolve() / f"{filename}.wav"
132
+
133
+
134
+ def validate_args(args):
135
+ assert (
136
+ args.text or args.file
137
+ ), "Either text or file must be provided Matcha-T(ea)TTS need sometext to whisk the waveforms."
138
+ assert args.temperature >= 0, "Sampling temperature cannot be negative"
139
+ assert args.steps > 0, "Number of ODE steps must be greater than 0"
140
+
141
+ if args.checkpoint_path is None:
142
+ # When using pretrained models
143
+ if args.model in SINGLESPEAKER_MODEL:
144
+ args = validate_args_for_single_speaker_model(args)
145
+
146
+ if args.model in MULTISPEAKER_MODEL:
147
+ args = validate_args_for_multispeaker_model(args)
148
+ else:
149
+ # When using a custom model
150
+ if args.vocoder != "hifigan_univ_v1":
151
+ warn_ = "[-] Using custom model checkpoint! I would suggest passing --vocoder hifigan_univ_v1, unless the custom model is trained on LJ Speech."
152
+ warnings.warn(warn_, UserWarning)
153
+ if args.speaking_rate is None:
154
+ args.speaking_rate = 1.0
155
+
156
+ if args.batched:
157
+ assert args.batch_size > 0, "Batch size must be greater than 0"
158
+ assert args.speaking_rate > 0, "Speaking rate must be greater than 0"
159
+
160
+ return args
161
+
162
+
163
+ def validate_args_for_multispeaker_model(args):
164
+ if args.vocoder is not None:
165
+ if args.vocoder != MULTISPEAKER_MODEL[args.model]["vocoder"]:
166
+ warn_ = f"[-] Using {args.model} model! I would suggest passing --vocoder {MULTISPEAKER_MODEL[args.model]['vocoder']}"
167
+ warnings.warn(warn_, UserWarning)
168
+ else:
169
+ args.vocoder = MULTISPEAKER_MODEL[args.model]["vocoder"]
170
+
171
+ if args.speaking_rate is None:
172
+ args.speaking_rate = MULTISPEAKER_MODEL[args.model]["speaking_rate"]
173
+
174
+ spk_range = MULTISPEAKER_MODEL[args.model]["spk_range"]
175
+ if args.spk is not None:
176
+ assert (
177
+ args.spk >= spk_range[0] and args.spk <= spk_range[-1]
178
+ ), f"Speaker ID must be between {spk_range} for this model."
179
+ else:
180
+ available_spk_id = MULTISPEAKER_MODEL[args.model]["spk"]
181
+ warn_ = f"[!] Speaker ID not provided! Using speaker ID {available_spk_id}"
182
+ warnings.warn(warn_, UserWarning)
183
+ args.spk = available_spk_id
184
+
185
+ return args
186
+
187
+
188
+ def validate_args_for_single_speaker_model(args):
189
+ if args.vocoder is not None:
190
+ if args.vocoder != SINGLESPEAKER_MODEL[args.model]["vocoder"]:
191
+ warn_ = f"[-] Using {args.model} model! I would suggest passing --vocoder {SINGLESPEAKER_MODEL[args.model]['vocoder']}"
192
+ warnings.warn(warn_, UserWarning)
193
+ else:
194
+ args.vocoder = SINGLESPEAKER_MODEL[args.model]["vocoder"]
195
+
196
+ if args.speaking_rate is None:
197
+ args.speaking_rate = SINGLESPEAKER_MODEL[args.model]["speaking_rate"]
198
+
199
+ if args.spk != SINGLESPEAKER_MODEL[args.model]["spk"]:
200
+ warn_ = f"[-] Ignoring speaker id {args.spk} for {args.model}"
201
+ warnings.warn(warn_, UserWarning)
202
+ args.spk = SINGLESPEAKER_MODEL[args.model]["spk"]
203
+
204
+ return args
205
+
206
+
207
+ @torch.inference_mode()
208
+ def cli():
209
+ parser = argparse.ArgumentParser(
210
+ description=" 🍵 Matcha-TTS: A fast TTS architecture with conditional flow matching"
211
+ )
212
+ parser.add_argument(
213
+ "--model",
214
+ type=str,
215
+ default="matcha_ljspeech",
216
+ help="Model to use",
217
+ choices=MATCHA_URLS.keys(),
218
+ )
219
+
220
+ parser.add_argument(
221
+ "--checkpoint_path",
222
+ type=str,
223
+ default=None,
224
+ help="Path to the custom model checkpoint",
225
+ )
226
+
227
+ parser.add_argument(
228
+ "--vocoder",
229
+ type=str,
230
+ default=None,
231
+ help="Vocoder to use (default: will use the one suggested with the pretrained model))",
232
+ choices=VOCODER_URLS.keys(),
233
+ )
234
+ parser.add_argument("--text", type=str, default=None, help="Text to synthesize")
235
+ parser.add_argument("--file", type=str, default=None, help="Text file to synthesize")
236
+ parser.add_argument("--spk", type=int, default=None, help="Speaker ID")
237
+ parser.add_argument(
238
+ "--temperature",
239
+ type=float,
240
+ default=0.667,
241
+ help="Variance of the x0 noise (default: 0.667)",
242
+ )
243
+ parser.add_argument(
244
+ "--speaking_rate",
245
+ type=float,
246
+ default=None,
247
+ help="change the speaking rate, a higher value means slower speaking rate (default: 1.0)",
248
+ )
249
+ parser.add_argument("--steps", type=int, default=10, help="Number of ODE steps (default: 10)")
250
+ parser.add_argument("--cpu", action="store_true", help="Use CPU for inference (default: use GPU if available)")
251
+ parser.add_argument(
252
+ "--denoiser_strength",
253
+ type=float,
254
+ default=0.00025,
255
+ help="Strength of the vocoder bias denoiser (default: 0.00025)",
256
+ )
257
+ parser.add_argument(
258
+ "--output_folder",
259
+ type=str,
260
+ default=os.getcwd(),
261
+ help="Output folder to save results (default: current dir)",
262
+ )
263
+ parser.add_argument("--batched", action="store_true", help="Batched inference (default: False)")
264
+ parser.add_argument(
265
+ "--batch_size", type=int, default=32, help="Batch size only useful when --batched (default: 32)"
266
+ )
267
+
268
+ args = parser.parse_args()
269
+
270
+ args = validate_args(args)
271
+ device = get_device(args)
272
+ print_config(args)
273
+ paths = assert_required_models_available(args)
274
+
275
+ if args.checkpoint_path is not None:
276
+ print(f"[🍵] Loading custom model from {args.checkpoint_path}")
277
+ paths["matcha"] = args.checkpoint_path
278
+ args.model = "custom_model"
279
+
280
+ model = load_matcha(args.model, paths["matcha"], device)
281
+ vocoder, denoiser = load_vocoder(args.vocoder, paths["vocoder"], device)
282
+
283
+ texts = get_texts(args)
284
+
285
+ spk = torch.tensor([args.spk], device=device, dtype=torch.long) if args.spk is not None else None
286
+ if len(texts) == 1 or not args.batched:
287
+ unbatched_synthesis(args, device, model, vocoder, denoiser, texts, spk)
288
+ else:
289
+ batched_synthesis(args, device, model, vocoder, denoiser, texts, spk)
290
+
291
+
292
+ class BatchedSynthesisDataset(torch.utils.data.Dataset):
293
+ def __init__(self, processed_texts):
294
+ self.processed_texts = processed_texts
295
+
296
+ def __len__(self):
297
+ return len(self.processed_texts)
298
+
299
+ def __getitem__(self, idx):
300
+ return self.processed_texts[idx]
301
+
302
+
303
+ def batched_collate_fn(batch):
304
+ x = []
305
+ x_lengths = []
306
+
307
+ for b in batch:
308
+ x.append(b["x"].squeeze(0))
309
+ x_lengths.append(b["x_lengths"])
310
+
311
+ x = torch.nn.utils.rnn.pad_sequence(x, batch_first=True)
312
+ x_lengths = torch.concat(x_lengths, dim=0)
313
+ return {"x": x, "x_lengths": x_lengths}
314
+
315
+
316
+ def batched_synthesis(args, device, model, vocoder, denoiser, texts, spk):
317
+ total_rtf = []
318
+ total_rtf_w = []
319
+ processed_text = [process_text(i, text, "cpu") for i, text in enumerate(texts)]
320
+ dataloader = torch.utils.data.DataLoader(
321
+ BatchedSynthesisDataset(processed_text),
322
+ batch_size=args.batch_size,
323
+ collate_fn=batched_collate_fn,
324
+ num_workers=8,
325
+ )
326
+ for i, batch in enumerate(dataloader):
327
+ i = i + 1
328
+ start_t = dt.datetime.now()
329
+ output = model.synthesise(
330
+ batch["x"].to(device),
331
+ batch["x_lengths"].to(device),
332
+ n_timesteps=args.steps,
333
+ temperature=args.temperature,
334
+ spks=spk,
335
+ length_scale=args.speaking_rate,
336
+ )
337
+
338
+ output["waveform"] = to_waveform(output["mel"], vocoder, denoiser)
339
+ t = (dt.datetime.now() - start_t).total_seconds()
340
+ rtf_w = t * 22050 / (output["waveform"].shape[-1])
341
+ print(f"[🍵-Batch: {i}] Matcha-TTS RTF: {output['rtf']:.4f}")
342
+ print(f"[🍵-Batch: {i}] Matcha-TTS + VOCODER RTF: {rtf_w:.4f}")
343
+ total_rtf.append(output["rtf"])
344
+ total_rtf_w.append(rtf_w)
345
+ for j in range(output["mel"].shape[0]):
346
+ base_name = f"utterance_{j:03d}_speaker_{args.spk:03d}" if args.spk is not None else f"utterance_{j:03d}"
347
+ length = output["mel_lengths"][j]
348
+ new_dict = {"mel": output["mel"][j][:, :length], "waveform": output["waveform"][j][: length * 256]}
349
+ location = save_to_folder(base_name, new_dict, args.output_folder)
350
+ print(f"[🍵-{j}] Waveform saved: {location}")
351
+
352
+ print("".join(["="] * 100))
353
+ print(f"[🍵] Average Matcha-TTS RTF: {np.mean(total_rtf):.4f} ± {np.std(total_rtf)}")
354
+ print(f"[🍵] Average Matcha-TTS + VOCODER RTF: {np.mean(total_rtf_w):.4f} ± {np.std(total_rtf_w)}")
355
+ print("[🍵] Enjoy the freshly whisked 🍵 Matcha-TTS!")
356
+
357
+
358
+ def unbatched_synthesis(args, device, model, vocoder, denoiser, texts, spk):
359
+ total_rtf = []
360
+ total_rtf_w = []
361
+ for i, text in enumerate(texts):
362
+ i = i + 1
363
+ base_name = f"utterance_{i:03d}_speaker_{args.spk:03d}" if args.spk is not None else f"utterance_{i:03d}"
364
+
365
+ print("".join(["="] * 100))
366
+ text = text.strip()
367
+ text_processed = process_text(i, text, device)
368
+
369
+ print(f"[🍵] Whisking Matcha-T(ea)TS for: {i}")
370
+ start_t = dt.datetime.now()
371
+ output = model.synthesise(
372
+ text_processed["x"],
373
+ text_processed["x_lengths"],
374
+ n_timesteps=args.steps,
375
+ temperature=args.temperature,
376
+ spks=spk,
377
+ length_scale=args.speaking_rate,
378
+ )
379
+ output["waveform"] = to_waveform(output["mel"], vocoder, denoiser)
380
+ # RTF with HiFiGAN
381
+ t = (dt.datetime.now() - start_t).total_seconds()
382
+ rtf_w = t * 22050 / (output["waveform"].shape[-1])
383
+ print(f"[🍵-{i}] Matcha-TTS RTF: {output['rtf']:.4f}")
384
+ print(f"[🍵-{i}] Matcha-TTS + VOCODER RTF: {rtf_w:.4f}")
385
+ total_rtf.append(output["rtf"])
386
+ total_rtf_w.append(rtf_w)
387
+
388
+ location = save_to_folder(base_name, output, args.output_folder)
389
+ print(f"[+] Waveform saved: {location}")
390
+
391
+ print("".join(["="] * 100))
392
+ print(f"[🍵] Average Matcha-TTS RTF: {np.mean(total_rtf):.4f} ± {np.std(total_rtf)}")
393
+ print(f"[🍵] Average Matcha-TTS + VOCODER RTF: {np.mean(total_rtf_w):.4f} ± {np.std(total_rtf_w)}")
394
+ print("[🍵] Enjoy the freshly whisked 🍵 Matcha-TTS!")
395
+
396
+
397
+ def print_config(args):
398
+ print("[!] Configurations: ")
399
+ print(f"\t- Model: {args.model}")
400
+ print(f"\t- Vocoder: {args.vocoder}")
401
+ print(f"\t- Temperature: {args.temperature}")
402
+ print(f"\t- Speaking rate: {args.speaking_rate}")
403
+ print(f"\t- Number of ODE steps: {args.steps}")
404
+ print(f"\t- Speaker: {args.spk}")
405
+
406
+
407
+ def get_device(args):
408
+ if torch.cuda.is_available() and not args.cpu:
409
+ print("[+] GPU Available! Using GPU")
410
+ device = torch.device("cuda")
411
+ else:
412
+ print("[-] GPU not available or forced CPU run! Using CPU")
413
+ device = torch.device("cpu")
414
+ return device
415
+
416
+
417
+ if __name__ == "__main__":
418
+ cli()
File without changes
@@ -0,0 +1,28 @@
1
+ v1 = {
2
+ "resblock": "1",
3
+ "num_gpus": 0,
4
+ "batch_size": 16,
5
+ "learning_rate": 0.0004,
6
+ "adam_b1": 0.8,
7
+ "adam_b2": 0.99,
8
+ "lr_decay": 0.999,
9
+ "seed": 1234,
10
+ "upsample_rates": [8, 8, 2, 2],
11
+ "upsample_kernel_sizes": [16, 16, 4, 4],
12
+ "upsample_initial_channel": 512,
13
+ "resblock_kernel_sizes": [3, 7, 11],
14
+ "resblock_dilation_sizes": [[1, 3, 5], [1, 3, 5], [1, 3, 5]],
15
+ "resblock_initial_channel": 256,
16
+ "segment_size": 8192,
17
+ "num_mels": 80,
18
+ "num_freq": 1025,
19
+ "n_fft": 1024,
20
+ "hop_size": 256,
21
+ "win_size": 1024,
22
+ "sampling_rate": 22050,
23
+ "fmin": 0,
24
+ "fmax": 8000,
25
+ "fmax_loss": None,
26
+ "num_workers": 4,
27
+ "dist_config": {"dist_backend": "nccl", "dist_url": "tcp://localhost:54321", "world_size": 1},
28
+ }
@@ -0,0 +1,64 @@
1
+ # Code modified from Rafael Valle's implementation https://github.com/NVIDIA/waveglow/blob/5bc2a53e20b3b533362f974cfa1ea0267ae1c2b1/denoiser.py
2
+
3
+ """Waveglow style denoiser can be used to remove the artifacts from the HiFiGAN generated audio."""
4
+ import torch
5
+
6
+
7
+ class Denoiser(torch.nn.Module):
8
+ """Removes model bias from audio produced with waveglow"""
9
+
10
+ def __init__(self, vocoder, filter_length=1024, n_overlap=4, win_length=1024, mode="zeros"):
11
+ super().__init__()
12
+ self.filter_length = filter_length
13
+ self.hop_length = int(filter_length / n_overlap)
14
+ self.win_length = win_length
15
+
16
+ dtype, device = next(vocoder.parameters()).dtype, next(vocoder.parameters()).device
17
+ self.device = device
18
+ if mode == "zeros":
19
+ mel_input = torch.zeros((1, 80, 88), dtype=dtype, device=device)
20
+ elif mode == "normal":
21
+ mel_input = torch.randn((1, 80, 88), dtype=dtype, device=device)
22
+ else:
23
+ raise Exception(f"Mode {mode} if not supported")
24
+
25
+ def stft_fn(audio, n_fft, hop_length, win_length, window):
26
+ spec = torch.stft(
27
+ audio,
28
+ n_fft=n_fft,
29
+ hop_length=hop_length,
30
+ win_length=win_length,
31
+ window=window,
32
+ return_complex=True,
33
+ )
34
+ spec = torch.view_as_real(spec)
35
+ return torch.sqrt(spec.pow(2).sum(-1)), torch.atan2(spec[..., -1], spec[..., 0])
36
+
37
+ self.stft = lambda x: stft_fn(
38
+ audio=x,
39
+ n_fft=self.filter_length,
40
+ hop_length=self.hop_length,
41
+ win_length=self.win_length,
42
+ window=torch.hann_window(self.win_length, device=device),
43
+ )
44
+ self.istft = lambda x, y: torch.istft(
45
+ torch.complex(x * torch.cos(y), x * torch.sin(y)),
46
+ n_fft=self.filter_length,
47
+ hop_length=self.hop_length,
48
+ win_length=self.win_length,
49
+ window=torch.hann_window(self.win_length, device=device),
50
+ )
51
+
52
+ with torch.no_grad():
53
+ bias_audio = vocoder(mel_input).float().squeeze(0)
54
+ bias_spec, _ = self.stft(bias_audio)
55
+
56
+ self.register_buffer("bias_spec", bias_spec[:, :, 0][:, :, None])
57
+
58
+ @torch.inference_mode()
59
+ def forward(self, audio, strength=0.0005):
60
+ audio_spec, audio_angles = self.stft(audio)
61
+ audio_spec_denoised = audio_spec - self.bias_spec.to(audio.device) * strength
62
+ audio_spec_denoised = torch.clamp(audio_spec_denoised, 0.0)
63
+ audio_denoised = self.istft(audio_spec_denoised, audio_angles)
64
+ return audio_denoised
matcha/hifigan/env.py ADDED
@@ -0,0 +1,17 @@
1
+ """ from https://github.com/jik876/hifi-gan """
2
+
3
+ import os
4
+ import shutil
5
+
6
+
7
+ class AttrDict(dict):
8
+ def __init__(self, *args, **kwargs):
9
+ super().__init__(*args, **kwargs)
10
+ self.__dict__ = self
11
+
12
+
13
+ def build_env(config, config_name, path):
14
+ t_path = os.path.join(path, config_name)
15
+ if config != t_path:
16
+ os.makedirs(path, exist_ok=True)
17
+ shutil.copyfile(config, os.path.join(path, config_name))