GPT-5.3 Instant / Sonnet 4.6 Ext
リバーブアルゴリズム
技術解説文書
理論・実装・知覚・現代的手法の統合解説
Freeverb3 / FDN / Dattorro / Lexicon / 畳み込みリバーブ / ニューラルFDN
大きなホールで音楽を聴くと、楽器が演奏を停止した後もしばらく音が響き続ける。演奏中も音は響いており、それが音楽に艶やかさを与えるため、ホールでの演奏が好まれる。響きの美しいホールとして、東京・赤坂のサントリーホールなどが有名である。
リバーブとは単なる「残り音」ではなく、空間の情報そのものであり、音の奥行き・距離感・質感を決定する要素である。音響的には以下の2つの時間領域が同時に存在する。
実際のホールを使うことは時間的・金銭的に難しく、CDマスタリング等では仮想的にホールの響きを作り出すソフトウェアが使われる。Freeverb3はその代表例である。響きを作り出す方式には大きく分けて2つある。
|
方式 |
概要・特徴 |
|
FIR(畳み込みリバーブ) |
実際の空間のインパルス応答を録音して使用。リアルだが柔軟性低く計算負荷が高い。「そのホールをコピーする技術」 |
|
IIR(アルゴリズミックリバーブ) |
数学モデルで人工的に生成。軽量・調整可能・創造的だが設計が難しい。「ホールらしさを作る技術」。Lexicon等の商用ハードはほぼこちら |
音の前後感(奥行き)は主に次の3要素で決まる。
つまり奥行きはリバーブ設計そのものである。
人間は「個々の反射」ではなく、エネルギー分布と時間変化のパターンを知覚している。ミックスで必要なのは正確な反射配置ではなく、密度(density)・減衰(decay)・周波数バランスである。
FIR(IR)リバーブが使いにくい場面がある理由として、以下が挙げられる。
これに対してアルゴリズミックリバーブは「聴感最適化された嘘」として機能し、ポップス・映画音楽・ゲーム音響など「音楽としての気持ちよさ」が優先される場面で有利となる。
もっとも古くから実装され、フリーソフトでも広く使われているのが、comb filterとallpass filterを組み合わせたリバーブである。ARI-WEBのページに詳しい説明がある。Freeverb3の前身であるFreeverbもこのアルゴリズムに基づいており、「Schroeder(シュレーダ)のリバーブ」と呼ばれる。
問題の本質はモード(共鳴)の偏り、すなわちランダム性の不足にある。comb filterが等間隔の周波数ピーク(定在波的な構造)を生じさせることが「チーン」という金属感の原因である。
そのため「高品質さ」を求める場面では使われることが少ない。一方で、金属的な音からプレートリバーブ(金属板に音を入力して振動を出力とする実機)の代わりとして使われることがある。
Freeverbは経験的に求めた数値に基づいてフィルタが作成されており、比較的金属的な音が少ないとされるが、限界はある。
|
実装名 |
特徴 |
|
Freeverb |
Schroeder改良型。軽量・簡易。経験的パラメータで比較的金属感を抑制 |
|
CCRMAのNRev |
Freeverbと同様のアルゴリズムをより洗練させたもの |
|
NVerb(v2) |
Allpassの入れ子+入力フィードバックを利用してリンギングを極力抑制。低音の響きが改善 |
通常(直列):input → AP → AP → AP と接続するのに対し、入れ子では AP の内部に別のリバーブアルゴリズムを挿入する。これにより:
直列のオールパスフィルタより入れ子の方が品質が高いことはあまり知られていないが、Schroeder自身も昔からこのアルゴリズムに言及していた。
◆ comb filterのfeedback部分にmodulationを加えてChorusとすることでリンギングが抑えられやすく、LexiconのConcert Hallアルゴリズムは「Chorus comb filter + allpass filter + 入れ子allpass filter」に基づいていると推測される。
Schroederリバーブの問題を解決するために生まれた方式の一つ。いくつかの異なった長さのdelay lineと、それを撹拌・出力するための行列からなるアルゴリズムである。Freeverb3ではHibiki Reverbとして実装。
FDNは多入力多出力の再帰システムとして以下のように記述できる。
x(n) = A · x(n-D) + B · u(n)
y(n) = C · x(n)
システムが安定 ⟺ スペクトル半径 ρ(A) < 1 が条件となる。ただしFDNではディレイがあるため、より正確には「Aがユニタリ(または直交)かつ減衰が入っている状態で安定」となる。
つまりFDNは「多数の減衰振動モードの集合」である。固有値が偏ると特定周波数が強調(リンギング)し、ディレイ長が単純比になるとモードが重なる。これはSchroederが金属的になる理由と同じ構造的問題である。
8個以上のディレイラインとアダマール行列を使えば、かなり簡単に高品質な残響が作れる。実際の残響にあるような周波数の位相変化などについては、リアルタイムに行列を変化させることで対応する実装が多い。初期残響音の生成にもアルゴリズム的に対応しやすく、広く活用されている。
ビンテージデジタルリバーブとして広まったLexicon 224やEMT 250は「暖かい」きれいなリバーブとして高く評価されているが、allpass filterを利用したループ(タンク)のアルゴリズムによるところが大きい。大きなループを作ることで、FDNと同様に時間とともに密度が高くなるリバーブを作ることができる。
アルゴリズムとしては単純だが、各最適なdelay長とgainを探すのが難しい。
Lexicon 224はリバースエンジニアリングによってESPのリバーブとしても実装され、論文にも掲載されている。ESPのマニュアルはFreeverb3のサイトにミラーされている。
feedback loopの長さがあまり長くなく、Plate Reverbとされているが、係数を調整すれば相応の響きが得られる。Freeverb3_VSTではSTRevとして、ホール用の別ループに基づいたProG Reverb(Progenitor Reverb)としても実装されている。
◆ Progenitor Reverbのメインfeedback loopはDattorroの公開アルゴリズムに基づくが、入力のdiffuser・出力のタップは独自の経験に基づく。ループ内部やdiffuserのfeedback係数は0.5程度が基本で、実験によると0.4〜0.8の間に最適値があるとされる。
全体構造は以下の流れとなる:入力 → プリディレイ → 複数のAllpass(diffuser) → メインループ(2系統クロスフィードバック) → タップ出力(複数点) → ダンピング
核心はクロスフィードバックである。左ループと右ループがそれぞれ自分自身にフィードバックしながら、相手にもフィードバック(クロス)する。これにより情報が混ざり、密度が爆発的に増える。
|
構成要素 |
知覚的役割 |
|
Allpass diffuser(入力直後) |
トランジェントを分散、初期エコーを消す「空間に入った瞬間の拡散」 |
|
ループ内Allpass |
追加拡散。フィードバック係数0.4〜0.8が最適 |
|
ダンピング(LPF) |
高域を自然に減衰。これがないと「デジタル臭い」 |
|
モジュレーション |
固定モードを時間的に破壊。金属感を除去し「生きている」感を生む |
|
タップ出力(複数点) |
異なる時間位置・位相からの出力。ステレオ感・広がりを生成 |
FDNとの本質的違いは以下のとおり。FDNが行列で一気に混ぜるのに対し、Dattorroは構造的に(時間的・段階的に)混ぜる。これによりより「音楽的」に調整しやすい。
ある程度新しいLexiconのリバーブは周波数分割により、それぞれの帯域に最適なアルゴリズムを利用して残響を生成している。
パラメータBass XOVは、低周波を分割処理して低音域の残響時間を延長等するための仕組みである。Lexiconはかなり初期からこの分割アルゴリズムを採用しており、低音に強い暖かみのあるリバーブとなっている。実際の環境でも、低音は指向性が低く高音は指向性が高いため、分割処理の採用には物理的な合理性がある。
情報理論的には、低域はエントロピー増加(豊かさ)、高域は相互情報量減少(拡散)を早期に達成する。
|
世代 |
代表例 |
核心構造 |
音の特徴 |
|
第1世代 |
EMT 250(1976) |
短ループ+Allpass |
不完全だが暖かい粒状感 |
|
第2世代 |
Lexicon 224 / 480L |
知覚最適化+マルチバンド+ランダム化 |
音楽的・魔法的な尾 |
|
第3世代 |
Bricasti M7 |
Waveguide的物理近似 |
現実の空間を再現 |
|
第4世代 |
DiffFDN / PINN |
学習による統合 |
知覚・物理・情報の統合 |
convolution の正確な訳語は「畳み込み」である。「叩き込み」という表記は画像処理ソフトの誤訳に端を発する誤りであり、技術文書では使用しない。
数学的定義:
y(n) = Σ_k x(k) · h(n-k)
音響的意味:IR = 空間(または機器)の「応答の全て」であり、コンボリューション = 「入力をその空間で鳴らした結果を計算すること」である。
マイク変換(例:SM57 → U87)に必要なのはデコンボリューション(逆フィルタ)である。
H_IR(ω) = Y(ω) / X(ω)
実務上の問題として、周波数でゼロに近い箇所での「ゼロ割」によるノイズ増幅がある。対策として正則化(regularization)や帯域制限が用いられる。
理想はデルタ関数入力だが、実際にはS/Nが悪すぎて使えない。現代の標準手法はサイン波スイープまたはTSP(Time-Stretched Pulse)を使う方式である。
FFT畳み込みの式:Y = IFFT(FFT(X) · FFT(H))
FFTはブロック処理のため、ブロックサイズ分の遅延が発生する(例:1024サンプル → 約20ms)。
これにより低レイテンシと高速処理を両立する。
IRが表現できるのはLTI(Linear Time-Invariant)系のみである。
|
再現できるもの |
再現できないもの |
|
周波数特性・残響・位相応答 |
真空管アンプの偶数次倍音歪み(非線形歪み) |
|
空間の線形応答全般 |
スピーカーの非線形コンプレッション効果 |
|
FM的変調(時間依存の周波数変化) |
IRは「音の形」は再現できるが「振る舞い」は再現できない。また、収録機材(スピーカー・マイク)の特性はデコンボリューションである程度除去できるが、S/N比・ダイナミックレンジ・歪みの制約から完全除去は不可能である。
当時の代表的なコンボリューションリバーブソフトは以下のとおりである。
|
ソフトウェア |
特徴 |
|
SIR(Windows専用・フリー) |
初期は高レイテンシ。バージョンアップで順次改善 |
|
WAVES IR-1 / IR-L |
業界標準クラスの商用製品 |
|
Altiverb |
4ch IRによりステレオI/Oに対応。定位再現性が高く付属ライブラリの質も高い。ただしiLok必須・高価格が障壁 |
|
Voxengo Pristine Space |
高コストパフォーマンスの商用製品 |
|
WizooVerb W2 |
商用製品 |
◆ AltiverbはステレオI/Oに対応した4chのIRを持つため定位再現性に優れる。Altiverb専用フォーマット(リトルエンディアン24bit PCM+リソースフォークのゲイン補正情報)のWAV変換手順が共有された。フリーのIR素材配布サイトとしてNoisevault・Voxengo・memi.comなどが活用された。
IRは「空間の録音」だけではなく、様々な創造的応用がある。
以下はC++によるFDNの基本実装例である。テンプレートパラメータ length がFDNの次元数を指定する。feedbackの範囲は [-1.0, 1.0] で、範囲外では発散する。
template<typename Sample, size_t length>
struct FeedbackDelayNetwork {
size_t bufIndex = 0;
std::array<std::array<Sample, length>, 2> buf{};
std::array<std::array<Sample, length>, length> matrix{};
std::array<Delay<Sample>, length> delay;
std::array<RateLimiter<Sample>, length> delayTimeSample;
Sample process(Sample input, Sample feedback) {
bufIndex ^= 1;
auto &front = buf[bufIndex];
auto &back = buf[bufIndex ^ 1];
front.fill(0);
for (size_t i = 0; i < length; ++i)
for (size_t j = 0; j < length; ++j)
front[i] += matrix[i][j] * back[j];
input /= Sample(length);
for (size_t idx = 0; idx < length; ++idx) {
auto &&sig = input + feedback * front[idx];
front[idx] = delay[idx].process(
sig, delayTimeSample[idx].process());
}
return std::accumulate(front.begin(), front.end(), Sample(0));
}
};
◆ リセット関連のメソッドは省略。テンプレートパラメータ length が大きい時はstd::vectorへの書き換えを推奨(dim=200程度が上限の目安)。
引数 feedback はフィードバック行列の値をまとめて変更するスカラー係数。ただし Delay は線形補間を行っているため、ディレイ時間が整数でなければ徐々に出力が減衰する。
FDNが発散しない条件:ρ(g·A) ≤ 1(ρ:スペクトル半径)
直交行列 A について A^T · A = I が成立する。これにより |λ_i| = 1 となり、エネルギーが保存される。
‖y‖² = ‖Ay‖²
つまり、直交行列 + |g| < 1 の組み合わせで必ず安定となる。減衰は g のみで制御される。
◆ Schlecht と Habets の "On lossless feedback delay networks" によると、FDNが発散しないためにはフィードバック行列をユニタリ行列か三角行列にするとよい。
最適解は解析的に求まらず、探索と経験則のハイブリッドとなる。
Schlecht と Habets の研究によると、FDNが発散しないフィードバック行列の主な種類として、ユニタリ行列(複素数を含む場合あり)と三角行列がある。今回の実装では直交行列(実数のユニタリ行列)で十分である。
|
行列の種類 |
特徴・音の傾向 |
|
ランダム直交行列 |
高い拡散性・均一なエネルギー分布。金属感少なく滑らか。scipy.stats.ortho_group.rvs()相当 |
|
特殊直交行列 |
行列式=1。ランダム直交との音の違いは聴き取りにくい |
|
Householder行列 |
H = I - 2(vv^T)/(v^Tv)の形。dim個の乱数から構築可能。拡散は弱めでキャラが出やすい |
|
アダマール行列 |
±1のみ。完全直交。高速(加算のみ)。ランダム直交と似た音でCPU効率良好 |
|
巡回行列 |
シフト構造・周期性あり。「管っぽい」音。DFTで対角化可能 |
|
三角行列 |
初期反射が強く金属感あり。ショートディレイが目立つ |
|
Conference行列 |
対角成分が0。非常に自然で自己ループ(金属音源)が最小。大変良い音 |
|
吸収オールパス行列 |
Schlecht-Habets論文の式(10)。FDNを使わない方が効率的な場合あり |
Mezzadri の "How to generate random matrices from the classical compact groups" を参考にした実装。scipy.stats.ortho_group.rvs() のC++翻訳版。
template<size_t dim>
void randomOrthogonal(unsigned seed,
std::array<std::array<Sample, dim>, dim> &H) {
pcg64 rng{}; rng.seed(seed);
std::normal_distribution<Sample> dist{};
H.fill({});
for (size_t i = 0; i < dim; ++i) H[i][i] = Sample(1);
std::array<Sample, dim> x;
for (size_t n = 0; n < dim; ++n) {
auto xRange = dim - n;
for (size_t i = 0; i < xRange; ++i) x[i] = dist(rng);
Sample norm2 = 0;
for (size_t i = 0; i < xRange; ++i) norm2 += x[i] * x[i];
Sample x0 = x[0];
Sample D = x0 >= 0 ? Sample(1) : Sample(-1);
x[0] += D * std::sqrt(norm2);
Sample denom = std::sqrt(
(norm2 - x0*x0 + x[0]*x[0]) / Sample(2));
for (size_t i = 0; i < xRange; ++i) x[i] /= denom;
for (size_t row = 0; row < dim; ++row) {
Sample dotH = 0;
for (size_t col = 0; col < xRange; ++col)
dotH += H[col][row] * x[col];
for (size_t col = 0; col < xRange; ++col)
H[col][row] = D * (H[col][row] - dotH * x[col]);
}
}
}
◆ 乱数生成器にPCGを使用するのはNumPyのdefault_rng()で採用されているため。安定性が重要なのでstd::minstd_randより好ましい。
初期値として 1/sqrt(dim) を使い、タイリングで再帰的に構成する。dim は2の冪乗でなければならない。
template<size_t dim>
void constructHadamardSylvester(
std::array<std::array<Sample, dim>, dim> &mat) {
static_assert(dim && ((dim & (dim-1)) == 0), ...);
mat[0][0] = Sample(1) / std::sqrt(Sample(dim));
size_t start = 1; size_t end = 2;
while (start < dim) {
for (size_t row = start; row < end; ++row)
for (size_t col = start; col < end; ++col) {
auto &&value = mat[row-start][col-start];
mat[row-start][col] = value; // Upper right
mat[row][col-start] = value; // Lower left
mat[row][col] = -value; // Lower right
}
start *= 2; end *= 2;
}
}
H = I - 2(vv^T)/(v^Tv) の形で表現される。dim個の乱数から直交行列を組み立てられ、対称行列になる(H = H^T)特徴がある。
template<size_t dim>
void randomHouseholder(unsigned seed,
std::array<std::array<Sample, dim>, dim> &matrix) {
// ... (一様乱数でvecを初期化)
auto scale = Sample(-2) / denom;
for (size_t i = 0; i < dim; ++i) {
matrix[i][i] = Sample(1) + scale * vec[i] * vec[i];
for (size_t j = i+1; j < dim; ++j) {
auto value = scale * vec[i] * vec[j];
matrix[i][j] = value; matrix[j][i] = value;
}
}
}
Conference行列の大きさは「2つの平方数の和となる偶数 q(OEISのA286636相当)に対してq+1」という条件を満たす必要がある。OEIS数列A000952(候補:62, 54, 50, 46, 42, 38, 30, 26, 18, 14, 10, 6, 2)を候補として使用。
対角成分が0であるため、単純なコムフィルタになっている部分がなく音質が良い。
Schlecht-Habets の "Time-varying feedback matrices in FDN" で紹介された行列。オールパスフィルタの入れ子を表現する。α の範囲が (-1, 1) なら収束する。
template<size_t dim>
void randomAbsorbent(unsigned seed, Sample low, Sample high,
std::array<std::array<Sample, dim>, dim> &mat) {
// dim は偶数必須
constexpr size_t half = dim / 2;
// 上半分(half×half)の直交行列 A を生成
randomOrthogonal(seeder(rng), A);
for (size_t col = 0; col < half; ++col) {
auto gain = dist(rng);
mat[half+col][half+col] = gain; // 右下
mat[half+col][col] = Sample(1) - gain*gain; // 左下
for (size_t row = 0; row < half; ++row) {
mat[row][half+col] = A[row][col]; // 右上
mat[row][col] = -A[row][col]*gain; // 左上
}
}
}
randomSpecialOrthogonal の乱数生成部分を以下のように変更することで、単位行列への近さを調整できる。
x[0] = Sample(1);
for (size_t i = 1; i < xRange; ++i)
x[i] = identityAmount * dist(rng);
音響的には identityAmount を下げると初期反射が強化され後期残響が弱化する傾向がある。
通常はフィードバック行列 A から固有値が決まるが、逆に固有値を先に設計する「固有値直接設計」も可能である。
固有値設計の本質は「減衰スペクトルの設計」である。
|
良いリバーブ |
悪いリバーブ |
|
エコーを感じない(密度が時間と共に増える) |
金属的(metallic) |
|
低音が自然に伸びる |
周期的(ピンポン感) |
|
高音がうるさくない |
濁る or 輪郭が消える |
|
音像を壊さない |
特定帯域が強い |
|
エネルギー分布が時間とともに均一化する |
リンギングが明確に聴こえる |
人間が違いを感じる最小量(JND)の目安:
JNDを知ることで「無駄に精密な設計は不要」という設計原則が導かれる。1ms単位の最適化や聴覚限界以下の周波数分解能設計は実質的な意味を持たない。
強い音が近い帯域の弱い音を隠す。EMT 250の「粒状感」がマスキングを生み、完全拡散よりも心地よく聴こえる場合がある(「不完全さが知覚的最適」というパラドックス)。
直後の音が聞こえなくなる効果。初期反射は直接音にマスクされるため完全な物理再現は不要。
音場を「波」ではなく「情報源」として捉える。
良いリバーブの目標:時間とともにエントロピーが滑らかに増加すること。
金属音の情報理論的解釈:情報が拡散されず、構造が知覚されてしまう現象である。
Lexicon 480Lの知覚的な「魔法」は、Bass XOV(マルチバンド処理)・制御されたモジュレーション・Loop Tank構造の組み合わせによる。
Random Hallでは内部モジュレーション(Decay Optimization)がCHOに相当する。
◆ マニュアルでは「BASS MULT最大、RT HF CUT中、HF CUTOFF低」が理想的なコンサートホール設定として明記されている。
Bass XOVは周波数ごとに最適な情報拡散速度を変える機構であり、以下の物理的・知覚的事実に基づく。
公式マニュアルによると、V2 modulationはlate reverb tailのpitch variationであり、chorusやflangeとは異なる。
各delay tapの時間 D_i(t) を独立に変調:D_i(t) = D_i + Δ · m(t, level)
// C++実装(簡略)
Sample sine = std::sin(2.0f * M_PI * modFreqBase * phase[i]);
Sample noise = 0;
for (int k = 0; k < 3; ++k)
noise += std::sin(2.0f * M_PI * (modFreqBase*(k+1)) * np[i])
/ (k+1);
noise /= 3.0f;
// Lowはsine支配、Highはnoise支配、Midはブレンド
世界初の商用デジタルリバーブ(1976年)。Loop Tankの元祖。
Bricasti M7の内部アルゴリズムは完全非公開だが、音響特性から散乱型Waveguide Networkを強く意識した構造と広く推測されている。
|
特性 |
Lexicon 480L |
Valhalla VintageVerb |
Bricasti M7 |
|
3D感/奥行き |
魔法的(知覚最適化) |
美しい広がり |
圧倒的リアリティ |
|
暖かさ/低域 |
多バンドで豊か |
十分暖かい |
自然だが肉厚 |
|
音楽性 |
最高(感情を誘う) |
高い(Lexicon風) |
やや控えめ |
|
金属音 |
ランダム化で良好 |
非常に優秀 |
ほぼゼロ |
|
ミックス適性 |
前に出て埋もれにくい |
前に出る・ポップス向き |
自然に溶け込む |
|
キャラクター |
ヴィンテージ魔法 |
現代的Lush |
現代的リアル |
◆ Lexicon 480Lは「物理的正しさより知覚的正しさ」を体現した存在。DiffFDNやPINNが目指す「perceptual loss最適化」を、1980年代に人間の耳で先取りしていた。
従来のFDN設計は安定性と拡散性を数学的に追求してきたが、「人間がどう聞こえるか」を直接最適化することができる。
J(θ) = Σ_t w_t · d(P(y_θ(t)), P(y_target(t)))
def perceptual_loss(y, y_target):
Y = loudness(mel(y))
Yt = loudness(mel(y_target))
return torch.mean(torch.abs(Y - Yt))
FDN自体をニューラルネットで学習させる。直交制約はパラメータ化によって保持する。
class FDN(nn.Module):
def __init__(self, N=8):
super().__init__()
self.S = nn.Parameter(torch.randn(N, N))
self.delay = nn.Parameter(torch.rand(N) * 2000)
def orthogonal_matrix(self):
S = self.S - self.S.T # 反対称行列
return torch.matrix_exp(S) # exp(S) は常に直交
反対称行列 S の matrix_exp をとることで、A = exp(S) が常に直交行列となり安定性が保証される。
def total_loss(x, y, y_target):
lp = perceptual_loss(y, y_target)
le = -entropy_loss(y) # エントロピー最大化
lmi = mutual_info_loss(x, y) # 相互情報量最小化
ld = decorrelation_loss(y) # デコリレーション
return lp + 0.1*le + 0.1*lmi + 0.1*ld
波動方程式 ∂²p/∂t² = c² ∇²p を損失関数に組み込む。
Loss = DataLoss + PhysicsLoss
PhysicsLoss = ‖∂²p/∂t² - c² ∇²p‖²
従来IR:y(n) = x(n) * h(n)(hが固定)に対し、ニューラルIRは:y(n) = Σ_k x(k) · h(n, k)(hが時間依存)。
Seventh HeavenはFusion-IR(複数IRのmodulated capture)という独自技術でM7を再現している。静的IR(Samplicity M7 IR等)とは根本的に異なる。
固有値を動的に制御するモデル:λ_k(t) = r_k(t) · exp(jθ_k(t))
◆ これは残響を「静的構造から動的場へ」移行させる重要なアイデアである。
IRはVolterra系列の「1次項だけ」である。現実の音響環境には以下の非線形性が存在する。
これらはすべてVolterraの2次・3次項で表現可能である。単なる後段歪み(waveshaper)は不十分で、畳み込みの中に非線形性を入れる必要がある。
線形系:y(t) = ∫ h₁(τ) x(t-τ) dτ
Volterra系列(非線形に拡張):
y(t) = ∫ h₁(τ) x(t-τ) dτ
+ ∬ h₂(τ₁,τ₂) x(t-τ₁) x(t-τ₂) dτ₁dτ₂
+ ...
x_i(n+1) = Σ_j A_ij x_j(n) + Σ_{j,k} B_ijk x_j(n) x_k(n)
// C++実装例
y[i] += alpha * x[i] * x[i]; // 2次Volterra項
◆ α は 0.001〜0.01 程度の小さな値にする。クリッピング防止(tanh等)が必須。
class NonlinearFDN(nn.Module):
def __init__(self, N=8):
super().__init__()
self.S = nn.Parameter(torch.randn(N, N))
self.alpha = nn.Parameter(torch.tensor(0.01))
def forward(self, x):
A = torch.matrix_exp(self.S - self.S.T)
y_lin = x @ A
y_nl = self.alpha * (x ** 2)
return y_lin + y_nl
非線形係数 α を固定せず時間・状態依存にする。
本質:非線形を「状態依存システム」にすることで、より自然な空間応答を模擬する。
Volterra核 h₂(τ₁,τ₂) の次元爆発問題をNNで近似する。
class NeuralVolterra(nn.Module):
def __init__(self):
super().__init__()
self.net = nn.Sequential(
nn.Linear(128, 64),
nn.ReLU(),
nn.Linear(64, 1)
)
def forward(self, x):
return self.net(x) # xは時系列フレーム
class HybridReverb(nn.Module):
def __init__(self):
super().__init__()
self.fdn = FDN()
self.nl = NeuralVolterra()
def forward(self, x):
y_lin = self.fdn(x)
y_nl = self.nl(frame_signal(x))
return y_lin + y_nl.squeeze()
以下の処理パイプラインが非線形を含む高品質リバーブの推奨構成である。
|
レベル |
観点・手法 |
|
レベル1:物理 |
波動方程式 ∂²p/∂t² = c² ∇²p |
|
レベル2:構造 |
FDN / Waveguide Network(波動の低次元近似) |
|
レベル3:統計 |
モード分散・拡散・エネルギー分布 |
|
レベル4:知覚 |
JND・マスキング・ERBフィルタ・perceptual loss |
|
レベル5:学習 |
Differentiable FDN・PINN・Neural Volterra |
|
レベル6:情報 |
エントロピー最大化・相互情報量最小化 |
商用機は次の暗黙の目的関数を人間の耳で最適化した結果である。
J(θ) = d_spec + d_time + d_info + d_mask
各観点から統合すると、良いリバーブとは以下の条件を満たすものである。
一言でまとめると:
「音のエネルギー・情報・知覚が時間とともに制御された拡散をする動的システム」
FORTUNE PROVIDES QUESTIONS FOR THE GREAT ANSWERS: #19
A: To be or not to be.
Q: What is the square root of 4b^2?
Rule of Open-Source Programming #1:
Don't whine unless you are going to implement it yourself.
-- Shlomi Fish
-- "Rules of Open Source Programming"