Nes_Snd_Emu-0.1.7 noise, test_apu_timers attn: blargg

Discuss emulation of the Nintendo Entertainment System and Famicom.

Moderator: Moderators

Post Reply
mattmatteh
Posts: 345
Joined: Fri Jul 29, 2005 3:40 pm
Location: near chicago
Contact:

Nes_Snd_Emu-0.1.7 noise, test_apu_timers attn: blargg

Post by mattmatteh » Fri Mar 13, 2009 1:32 pm

i was testing out the noise channel on my emulator using blarggs test_apu_timers/noise_pitch.nes test. the timer is right, all changes are at multiples of 0.00228 sec ( freq 15, look up table is 4068). the first few pulses are the same as test_apu_timers/noise_pitch.nes, but then its different like my shifter is not right.

then i looked at Nes_Snd_Emu-0.1.7/nes_apu/Nes_Oscs.cpp to see if i missed something with the shifter. blargg, if i read the code right ..

silenced:

Code: Select all

// approximate noise cycling while muted, by shuffling up noise register
// to do: precise muted noise cycling?
if ( !(regs [2] & mode_flag) )
{
     int feedback = (noise << 13) ^ (noise << 14);
     noise = (feedback & 0x4000) | (noise >> 1);
}
not silenced

Code: Select all

const int tap = (regs [2] & mode_flag ? 8 : 13);

do
{
     int feedback = (noise << tap) ^ (noise << 14);
     time += period;

     if ( (noise + 1) & 2 ) {
          // bits 0 and 1 of noise differ
          delta = -delta;
          synth.offset_resampled( rtime, delta, output );
     }

     rtime += rperiod;
     noise = (feedback & 0x4000) | (noise >> 1);
     }
while ( time < end_time );
if i am reading this right, you dont use the loop flag to determine the bit used, variable tap, when noise is silenced. i thought the timer would always clock the shift register, and the loop flag would always determine which bit is used.

above is the comment that says approximate. seems that it would be just as easy to do the same noise shifting for silenced or not silenced.

blargg, could you explain what you mean with "to do: precise muted noise cycling?"

if the noise pattern is 32767 bits long, then i should see that pattern in the wave, i tried to see if i could line up my output with the timer test, but found no match when shifted in time.

matt

User avatar
blargg
Posts: 3715
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

Post by blargg » Fri Mar 13, 2009 2:00 pm

That code doesn't precisely emulate the noise shift register when it's not making any sound. When it's running at maximum rate, it can take quite a bit of processing time. If you want full accuracy, ignore that optimization and do whatever the main loop does.

User avatar
blargg
Posts: 3715
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

Post by blargg » Wed Apr 01, 2009 5:21 am

By the way, I just wrote a function which quickly clocks the noise LFSR any number of times. At its heart, it uses algorithms which calculate the equivalent of shifting the LFSR many times in a row, found using an automated LFSR-analyzing program. For example, n ^= (n >> 3) ^ ((n & 0xE) << 11) ^ ((n & 0x7) << 12) is equivalent to executing n = ((n << 13) ^ (n << 14)) & 0x4000 | (n >> 1) repeatedly 255 times in a row.

Code: Select all

/* Clocks NES noise LFSR 'n' count times and returns new LFSR contents. */
int clock_lfsr( int n, int mode, int count )
{
    if ( mode )
    {
        count %= 93;
        
        for ( ; count >= 9; count -= 9 )
            n = (n >> 9) ^
                (n & 0x7FC0) ^
                ((n & 0x1FF) << 6);
        
        while ( --count >= 0 )
            n = ((n << 8) ^ (n << 14)) & 0x4000 | (n >> 1);
    }
    else
    {
        count %= 32767;
        
        for ( ; count >= 255; count -= 255 )
            n ^= (n >> 3) ^
                 ((n & 0xE) << 11) ^
                 ((n & 0x7) << 12);
        
        for ( ; count >= 15; count -= 15 )
            n ^= (n >> 1) ^
                 ((n & 0x2) << 13) ^
                 ((n & 0x1) << 14);
        
        while ( --count >= 0 )
            n = ((n << 13) ^ (n << 14)) & 0x4000 | (n >> 1);
    }
    
    return n;
}

User avatar
hap
Posts: 355
Joined: Thu Mar 24, 2005 3:17 pm
Contact:

Post by hap » Wed Apr 01, 2009 2:03 pm

not-completely-off-topic: any candidates for n = ((n << 13) ^ (n << 16)) & 0x10000 | (n >> 1) ? (AY8910 noise LFSR)
Which program did you use?

User avatar
blargg
Posts: 3715
Joined: Mon Sep 27, 2004 8:33 am
Location: Central Texas, USA
Contact:

Post by blargg » Thu Apr 02, 2009 7:44 pm

Here's the program (very simple C affair): iterated_lfsr.zip

Here are a couple of equivalent expressions for that AY sound chip LFSR. Do you need really high iteration counts, like in the thousands?
n = ((n << 13) ^ (n << 16)) & 0x10000 | (n >> 1); // 1 iter
n = n ^ (n >> 3) ^ ((n & 0x38) << 11) ^ ((n & 0x7) << 14); // 17 iter
n = n ^ (n >> 11) ^ (n >> 8) ^ ((n & 0x3FF8) << 3) ^ ((n & 0x7) << 6) ^ ((n & 0xFF) << 9); // 266 iter

User avatar
hap
Posts: 355
Joined: Thu Mar 24, 2005 3:17 pm
Contact:

Post by hap » Fri Apr 03, 2009 4:59 am

Thanks, this is a pretty smart optimization for when noise is not in use. :)
In the thousands: I don't think that's needed.

Post Reply