| | import numba as nb |
| | import numpy as np |
| |
|
| |
|
| | @nb.njit() |
| | def find_nearest_stft_bin(f0_, freqs): |
| | freqs = np.expand_dims(freqs, 0) |
| | f0_ = np.expand_dims(f0_, 1) |
| | return np.abs(freqs - f0_).argmin() |
| |
|
| |
|
| | @nb.njit() |
| | def get_med_curve(f0, step_size=20): |
| | v_begin = -1 |
| | v_end = -1 |
| | x_med_curve = [] |
| | y_med_curve = [] |
| | T = len(f0) |
| |
|
| | for i in range(T): |
| | if f0[i] >= 50 and i < T - 1: |
| | if v_begin == -1: |
| | v_begin = i |
| | v_end = i |
| | else: |
| | if v_end != -1: |
| | if v_end - v_begin > 3: |
| | for j in range(v_begin, v_end + 1 - step_size, step_size): |
| | frag_med = np.median(f0[j:j + step_size]) |
| | x_med_curve.append(j) |
| | y_med_curve.append(frag_med) |
| | x_med_curve.append(v_end) |
| | y_med_curve.append(np.median(f0[v_end - step_size:v_end + 1])) |
| | v_end = v_begin = -1 |
| | x_med_curve = [0] + x_med_curve + [T] |
| | x_med_curve = np.array(x_med_curve) |
| | y_med_curve = [y_med_curve[0]] + y_med_curve + [y_med_curve[-1]] |
| | y_med_curve = np.array(y_med_curve) |
| | return x_med_curve, y_med_curve |
| |
|
| |
|
| | @nb.njit() |
| | def clean_short_v_frag(f0): |
| | v_begin = -1 |
| | T = len(f0) |
| |
|
| | uv = np.zeros_like(f0).astype(np.bool_) |
| | for i in range(T): |
| | if f0[i] >= 1e-4 and i < T - 1: |
| | if v_begin == -1: |
| | v_begin = i |
| | else: |
| | if v_begin != -1: |
| | v_end = i if f0[i] >= 1e-4 else i - 1 |
| | if v_end - v_begin + 1 < 3: |
| | uv[v_begin:v_end + 1] = 1 |
| | v_begin = -1 |
| | return uv |
| |
|
| |
|
| | @nb.njit() |
| | def find_best_f0_using_har_energy(spec, pitches, freqs, hars, hars_mhalf, f0_min, f0_max): |
| | re = np.zeros_like(spec) |
| | T = len(spec) |
| | for i in range(T): |
| | spec_i = spec[i] |
| | for j, f0_j in enumerate(pitches[i]): |
| | if f0_j == 0 or f0_j < f0_min[i] or f0_j > f0_max[i]: |
| | continue |
| | mask = np.zeros((10000,)) |
| | mask_mhalf = np.zeros((10000,)) |
| | for mul in hars: |
| | b = find_nearest_stft_bin(np.array((f0_j * mul,)), freqs) |
| | for delta in range(-1, 2): |
| | mask[b + delta] = 1 |
| | for mul in hars_mhalf: |
| | b_mhalf = find_nearest_stft_bin(np.array((f0_j * (mul - 0.5),)), freqs) |
| | for delta in range(-1, 2): |
| | mask_mhalf[b_mhalf + delta] = 1 |
| | mask = mask[:len(spec_i)] |
| | mask_mhalf = mask_mhalf[:len(spec_i)] |
| | energy = (np.exp(spec_i) * mask).sum() / mask.sum() |
| | energy_mhalf = (np.exp(spec_i) * mask_mhalf).sum() / mask_mhalf.sum() |
| | re[i, j] = energy / energy_mhalf |
| | f0_2d_mask = 10000 * (re > 2) + 20000 * (re > 3) + np.expand_dims(np.arange(re.shape[1])[::-1], 0) |
| | f0_idx = np.zeros((T,), dtype=np.int_) |
| | for i in range(T): |
| | f0_idx[i] = f0_2d_mask[i].argmax() |
| | uv = re.sum(-1) == 0 |
| |
|
| | f0 = np.zeros((T,)) |
| | for i in range(T): |
| | f0[i] = pitches[i, f0_idx[i]] |
| | f0 = f0 * (1 - uv) |
| | uv = clean_short_v_frag(f0) |
| | f0[uv] = 0 |
| | x_med_curve, y_med_curve = get_med_curve(f0) |
| | re = re * (re > 1.5) |
| | return re, f0, x_med_curve, y_med_curve |
| |
|