Hecheng0625 commited on
Commit
7ee3434
1 Parent(s): c968fc3

Upload 61 files

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitattributes +1 -0
  2. app.py +355 -0
  3. text/__init__.py +79 -0
  4. text/cleaners.py +98 -0
  5. text/cmudict.py +145 -0
  6. text/g2p.py +38 -0
  7. text/g2p_module.py +230 -0
  8. text/lexicon/librispeech-lexicon.txt +0 -0
  9. text/lexicon/pinyin-lexicon-r.txt +4120 -0
  10. text/numbers.py +77 -0
  11. text/pinyin.py +218 -0
  12. text/symbol_table.py +292 -0
  13. text/symbols.py +34 -0
  14. text/text_token_collation.py +123 -0
  15. utils/HyperParams/__init__.py +6 -0
  16. utils/HyperParams/hps.py +43 -0
  17. utils/__init__.py +0 -0
  18. utils/audio.py +74 -0
  19. utils/audio_slicer.py +476 -0
  20. utils/cut_by_vad.py +105 -0
  21. utils/data_utils.py +588 -0
  22. utils/distribution.py +270 -0
  23. utils/dsp.py +97 -0
  24. utils/duration.py +86 -0
  25. utils/f0.py +275 -0
  26. utils/hparam.py +659 -0
  27. utils/hubert.py +155 -0
  28. utils/io.py +182 -0
  29. utils/io_optim.py +123 -0
  30. utils/mel.py +280 -0
  31. utils/mert.py +139 -0
  32. utils/mfa_prepare.py +116 -0
  33. utils/model_summary.py +74 -0
  34. utils/prompt_preparer.py +68 -0
  35. utils/ssim.py +80 -0
  36. utils/stft.py +278 -0
  37. utils/symbol_table.py +317 -0
  38. utils/tokenizer.py +150 -0
  39. utils/topk_sampling.py +89 -0
  40. utils/trainer_utils.py +16 -0
  41. utils/util.py +687 -0
  42. utils/whisper_transcription.py +122 -0
  43. utils/world.py +92 -0
  44. visualization/SingVisio/System_Introduction_of_SingVisio_V2.pdf +3 -0
  45. visualization/SingVisio/webpage/Dockerfile +23 -0
  46. visualization/SingVisio/webpage/README.md +126 -0
  47. visualization/SingVisio/webpage/config/default.json +407 -0
  48. visualization/SingVisio/webpage/img/difference_bar.jpg +0 -0
  49. visualization/SingVisio/webpage/img/syllable.png +0 -0
  50. visualization/SingVisio/webpage/index.html +390 -0
.gitattributes CHANGED
@@ -37,3 +37,4 @@ imgs/vocoder/gan/MSSBCQTD.png filter=lfs diff=lfs merge=lfs -text
37
  models/codec/facodec/modules/JDC/bst.t7 filter=lfs diff=lfs merge=lfs -text
38
  models/tts/maskgct/g2p/sources/chinese_lexicon.txt filter=lfs diff=lfs merge=lfs -text
39
  models/tts/maskgct/wav/prompt.wav filter=lfs diff=lfs merge=lfs -text
 
 
37
  models/codec/facodec/modules/JDC/bst.t7 filter=lfs diff=lfs merge=lfs -text
38
  models/tts/maskgct/g2p/sources/chinese_lexicon.txt filter=lfs diff=lfs merge=lfs -text
39
  models/tts/maskgct/wav/prompt.wav filter=lfs diff=lfs merge=lfs -text
40
+ visualization/SingVisio/System_Introduction_of_SingVisio_V2.pdf filter=lfs diff=lfs merge=lfs -text
app.py ADDED
@@ -0,0 +1,355 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import torch
3
+ import safetensors
4
+ from huggingface_hub import hf_hub_download
5
+ import soundfile as sf
6
+
7
+ import numpy as np
8
+ import librosa
9
+ from models.codec.kmeans.repcodec_model import RepCodec
10
+ from models.tts.maskgct.maskgct_s2a import MaskGCT_S2A
11
+ from models.tts.maskgct.maskgct_t2s import MaskGCT_T2S
12
+ from models.codec.amphion_codec.codec import CodecEncoder, CodecDecoder
13
+ from transformers import Wav2Vec2BertModel
14
+ from utils.util import load_config
15
+ from models.tts.maskgct.g2p.g2p_generation import g2p, chn_eng_g2p
16
+
17
+ from transformers import SeamlessM4TFeatureExtractor
18
+
19
+ processor = SeamlessM4TFeatureExtractor.from_pretrained("facebook/w2v-bert-2.0")
20
+
21
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
22
+
23
+
24
+ def g2p_(text, language):
25
+ if language in ["zh", "en"]:
26
+ return chn_eng_g2p(text)
27
+ else:
28
+ return g2p(text, sentence=None, language=language)
29
+
30
+
31
+ def build_t2s_model(cfg, device):
32
+ t2s_model = MaskGCT_T2S(cfg=cfg)
33
+ t2s_model.eval()
34
+ t2s_model.to(device)
35
+ return t2s_model
36
+
37
+
38
+ def build_s2a_model(cfg, device):
39
+ soundstorm_model = MaskGCT_S2A(cfg=cfg)
40
+ soundstorm_model.eval()
41
+ soundstorm_model.to(device)
42
+ return soundstorm_model
43
+
44
+
45
+ def build_semantic_model(device):
46
+ semantic_model = Wav2Vec2BertModel.from_pretrained("facebook/w2v-bert-2.0")
47
+ semantic_model.eval()
48
+ semantic_model.to(device)
49
+ stat_mean_var = torch.load("./models/tts/maskgct/ckpt/wav2vec2bert_stats.pt")
50
+ semantic_mean = stat_mean_var["mean"]
51
+ semantic_std = torch.sqrt(stat_mean_var["var"])
52
+ semantic_mean = semantic_mean.to(device)
53
+ semantic_std = semantic_std.to(device)
54
+ return semantic_model, semantic_mean, semantic_std
55
+
56
+
57
+ def build_semantic_codec(cfg, device):
58
+ semantic_codec = RepCodec(cfg=cfg)
59
+ semantic_codec.eval()
60
+ semantic_codec.to(device)
61
+ return semantic_codec
62
+
63
+
64
+ def build_acoustic_codec(cfg, device):
65
+ codec_encoder = CodecEncoder(cfg=cfg.encoder)
66
+ codec_decoder = CodecDecoder(cfg=cfg.decoder)
67
+ codec_encoder.eval()
68
+ codec_decoder.eval()
69
+ codec_encoder.to(device)
70
+ codec_decoder.to(device)
71
+ return codec_encoder, codec_decoder
72
+
73
+
74
+ @torch.no_grad()
75
+ def extract_features(speech, processor):
76
+ inputs = processor(speech, sampling_rate=16000, return_tensors="pt")
77
+ input_features = inputs["input_features"][0]
78
+ attention_mask = inputs["attention_mask"][0]
79
+ return input_features, attention_mask
80
+
81
+
82
+ @torch.no_grad()
83
+ def extract_semantic_code(semantic_mean, semantic_std, input_features, attention_mask):
84
+ vq_emb = semantic_model(
85
+ input_features=input_features,
86
+ attention_mask=attention_mask,
87
+ output_hidden_states=True,
88
+ )
89
+ feat = vq_emb.hidden_states[17] # (B, T, C)
90
+ feat = (feat - semantic_mean.to(feat)) / semantic_std.to(feat)
91
+
92
+ semantic_code, rec_feat = semantic_codec.quantize(feat) # (B, T)
93
+ return semantic_code, rec_feat
94
+
95
+
96
+ @torch.no_grad()
97
+ def extract_acoustic_code(speech):
98
+ vq_emb = codec_encoder(speech.unsqueeze(1))
99
+ _, vq, _, _, _ = codec_decoder.quantizer(vq_emb)
100
+ acoustic_code = vq.permute(1, 2, 0)
101
+ return acoustic_code
102
+
103
+
104
+ @torch.no_grad()
105
+ def text2semantic(
106
+ device,
107
+ prompt_speech,
108
+ prompt_text,
109
+ prompt_language,
110
+ target_text,
111
+ target_language,
112
+ target_len=None,
113
+ n_timesteps=50,
114
+ cfg=2.5,
115
+ rescale_cfg=0.75,
116
+ ):
117
+
118
+ prompt_phone_id = g2p_(prompt_text, prompt_language)[1]
119
+
120
+ target_phone_id = g2p_(target_text, target_language)[1]
121
+
122
+ if target_len is None:
123
+ target_len = int(
124
+ (len(prompt_speech) * len(target_phone_id) / len(prompt_phone_id))
125
+ / 16000
126
+ * 50
127
+ )
128
+ else:
129
+ target_len = int(target_len * 50)
130
+
131
+ prompt_phone_id = torch.tensor(prompt_phone_id, dtype=torch.long).to(device)
132
+ target_phone_id = torch.tensor(target_phone_id, dtype=torch.long).to(device)
133
+
134
+ phone_id = torch.cat([prompt_phone_id, target_phone_id])
135
+
136
+ input_fetures, attention_mask = extract_features(prompt_speech, processor)
137
+ input_fetures = input_fetures.unsqueeze(0).to(device)
138
+ attention_mask = attention_mask.unsqueeze(0).to(device)
139
+ semantic_code, _ = extract_semantic_code(
140
+ semantic_mean, semantic_std, input_fetures, attention_mask
141
+ )
142
+
143
+ predict_semantic = t2s_model.reverse_diffusion(
144
+ semantic_code[:, :],
145
+ target_len,
146
+ phone_id.unsqueeze(0),
147
+ n_timesteps=n_timesteps,
148
+ cfg=cfg,
149
+ rescale_cfg=rescale_cfg,
150
+ )
151
+
152
+ combine_semantic_code = torch.cat([semantic_code[:, :], predict_semantic], dim=-1)
153
+ prompt_semantic_code = semantic_code
154
+
155
+ return combine_semantic_code, prompt_semantic_code
156
+
157
+
158
+ @torch.no_grad()
159
+ def semantic2acoustic(
160
+ device,
161
+ combine_semantic_code,
162
+ acoustic_code,
163
+ n_timesteps=[25, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
164
+ cfg=2.5,
165
+ rescale_cfg=0.75,
166
+ ):
167
+
168
+ semantic_code = combine_semantic_code
169
+
170
+ cond = s2a_model_1layer.cond_emb(semantic_code)
171
+ prompt = acoustic_code[:, :, :]
172
+ predict_1layer = s2a_model_1layer.reverse_diffusion(
173
+ cond=cond,
174
+ prompt=prompt,
175
+ temp=1.5,
176
+ filter_thres=0.98,
177
+ n_timesteps=n_timesteps[:1],
178
+ cfg=cfg,
179
+ rescale_cfg=rescale_cfg,
180
+ )
181
+
182
+ cond = s2a_model_full.cond_emb(semantic_code)
183
+ prompt = acoustic_code[:, :, :]
184
+ predict_full = s2a_model_full.reverse_diffusion(
185
+ cond=cond,
186
+ prompt=prompt,
187
+ temp=1.5,
188
+ filter_thres=0.98,
189
+ n_timesteps=n_timesteps,
190
+ cfg=cfg,
191
+ rescale_cfg=rescale_cfg,
192
+ gt_code=predict_1layer,
193
+ )
194
+
195
+ vq_emb = codec_decoder.vq2emb(predict_full.permute(2, 0, 1), n_quantizers=12)
196
+ recovered_audio = codec_decoder(vq_emb)
197
+ prompt_vq_emb = codec_decoder.vq2emb(prompt.permute(2, 0, 1), n_quantizers=12)
198
+ recovered_prompt_audio = codec_decoder(prompt_vq_emb)
199
+ recovered_prompt_audio = recovered_prompt_audio[0][0].cpu().numpy()
200
+ recovered_audio = recovered_audio[0][0].cpu().numpy()
201
+ combine_audio = np.concatenate([recovered_prompt_audio, recovered_audio])
202
+
203
+ return combine_audio, recovered_audio
204
+
205
+
206
+ # Load the model and checkpoints
207
+ def load_models():
208
+ cfg_path = "./models/tts/maskgct/config/maskgct.json"
209
+
210
+ cfg = load_config(cfg_path)
211
+ semantic_model, semantic_mean, semantic_std = build_semantic_model(device)
212
+ semantic_codec = build_semantic_codec(cfg.model.semantic_codec, device)
213
+ codec_encoder, codec_decoder = build_acoustic_codec(
214
+ cfg.model.acoustic_codec, device
215
+ )
216
+ t2s_model = build_t2s_model(cfg.model.t2s_model, device)
217
+ s2a_model_1layer = build_s2a_model(cfg.model.s2a_model.s2a_1layer, device)
218
+ s2a_model_full = build_s2a_model(cfg.model.s2a_model.s2a_full, device)
219
+
220
+ # Download checkpoints
221
+ semantic_code_ckpt = hf_hub_download(
222
+ "amphion/MaskGCT", filename="semantic_codec/model.safetensors"
223
+ )
224
+ codec_encoder_ckpt = hf_hub_download(
225
+ "amphion/MaskGCT", filename="acoustic_codec/model.safetensors"
226
+ )
227
+ codec_decoder_ckpt = hf_hub_download(
228
+ "amphion/MaskGCT", filename="acoustic_codec/model_1.safetensors"
229
+ )
230
+ t2s_model_ckpt = hf_hub_download(
231
+ "amphion/MaskGCT", filename="t2s_model/model.safetensors"
232
+ )
233
+ s2a_1layer_ckpt = hf_hub_download(
234
+ "amphion/MaskGCT", filename="s2a_model/s2a_model_1layer/model.safetensors"
235
+ )
236
+ s2a_full_ckpt = hf_hub_download(
237
+ "amphion/MaskGCT", filename="s2a_model/s2a_model_full/model.safetensors"
238
+ )
239
+
240
+ safetensors.torch.load_model(semantic_codec, semantic_code_ckpt)
241
+ safetensors.torch.load_model(codec_encoder, codec_encoder_ckpt)
242
+ safetensors.torch.load_model(codec_decoder, codec_decoder_ckpt)
243
+ safetensors.torch.load_model(t2s_model, t2s_model_ckpt)
244
+ safetensors.torch.load_model(s2a_model_1layer, s2a_1layer_ckpt)
245
+ safetensors.torch.load_model(s2a_model_full, s2a_full_ckpt)
246
+
247
+ return (
248
+ semantic_model,
249
+ semantic_mean,
250
+ semantic_std,
251
+ semantic_codec,
252
+ codec_encoder,
253
+ codec_decoder,
254
+ t2s_model,
255
+ s2a_model_1layer,
256
+ s2a_model_full,
257
+ )
258
+
259
+
260
+ @torch.no_grad()
261
+ def maskgct_inference(
262
+ prompt_speech_path,
263
+ prompt_text,
264
+ target_text,
265
+ language="en",
266
+ target_language="en",
267
+ target_len=None,
268
+ n_timesteps=25,
269
+ cfg=2.5,
270
+ rescale_cfg=0.75,
271
+ n_timesteps_s2a=[25, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
272
+ cfg_s2a=2.5,
273
+ rescale_cfg_s2a=0.75,
274
+ device=torch.device("cuda:5"),
275
+ ):
276
+ speech_16k = librosa.load(prompt_speech_path, sr=16000)[0]
277
+ speech = librosa.load(prompt_speech_path, sr=24000)[0]
278
+
279
+ combine_semantic_code, _ = text2semantic(
280
+ device,
281
+ speech_16k,
282
+ prompt_text,
283
+ language,
284
+ target_text,
285
+ target_language,
286
+ target_len,
287
+ n_timesteps,
288
+ cfg,
289
+ rescale_cfg,
290
+ )
291
+ acoustic_code = extract_acoustic_code(torch.tensor(speech).unsqueeze(0).to(device))
292
+ _, recovered_audio = semantic2acoustic(
293
+ device,
294
+ combine_semantic_code,
295
+ acoustic_code,
296
+ n_timesteps=n_timesteps_s2a,
297
+ cfg=cfg_s2a,
298
+ rescale_cfg=rescale_cfg_s2a,
299
+ )
300
+
301
+ return recovered_audio
302
+
303
+
304
+ @torch.no_grad()
305
+ def inference(
306
+ prompt_wav,
307
+ prompt_text,
308
+ target_text,
309
+ target_len,
310
+ n_timesteps,
311
+ language,
312
+ target_language,
313
+ ):
314
+ save_path = "./output/output.wav"
315
+ os.makedirs("./output", exist_ok=True)
316
+ recovered_audio = maskgct_inference(
317
+ prompt_wav,
318
+ prompt_text,
319
+ target_text,
320
+ language,
321
+ target_language,
322
+ target_len=target_len,
323
+ n_timesteps=int(n_timesteps),
324
+ device=device,
325
+ )
326
+ sf.write(save_path, recovered_audio, 24000)
327
+ return save_path
328
+
329
+
330
+ # Language list
331
+ language_list = ["en", "zh", "ja", "ko", "fr", "de"]
332
+
333
+ # Gradio interface
334
+ iface = gr.Interface(
335
+ fn=inference,
336
+ inputs=[
337
+ gr.Audio(label="Upload Prompt Wav", type="filepath"),
338
+ gr.Textbox(label="Prompt Text"),
339
+ gr.Textbox(label="Target Text"),
340
+ gr.Number(
341
+ label="Target Duration (in seconds)", value=None
342
+ ), # Removed 'optional=True'
343
+ gr.Slider(
344
+ label="Number of Timesteps", minimum=15, maximum=100, value=25, step=1
345
+ ),
346
+ gr.Dropdown(label="Language", choices=language_list, value="en"),
347
+ gr.Dropdown(label="Target Language", choices=language_list, value="en"),
348
+ ],
349
+ outputs=gr.Audio(label="Generated Audio"),
350
+ title="MaskGCT TTS Demo",
351
+ description="Generate speech from text using the MaskGCT model.",
352
+ )
353
+
354
+ # Launch the interface
355
+ iface.launch(allowed_paths=["./output"])
text/__init__.py ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023 Amphion.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ """ This code is modified from https://github.com/keithito/tacotron """
7
+ import re
8
+ from text import cleaners
9
+ from text.symbols import symbols
10
+
11
+
12
+ # Mappings from symbol to numeric ID and vice versa:
13
+ _symbol_to_id = {s: i for i, s in enumerate(symbols)}
14
+ _id_to_symbol = {i: s for i, s in enumerate(symbols)}
15
+
16
+ # Regular expression matching text enclosed in curly braces:
17
+ _curly_re = re.compile(r"(.*?)\{(.+?)\}(.*)")
18
+
19
+
20
+ def text_to_sequence(text, cleaner_names):
21
+ """Converts a string of text to a sequence of IDs corresponding to the symbols in the text.
22
+
23
+ The text can optionally have ARPAbet sequences enclosed in curly braces embedded
24
+ in it. For example, "Turn left on {HH AW1 S S T AH0 N} Street."
25
+
26
+ Args:
27
+ text: string to convert to a sequence
28
+ cleaner_names: names of the cleaner functions to run the text through
29
+
30
+ Returns:
31
+ List of integers corresponding to the symbols in the text
32
+ """
33
+ sequence = []
34
+
35
+ # Check for curly braces and treat their contents as ARPAbet:
36
+ while len(text):
37
+ m = _curly_re.match(text)
38
+
39
+ if not m:
40
+ sequence += _symbols_to_sequence(_clean_text(text, cleaner_names))
41
+ break
42
+ sequence += _symbols_to_sequence(_clean_text(m.group(1), cleaner_names))
43
+ sequence += _arpabet_to_sequence(m.group(2))
44
+ text = m.group(3)
45
+ return sequence
46
+
47
+
48
+ def sequence_to_text(sequence):
49
+ """Converts a sequence of IDs back to a string"""
50
+ result = ""
51
+ for symbol_id in sequence:
52
+ if symbol_id in _id_to_symbol:
53
+ s = _id_to_symbol[symbol_id]
54
+ # Enclose ARPAbet back in curly braces:
55
+ if len(s) > 1 and s[0] == "@":
56
+ s = "{%s}" % s[1:]
57
+ result += s
58
+ return result.replace("}{", " ")
59
+
60
+
61
+ def _clean_text(text, cleaner_names):
62
+ for name in cleaner_names:
63
+ cleaner = getattr(cleaners, name)
64
+ if not cleaner:
65
+ raise Exception("Unknown cleaner: %s" % name)
66
+ text = cleaner(text)
67
+ return text
68
+
69
+
70
+ def _symbols_to_sequence(symbols):
71
+ return [_symbol_to_id[s] for s in symbols if _should_keep_symbol(s)]
72
+
73
+
74
+ def _arpabet_to_sequence(text):
75
+ return _symbols_to_sequence(["@" + s for s in text.split()])
76
+
77
+
78
+ def _should_keep_symbol(s):
79
+ return s in _symbol_to_id and s != "_" and s != "~"
text/cleaners.py ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023 Amphion.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ """ This code is modified from https://github.com/keithito/tacotron """
7
+
8
+ """
9
+ Cleaners are transformations that run over the input text at both training and eval time.
10
+
11
+ Cleaners can be selected by passing a comma-delimited list of cleaner names as the "cleaners"
12
+ hyperparameter. Some cleaners are English-specific. You'll typically want to use:
13
+ 1. "english_cleaners" for English text
14
+ 2. "transliteration_cleaners" for non-English text that can be transliterated to ASCII using
15
+ the Unidecode library (https://pypi.python.org/pypi/Unidecode)
16
+ 3. "basic_cleaners" if you do not want to transliterate (in this case, you should also update
17
+ the symbols in symbols.py to match your data).
18
+ """
19
+
20
+
21
+ # Regular expression matching whitespace:
22
+ import re
23
+ from unidecode import unidecode
24
+ from .numbers import normalize_numbers
25
+
26
+ _whitespace_re = re.compile(r"\s+")
27
+
28
+ # List of (regular expression, replacement) pairs for abbreviations:
29
+ _abbreviations = [
30
+ (re.compile("\\b%s\\." % x[0], re.IGNORECASE), x[1])
31
+ for x in [
32
+ ("mrs", "misess"),
33
+ ("mr", "mister"),
34
+ ("dr", "doctor"),
35
+ ("st", "saint"),
36
+ ("co", "company"),
37
+ ("jr", "junior"),
38
+ ("maj", "major"),
39
+ ("gen", "general"),
40
+ ("drs", "doctors"),
41
+ ("rev", "reverend"),
42
+ ("lt", "lieutenant"),
43
+ ("hon", "honorable"),
44
+ ("sgt", "sergeant"),
45
+ ("capt", "captain"),
46
+ ("esq", "esquire"),
47
+ ("ltd", "limited"),
48
+ ("col", "colonel"),
49
+ ("ft", "fort"),
50
+ ]
51
+ ]
52
+
53
+
54
+ def expand_abbreviations(text):
55
+ for regex, replacement in _abbreviations:
56
+ text = re.sub(regex, replacement, text)
57
+ return text
58
+
59
+
60
+ def expand_numbers(text):
61
+ return normalize_numbers(text)
62
+
63
+
64
+ def lowercase(text):
65
+ return text.lower()
66
+
67
+
68
+ def collapse_whitespace(text):
69
+ return re.sub(_whitespace_re, " ", text)
70
+
71
+
72
+ def convert_to_ascii(text):
73
+ return unidecode(text)
74
+
75
+
76
+ def basic_cleaners(text):
77
+ """Basic pipeline that lowercases and collapses whitespace without transliteration."""
78
+ text = lowercase(text)
79
+ text = collapse_whitespace(text)
80
+ return text
81
+
82
+
83
+ def transliteration_cleaners(text):
84
+ """Pipeline for non-English text that transliterates to ASCII."""
85
+ text = convert_to_ascii(text)
86
+ text = lowercase(text)
87
+ text = collapse_whitespace(text)
88
+ return text
89
+
90
+
91
+ def english_cleaners(text):
92
+ """Pipeline for English text, including number and abbreviation expansion."""
93
+ text = convert_to_ascii(text)
94
+ text = lowercase(text)
95
+ text = expand_numbers(text)
96
+ text = expand_abbreviations(text)
97
+ text = collapse_whitespace(text)
98
+ return text
text/cmudict.py ADDED
@@ -0,0 +1,145 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023 Amphion.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ """ This code is modified from https://github.com/keithito/tacotron """
7
+
8
+ import re
9
+
10
+
11
+ valid_symbols = [
12
+ "AA",
13
+ "AA0",
14
+ "AA1",
15
+ "AA2",
16
+ "AE",
17
+ "AE0",
18
+ "AE1",
19
+ "AE2",
20
+ "AH",
21
+ "AH0",
22
+ "AH1",
23
+ "AH2",
24
+ "AO",
25
+ "AO0",
26
+ "AO1",
27
+ "AO2",
28
+ "AW",
29
+ "AW0",
30
+ "AW1",
31
+ "AW2",
32
+ "AY",
33
+ "AY0",
34
+ "AY1",
35
+ "AY2",
36
+ "B",
37
+ "CH",
38
+ "D",
39
+ "DH",
40
+ "EH",
41
+ "EH0",
42
+ "EH1",
43
+ "EH2",
44
+ "ER",
45
+ "ER0",
46
+ "ER1",
47
+ "ER2",
48
+ "EY",
49
+ "EY0",
50
+ "EY1",
51
+ "EY2",
52
+ "F",
53
+ "G",
54
+ "HH",
55
+ "IH",
56
+ "IH0",
57
+ "IH1",
58
+ "IH2",
59
+ "IY",
60
+ "IY0",
61
+ "IY1",
62
+ "IY2",
63
+ "JH",
64
+ "K",
65
+ "L",
66
+ "M",
67
+ "N",
68
+ "NG",
69
+ "OW",
70
+ "OW0",
71
+ "OW1",
72
+ "OW2",
73
+ "OY",
74
+ "OY0",
75
+ "OY1",
76
+ "OY2",
77
+ "P",
78
+ "R",
79
+ "S",
80
+ "SH",
81
+ "T",
82
+ "TH",
83
+ "UH",
84
+ "UH0",
85
+ "UH1",
86
+ "UH2",
87
+ "UW",
88
+ "UW0",
89
+ "UW1",
90
+ "UW2",
91
+ "V",
92
+ "W",
93
+ "Y",
94
+ "Z",
95
+ "ZH",
96
+ ]
97
+
98
+ _valid_symbol_set = set(valid_symbols)
99
+
100
+
101
+ class CMUDict:
102
+ """Thin wrapper around CMUDict data. http://www.speech.cs.cmu.edu/cgi-bin/cmudict"""
103
+
104
+ def __init__(self, file_or_path, keep_ambiguous=True):
105
+ if isinstance(file_or_path, str):
106
+ with open(file_or_path, encoding="latin-1") as f:
107
+ entries = _parse_cmudict(f)
108
+ else:
109
+ entries = _parse_cmudict(file_or_path)
110
+ if not keep_ambiguous:
111
+ entries = {word: pron for word, pron in entries.items() if len(pron) == 1}
112
+ self._entries = entries
113
+
114
+ def __len__(self):
115
+ return len(self._entries)
116
+
117
+ def lookup(self, word):
118
+ """Returns list of ARPAbet pronunciations of the given word."""
119
+ return self._entries.get(word.upper())
120
+
121
+
122
+ _alt_re = re.compile(r"\([0-9]+\)")
123
+
124
+
125
+ def _parse_cmudict(file):
126
+ cmudict = {}
127
+ for line in file:
128
+ if len(line) and (line[0] >= "A" and line[0] <= "Z" or line[0] == "'"):
129
+ parts = line.split(" ")
130
+ word = re.sub(_alt_re, "", parts[0])
131
+ pronunciation = _get_pronunciation(parts[1])
132
+ if pronunciation:
133
+ if word in cmudict:
134
+ cmudict[word].append(pronunciation)
135
+ else:
136
+ cmudict[word] = [pronunciation]
137
+ return cmudict
138
+
139
+
140
+ def _get_pronunciation(s):
141
+ parts = s.strip().split(" ")
142
+ for part in parts:
143
+ if part not in _valid_symbol_set:
144
+ return None
145
+ return " ".join(parts)
text/g2p.py ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023 Amphion.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ import re
7
+ from g2p_en import G2p
8
+ from string import punctuation
9
+
10
+
11
+ def read_lexicon(lex_path):
12
+ lexicon = {}
13
+ with open(lex_path) as f:
14
+ for line in f:
15
+ temp = re.split(r"\s+", line.strip("\n"))
16
+ word = temp[0]
17
+ phones = temp[1:]
18
+ if word.lower() not in lexicon:
19
+ lexicon[word.lower()] = phones
20
+ return lexicon
21
+
22
+
23
+ def preprocess_english(text, lexicon):
24
+ text = text.rstrip(punctuation)
25
+
26
+ g2p = G2p()
27
+ phones = []
28
+ words = re.split(r"([,;.\-\?\!\s+])", text)
29
+ for w in words:
30
+ if w.lower() in lexicon:
31
+ phones += lexicon[w.lower()]
32
+ else:
33
+ phones += list(filter(lambda p: p != " ", g2p(w)))
34
+ phones = "}{".join(phones)
35
+ phones = re.sub(r"\{[^\w\s]?\}", "{sp}", phones)
36
+ phones = phones.replace("}{", " ")
37
+
38
+ return phones
text/g2p_module.py ADDED
@@ -0,0 +1,230 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023 Amphion.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+
7
+ import re
8
+ from g2p_en import G2p
9
+ from string import punctuation
10
+ from typing import Any, Dict, List, Optional, Pattern, Union
11
+
12
+ from phonemizer.backend import EspeakBackend
13
+ from phonemizer.backend.espeak.language_switch import LanguageSwitch
14
+ from phonemizer.backend.espeak.words_mismatch import WordMismatch
15
+ from phonemizer.punctuation import Punctuation
16
+ from phonemizer.separator import Separator
17
+
18
+ try:
19
+ from pypinyin import Style, pinyin
20
+ from pypinyin.style._utils import get_finals, get_initials
21
+ except Exception:
22
+ pass
23
+
24
+
25
+ # This code is modified from
26
+ # https://github.com/lifeiteng/vall-e/blob/9c69096d603ce13174fb5cb025f185e2e9b36ac7/valle/data/tokenizer.py
27
+
28
+
29
+ class PypinyinBackend:
30
+ """PypinyinBackend for Chinese. Most codes is referenced from espnet.
31
+ There are two types pinyin or initials_finals, one is
32
+ just like "ni1 hao3", the other is like "n i1 h ao3".
33
+ """
34
+
35
+ def __init__(
36
+ self,
37
+ backend="initials_finals",
38
+ punctuation_marks: Union[str, Pattern] = Punctuation.default_marks(),
39
+ ) -> None:
40
+ self.backend = backend
41
+ self.punctuation_marks = punctuation_marks
42
+
43
+ def phonemize(
44
+ self, text: List[str], separator: Separator, strip=True, njobs=1
45
+ ) -> List[str]:
46
+ assert isinstance(text, List)
47
+ phonemized = []
48
+ for _text in text:
49
+ _text = re.sub(" +", " ", _text.strip())
50
+ _text = _text.replace(" ", separator.word)
51
+ phones = []
52
+ if self.backend == "pypinyin":
53
+ for n, py in enumerate(
54
+ pinyin(_text, style=Style.TONE3, neutral_tone_with_five=True)
55
+ ):
56
+ if all([c in self.punctuation_marks for c in py[0]]):
57
+ if len(phones):
58
+ assert phones[-1] == separator.syllable
59
+ phones.pop(-1)
60
+
61
+ phones.extend(list(py[0]))
62
+ else:
63
+ phones.extend([py[0], separator.syllable])
64
+ elif self.backend == "pypinyin_initials_finals":
65
+ for n, py in enumerate(
66
+ pinyin(_text, style=Style.TONE3, neutral_tone_with_five=True)
67
+ ):
68
+ if all([c in self.punctuation_marks for c in py[0]]):
69
+ if len(phones):
70
+ assert phones[-1] == separator.syllable
71
+ phones.pop(-1)
72
+ phones.extend(list(py[0]))
73
+ else:
74
+ if py[0][-1].isalnum():
75
+ initial = get_initials(py[0], strict=False)
76
+ if py[0][-1].isdigit():
77
+ final = get_finals(py[0][:-1], strict=False) + py[0][-1]
78
+ else:
79
+ final = get_finals(py[0], strict=False)
80
+ phones.extend(
81
+ [
82
+ initial,
83
+ separator.phone,
84
+ final,
85
+ separator.syllable,
86
+ ]
87
+ )
88
+ else:
89
+ assert ValueError
90
+ else:
91
+ raise NotImplementedError
92
+ phonemized.append(
93
+ "".join(phones).rstrip(f"{separator.word}{separator.syllable}")
94
+ )
95
+ return phonemized
96
+
97
+
98
+ class G2PModule:
99
+ """Phonemize Text."""
100
+
101
+ # We support espeak to extract IPA (International Phonetic Alphabet), which supports 100 languages,
102
+ # https://github.com/espeak-ng/espeak-ng/blob/master/docs/languages.md
103
+
104
+ def __init__(
105
+ self,
106
+ language="en-us",
107
+ backend="espeak",
108
+ separator=Separator(word="_", syllable="-", phone="|"),
109
+ preserve_punctuation=True,
110
+ punctuation_marks: Union[str, Pattern] = Punctuation.default_marks(),
111
+ with_stress: bool = False,
112
+ tie: Union[bool, str] = False,
113
+ language_switch: LanguageSwitch = "keep-flags",
114
+ words_mismatch: WordMismatch = "ignore",
115
+ ) -> None:
116
+ self.separator = separator
117
+ self.backend = self._initialize_backend(
118
+ backend,
119
+ language,
120
+ punctuation_marks,
121
+ preserve_punctuation,
122
+ with_stress,
123
+ tie,
124
+ language_switch,
125
+ words_mismatch,
126
+ )
127
+
128
+ def _initialize_backend(
129
+ self,
130
+ backend,
131
+ language,
132
+ punctuation_marks,
133
+ preserve_punctuation,
134
+ with_stress,
135
+ tie,
136
+ language_switch,
137
+ words_mismatch,
138
+ ):
139
+ if backend == "espeak":
140
+ return EspeakBackend(
141
+ language,
142
+ punctuation_marks=punctuation_marks,
143
+ preserve_punctuation=preserve_punctuation,
144
+ with_stress=with_stress,
145
+ tie=tie,
146
+ language_switch=language_switch,
147
+ words_mismatch=words_mismatch,
148
+ )
149
+ elif backend in ["pypinyin", "pypinyin_initials_finals"]:
150
+ if language != "cmn":
151
+ raise ValueError(
152
+ f"{language} is not supported for pypinyin and pypinyin_initials_finals."
153
+ )
154
+ return PypinyinBackend(
155
+ backend=backend,
156
+ punctuation_marks=punctuation_marks + self.separator.word,
157
+ )
158
+ else:
159
+ raise NotImplementedError(f"{backend}")
160
+
161
+ def to_list(self, phonemized: str) -> List[str]:
162
+ fields = []
163
+ for word in phonemized.split(self.separator.word):
164
+ pp = re.findall(r"\w+|[^\w\s]", word, re.UNICODE)
165
+ fields.extend(
166
+ [p for p in pp if p != self.separator.phone] + [self.separator.word]
167
+ )
168
+ assert len("".join(fields[:-1])) == len(phonemized) - phonemized.count(
169
+ self.separator.phone
170
+ )
171
+ return fields[:-1]
172
+
173
+ def phonemization(self, text, strip=True) -> List[List[str]]:
174
+ if isinstance(text, str):
175
+ text = [text]
176
+
177
+ phonemized = self.backend.phonemize(
178
+ text, separator=self.separator, strip=strip, njobs=1
179
+ )
180
+ phonemes = [self.to_list(p) for p in phonemized]
181
+ return phonemes
182
+
183
+ def g2p_conversion(self, text: str) -> List[str]:
184
+ phonemes = self.phonemization([text.strip()])
185
+ return phonemes[0]
186
+
187
+
188
+ class LexiconModule:
189
+ def __init__(self, lex_path, language="en-us") -> None:
190
+ # todo: check lexicon derivation, merge with G2PModule?
191
+ lexicon = {}
192
+ with open(lex_path) as f:
193
+ for line in f:
194
+ temp = re.split(r"\s+", line.strip("\n"))
195
+ word = temp[0]
196
+ phones = temp[1:]
197
+ if word.lower() not in lexicon:
198
+ lexicon[word.lower()] = phones
199
+ self.lexicon = lexicon
200
+ self.language = language
201
+ self.lang2g2p = {"en-us": G2p()}
202
+
203
+ def g2p_conversion(self, text):
204
+ phone = None
205
+
206
+ # todo: preprocess with other languages
207
+ if self.language == "en-us":
208
+ phone = self.preprocess_english(text)
209
+ else:
210
+ print("No support to", self.language)
211
+ raise
212
+
213
+ return phone
214
+
215
+ def preprocess_english(self, text):
216
+ text = text.rstrip(punctuation)
217
+
218
+ g2p = self.lang2g2p["en-us"]
219
+ phones = []
220
+ words = re.split(r"([,;.\-\?\!\s+])", text)
221
+ for w in words:
222
+ if w.lower() in self.lexicon:
223
+ phones += self.lexicon[w.lower()]
224
+ else:
225
+ phones += list(filter(lambda p: p != " ", g2p(w)))
226
+ phones = "}{".join(phones)
227
+ phones = re.sub(r"\{[^\w\s]?\}", "{sp}", phones)
228
+ phones = phones.replace("}{", " ")
229
+
230
+ return phones
text/lexicon/librispeech-lexicon.txt ADDED
The diff for this file is too large to render. See raw diff
 
text/lexicon/pinyin-lexicon-r.txt ADDED
@@ -0,0 +1,4120 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ a1 a1
2
+ a2 a2
3
+ a3 a3
4
+ a4 a4
5
+ a5 a5
6
+ ai1 ai1
7
+ ai2 ai2
8
+ ai3 ai3
9
+ ai4 ai4
10
+ ai5 ai5
11
+ an1 an1
12
+ an2 an2
13
+ an3 an3
14
+ an4 an4
15
+ an5 an5
16
+ ang1 ang1
17
+ ang2 ang2
18
+ ang3 ang3
19
+ ang4 ang4
20
+ ang5 ang5
21
+ ao1 ao1
22
+ ao2 ao2
23
+ ao3 ao3
24
+ ao4 ao4
25
+ ao5 ao5
26
+ ba1 b a1
27
+ ba2 b a2
28
+ ba3 b a3
29
+ ba4 b a4
30
+ ba5 b a5
31
+ bai1 b ai1
32
+ bai2 b ai2
33
+ bai3 b ai3
34
+ bai4 b ai4
35
+ bai5 b ai5
36
+ ban1 b an1
37
+ ban2 b an2
38
+ ban3 b an3
39
+ ban4 b an4
40
+ ban5 b an5
41
+ bang1 b ang1
42
+ bang2 b ang2
43
+ bang3 b ang3
44
+ bang4 b ang4
45
+ bang5 b ang5
46
+ bao1 b ao1
47
+ bao2 b ao2
48
+ bao3 b ao3
49
+ bao4 b ao4
50
+ bao5 b ao5
51
+ bei1 b ei1
52
+ bei2 b ei2
53
+ bei3 b ei3
54
+ bei4 b ei4
55
+ bei5 b ei5
56
+ ben1 b en1
57
+ ben2 b en2
58
+ ben3 b en3
59
+ ben4 b en4
60
+ ben5 b en5
61
+ beng1 b eng1
62
+ beng2 b eng2
63
+ beng3 b eng3
64
+ beng4 b eng4
65
+ beng5 b eng5
66
+ bi1 b i1
67
+ bi2 b i2
68
+ bi3 b i3
69
+ bi4 b i4
70
+ bi5 b i5
71
+ bian1 b ian1
72
+ bian2 b ian2
73
+ bian3 b ian3
74
+ bian4 b ian4
75
+ bian5 b ian5
76
+ biao1 b iao1
77
+ biao2 b iao2
78
+ biao3 b iao3
79
+ biao4 b iao4
80
+ biao5 b iao5
81
+ bie1 b ie1
82
+ bie2 b ie2
83
+ bie3 b ie3
84
+ bie4 b ie4
85
+ bie5 b ie5
86
+ bin1 b in1
87
+ bin2 b in2
88
+ bin3 b in3
89
+ bin4 b in4
90
+ bin5 b in5
91
+ bing1 b ing1
92
+ bing2 b ing2
93
+ bing3 b ing3
94
+ bing4 b ing4
95
+ bing5 b ing5
96
+ bo1 b o1
97
+ bo2 b o2
98
+ bo3 b o3
99
+ bo4 b o4
100
+ bo5 b o5
101
+ bu1 b u1
102
+ bu2 b u2
103
+ bu3 b u3
104
+ bu4 b u4
105
+ bu5 b u5
106
+ ca1 c a1
107
+ ca2 c a2
108
+ ca3 c a3
109
+ ca4 c a4
110
+ ca5 c a5
111
+ cai1 c ai1
112
+ cai2 c ai2
113
+ cai3 c ai3
114
+ cai4 c ai4
115
+ cai5 c ai5
116
+ can1 c an1
117
+ can2 c an2
118
+ can3 c an3
119
+ can4 c an4
120
+ can5 c an5
121
+ cang1 c ang1
122
+ cang2 c ang2
123
+ cang3 c ang3
124
+ cang4 c ang4
125
+ cang5 c ang5
126
+ cao1 c ao1
127
+ cao2 c ao2
128
+ cao3 c ao3
129
+ cao4 c ao4
130
+ cao5 c ao5
131
+ ce1 c e1
132
+ ce2 c e2
133
+ ce3 c e3
134
+ ce4 c e4
135
+ ce5 c e5
136
+ cen1 c en1
137
+ cen2 c en2
138
+ cen3 c en3
139
+ cen4 c en4
140
+ cen5 c en5
141
+ ceng1 c eng1
142
+ ceng2 c eng2
143
+ ceng3 c eng3
144
+ ceng4 c eng4
145
+ ceng5 c eng5
146
+ cha1 ch a1
147
+ cha2 ch a2
148
+ cha3 ch a3
149
+ cha4 ch a4
150
+ cha5 ch a5
151
+ chai1 ch ai1
152
+ chai2 ch ai2
153
+ chai3 ch ai3
154
+ chai4 ch ai4
155
+ chai5 ch ai5
156
+ chan1 ch an1
157
+ chan2 ch an2
158
+ chan3 ch an3
159
+ chan4 ch an4
160
+ chan5 ch an5
161
+ chang1 ch ang1
162
+ chang2 ch ang2
163
+ chang3 ch ang3
164
+ chang4 ch ang4
165
+ chang5 ch ang5
166
+ chao1 ch ao1
167
+ chao2 ch ao2
168
+ chao3 ch ao3
169
+ chao4 ch ao4
170
+ chao5 ch ao5
171
+ che1 ch e1
172
+ che2 ch e2
173
+ che3 ch e3
174
+ che4 ch e4
175
+ che5 ch e5
176
+ chen1 ch en1
177
+ chen2 ch en2
178
+ chen3 ch en3
179
+ chen4 ch en4
180
+ chen5 ch en5
181
+ cheng1 ch eng1
182
+ cheng2 ch eng2
183
+ cheng3 ch eng3
184
+ cheng4 ch eng4
185
+ cheng5 ch eng5
186
+ chi1 ch iii1
187
+ chi2 ch iii2
188
+ chi3 ch iii3
189
+ chi4 ch iii4
190
+ chi5 ch iii5
191
+ chong1 ch ong1
192
+ chong2 ch ong2
193
+ chong3 ch ong3
194
+ chong4 ch ong4
195
+ chong5 ch ong5
196
+ chou1 ch ou1
197
+ chou2 ch ou2
198
+ chou3 ch ou3
199
+ chou4 ch ou4
200
+ chou5 ch ou5
201
+ chu1 ch u1
202
+ chu2 ch u2
203
+ chu3 ch u3
204
+ chu4 ch u4
205
+ chu5 ch u5
206
+ chuai1 ch uai1
207
+ chuai2 ch uai2
208
+ chuai3 ch uai3
209
+ chuai4 ch uai4
210
+ chuai5 ch uai5
211
+ chuan1 ch uan1
212
+ chuan2 ch uan2
213
+ chuan3 ch uan3
214
+ chuan4 ch uan4
215
+ chuan5 ch uan5
216
+ chuang1 ch uang1
217
+ chuang2 ch uang2
218
+ chuang3 ch uang3
219
+ chuang4 ch uang4
220
+ chuang5 ch uang5
221
+ chui1 ch uei1
222
+ chui2 ch uei2
223
+ chui3 ch uei3
224
+ chui4 ch uei4
225
+ chui5 ch uei5
226
+ chun1 ch uen1
227
+ chun2 ch uen2
228
+ chun3 ch uen3
229
+ chun4 ch uen4
230
+ chun5 ch uen5
231
+ chuo1 ch uo1
232
+ chuo2 ch uo2
233
+ chuo3 ch uo3
234
+ chuo4 ch uo4
235
+ chuo5 ch uo5
236
+ ci1 c ii1
237
+ ci2 c ii2
238
+ ci3 c ii3
239
+ ci4 c ii4
240
+ ci5 c ii5
241
+ cong1 c ong1
242
+ cong2 c ong2
243
+ cong3 c ong3
244
+ cong4 c ong4
245
+ cong5 c ong5
246
+ cou1 c ou1
247
+ cou2 c ou2
248
+ cou3 c ou3
249
+ cou4 c ou4
250
+ cou5 c ou5
251
+ cu1 c u1
252
+ cu2 c u2
253
+ cu3 c u3
254
+ cu4 c u4
255
+ cu5 c u5
256
+ cuan1 c uan1
257
+ cuan2 c uan2
258
+ cuan3 c uan3
259
+ cuan4 c uan4
260
+ cuan5 c uan5
261
+ cui1 c uei1
262
+ cui2 c uei2
263
+ cui3 c uei3
264
+ cui4 c uei4
265
+ cui5 c uei5
266
+ cun1 c uen1
267
+ cun2 c uen2
268
+ cun3 c uen3
269
+ cun4 c uen4
270
+ cun5 c uen5
271
+ cuo1 c uo1
272
+ cuo2 c uo2
273
+ cuo3 c uo3
274
+ cuo4 c uo4
275
+ cuo5 c uo5
276
+ da1 d a1
277
+ da2 d a2
278
+ da3 d a3
279
+ da4 d a4
280
+ da5 d a5
281
+ dai1 d ai1
282
+ dai2 d ai2
283
+ dai3 d ai3
284
+ dai4 d ai4
285
+ dai5 d ai5
286
+ dan1 d an1
287
+ dan2 d an2
288
+ dan3 d an3
289
+ dan4 d an4
290
+ dan5 d an5
291
+ dang1 d ang1
292
+ dang2 d ang2
293
+ dang3 d ang3
294
+ dang4 d ang4
295
+ dang5 d ang5
296
+ dao1 d ao1
297
+ dao2 d ao2
298
+ dao3 d ao3
299
+ dao4 d ao4
300
+ dao5 d ao5
301
+ de1 d e1
302
+ de2 d e2
303
+ de3 d e3
304
+ de4 d e4
305
+ de5 d e5
306
+ dei1 d ei1
307
+ dei2 d ei2
308
+ dei3 d ei3
309
+ dei4 d ei4
310
+ dei5 d ei5
311
+ den1 d en1
312
+ den2 d en2
313
+ den3 d en3
314
+ den4 d en4
315
+ den5 d en5
316
+ deng1 d eng1
317
+ deng2 d eng2
318
+ deng3 d eng3
319
+ deng4 d eng4
320
+ deng5 d eng5
321
+ di1 d i1
322
+ di2 d i2
323
+ di3 d i3
324
+ di4 d i4
325
+ di5 d i5
326
+ dia1 d ia1
327
+ dia2 d ia2
328
+ dia3 d ia3
329
+ dia4 d ia4
330
+ dia5 d ia5
331
+ dian1 d ian1
332
+ dian2 d ian2
333
+ dian3 d ian3
334
+ dian4 d ian4
335
+ dian5 d ian5
336
+ diao1 d iao1
337
+ diao2 d iao2
338
+ diao3 d iao3
339
+ diao4 d iao4
340
+ diao5 d iao5
341
+ die1 d ie1
342
+ die2 d ie2
343
+ die3 d ie3
344
+ die4 d ie4
345
+ die5 d ie5
346
+ ding1 d ing1
347
+ ding2 d ing2
348
+ ding3 d ing3
349
+ ding4 d ing4
350
+ ding5 d ing5
351
+ diu1 d iou1
352
+ diu2 d iou2
353
+ diu3 d iou3
354
+ diu4 d iou4
355
+ diu5 d iou5
356
+ dong1 d ong1
357
+ dong2 d ong2
358
+ dong3 d ong3
359
+ dong4 d ong4
360
+ dong5 d ong5
361
+ dou1 d ou1
362
+ dou2 d ou2
363
+ dou3 d ou3
364
+ dou4 d ou4
365
+ dou5 d ou5
366
+ du1 d u1
367
+ du2 d u2
368
+ du3 d u3
369
+ du4 d u4
370
+ du5 d u5
371
+ duan1 d uan1
372
+ duan2 d uan2
373
+ duan3 d uan3
374
+ duan4 d uan4
375
+ duan5 d uan5
376
+ dui1 d uei1
377
+ dui2 d uei2
378
+ dui3 d uei3
379
+ dui4 d uei4
380
+ dui5 d uei5
381
+ dun1 d uen1
382
+ dun2 d uen2
383
+ dun3 d uen3
384
+ dun4 d uen4
385
+ dun5 d uen5
386
+ duo1 d uo1
387
+ duo2 d uo2
388
+ duo3 d uo3
389
+ duo4 d uo4
390
+ duo5 d uo5
391
+ e1 e1
392
+ e2 e2
393
+ e3 e3
394
+ e4 e4
395
+ e5 e5
396
+ ei1 ei1
397
+ ei2 ei2
398
+ ei3 ei3
399
+ ei4 ei4
400
+ ei5 ei5
401
+ en1 en1
402
+ en2 en2
403
+ en3 en3
404
+ en4 en4
405
+ en5 en5
406
+ eng1 eng1
407
+ eng2 eng2
408
+ eng3 eng3
409
+ eng4 eng4
410
+ eng5 eng5
411
+ r1 er1
412
+ r2 er2
413
+ r3 er3
414
+ r4 er4
415
+ r5 er5
416
+ er1 er1
417
+ er2 er2
418
+ er3 er3
419
+ er4 er4
420
+ er5 er5
421
+ fa1 f a1
422
+ fa2 f a2
423
+ fa3 f a3
424
+ fa4 f a4
425
+ fa5 f a5
426
+ fan1 f an1
427
+ fan2 f an2
428
+ fan3 f an3
429
+ fan4 f an4
430
+ fan5 f an5
431
+ fang1 f ang1
432
+ fang2 f ang2
433
+ fang3 f ang3
434
+ fang4 f ang4
435
+ fang5 f ang5
436
+ fei1 f ei1
437
+ fei2 f ei2
438
+ fei3 f ei3
439
+ fei4 f ei4
440
+ fei5 f ei5
441
+ fen1 f en1
442
+ fen2 f en2
443
+ fen3 f en3
444
+ fen4 f en4
445
+ fen5 f en5
446
+ feng1 f eng1
447
+ feng2 f eng2
448
+ feng3 f eng3
449
+ feng4 f eng4
450
+ feng5 f eng5
451
+ fo1 f o1
452
+ fo2 f o2
453
+ fo3 f o3
454
+ fo4 f o4
455
+ fo5 f o5
456
+ fou1 f ou1
457
+ fou2 f ou2
458
+ fou3 f ou3
459
+ fou4 f ou4
460
+ fou5 f ou5
461
+ fu1 f u1
462
+ fu2 f u2
463
+ fu3 f u3
464
+ fu4 f u4
465
+ fu5 f u5
466
+ ga1 g a1
467
+ ga2 g a2
468
+ ga3 g a3
469
+ ga4 g a4
470
+ ga5 g a5
471
+ gai1 g ai1
472
+ gai2 g ai2
473
+ gai3 g ai3
474
+ gai4 g ai4
475
+ gai5 g ai5
476
+ gan1 g an1
477
+ gan2 g an2
478
+ gan3 g an3
479
+ gan4 g an4
480
+ gan5 g an5
481
+ gang1 g ang1
482
+ gang2 g ang2
483
+ gang3 g ang3
484
+ gang4 g ang4
485
+ gang5 g ang5
486
+ gao1 g ao1
487
+ gao2 g ao2
488
+ gao3 g ao3
489
+ gao4 g ao4
490
+ gao5 g ao5
491
+ ge1 g e1
492
+ ge2 g e2
493
+ ge3 g e3
494
+ ge4 g e4
495
+ ge5 g e5
496
+ gei1 g ei1
497
+ gei2 g ei2
498
+ gei3 g ei3
499
+ gei4 g ei4
500
+ gei5 g ei5
501
+ gen1 g en1
502
+ gen2 g en2
503
+ gen3 g en3
504
+ gen4 g en4
505
+ gen5 g en5
506
+ geng1 g eng1
507
+ geng2 g eng2
508
+ geng3 g eng3
509
+ geng4 g eng4
510
+ geng5 g eng5
511
+ gong1 g ong1
512
+ gong2 g ong2
513
+ gong3 g ong3
514
+ gong4 g ong4
515
+ gong5 g ong5
516
+ gou1 g ou1
517
+ gou2 g ou2
518
+ gou3 g ou3
519
+ gou4 g ou4
520
+ gou5 g ou5
521
+ gu1 g u1
522
+ gu2 g u2
523
+ gu3 g u3
524
+ gu4 g u4
525
+ gu5 g u5
526
+ gua1 g ua1
527
+ gua2 g ua2
528
+ gua3 g ua3
529
+ gua4 g ua4
530
+ gua5 g ua5
531
+ guai1 g uai1
532
+ guai2 g uai2
533
+ guai3 g uai3
534
+ guai4 g uai4
535
+ guai5 g uai5
536
+ guan1 g uan1
537
+ guan2 g uan2
538
+ guan3 g uan3
539
+ guan4 g uan4
540
+ guan5 g uan5
541
+ guang1 g uang1
542
+ guang2 g uang2
543
+ guang3 g uang3
544
+ guang4 g uang4
545
+ guang5 g uang5
546
+ gui1 g uei1
547
+ gui2 g uei2
548
+ gui3 g uei3
549
+ gui4 g uei4
550
+ gui5 g uei5
551
+ gun1 g uen1
552
+ gun2 g uen2
553
+ gun3 g uen3
554
+ gun4 g uen4
555
+ gun5 g uen5
556
+ guo1 g uo1
557
+ guo2 g uo2
558
+ guo3 g uo3
559
+ guo4 g uo4
560
+ guo5 g uo5
561
+ ha1 h a1
562
+ ha2 h a2
563
+ ha3 h a3
564
+ ha4 h a4
565
+ ha5 h a5
566
+ hai1 h ai1
567
+ hai2 h ai2
568
+ hai3 h ai3
569
+ hai4 h ai4
570
+ hai5 h ai5
571
+ han1 h an1
572
+ han2 h an2
573
+ han3 h an3
574
+ han4 h an4
575
+ han5 h an5
576
+ hang1 h ang1
577
+ hang2 h ang2
578
+ hang3 h ang3
579
+ hang4 h ang4
580
+ hang5 h ang5
581
+ hao1 h ao1
582
+ hao2 h ao2
583
+ hao3 h ao3
584
+ hao4 h ao4
585
+ hao5 h ao5
586
+ he1 h e1
587
+ he2 h e2
588
+ he3 h e3
589
+ he4 h e4
590
+ he5 h e5
591
+ hei1 h ei1
592
+ hei2 h ei2
593
+ hei3 h ei3
594
+ hei4 h ei4
595
+ hei5 h ei5
596
+ hen1 h en1
597
+ hen2 h en2
598
+ hen3 h en3
599
+ hen4 h en4
600
+ hen5 h en5
601
+ heng1 h eng1
602
+ heng2 h eng2
603
+ heng3 h eng3
604
+ heng4 h eng4
605
+ heng5 h eng5
606
+ hong1 h ong1
607
+ hong2 h ong2
608
+ hong3 h ong3
609
+ hong4 h ong4
610
+ hong5 h ong5
611
+ hou1 h ou1
612
+ hou2 h ou2
613
+ hou3 h ou3
614
+ hou4 h ou4
615
+ hou5 h ou5
616
+ hu1 h u1
617
+ hu2 h u2
618
+ hu3 h u3
619
+ hu4 h u4
620
+ hu5 h u5
621
+ hua1 h ua1
622
+ hua2 h ua2
623
+ hua3 h ua3
624
+ hua4 h ua4
625
+ hua5 h ua5
626
+ huai1 h uai1
627
+ huai2 h uai2
628
+ huai3 h uai3
629
+ huai4 h uai4
630
+ huai5 h uai5
631
+ huan1 h uan1
632
+ huan2 h uan2
633
+ huan3 h uan3
634
+ huan4 h uan4
635
+ huan5 h uan5
636
+ huang1 h uang1
637
+ huang2 h uang2
638
+ huang3 h uang3
639
+ huang4 h uang4
640
+ huang5 h uang5
641
+ hui1 h uei1
642
+ hui2 h uei2
643
+ hui3 h uei3
644
+ hui4 h uei4
645
+ hui5 h uei5
646
+ hun1 h uen1
647
+ hun2 h uen2
648
+ hun3 h uen3
649
+ hun4 h uen4
650
+ hun5 h uen5
651
+ huo1 h uo1
652
+ huo2 h uo2
653
+ huo3 h uo3
654
+ huo4 h uo4
655
+ huo5 h uo5
656
+ ji1 j i1
657
+ ji2 j i2
658
+ ji3 j i3
659
+ ji4 j i4
660
+ ji5 j i5
661
+ jia1 j ia1
662
+ jia2 j ia2
663
+ jia3 j ia3
664
+ jia4 j ia4
665
+ jia5 j ia5
666
+ jian1 j ian1
667
+ jian2 j ian2
668
+ jian3 j ian3
669
+ jian4 j ian4
670
+ jian5 j ian5
671
+ jiang1 j iang1
672
+ jiang2 j iang2
673
+ jiang3 j iang3
674
+ jiang4 j iang4
675
+ jiang5 j iang5
676
+ jiao1 j iao1
677
+ jiao2 j iao2
678
+ jiao3 j iao3
679
+ jiao4 j iao4
680
+ jiao5 j iao5
681
+ jie1 j ie1
682
+ jie2 j ie2
683
+ jie3 j ie3
684
+ jie4 j ie4
685
+ jie5 j ie5
686
+ jin1 j in1
687
+ jin2 j in2
688
+ jin3 j in3
689
+ jin4 j in4
690
+ jin5 j in5
691
+ jing1 j ing1
692
+ jing2 j ing2
693
+ jing3 j ing3
694
+ jing4 j ing4
695
+ jing5 j ing5
696
+ jiong1 j iong1
697
+ jiong2 j iong2
698
+ jiong3 j iong3
699
+ jiong4 j iong4
700
+ jiong5 j iong5
701
+ jiu1 j iou1
702
+ jiu2 j iou2
703
+ jiu3 j iou3
704
+ jiu4 j iou4
705
+ jiu5 j iou5
706
+ ju1 j v1
707
+ ju2 j v2
708
+ ju3 j v3
709
+ ju4 j v4
710
+ ju5 j v5
711
+ juan1 j van1
712
+ juan2 j van2
713
+ juan3 j van3
714
+ juan4 j van4
715
+ juan5 j van5
716
+ jue1 j ve1
717
+ jue2 j ve2
718
+ jue3 j ve3
719
+ jue4 j ve4
720
+ jue5 j ve5
721
+ jun1 j vn1
722
+ jun2 j vn2
723
+ jun3 j vn3
724
+ jun4 j vn4
725
+ jun5 j vn5
726
+ ka1 k a1
727
+ ka2 k a2
728
+ ka3 k a3
729
+ ka4 k a4
730
+ ka5 k a5
731
+ kai1 k ai1
732
+ kai2 k ai2
733
+ kai3 k ai3
734
+ kai4 k ai4
735
+ kai5 k ai5
736
+ kan1 k an1
737
+ kan2 k an2
738
+ kan3 k an3
739
+ kan4 k an4
740
+ kan5 k an5
741
+ kang1 k ang1
742
+ kang2 k ang2
743
+ kang3 k ang3
744
+ kang4 k ang4
745
+ kang5 k ang5
746
+ kao1 k ao1
747
+ kao2 k ao2
748
+ kao3 k ao3
749
+ kao4 k ao4
750
+ kao5 k ao5
751
+ ke1 k e1
752
+ ke2 k e2
753
+ ke3 k e3
754
+ ke4 k e4
755
+ ke5 k e5
756
+ kei1 k ei1
757
+ kei2 k ei2
758
+ kei3 k ei3
759
+ kei4 k ei4
760
+ kei5 k ei5
761
+ ken1 k en1
762
+ ken2 k en2
763
+ ken3 k en3
764
+ ken4 k en4
765
+ ken5 k en5
766
+ keng1 k eng1
767
+ keng2 k eng2
768
+ keng3 k eng3
769
+ keng4 k eng4
770
+ keng5 k eng5
771
+ kong1 k ong1
772
+ kong2 k ong2
773
+ kong3 k ong3
774
+ kong4 k ong4
775
+ kong5 k ong5
776
+ kou1 k ou1
777
+ kou2 k ou2
778
+ kou3 k ou3
779
+ kou4 k ou4
780
+ kou5 k ou5
781
+ ku1 k u1
782
+ ku2 k u2
783
+ ku3 k u3
784
+ ku4 k u4
785
+ ku5 k u5
786
+ kua1 k ua1
787
+ kua2 k ua2
788
+ kua3 k ua3
789
+ kua4 k ua4
790
+ kua5 k ua5
791
+ kuai1 k uai1
792
+ kuai2 k uai2
793
+ kuai3 k uai3
794
+ kuai4 k uai4
795
+ kuai5 k uai5
796
+ kuan1 k uan1
797
+ kuan2 k uan2
798
+ kuan3 k uan3
799
+ kuan4 k uan4
800
+ kuan5 k uan5
801
+ kuang1 k uang1
802
+ kuang2 k uang2
803
+ kuang3 k uang3
804
+ kuang4 k uang4
805
+ kuang5 k uang5
806
+ kui1 k uei1
807
+ kui2 k uei2
808
+ kui3 k uei3
809
+ kui4 k uei4
810
+ kui5 k uei5
811
+ kun1 k uen1
812
+ kun2 k uen2
813
+ kun3 k uen3
814
+ kun4 k uen4
815
+ kun5 k uen5
816
+ kuo1 k uo1
817
+ kuo2 k uo2
818
+ kuo3 k uo3
819
+ kuo4 k uo4
820
+ kuo5 k uo5
821
+ la1 l a1
822
+ la2 l a2
823
+ la3 l a3
824
+ la4 l a4
825
+ la5 l a5
826
+ lai1 l ai1
827
+ lai2 l ai2
828
+ lai3 l ai3
829
+ lai4 l ai4
830
+ lai5 l ai5
831
+ lan1 l an1
832
+ lan2 l an2
833
+ lan3 l an3
834
+ lan4 l an4
835
+ lan5 l an5
836
+ lang1 l ang1
837
+ lang2 l ang2
838
+ lang3 l ang3
839
+ lang4 l ang4
840
+ lang5 l ang5
841
+ lao1 l ao1
842
+ lao2 l ao2
843
+ lao3 l ao3
844
+ lao4 l ao4
845
+ lao5 l ao5
846
+ le1 l e1
847
+ le2 l e2
848
+ le3 l e3
849
+ le4 l e4
850
+ le5 l e5
851
+ lei1 l ei1
852
+ lei2 l ei2
853
+ lei3 l ei3
854
+ lei4 l ei4
855
+ lei5 l ei5
856
+ leng1 l eng1
857
+ leng2 l eng2
858
+ leng3 l eng3
859
+ leng4 l eng4
860
+ leng5 l eng5
861
+ li1 l i1
862
+ li2 l i2
863
+ li3 l i3
864
+ li4 l i4
865
+ li5 l i5
866
+ lia1 l ia1
867
+ lia2 l ia2
868
+ lia3 l ia3
869
+ lia4 l ia4
870
+ lia5 l ia5
871
+ lian1 l ian1
872
+ lian2 l ian2
873
+ lian3 l ian3
874
+ lian4 l ian4
875
+ lian5 l ian5
876
+ liang1 l iang1
877
+ liang2 l iang2
878
+ liang3 l iang3
879
+ liang4 l iang4
880
+ liang5 l iang5
881
+ liao1 l iao1
882
+ liao2 l iao2
883
+ liao3 l iao3
884
+ liao4 l iao4
885
+ liao5 l iao5
886
+ lie1 l ie1
887
+ lie2 l ie2
888
+ lie3 l ie3
889
+ lie4 l ie4
890
+ lie5 l ie5
891
+ lin1 l in1
892
+ lin2 l in2
893
+ lin3 l in3
894
+ lin4 l in4
895
+ lin5 l in5
896
+ ling1 l ing1
897
+ ling2 l ing2
898
+ ling3 l ing3
899
+ ling4 l ing4
900
+ ling5 l ing5
901
+ liu1 l iou1
902
+ liu2 l iou2
903
+ liu3 l iou3
904
+ liu4 l iou4
905
+ liu5 l iou5
906
+ lo1 l o1
907
+ lo2 l o2
908
+ lo3 l o3
909
+ lo4 l o4
910
+ lo5 l o5
911
+ long1 l ong1
912
+ long2 l ong2
913
+ long3 l ong3
914
+ long4 l ong4
915
+ long5 l ong5
916
+ lou1 l ou1
917
+ lou2 l ou2
918
+ lou3 l ou3
919
+ lou4 l ou4
920
+ lou5 l ou5
921
+ lu1 l u1
922
+ lu2 l u2
923
+ lu3 l u3
924
+ lu4 l u4
925
+ lu5 l u5
926
+ luan1 l uan1
927
+ luan2 l uan2
928
+ luan3 l uan3
929
+ luan4 l uan4
930
+ luan5 l uan5
931
+ lue1 l ve1
932
+ lue2 l ve2
933
+ lue3 l ve3
934
+ lue4 l ve4
935
+ lue5 l ve5
936
+ lve1 l ve1
937
+ lve2 l ve2
938
+ lve3 l ve3
939
+ lve4 l ve4
940
+ lve5 l ve5
941
+ lun1 l uen1
942
+ lun2 l uen2
943
+ lun3 l uen3
944
+ lun4 l uen4
945
+ lun5 l uen5
946
+ luo1 l uo1
947
+ luo2 l uo2
948
+ luo3 l uo3
949
+ luo4 l uo4
950
+ luo5 l uo5
951
+ lv1 l v1
952
+ lv2 l v2
953
+ lv3 l v3
954
+ lv4 l v4
955
+ lv5 l v5
956
+ ma1 m a1
957
+ ma2 m a2
958
+ ma3 m a3
959
+ ma4 m a4
960
+ ma5 m a5
961
+ mai1 m ai1
962
+ mai2 m ai2
963
+ mai3 m ai3
964
+ mai4 m ai4
965
+ mai5 m ai5
966
+ man1 m an1
967
+ man2 m an2
968
+ man3 m an3
969
+ man4 m an4
970
+ man5 m an5
971
+ mang1 m ang1
972
+ mang2 m ang2
973
+ mang3 m ang3
974
+ mang4 m ang4
975
+ mang5 m ang5
976
+ mao1 m ao1
977
+ mao2 m ao2
978
+ mao3 m ao3
979
+ mao4 m ao4
980
+ mao5 m ao5
981
+ me1 m e1
982
+ me2 m e2
983
+ me3 m e3
984
+ me4 m e4
985
+ me5 m e5
986
+ mei1 m ei1
987
+ mei2 m ei2
988
+ mei3 m ei3
989
+ mei4 m ei4
990
+ mei5 m ei5
991
+ men1 m en1
992
+ men2 m en2
993
+ men3 m en3
994
+ men4 m en4
995
+ men5 m en5
996
+ meng1 m eng1
997
+ meng2 m eng2
998
+ meng3 m eng3
999
+ meng4 m eng4
1000
+ meng5 m eng5
1001
+ mi1 m i1
1002
+ mi2 m i2
1003
+ mi3 m i3
1004
+ mi4 m i4
1005
+ mi5 m i5
1006
+ mian1 m ian1
1007
+ mian2 m ian2
1008
+ mian3 m ian3
1009
+ mian4 m ian4
1010
+ mian5 m ian5
1011
+ miao1 m iao1
1012
+ miao2 m iao2
1013
+ miao3 m iao3
1014
+ miao4 m iao4
1015
+ miao5 m iao5
1016
+ mie1 m ie1
1017
+ mie2 m ie2
1018
+ mie3 m ie3
1019
+ mie4 m ie4
1020
+ mie5 m ie5
1021
+ min1 m in1
1022
+ min2 m in2
1023
+ min3 m in3
1024
+ min4 m in4
1025
+ min5 m in5
1026
+ ming1 m ing1
1027
+ ming2 m ing2
1028
+ ming3 m ing3
1029
+ ming4 m ing4
1030
+ ming5 m ing5
1031
+ miu1 m iou1
1032
+ miu2 m iou2
1033
+ miu3 m iou3
1034
+ miu4 m iou4
1035
+ miu5 m iou5
1036
+ mo1 m o1
1037
+ mo2 m o2
1038
+ mo3 m o3
1039
+ mo4 m o4
1040
+ mo5 m o5
1041
+ mou1 m ou1
1042
+ mou2 m ou2
1043
+ mou3 m ou3
1044
+ mou4 m ou4
1045
+ mou5 m ou5
1046
+ mu1 m u1
1047
+ mu2 m u2
1048
+ mu3 m u3
1049
+ mu4 m u4
1050
+ mu5 m u5
1051
+ na1 n a1
1052
+ na2 n a2
1053
+ na3 n a3
1054
+ na4 n a4
1055
+ na5 n a5
1056
+ nai1 n ai1
1057
+ nai2 n ai2
1058
+ nai3 n ai3
1059
+ nai4 n ai4
1060
+ nai5 n ai5
1061
+ nan1 n an1
1062
+ nan2 n an2
1063
+ nan3 n an3
1064
+ nan4 n an4
1065
+ nan5 n an5
1066
+ nang1 n ang1
1067
+ nang2 n ang2
1068
+ nang3 n ang3
1069
+ nang4 n ang4
1070
+ nang5 n ang5
1071
+ nao1 n ao1
1072
+ nao2 n ao2
1073
+ nao3 n ao3
1074
+ nao4 n ao4
1075
+ nao5 n ao5
1076
+ ne1 n e1
1077
+ ne2 n e2
1078
+ ne3 n e3
1079
+ ne4 n e4
1080
+ ne5 n e5
1081
+ nei1 n ei1
1082
+ nei2 n ei2
1083
+ nei3 n ei3
1084
+ nei4 n ei4
1085
+ nei5 n ei5
1086
+ nen1 n en1
1087
+ nen2 n en2
1088
+ nen3 n en3
1089
+ nen4 n en4
1090
+ nen5 n en5
1091
+ neng1 n eng1
1092
+ neng2 n eng2
1093
+ neng3 n eng3
1094
+ neng4 n eng4
1095
+ neng5 n eng5
1096
+ ni1 n i1
1097
+ ni2 n i2
1098
+ ni3 n i3
1099
+ ni4 n i4
1100
+ ni5 n i5
1101
+ nian1 n ian1
1102
+ nian2 n ian2
1103
+ nian3 n ian3
1104
+ nian4 n ian4
1105
+ nian5 n ian5
1106
+ niang1 n iang1
1107
+ niang2 n iang2
1108
+ niang3 n iang3
1109
+ niang4 n iang4
1110
+ niang5 n iang5
1111
+ niao1 n iao1
1112
+ niao2 n iao2
1113
+ niao3 n iao3
1114
+ niao4 n iao4
1115
+ niao5 n iao5
1116
+ nie1 n ie1
1117
+ nie2 n ie2
1118
+ nie3 n ie3
1119
+ nie4 n ie4
1120
+ nie5 n ie5
1121
+ nin1 n in1
1122
+ nin2 n in2
1123
+ nin3 n in3
1124
+ nin4 n in4
1125
+ nin5 n in5
1126
+ ning1 n ing1
1127
+ ning2 n ing2
1128
+ ning3 n ing3
1129
+ ning4 n ing4
1130
+ ning5 n ing5
1131
+ niu1 n iou1
1132
+ niu2 n iou2
1133
+ niu3 n iou3
1134
+ niu4 n iou4
1135
+ niu5 n iou5
1136
+ nong1 n ong1
1137
+ nong2 n ong2
1138
+ nong3 n ong3
1139
+ nong4 n ong4
1140
+ nong5 n ong5
1141
+ nou1 n ou1
1142
+ nou2 n ou2
1143
+ nou3 n ou3
1144
+ nou4 n ou4
1145
+ nou5 n ou5
1146
+ nu1 n u1
1147
+ nu2 n u2
1148
+ nu3 n u3
1149
+ nu4 n u4
1150
+ nu5 n u5
1151
+ nuan1 n uan1
1152
+ nuan2 n uan2
1153
+ nuan3 n uan3
1154
+ nuan4 n uan4
1155
+ nuan5 n uan5
1156
+ nue1 n ve1
1157
+ nue2 n ve2
1158
+ nue3 n ve3
1159
+ nue4 n ve4
1160
+ nue5 n ve5
1161
+ nve1 n ve1
1162
+ nve2 n ve2
1163
+ nve3 n ve3
1164
+ nve4 n ve4
1165
+ nve5 n ve5
1166
+ nuo1 n uo1
1167
+ nuo2 n uo2
1168
+ nuo3 n uo3
1169
+ nuo4 n uo4
1170
+ nuo5 n uo5
1171
+ nv1 n v1
1172
+ nv2 n v2
1173
+ nv3 n v3
1174
+ nv4 n v4
1175
+ nv5 n v5
1176
+ o1 o1
1177
+ o2 o2
1178
+ o3 o3
1179
+ o4 o4
1180
+ o5 o5
1181
+ ou1 ou1
1182
+ ou2 ou2
1183
+ ou3 ou3
1184
+ ou4 ou4
1185
+ ou5 ou5
1186
+ pa1 p a1
1187
+ pa2 p a2
1188
+ pa3 p a3
1189
+ pa4 p a4
1190
+ pa5 p a5
1191
+ pai1 p ai1
1192
+ pai2 p ai2
1193
+ pai3 p ai3
1194
+ pai4 p ai4
1195
+ pai5 p ai5
1196
+ pan1 p an1
1197
+ pan2 p an2
1198
+ pan3 p an3
1199
+ pan4 p an4
1200
+ pan5 p an5
1201
+ pang1 p ang1
1202
+ pang2 p ang2
1203
+ pang3 p ang3
1204
+ pang4 p ang4
1205
+ pang5 p ang5
1206
+ pao1 p ao1
1207
+ pao2 p ao2
1208
+ pao3 p ao3
1209
+ pao4 p ao4
1210
+ pao5 p ao5
1211
+ pei1 p ei1
1212
+ pei2 p ei2
1213
+ pei3 p ei3
1214
+ pei4 p ei4
1215
+ pei5 p ei5
1216
+ pen1 p en1
1217
+ pen2 p en2
1218
+ pen3 p en3
1219
+ pen4 p en4
1220
+ pen5 p en5
1221
+ peng1 p eng1
1222
+ peng2 p eng2
1223
+ peng3 p eng3
1224
+ peng4 p eng4
1225
+ peng5 p eng5
1226
+ pi1 p i1
1227
+ pi2 p i2
1228
+ pi3 p i3
1229
+ pi4 p i4
1230
+ pi5 p i5
1231
+ pian1 p ian1
1232
+ pian2 p ian2
1233
+ pian3 p ian3
1234
+ pian4 p ian4
1235
+ pian5 p ian5
1236
+ piao1 p iao1
1237
+ piao2 p iao2
1238
+ piao3 p iao3
1239
+ piao4 p iao4
1240
+ piao5 p iao5
1241
+ pie1 p ie1
1242
+ pie2 p ie2
1243
+ pie3 p ie3
1244
+ pie4 p ie4
1245
+ pie5 p ie5
1246
+ pin1 p in1
1247
+ pin2 p in2
1248
+ pin3 p in3
1249
+ pin4 p in4
1250
+ pin5 p in5
1251
+ ping1 p ing1
1252
+ ping2 p ing2
1253
+ ping3 p ing3
1254
+ ping4 p ing4
1255
+ ping5 p ing5
1256
+ po1 p o1
1257
+ po2 p o2
1258
+ po3 p o3
1259
+ po4 p o4
1260
+ po5 p o5
1261
+ pou1 p ou1
1262
+ pou2 p ou2
1263
+ pou3 p ou3
1264
+ pou4 p ou4
1265
+ pou5 p ou5
1266
+ pu1 p u1
1267
+ pu2 p u2
1268
+ pu3 p u3
1269
+ pu4 p u4
1270
+ pu5 p u5
1271
+ qi1 q i1
1272
+ qi2 q i2
1273
+ qi3 q i3
1274
+ qi4 q i4
1275
+ qi5 q i5
1276
+ qia1 q ia1
1277
+ qia2 q ia2
1278
+ qia3 q ia3
1279
+ qia4 q ia4
1280
+ qia5 q ia5
1281
+ qian1 q ian1
1282
+ qian2 q ian2
1283
+ qian3 q ian3
1284
+ qian4 q ian4
1285
+ qian5 q ian5
1286
+ qiang1 q iang1
1287
+ qiang2 q iang2
1288
+ qiang3 q iang3
1289
+ qiang4 q iang4
1290
+ qiang5 q iang5
1291
+ qiao1 q iao1
1292
+ qiao2 q iao2
1293
+ qiao3 q iao3
1294
+ qiao4 q iao4
1295
+ qiao5 q iao5
1296
+ qie1 q ie1
1297
+ qie2 q ie2
1298
+ qie3 q ie3
1299
+ qie4 q ie4
1300
+ qie5 q ie5
1301
+ qin1 q in1
1302
+ qin2 q in2
1303
+ qin3 q in3
1304
+ qin4 q in4
1305
+ qin5 q in5
1306
+ qing1 q ing1
1307
+ qing2 q ing2
1308
+ qing3 q ing3
1309
+ qing4 q ing4
1310
+ qing5 q ing5
1311
+ qiong1 q iong1
1312
+ qiong2 q iong2
1313
+ qiong3 q iong3
1314
+ qiong4 q iong4
1315
+ qiong5 q iong5
1316
+ qiu1 q iou1
1317
+ qiu2 q iou2
1318
+ qiu3 q iou3
1319
+ qiu4 q iou4
1320
+ qiu5 q iou5
1321
+ qu1 q v1
1322
+ qu2 q v2
1323
+ qu3 q v3
1324
+ qu4 q v4
1325
+ qu5 q v5
1326
+ quan1 q van1
1327
+ quan2 q van2
1328
+ quan3 q van3
1329
+ quan4 q van4
1330
+ quan5 q van5
1331
+ que1 q ve1
1332
+ que2 q ve2
1333
+ que3 q ve3
1334
+ que4 q ve4
1335
+ que5 q ve5
1336
+ qun1 q vn1
1337
+ qun2 q vn2
1338
+ qun3 q vn3
1339
+ qun4 q vn4
1340
+ qun5 q vn5
1341
+ ran1 r an1
1342
+ ran2 r an2
1343
+ ran3 r an3
1344
+ ran4 r an4
1345
+ ran5 r an5
1346
+ rang1 r ang1
1347
+ rang2 r ang2
1348
+ rang3 r ang3
1349
+ rang4 r ang4
1350
+ rang5 r ang5
1351
+ rao1 r ao1
1352
+ rao2 r ao2
1353
+ rao3 r ao3
1354
+ rao4 r ao4
1355
+ rao5 r ao5
1356
+ re1 r e1
1357
+ re2 r e2
1358
+ re3 r e3
1359
+ re4 r e4
1360
+ re5 r e5
1361
+ ren1 r en1
1362
+ ren2 r en2
1363
+ ren3 r en3
1364
+ ren4 r en4
1365
+ ren5 r en5
1366
+ reng1 r eng1
1367
+ reng2 r eng2
1368
+ reng3 r eng3
1369
+ reng4 r eng4
1370
+ reng5 r eng5
1371
+ ri1 r iii1
1372
+ ri2 r iii2
1373
+ ri3 r iii3
1374
+ ri4 r iii4
1375
+ ri5 r iii5
1376
+ rong1 r ong1
1377
+ rong2 r ong2
1378
+ rong3 r ong3
1379
+ rong4 r ong4
1380
+ rong5 r ong5
1381
+ rou1 r ou1
1382
+ rou2 r ou2
1383
+ rou3 r ou3
1384
+ rou4 r ou4
1385
+ rou5 r ou5
1386
+ ru1 r u1
1387
+ ru2 r u2
1388
+ ru3 r u3
1389
+ ru4 r u4
1390
+ ru5 r u5
1391
+ rua1 r ua1
1392
+ rua2 r ua2
1393
+ rua3 r ua3
1394
+ rua4 r ua4
1395
+ rua5 r ua5
1396
+ ruan1 r uan1
1397
+ ruan2 r uan2
1398
+ ruan3 r uan3
1399
+ ruan4 r uan4
1400
+ ruan5 r uan5
1401
+ rui1 r uei1
1402
+ rui2 r uei2
1403
+ rui3 r uei3
1404
+ rui4 r uei4
1405
+ rui5 r uei5
1406
+ run1 r uen1
1407
+ run2 r uen2
1408
+ run3 r uen3
1409
+ run4 r uen4
1410
+ run5 r uen5
1411
+ ruo1 r uo1
1412
+ ruo2 r uo2
1413
+ ruo3 r uo3
1414
+ ruo4 r uo4
1415
+ ruo5 r uo5
1416
+ sa1 s a1
1417
+ sa2 s a2
1418
+ sa3 s a3
1419
+ sa4 s a4
1420
+ sa5 s a5
1421
+ sai1 s ai1
1422
+ sai2 s ai2
1423
+ sai3 s ai3
1424
+ sai4 s ai4
1425
+ sai5 s ai5
1426
+ san1 s an1
1427
+ san2 s an2
1428
+ san3 s an3
1429
+ san4 s an4
1430
+ san5 s an5
1431
+ sang1 s ang1
1432
+ sang2 s ang2
1433
+ sang3 s ang3
1434
+ sang4 s ang4
1435
+ sang5 s ang5
1436
+ sao1 s ao1
1437
+ sao2 s ao2
1438
+ sao3 s ao3
1439
+ sao4 s ao4
1440
+ sao5 s ao5
1441
+ se1 s e1
1442
+ se2 s e2
1443
+ se3 s e3
1444
+ se4 s e4
1445
+ se5 s e5
1446
+ sen1 s en1
1447
+ sen2 s en2
1448
+ sen3 s en3
1449
+ sen4 s en4
1450
+ sen5 s en5
1451
+ seng1 s eng1
1452
+ seng2 s eng2
1453
+ seng3 s eng3
1454
+ seng4 s eng4
1455
+ seng5 s eng5
1456
+ sha1 sh a1
1457
+ sha2 sh a2
1458
+ sha3 sh a3
1459
+ sha4 sh a4
1460
+ sha5 sh a5
1461
+ shai1 sh ai1
1462
+ shai2 sh ai2
1463
+ shai3 sh ai3
1464
+ shai4 sh ai4
1465
+ shai5 sh ai5
1466
+ shan1 sh an1
1467
+ shan2 sh an2
1468
+ shan3 sh an3
1469
+ shan4 sh an4
1470
+ shan5 sh an5
1471
+ shang1 sh ang1
1472
+ shang2 sh ang2
1473
+ shang3 sh ang3
1474
+ shang4 sh ang4
1475
+ shang5 sh ang5
1476
+ shao1 sh ao1
1477
+ shao2 sh ao2
1478
+ shao3 sh ao3
1479
+ shao4 sh ao4
1480
+ shao5 sh ao5
1481
+ she1 sh e1
1482
+ she2 sh e2
1483
+ she3 sh e3
1484
+ she4 sh e4
1485
+ she5 sh e5
1486
+ shei1 sh ei1
1487
+ shei2 sh ei2
1488
+ shei3 sh ei3
1489
+ shei4 sh ei4
1490
+ shei5 sh ei5
1491
+ shen1 sh en1
1492
+ shen2 sh en2
1493
+ shen3 sh en3
1494
+ shen4 sh en4
1495
+ shen5 sh en5
1496
+ sheng1 sh eng1
1497
+ sheng2 sh eng2
1498
+ sheng3 sh eng3
1499
+ sheng4 sh eng4
1500
+ sheng5 sh eng5
1501
+ shi1 sh iii1
1502
+ shi2 sh iii2
1503
+ shi3 sh iii3
1504
+ shi4 sh iii4
1505
+ shi5 sh iii5
1506
+ shou1 sh ou1
1507
+ shou2 sh ou2
1508
+ shou3 sh ou3
1509
+ shou4 sh ou4
1510
+ shou5 sh ou5
1511
+ shu1 sh u1
1512
+ shu2 sh u2
1513
+ shu3 sh u3
1514
+ shu4 sh u4
1515
+ shu5 sh u5
1516
+ shua1 sh ua1
1517
+ shua2 sh ua2
1518
+ shua3 sh ua3
1519
+ shua4 sh ua4
1520
+ shua5 sh ua5
1521
+ shuai1 sh uai1
1522
+ shuai2 sh uai2
1523
+ shuai3 sh uai3
1524
+ shuai4 sh uai4
1525
+ shuai5 sh uai5
1526
+ shuan1 sh uan1
1527
+ shuan2 sh uan2
1528
+ shuan3 sh uan3
1529
+ shuan4 sh uan4
1530
+ shuan5 sh uan5
1531
+ shuang1 sh uang1
1532
+ shuang2 sh uang2
1533
+ shuang3 sh uang3
1534
+ shuang4 sh uang4
1535
+ shuang5 sh uang5
1536
+ shui1 sh uei1
1537
+ shui2 sh uei2
1538
+ shui3 sh uei3
1539
+ shui4 sh uei4
1540
+ shui5 sh uei5
1541
+ shun1 sh uen1
1542
+ shun2 sh uen2
1543
+ shun3 sh uen3
1544
+ shun4 sh uen4
1545
+ shun5 sh uen5
1546
+ shuo1 sh uo1
1547
+ shuo2 sh uo2
1548
+ shuo3 sh uo3
1549
+ shuo4 sh uo4
1550
+ shuo5 sh uo5
1551
+ si1 s ii1
1552
+ si2 s ii2
1553
+ si3 s ii3
1554
+ si4 s ii4
1555
+ si5 s ii5
1556
+ song1 s ong1
1557
+ song2 s ong2
1558
+ song3 s ong3
1559
+ song4 s ong4
1560
+ song5 s ong5
1561
+ sou1 s ou1
1562
+ sou2 s ou2
1563
+ sou3 s ou3
1564
+ sou4 s ou4
1565
+ sou5 s ou5
1566
+ su1 s u1
1567
+ su2 s u2
1568
+ su3 s u3
1569
+ su4 s u4
1570
+ su5 s u5
1571
+ suan1 s uan1
1572
+ suan2 s uan2
1573
+ suan3 s uan3
1574
+ suan4 s uan4
1575
+ suan5 s uan5
1576
+ sui1 s uei1
1577
+ sui2 s uei2
1578
+ sui3 s uei3
1579
+ sui4 s uei4
1580
+ sui5 s uei5
1581
+ sun1 s uen1
1582
+ sun2 s uen2
1583
+ sun3 s uen3
1584
+ sun4 s uen4
1585
+ sun5 s uen5
1586
+ suo1 s uo1
1587
+ suo2 s uo2
1588
+ suo3 s uo3
1589
+ suo4 s uo4
1590
+ suo5 s uo5
1591
+ ta1 t a1
1592
+ ta2 t a2
1593
+ ta3 t a3
1594
+ ta4 t a4
1595
+ ta5 t a5
1596
+ tai1 t ai1
1597
+ tai2 t ai2
1598
+ tai3 t ai3
1599
+ tai4 t ai4
1600
+ tai5 t ai5
1601
+ tan1 t an1
1602
+ tan2 t an2
1603
+ tan3 t an3
1604
+ tan4 t an4
1605
+ tan5 t an5
1606
+ tang1 t ang1
1607
+ tang2 t ang2
1608
+ tang3 t ang3
1609
+ tang4 t ang4
1610
+ tang5 t ang5
1611
+ tao1 t ao1
1612
+ tao2 t ao2
1613
+ tao3 t ao3
1614
+ tao4 t ao4
1615
+ tao5 t ao5
1616
+ te1 t e1
1617
+ te2 t e2
1618
+ te3 t e3
1619
+ te4 t e4
1620
+ te5 t e5
1621
+ tei1 t ei1
1622
+ tei2 t ei2
1623
+ tei3 t ei3
1624
+ tei4 t ei4
1625
+ tei5 t ei5
1626
+ teng1 t eng1
1627
+ teng2 t eng2
1628
+ teng3 t eng3
1629
+ teng4 t eng4
1630
+ teng5 t eng5
1631
+ ti1 t i1
1632
+ ti2 t i2
1633
+ ti3 t i3
1634
+ ti4 t i4
1635
+ ti5 t i5
1636
+ tian1 t ian1
1637
+ tian2 t ian2
1638
+ tian3 t ian3
1639
+ tian4 t ian4
1640
+ tian5 t ian5
1641
+ tiao1 t iao1
1642
+ tiao2 t iao2
1643
+ tiao3 t iao3
1644
+ tiao4 t iao4
1645
+ tiao5 t iao5
1646
+ tie1 t ie1
1647
+ tie2 t ie2
1648
+ tie3 t ie3
1649
+ tie4 t ie4
1650
+ tie5 t ie5
1651
+ ting1 t ing1
1652
+ ting2 t ing2
1653
+ ting3 t ing3
1654
+ ting4 t ing4
1655
+ ting5 t ing5
1656
+ tong1 t ong1
1657
+ tong2 t ong2
1658
+ tong3 t ong3
1659
+ tong4 t ong4
1660
+ tong5 t ong5
1661
+ tou1 t ou1
1662
+ tou2 t ou2
1663
+ tou3 t ou3
1664
+ tou4 t ou4
1665
+ tou5 t ou5
1666
+ tu1 t u1
1667
+ tu2 t u2
1668
+ tu3 t u3
1669
+ tu4 t u4
1670
+ tu5 t u5
1671
+ tuan1 t uan1
1672
+ tuan2 t uan2
1673
+ tuan3 t uan3
1674
+ tuan4 t uan4
1675
+ tuan5 t uan5
1676
+ tui1 t uei1
1677
+ tui2 t uei2
1678
+ tui3 t uei3
1679
+ tui4 t uei4
1680
+ tui5 t uei5
1681
+ tun1 t uen1
1682
+ tun2 t uen2
1683
+ tun3 t uen3
1684
+ tun4 t uen4
1685
+ tun5 t uen5
1686
+ tuo1 t uo1
1687
+ tuo2 t uo2
1688
+ tuo3 t uo3
1689
+ tuo4 t uo4
1690
+ tuo5 t uo5
1691
+ wa1 w ua1
1692
+ wa2 w ua2
1693
+ wa3 w ua3
1694
+ wa4 w ua4
1695
+ wa5 w ua5
1696
+ wai1 w uai1
1697
+ wai2 w uai2
1698
+ wai3 w uai3
1699
+ wai4 w uai4
1700
+ wai5 w uai5
1701
+ wan1 w uan1
1702
+ wan2 w uan2
1703
+ wan3 w uan3
1704
+ wan4 w uan4
1705
+ wan5 w uan5
1706
+ wang1 w uang1
1707
+ wang2 w uang2
1708
+ wang3 w uang3
1709
+ wang4 w uang4
1710
+ wang5 w uang5
1711
+ wei1 w uei1
1712
+ wei2 w uei2
1713
+ wei3 w uei3
1714
+ wei4 w uei4
1715
+ wei5 w uei5
1716
+ wen1 w uen1
1717
+ wen2 w uen2
1718
+ wen3 w uen3
1719
+ wen4 w uen4
1720
+ wen5 w uen5
1721
+ weng1 w uen1
1722
+ weng2 w uen2
1723
+ weng3 w uen3
1724
+ weng4 w uen4
1725
+ weng5 w uen5
1726
+ wo1 w uo1
1727
+ wo2 w uo2
1728
+ wo3 w uo3
1729
+ wo4 w uo4
1730
+ wo5 w uo5
1731
+ wu1 w u1
1732
+ wu2 w u2
1733
+ wu3 w u3
1734
+ wu4 w u4
1735
+ wu5 w u5
1736
+ xi1 x i1
1737
+ xi2 x i2
1738
+ xi3 x i3
1739
+ xi4 x i4
1740
+ xi5 x i5
1741
+ xia1 x ia1
1742
+ xia2 x ia2
1743
+ xia3 x ia3
1744
+ xia4 x ia4
1745
+ xia5 x ia5
1746
+ xian1 x ian1
1747
+ xian2 x ian2
1748
+ xian3 x ian3
1749
+ xian4 x ian4
1750
+ xian5 x ian5
1751
+ xiang1 x iang1
1752
+ xiang2 x iang2
1753
+ xiang3 x iang3
1754
+ xiang4 x iang4
1755
+ xiang5 x iang5
1756
+ xiao1 x iao1
1757
+ xiao2 x iao2
1758
+ xiao3 x iao3
1759
+ xiao4 x iao4
1760
+ xiao5 x iao5
1761
+ xie1 x ie1
1762
+ xie2 x ie2
1763
+ xie3 x ie3
1764
+ xie4 x ie4
1765
+ xie5 x ie5
1766
+ xin1 x in1
1767
+ xin2 x in2
1768
+ xin3 x in3
1769
+ xin4 x in4
1770
+ xin5 x in5
1771
+ xing1 x ing1
1772
+ xing2 x ing2
1773
+ xing3 x ing3
1774
+ xing4 x ing4
1775
+ xing5 x ing5
1776
+ xiong1 x iong1
1777
+ xiong2 x iong2
1778
+ xiong3 x iong3
1779
+ xiong4 x iong4
1780
+ xiong5 x iong5
1781
+ xiu1 x iou1
1782
+ xiu2 x iou2
1783
+ xiu3 x iou3
1784
+ xiu4 x iou4
1785
+ xiu5 x iou5
1786
+ xu1 x v1
1787
+ xu2 x v2
1788
+ xu3 x v3
1789
+ xu4 x v4
1790
+ xu5 x v5
1791
+ xuan1 x van1
1792
+ xuan2 x van2
1793
+ xuan3 x van3
1794
+ xuan4 x van4
1795
+ xuan5 x van5
1796
+ xue1 x ve1
1797
+ xue2 x ve2
1798
+ xue3 x ve3
1799
+ xue4 x ve4
1800
+ xue5 x ve5
1801
+ xun1 x vn1
1802
+ xun2 x vn2
1803
+ xun3 x vn3
1804
+ xun4 x vn4
1805
+ xun5 x vn5
1806
+ ya1 y ia1
1807
+ ya2 y ia2
1808
+ ya3 y ia3
1809
+ ya4 y ia4
1810
+ ya5 y ia5
1811
+ yan1 y ian1
1812
+ yan2 y ian2
1813
+ yan3 y ian3
1814
+ yan4 y ian4
1815
+ yan5 y ian5
1816
+ yang1 y iang1
1817
+ yang2 y iang2
1818
+ yang3 y iang3
1819
+ yang4 y iang4
1820
+ yang5 y iang5
1821
+ yao1 y iao1
1822
+ yao2 y iao2
1823
+ yao3 y iao3
1824
+ yao4 y iao4
1825
+ yao5 y iao5
1826
+ ye1 y ie1
1827
+ ye2 y ie2
1828
+ ye3 y ie3
1829
+ ye4 y ie4
1830
+ ye5 y ie5
1831
+ yi1 y i1
1832
+ yi2 y i2
1833
+ yi3 y i3
1834
+ yi4 y i4
1835
+ yi5 y i5
1836
+ yin1 y in1
1837
+ yin2 y in2
1838
+ yin3 y in3
1839
+ yin4 y in4
1840
+ yin5 y in5
1841
+ ying1 y ing1
1842
+ ying2 y ing2
1843
+ ying3 y ing3
1844
+ ying4 y ing4
1845
+ ying5 y ing5
1846
+ yo1 y iou1
1847
+ yo2 y iou2
1848
+ yo3 y iou3
1849
+ yo4 y iou4
1850
+ yo5 y iou5
1851
+ yong1 y iong1
1852
+ yong2 y iong2
1853
+ yong3 y iong3
1854
+ yong4 y iong4
1855
+ yong5 y iong5
1856
+ you1 y iou1
1857
+ you2 y iou2
1858
+ you3 y iou3
1859
+ you4 y iou4
1860
+ you5 y iou5
1861
+ yu1 y v1
1862
+ yu2 y v2
1863
+ yu3 y v3
1864
+ yu4 y v4
1865
+ yu5 y v5
1866
+ yuan1 y van1
1867
+ yuan2 y van2
1868
+ yuan3 y van3
1869
+ yuan4 y van4
1870
+ yuan5 y van5
1871
+ yue1 y ve1
1872
+ yue2 y ve2
1873
+ yue3 y ve3
1874
+ yue4 y ve4
1875
+ yue5 y ve5
1876
+ yun1 y vn1
1877
+ yun2 y vn2
1878
+ yun3 y vn3
1879
+ yun4 y vn4
1880
+ yun5 y vn5
1881
+ za1 z a1
1882
+ za2 z a2
1883
+ za3 z a3
1884
+ za4 z a4
1885
+ za5 z a5
1886
+ zai1 z ai1
1887
+ zai2 z ai2
1888
+ zai3 z ai3
1889
+ zai4 z ai4
1890
+ zai5 z ai5
1891
+ zan1 z an1
1892
+ zan2 z an2
1893
+ zan3 z an3
1894
+ zan4 z an4
1895
+ zan5 z an5
1896
+ zang1 z ang1
1897
+ zang2 z ang2
1898
+ zang3 z ang3
1899
+ zang4 z ang4
1900
+ zang5 z ang5
1901
+ zao1 z ao1
1902
+ zao2 z ao2
1903
+ zao3 z ao3
1904
+ zao4 z ao4
1905
+ zao5 z ao5
1906
+ ze1 z e1
1907
+ ze2 z e2
1908
+ ze3 z e3
1909
+ ze4 z e4
1910
+ ze5 z e5
1911
+ zei1 z ei1
1912
+ zei2 z ei2
1913
+ zei3 z ei3
1914
+ zei4 z ei4
1915
+ zei5 z ei5
1916
+ zen1 z en1
1917
+ zen2 z en2
1918
+ zen3 z en3
1919
+ zen4 z en4
1920
+ zen5 z en5
1921
+ zeng1 z eng1
1922
+ zeng2 z eng2
1923
+ zeng3 z eng3
1924
+ zeng4 z eng4
1925
+ zeng5 z eng5
1926
+ zha1 zh a1
1927
+ zha2 zh a2
1928
+ zha3 zh a3
1929
+ zha4 zh a4
1930
+ zha5 zh a5
1931
+ zhai1 zh ai1
1932
+ zhai2 zh ai2
1933
+ zhai3 zh ai3
1934
+ zhai4 zh ai4
1935
+ zhai5 zh ai5
1936
+ zhan1 zh an1
1937
+ zhan2 zh an2
1938
+ zhan3 zh an3
1939
+ zhan4 zh an4
1940
+ zhan5 zh an5
1941
+ zhang1 zh ang1
1942
+ zhang2 zh ang2
1943
+ zhang3 zh ang3
1944
+ zhang4 zh ang4
1945
+ zhang5 zh ang5
1946
+ zhao1 zh ao1
1947
+ zhao2 zh ao2
1948
+ zhao3 zh ao3
1949
+ zhao4 zh ao4
1950
+ zhao5 zh ao5
1951
+ zhe1 zh e1
1952
+ zhe2 zh e2
1953
+ zhe3 zh e3
1954
+ zhe4 zh e4
1955
+ zhe5 zh e5
1956
+ zhei1 zh ei1
1957
+ zhei2 zh ei2
1958
+ zhei3 zh ei3
1959
+ zhei4 zh ei4
1960
+ zhei5 zh ei5
1961
+ zhen1 zh en1
1962
+ zhen2 zh en2
1963
+ zhen3 zh en3
1964
+ zhen4 zh en4
1965
+ zhen5 zh en5
1966
+ zheng1 zh eng1
1967
+ zheng2 zh eng2
1968
+ zheng3 zh eng3
1969
+ zheng4 zh eng4
1970
+ zheng5 zh eng5
1971
+ zhi1 zh iii1
1972
+ zhi2 zh iii2
1973
+ zhi3 zh iii3
1974
+ zhi4 zh iii4
1975
+ zhi5 zh iii5
1976
+ zhong1 zh ong1
1977
+ zhong2 zh ong2
1978
+ zhong3 zh ong3
1979
+ zhong4 zh ong4
1980
+ zhong5 zh ong5
1981
+ zhou1 zh ou1
1982
+ zhou2 zh ou2
1983
+ zhou3 zh ou3
1984
+ zhou4 zh ou4
1985
+ zhou5 zh ou5
1986
+ zhu1 zh u1
1987
+ zhu2 zh u2
1988
+ zhu3 zh u3
1989
+ zhu4 zh u4
1990
+ zhu5 zh u5
1991
+ zhua1 zh ua1
1992
+ zhua2 zh ua2
1993
+ zhua3 zh ua3
1994
+ zhua4 zh ua4
1995
+ zhua5 zh ua5
1996
+ zhuai1 zh uai1
1997
+ zhuai2 zh uai2
1998
+ zhuai3 zh uai3
1999
+ zhuai4 zh uai4
2000
+ zhuai5 zh uai5
2001
+ zhuan1 zh uan1
2002
+ zhuan2 zh uan2
2003
+ zhuan3 zh uan3
2004
+ zhuan4 zh uan4
2005
+ zhuan5 zh uan5
2006
+ zhuang1 zh uang1
2007
+ zhuang2 zh uang2
2008
+ zhuang3 zh uang3
2009
+ zhuang4 zh uang4
2010
+ zhuang5 zh uang5
2011
+ zhui1 zh uei1
2012
+ zhui2 zh uei2
2013
+ zhui3 zh uei3
2014
+ zhui4 zh uei4
2015
+ zhui5 zh uei5
2016
+ zhun1 zh uen1
2017
+ zhun2 zh uen2
2018
+ zhun3 zh uen3
2019
+ zhun4 zh uen4
2020
+ zhun5 zh uen5
2021
+ zhuo1 zh uo1
2022
+ zhuo2 zh uo2
2023
+ zhuo3 zh uo3
2024
+ zhuo4 zh uo4
2025
+ zhuo5 zh uo5
2026
+ zi1 z ii1
2027
+ zi2 z ii2
2028
+ zi3 z ii3
2029
+ zi4 z ii4
2030
+ zi5 z ii5
2031
+ zong1 z ong1
2032
+ zong2 z ong2
2033
+ zong3 z ong3
2034
+ zong4 z ong4
2035
+ zong5 z ong5
2036
+ zou1 z ou1
2037
+ zou2 z ou2
2038
+ zou3 z ou3
2039
+ zou4 z ou4
2040
+ zou5 z ou5
2041
+ zu1 z u1
2042
+ zu2 z u2
2043
+ zu3 z u3
2044
+ zu4 z u4
2045
+ zu5 z u5
2046
+ zuan1 z uan1
2047
+ zuan2 z uan2
2048
+ zuan3 z uan3
2049
+ zuan4 z uan4
2050
+ zuan5 z uan5
2051
+ zui1 z uei1
2052
+ zui2 z uei2
2053
+ zui3 z uei3
2054
+ zui4 z uei4
2055
+ zui5 z uei5
2056
+ zun1 z uen1
2057
+ zun2 z uen2
2058
+ zun3 z uen3
2059
+ zun4 z uen4
2060
+ zun5 z uen5
2061
+ zuo1 z uo1
2062
+ zuo2 z uo2
2063
+ zuo3 z uo3
2064
+ zuo4 z uo4
2065
+ zuo5 z uo5
2066
+ ar1 a1 rr
2067
+ ar2 a2 rr
2068
+ ar3 a3 rr
2069
+ ar4 a4 rr
2070
+ ar5 a5 rr
2071
+ air1 ai1 rr
2072
+ air2 ai2 rr
2073
+ air3 ai3 rr
2074
+ air4 ai4 rr
2075
+ air5 ai5 rr
2076
+ anr1 an1 rr
2077
+ anr2 an2 rr
2078
+ anr3 an3 rr
2079
+ anr4 an4 rr
2080
+ anr5 an5 rr
2081
+ angr1 ang1 rr
2082
+ angr2 ang2 rr
2083
+ angr3 ang3 rr
2084
+ angr4 ang4 rr
2085
+ angr5 ang5 rr
2086
+ aor1 ao1 rr
2087
+ aor2 ao2 rr
2088
+ aor3 ao3 rr
2089
+ aor4 ao4 rr
2090
+ aor5 ao5 rr
2091
+ bar1 b a1 rr
2092
+ bar2 b a2 rr
2093
+ bar3 b a3 rr
2094
+ bar4 b a4 rr
2095
+ bar5 b a5 rr
2096
+ bair1 b ai1 rr
2097
+ bair2 b ai2 rr
2098
+ bair3 b ai3 rr
2099
+ bair4 b ai4 rr
2100
+ bair5 b ai5 rr
2101
+ banr1 b an1 rr
2102
+ banr2 b an2 rr
2103
+ banr3 b an3 rr
2104
+ banr4 b an4 rr
2105
+ banr5 b an5 rr
2106
+ bangr1 b ang1 rr
2107
+ bangr2 b ang2 rr
2108
+ bangr3 b ang3 rr
2109
+ bangr4 b ang4 rr
2110
+ bangr5 b ang5 rr
2111
+ baor1 b ao1 rr
2112
+ baor2 b ao2 rr
2113
+ baor3 b ao3 rr
2114
+ baor4 b ao4 rr
2115
+ baor5 b ao5 rr
2116
+ beir1 b ei1 rr
2117
+ beir2 b ei2 rr
2118
+ beir3 b ei3 rr
2119
+ beir4 b ei4 rr
2120
+ beir5 b ei5 rr
2121
+ benr1 b en1 rr
2122
+ benr2 b en2 rr
2123
+ benr3 b en3 rr
2124
+ benr4 b en4 rr
2125
+ benr5 b en5 rr
2126
+ bengr1 b eng1 rr
2127
+ bengr2 b eng2 rr
2128
+ bengr3 b eng3 rr
2129
+ bengr4 b eng4 rr
2130
+ bengr5 b eng5 rr
2131
+ bir1 b i1 rr
2132
+ bir2 b i2 rr
2133
+ bir3 b i3 rr
2134
+ bir4 b i4 rr
2135
+ bir5 b i5 rr
2136
+ bianr1 b ian1 rr
2137
+ bianr2 b ian2 rr
2138
+ bianr3 b ian3 rr
2139
+ bianr4 b ian4 rr
2140
+ bianr5 b ian5 rr
2141
+ biaor1 b iao1 rr
2142
+ biaor2 b iao2 rr
2143
+ biaor3 b iao3 rr
2144
+ biaor4 b iao4 rr
2145
+ biaor5 b iao5 rr
2146
+ bier1 b ie1 rr
2147
+ bier2 b ie2 rr
2148
+ bier3 b ie3 rr
2149
+ bier4 b ie4 rr
2150
+ bier5 b ie5 rr
2151
+ binr1 b in1 rr
2152
+ binr2 b in2 rr
2153
+ binr3 b in3 rr
2154
+ binr4 b in4 rr
2155
+ binr5 b in5 rr
2156
+ bingr1 b ing1 rr
2157
+ bingr2 b ing2 rr
2158
+ bingr3 b ing3 rr
2159
+ bingr4 b ing4 rr
2160
+ bingr5 b ing5 rr
2161
+ bor1 b o1 rr
2162
+ bor2 b o2 rr
2163
+ bor3 b o3 rr
2164
+ bor4 b o4 rr
2165
+ bor5 b o5 rr
2166
+ bur1 b u1 rr
2167
+ bur2 b u2 rr
2168
+ bur3 b u3 rr
2169
+ bur4 b u4 rr
2170
+ bur5 b u5 rr
2171
+ car1 c a1 rr
2172
+ car2 c a2 rr
2173
+ car3 c a3 rr
2174
+ car4 c a4 rr
2175
+ car5 c a5 rr
2176
+ cair1 c ai1 rr
2177
+ cair2 c ai2 rr
2178
+ cair3 c ai3 rr
2179
+ cair4 c ai4 rr
2180
+ cair5 c ai5 rr
2181
+ canr1 c an1 rr
2182
+ canr2 c an2 rr
2183
+ canr3 c an3 rr
2184
+ canr4 c an4 rr
2185
+ canr5 c an5 rr
2186
+ cangr1 c ang1 rr
2187
+ cangr2 c ang2 rr
2188
+ cangr3 c ang3 rr
2189
+ cangr4 c ang4 rr
2190
+ cangr5 c ang5 rr
2191
+ caor1 c ao1 rr
2192
+ caor2 c ao2 rr
2193
+ caor3 c ao3 rr
2194
+ caor4 c ao4 rr
2195
+ caor5 c ao5 rr
2196
+ cer1 c e1 rr
2197
+ cer2 c e2 rr
2198
+ cer3 c e3 rr
2199
+ cer4 c e4 rr
2200
+ cer5 c e5 rr
2201
+ cenr1 c en1 rr
2202
+ cenr2 c en2 rr
2203
+ cenr3 c en3 rr
2204
+ cenr4 c en4 rr
2205
+ cenr5 c en5 rr
2206
+ cengr1 c eng1 rr
2207
+ cengr2 c eng2 rr
2208
+ cengr3 c eng3 rr
2209
+ cengr4 c eng4 rr
2210
+ cengr5 c eng5 rr
2211
+ char1 ch a1 rr
2212
+ char2 ch a2 rr
2213
+ char3 ch a3 rr
2214
+ char4 ch a4 rr
2215
+ char5 ch a5 rr
2216
+ chair1 ch ai1 rr
2217
+ chair2 ch ai2 rr
2218
+ chair3 ch ai3 rr
2219
+ chair4 ch ai4 rr
2220
+ chair5 ch ai5 rr
2221
+ chanr1 ch an1 rr
2222
+ chanr2 ch an2 rr
2223
+ chanr3 ch an3 rr
2224
+ chanr4 ch an4 rr
2225
+ chanr5 ch an5 rr
2226
+ changr1 ch ang1 rr
2227
+ changr2 ch ang2 rr
2228
+ changr3 ch ang3 rr
2229
+ changr4 ch ang4 rr
2230
+ changr5 ch ang5 rr
2231
+ chaor1 ch ao1 rr
2232
+ chaor2 ch ao2 rr
2233
+ chaor3 ch ao3 rr
2234
+ chaor4 ch ao4 rr
2235
+ chaor5 ch ao5 rr
2236
+ cher1 ch e1 rr
2237
+ cher2 ch e2 rr
2238
+ cher3 ch e3 rr
2239
+ cher4 ch e4 rr
2240
+ cher5 ch e5 rr
2241
+ chenr1 ch en1 rr
2242
+ chenr2 ch en2 rr
2243
+ chenr3 ch en3 rr
2244
+ chenr4 ch en4 rr
2245
+ chenr5 ch en5 rr
2246
+ chengr1 ch eng1 rr
2247
+ chengr2 ch eng2 rr
2248
+ chengr3 ch eng3 rr
2249
+ chengr4 ch eng4 rr
2250
+ chengr5 ch eng5 rr
2251
+ chir1 ch iii1 rr
2252
+ chir2 ch iii2 rr
2253
+ chir3 ch iii3 rr
2254
+ chir4 ch iii4 rr
2255
+ chir5 ch iii5 rr
2256
+ chongr1 ch ong1 rr
2257
+ chongr2 ch ong2 rr
2258
+ chongr3 ch ong3 rr
2259
+ chongr4 ch ong4 rr
2260
+ chongr5 ch ong5 rr
2261
+ chour1 ch ou1 rr
2262
+ chour2 ch ou2 rr
2263
+ chour3 ch ou3 rr
2264
+ chour4 ch ou4 rr
2265
+ chour5 ch ou5 rr
2266
+ chur1 ch u1 rr
2267
+ chur2 ch u2 rr
2268
+ chur3 ch u3 rr
2269
+ chur4 ch u4 rr
2270
+ chur5 ch u5 rr
2271
+ chuair1 ch uai1 rr
2272
+ chuair2 ch uai2 rr
2273
+ chuair3 ch uai3 rr
2274
+ chuair4 ch uai4 rr
2275
+ chuair5 ch uai5 rr
2276
+ chuanr1 ch uan1 rr
2277
+ chuanr2 ch uan2 rr
2278
+ chuanr3 ch uan3 rr
2279
+ chuanr4 ch uan4 rr
2280
+ chuanr5 ch uan5 rr
2281
+ chuangr1 ch uang1 rr
2282
+ chuangr2 ch uang2 rr
2283
+ chuangr3 ch uang3 rr
2284
+ chuangr4 ch uang4 rr
2285
+ chuangr5 ch uang5 rr
2286
+ chuir1 ch uei1 rr
2287
+ chuir2 ch uei2 rr
2288
+ chuir3 ch uei3 rr
2289
+ chuir4 ch uei4 rr
2290
+ chuir5 ch uei5 rr
2291
+ chunr1 ch uen1 rr
2292
+ chunr2 ch uen2 rr
2293
+ chunr3 ch uen3 rr
2294
+ chunr4 ch uen4 rr
2295
+ chunr5 ch uen5 rr
2296
+ chuor1 ch uo1 rr
2297
+ chuor2 ch uo2 rr
2298
+ chuor3 ch uo3 rr
2299
+ chuor4 ch uo4 rr
2300
+ chuor5 ch uo5 rr
2301
+ cir1 c ii1 rr
2302
+ cir2 c ii2 rr
2303
+ cir3 c ii3 rr
2304
+ cir4 c ii4 rr
2305
+ cir5 c ii5 rr
2306
+ congr1 c ong1 rr
2307
+ congr2 c ong2 rr
2308
+ congr3 c ong3 rr
2309
+ congr4 c ong4 rr
2310
+ congr5 c ong5 rr
2311
+ cour1 c ou1 rr
2312
+ cour2 c ou2 rr
2313
+ cour3 c ou3 rr
2314
+ cour4 c ou4 rr
2315
+ cour5 c ou5 rr
2316
+ cur1 c u1 rr
2317
+ cur2 c u2 rr
2318
+ cur3 c u3 rr
2319
+ cur4 c u4 rr
2320
+ cur5 c u5 rr
2321
+ cuanr1 c uan1 rr
2322
+ cuanr2 c uan2 rr
2323
+ cuanr3 c uan3 rr
2324
+ cuanr4 c uan4 rr
2325
+ cuanr5 c uan5 rr
2326
+ cuir1 c uei1 rr
2327
+ cuir2 c uei2 rr
2328
+ cuir3 c uei3 rr
2329
+ cuir4 c uei4 rr
2330
+ cuir5 c uei5 rr
2331
+ cunr1 c uen1 rr
2332
+ cunr2 c uen2 rr
2333
+ cunr3 c uen3 rr
2334
+ cunr4 c uen4 rr
2335
+ cunr5 c uen5 rr
2336
+ cuor1 c uo1 rr
2337
+ cuor2 c uo2 rr
2338
+ cuor3 c uo3 rr
2339
+ cuor4 c uo4 rr
2340
+ cuor5 c uo5 rr
2341
+ dar1 d a1 rr
2342
+ dar2 d a2 rr
2343
+ dar3 d a3 rr
2344
+ dar4 d a4 rr
2345
+ dar5 d a5 rr
2346
+ dair1 d ai1 rr
2347
+ dair2 d ai2 rr
2348
+ dair3 d ai3 rr
2349
+ dair4 d ai4 rr
2350
+ dair5 d ai5 rr
2351
+ danr1 d an1 rr
2352
+ danr2 d an2 rr
2353
+ danr3 d an3 rr
2354
+ danr4 d an4 rr
2355
+ danr5 d an5 rr
2356
+ dangr1 d ang1 rr
2357
+ dangr2 d ang2 rr
2358
+ dangr3 d ang3 rr
2359
+ dangr4 d ang4 rr
2360
+ dangr5 d ang5 rr
2361
+ daor1 d ao1 rr
2362
+ daor2 d ao2 rr
2363
+ daor3 d ao3 rr
2364
+ daor4 d ao4 rr
2365
+ daor5 d ao5 rr
2366
+ der1 d e1 rr
2367
+ der2 d e2 rr
2368
+ der3 d e3 rr
2369
+ der4 d e4 rr
2370
+ der5 d e5 rr
2371
+ deir1 d ei1 rr
2372
+ deir2 d ei2 rr
2373
+ deir3 d ei3 rr
2374
+ deir4 d ei4 rr
2375
+ deir5 d ei5 rr
2376
+ denr1 d en1 rr
2377
+ denr2 d en2 rr
2378
+ denr3 d en3 rr
2379
+ denr4 d en4 rr
2380
+ denr5 d en5 rr
2381
+ dengr1 d eng1 rr
2382
+ dengr2 d eng2 rr
2383
+ dengr3 d eng3 rr
2384
+ dengr4 d eng4 rr
2385
+ dengr5 d eng5 rr
2386
+ dir1 d i1 rr
2387
+ dir2 d i2 rr
2388
+ dir3 d i3 rr
2389
+ dir4 d i4 rr
2390
+ dir5 d i5 rr
2391
+ diar1 d ia1 rr
2392
+ diar2 d ia2 rr
2393
+ diar3 d ia3 rr
2394
+ diar4 d ia4 rr
2395
+ diar5 d ia5 rr
2396
+ dianr1 d ian1 rr
2397
+ dianr2 d ian2 rr
2398
+ dianr3 d ian3 rr
2399
+ dianr4 d ian4 rr
2400
+ dianr5 d ian5 rr
2401
+ diaor1 d iao1 rr
2402
+ diaor2 d iao2 rr
2403
+ diaor3 d iao3 rr
2404
+ diaor4 d iao4 rr
2405
+ diaor5 d iao5 rr
2406
+ dier1 d ie1 rr
2407
+ dier2 d ie2 rr
2408
+ dier3 d ie3 rr
2409
+ dier4 d ie4 rr
2410
+ dier5 d ie5 rr
2411
+ dingr1 d ing1 rr
2412
+ dingr2 d ing2 rr
2413
+ dingr3 d ing3 rr
2414
+ dingr4 d ing4 rr
2415
+ dingr5 d ing5 rr
2416
+ diur1 d iou1 rr
2417
+ diur2 d iou2 rr
2418
+ diur3 d iou3 rr
2419
+ diur4 d iou4 rr
2420
+ diur5 d iou5 rr
2421
+ dongr1 d ong1 rr
2422
+ dongr2 d ong2 rr
2423
+ dongr3 d ong3 rr
2424
+ dongr4 d ong4 rr
2425
+ dongr5 d ong5 rr
2426
+ dour1 d ou1 rr
2427
+ dour2 d ou2 rr
2428
+ dour3 d ou3 rr
2429
+ dour4 d ou4 rr
2430
+ dour5 d ou5 rr
2431
+ dur1 d u1 rr
2432
+ dur2 d u2 rr
2433
+ dur3 d u3 rr
2434
+ dur4 d u4 rr
2435
+ dur5 d u5 rr
2436
+ duanr1 d uan1 rr
2437
+ duanr2 d uan2 rr
2438
+ duanr3 d uan3 rr
2439
+ duanr4 d uan4 rr
2440
+ duanr5 d uan5 rr
2441
+ duir1 d uei1 rr
2442
+ duir2 d uei2 rr
2443
+ duir3 d uei3 rr
2444
+ duir4 d uei4 rr
2445
+ duir5 d uei5 rr
2446
+ dunr1 d uen1 rr
2447
+ dunr2 d uen2 rr
2448
+ dunr3 d uen3 rr
2449
+ dunr4 d uen4 rr
2450
+ dunr5 d uen5 rr
2451
+ duor1 d uo1 rr
2452
+ duor2 d uo2 rr
2453
+ duor3 d uo3 rr
2454
+ duor4 d uo4 rr
2455
+ duor5 d uo5 rr
2456
+ er1 e1 rr
2457
+ er2 e2 rr
2458
+ er3 e3 rr
2459
+ er4 e4 rr
2460
+ er5 e5 rr
2461
+ eir1 ei1 rr
2462
+ eir2 ei2 rr
2463
+ eir3 ei3 rr
2464
+ eir4 ei4 rr
2465
+ eir5 ei5 rr
2466
+ enr1 en1 rr
2467
+ enr2 en2 rr
2468
+ enr3 en3 rr
2469
+ enr4 en4 rr
2470
+ enr5 en5 rr
2471
+ engr1 eng1 rr
2472
+ engr2 eng2 rr
2473
+ engr3 eng3 rr
2474
+ engr4 eng4 rr
2475
+ engr5 eng5 rr
2476
+ far1 f a1 rr
2477
+ far2 f a2 rr
2478
+ far3 f a3 rr
2479
+ far4 f a4 rr
2480
+ far5 f a5 rr
2481
+ fanr1 f an1 rr
2482
+ fanr2 f an2 rr
2483
+ fanr3 f an3 rr
2484
+ fanr4 f an4 rr
2485
+ fanr5 f an5 rr
2486
+ fangr1 f ang1 rr
2487
+ fangr2 f ang2 rr
2488
+ fangr3 f ang3 rr
2489
+ fangr4 f ang4 rr
2490
+ fangr5 f ang5 rr
2491
+ feir1 f ei1 rr
2492
+ feir2 f ei2 rr
2493
+ feir3 f ei3 rr
2494
+ feir4 f ei4 rr
2495
+ feir5 f ei5 rr
2496
+ fenr1 f en1 rr
2497
+ fenr2 f en2 rr
2498
+ fenr3 f en3 rr
2499
+ fenr4 f en4 rr
2500
+ fenr5 f en5 rr
2501
+ fengr1 f eng1 rr
2502
+ fengr2 f eng2 rr
2503
+ fengr3 f eng3 rr
2504
+ fengr4 f eng4 rr
2505
+ fengr5 f eng5 rr
2506
+ for1 f o1 rr
2507
+ for2 f o2 rr
2508
+ for3 f o3 rr
2509
+ for4 f o4 rr
2510
+ for5 f o5 rr
2511
+ four1 f ou1 rr
2512
+ four2 f ou2 rr
2513
+ four3 f ou3 rr
2514
+ four4 f ou4 rr
2515
+ four5 f ou5 rr
2516
+ fur1 f u1 rr
2517
+ fur2 f u2 rr
2518
+ fur3 f u3 rr
2519
+ fur4 f u4 rr
2520
+ fur5 f u5 rr
2521
+ gar1 g a1 rr
2522
+ gar2 g a2 rr
2523
+ gar3 g a3 rr
2524
+ gar4 g a4 rr
2525
+ gar5 g a5 rr
2526
+ gair1 g ai1 rr
2527
+ gair2 g ai2 rr
2528
+ gair3 g ai3 rr
2529
+ gair4 g ai4 rr
2530
+ gair5 g ai5 rr
2531
+ ganr1 g an1 rr
2532
+ ganr2 g an2 rr
2533
+ ganr3 g an3 rr
2534
+ ganr4 g an4 rr
2535
+ ganr5 g an5 rr
2536
+ gangr1 g ang1 rr
2537
+ gangr2 g ang2 rr
2538
+ gangr3 g ang3 rr
2539
+ gangr4 g ang4 rr
2540
+ gangr5 g ang5 rr
2541
+ gaor1 g ao1 rr
2542
+ gaor2 g ao2 rr
2543
+ gaor3 g ao3 rr
2544
+ gaor4 g ao4 rr
2545
+ gaor5 g ao5 rr
2546
+ ger1 g e1 rr
2547
+ ger2 g e2 rr
2548
+ ger3 g e3 rr
2549
+ ger4 g e4 rr
2550
+ ger5 g e5 rr
2551
+ geir1 g ei1 rr
2552
+ geir2 g ei2 rr
2553
+ geir3 g ei3 rr
2554
+ geir4 g ei4 rr
2555
+ geir5 g ei5 rr
2556
+ genr1 g en1 rr
2557
+ genr2 g en2 rr
2558
+ genr3 g en3 rr
2559
+ genr4 g en4 rr
2560
+ genr5 g en5 rr
2561
+ gengr1 g eng1 rr
2562
+ gengr2 g eng2 rr
2563
+ gengr3 g eng3 rr
2564
+ gengr4 g eng4 rr
2565
+ gengr5 g eng5 rr
2566
+ gongr1 g ong1 rr
2567
+ gongr2 g ong2 rr
2568
+ gongr3 g ong3 rr
2569
+ gongr4 g ong4 rr
2570
+ gongr5 g ong5 rr
2571
+ gour1 g ou1 rr
2572
+ gour2 g ou2 rr
2573
+ gour3 g ou3 rr
2574
+ gour4 g ou4 rr
2575
+ gour5 g ou5 rr
2576
+ gur1 g u1 rr
2577
+ gur2 g u2 rr
2578
+ gur3 g u3 rr
2579
+ gur4 g u4 rr
2580
+ gur5 g u5 rr
2581
+ guar1 g ua1 rr
2582
+ guar2 g ua2 rr
2583
+ guar3 g ua3 rr
2584
+ guar4 g ua4 rr
2585
+ guar5 g ua5 rr
2586
+ guair1 g uai1 rr
2587
+ guair2 g uai2 rr
2588
+ guair3 g uai3 rr
2589
+ guair4 g uai4 rr
2590
+ guair5 g uai5 rr
2591
+ guanr1 g uan1 rr
2592
+ guanr2 g uan2 rr
2593
+ guanr3 g uan3 rr
2594
+ guanr4 g uan4 rr
2595
+ guanr5 g uan5 rr
2596
+ guangr1 g uang1 rr
2597
+ guangr2 g uang2 rr
2598
+ guangr3 g uang3 rr
2599
+ guangr4 g uang4 rr
2600
+ guangr5 g uang5 rr
2601
+ guir1 g uei1 rr
2602
+ guir2 g uei2 rr
2603
+ guir3 g uei3 rr
2604
+ guir4 g uei4 rr
2605
+ guir5 g uei5 rr
2606
+ gunr1 g uen1 rr
2607
+ gunr2 g uen2 rr
2608
+ gunr3 g uen3 rr
2609
+ gunr4 g uen4 rr
2610
+ gunr5 g uen5 rr
2611
+ guor1 g uo1 rr
2612
+ guor2 g uo2 rr
2613
+ guor3 g uo3 rr
2614
+ guor4 g uo4 rr
2615
+ guor5 g uo5 rr
2616
+ har1 h a1 rr
2617
+ har2 h a2 rr
2618
+ har3 h a3 rr
2619
+ har4 h a4 rr
2620
+ har5 h a5 rr
2621
+ hair1 h ai1 rr
2622
+ hair2 h ai2 rr
2623
+ hair3 h ai3 rr
2624
+ hair4 h ai4 rr
2625
+ hair5 h ai5 rr
2626
+ hanr1 h an1 rr
2627
+ hanr2 h an2 rr
2628
+ hanr3 h an3 rr
2629
+ hanr4 h an4 rr
2630
+ hanr5 h an5 rr
2631
+ hangr1 h ang1 rr
2632
+ hangr2 h ang2 rr
2633
+ hangr3 h ang3 rr
2634
+ hangr4 h ang4 rr
2635
+ hangr5 h ang5 rr
2636
+ haor1 h ao1 rr
2637
+ haor2 h ao2 rr
2638
+ haor3 h ao3 rr
2639
+ haor4 h ao4 rr
2640
+ haor5 h ao5 rr
2641
+ her1 h e1 rr
2642
+ her2 h e2 rr
2643
+ her3 h e3 rr
2644
+ her4 h e4 rr
2645
+ her5 h e5 rr
2646
+ heir1 h ei1 rr
2647
+ heir2 h ei2 rr
2648
+ heir3 h ei3 rr
2649
+ heir4 h ei4 rr
2650
+ heir5 h ei5 rr
2651
+ henr1 h en1 rr
2652
+ henr2 h en2 rr
2653
+ henr3 h en3 rr
2654
+ henr4 h en4 rr
2655
+ henr5 h en5 rr
2656
+ hengr1 h eng1 rr
2657
+ hengr2 h eng2 rr
2658
+ hengr3 h eng3 rr
2659
+ hengr4 h eng4 rr
2660
+ hengr5 h eng5 rr
2661
+ hongr1 h ong1 rr
2662
+ hongr2 h ong2 rr
2663
+ hongr3 h ong3 rr
2664
+ hongr4 h ong4 rr
2665
+ hongr5 h ong5 rr
2666
+ hour1 h ou1 rr
2667
+ hour2 h ou2 rr
2668
+ hour3 h ou3 rr
2669
+ hour4 h ou4 rr
2670
+ hour5 h ou5 rr
2671
+ hur1 h u1 rr
2672
+ hur2 h u2 rr
2673
+ hur3 h u3 rr
2674
+ hur4 h u4 rr
2675
+ hur5 h u5 rr
2676
+ huar1 h ua1 rr
2677
+ huar2 h ua2 rr
2678
+ huar3 h ua3 rr
2679
+ huar4 h ua4 rr
2680
+ huar5 h ua5 rr
2681
+ huair1 h uai1 rr
2682
+ huair2 h uai2 rr
2683
+ huair3 h uai3 rr
2684
+ huair4 h uai4 rr
2685
+ huair5 h uai5 rr
2686
+ huanr1 h uan1 rr
2687
+ huanr2 h uan2 rr
2688
+ huanr3 h uan3 rr
2689
+ huanr4 h uan4 rr
2690
+ huanr5 h uan5 rr
2691
+ huangr1 h uang1 rr
2692
+ huangr2 h uang2 rr
2693
+ huangr3 h uang3 rr
2694
+ huangr4 h uang4 rr
2695
+ huangr5 h uang5 rr
2696
+ huir1 h uei1 rr
2697
+ huir2 h uei2 rr
2698
+ huir3 h uei3 rr
2699
+ huir4 h uei4 rr
2700
+ huir5 h uei5 rr
2701
+ hunr1 h uen1 rr
2702
+ hunr2 h uen2 rr
2703
+ hunr3 h uen3 rr
2704
+ hunr4 h uen4 rr
2705
+ hunr5 h uen5 rr
2706
+ huor1 h uo1 rr
2707
+ huor2 h uo2 rr
2708
+ huor3 h uo3 rr
2709
+ huor4 h uo4 rr
2710
+ huor5 h uo5 rr
2711
+ jir1 j i1 rr
2712
+ jir2 j i2 rr
2713
+ jir3 j i3 rr
2714
+ jir4 j i4 rr
2715
+ jir5 j i5 rr
2716
+ jiar1 j ia1 rr
2717
+ jiar2 j ia2 rr
2718
+ jiar3 j ia3 rr
2719
+ jiar4 j ia4 rr
2720
+ jiar5 j ia5 rr
2721
+ jianr1 j ian1 rr
2722
+ jianr2 j ian2 rr
2723
+ jianr3 j ian3 rr
2724
+ jianr4 j ian4 rr
2725
+ jianr5 j ian5 rr
2726
+ jiangr1 j iang1 rr
2727
+ jiangr2 j iang2 rr
2728
+ jiangr3 j iang3 rr
2729
+ jiangr4 j iang4 rr
2730
+ jiangr5 j iang5 rr
2731
+ jiaor1 j iao1 rr
2732
+ jiaor2 j iao2 rr
2733
+ jiaor3 j iao3 rr
2734
+ jiaor4 j iao4 rr
2735
+ jiaor5 j iao5 rr
2736
+ jier1 j ie1 rr
2737
+ jier2 j ie2 rr
2738
+ jier3 j ie3 rr
2739
+ jier4 j ie4 rr
2740
+ jier5 j ie5 rr
2741
+ jinr1 j in1 rr
2742
+ jinr2 j in2 rr
2743
+ jinr3 j in3 rr
2744
+ jinr4 j in4 rr
2745
+ jinr5 j in5 rr
2746
+ jingr1 j ing1 rr
2747
+ jingr2 j ing2 rr
2748
+ jingr3 j ing3 rr
2749
+ jingr4 j ing4 rr
2750
+ jingr5 j ing5 rr
2751
+ jiongr1 j iong1 rr
2752
+ jiongr2 j iong2 rr
2753
+ jiongr3 j iong3 rr
2754
+ jiongr4 j iong4 rr
2755
+ jiongr5 j iong5 rr
2756
+ jiur1 j iou1 rr
2757
+ jiur2 j iou2 rr
2758
+ jiur3 j iou3 rr
2759
+ jiur4 j iou4 rr
2760
+ jiur5 j iou5 rr
2761
+ jur1 j v1 rr
2762
+ jur2 j v2 rr
2763
+ jur3 j v3 rr
2764
+ jur4 j v4 rr
2765
+ jur5 j v5 rr
2766
+ juanr1 j van1 rr
2767
+ juanr2 j van2 rr
2768
+ juanr3 j van3 rr
2769
+ juanr4 j van4 rr
2770
+ juanr5 j van5 rr
2771
+ juer1 j ve1 rr
2772
+ juer2 j ve2 rr
2773
+ juer3 j ve3 rr
2774
+ juer4 j ve4 rr
2775
+ juer5 j ve5 rr
2776
+ junr1 j vn1 rr
2777
+ junr2 j vn2 rr
2778
+ junr3 j vn3 rr
2779
+ junr4 j vn4 rr
2780
+ junr5 j vn5 rr
2781
+ kar1 k a1 rr
2782
+ kar2 k a2 rr
2783
+ kar3 k a3 rr
2784
+ kar4 k a4 rr
2785
+ kar5 k a5 rr
2786
+ kair1 k ai1 rr
2787
+ kair2 k ai2 rr
2788
+ kair3 k ai3 rr
2789
+ kair4 k ai4 rr
2790
+ kair5 k ai5 rr
2791
+ kanr1 k an1 rr
2792
+ kanr2 k an2 rr
2793
+ kanr3 k an3 rr
2794
+ kanr4 k an4 rr
2795
+ kanr5 k an5 rr
2796
+ kangr1 k ang1 rr
2797
+ kangr2 k ang2 rr
2798
+ kangr3 k ang3 rr
2799
+ kangr4 k ang4 rr
2800
+ kangr5 k ang5 rr
2801
+ kaor1 k ao1 rr
2802
+ kaor2 k ao2 rr
2803
+ kaor3 k ao3 rr
2804
+ kaor4 k ao4 rr
2805
+ kaor5 k ao5 rr
2806
+ ker1 k e1 rr
2807
+ ker2 k e2 rr
2808
+ ker3 k e3 rr
2809
+ ker4 k e4 rr
2810
+ ker5 k e5 rr
2811
+ keir1 k ei1 rr
2812
+ keir2 k ei2 rr
2813
+ keir3 k ei3 rr
2814
+ keir4 k ei4 rr
2815
+ keir5 k ei5 rr
2816
+ kenr1 k en1 rr
2817
+ kenr2 k en2 rr
2818
+ kenr3 k en3 rr
2819
+ kenr4 k en4 rr
2820
+ kenr5 k en5 rr
2821
+ kengr1 k eng1 rr
2822
+ kengr2 k eng2 rr
2823
+ kengr3 k eng3 rr
2824
+ kengr4 k eng4 rr
2825
+ kengr5 k eng5 rr
2826
+ kongr1 k ong1 rr
2827
+ kongr2 k ong2 rr
2828
+ kongr3 k ong3 rr
2829
+ kongr4 k ong4 rr
2830
+ kongr5 k ong5 rr
2831
+ kour1 k ou1 rr
2832
+ kour2 k ou2 rr
2833
+ kour3 k ou3 rr
2834
+ kour4 k ou4 rr
2835
+ kour5 k ou5 rr
2836
+ kur1 k u1 rr
2837
+ kur2 k u2 rr
2838
+ kur3 k u3 rr
2839
+ kur4 k u4 rr
2840
+ kur5 k u5 rr
2841
+ kuar1 k ua1 rr
2842
+ kuar2 k ua2 rr
2843
+ kuar3 k ua3 rr
2844
+ kuar4 k ua4 rr
2845
+ kuar5 k ua5 rr
2846
+ kuair1 k uai1 rr
2847
+ kuair2 k uai2 rr
2848
+ kuair3 k uai3 rr
2849
+ kuair4 k uai4 rr
2850
+ kuair5 k uai5 rr
2851
+ kuanr1 k uan1 rr
2852
+ kuanr2 k uan2 rr
2853
+ kuanr3 k uan3 rr
2854
+ kuanr4 k uan4 rr
2855
+ kuanr5 k uan5 rr
2856
+ kuangr1 k uang1 rr
2857
+ kuangr2 k uang2 rr
2858
+ kuangr3 k uang3 rr
2859
+ kuangr4 k uang4 rr
2860
+ kuangr5 k uang5 rr
2861
+ kuir1 k uei1 rr
2862
+ kuir2 k uei2 rr
2863
+ kuir3 k uei3 rr
2864
+ kuir4 k uei4 rr
2865
+ kuir5 k uei5 rr
2866
+ kunr1 k uen1 rr
2867
+ kunr2 k uen2 rr
2868
+ kunr3 k uen3 rr
2869
+ kunr4 k uen4 rr
2870
+ kunr5 k uen5 rr
2871
+ kuor1 k uo1 rr
2872
+ kuor2 k uo2 rr
2873
+ kuor3 k uo3 rr
2874
+ kuor4 k uo4 rr
2875
+ kuor5 k uo5 rr
2876
+ lar1 l a1 rr
2877
+ lar2 l a2 rr
2878
+ lar3 l a3 rr
2879
+ lar4 l a4 rr
2880
+ lar5 l a5 rr
2881
+ lair1 l ai1 rr
2882
+ lair2 l ai2 rr
2883
+ lair3 l ai3 rr
2884
+ lair4 l ai4 rr
2885
+ lair5 l ai5 rr
2886
+ lanr1 l an1 rr
2887
+ lanr2 l an2 rr
2888
+ lanr3 l an3 rr
2889
+ lanr4 l an4 rr
2890
+ lanr5 l an5 rr
2891
+ langr1 l ang1 rr
2892
+ langr2 l ang2 rr
2893
+ langr3 l ang3 rr
2894
+ langr4 l ang4 rr
2895
+ langr5 l ang5 rr
2896
+ laor1 l ao1 rr
2897
+ laor2 l ao2 rr
2898
+ laor3 l ao3 rr
2899
+ laor4 l ao4 rr
2900
+ laor5 l ao5 rr
2901
+ ler1 l e1 rr
2902
+ ler2 l e2 rr
2903
+ ler3 l e3 rr
2904
+ ler4 l e4 rr
2905
+ ler5 l e5 rr
2906
+ leir1 l ei1 rr
2907
+ leir2 l ei2 rr
2908
+ leir3 l ei3 rr
2909
+ leir4 l ei4 rr
2910
+ leir5 l ei5 rr
2911
+ lengr1 l eng1 rr
2912
+ lengr2 l eng2 rr
2913
+ lengr3 l eng3 rr
2914
+ lengr4 l eng4 rr
2915
+ lengr5 l eng5 rr
2916
+ lir1 l i1 rr
2917
+ lir2 l i2 rr
2918
+ lir3 l i3 rr
2919
+ lir4 l i4 rr
2920
+ lir5 l i5 rr
2921
+ liar1 l ia1 rr
2922
+ liar2 l ia2 rr
2923
+ liar3 l ia3 rr
2924
+ liar4 l ia4 rr
2925
+ liar5 l ia5 rr
2926
+ lianr1 l ian1 rr
2927
+ lianr2 l ian2 rr
2928
+ lianr3 l ian3 rr
2929
+ lianr4 l ian4 rr
2930
+ lianr5 l ian5 rr
2931
+ liangr1 l iang1 rr
2932
+ liangr2 l iang2 rr
2933
+ liangr3 l iang3 rr
2934
+ liangr4 l iang4 rr
2935
+ liangr5 l iang5 rr
2936
+ liaor1 l iao1 rr
2937
+ liaor2 l iao2 rr
2938
+ liaor3 l iao3 rr
2939
+ liaor4 l iao4 rr
2940
+ liaor5 l iao5 rr
2941
+ lier1 l ie1 rr
2942
+ lier2 l ie2 rr
2943
+ lier3 l ie3 rr
2944
+ lier4 l ie4 rr
2945
+ lier5 l ie5 rr
2946
+ linr1 l in1 rr
2947
+ linr2 l in2 rr
2948
+ linr3 l in3 rr
2949
+ linr4 l in4 rr
2950
+ linr5 l in5 rr
2951
+ lingr1 l ing1 rr
2952
+ lingr2 l ing2 rr
2953
+ lingr3 l ing3 rr
2954
+ lingr4 l ing4 rr
2955
+ lingr5 l ing5 rr
2956
+ liur1 l iou1 rr
2957
+ liur2 l iou2 rr
2958
+ liur3 l iou3 rr
2959
+ liur4 l iou4 rr
2960
+ liur5 l iou5 rr
2961
+ lor1 l o1 rr
2962
+ lor2 l o2 rr
2963
+ lor3 l o3 rr
2964
+ lor4 l o4 rr
2965
+ lor5 l o5 rr
2966
+ longr1 l ong1 rr
2967
+ longr2 l ong2 rr
2968
+ longr3 l ong3 rr
2969
+ longr4 l ong4 rr
2970
+ longr5 l ong5 rr
2971
+ lour1 l ou1 rr
2972
+ lour2 l ou2 rr
2973
+ lour3 l ou3 rr
2974
+ lour4 l ou4 rr
2975
+ lour5 l ou5 rr
2976
+ lur1 l u1 rr
2977
+ lur2 l u2 rr
2978
+ lur3 l u3 rr
2979
+ lur4 l u4 rr
2980
+ lur5 l u5 rr
2981
+ luanr1 l uan1 rr
2982
+ luanr2 l uan2 rr
2983
+ luanr3 l uan3 rr
2984
+ luanr4 l uan4 rr
2985
+ luanr5 l uan5 rr
2986
+ luer1 l ve1 rr
2987
+ luer2 l ve2 rr
2988
+ luer3 l ve3 rr
2989
+ luer4 l ve4 rr
2990
+ luer5 l ve5 rr
2991
+ lver1 l ve1 rr
2992
+ lver2 l ve2 rr
2993
+ lver3 l ve3 rr
2994
+ lver4 l ve4 rr
2995
+ lver5 l ve5 rr
2996
+ lunr1 l uen1 rr
2997
+ lunr2 l uen2 rr
2998
+ lunr3 l uen3 rr
2999
+ lunr4 l uen4 rr
3000
+ lunr5 l uen5 rr
3001
+ luor1 l uo1 rr
3002
+ luor2 l uo2 rr
3003
+ luor3 l uo3 rr
3004
+ luor4 l uo4 rr
3005
+ luor5 l uo5 rr
3006
+ lvr1 l v1 rr
3007
+ lvr2 l v2 rr
3008
+ lvr3 l v3 rr
3009
+ lvr4 l v4 rr
3010
+ lvr5 l v5 rr
3011
+ mar1 m a1 rr
3012
+ mar2 m a2 rr
3013
+ mar3 m a3 rr
3014
+ mar4 m a4 rr
3015
+ mar5 m a5 rr
3016
+ mair1 m ai1 rr
3017
+ mair2 m ai2 rr
3018
+ mair3 m ai3 rr
3019
+ mair4 m ai4 rr
3020
+ mair5 m ai5 rr
3021
+ manr1 m an1 rr
3022
+ manr2 m an2 rr
3023
+ manr3 m an3 rr
3024
+ manr4 m an4 rr
3025
+ manr5 m an5 rr
3026
+ mangr1 m ang1 rr
3027
+ mangr2 m ang2 rr
3028
+ mangr3 m ang3 rr
3029
+ mangr4 m ang4 rr
3030
+ mangr5 m ang5 rr
3031
+ maor1 m ao1 rr
3032
+ maor2 m ao2 rr
3033
+ maor3 m ao3 rr
3034
+ maor4 m ao4 rr
3035
+ maor5 m ao5 rr
3036
+ mer1 m e1 rr
3037
+ mer2 m e2 rr
3038
+ mer3 m e3 rr
3039
+ mer4 m e4 rr
3040
+ mer5 m e5 rr
3041
+ meir1 m ei1 rr
3042
+ meir2 m ei2 rr
3043
+ meir3 m ei3 rr
3044
+ meir4 m ei4 rr
3045
+ meir5 m ei5 rr
3046
+ menr1 m en1 rr
3047
+ menr2 m en2 rr
3048
+ menr3 m en3 rr
3049
+ menr4 m en4 rr
3050
+ menr5 m en5 rr
3051
+ mengr1 m eng1 rr
3052
+ mengr2 m eng2 rr
3053
+ mengr3 m eng3 rr
3054
+ mengr4 m eng4 rr
3055
+ mengr5 m eng5 rr
3056
+ mir1 m i1 rr
3057
+ mir2 m i2 rr
3058
+ mir3 m i3 rr
3059
+ mir4 m i4 rr
3060
+ mir5 m i5 rr
3061
+ mianr1 m ian1 rr
3062
+ mianr2 m ian2 rr
3063
+ mianr3 m ian3 rr
3064
+ mianr4 m ian4 rr
3065
+ mianr5 m ian5 rr
3066
+ miaor1 m iao1 rr
3067
+ miaor2 m iao2 rr
3068
+ miaor3 m iao3 rr
3069
+ miaor4 m iao4 rr
3070
+ miaor5 m iao5 rr
3071
+ mier1 m ie1 rr
3072
+ mier2 m ie2 rr
3073
+ mier3 m ie3 rr
3074
+ mier4 m ie4 rr
3075
+ mier5 m ie5 rr
3076
+ minr1 m in1 rr
3077
+ minr2 m in2 rr
3078
+ minr3 m in3 rr
3079
+ minr4 m in4 rr
3080
+ minr5 m in5 rr
3081
+ mingr1 m ing1 rr
3082
+ mingr2 m ing2 rr
3083
+ mingr3 m ing3 rr
3084
+ mingr4 m ing4 rr
3085
+ mingr5 m ing5 rr
3086
+ miur1 m iou1 rr
3087
+ miur2 m iou2 rr
3088
+ miur3 m iou3 rr
3089
+ miur4 m iou4 rr
3090
+ miur5 m iou5 rr
3091
+ mor1 m o1 rr
3092
+ mor2 m o2 rr
3093
+ mor3 m o3 rr
3094
+ mor4 m o4 rr
3095
+ mor5 m o5 rr
3096
+ mour1 m ou1 rr
3097
+ mour2 m ou2 rr
3098
+ mour3 m ou3 rr
3099
+ mour4 m ou4 rr
3100
+ mour5 m ou5 rr
3101
+ mur1 m u1 rr
3102
+ mur2 m u2 rr
3103
+ mur3 m u3 rr
3104
+ mur4 m u4 rr
3105
+ mur5 m u5 rr
3106
+ nar1 n a1 rr
3107
+ nar2 n a2 rr
3108
+ nar3 n a3 rr
3109
+ nar4 n a4 rr
3110
+ nar5 n a5 rr
3111
+ nair1 n ai1 rr
3112
+ nair2 n ai2 rr
3113
+ nair3 n ai3 rr
3114
+ nair4 n ai4 rr
3115
+ nair5 n ai5 rr
3116
+ nanr1 n an1 rr
3117
+ nanr2 n an2 rr
3118
+ nanr3 n an3 rr
3119
+ nanr4 n an4 rr
3120
+ nanr5 n an5 rr
3121
+ nangr1 n ang1 rr
3122
+ nangr2 n ang2 rr
3123
+ nangr3 n ang3 rr
3124
+ nangr4 n ang4 rr
3125
+ nangr5 n ang5 rr
3126
+ naor1 n ao1 rr
3127
+ naor2 n ao2 rr
3128
+ naor3 n ao3 rr
3129
+ naor4 n ao4 rr
3130
+ naor5 n ao5 rr
3131
+ ner1 n e1 rr
3132
+ ner2 n e2 rr
3133
+ ner3 n e3 rr
3134
+ ner4 n e4 rr
3135
+ ner5 n e5 rr
3136
+ neir1 n ei1 rr
3137
+ neir2 n ei2 rr
3138
+ neir3 n ei3 rr
3139
+ neir4 n ei4 rr
3140
+ neir5 n ei5 rr
3141
+ nenr1 n en1 rr
3142
+ nenr2 n en2 rr
3143
+ nenr3 n en3 rr
3144
+ nenr4 n en4 rr
3145
+ nenr5 n en5 rr
3146
+ nengr1 n eng1 rr
3147
+ nengr2 n eng2 rr
3148
+ nengr3 n eng3 rr
3149
+ nengr4 n eng4 rr
3150
+ nengr5 n eng5 rr
3151
+ nir1 n i1 rr
3152
+ nir2 n i2 rr
3153
+ nir3 n i3 rr
3154
+ nir4 n i4 rr
3155
+ nir5 n i5 rr
3156
+ nianr1 n ian1 rr
3157
+ nianr2 n ian2 rr
3158
+ nianr3 n ian3 rr
3159
+ nianr4 n ian4 rr
3160
+ nianr5 n ian5 rr
3161
+ niangr1 n iang1 rr
3162
+ niangr2 n iang2 rr
3163
+ niangr3 n iang3 rr
3164
+ niangr4 n iang4 rr
3165
+ niangr5 n iang5 rr
3166
+ niaor1 n iao1 rr
3167
+ niaor2 n iao2 rr
3168
+ niaor3 n iao3 rr
3169
+ niaor4 n iao4 rr
3170
+ niaor5 n iao5 rr
3171
+ nier1 n ie1 rr
3172
+ nier2 n ie2 rr
3173
+ nier3 n ie3 rr
3174
+ nier4 n ie4 rr
3175
+ nier5 n ie5 rr
3176
+ ninr1 n in1 rr
3177
+ ninr2 n in2 rr
3178
+ ninr3 n in3 rr
3179
+ ninr4 n in4 rr
3180
+ ninr5 n in5 rr
3181
+ ningr1 n ing1 rr
3182
+ ningr2 n ing2 rr
3183
+ ningr3 n ing3 rr
3184
+ ningr4 n ing4 rr
3185
+ ningr5 n ing5 rr
3186
+ niur1 n iou1 rr
3187
+ niur2 n iou2 rr
3188
+ niur3 n iou3 rr
3189
+ niur4 n iou4 rr
3190
+ niur5 n iou5 rr
3191
+ nongr1 n ong1 rr
3192
+ nongr2 n ong2 rr
3193
+ nongr3 n ong3 rr
3194
+ nongr4 n ong4 rr
3195
+ nongr5 n ong5 rr
3196
+ nour1 n ou1 rr
3197
+ nour2 n ou2 rr
3198
+ nour3 n ou3 rr
3199
+ nour4 n ou4 rr
3200
+ nour5 n ou5 rr
3201
+ nur1 n u1 rr
3202
+ nur2 n u2 rr
3203
+ nur3 n u3 rr
3204
+ nur4 n u4 rr
3205
+ nur5 n u5 rr
3206
+ nuanr1 n uan1 rr
3207
+ nuanr2 n uan2 rr
3208
+ nuanr3 n uan3 rr
3209
+ nuanr4 n uan4 rr
3210
+ nuanr5 n uan5 rr
3211
+ nuer1 n ve1 rr
3212
+ nuer2 n ve2 rr
3213
+ nuer3 n ve3 rr
3214
+ nuer4 n ve4 rr
3215
+ nuer5 n ve5 rr
3216
+ nver1 n ve1 rr
3217
+ nver2 n ve2 rr
3218
+ nver3 n ve3 rr
3219
+ nver4 n ve4 rr
3220
+ nver5 n ve5 rr
3221
+ nuor1 n uo1 rr
3222
+ nuor2 n uo2 rr
3223
+ nuor3 n uo3 rr
3224
+ nuor4 n uo4 rr
3225
+ nuor5 n uo5 rr
3226
+ nvr1 n v1 rr
3227
+ nvr2 n v2 rr
3228
+ nvr3 n v3 rr
3229
+ nvr4 n v4 rr
3230
+ nvr5 n v5 rr
3231
+ or1 o1 rr
3232
+ or2 o2 rr
3233
+ or3 o3 rr
3234
+ or4 o4 rr
3235
+ or5 o5 rr
3236
+ our1 ou1 rr
3237
+ our2 ou2 rr
3238
+ our3 ou3 rr
3239
+ our4 ou4 rr
3240
+ our5 ou5 rr
3241
+ par1 p a1 rr
3242
+ par2 p a2 rr
3243
+ par3 p a3 rr
3244
+ par4 p a4 rr
3245
+ par5 p a5 rr
3246
+ pair1 p ai1 rr
3247
+ pair2 p ai2 rr
3248
+ pair3 p ai3 rr
3249
+ pair4 p ai4 rr
3250
+ pair5 p ai5 rr
3251
+ panr1 p an1 rr
3252
+ panr2 p an2 rr
3253
+ panr3 p an3 rr
3254
+ panr4 p an4 rr
3255
+ panr5 p an5 rr
3256
+ pangr1 p ang1 rr
3257
+ pangr2 p ang2 rr
3258
+ pangr3 p ang3 rr
3259
+ pangr4 p ang4 rr
3260
+ pangr5 p ang5 rr
3261
+ paor1 p ao1 rr
3262
+ paor2 p ao2 rr
3263
+ paor3 p ao3 rr
3264
+ paor4 p ao4 rr
3265
+ paor5 p ao5 rr
3266
+ peir1 p ei1 rr
3267
+ peir2 p ei2 rr
3268
+ peir3 p ei3 rr
3269
+ peir4 p ei4 rr
3270
+ peir5 p ei5 rr
3271
+ penr1 p en1 rr
3272
+ penr2 p en2 rr
3273
+ penr3 p en3 rr
3274
+ penr4 p en4 rr
3275
+ penr5 p en5 rr
3276
+ pengr1 p eng1 rr
3277
+ pengr2 p eng2 rr
3278
+ pengr3 p eng3 rr
3279
+ pengr4 p eng4 rr
3280
+ pengr5 p eng5 rr
3281
+ pir1 p i1 rr
3282
+ pir2 p i2 rr
3283
+ pir3 p i3 rr
3284
+ pir4 p i4 rr
3285
+ pir5 p i5 rr
3286
+ pianr1 p ian1 rr
3287
+ pianr2 p ian2 rr
3288
+ pianr3 p ian3 rr
3289
+ pianr4 p ian4 rr
3290
+ pianr5 p ian5 rr
3291
+ piaor1 p iao1 rr
3292
+ piaor2 p iao2 rr
3293
+ piaor3 p iao3 rr
3294
+ piaor4 p iao4 rr
3295
+ piaor5 p iao5 rr
3296
+ pier1 p ie1 rr
3297
+ pier2 p ie2 rr
3298
+ pier3 p ie3 rr
3299
+ pier4 p ie4 rr
3300
+ pier5 p ie5 rr
3301
+ pinr1 p in1 rr
3302
+ pinr2 p in2 rr
3303
+ pinr3 p in3 rr
3304
+ pinr4 p in4 rr
3305
+ pinr5 p in5 rr
3306
+ pingr1 p ing1 rr
3307
+ pingr2 p ing2 rr
3308
+ pingr3 p ing3 rr
3309
+ pingr4 p ing4 rr
3310
+ pingr5 p ing5 rr
3311
+ por1 p o1 rr
3312
+ por2 p o2 rr
3313
+ por3 p o3 rr
3314
+ por4 p o4 rr
3315
+ por5 p o5 rr
3316
+ pour1 p ou1 rr
3317
+ pour2 p ou2 rr
3318
+ pour3 p ou3 rr
3319
+ pour4 p ou4 rr
3320
+ pour5 p ou5 rr
3321
+ pur1 p u1 rr
3322
+ pur2 p u2 rr
3323
+ pur3 p u3 rr
3324
+ pur4 p u4 rr
3325
+ pur5 p u5 rr
3326
+ qir1 q i1 rr
3327
+ qir2 q i2 rr
3328
+ qir3 q i3 rr
3329
+ qir4 q i4 rr
3330
+ qir5 q i5 rr
3331
+ qiar1 q ia1 rr
3332
+ qiar2 q ia2 rr
3333
+ qiar3 q ia3 rr
3334
+ qiar4 q ia4 rr
3335
+ qiar5 q ia5 rr
3336
+ qianr1 q ian1 rr
3337
+ qianr2 q ian2 rr
3338
+ qianr3 q ian3 rr
3339
+ qianr4 q ian4 rr
3340
+ qianr5 q ian5 rr
3341
+ qiangr1 q iang1 rr
3342
+ qiangr2 q iang2 rr
3343
+ qiangr3 q iang3 rr
3344
+ qiangr4 q iang4 rr
3345
+ qiangr5 q iang5 rr
3346
+ qiaor1 q iao1 rr
3347
+ qiaor2 q iao2 rr
3348
+ qiaor3 q iao3 rr
3349
+ qiaor4 q iao4 rr
3350
+ qiaor5 q iao5 rr
3351
+ qier1 q ie1 rr
3352
+ qier2 q ie2 rr
3353
+ qier3 q ie3 rr
3354
+ qier4 q ie4 rr
3355
+ qier5 q ie5 rr
3356
+ qinr1 q in1 rr
3357
+ qinr2 q in2 rr
3358
+ qinr3 q in3 rr
3359
+ qinr4 q in4 rr
3360
+ qinr5 q in5 rr
3361
+ qingr1 q ing1 rr
3362
+ qingr2 q ing2 rr
3363
+ qingr3 q ing3 rr
3364
+ qingr4 q ing4 rr
3365
+ qingr5 q ing5 rr
3366
+ qiongr1 q iong1 rr
3367
+ qiongr2 q iong2 rr
3368
+ qiongr3 q iong3 rr
3369
+ qiongr4 q iong4 rr
3370
+ qiongr5 q iong5 rr
3371
+ qiur1 q iou1 rr
3372
+ qiur2 q iou2 rr
3373
+ qiur3 q iou3 rr
3374
+ qiur4 q iou4 rr
3375
+ qiur5 q iou5 rr
3376
+ qur1 q v1 rr
3377
+ qur2 q v2 rr
3378
+ qur3 q v3 rr
3379
+ qur4 q v4 rr
3380
+ qur5 q v5 rr
3381
+ quanr1 q van1 rr
3382
+ quanr2 q van2 rr
3383
+ quanr3 q van3 rr
3384
+ quanr4 q van4 rr
3385
+ quanr5 q van5 rr
3386
+ quer1 q ve1 rr
3387
+ quer2 q ve2 rr
3388
+ quer3 q ve3 rr
3389
+ quer4 q ve4 rr
3390
+ quer5 q ve5 rr
3391
+ qunr1 q vn1 rr
3392
+ qunr2 q vn2 rr
3393
+ qunr3 q vn3 rr
3394
+ qunr4 q vn4 rr
3395
+ qunr5 q vn5 rr
3396
+ ranr1 r an1 rr
3397
+ ranr2 r an2 rr
3398
+ ranr3 r an3 rr
3399
+ ranr4 r an4 rr
3400
+ ranr5 r an5 rr
3401
+ rangr1 r ang1 rr
3402
+ rangr2 r ang2 rr
3403
+ rangr3 r ang3 rr
3404
+ rangr4 r ang4 rr
3405
+ rangr5 r ang5 rr
3406
+ raor1 r ao1 rr
3407
+ raor2 r ao2 rr
3408
+ raor3 r ao3 rr
3409
+ raor4 r ao4 rr
3410
+ raor5 r ao5 rr
3411
+ rer1 r e1 rr
3412
+ rer2 r e2 rr
3413
+ rer3 r e3 rr
3414
+ rer4 r e4 rr
3415
+ rer5 r e5 rr
3416
+ renr1 r en1 rr
3417
+ renr2 r en2 rr
3418
+ renr3 r en3 rr
3419
+ renr4 r en4 rr
3420
+ renr5 r en5 rr
3421
+ rengr1 r eng1 rr
3422
+ rengr2 r eng2 rr
3423
+ rengr3 r eng3 rr
3424
+ rengr4 r eng4 rr
3425
+ rengr5 r eng5 rr
3426
+ rir1 r iii1 rr
3427
+ rir2 r iii2 rr
3428
+ rir3 r iii3 rr
3429
+ rir4 r iii4 rr
3430
+ rir5 r iii5 rr
3431
+ rongr1 r ong1 rr
3432
+ rongr2 r ong2 rr
3433
+ rongr3 r ong3 rr
3434
+ rongr4 r ong4 rr
3435
+ rongr5 r ong5 rr
3436
+ rour1 r ou1 rr
3437
+ rour2 r ou2 rr
3438
+ rour3 r ou3 rr
3439
+ rour4 r ou4 rr
3440
+ rour5 r ou5 rr
3441
+ rur1 r u1 rr
3442
+ rur2 r u2 rr
3443
+ rur3 r u3 rr
3444
+ rur4 r u4 rr
3445
+ rur5 r u5 rr
3446
+ ruar1 r ua1 rr
3447
+ ruar2 r ua2 rr
3448
+ ruar3 r ua3 rr
3449
+ ruar4 r ua4 rr
3450
+ ruar5 r ua5 rr
3451
+ ruanr1 r uan1 rr
3452
+ ruanr2 r uan2 rr
3453
+ ruanr3 r uan3 rr
3454
+ ruanr4 r uan4 rr
3455
+ ruanr5 r uan5 rr
3456
+ ruir1 r uei1 rr
3457
+ ruir2 r uei2 rr
3458
+ ruir3 r uei3 rr
3459
+ ruir4 r uei4 rr
3460
+ ruir5 r uei5 rr
3461
+ runr1 r uen1 rr
3462
+ runr2 r uen2 rr
3463
+ runr3 r uen3 rr
3464
+ runr4 r uen4 rr
3465
+ runr5 r uen5 rr
3466
+ ruor1 r uo1 rr
3467
+ ruor2 r uo2 rr
3468
+ ruor3 r uo3 rr
3469
+ ruor4 r uo4 rr
3470
+ ruor5 r uo5 rr
3471
+ sar1 s a1 rr
3472
+ sar2 s a2 rr
3473
+ sar3 s a3 rr
3474
+ sar4 s a4 rr
3475
+ sar5 s a5 rr
3476
+ sair1 s ai1 rr
3477
+ sair2 s ai2 rr
3478
+ sair3 s ai3 rr
3479
+ sair4 s ai4 rr
3480
+ sair5 s ai5 rr
3481
+ sanr1 s an1 rr
3482
+ sanr2 s an2 rr
3483
+ sanr3 s an3 rr
3484
+ sanr4 s an4 rr
3485
+ sanr5 s an5 rr
3486
+ sangr1 s ang1 rr
3487
+ sangr2 s ang2 rr
3488
+ sangr3 s ang3 rr
3489
+ sangr4 s ang4 rr
3490
+ sangr5 s ang5 rr
3491
+ saor1 s ao1 rr
3492
+ saor2 s ao2 rr
3493
+ saor3 s ao3 rr
3494
+ saor4 s ao4 rr
3495
+ saor5 s ao5 rr
3496
+ ser1 s e1 rr
3497
+ ser2 s e2 rr
3498
+ ser3 s e3 rr
3499
+ ser4 s e4 rr
3500
+ ser5 s e5 rr
3501
+ senr1 s en1 rr
3502
+ senr2 s en2 rr
3503
+ senr3 s en3 rr
3504
+ senr4 s en4 rr
3505
+ senr5 s en5 rr
3506
+ sengr1 s eng1 rr
3507
+ sengr2 s eng2 rr
3508
+ sengr3 s eng3 rr
3509
+ sengr4 s eng4 rr
3510
+ sengr5 s eng5 rr
3511
+ shar1 sh a1 rr
3512
+ shar2 sh a2 rr
3513
+ shar3 sh a3 rr
3514
+ shar4 sh a4 rr
3515
+ shar5 sh a5 rr
3516
+ shair1 sh ai1 rr
3517
+ shair2 sh ai2 rr
3518
+ shair3 sh ai3 rr
3519
+ shair4 sh ai4 rr
3520
+ shair5 sh ai5 rr
3521
+ shanr1 sh an1 rr
3522
+ shanr2 sh an2 rr
3523
+ shanr3 sh an3 rr
3524
+ shanr4 sh an4 rr
3525
+ shanr5 sh an5 rr
3526
+ shangr1 sh ang1 rr
3527
+ shangr2 sh ang2 rr
3528
+ shangr3 sh ang3 rr
3529
+ shangr4 sh ang4 rr
3530
+ shangr5 sh ang5 rr
3531
+ shaor1 sh ao1 rr
3532
+ shaor2 sh ao2 rr
3533
+ shaor3 sh ao3 rr
3534
+ shaor4 sh ao4 rr
3535
+ shaor5 sh ao5 rr
3536
+ sher1 sh e1 rr
3537
+ sher2 sh e2 rr
3538
+ sher3 sh e3 rr
3539
+ sher4 sh e4 rr
3540
+ sher5 sh e5 rr
3541
+ sheir1 sh ei1 rr
3542
+ sheir2 sh ei2 rr
3543
+ sheir3 sh ei3 rr
3544
+ sheir4 sh ei4 rr
3545
+ sheir5 sh ei5 rr
3546
+ shenr1 sh en1 rr
3547
+ shenr2 sh en2 rr
3548
+ shenr3 sh en3 rr
3549
+ shenr4 sh en4 rr
3550
+ shenr5 sh en5 rr
3551
+ shengr1 sh eng1 rr
3552
+ shengr2 sh eng2 rr
3553
+ shengr3 sh eng3 rr
3554
+ shengr4 sh eng4 rr
3555
+ shengr5 sh eng5 rr
3556
+ shir1 sh iii1 rr
3557
+ shir2 sh iii2 rr
3558
+ shir3 sh iii3 rr
3559
+ shir4 sh iii4 rr
3560
+ shir5 sh iii5 rr
3561
+ shour1 sh ou1 rr
3562
+ shour2 sh ou2 rr
3563
+ shour3 sh ou3 rr
3564
+ shour4 sh ou4 rr
3565
+ shour5 sh ou5 rr
3566
+ shur1 sh u1 rr
3567
+ shur2 sh u2 rr
3568
+ shur3 sh u3 rr
3569
+ shur4 sh u4 rr
3570
+ shur5 sh u5 rr
3571
+ shuar1 sh ua1 rr
3572
+ shuar2 sh ua2 rr
3573
+ shuar3 sh ua3 rr
3574
+ shuar4 sh ua4 rr
3575
+ shuar5 sh ua5 rr
3576
+ shuair1 sh uai1 rr
3577
+ shuair2 sh uai2 rr
3578
+ shuair3 sh uai3 rr
3579
+ shuair4 sh uai4 rr
3580
+ shuair5 sh uai5 rr
3581
+ shuanr1 sh uan1 rr
3582
+ shuanr2 sh uan2 rr
3583
+ shuanr3 sh uan3 rr
3584
+ shuanr4 sh uan4 rr
3585
+ shuanr5 sh uan5 rr
3586
+ shuangr1 sh uang1 rr
3587
+ shuangr2 sh uang2 rr
3588
+ shuangr3 sh uang3 rr
3589
+ shuangr4 sh uang4 rr
3590
+ shuangr5 sh uang5 rr
3591
+ shuir1 sh uei1 rr
3592
+ shuir2 sh uei2 rr
3593
+ shuir3 sh uei3 rr
3594
+ shuir4 sh uei4 rr
3595
+ shuir5 sh uei5 rr
3596
+ shunr1 sh uen1 rr
3597
+ shunr2 sh uen2 rr
3598
+ shunr3 sh uen3 rr
3599
+ shunr4 sh uen4 rr
3600
+ shunr5 sh uen5 rr
3601
+ shuor1 sh uo1 rr
3602
+ shuor2 sh uo2 rr
3603
+ shuor3 sh uo3 rr
3604
+ shuor4 sh uo4 rr
3605
+ shuor5 sh uo5 rr
3606
+ sir1 s ii1 rr
3607
+ sir2 s ii2 rr
3608
+ sir3 s ii3 rr
3609
+ sir4 s ii4 rr
3610
+ sir5 s ii5 rr
3611
+ songr1 s ong1 rr
3612
+ songr2 s ong2 rr
3613
+ songr3 s ong3 rr
3614
+ songr4 s ong4 rr
3615
+ songr5 s ong5 rr
3616
+ sour1 s ou1 rr
3617
+ sour2 s ou2 rr
3618
+ sour3 s ou3 rr
3619
+ sour4 s ou4 rr
3620
+ sour5 s ou5 rr
3621
+ sur1 s u1 rr
3622
+ sur2 s u2 rr
3623
+ sur3 s u3 rr
3624
+ sur4 s u4 rr
3625
+ sur5 s u5 rr
3626
+ suanr1 s uan1 rr
3627
+ suanr2 s uan2 rr
3628
+ suanr3 s uan3 rr
3629
+ suanr4 s uan4 rr
3630
+ suanr5 s uan5 rr
3631
+ suir1 s uei1 rr
3632
+ suir2 s uei2 rr
3633
+ suir3 s uei3 rr
3634
+ suir4 s uei4 rr
3635
+ suir5 s uei5 rr
3636
+ sunr1 s uen1 rr
3637
+ sunr2 s uen2 rr
3638
+ sunr3 s uen3 rr
3639
+ sunr4 s uen4 rr
3640
+ sunr5 s uen5 rr
3641
+ suor1 s uo1 rr
3642
+ suor2 s uo2 rr
3643
+ suor3 s uo3 rr
3644
+ suor4 s uo4 rr
3645
+ suor5 s uo5 rr
3646
+ tar1 t a1 rr
3647
+ tar2 t a2 rr
3648
+ tar3 t a3 rr
3649
+ tar4 t a4 rr
3650
+ tar5 t a5 rr
3651
+ tair1 t ai1 rr
3652
+ tair2 t ai2 rr
3653
+ tair3 t ai3 rr
3654
+ tair4 t ai4 rr
3655
+ tair5 t ai5 rr
3656
+ tanr1 t an1 rr
3657
+ tanr2 t an2 rr
3658
+ tanr3 t an3 rr
3659
+ tanr4 t an4 rr
3660
+ tanr5 t an5 rr
3661
+ tangr1 t ang1 rr
3662
+ tangr2 t ang2 rr
3663
+ tangr3 t ang3 rr
3664
+ tangr4 t ang4 rr
3665
+ tangr5 t ang5 rr
3666
+ taor1 t ao1 rr
3667
+ taor2 t ao2 rr
3668
+ taor3 t ao3 rr
3669
+ taor4 t ao4 rr
3670
+ taor5 t ao5 rr
3671
+ ter1 t e1 rr
3672
+ ter2 t e2 rr
3673
+ ter3 t e3 rr
3674
+ ter4 t e4 rr
3675
+ ter5 t e5 rr
3676
+ teir1 t ei1 rr
3677
+ teir2 t ei2 rr
3678
+ teir3 t ei3 rr
3679
+ teir4 t ei4 rr
3680
+ teir5 t ei5 rr
3681
+ tengr1 t eng1 rr
3682
+ tengr2 t eng2 rr
3683
+ tengr3 t eng3 rr
3684
+ tengr4 t eng4 rr
3685
+ tengr5 t eng5 rr
3686
+ tir1 t i1 rr
3687
+ tir2 t i2 rr
3688
+ tir3 t i3 rr
3689
+ tir4 t i4 rr
3690
+ tir5 t i5 rr
3691
+ tianr1 t ian1 rr
3692
+ tianr2 t ian2 rr
3693
+ tianr3 t ian3 rr
3694
+ tianr4 t ian4 rr
3695
+ tianr5 t ian5 rr
3696
+ tiaor1 t iao1 rr
3697
+ tiaor2 t iao2 rr
3698
+ tiaor3 t iao3 rr
3699
+ tiaor4 t iao4 rr
3700
+ tiaor5 t iao5 rr
3701
+ tier1 t ie1 rr
3702
+ tier2 t ie2 rr
3703
+ tier3 t ie3 rr
3704
+ tier4 t ie4 rr
3705
+ tier5 t ie5 rr
3706
+ tingr1 t ing1 rr
3707
+ tingr2 t ing2 rr
3708
+ tingr3 t ing3 rr
3709
+ tingr4 t ing4 rr
3710
+ tingr5 t ing5 rr
3711
+ tongr1 t ong1 rr
3712
+ tongr2 t ong2 rr
3713
+ tongr3 t ong3 rr
3714
+ tongr4 t ong4 rr
3715
+ tongr5 t ong5 rr
3716
+ tour1 t ou1 rr
3717
+ tour2 t ou2 rr
3718
+ tour3 t ou3 rr
3719
+ tour4 t ou4 rr
3720
+ tour5 t ou5 rr
3721
+ tur1 t u1 rr
3722
+ tur2 t u2 rr
3723
+ tur3 t u3 rr
3724
+ tur4 t u4 rr
3725
+ tur5 t u5 rr
3726
+ tuanr1 t uan1 rr
3727
+ tuanr2 t uan2 rr
3728
+ tuanr3 t uan3 rr
3729
+ tuanr4 t uan4 rr
3730
+ tuanr5 t uan5 rr
3731
+ tuir1 t uei1 rr
3732
+ tuir2 t uei2 rr
3733
+ tuir3 t uei3 rr
3734
+ tuir4 t uei4 rr
3735
+ tuir5 t uei5 rr
3736
+ tunr1 t uen1 rr
3737
+ tunr2 t uen2 rr
3738
+ tunr3 t uen3 rr
3739
+ tunr4 t uen4 rr
3740
+ tunr5 t uen5 rr
3741
+ tuor1 t uo1 rr
3742
+ tuor2 t uo2 rr
3743
+ tuor3 t uo3 rr
3744
+ tuor4 t uo4 rr
3745
+ tuor5 t uo5 rr
3746
+ war1 w ua1 rr
3747
+ war2 w ua2 rr
3748
+ war3 w ua3 rr
3749
+ war4 w ua4 rr
3750
+ war5 w ua5 rr
3751
+ wair1 w uai1 rr
3752
+ wair2 w uai2 rr
3753
+ wair3 w uai3 rr
3754
+ wair4 w uai4 rr
3755
+ wair5 w uai5 rr
3756
+ wanr1 w uan1 rr
3757
+ wanr2 w uan2 rr
3758
+ wanr3 w uan3 rr
3759
+ wanr4 w uan4 rr
3760
+ wanr5 w uan5 rr
3761
+ wangr1 w uang1 rr
3762
+ wangr2 w uang2 rr
3763
+ wangr3 w uang3 rr
3764
+ wangr4 w uang4 rr
3765
+ wangr5 w uang5 rr
3766
+ weir1 w uei1 rr
3767
+ weir2 w uei2 rr
3768
+ weir3 w uei3 rr
3769
+ weir4 w uei4 rr
3770
+ weir5 w uei5 rr
3771
+ wenr1 w uen1 rr
3772
+ wenr2 w uen2 rr
3773
+ wenr3 w uen3 rr
3774
+ wenr4 w uen4 rr
3775
+ wenr5 w uen5 rr
3776
+ wengr1 w uen1 rr
3777
+ wengr2 w uen2 rr
3778
+ wengr3 w uen3 rr
3779
+ wengr4 w uen4 rr
3780
+ wengr5 w uen5 rr
3781
+ wor1 w uo1 rr
3782
+ wor2 w uo2 rr
3783
+ wor3 w uo3 rr
3784
+ wor4 w uo4 rr
3785
+ wor5 w uo5 rr
3786
+ wur1 w u1 rr
3787
+ wur2 w u2 rr
3788
+ wur3 w u3 rr
3789
+ wur4 w u4 rr
3790
+ wur5 w u5 rr
3791
+ xir1 x i1 rr
3792
+ xir2 x i2 rr
3793
+ xir3 x i3 rr
3794
+ xir4 x i4 rr
3795
+ xir5 x i5 rr
3796
+ xiar1 x ia1 rr
3797
+ xiar2 x ia2 rr
3798
+ xiar3 x ia3 rr
3799
+ xiar4 x ia4 rr
3800
+ xiar5 x ia5 rr
3801
+ xianr1 x ian1 rr
3802
+ xianr2 x ian2 rr
3803
+ xianr3 x ian3 rr
3804
+ xianr4 x ian4 rr
3805
+ xianr5 x ian5 rr
3806
+ xiangr1 x iang1 rr
3807
+ xiangr2 x iang2 rr
3808
+ xiangr3 x iang3 rr
3809
+ xiangr4 x iang4 rr
3810
+ xiangr5 x iang5 rr
3811
+ xiaor1 x iao1 rr
3812
+ xiaor2 x iao2 rr
3813
+ xiaor3 x iao3 rr
3814
+ xiaor4 x iao4 rr
3815
+ xiaor5 x iao5 rr
3816
+ xier1 x ie1 rr
3817
+ xier2 x ie2 rr
3818
+ xier3 x ie3 rr
3819
+ xier4 x ie4 rr
3820
+ xier5 x ie5 rr
3821
+ xinr1 x in1 rr
3822
+ xinr2 x in2 rr
3823
+ xinr3 x in3 rr
3824
+ xinr4 x in4 rr
3825
+ xinr5 x in5 rr
3826
+ xingr1 x ing1 rr
3827
+ xingr2 x ing2 rr
3828
+ xingr3 x ing3 rr
3829
+ xingr4 x ing4 rr
3830
+ xingr5 x ing5 rr
3831
+ xiongr1 x iong1 rr
3832
+ xiongr2 x iong2 rr
3833
+ xiongr3 x iong3 rr
3834
+ xiongr4 x iong4 rr
3835
+ xiongr5 x iong5 rr
3836
+ xiur1 x iou1 rr
3837
+ xiur2 x iou2 rr
3838
+ xiur3 x iou3 rr
3839
+ xiur4 x iou4 rr
3840
+ xiur5 x iou5 rr
3841
+ xur1 x v1 rr
3842
+ xur2 x v2 rr
3843
+ xur3 x v3 rr
3844
+ xur4 x v4 rr
3845
+ xur5 x v5 rr
3846
+ xuanr1 x van1 rr
3847
+ xuanr2 x van2 rr
3848
+ xuanr3 x van3 rr
3849
+ xuanr4 x van4 rr
3850
+ xuanr5 x van5 rr
3851
+ xuer1 x ve1 rr
3852
+ xuer2 x ve2 rr
3853
+ xuer3 x ve3 rr
3854
+ xuer4 x ve4 rr
3855
+ xuer5 x ve5 rr
3856
+ xunr1 x vn1 rr
3857
+ xunr2 x vn2 rr
3858
+ xunr3 x vn3 rr
3859
+ xunr4 x vn4 rr
3860
+ xunr5 x vn5 rr
3861
+ yar1 y ia1 rr
3862
+ yar2 y ia2 rr
3863
+ yar3 y ia3 rr
3864
+ yar4 y ia4 rr
3865
+ yar5 y ia5 rr
3866
+ yanr1 y ian1 rr
3867
+ yanr2 y ian2 rr
3868
+ yanr3 y ian3 rr
3869
+ yanr4 y ian4 rr
3870
+ yanr5 y ian5 rr
3871
+ yangr1 y iang1 rr
3872
+ yangr2 y iang2 rr
3873
+ yangr3 y iang3 rr
3874
+ yangr4 y iang4 rr
3875
+ yangr5 y iang5 rr
3876
+ yaor1 y iao1 rr
3877
+ yaor2 y iao2 rr
3878
+ yaor3 y iao3 rr
3879
+ yaor4 y iao4 rr
3880
+ yaor5 y iao5 rr
3881
+ yer1 y ie1 rr
3882
+ yer2 y ie2 rr
3883
+ yer3 y ie3 rr
3884
+ yer4 y ie4 rr
3885
+ yer5 y ie5 rr
3886
+ yir1 y i1 rr
3887
+ yir2 y i2 rr
3888
+ yir3 y i3 rr
3889
+ yir4 y i4 rr
3890
+ yir5 y i5 rr
3891
+ yinr1 y in1 rr
3892
+ yinr2 y in2 rr
3893
+ yinr3 y in3 rr
3894
+ yinr4 y in4 rr
3895
+ yinr5 y in5 rr
3896
+ yingr1 y ing1 rr
3897
+ yingr2 y ing2 rr
3898
+ yingr3 y ing3 rr
3899
+ yingr4 y ing4 rr
3900
+ yingr5 y ing5 rr
3901
+ yor1 y iou1 rr
3902
+ yor2 y iou2 rr
3903
+ yor3 y iou3 rr
3904
+ yor4 y iou4 rr
3905
+ yor5 y iou5 rr
3906
+ yongr1 y iong1 rr
3907
+ yongr2 y iong2 rr
3908
+ yongr3 y iong3 rr
3909
+ yongr4 y iong4 rr
3910
+ yongr5 y iong5 rr
3911
+ your1 y iou1 rr
3912
+ your2 y iou2 rr
3913
+ your3 y iou3 rr
3914
+ your4 y iou4 rr
3915
+ your5 y iou5 rr
3916
+ yur1 y v1 rr
3917
+ yur2 y v2 rr
3918
+ yur3 y v3 rr
3919
+ yur4 y v4 rr
3920
+ yur5 y v5 rr
3921
+ yuanr1 y van1 rr
3922
+ yuanr2 y van2 rr
3923
+ yuanr3 y van3 rr
3924
+ yuanr4 y van4 rr
3925
+ yuanr5 y van5 rr
3926
+ yuer1 y ve1 rr
3927
+ yuer2 y ve2 rr
3928
+ yuer3 y ve3 rr
3929
+ yuer4 y ve4 rr
3930
+ yuer5 y ve5 rr
3931
+ yunr1 y vn1 rr
3932
+ yunr2 y vn2 rr
3933
+ yunr3 y vn3 rr
3934
+ yunr4 y vn4 rr
3935
+ yunr5 y vn5 rr
3936
+ zar1 z a1 rr
3937
+ zar2 z a2 rr
3938
+ zar3 z a3 rr
3939
+ zar4 z a4 rr
3940
+ zar5 z a5 rr
3941
+ zair1 z ai1 rr
3942
+ zair2 z ai2 rr
3943
+ zair3 z ai3 rr
3944
+ zair4 z ai4 rr
3945
+ zair5 z ai5 rr
3946
+ zanr1 z an1 rr
3947
+ zanr2 z an2 rr
3948
+ zanr3 z an3 rr
3949
+ zanr4 z an4 rr
3950
+ zanr5 z an5 rr
3951
+ zangr1 z ang1 rr
3952
+ zangr2 z ang2 rr
3953
+ zangr3 z ang3 rr
3954
+ zangr4 z ang4 rr
3955
+ zangr5 z ang5 rr
3956
+ zaor1 z ao1 rr
3957
+ zaor2 z ao2 rr
3958
+ zaor3 z ao3 rr
3959
+ zaor4 z ao4 rr
3960
+ zaor5 z ao5 rr
3961
+ zer1 z e1 rr
3962
+ zer2 z e2 rr
3963
+ zer3 z e3 rr
3964
+ zer4 z e4 rr
3965
+ zer5 z e5 rr
3966
+ zeir1 z ei1 rr
3967
+ zeir2 z ei2 rr
3968
+ zeir3 z ei3 rr
3969
+ zeir4 z ei4 rr
3970
+ zeir5 z ei5 rr
3971
+ zenr1 z en1 rr
3972
+ zenr2 z en2 rr
3973
+ zenr3 z en3 rr
3974
+ zenr4 z en4 rr
3975
+ zenr5 z en5 rr
3976
+ zengr1 z eng1 rr
3977
+ zengr2 z eng2 rr
3978
+ zengr3 z eng3 rr
3979
+ zengr4 z eng4 rr
3980
+ zengr5 z eng5 rr
3981
+ zhar1 zh a1 rr
3982
+ zhar2 zh a2 rr
3983
+ zhar3 zh a3 rr
3984
+ zhar4 zh a4 rr
3985
+ zhar5 zh a5 rr
3986
+ zhair1 zh ai1 rr
3987
+ zhair2 zh ai2 rr
3988
+ zhair3 zh ai3 rr
3989
+ zhair4 zh ai4 rr
3990
+ zhair5 zh ai5 rr
3991
+ zhanr1 zh an1 rr
3992
+ zhanr2 zh an2 rr
3993
+ zhanr3 zh an3 rr
3994
+ zhanr4 zh an4 rr
3995
+ zhanr5 zh an5 rr
3996
+ zhangr1 zh ang1 rr
3997
+ zhangr2 zh ang2 rr
3998
+ zhangr3 zh ang3 rr
3999
+ zhangr4 zh ang4 rr
4000
+ zhangr5 zh ang5 rr
4001
+ zhaor1 zh ao1 rr
4002
+ zhaor2 zh ao2 rr
4003
+ zhaor3 zh ao3 rr
4004
+ zhaor4 zh ao4 rr
4005
+ zhaor5 zh ao5 rr
4006
+ zher1 zh e1 rr
4007
+ zher2 zh e2 rr
4008
+ zher3 zh e3 rr
4009
+ zher4 zh e4 rr
4010
+ zher5 zh e5 rr
4011
+ zheir1 zh ei1 rr
4012
+ zheir2 zh ei2 rr
4013
+ zheir3 zh ei3 rr
4014
+ zheir4 zh ei4 rr
4015
+ zheir5 zh ei5 rr
4016
+ zhenr1 zh en1 rr
4017
+ zhenr2 zh en2 rr
4018
+ zhenr3 zh en3 rr
4019
+ zhenr4 zh en4 rr
4020
+ zhenr5 zh en5 rr
4021
+ zhengr1 zh eng1 rr
4022
+ zhengr2 zh eng2 rr
4023
+ zhengr3 zh eng3 rr
4024
+ zhengr4 zh eng4 rr
4025
+ zhengr5 zh eng5 rr
4026
+ zhir1 zh iii1 rr
4027
+ zhir2 zh iii2 rr
4028
+ zhir3 zh iii3 rr
4029
+ zhir4 zh iii4 rr
4030
+ zhir5 zh iii5 rr
4031
+ zhongr1 zh ong1 rr
4032
+ zhongr2 zh ong2 rr
4033
+ zhongr3 zh ong3 rr
4034
+ zhongr4 zh ong4 rr
4035
+ zhongr5 zh ong5 rr
4036
+ zhour1 zh ou1 rr
4037
+ zhour2 zh ou2 rr
4038
+ zhour3 zh ou3 rr
4039
+ zhour4 zh ou4 rr
4040
+ zhour5 zh ou5 rr
4041
+ zhur1 zh u1 rr
4042
+ zhur2 zh u2 rr
4043
+ zhur3 zh u3 rr
4044
+ zhur4 zh u4 rr
4045
+ zhur5 zh u5 rr
4046
+ zhuar1 zh ua1 rr
4047
+ zhuar2 zh ua2 rr
4048
+ zhuar3 zh ua3 rr
4049
+ zhuar4 zh ua4 rr
4050
+ zhuar5 zh ua5 rr
4051
+ zhuair1 zh uai1 rr
4052
+ zhuair2 zh uai2 rr
4053
+ zhuair3 zh uai3 rr
4054
+ zhuair4 zh uai4 rr
4055
+ zhuair5 zh uai5 rr
4056
+ zhuanr1 zh uan1 rr
4057
+ zhuanr2 zh uan2 rr
4058
+ zhuanr3 zh uan3 rr
4059
+ zhuanr4 zh uan4 rr
4060
+ zhuanr5 zh uan5 rr
4061
+ zhuangr1 zh uang1 rr
4062
+ zhuangr2 zh uang2 rr
4063
+ zhuangr3 zh uang3 rr
4064
+ zhuangr4 zh uang4 rr
4065
+ zhuangr5 zh uang5 rr
4066
+ zhuir1 zh uei1 rr
4067
+ zhuir2 zh uei2 rr
4068
+ zhuir3 zh uei3 rr
4069
+ zhuir4 zh uei4 rr
4070
+ zhuir5 zh uei5 rr
4071
+ zhunr1 zh uen1 rr
4072
+ zhunr2 zh uen2 rr
4073
+ zhunr3 zh uen3 rr
4074
+ zhunr4 zh uen4 rr
4075
+ zhunr5 zh uen5 rr
4076
+ zhuor1 zh uo1 rr
4077
+ zhuor2 zh uo2 rr
4078
+ zhuor3 zh uo3 rr
4079
+ zhuor4 zh uo4 rr
4080
+ zhuor5 zh uo5 rr
4081
+ zir1 z ii1 rr
4082
+ zir2 z ii2 rr
4083
+ zir3 z ii3 rr
4084
+ zir4 z ii4 rr
4085
+ zir5 z ii5 rr
4086
+ zongr1 z ong1 rr
4087
+ zongr2 z ong2 rr
4088
+ zongr3 z ong3 rr
4089
+ zongr4 z ong4 rr
4090
+ zongr5 z ong5 rr
4091
+ zour1 z ou1 rr
4092
+ zour2 z ou2 rr
4093
+ zour3 z ou3 rr
4094
+ zour4 z ou4 rr
4095
+ zour5 z ou5 rr
4096
+ zur1 z u1 rr
4097
+ zur2 z u2 rr
4098
+ zur3 z u3 rr
4099
+ zur4 z u4 rr
4100
+ zur5 z u5 rr
4101
+ zuanr1 z uan1 rr
4102
+ zuanr2 z uan2 rr
4103
+ zuanr3 z uan3 rr
4104
+ zuanr4 z uan4 rr
4105
+ zuanr5 z uan5 rr
4106
+ zuir1 z uei1 rr
4107
+ zuir2 z uei2 rr
4108
+ zuir3 z uei3 rr
4109
+ zuir4 z uei4 rr
4110
+ zuir5 z uei5 rr
4111
+ zunr1 z uen1 rr
4112
+ zunr2 z uen2 rr
4113
+ zunr3 z uen3 rr
4114
+ zunr4 z uen4 rr
4115
+ zunr5 z uen5 rr
4116
+ zuor1 z uo1 rr
4117
+ zuor2 z uo2 rr
4118
+ zuor3 z uo3 rr
4119
+ zuor4 z uo4 rr
4120
+ zuor5 z uo5 rr
text/numbers.py ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023 Amphion.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ """ This code is modified from https://github.com/keithito/tacotron """
7
+
8
+ import inflect
9
+ import re
10
+
11
+ _inflect = inflect.engine()
12
+ _comma_number_re = re.compile(r"([0-9][0-9\,]+[0-9])")
13
+ _decimal_number_re = re.compile(r"([0-9]+\.[0-9]+)")
14
+ _pounds_re = re.compile(r"£([0-9\,]*[0-9]+)")
15
+ _dollars_re = re.compile(r"\$([0-9\.\,]*[0-9]+)")
16
+ _ordinal_re = re.compile(r"[0-9]+(st|nd|rd|th)")
17
+ _number_re = re.compile(r"[0-9]+")
18
+
19
+
20
+ def _remove_commas(m):
21
+ return m.group(1).replace(",", "")
22
+
23
+
24
+ def _expand_decimal_point(m):
25
+ return m.group(1).replace(".", " point ")
26
+
27
+
28
+ def _expand_dollars(m):
29
+ match = m.group(1)
30
+ parts = match.split(".")
31
+ if len(parts) > 2:
32
+ return match + " dollars" # Unexpected format
33
+ dollars = int(parts[0]) if parts[0] else 0
34
+ cents = int(parts[1]) if len(parts) > 1 and parts[1] else 0
35
+ if dollars and cents:
36
+ dollar_unit = "dollar" if dollars == 1 else "dollars"
37
+ cent_unit = "cent" if cents == 1 else "cents"
38
+ return "%s %s, %s %s" % (dollars, dollar_unit, cents, cent_unit)
39
+ elif dollars:
40
+ dollar_unit = "dollar" if dollars == 1 else "dollars"
41
+ return "%s %s" % (dollars, dollar_unit)
42
+ elif cents:
43
+ cent_unit = "cent" if cents == 1 else "cents"
44
+ return "%s %s" % (cents, cent_unit)
45
+ else:
46
+ return "zero dollars"
47
+
48
+
49
+ def _expand_ordinal(m):
50
+ return _inflect.number_to_words(m.group(0))
51
+
52
+
53
+ def _expand_number(m):
54
+ num = int(m.group(0))
55
+ if num > 1000 and num < 3000:
56
+ if num == 2000:
57
+ return "two thousand"
58
+ elif num > 2000 and num < 2010:
59
+ return "two thousand " + _inflect.number_to_words(num % 100)
60
+ elif num % 100 == 0:
61
+ return _inflect.number_to_words(num // 100) + " hundred"
62
+ else:
63
+ return _inflect.number_to_words(
64
+ num, andword="", zero="oh", group=2
65
+ ).replace(", ", " ")
66
+ else:
67
+ return _inflect.number_to_words(num, andword="")
68
+
69
+
70
+ def normalize_numbers(text):
71
+ text = re.sub(_comma_number_re, _remove_commas, text)
72
+ text = re.sub(_pounds_re, r"\1 pounds", text)
73
+ text = re.sub(_dollars_re, _expand_dollars, text)
74
+ text = re.sub(_decimal_number_re, _expand_decimal_point, text)
75
+ text = re.sub(_ordinal_re, _expand_ordinal, text)
76
+ text = re.sub(_number_re, _expand_number, text)
77
+ return text
text/pinyin.py ADDED
@@ -0,0 +1,218 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023 Amphion.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ initials = [
7
+ "b",
8
+ "c",
9
+ "ch",
10
+ "d",
11
+ "f",
12
+ "g",
13
+ "h",
14
+ "j",
15
+ "k",
16
+ "l",
17
+ "m",
18
+ "n",
19
+ "p",
20
+ "q",
21
+ "r",
22
+ "s",
23
+ "sh",
24
+ "t",
25
+ "w",
26
+ "x",
27
+ "y",
28
+ "z",
29
+ "zh",
30
+ ]
31
+ finals = [
32
+ "a1",
33
+ "a2",
34
+ "a3",
35
+ "a4",
36
+ "a5",
37
+ "ai1",
38
+ "ai2",
39
+ "ai3",
40
+ "ai4",
41
+ "ai5",
42
+ "an1",
43
+ "an2",
44
+ "an3",
45
+ "an4",
46
+ "an5",
47
+ "ang1",
48
+ "ang2",
49
+ "ang3",
50
+ "ang4",
51
+ "ang5",
52
+ "ao1",
53
+ "ao2",
54
+ "ao3",
55
+ "ao4",
56
+ "ao5",
57
+ "e1",
58
+ "e2",
59
+ "e3",
60
+ "e4",
61
+ "e5",
62
+ "ei1",
63
+ "ei2",
64
+ "ei3",
65
+ "ei4",
66
+ "ei5",
67
+ "en1",
68
+ "en2",
69
+ "en3",
70
+ "en4",
71
+ "en5",
72
+ "eng1",
73
+ "eng2",
74
+ "eng3",
75
+ "eng4",
76
+ "eng5",
77
+ "er1",
78
+ "er2",
79
+ "er3",
80
+ "er4",
81
+ "er5",
82
+ "i1",
83
+ "i2",
84
+ "i3",
85
+ "i4",
86
+ "i5",
87
+ "ia1",
88
+ "ia2",
89
+ "ia3",
90
+ "ia4",
91
+ "ia5",
92
+ "ian1",
93
+ "ian2",
94
+ "ian3",
95
+ "ian4",
96
+ "ian5",
97
+ "iang1",
98
+ "iang2",
99
+ "iang3",
100
+ "iang4",
101
+ "iang5",
102
+ "iao1",
103
+ "iao2",
104
+ "iao3",
105
+ "iao4",
106
+ "iao5",
107
+ "ie1",
108
+ "ie2",
109
+ "ie3",
110
+ "ie4",
111
+ "ie5",
112
+ "ii1",
113
+ "ii2",
114
+ "ii3",
115
+ "ii4",
116
+ "ii5",
117
+ "iii1",
118
+ "iii2",
119
+ "iii3",
120
+ "iii4",
121
+ "iii5",
122
+ "in1",
123
+ "in2",
124
+ "in3",
125
+ "in4",
126
+ "in5",
127
+ "ing1",
128
+ "ing2",
129
+ "ing3",
130
+ "ing4",
131
+ "ing5",
132
+ "iong1",
133
+ "iong2",
134
+ "iong3",
135
+ "iong4",
136
+ "iong5",
137
+ "iou1",
138
+ "iou2",
139
+ "iou3",
140
+ "iou4",
141
+ "iou5",
142
+ "o1",
143
+ "o2",
144
+ "o3",
145
+ "o4",
146
+ "o5",
147
+ "ong1",
148
+ "ong2",
149
+ "ong3",
150
+ "ong4",
151
+ "ong5",
152
+ "ou1",
153
+ "ou2",
154
+ "ou3",
155
+ "ou4",
156
+ "ou5",
157
+ "u1",
158
+ "u2",
159
+ "u3",
160
+ "u4",
161
+ "u5",
162
+ "ua1",
163
+ "ua2",
164
+ "ua3",
165
+ "ua4",
166
+ "ua5",
167
+ "uai1",
168
+ "uai2",
169
+ "uai3",
170
+ "uai4",
171
+ "uai5",
172
+ "uan1",
173
+ "uan2",
174
+ "uan3",
175
+ "uan4",
176
+ "uan5",
177
+ "uang1",
178
+ "uang2",
179
+ "uang3",
180
+ "uang4",
181
+ "uang5",
182
+ "uei1",
183
+ "uei2",
184
+ "uei3",
185
+ "uei4",
186
+ "uei5",
187
+ "uen1",
188
+ "uen2",
189
+ "uen3",
190
+ "uen4",
191
+ "uen5",
192
+ "uo1",
193
+ "uo2",
194
+ "uo3",
195
+ "uo4",
196
+ "uo5",
197
+ "v1",
198
+ "v2",
199
+ "v3",
200
+ "v4",
201
+ "v5",
202
+ "van1",
203
+ "van2",
204
+ "van3",
205
+ "van4",
206
+ "van5",
207
+ "ve1",
208
+ "ve2",
209
+ "ve3",
210
+ "ve4",
211
+ "ve5",
212
+ "vn1",
213
+ "vn2",
214
+ "vn3",
215
+ "vn4",
216
+ "vn5",
217
+ ]
218
+ valid_symbols = initials + finals + ["rr"]
text/symbol_table.py ADDED
@@ -0,0 +1,292 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2020 Mobvoi Inc. (authors: Fangjun Kuang)
2
+ #
3
+ # See ../../../LICENSE for clarification regarding multiple authors
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ from dataclasses import dataclass
18
+ from dataclasses import field
19
+ from typing import Dict
20
+ from typing import Generic
21
+ from typing import List
22
+ from typing import Optional
23
+ from typing import TypeVar
24
+ from typing import Union
25
+
26
+ Symbol = TypeVar("Symbol")
27
+
28
+ # SymbolTable is copied from
29
+ # https://github.com/k2-fsa/k2/blob/master/k2/python/k2/symbol_table.py
30
+
31
+ """
32
+ SymbolTable: map symbol to id
33
+ """
34
+
35
+
36
+ @dataclass(repr=False)
37
+ class SymbolTable(Generic[Symbol]):
38
+ """SymbolTable that maps symbol IDs, found on the FSA arcs to
39
+ actual objects. These objects can be arbitrary Python objects
40
+ that can serve as keys in a dictionary (i.e. they need to be
41
+ hashable and immutable).
42
+
43
+ The SymbolTable can only be read to/written from disk if the
44
+ symbols are strings.
45
+ """
46
+
47
+ _id2sym: Dict[int, Symbol] = field(default_factory=dict)
48
+ """Map an integer to a symbol.
49
+ """
50
+
51
+ _sym2id: Dict[Symbol, int] = field(default_factory=dict)
52
+ """Map a symbol to an integer.
53
+ """
54
+
55
+ _next_available_id: int = 1
56
+ """A helper internal field that helps adding new symbols
57
+ to the table efficiently.
58
+ """
59
+
60
+ eps: Symbol = "<eps>"
61
+ """Null symbol, always mapped to index 0.
62
+ """
63
+
64
+ def __post_init__(self):
65
+ assert all(self._sym2id[sym] == idx for idx, sym in self._id2sym.items())
66
+ assert all(self._id2sym[idx] == sym for sym, idx in self._sym2id.items())
67
+ assert 0 not in self._id2sym or self._id2sym[0] == self.eps
68
+
69
+ self._next_available_id = max(self._id2sym, default=0) + 1
70
+ self._id2sym.setdefault(0, self.eps)
71
+ self._sym2id.setdefault(self.eps, 0)
72
+
73
+ @staticmethod
74
+ def from_str(s: str) -> "SymbolTable":
75
+ """Build a symbol table from a string.
76
+
77
+ The string consists of lines. Every line has two fields separated
78
+ by space(s), tab(s) or both. The first field is the symbol and the
79
+ second the integer id of the symbol.
80
+
81
+ Args:
82
+ s:
83
+ The input string with the format described above.
84
+ Returns:
85
+ An instance of :class:`SymbolTable`.
86
+ """
87
+ id2sym: Dict[int, str] = dict()
88
+ sym2id: Dict[str, int] = dict()
89
+
90
+ for line in s.split("\n"):
91
+ fields = line.split()
92
+ if len(fields) == 0:
93
+ continue # skip empty lines
94
+ assert (
95
+ len(fields) == 2
96
+ ), f"Expect a line with 2 fields. Given: {len(fields)}"
97
+ sym, idx = fields[0], int(fields[1])
98
+ assert sym not in sym2id, f"Duplicated symbol {sym}"
99
+ assert idx not in id2sym, f"Duplicated id {idx}"
100
+ id2sym[idx] = sym
101
+ sym2id[sym] = idx
102
+
103
+ eps = id2sym.get(0, "<eps>")
104
+
105
+ return SymbolTable(_id2sym=id2sym, _sym2id=sym2id, eps=eps)
106
+
107
+ @staticmethod
108
+ def from_file(filename: str) -> "SymbolTable":
109
+ """Build a symbol table from file.
110
+
111
+ Every line in the symbol table file has two fields separated by
112
+ space(s), tab(s) or both. The following is an example file:
113
+
114
+ .. code-block::
115
+
116
+ <eps> 0
117
+ a 1
118
+ b 2
119
+ c 3
120
+
121
+ Args:
122
+ filename:
123
+ Name of the symbol table file. Its format is documented above.
124
+
125
+ Returns:
126
+ An instance of :class:`SymbolTable`.
127
+
128
+ """
129
+ with open(filename, "r", encoding="utf-8") as f:
130
+ return SymbolTable.from_str(f.read().strip())
131
+
132
+ def to_str(self) -> str:
133
+ """
134
+ Returns:
135
+ Return a string representation of this object. You can pass
136
+ it to the method ``from_str`` to recreate an identical object.
137
+ """
138
+ s = ""
139
+ for idx, symbol in sorted(self._id2sym.items()):
140
+ s += f"{symbol} {idx}\n"
141
+ return s
142
+
143
+ def to_file(self, filename: str):
144
+ """Serialize the SymbolTable to a file.
145
+
146
+ Every line in the symbol table file has two fields separated by
147
+ space(s), tab(s) or both. The following is an example file:
148
+
149
+ .. code-block::
150
+
151
+ <eps> 0
152
+ a 1
153
+ b 2
154
+ c 3
155
+
156
+ Args:
157
+ filename:
158
+ Name of the symbol table file. Its format is documented above.
159
+ """
160
+ with open(filename, "w") as f:
161
+ for idx, symbol in sorted(self._id2sym.items()):
162
+ print(symbol, idx, file=f)
163
+
164
+ def add(self, symbol: Symbol, index: Optional[int] = None) -> int:
165
+ """Add a new symbol to the SymbolTable.
166
+
167
+ Args:
168
+ symbol:
169
+ The symbol to be added.
170
+ index:
171
+ Optional int id to which the symbol should be assigned.
172
+ If it is not available, a ValueError will be raised.
173
+
174
+ Returns:
175
+ The int id to which the symbol has been assigned.
176
+ """
177
+ # Already in the table? Return its ID.
178
+ if symbol in self._sym2id:
179
+ return self._sym2id[symbol]
180
+ # Specific ID not provided - use next available.
181
+ if index is None:
182
+ index = self._next_available_id
183
+ # Specific ID provided but not available.
184
+ if index in self._id2sym:
185
+ raise ValueError(
186
+ f"Cannot assign id '{index}' to '{symbol}' - "
187
+ f"already occupied by {self._id2sym[index]}"
188
+ )
189
+ self._sym2id[symbol] = index
190
+ self._id2sym[index] = symbol
191
+
192
+ # Update next available ID if needed
193
+ if self._next_available_id <= index:
194
+ self._next_available_id = index + 1
195
+
196
+ return index
197
+
198
+ def get(self, k: Union[int, Symbol]) -> Union[Symbol, int]:
199
+ """Get a symbol for an id or get an id for a symbol
200
+
201
+ Args:
202
+ k:
203
+ If it is an id, it tries to find the symbol corresponding
204
+ to the id; if it is a symbol, it tries to find the id
205
+ corresponding to the symbol.
206
+
207
+ Returns:
208
+ An id or a symbol depending on the given `k`.
209
+ """
210
+ if isinstance(k, int):
211
+ return self._id2sym[k]
212
+ else:
213
+ return self._sym2id[k]
214
+
215
+ def merge(self, other: "SymbolTable") -> "SymbolTable":
216
+ """Create a union of two SymbolTables.
217
+ Raises an AssertionError if the same IDs are occupied by
218
+ different symbols.
219
+
220
+ Args:
221
+ other:
222
+ A symbol table to merge with ``self``.
223
+
224
+ Returns:
225
+ A new symbol table.
226
+ """
227
+ self._check_compatible(other)
228
+ return SymbolTable(
229
+ _id2sym={**self._id2sym, **other._id2sym},
230
+ _sym2id={**self._sym2id, **other._sym2id},
231
+ eps=self.eps,
232
+ )
233
+
234
+ def _check_compatible(self, other: "SymbolTable") -> None:
235
+ # Epsilon compatibility
236
+ assert self.eps == other.eps, (
237
+ f"Mismatched epsilon symbol: " f"{self.eps} != {other.eps}"
238
+ )
239
+ # IDs compatibility
240
+ common_ids = set(self._id2sym).intersection(other._id2sym)
241
+ for idx in common_ids:
242
+ assert self[idx] == other[idx], (
243
+ f"ID conflict for id: {idx}, "
244
+ f'self[idx] = "{self[idx]}", '
245
+ f'other[idx] = "{other[idx]}"'
246
+ )
247
+ # Symbols compatibility
248
+ common_symbols = set(self._sym2id).intersection(other._sym2id)
249
+ for sym in common_symbols:
250
+ assert self[sym] == other[sym], (
251
+ f"ID conflict for id: {sym}, "
252
+ f'self[sym] = "{self[sym]}", '
253
+ f'other[sym] = "{other[sym]}"'
254
+ )
255
+
256
+ def __getitem__(self, item: Union[int, Symbol]) -> Union[Symbol, int]:
257
+ return self.get(item)
258
+
259
+ def __contains__(self, item: Union[int, Symbol]) -> bool:
260
+ if isinstance(item, int):
261
+ return item in self._id2sym
262
+ else:
263
+ return item in self._sym2id
264
+
265
+ def __len__(self) -> int:
266
+ return len(self._id2sym)
267
+
268
+ def __eq__(self, other: "SymbolTable") -> bool:
269
+ if len(self) != len(other):
270
+ return False
271
+
272
+ for s in self.symbols:
273
+ if self[s] != other[s]:
274
+ return False
275
+
276
+ return True
277
+
278
+ @property
279
+ def ids(self) -> List[int]:
280
+ """Returns a list of integer IDs corresponding to the symbols."""
281
+ ans = list(self._id2sym.keys())
282
+ ans.sort()
283
+ return ans
284
+
285
+ @property
286
+ def symbols(self) -> List[Symbol]:
287
+ """Returns a list of symbols (e.g., strings) corresponding to
288
+ the integer IDs.
289
+ """
290
+ ans = list(self._sym2id.keys())
291
+ ans.sort()
292
+ return ans
text/symbols.py ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023 Amphion.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ """ This code is modified from https://github.com/keithito/tacotron """
7
+
8
+ """
9
+ Defines the set of symbols used in text input to the model.
10
+
11
+ The default is a set of ASCII characters that works well for English or text that has been run through Unidecode. For other data, you can modify _characters. See TRAINING_DATA.md for details. """
12
+
13
+ from text import cmudict, pinyin
14
+
15
+ _pad = "_"
16
+ _punctuation = "!'(),.:;? "
17
+ _special = "-"
18
+ _letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
19
+ _silences = ["@sp", "@spn", "@sil"]
20
+
21
+ # Prepend "@" to ARPAbet symbols to ensure uniqueness (some are the same as uppercase letters):
22
+ _arpabet = ["@" + s for s in cmudict.valid_symbols]
23
+ _pinyin = ["@" + s for s in pinyin.valid_symbols]
24
+
25
+ # Export all symbols:
26
+ symbols = (
27
+ [_pad]
28
+ + list(_special)
29
+ + list(_punctuation)
30
+ + list(_letters)
31
+ + _arpabet
32
+ + _silences
33
+ # + _pinyin # for chinese
34
+ )
text/text_token_collation.py ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023 Amphion.
2
+
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ from pathlib import Path
7
+ from typing import List, Tuple
8
+ import os
9
+ import numpy as np
10
+ import torch
11
+ from text.symbol_table import SymbolTable
12
+ from text import text_to_sequence
13
+
14
+
15
+ """
16
+ TextToken: map text to id
17
+ """
18
+
19
+
20
+ # TextTokenCollator is modified from
21
+ # https://github.com/lifeiteng/vall-e/blob/9c69096d603ce13174fb5cb025f185e2e9b36ac7/valle/data/collation.py
22
+ class TextTokenCollator:
23
+ def __init__(
24
+ self,
25
+ text_tokens: List[str],
26
+ add_eos: bool = True,
27
+ add_bos: bool = True,
28
+ pad_symbol: str = "<pad>",
29
+ bos_symbol: str = "<bos>",
30
+ eos_symbol: str = "<eos>",
31
+ ):
32
+ self.pad_symbol = pad_symbol
33
+ self.add_eos = add_eos
34
+ self.add_bos = add_bos
35
+ self.bos_symbol = bos_symbol
36
+ self.eos_symbol = eos_symbol
37
+
38
+ unique_tokens = [pad_symbol]
39
+ if add_bos:
40
+ unique_tokens.append(bos_symbol)
41
+ if add_eos:
42
+ unique_tokens.append(eos_symbol)
43
+ unique_tokens.extend(sorted(text_tokens))
44
+
45
+ self.token2idx = {token: idx for idx, token in enumerate(unique_tokens)}
46
+ self.idx2token = unique_tokens
47
+
48
+ def index(self, tokens_list: List[str]) -> Tuple[torch.Tensor, torch.Tensor]:
49
+ seqs, seq_lens = [], []
50
+ for tokens in tokens_list:
51
+ assert all([True if s in self.token2idx else False for s in tokens]) is True
52
+ seq = (
53
+ ([self.bos_symbol] if self.add_bos else [])
54
+ + list(tokens)
55
+ + ([self.eos_symbol] if self.add_eos else [])
56
+ )
57
+ seqs.append(seq)
58
+ seq_lens.append(len(seq))
59
+
60
+ max_len = max(seq_lens)
61
+ for k, (seq, seq_len) in enumerate(zip(seqs, seq_lens)):
62
+ seq.extend([self.pad_symbol] * (max_len - seq_len))
63
+
64
+ tokens = torch.from_numpy(
65
+ np.array(
66
+ [[self.token2idx[token] for token in seq] for seq in seqs],
67
+ dtype=np.int64,
68
+ )
69
+ )
70
+ tokens_lens = torch.IntTensor(seq_lens)
71
+
72
+ return tokens, tokens_lens
73
+
74
+ def __call__(self, text):
75
+ tokens_seq = [p for p in text]
76
+ seq = (
77
+ ([self.bos_symbol] if self.add_bos else [])
78
+ + tokens_seq
79
+ + ([self.eos_symbol] if self.add_eos else [])
80
+ )
81
+
82
+ token_ids = [self.token2idx[token] for token in seq]
83
+ token_lens = len(tokens_seq) + self.add_eos + self.add_bos
84
+
85
+ return token_ids, token_lens
86
+
87
+
88
+ def get_text_token_collater(text_tokens_file: str) -> TextTokenCollator:
89
+ text_tokens_path = Path(text_tokens_file)
90
+ unique_tokens = SymbolTable.from_file(text_tokens_path)
91
+ collater = TextTokenCollator(unique_tokens.symbols, add_bos=True, add_eos=True)
92
+ token2idx = collater.token2idx
93
+ return collater, token2idx
94
+
95
+
96
+ class phoneIDCollation:
97
+ def __init__(self, cfg, dataset=None, symbols_dict_file=None) -> None:
98
+ if cfg.preprocess.phone_extractor != "lexicon":
99
+ ### get text token collator
100
+ if symbols_dict_file is None:
101
+ assert dataset is not None
102
+ symbols_dict_file = os.path.join(
103
+ cfg.preprocess.processed_dir, dataset, cfg.preprocess.symbols_dict
104
+ )
105
+ self.text_token_colloator, token2idx = get_text_token_collater(
106
+ symbols_dict_file
107
+ )
108
+ # # unique_tokens = SymbolTable.from_file(symbols_dict_path)
109
+ # # text_tokenizer = TextToken(unique_tokens.symbols, add_bos=True, add_eos=True)
110
+
111
+ # # update phone symbols dict file with pad_symbol or optional tokens (add_bos and add_eos) in TextTokenCollator
112
+ # phone_symbol_dict = SymbolTable()
113
+ # for s in sorted(list(set(token2idx.keys()))):
114
+ # phone_symbol_dict.add(s)
115
+ # phone_symbol_dict.to_file(symbols_dict_file)
116
+
117
+ def get_phone_id_sequence(self, cfg, phones_seq):
118
+ if cfg.preprocess.phone_extractor == "lexicon":
119
+ phones_seq = " ".join(phones_seq)
120
+ sequence = text_to_sequence(phones_seq, cfg.preprocess.text_cleaners)
121
+ else:
122
+ sequence, seq_len = self.text_token_colloator(phones_seq)
123
+ return sequence
utils/HyperParams/__init__.py ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023 Amphion.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ from .hps import HyperParams
utils/HyperParams/hps.py ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023 Amphion.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+
7
+ class HyperParams:
8
+ """The class to store hyperparameters. The key is case-insensitive.
9
+
10
+ Args:
11
+ *args: a list of dict or HyperParams.
12
+ **kwargs: a list of key-value pairs.
13
+ """
14
+
15
+ def __init__(self, **kwargs):
16
+ for k, v in kwargs.items():
17
+ if type(v) == dict:
18
+ v = HyperParams(**v)
19
+ self[k] = v
20
+
21
+ def keys(self):
22
+ return self.__dict__.keys()
23
+
24
+ def items(self):
25
+ return self.__dict__.items()
26
+
27
+ def values(self):
28
+ return self.__dict__.values()
29
+
30
+ def __len__(self):
31
+ return len(self.__dict__)
32
+
33
+ def __getitem__(self, key):
34
+ return getattr(self, key)
35
+
36
+ def __setitem__(self, key, value):
37
+ return setattr(self, key, value)
38
+
39
+ def __contains__(self, key):
40
+ return key in self.__dict__
41
+
42
+ def __repr__(self):
43
+ return self.__dict__.__repr__()
utils/__init__.py ADDED
File without changes
utils/audio.py ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023 Amphion.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ import torch
7
+ import numpy as np
8
+ from numpy import linalg as LA
9
+ import librosa
10
+ import soundfile as sf
11
+ import librosa.filters
12
+
13
+
14
+ def load_audio_torch(wave_file, fs):
15
+ """Load audio data into torch tensor
16
+
17
+ Args:
18
+ wave_file (str): path to wave file
19
+ fs (int): sample rate
20
+
21
+ Returns:
22
+ audio (tensor): audio data in tensor
23
+ fs (int): sample rate
24
+ """
25
+
26
+ audio, sample_rate = librosa.load(wave_file, sr=fs, mono=True)
27
+ # audio: (T,)
28
+ assert len(audio) > 2
29
+
30
+ # Check the audio type (for soundfile loading backbone) - float, 8bit or 16bit
31
+ if np.issubdtype(audio.dtype, np.integer):
32
+ max_mag = -np.iinfo(audio.dtype).min
33
+ else:
34
+ max_mag = max(np.amax(audio), -np.amin(audio))
35
+ max_mag = (
36
+ (2**31) + 1
37
+ if max_mag > (2**15)
38
+ else ((2**15) + 1 if max_mag > 1.01 else 1.0)
39
+ )
40
+
41
+ # Normalize the audio
42
+ audio = torch.FloatTensor(audio.astype(np.float32)) / max_mag
43
+
44
+ if (torch.isnan(audio) | torch.isinf(audio)).any():
45
+ return [], sample_rate or fs or 48000
46
+
47
+ # Resample the audio to our target samplerate
48
+ if fs is not None and fs != sample_rate:
49
+ audio = torch.from_numpy(
50
+ librosa.core.resample(audio.numpy(), orig_sr=sample_rate, target_sr=fs)
51
+ )
52
+ sample_rate = fs
53
+
54
+ return audio, fs
55
+
56
+
57
+ def _stft(y, cfg):
58
+ return librosa.stft(
59
+ y=y, n_fft=cfg.n_fft, hop_length=cfg.hop_size, win_length=cfg.win_size
60
+ )
61
+
62
+
63
+ def energy(wav, cfg):
64
+ D = _stft(wav, cfg)
65
+ magnitudes = np.abs(D).T # [F, T]
66
+ return LA.norm(magnitudes, axis=1)
67
+
68
+
69
+ def get_energy_from_tacotron(audio, _stft):
70
+ audio = torch.clip(torch.FloatTensor(audio).unsqueeze(0), -1, 1)
71
+ audio = torch.autograd.Variable(audio, requires_grad=False)
72
+ mel, energy = _stft.mel_spectrogram(audio)
73
+ energy = torch.squeeze(energy, 0).numpy().astype(np.float32)
74
+ return mel, energy
utils/audio_slicer.py ADDED
@@ -0,0 +1,476 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023 Amphion.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ import os
7
+ import json
8
+ import numpy as np
9
+ from tqdm import tqdm
10
+ import torch
11
+ import torchaudio
12
+
13
+ from utils.io import save_audio
14
+ from utils.audio import load_audio_torch
15
+
16
+
17
+ # This function is obtained from librosa.
18
+ def get_rms(
19
+ y,
20
+ *,
21
+ frame_length=2048,
22
+ hop_length=512,
23
+ pad_mode="constant",
24
+ ):
25
+ padding = (int(frame_length // 2), int(frame_length // 2))
26
+ y = np.pad(y, padding, mode=pad_mode)
27
+
28
+ axis = -1
29
+ # put our new within-frame axis at the end for now
30
+ out_strides = y.strides + tuple([y.strides[axis]])
31
+ # Reduce the shape on the framing axis
32
+ x_shape_trimmed = list(y.shape)
33
+ x_shape_trimmed[axis] -= frame_length - 1
34
+ out_shape = tuple(x_shape_trimmed) + tuple([frame_length])
35
+ xw = np.lib.stride_tricks.as_strided(y, shape=out_shape, strides=out_strides)
36
+ if axis < 0:
37
+ target_axis = axis - 1
38
+ else:
39
+ target_axis = axis + 1
40
+ xw = np.moveaxis(xw, -1, target_axis)
41
+ # Downsample along the target axis
42
+ slices = [slice(None)] * xw.ndim
43
+ slices[axis] = slice(0, None, hop_length)
44
+ x = xw[tuple(slices)]
45
+
46
+ # Calculate power
47
+ power = np.mean(np.abs(x) ** 2, axis=-2, keepdims=True)
48
+
49
+ return np.sqrt(power)
50
+
51
+
52
+ class Slicer:
53
+ """
54
+ Copy from: https://github.com/openvpi/audio-slicer/blob/main/slicer2.py
55
+ """
56
+
57
+ def __init__(
58
+ self,
59
+ sr: int,
60
+ threshold: float = -40.0,
61
+ min_length: int = 5000,
62
+ min_interval: int = 300,
63
+ hop_size: int = 10,
64
+ max_sil_kept: int = 5000,
65
+ ):
66
+ if not min_length >= min_interval >= hop_size:
67
+ raise ValueError(
68
+ "The following condition must be satisfied: min_length >= min_interval >= hop_size"
69
+ )
70
+ if not max_sil_kept >= hop_size:
71
+ raise ValueError(
72
+ "The following condition must be satisfied: max_sil_kept >= hop_size"
73
+ )
74
+ min_interval = sr * min_interval / 1000
75
+ self.threshold = 10 ** (threshold / 20.0)
76
+ self.hop_size = round(sr * hop_size / 1000)
77
+ self.win_size = min(round(min_interval), 4 * self.hop_size)
78
+ self.min_length = round(sr * min_length / 1000 / self.hop_size)
79
+ self.min_interval = round(min_interval / self.hop_size)
80
+ self.max_sil_kept = round(sr * max_sil_kept / 1000 / self.hop_size)
81
+
82
+ def _apply_slice(self, waveform, begin, end):
83
+ begin = begin * self.hop_size
84
+ if len(waveform.shape) > 1:
85
+ end = min(waveform.shape[1], end * self.hop_size)
86
+ return waveform[:, begin:end], begin, end
87
+ else:
88
+ end = min(waveform.shape[0], end * self.hop_size)
89
+ return waveform[begin:end], begin, end
90
+
91
+ # @timeit
92
+ def slice(self, waveform, return_chunks_positions=False):
93
+ if len(waveform.shape) > 1:
94
+ # (#channle, wave_len) -> (wave_len)
95
+ samples = waveform.mean(axis=0)
96
+ else:
97
+ samples = waveform
98
+ if samples.shape[0] <= self.min_length:
99
+ return [waveform]
100
+ rms_list = get_rms(
101
+ y=samples, frame_length=self.win_size, hop_length=self.hop_size
102
+ ).squeeze(0)
103
+ sil_tags = []
104
+ silence_start = None
105
+ clip_start = 0
106
+ for i, rms in enumerate(rms_list):
107
+ # Keep looping while frame is silent.
108
+ if rms < self.threshold:
109
+ # Record start of silent frames.
110
+ if silence_start is None:
111
+ silence_start = i
112
+ continue
113
+ # Keep looping while frame is not silent and silence start has not been recorded.
114
+ if silence_start is None:
115
+ continue
116
+ # Clear recorded silence start if interval is not enough or clip is too short
117
+ is_leading_silence = silence_start == 0 and i > self.max_sil_kept
118
+ need_slice_middle = (
119
+ i - silence_start >= self.min_interval
120
+ and i - clip_start >= self.min_length
121
+ )
122
+ if not is_leading_silence and not need_slice_middle:
123
+ silence_start = None
124
+ continue
125
+ # Need slicing. Record the range of silent frames to be removed.
126
+ if i - silence_start <= self.max_sil_kept:
127
+ pos = rms_list[silence_start : i + 1].argmin() + silence_start
128
+ if silence_start == 0:
129
+ sil_tags.append((0, pos))
130
+ else:
131
+ sil_tags.append((pos, pos))
132
+ clip_start = pos
133
+ elif i - silence_start <= self.max_sil_kept * 2:
134
+ pos = rms_list[
135
+ i - self.max_sil_kept : silence_start + self.max_sil_kept + 1
136
+ ].argmin()
137
+ pos += i - self.max_sil_kept
138
+ pos_l = (
139
+ rms_list[
140
+ silence_start : silence_start + self.max_sil_kept + 1
141
+ ].argmin()
142
+ + silence_start
143
+ )
144
+ pos_r = (
145
+ rms_list[i - self.max_sil_kept : i + 1].argmin()
146
+ + i
147
+ - self.max_sil_kept
148
+ )
149
+ if silence_start == 0:
150
+ sil_tags.append((0, pos_r))
151
+ clip_start = pos_r
152
+ else:
153
+ sil_tags.append((min(pos_l, pos), max(pos_r, pos)))
154
+ clip_start = max(pos_r, pos)
155
+ else:
156
+ pos_l = (
157
+ rms_list[
158
+ silence_start : silence_start + self.max_sil_kept + 1
159
+ ].argmin()
160
+ + silence_start
161
+ )
162
+ pos_r = (
163
+ rms_list[i - self.max_sil_kept : i + 1].argmin()
164
+ + i
165
+ - self.max_sil_kept
166
+ )
167
+ if silence_start == 0:
168
+ sil_tags.append((0, pos_r))
169
+ else:
170
+ sil_tags.append((pos_l, pos_r))
171
+ clip_start = pos_r
172
+ silence_start = None
173
+ # Deal with trailing silence.
174
+ total_frames = rms_list.shape[0]
175
+ if (
176
+ silence_start is not None
177
+ and total_frames - silence_start >= self.min_interval
178
+ ):
179
+ silence_end = min(total_frames, silence_start + self.max_sil_kept)
180
+ pos = rms_list[silence_start : silence_end + 1].argmin() + silence_start
181
+ sil_tags.append((pos, total_frames + 1))
182
+ # Apply and return slices.
183
+ if len(sil_tags) == 0:
184
+ return [waveform]
185
+ else:
186
+ chunks = []
187
+ chunks_pos_of_waveform = []
188
+
189
+ if sil_tags[0][0] > 0:
190
+ chunk, begin, end = self._apply_slice(waveform, 0, sil_tags[0][0])
191
+ chunks.append(chunk)
192
+ chunks_pos_of_waveform.append((begin, end))
193
+
194
+ for i in range(len(sil_tags) - 1):
195
+ chunk, begin, end = self._apply_slice(
196
+ waveform, sil_tags[i][1], sil_tags[i + 1][0]
197
+ )
198
+ chunks.append(chunk)
199
+ chunks_pos_of_waveform.append((begin, end))
200
+
201
+ if sil_tags[-1][1] < total_frames:
202
+ chunk, begin, end = self._apply_slice(
203
+ waveform, sil_tags[-1][1], total_frames
204
+ )
205
+ chunks.append(chunk)
206
+ chunks_pos_of_waveform.append((begin, end))
207
+
208
+ return (
209
+ chunks
210
+ if not return_chunks_positions
211
+ else (
212
+ chunks,
213
+ chunks_pos_of_waveform,
214
+ )
215
+ )
216
+
217
+
218
+ def split_utterances_from_audio(
219
+ wav_file,
220
+ output_dir,
221
+ max_duration_of_utterance=10.0,
222
+ min_interval=300,
223
+ db_threshold=-40,
224
+ ):
225
+ """
226
+ Split a long audio into utterances accoring to the silence (VAD).
227
+
228
+ max_duration_of_utterance (second):
229
+ The maximum duration of every utterance (seconds)
230
+ min_interval (millisecond):
231
+ The smaller min_interval is, the more sliced audio clips this script is likely to generate.
232
+ """
233
+ print("File:", wav_file.split("/")[-1])
234
+ waveform, fs = torchaudio.load(wav_file)
235
+
236
+ slicer = Slicer(sr=fs, min_interval=min_interval, threshold=db_threshold)
237
+ chunks, positions = slicer.slice(waveform, return_chunks_positions=True)
238
+
239
+ durations = [(end - begin) / fs for begin, end in positions]
240
+ print(
241
+ "Slicer's min silence part is {}ms, min and max duration of sliced utterances is {}s and {}s".format(
242
+ min_interval, min(durations), max(durations)
243
+ )
244
+ )
245
+
246
+ res_chunks, res_positions = [], []
247
+ for i, chunk in enumerate(chunks):
248
+ if len(chunk.shape) == 1:
249
+ chunk = chunk[None, :]
250
+
251
+ begin, end = positions[i]
252
+ assert end - begin == chunk.shape[-1]
253
+
254
+ max_wav_len = max_duration_of_utterance * fs
255
+ if chunk.shape[-1] <= max_wav_len:
256
+ res_chunks.append(chunk)
257
+ res_positions.append(positions[i])
258
+ else:
259
+ # TODO: to reserve overlapping and conduct fade-in, fade-out
260
+
261
+ # Get segments number
262
+ number = 2
263
+ while chunk.shape[-1] // number >= max_wav_len:
264
+ number += 1
265
+ seg_len = chunk.shape[-1] // number
266
+
267
+ # Split
268
+ for num in range(number):
269
+ s = seg_len * num
270
+ t = min(s + seg_len, chunk.shape[-1])
271
+
272
+ seg_begin = begin + s
273
+ seg_end = begin + t
274
+
275
+ res_chunks.append(chunk[:, s:t])
276
+ res_positions.append((seg_begin, seg_end))
277
+
278
+ # Save utterances
279
+ os.makedirs(output_dir, exist_ok=True)
280
+ res = {"fs": int(fs)}
281
+ for i, chunk in enumerate(res_chunks):
282
+ filename = "{:04d}.wav".format(i)
283
+ res[filename] = [int(p) for p in res_positions[i]]
284
+ save_audio(os.path.join(output_dir, filename), chunk, fs)
285
+
286
+ # Save positions
287
+ with open(os.path.join(output_dir, "positions.json"), "w") as f:
288
+ json.dump(res, f, indent=4, ensure_ascii=False)
289
+ return res
290
+
291
+
292
+ def is_silence(
293
+ wavform,
294
+ fs,
295
+ threshold=-40.0,
296
+ min_interval=300,
297
+ hop_size=10,
298
+ min_length=5000,
299
+ ):
300
+ """
301
+ Detect whether the given wavform is a silence
302
+
303
+ wavform: (T, )
304
+ """
305
+ threshold = 10 ** (threshold / 20.0)
306
+
307
+ hop_size = round(fs * hop_size / 1000)
308
+ win_size = min(round(min_interval), 4 * hop_size)
309
+ min_length = round(fs * min_length / 1000 / hop_size)
310
+
311
+ if wavform.shape[0] <= min_length:
312
+ return True
313
+
314
+ # (#Frame,)
315
+ rms_array = get_rms(y=wavform, frame_length=win_size, hop_length=hop_size).squeeze(
316
+ 0
317
+ )
318
+ return (rms_array < threshold).all()
319
+
320
+
321
+ def split_audio(
322
+ wav_file, target_sr, output_dir, max_duration_of_segment=10.0, overlap_duration=1.0
323
+ ):
324
+ """
325
+ Split a long audio into segments.
326
+
327
+ target_sr:
328
+ The target sampling rate to save the segments.
329
+ max_duration_of_utterance (second):
330
+ The maximum duration of every utterance (second)
331
+ overlap_duraion:
332
+ Each segment has "overlap duration" (second) overlap with its previous and next segment
333
+ """
334
+ # (#channel, T) -> (T,)
335
+ waveform, fs = torchaudio.load(wav_file)
336
+ waveform = torchaudio.functional.resample(
337
+ waveform, orig_freq=fs, new_freq=target_sr
338
+ )
339
+ waveform = torch.mean(waveform, dim=0)
340
+
341
+ # waveform, _ = load_audio_torch(wav_file, target_sr)
342
+ assert len(waveform.shape) == 1
343
+
344
+ assert overlap_duration < max_duration_of_segment
345
+ length = int(max_duration_of_segment * target_sr)
346
+ stride = int((max_duration_of_segment - overlap_duration) * target_sr)
347
+ chunks = []
348
+ for i in range(0, len(waveform), stride):
349
+ # (length,)
350
+ chunks.append(waveform[i : i + length])
351
+ if i + length >= len(waveform):
352
+ break
353
+
354
+ # Save segments
355
+ os.makedirs(output_dir, exist_ok=True)
356
+ results = []
357
+ for i, chunk in enumerate(chunks):
358
+ uid = "{:04d}".format(i)
359
+ filename = os.path.join(output_dir, "{}.wav".format(uid))
360
+ results.append(
361
+ {"Uid": uid, "Path": filename, "Duration": len(chunk) / target_sr}
362
+ )
363
+ save_audio(
364
+ filename,
365
+ chunk,
366
+ target_sr,
367
+ turn_up=not is_silence(chunk, target_sr),
368
+ add_silence=False,
369
+ )
370
+
371
+ return results
372
+
373
+
374
+ def merge_segments_torchaudio(wav_files, fs, output_path, overlap_duration=1.0):
375
+ """Merge the given wav_files (may have overlaps) into a long audio
376
+
377
+ fs:
378
+ The sampling rate of the wav files.
379
+ output_path:
380
+ The output path to save the merged audio.
381
+ overlap_duration (float, optional):
382
+ Each segment has "overlap duration" (second) overlap with its previous and next segment. Defaults to 1.0.
383
+ """
384
+
385
+ waveforms = []
386
+ for file in wav_files:
387
+ # (T,)
388
+ waveform, _ = load_audio_torch(file, fs)
389
+ waveforms.append(waveform)
390
+
391
+ if len(waveforms) == 1:
392
+ save_audio(output_path, waveforms[0], fs, add_silence=False, turn_up=False)
393
+ return
394
+
395
+ overlap_len = int(overlap_duration * fs)
396
+ fade_out = torchaudio.transforms.Fade(fade_out_len=overlap_len)
397
+ fade_in = torchaudio.transforms.Fade(fade_in_len=overlap_len)
398
+ fade_in_and_out = torchaudio.transforms.Fade(fade_out_len=overlap_len)
399
+
400
+ segments_lens = [len(wav) for wav in waveforms]
401
+ merged_waveform_len = sum(segments_lens) - overlap_len * (len(waveforms) - 1)
402
+ merged_waveform = torch.zeros(merged_waveform_len)
403
+
404
+ start = 0
405
+ for index, wav in enumerate(
406
+ tqdm(waveforms, desc="Merge for {}".format(output_path))
407
+ ):
408
+ wav_len = len(wav)
409
+
410
+ if index == 0:
411
+ wav = fade_out(wav)
412
+ elif index == len(waveforms) - 1:
413
+ wav = fade_in(wav)
414
+ else:
415
+ wav = fade_in_and_out(wav)
416
+
417
+ merged_waveform[start : start + wav_len] = wav
418
+ start += wav_len - overlap_len
419
+
420
+ save_audio(output_path, merged_waveform, fs, add_silence=False, turn_up=True)
421
+
422
+
423
+ def merge_segments_encodec(wav_files, fs, output_path, overlap_duration=1.0):
424
+ """Merge the given wav_files (may have overlaps) into a long audio
425
+
426
+ fs:
427
+ The sampling rate of the wav files.
428
+ output_path:
429
+ The output path to save the merged audio.
430
+ overlap_duration (float, optional):
431
+ Each segment has "overlap duration" (second) overlap with its previous and next segment. Defaults to 1.0.
432
+ """
433
+
434
+ waveforms = []
435
+ for file in wav_files:
436
+ # (T,)
437
+ waveform, _ = load_audio_torch(file, fs)
438
+ waveforms.append(waveform)
439
+
440
+ if len(waveforms) == 1:
441
+ save_audio(output_path, waveforms[0], fs, add_silence=False, turn_up=False)
442
+ return
443
+
444
+ device = waveforms[0].device
445
+ dtype = waveforms[0].dtype
446
+ shape = waveforms[0].shape[:-1]
447
+
448
+ overlap_len = int(overlap_duration * fs)
449
+ segments_lens = [len(wav) for wav in waveforms]
450
+ merged_waveform_len = sum(segments_lens) - overlap_len * (len(waveforms) - 1)
451
+
452
+ sum_weight = torch.zeros(merged_waveform_len, device=device, dtype=dtype)
453
+ out = torch.zeros(*shape, merged_waveform_len, device=device, dtype=dtype)
454
+ offset = 0
455
+
456
+ for frame in waveforms:
457
+ frame_length = frame.size(-1)
458
+ t = torch.linspace(0, 1, frame_length + 2, device=device, dtype=torch.float32)[
459
+ 1:-1
460
+ ]
461
+ weight = 0.5 - (t - 0.5).abs()
462
+ weighted_frame = frame * weight
463
+
464
+ cur = out[..., offset : offset + frame_length]
465
+ cur += weighted_frame[..., : cur.size(-1)]
466
+ out[..., offset : offset + frame_length] = cur
467
+
468
+ cur = sum_weight[offset : offset + frame_length]
469
+ cur += weight[..., : cur.size(-1)]
470
+ sum_weight[offset : offset + frame_length] = cur
471
+
472
+ offset += frame_length - overlap_len
473
+
474
+ assert sum_weight.min() > 0
475
+ merged_waveform = out / sum_weight
476
+ save_audio(output_path, merged_waveform, fs, add_silence=False, turn_up=True)
utils/cut_by_vad.py ADDED
@@ -0,0 +1,105 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023 Amphion.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ """ This code is modified from https://github.com/facebookresearch/libri-light/blob/main/data_preparation/cut_by_vad.py"""
7
+ import pathlib
8
+ import soundfile as sf
9
+ import numpy as np
10
+ import json
11
+ import multiprocessing
12
+ import tqdm
13
+
14
+
15
+ def save(seq, fname, index, extension):
16
+ """save audio sequences to file"""
17
+ output = np.hstack(seq)
18
+ file_name = fname.parent / (fname.stem + f"_{index:04}{extension}")
19
+ fname.parent.mkdir(exist_ok=True, parents=True)
20
+ sf.write(file_name, output, samplerate=16000)
21
+
22
+
23
+ def cut_sequence(path, vad, path_out, target_len_sec, out_extension):
24
+ """cut audio sequences based on VAD"""
25
+ data, samplerate = sf.read(path)
26
+
27
+ assert len(data.shape) == 1
28
+ assert samplerate == 16000
29
+
30
+ to_stitch = []
31
+ length_accumulated = 0.0
32
+
33
+ i = 0
34
+ # Iterate over VAD segments
35
+ for start, end in vad:
36
+ start_index = int(start * samplerate)
37
+ end_index = int(end * samplerate)
38
+ slice = data[start_index:end_index]
39
+
40
+ # Save slices that exceed the target length or if there's already accumulated audio
41
+ if (
42
+ length_accumulated + (end - start) > target_len_sec
43
+ and length_accumulated > 0
44
+ ):
45
+ save(to_stitch, path_out, i, out_extension)
46
+ to_stitch = []
47
+ i += 1
48
+ length_accumulated = 0
49
+
50
+ # Add the current slice to the list to be stitched
51
+ to_stitch.append(slice)
52
+ length_accumulated += end - start
53
+
54
+ # Save any remaining slices
55
+ if to_stitch:
56
+ save(to_stitch, path_out, i, out_extension)
57
+
58
+
59
+ def cut_book(task):
60
+ """process each book in the dataset"""
61
+ path_book, root_out, target_len_sec, extension = task
62
+
63
+ speaker = pathlib.Path(path_book.parent.name)
64
+
65
+ for i, meta_file_path in enumerate(path_book.glob("*.json")):
66
+ with open(meta_file_path, "r") as f:
67
+ meta = json.loads(f.read())
68
+ book_id = meta["book_meta"]["id"]
69
+ vad = meta["voice_activity"]
70
+
71
+ sound_file = meta_file_path.parent / (meta_file_path.stem + ".flac")
72
+
73
+ path_out = root_out / speaker / book_id / (meta_file_path.stem)
74
+ cut_sequence(sound_file, vad, path_out, target_len_sec, extension)
75
+
76
+
77
+ def cut_segments(
78
+ input_dir, output_dir, target_len_sec=30, n_process=32, out_extension=".wav"
79
+ ):
80
+ """Main function to cut segments from audio files"""
81
+
82
+ pathlib.Path(output_dir).mkdir(exist_ok=True, parents=True)
83
+ list_dir = pathlib.Path(input_dir).glob("*/*")
84
+ list_dir = [x for x in list_dir if x.is_dir()]
85
+
86
+ print(f"{len(list_dir)} directories detected")
87
+ print(f"Launching {n_process} processes")
88
+
89
+ # Create tasks for multiprocessing
90
+ tasks = [
91
+ (path_book, output_dir, target_len_sec, out_extension) for path_book in list_dir
92
+ ]
93
+
94
+ # Process tasks in parallel using multiprocessing
95
+ with multiprocessing.Pool(processes=n_process) as pool:
96
+ for _ in tqdm.tqdm(pool.imap_unordered(cut_book, tasks), total=len(tasks)):
97
+ pass
98
+
99
+
100
+ if __name__ == "__main__":
101
+ input_dir = "/path/to/input_dir"
102
+ output_dir = "/path/to/output_dir"
103
+ target_len_sec = 10
104
+ n_process = 16
105
+ cut_segments(input_dir, output_dir, target_len_sec, n_process)
utils/data_utils.py ADDED
@@ -0,0 +1,588 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023 Amphion.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ import json
7
+ import os
8
+
9
+ import numpy as np
10
+ from scipy.interpolate import interp1d
11
+ from tqdm import tqdm
12
+ from sklearn.preprocessing import StandardScaler
13
+
14
+
15
+ def intersperse(lst, item):
16
+ """
17
+ Insert an item in between any two consecutive elements of the given list, including beginning and end of list
18
+
19
+ Example:
20
+ >>> intersperse(0, [1, 74, 5, 31])
21
+ [0, 1, 0, 74, 0, 5, 0, 31, 0]
22
+ """
23
+ result = [item] * (len(lst) * 2 + 1)
24
+ result[1::2] = lst
25
+ return result
26
+
27
+
28
+ def load_content_feature_path(meta_data, processed_dir, feat_dir):
29
+ utt2feat_path = {}
30
+ for utt_info in meta_data:
31
+ utt = utt_info["Dataset"] + "_" + utt_info["Uid"]
32
+ feat_path = os.path.join(
33
+ processed_dir, utt_info["Dataset"], feat_dir, f'{utt_info["Uid"]}.npy'
34
+ )
35
+ utt2feat_path[utt] = feat_path
36
+
37
+ return utt2feat_path
38
+
39
+
40
+ def load_source_content_feature_path(meta_data, feat_dir):
41
+ utt2feat_path = {}
42
+ for utt in meta_data:
43
+ feat_path = os.path.join(feat_dir, f"{utt}.npy")
44
+ utt2feat_path[utt] = feat_path
45
+
46
+ return utt2feat_path
47
+
48
+
49
+ def get_spk_map(spk2id_path, utt2spk_path):
50
+ utt2spk = {}
51
+ with open(spk2id_path, "r") as spk2id_file:
52
+ spk2id = json.load(spk2id_file)
53
+ with open(utt2spk_path, encoding="utf-8") as f:
54
+ for line in f.readlines():
55
+ utt, spk = line.strip().split("\t")
56
+ utt2spk[utt] = spk
57
+ return spk2id, utt2spk
58
+
59
+
60
+ def get_target_f0_median(f0_dir):
61
+ total_f0 = []
62
+ for utt in os.listdir(f0_dir):
63
+ if not utt.endswith(".npy"):
64
+ continue
65
+ f0_feat_path = os.path.join(f0_dir, utt)
66
+ f0 = np.load(f0_feat_path)
67
+ total_f0 += f0.tolist()
68
+
69
+ total_f0 = np.array(total_f0)
70
+ voiced_position = np.where(total_f0 != 0)
71
+ return np.median(total_f0[voiced_position])
72
+
73
+
74
+ def get_conversion_f0_factor(source_f0, target_median, source_median=None):
75
+ """Align the median between source f0 and target f0
76
+
77
+ Note: Here we use multiplication, whose factor is target_median/source_median
78
+
79
+ Reference: Frequency and pitch interval
80
+ http://blog.ccyg.studio/article/be12c2ee-d47c-4098-9782-ca76da3035e4/
81
+ """
82
+ if source_median is None:
83
+ voiced_position = np.where(source_f0 != 0)
84
+ source_median = np.median(source_f0[voiced_position])
85
+ factor = target_median / source_median
86
+ return source_median, factor
87
+
88
+
89
+ def transpose_key(frame_pitch, trans_key):
90
+ # Transpose by user's argument
91
+ print("Transpose key = {} ...\n".format(trans_key))
92
+
93
+ transed_pitch = frame_pitch * 2 ** (trans_key / 12)
94
+ return transed_pitch
95
+
96
+
97
+ def pitch_shift_to_target(frame_pitch, target_pitch_median, source_pitch_median=None):
98
+ # Loading F0 Base (median) and shift
99
+ source_pitch_median, factor = get_conversion_f0_factor(
100
+ frame_pitch, target_pitch_median, source_pitch_median
101
+ )
102
+ print(
103
+ "Auto transposing: source f0 median = {:.1f}, target f0 median = {:.1f}, factor = {:.2f}".format(
104
+ source_pitch_median, target_pitch_median, factor
105
+ )
106
+ )
107
+ transed_pitch = frame_pitch * factor
108
+ return transed_pitch
109
+
110
+
111
+ def load_frame_pitch(
112
+ meta_data,
113
+ processed_dir,
114
+ pitch_dir,
115
+ use_log_scale=False,
116
+ return_norm=False,
117
+ interoperate=False,
118
+ utt2spk=None,
119
+ ):
120
+ utt2pitch = {}
121
+ utt2uv = {}
122
+ if utt2spk is None:
123
+ pitch_scaler = StandardScaler()
124
+ for utt_info in meta_data:
125
+ utt = utt_info["Dataset"] + "_" + utt_info["Uid"]
126
+ pitch_path = os.path.join(
127
+ processed_dir, utt_info["Dataset"], pitch_dir, f'{utt_info["Uid"]}.npy'
128
+ )
129
+ pitch = np.load(pitch_path)
130
+ assert len(pitch) > 0
131
+ uv = pitch != 0
132
+ utt2uv[utt] = uv
133
+ if use_log_scale:
134
+ nonzero_idxes = np.where(pitch != 0)[0]
135
+ pitch[nonzero_idxes] = np.log(pitch[nonzero_idxes])
136
+ utt2pitch[utt] = pitch
137
+ pitch_scaler.partial_fit(pitch.reshape(-1, 1))
138
+
139
+ mean, std = pitch_scaler.mean_[0], pitch_scaler.scale_[0]
140
+ if return_norm:
141
+ for utt_info in meta_data:
142
+ utt = utt_info["Dataset"] + "_" + utt_info["Uid"]
143
+ pitch = utt2pitch[utt]
144
+ normalized_pitch = (pitch - mean) / std
145
+ utt2pitch[utt] = normalized_pitch
146
+ pitch_statistic = {"mean": mean, "std": std}
147
+ else:
148
+ spk2utt = {}
149
+ pitch_statistic = []
150
+ for utt_info in meta_data:
151
+ utt = utt_info["Dataset"] + "_" + utt_info["Uid"]
152
+ if not utt2spk[utt] in spk2utt:
153
+ spk2utt[utt2spk[utt]] = []
154
+ spk2utt[utt2spk[utt]].append(utt)
155
+
156
+ for spk in spk2utt:
157
+ pitch_scaler = StandardScaler()
158
+ for utt in spk2utt[spk]:
159
+ dataset = utt.split("_")[0]
160
+ uid = "_".join(utt.split("_")[1:])
161
+ pitch_path = os.path.join(
162
+ processed_dir, dataset, pitch_dir, f"{uid}.npy"
163
+ )
164
+ pitch = np.load(pitch_path)
165
+ assert len(pitch) > 0
166
+ uv = pitch != 0
167
+ utt2uv[utt] = uv
168
+ if use_log_scale:
169
+ nonzero_idxes = np.where(pitch != 0)[0]
170
+ pitch[nonzero_idxes] = np.log(pitch[nonzero_idxes])
171
+ utt2pitch[utt] = pitch
172
+ pitch_scaler.partial_fit(pitch.reshape(-1, 1))
173
+
174
+ mean, std = pitch_scaler.mean_[0], pitch_scaler.scale_[0]
175
+ if return_norm:
176
+ for utt in spk2utt[spk]:
177
+ pitch = utt2pitch[utt]
178
+ normalized_pitch = (pitch - mean) / std
179
+ utt2pitch[utt] = normalized_pitch
180
+ pitch_statistic.append({"spk": spk, "mean": mean, "std": std})
181
+
182
+ return utt2pitch, utt2uv, pitch_statistic
183
+
184
+
185
+ # discard
186
+ def load_phone_pitch(
187
+ meta_data,
188
+ processed_dir,
189
+ pitch_dir,
190
+ utt2dur,
191
+ use_log_scale=False,
192
+ return_norm=False,
193
+ interoperate=True,
194
+ utt2spk=None,
195
+ ):
196
+ print("Load Phone Pitch")
197
+ utt2pitch = {}
198
+ utt2uv = {}
199
+ if utt2spk is None:
200
+ pitch_scaler = StandardScaler()
201
+ for utt_info in tqdm(meta_data):
202
+ utt = utt_info["Dataset"] + "_" + utt_info["Uid"]
203
+ pitch_path = os.path.join(
204
+ processed_dir, utt_info["Dataset"], pitch_dir, f'{utt_info["Uid"]}.npy'
205
+ )
206
+ frame_pitch = np.load(pitch_path)
207
+ assert len(frame_pitch) > 0
208
+ uv = frame_pitch != 0
209
+ utt2uv[utt] = uv
210
+ phone_pitch = phone_average_pitch(frame_pitch, utt2dur[utt], interoperate)
211
+ if use_log_scale:
212
+ nonzero_idxes = np.where(phone_pitch != 0)[0]
213
+ phone_pitch[nonzero_idxes] = np.log(phone_pitch[nonzero_idxes])
214
+ utt2pitch[utt] = phone_pitch
215
+ pitch_scaler.partial_fit(remove_outlier(phone_pitch).reshape(-1, 1))
216
+
217
+ mean, std = pitch_scaler.mean_[0], pitch_scaler.scale_[0]
218
+ max_value = np.finfo(np.float64).min
219
+ min_value = np.finfo(np.float64).max
220
+ if return_norm:
221
+ for utt_info in meta_data:
222
+ utt = utt_info["Dataset"] + "_" + utt_info["Uid"]
223
+ pitch = utt2pitch[utt]
224
+ normalized_pitch = (pitch - mean) / std
225
+ max_value = max(max_value, max(normalized_pitch))
226
+ min_value = min(min_value, min(normalized_pitch))
227
+ utt2pitch[utt] = normalized_pitch
228
+ phone_normalized_pitch_path = os.path.join(
229
+ processed_dir,
230
+ utt_info["Dataset"],
231
+ "phone_level_" + pitch_dir,
232
+ f'{utt_info["Uid"]}.npy',
233
+ )
234
+ pitch_statistic = {
235
+ "mean": mean,
236
+ "std": std,
237
+ "min_value": min_value,
238
+ "max_value": max_value,
239
+ }
240
+ else:
241
+ spk2utt = {}
242
+ pitch_statistic = []
243
+ for utt_info in tqdm(meta_data):
244
+ utt = utt_info["Dataset"] + "_" + utt_info["Uid"]
245
+ if not utt2spk[utt] in spk2utt:
246
+ spk2utt[utt2spk[utt]] = []
247
+ spk2utt[utt2spk[utt]].append(utt)
248
+
249
+ for spk in spk2utt:
250
+ pitch_scaler = StandardScaler()
251
+ for utt in spk2utt[spk]:
252
+ dataset = utt.split("_")[0]
253
+ uid = "_".join(utt.split("_")[1:])
254
+ pitch_path = os.path.join(
255
+ processed_dir, dataset, pitch_dir, f"{uid}.npy"
256
+ )
257
+ frame_pitch = np.load(pitch_path)
258
+ assert len(frame_pitch) > 0
259
+ uv = frame_pitch != 0
260
+ utt2uv[utt] = uv
261
+ phone_pitch = phone_average_pitch(
262
+ frame_pitch, utt2dur[utt], interoperate
263
+ )
264
+ if use_log_scale:
265
+ nonzero_idxes = np.where(phone_pitch != 0)[0]
266
+ phone_pitch[nonzero_idxes] = np.log(phone_pitch[nonzero_idxes])
267
+ utt2pitch[utt] = phone_pitch
268
+ pitch_scaler.partial_fit(remove_outlier(phone_pitch).reshape(-1, 1))
269
+
270
+ mean, std = pitch_scaler.mean_[0], pitch_scaler.scale_[0]
271
+ max_value = np.finfo(np.float64).min
272
+ min_value = np.finfo(np.float64).max
273
+
274
+ if return_norm:
275
+ for utt in spk2utt[spk]:
276
+ pitch = utt2pitch[utt]
277
+ normalized_pitch = (pitch - mean) / std
278
+ max_value = max(max_value, max(normalized_pitch))
279
+ min_value = min(min_value, min(normalized_pitch))
280
+ utt2pitch[utt] = normalized_pitch
281
+ pitch_statistic.append(
282
+ {
283
+ "spk": spk,
284
+ "mean": mean,
285
+ "std": std,
286
+ "min_value": min_value,
287
+ "max_value": max_value,
288
+ }
289
+ )
290
+
291
+ return utt2pitch, utt2uv, pitch_statistic
292
+
293
+
294
+ def phone_average_pitch(pitch, dur, interoperate=False):
295
+ pos = 0
296
+
297
+ if interoperate:
298
+ nonzero_ids = np.where(pitch != 0)[0]
299
+ interp_fn = interp1d(
300
+ nonzero_ids,
301
+ pitch[nonzero_ids],
302
+ fill_value=(pitch[nonzero_ids[0]], pitch[nonzero_ids[-1]]),
303
+ bounds_error=False,
304
+ )
305
+ pitch = interp_fn(np.arange(0, len(pitch)))
306
+ phone_pitch = np.zeros(len(dur))
307
+
308
+ for i, d in enumerate(dur):
309
+ d = int(d)
310
+ if d > 0 and pos < len(pitch):
311
+ phone_pitch[i] = np.mean(pitch[pos : pos + d])
312
+ else:
313
+ phone_pitch[i] = 0
314
+ pos += d
315
+ return phone_pitch
316
+
317
+
318
+ def load_energy(
319
+ meta_data,
320
+ processed_dir,
321
+ energy_dir,
322
+ use_log_scale=False,
323
+ return_norm=False,
324
+ utt2spk=None,
325
+ ):
326
+ utt2energy = {}
327
+ if utt2spk is None:
328
+ for utt_info in meta_data:
329
+ utt = utt_info["Dataset"] + "_" + utt_info["Uid"]
330
+ energy_path = os.path.join(
331
+ processed_dir, utt_info["Dataset"], energy_dir, f'{utt_info["Uid"]}.npy'
332
+ )
333
+ if not os.path.exists(energy_path):
334
+ continue
335
+ energy = np.load(energy_path)
336
+ assert len(energy) > 0
337
+
338
+ if use_log_scale:
339
+ nonzero_idxes = np.where(energy != 0)[0]
340
+ energy[nonzero_idxes] = np.log(energy[nonzero_idxes])
341
+ utt2energy[utt] = energy
342
+
343
+ if return_norm:
344
+ with open(
345
+ os.path.join(
346
+ processed_dir, utt_info["Dataset"], energy_dir, "statistics.json"
347
+ )
348
+ ) as f:
349
+ stats = json.load(f)
350
+ mean, std = (
351
+ stats[utt_info["Dataset"] + "_" + utt_info["Singer"]][
352
+ "voiced_positions"
353
+ ]["mean"],
354
+ stats["LJSpeech_LJSpeech"]["voiced_positions"]["std"],
355
+ )
356
+ for utt in utt2energy.keys():
357
+ energy = utt2energy[utt]
358
+ normalized_energy = (energy - mean) / std
359
+ utt2energy[utt] = normalized_energy
360
+
361
+ energy_statistic = {"mean": mean, "std": std}
362
+ else:
363
+ spk2utt = {}
364
+ energy_statistic = []
365
+ for utt_info in meta_data:
366
+ utt = utt_info["Dataset"] + "_" + utt_info["Uid"]
367
+ if not utt2spk[utt] in spk2utt:
368
+ spk2utt[utt2spk[utt]] = []
369
+ spk2utt[utt2spk[utt]].append(utt)
370
+
371
+ for spk in spk2utt:
372
+ energy_scaler = StandardScaler()
373
+ for utt in spk2utt[spk]:
374
+ dataset = utt.split("_")[0]
375
+ uid = "_".join(utt.split("_")[1:])
376
+ energy_path = os.path.join(
377
+ processed_dir, dataset, energy_dir, f"{uid}.npy"
378
+ )
379
+ if not os.path.exists(energy_path):
380
+ continue
381
+ frame_energy = np.load(energy_path)
382
+ assert len(frame_energy) > 0
383
+
384
+ if use_log_scale:
385
+ nonzero_idxes = np.where(frame_energy != 0)[0]
386
+ frame_energy[nonzero_idxes] = np.log(frame_energy[nonzero_idxes])
387
+ utt2energy[utt] = frame_energy
388
+ energy_scaler.partial_fit(frame_energy.reshape(-1, 1))
389
+
390
+ mean, std = energy_scaler.mean_[0], energy_scaler.scale_[0]
391
+ if return_norm:
392
+ for utt in spk2utt[spk]:
393
+ energy = utt2energy[utt]
394
+ normalized_energy = (energy - mean) / std
395
+ utt2energy[utt] = normalized_energy
396
+ energy_statistic.append({"spk": spk, "mean": mean, "std": std})
397
+
398
+ return utt2energy, energy_statistic
399
+
400
+
401
+ def load_frame_energy(
402
+ meta_data,
403
+ processed_dir,
404
+ energy_dir,
405
+ use_log_scale=False,
406
+ return_norm=False,
407
+ interoperate=False,
408
+ utt2spk=None,
409
+ ):
410
+ utt2energy = {}
411
+ if utt2spk is None:
412
+ energy_scaler = StandardScaler()
413
+ for utt_info in meta_data:
414
+ utt = utt_info["Dataset"] + "_" + utt_info["Uid"]
415
+ energy_path = os.path.join(
416
+ processed_dir, utt_info["Dataset"], energy_dir, f'{utt_info["Uid"]}.npy'
417
+ )
418
+ frame_energy = np.load(energy_path)
419
+ assert len(frame_energy) > 0
420
+
421
+ if use_log_scale:
422
+ nonzero_idxes = np.where(frame_energy != 0)[0]
423
+ frame_energy[nonzero_idxes] = np.log(frame_energy[nonzero_idxes])
424
+ utt2energy[utt] = frame_energy
425
+ energy_scaler.partial_fit(frame_energy.reshape(-1, 1))
426
+
427
+ mean, std = energy_scaler.mean_[0], energy_scaler.scale_[0]
428
+ if return_norm:
429
+ for utt_info in meta_data:
430
+ utt = utt_info["Dataset"] + "_" + utt_info["Uid"]
431
+ energy = utt2energy[utt]
432
+ normalized_energy = (energy - mean) / std
433
+ utt2energy[utt] = normalized_energy
434
+ energy_statistic = {"mean": mean, "std": std}
435
+
436
+ else:
437
+ spk2utt = {}
438
+ energy_statistic = []
439
+ for utt_info in meta_data:
440
+ utt = utt_info["Dataset"] + "_" + utt_info["Uid"]
441
+ if not utt2spk[utt] in spk2utt:
442
+ spk2utt[utt2spk[utt]] = []
443
+ spk2utt[utt2spk[utt]].append(utt)
444
+
445
+ for spk in spk2utt:
446
+ energy_scaler = StandardScaler()
447
+ for utt in spk2utt[spk]:
448
+ dataset = utt.split("_")[0]
449
+ uid = "_".join(utt.split("_")[1:])
450
+ energy_path = os.path.join(
451
+ processed_dir, dataset, energy_dir, f"{uid}.npy"
452
+ )
453
+ frame_energy = np.load(energy_path)
454
+ assert len(frame_energy) > 0
455
+
456
+ if use_log_scale:
457
+ nonzero_idxes = np.where(frame_energy != 0)[0]
458
+ frame_energy[nonzero_idxes] = np.log(frame_energy[nonzero_idxes])
459
+ utt2energy[utt] = frame_energy
460
+ energy_scaler.partial_fit(frame_energy.reshape(-1, 1))
461
+
462
+ mean, std = energy_scaler.mean_[0], energy_scaler.scale_[0]
463
+ if return_norm:
464
+ for utt in spk2utt[spk]:
465
+ energy = utt2energy[utt]
466
+ normalized_energy = (energy - mean) / std
467
+ utt2energy[utt] = normalized_energy
468
+ energy_statistic.append({"spk": spk, "mean": mean, "std": std})
469
+
470
+ return utt2energy, energy_statistic
471
+
472
+
473
+ def align_length(feature, target_len, pad_value=0.0):
474
+ feature_len = feature.shape[-1]
475
+ dim = len(feature.shape)
476
+ # align 1-D data
477
+ if dim == 2:
478
+ if target_len > feature_len:
479
+ feature = np.pad(
480
+ feature,
481
+ ((0, 0), (0, target_len - feature_len)),
482
+ constant_values=pad_value,
483
+ )
484
+ else:
485
+ feature = feature[:, :target_len]
486
+ # align 2-D data
487
+ elif dim == 1:
488
+ if target_len > feature_len:
489
+ feature = np.pad(
490
+ feature, (0, target_len - feature_len), constant_values=pad_value
491
+ )
492
+ else:
493
+ feature = feature[:target_len]
494
+ else:
495
+ raise NotImplementedError
496
+ return feature
497
+
498
+
499
+ def align_whisper_feauture_length(
500
+ feature, target_len, fast_mapping=True, source_hop=320, target_hop=256
501
+ ):
502
+ factor = np.gcd(source_hop, target_hop)
503
+ source_hop //= factor
504
+ target_hop //= factor
505
+ # print(
506
+ # "Mapping source's {} frames => target's {} frames".format(
507
+ # target_hop, source_hop
508
+ # )
509
+ # )
510
+
511
+ max_source_len = 1500
512
+ target_len = min(target_len, max_source_len * source_hop // target_hop)
513
+
514
+ width = feature.shape[-1]
515
+
516
+ if fast_mapping:
517
+ source_len = target_len * target_hop // source_hop + 1
518
+ feature = feature[:source_len]
519
+
520
+ else:
521
+ source_len = max_source_len
522
+
523
+ # const ~= target_len * target_hop
524
+ const = source_len * source_hop // target_hop * target_hop
525
+
526
+ # (source_len * source_hop, dim)
527
+ up_sampling_feats = np.repeat(feature, source_hop, axis=0)
528
+ # (const, dim) -> (const/target_hop, target_hop, dim) -> (const/target_hop, dim)
529
+ down_sampling_feats = np.average(
530
+ up_sampling_feats[:const].reshape(-1, target_hop, width), axis=1
531
+ )
532
+ assert len(down_sampling_feats) >= target_len
533
+
534
+ # (target_len, dim)
535
+ feat = down_sampling_feats[:target_len]
536
+
537
+ return feat
538
+
539
+
540
+ def align_content_feature_length(feature, target_len, source_hop=320, target_hop=256):
541
+ factor = np.gcd(source_hop, target_hop)
542
+ source_hop //= factor
543
+ target_hop //= factor
544
+ # print(
545
+ # "Mapping source's {} frames => target's {} frames".format(
546
+ # target_hop, source_hop
547
+ # )
548
+ # )
549
+
550
+ # (source_len, 256)
551
+ source_len, width = feature.shape
552
+
553
+ # const ~= target_len * target_hop
554
+ const = source_len * source_hop // target_hop * target_hop
555
+
556
+ # (source_len * source_hop, dim)
557
+ up_sampling_feats = np.repeat(feature, source_hop, axis=0)
558
+ # (const, dim) -> (const/target_hop, target_hop, dim) -> (const/target_hop, dim)
559
+ down_sampling_feats = np.average(
560
+ up_sampling_feats[:const].reshape(-1, target_hop, width), axis=1
561
+ )
562
+
563
+ err = abs(target_len - len(down_sampling_feats))
564
+ if err > 4: ## why 4 not 3?
565
+ print("target_len:", target_len)
566
+ print("raw feature:", feature.shape)
567
+ print("up_sampling:", up_sampling_feats.shape)
568
+ print("down_sampling_feats:", down_sampling_feats.shape)
569
+ exit()
570
+ if len(down_sampling_feats) < target_len:
571
+ # (1, dim) -> (err, dim)
572
+ end = down_sampling_feats[-1][None, :].repeat(err, axis=0)
573
+ down_sampling_feats = np.concatenate([down_sampling_feats, end], axis=0)
574
+
575
+ # (target_len, dim)
576
+ feat = down_sampling_feats[:target_len]
577
+
578
+ return feat
579
+
580
+
581
+ def remove_outlier(values):
582
+ values = np.array(values)
583
+ p25 = np.percentile(values, 25)
584
+ p75 = np.percentile(values, 75)
585
+ lower = p25 - 1.5 * (p75 - p25)
586
+ upper = p75 + 1.5 * (p75 - p25)
587
+ normal_indices = np.logical_and(values > lower, values < upper)
588
+ return values[normal_indices]
utils/distribution.py ADDED
@@ -0,0 +1,270 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023 Amphion.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ import numpy as np
7
+ import torch
8
+ import torch.nn.functional as F
9
+
10
+ from torch.distributions import Normal
11
+
12
+
13
+ def log_sum_exp(x):
14
+ """numerically stable log_sum_exp implementation that prevents overflow"""
15
+ # TF ordering
16
+ axis = len(x.size()) - 1
17
+ m, _ = torch.max(x, dim=axis)
18
+ m2, _ = torch.max(x, dim=axis, keepdim=True)
19
+ return m + torch.log(torch.sum(torch.exp(x - m2), dim=axis))
20
+
21
+
22
+ def discretized_mix_logistic_loss(
23
+ y_hat, y, num_classes=256, log_scale_min=-7.0, reduce=True
24
+ ):
25
+ """Discretized mixture of logistic distributions loss
26
+
27
+ Note that it is assumed that input is scaled to [-1, 1].
28
+
29
+ Args:
30
+ y_hat (Tensor): Predicted output (B x C x T)
31
+ y (Tensor): Target (B x T x 1).
32
+ num_classes (int): Number of classes
33
+ log_scale_min (float): Log scale minimum value
34
+ reduce (bool): If True, the losses are averaged or summed for each
35
+ minibatch.
36
+
37
+ Returns
38
+ Tensor: loss
39
+ """
40
+ assert y_hat.dim() == 3
41
+ assert y_hat.size(1) % 3 == 0
42
+ nr_mix = y_hat.size(1) // 3
43
+
44
+ # (B x T x C)
45
+ y_hat = y_hat.transpose(1, 2)
46
+
47
+ # unpack parameters. (B, T, num_mixtures) x 3
48
+ logit_probs = y_hat[:, :, :nr_mix]
49
+ means = y_hat[:, :, nr_mix : 2 * nr_mix]
50
+ log_scales = torch.clamp(y_hat[:, :, 2 * nr_mix : 3 * nr_mix], min=log_scale_min)
51
+
52
+ # B x T x 1 -> B x T x num_mixtures
53
+ y = y.expand_as(means)
54
+
55
+ centered_y = y - means
56
+ inv_stdv = torch.exp(-log_scales)
57
+ plus_in = inv_stdv * (centered_y + 1.0 / (num_classes - 1))
58
+ cdf_plus = torch.sigmoid(plus_in)
59
+ min_in = inv_stdv * (centered_y - 1.0 / (num_classes - 1))
60
+ cdf_min = torch.sigmoid(min_in)
61
+
62
+ # log probability for edge case of 0 (before scaling)
63
+ # equivalent: torch.log(torch.sigmoid(plus_in))
64
+ log_cdf_plus = plus_in - F.softplus(plus_in)
65
+
66
+ # log probability for edge case of 255 (before scaling)
67
+ # equivalent: (1 - torch.sigmoid(min_in)).log()
68
+ log_one_minus_cdf_min = -F.softplus(min_in)
69
+
70
+ # probability for all other cases
71
+ cdf_delta = cdf_plus - cdf_min
72
+
73
+ mid_in = inv_stdv * centered_y
74
+ # log probability in the center of the bin, to be used in extreme cases
75
+ # (not actually used in our code)
76
+ log_pdf_mid = mid_in - log_scales - 2.0 * F.softplus(mid_in)
77
+
78
+ # tf equivalent
79
+ """
80
+ log_probs = tf.where(x < -0.999, log_cdf_plus,
81
+ tf.where(x > 0.999, log_one_minus_cdf_min,
82
+ tf.where(cdf_delta > 1e-5,
83
+ tf.log(tf.maximum(cdf_delta, 1e-12)),
84
+ log_pdf_mid - np.log(127.5))))
85
+ """
86
+ # TODO: cdf_delta <= 1e-5 actually can happen. How can we choose the value
87
+ # for num_classes=65536 case? 1e-7? not sure..
88
+ inner_inner_cond = (cdf_delta > 1e-5).float()
89
+
90
+ inner_inner_out = inner_inner_cond * torch.log(
91
+ torch.clamp(cdf_delta, min=1e-12)
92
+ ) + (1.0 - inner_inner_cond) * (log_pdf_mid - np.log((num_classes - 1) / 2))
93
+ inner_cond = (y > 0.999).float()
94
+ inner_out = (
95
+ inner_cond * log_one_minus_cdf_min + (1.0 - inner_cond) * inner_inner_out
96
+ )
97
+ cond = (y < -0.999).float()
98
+ log_probs = cond * log_cdf_plus + (1.0 - cond) * inner_out
99
+
100
+ log_probs = log_probs + F.log_softmax(logit_probs, -1)
101
+
102
+ if reduce:
103
+ return -torch.sum(log_sum_exp(log_probs))
104
+ else:
105
+ return -log_sum_exp(log_probs).unsqueeze(-1)
106
+
107
+
108
+ def to_one_hot(tensor, n, fill_with=1.0):
109
+ # we perform one hot encore with respect to the last axis
110
+ one_hot = torch.FloatTensor(tensor.size() + (n,)).zero_()
111
+ if tensor.is_cuda:
112
+ one_hot = one_hot.cuda()
113
+ one_hot.scatter_(len(tensor.size()), tensor.unsqueeze(-1), fill_with)
114
+ return one_hot
115
+
116
+
117
+ def sample_from_discretized_mix_logistic(y, log_scale_min=-7.0, clamp_log_scale=False):
118
+ """
119
+ Sample from discretized mixture of logistic distributions
120
+
121
+ Args:
122
+ y (Tensor): B x C x T
123
+ log_scale_min (float): Log scale minimum value
124
+
125
+ Returns:
126
+ Tensor: sample in range of [-1, 1].
127
+ """
128
+ assert y.size(1) % 3 == 0
129
+ nr_mix = y.size(1) // 3
130
+
131
+ # B x T x C
132
+ y = y.transpose(1, 2)
133
+ logit_probs = y[:, :, :nr_mix]
134
+
135
+ # sample mixture indicator from softmax
136
+ temp = logit_probs.data.new(logit_probs.size()).uniform_(1e-5, 1.0 - 1e-5)
137
+ temp = logit_probs.data - torch.log(-torch.log(temp))
138
+ _, argmax = temp.max(dim=-1)
139
+
140
+ # (B, T) -> (B, T, nr_mix)
141
+ one_hot = to_one_hot(argmax, nr_mix)
142
+ # select logistic parameters
143
+ means = torch.sum(y[:, :, nr_mix : 2 * nr_mix] * one_hot, dim=-1)
144
+ log_scales = torch.sum(y[:, :, 2 * nr_mix : 3 * nr_mix] * one_hot, dim=-1)
145
+ if clamp_log_scale:
146
+ log_scales = torch.clamp(log_scales, min=log_scale_min)
147
+ # sample from logistic & clip to interval
148
+ # we don't actually round to the nearest 8bit value when sampling
149
+ u = means.data.new(means.size()).uniform_(1e-5, 1.0 - 1e-5)
150
+ x = means + torch.exp(log_scales) * (torch.log(u) - torch.log(1.0 - u))
151
+
152
+ x = torch.clamp(torch.clamp(x, min=-1.0), max=1.0)
153
+
154
+ return x
155
+
156
+
157
+ # we can easily define discretized version of the gaussian loss, however,
158
+ # use continuous version as same as the https://clarinet-demo.github.io/
159
+ def mix_gaussian_loss(y_hat, y, log_scale_min=-7.0, reduce=True):
160
+ """Mixture of continuous gaussian distributions loss
161
+
162
+ Note that it is assumed that input is scaled to [-1, 1].
163
+
164
+ Args:
165
+ y_hat (Tensor): Predicted output (B x C x T)
166
+ y (Tensor): Target (B x T x 1).
167
+ log_scale_min (float): Log scale minimum value
168
+ reduce (bool): If True, the losses are averaged or summed for each
169
+ minibatch.
170
+ Returns
171
+ Tensor: loss
172
+ """
173
+ assert y_hat.dim() == 3
174
+ C = y_hat.size(1)
175
+ if C == 2:
176
+ nr_mix = 1
177
+ else:
178
+ assert y_hat.size(1) % 3 == 0
179
+ nr_mix = y_hat.size(1) // 3
180
+
181
+ # (B x T x C)
182
+ y_hat = y_hat.transpose(1, 2)
183
+
184
+ # unpack parameters.
185
+ if C == 2:
186
+ # special case for C == 2, just for compatibility
187
+ logit_probs = None
188
+ means = y_hat[:, :, 0:1]
189
+ log_scales = torch.clamp(y_hat[:, :, 1:2], min=log_scale_min)
190
+ else:
191
+ # (B, T, num_mixtures) x 3
192
+ logit_probs = y_hat[:, :, :nr_mix]
193
+ means = y_hat[:, :, nr_mix : 2 * nr_mix]
194
+ log_scales = torch.clamp(
195
+ y_hat[:, :, 2 * nr_mix : 3 * nr_mix], min=log_scale_min
196
+ )
197
+
198
+ # B x T x 1 -> B x T x num_mixtures
199
+ y = y.expand_as(means)
200
+
201
+ centered_y = y - means
202
+ dist = Normal(loc=0.0, scale=torch.exp(log_scales))
203
+ # do we need to add a trick to avoid log(0)?
204
+ log_probs = dist.log_prob(centered_y)
205
+
206
+ if nr_mix > 1:
207
+ log_probs = log_probs + F.log_softmax(logit_probs, -1)
208
+
209
+ if reduce:
210
+ if nr_mix == 1:
211
+ return -torch.sum(log_probs)
212
+ else:
213
+ return -torch.sum(log_sum_exp(log_probs))
214
+ else:
215
+ if nr_mix == 1:
216
+ return -log_probs
217
+ else:
218
+ return -log_sum_exp(log_probs).unsqueeze(-1)
219
+
220
+
221
+ def sample_from_mix_gaussian(y, log_scale_min=-7.0):
222
+ """
223
+ Sample from (discretized) mixture of gaussian distributions
224
+ Args:
225
+ y (Tensor): B x C x T
226
+ log_scale_min (float): Log scale minimum value
227
+ Returns:
228
+ Tensor: sample in range of [-1, 1].
229
+ """
230
+ C = y.size(1)
231
+ if C == 2:
232
+ nr_mix = 1
233
+ else:
234
+ assert y.size(1) % 3 == 0
235
+ nr_mix = y.size(1) // 3
236
+
237
+ # B x T x C
238
+ y = y.transpose(1, 2)
239
+
240
+ if C == 2:
241
+ logit_probs = None
242
+ else:
243
+ logit_probs = y[:, :, :nr_mix]
244
+
245
+ if nr_mix > 1:
246
+ # sample mixture indicator from softmax
247
+ temp = logit_probs.data.new(logit_probs.size()).uniform_(1e-5, 1.0 - 1e-5)
248
+ temp = logit_probs.data - torch.log(-torch.log(temp))
249
+ _, argmax = temp.max(dim=-1)
250
+
251
+ # (B, T) -> (B, T, nr_mix)
252
+ one_hot = to_one_hot(argmax, nr_mix)
253
+
254
+ # Select means and log scales
255
+ means = torch.sum(y[:, :, nr_mix : 2 * nr_mix] * one_hot, dim=-1)
256
+ log_scales = torch.sum(y[:, :, 2 * nr_mix : 3 * nr_mix] * one_hot, dim=-1)
257
+ else:
258
+ if C == 2:
259
+ means, log_scales = y[:, :, 0], y[:, :, 1]
260
+ elif C == 3:
261
+ means, log_scales = y[:, :, 1], y[:, :, 2]
262
+ else:
263
+ assert False, "shouldn't happen"
264
+
265
+ scales = torch.exp(log_scales)
266
+ dist = Normal(loc=means, scale=scales)
267
+ x = dist.sample()
268
+
269
+ x = torch.clamp(x, min=-1.0, max=1.0)
270
+ return x
utils/dsp.py ADDED
@@ -0,0 +1,97 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023 Amphion.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ import numpy as np
7
+ import torch
8
+
9
+ # ZERO = 1e-12
10
+
11
+
12
+ def gaussian_normalize_mel_channel(mel, mu, sigma):
13
+ """
14
+ Shift to Standorm Normal Distribution
15
+
16
+ Args:
17
+ mel: (n_mels, frame_len)
18
+ mu: (n_mels,), mean value
19
+ sigma: (n_mels,), sd value
20
+ Return:
21
+ Tensor like mel
22
+ """
23
+ mu = np.expand_dims(mu, -1)
24
+ sigma = np.expand_dims(sigma, -1)
25
+ return (mel - mu) / sigma
26
+
27
+
28
+ def de_gaussian_normalize_mel_channel(mel, mu, sigma):
29
+ """
30
+
31
+ Args:
32
+ mel: (n_mels, frame_len)
33
+ mu: (n_mels,), mean value
34
+ sigma: (n_mels,), sd value
35
+ Return:
36
+ Tensor like mel
37
+ """
38
+ mu = np.expand_dims(mu, -1)
39
+ sigma = np.expand_dims(sigma, -1)
40
+ return sigma * mel + mu
41
+
42
+
43
+ def decompress(audio_compressed, bits):
44
+ mu = 2**bits - 1
45
+ audio = np.sign(audio_compressed) / mu * ((1 + mu) ** np.abs(audio_compressed) - 1)
46
+ return audio
47
+
48
+
49
+ def compress(audio, bits):
50
+ mu = 2**bits - 1
51
+ audio_compressed = np.sign(audio) * np.log(1 + mu * np.abs(audio)) / np.log(mu + 1)
52
+ return audio_compressed
53
+
54
+
55
+ def label_to_audio(quant, bits):
56
+ classes = 2**bits
57
+ audio = 2 * quant / (classes - 1.0) - 1.0
58
+ return audio
59
+
60
+
61
+ def audio_to_label(audio, bits):
62
+ """Normalized audio data tensor to digit array
63
+
64
+ Args:
65
+ audio (tensor): audio data
66
+ bits (int): data bits
67
+
68
+ Returns:
69
+ array<int>: digit array of audio data
70
+ """
71
+ classes = 2**bits
72
+ # initialize an increasing array with values from -1 to 1
73
+ bins = np.linspace(-1, 1, classes)
74
+ # change value in audio tensor to digits
75
+ quant = np.digitize(audio, bins) - 1
76
+ return quant
77
+
78
+
79
+ def label_to_onehot(x, bits):
80
+ """Converts a class vector (integers) to binary class matrix.
81
+ Args:
82
+ x: class vector to be converted into a matrix
83
+ (integers from 0 to num_classes).
84
+ num_classes: total number of classes.
85
+ Returns:
86
+ A binary matrix representation of the input. The classes axis
87
+ is placed last.
88
+ """
89
+ classes = 2**bits
90
+
91
+ result = torch.zeros((x.shape[0], classes), dtype=torch.float32)
92
+ for i in range(x.shape[0]):
93
+ result[i, x[i]] = 1
94
+
95
+ output_shape = x.shape + (classes,)
96
+ output = torch.reshape(result, output_shape)
97
+ return output
utils/duration.py ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023 Amphion.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ import numpy as np
7
+ import os
8
+ import tgt
9
+
10
+
11
+ def get_alignment(tier, cfg):
12
+ sample_rate = cfg["sample_rate"]
13
+ hop_size = cfg["hop_size"]
14
+
15
+ sil_phones = ["sil", "sp", "spn"]
16
+
17
+ phones = []
18
+ durations = []
19
+ start_time = 0
20
+ end_time = 0
21
+ end_idx = 0
22
+
23
+ for t in tier._objects:
24
+ s, e, p = t.start_time, t.end_time, t.text
25
+
26
+ # Trim leading silences
27
+ if phones == []:
28
+ if p in sil_phones:
29
+ continue
30
+ else:
31
+ start_time = s
32
+
33
+ if p not in sil_phones:
34
+ # For ordinary phones
35
+ phones.append(p)
36
+ end_time = e
37
+ end_idx = len(phones)
38
+ else:
39
+ # For silent phones
40
+ phones.append(p)
41
+
42
+ durations.append(
43
+ int(
44
+ np.round(e * sample_rate / hop_size)
45
+ - np.round(s * sample_rate / hop_size)
46
+ )
47
+ )
48
+
49
+ # Trim tailing silences
50
+ phones = phones[:end_idx]
51
+ durations = durations[:end_idx]
52
+
53
+ return phones, durations, start_time, end_time
54
+
55
+
56
+ def get_duration(utt, wav, cfg):
57
+ speaker = utt["Singer"]
58
+ basename = utt["Uid"]
59
+ dataset = utt["Dataset"]
60
+ sample_rate = cfg["sample_rate"]
61
+
62
+ # print(cfg.processed_dir, dataset, speaker, basename)
63
+ wav_path = os.path.join(
64
+ cfg.processed_dir, dataset, "raw_data", speaker, "{}.wav".format(basename)
65
+ )
66
+ text_path = os.path.join(
67
+ cfg.processed_dir, dataset, "raw_data", speaker, "{}.lab".format(basename)
68
+ )
69
+ tg_path = os.path.join(
70
+ cfg.processed_dir, dataset, "TextGrid", speaker, "{}.TextGrid".format(basename)
71
+ )
72
+
73
+ # Read raw text
74
+ with open(text_path, "r") as f:
75
+ raw_text = f.readline().strip("\n")
76
+
77
+ # Get alignments
78
+ textgrid = tgt.io.read_textgrid(tg_path)
79
+ phone, duration, start, end = get_alignment(
80
+ textgrid.get_tier_by_name("phones"), cfg
81
+ )
82
+ text = "{" + " ".join(phone) + "}"
83
+ if start >= end:
84
+ return None
85
+
86
+ return duration, text, int(sample_rate * start), int(sample_rate * end)
utils/f0.py ADDED
@@ -0,0 +1,275 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023 Amphion.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ import librosa
7
+ import numpy as np
8
+ import torch
9
+ import parselmouth
10
+ import torchcrepe
11
+ import pyworld as pw
12
+
13
+
14
+ def f0_to_coarse(f0, pitch_bin, f0_min, f0_max):
15
+ """
16
+ Convert f0 (Hz) to pitch (mel scale), and then quantize the mel-scale pitch to the
17
+ range from [1, 2, 3, ..., pitch_bin-1]
18
+
19
+ Reference: https://en.wikipedia.org/wiki/Mel_scale
20
+
21
+ Args:
22
+ f0 (array or Tensor): Hz
23
+ pitch_bin (int): the vocabulary size
24
+ f0_min (int): the minimum f0 (Hz)
25
+ f0_max (int): the maximum f0 (Hz)
26
+
27
+ Returns:
28
+ quantized f0 (array or Tensor)
29
+ """
30
+ f0_mel_min = 1127 * np.log(1 + f0_min / 700)
31
+ f0_mel_max = 1127 * np.log(1 + f0_max / 700)
32
+
33
+ is_torch = isinstance(f0, torch.Tensor)
34
+ f0_mel = 1127 * (1 + f0 / 700).log() if is_torch else 1127 * np.log(1 + f0 / 700)
35
+ f0_mel[f0_mel > 0] = (f0_mel[f0_mel > 0] - f0_mel_min) * (pitch_bin - 2) / (
36
+ f0_mel_max - f0_mel_min
37
+ ) + 1
38
+
39
+ f0_mel[f0_mel <= 1] = 1
40
+ f0_mel[f0_mel > pitch_bin - 1] = pitch_bin - 1
41
+ f0_coarse = (f0_mel + 0.5).long() if is_torch else np.rint(f0_mel).astype(np.int32)
42
+ assert f0_coarse.max() <= 255 and f0_coarse.min() >= 1, (
43
+ f0_coarse.max(),
44
+ f0_coarse.min(),
45
+ )
46
+ return f0_coarse
47
+
48
+
49
+ def interpolate(f0):
50
+ """Interpolate the unvoiced part. Thus the f0 can be passed to a subtractive synthesizer.
51
+ Args:
52
+ f0: A numpy array of shape (seq_len,)
53
+ Returns:
54
+ f0: Interpolated f0 of shape (seq_len,)
55
+ uv: Unvoiced part of shape (seq_len,)
56
+ """
57
+ uv = f0 == 0
58
+ if len(f0[~uv]) > 0:
59
+ # interpolate the unvoiced f0
60
+ f0[uv] = np.interp(np.where(uv)[0], np.where(~uv)[0], f0[~uv])
61
+ uv = uv.astype("float")
62
+ uv = np.min(np.array([uv[:-2], uv[1:-1], uv[2:]]), axis=0)
63
+ uv = np.pad(uv, (1, 1))
64
+ return f0, uv
65
+
66
+
67
+ def get_log_f0(f0):
68
+ f0[np.where(f0 == 0)] = 1
69
+ log_f0 = np.log(f0)
70
+ return log_f0
71
+
72
+
73
+ def get_f0_features_using_pyin(audio, cfg):
74
+ """Using pyin to extract the f0 feature.
75
+ Args:
76
+ audio
77
+ fs
78
+ win_length
79
+ hop_length
80
+ f0_min
81
+ f0_max
82
+ Returns:
83
+ f0: numpy array of shape (frame_len,)
84
+ """
85
+ f0, voiced_flag, voiced_probs = librosa.pyin(
86
+ y=audio,
87
+ fmin=cfg.f0_min,
88
+ fmax=cfg.f0_max,
89
+ sr=cfg.sample_rate,
90
+ win_length=cfg.win_size,
91
+ hop_length=cfg.hop_size,
92
+ )
93
+ # Set nan to 0
94
+ f0[voiced_flag == False] = 0
95
+ return f0
96
+
97
+
98
+ def get_f0_features_using_parselmouth(audio, cfg, speed=1):
99
+ """Using parselmouth to extract the f0 feature.
100
+ Args:
101
+ audio
102
+ mel_len
103
+ hop_length
104
+ fs
105
+ f0_min
106
+ f0_max
107
+ speed(default=1)
108
+ Returns:
109
+ f0: numpy array of shape (frame_len,)
110
+ pitch_coarse: numpy array of shape (frame_len,)
111
+ """
112
+ hop_size = int(np.round(cfg.hop_size * speed))
113
+
114
+ # Calculate the time step for pitch extraction
115
+ time_step = hop_size / cfg.sample_rate * 1000
116
+
117
+ f0 = (
118
+ parselmouth.Sound(audio, cfg.sample_rate)
119
+ .to_pitch_ac(
120
+ time_step=time_step / 1000,
121
+ voicing_threshold=0.6,
122
+ pitch_floor=cfg.f0_min,
123
+ pitch_ceiling=cfg.f0_max,
124
+ )
125
+ .selected_array["frequency"]
126
+ )
127
+ return f0
128
+
129
+
130
+ def get_f0_features_using_dio(audio, cfg):
131
+ """Using dio to extract the f0 feature.
132
+ Args:
133
+ audio
134
+ mel_len
135
+ fs
136
+ hop_length
137
+ f0_min
138
+ f0_max
139
+ Returns:
140
+ f0: numpy array of shape (frame_len,)
141
+ """
142
+ # Get the raw f0
143
+ _f0, t = pw.dio(
144
+ audio.astype("double"),
145
+ cfg.sample_rate,
146
+ f0_floor=cfg.f0_min,
147
+ f0_ceil=cfg.f0_max,
148
+ channels_in_octave=2,
149
+ frame_period=(1000 * cfg.hop_size / cfg.sample_rate),
150
+ )
151
+ # Get the f0
152
+ f0 = pw.stonemask(audio.astype("double"), _f0, t, cfg.sample_rate)
153
+ return f0
154
+
155
+
156
+ def get_f0_features_using_harvest(audio, mel_len, fs, hop_length, f0_min, f0_max):
157
+ """Using harvest to extract the f0 feature.
158
+ Args:
159
+ audio
160
+ mel_len
161
+ fs
162
+ hop_length
163
+ f0_min
164
+ f0_max
165
+ Returns:
166
+ f0: numpy array of shape (frame_len,)
167
+ """
168
+ f0, _ = pw.harvest(
169
+ audio.astype("double"),
170
+ fs,
171
+ f0_floor=f0_min,
172
+ f0_ceil=f0_max,
173
+ frame_period=(1000 * hop_length / fs),
174
+ )
175
+ f0 = f0.astype("float")[:mel_len]
176
+ return f0
177
+
178
+
179
+ def get_f0_features_using_crepe(
180
+ audio, mel_len, fs, hop_length, hop_length_new, f0_min, f0_max, threshold=0.3
181
+ ):
182
+ """Using torchcrepe to extract the f0 feature.
183
+ Args:
184
+ audio
185
+ mel_len
186
+ fs
187
+ hop_length
188
+ hop_length_new
189
+ f0_min
190
+ f0_max
191
+ threshold(default=0.3)
192
+ Returns:
193
+ f0: numpy array of shape (frame_len,)
194
+ """
195
+ # Currently, crepe only supports 16khz audio
196
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
197
+ audio_16k = librosa.resample(audio, orig_sr=fs, target_sr=16000)
198
+ audio_16k_torch = torch.FloatTensor(audio_16k).unsqueeze(0).to(device)
199
+
200
+ # Get the raw pitch
201
+ f0, pd = torchcrepe.predict(
202
+ audio_16k_torch,
203
+ 16000,
204
+ hop_length_new,
205
+ f0_min,
206
+ f0_max,
207
+ pad=True,
208
+ model="full",
209
+ batch_size=1024,
210
+ device=device,
211
+ return_periodicity=True,
212
+ )
213
+
214
+ # Filter, de-silence, set up threshold for unvoiced part
215
+ pd = torchcrepe.filter.median(pd, 3)
216
+ pd = torchcrepe.threshold.Silence(-60.0)(pd, audio_16k_torch, 16000, hop_length_new)
217
+ f0 = torchcrepe.threshold.At(threshold)(f0, pd)
218
+ f0 = torchcrepe.filter.mean(f0, 3)
219
+
220
+ # Convert unvoiced part to 0hz
221
+ f0 = torch.where(torch.isnan(f0), torch.full_like(f0, 0), f0)
222
+
223
+ # Interpolate f0
224
+ nzindex = torch.nonzero(f0[0]).squeeze()
225
+ f0 = torch.index_select(f0[0], dim=0, index=nzindex).cpu().numpy()
226
+ time_org = 0.005 * nzindex.cpu().numpy()
227
+ time_frame = np.arange(mel_len) * hop_length / fs
228
+ f0 = np.interp(time_frame, time_org, f0, left=f0[0], right=f0[-1])
229
+ return f0
230
+
231
+
232
+ def get_f0(audio, cfg, use_interpolate=False, return_uv=False):
233
+ if cfg.pitch_extractor == "dio":
234
+ f0 = get_f0_features_using_dio(audio, cfg)
235
+ elif cfg.pitch_extractor == "pyin":
236
+ f0 = get_f0_features_using_pyin(audio, cfg)
237
+ elif cfg.pitch_extractor == "parselmouth":
238
+ f0 = get_f0_features_using_parselmouth(audio, cfg)
239
+
240
+ if use_interpolate:
241
+ f0, uv = interpolate(f0)
242
+ else:
243
+ uv = f0 == 0
244
+
245
+ if return_uv:
246
+ return f0, uv
247
+
248
+ return f0
249
+
250
+
251
+ def get_cents(f0_hz):
252
+ """
253
+ F_{cent} = 1200 * log2 (F/440)
254
+
255
+ Reference:
256
+ APSIPA'17, Perceptual Evaluation of Singing Quality
257
+ """
258
+ voiced_f0 = f0_hz[f0_hz != 0]
259
+ return 1200 * np.log2(voiced_f0 / 440)
260
+
261
+
262
+ def get_pitch_derivatives(f0_hz):
263
+ """
264
+ f0_hz: (,T)
265
+ """
266
+ f0_cent = get_cents(f0_hz)
267
+ return f0_cent[1:] - f0_cent[:-1]
268
+
269
+
270
+ def get_pitch_sub_median(f0_hz):
271
+ """
272
+ f0_hz: (,T)
273
+ """
274
+ f0_cent = get_cents(f0_hz)
275
+ return f0_cent - np.median(f0_cent)
utils/hparam.py ADDED
@@ -0,0 +1,659 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023 Amphion.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ # This code is modified from https://github.com/tensorflow/tensorflow/blob/master/tensorflow/contrib/training/python/training/hparam.py pylint: disable=line-too-long
7
+ """Hyperparameter values."""
8
+ from __future__ import absolute_import
9
+ from __future__ import division
10
+ from __future__ import print_function
11
+
12
+ import json
13
+ import numbers
14
+ import re
15
+ import six
16
+
17
+ # Define the regular expression for parsing a single clause of the input
18
+ # (delimited by commas). A legal clause looks like:
19
+ # <variable name>[<index>]? = <rhs>
20
+ # where <rhs> is either a single token or [] enclosed list of tokens.
21
+ # For example: "var[1] = a" or "x = [1,2,3]"
22
+ PARAM_RE = re.compile(
23
+ r"""
24
+ (?P<name>[a-zA-Z][\w\.]*) # variable name: "var" or "x"
25
+ (\[\s*(?P<index>\d+)\s*\])? # (optional) index: "1" or None
26
+ \s*=\s*
27
+ ((?P<val>[^,\[]*) # single value: "a" or None
28
+ |
29
+ \[(?P<vals>[^\]]*)\]) # list of values: None or "1,2,3"
30
+ ($|,\s*)""",
31
+ re.VERBOSE,
32
+ )
33
+
34
+
35
+ def _parse_fail(name, var_type, value, values):
36
+ """Helper function for raising a value error for bad assignment."""
37
+ raise ValueError(
38
+ "Could not parse hparam '%s' of type '%s' with value '%s' in %s"
39
+ % (name, var_type.__name__, value, values)
40
+ )
41
+
42
+
43
+ def _reuse_fail(name, values):
44
+ """Helper function for raising a value error for reuse of name."""
45
+ raise ValueError("Multiple assignments to variable '%s' in %s" % (name, values))
46
+
47
+
48
+ def _process_scalar_value(name, parse_fn, var_type, m_dict, values, results_dictionary):
49
+ """Update results_dictionary with a scalar value.
50
+
51
+ Used to update the results_dictionary to be returned by parse_values when
52
+ encountering a clause with a scalar RHS (e.g. "s=5" or "arr[0]=5".)
53
+
54
+ Mutates results_dictionary.
55
+
56
+ Args:
57
+ name: Name of variable in assignment ("s" or "arr").
58
+ parse_fn: Function for parsing the actual value.
59
+ var_type: Type of named variable.
60
+ m_dict: Dictionary constructed from regex parsing.
61
+ m_dict['val']: RHS value (scalar)
62
+ m_dict['index']: List index value (or None)
63
+ values: Full expression being parsed
64
+ results_dictionary: The dictionary being updated for return by the parsing
65
+ function.
66
+
67
+ Raises:
68
+ ValueError: If the name has already been used.
69
+ """
70
+ try:
71
+ parsed_value = parse_fn(m_dict["val"])
72
+ except ValueError:
73
+ _parse_fail(name, var_type, m_dict["val"], values)
74
+
75
+ # If no index is provided
76
+ if not m_dict["index"]:
77
+ if name in results_dictionary:
78
+ _reuse_fail(name, values)
79
+ results_dictionary[name] = parsed_value
80
+ else:
81
+ if name in results_dictionary:
82
+ # The name has already been used as a scalar, then it
83
+ # will be in this dictionary and map to a non-dictionary.
84
+ if not isinstance(results_dictionary.get(name), dict):
85
+ _reuse_fail(name, values)
86
+ else:
87
+ results_dictionary[name] = {}
88
+
89
+ index = int(m_dict["index"])
90
+ # Make sure the index position hasn't already been assigned a value.
91
+ if index in results_dictionary[name]:
92
+ _reuse_fail("{}[{}]".format(name, index), values)
93
+ results_dictionary[name][index] = parsed_value
94
+
95
+
96
+ def _process_list_value(name, parse_fn, var_type, m_dict, values, results_dictionary):
97
+ """Update results_dictionary from a list of values.
98
+
99
+ Used to update results_dictionary to be returned by parse_values when
100
+ encountering a clause with a list RHS (e.g. "arr=[1,2,3]".)
101
+
102
+ Mutates results_dictionary.
103
+
104
+ Args:
105
+ name: Name of variable in assignment ("arr").
106
+ parse_fn: Function for parsing individual values.
107
+ var_type: Type of named variable.
108
+ m_dict: Dictionary constructed from regex parsing.
109
+ m_dict['val']: RHS value (scalar)
110
+ values: Full expression being parsed
111
+ results_dictionary: The dictionary being updated for return by the parsing
112
+ function.
113
+
114
+ Raises:
115
+ ValueError: If the name has an index or the values cannot be parsed.
116
+ """
117
+ if m_dict["index"] is not None:
118
+ raise ValueError("Assignment of a list to a list index.")
119
+ elements = filter(None, re.split("[ ,]", m_dict["vals"]))
120
+ # Make sure the name hasn't already been assigned a value
121
+ if name in results_dictionary:
122
+ raise _reuse_fail(name, values)
123
+ try:
124
+ results_dictionary[name] = [parse_fn(e) for e in elements]
125
+ except ValueError:
126
+ _parse_fail(name, var_type, m_dict["vals"], values)
127
+
128
+
129
+ def _cast_to_type_if_compatible(name, param_type, value):
130
+ """Cast hparam to the provided type, if compatible.
131
+
132
+ Args:
133
+ name: Name of the hparam to be cast.
134
+ param_type: The type of the hparam.
135
+ value: The value to be cast, if compatible.
136
+
137
+ Returns:
138
+ The result of casting `value` to `param_type`.
139
+
140
+ Raises:
141
+ ValueError: If the type of `value` is not compatible with param_type.
142
+ * If `param_type` is a string type, but `value` is not.
143
+ * If `param_type` is a boolean, but `value` is not, or vice versa.
144
+ * If `param_type` is an integer type, but `value` is not.
145
+ * If `param_type` is a float type, but `value` is not a numeric type.
146
+ """
147
+ fail_msg = "Could not cast hparam '%s' of type '%s' from value %r" % (
148
+ name,
149
+ param_type,
150
+ value,
151
+ )
152
+
153
+ # Some callers use None, for which we can't do any casting/checking. :(
154
+ if issubclass(param_type, type(None)):
155
+ return value
156
+
157
+ # Avoid converting a non-string type to a string.
158
+ if issubclass(param_type, (six.string_types, six.binary_type)) and not isinstance(
159
+ value, (six.string_types, six.binary_type)
160
+ ):
161
+ raise ValueError(fail_msg)
162
+
163
+ # Avoid converting a number or string type to a boolean or vice versa.
164
+ if issubclass(param_type, bool) != isinstance(value, bool):
165
+ raise ValueError(fail_msg)
166
+
167
+ # Avoid converting float to an integer (the reverse is fine).
168
+ if issubclass(param_type, numbers.Integral) and not isinstance(
169
+ value, numbers.Integral
170
+ ):
171
+ raise ValueError(fail_msg)
172
+
173
+ # Avoid converting a non-numeric type to a numeric type.
174
+ if issubclass(param_type, numbers.Number) and not isinstance(value, numbers.Number):
175
+ raise ValueError(fail_msg)
176
+
177
+ return param_type(value)
178
+
179
+
180
+ def parse_values(values, type_map, ignore_unknown=False):
181
+ """Parses hyperparameter values from a string into a python map.
182
+
183
+ `values` is a string containing comma-separated `name=value` pairs.
184
+ For each pair, the value of the hyperparameter named `name` is set to
185
+ `value`.
186
+
187
+ If a hyperparameter name appears multiple times in `values`, a ValueError
188
+ is raised (e.g. 'a=1,a=2', 'a[1]=1,a[1]=2').
189
+
190
+ If a hyperparameter name in both an index assignment and scalar assignment,
191
+ a ValueError is raised. (e.g. 'a=[1,2,3],a[0] = 1').
192
+
193
+ The hyperparameter name may contain '.' symbols, which will result in an
194
+ attribute name that is only accessible through the getattr and setattr
195
+ functions. (And must be first explicit added through add_hparam.)
196
+
197
+ WARNING: Use of '.' in your variable names is allowed, but is not well
198
+ supported and not recommended.
199
+
200
+ The `value` in `name=value` must follows the syntax according to the
201
+ type of the parameter:
202
+
203
+ * Scalar integer: A Python-parsable integer point value. E.g.: 1,
204
+ 100, -12.
205
+ * Scalar float: A Python-parsable floating point value. E.g.: 1.0,
206
+ -.54e89.
207
+ * Boolean: Either true or false.
208
+ * Scalar string: A non-empty sequence of characters, excluding comma,
209
+ spaces, and square brackets. E.g.: foo, bar_1.
210
+ * List: A comma separated list of scalar values of the parameter type
211
+ enclosed in square brackets. E.g.: [1,2,3], [1.0,1e-12], [high,low].
212
+
213
+ When index assignment is used, the corresponding type_map key should be the
214
+ list name. E.g. for "arr[1]=0" the type_map must have the key "arr" (not
215
+ "arr[1]").
216
+
217
+ Args:
218
+ values: String. Comma separated list of `name=value` pairs where
219
+ 'value' must follow the syntax described above.
220
+ type_map: A dictionary mapping hyperparameter names to types. Note every
221
+ parameter name in values must be a key in type_map. The values must
222
+ conform to the types indicated, where a value V is said to conform to a
223
+ type T if either V has type T, or V is a list of elements of type T.
224
+ Hence, for a multidimensional parameter 'x' taking float values,
225
+ 'x=[0.1,0.2]' will parse successfully if type_map['x'] = float.
226
+ ignore_unknown: Bool. Whether values that are missing a type in type_map
227
+ should be ignored. If set to True, a ValueError will not be raised for
228
+ unknown hyperparameter type.
229
+
230
+ Returns:
231
+ A python map mapping each name to either:
232
+ * A scalar value.
233
+ * A list of scalar values.
234
+ * A dictionary mapping index numbers to scalar values.
235
+ (e.g. "x=5,L=[1,2],arr[1]=3" results in {'x':5,'L':[1,2],'arr':{1:3}}")
236
+
237
+ Raises:
238
+ ValueError: If there is a problem with input.
239
+ * If `values` cannot be parsed.
240
+ * If a list is assigned to a list index (e.g. 'a[1] = [1,2,3]').
241
+ * If the same rvalue is assigned two different values (e.g. 'a=1,a=2',
242
+ 'a[1]=1,a[1]=2', or 'a=1,a=[1]')
243
+ """
244
+ results_dictionary = {}
245
+ pos = 0
246
+ while pos < len(values):
247
+ m = PARAM_RE.match(values, pos)
248
+ if not m:
249
+ raise ValueError("Malformed hyperparameter value: %s" % values[pos:])
250
+ # Check that there is a comma between parameters and move past it.
251
+ pos = m.end()
252
+ # Parse the values.
253
+ m_dict = m.groupdict()
254
+ name = m_dict["name"]
255
+ if name not in type_map:
256
+ if ignore_unknown:
257
+ continue
258
+ raise ValueError("Unknown hyperparameter type for %s" % name)
259
+ type_ = type_map[name]
260
+
261
+ # Set up correct parsing function (depending on whether type_ is a bool)
262
+ if type_ == bool:
263
+
264
+ def parse_bool(value):
265
+ if value in ["true", "True"]:
266
+ return True
267
+ elif value in ["false", "False"]:
268
+ return False
269
+ else:
270
+ try:
271
+ return bool(int(value))
272
+ except ValueError:
273
+ _parse_fail(name, type_, value, values)
274
+
275
+ parse = parse_bool
276
+ else:
277
+ parse = type_
278
+
279
+ # If a singe value is provided
280
+ if m_dict["val"] is not None:
281
+ _process_scalar_value(
282
+ name, parse, type_, m_dict, values, results_dictionary
283
+ )
284
+
285
+ # If the assigned value is a list:
286
+ elif m_dict["vals"] is not None:
287
+ _process_list_value(name, parse, type_, m_dict, values, results_dictionary)
288
+
289
+ else: # Not assigned a list or value
290
+ _parse_fail(name, type_, "", values)
291
+
292
+ return results_dictionary
293
+
294
+
295
+ class HParams(object):
296
+ """Class to hold a set of hyperparameters as name-value pairs.
297
+
298
+ A `HParams` object holds hyperparameters used to build and train a model,
299
+ such as the number of hidden units in a neural net layer or the learning rate
300
+ to use when training.
301
+
302
+ You first create a `HParams` object by specifying the names and values of the
303
+ hyperparameters.
304
+
305
+ To make them easily accessible the parameter names are added as direct
306
+ attributes of the class. A typical usage is as follows:
307
+
308
+ ```python
309
+ # Create a HParams object specifying names and values of the model
310
+ # hyperparameters:
311
+ hparams = HParams(learning_rate=0.1, num_hidden_units=100)
312
+
313
+ # The hyperparameter are available as attributes of the HParams object:
314
+ hparams.learning_rate ==> 0.1
315
+ hparams.num_hidden_units ==> 100
316
+ ```
317
+
318
+ Hyperparameters have type, which is inferred from the type of their value
319
+ passed at construction type. The currently supported types are: integer,
320
+ float, boolean, string, and list of integer, float, boolean, or string.
321
+
322
+ You can override hyperparameter values by calling the
323
+ [`parse()`](#HParams.parse) method, passing a string of comma separated
324
+ `name=value` pairs. This is intended to make it possible to override
325
+ any hyperparameter values from a single command-line flag to which
326
+ the user passes 'hyper-param=value' pairs. It avoids having to define
327
+ one flag for each hyperparameter.
328
+
329
+ The syntax expected for each value depends on the type of the parameter.
330
+ See `parse()` for a description of the syntax.
331
+
332
+ Example:
333
+
334
+ ```python
335
+ # Define a command line flag to pass name=value pairs.
336
+ # For example using argparse:
337
+ import argparse
338
+ parser = argparse.ArgumentParser(description='Train my model.')
339
+ parser.add_argument('--hparams', type=str,
340
+ help='Comma separated list of "name=value" pairs.')
341
+ args = parser.parse_args()
342
+ ...
343
+ def my_program():
344
+ # Create a HParams object specifying the names and values of the
345
+ # model hyperparameters:
346
+ hparams = tf.HParams(learning_rate=0.1, num_hidden_units=100,
347
+ activations=['relu', 'tanh'])
348
+
349
+ # Override hyperparameters values by parsing the command line
350
+ hparams.parse(args.hparams)
351
+
352
+ # If the user passed `--hparams=learning_rate=0.3` on the command line
353
+ # then 'hparams' has the following attributes:
354
+ hparams.learning_rate ==> 0.3
355
+ hparams.num_hidden_units ==> 100
356
+ hparams.activations ==> ['relu', 'tanh']
357
+
358
+ # If the hyperparameters are in json format use parse_json:
359
+ hparams.parse_json('{"learning_rate": 0.3, "activations": "relu"}')
360
+ ```
361
+ """
362
+
363
+ _HAS_DYNAMIC_ATTRIBUTES = True # Required for pytype checks.
364
+
365
+ def __init__(self, model_structure=None, **kwargs):
366
+ """Create an instance of `HParams` from keyword arguments.
367
+
368
+ The keyword arguments specify name-values pairs for the hyperparameters.
369
+ The parameter types are inferred from the type of the values passed.
370
+
371
+ The parameter names are added as attributes of `HParams` object, so they
372
+ can be accessed directly with the dot notation `hparams._name_`.
373
+
374
+ Example:
375
+
376
+ ```python
377
+ # Define 3 hyperparameters: 'learning_rate' is a float parameter,
378
+ # 'num_hidden_units' an integer parameter, and 'activation' a string
379
+ # parameter.
380
+ hparams = tf.HParams(
381
+ learning_rate=0.1, num_hidden_units=100, activation='relu')
382
+
383
+ hparams.activation ==> 'relu'
384
+ ```
385
+
386
+ Note that a few names are reserved and cannot be used as hyperparameter
387
+ names. If you use one of the reserved name the constructor raises a
388
+ `ValueError`.
389
+
390
+ Args:
391
+ model_structure: An instance of ModelStructure, defining the feature
392
+ crosses to be used in the Trial.
393
+ **kwargs: Key-value pairs where the key is the hyperparameter name and
394
+ the value is the value for the parameter.
395
+
396
+ Raises:
397
+ ValueError: If both `hparam_def` and initialization values are provided,
398
+ or if one of the arguments is invalid.
399
+
400
+ """
401
+ # Register the hyperparameters and their type in _hparam_types.
402
+ # This simplifies the implementation of parse().
403
+ # _hparam_types maps the parameter name to a tuple (type, bool).
404
+ # The type value is the type of the parameter for scalar hyperparameters,
405
+ # or the type of the list elements for multidimensional hyperparameters.
406
+ # The bool value is True if the value is a list, False otherwise.
407
+ self._hparam_types = {}
408
+ self._model_structure = model_structure
409
+ for name, value in six.iteritems(kwargs):
410
+ self.add_hparam(name, value)
411
+
412
+ def add_hparam(self, name, value):
413
+ """Adds {name, value} pair to hyperparameters.
414
+
415
+ Args:
416
+ name: Name of the hyperparameter.
417
+ value: Value of the hyperparameter. Can be one of the following types:
418
+ int, float, string, int list, float list, or string list.
419
+
420
+ Raises:
421
+ ValueError: if one of the arguments is invalid.
422
+ """
423
+ # Keys in kwargs are unique, but 'name' could the name of a pre-existing
424
+ # attribute of this object. In that case we refuse to use it as a
425
+ # hyperparameter name.
426
+ if getattr(self, name, None) is not None:
427
+ raise ValueError("Hyperparameter name is reserved: %s" % name)
428
+ if isinstance(value, (list, tuple)):
429
+ if not value:
430
+ raise ValueError(
431
+ "Multi-valued hyperparameters cannot be empty: %s" % name
432
+ )
433
+ self._hparam_types[name] = (type(value[0]), True)
434
+ else:
435
+ self._hparam_types[name] = (type(value), False)
436
+ setattr(self, name, value)
437
+
438
+ def set_hparam(self, name, value):
439
+ """Set the value of an existing hyperparameter.
440
+
441
+ This function verifies that the type of the value matches the type of the
442
+ existing hyperparameter.
443
+
444
+ Args:
445
+ name: Name of the hyperparameter.
446
+ value: New value of the hyperparameter.
447
+
448
+ Raises:
449
+ KeyError: If the hyperparameter doesn't exist.
450
+ ValueError: If there is a type mismatch.
451
+ """
452
+ param_type, is_list = self._hparam_types[name]
453
+ if isinstance(value, list):
454
+ if not is_list:
455
+ raise ValueError(
456
+ "Must not pass a list for single-valued parameter: %s" % name
457
+ )
458
+ setattr(
459
+ self,
460
+ name,
461
+ [_cast_to_type_if_compatible(name, param_type, v) for v in value],
462
+ )
463
+ else:
464
+ if is_list:
465
+ raise ValueError(
466
+ "Must pass a list for multi-valued parameter: %s." % name
467
+ )
468
+ setattr(self, name, _cast_to_type_if_compatible(name, param_type, value))
469
+
470
+ def del_hparam(self, name):
471
+ """Removes the hyperparameter with key 'name'.
472
+
473
+ Does nothing if it isn't present.
474
+
475
+ Args:
476
+ name: Name of the hyperparameter.
477
+ """
478
+ if hasattr(self, name):
479
+ delattr(self, name)
480
+ del self._hparam_types[name]
481
+
482
+ def parse(self, values):
483
+ """Override existing hyperparameter values, parsing new values from a string.
484
+
485
+ See parse_values for more detail on the allowed format for values.
486
+
487
+ Args:
488
+ values: String. Comma separated list of `name=value` pairs where 'value'
489
+ must follow the syntax described above.
490
+
491
+ Returns:
492
+ The `HParams` instance.
493
+
494
+ Raises:
495
+ ValueError: If `values` cannot be parsed or a hyperparameter in `values`
496
+ doesn't exist.
497
+ """
498
+ type_map = {}
499
+ for name, t in self._hparam_types.items():
500
+ param_type, _ = t
501
+ type_map[name] = param_type
502
+
503
+ values_map = parse_values(values, type_map)
504
+ return self.override_from_dict(values_map)
505
+
506
+ def override_from_dict(self, values_dict):
507
+ """Override existing hyperparameter values, parsing new values from a dictionary.
508
+
509
+ Args:
510
+ values_dict: Dictionary of name:value pairs.
511
+
512
+ Returns:
513
+ The `HParams` instance.
514
+
515
+ Raises:
516
+ KeyError: If a hyperparameter in `values_dict` doesn't exist.
517
+ ValueError: If `values_dict` cannot be parsed.
518
+ """
519
+ for name, value in values_dict.items():
520
+ self.set_hparam(name, value)
521
+ return self
522
+
523
+ def set_model_structure(self, model_structure):
524
+ self._model_structure = model_structure
525
+
526
+ def get_model_structure(self):
527
+ return self._model_structure
528
+
529
+ def to_json(self, indent=None, separators=None, sort_keys=False):
530
+ """Serializes the hyperparameters into JSON.
531
+
532
+ Args:
533
+ indent: If a non-negative integer, JSON array elements and object members
534
+ will be pretty-printed with that indent level. An indent level of 0, or
535
+ negative, will only insert newlines. `None` (the default) selects the
536
+ most compact representation.
537
+ separators: Optional `(item_separator, key_separator)` tuple. Default is
538
+ `(', ', ': ')`.
539
+ sort_keys: If `True`, the output dictionaries will be sorted by key.
540
+
541
+ Returns:
542
+ A JSON string.
543
+ """
544
+
545
+ def remove_callables(x):
546
+ """Omit callable elements from input with arbitrary nesting."""
547
+ if isinstance(x, dict):
548
+ return {
549
+ k: remove_callables(v)
550
+ for k, v in six.iteritems(x)
551
+ if not callable(v)
552
+ }
553
+ elif isinstance(x, list):
554
+ return [remove_callables(i) for i in x if not callable(i)]
555
+ return x
556
+
557
+ return json.dumps(
558
+ remove_callables(self.values()),
559
+ indent=indent,
560
+ separators=separators,
561
+ sort_keys=sort_keys,
562
+ )
563
+
564
+ def parse_json(self, values_json):
565
+ """Override existing hyperparameter values, parsing new values from a json object.
566
+
567
+ Args:
568
+ values_json: String containing a json object of name:value pairs.
569
+
570
+ Returns:
571
+ The `HParams` instance.
572
+
573
+ Raises:
574
+ KeyError: If a hyperparameter in `values_json` doesn't exist.
575
+ ValueError: If `values_json` cannot be parsed.
576
+ """
577
+ values_map = json.loads(values_json)
578
+ return self.override_from_dict(values_map)
579
+
580
+ def values(self):
581
+ """Return the hyperparameter values as a Python dictionary.
582
+
583
+ Returns:
584
+ A dictionary with hyperparameter names as keys. The values are the
585
+ hyperparameter values.
586
+ """
587
+ return {n: getattr(self, n) for n in self._hparam_types.keys()}
588
+
589
+ def get(self, key, default=None):
590
+ """Returns the value of `key` if it exists, else `default`."""
591
+ if key in self._hparam_types:
592
+ # Ensure that default is compatible with the parameter type.
593
+ if default is not None:
594
+ param_type, is_param_list = self._hparam_types[key]
595
+ type_str = "list<%s>" % param_type if is_param_list else str(param_type)
596
+ fail_msg = (
597
+ "Hparam '%s' of type '%s' is incompatible with "
598
+ "default=%s" % (key, type_str, default)
599
+ )
600
+
601
+ is_default_list = isinstance(default, list)
602
+ if is_param_list != is_default_list:
603
+ raise ValueError(fail_msg)
604
+
605
+ try:
606
+ if is_default_list:
607
+ for value in default:
608
+ _cast_to_type_if_compatible(key, param_type, value)
609
+ else:
610
+ _cast_to_type_if_compatible(key, param_type, default)
611
+ except ValueError as e:
612
+ raise ValueError("%s. %s" % (fail_msg, e))
613
+
614
+ return getattr(self, key)
615
+
616
+ return default
617
+
618
+ def __contains__(self, key):
619
+ return key in self._hparam_types
620
+
621
+ def __str__(self):
622
+ return str(sorted(self.values().items()))
623
+
624
+ def __repr__(self):
625
+ return "%s(%s)" % (type(self).__name__, self.__str__())
626
+
627
+ @staticmethod
628
+ def _get_kind_name(param_type, is_list):
629
+ """Returns the field name given parameter type and is_list.
630
+
631
+ Args:
632
+ param_type: Data type of the hparam.
633
+ is_list: Whether this is a list.
634
+
635
+ Returns:
636
+ A string representation of the field name.
637
+
638
+ Raises:
639
+ ValueError: If parameter type is not recognized.
640
+ """
641
+ if issubclass(param_type, bool):
642
+ # This check must happen before issubclass(param_type, six.integer_types),
643
+ # since Python considers bool to be a subclass of int.
644
+ typename = "bool"
645
+ elif issubclass(param_type, six.integer_types):
646
+ # Setting 'int' and 'long' types to be 'int64' to ensure the type is
647
+ # compatible with both Python2 and Python3.
648
+ typename = "int64"
649
+ elif issubclass(param_type, (six.string_types, six.binary_type)):
650
+ # Setting 'string' and 'bytes' types to be 'bytes' to ensure the type is
651
+ # compatible with both Python2 and Python3.
652
+ typename = "bytes"
653
+ elif issubclass(param_type, float):
654
+ typename = "float"
655
+ else:
656
+ raise ValueError("Unsupported parameter type: %s" % str(param_type))
657
+
658
+ suffix = "list" if is_list else "value"
659
+ return "_".join([typename, suffix])
utils/hubert.py ADDED
@@ -0,0 +1,155 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023 Amphion.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ # This code is modified from https://github.com/svc-develop-team/so-vits-svc/blob/4.0/preprocess_hubert_f0.py
7
+
8
+ import os
9
+ import librosa
10
+ import torch
11
+ import numpy as np
12
+ from fairseq import checkpoint_utils
13
+ from tqdm import tqdm
14
+ import torch
15
+
16
+
17
+ def load_hubert_model(hps):
18
+ # Load model
19
+ ckpt_path = hps.hubert_file
20
+ print("Load Hubert Model...")
21
+
22
+ models, saved_cfg, task = checkpoint_utils.load_model_ensemble_and_task(
23
+ [ckpt_path],
24
+ suffix="",
25
+ )
26
+ model = models[0]
27
+ model.eval()
28
+
29
+ if torch.cuda.is_available():
30
+ model = model.cuda()
31
+
32
+ return model
33
+
34
+
35
+ def get_hubert_content(hmodel, wav_16k_tensor):
36
+ feats = wav_16k_tensor
37
+ if feats.dim() == 2: # double channels
38
+ feats = feats.mean(-1)
39
+ assert feats.dim() == 1, feats.dim()
40
+ feats = feats.view(1, -1)
41
+ padding_mask = torch.BoolTensor(feats.shape).fill_(False)
42
+ inputs = {
43
+ "source": feats.to(wav_16k_tensor.device),
44
+ "padding_mask": padding_mask.to(wav_16k_tensor.device),
45
+ "output_layer": 9, # layer 9
46
+ }
47
+ with torch.no_grad():
48
+ logits = hmodel.extract_features(**inputs)
49
+ feats = hmodel.final_proj(logits[0]).squeeze(0)
50
+
51
+ return feats
52
+
53
+
54
+ def content_vector_encoder(model, audio_path, default_sampling_rate=16000):
55
+ """
56
+ # content vector default sr: 16000
57
+ """
58
+
59
+ wav16k, sr = librosa.load(audio_path, sr=default_sampling_rate)
60
+ device = next(model.parameters()).device
61
+ wav16k = torch.from_numpy(wav16k).to(device)
62
+
63
+ # (1, 256, frame_len)
64
+ content_feature = get_hubert_content(model, wav_16k_tensor=wav16k)
65
+
66
+ return content_feature.cpu().detach().numpy()
67
+
68
+
69
+ def repeat_expand_2d(content, target_len):
70
+ """
71
+ content : [hubert_dim(256), src_len]
72
+ target: [hubert_dim(256), target_len]
73
+ """
74
+ src_len = content.shape[-1]
75
+ target = torch.zeros([content.shape[0], target_len], dtype=torch.float).to(
76
+ content.device
77
+ )
78
+ temp = torch.arange(src_len + 1) * target_len / src_len
79
+ current_pos = 0
80
+ for i in range(target_len):
81
+ if i < temp[current_pos + 1]:
82
+ target[:, i] = content[:, current_pos]
83
+ else:
84
+ current_pos += 1
85
+ target[:, i] = content[:, current_pos]
86
+
87
+ return target
88
+
89
+
90
+ def get_mapped_features(raw_content_features, mapping_features):
91
+ """
92
+ Content Vector: frameshift = 20ms, hop_size = 480 in 24k
93
+
94
+ Now it's only used for mapping to bigvgan's mels (sr = 24k, hop_size = 256, frameshift ~= 10.7 ms)
95
+ """
96
+ source_hop = 480
97
+ target_hop = 256
98
+
99
+ factor = np.gcd(source_hop, target_hop)
100
+ source_hop //= factor
101
+ target_hop //= factor
102
+ print(
103
+ "Mapping source's {} frames => target's {} frames".format(
104
+ target_hop, source_hop
105
+ )
106
+ )
107
+
108
+ results = []
109
+ for index, mapping_feat in enumerate(tqdm(mapping_features)):
110
+ # mappping_feat: (mels_frame_len, n_mels)
111
+ target_len = len(mapping_feat)
112
+
113
+ # (source_len, 256)
114
+ raw_feats = raw_content_features[index][0].cpu().numpy().T
115
+ source_len, width = raw_feats.shape
116
+
117
+ # const ~= target_len * target_hop
118
+ const = source_len * source_hop // target_hop * target_hop
119
+
120
+ # (source_len * source_hop, dim)
121
+ up_sampling_feats = np.repeat(raw_feats, source_hop, axis=0)
122
+ # (const, dim) -> (const/target_hop, target_hop, dim) -> (const/target_hop, dim)
123
+ down_sampling_feats = np.average(
124
+ up_sampling_feats[:const].reshape(-1, target_hop, width), axis=1
125
+ )
126
+
127
+ err = abs(target_len - len(down_sampling_feats))
128
+ if err > 3:
129
+ print("index:", index)
130
+ print("mels:", mapping_feat.shape)
131
+ print("raw content vector:", raw_feats.shape)
132
+ print("up_sampling:", up_sampling_feats.shape)
133
+ print("down_sampling_feats:", down_sampling_feats.shape)
134
+ exit()
135
+ if len(down_sampling_feats) < target_len:
136
+ # (1, dim) -> (err, dim)
137
+ end = down_sampling_feats[-1][None, :].repeat(err, axis=0)
138
+ down_sampling_feats = np.concatenate([down_sampling_feats, end], axis=0)
139
+
140
+ # (target_len, dim)
141
+ feats = down_sampling_feats[:target_len]
142
+ results.append(feats)
143
+
144
+ return results
145
+
146
+
147
+ def extract_hubert_features_of_dataset(datasets, model, out_dir):
148
+ for utt in tqdm(datasets):
149
+ uid = utt["Uid"]
150
+ audio_path = utt["Path"]
151
+
152
+ content_vector_feature = content_vector_encoder(model, audio_path) # (T, 256)
153
+
154
+ save_path = os.path.join(out_dir, uid + ".npy")
155
+ np.save(save_path, content_vector_feature)
utils/io.py ADDED
@@ -0,0 +1,182 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023 Amphion.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ import os
7
+ import numpy as np
8
+ import torch
9
+ import torchaudio
10
+
11
+
12
+ def save_feature(process_dir, feature_dir, item, feature, overrides=True):
13
+ """Save features to path
14
+
15
+ Args:
16
+ process_dir (str): directory to store features
17
+ feature_dir (_type_): directory to store one type of features (mel, energy, ...)
18
+ item (str): uid
19
+ feature (tensor): feature tensor
20
+ overrides (bool, optional): whether to override existing files. Defaults to True.
21
+ """
22
+ process_dir = os.path.join(process_dir, feature_dir)
23
+ os.makedirs(process_dir, exist_ok=True)
24
+ out_path = os.path.join(process_dir, item + ".npy")
25
+
26
+ if os.path.exists(out_path):
27
+ if overrides:
28
+ np.save(out_path, feature)
29
+ else:
30
+ np.save(out_path, feature)
31
+
32
+
33
+ def save_txt(process_dir, feature_dir, item, feature, overrides=True):
34
+ process_dir = os.path.join(process_dir, feature_dir)
35
+ os.makedirs(process_dir, exist_ok=True)
36
+ out_path = os.path.join(process_dir, item + ".txt")
37
+
38
+ if os.path.exists(out_path):
39
+ if overrides:
40
+ f = open(out_path, "w")
41
+ f.writelines(feature)
42
+ f.close()
43
+ else:
44
+ f = open(out_path, "w")
45
+ f.writelines(feature)
46
+ f.close()
47
+
48
+
49
+ def save_audio(path, waveform, fs, add_silence=False, turn_up=False, volume_peak=0.9):
50
+ """Save audio to path with processing (turn up volume, add silence)
51
+ Args:
52
+ path (str): path to save audio
53
+ waveform (numpy array): waveform to save
54
+ fs (int): sampling rate
55
+ add_silence (bool, optional): whether to add silence to beginning and end. Defaults to False.
56
+ turn_up (bool, optional): whether to turn up volume. Defaults to False.
57
+ volume_peak (float, optional): volume peak. Defaults to 0.9.
58
+ """
59
+ if turn_up:
60
+ # continue to turn up to volume_peak
61
+ ratio = volume_peak / max(waveform.max(), abs(waveform.min()))
62
+ waveform = waveform * ratio
63
+
64
+ if add_silence:
65
+ silence_len = fs // 20
66
+ silence = np.zeros((silence_len,), dtype=waveform.dtype)
67
+ result = np.concatenate([silence, waveform, silence])
68
+ waveform = result
69
+
70
+ waveform = torch.as_tensor(waveform, dtype=torch.float32, device="cpu")
71
+ if len(waveform.size()) == 1:
72
+ waveform = waveform[None, :]
73
+ elif waveform.size(0) != 1:
74
+ # Stereo to mono
75
+ waveform = torch.mean(waveform, dim=0, keepdim=True)
76
+ torchaudio.save(path, waveform, fs, encoding="PCM_S", bits_per_sample=16)
77
+
78
+
79
+ def save_torch_audio(process_dir, feature_dir, item, wav_torch, fs, overrides=True):
80
+ """Save torch audio to path without processing
81
+ Args:
82
+ process_dir (str): directory to store features
83
+ feature_dir (_type_): directory to store one type of features (mel, energy, ...)
84
+ item (str): uid
85
+ wav_torch (tensor): feature tensor
86
+ fs (int): sampling rate
87
+ overrides (bool, optional): whether to override existing files. Defaults to True.
88
+ """
89
+ if wav_torch.shape != 2:
90
+ wav_torch = wav_torch.unsqueeze(0)
91
+
92
+ process_dir = os.path.join(process_dir, feature_dir)
93
+ os.makedirs(process_dir, exist_ok=True)
94
+ out_path = os.path.join(process_dir, item + ".wav")
95
+
96
+ torchaudio.save(out_path, wav_torch, fs)
97
+
98
+
99
+ async def async_load_audio(path, sample_rate: int = 24000):
100
+ r"""
101
+ Args:
102
+ path: The source loading path.
103
+ sample_rate: The target sample rate, will automatically resample if necessary.
104
+
105
+ Returns:
106
+ waveform: The waveform object. Should be [1 x sequence_len].
107
+ """
108
+
109
+ async def use_torchaudio_load(path):
110
+ return torchaudio.load(path)
111
+
112
+ waveform, sr = await use_torchaudio_load(path)
113
+ waveform = torch.mean(waveform, dim=0, keepdim=True)
114
+
115
+ if sr != sample_rate:
116
+ waveform = torchaudio.functional.resample(waveform, sr, sample_rate)
117
+
118
+ if torch.any(torch.isnan(waveform) or torch.isinf(waveform)):
119
+ raise ValueError("NaN or Inf found in waveform.")
120
+ return waveform
121
+
122
+
123
+ async def async_save_audio(
124
+ path,
125
+ waveform,
126
+ sample_rate: int = 24000,
127
+ add_silence: bool = False,
128
+ volume_peak: float = 0.9,
129
+ ):
130
+ r"""
131
+ Args:
132
+ path: The target saving path.
133
+ waveform: The waveform object. Should be [n_channel x sequence_len].
134
+ sample_rate: Sample rate.
135
+ add_silence: If ``true``, concat 0.05s silence to beginning and end.
136
+ volume_peak: Turn up volume for larger number, vice versa.
137
+ """
138
+
139
+ async def use_torchaudio_save(path, waveform, sample_rate):
140
+ torchaudio.save(
141
+ path, waveform, sample_rate, encoding="PCM_S", bits_per_sample=16
142
+ )
143
+
144
+ waveform = torch.as_tensor(waveform, device="cpu", dtype=torch.float32)
145
+ shape = waveform.size()[:-1]
146
+
147
+ ratio = abs(volume_peak) / max(waveform.max(), abs(waveform.min()))
148
+ waveform = waveform * ratio
149
+
150
+ if add_silence:
151
+ silence_len = sample_rate // 20
152
+ silence = torch.zeros((*shape, silence_len), dtype=waveform.type())
153
+ waveform = torch.concatenate((silence, waveform, silence), dim=-1)
154
+
155
+ if waveform.dim() == 1:
156
+ waveform = waveform[None]
157
+
158
+ await use_torchaudio_save(path, waveform, sample_rate)
159
+
160
+
161
+ def load_mel_extrema(cfg, dataset_name, split):
162
+ dataset_dir = os.path.join(
163
+ cfg.OUTPUT_PATH,
164
+ "preprocess/{}_version".format(cfg.data.process_version),
165
+ dataset_name,
166
+ )
167
+
168
+ min_file = os.path.join(
169
+ dataset_dir,
170
+ "mel_min_max",
171
+ split.split("_")[-1],
172
+ "mel_min.npy",
173
+ )
174
+ max_file = os.path.join(
175
+ dataset_dir,
176
+ "mel_min_max",
177
+ split.split("_")[-1],
178
+ "mel_max.npy",
179
+ )
180
+ mel_min = np.load(min_file)
181
+ mel_max = np.load(max_file)
182
+ return mel_min, mel_max
utils/io_optim.py ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023 Amphion.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ import torch
7
+ import torchaudio
8
+ import json
9
+ import os
10
+ import numpy as np
11
+ import librosa
12
+ import whisper
13
+ from torch.nn.utils.rnn import pad_sequence
14
+
15
+
16
+ class TorchaudioDataset(torch.utils.data.Dataset):
17
+ def __init__(self, cfg, dataset, sr, accelerator=None, metadata=None):
18
+ """
19
+ Args:
20
+ cfg: config
21
+ dataset: dataset name
22
+
23
+ """
24
+ assert isinstance(dataset, str)
25
+
26
+ self.sr = sr
27
+ self.cfg = cfg
28
+
29
+ if metadata is None:
30
+ self.train_metadata_path = os.path.join(
31
+ cfg.preprocess.processed_dir, dataset, cfg.preprocess.train_file
32
+ )
33
+ self.valid_metadata_path = os.path.join(
34
+ cfg.preprocess.processed_dir, dataset, cfg.preprocess.valid_file
35
+ )
36
+ self.metadata = self.get_metadata()
37
+ else:
38
+ self.metadata = metadata
39
+
40
+ if accelerator is not None:
41
+ self.device = accelerator.device
42
+ elif torch.cuda.is_available():
43
+ self.device = torch.device("cuda")
44
+ else:
45
+ self.device = torch.device("cpu")
46
+
47
+ def get_metadata(self):
48
+ metadata = []
49
+ with open(self.train_metadata_path, "r", encoding="utf-8") as t:
50
+ metadata.extend(json.load(t))
51
+ with open(self.valid_metadata_path, "r", encoding="utf-8") as v:
52
+ metadata.extend(json.load(v))
53
+ return metadata
54
+
55
+ def __len__(self):
56
+ return len(self.metadata)
57
+
58
+ def __getitem__(self, index):
59
+ utt_info = self.metadata[index]
60
+ wav_path = utt_info["Path"]
61
+
62
+ wav, sr = torchaudio.load(wav_path)
63
+
64
+ # resample
65
+ if sr != self.sr:
66
+ wav = torchaudio.functional.resample(wav, sr, self.sr)
67
+ # downmixing
68
+ if wav.shape[0] > 1:
69
+ wav = torch.mean(wav, dim=0, keepdim=True)
70
+ assert wav.shape[0] == 1
71
+ wav = wav.squeeze(0)
72
+ # record the length of wav without padding
73
+ length = wav.shape[0]
74
+ # wav: (T)
75
+ return utt_info, wav, length
76
+
77
+
78
+ class LibrosaDataset(TorchaudioDataset):
79
+ def __init__(self, cfg, dataset, sr, accelerator=None, metadata=None):
80
+ super().__init__(cfg, dataset, sr, accelerator, metadata)
81
+
82
+ def __getitem__(self, index):
83
+ utt_info = self.metadata[index]
84
+ wav_path = utt_info["Path"]
85
+
86
+ wav, _ = librosa.load(wav_path, sr=self.sr)
87
+ # wav: (T)
88
+ wav = torch.from_numpy(wav)
89
+
90
+ # record the length of wav without padding
91
+ length = wav.shape[0]
92
+ return utt_info, wav, length
93
+
94
+
95
+ class FFmpegDataset(TorchaudioDataset):
96
+ def __init__(self, cfg, dataset, sr, accelerator=None, metadata=None):
97
+ super().__init__(cfg, dataset, sr, accelerator, metadata)
98
+
99
+ def __getitem__(self, index):
100
+ utt_info = self.metadata[index]
101
+ wav_path = utt_info["Path"]
102
+
103
+ # wav: (T,)
104
+ wav = whisper.load_audio(wav_path, sr=16000) # sr = 16000
105
+ # convert to torch tensor
106
+ wav = torch.from_numpy(wav)
107
+ # record the length of wav without padding
108
+ length = wav.shape[0]
109
+
110
+ return utt_info, wav, length
111
+
112
+
113
+ def collate_batch(batch_list):
114
+ """
115
+ Args:
116
+ batch_list: list of (metadata, wav, length)
117
+ """
118
+ metadata = [item[0] for item in batch_list]
119
+ # wavs: (B, T)
120
+ wavs = pad_sequence([item[1] for item in batch_list], batch_first=True)
121
+ lens = [item[2] for item in batch_list]
122
+
123
+ return metadata, wavs, lens
utils/mel.py ADDED
@@ -0,0 +1,280 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023 Amphion.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ import torch
7
+ from librosa.filters import mel as librosa_mel_fn
8
+
9
+
10
+ def dynamic_range_compression_torch(x, C=1, clip_val=1e-5):
11
+ # Min value: ln(1e-5) = -11.5129
12
+ return torch.log(torch.clamp(x, min=clip_val) * C)
13
+
14
+
15
+ def spectral_normalize_torch(magnitudes):
16
+ output = dynamic_range_compression_torch(magnitudes)
17
+ return output
18
+
19
+
20
+ def extract_linear_features(y, cfg, center=False):
21
+ if torch.min(y) < -1.0:
22
+ print("min value is ", torch.min(y))
23
+ if torch.max(y) > 1.0:
24
+ print("max value is ", torch.max(y))
25
+
26
+ global hann_window
27
+ hann_window[str(y.device)] = torch.hann_window(cfg.win_size).to(y.device)
28
+
29
+ y = torch.nn.functional.pad(
30
+ y.unsqueeze(1),
31
+ (int((cfg.n_fft - cfg.hop_size) / 2), int((cfg.n_fft - cfg.hop_size) / 2)),
32
+ mode="reflect",
33
+ )
34
+ y = y.squeeze(1)
35
+
36
+ # complex tensor as default, then use view_as_real for future pytorch compatibility
37
+ spec = torch.stft(
38
+ y,
39
+ cfg.n_fft,
40
+ hop_length=cfg.hop_size,
41
+ win_length=cfg.win_size,
42
+ window=hann_window[str(y.device)],
43
+ center=center,
44
+ pad_mode="reflect",
45
+ normalized=False,
46
+ onesided=True,
47
+ return_complex=True,
48
+ )
49
+ spec = torch.view_as_real(spec)
50
+ spec = torch.sqrt(spec.pow(2).sum(-1) + (1e-9))
51
+ spec = torch.squeeze(spec, 0)
52
+ return spec
53
+
54
+
55
+ def mel_spectrogram_torch(y, cfg, center=False):
56
+ """
57
+ TODO: to merge this funtion with the extract_mel_features below
58
+ """
59
+ if torch.min(y) < -1.0:
60
+ print("min value is ", torch.min(y))
61
+ if torch.max(y) > 1.0:
62
+ print("max value is ", torch.max(y))
63
+
64
+ global mel_basis, hann_window
65
+ if cfg.fmax not in mel_basis:
66
+ mel = librosa_mel_fn(
67
+ sr=cfg.sample_rate,
68
+ n_fft=cfg.n_fft,
69
+ n_mels=cfg.n_mel,
70
+ fmin=cfg.fmin,
71
+ fmax=cfg.fmax,
72
+ )
73
+ mel_basis[str(cfg.fmax) + "_" + str(y.device)] = (
74
+ torch.from_numpy(mel).float().to(y.device)
75
+ )
76
+ hann_window[str(y.device)] = torch.hann_window(cfg.win_size).to(y.device)
77
+
78
+ y = torch.nn.functional.pad(
79
+ y.unsqueeze(1),
80
+ (int((cfg.n_fft - cfg.hop_size) / 2), int((cfg.n_fft - cfg.hop_size) / 2)),
81
+ mode="reflect",
82
+ )
83
+ y = y.squeeze(1)
84
+
85
+ spec = torch.stft(
86
+ y,
87
+ cfg.n_fft,
88
+ hop_length=cfg.hop_size,
89
+ win_length=cfg.win_size,
90
+ window=hann_window[str(y.device)],
91
+ center=center,
92
+ pad_mode="reflect",
93
+ normalized=False,
94
+ onesided=True,
95
+ return_complex=True,
96
+ )
97
+
98
+ spec = torch.view_as_real(spec)
99
+ spec = torch.sqrt(spec.pow(2).sum(-1) + 1e-6)
100
+
101
+ spec = torch.matmul(mel_basis[str(cfg.fmax) + "_" + str(y.device)], spec)
102
+ spec = spectral_normalize_torch(spec)
103
+
104
+ return spec
105
+
106
+
107
+ mel_basis = {}
108
+ hann_window = {}
109
+
110
+
111
+ def extract_mel_features(
112
+ y,
113
+ cfg,
114
+ center=False,
115
+ ):
116
+ """Extract mel features
117
+
118
+ Args:
119
+ y (tensor): audio data in tensor
120
+ cfg (dict): configuration in cfg.preprocess
121
+ center (bool, optional): In STFT, whether t-th frame is centered at time t*hop_length. Defaults to False.
122
+
123
+ Returns:
124
+ tensor: a tensor containing the mel feature calculated based on STFT result
125
+ """
126
+ if torch.min(y) < -1.0:
127
+ print("min value is ", torch.min(y))
128
+ if torch.max(y) > 1.0:
129
+ print("max value is ", torch.max(y))
130
+
131
+ global mel_basis, hann_window
132
+ if cfg.fmax not in mel_basis:
133
+ mel = librosa_mel_fn(
134
+ sr=cfg.sample_rate,
135
+ n_fft=cfg.n_fft,
136
+ n_mels=cfg.n_mel,
137
+ fmin=cfg.fmin,
138
+ fmax=cfg.fmax,
139
+ )
140
+ mel_basis[str(cfg.fmax) + "_" + str(y.device)] = (
141
+ torch.from_numpy(mel).float().to(y.device)
142
+ )
143
+ hann_window[str(y.device)] = torch.hann_window(cfg.win_size).to(y.device)
144
+
145
+ y = torch.nn.functional.pad(
146
+ y.unsqueeze(1),
147
+ (int((cfg.n_fft - cfg.hop_size) / 2), int((cfg.n_fft - cfg.hop_size) / 2)),
148
+ mode="reflect",
149
+ )
150
+ y = y.squeeze(1)
151
+
152
+ # complex tensor as default, then use view_as_real for future pytorch compatibility
153
+ spec = torch.stft(
154
+ y,
155
+ cfg.n_fft,
156
+ hop_length=cfg.hop_size,
157
+ win_length=cfg.win_size,
158
+ window=hann_window[str(y.device)],
159
+ center=center,
160
+ pad_mode="reflect",
161
+ normalized=False,
162
+ onesided=True,
163
+ return_complex=True,
164
+ )
165
+ spec = torch.view_as_real(spec)
166
+ spec = torch.sqrt(spec.pow(2).sum(-1) + (1e-9))
167
+
168
+ spec = torch.matmul(mel_basis[str(cfg.fmax) + "_" + str(y.device)], spec)
169
+ spec = spectral_normalize_torch(spec)
170
+ return spec.squeeze(0)
171
+
172
+
173
+ def extract_mel_features_tts(
174
+ y,
175
+ cfg,
176
+ center=False,
177
+ taco=False,
178
+ _stft=None,
179
+ ):
180
+ """Extract mel features
181
+
182
+ Args:
183
+ y (tensor): audio data in tensor
184
+ cfg (dict): configuration in cfg.preprocess
185
+ center (bool, optional): In STFT, whether t-th frame is centered at time t*hop_length. Defaults to False.
186
+ taco: use tacotron mel
187
+
188
+ Returns:
189
+ tensor: a tensor containing the mel feature calculated based on STFT result
190
+ """
191
+ if not taco:
192
+ if torch.min(y) < -1.0:
193
+ print("min value is ", torch.min(y))
194
+ if torch.max(y) > 1.0:
195
+ print("max value is ", torch.max(y))
196
+
197
+ global mel_basis, hann_window
198
+ if cfg.fmax not in mel_basis:
199
+ mel = librosa_mel_fn(
200
+ sr=cfg.sample_rate,
201
+ n_fft=cfg.n_fft,
202
+ n_mels=cfg.n_mel,
203
+ fmin=cfg.fmin,
204
+ fmax=cfg.fmax,
205
+ )
206
+ mel_basis[str(cfg.fmax) + "_" + str(y.device)] = (
207
+ torch.from_numpy(mel).float().to(y.device)
208
+ )
209
+ hann_window[str(y.device)] = torch.hann_window(cfg.win_size).to(y.device)
210
+
211
+ y = torch.nn.functional.pad(
212
+ y.unsqueeze(1),
213
+ (int((cfg.n_fft - cfg.hop_size) / 2), int((cfg.n_fft - cfg.hop_size) / 2)),
214
+ mode="reflect",
215
+ )
216
+ y = y.squeeze(1)
217
+
218
+ # complex tensor as default, then use view_as_real for future pytorch compatibility
219
+ spec = torch.stft(
220
+ y,
221
+ cfg.n_fft,
222
+ hop_length=cfg.hop_size,
223
+ win_length=cfg.win_size,
224
+ window=hann_window[str(y.device)],
225
+ center=center,
226
+ pad_mode="reflect",
227
+ normalized=False,
228
+ onesided=True,
229
+ return_complex=True,
230
+ )
231
+ spec = torch.view_as_real(spec)
232
+ spec = torch.sqrt(spec.pow(2).sum(-1) + (1e-9))
233
+
234
+ spec = torch.matmul(mel_basis[str(cfg.fmax) + "_" + str(y.device)], spec)
235
+ spec = spectral_normalize_torch(spec)
236
+ else:
237
+ audio = torch.clip(y, -1, 1)
238
+ audio = torch.autograd.Variable(audio, requires_grad=False)
239
+ spec, energy = _stft.mel_spectrogram(audio)
240
+
241
+ return spec.squeeze(0)
242
+
243
+
244
+ def amplitude_phase_spectrum(y, cfg):
245
+ hann_window = torch.hann_window(cfg.win_size).to(y.device)
246
+
247
+ y = torch.nn.functional.pad(
248
+ y.unsqueeze(1),
249
+ (int((cfg.n_fft - cfg.hop_size) / 2), int((cfg.n_fft - cfg.hop_size) / 2)),
250
+ mode="reflect",
251
+ )
252
+ y = y.squeeze(1)
253
+
254
+ stft_spec = torch.stft(
255
+ y,
256
+ cfg.n_fft,
257
+ hop_length=cfg.hop_size,
258
+ win_length=cfg.win_size,
259
+ window=hann_window,
260
+ center=False,
261
+ return_complex=True,
262
+ )
263
+
264
+ stft_spec = torch.view_as_real(stft_spec)
265
+ if stft_spec.size()[0] == 1:
266
+ stft_spec = stft_spec.squeeze(0)
267
+
268
+ if len(list(stft_spec.size())) == 4:
269
+ rea = stft_spec[:, :, :, 0] # [batch_size, n_fft//2+1, frames]
270
+ imag = stft_spec[:, :, :, 1] # [batch_size, n_fft//2+1, frames]
271
+ else:
272
+ rea = stft_spec[:, :, 0] # [n_fft//2+1, frames]
273
+ imag = stft_spec[:, :, 1] # [n_fft//2+1, frames]
274
+
275
+ log_amplitude = torch.log(
276
+ torch.abs(torch.sqrt(torch.pow(rea, 2) + torch.pow(imag, 2))) + 1e-5
277
+ ) # [n_fft//2+1, frames]
278
+ phase = torch.atan2(imag, rea) # [n_fft//2+1, frames]
279
+
280
+ return log_amplitude, phase, rea, imag
utils/mert.py ADDED
@@ -0,0 +1,139 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023 Amphion.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ # This code is modified from https://huggingface.co/m-a-p/MERT-v1-330M
7
+
8
+ import torch
9
+ from tqdm import tqdm
10
+ import numpy as np
11
+
12
+ from transformers import Wav2Vec2FeatureExtractor
13
+ from transformers import AutoModel
14
+ import torchaudio
15
+ import torchaudio.transforms as T
16
+ from sklearn.preprocessing import StandardScaler
17
+
18
+
19
+ def mert_encoder(model, processor, audio_path, hps):
20
+ """
21
+ # mert default sr: 24000
22
+ """
23
+ with torch.no_grad():
24
+ resample_rate = processor.sampling_rate
25
+ device = next(model.parameters()).device
26
+
27
+ input_audio, sampling_rate = torchaudio.load(audio_path)
28
+ input_audio = input_audio.squeeze()
29
+
30
+ if sampling_rate != resample_rate:
31
+ resampler = T.Resample(sampling_rate, resample_rate)
32
+ input_audio = resampler(input_audio)
33
+
34
+ inputs = processor(
35
+ input_audio, sampling_rate=resample_rate, return_tensors="pt"
36
+ ).to(
37
+ device
38
+ ) # {input_values: tensor, attention_mask: tensor}
39
+
40
+ outputs = model(**inputs, output_hidden_states=True) # list: len is 25
41
+
42
+ # [25 layer, Time steps, 1024 feature_dim]
43
+ # all_layer_hidden_states = torch.stack(outputs.hidden_states).squeeze()
44
+ # mert_features.append(all_layer_hidden_states)
45
+
46
+ feature = outputs.hidden_states[
47
+ hps.mert_feature_layer
48
+ ].squeeze() # [1, frame len, 1024] -> [frame len, 1024]
49
+
50
+ return feature.cpu().detach().numpy()
51
+
52
+
53
+ def mert_features_normalization(raw_mert_features):
54
+ normalized_mert_features = list()
55
+
56
+ mert_features = np.array(raw_mert_features)
57
+ scaler = StandardScaler().fit(mert_features)
58
+ for raw_mert_feature in raw_mert_feature:
59
+ normalized_mert_feature = scaler.transform(raw_mert_feature)
60
+ normalized_mert_features.append(normalized_mert_feature)
61
+ return normalized_mert_features
62
+
63
+
64
+ def get_mapped_mert_features(raw_mert_features, mapping_features, fast_mapping=True):
65
+ source_hop = 320
66
+ target_hop = 256
67
+
68
+ factor = np.gcd(source_hop, target_hop)
69
+ source_hop //= factor
70
+ target_hop //= factor
71
+ print(
72
+ "Mapping source's {} frames => target's {} frames".format(
73
+ target_hop, source_hop
74
+ )
75
+ )
76
+
77
+ mert_features = []
78
+ for index, mapping_feat in enumerate(tqdm(mapping_features)):
79
+ # mapping_feat: (mels_frame_len, n_mels)
80
+ target_len = mapping_feat.shape[0]
81
+
82
+ # (frame_len, 1024)
83
+ raw_feats = raw_mert_features[index].cpu().numpy()
84
+ source_len, width = raw_feats.shape
85
+
86
+ # const ~= target_len * target_hop
87
+ const = source_len * source_hop // target_hop * target_hop
88
+
89
+ # (source_len * source_hop, dim)
90
+ up_sampling_feats = np.repeat(raw_feats, source_hop, axis=0)
91
+ # (const, dim) -> (const/target_hop, target_hop, dim) -> (const/target_hop, dim)
92
+ down_sampling_feats = np.average(
93
+ up_sampling_feats[:const].reshape(-1, target_hop, width), axis=1
94
+ )
95
+
96
+ err = abs(target_len - len(down_sampling_feats))
97
+ if err > 3:
98
+ print("index:", index)
99
+ print("mels:", mapping_feat.shape)
100
+ print("raw mert vector:", raw_feats.shape)
101
+ print("up_sampling:", up_sampling_feats.shape)
102
+ print("const:", const)
103
+ print("down_sampling_feats:", down_sampling_feats.shape)
104
+ exit()
105
+ if len(down_sampling_feats) < target_len:
106
+ # (1, dim) -> (err, dim)
107
+ end = down_sampling_feats[-1][None, :].repeat(err, axis=0)
108
+ down_sampling_feats = np.concatenate([down_sampling_feats, end], axis=0)
109
+
110
+ # (target_len, dim)
111
+ feats = down_sampling_feats[:target_len]
112
+ mert_features.append(feats)
113
+
114
+ return mert_features
115
+
116
+
117
+ def load_mert_model(hps):
118
+ print("Loading MERT Model: ", hps.mert_model)
119
+
120
+ # Load model
121
+ model_name = hps.mert_model
122
+ model = AutoModel.from_pretrained(model_name, trust_remote_code=True)
123
+
124
+ if torch.cuda.is_available():
125
+ model = model.cuda()
126
+
127
+ # model = model.eval()
128
+
129
+ preprocessor = Wav2Vec2FeatureExtractor.from_pretrained(
130
+ model_name, trust_remote_code=True
131
+ )
132
+ return model, preprocessor
133
+
134
+
135
+ # loading the corresponding preprocessor config
136
+ # def load_preprocessor (model_name="m-a-p/MERT-v1-330M"):
137
+ # print('load_preprocessor...')
138
+ # preprocessor = Wav2Vec2FeatureExtractor.from_pretrained(model_name,trust_remote_code=True)
139
+ # return preprocessor
utils/mfa_prepare.py ADDED
@@ -0,0 +1,116 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023 Amphion.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ """ This code is modified from https://montreal-forced-aligner.readthedocs.io/en/latest/user_guide/performance.html"""
7
+
8
+ import os
9
+ import subprocess
10
+ from multiprocessing import Pool
11
+ from tqdm import tqdm
12
+ import torchaudio
13
+ from pathlib import Path
14
+
15
+
16
+ def remove_empty_dirs(path):
17
+ """remove empty directories in a given path"""
18
+ # Check if the given path is a directory
19
+ if not os.path.isdir(path):
20
+ print(f"{path} is not a directory")
21
+ return
22
+
23
+ # Walk through all directories and subdirectories
24
+ for root, dirs, _ in os.walk(path, topdown=False):
25
+ for dir in dirs:
26
+ dir_path = os.path.join(root, dir)
27
+ # Check if the directory is empty
28
+ if not os.listdir(dir_path):
29
+ os.rmdir(dir_path) # "Removed empty directory
30
+
31
+
32
+ def process_single_wav_file(task):
33
+ """process a single wav file"""
34
+ wav_file, output_dir = task
35
+ speaker_id, book_name, filename = Path(wav_file).parts[-3:]
36
+
37
+ output_book_dir = Path(output_dir, speaker_id)
38
+ output_book_dir.mkdir(parents=True, exist_ok=True)
39
+ new_filename = f"{speaker_id}_{book_name}_{filename}"
40
+
41
+ new_wav_file = Path(output_book_dir, new_filename)
42
+ command = [
43
+ "ffmpeg",
44
+ "-nostdin",
45
+ "-hide_banner",
46
+ "-loglevel",
47
+ "error",
48
+ "-nostats",
49
+ "-i",
50
+ wav_file,
51
+ "-acodec",
52
+ "pcm_s16le",
53
+ "-ar",
54
+ "16000",
55
+ new_wav_file,
56
+ ]
57
+ subprocess.check_call(
58
+ command
59
+ ) # Run the command to convert the file to 16kHz and 16-bit PCM
60
+ os.remove(wav_file)
61
+
62
+
63
+ def process_wav_files(wav_files, output_dir, n_process):
64
+ """process wav files in parallel"""
65
+ tasks = [(wav_file, output_dir) for wav_file in wav_files]
66
+ print(f"Processing {len(tasks)} files")
67
+ with Pool(processes=n_process) as pool:
68
+ for _ in tqdm(
69
+ pool.imap_unordered(process_single_wav_file, tasks), total=len(tasks)
70
+ ):
71
+ pass
72
+ print("Removing empty directories...")
73
+ remove_empty_dirs(output_dir)
74
+ print("Done!")
75
+
76
+
77
+ def get_wav_files(dataset_path):
78
+ """get all wav files in the dataset"""
79
+ wav_files = []
80
+ for speaker_id in os.listdir(dataset_path):
81
+ speaker_dir = os.path.join(dataset_path, speaker_id)
82
+ if not os.path.isdir(speaker_dir):
83
+ continue
84
+ for book_name in os.listdir(speaker_dir):
85
+ book_dir = os.path.join(speaker_dir, book_name)
86
+ if not os.path.isdir(book_dir):
87
+ continue
88
+ for file in os.listdir(book_dir):
89
+ if file.endswith(".wav"):
90
+ wav_files.append(os.path.join(book_dir, file))
91
+ print("Found {} wav files".format(len(wav_files)))
92
+ return wav_files
93
+
94
+
95
+ def filter_wav_files_by_length(wav_files, max_len_sec=15):
96
+ """filter wav files by length"""
97
+ print("original wav files: {}".format(len(wav_files)))
98
+ filtered_wav_files = []
99
+ for audio_file in wav_files:
100
+ metadata = torchaudio.info(str(audio_file))
101
+ audio_length = metadata.num_frames / metadata.sample_rate
102
+ if audio_length <= max_len_sec:
103
+ filtered_wav_files.append(audio_file)
104
+ else:
105
+ os.remove(audio_file)
106
+ print("filtered wav files: {}".format(len(filtered_wav_files)))
107
+ return filtered_wav_files
108
+
109
+
110
+ if __name__ == "__main__":
111
+ dataset_path = "/path/to/output/directory"
112
+ n_process = 16
113
+ max_len_sec = 15
114
+ wav_files = get_wav_files(dataset_path)
115
+ filtered_wav_files = filter_wav_files_by_length(wav_files, max_len_sec)
116
+ process_wav_files(filtered_wav_files, dataset_path, n_process)
utils/model_summary.py ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023 Amphion.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ import humanfriendly
7
+ import numpy as np
8
+ import torch
9
+
10
+
11
+ def get_human_readable_count(number: int) -> str:
12
+ """Return human_readable_count
13
+
14
+ Originated from:
15
+ https://github.com/PyTorchLightning/pytorch-lightning/blob/master/pytorch_lightning/core/memory.py
16
+
17
+ Abbreviates an integer number with K, M, B, T for thousands, millions,
18
+ billions and trillions, respectively.
19
+ Examples:
20
+ >>> get_human_readable_count(123)
21
+ '123 '
22
+ >>> get_human_readable_count(1234) # (one thousand)
23
+ '1 K'
24
+ >>> get_human_readable_count(2e6) # (two million)
25
+ '2 M'
26
+ >>> get_human_readable_count(3e9) # (three billion)
27
+ '3 B'
28
+ >>> get_human_readable_count(4e12) # (four trillion)
29
+ '4 T'
30
+ >>> get_human_readable_count(5e15) # (more than trillion)
31
+ '5,000 T'
32
+ Args:
33
+ number: a positive integer number
34
+ Return:
35
+ A string formatted according to the pattern described above.
36
+ """
37
+ assert number >= 0
38
+ labels = [" ", "K", "M", "B", "T"]
39
+ num_digits = int(np.floor(np.log10(number)) + 1 if number > 0 else 1)
40
+ num_groups = int(np.ceil(num_digits / 3))
41
+ num_groups = min(num_groups, len(labels))
42
+ shift = -3 * (num_groups - 1)
43
+ number = number * (10**shift)
44
+ index = num_groups - 1
45
+ return f"{number:.2f} {labels[index]}"
46
+
47
+
48
+ def to_bytes(dtype) -> int:
49
+ return int(str(dtype)[-2:]) // 8
50
+
51
+
52
+ def model_summary(model: torch.nn.Module) -> str:
53
+ message = "Model structure:\n"
54
+ message += str(model)
55
+ tot_params = sum(p.numel() for p in model.parameters())
56
+ num_params = sum(p.numel() for p in model.parameters() if p.requires_grad)
57
+ percent_trainable = "{:.1f}".format(num_params * 100.0 / tot_params)
58
+ tot_params = get_human_readable_count(tot_params)
59
+ num_params = get_human_readable_count(num_params)
60
+ message += "\n\nModel summary:\n"
61
+ message += f" Class Name: {model.__class__.__name__}\n"
62
+ message += f" Total Number of model parameters: {tot_params}\n"
63
+ message += (
64
+ f" Number of trainable parameters: {num_params} ({percent_trainable}%)\n"
65
+ )
66
+ num_bytes = humanfriendly.format_size(
67
+ sum(
68
+ p.numel() * to_bytes(p.dtype) for p in model.parameters() if p.requires_grad
69
+ )
70
+ )
71
+ message += f" Size: {num_bytes}\n"
72
+ dtype = next(iter(model.parameters())).dtype
73
+ message += f" Type: {dtype}"
74
+ return message
utils/prompt_preparer.py ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023 Amphion.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ import torch
7
+
8
+
9
+ class PromptPreparer:
10
+ def prepare_prompts(self, y, y_lens, codes, nar_stage, y_prompts_codes):
11
+ if self.prefix_mode == 0:
12
+ y_emb, prefix_len = self._handle_prefix_mode_0(y, codes, nar_stage)
13
+ elif self.prefix_mode == 1:
14
+ y_emb, prefix_len = self._handle_prefix_mode_1(y, y_lens, codes, nar_stage)
15
+ elif self.prefix_mode in [2, 4]:
16
+ y_emb, prefix_len = self._handle_prefix_mode_2_4(
17
+ y, y_lens, codes, nar_stage, y_prompts_codes
18
+ )
19
+ else:
20
+ raise ValueError("Invalid prefix mode")
21
+
22
+ return y_emb, prefix_len
23
+
24
+ def _handle_prefix_mode_0(self, y, codes, nar_stage):
25
+ prefix_len = 0
26
+ y_emb = self.nar_audio_embeddings[0](y)
27
+ for j in range(1, nar_stage):
28
+ y_emb = y_emb + self.nar_audio_embeddings[j](codes[..., j])
29
+ return y_emb, 0
30
+
31
+ def _handle_prefix_mode_1(self, y, y_lens, codes, nar_stage):
32
+ int_low = (0.25 * y_lens.min()).type(torch.int64).item()
33
+ prefix_len = torch.randint(int_low, int_low * 2, size=()).item()
34
+ prefix_len = min(prefix_len, 225)
35
+
36
+ y_prompts = self.nar_audio_embeddings[0](y[:, :prefix_len])
37
+ y_emb = self.nar_audio_embeddings[0](y[:, prefix_len:])
38
+ for j in range(1, self.num_quantizers):
39
+ y_prompts += self.nar_audio_embeddings[j](codes[:, :prefix_len, j])
40
+ if j < nar_stage:
41
+ y_emb += self.nar_audio_embeddings[j](codes[:, prefix_len:, j])
42
+ y_emb = torch.concat([y_prompts, y_emb], axis=1)
43
+ return y_emb, prefix_len
44
+
45
+ def _handle_prefix_mode_2_4(self, y, y_lens, codes, nar_stage, y_prompts_codes):
46
+ if self.prefix_mode == 2:
47
+ prefix_len = min(225, int(0.25 * y_lens.min().item()))
48
+
49
+ y_prompts_codes = []
50
+ for b in range(codes.shape[0]):
51
+ start = self.rng.randint(0, y_lens[b].item() - prefix_len)
52
+ y_prompts_codes.append(
53
+ torch.clone(codes[b, start : start + prefix_len])
54
+ )
55
+ codes[b, start : start + prefix_len, nar_stage] = self.audio_token_num
56
+ y_prompts_codes = torch.stack(y_prompts_codes, dim=0)
57
+ else:
58
+ prefix_len = y_prompts_codes.shape[1]
59
+
60
+ y_prompts = self.nar_audio_embeddings[0](y_prompts_codes[..., 0])
61
+ y_emb = self.nar_audio_embeddings[0](y)
62
+ for j in range(1, self.num_quantizers):
63
+ y_prompts += self.nar_audio_embeddings[j](y_prompts_codes[..., j])
64
+ if j < nar_stage:
65
+ y_emb += self.nar_audio_embeddings[j](codes[..., j])
66
+ y_emb = torch.concat([y_prompts, y_emb], axis=1)
67
+
68
+ return y_emb, prefix_len
utils/ssim.py ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023 Amphion.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ # This code is modified from https://github.com/Po-Hsun-Su/pytorch-ssim
7
+
8
+ import torch
9
+ import torch.nn.functional as F
10
+ from torch.autograd import Variable
11
+ from math import exp
12
+
13
+
14
+ def gaussian(window_size, sigma):
15
+ gauss = torch.Tensor(
16
+ [
17
+ exp(-((x - window_size // 2) ** 2) / float(2 * sigma**2))
18
+ for x in range(window_size)
19
+ ]
20
+ )
21
+ return gauss / gauss.sum()
22
+
23
+
24
+ def create_window(window_size, channel):
25
+ _1D_window = gaussian(window_size, 1.5).unsqueeze(1)
26
+ _2D_window = _1D_window.mm(_1D_window.t()).float().unsqueeze(0).unsqueeze(0)
27
+ window = Variable(
28
+ _2D_window.expand(channel, 1, window_size, window_size).contiguous()
29
+ )
30
+ return window
31
+
32
+
33
+ def _ssim(img1, img2, window, window_size, channel, size_average=True):
34
+ mu1 = F.conv2d(img1, window, padding=window_size // 2, groups=channel)
35
+ mu2 = F.conv2d(img2, window, padding=window_size // 2, groups=channel)
36
+
37
+ mu1_sq = mu1.pow(2)
38
+ mu2_sq = mu2.pow(2)
39
+ mu1_mu2 = mu1 * mu2
40
+
41
+ sigma1_sq = (
42
+ F.conv2d(img1 * img1, window, padding=window_size // 2, groups=channel) - mu1_sq
43
+ )
44
+ sigma2_sq = (
45
+ F.conv2d(img2 * img2, window, padding=window_size // 2, groups=channel) - mu2_sq
46
+ )
47
+ sigma12 = (
48
+ F.conv2d(img1 * img2, window, padding=window_size // 2, groups=channel)
49
+ - mu1_mu2
50
+ )
51
+
52
+ C1 = 0.01**2
53
+ C2 = 0.03**2
54
+
55
+ ssim_map = ((2 * mu1_mu2 + C1) * (2 * sigma12 + C2)) / (
56
+ (mu1_sq + mu2_sq + C1) * (sigma1_sq + sigma2_sq + C2)
57
+ )
58
+
59
+ if size_average:
60
+ return ssim_map.mean()
61
+ else:
62
+ return ssim_map.mean(1)
63
+
64
+
65
+ class SSIM(torch.nn.Module):
66
+ def __init__(self, window_size=11, size_average=True):
67
+ super(SSIM, self).__init__()
68
+ self.window_size = window_size
69
+ self.size_average = size_average
70
+ self.channel = 1
71
+ self.window = create_window(window_size, self.channel)
72
+
73
+ def forward(self, fake, real, bias=6.0):
74
+ fake = fake[:, None, :, :] + bias # [B, 1, T, n_mels]
75
+ real = real[:, None, :, :] + bias # [B, 1, T, n_mels]
76
+ self.window = self.window.to(dtype=fake.dtype, device=fake.device)
77
+ loss = 1 - _ssim(
78
+ fake, real, self.window, self.window_size, self.channel, self.size_average
79
+ )
80
+ return loss
utils/stft.py ADDED
@@ -0,0 +1,278 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023 Amphion.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ import torch
7
+ import torch.nn.functional as F
8
+ import numpy as np
9
+ from scipy.signal import get_window
10
+ from librosa.util import pad_center, tiny
11
+ from librosa.filters import mel as librosa_mel_fn
12
+
13
+ import torch
14
+ import numpy as np
15
+ import librosa.util as librosa_util
16
+ from scipy.signal import get_window
17
+
18
+
19
+ def window_sumsquare(
20
+ window,
21
+ n_frames,
22
+ hop_length,
23
+ win_length,
24
+ n_fft,
25
+ dtype=np.float32,
26
+ norm=None,
27
+ ):
28
+ """
29
+ # from librosa 0.6
30
+ Compute the sum-square envelope of a window function at a given hop length.
31
+
32
+ This is used to estimate modulation effects induced by windowing
33
+ observations in short-time fourier transforms.
34
+
35
+ Parameters
36
+ ----------
37
+ window : string, tuple, number, callable, or list-like
38
+ Window specification, as in `get_window`
39
+
40
+ n_frames : int > 0
41
+ The number of analysis frames
42
+
43
+ hop_length : int > 0
44
+ The number of samples to advance between frames
45
+
46
+ win_length : [optional]
47
+ The length of the window function. By default, this matches `n_fft`.
48
+
49
+ n_fft : int > 0
50
+ The length of each analysis frame.
51
+
52
+ dtype : np.dtype
53
+ The data type of the output
54
+
55
+ Returns
56
+ -------
57
+ wss : np.ndarray, shape=`(n_fft + hop_length * (n_frames - 1))`
58
+ The sum-squared envelope of the window function
59
+ """
60
+ if win_length is None:
61
+ win_length = n_fft
62
+
63
+ n = n_fft + hop_length * (n_frames - 1)
64
+ x = np.zeros(n, dtype=dtype)
65
+
66
+ # Compute the squared window at the desired length
67
+ win_sq = get_window(window, win_length, fftbins=True)
68
+ win_sq = librosa_util.normalize(win_sq, norm=norm) ** 2
69
+ win_sq = librosa_util.pad_center(win_sq, n_fft)
70
+
71
+ # Fill the envelope
72
+ for i in range(n_frames):
73
+ sample = i * hop_length
74
+ x[sample : min(n, sample + n_fft)] += win_sq[: max(0, min(n_fft, n - sample))]
75
+ return x
76
+
77
+
78
+ def griffin_lim(magnitudes, stft_fn, n_iters=30):
79
+ """
80
+ PARAMS
81
+ ------
82
+ magnitudes: spectrogram magnitudes
83
+ stft_fn: STFT class with transform (STFT) and inverse (ISTFT) methods
84
+ """
85
+
86
+ angles = np.angle(np.exp(2j * np.pi * np.random.rand(*magnitudes.size())))
87
+ angles = angles.astype(np.float32)
88
+ angles = torch.autograd.Variable(torch.from_numpy(angles))
89
+ signal = stft_fn.inverse(magnitudes, angles).squeeze(1)
90
+
91
+ for i in range(n_iters):
92
+ _, angles = stft_fn.transform(signal)
93
+ signal = stft_fn.inverse(magnitudes, angles).squeeze(1)
94
+ return signal
95
+
96
+
97
+ def dynamic_range_compression(x, C=1, clip_val=1e-5):
98
+ """
99
+ PARAMS
100
+ ------
101
+ C: compression factor
102
+ """
103
+ return torch.log(torch.clamp(x, min=clip_val) * C)
104
+
105
+
106
+ def dynamic_range_decompression(x, C=1):
107
+ """
108
+ PARAMS
109
+ ------
110
+ C: compression factor used to compress
111
+ """
112
+ return torch.exp(x) / C
113
+
114
+
115
+ class STFT(torch.nn.Module):
116
+ """adapted from Prem Seetharaman's https://github.com/pseeth/pytorch-stft"""
117
+
118
+ def __init__(self, filter_length, hop_length, win_length, window="hann"):
119
+ super(STFT, self).__init__()
120
+ self.filter_length = filter_length
121
+ self.hop_length = hop_length
122
+ self.win_length = win_length
123
+ self.window = window
124
+ self.forward_transform = None
125
+ scale = self.filter_length / self.hop_length
126
+ fourier_basis = np.fft.fft(np.eye(self.filter_length))
127
+
128
+ cutoff = int((self.filter_length / 2 + 1))
129
+ fourier_basis = np.vstack(
130
+ [np.real(fourier_basis[:cutoff, :]), np.imag(fourier_basis[:cutoff, :])]
131
+ )
132
+
133
+ forward_basis = torch.FloatTensor(fourier_basis[:, None, :])
134
+ inverse_basis = torch.FloatTensor(
135
+ np.linalg.pinv(scale * fourier_basis).T[:, None, :]
136
+ )
137
+
138
+ if window is not None:
139
+ assert filter_length >= win_length
140
+ # get window and zero center pad it to filter_length
141
+ fft_window = get_window(window, win_length, fftbins=True)
142
+ fft_window = pad_center(fft_window, filter_length)
143
+ fft_window = torch.from_numpy(fft_window).float()
144
+
145
+ # window the bases
146
+ forward_basis *= fft_window
147
+ inverse_basis *= fft_window
148
+
149
+ self.register_buffer("forward_basis", forward_basis.float())
150
+ self.register_buffer("inverse_basis", inverse_basis.float())
151
+
152
+ def transform(self, input_data):
153
+ num_batches = input_data.size(0)
154
+ num_samples = input_data.size(1)
155
+
156
+ self.num_samples = num_samples
157
+
158
+ # similar to librosa, reflect-pad the input
159
+ input_data = input_data.view(num_batches, 1, num_samples)
160
+ input_data = F.pad(
161
+ input_data.unsqueeze(1),
162
+ (int(self.filter_length / 2), int(self.filter_length / 2), 0, 0),
163
+ mode="reflect",
164
+ )
165
+ input_data = input_data.squeeze(1)
166
+
167
+ forward_transform = F.conv1d(
168
+ input_data.cuda(),
169
+ torch.autograd.Variable(self.forward_basis, requires_grad=False).cuda(),
170
+ stride=self.hop_length,
171
+ padding=0,
172
+ ).cpu()
173
+
174
+ cutoff = int((self.filter_length / 2) + 1)
175
+ real_part = forward_transform[:, :cutoff, :]
176
+ imag_part = forward_transform[:, cutoff:, :]
177
+
178
+ magnitude = torch.sqrt(real_part**2 + imag_part**2)
179
+ phase = torch.autograd.Variable(torch.atan2(imag_part.data, real_part.data))
180
+
181
+ return magnitude, phase
182
+
183
+ def inverse(self, magnitude, phase):
184
+ recombine_magnitude_phase = torch.cat(
185
+ [magnitude * torch.cos(phase), magnitude * torch.sin(phase)], dim=1
186
+ )
187
+
188
+ inverse_transform = F.conv_transpose1d(
189
+ recombine_magnitude_phase,
190
+ torch.autograd.Variable(self.inverse_basis, requires_grad=False),
191
+ stride=self.hop_length,
192
+ padding=0,
193
+ )
194
+
195
+ if self.window is not None:
196
+ window_sum = window_sumsquare(
197
+ self.window,
198
+ magnitude.size(-1),
199
+ hop_length=self.hop_length,
200
+ win_length=self.win_length,
201
+ n_fft=self.filter_length,
202
+ dtype=np.float32,
203
+ )
204
+ # remove modulation effects
205
+ approx_nonzero_indices = torch.from_numpy(
206
+ np.where(window_sum > tiny(window_sum))[0]
207
+ )
208
+ window_sum = torch.autograd.Variable(
209
+ torch.from_numpy(window_sum), requires_grad=False
210
+ )
211
+ window_sum = window_sum.cuda() if magnitude.is_cuda else window_sum
212
+ inverse_transform[:, :, approx_nonzero_indices] /= window_sum[
213
+ approx_nonzero_indices
214
+ ]
215
+
216
+ # scale by hop ratio
217
+ inverse_transform *= float(self.filter_length) / self.hop_length
218
+
219
+ inverse_transform = inverse_transform[:, :, int(self.filter_length / 2) :]
220
+ inverse_transform = inverse_transform[:, :, : -int(self.filter_length / 2) :]
221
+
222
+ return inverse_transform
223
+
224
+ def forward(self, input_data):
225
+ self.magnitude, self.phase = self.transform(input_data)
226
+ reconstruction = self.inverse(self.magnitude, self.phase)
227
+ return reconstruction
228
+
229
+
230
+ class TacotronSTFT(torch.nn.Module):
231
+ def __init__(
232
+ self,
233
+ filter_length,
234
+ hop_length,
235
+ win_length,
236
+ n_mel_channels,
237
+ sampling_rate,
238
+ mel_fmin,
239
+ mel_fmax,
240
+ ):
241
+ super(TacotronSTFT, self).__init__()
242
+ self.n_mel_channels = n_mel_channels
243
+ self.sampling_rate = sampling_rate
244
+ self.stft_fn = STFT(filter_length, hop_length, win_length)
245
+ mel_basis = librosa_mel_fn(
246
+ sampling_rate, filter_length, n_mel_channels, mel_fmin, mel_fmax
247
+ )
248
+ mel_basis = torch.from_numpy(mel_basis).float()
249
+ self.register_buffer("mel_basis", mel_basis)
250
+
251
+ def spectral_normalize(self, magnitudes):
252
+ output = dynamic_range_compression(magnitudes)
253
+ return output
254
+
255
+ def spectral_de_normalize(self, magnitudes):
256
+ output = dynamic_range_decompression(magnitudes)
257
+ return output
258
+
259
+ def mel_spectrogram(self, y):
260
+ """Computes mel-spectrograms from a batch of waves
261
+ PARAMS
262
+ ------
263
+ y: Variable(torch.FloatTensor) with shape (B, T) in range [-1, 1]
264
+
265
+ RETURNS
266
+ -------
267
+ mel_output: torch.FloatTensor of shape (B, n_mel_channels, T)
268
+ """
269
+ assert torch.min(y.data) >= -1
270
+ assert torch.max(y.data) <= 1
271
+
272
+ magnitudes, phases = self.stft_fn.transform(y)
273
+ magnitudes = magnitudes.data
274
+ mel_output = torch.matmul(self.mel_basis, magnitudes)
275
+ mel_output = self.spectral_normalize(mel_output)
276
+ energy = torch.norm(magnitudes, dim=1)
277
+
278
+ return mel_output, energy
utils/symbol_table.py ADDED
@@ -0,0 +1,317 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023 Amphion.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ # This code is modified from
7
+ # https://github.com/lifeiteng/vall-e/blob/9c69096d603ce13174fb5cb025f185e2e9b36ac7/valle/utils/symbol_table.py
8
+
9
+ from dataclasses import dataclass
10
+ from dataclasses import field
11
+ from typing import Dict
12
+ from typing import Generic
13
+ from typing import List
14
+ from typing import Optional
15
+ from typing import TypeVar
16
+ from typing import Union
17
+
18
+ Symbol = TypeVar("Symbol")
19
+
20
+
21
+ @dataclass(repr=False)
22
+ class SymbolTable(Generic[Symbol]):
23
+ """SymbolTable that maps symbol IDs, found on the FSA arcs to
24
+ actual objects. These objects can be arbitrary Python objects
25
+ that can serve as keys in a dictionary (i.e. they need to be
26
+ hashable and immutable).
27
+
28
+ The SymbolTable can only be read to/written from disk if the
29
+ symbols are strings.
30
+ """
31
+
32
+ _id2sym: Dict[int, Symbol] = field(default_factory=dict)
33
+ """Map an integer to a symbol.
34
+ """
35
+
36
+ _sym2id: Dict[Symbol, int] = field(default_factory=dict)
37
+ """Map a symbol to an integer.
38
+ """
39
+
40
+ _next_available_id: int = 1
41
+ """A helper internal field that helps adding new symbols
42
+ to the table efficiently.
43
+ """
44
+
45
+ eps: Symbol = "<eps>"
46
+ """Null symbol, always mapped to index 0.
47
+ """
48
+
49
+ def __post_init__(self):
50
+ assert all(self._sym2id[sym] == idx for idx, sym in self._id2sym.items())
51
+ assert all(self._id2sym[idx] == sym for sym, idx in self._sym2id.items())
52
+ assert 0 not in self._id2sym or self._id2sym[0] == self.eps
53
+
54
+ self._next_available_id = max(self._id2sym, default=0) + 1
55
+ self._id2sym.setdefault(0, self.eps)
56
+ self._sym2id.setdefault(self.eps, 0)
57
+
58
+ @staticmethod
59
+ def from_str(s: str) -> "SymbolTable":
60
+ """Build a symbol table from a string.
61
+
62
+ The string consists of lines. Every line has two fields separated
63
+ by space(s), tab(s) or both. The first field is the symbol and the
64
+ second the integer id of the symbol.
65
+
66
+ Args:
67
+ s:
68
+ The input string with the format described above.
69
+ Returns:
70
+ An instance of :class:`SymbolTable`.
71
+ """
72
+ id2sym: Dict[int, str] = dict()
73
+ sym2id: Dict[str, int] = dict()
74
+
75
+ for line in s.split("\n"):
76
+ fields = line.split()
77
+ if len(fields) == 0:
78
+ continue # skip empty lines
79
+ assert (
80
+ len(fields) == 2
81
+ ), f"Expect a line with 2 fields. Given: {len(fields)}"
82
+ sym, idx = fields[0], int(fields[1])
83
+ assert sym not in sym2id, f"Duplicated symbol {sym}"
84
+ assert idx not in id2sym, f"Duplicated id {idx}"
85
+ id2sym[idx] = sym
86
+ sym2id[sym] = idx
87
+
88
+ eps = id2sym.get(0, "<eps>")
89
+
90
+ return SymbolTable(_id2sym=id2sym, _sym2id=sym2id, eps=eps)
91
+
92
+ @staticmethod
93
+ def from_file(filename: str) -> "SymbolTable":
94
+ """Build a symbol table from file.
95
+
96
+ Every line in the symbol table file has two fields separated by
97
+ space(s), tab(s) or both. The following is an example file:
98
+
99
+ .. code-block::
100
+
101
+ <eps> 0
102
+ a 1
103
+ b 2
104
+ c 3
105
+
106
+ Args:
107
+ filename:
108
+ Name of the symbol table file. Its format is documented above.
109
+
110
+ Returns:
111
+ An instance of :class:`SymbolTable`.
112
+
113
+ """
114
+ with open(filename, "r", encoding="utf-8") as f:
115
+ return SymbolTable.from_str(f.read().strip())
116
+
117
+ def to_str(self) -> str:
118
+ """
119
+ Returns:
120
+ Return a string representation of this object. You can pass
121
+ it to the method ``from_str`` to recreate an identical object.
122
+ """
123
+ s = ""
124
+ for idx, symbol in sorted(self._id2sym.items()):
125
+ s += f"{symbol} {idx}\n"
126
+ return s
127
+
128
+ def to_file(self, filename: str):
129
+ """Serialize the SymbolTable to a file.
130
+
131
+ Every line in the symbol table file has two fields separated by
132
+ space(s), tab(s) or both. The following is an example file:
133
+
134
+ .. code-block::
135
+
136
+ <eps> 0
137
+ a 1
138
+ b 2
139
+ c 3
140
+
141
+ Args:
142
+ filename:
143
+ Name of the symbol table file. Its format is documented above.
144
+ """
145
+ with open(filename, "w") as f:
146
+ for idx, symbol in sorted(self._id2sym.items()):
147
+ print(symbol, idx, file=f)
148
+
149
+ def add(self, symbol: Symbol, index: Optional[int] = None) -> int:
150
+ """Add a new symbol to the SymbolTable.
151
+
152
+ Args:
153
+ symbol:
154
+ The symbol to be added.
155
+ index:
156
+ Optional int id to which the symbol should be assigned.
157
+ If it is not available, a ValueError will be raised.
158
+
159
+ Returns:
160
+ The int id to which the symbol has been assigned.
161
+ """
162
+ # Already in the table? Return its ID.
163
+ if symbol in self._sym2id:
164
+ return self._sym2id[symbol]
165
+ # Specific ID not provided - use next available.
166
+ if index is None:
167
+ index = self._next_available_id
168
+ # Specific ID provided but not available.
169
+ if index in self._id2sym:
170
+ raise ValueError(
171
+ f"Cannot assign id '{index}' to '{symbol}' - "
172
+ f"already occupied by {self._id2sym[index]}"
173
+ )
174
+ self._sym2id[symbol] = index
175
+ self._id2sym[index] = symbol
176
+
177
+ # Update next available ID if needed
178
+ if self._next_available_id <= index:
179
+ self._next_available_id = index + 1
180
+
181
+ return index
182
+
183
+ def get(self, k: Union[int, Symbol]) -> Union[Symbol, int]:
184
+ """Get a symbol for an id or get an id for a symbol
185
+
186
+ Args:
187
+ k:
188
+ If it is an id, it tries to find the symbol corresponding
189
+ to the id; if it is a symbol, it tries to find the id
190
+ corresponding to the symbol.
191
+
192
+ Returns:
193
+ An id or a symbol depending on the given `k`.
194
+ """
195
+ if isinstance(k, int):
196
+ return self._id2sym[k]
197
+ else:
198
+ return self._sym2id[k]
199
+
200
+ def merge(self, other: "SymbolTable") -> "SymbolTable":
201
+ """Create a union of two SymbolTables.
202
+ Raises an AssertionError if the same IDs are occupied by
203
+ different symbols.
204
+
205
+ Args:
206
+ other:
207
+ A symbol table to merge with ``self``.
208
+
209
+ Returns:
210
+ A new symbol table.
211
+ """
212
+ self._check_compatible(other)
213
+ return SymbolTable(
214
+ _id2sym={**self._id2sym, **other._id2sym},
215
+ _sym2id={**self._sym2id, **other._sym2id},
216
+ eps=self.eps,
217
+ )
218
+
219
+ def _check_compatible(self, other: "SymbolTable") -> None:
220
+ # Epsilon compatibility
221
+ assert self.eps == other.eps, (
222
+ f"Mismatched epsilon symbol: " f"{self.eps} != {other.eps}"
223
+ )
224
+ # IDs compatibility
225
+ common_ids = set(self._id2sym).intersection(other._id2sym)
226
+ for idx in common_ids:
227
+ assert self[idx] == other[idx], (
228
+ f"ID conflict for id: {idx}, "
229
+ f'self[idx] = "{self[idx]}", '
230
+ f'other[idx] = "{other[idx]}"'
231
+ )
232
+ # Symbols compatibility
233
+ common_symbols = set(self._sym2id).intersection(other._sym2id)
234
+ for sym in common_symbols:
235
+ assert self[sym] == other[sym], (
236
+ f"ID conflict for id: {sym}, "
237
+ f'self[sym] = "{self[sym]}", '
238
+ f'other[sym] = "{other[sym]}"'
239
+ )
240
+
241
+ def __getitem__(self, item: Union[int, Symbol]) -> Union[Symbol, int]:
242
+ return self.get(item)
243
+
244
+ def __contains__(self, item: Union[int, Symbol]) -> bool:
245
+ if isinstance(item, int):
246
+ return item in self._id2sym
247
+ else:
248
+ return item in self._sym2id
249
+
250
+ def __len__(self) -> int:
251
+ return len(self._id2sym)
252
+
253
+ def __eq__(self, other: "SymbolTable") -> bool:
254
+ if len(self) != len(other):
255
+ return False
256
+
257
+ for s in self.symbols:
258
+ if self[s] != other[s]:
259
+ return False
260
+
261
+ return True
262
+
263
+ @property
264
+ def ids(self) -> List[int]:
265
+ """Returns a list of integer IDs corresponding to the symbols."""
266
+ ans = list(self._id2sym.keys())
267
+ ans.sort()
268
+ return ans
269
+
270
+ @property
271
+ def symbols(self) -> List[Symbol]:
272
+ """Returns a list of symbols (e.g., strings) corresponding to
273
+ the integer IDs.
274
+ """
275
+ ans = list(self._sym2id.keys())
276
+ ans.sort()
277
+ return ans
278
+
279
+
280
+ class TextToken:
281
+ def __init__(
282
+ self,
283
+ text_tokens: List[str],
284
+ add_eos: bool = True,
285
+ add_bos: bool = True,
286
+ pad_symbol: str = "<pad>",
287
+ bos_symbol: str = "<bos>",
288
+ eos_symbol: str = "<eos>",
289
+ ):
290
+ self.pad_symbol = pad_symbol
291
+ self.add_eos = add_eos
292
+ self.add_bos = add_bos
293
+ self.bos_symbol = bos_symbol
294
+ self.eos_symbol = eos_symbol
295
+
296
+ unique_tokens = [pad_symbol]
297
+ if add_bos:
298
+ unique_tokens.append(bos_symbol)
299
+ if add_eos:
300
+ unique_tokens.append(eos_symbol)
301
+ unique_tokens.extend(sorted(text_tokens))
302
+
303
+ self.token2idx = {token: idx for idx, token in enumerate(unique_tokens)}
304
+ self.idx2token = unique_tokens
305
+
306
+ def get_token_id_seq(self, text):
307
+ tokens_seq = [p for p in text]
308
+ seq = (
309
+ ([self.bos_symbol] if self.add_bos else [])
310
+ + tokens_seq
311
+ + ([self.eos_symbol] if self.add_eos else [])
312
+ )
313
+
314
+ token_ids = [self.token2idx[token] for token in seq]
315
+ token_lens = len(tokens_seq) + self.add_eos + self.add_bos
316
+
317
+ return token_ids, token_lens
utils/tokenizer.py ADDED
@@ -0,0 +1,150 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023 Amphion.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ # This code is modified from
7
+ # https://github.com/lifeiteng/vall-e/blob/9c69096d603ce13174fb5cb025f185e2e9b36ac7/valle/data/tokenizer.py
8
+
9
+ import re
10
+ from typing import Any, Dict, List, Optional, Pattern, Union
11
+
12
+ import torch
13
+ import torchaudio
14
+ from encodec import EncodecModel
15
+ from encodec.utils import convert_audio
16
+
17
+
18
+ class AudioTokenizer:
19
+ """EnCodec audio tokenizer for encoding and decoding audio.
20
+
21
+ Attributes:
22
+ device: The device on which the codec model is loaded.
23
+ codec: The pretrained EnCodec model.
24
+ sample_rate: Sample rate of the model.
25
+ channels: Number of audio channels in the model.
26
+ """
27
+
28
+ def __init__(self, device: Any = None) -> None:
29
+ model = EncodecModel.encodec_model_24khz()
30
+ model.set_target_bandwidth(6.0)
31
+ remove_encodec_weight_norm(model)
32
+
33
+ if not device:
34
+ device = torch.device("cpu")
35
+ if torch.cuda.is_available():
36
+ device = torch.device("cuda:0")
37
+
38
+ self._device = device
39
+
40
+ self.codec = model.to(device)
41
+ self.sample_rate = model.sample_rate
42
+ self.channels = model.channels
43
+
44
+ @property
45
+ def device(self):
46
+ return self._device
47
+
48
+ def encode(self, wav: torch.Tensor) -> torch.Tensor:
49
+ """Encode the audio waveform.
50
+
51
+ Args:
52
+ wav: A tensor representing the audio waveform.
53
+
54
+ Returns:
55
+ A tensor representing the encoded audio.
56
+ """
57
+ return self.codec.encode(wav.to(self.device))
58
+
59
+ def decode(self, frames: torch.Tensor) -> torch.Tensor:
60
+ """Decode the encoded audio frames.
61
+
62
+ Args:
63
+ frames: A tensor representing the encoded audio frames.
64
+
65
+ Returns:
66
+ A tensor representing the decoded audio waveform.
67
+ """
68
+ return self.codec.decode(frames)
69
+
70
+
71
+ def tokenize_audio(tokenizer: AudioTokenizer, audio_path: str):
72
+ """
73
+ Tokenize the audio waveform using the given AudioTokenizer.
74
+
75
+ Args:
76
+ tokenizer: An instance of AudioTokenizer.
77
+ audio_path: Path to the audio file.
78
+
79
+ Returns:
80
+ A tensor of encoded frames from the audio.
81
+
82
+ Raises:
83
+ FileNotFoundError: If the audio file is not found.
84
+ RuntimeError: If there's an error processing the audio data.
85
+ """
86
+ # try:
87
+ # Load and preprocess the audio waveform
88
+ wav, sr = torchaudio.load(audio_path)
89
+ wav = convert_audio(wav, sr, tokenizer.sample_rate, tokenizer.channels)
90
+ wav = wav.unsqueeze(0)
91
+
92
+ # Extract discrete codes from EnCodec
93
+ with torch.no_grad():
94
+ encoded_frames = tokenizer.encode(wav)
95
+ return encoded_frames
96
+
97
+ # except FileNotFoundError:
98
+ # raise FileNotFoundError(f"Audio file not found at {audio_path}")
99
+ # except Exception as e:
100
+ # raise RuntimeError(f"Error processing audio data: {e}")
101
+
102
+
103
+ def remove_encodec_weight_norm(model):
104
+ from encodec.modules import SConv1d
105
+ from encodec.modules.seanet import SConvTranspose1d, SEANetResnetBlock
106
+ from torch.nn.utils import remove_weight_norm
107
+
108
+ encoder = model.encoder.model
109
+ for key in encoder._modules:
110
+ if isinstance(encoder._modules[key], SEANetResnetBlock):
111
+ remove_weight_norm(encoder._modules[key].shortcut.conv.conv)
112
+ block_modules = encoder._modules[key].block._modules
113
+ for skey in block_modules:
114
+ if isinstance(block_modules[skey], SConv1d):
115
+ remove_weight_norm(block_modules[skey].conv.conv)
116
+ elif isinstance(encoder._modules[key], SConv1d):
117
+ remove_weight_norm(encoder._modules[key].conv.conv)
118
+
119
+ decoder = model.decoder.model
120
+ for key in decoder._modules:
121
+ if isinstance(decoder._modules[key], SEANetResnetBlock):
122
+ remove_weight_norm(decoder._modules[key].shortcut.conv.conv)
123
+ block_modules = decoder._modules[key].block._modules
124
+ for skey in block_modules:
125
+ if isinstance(block_modules[skey], SConv1d):
126
+ remove_weight_norm(block_modules[skey].conv.conv)
127
+ elif isinstance(decoder._modules[key], SConvTranspose1d):
128
+ remove_weight_norm(decoder._modules[key].convtr.convtr)
129
+ elif isinstance(decoder._modules[key], SConv1d):
130
+ remove_weight_norm(decoder._modules[key].conv.conv)
131
+
132
+
133
+ def extract_encodec_token(wav_path):
134
+ model = EncodecModel.encodec_model_24khz()
135
+ model.set_target_bandwidth(6.0)
136
+
137
+ wav, sr = torchaudio.load(wav_path)
138
+ wav = convert_audio(wav, sr, model.sample_rate, model.channels)
139
+ wav = wav.unsqueeze(0)
140
+ if torch.cuda.is_available():
141
+ model = model.cuda()
142
+ wav = wav.cuda()
143
+ with torch.no_grad():
144
+ encoded_frames = model.encode(wav)
145
+ codes_ = torch.cat(
146
+ [encoded[0] for encoded in encoded_frames], dim=-1
147
+ ) # [B, n_q, T]
148
+ codes = codes_.cpu().numpy()[0, :, :].T # [T, 8]
149
+
150
+ return codes
utils/topk_sampling.py ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023 Amphion.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+
7
+ import torch
8
+ import torch.nn.functional as F
9
+
10
+
11
+ # This function is modified from https://github.com/microsoft/unilm/blob/master/xtune/src/transformers/modeling_utils.py
12
+ def top_k_top_p_filtering(
13
+ logits, top_k=0, top_p=1.0, filter_value=-float("Inf"), min_tokens_to_keep=1
14
+ ):
15
+ """
16
+ Filter a distribution of logits using top-k and/or nucleus (top-p) filtering.
17
+
18
+ Args:
19
+ logits (torch.Tensor): Logits distribution with shape (batch size, vocabulary size).
20
+ top_k (int, optional): Keep only top k tokens with highest probability (top-k filtering).
21
+ Set to 0 to disable. Defaults to 0.
22
+ top_p (float, optional): Keep the top tokens with a cumulative probability >= top_p (nucleus filtering).
23
+ Must be between 0 and 1, inclusive. Defaults to 1.0.
24
+ filter_value (float, optional): The value to assign to filtered logits. Defaults to -float('Inf').
25
+ min_tokens_to_keep (int, optional): Ensure that at least this number of tokens are kept per batch example.
26
+ Defaults to 1.
27
+
28
+ Returns:
29
+ torch.Tensor: The filtered logits.
30
+ """
31
+ """
32
+ Nucleus filtering is described in Holtzman et al. (http://arxiv.org/abs/1904.09751)
33
+ Make sure we keep at least min_tokens_to_keep per batch example in the output
34
+ From: https://gist.github.com/thomwolf/1a5a29f6962089e871b94cbd09daf317
35
+ """
36
+ if top_k > 0:
37
+ # Apply top-k filtering
38
+ top_k = min(max(top_k, min_tokens_to_keep), logits.size(-1))
39
+ indices_to_remove = logits < torch.topk(logits, top_k).values[..., -1, None]
40
+ logits[indices_to_remove] = filter_value
41
+
42
+ if top_p < 1.0:
43
+ # Apply top-p filtering
44
+ sorted_logits, sorted_indices = torch.sort(logits, descending=True)
45
+ cumulative_probs = torch.cumsum(F.softmax(sorted_logits, dim=-1), dim=-1)
46
+
47
+ # Create a mask to remove tokens with cumulative probability above the top_p threshold
48
+ sorted_indices_to_remove = cumulative_probs > top_p
49
+ if min_tokens_to_keep > 1:
50
+ sorted_indices_to_remove[..., :min_tokens_to_keep] = 0
51
+ sorted_indices_to_remove[..., 1:] = sorted_indices_to_remove[..., :-1].clone()
52
+ sorted_indices_to_remove[..., 0] = 0
53
+
54
+ # Scatter sorted tensors back to original indexing
55
+ indices_to_remove = sorted_indices.scatter(
56
+ 1, sorted_indices, sorted_indices_to_remove
57
+ )
58
+ logits[indices_to_remove] = filter_value
59
+
60
+ return logits
61
+
62
+
63
+ def topk_sampling(logits, top_k=50, top_p=1.0, temperature=1.0):
64
+ """
65
+ Perform top-k and top-p sampling on logits.
66
+
67
+ Args:
68
+ logits (torch.Tensor): The logits to sample from.
69
+ top_k (int, optional): The number of highest probability tokens to keep for top-k filtering.
70
+ Must be a positive integer. Defaults to 50.
71
+ top_p (float, optional): The cumulative probability threshold for nucleus sampling.
72
+ Must be between 0 and 1. Defaults to 1.0.
73
+ temperature (float, optional): The scaling factor to adjust the logits distribution.
74
+ Must be strictly positive. Defaults to 1.0.
75
+
76
+ Returns:
77
+ torch.Tensor: The sampled token.
78
+ """
79
+
80
+ # Adjust logits using temperature
81
+ if temperature != 1.0:
82
+ logits = logits / temperature
83
+
84
+ # Top-p/top-k filtering
85
+ logits = top_k_top_p_filtering(logits, top_k=top_k, top_p=top_p)
86
+
87
+ # Sample from the filtered distribution
88
+ token = torch.multinomial(F.softmax(logits, dim=-1), num_samples=1)
89
+ return token
utils/trainer_utils.py ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023 Amphion.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ import torch
7
+
8
+
9
+ def check_nan(logger, loss, y_pred, y_gt):
10
+ if torch.any(torch.isnan(loss)):
11
+ logger.info("out has nan: ", torch.any(torch.isnan(y_pred)))
12
+ logger.info("y_gt has nan: ", torch.any(torch.isnan(y_gt)))
13
+ logger.info("out: ", y_pred)
14
+ logger.info("y_gt: ", y_gt)
15
+ logger.info("loss = {:.4f}\n".format(loss.item()))
16
+ exit()
utils/util.py ADDED
@@ -0,0 +1,687 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023 Amphion.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+
7
+ import collections
8
+ import glob
9
+ import os
10
+ import random
11
+ import time
12
+ import argparse
13
+ from collections import OrderedDict
14
+
15
+ import json5
16
+ import numpy as np
17
+ import glob
18
+ from torch.nn import functional as F
19
+
20
+
21
+ try:
22
+ from ruamel.yaml import YAML as yaml
23
+ except:
24
+ from ruamel_yaml import YAML as yaml
25
+
26
+ import torch
27
+
28
+ from utils.hparam import HParams
29
+ import logging
30
+ from logging import handlers
31
+
32
+
33
+ def str2bool(v):
34
+ """Used in argparse.ArgumentParser.add_argument to indicate
35
+ that a type is a bool type and user can enter
36
+
37
+ - yes, true, t, y, 1, to represent True
38
+ - no, false, f, n, 0, to represent False
39
+
40
+ See https://stackoverflow.com/questions/15008758/parsing-boolean-values-with-argparse # noqa
41
+ """
42
+ if isinstance(v, bool):
43
+ return v
44
+ if v.lower() in ("yes", "true", "t", "y", "1"):
45
+ return True
46
+ elif v.lower() in ("no", "false", "f", "n", "0"):
47
+ return False
48
+ else:
49
+ raise argparse.ArgumentTypeError("Boolean value expected.")
50
+
51
+
52
+ def find_checkpoint_of_mapper(mapper_ckpt_dir):
53
+ mapper_ckpts = glob.glob(os.path.join(mapper_ckpt_dir, "ckpts/*.pt"))
54
+
55
+ # Select the max steps
56
+ mapper_ckpts.sort()
57
+ mapper_weights_file = mapper_ckpts[-1]
58
+ return mapper_weights_file
59
+
60
+
61
+ def pad_f0_to_tensors(f0s, batched=None):
62
+ # Initialize
63
+ tensors = []
64
+
65
+ if batched == None:
66
+ # Get the max frame for padding
67
+ size = -1
68
+ for f0 in f0s:
69
+ size = max(size, f0.shape[-1])
70
+
71
+ tensor = torch.zeros(len(f0s), size)
72
+
73
+ for i, f0 in enumerate(f0s):
74
+ tensor[i, : f0.shape[-1]] = f0[:]
75
+
76
+ tensors.append(tensor)
77
+ else:
78
+ start = 0
79
+ while start + batched - 1 < len(f0s):
80
+ end = start + batched - 1
81
+
82
+ # Get the max frame for padding
83
+ size = -1
84
+ for i in range(start, end + 1):
85
+ size = max(size, f0s[i].shape[-1])
86
+
87
+ tensor = torch.zeros(batched, size)
88
+
89
+ for i in range(start, end + 1):
90
+ tensor[i - start, : f0s[i].shape[-1]] = f0s[i][:]
91
+
92
+ tensors.append(tensor)
93
+
94
+ start = start + batched
95
+
96
+ if start != len(f0s):
97
+ end = len(f0s)
98
+
99
+ # Get the max frame for padding
100
+ size = -1
101
+ for i in range(start, end):
102
+ size = max(size, f0s[i].shape[-1])
103
+
104
+ tensor = torch.zeros(len(f0s) - start, size)
105
+
106
+ for i in range(start, end):
107
+ tensor[i - start, : f0s[i].shape[-1]] = f0s[i][:]
108
+
109
+ tensors.append(tensor)
110
+
111
+ return tensors
112
+
113
+
114
+ def pad_mels_to_tensors(mels, batched=None):
115
+ """
116
+ Args:
117
+ mels: A list of mel-specs
118
+ Returns:
119
+ tensors: A list of tensors containing the batched mel-specs
120
+ mel_frames: A list of tensors containing the frames of the original mel-specs
121
+ """
122
+ # Initialize
123
+ tensors = []
124
+ mel_frames = []
125
+
126
+ # Split mel-specs into batches to avoid cuda memory exceed
127
+ if batched == None:
128
+ # Get the max frame for padding
129
+ size = -1
130
+ for mel in mels:
131
+ size = max(size, mel.shape[-1])
132
+
133
+ tensor = torch.zeros(len(mels), mels[0].shape[0], size)
134
+ mel_frame = torch.zeros(len(mels), dtype=torch.int32)
135
+
136
+ for i, mel in enumerate(mels):
137
+ tensor[i, :, : mel.shape[-1]] = mel[:]
138
+ mel_frame[i] = mel.shape[-1]
139
+
140
+ tensors.append(tensor)
141
+ mel_frames.append(mel_frame)
142
+ else:
143
+ start = 0
144
+ while start + batched - 1 < len(mels):
145
+ end = start + batched - 1
146
+
147
+ # Get the max frame for padding
148
+ size = -1
149
+ for i in range(start, end + 1):
150
+ size = max(size, mels[i].shape[-1])
151
+
152
+ tensor = torch.zeros(batched, mels[0].shape[0], size)
153
+ mel_frame = torch.zeros(batched, dtype=torch.int32)
154
+
155
+ for i in range(start, end + 1):
156
+ tensor[i - start, :, : mels[i].shape[-1]] = mels[i][:]
157
+ mel_frame[i - start] = mels[i].shape[-1]
158
+
159
+ tensors.append(tensor)
160
+ mel_frames.append(mel_frame)
161
+
162
+ start = start + batched
163
+
164
+ if start != len(mels):
165
+ end = len(mels)
166
+
167
+ # Get the max frame for padding
168
+ size = -1
169
+ for i in range(start, end):
170
+ size = max(size, mels[i].shape[-1])
171
+
172
+ tensor = torch.zeros(len(mels) - start, mels[0].shape[0], size)
173
+ mel_frame = torch.zeros(len(mels) - start, dtype=torch.int32)
174
+
175
+ for i in range(start, end):
176
+ tensor[i - start, :, : mels[i].shape[-1]] = mels[i][:]
177
+ mel_frame[i - start] = mels[i].shape[-1]
178
+
179
+ tensors.append(tensor)
180
+ mel_frames.append(mel_frame)
181
+
182
+ return tensors, mel_frames
183
+
184
+
185
+ def load_model_config(args):
186
+ """Load model configurations (in args.json under checkpoint directory)
187
+
188
+ Args:
189
+ args (ArgumentParser): arguments to run bins/preprocess.py
190
+
191
+ Returns:
192
+ dict: dictionary that stores model configurations
193
+ """
194
+ if args.checkpoint_dir is None:
195
+ assert args.checkpoint_file is not None
196
+ checkpoint_dir = os.path.split(args.checkpoint_file)[0]
197
+ else:
198
+ checkpoint_dir = args.checkpoint_dir
199
+ config_path = os.path.join(checkpoint_dir, "args.json")
200
+ print("config_path: ", config_path)
201
+
202
+ config = load_config(config_path)
203
+ return config
204
+
205
+
206
+ def remove_and_create(dir):
207
+ if os.path.exists(dir):
208
+ os.system("rm -r {}".format(dir))
209
+ os.makedirs(dir, exist_ok=True)
210
+
211
+
212
+ def has_existed(path, warning=False):
213
+ if not warning:
214
+ return os.path.exists(path)
215
+
216
+ if os.path.exists(path):
217
+ answer = input(
218
+ "The path {} has existed. \nInput 'y' (or hit Enter) to skip it, and input 'n' to re-write it [y/n]\n".format(
219
+ path
220
+ )
221
+ )
222
+ if not answer == "n":
223
+ return True
224
+
225
+ return False
226
+
227
+
228
+ def remove_older_ckpt(saved_model_name, checkpoint_dir, max_to_keep=5):
229
+ if os.path.exists(os.path.join(checkpoint_dir, "checkpoint")):
230
+ with open(os.path.join(checkpoint_dir, "checkpoint"), "r") as f:
231
+ ckpts = [x.strip() for x in f.readlines()]
232
+ else:
233
+ ckpts = []
234
+ ckpts.append(saved_model_name)
235
+ for item in ckpts[:-max_to_keep]:
236
+ if os.path.exists(os.path.join(checkpoint_dir, item)):
237
+ os.remove(os.path.join(checkpoint_dir, item))
238
+ with open(os.path.join(checkpoint_dir, "checkpoint"), "w") as f:
239
+ for item in ckpts[-max_to_keep:]:
240
+ f.write("{}\n".format(item))
241
+
242
+
243
+ def set_all_random_seed(seed: int):
244
+ random.seed(seed)
245
+ np.random.seed(seed)
246
+ torch.random.manual_seed(seed)
247
+
248
+
249
+ def save_checkpoint(
250
+ args,
251
+ generator,
252
+ g_optimizer,
253
+ step,
254
+ discriminator=None,
255
+ d_optimizer=None,
256
+ max_to_keep=5,
257
+ ):
258
+ saved_model_name = "model.ckpt-{}.pt".format(step)
259
+ checkpoint_path = os.path.join(args.checkpoint_dir, saved_model_name)
260
+
261
+ if discriminator and d_optimizer:
262
+ torch.save(
263
+ {
264
+ "generator": generator.state_dict(),
265
+ "discriminator": discriminator.state_dict(),
266
+ "g_optimizer": g_optimizer.state_dict(),
267
+ "d_optimizer": d_optimizer.state_dict(),
268
+ "global_step": step,
269
+ },
270
+ checkpoint_path,
271
+ )
272
+ else:
273
+ torch.save(
274
+ {
275
+ "generator": generator.state_dict(),
276
+ "g_optimizer": g_optimizer.state_dict(),
277
+ "global_step": step,
278
+ },
279
+ checkpoint_path,
280
+ )
281
+
282
+ print("Saved checkpoint: {}".format(checkpoint_path))
283
+
284
+ if os.path.exists(os.path.join(args.checkpoint_dir, "checkpoint")):
285
+ with open(os.path.join(args.checkpoint_dir, "checkpoint"), "r") as f:
286
+ ckpts = [x.strip() for x in f.readlines()]
287
+ else:
288
+ ckpts = []
289
+ ckpts.append(saved_model_name)
290
+ for item in ckpts[:-max_to_keep]:
291
+ if os.path.exists(os.path.join(args.checkpoint_dir, item)):
292
+ os.remove(os.path.join(args.checkpoint_dir, item))
293
+ with open(os.path.join(args.checkpoint_dir, "checkpoint"), "w") as f:
294
+ for item in ckpts[-max_to_keep:]:
295
+ f.write("{}\n".format(item))
296
+
297
+
298
+ def attempt_to_restore(
299
+ generator, g_optimizer, checkpoint_dir, discriminator=None, d_optimizer=None
300
+ ):
301
+ checkpoint_list = os.path.join(checkpoint_dir, "checkpoint")
302
+ if os.path.exists(checkpoint_list):
303
+ checkpoint_filename = open(checkpoint_list).readlines()[-1].strip()
304
+ checkpoint_path = os.path.join(checkpoint_dir, "{}".format(checkpoint_filename))
305
+ print("Restore from {}".format(checkpoint_path))
306
+ checkpoint = torch.load(checkpoint_path, map_location="cpu")
307
+ if generator:
308
+ if not list(generator.state_dict().keys())[0].startswith("module."):
309
+ raw_dict = checkpoint["generator"]
310
+ clean_dict = OrderedDict()
311
+ for k, v in raw_dict.items():
312
+ if k.startswith("module."):
313
+ clean_dict[k[7:]] = v
314
+ else:
315
+ clean_dict[k] = v
316
+ generator.load_state_dict(clean_dict)
317
+ else:
318
+ generator.load_state_dict(checkpoint["generator"])
319
+ if g_optimizer:
320
+ g_optimizer.load_state_dict(checkpoint["g_optimizer"])
321
+ global_step = 100000
322
+ if discriminator and "discriminator" in checkpoint.keys():
323
+ discriminator.load_state_dict(checkpoint["discriminator"])
324
+ global_step = checkpoint["global_step"]
325
+ print("restore discriminator")
326
+ if d_optimizer and "d_optimizer" in checkpoint.keys():
327
+ d_optimizer.load_state_dict(checkpoint["d_optimizer"])
328
+ print("restore d_optimizer...")
329
+ else:
330
+ global_step = 0
331
+ return global_step
332
+
333
+
334
+ class ExponentialMovingAverage(object):
335
+ def __init__(self, decay):
336
+ self.decay = decay
337
+ self.shadow = {}
338
+
339
+ def register(self, name, val):
340
+ self.shadow[name] = val.clone()
341
+
342
+ def update(self, name, x):
343
+ assert name in self.shadow
344
+ update_delta = self.shadow[name] - x
345
+ self.shadow[name] -= (1.0 - self.decay) * update_delta
346
+
347
+
348
+ def apply_moving_average(model, ema):
349
+ for name, param in model.named_parameters():
350
+ if name in ema.shadow:
351
+ ema.update(name, param.data)
352
+
353
+
354
+ def register_model_to_ema(model, ema):
355
+ for name, param in model.named_parameters():
356
+ if param.requires_grad:
357
+ ema.register(name, param.data)
358
+
359
+
360
+ class YParams(HParams):
361
+ def __init__(self, yaml_file):
362
+ if not os.path.exists(yaml_file):
363
+ raise IOError("yaml file: {} is not existed".format(yaml_file))
364
+ super().__init__()
365
+ self.d = collections.OrderedDict()
366
+ with open(yaml_file) as fp:
367
+ for _, v in yaml().load(fp).items():
368
+ for k1, v1 in v.items():
369
+ try:
370
+ if self.get(k1):
371
+ self.set_hparam(k1, v1)
372
+ else:
373
+ self.add_hparam(k1, v1)
374
+ self.d[k1] = v1
375
+ except Exception:
376
+ import traceback
377
+
378
+ print(traceback.format_exc())
379
+
380
+ # @property
381
+ def get_elements(self):
382
+ return self.d.items()
383
+
384
+
385
+ def override_config(base_config, new_config):
386
+ """Update new configurations in the original dict with the new dict
387
+
388
+ Args:
389
+ base_config (dict): original dict to be overridden
390
+ new_config (dict): dict with new configurations
391
+
392
+ Returns:
393
+ dict: updated configuration dict
394
+ """
395
+ for k, v in new_config.items():
396
+ if type(v) == dict:
397
+ if k not in base_config.keys():
398
+ base_config[k] = {}
399
+ base_config[k] = override_config(base_config[k], v)
400
+ else:
401
+ base_config[k] = v
402
+ return base_config
403
+
404
+
405
+ def get_lowercase_keys_config(cfg):
406
+ """Change all keys in cfg to lower case
407
+
408
+ Args:
409
+ cfg (dict): dictionary that stores configurations
410
+
411
+ Returns:
412
+ dict: dictionary that stores configurations
413
+ """
414
+ updated_cfg = dict()
415
+ for k, v in cfg.items():
416
+ if type(v) == dict:
417
+ v = get_lowercase_keys_config(v)
418
+ updated_cfg[k.lower()] = v
419
+ return updated_cfg
420
+
421
+
422
+ def _load_config(config_fn, lowercase=False):
423
+ """Load configurations into a dictionary
424
+
425
+ Args:
426
+ config_fn (str): path to configuration file
427
+ lowercase (bool, optional): whether changing keys to lower case. Defaults to False.
428
+
429
+ Returns:
430
+ dict: dictionary that stores configurations
431
+ """
432
+ with open(config_fn, "r") as f:
433
+ data = f.read()
434
+ config_ = json5.loads(data)
435
+ if "base_config" in config_:
436
+ # load configurations from new path
437
+ p_config_path = os.path.join(os.getenv("WORK_DIR"), config_["base_config"])
438
+ p_config_ = _load_config(p_config_path)
439
+ config_ = override_config(p_config_, config_)
440
+ if lowercase:
441
+ # change keys in config_ to lower case
442
+ config_ = get_lowercase_keys_config(config_)
443
+ return config_
444
+
445
+
446
+ def load_config(config_fn, lowercase=False):
447
+ """Load configurations into a dictionary
448
+
449
+ Args:
450
+ config_fn (str): path to configuration file
451
+ lowercase (bool, optional): _description_. Defaults to False.
452
+
453
+ Returns:
454
+ JsonHParams: an object that stores configurations
455
+ """
456
+ config_ = _load_config(config_fn, lowercase=lowercase)
457
+ # create an JsonHParams object with configuration dict
458
+ cfg = JsonHParams(**config_)
459
+ return cfg
460
+
461
+
462
+ def save_config(save_path, cfg):
463
+ """Save configurations into a json file
464
+
465
+ Args:
466
+ save_path (str): path to save configurations
467
+ cfg (dict): dictionary that stores configurations
468
+ """
469
+ with open(save_path, "w") as f:
470
+ json5.dump(
471
+ cfg, f, ensure_ascii=False, indent=4, quote_keys=True, sort_keys=True
472
+ )
473
+
474
+
475
+ class JsonHParams:
476
+ def __init__(self, **kwargs):
477
+ for k, v in kwargs.items():
478
+ if type(v) == dict:
479
+ v = JsonHParams(**v)
480
+ self[k] = v
481
+
482
+ def keys(self):
483
+ return self.__dict__.keys()
484
+
485
+ def items(self):
486
+ return self.__dict__.items()
487
+
488
+ def values(self):
489
+ return self.__dict__.values()
490
+
491
+ def __len__(self):
492
+ return len(self.__dict__)
493
+
494
+ def __getitem__(self, key):
495
+ return getattr(self, key)
496
+
497
+ def __setitem__(self, key, value):
498
+ return setattr(self, key, value)
499
+
500
+ def __contains__(self, key):
501
+ return key in self.__dict__
502
+
503
+ def __repr__(self):
504
+ return self.__dict__.__repr__()
505
+
506
+
507
+ class ValueWindow:
508
+ def __init__(self, window_size=100):
509
+ self._window_size = window_size
510
+ self._values = []
511
+
512
+ def append(self, x):
513
+ self._values = self._values[-(self._window_size - 1) :] + [x]
514
+
515
+ @property
516
+ def sum(self):
517
+ return sum(self._values)
518
+
519
+ @property
520
+ def count(self):
521
+ return len(self._values)
522
+
523
+ @property
524
+ def average(self):
525
+ return self.sum / max(1, self.count)
526
+
527
+ def reset(self):
528
+ self._values = []
529
+
530
+
531
+ class Logger(object):
532
+ def __init__(
533
+ self,
534
+ filename,
535
+ level="info",
536
+ when="D",
537
+ backCount=10,
538
+ fmt="%(asctime)s : %(message)s",
539
+ ):
540
+ self.level_relations = {
541
+ "debug": logging.DEBUG,
542
+ "info": logging.INFO,
543
+ "warning": logging.WARNING,
544
+ "error": logging.ERROR,
545
+ "crit": logging.CRITICAL,
546
+ }
547
+ if level == "debug":
548
+ fmt = "%(asctime)s - %(pathname)s[line:%(lineno)d] - %(levelname)s: %(message)s"
549
+ self.logger = logging.getLogger(filename)
550
+ format_str = logging.Formatter(fmt)
551
+ self.logger.setLevel(self.level_relations.get(level))
552
+ sh = logging.StreamHandler()
553
+ sh.setFormatter(format_str)
554
+ th = handlers.TimedRotatingFileHandler(
555
+ filename=filename, when=when, backupCount=backCount, encoding="utf-8"
556
+ )
557
+ th.setFormatter(format_str)
558
+ self.logger.addHandler(sh)
559
+ self.logger.addHandler(th)
560
+ self.logger.info(
561
+ "==========================New Starting Here=============================="
562
+ )
563
+
564
+
565
+ def init_weights(m, mean=0.0, std=0.01):
566
+ classname = m.__class__.__name__
567
+ if classname.find("Conv") != -1:
568
+ m.weight.data.normal_(mean, std)
569
+
570
+
571
+ def get_padding(kernel_size, dilation=1):
572
+ return int((kernel_size * dilation - dilation) / 2)
573
+
574
+
575
+ def slice_segments(x, ids_str, segment_size=4):
576
+ ret = torch.zeros_like(x[:, :, :segment_size])
577
+ for i in range(x.size(0)):
578
+ idx_str = ids_str[i]
579
+ idx_end = idx_str + segment_size
580
+ ret[i] = x[i, :, idx_str:idx_end]
581
+ return ret
582
+
583
+
584
+ def rand_slice_segments(x, x_lengths=None, segment_size=4):
585
+ b, d, t = x.size()
586
+ if x_lengths is None:
587
+ x_lengths = t
588
+ ids_str_max = x_lengths - segment_size + 1
589
+ ids_str = (torch.rand([b]).to(device=x.device) * ids_str_max).to(dtype=torch.long)
590
+ ret = slice_segments(x, ids_str, segment_size)
591
+ return ret, ids_str
592
+
593
+
594
+ def subsequent_mask(length):
595
+ mask = torch.tril(torch.ones(length, length)).unsqueeze(0).unsqueeze(0)
596
+ return mask
597
+
598
+
599
+ @torch.jit.script
600
+ def fused_add_tanh_sigmoid_multiply(input_a, input_b, n_channels):
601
+ n_channels_int = n_channels[0]
602
+ in_act = input_a + input_b
603
+ t_act = torch.tanh(in_act[:, :n_channels_int, :])
604
+ s_act = torch.sigmoid(in_act[:, n_channels_int:, :])
605
+ acts = t_act * s_act
606
+ return acts
607
+
608
+
609
+ def convert_pad_shape(pad_shape):
610
+ l = pad_shape[::-1]
611
+ pad_shape = [item for sublist in l for item in sublist]
612
+ return pad_shape
613
+
614
+
615
+ def sequence_mask(length, max_length=None):
616
+ if max_length is None:
617
+ max_length = length.max()
618
+ x = torch.arange(max_length, dtype=length.dtype, device=length.device)
619
+ return x.unsqueeze(0) < length.unsqueeze(1)
620
+
621
+
622
+ def generate_path(duration, mask):
623
+ """
624
+ duration: [b, 1, t_x]
625
+ mask: [b, 1, t_y, t_x]
626
+ """
627
+ device = duration.device
628
+
629
+ b, _, t_y, t_x = mask.shape
630
+ cum_duration = torch.cumsum(duration, -1)
631
+
632
+ cum_duration_flat = cum_duration.view(b * t_x)
633
+ path = sequence_mask(cum_duration_flat, t_y).to(mask.dtype)
634
+ path = path.view(b, t_x, t_y)
635
+ path = path - F.pad(path, convert_pad_shape([[0, 0], [1, 0], [0, 0]]))[:, :-1]
636
+ path = path.unsqueeze(1).transpose(2, 3) * mask
637
+ return path
638
+
639
+
640
+ def clip_grad_value_(parameters, clip_value, norm_type=2):
641
+ if isinstance(parameters, torch.Tensor):
642
+ parameters = [parameters]
643
+ parameters = list(filter(lambda p: p.grad is not None, parameters))
644
+ norm_type = float(norm_type)
645
+ if clip_value is not None:
646
+ clip_value = float(clip_value)
647
+
648
+ total_norm = 0
649
+ for p in parameters:
650
+ param_norm = p.grad.data.norm(norm_type)
651
+ total_norm += param_norm.item() ** norm_type
652
+ if clip_value is not None:
653
+ p.grad.data.clamp_(min=-clip_value, max=clip_value)
654
+ total_norm = total_norm ** (1.0 / norm_type)
655
+ return total_norm
656
+
657
+
658
+ def get_current_time():
659
+ pass
660
+
661
+
662
+ def make_pad_mask(lengths: torch.Tensor, max_len: int = 0) -> torch.Tensor:
663
+ """
664
+ Args:
665
+ lengths:
666
+ A 1-D tensor containing sentence lengths.
667
+ max_len:
668
+ The length of masks.
669
+ Returns:
670
+ Return a 2-D bool tensor, where masked positions
671
+ are filled with `True` and non-masked positions are
672
+ filled with `False`.
673
+
674
+ >>> lengths = torch.tensor([1, 3, 2, 5])
675
+ >>> make_pad_mask(lengths)
676
+ tensor([[False, True, True, True, True],
677
+ [False, False, False, True, True],
678
+ [False, False, True, True, True],
679
+ [False, False, False, False, False]])
680
+ """
681
+ assert lengths.ndim == 1, lengths.ndim
682
+ max_len = max(max_len, lengths.max())
683
+ n = lengths.size(0)
684
+ seq_range = torch.arange(0, max_len, device=lengths.device)
685
+ expaned_lengths = seq_range.unsqueeze(0).expand(n, max_len)
686
+
687
+ return expaned_lengths >= lengths.unsqueeze(-1)
utils/whisper_transcription.py ADDED
@@ -0,0 +1,122 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023 Amphion.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ import os
7
+ import pathlib
8
+ import string
9
+ import time
10
+ from multiprocessing import Pool, Value, Lock
11
+ from transformers import AutoModelForSpeechSeq2Seq, AutoProcessor
12
+ import torch
13
+ import whisper
14
+
15
+ processed_files_count = Value("i", 0) # count of processed files
16
+ lock = Lock() # lock for the count
17
+
18
+
19
+ def preprocess_text(text):
20
+ """Preprocess text after ASR"""
21
+ return text.lower().translate(str.maketrans("", "", string.punctuation))
22
+
23
+
24
+ def transcribe_audio(model, processor, audio_file, device):
25
+ """Transcribe audio file"""
26
+ audio = whisper.load_audio(audio_file) # load from path
27
+ audio = whisper.pad_or_trim(audio) # default 30 seconds
28
+ inputs = whisper.log_mel_spectrogram(audio).to(
29
+ device=device
30
+ ) # convert to spectrogram
31
+ inputs = inputs.unsqueeze(0).type(torch.cuda.HalfTensor) # add batch dimension
32
+
33
+ outputs = model.generate(
34
+ inputs=inputs, max_new_tokens=128
35
+ ) # generate transcription
36
+ transcription = processor.batch_decode(outputs, skip_special_tokens=True)[
37
+ 0
38
+ ] # decode
39
+ transcription_processed = preprocess_text(transcription) # preprocess
40
+ return transcription_processed
41
+
42
+
43
+ def write_transcription(audio_file, transcription):
44
+ """Write transcription to txt file"""
45
+ txt_file = audio_file.with_suffix(".txt")
46
+ with open(txt_file, "w") as file:
47
+ file.write(transcription)
48
+
49
+
50
+ def init_whisper(model_id, device):
51
+ """Initialize whisper model and processor"""
52
+ torch_dtype = torch.float16 if torch.cuda.is_available() else torch.float32
53
+ print(f"Loading model {model_id}") # model_id = "distil-whisper/distil-large-v2"
54
+ distil_model = AutoModelForSpeechSeq2Seq.from_pretrained(
55
+ model_id, torch_dtype=torch_dtype, low_cpu_mem_usage=True, use_safetensors=False
56
+ )
57
+ distil_model = distil_model.to(device)
58
+ processor = AutoProcessor.from_pretrained(model_id)
59
+ return distil_model, processor
60
+
61
+
62
+ def asr_wav_files(file_list, gpu_id, total_files, model_id):
63
+ """Transcribe wav files in a list"""
64
+ device = f"cuda:{gpu_id}" if torch.cuda.is_available() else "cpu"
65
+ whisper_model, processor = init_whisper(model_id, device)
66
+ print(f"Processing on {device} starts")
67
+ start_time = time.time()
68
+ for audio_file in file_list:
69
+ try:
70
+ transcription = transcribe_audio(
71
+ whisper_model, processor, audio_file, device
72
+ )
73
+ write_transcription(audio_file, transcription)
74
+ with lock:
75
+ processed_files_count.value += 1
76
+ if processed_files_count.value % 5 == 0:
77
+ current_time = time.time()
78
+ avg_time_per_file = (current_time - start_time) / (
79
+ processed_files_count.value
80
+ )
81
+ remaining_files = total_files - processed_files_count.value
82
+ estimated_time_remaining = avg_time_per_file * remaining_files
83
+ remaining_time_formatted = time.strftime(
84
+ "%H:%M:%S", time.gmtime(estimated_time_remaining)
85
+ )
86
+ print(
87
+ f"Processed {processed_files_count.value}/{total_files} files, time: {time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())}, Estimated time remaining: {remaining_time_formatted}"
88
+ )
89
+ except Exception as e:
90
+ print(f"Error processing file {audio_file}: {e}")
91
+
92
+
93
+ def asr_main(input_dir, num_gpus, model_id):
94
+ """Transcribe wav files in a directory"""
95
+ num_processes = min(num_gpus, os.cpu_count())
96
+ print(f"Using {num_processes} GPUs for transcription")
97
+ wav_files = list(pathlib.Path(input_dir).rglob("*.wav"))
98
+ total_files = len(wav_files)
99
+ print(f"Found {total_files} wav files in {input_dir}")
100
+ files_per_process = len(wav_files) // num_processes
101
+ print(f"Processing {files_per_process} files per process")
102
+ with Pool(num_processes) as p:
103
+ p.starmap(
104
+ asr_wav_files,
105
+ [
106
+ (
107
+ wav_files[i * files_per_process : (i + 1) * files_per_process],
108
+ i % num_gpus,
109
+ total_files,
110
+ model_id,
111
+ )
112
+ for i in range(num_processes)
113
+ ],
114
+ )
115
+ print("Done!")
116
+
117
+
118
+ if __name__ == "__main__":
119
+ input_dir = "/path/to/output/directory"
120
+ num_gpus = 2
121
+ model_id = "distil-whisper/distil-large-v2"
122
+ asr_main(input_dir, num_gpus, model_id)
utils/world.py ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023 Amphion.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ # 1. Extract WORLD features including F0, AP, SP
7
+ # 2. Transform between SP and MCEP
8
+ import torchaudio
9
+ import pyworld as pw
10
+ import numpy as np
11
+ import torch
12
+ import diffsptk
13
+ import os
14
+ from tqdm import tqdm
15
+ import pickle
16
+ import torchaudio
17
+
18
+
19
+ def get_mcep_params(fs):
20
+ """Hyperparameters of transformation between SP and MCEP
21
+
22
+ Reference:
23
+ https://github.com/CSTR-Edinburgh/merlin/blob/master/misc/scripts/vocoder/world_v2/copy_synthesis.sh
24
+
25
+ """
26
+ if fs in [44100, 48000]:
27
+ fft_size = 2048
28
+ alpha = 0.77
29
+ if fs in [16000]:
30
+ fft_size = 1024
31
+ alpha = 0.58
32
+ return fft_size, alpha
33
+
34
+
35
+ def extract_world_features(waveform, frameshift=10):
36
+ # waveform: (1, seq)
37
+ # x: (seq,)
38
+ x = np.array(waveform, dtype=np.double)
39
+
40
+ _f0, t = pw.dio(x, fs, frame_period=frameshift) # raw pitch extractor
41
+ f0 = pw.stonemask(x, _f0, t, fs) # pitch refinement
42
+ sp = pw.cheaptrick(x, f0, t, fs) # extract smoothed spectrogram
43
+ ap = pw.d4c(x, f0, t, fs) # extract aperiodicity
44
+
45
+ return f0, sp, ap, fs
46
+
47
+
48
+ def sp2mcep(x, mcsize, fs):
49
+ fft_size, alpha = get_mcep_params(fs)
50
+ x = torch.as_tensor(x, dtype=torch.float)
51
+
52
+ tmp = diffsptk.ScalarOperation("SquareRoot")(x)
53
+ tmp = diffsptk.ScalarOperation("Multiplication", 32768.0)(tmp)
54
+ mgc = diffsptk.MelCepstralAnalysis(
55
+ cep_order=mcsize - 1, fft_length=fft_size, alpha=alpha, n_iter=1
56
+ )(tmp)
57
+ return mgc.numpy()
58
+
59
+
60
+ def mcep2sp(x, mcsize, fs):
61
+ fft_size, alpha = get_mcep_params(fs)
62
+ x = torch.as_tensor(x, dtype=torch.float)
63
+
64
+ tmp = diffsptk.MelGeneralizedCepstrumToSpectrum(
65
+ alpha=alpha,
66
+ cep_order=mcsize - 1,
67
+ fft_length=fft_size,
68
+ )(x)
69
+ tmp = diffsptk.ScalarOperation("Division", 32768.0)(tmp)
70
+ sp = diffsptk.ScalarOperation("Power", 2)(tmp)
71
+ return sp.double().numpy()
72
+
73
+
74
+ def f0_statistics(f0_features, path):
75
+ print("\nF0 statistics...")
76
+
77
+ total_f0 = []
78
+ for f0 in tqdm(f0_features):
79
+ total_f0 += [f for f in f0 if f != 0]
80
+
81
+ mean = sum(total_f0) / len(total_f0)
82
+ print("Min = {}, Max = {}, Mean = {}".format(min(total_f0), max(total_f0), mean))
83
+
84
+ with open(path, "wb") as f:
85
+ pickle.dump([mean, total_f0], f)
86
+
87
+
88
+ def world_synthesis(f0, sp, ap, fs, frameshift):
89
+ y = pw.synthesize(
90
+ f0, sp, ap, fs, frame_period=frameshift
91
+ ) # synthesize an utterance using the parameters
92
+ return y
visualization/SingVisio/System_Introduction_of_SingVisio_V2.pdf ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5dd205eace26d91a558e70662a61f017e3ca78e89d98cf45a72ee0911c6a64d2
3
+ size 4592895
visualization/SingVisio/webpage/Dockerfile ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023 Amphion.
2
+ #
3
+ # This source code is licensed under the MIT license found in the
4
+ # LICENSE file in the root directory of this source tree.
5
+
6
+ FROM python:3.10
7
+
8
+ WORKDIR /app
9
+
10
+ COPY resources ./resources
11
+ COPY img ./img
12
+ COPY index.html ./index.html
13
+ COPY server.py ./server.py
14
+ COPY config ./config
15
+
16
+ RUN pip install numpy scikit-learn flask flask_cors gunicorn -i https://pypi.tuna.tsinghua.edu.cn/simple
17
+
18
+ EXPOSE 8000
19
+
20
+ ENTRYPOINT ["gunicorn", "-w", "8", "-b", "0.0.0.0:8000", "server:app"]
21
+
22
+ # docker build -t singvisio .
23
+ # docker run -v $(pwd)/data:/app/data -p 8000:8000 singvisio
visualization/SingVisio/webpage/README.md ADDED
@@ -0,0 +1,126 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ## SingVisio Webpage
2
+
3
+ This is the source code for the SingVisio Webpage. This README file will introduce the project and provide an installation guide. For introduction to SingVisio, please check this [README.md](../../../egs/visualization/SingVisio/README.md) file.
4
+
5
+ ### Tech Stack
6
+
7
+ - [Tailwind CSS](https://tailwindcss.com/)
8
+ - [Flowbite](https://flowbite.com/)
9
+ - [D3.js](https://d3js.org/)
10
+ - [Driver.js](https://driverjs.com/)
11
+
12
+ ### Structure
13
+
14
+ - `index.html`: The entry point file.
15
+ - `config`: Contains JSON configuration files loaded by `index.html`.
16
+ - `img`: Image files.
17
+ - `resources`: Contains CSS styles and JavaScript files.
18
+ - `init.js`: Loads the configuration and initializes variables.
19
+ - `function.js`: Houses the functions used in this project.
20
+ - `event.js`: Binds webpage mouse and keyboard events to functions.
21
+ - `Dockerfile`: For building a Docker image if deployment is needed.
22
+
23
+ ### Configuration
24
+
25
+ Before installation, you need to configure the data path in the `config/default.json` file.
26
+
27
+ To better understand our project, please note that this configuration pertains to our pre-processed data. If you want to visualize your own data, you can follow the guide below to properly set up the system.
28
+
29
+ 1. **Update the Data Configuration** in the `config/default.json` file.
30
+
31
+ SingVisio will read the configuration from this JSON file and render the webpage. Be aware that any errors in the JSON file may cause the system to shut down.
32
+
33
+ ```json
34
+ {
35
+ "pathData": {
36
+ "<mode_name>": { // supports multiple modes
37
+ "users": ["basic", "advanced"], // mode choice: "basic" or "advanced"
38
+ "multi": ["<id>"], // song_id, sourcesinger_id, or target_id. Set to false to disable. Enables multiple choices for the configured checkbox.
39
+ "curve": true, // set to true if the metric curve is needed
40
+ "referenceMap": { // configures reference paths when multiple choices are enabled.
41
+ "<sourcesinger_id>": [ // e.g., m4singer_Tenor-6
42
+ "<path_to_wav>", // e.g., Tenor-6_寂寞沙洲冷_0002
43
+ ]
44
+ },
45
+ "data": [
46
+ { // supports multiple datasets
47
+ "dataset": "<dataset_name>",
48
+ "basePath": "<path_to_the_processed_data>",
49
+ "pathMap": {
50
+ "<sourcesinger_id>": {
51
+ "songs": [
52
+ "<song_id>" // set song ID; supports multiple IDs
53
+ ],
54
+ "targets": [
55
+ "<target_id>" // set target singer ID; supports multiple IDs
56
+ ]
57
+ }
58
+ }
59
+ }
60
+ ]
61
+ }
62
+ },
63
+ "mapToName": {
64
+ "<map_from>": "<map_to>"
65
+ },
66
+ "mapToSong": {
67
+ "<map_from>": "<map_to>"
68
+ },
69
+ "mapToSpace": {
70
+ "<map_from>": "<map_to>"
71
+ },
72
+ "picTypes": [
73
+ "<pic_type>" // supports multiple types
74
+ ],
75
+ "evaluation_data": [
76
+ { // supports multiple data sets
77
+ "target": "<target_id>",
78
+ "sourcesinger": "<sourcesinger_id>",
79
+ "song": "<song_id>",
80
+ "best": [
81
+ "<best_metric>" // activated when clicking the respective metric
82
+ ]
83
+ },
84
+ ],
85
+ "colorList": [
86
+ "<color_hex_code>" // supports multiple colors
87
+ ],
88
+ "histogramData": [
89
+ { // displayed in the top left graph
90
+ "type": "high", // "high" or "low"; "high" means the higher, the better
91
+ "name": "<metric_name>",
92
+ "value": <metric_value>
93
+ }
94
+ ]
95
+ }
96
+ ```
97
+
98
+ 2. **Change the Data Source Path**
99
+
100
+ The total size of our pre-processed data is approximately 60-70 GB. We provide an online host server, and the server path (`baseLink`) can be modified in the `index.html` file on line 15.
101
+
102
+ If you prefer to host the data on your local computer, you can set the `baseLink` value to an empty string as shown below. This will direct the server to read data from your local `data` folder.
103
+
104
+ ```html
105
+ <script>
106
+ const baseLink = ''; // do not end with '/'
107
+ </script>
108
+ ```
109
+
110
+ ### Installation
111
+
112
+ This project does not require a build process. There are multiple ways to run it, but here we introduce the simplest method:
113
+
114
+ 1. Install Python 3.10 and required packages.
115
+ ```bash
116
+ pip install numpy scikit-learn flask flask_cors gunicorn
117
+ ```
118
+
119
+ 2. Run the following command to start the HTTP server:
120
+
121
+ ```bash
122
+ cd webpage
123
+ gunicorn -w 8 -b 0.0.0.0:8080 server:app
124
+ ```
125
+
126
+ 3. After starting the HTTP web server, open the following link in your browser: [http://localhost:8080/](http://localhost:8080/)
visualization/SingVisio/webpage/config/default.json ADDED
@@ -0,0 +1,407 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "pathData": {
3
+ "Step Comparison": {
4
+ "users": ["basic", "advanced"],
5
+ "multi": false,
6
+ "data": [
7
+ {
8
+ "dataset": "SVCC",
9
+ "basePath": "data/gd_svcc",
10
+ "pathMap": {
11
+ "SF1": {
12
+ "songs": [
13
+ "30001",
14
+ "30002",
15
+ "30003"
16
+ ],
17
+ "targets": [
18
+ "svcc_IDF1",
19
+ "svcc_IDM1",
20
+ "svcc_CDF1",
21
+ "svcc_CDM1"
22
+ ]
23
+ },
24
+ "SM1": {
25
+ "songs": [
26
+ "30001",
27
+ "30002",
28
+ "30003"
29
+ ],
30
+ "targets": [
31
+ "svcc_IDF1",
32
+ "svcc_IDM1",
33
+ "svcc_CDF1",
34
+ "svcc_CDM1"
35
+ ]
36
+ }
37
+ }
38
+ },
39
+ {
40
+ "dataset": "M4Singer",
41
+ "basePath": "data/gd_m4sg",
42
+ "pathMap": {
43
+ "Alto-1": {
44
+ "songs": [
45
+ "美错_0014"
46
+ ],
47
+ "targets": [
48
+ "opencpop"
49
+ ]
50
+ },
51
+ "Bass-1": {
52
+ "songs": [
53
+ "十年_0008"
54
+ ],
55
+ "targets": [
56
+ "opencpop"
57
+ ]
58
+ },
59
+ "Soprano-2": {
60
+ "songs": [
61
+ "同桌的你_0018"
62
+ ],
63
+ "targets": [
64
+ "opencpop"
65
+ ]
66
+ },
67
+ "Tenor-5": {
68
+ "songs": [
69
+ "爱笑的眼睛_0010"
70
+ ],
71
+ "targets": [
72
+ "opencpop"
73
+ ]
74
+ }
75
+ }
76
+ }
77
+ ]
78
+ },
79
+ "Metric Comparison": {
80
+ "users": ["basic", "advanced"],
81
+ "multi": false,
82
+ "curve": true,
83
+ "data": [
84
+ {
85
+ "dataset": "SVCC",
86
+ "basePath": "data/ev_best",
87
+ "pathMap": {
88
+ "SM1": {
89
+ "songs": [
90
+ "30009"
91
+ ],
92
+ "targets": [
93
+ "svcc_IDM1"
94
+ ]
95
+ },
96
+ "SF1": {
97
+ "songs": [
98
+ "30005",
99
+ "30006",
100
+ "30009",
101
+ "30016",
102
+ "30022",
103
+ "30019"
104
+ ],
105
+ "targets": [
106
+ "svcc_IDF1"
107
+ ]
108
+ }
109
+ }
110
+ }
111
+ ]
112
+ },
113
+ "Source Singer Comparison": {
114
+ "users": ["advanced"],
115
+ "multi": [
116
+ "sourcesinger_id"
117
+ ],
118
+ "referenceMap": {
119
+ "m4singer_Alto-7": [
120
+ "Alto-7_寂寞沙洲冷_0000",
121
+ "Alto-7_寂寞沙洲冷_0011"
122
+ ],
123
+ "m4singer_Bass-1": [
124
+ "Bass-1_寂寞沙洲冷_0002",
125
+ "Bass-1_寂寞沙洲冷_0021"
126
+ ],
127
+ "m4singer_Tenor-6": [
128
+ "Tenor-6_寂寞沙洲冷_0002",
129
+ "Tenor-6_寂寞沙洲冷_0020"
130
+ ],
131
+ "m4singer_Tenor-7": [
132
+ "Tenor-7_寂寞沙洲冷_0002",
133
+ "Tenor-7_寂寞沙洲冷_0013",
134
+ "Tenor-7_寂寞沙洲冷_0023"
135
+ ]
136
+ },
137
+ "indexMode": "number",
138
+ "data": [
139
+ {
140
+ "dataset": "M4Singer",
141
+ "basePath": "data/dc_dss",
142
+ "pathMap": {
143
+ "Alto-7": {
144
+ "songs": [
145
+ "寂寞沙洲冷_0000",
146
+ "寂寞沙洲冷_0011"
147
+ ],
148
+ "targets": [
149
+ "m4singer_Tenor-7",
150
+ "m4singer_Alto-7"
151
+ ]
152
+ },
153
+ "Bass-1": {
154
+ "songs": [
155
+ "寂寞沙洲冷_0002",
156
+ "寂寞沙洲冷_0021"
157
+ ],
158
+ "targets": [
159
+ "m4singer_Tenor-7",
160
+ "m4singer_Bass-1"
161
+ ]
162
+ },
163
+ "Tenor-6": {
164
+ "songs": [
165
+ "寂寞沙洲冷_0002",
166
+ "寂寞沙洲冷_0020"
167
+ ],
168
+ "targets": [
169
+ "m4singer_Tenor-7",
170
+ "m4singer_Tenor-6"
171
+ ]
172
+ },
173
+ "Tenor-7": {
174
+ "songs": [
175
+ "寂寞沙洲冷_0002",
176
+ "寂寞沙洲冷_0013"
177
+ ],
178
+ "targets": [
179
+ "m4singer_Alto-7",
180
+ "m4singer_Bass-1",
181
+ "m4singer_Tenor-6"
182
+ ]
183
+ }
184
+ }
185
+ }
186
+ ]
187
+ },
188
+ "Song Comparison": {
189
+ "users": ["advanced"],
190
+ "multi": [
191
+ "song_id"
192
+ ],
193
+ "referenceMap": {
194
+ "m4singer_Tenor-6": [
195
+ "Tenor-6_寂寞沙洲冷_0002",
196
+ "Tenor-6_寂寞沙洲冷_0020"
197
+ ],
198
+ "m4singer_Tenor-7": [
199
+ "Tenor-7_寂寞沙洲冷_0002",
200
+ "Tenor-7_寂寞沙洲冷_0013"
201
+ ]
202
+ },
203
+ "data": [
204
+ {
205
+ "dataset": "M4Singer",
206
+ "basePath": "data/dc_dss",
207
+ "pathMap": {
208
+ "Tenor-6": {
209
+ "songs": [
210
+ "寂寞沙洲冷_0002",
211
+ "寂寞沙洲冷_0020"
212
+ ],
213
+ "targets": [
214
+ "m4singer_Tenor-7",
215
+ "m4singer_Tenor-6"
216
+ ]
217
+ }
218
+ }
219
+ }
220
+ ]
221
+ },
222
+ "Target Singer Comparison": {
223
+ "users": ["advanced"],
224
+ "multi": [
225
+ "song_id",
226
+ "target_id"
227
+ ],
228
+ "referenceMap": {
229
+ "m4singer_Alto-7": [
230
+ "Alto-7_寂寞沙洲冷_0000",
231
+ "Alto-7_寂寞沙洲冷_0011"
232
+ ],
233
+ "m4singer_Bass-1": [
234
+ "Bass-1_寂寞沙洲冷_0002",
235
+ "Bass-1_寂寞沙洲冷_0021"
236
+ ],
237
+ "m4singer_Tenor-7": [
238
+ "Tenor-7_寂寞沙洲冷_0002",
239
+ "Tenor-7_寂寞沙洲冷_0013"
240
+ ],
241
+ "m4singer_Tenor-6": [
242
+ "Tenor-6_寂寞沙洲冷_0002",
243
+ "Tenor-6_寂寞沙洲冷_0020"
244
+ ]
245
+ },
246
+ "data": [
247
+ {
248
+ "dataset": "M4Singer",
249
+ "basePath": "data/dc_ssd",
250
+ "pathMap": {
251
+ "Tenor-6": {
252
+ "songs": [
253
+ "寂寞沙洲冷_0002",
254
+ "寂寞沙洲冷_0020"
255
+ ],
256
+ "targets": [
257
+ "m4singer_Alto-7",
258
+ "m4singer_Bass-1",
259
+ "m4singer_Tenor-7",
260
+ "m4singer_Tenor-6"
261
+ ]
262
+ }
263
+ }
264
+ }
265
+ ]
266
+ }
267
+ },
268
+ "mapToName": {
269
+ "SF1": "Singer 1",
270
+ "SM1": "Singer 2",
271
+ "CDF1": "Singer 3",
272
+ "CDM1": "Singer 4",
273
+ "IDF1": "Singer 5",
274
+ "IDM1": "Singer 6",
275
+ "svcc_CDF1": "Singer 3",
276
+ "svcc_CDM1": "Singer 4",
277
+ "svcc_IDF1": "Singer 5",
278
+ "svcc_IDM1": "Singer 6",
279
+ "Alto-1": "Singer 7",
280
+ "m4singer_Alto-1": "Singer 7",
281
+ "Alto-7": "Singer 8",
282
+ "m4singer_Alto-7": "Singer 8",
283
+ "Bass-1": "Singer 9",
284
+ "m4singer_Bass-1": "Singer 9",
285
+ "Soprano-2": "Singer 10",
286
+ "m4singer_Soprano-2": "Singer 10",
287
+ "Tenor-5": "Singer 11",
288
+ "m4singer_Tenor-5": "Singer 11",
289
+ "Tenor-6": "Singer 12",
290
+ "m4singer_Tenor-6": "Singer 12",
291
+ "Tenor-7": "Singer 13",
292
+ "m4singer_Tenor-7": "Singer 13",
293
+ "opencpop": "Singer 14"
294
+ },
295
+ "mapToSong": {
296
+ "30001": "Song 1",
297
+ "30002": "Song 2",
298
+ "30003": "Song 3",
299
+ "10001": "Song 4",
300
+ "10030": "Song 5",
301
+ "10120": "Song 6",
302
+ "10140": "Song 7",
303
+ "美错_0014": "Song 8",
304
+ "十年_0008": "Song 9",
305
+ "同桌的你_0018": "Song 10",
306
+ "爱笑的眼睛_0010": "Song 11",
307
+ "寂寞沙洲冷_0000": "Song 12",
308
+ "寂寞沙洲冷_0002": "Song 12",
309
+ "寂寞沙洲冷_0011": "Song 13",
310
+ "寂寞沙洲冷_0013": "Song 13",
311
+ "寂寞沙洲冷_0020": "Song 13",
312
+ "寂寞沙洲冷_0021": "Song 14",
313
+ "30005": "Song 15",
314
+ "30006": "Song 16",
315
+ "30009": "Song 17",
316
+ "30016": "Song 18",
317
+ "30022": "Song 19",
318
+ "30019": "Song 20"
319
+ },
320
+ "mapToSpace": {
321
+ "encoded_step": "Step (Diffusion step)",
322
+ "noise_step_layer0": "Step + Noise (First layer)",
323
+ "noise_step_layer10": "Step + Noise (Middle layer)",
324
+ "noise_step_layer19": "Step + Noise (Last layer)",
325
+ "noise_step_condition_layer0": "Step + Noise + Condition (First layer)",
326
+ "noise_step_condition_layer10": "Step + Noise + Condition (Middle layer)",
327
+ "noise_step_condition_layer19": "Step + Noise + Condition (Last layer)"
328
+ },
329
+ "picTypes": [
330
+ "encoded_step",
331
+ "noise_step_layer0",
332
+ "noise_step_layer10",
333
+ "noise_step_layer19",
334
+ "noise_step_condition_layer0",
335
+ "noise_step_condition_layer10",
336
+ "noise_step_condition_layer19"
337
+ ],
338
+ "evaluation_data": [
339
+ {
340
+ "target": "svcc_IDM1",
341
+ "sourcesinger": "SM1",
342
+ "song": "30009",
343
+ "best": [
344
+ "MCD"
345
+ ]
346
+ },
347
+ {
348
+ "target": "svcc_IDF1",
349
+ "sourcesinger": "SF1",
350
+ "song": "30016",
351
+ "best": [
352
+ "F0CORR",
353
+ "FAD"
354
+ ]
355
+ },
356
+ {
357
+ "target": "svcc_IDF1",
358
+ "sourcesinger": "SF1",
359
+ "song": "30009",
360
+ "best": [
361
+ "F0RMSE",
362
+ "CER"
363
+ ]
364
+ },
365
+ {
366
+ "target": "svcc_IDF1",
367
+ "sourcesinger": "SF1",
368
+ "song": "30019",
369
+ "best": [
370
+ "Dembed"
371
+ ]
372
+ }
373
+ ],
374
+ "colorList": [
375
+ "#FFA500",
376
+ "#1C64F2",
377
+ "#7E3AF2",
378
+ "#9F580A"
379
+ ],
380
+ "histogramData": [
381
+ {
382
+ "type": "high",
383
+ "name": "F0CORR",
384
+ "value": 0.946698913
385
+ },
386
+ {
387
+ "type": "high",
388
+ "name": "Dembed",
389
+ "value": 0.688410708
390
+ },
391
+ {
392
+ "type": "low",
393
+ "name": "MCD",
394
+ "value": 11.44773471
395
+ },
396
+ {
397
+ "type": "low",
398
+ "name": "F0RMSE",
399
+ "value": 70.81400428
400
+ },
401
+ {
402
+ "type": "low",
403
+ "name": "FAD",
404
+ "value": 10.35121372
405
+ }
406
+ ]
407
+ }
visualization/SingVisio/webpage/img/difference_bar.jpg ADDED
visualization/SingVisio/webpage/img/syllable.png ADDED
visualization/SingVisio/webpage/index.html ADDED
@@ -0,0 +1,390 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!--
2
+ Copyright (c) 2023 Amphion.
3
+ This source code is licensed under the MIT license found in the
4
+ LICENSE file in the root directory of this source tree。
5
+ -->
6
+
7
+ <!DOCTYPE html>
8
+ <html>
9
+
10
+ <head>
11
+ <meta charset="utf-8">
12
+ <meta name="viewport" content="width=1200px, initial-scale=1.0">
13
+ <title>SingVisio: Visual Analytics of Diffusion Model for Singing Voice Conversion</title>
14
+ <script>
15
+ const baseLink = 'https://dsvc.openmmlab.org.cn'; // end without '/'
16
+ </script>
17
+ <!-- Load Tailwind CSS and D3.js -->
18
+ <script src="./resources/tailwind.js"></script>
19
+ <script src="./resources/d3.v4.min.js"></script>
20
+ <script src="./resources/htl.min.js"></script>
21
+ <script src="./resources/d3-scale-chromatic.v1.min.js"></script>
22
+ <script src="./resources/d3-contour.v1.min.js"></script>
23
+ <!-- Load the Guide driver -->
24
+ <script src="./resources/driver.js.iife.min.js"></script>
25
+ <link rel="stylesheet" href="./resources/driver.min.css">
26
+ <!-- Config Tailwind CSS -->
27
+ <script type="module">
28
+ import cfg from "./tailwind.config.js";
29
+ tailwind.config = cfg;
30
+ </script>
31
+ <style type="text/tailwindcss">
32
+ @layer components {
33
+ .btn-small {
34
+ @apply px-3 py-2 text-xs font-medium text-center text-gray-900 focus:outline-none bg-white rounded-lg border border-gray-200 hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:ring-4 focus:ring-gray-200 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700
35
+ }
36
+ .btn {
37
+ @apply text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 mr-2 mb-2 dark:bg-blue-600 dark:hover:bg-blue-700 focus:outline-none dark:focus:ring-blue-800;
38
+ }
39
+ .btn-sec {
40
+ @apply py-2.5 px-5 mr-2 mb-2 text-sm font-medium text-gray-900 focus:outline-none bg-white rounded-lg border border-gray-200 hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:ring-4 focus:ring-gray-200 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700
41
+ }
42
+ .select-select {
43
+ @apply my-0 py-2 px-1 bg-gray-50 border border-gray-300 text-gray-900 text-xs rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500
44
+ }
45
+ .select-label {
46
+ @apply block text-sm font-medium text-gray-900 dark:text-white;
47
+ }
48
+ .card {
49
+ @apply p-6 bg-white border border-gray-200 rounded-lg dark:bg-gray-800 dark:border-gray-700
50
+ }
51
+ .card-title {
52
+ @apply mb-2 text-base font-bold tracking-tight text-gray-900 dark:text-white
53
+ }
54
+ .timeline-point {
55
+ @apply absolute w-3 h-3 bg-gray-200 rounded-full mt-1.5 -left-1.5 border border-white dark:border-gray-900 dark:bg-gray-700
56
+ }
57
+ .timeline-title {
58
+ @apply text-lg font-semibold text-gray-900 dark:text-white
59
+ }
60
+ .timeline-subtitle {
61
+ @apply text-base font-normal text-gray-500 dark:text-gray-400
62
+ }
63
+ .small-input {
64
+ @apply block w-full p-2 text-gray-900 border border-gray-300 rounded-lg bg-gray-50 sm:text-xs focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500;
65
+ }
66
+ .checkbox {
67
+ @apply w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600
68
+ }
69
+ .dropdown_button_text {
70
+ @apply w-full text-xs font-normal text-gray-900 dark:text-white text-left
71
+ }
72
+ .dropdown_button {
73
+ @apply btn-sec text-xs flex items-center w-full px-2 py-2 my-0 disabled:cursor-not-allowed disabled:opacity-50
74
+ }
75
+ }
76
+ </style>
77
+ <style>
78
+ input.step-axis {
79
+ outline: none;
80
+ -webkit-appearance: none;
81
+ background: #0000002b;
82
+ height: 8px;
83
+ }
84
+
85
+ input.step-axis::-webkit-slider-thumb {
86
+ -webkit-appearance: none;
87
+ position: relative;
88
+ width: 18px;
89
+ height: 18px;
90
+ background: url("./img/syllable.png") no-repeat;
91
+ background-size: 18px;
92
+ border-radius: 50%;
93
+ cursor: pointer;
94
+ }
95
+
96
+ audio {
97
+ outline: none;
98
+ height: 34px;
99
+ }
100
+
101
+ /* make a input with two handles */
102
+ .inputs {
103
+ display: block;
104
+ width: 100%;
105
+ height: 10px;
106
+ /* background-color: azure; */
107
+ }
108
+
109
+ .inputs input {
110
+ position: absolute;
111
+ }
112
+
113
+ .inputs input::-webkit-slider-thumb {
114
+ pointer-events: all;
115
+ z-index: 2;
116
+ }
117
+
118
+ .inputs input::-webkit-slider-runnable-track {
119
+ pointer-events: none;
120
+ z-index: 1;
121
+ }
122
+ </style>
123
+ </head>
124
+
125
+ <body class="bg-gray-100 dark:bg-gray-900">
126
+ <div id="alert"
127
+ class="hidden fixed top-0 right-0 left-0 z-50 w-full h-[100vh] bg-black bg-opacity-50 justify-center items-center overflow-y-hidden">
128
+ <div class="card flex flex-col min-w-[400px] max-w-2xl max-h-[80vh] p-0 overflow-hidden">
129
+ <!-- Modal header -->
130
+ <div class="flex items-center justify-between p-4 md:p-5 border-b rounded-t dark:border-gray-600">
131
+ <h3 id="alert_title" class="text-xl font-semibold text-gray-900 dark:text-white">
132
+ Title
133
+ </h3>
134
+ <button id="close_alert" type="button"
135
+ class="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm w-8 h-8 ms-auto inline-flex justify-center items-center dark:hover:bg-gray-600 dark:hover:text-white">
136
+ <svg class="w-3 h-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none"
137
+ viewBox="0 0 14 14">
138
+ <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
139
+ d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6" />
140
+ </svg>
141
+ <span class="sr-only">Close modal</span>
142
+ </button>
143
+ </div>
144
+ <!-- Modal body -->
145
+ <div id="alert_text"
146
+ class="p-4 md:p-5 space-y-4 text-base leading-relaxed text-gray-700 dark:text-gray-200 overflow-y-auto">
147
+ Text
148
+ </div>
149
+ <!-- Modal footer -->
150
+ <div class="flex items-center p-4 md:p-5 border-t border-gray-200 rounded-b dark:border-gray-600">
151
+ <button id="finish_alert" type="button"
152
+ class="ml-auto text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">OK</button>
153
+ </div>
154
+ </div>
155
+ </div>
156
+ <div class="bg-white dark:bg-gray-800 w-full py-4 px-6 border border-b border-gray-200 dark:border-gray-600">
157
+ <div class="mx-auto max-w-[1490px] grid grid-cols-6 align-center items-center">
158
+ <!-- <img class="dark:hidden" src="img/cuhksz_logo.png" alt="cuhksz logo" class="h-[40px]">
159
+ <img class="hidden dark:block" src="img/cuhksz_logo_white.png" alt="cuhksz logo" class="h-[40px]"> -->
160
+ <span class="col-span-1"></span>
161
+ <span id="title" class="col-span-4 mx-auto font-[800] text-[20px] dark:text-white">SingVisio: Visual
162
+ Analytics of Diffusion Model for Singing Voice Conversion</span>
163
+ <!-- <span class="ml-auto mr-0 text-sm dark:text-white">Team: <i>Human Language Technology Lab,
164
+ CUHK-Shenzhen</i></span> -->
165
+ <div class="flex">
166
+ <button class="btn-small ml-auto" id="mode_change">Switch to _</button>
167
+ <button class="btn-small ml-2" id="help">Help?</button>
168
+ </div>
169
+ </div>
170
+ </div>
171
+ <div class="max-w-[1500px] m-auto">
172
+ <div class="flex flex-row items-start gap-0.5 py-3 p-1">
173
+ <div class="w-[300px] flex flex-col flex-none">
174
+ <div id="performance" class="card p-2 mb-2 flex flex-col flex-none relative">
175
+ <button class="absolute right-1 top-1 btn-small px-1.5 py-0.5 ml-auto rounded-full"
176
+ id="metrics_help">?</button>
177
+ <div class="flex flex-row">
178
+ <div id="histogram" class="flex-none"></div>
179
+ <div id="histogram2" class="flex-none"></div>
180
+ </div>
181
+ <span class="text-[12px] mx-auto dark:text-white">Metrics</span>
182
+ </div>
183
+
184
+ <div id="touch_map" class="card p-2 relative">
185
+ <button class="absolute right-1 top-1 btn-small px-1.5 py-0.5 ml-auto rounded-full"
186
+ id="projection_help">?</button>
187
+ <div class="flex mb-1 align-center items-center space-between dark:text-white">
188
+ <div class="ml-1 text-sm">Step: <span id="current_step_display_number"></span></div>
189
+ <div class="ml-auto flex mr-2">
190
+ <button class="btn-sec h-9 w-9 p-2.5 mb-0" id="reset_map">
191
+ <svg class="w-3.5 h-3.5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg"
192
+ fill="none" viewBox="0 0 18 20">
193
+ <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
194
+ stroke-width="2"
195
+ d="M16 1v5h-5M2 19v-5h5m10-4a8 8 0 0 1-14.947 3.97M1 10a8 8 0 0 1 14.947-3.97" />
196
+ </svg>
197
+ </button>
198
+ </div>
199
+ </div>
200
+ <div id="dataviz_axisZoom" class="flex flex-wrap border bg-white dark:bg-gray-800 relative"></div>
201
+ </div>
202
+ </div>
203
+ <div class="w-full">
204
+ <div id="step_preview" class="flex min-w-[500px] w-full bg-white dark:bg-gray-800 p-2 card mb-2">
205
+ <div class="mx-auto" id="preview_container">
206
+ </div>
207
+ <div class="mx-auto" id="preview_container2">
208
+ </div>
209
+ <div class="flex flex-col">
210
+ <button class="btn-sec" id="refreshpreview">
211
+ <svg class="w-4 h-4" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none"
212
+ viewBox="0 0 18 20">
213
+ <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
214
+ stroke-width="2"
215
+ d="M16 1v5h-5M2 19v-5h5m10-4a8 8 0 0 1-14.947 3.97M1 10a8 8 0 0 1 14.947-3.97" />
216
+ </svg>
217
+ </button>
218
+ </div>
219
+ </div>
220
+ <div id="mel_card_container" class="grid grid-cols-3 min-w-[915px] w-full gap-1 justify-items-center">
221
+ </div>
222
+ <div id="tips">
223
+ </div>
224
+ <div id="tooltip" role="tooltip"
225
+ class="invisible absolute z-10 inline-block px-3 py-2 text-sm font-medium text-white bg-gray-900 rounded-lg shadow-sm opacity-[0.9] dark:bg-gray-700">
226
+ Tooltip content
227
+ </div>
228
+ </div>
229
+ <div class="shrink-0 w-[180px]">
230
+
231
+ <div class="card py-2 px-3 relative">
232
+ <button class="absolute right-1 top-1 btn-small px-1.5 py-0.5 ml-auto rounded-full"
233
+ id="control_help">?</button>
234
+ <div class="flex items-center">
235
+ <h5 class="card-title my-1 text-lg">Control Panel</h5>
236
+ </div>
237
+ <div class="flex flex-col w-full rounded-lg gap-0.5" id="control_panel">
238
+ <div>
239
+ <label for="mode_id" class="select-label">Display Mode</label>
240
+ <select id="mode_id" class="select-select"></select>
241
+ </div>
242
+ <div>
243
+ <label for="sourcesinger_id" class="select-label">Source Singer</label>
244
+ <button id="sourcesinger_id" class="dropdown_button" type="button">
245
+ <span class="dropdown_button_text" id="sourcesinger_id_text">Choose Singer</span> <svg
246
+ class="w-2.5 h-2.5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg"
247
+ fill="none" viewBox="0 0 10 6">
248
+ <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
249
+ stroke-width="2" d="m1 1 4 4 4-4" />
250
+ </svg>
251
+ </button>
252
+ <!-- Dropdown menu -->
253
+ <div id="sourcesinger_id_dropdown"
254
+ class="absolute z-10 hidden bg-white divide-y divide-gray-100 rounded-lg shadow w-44 dark:bg-gray-700">
255
+ <ul class="py-2 text-sm text-gray-700 dark:text-gray-200">
256
+ </ul>
257
+ </div>
258
+ </div>
259
+ <div>
260
+ <label for="song_id" class="select-label">Song</label>
261
+ <button id="song_id" class="dropdown_button" type="button">
262
+ <span class="dropdown_button_text" id="song_id_text">Choose Song</span> <svg
263
+ class="w-2.5 h-2.5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg"
264
+ fill="none" viewBox="0 0 10 6">
265
+ <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
266
+ stroke-width="2" d="m1 1 4 4 4-4" />
267
+ </svg>
268
+ </button>
269
+ <!-- Dropdown menu -->
270
+ <div id="song_id_dropdown"
271
+ class="absolute z-10 hidden bg-white divide-y divide-gray-100 rounded-lg shadow w-44 dark:bg-gray-700">
272
+ <ul class="py-2 text-sm text-gray-700 dark:text-gray-200">
273
+ </ul>
274
+ </div>
275
+ </div>
276
+ <div>
277
+ <label for="target_id" class="select-label">Target Singer</label>
278
+ <button id="target_id" class="dropdown_button" type="button">
279
+ <span class="dropdown_button_text" id="target_id_text">Target Singer</span> <svg
280
+ class="w-2.5 h-2.5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg"
281
+ fill="none" viewBox="0 0 10 6">
282
+ <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
283
+ stroke-width="2" d="m1 1 4 4 4-4" />
284
+ </svg>
285
+ </button>
286
+ <!-- Dropdown menu -->
287
+ <div id="target_id_dropdown"
288
+ class="absolute z-10 hidden bg-white divide-y divide-gray-100 rounded-lg shadow w-44 dark:bg-gray-700">
289
+ <ul class="py-2 text-sm text-gray-700 dark:text-gray-200">
290
+ </ul>
291
+ </div>
292
+ </div>
293
+ <div class="relative">
294
+ <label for="pic_id" class="select-label">Projection Embedding</label>
295
+ <select id="pic_id" class="select-select"></select>
296
+ </div>
297
+ <div class="relative" id="components">
298
+ <label for="components" class="select-label">Components</label>
299
+ <div class="flex flex-col gap-0.5">
300
+ <div class="flex items-center">
301
+ <input id="components_pitch" type="checkbox" checked class="checkbox">
302
+ <label for="components_pitch"
303
+ class="ml-1 text-[0.775rem] font-normal text-gray-900 dark:text-gray-300">F0
304
+ contour</label>
305
+ </div>
306
+ <div class="flex items-start">
307
+ <input id="components_frequncy" type="checkbox" checked class="checkbox">
308
+ <div class="flex flex-col gap-0.5 grow">
309
+ <label for="components_frequncy"
310
+ class="ml-1 mb-1 text-[0.775rem] font-normal text-gray-900 dark:text-gray-300">Frequency</label>
311
+ <div class="flex inputs w-full">
312
+ <input id="inputs_min" type="range"
313
+ class="h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer dark:bg-gray-700"
314
+ value="0" min="0">
315
+ <input id="inputs_max" type="range"
316
+ class="h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer dark:bg-gray-700"
317
+ value="100" max="100">
318
+ </div>
319
+ <div class="flex w-full">
320
+ <span id="inputs_left" class="ml-1 mr-auto text-[0.7rem] font-normal text-gray-900 dark:text-white">0</span>
321
+ <span id="inputs_right" class="mr-2 ml-auto text-[0.7rem] font-normal text-gray-900 dark:text-white">100</span>
322
+ </div>
323
+ </div>
324
+ </div>
325
+
326
+ <div class="flex items-start">
327
+ <input id="sampling_steps" type="checkbox" class="checkbox">
328
+ <div class="flex flex-col grow">
329
+ <label for="sampling_steps"
330
+ class="ml-1 text-[0.775rem] font-normal text-gray-900 dark:text-gray-300">Sampling
331
+ steps</label>
332
+ <div class="flex flex-row h-[32px]">
333
+ <span class="my-auto mx-1 text-[0.775rem] font-normal text-gray-900 dark:text-white">Step count:</span>
334
+ <input type="text"
335
+ class="small-input flex-none w-[50px] text-center bg-white dark:bg-gray-800"
336
+ id="sampling_num" value="100">
337
+ </div>
338
+
339
+ </div>
340
+ </div>
341
+ </div>
342
+ </div>
343
+
344
+
345
+ <div id="step_axis">
346
+ <label for="range" class="select-label">Step Axis</label>
347
+
348
+ <div
349
+ class="items-center w-full rounded-lg bg-gray-50 flex flex-row gap-2 px-2 py-0.5 border border-gray-300 dark:border-gray-600 dark:text-white dark:bg-gray-700">
350
+
351
+ <input class="step-axis my-2 w-full" id="range" type="range" min="0" max="999" value="0"
352
+ step="1">
353
+ <button class="btn-small" id="controls">
354
+ <svg id="icon_play" style="display: none" class="w-3 h-3" aria-hidden="true"
355
+ xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 14 16">
356
+ <path
357
+ d="M0 .984v14.032a1 1 0 0 0 1.506.845l12.006-7.016a.974.974 0 0 0 0-1.69L1.506.139A1 1 0 0 0 0 .984Z" />
358
+ </svg>
359
+ <svg id="icon_stop" class="w-3 h-3" aria-hidden="true"
360
+ xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 12 16">
361
+ <path
362
+ d="M3 0H2a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h1a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2Zm7 0H9a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h1a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2Z" />
363
+ </svg>
364
+ </button>
365
+
366
+ </div>
367
+ <div class="flex gap-1 mt-2">
368
+ <span class="my-auto mr-1 text-sm font-medium text-gray-900 dark:text-white">Step:</span>
369
+ <input type="text"
370
+ class="small-input flex-none w-[60px] text-center bg-white dark:bg-gray-800" id="value">
371
+ <button class="btn-small" id="add_preview">
372
+ Pin
373
+ </button>
374
+ </div>
375
+ </div>
376
+
377
+ </div>
378
+ </div>
379
+ </div>
380
+ </div>
381
+
382
+ </div>
383
+
384
+ <script src="./resources/init.js"></script>
385
+ <script src="./resources/function.js"></script>
386
+ <script src="./resources/event.js"></script>
387
+ <script>
388
+ initConfig('./config/default.json')
389
+ </script>
390
+ </body>