Skip to content

Instantly share code, notes, and snippets.

@xavriley
Created February 11, 2016 09:44
Show Gist options
  • Save xavriley/b0fc5c7989b2f0b4c353 to your computer and use it in GitHub Desktop.
Save xavriley/b0fc5c7989b2f0b4c353 to your computer and use it in GitHub Desktop.
Emulating the 2A03 NES sound chip in SuperCollider

These are just proof of concept at the moment. All taken from the following sources:

Credits for Nescaline to:

* Copyright (c) 2014 Vesa Kivimäki
* Copyright (c) 2004-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>

You can try out/compare with Nescaline by downloading LMMS from https://lmms.io

Pulse

Easy - Pulse.ar with widths of 0.125, 0.25 or 0.5

Triangle

This is a 5 bit (32 step) Triangle waveform. The best I could do was this:

{ OscN.ar([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0].linlin(0,15,-1,1).as(LocalBuf), 330) }.plot

Which gives this kind of thing

Noise

This was awkward. The algorithm for noise in Nescaline sounds pulsey, slightly pitched and filtered so as not to be too harsh. The thing is it all comes from a deterministic algorithm where you take 1 as a 16 bit int

00000001

get bit 8 (or 13 depending on mode) with it shifted left by one, xor with the original bit 14, shift the contents of that left by one and then cycle bit 14 to 0. I think.

You then take that number and use it as the source for the next noise cycle. It's similar to some techniques used in "Byte Beat".

Anyway the resulting sound is this characteristic pulsey noise. The reason this is hard to implement exactly in SuperCollider is the single sample feedback required to feed the results of the last step into the current one. I'm a beginner with SuperCollider effectively so I don't fancy writing a plugin at this stage (although it might be nice to try in future). For those reasons I've faked the noise with:

(
	{
	    var noise_freqs =[1.0,2.0,4.0,5.34,8.0,10.68,16.0,19.03,25.4,32.0,42.71,64.0,128.0,256.0,512.0,1024.0];
	    Decimator.ar(Latch.ar(LPF.ar(WhiteNoise.ar,3000), Impulse.ar(220*b[0])),44100,4) 
	 }.play
)

I'm Latching onto noise which is giving it that pulsey square quality and using the frequencies defined in the technical documentation (or close to) to get that slightly pitched quality. Finally the filter and the Decimator help to shape the sound to something fairly close to the original, although admittedly not as good.

@xavriley
Copy link
Author

xavriley commented Jun 7, 2021

Thanks for sharing! 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment