Recently, there has been a great deal of progress towards accurate video filtering, especially now that Blargg's NTSC video filters have found their way into many emulators.
But what about audio? Most emulators just do a simple averaging of samples (if they even sample at the full NES CPU clock rate in the first place). A few others use Blipbuffer or other forms of band-limited synthesis. But the actual NES had a sound output somewhat more complex than this.
Kevin Horton has shown a diagram of the NES audio path (
http://www.tripoint.org/kevtris/nes/images/NESAudio.gif). I don't know enough about analog filtering to know what this does, but I seem to remember hearing it's some sort of lowpass filter. What would be ideal for NES sound emulation would be to write a filter (FIR-type?) that would reproduce the characteristics of this official circuitry as close as possible. Famicom extended sound channels open up a whole new can of worms; I have no idea what (if any) filtering would be used on those.
Has anyone attempted to "tune" sound emulation to sound like the real thing when taking the filter into account?
Analog filtering is a forced step when designing analog amplifier. However, those amplifiers are designed so that the filtering doesn't affect audio frequencies (20Hz to 20kHz) so it's nonsense to emulate this, actually the sound will be filtered anyway during the process from your PC soundcards to your amplifier and your speakers, so it's nonsense to emulate this.
Most famicom cards just pass the audio trough two pins, and other than this the sound shematic is the same (amplified before going to the cartridge, acording to the Family Computer Shematic on main NESdev page).
If I'm not wrong, thw own blargg has documented the NES output calculation for each channel, including that DMC/Triangle effect.
The pipeline is like this:
Channel digital values -> Nonlinear summation -> Band-pass filter -> RCA jack
Blargg documented the nonlinear summation. But has the band-pass filter been documented?
Yeah, it was pretty much the band-pass filter I was referring to. Blargg did a good job of documenting the mixing ratios, and obviously the amplification will be handled by the sound hardware. But there is almost certainly some kind of analog filter in the circuit that affects audible frequencies, and it would be nice if it could be accurately emulated.
In fact, emulating the analog filter might not even take any CPU time. Once we figure out the exact frequency response, we could pass it to
BlipBuffer and have it pre-equalize the transition samples.
Without extra equipment it's a bit hard to measure the frequency response of the post-APU circuitry, since a PC's digitizer has its own frequency response that gets in the way if you simply try to digitize the output. For the NTSC NES, there is some low-pass and high-pass, the latter clear when you try to play a low frequency square wave and get a pointy thing out instead. As tepples said, the low-pass can be emulated as a part of the synthesis kernel (treble_eq() in Blip_Buffer), and the high-pass can be done with a simple "leaky integrator":
out = out + (in [0] - in [-1])
out = out - (sum / 512)
The 512 sets how much high-pass filtering is done. 512 can be implemented with a right shift by 9 bits, so it's preferable to something not a power of 2. If you're using Blip_Buffer, you can set this with bass_freq().
blargg wrote:
Without extra equipment it's a bit hard to measure the frequency response of the post-APU circuitry, since a PC's digitizer has its own frequency response that gets in the way if you simply try to digitize the output.
You're right about the high-pass portion of the response (DC through 300 Hz), as common ADCs have built-in DC killing high-pass circuits. But doesn't a 24-bit 96 kHz prosumer external ADC have enough room to cover the interesting part of the low-pass portion of the response (4 kHz through 24 kHz)?
Quote:
The 512 sets how much high-pass filtering is done. 512 can be implemented with a right shift by 9 bits, so it's preferable to something not a power of 2. If you're using Blip_Buffer, you can set this with bass_freq().
Unless you change the second line to
out = out - (sum * cutoffValue / 65536)
This gives a bit less granularity in the cutoff frequency, as mul+shift is faster than div on most architectures.
blargg: <i>Without extra equipment it's a bit hard to measure the frequency response of the post-APU circuitry, since a PC's digitizer has its own frequency response that gets in the way if you simply try to digitize the output. </i>
Couldn't someone familiar with audio filtering figure it out from the circuitry itself (which Kevin traced)? Presumably the engineers who designed the output path had some way to translate resistor and cap values into filter cutoff points, and it should be possible to figure out what the filter does from this. Maybe there's even some kind of engineering/CAD software that is used to design analog filters.
As for BlipBuffer, isn't bandlimited synthesis for rectangle waves only, or does it also work with triangle/noise/DPCM?
Anyone familiar with SPICE or a derivative?
Can a NES owner confirm Kevtris' diagram? (disagrees with Electronix's schematic) Assuming it's correct, there's at least the obvious ~59Hz-23MHz(???) RC filter at the end.
Josh: All transitions on the NES are square steps.
Heh, I have used PCPICE one time at scool to trace out a filter. It was impressing. Now I don't have the programm instaled on my PC, and it's not freeware. I don't want to spend lots of hours at scool after courses to do this, unless I'd really be forced to.