NON-ML VOCODER / MECHANISM GUIDE

PML + 60 FWCEP
声を分解して、もう一度作る仕組み

低域処理を変更したパルスモデルを、原音から中間特徴量、保存表現、再合成まで。1つの実例を軸に読み解き、最後に5つの音声で確かめます。

← 比較結果・採用判断に戻る

まず全体像

声を「いつ・どんな響き・どこが不規則」に分けて、作り直す

原音をそのまま保存する代わりに、短い時間ごとのF0(パルスを置く間隔)、スペクトル包絡(音色と大きさ)、雑音マスク(不規則にする周波数帯)へ分解します。復号側はこの3種類から短い音の断片を作り、時間上で重ねます。

① 時間のものさし

F0が高いほどパルスを細かく並べます。無声音にも合成処理のための時計を持たせます。

② 音色の輪郭

包絡は、どの周波数を強くするかを表す滑らかな曲線。60個の係数へまとめて保存します。

③ 規則的か、不規則か

位相の揺らぎから雑音マスクを作り、周波数ごとにパルスを雑音的に変形します。

原音16 kHzの波形
→
解析F0・包絡・PDD
→
保存F0・60 FWCEP・NM
→
復号と合成包絡復元・低域変更・パルス
→
再合成音断片の重ね合わせ

この流れ図は模式図です。以下の特徴量図は、保存済みの実際の解析・合成データから描いています。

今回の推奨案で変えたのは2点。 雑音にする帯域を低域側にも延ばすことと、大きな包絡配列を60係数へまとめることです。PMLの中核は公開実装に基づく信号処理で、音声生成に学習済みニューラルモデルは使いません。
役割の整理

途中で出てくる特徴量は何か

名前表すもの今回の形復号時に必要?
F0基本周波数。合成では連続したパルス時計5 msごとに1値、Hz保存する
SPEC振幅スペクトル包絡5 ms × 2049周波数点60 FWCEPから復元
PDD位相差の揺らぎ。規則的な倍音かを判断する手掛かり5 ms × 2049点、rad相当解析途中だけ
NM雑音的にする帯域のマスク5 ms × 2049個の0/1ビット詰めで保存
FWCEP周波数軸を伸縮して表した、対数包絡の係数5 ms × 60係数float32で保存

代表例は LibriSpeech test-clean の話者1221、録音1221-135766-0005の先頭6秒です。同じ録音を最後まで追い、処理段階ごとの変化を見ます。F0などの「推定」は正解ラベルではありません。

1 / 分析する

F0:パルスを置く時計を作る

まずREAPERで原音の基本周波数を推定します。生の結果には「有声と判断しなかったフレーム」があります。PMLではそのままパルスを止めず、周囲のF0を補間し、範囲制限と段差をなだらかにする処理を行って、連続した時計にします。

青はREAPERが有声と判定した区間のF0。橙は無声区間にも値を補間したパルス配置用クロック。無声区間の橙線は、その声に実在する音高の測定値ではありません。 表示単位:秒 / Hz / normalized waveform amplitude
実データの可視化
青はREAPERが有声と判定した区間のF0。橙は無声区間にも値を補間したパルス配置用クロック。無声区間の橙線は、その声に実在する音高の測定値ではありません。 表示単位:秒 / Hz / normalized waveform amplitude
無声区間の線は、そこで声帯が振動しているという主張ではありません。 あくまで合成断片を置くスケジュールです。不規則な音にするかどうかは、別のNMが周波数ごとに担います。
次のパルス時刻 = 今のパルス時刻 + 1 / F0(今の時刻) 例:F0 = 200 Hz → 約5 ms間隔
今回の実装でのF0の使い分け

連続F0はPDDの解析窓と合成時計に使います。CheapTrickの包絡推定に限って、StoneMaskで精密化した別のF0を使います。この精密化したF0へ合成時計全体を置き換えているわけではありません。解析時の範囲設定は65〜700 Hz。段差除去後の値は個別に記録し、追加の隠れた修正はしていません。

2 / 音色を取り出す

包絡:細い倍音線から、滑らかな響きの輪郭へ

原音のスペクトルには細い倍音線が並びます。その線を1本ずつ保存する代わりに、CheapTrickで周波数方向の滑らかな包絡を推定します。共鳴の山や、音の大きさの変化をこの曲線にまとめます。

細い倍音そのものではなく、周波数ごとの大まかな強さを取り出します。保存されたSPECはCheapTrickのpowerを平方根にした振幅。StoneMask補正F0はこの包絡推定にのみ用います。 表示単位:1197×2049, 5ms間隔, 0〜8kHz, 20log10(SPEC/SPEC.max)
実データの可視化
細い倍音そのものではなく、周波数ごとの大まかな強さを取り出します。保存されたSPECはCheapTrickのpowerを平方根にした振幅。StoneMask補正F0はこの包絡推定にのみ用います。 表示単位:1197×2049, 5ms間隔, 0〜8kHz, 20log10(SPEC/SPEC.max)

CheapTrickの出力はパワーに対応する量です。この試作ではその平方根を取って、PMLへ渡す振幅包絡SPECにします。

SPEC(t, f) = √ CheapTrick出力(t, f)
これは原音のSTFTをそのまま保存したものでも、純粋な声道だけを完全分離したものでもありません。声の響き・励振側の傾斜などを含む推定包絡です。公開実装の単位を明示して接続した経路で、論文のSTRAIGHT解析をそのまま再現したものではありません。
3 / 不規則さを調べる

PDD → NM:どこを雑音的にするか

同じような振動が繰り返される音では、倍音どうしの位相関係も比較的安定します。雑音では、その関係が揺らぎます。PDDはこの揺らぎを周波数ごとに数値化します。

  1. 連続F0に沿い、1周期に4回の解析時刻を置く。
  2. 約2.5周期の窓で倍音付近のピークと位相を読む。
  3. 基本波を基準にした相対位相から、隣接倍音の位相差を求める。
  4. ゆっくりした変化を除き、残った揺らぎを円周統計で集計する。
  5. PDD > 0.75を雑音側とし、小さな穴や孤立領域を形態学的処理で整理する。
PDDは位相歪みのばらつきを表す量。大きいほど周期性が弱いという手掛かりとして使います。正解の有声/無声ラベルや雑音混合比ではありません。図の色は2.5 rad以上を同色に飽和表示。 表示単位:1197×2049, radians
実データの可視化
PDDは位相歪みのばらつきを表す量。大きいほど周期性が弱いという手掛かりとして使います。正解の有声/無声ラベルや雑音混合比ではありません。図の色は2.5 rad以上を同色に飽和表示。 表示単位:1197×2049, radians
NM = 0:規則的なパルスを保つ側 NM = 1:雑音的な変形を使う側
PDDは「雑音の混合率」そのものではありません。 位相推定の誤りやF0のずれ、信号の弱さにも影響される指標です。NMも真の有声・無声の正解ではなく、合成器を制御するための判定です。
なぜ0と1だけなのに、合成では中間値も出てくるのか

保存するNMは0/1です。一方で合成前には周波数方向を平滑化するため、帯域の境目には0と1の間の値ができます。今回は「0〜1の連続判定が最善」と結論したわけではありません。保存表現は2値、実効マスクは境界が滑らか、という実装です。

4 / 今回の変更点

低域を一律に規則的なまま残さない

元の処理では解析時に約1.5 F0より下、合成時に約2 F0より下のマスクを0にします。この「低域保護」は低い倍音を規則的に保つ一方、無声に近い区間でも細い低域の線を残す原因になり得ます。

今回の変更では、合成時に2 F0付近の最初の保護外のビンの値を、それより下にもコピーします。0なら低域は0のまま、1なら低域も雑音側へ広がります。その後の平滑化は同じです。

同じ保存NMから、低域規則だけを変えた比較。赤線は2×クロックF0。変更後はその境界の値を低域に借ります。境界値が0なら低域も0のままです。 表示単位:1197×257表示(全保存配列1197×2049), 無次元0/1, 低域0〜1kHz
実データの可視化
同じ保存NMから、低域規則だけを変えた比較。赤線は2×クロックF0。変更後はその境界の値を低域に借ります。境界値が0なら低域も0のままです。 表示単位:1197×257表示(全保存配列1197×2049), 無次元0/1, 低域0〜1kHz
合成ではパルス時刻に二値NMを最近傍で選び、周波数方向に9点Hann・往復フィルタで平滑化します。0と1の間の値も生じます。0.5は単純な「雑音50%」を意味しません。 表示単位:1284×2049 (図は0〜1kHz), 無次元
実データの可視化
合成ではパルス時刻に二値NMを最近傍で選び、周波数方向に9点Hann・往復フィルタで平滑化します。0と1の間の値も生じます。0.5は単純な「雑音50%」を意味しません。 表示単位:1284×2049 (図は0〜1kHz), 無次元
k = floor(4096 × 2 F0 / 16000) 元の処理:NM[0:k] = 0 変更後 :NM[0:k] = NM[k] その後、周波数方向を平滑化 → 実効マスク M
狙いは「雑音を全体に増やす」ことではなく、低域だけを機械的に周期音へ固定する制約を緩めることです。実図で低域のマスクとスペクトルの変化を対応づけて見られます。

これは単純な外挿の仮説です。低域の真の雑音量を測り直したものではありません。また平滑化があるので、変化はカット位置のすぐ上にも及びます。

5 / 小さく保存する

2049点の包絡を、60個のFWCEPへ

包絡は滑らかなので、2049点すべてを独立した値として保存する必要はないかもしれません。そこで振幅の自然対数を取り、低周波を細かく扱うように周波数軸をmel系の軸へ伸縮し、変換後の包絡を少数の係数で表します。

包絡2049点の振幅
→
log + 軸の伸縮低域を細かく
→
逆FFT係数に変換
→
先頭60個float32で保存
c0は別の縦軸で示し、c1〜c59は±0.4で色を飽和表示。係数番号は周波数ではありません。実際の保存値はfloat32、NMとF0はこの圧縮では変えません。 表示単位:1197×60, natural-log amplitude cepstral coefficients
実データの可視化
c0は別の縦軸で示し、c1〜c59は±0.4で色を飽和表示。係数番号は周波数ではありません。実際の保存値はfloat32、NMとF0はこの圧縮では変えません。 表示単位:1197×60, natural-log amplitude cepstral coefficients
60係数の逆変換後にexpを取り、正の振幅包絡へ戻します。この図の差は包絡の表現誤差であり、合成音全体の誤差や聴感差とは別です。 表示単位:frame index 240, dB amplitude
実データの可視化
60係数の逆変換後にexpを取り、正の振幅包絡へ戻します。この図の差は包絡の表現誤差であり、合成音全体の誤差や聴感差とは別です。 表示単位:frame index 240, dB amplitude

復号時は60係数をゼロ埋めしてFFTをかけ、周波数軸を戻し、指数関数で振幅に戻します。高次の係数を捨てるので、元の包絡に完全には戻りません。細かい凹凸がならされる効果もあります。

保存:振幅包絡 → log → 周波数ワープ → 係数化 → 60係数 復号:60係数 → ゼロ埋め/FFT → 逆ワープ → exp → 振幅包絡
60個の周波数帯の大きさを直接保存するわけではありません。 係数は包絡全体を表す基底の重みです。これは公開sigprocのFWCEP互換変換で、一般的なSPTKのMCEPやMFCCと同一ではありません。係数0は全体レベルに関係するため、ヒートマップでは他の係数と色域を分ける場合があります。
変換と容量をもう少し正確に

次数59、係数数60。入力は自然対数振幅で、非DC係数を2倍する公開実装の規約を保っています。Python 2由来の整数Hzグリッドや補間も含めた互換経路です。振幅包絡が変わると、後段で作る最小位相も変わるため、音への影響は振幅だけに限りません。

1フレームの保存項目容量
60 FWCEP × float32240 bytes
NM 2049 bits(端数込み)257 bytes
F0 × float648 bytes
合計505 bytes / 5 ms

公称808 kbit/s。密なfloat64包絡と比べると大幅に小さくなりますが、16 kHz・16 bitのPCM(256 kbit/s)よりまだ大きい表現です。低ビットレート音声コーデックとして完成したものではありません。PDDや原音は復号ファイルに入っていません。

自分で時刻を動かす

1フレームの中身を追いかける

代表録音の実測値を20 msごとに抜き出しています。スライダーを動かすと、その時刻の包絡、PDD、保存NMと低域変更後のNMを一緒に確認できます。周波数点は表示用に間引いています。

上段:元包絡(青)と60係数から復元した包絡(橙)。中段:PDD(紫)と判定しきい値0.75(灰破線)。下段:保存NM(青)と低域変更後の二値NM(橙)。下段は周波数平滑後の実効マスクではありません。各軸は固定です。包絡のdBは20 log10(振幅包絡)で、実際の音圧レベルではありません。NMは表示点を階段状に結んでいます。
このフレームの60係数を数値で見る

係数番号は周波数ではありません。保存されたfloat32値を表示用に小数5桁へ丸めています。

6 / 音を作る

パルスを、周波数ごとに雑音的に変形する

PMLでは各パルス時刻に短い合成断片を作ります。復元包絡へ0.5 F0をカットオフとするハイパス特性をかけ、振幅から最小位相を作り、パルス間隔に応じて大きさを補正します。

さらに短いガウス雑音をFFTして正規化した複素スペクトルGNを作ります。それを実効マスクMを指数として、パルス側のスペクトルに掛けます。

パルス断片のスペクトル ≈ 時刻を合わせる位相 × 最小位相の包絡 × √(fs / F0) × GN^M M = 0 → GN^0 = 1:雑音による変形なし M = 1 → GN^1 = GN:雑音スペクトルで変形 0 < M < 1 → 複素数のべきによる中間状態
凍結済みデコーダを同じseedで再実行して取り出した実パルス。最終float32波形は保存済み音声と全サンプル一致。上段にはHP(0.5×F0)とsqrt(fs/F0)も含みます。下段は1周期の正弦波ではなく、重ね足すための約50msの1パルス応答です。 表示単位:2049 complex envelope bins / 801 waveform samples; relative milliseconds
実データの可視化
凍結済みデコーダを同じseedで再実行して取り出した実パルス。最終float32波形は保存済み音声と全サンプル一致。上段にはHP(0.5×F0)とsqrt(fs/F0)も含みます。下段は1周期の正弦波ではなく、重ね足すための約50msの1パルス応答です。 表示単位:2049 complex envelope bins / 801 waveform samples; relative milliseconds
単純に「周期波+雑音」を足しているのではありません。 周波数ごとに複素スペクトルを乗算してから波形へ戻す方式です。そのためNMを「雑音のパワー比」と読むこともできません。

逆FFTで得た断片の端を短い窓で減衰し、指定時刻へ重ね合わせます。この時間上の断片の足し合わせと、「周期成分と雑音成分を別々に作って足す」方式は区別してください。

最小位相・乱数・窓の意味
  • 最小位相:振幅包絡から位相を一意の規約で作る方法。原音の位相を完全保存しているわけではありません。
  • 合成窓:少なくとも約50 ms、または4周期を収める長さ。1パルスの響きが減衰する余地を確保します。
  • 乱数:同じ特徴量でもseedを変えれば雑音の細部が変わります。ここでは保存済みの固定seed出力を使っています。
  • F0を変えると:パルス間隔だけでなく、ハイパス、低域カット位置、エネルギー補正、雑音断片長も変わります。音程編集の品質は再合成品質と別の課題です。
7 / 原音に戻れたか

最後に、同じ録音のスペクトログラムで確かめる

STFTは倍音の細い線や時間変化を見やすく、mel表示は低域を細かく見られます。同じ表示条件の原音と最終出力を比較してください。包絡やPDDの図と、ここでの実際の生成音の図は別物です。

40ms Hann窓、5ms hop、1024 FFT。原音と合成音で同じ色範囲・同じ基準値を使用。横に連なる倍音の帯と無声域の広がりを比較できます。 表示単位:power dB, 0〜8kHz
実データの可視化
40ms Hann窓、5ms hop、1024 FFT。原音と合成音で同じ色範囲・同じ基準値を使用。横に連なる倍音の帯と無声域の広がりを比較できます。 表示単位:power dB, 0〜8kHz
見た目が似ていることは、自然さや話者らしさをすべて保証しません。逆に、位相や雑音の微細構造が違えば、波形が一致しなくても音として近い場合があります。包絡の細部、無声区間、遷移の再現にはまだ課題があります。
5つの実例

原音・変更前base・今回の最終案を並べて聴く

全て先頭最大6秒、16 kHz。表示用PCM16へ変換しています。個別の音量正規化はしていません。途中の条件は折り畳みから比較できます。

例1:librispeech_1089-134686-0008

原音
変更前base:HNM v3
最終案:低域変更PML + 60 FWCEP
途中の条件を聴く
PML:元の低域保護
低域変更PML:密な包絡

例2:librispeech_1188-133604-0003

原音
変更前base:HNM v3
最終案:低域変更PML + 60 FWCEP
途中の条件を聴く
PML:元の低域保護
低域変更PML:密な包絡

例3:librispeech_121-121726-0012

原音
変更前base:HNM v3
最終案:低域変更PML + 60 FWCEP
途中の条件を聴く
PML:元の低域保護
低域変更PML:密な包絡

例4:librispeech_1221-135766-0005

原音
変更前base:HNM v3
最終案:低域変更PML + 60 FWCEP
途中の条件を聴く
PML:元の低域保護
低域変更PML:密な包絡

例5:librispeech_1089-134686-0032

原音
変更前base:HNM v3
最終案:低域変更PML + 60 FWCEP
途中の条件を聴く
PML:元の低域保護
低域変更PML:密な包絡
現在地

できたことと、まだ残っていること

保存形式について:ここに示す容量805.430 kbit/sと復号測定は研究時のPMLFWC28容器による実測です。今回のパッケージAPIはPMLFWC01でヘッダーが異なり、新容器の実容量・一連のAPI速度はまだ測定していません。研究結果を新APIの再測定結果として扱わないでください。

60

包絡を保存する係数数。F0とNMは別途保存します。

108

設定の選択に使わなかった追加録音で比較。36話者。

3.275

追加108録音での予測MOS平均。人間の評点ではありません。

小容量版の予測MOSは3.275、密な包絡版は3.281。差は−0.006で、話者単位の95%信頼区間は−0.028〜+0.019でした。「似た点推定だった」という結果で、事前に非劣性の幅を決めた統計的な同等性の証明ではありません。

出典・実装の位置づけ

2026-10-16作成。今回の資料は既存反復21・23・28・29の保存済みデータと実装から作成し、新たな性能探索や設定調整はしていません。図は実測配列の可視化、冒頭とFWCEPの流れ図は説明のための模式図です。