APU Noise Channel

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
APU Noise Channel
by on (#59378)
Alright, so. I've been trying to fix the noise channel in my emulator, and almost every emulator source I try to use as a reference disagree with one another.
And none of them seem to work properly in my emulator.
The sound generated from this channel is like nails on a chalk board, and is ultra random (sometimes it crackles your speakers so much, it sounds like they are going to explode, other times it's dead silent when it should be generating sound).

http://www.filesend.net/download.php?f=395eabbb7bcb572ec5fb1644d4ef0a84

There is a link to the recorded sound (Mega Man 3 intro, wooo). I can supply code as well, if need be.

EDIT: Forgot my question, lol. To start, which documents should I be using?

by on (#59518)
Ok, got the channel working properly (I think). Noise used in music sounds fine now, but sound effects are a different question :S

Sound effects now sound like a high-frequency screech. Any idea what would cause this? I'm not using DC blocking or any other filtering, could that be the cause?

by on (#59519)
Welcome to the forums, I can't really help you there except for just read up online on some peoples homemade APU documents, or just wait for the other members to come on XD

by on (#59525)
You are simulating the shift register and XOR operators to get proper NES noise, right? NES noise channel outputs either 0 or the channel's amplitude. It looks like a square wave with a random period.

Sounds like you are overflowing something into the negatives.

by on (#59528)
Here is how I'm manipulating the Shift Register, etc.

Code:
int bit0 = (this.shiftRegister & 0x4000) >> 14;
int bit1 = (this.shiftRegister & this.xor_tap) != 0 ? 1 : 0;

this.shiftRegister |= (bit0 ^ bit1);
this.shiftRegister <<= 1;


Code:
noiseMode = (data & 0x80) != 0;
xor_tap = (noiseMode) ? 0x100 : 0x2000;


It looks nothing like what the wiki describes (it's reversed bits, actually), but this is the only way it sounds proper. And it only sounds proper when used for music (intro sequences, etc).

by on (#59529)
I'm not sure why you're reversing things. Anyway, your code inserts the new bit at the wrong time. You should do the shift before ORing the feedback in, not after.

BTW, here's a tested direct translation of the Wiki page to C:
Code:
int other_bit = loop ? 6 : 1;
int feedback = (n & 1) ^ (n >> other_bit & 1);
n = n >> 1;
n = n | (feedback << 14);

by on (#59536)
Thanks blargg! :D Another question I have about the noise channel is the frequency calculation.

This is what the no$ docs say about it:

Code:
400Eh - APU Frequency Channel 4 (Noise)

  0-3     Noise frequency, F=1.79MHz/2/(N+1)


Is this accurate? I think some of my noise problems could be an invalid frequency.

by on (#59537)
GBATEK is almost the bible for GBA and DS, but his EveryNES isn't always easy to understand. In this case, the frequency written to the noise channel is not used directly. Instead, it's an index into a lookup table:
Quote:
002,004,008,010,020,030,040,050,065,07F,0BE,0FE,17D,1FC,3F9,7F2

The CPU clock is divided by two times the value from this LUT.

by on (#59538)
Like this?

Code:
public override void SetRegister3(byte data)
{
    noiseMode = (data & 0x80) != 0;

    if (this.Nes.RegionFormat == NesRegionFormat.Ntsc)
    {
        this.FrequencyTimer = NoiLut[0][data & 0x0F] * 2;
    }
    else
    {
        this.FrequencyTimer = NoiLut[1][data & 0x0F] * 2;
    }

    this.UpdateFrequency();
}


I'm still getting this weird effect in my noise channel, would actually hearing it do anything to diagnose the problem?

by on (#59541)
- It may not be a matter of how you're generating signed/unsigned samples, but the way you're resample it and the amount of samples. In other words, AFAIK, you should generate the samples at same rate of the NES, or 1 sample per CPU cycle; and do some resampling method.