Wizard Notes

音楽信号解析の技術録、音楽のレビューおよび分析、作曲活動に関する雑記です

Python (LibROSA) でピッチシフト librosa.effects.pitch_shift

この記事をシェアする

まえがき

ボーカルや楽器の録音データに対して、

音の長さを変えずに、音の高さを変えたい

と思うことがあるかもしれません。

この処理はピッチシフト*1と呼ばれていて、具体的な使用例としては、

  • 移調/転調
  • ハモり/コーラスパートの生成
  • 音の高さの修正

といった処理・エフェクトが挙げられます。

Pythonの音楽分析モジュール LibROSA にはピッチシフトを簡単に実行できる関数が用意されているため、簡単に紹介したいと思います。

librosa.effects.pitch_shift() の使い方

引数について

librosa - librosa.effects.pitch_shift

librosa.effects.pitch_shift(y, sr, n_steps, bins_per_octave=12, res_type='kaiser_best', **kwargs)

重要な引数は以下の通りです。

  • y: np.ndarray型の、時間波形領域の入力信号です。ver. 0.8.0 時点では、1次元配列、すなわちモノラルの信号のみを対象としています。
  • sr: サンプリング周波数
  • n_steps: float型であり、どのくらい周波数をシフトさせるかを制御する引数です。
  • bins_per_octave: float型であり、オクターブのビン数(1オクターブ内に音程がいくつあるか)を指定します。

なお、中身はlibrosa.effects.pitch_shift()の正体はフェーズボコーダであり、そのパラメタ(STFTフレーム長など)も引数として指定することができます。

半音単位のピッチシフト

n_stepsの値を変更することで、音の高さをどのくらい上げ下げするのか制御します。

具体的には、このn_stepsによって、オクターブ(周波数比2:1)に対してどのくらいシフトさせるかを決めることになります。

デフォルト値のようにbins_per_octave=12であれば、n_stepsが1増えるごとに、1半音上がるということになります。

例:

  • 1オクターブ上: n_steps=12
  • 1オクターブ下: n_steps=-12
  • 完全5度上(半音7個分): n_steps=7
  • 完全4度上(半音5個分): n_steps=5

このように、元の音源をN半音を上げ下げするような、音波音単位のピッチシフトはn_stepsに整数値を設定すればOKです*2

周波数を指定するピッチシフト

「10Hzほど音の高さを上げたい」というような、基本周波数をどれくらいシフトするのかを指定したいピッチシフトを行う場合です。

ピッチシフト前と後の基本周波数をそれぞれFo, Fo_shiftとすると、以下の関係が成立します。

Fo_shift = Fo * 2.0 ** (n_steps/bins_per_octave)
(**はべき乗)

n_steps / bins_per_octave = log2 (Fo_shift / Fo)

簡単化のためbins_per_octave=1とすると、

n_steps = log2 (Fo_shift / Fo)

となり、ピッチシフト前後の周波数比に対して2を底とする対数を取ることでn_stepsの値を求めることができます。

使い方のサンプル

プロット

f:id:Kurene:20201002051639p:plain

コード

※STFT窓長とプロットの都合上、サンプリング周波数を2048にしています。

注意

librosa.effects.pitch_shift()で使われているフェーズボコーダlibrosa.phase_vocoderはナイーブな実装であるため、特にピッチを上げるピッチシフトでは音質が劣化しやすい傾向があります。 従って、実用時には注意が必要です。

librosa.phase_vocoderのドキュメントには、 RubberBand libraryのPythonラッパーであるpyrubberbandモジュールの利用が推奨されています。

*1:エフェクトとしてのピッチシフトは、対数周波数領域でのシフトであり倍音の周波数比は保持されるため、音楽的に調和した信号が出力されます。一方で、例えばどの倍音も100Hzだけ上下する、つまり線形周波数領域でのシフトは、音楽的に調和しなくなります。

*2:微分音の場合、例えば四分音上げる場合はn_steps=0.5とすることで対応できます