Files
diodiogod 40f0e873be Integrate Voice Fixer audio restoration (Issue #153)
- Bundle VoiceFixer locally to avoid cache downloads
- Create voice_fixer_downloader for TTS/voicefixer/ model management
- Implement Voice Fixer node with 3 restoration modes (original, high-freq removal, train mode)
- Register node in nodes.py with proper error handling
- Patch bundled VoiceFixer hardcoded paths to use TTS/voicefixer/ directory
- Disable auto-download in restorer/__init__.py, handled by node instead
- Support lazy loading and CUDA acceleration
- All models download to organized TTS/ folder, never to cache
2025-10-29 14:15:52 -03:00

87 lines
3.7 KiB
Python

from voicefixer_bundled.vocoder.model.generator import Generator
from voicefixer_bundled.tools.wav import read_wave, save_wave
from voicefixer_bundled.tools.pytorch_util import *
from voicefixer_bundled.vocoder.model.util import *
from voicefixer_bundled.vocoder.config import Config
import os
import numpy as np
class Vocoder(nn.Module):
def __init__(self, sample_rate):
super(Vocoder, self).__init__()
Config.refresh(sample_rate)
self.rate = sample_rate
if(not os.path.exists(Config.ckpt)):
raise RuntimeError("Error 1: The checkpoint for synthesis module / vocoder (model.ckpt-1490000_trimed) is not found in ~/.cache/voicefixer/synthesis_module/44100. \
By default the checkpoint should be download automatically by this program. Something bad may happened. Apologies for the inconvenience.\
But don't worry! Alternatively you can download it directly from Zenodo: https://zenodo.org/record/5600188/files/model.ckpt-1490000_trimed.pt?download=1")
self._load_pretrain(Config.ckpt)
self.weight_torch = Config.get_mel_weight_torch(percent=1.0)[
None, None, None, ...
]
def _load_pretrain(self, pth):
self.model = Generator(Config.cin_channels)
checkpoint = load_checkpoint(pth, torch.device("cpu"))
load_try(checkpoint["generator"], self.model)
self.model.eval()
self.model.remove_weight_norm()
self.model.remove_weight_norm()
for p in self.model.parameters():
p.requires_grad = False
# def vocoder_mel_npy(self, mel, save_dir, sample_rate, gain):
# mel = mel / Config.get_mel_weight(percent=gain)[...,None]
# mel = normalize(amp_to_db(np.abs(mel)) - 20)
# mel = pre(np.transpose(mel, (1, 0)))
# with torch.no_grad():
# wav_re = self.model(mel) # torch.Size([1, 1, 104076])
# save_wave(tensor2numpy(wav_re)*2**15,save_dir,sample_rate=sample_rate)
def forward(self, mel, cuda=False):
"""
:param non normalized mel spectrogram: [batchsize, 1, t-steps, n_mel]
:return: [batchsize, 1, samples]
"""
assert mel.size()[-1] == 128
check_cuda_availability(cuda=cuda)
self.model = try_tensor_cuda(self.model, cuda=cuda)
mel = try_tensor_cuda(mel, cuda=cuda)
self.weight_torch = self.weight_torch.type_as(mel)
mel = mel / self.weight_torch
mel = tr_normalize(tr_amp_to_db(torch.abs(mel)) - 20.0)
mel = tr_pre(mel[:, 0, ...])
wav_re = self.model(mel)
return wav_re
def oracle(self, fpath, out_path, cuda=False):
check_cuda_availability(cuda=cuda)
self.model = try_tensor_cuda(self.model, cuda=cuda)
wav = read_wave(fpath, sample_rate=self.rate)[..., 0]
wav = wav / np.max(np.abs(wav))
stft = np.abs(
librosa.stft(
wav,
hop_length=Config.hop_length,
win_length=Config.win_size,
n_fft=Config.n_fft,
)
)
mel = linear_to_mel(stft)
mel = normalize(amp_to_db(np.abs(mel)) - 20)
mel = pre(np.transpose(mel, (1, 0)))
mel = try_tensor_cuda(mel, cuda=cuda)
with torch.no_grad():
wav_re = self.model(mel)
save_wave(tensor2numpy(wav_re * 2**15), out_path, sample_rate=self.rate)
if __name__ == "__main__":
model = Vocoder(sample_rate=44100)
print(model.device)
# model.load_pretrain(Config.ckpt)
# model.oracle(path="/Users/liuhaohe/Desktop/test.wav",
# sample_rate=44100,
# save_dir="/Users/liuhaohe/Desktop/test_vocoder.wav")