| import subprocess |
| import librosa |
| import librosa.filters |
| import numpy as np |
| import torch |
| from scipy import signal |
| from scipy.io import wavfile |
| import torch.nn.functional as F |
|
|
|
|
| def save_wav(wav, path, sr, norm=False): |
| if norm: |
| wav = wav / np.abs(wav).max() |
| wav *= 32767 |
| |
| wavfile.write(path, sr, wav.astype(np.int16)) |
|
|
|
|
| def to_mp3(out_path): |
| subprocess.check_call( |
| f'ffmpeg -threads 1 -loglevel error -i "{out_path}.wav" -vn -ar 44100 -ac 1 -b:a 192k -y -hide_banner "{out_path}.mp3"', |
| shell=True, stdin=subprocess.PIPE) |
| subprocess.check_call(f'rm -f "{out_path}.wav"', shell=True) |
|
|
|
|
| def get_hop_size(hparams): |
| hop_size = hparams['hop_size'] |
| if hop_size is None: |
| assert hparams['frame_shift_ms'] is not None |
| hop_size = int(hparams['frame_shift_ms'] / 1000 * hparams['audio_sample_rate']) |
| return hop_size |
|
|
|
|
| |
| def griffin_lim(S, hparams, angles=None): |
| angles = np.exp(2j * np.pi * np.random.rand(*S.shape)) if angles is None else angles |
| S_complex = np.abs(S).astype(np.complex) |
| y = _istft(S_complex * angles, hparams) |
| for i in range(hparams['griffin_lim_iters']): |
| angles = np.exp(1j * np.angle(_stft(y, hparams))) |
| y = _istft(S_complex * angles, hparams) |
| return y |
|
|
|
|
| def preemphasis(wav, k, preemphasize=True): |
| if preemphasize: |
| return signal.lfilter([1, -k], [1], wav) |
| return wav |
|
|
|
|
| def inv_preemphasis(wav, k, inv_preemphasize=True): |
| if inv_preemphasize: |
| return signal.lfilter([1], [1, -k], wav) |
| return wav |
|
|
|
|
| def _stft(y, hparams): |
| return librosa.stft(y=y, n_fft=hparams['fft_size'], hop_length=get_hop_size(hparams), |
| win_length=hparams['win_size'], pad_mode='constant') |
|
|
|
|
| def _istft(y, hparams): |
| return librosa.istft(y, hop_length=get_hop_size(hparams), win_length=hparams['win_size']) |
|
|
|
|
|
|
| def librosa_pad_lr(x, fsize, fshift, pad_sides=1): |
| '''compute right padding (final frame) or both sides padding (first and final frames) |
| ''' |
| assert pad_sides in (1, 2) |
| |
| pad = (x.shape[0] // fshift + 1) * fshift - x.shape[0] |
| if pad_sides == 1: |
| return 0, pad |
| else: |
| return pad // 2, pad // 2 + pad % 2 |
|
|
|
|
| |
| _mel_basis = None |
| _inv_mel_basis = None |
|
|
|
|
| def _linear_to_mel(spectogram, hparams): |
| global _mel_basis |
| if _mel_basis is None: |
| _mel_basis = _build_mel_basis(hparams) |
| return np.dot(_mel_basis, spectogram) |
|
|
|
|
| def _mel_to_linear(mel_spectrogram, hparams): |
| global _inv_mel_basis |
| if _inv_mel_basis is None: |
| _inv_mel_basis = np.linalg.pinv(_build_mel_basis(hparams)) |
| return np.maximum(1e-10, np.dot(_inv_mel_basis, mel_spectrogram)) |
|
|
|
|
| def _build_mel_basis(hparams): |
| assert hparams['fmax'] <= hparams['audio_sample_rate'] // 2 |
| return librosa.filters.mel(hparams['audio_sample_rate'], hparams['fft_size'], n_mels=hparams['audio_num_mel_bins'], |
| fmin=hparams['fmin'], fmax=hparams['fmax']) |
|
|
|
|
| def amp_to_db(x): |
| return 20 * np.log10(np.maximum(1e-5, x)) |
|
|
|
|
| def db_to_amp(x): |
| return 10.0 ** (x * 0.05) |
|
|
|
|
| def normalize(S, hparams): |
| return (S - hparams['min_level_db']) / -hparams['min_level_db'] |
|
|
|
|
| def denormalize(D, hparams): |
| return (D * -hparams['min_level_db']) + hparams['min_level_db'] |
|
|
|
|
| |
|
|
|
|
| def istft(amp, ang, hparams, pad=False, window=None): |
| spec = amp * torch.exp(1j * ang) |
| spec_r = spec.real |
| spec_i = spec.imag |
| spec = torch.stack([spec_r, spec_i], -1) |
| if window is None: |
| window = torch.hann_window(hparams['win_size']).to(amp.device) |
| if pad: |
| spec = F.pad(spec, [0, 0, 0, 1], mode='reflect') |
| wav = torch.istft(spec, hparams['fft_size'], hparams['hop_size'], hparams['win_size']) |
| return wav |
|
|
|
|
| def griffin_lim_torch(amp, ang, hparams, n_iters=30): |
| """ |
| |
| Examples: |
| >>> x_stft = librosa.stft(wav, n_fft=fft_size, hop_length=hop_size, win_length=win_length, pad_mode="constant") |
| >>> x_stft = x_stft[None, ...] |
| >>> amp = np.abs(x_stft) |
| >>> angle_init = np.exp(2j * np.pi * np.random.rand(*x_stft.shape)) |
| >>> amp = torch.FloatTensor(amp) |
| >>> wav = griffin_lim_torch(amp, angle_init, hparams) |
| |
| :param amp: [B, n_fft, T] |
| :param ang: [B, n_fft, T] |
| :return: [B, T_wav] |
| """ |
| window = torch.hann_window(hparams['win_size']).to(amp.device) |
| y = istft(amp, ang, hparams, window=window) |
| for i in range(n_iters): |
| x_stft = torch.stft(y, hparams['fft_size'], hparams['hop_size'], hparams['win_size'], window) |
| x_stft = x_stft[..., 0] + 1j * x_stft[..., 1] |
| ang = torch.angle(x_stft) |
| y = istft(amp, ang, hparams, window=window) |
| return y |
|
|