タイムストレッチとピッチシフト
テープを速く回すと、ピッチと長さが一緒に変わります。現代の編集 DSP は、この 2 つを分離します。
| 操作 | 変えるもの | 保ちたいもの |
|---|---|---|
| タイムストレッチ | 長さ | ピッチ |
| ピッチシフト | ピッチ | 長さ |
このページでは、その分離の仕組みを説明し、libsonare のストレッチバックエンドがそれをどう実装しているかを示します。用語を先に押さえたい場合は 編集の基礎 を読んでください。
フェーズボコーダ
中心的な道具はフェーズボコーダです。
大まかには次の 3 段階で動きます。
- STFT(short-time Fourier transform、短時間フーリエ変換)で音声を短い時間・周波数フレームに分ける。
- 新しい時間軸に対応する位置からスペクトルフレームを読み、必要に応じて補間する。
- 連続する解析フレームから各ビンの位相の進みを推定し、出力側の時間軸で積算する。
手順 1 はスペクトル解析と同じ STFT の原理を使います。ただし、特徴量ごとに窓長やホップ長が異なることがあります。フレームの切り出し方は スペクトログラムと STFT に図があります。
難しいのは位相の整合です。STFT は各フレームを周波数ビン、つまり狭い周波数帯ごとの区画に分けます。フレームの間隔を解析時と変えると、音を構成する個々の周波数成分(部分音)が途切れず続くように、各ビンの位相を再伝播させなければなりません。ここを誤ると、金属的で「位相っぽい」アーティファクトになります。
出力では、元のスペクトルフレームを新しい時間軸に沿って読みます。ゆっくり読めば、スペクトルの変化がより多くの出力フレームに広がります。波形の薄切りを間引いたり複製したりする処理ではありません。推定した位相の進みを使い、合成フレーム間でも各周波数成分を連続させます。
2 つの操作、1 つのバックエンド
| 操作 | 変えるもの | 保つもの | 方法 |
|---|---|---|---|
| タイムストレッチ | 長さ | ピッチ | フェーズボコーダが時間軸をスケール |
| ピッチシフト | ピッチ | おおむね元の長さ | ピッチ比の逆数で伸縮し、変換後のレートからリサンプル |
ピッチシフトとタイムストレッチがバックエンドを共有するのはこのためです。ピッチシフトは、タイムストレッチの後にリサンプリングしたものです。
rate > 1.0 はクリップを短くし、semitones = 12 は 1 オクターブ上へ動かします。
半音上げるなら、まず 1 / 2^(1/12) のレートで少し長く伸ばし、約 2^(1/12) 倍のレートでリサンプルします。リサンプリング時の丸めにより、出力サンプル数はわずかにずれることがあります。
大きな変更でアーティファクトが出る理由
どちらの操作も、情報を生成または破棄します。
| 編集 | 起こりやすい問題 |
|---|---|
| 音を 2 倍の長さに伸ばす | 追加された音の多くが位相の仮定から合成される |
| 声を完全 5 度上げる | 補正しない限りフォルマントも動く |
| 大きくトランジェントを変える | アタックが軟らかくなったり、にじんだりする |
小さな変更では仮定が成り立つので、処理の跡はほとんど目立ちません。大きな変更では仮定が崩れ、にじみ、トランジェント(音の出はじめやドラムの打点の鋭い立ち上がり)の鈍り、早回しのような甲高い音色として表に出ます。
アタックが鈍るのには具体的な理由があります。解析フレームはそれぞれ窓 1 つぶんの長さ(既定では 2048 サンプル、48 kHz で約 43 ms)なので、その中のアタックはフレーム全体に広がります。さらにビンごとに位相を個別に進め直すと、アタックを鋭くしていたビン同士の位相のそろい方が崩れます。窓を長くすると周波数は細かく分かれますが時間方向のにじみが増え、短くするとその逆になります。
実用上の指針は、自然な結果を求めるなら控えめに、大きな変更は意図した音作りの効果として扱う、ということです。
libsonare がストレッチをどう実装するか
libsonare の既定の NativeSpectral バックエンドは、ピークロック付きフェーズボコーダー(phase_vocoder_phaselocked。Laroche と Dolson(1999)の identity phase locking)を使い、ピッチ変更にはリサンプリングを組み合わせます。ピークロックはスペクトルピーク周辺のビンの位相を揃え、位相感のあるアーティファクトを減らす手法です。C++ では通常の phase_vocoder を使うバックエンドも選べます。JavaScript と Python の入口はネイティブスペクトル経路を使います。
timeStretchは、フェーズボコーダで時間軸を伸縮します。pitchShiftは、上方向のピッチ比をRとすると1/Rのレートで伸ばし、sampleRate × Rの実効レートからリサンプルします。- 同じコアは
noteStretch(区間限定のストレッチ)やvoiceChangeのピッチ段でも使われます。輪郭に沿うピッチ補正は別のエンジンを使います(再合成エンジンは 2 種類)。
入力はデコード済みのモノラルサンプルです。アーティファクトは素材と伸縮率で変わり、持続音より過渡音や密度の高いミックスが目立ちやすいことがあります。STFT の窓長とホップ長も結果に影響します。ビット単位で元のまま残したい箇所は、ストレッチャーを通さないでください。
関連: 編集の基礎、ピッチ補正、ボイスとフォルマント、編集 DSP