Upgrade to Pro — share decks privately, control downloads, hide ads and more …

F0推定アルゴリズムHarvestは中で何をしているのか

nagiss
September 25, 2023

 F0推定アルゴリズムHarvestは中で何をしているのか

DeNAの2023/5/24の音声トークの発表資料を焼き直したものです。

nagiss

September 25, 2023
Tweet

More Decks by nagiss

Other Decks in Technology

Transcript

  1. © DeNA Co., Ltd. 2 1 • Harvest のコードをある程度読み解いたので、せっかくなら公開しておこうと資料の形にしたもの ◦

    隅々まで読み解こうとはしていないので所々「よくわからない」があります • 参考にしたもの ◦ 実装 https://github.com/mmorise/World/blob/master/src/harvest.cpp ◦ 森勢将雅, “高い雑音耐性と推定精度を両立する基本周波数推定法の提案と評価,” 信学技報, 2016 http://www.isc.meiji.ac.jp/~mmorise/lab/publication/paper/SP2016-62.pdf この資料は何?
  2. © DeNA Co., Ltd. 3 2 • Harvest では内部的に 1ms

    を 1 フレームとして扱っている。 ◦ 1ms 以外で出力する場合は最後に最近傍補間している。 • 例として JVS003 UT-PARAPHRASE-sent239-phrase2 を分析 人生は結局、孤独を和らげるために、生きているようなもんだ ◦ 下線部の 1 秒間 ◦ 「き」が無声化している 前置き 分析対象とした音声のスペクトログラム
  3. © DeNA Co., Ltd. 4 3 コード概観 - 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
  4. © DeNA Co., Ltd. 5 4 • 入力音声を帯域の異なるバンドパスフィルタに通して複 製し、それぞれを正弦波と見做してゼロ交叉・山と谷の 時間間隔により

    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
  5. © DeNA Co., Ltd. 6 5 GetRawF0Candidates - バンドパスフィルタ cos

    関数とナットール窓を掛け合わせて作られた線形位相バンドパスフィルタと、 その周波数応答 (ピークの周波数が 200Hz の場合) sr = 24000 freq = 200 # バンドパスフィルタのピーク周波数 period = sr // freq # 周期 n_fft = 1 << 16 win = 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 になる • 時間領域の掛け算は周波数領域の畳み込みなので、上記の周波数応答が得られる
  6. © DeNA Co., Ltd. 8 7 • 帯域を横軸、得られた周波数を縦軸に取ったグラフを書 くと、いくつかの台ができる。 ◦

    論文中の図 • 各台の周波数を平均をとることで 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
  7. © DeNA Co., Ltd. 10 9 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 回走る
  8. © DeNA Co., Ltd. 12 11 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 候補を削除する。
  9. © DeNA Co., Ltd. 14 13 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) でまた使うことになる
  10. © DeNA Co., Ltd. 16 15 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 にする。
  11. © DeNA Co., Ltd. 18 17 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 フレーム以下しか連続しない有声区間を削除する。
  12. © DeNA Co., Ltd. 20 19 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 乗に比例する大きさ のメモリを確保していることになる
  13. © DeNA Co., Ltd. 21 20 FixStep3 - GetMultiChannelF0 -

    結果の例 有声区間ごとに分けられた F0 軌跡
  14. © DeNA Co., Ltd. 22 21 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 候補は無視して いる、多分
  15. © DeNA Co., Ltd. 23 22 FixStep3 - Extend -

    結果の例 伸ばされた F0 軌跡たち
  16. © DeNA Co., Ltd. 24 23 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 フレーム未満で削除 • 区間が重なる場合には、重なった部分の信頼度の和が大 きい方を選ぶ。
  17. © DeNA Co., Ltd. 25 24 FixStep3 - MergeF0 -

    結果の例 マージされた F0 軌跡
  18. © DeNA Co., Ltd. 26 25 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 • 短い無声区間を線形補間で埋める。
  19. © DeNA Co., Ltd. 28 27 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 をかけて滑らかにする。