FIR Filter
A FIR Filter (Finite impulse response filter) is a type of filter used on signal processing. It works by taking the sum of last Nth samples multiplied by a value, called FIR taps. It's finite because if you pass a FIR filter in an impulse response, the impulse will fade out after passing though the N taps. That's easy to notice since the FIR filter never uses itself as feed unlike the IIR Filter.
On the SNES, the FIR filter has 8 taps which are 1.7 fixed point values. The filter is applied on the echo output so it has direct influence to the sound output and can be used to archive different effects which is more detailed on the following topics.
Mathematical Definition
The FIR filter can be defined in the following mathematical formula:
For the current output sample Y[n], take the sum of previous N samples from source (including current), multiplied by the FIR coefficient, which is:
The SNES has eight FIR taps, which limits N to 8:
However, the samples are processed from the oldest to the newest sample. That means for the first FIR tap is applied to the oldest sample while the 8th tap is applied to the newest sample:
Which in other words, it yields to the equivalent pseudo-code:
y[n] = FIR[0] * x[n - 7] + FIR[1] * x[n - 6] + FIR[2] * x[n - 5] + FIR[3] * x[n - 4] + FIR[4] * x[n - 3] + FIR[5] * x[n - 2] + FIR[6] * x[n - 1] + FIR[7] * x[n - 0];
Where FIR is a array containing the eight taps.
S-DSP Implementation
Because the S-DSP doesn't have floating point capability, the tap values are actually in the 1.7 fixed point, signed format. This means that values between $00-$7F is positive (0 to 127) and $80-$FF is negative (-128 to -1) and after doing the multiplication the value then is divided by 128.
In addition, the tap sum is done on a 16-bit integer type, which means that if an overflow occur the value gets clipped. The only exception for this is the last multiplication (last FIR tap multiplied by the first sample). For this case, the number gets clamped instead of clipped, e.g.: 18623 + 16888 will yield to 32767 instead of overflowing to -30025.
An accurate implementation of the FIR filter using the above rules would be:
S = (FIR[0] * x[n - 7] >> 6) + (FIR[1] * x[n - 6] >> 6) + (FIR[2] * x[n - 5] >> 6) + (FIR[3] * x[n - 4] >> 6) + (FIR[4] * x[n - 3] >> 6) + (FIR[5] * x[n - 2] >> 6) + (FIR[6] * x[n - 1] >> 6);
The ">>" operator is the arithmetic right shift operation, which on this context is the equivalent by dividing the value by 128 (without decimal places).
With the first 7 taps calculated, we clip it so it's always within the -32768 to 32767 range:
S = S & 0xFFFF;
Now we add the last tap which is multiplied by the current sample, x[n]:
S = S + (FIR[0] * x[n] >> 6);
clamp it to the -32768 to 32767:
S = S > 32767 ? 32767 : S; S = S < -32768 ? -32768 : S;
It's important to remember that the Echo buffer uses 15-bit samples instead of 16-bit and it's left-aligned, so the binary format is: "seee eeee eeee eee0" and not "ssee eeee eeee eeee". However, when the sample is placed on the FIR array, it end ups right shifted so it gets to the "ssee eeee eeee eeee" format.
So we finally take the last bit and we have our FIR value done:
FIR = S & 0xFFFE;
Each sound channel (left and right) is processed separately.
Because of the integer clipping behavior on the first seven taps, it's important to your FIR filter DC gain never exceed 0 dB (or the absolute sum of all FIR taps never exceed 128) for avoiding audio clicks, specially with the first seven taps. Not all games obey that, so the most important is checking out the frequency response of the filter and checking how the gain behaves for the frequency range.
Once done, the FIR is multiplied by the L/R echo volume and it's output together the main volume. It's also multiplied by the echo feedback value and fed back to the echo buffer together the sound output.
External links
- Romhacking.net - Documents - Anomie's S-DSP Doc
- Fullsnes - Nocash SNES Specs
- Design of FIR Filters - Dr. Elena Punskaya
- What is FIR Filter? - FIR Filters for Digital Signal Processing
- ECE 2610 Signal and Systems - FIR Filters
- FIR Digital Filter Design | Spectral Audio Signal Processing
- FIR filter FAQ - dspGuru
- The relationship between decibels, volume and power - sengpielaudio