Snes9x DSP interpolation

Discussion of hardware and software development for Super NES and Super Famicom. See the SNESdev wiki for more information.

Moderator: Moderators

Forum rules
  • For making cartridges of your Super NES games, see Reproduction.
Post Reply
cheepsmb
Posts: 3
Joined: Sat Jan 28, 2023 1:23 pm

Snes9x DSP interpolation

Post by cheepsmb »

There's something I've never understood about audio interpolation.

https://github.com/snes9xgit/snes9x/blo ... #L429-L512
- Gaussian operates on next 4 incoming samples? Like it knows what the future looks like and is able to pre-act on it?
- And Sinc works on next 8 upcoming inputs?


https://github.com/snes9xgit/snes9x/blo ... #L652-L707
- Assuming the above is true and the brr decoder only works on 4 at a time .. does the filter ever get into a situation where it's working with "stale" data?


https://snes.nesdev.org/wiki/BRR_samples
0 1 2 3 .. 12 13 14 15 - AA BB CC DD EE FF GG HH

When the ptr is at 12-15, are the next AA-DD bytes ready or are they still unknown? Because if Gaussian is at 13 and AA isn't ready, then it's reusing some old value?

And if Sinc uses 8 points, wouldn't that be "crap" data for a few more outputs? I'm just guessing that Gaussian has enough time to do things on-demand and not prepare farther ahead for another 4 bytes, which would appear to affect Sinc ..

Honestly I'm thinking there's some nitty cycle timing that I'm overlooking, because I didn't fully follow the phase timing table.


Thanks anyone!
User avatar
jeffythedragonslayer
Posts: 344
Joined: Thu Dec 09, 2021 12:29 pm

Re: Snes9x DSP interpolation

Post by jeffythedragonslayer »

I don't use snes9x that much, but that's quite a few lines of code you've selected after the hyperlink anchors. Can you elaborate on why the code makes you think Gaussian and sinc are looking into the future?
cheepsmb
Posts: 3
Joined: Sat Jan 28, 2023 1:23 pm

Re: Snes9x DSP interpolation

Post by cheepsmb »

Code: Select all

int const* in = &v->buf [(v->interp_pos >> 12) + v->buf_pos];

out  = filt [0] * in [0];
out += filt [1] * in [1];
..
out += filt [7] * in [7];
out >>= 14;

CLAMP16( out );
return out;
inline VOICE_CLOCK( V3c ) = interpolate (above)
inline VOICE_CLOCK( V4 ) = decode brr

interp_pos >> 12 removes 2048 pitch fractional + buf_pos = current playback sample ?

in[7] = Sinc. buf_pos + 7 = seven bytes after buf_pos sample?
in[3] = Gaussian stops here.

Code: Select all

// Make pointers into gaussian based on fractional position between samples
int offset = v->interp_pos >> 4 & 0xFF;
short const* fwd = gauss + 255 - offset;
short const* rev = gauss       + offset; // mirror left half of gaussian

out  = (fwd [  0] * in [0]) >> 11;
out += (fwd [256] * in [1]) >> 11;
out += (rev [256] * in [2]) >> 11;
out = (int16_t) out;
out += (rev [  0] * in [3]) >> 11;

CLAMP16( out );
out &= ~1;

EDIT:
Didn't know about Mesen2, which is easier to understand
https://github.com/SourMesen/Mesen2/blo ... polation.h
https://github.com/SourMesen/Mesen2/blo ... pVoice.cpp

12-byte circular buffer
_interpolationPos = 0x0000 - 0x7fff
bufferPos = 0 or 4


If _interpolationPos >= 0x4000, decodes next 4 BRR bytes. But if _interpolationPos == 0x3000, then

Code: Select all

cubic:
uint8_t pos = (interpolationPos >> 12) + bufferPos;

float v0 = samples[pos % 12] / 32768.0f;
float v1 = samples[(pos + 1) % 12] / 32768.0f;
float v2 = samples[(pos + 2) % 12] / 32768.0f;
float v3 = samples[(pos + 3) % 12] / 32768.0f;
samples = 3,4,5,6. When was 4-6 decoded? Or are they still from previous data?
psycopathicteen
Posts: 3140
Joined: Wed May 19, 2010 6:12 pm

Re: Snes9x DSP interpolation

Post by psycopathicteen »

It doesn't actually predict the future, the filtered signal just comes out slightly delayed.
Post Reply