infer_rvc_python 1.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- infer_rvc_python/__init__.py +1 -0
- infer_rvc_python/lib/__init__.py +0 -0
- infer_rvc_python/lib/audio.py +21 -0
- infer_rvc_python/lib/infer_pack/__init__.py +0 -0
- infer_rvc_python/lib/infer_pack/attentions.py +417 -0
- infer_rvc_python/lib/infer_pack/commons.py +166 -0
- infer_rvc_python/lib/infer_pack/models.py +1142 -0
- infer_rvc_python/lib/infer_pack/modules.py +522 -0
- infer_rvc_python/lib/infer_pack/transforms.py +209 -0
- infer_rvc_python/lib/log_config.py +48 -0
- infer_rvc_python/lib/rmvpe.py +422 -0
- infer_rvc_python/main.py +967 -0
- infer_rvc_python/root_pipe.py +454 -0
- infer_rvc_python-1.3.0.dist-info/LICENSE +21 -0
- infer_rvc_python-1.3.0.dist-info/METADATA +175 -0
- infer_rvc_python-1.3.0.dist-info/RECORD +17 -0
- infer_rvc_python-1.3.0.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
import numpy as np, parselmouth, torch, sys
|
|
2
|
+
from time import time as ttime
|
|
3
|
+
import torch.nn.functional as F
|
|
4
|
+
import scipy.signal as signal
|
|
5
|
+
import pyworld, os, traceback, faiss, librosa, torchcrepe
|
|
6
|
+
from scipy import signal
|
|
7
|
+
from functools import lru_cache
|
|
8
|
+
from infer_rvc_python.lib.log_config import logger
|
|
9
|
+
|
|
10
|
+
now_dir = os.getcwd()
|
|
11
|
+
sys.path.append(now_dir)
|
|
12
|
+
|
|
13
|
+
bh, ah = signal.butter(N=5, Wn=48, btype="high", fs=16000)
|
|
14
|
+
|
|
15
|
+
input_audio_path2wav = {}
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@lru_cache
|
|
19
|
+
def cache_harvest_f0(input_audio_path, fs, f0max, f0min, frame_period):
|
|
20
|
+
audio = input_audio_path2wav[input_audio_path]
|
|
21
|
+
f0, t = pyworld.harvest(
|
|
22
|
+
audio,
|
|
23
|
+
fs=fs,
|
|
24
|
+
f0_ceil=f0max,
|
|
25
|
+
f0_floor=f0min,
|
|
26
|
+
frame_period=frame_period,
|
|
27
|
+
)
|
|
28
|
+
f0 = pyworld.stonemask(audio, f0, t, fs)
|
|
29
|
+
return f0
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def change_rms(data1, sr1, data2, sr2, rate): # 1 is the input audio, 2 is the output audio, rate is the proportion of 2
|
|
33
|
+
# print(data1.max(),data2.max())
|
|
34
|
+
rms1 = librosa.feature.rms(
|
|
35
|
+
y=data1, frame_length=sr1 // 2 * 2, hop_length=sr1 // 2
|
|
36
|
+
) # one dot every half second
|
|
37
|
+
rms2 = librosa.feature.rms(y=data2, frame_length=sr2 // 2 * 2, hop_length=sr2 // 2)
|
|
38
|
+
rms1 = torch.from_numpy(rms1)
|
|
39
|
+
rms1 = F.interpolate(
|
|
40
|
+
rms1.unsqueeze(0), size=data2.shape[0], mode="linear"
|
|
41
|
+
).squeeze()
|
|
42
|
+
rms2 = torch.from_numpy(rms2)
|
|
43
|
+
rms2 = F.interpolate(
|
|
44
|
+
rms2.unsqueeze(0), size=data2.shape[0], mode="linear"
|
|
45
|
+
).squeeze()
|
|
46
|
+
rms2 = torch.max(rms2, torch.zeros_like(rms2) + 1e-6)
|
|
47
|
+
data2 *= (
|
|
48
|
+
torch.pow(rms1, torch.tensor(1 - rate))
|
|
49
|
+
* torch.pow(rms2, torch.tensor(rate - 1))
|
|
50
|
+
).numpy()
|
|
51
|
+
return data2
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class VC(object):
|
|
55
|
+
def __init__(self, tgt_sr, config):
|
|
56
|
+
self.x_pad, self.x_query, self.x_center, self.x_max, self.is_half = (
|
|
57
|
+
config.x_pad,
|
|
58
|
+
config.x_query,
|
|
59
|
+
config.x_center,
|
|
60
|
+
config.x_max,
|
|
61
|
+
config.is_half,
|
|
62
|
+
)
|
|
63
|
+
self.sr = 16000 # hubert input sampling rate
|
|
64
|
+
self.window = 160 # points per frame
|
|
65
|
+
self.t_pad = self.sr * self.x_pad # Pad time before and after each bar
|
|
66
|
+
self.t_pad_tgt = tgt_sr * self.x_pad
|
|
67
|
+
self.t_pad2 = self.t_pad * 2
|
|
68
|
+
self.t_query = self.sr * self.x_query # Query time before and after the cut point
|
|
69
|
+
self.t_center = self.sr * self.x_center # Query point cut position
|
|
70
|
+
self.t_max = self.sr * self.x_max # Query-free duration threshold
|
|
71
|
+
self.device = config.device
|
|
72
|
+
|
|
73
|
+
def get_f0(
|
|
74
|
+
self,
|
|
75
|
+
input_audio_path,
|
|
76
|
+
x,
|
|
77
|
+
p_len,
|
|
78
|
+
f0_up_key,
|
|
79
|
+
f0_method,
|
|
80
|
+
filter_radius,
|
|
81
|
+
inp_f0=None,
|
|
82
|
+
):
|
|
83
|
+
global input_audio_path2wav
|
|
84
|
+
time_step = self.window / self.sr * 1000
|
|
85
|
+
f0_min = 50
|
|
86
|
+
f0_max = 1100
|
|
87
|
+
f0_mel_min = 1127 * np.log(1 + f0_min / 700)
|
|
88
|
+
f0_mel_max = 1127 * np.log(1 + f0_max / 700)
|
|
89
|
+
if f0_method == "pm":
|
|
90
|
+
f0 = (
|
|
91
|
+
parselmouth.Sound(x, self.sr)
|
|
92
|
+
.to_pitch_ac(
|
|
93
|
+
time_step=time_step / 1000,
|
|
94
|
+
voicing_threshold=0.6,
|
|
95
|
+
pitch_floor=f0_min,
|
|
96
|
+
pitch_ceiling=f0_max,
|
|
97
|
+
)
|
|
98
|
+
.selected_array["frequency"]
|
|
99
|
+
)
|
|
100
|
+
pad_size = (p_len - len(f0) + 1) // 2
|
|
101
|
+
if pad_size > 0 or p_len - len(f0) - pad_size > 0:
|
|
102
|
+
f0 = np.pad(
|
|
103
|
+
f0, [[pad_size, p_len - len(f0) - pad_size]], mode="constant"
|
|
104
|
+
)
|
|
105
|
+
elif f0_method == "harvest":
|
|
106
|
+
input_audio_path2wav[input_audio_path] = x.astype(np.double)
|
|
107
|
+
f0 = cache_harvest_f0(input_audio_path, self.sr, f0_max, f0_min, 10)
|
|
108
|
+
if filter_radius > 2:
|
|
109
|
+
f0 = signal.medfilt(f0, 3)
|
|
110
|
+
elif f0_method == "crepe":
|
|
111
|
+
model = "full"
|
|
112
|
+
# Pick a batch size that doesn't cause memory errors on your gpu
|
|
113
|
+
batch_size = 512
|
|
114
|
+
# Compute pitch using first gpu
|
|
115
|
+
audio = torch.tensor(np.copy(x))[None].float()
|
|
116
|
+
f0, pd = torchcrepe.predict(
|
|
117
|
+
audio,
|
|
118
|
+
self.sr,
|
|
119
|
+
self.window,
|
|
120
|
+
f0_min,
|
|
121
|
+
f0_max,
|
|
122
|
+
model,
|
|
123
|
+
batch_size=batch_size,
|
|
124
|
+
device=self.device,
|
|
125
|
+
return_periodicity=True,
|
|
126
|
+
)
|
|
127
|
+
pd = torchcrepe.filter.median(pd, 3)
|
|
128
|
+
f0 = torchcrepe.filter.mean(f0, 3)
|
|
129
|
+
f0[pd < 0.1] = 0
|
|
130
|
+
f0 = f0[0].cpu().numpy()
|
|
131
|
+
elif "rmvpe" in f0_method:
|
|
132
|
+
if hasattr(self, "model_rmvpe") == False:
|
|
133
|
+
from infer_rvc_python.lib.rmvpe import RMVPE
|
|
134
|
+
|
|
135
|
+
logger.info("Loading vocal pitch estimator model")
|
|
136
|
+
self.model_rmvpe = RMVPE(
|
|
137
|
+
"rmvpe.pt", is_half=self.is_half, device=self.device
|
|
138
|
+
)
|
|
139
|
+
thred = 0.03
|
|
140
|
+
if "+" in f0_method:
|
|
141
|
+
f0 = self.model_rmvpe.pitch_based_audio_inference(x, thred, f0_min, f0_max)
|
|
142
|
+
else:
|
|
143
|
+
f0 = self.model_rmvpe.infer_from_audio(x, thred)
|
|
144
|
+
|
|
145
|
+
f0 *= pow(2, f0_up_key / 12)
|
|
146
|
+
# with open("test.txt","w")as f:f.write("\n".join([str(i)for i in f0.tolist()]))
|
|
147
|
+
tf0 = self.sr // self.window # f0 points per second
|
|
148
|
+
if inp_f0 is not None:
|
|
149
|
+
delta_t = np.round(
|
|
150
|
+
(inp_f0[:, 0].max() - inp_f0[:, 0].min()) * tf0 + 1
|
|
151
|
+
).astype("int16")
|
|
152
|
+
replace_f0 = np.interp(
|
|
153
|
+
list(range(delta_t)), inp_f0[:, 0] * 100, inp_f0[:, 1]
|
|
154
|
+
)
|
|
155
|
+
shape = f0[self.x_pad * tf0 : self.x_pad * tf0 + len(replace_f0)].shape[0]
|
|
156
|
+
f0[self.x_pad * tf0 : self.x_pad * tf0 + len(replace_f0)] = replace_f0[
|
|
157
|
+
:shape
|
|
158
|
+
]
|
|
159
|
+
# with open("test_opt.txt","w")as f:f.write("\n".join([str(i)for i in f0.tolist()]))
|
|
160
|
+
f0bak = f0.copy()
|
|
161
|
+
f0_mel = 1127 * np.log(1 + f0 / 700)
|
|
162
|
+
f0_mel[f0_mel > 0] = (f0_mel[f0_mel > 0] - f0_mel_min) * 254 / (
|
|
163
|
+
f0_mel_max - f0_mel_min
|
|
164
|
+
) + 1
|
|
165
|
+
f0_mel[f0_mel <= 1] = 1
|
|
166
|
+
f0_mel[f0_mel > 255] = 255
|
|
167
|
+
try:
|
|
168
|
+
f0_coarse = np.rint(f0_mel).astype(np.int)
|
|
169
|
+
except: # noqa
|
|
170
|
+
f0_coarse = np.rint(f0_mel).astype(int)
|
|
171
|
+
return f0_coarse, f0bak # 1-0
|
|
172
|
+
|
|
173
|
+
def vc(
|
|
174
|
+
self,
|
|
175
|
+
model,
|
|
176
|
+
net_g,
|
|
177
|
+
sid,
|
|
178
|
+
audio0,
|
|
179
|
+
pitch,
|
|
180
|
+
pitchf,
|
|
181
|
+
times,
|
|
182
|
+
index,
|
|
183
|
+
big_npy,
|
|
184
|
+
index_rate,
|
|
185
|
+
version,
|
|
186
|
+
protect,
|
|
187
|
+
): # ,file_index,file_big_npy
|
|
188
|
+
feats = torch.from_numpy(audio0)
|
|
189
|
+
if self.is_half:
|
|
190
|
+
feats = feats.half()
|
|
191
|
+
else:
|
|
192
|
+
feats = feats.float()
|
|
193
|
+
if feats.dim() == 2: # double channels
|
|
194
|
+
feats = feats.mean(-1)
|
|
195
|
+
assert feats.dim() == 1, feats.dim()
|
|
196
|
+
feats = feats.view(1, -1)
|
|
197
|
+
padding_mask = torch.BoolTensor(feats.shape).to(self.device).fill_(False)
|
|
198
|
+
|
|
199
|
+
inputs = {
|
|
200
|
+
"source": feats.to(self.device),
|
|
201
|
+
"padding_mask": padding_mask,
|
|
202
|
+
"output_layer": 9 if version == "v1" else 12,
|
|
203
|
+
}
|
|
204
|
+
t0 = ttime()
|
|
205
|
+
with torch.no_grad():
|
|
206
|
+
logits = model.extract_features(**inputs)
|
|
207
|
+
feats = model.final_proj(logits[0]) if version == "v1" else logits[0]
|
|
208
|
+
if protect < 0.5 and pitch != None and pitchf != None:
|
|
209
|
+
feats0 = feats.clone()
|
|
210
|
+
if (
|
|
211
|
+
isinstance(index, type(None)) == False
|
|
212
|
+
and isinstance(big_npy, type(None)) == False
|
|
213
|
+
and index_rate != 0
|
|
214
|
+
):
|
|
215
|
+
npy = feats[0].cpu().numpy()
|
|
216
|
+
if self.is_half:
|
|
217
|
+
npy = npy.astype("float32")
|
|
218
|
+
|
|
219
|
+
# _, I = index.search(npy, 1)
|
|
220
|
+
# npy = big_npy[I.squeeze()]
|
|
221
|
+
|
|
222
|
+
score, ix = index.search(npy, k=8)
|
|
223
|
+
weight = np.square(1 / score)
|
|
224
|
+
weight /= weight.sum(axis=1, keepdims=True)
|
|
225
|
+
npy = np.sum(big_npy[ix] * np.expand_dims(weight, axis=2), axis=1)
|
|
226
|
+
|
|
227
|
+
if self.is_half:
|
|
228
|
+
npy = npy.astype("float16")
|
|
229
|
+
feats = (
|
|
230
|
+
torch.from_numpy(npy).unsqueeze(0).to(self.device) * index_rate
|
|
231
|
+
+ (1 - index_rate) * feats
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
feats = F.interpolate(feats.permute(0, 2, 1), scale_factor=2).permute(0, 2, 1)
|
|
235
|
+
if protect < 0.5 and pitch != None and pitchf != None:
|
|
236
|
+
feats0 = F.interpolate(feats0.permute(0, 2, 1), scale_factor=2).permute(
|
|
237
|
+
0, 2, 1
|
|
238
|
+
)
|
|
239
|
+
t1 = ttime()
|
|
240
|
+
p_len = audio0.shape[0] // self.window
|
|
241
|
+
if feats.shape[1] < p_len:
|
|
242
|
+
p_len = feats.shape[1]
|
|
243
|
+
if pitch != None and pitchf != None:
|
|
244
|
+
pitch = pitch[:, :p_len]
|
|
245
|
+
pitchf = pitchf[:, :p_len]
|
|
246
|
+
|
|
247
|
+
if protect < 0.5 and pitch != None and pitchf != None:
|
|
248
|
+
pitchff = pitchf.clone()
|
|
249
|
+
pitchff[pitchf > 0] = 1
|
|
250
|
+
pitchff[pitchf < 1] = protect
|
|
251
|
+
pitchff = pitchff.unsqueeze(-1)
|
|
252
|
+
feats = feats * pitchff + feats0 * (1 - pitchff)
|
|
253
|
+
feats = feats.to(feats0.dtype)
|
|
254
|
+
p_len = torch.tensor([p_len], device=self.device).long()
|
|
255
|
+
with torch.no_grad():
|
|
256
|
+
if pitch != None and pitchf != None:
|
|
257
|
+
audio1 = (
|
|
258
|
+
(net_g.infer(feats, p_len, pitch, pitchf, sid)[0][0, 0])
|
|
259
|
+
.data.cpu()
|
|
260
|
+
.float()
|
|
261
|
+
.numpy()
|
|
262
|
+
)
|
|
263
|
+
else:
|
|
264
|
+
audio1 = (
|
|
265
|
+
(net_g.infer(feats, p_len, sid)[0][0, 0]).data.cpu().float().numpy()
|
|
266
|
+
)
|
|
267
|
+
del feats, p_len, padding_mask
|
|
268
|
+
if torch.cuda.is_available():
|
|
269
|
+
torch.cuda.empty_cache()
|
|
270
|
+
t2 = ttime()
|
|
271
|
+
times[0] += t1 - t0
|
|
272
|
+
times[2] += t2 - t1
|
|
273
|
+
return audio1
|
|
274
|
+
|
|
275
|
+
def pipeline(
|
|
276
|
+
self,
|
|
277
|
+
model,
|
|
278
|
+
net_g,
|
|
279
|
+
sid,
|
|
280
|
+
audio,
|
|
281
|
+
input_audio_path,
|
|
282
|
+
times,
|
|
283
|
+
f0_up_key,
|
|
284
|
+
f0_method,
|
|
285
|
+
file_index,
|
|
286
|
+
# file_big_npy,
|
|
287
|
+
index_rate,
|
|
288
|
+
if_f0,
|
|
289
|
+
filter_radius,
|
|
290
|
+
tgt_sr,
|
|
291
|
+
resample_sr,
|
|
292
|
+
rms_mix_rate,
|
|
293
|
+
version,
|
|
294
|
+
protect,
|
|
295
|
+
f0_file=None,
|
|
296
|
+
):
|
|
297
|
+
if (
|
|
298
|
+
file_index != ""
|
|
299
|
+
# and file_big_npy != ""
|
|
300
|
+
# and os.path.exists(file_big_npy) == True
|
|
301
|
+
and os.path.exists(file_index) == True
|
|
302
|
+
and index_rate != 0
|
|
303
|
+
):
|
|
304
|
+
try:
|
|
305
|
+
index = faiss.read_index(file_index)
|
|
306
|
+
# big_npy = np.load(file_big_npy)
|
|
307
|
+
big_npy = index.reconstruct_n(0, index.ntotal)
|
|
308
|
+
except:
|
|
309
|
+
traceback.print_exc()
|
|
310
|
+
index = big_npy = None
|
|
311
|
+
else:
|
|
312
|
+
index = big_npy = None
|
|
313
|
+
logger.warning("File index Not found, set None")
|
|
314
|
+
|
|
315
|
+
audio = signal.filtfilt(bh, ah, audio)
|
|
316
|
+
audio_pad = np.pad(audio, (self.window // 2, self.window // 2), mode="reflect")
|
|
317
|
+
opt_ts = []
|
|
318
|
+
if audio_pad.shape[0] > self.t_max:
|
|
319
|
+
audio_sum = np.zeros_like(audio)
|
|
320
|
+
for i in range(self.window):
|
|
321
|
+
audio_sum += audio_pad[i : i - self.window]
|
|
322
|
+
for t in range(self.t_center, audio.shape[0], self.t_center):
|
|
323
|
+
opt_ts.append(
|
|
324
|
+
t
|
|
325
|
+
- self.t_query
|
|
326
|
+
+ np.where(
|
|
327
|
+
np.abs(audio_sum[t - self.t_query : t + self.t_query])
|
|
328
|
+
== np.abs(audio_sum[t - self.t_query : t + self.t_query]).min()
|
|
329
|
+
)[0][0]
|
|
330
|
+
)
|
|
331
|
+
s = 0
|
|
332
|
+
audio_opt = []
|
|
333
|
+
t = None
|
|
334
|
+
t1 = ttime()
|
|
335
|
+
audio_pad = np.pad(audio, (self.t_pad, self.t_pad), mode="reflect")
|
|
336
|
+
p_len = audio_pad.shape[0] // self.window
|
|
337
|
+
inp_f0 = None
|
|
338
|
+
if hasattr(f0_file, "name") == True:
|
|
339
|
+
try:
|
|
340
|
+
with open(f0_file.name, "r") as f:
|
|
341
|
+
lines = f.read().strip("\n").split("\n")
|
|
342
|
+
inp_f0 = []
|
|
343
|
+
for line in lines:
|
|
344
|
+
inp_f0.append([float(i) for i in line.split(",")])
|
|
345
|
+
inp_f0 = np.array(inp_f0, dtype="float32")
|
|
346
|
+
except:
|
|
347
|
+
traceback.print_exc()
|
|
348
|
+
sid = torch.tensor(sid, device=self.device).unsqueeze(0).long()
|
|
349
|
+
pitch, pitchf = None, None
|
|
350
|
+
if if_f0 == 1:
|
|
351
|
+
pitch, pitchf = self.get_f0(
|
|
352
|
+
input_audio_path,
|
|
353
|
+
audio_pad,
|
|
354
|
+
p_len,
|
|
355
|
+
f0_up_key,
|
|
356
|
+
f0_method,
|
|
357
|
+
filter_radius,
|
|
358
|
+
inp_f0,
|
|
359
|
+
)
|
|
360
|
+
pitch = pitch[:p_len]
|
|
361
|
+
pitchf = pitchf[:p_len]
|
|
362
|
+
if self.device == "mps":
|
|
363
|
+
pitchf = pitchf.astype(np.float32)
|
|
364
|
+
pitch = torch.tensor(pitch, device=self.device).unsqueeze(0).long()
|
|
365
|
+
pitchf = torch.tensor(pitchf, device=self.device).unsqueeze(0).float()
|
|
366
|
+
t2 = ttime()
|
|
367
|
+
times[1] += t2 - t1
|
|
368
|
+
for t in opt_ts:
|
|
369
|
+
t = t // self.window * self.window
|
|
370
|
+
if if_f0 == 1:
|
|
371
|
+
audio_opt.append(
|
|
372
|
+
self.vc(
|
|
373
|
+
model,
|
|
374
|
+
net_g,
|
|
375
|
+
sid,
|
|
376
|
+
audio_pad[s : t + self.t_pad2 + self.window],
|
|
377
|
+
pitch[:, s // self.window : (t + self.t_pad2) // self.window],
|
|
378
|
+
pitchf[:, s // self.window : (t + self.t_pad2) // self.window],
|
|
379
|
+
times,
|
|
380
|
+
index,
|
|
381
|
+
big_npy,
|
|
382
|
+
index_rate,
|
|
383
|
+
version,
|
|
384
|
+
protect,
|
|
385
|
+
)[self.t_pad_tgt : -self.t_pad_tgt]
|
|
386
|
+
)
|
|
387
|
+
else:
|
|
388
|
+
audio_opt.append(
|
|
389
|
+
self.vc(
|
|
390
|
+
model,
|
|
391
|
+
net_g,
|
|
392
|
+
sid,
|
|
393
|
+
audio_pad[s : t + self.t_pad2 + self.window],
|
|
394
|
+
None,
|
|
395
|
+
None,
|
|
396
|
+
times,
|
|
397
|
+
index,
|
|
398
|
+
big_npy,
|
|
399
|
+
index_rate,
|
|
400
|
+
version,
|
|
401
|
+
protect,
|
|
402
|
+
)[self.t_pad_tgt : -self.t_pad_tgt]
|
|
403
|
+
)
|
|
404
|
+
s = t
|
|
405
|
+
if if_f0 == 1:
|
|
406
|
+
audio_opt.append(
|
|
407
|
+
self.vc(
|
|
408
|
+
model,
|
|
409
|
+
net_g,
|
|
410
|
+
sid,
|
|
411
|
+
audio_pad[t:],
|
|
412
|
+
pitch[:, t // self.window :] if t is not None else pitch,
|
|
413
|
+
pitchf[:, t // self.window :] if t is not None else pitchf,
|
|
414
|
+
times,
|
|
415
|
+
index,
|
|
416
|
+
big_npy,
|
|
417
|
+
index_rate,
|
|
418
|
+
version,
|
|
419
|
+
protect,
|
|
420
|
+
)[self.t_pad_tgt : -self.t_pad_tgt]
|
|
421
|
+
)
|
|
422
|
+
else:
|
|
423
|
+
audio_opt.append(
|
|
424
|
+
self.vc(
|
|
425
|
+
model,
|
|
426
|
+
net_g,
|
|
427
|
+
sid,
|
|
428
|
+
audio_pad[t:],
|
|
429
|
+
None,
|
|
430
|
+
None,
|
|
431
|
+
times,
|
|
432
|
+
index,
|
|
433
|
+
big_npy,
|
|
434
|
+
index_rate,
|
|
435
|
+
version,
|
|
436
|
+
protect,
|
|
437
|
+
)[self.t_pad_tgt : -self.t_pad_tgt]
|
|
438
|
+
)
|
|
439
|
+
audio_opt = np.concatenate(audio_opt)
|
|
440
|
+
if rms_mix_rate != 1:
|
|
441
|
+
audio_opt = change_rms(audio, 16000, audio_opt, tgt_sr, rms_mix_rate)
|
|
442
|
+
if resample_sr >= 16000 and tgt_sr != resample_sr:
|
|
443
|
+
audio_opt = librosa.resample(
|
|
444
|
+
audio_opt, orig_sr=tgt_sr, target_sr=resample_sr
|
|
445
|
+
)
|
|
446
|
+
audio_max = np.abs(audio_opt).max() / 0.99
|
|
447
|
+
max_int16 = 32768
|
|
448
|
+
if audio_max > 1:
|
|
449
|
+
max_int16 /= audio_max
|
|
450
|
+
audio_opt = (audio_opt * max_int16).astype(np.int16)
|
|
451
|
+
del pitch, pitchf, sid
|
|
452
|
+
if torch.cuda.is_available():
|
|
453
|
+
torch.cuda.empty_cache()
|
|
454
|
+
return audio_opt
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Roger Condori
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: infer_rvc_python
|
|
3
|
+
Version: 1.3.0
|
|
4
|
+
Summary: Python wrapper for fast inference with rvc
|
|
5
|
+
Home-page: https://github.com/R3gm/infer_rvc_python
|
|
6
|
+
License: MIT
|
|
7
|
+
Author: R3gm
|
|
8
|
+
Requires-Python: >=3.10,<4.0
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Provides-Extra: all
|
|
16
|
+
Requires-Dist: edge-tts ; extra == "all"
|
|
17
|
+
Requires-Dist: faiss-cpu (==1.10.0)
|
|
18
|
+
Requires-Dist: ffmpeg-python (>=0.2.0)
|
|
19
|
+
Requires-Dist: librosa
|
|
20
|
+
Requires-Dist: numba (==0.56.4) ; extra == "all"
|
|
21
|
+
Requires-Dist: numpy
|
|
22
|
+
Requires-Dist: praat-parselmouth (>=0.4.2)
|
|
23
|
+
Requires-Dist: pyworld (==0.3.4)
|
|
24
|
+
Requires-Dist: scipy ; extra == "all"
|
|
25
|
+
Requires-Dist: soundfile
|
|
26
|
+
Requires-Dist: soxr (==1.1.0)
|
|
27
|
+
Requires-Dist: torch
|
|
28
|
+
Requires-Dist: torchaudio
|
|
29
|
+
Requires-Dist: torchcrepe (==0.0.20)
|
|
30
|
+
Requires-Dist: torchvision
|
|
31
|
+
Requires-Dist: transformers
|
|
32
|
+
Requires-Dist: typeguard (==4.2.0)
|
|
33
|
+
Project-URL: Repository, https://github.com/R3gm/infer_rvc_python
|
|
34
|
+
Description-Content-Type: text/markdown
|
|
35
|
+
|
|
36
|
+
# RVC-Python-Fast Inference
|
|
37
|
+
|
|
38
|
+
A streamlined Python wrapper for fast inference with RVC.
|
|
39
|
+
Specifically designed for inference tasks.
|
|
40
|
+
|
|
41
|
+
## Introduction
|
|
42
|
+
|
|
43
|
+
This streamlined wrapper offers an efficient solution for integrating RVC into your Python projects, focusing primarily on rapid inference. Whether you're working on voice conversion applications or related projects, this tool simplifies the process while maintaining performance.
|
|
44
|
+
|
|
45
|
+
## Key Features
|
|
46
|
+
- Preloaded Models: Accelerate inference by loading models into memory beforehand, minimizing latency during runtime.
|
|
47
|
+
- Batch Processing: Enhance efficiency by enabling batch processing, allowing for simultaneous conversion of multiple inputs, further optimizing throughput.
|
|
48
|
+
- Support for Array Input and Output: Facilitate seamless integration with existing data pipelines by accepting and returning arrays, enhancing compatibility across various platforms and frameworks.
|
|
49
|
+
|
|
50
|
+
## Getting Started
|
|
51
|
+
|
|
52
|
+
### Prerequisites
|
|
53
|
+
|
|
54
|
+
- You need to have ffmpeg and Python installed.
|
|
55
|
+
|
|
56
|
+
Pre-requirements:
|
|
57
|
+
```
|
|
58
|
+
pip install pip>=24 setuptools<=80.6.0
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Installation
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
pip install infer_rvc_python
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
# Usage
|
|
68
|
+
|
|
69
|
+
## Initialize the base class
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
from infer_rvc_python import BaseLoader
|
|
73
|
+
|
|
74
|
+
converter = BaseLoader(only_cpu=False, hubert_path=None, rmvpe_path=None)
|
|
75
|
+
```
|
|
76
|
+
`hubert_path` now accepts a pretrained model instead of a `.pt` file, with `r3gm/hubert_base` as the default value.
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
## Define a tag and select the model along with other parameters.
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
converter.apply_conf(
|
|
83
|
+
tag="yoimiya",
|
|
84
|
+
file_model="model.pth",
|
|
85
|
+
pitch_algo="rmvpe+",
|
|
86
|
+
pitch_lvl=0,
|
|
87
|
+
file_index="model.index",
|
|
88
|
+
index_influence=0.66,
|
|
89
|
+
respiration_median_filtering=3,
|
|
90
|
+
envelope_ratio=0.25,
|
|
91
|
+
consonant_breath_protection=0.33
|
|
92
|
+
)
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Select the audio or audios you want to convert.
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
# audio_files = ["audio.wav", "haha.mp3"]
|
|
99
|
+
audio_files = "myaudio.mp3"
|
|
100
|
+
|
|
101
|
+
# speakers_list = ["sunshine", "yoimiya"]
|
|
102
|
+
speakers_list = "yoimiya"
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Perform inference
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
result = converter(
|
|
109
|
+
audio_files,
|
|
110
|
+
speakers_list,
|
|
111
|
+
overwrite=False,
|
|
112
|
+
parallel_workers=4
|
|
113
|
+
)
|
|
114
|
+
```
|
|
115
|
+
The `result` is a list with the paths of the converted files.
|
|
116
|
+
|
|
117
|
+
## Unload models
|
|
118
|
+
```
|
|
119
|
+
converter.unload_models()
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
# Preloading model (Reduces inference time)
|
|
123
|
+
|
|
124
|
+
The initial execution will preload the model for the tag. Subsequent calls to inference with the same tag will benefit from preloaded components, thereby reducing inference time.
|
|
125
|
+
```
|
|
126
|
+
result_array, sample_rate = converter.generate_from_cache(
|
|
127
|
+
audio_data="myaudiofile_path.wav",
|
|
128
|
+
tag="yoimiya",
|
|
129
|
+
)
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
The param audio_data can be a path or a tuple with (array_data, sampling_rate)
|
|
133
|
+
|
|
134
|
+
```
|
|
135
|
+
# array_data = np.array([-22, -22, -15, ..., 0, 0, 0], dtype=np.int16)
|
|
136
|
+
# source_sample_rate = 16000
|
|
137
|
+
data = (array_data, source_sample_rate)
|
|
138
|
+
result_array, sample_rate = converter.generate_from_cache(
|
|
139
|
+
audio_data=data,
|
|
140
|
+
tag="yoimiya",
|
|
141
|
+
)
|
|
142
|
+
```
|
|
143
|
+
The result in both cases will be (array, sample_rate), which you can save or play in a notebook
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
# Save
|
|
147
|
+
import soundfile as sf
|
|
148
|
+
|
|
149
|
+
sf.write(
|
|
150
|
+
file="output_file.wav",
|
|
151
|
+
samplerate=sample_rate,
|
|
152
|
+
data=result_array
|
|
153
|
+
)
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
```
|
|
157
|
+
# Play; need to install ipython
|
|
158
|
+
from IPython.display import Audio
|
|
159
|
+
|
|
160
|
+
Audio(result_array, rate=sample_rate)
|
|
161
|
+
```
|
|
162
|
+
When settings or the tag are altered, the model requires reloading. To maintain multiple preloaded models, you can instantiate another BaseLoader object.
|
|
163
|
+
```
|
|
164
|
+
second_converter = BaseLoader()
|
|
165
|
+
```
|
|
166
|
+
# Credits
|
|
167
|
+
- RVC-Project
|
|
168
|
+
- FFMPEG
|
|
169
|
+
|
|
170
|
+
# License
|
|
171
|
+
This project is licensed under the MIT License.
|
|
172
|
+
|
|
173
|
+
# Disclaimer
|
|
174
|
+
This software is provided for educational and research purposes only. The authors and contributors of this project do not endorse or encourage any misuse or unethical use of this software. Any use of this software for purposes other than those intended is solely at the user's own risk. The authors and contributors shall not be held responsible for any damages or liabilities arising from the use of this software inappropriately.
|
|
175
|
+
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
infer_rvc_python/__init__.py,sha256=HsKnDUG34kbP3xSWmF9jua-u6zWFuBbNNT-ti3tNnSk,30
|
|
2
|
+
infer_rvc_python/lib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
+
infer_rvc_python/lib/audio.py,sha256=_0S3LBwvTtjVccSNJSVKEFEQUdU8dqqggLOsf62yikQ,924
|
|
4
|
+
infer_rvc_python/lib/infer_pack/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
+
infer_rvc_python/lib/infer_pack/attentions.py,sha256=SmdbDjD-xQf7PU8q9J0tZYo-mtUI3z1gcgDKP2wlCyU,14962
|
|
6
|
+
infer_rvc_python/lib/infer_pack/commons.py,sha256=WuR2iuA9m603iPX8mkVmcVEksMwsdomOA_v1DCNsj74,5317
|
|
7
|
+
infer_rvc_python/lib/infer_pack/models.py,sha256=mpNRxstdAIcrz6-1KF8dn9ffeeawHqwQXdeCalQ2s7o,40590
|
|
8
|
+
infer_rvc_python/lib/infer_pack/modules.py,sha256=y50TwUWaMmAU3h2qVgnhjnHCNB6VWQam3_gmdbECbhw,17203
|
|
9
|
+
infer_rvc_python/lib/infer_pack/transforms.py,sha256=Z4gQq5vd1JdSEad68IjUI6aWHVFGIQK7VKVLZI7t7jE,7462
|
|
10
|
+
infer_rvc_python/lib/log_config.py,sha256=HxfMXpVrJwqe85JCLnW4eNukMFV1LltYttiqbfuDntY,1106
|
|
11
|
+
infer_rvc_python/lib/rmvpe.py,sha256=vjKdR2QdEODhKgZoQ20bQR2zDsOkd2oIhDjx2gu4ZAU,14551
|
|
12
|
+
infer_rvc_python/main.py,sha256=-FY3XvusRK2E7F-4p_vLx2aT34pCPU-4WYQCx-49wl0,31502
|
|
13
|
+
infer_rvc_python/root_pipe.py,sha256=CmYh6rOXi8K4Y7fgLpdQc_rO-T8dNMr-3fl95mcPi3A,16526
|
|
14
|
+
infer_rvc_python-1.3.0.dist-info/LICENSE,sha256=8BAVpQQ-sP3ZmHViWyYI7_vjx7FPZqafwK_dXaaQhX0,1070
|
|
15
|
+
infer_rvc_python-1.3.0.dist-info/METADATA,sha256=O7xY_Xz8f0wzEKkwxEh6qW04XvoCSmOAGDtN5XC7q80,5196
|
|
16
|
+
infer_rvc_python-1.3.0.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
|
|
17
|
+
infer_rvc_python-1.3.0.dist-info/RECORD,,
|