bsnes/higan/sfc/dsp/echo.cpp

131 lines
3.2 KiB
C++

auto DSP::calculateFIR(bool channel, int index) -> int {
int sample = state.echoHistory[channel][(uint3)(state.echoHistoryOffset + index + 1)];
return (sample * (int8)REG(FIR + index * 0x10)) >> 6;
}
auto DSP::echoOutput(bool channel) -> int {
int output = (int16)((state._mainOut[channel] * (int8)REG(MVOLL + channel * 0x10)) >> 7)
+ (int16)((state._echoIn [channel] * (int8)REG(EVOLL + channel * 0x10)) >> 7);
return sclamp<16>(output);
}
auto DSP::echoRead(bool channel) -> void {
uint addr = state._echoPointer + channel * 2;
uint8 lo = apuram[(uint16)(addr + 0)];
uint8 hi = apuram[(uint16)(addr + 1)];
int s = (int16)((hi << 8) + lo);
state.echoHistory[channel][state.echoHistoryOffset] = s >> 1;
}
auto DSP::echoWrite(bool channel) -> void {
if(!(state._echoDisabled & 0x20)) {
uint addr = state._echoPointer + channel * 2;
int s = state._echoOut[channel];
apuram[(uint16)(addr + 0)] = s;
apuram[(uint16)(addr + 1)] = s >> 8;
}
state._echoOut[channel] = 0;
}
auto DSP::echo22() -> void {
//history
state.echoHistoryOffset++;
state._echoPointer = (uint16)((state._esa << 8) + state.echoOffset);
echoRead(0);
//FIR
int l = calculateFIR(0, 0);
int r = calculateFIR(1, 0);
state._echoIn[0] = l;
state._echoIn[1] = r;
}
auto DSP::echo23() -> void {
int l = calculateFIR(0, 1) + calculateFIR(0, 2);
int r = calculateFIR(1, 1) + calculateFIR(1, 2);
state._echoIn[0] += l;
state._echoIn[1] += r;
echoRead(1);
}
auto DSP::echo24() -> void {
int l = calculateFIR(0, 3) + calculateFIR(0, 4) + calculateFIR(0, 5);
int r = calculateFIR(1, 3) + calculateFIR(1, 4) + calculateFIR(1, 5);
state._echoIn[0] += l;
state._echoIn[1] += r;
}
auto DSP::echo25() -> void {
int l = state._echoIn[0] + calculateFIR(0, 6);
int r = state._echoIn[1] + calculateFIR(1, 6);
l = (int16)l;
r = (int16)r;
l += (int16)calculateFIR(0, 7);
r += (int16)calculateFIR(1, 7);
state._echoIn[0] = sclamp<16>(l) & ~1;
state._echoIn[1] = sclamp<16>(r) & ~1;
}
auto DSP::echo26() -> void {
//left output volumes
//(save sample for next clock so we can output both together)
state._mainOut[0] = echoOutput(0);
//echo feedback
int l = state._echoOut[0] + (int16)((state._echoIn[0] * (int8)REG(EFB)) >> 7);
int r = state._echoOut[1] + (int16)((state._echoIn[1] * (int8)REG(EFB)) >> 7);
state._echoOut[0] = sclamp<16>(l) & ~1;
state._echoOut[1] = sclamp<16>(r) & ~1;
}
auto DSP::echo27() -> void {
//output
int outl = state._mainOut[0];
int outr = echoOutput(1);
state._mainOut[0] = 0;
state._mainOut[1] = 0;
//todo: global muting isn't this simple
//(turns DAC on and off or something, causing small ~37-sample pulse when first muted)
if(REG(FLG) & 0x40) {
outl = 0;
outr = 0;
}
//output sample to DAC
stream->sample(outl / 32768.0, outr / 32768.0);
}
auto DSP::echo28() -> void {
state._echoDisabled = REG(FLG);
}
auto DSP::echo29() -> void {
state._esa = REG(ESA);
if(!state.echoOffset) state.echoLength = (REG(EDL) & 0x0f) << 11;
state.echoOffset += 4;
if(state.echoOffset >= state.echoLength) state.echoOffset = 0;
//write left echo
echoWrite(0);
state._echoDisabled = REG(FLG);
}
auto DSP::echo30() -> void {
//write right echo
echoWrite(1);
}