Quantcast
Channel: VBForums - Visual Basic 6 and Earlier
Viewing all articles
Browse latest Browse all 21192

Linear Feedback Shift Register

$
0
0
I'm a bit baffled, not to mention frustrated beyond comprehension and hopefully I can explain this right or I just once again created a dead thread noone can answer due to the advanced nature of what I'm about to write.

Theres a type of randomness out there called a Linear Feedback Shift Register, or for short, LFSR. A LFSR is a shift register whose input bit is a linear function of its previous state. Basically it works at a binary level. With that said, the most commonly used linear function of single bits of the LFSR is an XOR. The XOR gate of the LFSR shifts the bits either left or right. Just to give you an idea, take a look at this image of a 4 bit LFSR


And you can read more up on it through wikipedia HERE

I actually need this because I wrote an NES Emulator in VB6, which you can find in my signature. The Nintendo Entertainment System used this LFSR in one of their sound channels called Noise. The Noise sound channel is used in things such as percussion, explosions, bricks breaking, someone being hit, etc. However, this monstrosity uses a 15 bit size LFSR numbered from bit 14 to bit 0. Although I implemented it, it only half works. And I have no idea why. Some games it sounds great such as Double Dragon, but games like Super Mario Bros, I hear only half the percussion, and don't hear the bricks breaking. Just a thump. So it all boils down to only half the LFSR working. And mods, don't move this to the Games and Graphics section as it is regarding a programming problem. Just hear me out. The NES does Noise through 3 8-bit registers in memory which are (in Hex) $400C, $400E, and $400F. $400D is not used. Noise goes through a pseudo-random bit sequence and has 2 modes. The modes are determined by Bit 7 of register $400E which can be either 0 or 1, shown here:

Bits
7 6 5 4 3 2 1 0
M - - - - - - -

Where M is Mode. If its 0, the Noise is 32767 steps long. If its 1, then Noise is only 93 steps long. However, the particular 93-step sequence depends on where in the 32767-step sequence the shift register was when Mode flag was set. I personally have a feeling that one of my modes are not being executed. Probably the 32767 step sequence. Now before this sequence can be produced, it must go through a series of rules, which are:

Code:

The shift register is 15 bits wide, with bits numbered
14 - 13 - 12 - 11 - 10 - 9 - 8 - 7 - 6 - 5 - 4 - 3 - 2 - 1 - 0
When the timer clocks the shift register, the following actions occur in order:

    1. Feedback is calculated as the exclusive-OR of bit 0 and one other bit: bit 6 if Mode flag is set, otherwise bit 1.
    2. The shift register is shifted right by one bit.
    3. Bit 14, the leftmost bit, is set to the feedback calculated earlier.

You can find all the information on this here:
http://wiki.nesdev.com/w/index.php/APU_Noise

as well as even more information on it through a few of the links I put up in one of my posts in my NES Emulator thread. The code I used to execute this is here, with a lot of comments:

vb Code:
  1. Public Function Noise_Channel_Render_Sample() As Long
  2.    
  3.     Dim Bit0 As Long
  4.     Dim Bit1 As Long
  5.     Dim Bit6 As Long
  6.    
  7.         'if (Noise.datatype)
  8.         '    Noise.CurD = (Noise.CurD << 1) | (((Noise.CurD >> 14) ^ (Noise.CurD >> 8)) & 0x1);
  9.         'else    Noise.CurD = (Noise.CurD << 1) | (((Noise.CurD >> 14) ^ (Noise.CurD >> 13)) & 0x1);
  10.    
  11.     With Noise_Channel
  12.         If .Length_Counter > 0 And .Enabled Then
  13.             '.SampleCount = Within_Range(.SampleCount + 1, 0, LONG_RANGE) 'causes minor slowdown
  14.             .SampleCount = .SampleCount + 1
  15.             If .SampleCount >= .RenderedWavelength Then
  16.                 .SampleCount = .SampleCount - .RenderedWavelength
  17.                 If .Noise_Random_Generator_Mode = True Then '93 bits long
  18.                     'According to [url]http://wiki.nesdev.com/w/index.php/APU_Noise[/url]
  19.                    
  20.                     'The shift register is 15 bits wide, with bits numbered
  21.                     '14 - 13 - 12 - 11 - 10 - 9 - 8 - 7 - 6 - 5 - 4 - 3 - 2 - 1 - 0
  22.                    
  23.                     'Step 1) Feedback is calculated as the exclusive-OR of bit 0 and one other bit: bit 6 if Mode flag is set, otherwise bit 1.
  24.                     '        Note: Exclusive Or is Xor, not Or! Or is Inclusive.
  25.                         Bit0 = (.NoiseShiftData) \ Power_Of_2(14) 'Right Shifts it to bit 0 by right shifting 14 bits (see shift register table above)
  26.                         Bit6 = (.NoiseShiftData) \ Power_Of_2(8) 'Right Shifts it to bit 6 by right shifting 8 bits (see shift register table above)
  27.                         .Noise_Feedback = (Bit0 Xor Bit6)
  28.                 Else '32767 bits long
  29.                     'According to [url]http://wiki.nesdev.com/w/index.php/APU_Noise[/url]
  30.                    
  31.                     'The shift register is 15 bits wide, with bits numbered
  32.                     '14 - 13 - 12 - 11 - 10 - 9 - 8 - 7 - 6 - 5 - 4 - 3 - 2 - 1 - 0
  33.                    
  34.                     'Step 1) Feedback is calculated as the exclusive-OR of bit 0 and one other bit: bit 6 if Mode flag is set, otherwise bit 1.
  35.                     '        Note: Exclusive Or is Xor, not Or! Or is Inclusive.
  36.                         Bit0 = (.NoiseShiftData) \ Power_Of_2(14) 'Right Shifts it to bit 0 by right shifting 14 bits (see shift register table above)
  37.                         Bit1 = (.NoiseShiftData) \ Power_Of_2(13) 'Right Shifts it to bit 1 by right shifting 13 bits (see shift register table above)
  38.                         .Noise_Feedback = (Bit0 Xor Bit1)
  39.                 End If
  40.                
  41.                 'Step 2) The shift register is shifted right by one bit.
  42.                     .NoiseShiftData = .NoiseShiftData * 2
  43.                 'Step 3) Bit 14, the leftmost bit, is "set" to the feedback calculated earlier.
  44.                 '        Note: You set it using the Or operator, not the And operator like you would see in most emulators' source code
  45.                     '.Noise_Feedback = .Noise_Feedback Or BIT_14
  46.                 'Then the Noise shift gets updated and prepared to be outputed for sound.
  47.                     .NoiseShiftData = .NoiseShiftData Or (.Noise_Feedback And &H1&)
  48.             End If
  49.            
  50.             If .Envelope_Decay_Disable Then
  51.                 Noise_Channel_Render_Sample = ((.NoiseShiftData And &H1&) * &H40&) * .Volume
  52.                 Exit Function
  53.             Else
  54.                 Noise_Channel_Render_Sample = ((.NoiseShiftData And &H1&) * &H40&) * .Envelope
  55.                 Exit Function
  56.             End If
  57.         Else
  58.             .Volume = 0
  59.         End If
  60.         Noise_Channel_Render_Sample = 0
  61.         Exit Function
  62.     End With
  63. End Function

Seems like my code is consistent with the documentation thus far, unless I missed something. But here is another thing I noticed. The NesDev site also mentioned the shift register is 15 bits wide. However in my sound debugger of my emulator, Im seeing the shift register numbers far exceed that in the millions range randomly in either positive or negative. If you do the math, 15 bits is $8000 in hex, or in other words, 32768 in decimal. Im not sure if I should keep the shift register within the range of 32767 as I didn't ever find any other open source emulator do this. So through all this advanced crap thats probably making all of you scratch your heads and be like "huh?" :ehh:, my 2 problems are basically:

1. Only one of the modes are being heard, especially in super mario bros. Why is this? Could there be a bug in my code I overlooked in that function?

2. I'm not so sure if I should keep the LFSR within the range of 32767 (15 bits) as it really isnt done in any other emulator.

Hopefully I did the LFSR right. I given all the information I could at the moment as its super late but if anyone has any questions, let me know, or if any of you all have some bright ideas on how to properly do it, I would appreciate it. Thanks in advance. (Crosses my fingers)

Viewing all articles
Browse latest Browse all 21192

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>