DeNAの2023/5/24の音声トークの発表資料を焼き直したものです。
© DeNA Co., Ltd. 1nagissソリューション事業本部データ統括部AI技術開発部株式会社ディー・エヌ・エーF0 推定アルゴリズム Harvest は中で何をしているのか
View Slide
© DeNA Co., Ltd. 21● Harvest のコードをある程度読み解いたので、せっかくなら公開しておこうと資料の形にしたもの○ 隅々まで読み解こうとはしていないので所々「よくわからない」があります● 参考にしたもの○ 実装https://github.com/mmorise/World/blob/master/src/harvest.cpp○ 森勢将雅, “高い雑音耐性と推定精度を両立する基本周波数推定法の提案と評価,” 信学技報, 2016http://www.isc.meiji.ac.jp/~mmorise/lab/publication/paper/SP2016-62.pdfこの資料は何?
© DeNA Co., Ltd. 32● Harvest では内部的に 1ms を 1 フレームとして扱っている。○ 1ms 以外で出力する場合は最後に最近傍補間している。● 例として JVS003 UT-PARAPHRASE-sent239-phrase2 を分析人生は結局、孤独を和らげるために、生きているようなもんだ○ 下線部の 1 秒間○ 「き」が無声化している前置き分析対象とした音声のスペクトログラム
© DeNA Co., Ltd. 43 コード概観- Harvest- HarvestGeneralBody- GetWaveformAndSpectrum ... 直流成分の除去、後の畳み込みのための FFT- GetWaveformAndSpectrumSub- HarvestGeneralBodySub- GetRawF0Candidates- (number_of_bands) GetF0CandidateFromRawEvent- GetFilteredSignal ... FFT でその帯域の BPF を畳み込む- (2) fft_execute- GetFourZeroCrossingIntervals ... ゼロ交叉/ピークの点を列挙、間隔から f0 を計算- GetF0CandidateContour- (4) interp1 ... f0 を時間方向に補間- GetF0CandidateContourSub ... 4 つの平均を計算、ばらけていたら 0- DetectOfficialF0Candidates- (f0_length) DetectOfficialF0CandidatesSub1 ... 台を検出- (f0_length) DetectOfficialF0CandidatesSub2 ... 各台の平均 f0 を計算、細い台は無視- OverlapF0Candidates ... 前後 3 フレームに f0 候補をコピー- RefineF0Candidates ... f0 候補を瞬時周波数で修正- (f0_length * num_candidates) GetRefinedF0 ... 窓長の計算、GetMeanF0- GetMeanF0- GetBaseIndex ... 窓をかける場所を求める- GetMainWindow ... 地味に重い- GetDiffWindow ... MainWindow の微分した窓を求める- GetSpectra ... 2 つの窓で FFT する、ここが重い- (2) fft_execute- FixF0 ... 瞬時周波数の計算- RemoveUnreliableCandidates ... 前後どちらのフレームにも差が 5% 以内の f0 候補が無いような f0 候補を削除- ((f0_length - 2) * number_of_candidates) RemoveUnreliableCandidatesSub ... 前後 1 フレームに対して SelectBestF0- (2) SelectBestF0 ... 自身に最も近い f0 を得る- FixF0Contour- SearchF0Base ... 各フレームで最もスコアの高い f0 候補を抽出する- FixStep1 ... 前フレームの f0 と前2フレームから線形で予測した f0 の両方から 0.8% 以上の差がある場合は f0 を 0 にする- FixStep2 ... 5 フレーム以下しか連続しない有声区間を削除- GetBoundaryList ... 有声部の閉区間のリストを作る- FixStep3 ...- GetBoundaryList- GetMultiChannelF0 ... 有声区間ごとに分けて別の配列にする- Extend ... 各有声区間を前後に伸ばす- (number_of_sections * 2) ExtendF0- (distance + 1) SelectBestF0 ... 18% 以内の差なら採択する- ExtendSub ... 有声区間が十分な長さ (平均 100Hz なら 22 フレーム、200Hz なら 11 フレーム) ないものを削除- MergeF0 ... 有声区間をマージする- MakeSortedOrder ... 有声区間たちを開始時刻の昇順にソート- MergeF0Sub ... 区間が重なる場合に、重なった部分のスコアの和が大きい方を選ぶ- (2) SearchScore- FixStep4 ... 短い無声区間を線形補間で埋める- GetBoundaryList- SmoothF0Contour ... F0 軌跡に LPF をかけて滑らかにする- GetBoundaryList- GetMultiChannelF0 ... 2 回目- (number_of_boundaries) FilteringF0
© DeNA Co., Ltd. 54● 入力音声を帯域の異なるバンドパスフィルタに通して複製し、それぞれを正弦波と見做してゼロ交叉・山と谷の時間間隔により F0 を求めることで、F0の候補とする。○ 1 オクターブあたり 40ch、71Hz ~ 800Hz なら計140ch の信号になる。○ 求めた F0 がその帯域の中心から 10% 以上離れていたら候補としない。○ バンドパスフィルタは次スライド■ FFT を使って畳み込んでいるが、ちょっとずつやらないで入力音声全体を FFT しているので計算量は線形時間より大きい、とはいえここが律速することはなさそうGetRawF0Candidates- Harvest- HarvestGeneralBody- GetWaveformAndSpectrum ... 直流成分の除去、後の畳み込みのための FFT- GetWaveformAndSpectrumSub- HarvestGeneralBodySub- GetRawF0Candidates- (number_of_bands) GetF0CandidateFromRawEvent- GetFilteredSignal ... FFT でその帯域の BPF を畳み込む- (2) fft_execute- GetFourZeroCrossingIntervals ... ゼロ交叉/ピークの点を列挙、間隔から f0 を計算- GetF0CandidateContour- (4) interp1 ... f0 を時間方向に補間- GetF0CandidateContourSub ... 4 つの平均を計算、ばらけていたら 0- DetectOfficialF0Candidates- (f0_length) DetectOfficialF0CandidatesSub1 ... 台を検出- (f0_length) DetectOfficialF0CandidatesSub2 ... 各台の平均 f0 を計算、細い台は無視- OverlapF0Candidates ... 前後 3 フレームに f0 候補をコピー- RefineF0Candidates ... f0 候補を瞬時周波数で修正- (f0_length * num_candidates) GetRefinedF0 ... 窓長の計算、GetMeanF0- GetMeanF0- GetBaseIndex ... 窓をかける場所を求める- GetMainWindow ... 地味に重い- GetDiffWindow ... MainWindow の微分した窓を求める- GetSpectra ... 2 つの窓で FFT する、ここが重い- (2) fft_execute- FixF0 ... 瞬時周波数の計算- RemoveUnreliableCandidates ... 前後どちらのフレームにも差が 5% 以内の f0 候補が無いような f0 候補を削除- ((f0_length - 2) * number_of_candidates) RemoveUnreliableCandidatesSub ... 前後 1 フレームに対して SelectBestF0- (2) SelectBestF0 ... 自身に最も近い f0 を得る- FixF0Contour- SearchF0Base ... 各フレームで最もスコアの高い f0 候補を抽出する- FixStep1 ... 前フレームの f0 と前2フレームから線形で予測した f0 の両方から 0.8% 以上の差がある場合は f0 を 0 にする- FixStep2 ... 5 フレーム以下しか連続しない有声区間を削除- GetBoundaryList ... 有声部の閉区間のリストを作る- FixStep3 ...- GetBoundaryList- GetMultiChannelF0 ... 有声区間ごとに分けて別の配列にする- Extend ... 各有声区間を前後に伸ばす- (number_of_sections * 2) ExtendF0- (distance + 1) SelectBestF0 ... 18% 以内の差なら採択する- ExtendSub ... 有声区間が十分な長さ (平均 100Hz なら 22 フレーム、200Hz なら 11 フレーム) ないものを削除- MergeF0 ... 有声区間をマージする- MakeSortedOrder ... 有声区間たちを開始時刻の昇順にソート- MergeF0Sub ... 区間が重なる場合に、重なった部分のスコアの和が大きい方を選ぶ- (2) SearchScore- FixStep4 ... 短い無声区間を線形補間で埋める- GetBoundaryList- SmoothF0Contour ... F0 軌跡に LPF をかけて滑らかにする- GetBoundaryList- GetMultiChannelF0 ... 2 回目- (number_of_boundaries) FilteringF0
© DeNA Co., Ltd. 65 GetRawF0Candidates - バンドパスフィルタcos 関数とナットール窓を掛け合わせて作られた線形位相バンドパスフィルタと、その周波数応答 (ピークの周波数が 200Hz の場合)sr = 24000freq = 200 # バンドパスフィルタのピーク周波数period = sr // freq # 周期n_fft = 1 << 16win = np.zeros(n_fft)win[:4 * period] = scipy.signal.nuttall(4 * period)win[:4 * period] *= np.cos(np.linspace(0.0, 8.0 * np.pi, 4 * period))plt.figure(figsize=(10, 4))plt.plot(win[:4 * period])plt.grid(color="gray")plt.show()f = np.fft.rfft(win)w = 20 * np.log10(np.abs(f))w -= w.max()plt.figure(figsize=(10, 4))plt.plot(np.arange(n_fft // 2 + 1) / n_fft * sr, w)plt.grid(color="gray")plt.xlabel("frequency [Hz]")plt.ylabel("[dB]")plt.xlim(0, 1000)plt.ylim(-120, 0)plt.show()左の図の描画コード● 200Hz の cos 関数は周波数領域で 200 Hz にピークの立つデルタ関数になる● 長さ 4/200 秒のナットール窓は周波数領域でメインローブの半径が 200Hz になる● 時間領域の掛け算は周波数領域の畳み込みなので、上記の周波数応答が得られる
© DeNA Co., Ltd. 76 GetRawF0Candidates - 結果の例得られた F0 候補
© DeNA Co., Ltd. 87● 帯域を横軸、得られた周波数を縦軸に取ったグラフを書くと、いくつかの台ができる。○ 論文中の図● 各台の周波数を平均をとることで 1 つにまとめてしまう。細い台は除去する。DetectOfficialF0Candidates- Harvest- HarvestGeneralBody- GetWaveformAndSpectrum ... 直流成分の除去、後の畳み込みのための FFT- GetWaveformAndSpectrumSub- HarvestGeneralBodySub- GetRawF0Candidates- (number_of_bands) GetF0CandidateFromRawEvent- GetFilteredSignal ... FFT でその帯域の BPF を畳み込む- (2) fft_execute- GetFourZeroCrossingIntervals ... ゼロ交叉/ピークの点を列挙、間隔から f0 を計算- GetF0CandidateContour- (4) interp1 ... f0 を時間方向に補間- GetF0CandidateContourSub ... 4 つの平均を計算、ばらけていたら 0- DetectOfficialF0Candidates- (f0_length) DetectOfficialF0CandidatesSub1 ... 台を検出- (f0_length) DetectOfficialF0CandidatesSub2 ... 各台の平均 f0 を計算、細い台は無視- OverlapF0Candidates ... 前後 3 フレームに f0 候補をコピー- RefineF0Candidates ... f0 候補を瞬時周波数で修正- (f0_length * num_candidates) GetRefinedF0 ... 窓長の計算、GetMeanF0- GetMeanF0- GetBaseIndex ... 窓をかける場所を求める- GetMainWindow ... 地味に重い- GetDiffWindow ... MainWindow の微分した窓を求める- GetSpectra ... 2 つの窓で FFT する、ここが重い- (2) fft_execute- FixF0 ... 瞬時周波数の計算- RemoveUnreliableCandidates ... 前後どちらのフレームにも差が 5% 以内の f0 候補が無いような f0 候補を削除- ((f0_length - 2) * number_of_candidates) RemoveUnreliableCandidatesSub ... 前後 1 フレームに対して SelectBestF0- (2) SelectBestF0 ... 自身に最も近い f0 を得る- FixF0Contour- SearchF0Base ... 各フレームで最もスコアの高い f0 候補を抽出する- FixStep1 ... 前フレームの f0 と前2フレームから線形で予測した f0 の両方から 0.8% 以上の差がある場合は f0 を 0 にする- FixStep2 ... 5 フレーム以下しか連続しない有声区間を削除- GetBoundaryList ... 有声部の閉区間のリストを作る- FixStep3 ...- GetBoundaryList- GetMultiChannelF0 ... 有声区間ごとに分けて別の配列にする- Extend ... 各有声区間を前後に伸ばす- (number_of_sections * 2) ExtendF0- (distance + 1) SelectBestF0 ... 18% 以内の差なら採択する- ExtendSub ... 有声区間が十分な長さ (平均 100Hz なら 22 フレーム、200Hz なら 11 フレーム) ないものを削除- MergeF0 ... 有声区間をマージする- MakeSortedOrder ... 有声区間たちを開始時刻の昇順にソート- MergeF0Sub ... 区間が重なる場合に、重なった部分のスコアの和が大きい方を選ぶ- (2) SearchScore- FixStep4 ... 短い無声区間を線形補間で埋める- GetBoundaryList- SmoothF0Contour ... F0 軌跡に LPF をかけて滑らかにする- GetBoundaryList- GetMultiChannelF0 ... 2 回目- (number_of_boundaries) FilteringF0
© DeNA Co., Ltd. 98 DetectOfficialF0Candidates - 結果の例F0 候補
© DeNA Co., Ltd. 109 RefineF0Candidates- Harvest- HarvestGeneralBody- GetWaveformAndSpectrum ... 直流成分の除去、後の畳み込みのための FFT- GetWaveformAndSpectrumSub- HarvestGeneralBodySub- GetRawF0Candidates- (number_of_bands) GetF0CandidateFromRawEvent- GetFilteredSignal ... FFT でその帯域の BPF を畳み込む- (2) fft_execute- GetFourZeroCrossingIntervals ... ゼロ交叉/ピークの点を列挙、間隔から f0 を計算- GetF0CandidateContour- (4) interp1 ... f0 を時間方向に補間- GetF0CandidateContourSub ... 4 つの平均を計算、ばらけていたら 0- DetectOfficialF0Candidates- (f0_length) DetectOfficialF0CandidatesSub1 ... 台を検出- (f0_length) DetectOfficialF0CandidatesSub2 ... 各台の平均 f0 を計算、細い台は無視- OverlapF0Candidates ... 前後 3 フレームに f0 候補をコピー- RefineF0Candidates ... f0 候補を瞬時周波数で修正- (f0_length * num_candidates) GetRefinedF0 ... 窓長の計算、GetMeanF0- GetMeanF0- GetBaseIndex ... 窓をかける場所を求める- GetMainWindow ... 地味に重い- GetDiffWindow ... MainWindow の微分した窓を求める- GetSpectra ... 2 つの窓で FFT する、ここが重い- (2) fft_execute- FixF0 ... 瞬時周波数の計算- RemoveUnreliableCandidates ... 前後どちらのフレームにも差が 5% 以内の f0 候補が無いような f0 候補を削除- ((f0_length - 2) * number_of_candidates) RemoveUnreliableCandidatesSub ... 前後 1 フレームに対して SelectBestF0- (2) SelectBestF0 ... 自身に最も近い f0 を得る- FixF0Contour- SearchF0Base ... 各フレームで最もスコアの高い f0 候補を抽出する- FixStep1 ... 前フレームの f0 と前2フレームから線形で予測した f0 の両方から 0.8% 以上の差がある場合は f0 を 0 にする- FixStep2 ... 5 フレーム以下しか連続しない有声区間を削除- GetBoundaryList ... 有声部の閉区間のリストを作る- FixStep3 ...- GetBoundaryList- GetMultiChannelF0 ... 有声区間ごとに分けて別の配列にする- Extend ... 各有声区間を前後に伸ばす- (number_of_sections * 2) ExtendF0- (distance + 1) SelectBestF0 ... 18% 以内の差なら採択する- ExtendSub ... 有声区間が十分な長さ (平均 100Hz なら 22 フレーム、200Hz なら 11 フレーム) ないものを削除- MergeF0 ... 有声区間をマージする- MakeSortedOrder ... 有声区間たちを開始時刻の昇順にソート- MergeF0Sub ... 区間が重なる場合に、重なった部分のスコアの和が大きい方を選ぶ- (2) SearchScore- FixStep4 ... 短い無声区間を線形補間で埋める- GetBoundaryList- SmoothF0Contour ... F0 軌跡に LPF をかけて滑らかにする- GetBoundaryList- GetMultiChannelF0 ... 2 回目- (number_of_boundaries) FilteringF0● F0 候補を、瞬時周波数を求めることで再計算する。● よくわからない方法で求めていた。○ 窓関数をかけて DFT をすると複素スペクトルが得られるが、予め時間微分した窓関数をかけて DFT をすると複素スペクトルの時間微分が得られ、この 2 回のDFT の結果から瞬時周波数を求めているらしい。● F0 候補の信頼度もここでよくわからない式で求めていた。● とても重い○ F0 に対して適応的な (3 周期分の) 窓を使うので、毎回窓関数を計算している■ 入力サンプリングレートが 8000Hz の倍数なら窓は 300 種類くらいになりそうなので、それを全部前計算するとかで高速化できるかも○ FFT が候補の数 * 2 回走る
© DeNA Co., Ltd. 1110 RefineF0Candidates - 結果の例精緻化された F0 候補とその信頼度
© DeNA Co., Ltd. 1211 RemoveUnreliableCandidates- Harvest- HarvestGeneralBody- GetWaveformAndSpectrum ... 直流成分の除去、後の畳み込みのための FFT- GetWaveformAndSpectrumSub- HarvestGeneralBodySub- GetRawF0Candidates- (number_of_bands) GetF0CandidateFromRawEvent- GetFilteredSignal ... FFT でその帯域の BPF を畳み込む- (2) fft_execute- GetFourZeroCrossingIntervals ... ゼロ交叉/ピークの点を列挙、間隔から f0 を計算- GetF0CandidateContour- (4) interp1 ... f0 を時間方向に補間- GetF0CandidateContourSub ... 4 つの平均を計算、ばらけていたら 0- DetectOfficialF0Candidates- (f0_length) DetectOfficialF0CandidatesSub1 ... 台を検出- (f0_length) DetectOfficialF0CandidatesSub2 ... 各台の平均 f0 を計算、細い台は無視- OverlapF0Candidates ... 前後 3 フレームに f0 候補をコピー- RefineF0Candidates ... f0 候補を瞬時周波数で修正- (f0_length * num_candidates) GetRefinedF0 ... 窓長の計算、GetMeanF0- GetMeanF0- GetBaseIndex ... 窓をかける場所を求める- GetMainWindow ... 地味に重い- GetDiffWindow ... MainWindow の微分した窓を求める- GetSpectra ... 2 つの窓で FFT する、ここが重い- (2) fft_execute- FixF0 ... 瞬時周波数の計算- RemoveUnreliableCandidates ... 前後どちらのフレームにも差が 5% 以内の f0 候補が無いような f0 候補を削除- ((f0_length - 2) * number_of_candidates) RemoveUnreliableCandidatesSub ... 前後 1 フレームに対して SelectBestF0- (2) SelectBestF0 ... 自身に最も近い f0 を得る- FixF0Contour- SearchF0Base ... 各フレームで最もスコアの高い f0 候補を抽出する- FixStep1 ... 前フレームの f0 と前2フレームから線形で予測した f0 の両方から 0.8% 以上の差がある場合は f0 を 0 にする- FixStep2 ... 5 フレーム以下しか連続しない有声区間を削除- GetBoundaryList ... 有声部の閉区間のリストを作る- FixStep3 ...- GetBoundaryList- GetMultiChannelF0 ... 有声区間ごとに分けて別の配列にする- Extend ... 各有声区間を前後に伸ばす- (number_of_sections * 2) ExtendF0- (distance + 1) SelectBestF0 ... 18% 以内の差なら採択する- ExtendSub ... 有声区間が十分な長さ (平均 100Hz なら 22 フレーム、200Hz なら 11 フレーム) ないものを削除- MergeF0 ... 有声区間をマージする- MakeSortedOrder ... 有声区間たちを開始時刻の昇順にソート- MergeF0Sub ... 区間が重なる場合に、重なった部分のスコアの和が大きい方を選ぶ- (2) SearchScore- FixStep4 ... 短い無声区間を線形補間で埋める- GetBoundaryList- SmoothF0Contour ... F0 軌跡に LPF をかけて滑らかにする- GetBoundaryList- GetMultiChannelF0 ... 2 回目- (number_of_boundaries) FilteringF0● 前後どちらのフレームにも差が 5% 以内の F0 候補が無いような F0 候補を削除する。
© DeNA Co., Ltd. 1312 RemoveUnreliableCandidates - 結果の例F0 候補とその信頼度
© DeNA Co., Ltd. 1413 SearchF0Base- Harvest- HarvestGeneralBody- GetWaveformAndSpectrum ... 直流成分の除去、後の畳み込みのための FFT- GetWaveformAndSpectrumSub- HarvestGeneralBodySub- GetRawF0Candidates- (number_of_bands) GetF0CandidateFromRawEvent- GetFilteredSignal ... FFT でその帯域の BPF を畳み込む- (2) fft_execute- GetFourZeroCrossingIntervals ... ゼロ交叉/ピークの点を列挙、間隔から f0 を計算- GetF0CandidateContour- (4) interp1 ... f0 を時間方向に補間- GetF0CandidateContourSub ... 4 つの平均を計算、ばらけていたら 0- DetectOfficialF0Candidates- (f0_length) DetectOfficialF0CandidatesSub1 ... 台を検出- (f0_length) DetectOfficialF0CandidatesSub2 ... 各台の平均 f0 を計算、細い台は無視- OverlapF0Candidates ... 前後 3 フレームに f0 候補をコピー- RefineF0Candidates ... f0 候補を瞬時周波数で修正- (f0_length * num_candidates) GetRefinedF0 ... 窓長の計算、GetMeanF0- GetMeanF0- GetBaseIndex ... 窓をかける場所を求める- GetMainWindow ... 地味に重い- GetDiffWindow ... MainWindow の微分した窓を求める- GetSpectra ... 2 つの窓で FFT する、ここが重い- (2) fft_execute- FixF0 ... 瞬時周波数の計算- RemoveUnreliableCandidates ... 前後どちらのフレームにも差が 5% 以内の f0 候補が無いような f0 候補を削除- ((f0_length - 2) * number_of_candidates) RemoveUnreliableCandidatesSub ... 前後 1 フレームに対して SelectBestF0- (2) SelectBestF0 ... 自身に最も近い f0 を得る- FixF0Contour- SearchF0Base ... 各フレームで最もスコアの高い f0 候補を抽出する- FixStep1 ... 前フレームの f0 と前2フレームから線形で予測した f0 の両方から 0.8% 以上の差がある場合は f0 を 0 にする- FixStep2 ... 5 フレーム以下しか連続しない有声区間を削除- GetBoundaryList ... 有声部の閉区間のリストを作る- FixStep3 ...- GetBoundaryList- GetMultiChannelF0 ... 有声区間ごとに分けて別の配列にする- Extend ... 各有声区間を前後に伸ばす- (number_of_sections * 2) ExtendF0- (distance + 1) SelectBestF0 ... 18% 以内の差なら採択する- ExtendSub ... 有声区間が十分な長さ (平均 100Hz なら 22 フレーム、200Hz なら 11 フレーム) ないものを削除- MergeF0 ... 有声区間をマージする- MakeSortedOrder ... 有声区間たちを開始時刻の昇順にソート- MergeF0Sub ... 区間が重なる場合に、重なった部分のスコアの和が大きい方を選ぶ- (2) SearchScore- FixStep4 ... 短い無声区間を線形補間で埋める- GetBoundaryList- SmoothF0Contour ... F0 軌跡に LPF をかけて滑らかにする- GetBoundaryList- GetMultiChannelF0 ... 2 回目- (number_of_boundaries) FilteringF0● 各フレームで最もスコアの高い F0 候補を抽出する。● 注: F0 候補は後 (FixStep3) でまた使うことになる
© DeNA Co., Ltd. 1514 SearchF0Base - 結果の例各フレームで最も信頼度の高いF0 候補
© DeNA Co., Ltd. 1615 FixStep1- Harvest- HarvestGeneralBody- GetWaveformAndSpectrum ... 直流成分の除去、後の畳み込みのための FFT- GetWaveformAndSpectrumSub- HarvestGeneralBodySub- GetRawF0Candidates- (number_of_bands) GetF0CandidateFromRawEvent- GetFilteredSignal ... FFT でその帯域の BPF を畳み込む- (2) fft_execute- GetFourZeroCrossingIntervals ... ゼロ交叉/ピークの点を列挙、間隔から f0 を計算- GetF0CandidateContour- (4) interp1 ... f0 を時間方向に補間- GetF0CandidateContourSub ... 4 つの平均を計算、ばらけていたら 0- DetectOfficialF0Candidates- (f0_length) DetectOfficialF0CandidatesSub1 ... 台を検出- (f0_length) DetectOfficialF0CandidatesSub2 ... 各台の平均 f0 を計算、細い台は無視- OverlapF0Candidates ... 前後 3 フレームに f0 候補をコピー- RefineF0Candidates ... f0 候補を瞬時周波数で修正- (f0_length * num_candidates) GetRefinedF0 ... 窓長の計算、GetMeanF0- GetMeanF0- GetBaseIndex ... 窓をかける場所を求める- GetMainWindow ... 地味に重い- GetDiffWindow ... MainWindow の微分した窓を求める- GetSpectra ... 2 つの窓で FFT する、ここが重い- (2) fft_execute- FixF0 ... 瞬時周波数の計算- RemoveUnreliableCandidates ... 前後どちらのフレームにも差が 5% 以内の f0 候補が無いような f0 候補を削除- ((f0_length - 2) * number_of_candidates) RemoveUnreliableCandidatesSub ... 前後 1 フレームに対して SelectBestF0- (2) SelectBestF0 ... 自身に最も近い f0 を得る- FixF0Contour- SearchF0Base ... 各フレームで最もスコアの高い f0 候補を抽出する- FixStep1 ... 前フレームの f0 と前2フレームから線形で予測した f0 の両方から 0.8% 以上の差がある場合は f0 を 0 にする- FixStep2 ... 5 フレーム以下しか連続しない有声区間を削除- GetBoundaryList ... 有声部の閉区間のリストを作る- FixStep3 ...- GetBoundaryList- GetMultiChannelF0 ... 有声区間ごとに分けて別の配列にする- Extend ... 各有声区間を前後に伸ばす- (number_of_sections * 2) ExtendF0- (distance + 1) SelectBestF0 ... 18% 以内の差なら採択する- ExtendSub ... 有声区間が十分な長さ (平均 100Hz なら 22 フレーム、200Hz なら 11 フレーム) ないものを削除- MergeF0 ... 有声区間をマージする- MakeSortedOrder ... 有声区間たちを開始時刻の昇順にソート- MergeF0Sub ... 区間が重なる場合に、重なった部分のスコアの和が大きい方を選ぶ- (2) SearchScore- FixStep4 ... 短い無声区間を線形補間で埋める- GetBoundaryList- SmoothF0Contour ... F0 軌跡に LPF をかけて滑らかにする- GetBoundaryList- GetMultiChannelF0 ... 2 回目- (number_of_boundaries) FilteringF0● 前フレームの F0 と前 2 フレームから線形予測した F0 の両方から 0.8% 以上の差がある場合は F0 を 0 にする。
© DeNA Co., Ltd. 1716 FixStep1 - 結果の例F0 軌跡
© DeNA Co., Ltd. 1817 FixStep2- Harvest- HarvestGeneralBody- GetWaveformAndSpectrum ... 直流成分の除去、後の畳み込みのための FFT- GetWaveformAndSpectrumSub- HarvestGeneralBodySub- GetRawF0Candidates- (number_of_bands) GetF0CandidateFromRawEvent- GetFilteredSignal ... FFT でその帯域の BPF を畳み込む- (2) fft_execute- GetFourZeroCrossingIntervals ... ゼロ交叉/ピークの点を列挙、間隔から f0 を計算- GetF0CandidateContour- (4) interp1 ... f0 を時間方向に補間- GetF0CandidateContourSub ... 4 つの平均を計算、ばらけていたら 0- DetectOfficialF0Candidates- (f0_length) DetectOfficialF0CandidatesSub1 ... 台を検出- (f0_length) DetectOfficialF0CandidatesSub2 ... 各台の平均 f0 を計算、細い台は無視- OverlapF0Candidates ... 前後 3 フレームに f0 候補をコピー- RefineF0Candidates ... f0 候補を瞬時周波数で修正- (f0_length * num_candidates) GetRefinedF0 ... 窓長の計算、GetMeanF0- GetMeanF0- GetBaseIndex ... 窓をかける場所を求める- GetMainWindow ... 地味に重い- GetDiffWindow ... MainWindow の微分した窓を求める- GetSpectra ... 2 つの窓で FFT する、ここが重い- (2) fft_execute- FixF0 ... 瞬時周波数の計算- RemoveUnreliableCandidates ... 前後どちらのフレームにも差が 5% 以内の f0 候補が無いような f0 候補を削除- ((f0_length - 2) * number_of_candidates) RemoveUnreliableCandidatesSub ... 前後 1 フレームに対して SelectBestF0- (2) SelectBestF0 ... 自身に最も近い f0 を得る- FixF0Contour- SearchF0Base ... 各フレームで最もスコアの高い f0 候補を抽出する- FixStep1 ... 前フレームの f0 と前2フレームから線形で予測した f0 の両方から 0.8% 以上の差がある場合は f0 を 0 にする- FixStep2 ... 5 フレーム以下しか連続しない有声区間を削除する- GetBoundaryList ... 有声部の閉区間のリストを作る- FixStep3 ...- GetBoundaryList- GetMultiChannelF0 ... 有声区間ごとに分けて別の配列にする- Extend ... 各有声区間を前後に伸ばす- (number_of_sections * 2) ExtendF0- (distance + 1) SelectBestF0 ... 18% 以内の差なら採択する- ExtendSub ... 有声区間が十分な長さ (平均 100Hz なら 22 フレーム、200Hz なら 11 フレーム) ないものを削除- MergeF0 ... 有声区間をマージする- MakeSortedOrder ... 有声区間たちを開始時刻の昇順にソート- MergeF0Sub ... 区間が重なる場合に、重なった部分のスコアの和が大きい方を選ぶ- (2) SearchScore- FixStep4 ... 短い無声区間を線形補間で埋める- GetBoundaryList- SmoothF0Contour ... F0 軌跡に LPF をかけて滑らかにする- GetBoundaryList- GetMultiChannelF0 ... 2 回目- (number_of_boundaries) FilteringF0● 5 フレーム以下しか連続しない有声区間を削除する。
© DeNA Co., Ltd. 1918 FixStep2 - 結果の例F0 軌跡
© DeNA Co., Ltd. 2019 FixStep3 - GetMultiChannelF0- Harvest- HarvestGeneralBody- GetWaveformAndSpectrum ... 直流成分の除去、後の畳み込みのための FFT- GetWaveformAndSpectrumSub- HarvestGeneralBodySub- GetRawF0Candidates- (number_of_bands) GetF0CandidateFromRawEvent- GetFilteredSignal ... FFT でその帯域の BPF を畳み込む- (2) fft_execute- GetFourZeroCrossingIntervals ... ゼロ交叉/ピークの点を列挙、間隔から f0 を計算- GetF0CandidateContour- (4) interp1 ... f0 を時間方向に補間- GetF0CandidateContourSub ... 4 つの平均を計算、ばらけていたら 0- DetectOfficialF0Candidates- (f0_length) DetectOfficialF0CandidatesSub1 ... 台を検出- (f0_length) DetectOfficialF0CandidatesSub2 ... 各台の平均 f0 を計算、細い台は無視- OverlapF0Candidates ... 前後 3 フレームに f0 候補をコピー- RefineF0Candidates ... f0 候補を瞬時周波数で修正- (f0_length * num_candidates) GetRefinedF0 ... 窓長の計算、GetMeanF0- GetMeanF0- GetBaseIndex ... 窓をかける場所を求める- GetMainWindow ... 地味に重い- GetDiffWindow ... MainWindow の微分した窓を求める- GetSpectra ... 2 つの窓で FFT する、ここが重い- (2) fft_execute- FixF0 ... 瞬時周波数の計算- RemoveUnreliableCandidates ... 前後どちらのフレームにも差が 5% 以内の f0 候補が無いような f0 候補を削除- ((f0_length - 2) * number_of_candidates) RemoveUnreliableCandidatesSub ... 前後 1 フレームに対して SelectBestF0- (2) SelectBestF0 ... 自身に最も近い f0 を得る- FixF0Contour- SearchF0Base ... 各フレームで最もスコアの高い f0 候補を抽出する- FixStep1 ... 前フレームの f0 と前2フレームから線形で予測した f0 の両方から 0.8% 以上の差がある場合は f0 を 0 にする- FixStep2 ... 5 フレーム以下しか連続しない有声区間を削除- GetBoundaryList ... 有声部の閉区間のリストを作る- FixStep3 ...- GetBoundaryList- GetMultiChannelF0 ... 有声区間ごとに分けて別の配列にする- Extend ... 各有声区間を前後に伸ばす- (number_of_sections * 2) ExtendF0- (distance + 1) SelectBestF0 ... 18% 以内の差なら採択する- ExtendSub ... 有声区間が十分な長さ (平均 100Hz なら 22 フレーム、200Hz なら 11 フレーム) ないものを削除- MergeF0 ... 有声区間をマージする- MakeSortedOrder ... 有声区間たちを開始時刻の昇順にソート- MergeF0Sub ... 区間が重なる場合に、重なった部分のスコアの和が大きい方を選ぶ- (2) SearchScore- FixStep4 ... 短い無声区間を線形補間で埋める- GetBoundaryList- SmoothF0Contour ... F0 軌跡に LPF をかけて滑らかにする- GetBoundaryList- GetMultiChannelF0 ... 2 回目- (number_of_boundaries) FilteringF0● 有声区間ごとに分けて別の配列にする。● 有声区間の個数が入力音声の長さに比例すると考えると、入力音声の長さの 2 乗に比例する大きさのメモリを確保していることになる
© DeNA Co., Ltd. 2120 FixStep3 - GetMultiChannelF0 - 結果の例有声区間ごとに分けられた F0 軌跡
© DeNA Co., Ltd. 2221 FixStep3 - Extend- Harvest- HarvestGeneralBody- GetWaveformAndSpectrum ... 直流成分の除去、後の畳み込みのための FFT- GetWaveformAndSpectrumSub- HarvestGeneralBodySub- GetRawF0Candidates- (number_of_bands) GetF0CandidateFromRawEvent- GetFilteredSignal ... FFT でその帯域の BPF を畳み込む- (2) fft_execute- GetFourZeroCrossingIntervals ... ゼロ交叉/ピークの点を列挙、間隔から f0 を計算- GetF0CandidateContour- (4) interp1 ... f0 を時間方向に補間- GetF0CandidateContourSub ... 4 つの平均を計算、ばらけていたら 0- DetectOfficialF0Candidates- (f0_length) DetectOfficialF0CandidatesSub1 ... 台を検出- (f0_length) DetectOfficialF0CandidatesSub2 ... 各台の平均 f0 を計算、細い台は無視- OverlapF0Candidates ... 前後 3 フレームに f0 候補をコピー- RefineF0Candidates ... f0 候補を瞬時周波数で修正- (f0_length * num_candidates) GetRefinedF0 ... 窓長の計算、GetMeanF0- GetMeanF0- GetBaseIndex ... 窓をかける場所を求める- GetMainWindow ... 地味に重い- GetDiffWindow ... MainWindow の微分した窓を求める- GetSpectra ... 2 つの窓で FFT する、ここが重い- (2) fft_execute- FixF0 ... 瞬時周波数の計算- RemoveUnreliableCandidates ... 前後どちらのフレームにも差が 5% 以内の f0 候補が無いような f0 候補を削除- ((f0_length - 2) * number_of_candidates) RemoveUnreliableCandidatesSub ... 前後 1 フレームに対して SelectBestF0- (2) SelectBestF0 ... 自身に最も近い f0 を得る- FixF0Contour- SearchF0Base ... 各フレームで最もスコアの高い f0 候補を抽出する- FixStep1 ... 前フレームの f0 と前2フレームから線形で予測した f0 の両方から 0.8% 以上の差がある場合は f0 を 0 にする- FixStep2 ... 5 フレーム以下しか連続しない有声区間を削除- GetBoundaryList ... 有声部の閉区間のリストを作る- FixStep3 ...- GetBoundaryList- GetMultiChannelF0 ... 有声区間ごとに分けて別の配列にする- Extend ... 各有声区間を前後に伸ばす- (number_of_sections * 2) ExtendF0- (distance + 1) SelectBestF0 ... 18% 以内の差なら採択する- ExtendSub ... 有声区間が十分な長さ (平均 100Hz なら 22 フレーム、200Hz なら 11 フレーム) ないものを削除- MergeF0 ... 有声区間をマージする- MakeSortedOrder ... 有声区間たちを開始時刻の昇順にソート- MergeF0Sub ... 区間が重なる場合に、重なった部分のスコアの和が大きい方を選ぶ- (2) SearchScore- FixStep4 ... 短い無声区間を線形補間で埋める- GetBoundaryList- SmoothF0Contour ... F0 軌跡に LPF をかけて滑らかにする- GetBoundaryList- GetMultiChannelF0 ... 2 回目- (number_of_boundaries) FilteringF0● 各有声区間を前後に伸ばす。○ F0 が近いものを辿っている、多分○ 自身との差が 18% より大きい F0 候補は無視している、多分
© DeNA Co., Ltd. 2322 FixStep3 - Extend - 結果の例伸ばされた F0 軌跡たち
© DeNA Co., Ltd. 2423 FixStep3 - MergeF0- Harvest- HarvestGeneralBody- GetWaveformAndSpectrum ... 直流成分の除去、後の畳み込みのための FFT- GetWaveformAndSpectrumSub- HarvestGeneralBodySub- GetRawF0Candidates- (number_of_bands) GetF0CandidateFromRawEvent- GetFilteredSignal ... FFT でその帯域の BPF を畳み込む- (2) fft_execute- GetFourZeroCrossingIntervals ... ゼロ交叉/ピークの点を列挙、間隔から f0 を計算- GetF0CandidateContour- (4) interp1 ... f0 を時間方向に補間- GetF0CandidateContourSub ... 4 つの平均を計算、ばらけていたら 0- DetectOfficialF0Candidates- (f0_length) DetectOfficialF0CandidatesSub1 ... 台を検出- (f0_length) DetectOfficialF0CandidatesSub2 ... 各台の平均 f0 を計算、細い台は無視- OverlapF0Candidates ... 前後 3 フレームに f0 候補をコピー- RefineF0Candidates ... f0 候補を瞬時周波数で修正- (f0_length * num_candidates) GetRefinedF0 ... 窓長の計算、GetMeanF0- GetMeanF0- GetBaseIndex ... 窓をかける場所を求める- GetMainWindow ... 地味に重い- GetDiffWindow ... MainWindow の微分した窓を求める- GetSpectra ... 2 つの窓で FFT する、ここが重い- (2) fft_execute- FixF0 ... 瞬時周波数の計算- RemoveUnreliableCandidates ... 前後どちらのフレームにも差が 5% 以内の f0 候補が無いような f0 候補を削除- ((f0_length - 2) * number_of_candidates) RemoveUnreliableCandidatesSub ... 前後 1 フレームに対して SelectBestF0- (2) SelectBestF0 ... 自身に最も近い f0 を得る- FixF0Contour- SearchF0Base ... 各フレームで最もスコアの高い f0 候補を抽出する- FixStep1 ... 前フレームの f0 と前2フレームから線形で予測した f0 の両方から 0.8% 以上の差がある場合は f0 を 0 にする- FixStep2 ... 5 フレーム以下しか連続しない有声区間を削除- GetBoundaryList ... 有声部の閉区間のリストを作る- FixStep3 ...- GetBoundaryList- GetMultiChannelF0 ... 有声区間ごとに分けて別の配列にする- Extend ... 各有声区間を前後に伸ばす- (number_of_sections * 2) ExtendF0- (distance + 1) SelectBestF0 ... 18% 以内の差なら採択する- ExtendSub ... 有声区間が十分な長さ (平均 100Hz なら 22 フレーム、200Hz なら 11 フレーム) ないものを削除- MergeF0 ... 有声区間をマージする- MakeSortedOrder ... 有声区間たちを開始時刻の昇順にソート- MergeF0Sub ... 区間が重なる場合に、重なった部分のスコアの和が大きい方を選ぶ- (2) SearchScore- FixStep4 ... 短い無声区間を線形補間で埋める- GetBoundaryList- SmoothF0Contour ... F0 軌跡に LPF をかけて滑らかにする- GetBoundaryList- GetMultiChannelF0 ... 2 回目- (number_of_boundaries) FilteringF0● 短い有声区間は削除し、各有声区間をマージする。○ 削除の基準 … 波長の長さの 2.2 倍■ 区間の平均が 100Hz なら 22 フレーム未満、200Hz なら 11 フレーム未満で削除● 区間が重なる場合には、重なった部分の信頼度の和が大きい方を選ぶ。
© DeNA Co., Ltd. 2524 FixStep3 - MergeF0 - 結果の例マージされた F0 軌跡
© DeNA Co., Ltd. 2625 FixStep4- Harvest- HarvestGeneralBody- GetWaveformAndSpectrum ... 直流成分の除去、後の畳み込みのための FFT- GetWaveformAndSpectrumSub- HarvestGeneralBodySub- GetRawF0Candidates- (number_of_bands) GetF0CandidateFromRawEvent- GetFilteredSignal ... FFT でその帯域の BPF を畳み込む- (2) fft_execute- GetFourZeroCrossingIntervals ... ゼロ交叉/ピークの点を列挙、間隔から f0 を計算- GetF0CandidateContour- (4) interp1 ... f0 を時間方向に補間- GetF0CandidateContourSub ... 4 つの平均を計算、ばらけていたら 0- DetectOfficialF0Candidates- (f0_length) DetectOfficialF0CandidatesSub1 ... 台を検出- (f0_length) DetectOfficialF0CandidatesSub2 ... 各台の平均 f0 を計算、細い台は無視- OverlapF0Candidates ... 前後 3 フレームに f0 候補をコピー- RefineF0Candidates ... f0 候補を瞬時周波数で修正- (f0_length * num_candidates) GetRefinedF0 ... 窓長の計算、GetMeanF0- GetMeanF0- GetBaseIndex ... 窓をかける場所を求める- GetMainWindow ... 地味に重い- GetDiffWindow ... MainWindow の微分した窓を求める- GetSpectra ... 2 つの窓で FFT する、ここが重い- (2) fft_execute- FixF0 ... 瞬時周波数の計算- RemoveUnreliableCandidates ... 前後どちらのフレームにも差が 5% 以内の f0 候補が無いような f0 候補を削除- ((f0_length - 2) * number_of_candidates) RemoveUnreliableCandidatesSub ... 前後 1 フレームに対して SelectBestF0- (2) SelectBestF0 ... 自身に最も近い f0 を得る- FixF0Contour- SearchF0Base ... 各フレームで最もスコアの高い f0 候補を抽出する- FixStep1 ... 前フレームの f0 と前2フレームから線形で予測した f0 の両方から 0.8% 以上の差がある場合は f0 を 0 にする- FixStep2 ... 5 フレーム以下しか連続しない有声区間を削除- GetBoundaryList ... 有声部の閉区間のリストを作る- FixStep3 ...- GetBoundaryList- GetMultiChannelF0 ... 有声区間ごとに分けて別の配列にする- Extend ... 各有声区間を前後に伸ばす- (number_of_sections * 2) ExtendF0- (distance + 1) SelectBestF0 ... 18% 以内の差なら採択する- ExtendSub ... 有声区間が十分な長さ (平均 100Hz なら 22 フレーム、200Hz なら 11 フレーム) ないものを削除- MergeF0 ... 有声区間をマージする- MakeSortedOrder ... 有声区間たちを開始時刻の昇順にソート- MergeF0Sub ... 区間が重なる場合に、重なった部分のスコアの和が大きい方を選ぶ- (2) SearchScore- FixStep4 ... 短い無声区間を線形補間で埋める- GetBoundaryList- SmoothF0Contour ... F0 軌跡に LPF をかけて滑らかにする- GetBoundaryList- GetMultiChannelF0 ... 2 回目- (number_of_boundaries) FilteringF0● 短い無声区間を線形補間で埋める。
© DeNA Co., Ltd. 2726 FixStep4 - 結果の例F0 軌跡
© DeNA Co., Ltd. 2827 SmoothF0Contour- Harvest- HarvestGeneralBody- GetWaveformAndSpectrum ... 直流成分の除去、後の畳み込みのための FFT- GetWaveformAndSpectrumSub- HarvestGeneralBodySub- GetRawF0Candidates- (number_of_bands) GetF0CandidateFromRawEvent- GetFilteredSignal ... FFT でその帯域の BPF を畳み込む- (2) fft_execute- GetFourZeroCrossingIntervals ... ゼロ交叉/ピークの点を列挙、間隔から f0 を計算- GetF0CandidateContour- (4) interp1 ... f0 を時間方向に補間- GetF0CandidateContourSub ... 4 つの平均を計算、ばらけていたら 0- DetectOfficialF0Candidates- (f0_length) DetectOfficialF0CandidatesSub1 ... 台を検出- (f0_length) DetectOfficialF0CandidatesSub2 ... 各台の平均 f0 を計算、細い台は無視- OverlapF0Candidates ... 前後 3 フレームに f0 候補をコピー- RefineF0Candidates ... f0 候補を瞬時周波数で修正- (f0_length * num_candidates) GetRefinedF0 ... 窓長の計算、GetMeanF0- GetMeanF0- GetBaseIndex ... 窓をかける場所を求める- GetMainWindow ... 地味に重い- GetDiffWindow ... MainWindow の微分した窓を求める- GetSpectra ... 2 つの窓で FFT する、ここが重い- (2) fft_execute- FixF0 ... 瞬時周波数の計算- RemoveUnreliableCandidates ... 前後どちらのフレームにも差が 5% 以内の f0 候補が無いような f0 候補を削除- ((f0_length - 2) * number_of_candidates) RemoveUnreliableCandidatesSub ... 前後 1 フレームに対して SelectBestF0- (2) SelectBestF0 ... 自身に最も近い f0 を得る- FixF0Contour- SearchF0Base ... 各フレームで最もスコアの高い f0 候補を抽出する- FixStep1 ... 前フレームの f0 と前2フレームから線形で予測した f0 の両方から 0.8% 以上の差がある場合は f0 を 0 にする- FixStep2 ... 5 フレーム以下しか連続しない有声区間を削除- GetBoundaryList ... 有声部の閉区間のリストを作る- FixStep3 ...- GetBoundaryList- GetMultiChannelF0 ... 有声区間ごとに分けて別の配列にする- Extend ... 各有声区間を前後に伸ばす- (number_of_sections * 2) ExtendF0- (distance + 1) SelectBestF0 ... 18% 以内の差なら採択する- ExtendSub ... 有声区間が十分な長さ (平均 100Hz なら 22 フレーム、200Hz なら 11 フレーム) ないものを削除- MergeF0 ... 有声区間をマージする- MakeSortedOrder ... 有声区間たちを開始時刻の昇順にソート- MergeF0Sub ... 区間が重なる場合に、重なった部分のスコアの和が大きい方を選ぶ- (2) SearchScore- FixStep4 ... 短い無声区間を線形補間で埋める- GetBoundaryList- SmoothF0Contour ... F0 軌跡に LPF をかけて滑らかにする- GetBoundaryList- GetMultiChannelF0 ... 2 回目- (number_of_boundaries) FilteringF0● F0 軌跡に LPF をかけて滑らかにする。
© DeNA Co., Ltd. 2928 最終的な結果の例アルゴリズム全体を通して得られた F0 軌跡
© DeNA Co., Ltd. 3029 スペクトログラムと重ねてみるスペクトログラムと F0 軌跡
© DeNA Co., Ltd. 31こうして私たちの元へ届けられる——
© DeNA Co., Ltd. 32