bsnes/higan/sfc/dsp/brr.cpp

62 lines
1.6 KiB
C++

auto DSP::brrDecode(Voice& v) -> void {
//state.t_brr_byte = ram[v.brr_addr + v.brr_offset] cached from previous clock cycle
int nybbles = (state._brrByte << 8) + apuram[(uint16)(v.brrAddress + v.brrOffset + 1)];
const int filter = (state._brrHeader >> 2) & 3;
const int scale = (state._brrHeader >> 4);
//decode four samples
for(auto n : range(4)) {
//bits 12-15 = current nybble; sign extend, then shift right to 4-bit precision
//result: s = 4-bit sign-extended sample value
int s = (int16)nybbles >> 12;
nybbles <<= 4; //slide nybble so that on next loop iteration, bits 12-15 = current nybble
if(scale <= 12) {
s <<= scale;
s >>= 1;
} else {
s &= ~0x7ff;
}
//apply IIR filter (2 is the most commonly used)
const int p1 = v.buffer[12 + v.bufferOffset - 1];
const int p2 = v.buffer[12 + v.bufferOffset - 2] >> 1;
switch(filter) {
case 0:
break;
case 1:
//s += p1 * 0.46875
s += p1 >> 1;
s += (-p1) >> 5;
break;
case 2:
//s += p1 * 0.953125 - p2 * 0.46875
s += p1;
s -= p2;
s += p2 >> 4;
s += (p1 * -3) >> 6;
break;
case 3:
//s += p1 * 0.8984375 - p2 * 0.40625
s += p1;
s -= p2;
s += (p1 * -13) >> 7;
s += (p2 * 3) >> 4;
break;
}
//adjust and write sample (mirror the written sample for wrapping)
s = sclamp<16>(s);
s = (int16)(s << 1);
v.buffer[v.bufferOffset + 0] = s;
v.buffer[v.bufferOffset + 12] = s;
v.buffer[v.bufferOffset + 24] = s;
if(++v.bufferOffset >= 12) v.bufferOffset = 0;
}
}