NeoPy commited on
Commit
5850597
·
verified ·
1 Parent(s): a0dea8f

Update vc_infer_pipeline.py

Browse files
Files changed (1) hide show
  1. vc_infer_pipeline.py +383 -36
vc_infer_pipeline.py CHANGED
@@ -1,28 +1,276 @@
1
- import numpy as np, parselmouth, torch, pdb
2
  from time import time as ttime
 
 
 
 
 
 
 
 
 
3
  import torch.nn.functional as F
4
- from config import x_pad, x_query, x_center, x_max
5
- import scipy.signal as signal
6
- import pyworld, os, traceback, faiss
7
  from scipy import signal
 
 
 
 
 
8
 
9
  bh, ah = signal.butter(N=5, Wn=48, btype="high", fs=16000)
10
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
 
12
  class VC(object):
13
- def __init__(self, tgt_sr, device, is_half):
 
 
 
 
 
 
 
14
  self.sr = 16000 # hubert输入采样率
15
  self.window = 160 # 每帧点数
16
- self.t_pad = self.sr * x_pad # 每条前后pad时间
17
- self.t_pad_tgt = tgt_sr * x_pad
18
  self.t_pad2 = self.t_pad * 2
19
- self.t_query = self.sr * x_query # 查询切点前后查询时间
20
- self.t_center = self.sr * x_center # 查询切点位置
21
- self.t_max = self.sr * x_max # 免查询时长阈值
22
- self.device = device
23
- self.is_half = is_half
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
 
25
- def get_f0(self, x, p_len, f0_up_key, f0_method, inp_f0=None):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
  time_step = self.window / self.sr * 1000
27
  f0_min = 50
28
  f0_max = 1100
@@ -45,7 +293,12 @@ class VC(object):
45
  f0, [[pad_size, p_len - len(f0) - pad_size]], mode="constant"
46
  )
47
  elif f0_method == "harvest":
48
- f0, t = pyworld.harvest(
 
 
 
 
 
49
  x.astype(np.double),
50
  fs=self.sr,
51
  f0_ceil=f0_max,
@@ -54,6 +307,42 @@ class VC(object):
54
  )
55
  f0 = pyworld.stonemask(x.astype(np.double), f0, t, self.sr)
56
  f0 = signal.medfilt(f0, 3)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
  f0 *= pow(2, f0_up_key / 12)
58
  # with open("test.txt","w")as f:f.write("\n".join([str(i)for i in f0.tolist()]))
59
  tf0 = self.sr // self.window # 每秒f0点数
@@ -64,8 +353,10 @@ class VC(object):
64
  replace_f0 = np.interp(
65
  list(range(delta_t)), inp_f0[:, 0] * 100, inp_f0[:, 1]
66
  )
67
- shape = f0[x_pad * tf0 : x_pad * tf0 + len(replace_f0)].shape[0]
68
- f0[x_pad * tf0 : x_pad * tf0 + len(replace_f0)] = replace_f0[:shape]
 
 
69
  # with open("test_opt.txt","w")as f:f.write("\n".join([str(i)for i in f0.tolist()]))
70
  f0bak = f0.copy()
71
  f0_mel = 1127 * np.log(1 + f0 / 700)
@@ -75,6 +366,7 @@ class VC(object):
75
  f0_mel[f0_mel <= 1] = 1
76
  f0_mel[f0_mel > 255] = 255
77
  f0_coarse = np.rint(f0_mel).astype(np.int)
 
78
  return f0_coarse, f0bak # 1-0
79
 
80
  def vc(
@@ -89,6 +381,8 @@ class VC(object):
89
  index,
90
  big_npy,
91
  index_rate,
 
 
92
  ): # ,file_index,file_big_npy
93
  feats = torch.from_numpy(audio0)
94
  if self.is_half:
@@ -104,13 +398,14 @@ class VC(object):
104
  inputs = {
105
  "source": feats.to(self.device),
106
  "padding_mask": padding_mask,
107
- "output_layer": 9, # layer 9
108
  }
109
  t0 = ttime()
110
  with torch.no_grad():
111
  logits = model.extract_features(**inputs)
112
- feats = model.final_proj(logits[0])
113
-
 
114
  if (
115
  isinstance(index, type(None)) == False
116
  and isinstance(big_npy, type(None)) == False
@@ -119,8 +414,15 @@ class VC(object):
119
  npy = feats[0].cpu().numpy()
120
  if self.is_half:
121
  npy = npy.astype("float32")
122
- _, I = index.search(npy, 1)
123
- npy = big_npy[I.squeeze()]
 
 
 
 
 
 
 
124
  if self.is_half:
125
  npy = npy.astype("float16")
126
  feats = (
@@ -129,6 +431,10 @@ class VC(object):
129
  )
130
 
131
  feats = F.interpolate(feats.permute(0, 2, 1), scale_factor=2).permute(0, 2, 1)
 
 
 
 
132
  t1 = ttime()
133
  p_len = audio0.shape[0] // self.window
134
  if feats.shape[1] < p_len:
@@ -136,23 +442,26 @@ class VC(object):
136
  if pitch != None and pitchf != None:
137
  pitch = pitch[:, :p_len]
138
  pitchf = pitchf[:, :p_len]
 
 
 
 
 
 
 
 
139
  p_len = torch.tensor([p_len], device=self.device).long()
140
  with torch.no_grad():
141
  if pitch != None and pitchf != None:
142
  audio1 = (
143
- (net_g.infer(feats, p_len, pitch, pitchf, sid)[0][0, 0] * 32768)
144
  .data.cpu()
145
  .float()
146
  .numpy()
147
- .astype(np.int16)
148
  )
149
  else:
150
  audio1 = (
151
- (net_g.infer(feats, p_len, sid)[0][0, 0] * 32768)
152
- .data.cpu()
153
- .float()
154
- .numpy()
155
- .astype(np.int16)
156
  )
157
  del feats, p_len, padding_mask
158
  if torch.cuda.is_available():
@@ -168,31 +477,39 @@ class VC(object):
168
  net_g,
169
  sid,
170
  audio,
 
171
  times,
172
  f0_up_key,
173
  f0_method,
174
  file_index,
175
- file_big_npy,
176
  index_rate,
177
  if_f0,
 
 
 
 
 
 
 
178
  f0_file=None,
179
  ):
180
  if (
181
- file_big_npy != ""
182
- and file_index != ""
183
- and os.path.exists(file_big_npy) == True
184
  and os.path.exists(file_index) == True
185
  and index_rate != 0
186
  ):
187
  try:
188
  index = faiss.read_index(file_index)
189
- big_npy = np.load(file_big_npy)
 
190
  except:
191
  traceback.print_exc()
192
  index = big_npy = None
193
  else:
194
  index = big_npy = None
195
- print("Feature retrieval library doesn't exist or ratio is 0")
196
  audio = signal.filtfilt(bh, ah, audio)
197
  audio_pad = np.pad(audio, (self.window // 2, self.window // 2), mode="reflect")
198
  opt_ts = []
@@ -229,9 +546,20 @@ class VC(object):
229
  sid = torch.tensor(sid, device=self.device).unsqueeze(0).long()
230
  pitch, pitchf = None, None
231
  if if_f0 == 1:
232
- pitch, pitchf = self.get_f0(audio_pad, p_len, f0_up_key, f0_method, inp_f0)
 
 
 
 
 
 
 
 
 
233
  pitch = pitch[:p_len]
234
  pitchf = pitchf[:p_len]
 
 
235
  pitch = torch.tensor(pitch, device=self.device).unsqueeze(0).long()
236
  pitchf = torch.tensor(pitchf, device=self.device).unsqueeze(0).float()
237
  t2 = ttime()
@@ -251,6 +579,8 @@ class VC(object):
251
  index,
252
  big_npy,
253
  index_rate,
 
 
254
  )[self.t_pad_tgt : -self.t_pad_tgt]
255
  )
256
  else:
@@ -266,6 +596,8 @@ class VC(object):
266
  index,
267
  big_npy,
268
  index_rate,
 
 
269
  )[self.t_pad_tgt : -self.t_pad_tgt]
270
  )
271
  s = t
@@ -282,6 +614,8 @@ class VC(object):
282
  index,
283
  big_npy,
284
  index_rate,
 
 
285
  )[self.t_pad_tgt : -self.t_pad_tgt]
286
  )
287
  else:
@@ -297,10 +631,23 @@ class VC(object):
297
  index,
298
  big_npy,
299
  index_rate,
 
 
300
  )[self.t_pad_tgt : -self.t_pad_tgt]
301
  )
302
  audio_opt = np.concatenate(audio_opt)
 
 
 
 
 
 
 
 
 
 
 
303
  del pitch, pitchf, sid
304
  if torch.cuda.is_available():
305
  torch.cuda.empty_cache()
306
- return audio_opt
 
1
+ from functools import lru_cache
2
  from time import time as ttime
3
+
4
+ import faiss
5
+ import librosa
6
+ import numpy as np
7
+ import os
8
+ import parselmouth
9
+ import pyworld
10
+ import sys
11
+ import torch
12
  import torch.nn.functional as F
13
+ import torchcrepe
14
+ import traceback
 
15
  from scipy import signal
16
+ from torch import Tensor
17
+
18
+ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
19
+ now_dir = os.path.join(BASE_DIR)
20
+ sys.path.append(now_dir)
21
 
22
  bh, ah = signal.butter(N=5, Wn=48, btype="high", fs=16000)
23
 
24
+ input_audio_path2wav = {}
25
+
26
+
27
+ @lru_cache
28
+ def cache_harvest_f0(input_audio_path, fs, f0max, f0min, frame_period):
29
+ audio = input_audio_path2wav[input_audio_path]
30
+ f0, t = pyworld.harvest(
31
+ audio,
32
+ fs=fs,
33
+ f0_ceil=f0max,
34
+ f0_floor=f0min,
35
+ frame_period=frame_period,
36
+ )
37
+ f0 = pyworld.stonemask(audio, f0, t, fs)
38
+ return f0
39
+
40
+
41
+ def change_rms(data1, sr1, data2, sr2, rate): # 1是输入音频,2是输出音频,rate是2的占比
42
+ # print(data1.max(),data2.max())
43
+ rms1 = librosa.feature.rms(
44
+ y=data1, frame_length=sr1 // 2 * 2, hop_length=sr1 // 2
45
+ ) # 每半秒一个点
46
+ rms2 = librosa.feature.rms(y=data2, frame_length=sr2 // 2 * 2, hop_length=sr2 // 2)
47
+ rms1 = torch.from_numpy(rms1)
48
+ rms1 = F.interpolate(
49
+ rms1.unsqueeze(0), size=data2.shape[0], mode="linear"
50
+ ).squeeze()
51
+ rms2 = torch.from_numpy(rms2)
52
+ rms2 = F.interpolate(
53
+ rms2.unsqueeze(0), size=data2.shape[0], mode="linear"
54
+ ).squeeze()
55
+ rms2 = torch.max(rms2, torch.zeros_like(rms2) + 1e-6)
56
+ data2 *= (
57
+ torch.pow(rms1, torch.tensor(1 - rate))
58
+ * torch.pow(rms2, torch.tensor(rate - 1))
59
+ ).numpy()
60
+ return data2
61
+
62
 
63
  class VC(object):
64
+ def __init__(self, tgt_sr, config):
65
+ self.x_pad, self.x_query, self.x_center, self.x_max, self.is_half = (
66
+ config.x_pad,
67
+ config.x_query,
68
+ config.x_center,
69
+ config.x_max,
70
+ config.is_half,
71
+ )
72
  self.sr = 16000 # hubert输入采样率
73
  self.window = 160 # 每帧点数
74
+ self.t_pad = self.sr * self.x_pad # 每条前后pad时间
75
+ self.t_pad_tgt = tgt_sr * self.x_pad
76
  self.t_pad2 = self.t_pad * 2
77
+ self.t_query = self.sr * self.x_query # 查询切点前后查询时间
78
+ self.t_center = self.sr * self.x_center # 查询切点位置
79
+ self.t_max = self.sr * self.x_max # 免查询时长阈值
80
+ self.device = config.device
81
+
82
+ # Fork Feature: Get the best torch device to use for f0 algorithms that require a torch device. Will return the type (torch.device)
83
+ def get_optimal_torch_device(self, index: int = 0) -> torch.device:
84
+ # Get cuda device
85
+ if torch.cuda.is_available():
86
+ return torch.device(
87
+ f"cuda:{index % torch.cuda.device_count()}"
88
+ ) # Very fast
89
+ elif torch.backends.mps.is_available():
90
+ return torch.device("mps")
91
+ # Insert an else here to grab "xla" devices if available. TO DO later. Requires the torch_xla.core.xla_model library
92
+ # Else wise return the "cpu" as a torch device,
93
+ return torch.device("cpu")
94
+
95
+ # Fork Feature: Compute f0 with the crepe method
96
+ def get_f0_crepe_computation(
97
+ self,
98
+ x,
99
+ f0_min,
100
+ f0_max,
101
+ p_len,
102
+ hop_length=160, # 512 before. Hop length changes the speed that the voice jumps to a different dramatic pitch. Lower hop lengths means more pitch accuracy but longer inference time.
103
+ model="full", # Either use crepe-tiny "tiny" or crepe "full". Default is full
104
+ ):
105
+ x = x.astype(
106
+ np.float32
107
+ ) # fixes the F.conv2D exception. We needed to convert double to float.
108
+ x /= np.quantile(np.abs(x), 0.999)
109
+ torch_device = self.get_optimal_torch_device()
110
+ audio = torch.from_numpy(x).to(torch_device, copy=True)
111
+ audio = torch.unsqueeze(audio, dim=0)
112
+ if audio.ndim == 2 and audio.shape[0] > 1:
113
+ audio = torch.mean(audio, dim=0, keepdim=True).detach()
114
+ audio = audio.detach()
115
+ print("Initiating prediction with a crepe_hop_length of: " + str(hop_length))
116
+ pitch: Tensor = torchcrepe.predict(
117
+ audio,
118
+ self.sr,
119
+ hop_length,
120
+ f0_min,
121
+ f0_max,
122
+ model,
123
+ batch_size=hop_length * 2,
124
+ device=torch_device,
125
+ pad=True,
126
+ )
127
+ p_len = p_len or x.shape[0] // hop_length
128
+ # Resize the pitch for final f0
129
+ source = np.array(pitch.squeeze(0).cpu().float().numpy())
130
+ source[source < 0.001] = np.nan
131
+ target = np.interp(
132
+ np.arange(0, len(source) * p_len, len(source)) / p_len,
133
+ np.arange(0, len(source)),
134
+ source,
135
+ )
136
+ f0 = np.nan_to_num(target)
137
+ return f0 # Resized f0
138
+
139
+ def get_f0_official_crepe_computation(
140
+ self,
141
+ x,
142
+ f0_min,
143
+ f0_max,
144
+ model="full",
145
+ ):
146
+ # Pick a batch size that doesn't cause memory errors on your gpu
147
+ batch_size = 512
148
+ # Compute pitch using first gpu
149
+ audio = torch.tensor(np.copy(x))[None].float()
150
+ f0, pd = torchcrepe.predict(
151
+ audio,
152
+ self.sr,
153
+ self.window,
154
+ f0_min,
155
+ f0_max,
156
+ model,
157
+ batch_size=batch_size,
158
+ device=self.device,
159
+ return_periodicity=True,
160
+ )
161
+ pd = torchcrepe.filter.median(pd, 3)
162
+ f0 = torchcrepe.filter.mean(f0, 3)
163
+ f0[pd < 0.1] = 0
164
+ f0 = f0[0].cpu().numpy()
165
+ return f0
166
+
167
+ # Fork Feature: Compute pYIN f0 method
168
+ def get_f0_pyin_computation(self, x, f0_min, f0_max):
169
+ y, sr = librosa.load("saudio/Sidney.wav", self.sr, mono=True)
170
+ f0, _, _ = librosa.pyin(y, sr=self.sr, fmin=f0_min, fmax=f0_max)
171
+ f0 = f0[1:] # Get rid of extra first frame
172
+ return f0
173
+
174
+ # Fork Feature: Acquire median hybrid f0 estimation calculation
175
+ def get_f0_hybrid_computation(
176
+ self,
177
+ methods_str,
178
+ input_audio_path,
179
+ x,
180
+ f0_min,
181
+ f0_max,
182
+ p_len,
183
+ filter_radius,
184
+ crepe_hop_length,
185
+ time_step,
186
+ ):
187
+ # Get various f0 methods from input to use in the computation stack
188
+ s = methods_str
189
+ s = s.split("hybrid")[1]
190
+ s = s.replace("[", "").replace("]", "")
191
+ methods = s.split("+")
192
+ f0_computation_stack = []
193
+
194
+ print("Calculating f0 pitch estimations for methods: %s" % str(methods))
195
+ x = x.astype(np.float32)
196
+ x /= np.quantile(np.abs(x), 0.999)
197
+ # Get f0 calculations for all methods specified
198
+ for method in methods:
199
+ f0 = None
200
+ if method == "pm":
201
+ f0 = (
202
+ parselmouth.Sound(x, self.sr)
203
+ .to_pitch_ac(
204
+ time_step=time_step / 1000,
205
+ voicing_threshold=0.6,
206
+ pitch_floor=f0_min,
207
+ pitch_ceiling=f0_max,
208
+ )
209
+ .selected_array["frequency"]
210
+ )
211
+ pad_size = (p_len - len(f0) + 1) // 2
212
+ if pad_size > 0 or p_len - len(f0) - pad_size > 0:
213
+ f0 = np.pad(
214
+ f0, [[pad_size, p_len - len(f0) - pad_size]], mode="constant"
215
+ )
216
+ elif method == "crepe":
217
+ f0 = self.get_f0_official_crepe_computation(x, f0_min, f0_max)
218
+ f0 = f0[1:] # Get rid of extra first frame
219
+ elif method == "crepe-tiny":
220
+ f0 = self.get_f0_official_crepe_computation(x, f0_min, f0_max, "tiny")
221
+ f0 = f0[1:] # Get rid of extra first frame
222
+ elif method == "mangio-crepe":
223
+ f0 = self.get_f0_crepe_computation(
224
+ x, f0_min, f0_max, p_len, crepe_hop_length
225
+ )
226
+ elif method == "mangio-crepe-tiny":
227
+ f0 = self.get_f0_crepe_computation(
228
+ x, f0_min, f0_max, p_len, crepe_hop_length, "tiny"
229
+ )
230
+ elif method == "harvest":
231
+ f0 = cache_harvest_f0(input_audio_path, self.sr, f0_max, f0_min, 10)
232
+ if filter_radius > 2:
233
+ f0 = signal.medfilt(f0, 3)
234
+ f0 = f0[1:] # Get rid of first frame.
235
+ elif method == "dio": # Potentially buggy?
236
+ f0, t = pyworld.dio(
237
+ x.astype(np.double),
238
+ fs=self.sr,
239
+ f0_ceil=f0_max,
240
+ f0_floor=f0_min,
241
+ frame_period=10,
242
+ )
243
+ f0 = pyworld.stonemask(x.astype(np.double), f0, t, self.sr)
244
+ f0 = signal.medfilt(f0, 3)
245
+ f0 = f0[1:]
246
+ # elif method == "pyin": Not Working just yet
247
+ # f0 = self.get_f0_pyin_computation(x, f0_min, f0_max)
248
+ # Push method to the stack
249
+ f0_computation_stack.append(f0)
250
+
251
+ for fc in f0_computation_stack:
252
+ print(len(fc))
253
 
254
+ print("Calculating hybrid median f0 from the stack of: %s" % str(methods))
255
+ f0_median_hybrid = None
256
+ if len(f0_computation_stack) == 1:
257
+ f0_median_hybrid = f0_computation_stack[0]
258
+ else:
259
+ f0_median_hybrid = np.nanmedian(f0_computation_stack, axis=0)
260
+ return f0_median_hybrid
261
+
262
+ def get_f0(
263
+ self,
264
+ input_audio_path,
265
+ x,
266
+ p_len,
267
+ f0_up_key,
268
+ f0_method,
269
+ filter_radius,
270
+ crepe_hop_length,
271
+ inp_f0=None,
272
+ ):
273
+ global input_audio_path2wav
274
  time_step = self.window / self.sr * 1000
275
  f0_min = 50
276
  f0_max = 1100
 
293
  f0, [[pad_size, p_len - len(f0) - pad_size]], mode="constant"
294
  )
295
  elif f0_method == "harvest":
296
+ input_audio_path2wav[input_audio_path] = x.astype(np.double)
297
+ f0 = cache_harvest_f0(input_audio_path, self.sr, f0_max, f0_min, 10)
298
+ if filter_radius > 2:
299
+ f0 = signal.medfilt(f0, 3)
300
+ elif f0_method == "dio": # Potentially Buggy?
301
+ f0, t = pyworld.dio(
302
  x.astype(np.double),
303
  fs=self.sr,
304
  f0_ceil=f0_max,
 
307
  )
308
  f0 = pyworld.stonemask(x.astype(np.double), f0, t, self.sr)
309
  f0 = signal.medfilt(f0, 3)
310
+ elif f0_method == "crepe":
311
+ f0 = self.get_f0_official_crepe_computation(x, f0_min, f0_max)
312
+ elif f0_method == "crepe-tiny":
313
+ f0 = self.get_f0_official_crepe_computation(x, f0_min, f0_max, "tiny")
314
+ elif f0_method == "mangio-crepe":
315
+ f0 = self.get_f0_crepe_computation(
316
+ x, f0_min, f0_max, p_len, crepe_hop_length
317
+ )
318
+ elif f0_method == "mangio-crepe-tiny":
319
+ f0 = self.get_f0_crepe_computation(
320
+ x, f0_min, f0_max, p_len, crepe_hop_length, "tiny"
321
+ )
322
+ elif f0_method == "rmvpe":
323
+ if hasattr(self, "model_rmvpe") == False:
324
+ from rmvpe import RMVPE
325
+
326
+ self.model_rmvpe = RMVPE(
327
+ os.path.join(BASE_DIR, 'rmvpe.pt'), is_half=self.is_half, device=self.device
328
+ )
329
+ f0 = self.model_rmvpe.infer_from_audio(x, thred=0.03)
330
+
331
+ elif "hybrid" in f0_method:
332
+ # Perform hybrid median pitch estimation
333
+ input_audio_path2wav[input_audio_path] = x.astype(np.double)
334
+ f0 = self.get_f0_hybrid_computation(
335
+ f0_method,
336
+ input_audio_path,
337
+ x,
338
+ f0_min,
339
+ f0_max,
340
+ p_len,
341
+ filter_radius,
342
+ crepe_hop_length,
343
+ time_step,
344
+ )
345
+
346
  f0 *= pow(2, f0_up_key / 12)
347
  # with open("test.txt","w")as f:f.write("\n".join([str(i)for i in f0.tolist()]))
348
  tf0 = self.sr // self.window # 每秒f0点数
 
353
  replace_f0 = np.interp(
354
  list(range(delta_t)), inp_f0[:, 0] * 100, inp_f0[:, 1]
355
  )
356
+ shape = f0[self.x_pad * tf0 : self.x_pad * tf0 + len(replace_f0)].shape[0]
357
+ f0[self.x_pad * tf0 : self.x_pad * tf0 + len(replace_f0)] = replace_f0[
358
+ :shape
359
+ ]
360
  # with open("test_opt.txt","w")as f:f.write("\n".join([str(i)for i in f0.tolist()]))
361
  f0bak = f0.copy()
362
  f0_mel = 1127 * np.log(1 + f0 / 700)
 
366
  f0_mel[f0_mel <= 1] = 1
367
  f0_mel[f0_mel > 255] = 255
368
  f0_coarse = np.rint(f0_mel).astype(np.int)
369
+
370
  return f0_coarse, f0bak # 1-0
371
 
372
  def vc(
 
381
  index,
382
  big_npy,
383
  index_rate,
384
+ version,
385
+ protect,
386
  ): # ,file_index,file_big_npy
387
  feats = torch.from_numpy(audio0)
388
  if self.is_half:
 
398
  inputs = {
399
  "source": feats.to(self.device),
400
  "padding_mask": padding_mask,
401
+ "output_layer": 9 if version == "v1" else 12,
402
  }
403
  t0 = ttime()
404
  with torch.no_grad():
405
  logits = model.extract_features(**inputs)
406
+ feats = model.final_proj(logits[0]) if version == "v1" else logits[0]
407
+ if protect < 0.5 and pitch != None and pitchf != None:
408
+ feats0 = feats.clone()
409
  if (
410
  isinstance(index, type(None)) == False
411
  and isinstance(big_npy, type(None)) == False
 
414
  npy = feats[0].cpu().numpy()
415
  if self.is_half:
416
  npy = npy.astype("float32")
417
+
418
+ # _, I = index.search(npy, 1)
419
+ # npy = big_npy[I.squeeze()]
420
+
421
+ score, ix = index.search(npy, k=8)
422
+ weight = np.square(1 / score)
423
+ weight /= weight.sum(axis=1, keepdims=True)
424
+ npy = np.sum(big_npy[ix] * np.expand_dims(weight, axis=2), axis=1)
425
+
426
  if self.is_half:
427
  npy = npy.astype("float16")
428
  feats = (
 
431
  )
432
 
433
  feats = F.interpolate(feats.permute(0, 2, 1), scale_factor=2).permute(0, 2, 1)
434
+ if protect < 0.5 and pitch != None and pitchf != None:
435
+ feats0 = F.interpolate(feats0.permute(0, 2, 1), scale_factor=2).permute(
436
+ 0, 2, 1
437
+ )
438
  t1 = ttime()
439
  p_len = audio0.shape[0] // self.window
440
  if feats.shape[1] < p_len:
 
442
  if pitch != None and pitchf != None:
443
  pitch = pitch[:, :p_len]
444
  pitchf = pitchf[:, :p_len]
445
+
446
+ if protect < 0.5 and pitch != None and pitchf != None:
447
+ pitchff = pitchf.clone()
448
+ pitchff[pitchf > 0] = 1
449
+ pitchff[pitchf < 1] = protect
450
+ pitchff = pitchff.unsqueeze(-1)
451
+ feats = feats * pitchff + feats0 * (1 - pitchff)
452
+ feats = feats.to(feats0.dtype)
453
  p_len = torch.tensor([p_len], device=self.device).long()
454
  with torch.no_grad():
455
  if pitch != None and pitchf != None:
456
  audio1 = (
457
+ (net_g.infer(feats, p_len, pitch, pitchf, sid)[0][0, 0])
458
  .data.cpu()
459
  .float()
460
  .numpy()
 
461
  )
462
  else:
463
  audio1 = (
464
+ (net_g.infer(feats, p_len, sid)[0][0, 0]).data.cpu().float().numpy()
 
 
 
 
465
  )
466
  del feats, p_len, padding_mask
467
  if torch.cuda.is_available():
 
477
  net_g,
478
  sid,
479
  audio,
480
+ input_audio_path,
481
  times,
482
  f0_up_key,
483
  f0_method,
484
  file_index,
485
+ # file_big_npy,
486
  index_rate,
487
  if_f0,
488
+ filter_radius,
489
+ tgt_sr,
490
+ resample_sr,
491
+ rms_mix_rate,
492
+ version,
493
+ protect,
494
+ crepe_hop_length,
495
  f0_file=None,
496
  ):
497
  if (
498
+ file_index != ""
499
+ # and file_big_npy != ""
500
+ # and os.path.exists(file_big_npy) == True
501
  and os.path.exists(file_index) == True
502
  and index_rate != 0
503
  ):
504
  try:
505
  index = faiss.read_index(file_index)
506
+ # big_npy = np.load(file_big_npy)
507
+ big_npy = index.reconstruct_n(0, index.ntotal)
508
  except:
509
  traceback.print_exc()
510
  index = big_npy = None
511
  else:
512
  index = big_npy = None
 
513
  audio = signal.filtfilt(bh, ah, audio)
514
  audio_pad = np.pad(audio, (self.window // 2, self.window // 2), mode="reflect")
515
  opt_ts = []
 
546
  sid = torch.tensor(sid, device=self.device).unsqueeze(0).long()
547
  pitch, pitchf = None, None
548
  if if_f0 == 1:
549
+ pitch, pitchf = self.get_f0(
550
+ input_audio_path,
551
+ audio_pad,
552
+ p_len,
553
+ f0_up_key,
554
+ f0_method,
555
+ filter_radius,
556
+ crepe_hop_length,
557
+ inp_f0,
558
+ )
559
  pitch = pitch[:p_len]
560
  pitchf = pitchf[:p_len]
561
+ if self.device == "mps":
562
+ pitchf = pitchf.astype(np.float32)
563
  pitch = torch.tensor(pitch, device=self.device).unsqueeze(0).long()
564
  pitchf = torch.tensor(pitchf, device=self.device).unsqueeze(0).float()
565
  t2 = ttime()
 
579
  index,
580
  big_npy,
581
  index_rate,
582
+ version,
583
+ protect,
584
  )[self.t_pad_tgt : -self.t_pad_tgt]
585
  )
586
  else:
 
596
  index,
597
  big_npy,
598
  index_rate,
599
+ version,
600
+ protect,
601
  )[self.t_pad_tgt : -self.t_pad_tgt]
602
  )
603
  s = t
 
614
  index,
615
  big_npy,
616
  index_rate,
617
+ version,
618
+ protect,
619
  )[self.t_pad_tgt : -self.t_pad_tgt]
620
  )
621
  else:
 
631
  index,
632
  big_npy,
633
  index_rate,
634
+ version,
635
+ protect,
636
  )[self.t_pad_tgt : -self.t_pad_tgt]
637
  )
638
  audio_opt = np.concatenate(audio_opt)
639
+ if rms_mix_rate != 1:
640
+ audio_opt = change_rms(audio, 16000, audio_opt, tgt_sr, rms_mix_rate)
641
+ if resample_sr >= 16000 and tgt_sr != resample_sr:
642
+ audio_opt = librosa.resample(
643
+ audio_opt, orig_sr=tgt_sr, target_sr=resample_sr
644
+ )
645
+ audio_max = np.abs(audio_opt).max() / 0.99
646
+ max_int16 = 32768
647
+ if audio_max > 1:
648
+ max_int16 /= audio_max
649
+ audio_opt = (audio_opt * max_int16).astype(np.int16)
650
  del pitch, pitchf, sid
651
  if torch.cuda.is_available():
652
  torch.cuda.empty_cache()
653
+ return audio_opt