BRRフォーマット
SNESで使用されるサンプリング音源について説明します。

SNESの音源
SNESでは、音声処理はAPUと呼ばれるユニットで独立して行われており、APUのサウンドCPUであるSPC700プロセッサは、SNESのメインCPUである65C816と独立に動作します。
APUはSPC700プロセッサとDCPから構成され、その性能は次の通りとなっています。

(APU基本仕様)
64KB SRAM (ドライバプログラム・サンプリングデータなどとすべて共用)
サンプリング周波数 32kHz
同時発音数 8チャンネル
16ビット ADPCM ステレオ
クロック周波数 2.048MHz

(DSP機能)
BRR圧縮されたサンプリングデータのデコード
ADSR
ガウス分布補間
エコー
最大240msのディレイ
次数8のFIRフィルタ付きリバーブ
ピッチモジュレーション
ノイズ発生器 (0Hz~32kHz)
ピッチベンド

サウンドの再生に使用されるサンプリング音源は、すべてBRRコーデックで圧縮されており、その圧縮方式としてADPCM(適応的差分パルス符号変調)が使用されます。
再生時にはDSPが都度BRRコーデックを使用して展開して再生しています。
BRRコーデック
BRRという名称は、ビットレート削減(Bitrate Reduction)の略であり、ただの一般名詞に過ぎませんが、ここではSNES APUで使用されるBRRコーデックのことを意味するものとします。
BRRコーデックではADPCM方式で16ビットから4ビットへデータ圧縮が行われます。4ビットのデータは16個で1つのグループを作り、そして1バイトのRFレジスタとともに9バイトで1ブロックを形成します。

  バイト/ビット 7 6 5 4 3 2 1 0
0
粒度
フィルタ指定
ループ指定
終端宣言
1
サンプル1
サンプル0
2
サンプル3
サンプル2
3
サンプル5
サンプル4
4
サンプル7
サンプル6
5
サンプル9
サンプル8
6
サンプル11
サンプル10
7
サンプル13
サンプル12
8
サンプル15
サンプル14
RFレジスタはブロックに含まれるすべてのサンプルに関する情報を規定する部分で、DSPはこの情報に従ってデータの復号化を行います。

1. 粒度
粒度はそのブロックの量子化レベルを表すデータです。この粒度が高いほど量子化ステップ幅が大きくなり、大きな音量の変化を表現できることになります。
4ビットであるため、0から15までの値が原理上は使用できますが、実際には粒度12で16ビットすべてをカバーできるため、13以上は使用されません。

  粒度 範囲 量子化ステップ幅
0
-8 ~ 7
1
1
-16 ~ 14
2
2
- 32 ~ 28
4
3
-64 ~ 56
8
4
-128 ~ 112
16
5
-256 ~ 224
32
6
-512 ~ 448
64
7
-1024 ~ 896
128
8
-2048 ~ 1792
256
9
-4096 ~ 3584
512
10
-8192 ~ 7168
1024
11
-16384 ~ 14336
2048
12
-32768 ~ 28672
4096
粒度12でも正の最大音量(32767)を表現できていないように見えますが、過去に復号されたサンプル値との加減算が実行されるため、すべての値を表現することができます。ADPCMにおいて、各サンプルの値は、実際の各サンプルの信号強度を表しているのではなく、過去のサンプルから予測された差分信号であることに注意が必要です。

2. フィルタ
フィルタは復号時に、どのような方式で差分信号を復号化するかを規定したデータです。フィルタの値によって4種類の復号方式が使用されますが、1つのブロック内では同じ復号方式が適用されます。
それぞれのフィルタにおける復号化アルゴリズムは次のように実装されます。
(注: sampleは復号化対象の4ビットデータ、granularityは粒度、lastSample[1]は1つ前の復号済みサンプル、lastSample[0]は2つ前の復号済みサンプル)
switch (filter)
{
    case 0:
        return sample * (1 << granularity);

    case 1:
        return sample * (1 << granularity) + ((lastSample[1] * 15) >> 4);

    case 2:
        return sample * (1 << granularity) + ((lastSample[1] * 61) >> 5) - ((lastSample[0] * 15) >> 4);

    case 3:
        return sample * (1 << granularity) + ((lastSample[1] * 115) >> 6) - ((lastSample[0] * 13) >> 4);
}

なお、実際にはこの後ガウス分布補間による処理が施されます。

3. ループ指定および終端宣言
RFレジスタのビット1はループ指定フラグであり、このフラグが立っているブロックがある波形サンプルは、ループ点を持つことを意味します。ただし、BRR波形サンプル自身はループ開始点がどこであるのかといった情報は持たず、APU RAMに置かれた波形テーブルにおいて指定されます。
RFレジスタのLSBは終端宣言であり、このフラグが立っているブロックはその波形サンプルの最後のブロックであることを意味します。DSPは終端宣言がなされたブロックのデコードを終えると、対応するチャネルのENDXフラグを立てます。

4. サンプルデータ
BRRブロックの2バイト目以降は各サンプルの差分信号を表します。バイト順に下位ニブルから処理され、すべての差分信号は符号付4ビットとなります。したがって有効な値は-8~7となります。

ガウス分布補間
SNES実機では、表引きによるガウス分布補間が行われており、実際に再生されるサンプル(OUTX)は、前節で説明した復号アルゴリズムで生成されたものとは異なります。ガウス補間は過去に復号した4サンプルを用いて計算されており、その補間方法は以下のように実装されます。

static int GaussianInterpolate(int[] lastSample, int pitch)
{
    int interpolationIndex = pitch >> 4;
    out = (GaussTable[0xFF - interpolationIndex] * lastSample[3]) >> 11;
    out += (GaussTable[0x1FF - interpolationIndex] * lastSample[2]) >> 11;
    out += (GaussTable[0x100 - interpolationIndex] * lastSample[1]) >> 11;
    out = (short)(out[x] << 1) >> 1;
    out += (GaussTable[interpolationIndex] * lastSample[0]) >> 11;
    out = (out < -16384) ? -16384 : (out[x] > 16383) ? 16383 : out[x];
}

static readonly int[] GaussTable = new int[]{
    0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
    0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x002, 0x002, 0x002, 0x002, 0x002,
    0x002, 0x002, 0x003, 0x003, 0x003, 0x003, 0x003, 0x004, 0x004, 0x004, 0x004, 0x004, 0x005, 0x005, 0x005, 0x005,
    0x006, 0x006, 0x006, 0x006, 0x007, 0x007, 0x007, 0x008, 0x008, 0x008, 0x009, 0x009, 0x009, 0x00A, 0x00A, 0x00A,
    0x00B, 0x00B, 0x00B, 0x00C, 0x00C, 0x00D, 0x00D, 0x00E, 0x00E, 0x00F, 0x00F, 0x00F, 0x010, 0x010, 0x011, 0x011,
    0x012, 0x013, 0x013, 0x014, 0x014, 0x015, 0x015, 0x016, 0x017, 0x017, 0x018, 0x018, 0x019, 0x01A, 0x01B, 0x01B,
    0x01C, 0x01D, 0x01D, 0x01E, 0x01F, 0x020, 0x020, 0x021, 0x022, 0x023, 0x024, 0x024, 0x025, 0x026, 0x027, 0x028,
    0x029, 0x02A, 0x02B, 0x02C, 0x02D, 0x02E, 0x02F, 0x030, 0x031, 0x032, 0x033, 0x034, 0x035, 0x036, 0x037, 0x038,
    0x03A, 0x03B, 0x03C, 0x03D, 0x03E, 0x040, 0x041, 0x042, 0x043, 0x045, 0x046, 0x047, 0x049, 0x04A, 0x04C, 0x04D,
    0x04E, 0x050, 0x051, 0x053, 0x054, 0x056, 0x057, 0x059, 0x05A, 0x05C, 0x05E, 0x05F, 0x061, 0x063, 0x064, 0x066,
    0x068, 0x06A, 0x06B, 0x06D, 0x06F, 0x071, 0x073, 0x075, 0x076, 0x078, 0x07A, 0x07C, 0x07E, 0x080, 0x082, 0x084,
    0x086, 0x089, 0x08B, 0x08D, 0x08F, 0x091, 0x093, 0x096, 0x098, 0x09A, 0x09C, 0x09F, 0x0A1, 0x0A3, 0x0A6, 0x0A8,
    0x0AB, 0x0AD, 0x0AF, 0x0B2, 0x0B4, 0x0B7, 0x0BA, 0x0BC, 0x0BF, 0x0C1, 0x0C4, 0x0C7, 0x0C9, 0x0CC, 0x0CF, 0x0D2,
    0x0D4, 0x0D7, 0x0DA, 0x0DD, 0x0E0, 0x0E3, 0x0E6, 0x0E9, 0x0EC, 0x0EF, 0x0F2, 0x0F5, 0x0F8, 0x0FB, 0x0FE, 0x101,
    0x104, 0x107, 0x10B, 0x10E, 0x111, 0x114, 0x118, 0x11B, 0x11E, 0x122, 0x125, 0x129, 0x12C, 0x130, 0x133, 0x137,
    0x13A, 0x13E, 0x141, 0x145, 0x148, 0x14C, 0x150, 0x153, 0x157, 0x15B, 0x15F, 0x162, 0x166, 0x16A, 0x16E, 0x172,
    0x176, 0x17A, 0x17D, 0x181, 0x185, 0x189, 0x18D, 0x191, 0x195, 0x19A, 0x19E, 0x1A2, 0x1A6, 0x1AA, 0x1AE, 0x1B2,
    0x1B7, 0x1BB, 0x1BF, 0x1C3, 0x1C8, 0x1CC, 0x1D0, 0x1D5, 0x1D9, 0x1DD, 0x1E2, 0x1E6, 0x1EB, 0x1EF, 0x1F3, 0x1F8,
    0x1FC, 0x201, 0x205, 0x20A, 0x20F, 0x213, 0x218, 0x21C, 0x221, 0x226, 0x22A, 0x22F, 0x233, 0x238, 0x23D, 0x241,
    0x246, 0x24B, 0x250, 0x254, 0x259, 0x25E, 0x263, 0x267, 0x26C, 0x271, 0x276, 0x27B, 0x280, 0x284, 0x289, 0x28E,
    0x293, 0x298, 0x29D, 0x2A2, 0x2A6, 0x2AB, 0x2B0, 0x2B5, 0x2BA, 0x2BF, 0x2C4, 0x2C9, 0x2CE, 0x2D3, 0x2D8, 0x2DC,
    0x2E1, 0x2E6, 0x2EB, 0x2F0, 0x2F5, 0x2FA, 0x2FF, 0x304, 0x309, 0x30E, 0x313, 0x318, 0x31D, 0x322, 0x326, 0x32B,
    0x330, 0x335, 0x33A, 0x33F, 0x344, 0x349, 0x34E, 0x353, 0x357, 0x35C, 0x361, 0x366, 0x36B, 0x370, 0x374, 0x379,
    0x37E, 0x383, 0x388, 0x38C, 0x391, 0x396, 0x39B, 0x39F, 0x3A4, 0x3A9, 0x3AD, 0x3B2, 0x3B7, 0x3BB, 0x3C0, 0x3C5,
    0x3C9, 0x3CE, 0x3D2, 0x3D7, 0x3DC, 0x3E0, 0x3E5, 0x3E9, 0x3ED, 0x3F2, 0x3F6, 0x3FB, 0x3FF, 0x403, 0x408, 0x40C,
    0x410, 0x415, 0x419, 0x41D, 0x421, 0x425, 0x42A, 0x42E, 0x432, 0x436, 0x43A, 0x43E, 0x442, 0x446, 0x44A, 0x44E,
    0x452, 0x455, 0x459, 0x45D, 0x461, 0x465, 0x468, 0x46C, 0x470, 0x473, 0x477, 0x47A, 0x47E, 0x481, 0x485, 0x488,
    0x48C, 0x48F, 0x492, 0x496, 0x499, 0x49C, 0x49F, 0x4A2, 0x4A6, 0x4A9, 0x4AC, 0x4AF, 0x4B2, 0x4B5, 0x4B7, 0x4BA,
    0x4BD, 0x4C0, 0x4C3, 0x4C5, 0x4C8, 0x4CB, 0x4CD, 0x4D0, 0x4D2, 0x4D5, 0x4D7, 0x4D9, 0x4DC, 0x4DE, 0x4E0, 0x4E3,
    0x4E5, 0x4E7, 0x4E9, 0x4EB, 0x4ED, 0x4EF, 0x4F1, 0x4F3, 0x4F5, 0x4F6, 0x4F8, 0x4FA, 0x4FB, 0x4FD, 0x4FF, 0x500,
    0x502, 0x503, 0x504, 0x506, 0x507, 0x508, 0x50A, 0x50B, 0x50C, 0x50D, 0x50E, 0x50F, 0x510, 0x511, 0x511, 0x512,
    0x513, 0x514, 0x514, 0x515, 0x516, 0x516, 0x517, 0x517, 0x517, 0x518, 0x518, 0x518, 0x518, 0x518, 0x519, 0x519};