メロディとピッチ
ピッチ追跡は、音の基本周波数を時間に沿って追います。メロディ抽出、ボーカルのチューニング確認、採譜に近いワークフローの土台です。クロマ がオクターブを畳み込むのに対し、ピッチ追跡は実際の周波数を保ちます。本ページは MIR の全体像 のピッチの節を掘り下げます。
基本周波数(F0)
ピッチのある音には周期的な波形があり、スペクトルには部分音が現れることが多いです。基本周波数(F0)は、その周期性を決める周波数で、調和的な音では部分音の間隔も決めます。F0 の成分がスペクトルに現れなくても、欠落基音として音高を決めることがあります。鐘やシンバルのような非調和音では、部分音があっても明確な F0 がないことがあります。声、擦弦楽器、管楽器では、部分音が F0 の整数倍付近に並ぶことが多いため、倍音と呼ばれます。
たとえば歌手が A4 を伸ばすと、F0 は 440 Hz です。録音には 880 Hz、1320 Hz 付近などの倍音にもエネルギーが現れます。
人が知覚する音高は一般に F0 に対応します。そのため、ピッチ追跡は時間方向の F0 推定です。波形の周期性を推定し、スペクトルの最低ピークや最大ピークを選ぶだけでは済まない点が難しさになります。
「整数倍」には 2 つの限界がある
弦は硬さを持つため、上の部分音ほど理想的な倍音列より高くずれます。ピアノでは高次の部分音が正確な整数倍から数十セント上に来ます。鐘、シンバル、ドラムのような打奏体では部分音が整数比にならず、そもそも明確な F0 を持たないこともあります。F0 の成分がスペクトルからまったく失われていても、人はその音高を聞き取ることがあります。そのため、観測されたスペクトルの最低ピークや最大ピークを F0 とみなすことはできません。後述の推定器はスペクトルの最大値を選ばず、波形の周期性から F0 を推定します。
YIN と pYIN
libsonare には関連する 2 種類の推定器があります。
- YIN は時間領域の差分関数(difference function)を使って F0 を探します。波形がもっともよく繰り返すラグ、つまり周期を見つけ、それを周波数へ変換します。クリーンな単音音声では正確で軽量です。
- pYIN(probabilistic YIN)は、YIN を確率モデルで包み、複数の F0 候補を時間方向に追跡します。そのフレームがそもそも有声音かどうかという有声判定も推定するため、無音、息、ノイズで不要なピッチが出やすい実録音に対して頑健です。
pitchYin と pitchPyin の frameLength は入力レートでのサンプル数です。analyzeMelody / MelodyAnalyzer では 22050 Hz を基準とするサンプル数で指定し、入力レートへ換算します。既定の 2048 は 44.1 kHz では 4096 サンプルになります。低い音に合わせて窓長を選ぶときは、この違いに注意してください。
単音と多音
これらの推定器は単音入力、つまり 1 度に 1 音だけが鳴る素材(ソロボイス、リードライン、ベース)を仮定します。
ベースには既定より低い fmin が必要
fmin の既定は 65 Hz(C2)、fmax は 2093 Hz(C7)なので、既定のままで追えるのはおおよそ C2〜C7 です。エレクトリックベースの開放 E は 41.2 Hz、5 弦の Low B は 30.9 Hz で、どちらも探索範囲の外にあります。範囲外の音は倍音として、あるいは範囲の端に張り付いた値として返ります。ベースを扱うときは fmin を明示的に下げ、あわせて frameLength も伸ばしてください。YIN のラグ探索はフレーム長の半分で頭打ちになるため、44.1 kHz で 2048 サンプルのフレームでは、fmin をいくら下げても約 43 Hz より下は解けません。
これらの推定器はコード採譜器ではありません。フルミックスやコードを入力すると、単一 F0 という仮定が崩れます。混み合ったトラックの中のメロディを追う場合は、分離済みの録音か実際のリードステムを使ってください。HPSS は打撃成分を抑えられますが、重なった倍音楽器は残るため、フルミックスを単音にはしません。ピッチ追跡に渡す信号をよりクリーンにする前処理です。
有声判定:ピッチがないフレーム
すべてのフレームにピッチがあるわけではありません。休符、無声子音("s" や "t")、打楽器には明確な F0 がありません。素朴なトラッカーはそれでも何らかの数値を返し、跳ね回る無意味な線を作ります。pYIN の有声判定はそうしたフレームを無声音としてマークし、音楽に隙間があるところではメロディ線にも隙間を作ります。
pYIN はこの判定を 2 通りの形で返しますが、この 2 つは互換ではありません。voicedFlag(Python は voiced_flag)は Viterbi パスの有声/無声の状態、つまり判定そのもので、利用側が条件に使うべきなのはこちらです。ノート関数が voiced を求めるときは、これを 0.0/1.0 として渡します。
voicedProb は信頼度ではなく音高とともに上がる
voicedProb は信号品質の信頼度ではありません。そのフレームにおける有声観測の質量であり、有声側のピッチ仮説の確率の総和です。この質量は解析フレームの中にその音高の周期がいくつ収まるかに依存します。長い周期を短いフレームで測ると差分関数の谷が浅くなるためです。したがってフレーム長が固定なら、信号がまったく同じでも F0 とともに値が上がります。倍音 3 つの定常音を 2048 サンプル / 48 kHz で測ると、C2 では平均 0.1 をかなり下回り、C5 では 0.5 前後になります。しかもどちらも全フレームが有声と判定されます。
ここから 2 つの帰結があります。
- この値に固定のしきい値をかけると、低音域の素材ではノートセグメントが 1 つも返らなくなります。代わりに
voicedフラグを 0.0/1.0 として渡すか、voicedThreshold(既定 0.5)を下げてください。 - この値は補正の重みではありません。時間変化するピッチ補正は、フレームごとの補正量をこの値でスケールしません。明示的な
voiced配列が渡されなかったときに 有声判定を導くためだけに読むので、voicedと一緒に渡しても結果は変わりません。
libsonare がどう追跡するか
libsonare は単音音声向けに YIN と pYIN による F0 推定を実装しています。analyzeMelody / MelodyAnalyzer は既定では素の YIN を使い、usePyin: true を指定すると pYIN とその有声判定の出力を選びます。そのうえで平均周波数、ピッチ範囲、安定度、簡易的なビブラートレートを計算します。低レベルの pitchYin / pitchPyin では、YIN と pYIN のトラックを直接取得できます。結果は MIDI ノート番号へ変換してチューニングや編集ワークフローに使えます。ピッチ追跡は、分離された明確なピッチ素材で最も信頼でき、多音やノイズの多いミックスでは精度が落ちます。