C64 LFSR Noise

Hi, im trying to emulate the LFSR Noise from the Commodore 64.
This websites have been helpful:
//base:noise_waveform [Codebase64 wiki]
//SID reference
Also read about what is an LFSR and I think I understood.
I came up with this but it does not sound quite right, am I missing something?
It should sound like this: https://www.youtube.com/watch?v=XKBy974e7uk

(~lfsrC64={|seed = #[]|
var decimal, register, numeroBits, xor, waveform, binary;

	register = seed;
	bitNumber = seed.size;

	waveform = (2**bitNumber-1).asInteger.collect{ //max lfsr cycle is 2**bitNumber-1 wide

	if (register[0] != register[5], {xor = 1},{xor = 0}); //xor beetween bits 0 and 5
	register = register.rotate(1); //rotate to the right
	register = register.put(0, xor); //replace the first bit

		
	//8bit waveform only gets bits 2 4 8 11 13 17 20 22
		binary = [register[2], register[4], register[8], register[11], register[13], register[17], register[20], register[22]];
		
		decimal = 8.collect{ |i| 2**((8)-i-1) * binary[i]}; //8bit waveform from binary to decimal
	decimal = decimal.sum.asInteger;
	};

	waveform
})

~lfsrC64.value(Array.fill(23, {rrand(0,1)}))

b = Buffer.sendCollection(s, ~lfsrC64.value(Array.fill(23, {rrand(0,1)}))/255, 1);

(
SynthDef(\lfsrC64, { |bufnum, amp = 0.1, freq = 2000|
	var phase, sig;
	phase = Phasor.ar(0, freq * SampleDur.ir, 0, BufFrames.kr(bufnum));
	sig = BufRd.ar(1, bufnum, phase, interpolation: 1);
	Out.ar(0, sig*amp !2)
}
).add)

Synth(\lfsrC64, [\freq, 1000])

Please feel free to roast my code, I know is pretty bad. tysm
Edit: also I’m aware of this post but i cannot understand the code: LFSR Noise Generator.
And please ask me anything that is confusing about my code.

1 Like

Hey Rick,

The post you linked to is an old one – the beginning of my forays into exactly what you’re working on. I’ve actually since implemented the general design of the LFSR as in the NES and GameBoy as a UGen. It’ll get you close, but it’s not the same as the Commodore. I could/would be happy to make a new one that is more aligned with what you’re asking about and package them together.

Here’s the UGen. Let me know if you need help installing it.

The difference is the tap points. It looks like the Commodore is a 23 bit maximum length LFSR, but I haven’t verified that.

Happy to explain any of this here or through DM. It’s one of my favorite topics :nerd_face:

Hi! I wasnt able to build these ugens in my windows machine, ill try in linux tomorrow.
I agree, the LFSR from the GB/NES is pretty similar, I have that already working with pretty much the same code. I’ll give it some thought and i’ll try your ugens! tysm, expect a dm soon :slight_smile:

1 Like

Can you make a pull request?

this is the solution i found:

(~lfsrc64 = { |bits = 23, seed = 1, taps = #[0, 4]|
    var register, xor, number, output;
    number = seed;
    output = [];
    register = ((2**bits) - 1).asInteger.collect {
	xor = ((number >> taps[0]) & 1).bitXor((number >> taps[1]) & 1);
        number = (number >> 1) | (xor << (bits - 1)); 
        output = output.add( 
            [((number >> 20) & 1) * 2**7,
             ((number >> 18) & 1) * 2**6,
             ((number >> 14) & 1) * 2**5,
             ((number >> 11) & 1) * 2**4,
             ((number >> 9) & 1) * 2**3,
             ((number >> 5) & 1) * 2**2,
             ((number >> 2) & 1) * 2**1,
             ((number >> 0) & 1) * 2**0].sum);
        number.asInteger
    };
    register = register.as(OrderedIdentitySet).as(Array); 
	output.takeThese{|item, index| index >= register.size} / 255
})

not perfect but nicer, it takes a lot to evaluate the function.
@mjsyts in my issue i wasn’t really suggesting to add the signal to a buffer.
your ugen is nice but can output 1bit noise only, and it would be nice if it could output 8bit noise or whatever bit noise. tysm for your time!