Repository navigation
Signalsmith Pitch Shifting Algorithm Analysis
2026-10-18 記録。PR #95 で導入したピッチ処理を、信号処理、アルゴリズム、アプリの実装に分けて分析する。採用版は Signalsmith Stretch 1.4.0(a670068d9aeb64913331d5cc29337b19a457a7df)で、アプリ側は最終検証対象の 31801c662c7083b9b748f653a972cf19e3fe8454 を参照する。導入経緯、測定手順、ログ、回帰テストは Signalsmith Stretch によるピッチ処理に記録している。
記述の根拠は次の四つに分ける。
| 区分 | この記録での意味 |
|---|---|
| 確認した事実 | 固定したソース、アプリ実装、公開 API、SDK の記載から確認した内容。SDK の既定値は、その環境で実測した実行時の値とは区別する。 |
| 実測結果 | 既存の検証で、条件と手順を記録して得た数値。確認した条件の範囲に限定する。 |
| 推定 | 確認した処理の仕組みと比較結果から考えられる説明。原因を切り分けて実証した結果ではない。 |
| 未確認 | Apple の内部実装、未測定の条件、音楽一般への適用可能性など、今回の調査では判断できない内容。 |
確認した事実:処理の役割分担
変更前は AVAudioUnitTimePitch の pitch と rate でピッチとテンポを変えていた。変更後は Apple TimePitch のピッチを 0 に固定し、テンポ変更を担当させ、その後段の Signalsmith でピッチを変える。速度 1 のとき Apple TimePitch は bypass する。対象は音声の通常再生と調整済みコピーの書き出しで、動画の再生処理は含まない。
| 観点 | 変更前 | 変更後 |
|---|---|---|
| ピッチ変更 | Apple TimePitch | Signalsmith Stretch |
| テンポ変更 | Apple TimePitch | Apple TimePitch を継続使用 |
| ノードの構成 | 一つのノードで両方を変更 | テンポ用とピッチ用を直列に接続 |
| 確認できる内部処理 | 公開 API と SDK の記載の範囲 | 採用版の周波数写像と位相予測までソースで確認可能 |
処理の接続は、主要部分を抜き出すと次のとおりである。
player → Apple TimePitch(テンポ)→ Signalsmith(ピッチ)
→ 停止用フェード → 音量調整・EQ・reverb
→ mainMixer(サンプルレート変換)→ limiter → −1 dB → output
半音数
−3 半音なら約 0.8409 倍で、440 Hz は約 370 Hz になる。今回の実装は Signalsmith の process に毎回同じ入力・出力フレーム数を渡すため、Signalsmith 自体の時間伸縮率は 1 である。テンポを変えた場合も、その伸縮は前段の Apple TimePitch が担当する。
根拠:変更前の AudioEngineService、変更後の AudioEngineService、Signalsmith の呼び出し。
確認した事実:Signalsmith の信号処理
処理は短時間フーリエ変換(STFT)で入力を複素スペクトルに分解し、振幅と位相から出力を組み立てる方式である。今回の default preset は約 120 ms の解析窓を 30 ms ずつ進め、Kaiser 窓を使用する。48 kHz では解析窓が 5760 サンプル、移動間隔が 1440 サンプルになる。この解析窓の長さを、そのまま FFT の点数と同一視しない。
ピッチ変更時には、全チャンネルのエネルギーを合算して周波数方向に平滑化し、平滑化した値を上回る領域を探す。領域内のエネルギーで重み付けした周波数位置をピークの中心とする。これはスペクトル上の山の検出であり、楽曲全体から一つの基音を決める処理ではない。通常のピッチ変換に、単一の音程の検出成功を必要としない。
検出したピークの中心は目的の周波数へ移すが、その近傍では局所的な周波数軸の倍率を 1 に保つ。ピーク間では移動量を滑らかにつなぐ。出力位置を
次に、時間方向の位相差から出力を予測し、周波数方向の位相差でも予測し直す。初段はソースに phase-vocoder と明記された処理である。後段では上下の隣接成分と、少し離れた周波数成分から予測を作る。
二つの複素スペクトルを
この複素数を既に決まった出力に掛けると、別の位置の位相を予測できる。実装には標準的な周波数位置に応じた回転やエネルギーによる正規化もあり、この概念式だけで処理全体を表しているわけではない。予測は複素数のまま合成し、目標のエネルギーに合わせて振幅を調整する。位相差ごとに角度への変換と逆変換を行う計算を避けている。
複数チャンネルの場合は、周波数成分ごとに最もエネルギーが強いチャンネルの位相を決め、他のチャンネルには入力のチャンネル間位相差を適用する。曲全体で一つの基準チャンネルを固定する処理ではない。最後に逆変換と区間の重ね合わせで連続した波形へ戻す。
根拠:採用版ソースの default preset と窓設定、ピーク検出と周波数写像、位相予測とチャンネル間の処理。
作者の設計説明と、今回の音質改善についての推定
作者は、周波数方向の位相関係が音の発生時刻に、時間方向の位相関係が周波数の安定性に関係すると説明している。ピーク近傍の周波数写像は、特に上方向への移調でスペクトルの山が広がり、余分な成分が生じる問題への対策として説明されている。これは 作者の設計解説に記載された設計上の理由であり、今回のアプリで各要素の寄与を個別に測定した結果ではない。
今回の対象音源では、時間方向・周波数方向の位相予測とチャンネル間位相差の扱いが、濁りや揺れの少ない出力に寄与した可能性がある。ただし、これらを個別に無効化して比較する検証は行っていない。−3 半音の改善を、上方向への移調に対する対策だけで説明することもできない。どの処理が聴感上の改善をどれだけ生んだかは未確認である。
確認した事実と未確認事項:Apple TimePitch との比較限界
Apple の overlap は入力区間の重なりを制御し、公開ドキュメントには値を大きくすると出力のアーティファクトが減ると記載されている。既定値は 8、設定範囲は 3〜32 である。一方、調査環境の macOS SDK にある AudioUnitParameters.h の Smoothness の説明では、CPU コストとの関係と、打楽器の減速では小さい値が適する場合も示されている。Apple の overlap ドキュメント
同 SDK は kNewTimePitchParam_EnableSpectralCoherence を、ピークロックでスペクトルの位相関係を保つ設定として説明し、既定値を 1 としている。旧名の EnablePeakLocking はこの設定への別名である。この記載は SDK の契約の確認であり、変更前の全 OS・全実行条件で実行時パラメーターを測定した結果ではない。Apple の該当 API
Apple 内部の周波数写像、位相予測、窓長、チャンネル間の処理を、Signalsmith と同じ粒度では確認できていない。そのため、「従来は位相を扱っていなかった」「Apple は単純な再サンプリング方式である」「今回初めてピークを利用する方式になった」といった説明には根拠がない。比較できるのは、アプリが渡す設定、確認可能な仕様、得られた出力、Signalsmith 側の公開実装である。
確認した事実:リアルタイム処理と状態管理
アプリは C++ の Signalsmith を独自の Audio Unit で包む。DSP とバッファは allocateRenderResources で準備し、ピッチ値と reset 世代の要求を atomic 変数で受け渡す。DSP の状態変更はレンダースレッドで行う。入力取得後と DSP 処理後にも世代を確認し、途中で reset が要求されたブロックは破棄して無音にする。入力が無音でも内部の遅延音が残るため、入力側の無音フラグをそのまま出力に伝えない。
FFT には Accelerate を使い、ラッパーの Objective-C++ ファイルは Debug でも -O2 でコンパイルする。これらは実行性能のための実装であり、Apple より高音質になる直接の根拠ではない。Apple との CPU 負荷の優劣も、この分析では測定していない。C++ 単体で追加の new/new[] がなかった条件と、Accelerate 内部の確保を測定していない制約は、既存の実装記録を参照する。
根拠:Audio Unit の状態管理と render 処理、最適化設定、実装・競合の検証記録。
確認した事実・実測結果:遅延、終端、ピーク保護
今回の preset では splitComputation を無効にし、処理遅延を inputLatency() + outputLatency() から求める。44.1/48/96 kHz の既存検証では Signalsmith 単体で 120 ms だった。ピッチ 0 でも処理を継続し、ピッチ 0 とそれ以外の切り替えでこの遅延を変えない。アプリ全体の遅延は、Apple TimePitch と出力保護が報告する遅延も加えた値である。TimePitch は実時間と offline で報告値が異なり、速度 1 の bypass でも実時間の遅延が残ったため、bypass を理由に加算を省かない。
停止用フェードは Signalsmith の後段に置き、書き出しではゼロ入力で内部の出力を排出してから、先頭の処理遅延を除き、必要なフレーム数を保存する。これらは停止時の残音や書き出しの先頭・末尾を扱う処理である。音楽信号の位相予測とは役割が異なる。
出力保護は最終サンプルレート変換の後段に置く。リミッターへの +1 dB と後段の −1 dB を組み合わせ、小さい信号の合計ゲインを維持しながらピークに余裕を取る。これはクリッピング対策であり、位相の不整合や音のにじみを修復する処理ではない。今回の比較では、Apple 側にも出力保護を適用した条件を使用している。
根拠:出力保護の構成、書き出し renderer、遅延・終端の測定記録。
確認した事実:今回使っていない機能
フォルマント補正と tonality limit の追加指定は使用していない。したがって、声の共鳴特性を元の位置へ保つ機能や、高域の周波数倍率を変える追加設定を改善理由として挙げることはできない。一方、前述したピーク近傍の非線形な周波数写像は、tonality limit を指定しない場合も動作する。二つは別の処理である。
ライブラリには極端な時間伸縮に対応する位相予測の制限・乱数処理もあるが、今回の Signalsmith の利用は時間伸縮率 1 である。その機能を今回の改善理由には含めない。
実測結果と、そこから判断できる範囲
既存検証の同一音量条件を抜き出すと、次の結果である。入力側の音量は 0.75、ピッチは −3 半音、速度は 1 で、参照録画の音楽区間 3.0〜15.7 秒に時刻を合わせた。Apple 側は既に overlap=32 と出力保護を適用した状態であり、導入前の初期状態とは区別する。
| 指標 | Apple TimePitch +出力保護 | Signalsmith +出力保護 |
|---|---|---|
| 参照との対数 RMS 包絡の相関 | 0.9433 | 0.9673 |
| 周波数配置の平均類似度 | 0.8770 | 0.8879 |
測定方法と全条件は 既存の比較記録にある。音源、参照録画、生成音声はローカルでのみ扱い、この Wiki には掲載しない。この追記のために再測定した値ではない。
実測から確認できるのは、この音源・区間・設定で参照との対応が改善したことである。両方式に出力保護があるため、単にリミッターの有無を比較した結果ではない。ただし、周波数写像や位相予測の各要素を分離した実験ではないため、特定の要素の寄与率までは分からない。
これらの類似度は知覚上の音質点数ではない。参照録画と原音では圧縮条件、ゲイン、ステレオ像も異なる。合成音の全指標で Signalsmith が上回ったわけでもなく、Apple 全般に対する優位性や音楽一般での改善を示す結果には使えない。利用者から改善への肯定的な反応は得ているが、統制した聴取試験は実施していない。
推定としては、今回の条件では Signalsmith の周波数写像と位相再構成が聴感上の改善に寄与し、その出力を遅延・終端・状態管理・ピーク保護の実装が適切に扱っている、と考えられる。原因の切り分けには、各アルゴリズム要素の比較、複数の音源と移調量、音量をそろえた聴取試験が追加で必要である。