rmps

MPEG-1/2/2.5 Layer III エンコーダー · C++20 · WebAssembly

聴こえるところに、ビットを使う。

rmpsは「ビットに収まる量子化」ではなく「いちばん良く聴こえる量子化」を探します。 スケールファクターとグローバルゲインをビームサーチし、生の誤差ではなく マスキングモデルで採点して、全グラニュールの全バンドを決定します。

フレームごとの消費ビット マスキング閾値 ビットリザーバ 1列 = 1152サンプル = 26 ms

ほかと違うところ

MP3エンコーダーはどれも同じ問いに答えています。各バンドをどこまで粗く量子化したら 聴こえてしまうのか。rmpsの答え方が違うのは、次の4か所です。

量子化

貪欲ループではなくビームサーチ

スケールファクターとグローバルゲインを同時に探索し、最初に予算へ収まった候補で 確定せず、バンドごとに複数の経路を残します。幅はeffort値で決まります。

コスト関数

誤差ではなくマスキングで採点

探索はNMR(雑音対マスク比)とA特性SDRの混合を最小化します。閾値より下の歪みは コストゼロ、上に出た分だけが代価を払う対象です。

レート制御

ビットレートではなく品質を指定

知覚SDRを指定すると、それを保つためにビットレートを法定範囲いっぱいまで動かします。 サイズを決め打ちしたいときのCBRとPID制御のABRも用意しています。

過渡音

効くときだけショートブロック

ウィンドウ切替は高域主体のアタック(ハイハット、スネアの立ち上がり、シンバル)で 作動します。低音の厚いヒットはロングブロックのまま、サステインに必要な周波数分解能を保ちます。

処理の流れ

各段が次の段に渡ります。教科書的なエンコーダーと最後の2段が違ってくる理由が、 マスキングモデルです。

  1. ポリフェーズサブバンドフィルタ32バンド。1フレーム先読みし、リザーバが次に来る音を知れるようにします。
  2. MDCTバンドあたり18ライン。過渡音ゲートの判定でロング/ショートを切替。
  3. マスキングモデルスケールファクターバンドごとの閾値、ATH下限、拡散、プリエコー対策。
  4. ミッド/サイド判定固定モードではなく、実測ビットコストによるフレーム単位の判定。
  5. ビームサーチ閾値に対してスケールファクター、グローバルゲイン、ノイズシェーピングを決定。
  6. ビットリザーバとビットストリームハフマン符号化、リザーバ貸借、Xing/Infoシークテーブル。

ブラウザで使う

エンコーダー全体がWebAssemblyにコンパイルされます。読み込みもエンコードも ダウンロードもページ上で完結し、アップロードもサーバーもありません。

一括エンコード

import { encodeAudioBuffer } from './rmps.js';

const ac  = new AudioContext();
const buf = await ac.decodeAudioData(bytes);

const blob = await encodeAudioBuffer(buf, {
  quality: 70,        // 1..100
  mode: 'jointStereo',
  onProgress: ({ ratio }) => bar.value = ratio,
});

エンコードはCPUバウンドかつシングルスレッドです。ごく短い素材以外は同梱の モジュールワーカーで実行してください。数分の音声で数秒間CPUを占有するため、 メインスレッドだと目に見えて固まります。

ストリーミング

const enc = await RmpsEncoder.create({
  channels: 2, sampleRate: 44100, bitrate: 192,
});

for (let p = 0; p < L.length; p += enc.samplesPerPass) {
  sink(enc.encode(L.subarray(p, p + spp),
                  R.subarray(p, p + spp)));
}
const blob = enc.finish();   // flush + Xingヘッダ
enc.destroy();

encode()が0バイトを返すのは正常です。 1フレーム先読みで保持するうえ、 リザーバの出力も遅延します。取りこぼしではなく、後続の呼び出しか finish() で出てきます。finish() は実際の再生時間と シークテーブルでXingヘッダを書き直す役割も担うので、必ず呼んでください。

仕様

フォーマット

規格
MPEG-1/2/2.5 Layer III
サンプルレート
8 – 48 kHz
チャンネル
mono / stereo / joint / dual
レートモード
CBR, ABR, 品質VBR
シークテーブル
Xing / Info, 100点

ビルド

言語
C++20
依存
なし
ターゲット
CLI / 静的ライブラリ / wasm
ブラウザ版
emscripten + CMake
ライセンス
MIT

エンコーダーを試す