タイムストレッチとピッチシフト
テープを速く回すと、ピッチと長さが一緒に変わります。現代の編集 DSP は、この 2 つを分離します。
| 操作 | 変えるもの | 保ちたいもの |
|---|---|---|
| タイムストレッチ | 長さ | ピッチ |
| ピッチシフト | ピッチ | 長さ |
本ページはその分離の裏側を説明し、libsonare のストレッチバックエンドに根拠づけます。用語を先に知りたい場合は 編集の基礎 を読んでください。
フェーズボコーダ
中心的な道具はフェーズボコーダです。
大まかには次の 3 段階で動きます。
- STFT で音声を短い時間・周波数フレームに分ける。
- そのフレームを時間軸方向にリサンプリングし、進む速さを変える。
- 部分音がにじまず続くように位相を作り直す。
難しいのは位相の整合です。STFT は各フレームを周波数ビンに分けます。ビンとは、狭い周波数帯ごとの 1 区画のことです。フレーム間隔が解析時と異なると、音を構成する個々の周波数成分すなわち部分音が途切れず続くよう、各ビンの位相を再伝播させる必要があります。これを誤ると、金属的で「位相っぽい」アーティファクトが聞こえます。
直感的には、音を「短い時間の薄切り」に分け、その薄切りを並べ直す作業です。薄切りを間引けば速く(短く)なり、複製すれば遅く(長く)なります。このとき各切れ目で波がなめらかにつながるよう位相を調整するのが、フェーズボコーダの肝心な仕事です。
2 つの操作、1 つのバックエンド
| 操作 | 変えるもの | 保つもの | 方法 |
|---|---|---|---|
| タイムストレッチ | 長さ | ピッチ | フェーズボコーダが時間軸をスケール |
| ピッチシフト | ピッチ | 長さ | 比率でタイムストレッチし、元の長さへリサンプル |
ピッチシフトとタイムストレッチがバックエンドを共有するのはこのためです。ピッチシフトは、タイムストレッチの後にリサンプリングしたものです。
rate > 1.0 はクリップを短くし、semitones = 12 は 1 オクターブ上へ動かします。
たとえば半音上げたいなら、わずかに長くストレッチしてから少しだけ速く再生し直す、と考えると関係が分かりやすくなります。
大きな変更でアーティファクトが出る理由
どちらの操作も、情報を生成または破棄します。
| 編集 | 起こりやすい問題 |
|---|---|
| 音を 2 倍の長さに伸ばす | 追加された音の多くが位相の仮定から合成される |
| 声を完全 5 度上げる | 補正しない限りフォルマントも動く |
| 大きくトランジェントを変える | アタックが軟らかくなったり、にじんだりする |
小さな変更は仮定が成り立つため透明ですが、大きな変更では、にじみ・トランジェントの軟化・「チップマンク」的な音色として露呈します。
実用則は、自然な結果には控えめに、大きな変更は意図的な音作り効果として扱うことです。
libsonare がストレッチをどう実装するか
libsonare の timeStretch と pitchShift は、フェーズボコーダのコア(phase_vocoder)に、ピッチ軸のリサンプリングを組み合わせたものです。どの実装を使うかは StretchBackend で選びます。
timeStretchは、フェーズボコーダで時間軸を伸縮します。pitchShiftは、ピッチ比でタイムストレッチした後、元の長さへリサンプルします。- 同じコアは
noteStretch(区間限定のストレッチ)やvoiceChangeのピッチ経路でも使われます。
入力は、デコード済みのモノラル Float32Array またはサンプル列です。品質は変更量に応じてなだらかに劣化するため、控えめな比率ならアーティファクトを抑えやすくなります。
関連: 編集の基礎, ピッチ補正, ボイスとフォルマント, 編集 DSP