overdub

schwung-tin-tank

hiroikezawa/schwung-tin-tank · ★ 0

TIN TANK: lo-fi BTDR-3 style digital reverb (three PT2399-style delays) for Schwung on Ableton Move

README from GitHub, MIT

TIN TANK

Ableton Move 上の Schwung で動く Audio FX モジュールです(id tin-tank)。名前は、Intellijel がこの部品を「リバーブタンク」と呼んでいることと、ブリキ(tin)のような金属的で安っぽい響きから付けました。

Intellijel Digiverb 1U の非公式エミュレーションです。Digiverb 1U の中に載っている Accutronics(Belton)の Digi-Log リバーブモジュール BTDR-3V の音を、公開資料から DSP で再現しようとしたものです。 実機の録音やインパルス応答は使っていません(後述の「再現性の限界」を参照)。

狙っている音は、高品質なホールリバーブではなく、BTDR らしい ローファイなデジタル残響・仮想スプリング風の響き・高密度マルチタップディレイのような反射・金属的な粒立ちです。

  • 2 ノブ(原機と同じ構成)。Schwung 標準のノブグリッド 1 ページで、トラックのスロットでも Master FX でも使える
  • モノラル処理(原機と同じ)。Wet は L/R 同一、Dry は各チャンネルそのまま
  • DSP は完全オリジナル実装、MIT License(作者 Hiro Ikezawa)。外部ライブラリなし
  • CPU 負荷は Move 実機で約 1 %(下記)

動作環境

  • Ableton Move + Schwung(host 1.7.3 で動作確認)
  • Schwung Manager(Move の http://<Move の IP>:7700)からインストールする

インストール

Releases からインストールする

  1. Releases から最新の tin-tank-module.tar.gz をダウンロードする
  2. Schwung Manager(http://<Move の IP>:7700)の Modules →「Install custom」で、そのファイルをアップロードする
    • リポジトリを clone してあれば、コマンドでもできます: python3 scripts/install.py http://<Move の IP>:7700 --package <ダウンロードした tin-tank-module.tar.gz>
  3. Move を再起動する(起動中に一度使ったモジュールは、再起動するまで古い版のまま動きます)

ソースからビルドしてインストールする

aarch64 のクロスコンパイラ(aarch64-linux-gnu-gcc)と Python 3 が必要です。

bash scripts/build.sh arm64                         # dist/tin-tank-module.tar.gz ができる
python3 scripts/install.py http://<Move の IP>:7700  # Schwung Manager にアップロードしてインストール

インストール後は Move を再起動してください。install.py はデスクトップ向けのビルドを誤ってアップロードしないよう、 中身が ARM64 の tin-tank.so であることを確かめてから送ります。

アンインストール

Schwung Manager の Modules ページで TIN TANK を削除してください。

ノブパラメータ範囲初期値
1MIX0–100 %(等パワー)35 %
2DECAY0.70–3.00 秒(広帯域の T60)1.40 秒
3–8未使用原機の 2 ノブ構成のまま—

使い方

  1. トラックのスロット(Signal Chain)の Audio FX、または Master FX(Shift+Vol+Menu)に TIN TANK を入れる
  2. ノブ 1(MIX)で原音と残響のバランス、ノブ 2(DECAY)で残響の長さを決める
    • DECAY 最小(0.7 秒):67 ms 付近の反射から始まる、短くまばらなローファイ残響
    • 中央付近(1.4 秒前後):反射が重なって密になった、ローファイな残響
    • 最大(3 秒):約 3 秒かけて消える長い残響。回しても発振しない
  3. MIX 0 % は完全なバイパス(入力とビット単位で一致)、100 % は原音を含まない残響だけ

原機について調べて分かったこと

確認できた事実

  • Intellijel Digiverb 1U:ノブは Dry/Wet Mix と Decay の 2 つ。「約 3 秒近い残響」、 「仮想スプリングリバーブと高密度マルチタップディレイの中間のようなローファイな残響」と説明されている。 中に Accutronics のデジタルリバーブ「タンク」モジュールが載っている (BTDR-3V であることは、作者が所有する実機の基板写真で確認済み)。
  • BTDR-3 データシート(Accu-Bell / Accutronics):+5 V 単電源、入力 1.5 V peak まで、入力インピーダンス 10 kΩ、 出力インピーダンス 220 Ω、各出力のゲイン −3 dB、残留ノイズ −77 dBV。出力は 2 本(Output 1 / Output 2、 「モノラルにするときは足し合わせてよい」)。Decay は外付け抵抗 2 本、または 2 連ポット 1 個で調整 (Pot 1A/1B、Pot 2A/2B のピン)。応用回路の入力側に R1・R2・C1 による「プリ EQ のハイパス」がある。 「内部クロックの最大値は約 14 MHz」。
  • 米国特許 US 8,204,240 B2(Brian C. Neunaber, "Apparatus and method for artificial reverberation", 優先日 2007-06-30):PT2399 を使う人工残響回路。好ましい実施例は ディレイ 3 本(N = 3):
    • 入力側の 2 本:7T/4 ≈ 87.5 ms と 4T/3 ≈ 66.7 ms(T ≈ 50 ms)。66.7 ms の方は約 1 Hz の三角波 LFO でディレイ時間をわずかに揺らす(テールの周期的なパターンを崩すため)
    • フィードバック側の 1 本:T ≈ 50 ms。この経路には入力を直接入れない
    • 各ディレイの前に低域通過フィルタ(2 次ベッセル、約 13.6 kHz)。アンチエイリアスと空気吸収の近似を兼ねる
    • 各ディレイの出力は、自分の加算点にゲイン A のマイナーループで戻り、さらに 3 本の和が −2A/N のグローバルフィードバックで全加算点に戻る(極性はマイナーループと逆)。 つまりループ行列は A·(I − (2/N)·J)(スケールされたハウスホルダー反射、Jot の単位行列構成)
    • 残響時間はゲイン A で決まる(0 < |A| ≤ 1 で安定)
    • 出力はディレイ 152(50 ms)から。ステレオ版(FIG. 4)は 66.7 ms と 50 ms の 2 本を Output 1/2 にする。 出力に 2 次バターワース約 13.25 kHz のローパス
    • PT2399 版の回路定数:ディレイ設定抵抗 4.99 kΩ / 3.24 kΩ / 1.82 kΩ、LFO の積分抵抗 220 kΩ、三角波約 5 V peak
  • PT2399 データシート(Princeton Technology):ブロック図はコンパレータ(COMP)・変調/復調(MOD/DEM)・ 積分器(OP1/OP2 は「変調/復調用積分器」として外付けコンデンサを付ける)・44K ビットの RAM・VCO。 内部 LPF 用オペアンプ 2 個。THD 0.3 %(typ)、出力最大 2 Vrms(THD 10 %)。
  • PT2399 の設計式(Electric Druid が データシートの表から求めた近似): ディレイ[ms] = 11.46 × R[kΩ] + 29.70、ディレイ[ms] = 683.21 / クロック[MHz] + 0.08。 特許の 4.99k / 3.24k / 1.82k はそれぞれ 86.9 / 66.8 / 50.6 ms になり、特許の 87.5 / 66.7 / 50 ms と一致する。 さらに 50 ms のチップのクロックは約 13.5 MHz で、BTDR-3 データシートの「最大内部クロック約 14 MHz」と一致する。
  • DIY コミュニティの観察:Belton のブリックは PT2399 を 3 個含み、反射を模したフィードバック構成で、 1 個のディレイを約 1 Hz で揺らしている(コーラス感が出る、周期的すぎると感じる人もいる)。

推定・近似した部分(断定していないこと)

  • US 8,204,240 が BTDR-3 の中身そのものだという公式な資料はない。 ただし PT2399 が 3 個、 1 Hz の揺れ、出力 2 本、最大クロック約 14 MHz(=最短 50 ms のチップ)という公開情報がすべてこの特許の 実施例と一致するので、このモジュールはこの特許の構成をそのまま採用した。

  • Decay の 2 連ポットは、マイナーループの A とグローバルフィードバックの 2A/N を連動して変える ものと解釈した(どちらも A に比例し、比を保たないとループ行列が崩れるため)。ポットのカーブは不明なので、 ノブは「広帯域 T60 の秒数」で直接指定するようにした(下記)。

  • LFO の深さ ±0.55 ms:特許の三角波(5 V peak を、ピン 6 の 2.5 V を中心にした ±2.5 V と解釈)が 220 kΩ を通して 66.7 ms のチップのピン電流(約 0.77 mA)に ±11 µA を足す、として PT2399 の電流式から計算した値。 ピッチの揺れは約 ±4 セント相当。

  • PT2399 内部の音:データシートのブロック図(コンパレータ+積分器+1 ビット RAM)から、デルタ変調型の 変換と推定した。デルタ変調は「1 サンプルで動ける量」に上限があるので、大きく速い信号でスロープ過負荷 (高域の大振幅がざらつく)が起き、その上限と帯域はビットレート(= 44K ビット / ディレイ時間)に比例する。 このモジュールでは

    • 書き込み側のスルーレート制限:50 ms のチップがフルスケールの 5 kHz 正弦まで追従、 長いチップほどビットレートに比例して低くなる(66.7 ms で 3.75 kHz、87.5 ms で 2.86 kHz 相当)
    • 読み出し側の 1 次ローパス(復元フィルタ):ビットレート / 80(50 ms で約 11.3 kHz、66.7 ms で 8.4 kHz、 87.5 ms で 6.4 kHz)

    として入れた。比例関係は根拠があるが、絶対値(5 kHz、/80)は実測ではなく選んだ値。 1 ビット量子化そのもの、量子化ノイズ、クロックノイズはシミュレートしていない(ノイズを足さない方針)。

  • 内部クリップ:BTDR の入力上限 1.5 V peak に対して PT2399 の出力上限が約 2 Vrms なので、 ループの加算点で入力フルスケールの 1.9 倍に向かって tanh で丸める(1.4 倍までは完全に線形)。

  • 入力のハイパス 120 Hz(1 次):データシートの応用回路にあるプリ EQ ハイパスを置いたが、 Digiverb 1U の定数は不明なので、低域が膨らまない程度の値を選んだ。

  • Wet の音量:DECAY を伸ばすとループのエネルギーは 1/(1−A²) で増えるので、その増加分の半分(dB で)を 打ち消すゲイン (1−A²)^¼ を掛けている(原機にはない補正)。さらに Wet 単体は 0.85 から 1.0 へ tanh で丸め、 熱い入力でも int16 で硬くクリップしないようにしている。

DSP の構成

in(L+R)/2 ─ HP 120 Hz ─┬─(+)─ sat ─ LP 13.6k ─ PT2399 87.5 ms ──────────┬ y0
                        ├─(+)─ sat ─ LP 13.6k ─ PT2399 66.7 ms (1 Hz) ───┼ y1 ─┐
                        │ (+)─ sat ─ LP 13.6k ─ PT2399 50.0 ms ──────────┼ y2 ─┴ (y1+y2)/2 ─ LP 13.25k ─ Wet
                        │  ↑ 加算点 i = 入力 + A·y_i − (2A/3)·(y0+y1+y2)   │
                        └──┴───────────────────────────────────────────────┘
       PT2399 = スルーレート制限付きの書き込み → ディレイ → 復元ローパス
  • ディレイは 3 本だけで、長さが 7:4/3:1 という整数比に近い関係にあるため、反射は「グリッド状」に重なっていく。 これが滑らかなホールにならず、マルチタップディレイ的・金属的に聞こえる理由
  • 各パスでベッセル LPF とチップの帯域制限を通るので、反射が繰り返されるたびに高域が落ちていく
  • 66.7 ms のディレイだけ 1 Hz の三角波で揺れる(4 点エルミート補間で読む)。他の 2 本は整数ディレイ
  • DECAY → A は A = 10^(−3·L/T60)、L = 61 ms(テストで測った広帯域 T60 がノブの値に合うように校正)。 A は 30 ms のスムージングで毎サンプル追従するので、回してもクリックやピッチの跳びは出ない
  • MIX は等パワー(cos/sin)。ブロックごとにスムージングし、ブロック内は直線で補間
  • ディレイバッファはすべて構造体の中(3 × 8192 サンプル、インスタンス約 96 KB)。インスタンスは静的な 8 個のプールから取るので、オーディオスレッドでのメモリ確保・ロック・ファイル I/O はない
  • デノーマル対策:ループの加算点に 1e-18 の定数を足して、状態がデノーマル域に落ちないようにしている (出力は完全な 0 に戻ることをテストで確認)。NaN / Inf はブロックごとに検査し、出たら状態をクリア
  • サンプルレートは 44.1 kHz と 48 kHz に対応(時間と周波数はすべて fs から計算)

DECAY の最小値が 0.7 秒の理由

0.1.0 では最小 0.2 秒でしたが、そこではフィードバックがほぼ 0 になり、Wet のエネルギーの 98 % が 67 ms 後のこだま 1 回だけでした。MIX 50 % では原音にこだまが重なって薄いリバーブのように聞こえる一方、 MIX 100 % では遅れたコピーが 1 回鳴るだけで「リバーブが消えた」ように聞こえていました。 このモジュールはディレイが 3 本だけで反射の間隔が 50〜87 ms と広いため、短い残響時間ではそもそも残響にならないので、 最小値を 0.7 秒に上げています(このとき Wet のエネルギーの 32 % が最初の 100 ms より後の尾にあります)。 0.7 秒未満で保存されていた値は 0.7 秒として読み込まれます。

プリセット保存

Schwung の state に {"version":1,"mix":…,"decay":…} を保存し、セットやスロットの保存・復元で戻ります。 片方の値が欠けた state は丸ごと無視、範囲外の値は範囲内に丸めます。

テスト

bash scripts/test.sh          # すべて(ネイティブ、ASan/UBSan、ノブグリッド、arm64 ビルド + ABI、ライセンス)
bash scripts/render_demo.sh   # 試聴用 WAV を build/demo/ に書き出す

tests/test_engine.c の主な結果(デスクトップ、44.1 kHz):

項目結果
DECAY 0.7 / 1.0 / 1.4 / 2.0 / 3.0 秒 → 測定 T60(シュレーダー積分、T30×2)0.69 / 0.98 / 1.40 / 1.99 / 2.94 秒
DECAY 最小 0.7 秒Wet のエネルギーの 32 % が最初の 100 ms より後(尾がある)
最初の反射66.8 ms(それまで完全に無音)。以降 116.9, 133.8, 137.6, 154.6, 183.9 … ms
反射の密度(150 ms ごと、その区間の最大から −20 dB 以内の山の数)7 → 19 → 25 → 50(だんだん密になる)
正弦波の Wet ゲイン(DECAY 1.4 秒)40 Hz −26.6 dB、1 kHz −12.6 dB、2 kHz −5.9 dB、8 kHz −17.6 dB、12 kHz −26.4 dB、15 kHz −36.8 dB(くし形の凹凸あり)
低域40 Hz は 1 kHz より 14 dB 低い(膨らまない)
共鳴の最悪値(DECAY 3 秒、80 Hz–2 kHz を細かく走査)+8.4 dB(174 Hz)
テールの暗くなり方高域の割合が 初期 −3.9 dB → 1.5 秒後 −13.7 dB
MIX 0 %入力とビット一致
MIX 100 %Dry の混入なし、L/R 同一
MIX を 0→100 % に回したときのドローンの音量Dry 比 0〜+1.9 dB
DECAY 0.7 → 3 秒での Wet の音量(ノイズ入力)+1.2 dB(ドローンのような単音はモードに当たると +6.8 dB)
安定性フルスケールのノイズ+ドローンを DECAY 3 秒で 60 秒:NaN なし、リセットなし、ピーク ≤ 1.0
入力停止後5 秒後に −60 dB 以下、その後完全な 0
DECAY を 1 秒に 8 往復、MIX を毎ブロック切り替え出力の最大ステップは固定設定のときと同じ(0.0192)
ホストのブロックサイズ 1 / 7 / 64 / 333128 のときと出力が完全一致
48 kHz最初の反射 66.8 ms、T60 1.38 秒(DECAY 1.4)

tests/test_grid.mjs は Schwung の実際のページエンジンで画面を描き、ノブ 1 = MIX、ノブ 2 = DECAY、 ノブ 3–8 は何も書かないことを確かめます。

再現性の限界

  • 実機の録音・測定と比較していないので、実機と音が一致することは検証していません。 テストが確かめているのは「この設計どおりに動くこと」(残響時間、反射の時刻、安定性、MIX の正確さなど)までです。
  • 回路構成は US 8,204,240 の実施例に基づく推定です。BTDR-3 の実際の抵抗値・フィルタ定数・ Decay ポットのカーブ・LFO の深さは公開されていません。
  • PT2399 のデルタ変調はスルーレート制限と 1 次ローパスで近似しただけで、1 ビット量子化・粒状ノイズ・ クロックのリーク・個体差は再現していません。そのため実機より静かでクリーンな可能性があります。
  • Digiverb 1U 側の入出力回路(ゲイン、EQ、Mix 回路のカーブ)は不明です。MIX は等パワーで実装しています。

CPU 負荷

Move 実機(host 1.7.3、2026-10-23、taskset 0x7、通常優先度)で 128 サンプルのブロックあたり:

設定平均1 ブロック(2902 µs)に対して
初期値40.7 µs1.4 %
DECAY 最大・Wet 100 %27.6 µs1.0 %
DECAY を回し続ける24.4 µs0.8 %

最悪値(0.7〜1.6 ms)は、ベンチマークを通常優先度で走らせているため Move のリアルタイムスレッドに 割り込まれた時間を含んでいます。処理そのものは毎サンプル同じ計算で、重くなる分岐はありません。 デスクトップ(x86-64)では平均 4.6 µs です。

Move 実機での計測

scp build/bench-device-arm64 ableton@<Move の IP>:/data/UserData/
ssh ableton@<Move の IP> "taskset 0x7 /data/UserData/bench-device-arm64"

ファイル構成

パス内容
dsp/dv_engine.c / dv_engine.h残響の本体(3 本のディレイ網、PT2399 の近似、MIX)
dsp/dv_params.hパラメータ表(範囲・初期値。module.json とビルド時に照合)
dsp/dv_plugin.cSchwung の Audio FX API v2 への接続、state の保存・復元、インスタンスのプール
module.json / help.jsonモジュールの定義と、Move の画面で読めるヘルプ
scripts/build.shビルド(native / asan / arm64)
scripts/test.shすべてのテスト
scripts/install.pySchwung Manager へのインストール
scripts/render_demo.sh試聴用 WAV の書き出し
tests/エンジンのテスト、ノブグリッドのテスト、Move 用ベンチマーク
third_party/schwung/Schwung のプラグイン API ヘッダ(MIT、未改変)

更新履歴

  • 0.1.1:DECAY の範囲を 0.20–3.00 秒から 0.70–3.00 秒に変更(最小値ではリバーブではなく、こだま 1 回になっていたため)
  • 0.1.0:最初の版

ライセンス

MIT License(LICENSE)。第三者のファイルは Schwung のプラグイン API ヘッダ(MIT)だけです(THIRD_PARTY_LICENSES.md)。 「Digiverb」は Intellijel、「BTDR」「Digi-Log」は Accutronics / Belton の製品名で、このモジュールはそれらの メーカーとは関係のない独自のエミュレーションです。

参考資料