Does the gaussian interpolation keep the samples intact?

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
Does the gaussian interpolation keep the samples intact?
by on (#154647)
Does it just connect the dots or does it blur past the sample points? I'm asking because I am think of programming a sample scaler for the SPC700 so it can bypass the Gaussian filter. If it is going to scale samples every 2 octaves, is there going to be a noticeable leap in quality between the last note of an octave and the first note of the next?
Re: Does the gaussian interpolation keep the samples intact?
by on (#154657)
The S-DSP interpolator does not recover the original data.

It's a fairly constant filter curve in sample space if your sample frequency is well below 32 kHz (the important case for muffling), which means in most cases you can pretty much perfectly compensate for it just by prefiltering the samples before converting them to BRR.

I looked at this issue in the Bad Apple thread - graph here, latest version of my overkill un-optimized compensating filters here. One filter is for samples comfortably below 32 kHz or samples that may undergo pitch shifting. The other is for samples at exactly 32 kHz. I have yet to separate out the effects of the 6 dB spike at 32 16 kHz so as to be able to compensate for it in samples intended for a somewhat lower constant rate. There's about 12 dB of gain reduction baked into my prefilters, but if you use them you should be careful of clipping anyway, just in case.

(As far as I know, no one but me has ever tried those filters, so there's still the possibility that I did something catastrophically wrong when testing them, but as far as I can tell they should work.)

BRRTools already has an optional compensating filter when compressing, but the FIR isn't very long and if I recall correctly I could hear the difference; besides which I believe it targets the 32 kHz case and would thus result in some muffling at lower sample rates. Note that the Gaussian output option in BRRTools is broken due to a typo (or was as of that post), so it doesn't accurately represent what you'd hear from a SNES.

I get a bit of extra high-frequency noise when BRR-compressing Bad Apple after using a compensating filter on it. I'll probably investigate this more, but I suspect there's not a lot that can be done...

EDIT: Fixed a reference to the SNES output Nyquist; I accidentally said 32 kHz instead of 16 kHz.
Re: Does the gaussian interpolation keep the samples intact?
by on (#154685)
What happens at frequencies higher than the sample rate?
Re: Does the gaussian interpolation keep the samples intact?
by on (#154697)
The rolloff in input sample space is the same, but the spike at 16 kHz in frequency space (or at the folding frequency in output sample space, if you like) seems to be smaller and perhaps a little wobbly; it looks more pronounced at 64 kHz than at 44.1 kHz.

Please excuse the noisy curves; they're using non-integer resampling and it messes up the comparison. I've smoothed them so you can tell what's going on. Again, this plot is normalized to the input folding frequency, which is why the high-sample-rate curves drop out so early.

Attachment:
snesgain3_norm.png
snesgain3_norm.png [ 14.91 KiB | Viewed 3746 times ]

Say - what exactly does the analogue lowpass filter do? Anyone know what the frequency response looks like? If it happened to roughly compensate for the output Nyquist spike, we could ignore the spike when preparing samples...

...

Wait, did you mean "what does the output look like above the input sample's folding frequency"? It's not bad; there's some aliasing but it drops out quickly because of the rolloff. I doubt anything you could pull off manually in the time available would sound as good.

This plot compares a 32 kHz noise sample (blue) with a 16 kHz version of it (red) upsampled to 32 kHz via SNES gaussian interpolation. The notch is due to the bandlimiting filter used during resampling; you can see the same thing at the upper end of the blue curve.

EDIT: I have added a version of the 16 kHz curve that uses my prefilter to compensate for the interpolator. The aliasing peak is about 12 dB down from the signal, and it's only that high because the signal is fairly loud fairly close to the Nyquist.

Attachment:
noise3216.png
noise3216.png [ 18.76 KiB | Viewed 3730 times ]

EDIT2: I've plotted the 16 kHz sample with both prefiltering and gaussian interpolation (the magenta curve above) against the same noise sample with neither effect added (the 16 kHz equivalent of the blue curve above). For comparison, I've also included a curve for cubic interpolation without prefiltering.

Attachment:
noise1616c.png
noise1616c.png [ 44.45 KiB | Viewed 3729 times ]

As you can see, prefiltering the sample before BRR conversion allows the gaussian interpolator to essentially recover the original spectrum. The cubic by itself is incapable of this feat, and has louder aliasing that a compensating prefilter would make even worse.

...

Please take all this with a small grain of salt, as I'm using my own implementation of the gaussian interpolator using the SNES algorithm and lookup table. Its results should be basically identical (and it matches the description given by tepples in the 32 kHz case), but I haven't rigorously verified it. Also, I'm rushing the analysis a bit, so I may conceivably have screwed up somewhere. If my prefilters turn out to not work well on a real SNES or known bit-accurate emulation, it's probably not the hardware's fault.
Re: Does the gaussian interpolation keep the samples intact?
by on (#154722)
I'm out of attachments in my post above, so I guess I'll double-post...

93143 wrote:
Say - what exactly does the analogue lowpass filter do? Anyone know what the frequency response looks like? If it happened to roughly compensate for the output Nyquist spike, we could ignore the spike when preparing samples...

I was remembering this post, which says:

TmEE wrote:
The fliters present on the analog side have very low effect on the sound.

Now, this could mean a fairly wide range of things. But the filter on SNESAmp 3.3.4 seems a little out of that range, if the quick test I just did is any indication. Between 12 and 15 kHz, it plunges to -16 dB and stays there right up to 16 kHz. (Test was done by smoothing and differencing the power spectra of a couple of treble-heavy game tracks with and without analog simulation turned on.)

Attachment:
snesamp_analog.png
snesamp_analog.png [ 12.75 KiB | Viewed 3713 times ]

That can't be right, can it?

If that's anywhere near hardware-accurate, we can forget about bothering to correct for the <6 dB spike at 16 kHz that the digital processing introduces...

I suppose I could try to figure it out from the schematics...
Re: Does the gaussian interpolation keep the samples intact?
by on (#154725)
The LPF on DAC output is a 12db/octave slope thing with the cutoff frequency right around 16KHz, the typical "reconstruction filter".
The interpolator does a good job suppressing aliases past sample's own rate when it does freq scaling and as a result the aliases at the final output past 16KHz aren't gonna be very loud at the audible range (16...~20KHz) making the removal of LPF not have a significant effect on the output. I'll still be "muffled", just tiny bit less.
Re: Does the gaussian interpolation keep the samples intact?
by on (#154731)
I'm a little confused about the frequency stuff, but I guess if I'm doing NES-style square waves, and I double the samples for every octave going down, there wouldn't be any noticeable leaps in sound quality from one octave to the next.

I still thought of a problem though. If I'm doing a pitch sweep, how do I switch samples without interrupt the sound?
Re: Does the gaussian interpolation keep the samples intact?
by on (#154733)
Each wave has a 4 byte record, pointing to the start of the wave (bytes 0 and 1) and the start of the loop point (bytes 2 and 3). If you can rewrite the loop point atomically in some manner, so that the DSP never sees a half-written loop point while the channel is turned on, you can change where the wave resumes next time it loops. For a given duty cycle, it should be possible to keep 128, 64, 32, and 16 sample loops (total 135 bytes) in one 256-byte page of APU RAM and a 256-sample loop (144 bytes) in a second page so that writing byte 2 or 3 always keeps the loop point as valid sample data.

Or you can just not make multi-octave pitch sweeps and use the same wave throughout a sweep.
Re: Does the gaussian interpolation keep the samples intact?
by on (#154738)
I have an idea. Have the shortest wave be 32 samples long, so you can check $7C to see if it is at the end block or not. After setting the loop point, wait for it to get to the end block, then wait for it to get back to the beginning, then change the frequency.
Re: Does the gaussian interpolation keep the samples intact?
by on (#154748)
TmEE wrote:
The LPF on DAC output is a 12db/octave slope thing with the cutoff frequency right around 16KHz

So, a two-pole lowpass at 16 kHz, presumably having a gain of -6 dB at the cutoff.

That is pretty much the opposite of the digital spike effect. If what you say is true, I think I can declare my 32 kHz prefilter unnecessary, and my "16 kHz" prefilter universal. Unless I've done something really dumb or forgotten/misunderstood something fundamental and it doesn't do what the data seems to say it does... yes, this is a request for feedback...

psycopathicteen wrote:
I'm a little confused about the frequency stuff, but I guess if I'm doing NES-style square waves, and I double the samples for every octave going down, there wouldn't be any noticeable leaps in sound quality from one octave to the next.

...I think I finally get what you're trying to do. Since the SNES can't increase the playback rate by more than two octaves, using a single sample for a very wide frequency range would necessarily result in muffling of the lower frequencies, since the sample can't use enough points to maintain sharpness down there if it's expected to also be usable high up.

You may still get audible aliasing when using sample rates near or (especially) above 32 kHz, so be careful.

Naturally, you should still prefilter your samples; otherwise the classic "muffling" effect will show up, and it will change every time you switch samples.

If you're using something like a single-cycle square wave, I think it's probably wise to duplicate it a bunch so that it's more than twice as long as the filter, run the filter on the whole thing, and cut out a single waveform cycle from the middle of the expanded sample. This will eliminate boundary effects.
Re: Does the gaussian interpolation keep the samples intact?
by on (#154766)
Quote:
Naturally, you should still prefilter your samples; otherwise the classic "muffling" effect will show up, and it will change every time you switch samples.


Whoops, too late. I already automated the process.

Code:
lda #$00
ldy #$81
stw {address}

ldx #$00
lda #$01
sta {scale_factor}
sample_scaling_loop:
sta {blocks_left}
ldw {address}
sta $8000,x
sta $8002,x
tya
sta $8001,x
sta $8003,x
inx
inx
inx
inx
phx



ldx #$00
ldy #$00

-;
lda wave,x
inx
phx
ldx {scale_factor}
-;
iny
sta ({address}),y
dex
cpy #$08
bne +

dec {blocks_left}
beq ++
pha

ldy #$00
lda #$82
sta ({address}),y
lda #$09
adw {address}
stw {address}
ldy #$00

pla

+;

cpx #$00
bne -
plx
bra --




+;
plx
plx
ldy #$00
lda #$83
sta ({address}),y
lda #$09
adw {address}
stw {address}

asl {scale_factor}
lda {scale_factor}
cmp #$80
bne sample_scaling_loop