Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
prophesier
GitHub Repository: prophesier/diff-svc
Path: blob/main/utils/cwt.py
694 views
1
import librosa
2
import numpy as np
3
from pycwt import wavelet
4
from scipy.interpolate import interp1d
5
6
7
def load_wav(wav_file, sr):
8
wav, _ = librosa.load(wav_file, sr=sr, mono=True)
9
return wav
10
11
12
def convert_continuos_f0(f0):
13
'''CONVERT F0 TO CONTINUOUS F0
14
Args:
15
f0 (ndarray): original f0 sequence with the shape (T)
16
Return:
17
(ndarray): continuous f0 with the shape (T)
18
'''
19
# get uv information as binary
20
f0 = np.copy(f0)
21
uv = np.float32(f0 != 0)
22
23
# get start and end of f0
24
if (f0 == 0).all():
25
print("| all of the f0 values are 0.")
26
return uv, f0
27
start_f0 = f0[f0 != 0][0]
28
end_f0 = f0[f0 != 0][-1]
29
30
# padding start and end of f0 sequence
31
start_idx = np.where(f0 == start_f0)[0][0]
32
end_idx = np.where(f0 == end_f0)[0][-1]
33
f0[:start_idx] = start_f0
34
f0[end_idx:] = end_f0
35
36
# get non-zero frame index
37
nz_frames = np.where(f0 != 0)[0]
38
39
# perform linear interpolation
40
f = interp1d(nz_frames, f0[nz_frames])
41
cont_f0 = f(np.arange(0, f0.shape[0]))
42
43
return uv, cont_f0
44
45
46
def get_cont_lf0(f0, frame_period=5.0):
47
uv, cont_f0_lpf = convert_continuos_f0(f0)
48
# cont_f0_lpf = low_pass_filter(cont_f0_lpf, int(1.0 / (frame_period * 0.001)), cutoff=20)
49
cont_lf0_lpf = np.log(cont_f0_lpf)
50
return uv, cont_lf0_lpf
51
52
53
def get_lf0_cwt(lf0):
54
'''
55
input:
56
signal of shape (N)
57
output:
58
Wavelet_lf0 of shape(10, N), scales of shape(10)
59
'''
60
mother = wavelet.MexicanHat()
61
dt = 0.005
62
dj = 1
63
s0 = dt * 2
64
J = 9
65
66
Wavelet_lf0, scales, _, _, _, _ = wavelet.cwt(np.squeeze(lf0), dt, dj, s0, J, mother)
67
# Wavelet.shape => (J + 1, len(lf0))
68
Wavelet_lf0 = np.real(Wavelet_lf0).T
69
return Wavelet_lf0, scales
70
71
72
def norm_scale(Wavelet_lf0):
73
Wavelet_lf0_norm = np.zeros((Wavelet_lf0.shape[0], Wavelet_lf0.shape[1]))
74
mean = Wavelet_lf0.mean(0)[None, :]
75
std = Wavelet_lf0.std(0)[None, :]
76
Wavelet_lf0_norm = (Wavelet_lf0 - mean) / std
77
return Wavelet_lf0_norm, mean, std
78
79
80
def normalize_cwt_lf0(f0, mean, std):
81
uv, cont_lf0_lpf = get_cont_lf0(f0)
82
cont_lf0_norm = (cont_lf0_lpf - mean) / std
83
Wavelet_lf0, scales = get_lf0_cwt(cont_lf0_norm)
84
Wavelet_lf0_norm, _, _ = norm_scale(Wavelet_lf0)
85
86
return Wavelet_lf0_norm
87
88
89
def get_lf0_cwt_norm(f0s, mean, std):
90
uvs = list()
91
cont_lf0_lpfs = list()
92
cont_lf0_lpf_norms = list()
93
Wavelet_lf0s = list()
94
Wavelet_lf0s_norm = list()
95
scaless = list()
96
97
means = list()
98
stds = list()
99
for f0 in f0s:
100
uv, cont_lf0_lpf = get_cont_lf0(f0)
101
cont_lf0_lpf_norm = (cont_lf0_lpf - mean) / std
102
103
Wavelet_lf0, scales = get_lf0_cwt(cont_lf0_lpf_norm) # [560,10]
104
Wavelet_lf0_norm, mean_scale, std_scale = norm_scale(Wavelet_lf0) # [560,10],[1,10],[1,10]
105
106
Wavelet_lf0s_norm.append(Wavelet_lf0_norm)
107
uvs.append(uv)
108
cont_lf0_lpfs.append(cont_lf0_lpf)
109
cont_lf0_lpf_norms.append(cont_lf0_lpf_norm)
110
Wavelet_lf0s.append(Wavelet_lf0)
111
scaless.append(scales)
112
means.append(mean_scale)
113
stds.append(std_scale)
114
115
return Wavelet_lf0s_norm, scaless, means, stds
116
117
118
def inverse_cwt_torch(Wavelet_lf0, scales):
119
import torch
120
b = ((torch.arange(0, len(scales)).float().to(Wavelet_lf0.device)[None, None, :] + 1 + 2.5) ** (-2.5))
121
lf0_rec = Wavelet_lf0 * b
122
lf0_rec_sum = lf0_rec.sum(-1)
123
lf0_rec_sum = (lf0_rec_sum - lf0_rec_sum.mean(-1, keepdim=True)) / lf0_rec_sum.std(-1, keepdim=True)
124
return lf0_rec_sum
125
126
127
def inverse_cwt(Wavelet_lf0, scales):
128
b = ((np.arange(0, len(scales))[None, None, :] + 1 + 2.5) ** (-2.5))
129
lf0_rec = Wavelet_lf0 * b
130
lf0_rec_sum = lf0_rec.sum(-1)
131
lf0_rec_sum = (lf0_rec_sum - lf0_rec_sum.mean(-1, keepdims=True)) / lf0_rec_sum.std(-1, keepdims=True)
132
return lf0_rec_sum
133
134
135
def cwt2f0(cwt_spec, mean, std, cwt_scales):
136
assert len(mean.shape) == 1 and len(std.shape) == 1 and len(cwt_spec.shape) == 3
137
import torch
138
if isinstance(cwt_spec, torch.Tensor):
139
f0 = inverse_cwt_torch(cwt_spec, cwt_scales)
140
f0 = f0 * std[:, None] + mean[:, None]
141
f0 = f0.exp() # [B, T]
142
else:
143
f0 = inverse_cwt(cwt_spec, cwt_scales)
144
f0 = f0 * std[:, None] + mean[:, None]
145
f0 = np.exp(f0) # [B, T]
146
return f0
147
148