It’s been around ten years since I developed the original Druid NOISE 1B chip to produce good quality white noise. Finally it gets an update, and the new NOISE2 chip can produce pink noise as well as white noise, so there’s no need for external “pinking” filters.
Here’s what it sounds like, white noise and pink noise:
Here’s the spectrums for the two outputs. Note the scales on these two graphs are different, so you can’t compare one to the other directly…sorry!
The White noise output is flat to within 2 or 3dB over the audio range.
The Pink Noise follows the theoretical 3dB/octave slope over the audio range, and beyond, although we can’t see that here. The sharp dropoff above 20KHz and below 50Hz is due to the limitations of my digital recording setup. The unit has steep antialiasing filters at 20KHz.
So how did this come about?
Adding pink noise generation to my chip was suggested by Richie Burnett, who I know from the SynthDIY list. He suggested the “VossMcCartney algorithm” as the best method of doing it. I hadn’t heard of this, so I went off to research it.
The VossMcCartney Pink Noise Algorithm
The algorithm was first proposed in a 1978 paper by Voss and Clarke, and then became well known after being featured in a Martin Gardner column in Scientific American. The basic idea of the algorithm is to generate a pink noise sample by adding together lots of white noise generators that have been sampled at different rates. In the Voss algorithm, each generator is sampled at half the rate of the last one.
The topic and the algorithm came up in a discussion on the musicdsp mailing list in August and September 1999, and several further refinements were added. The major one was James McCartney pointing out that by shifting the update times of the different generators, only one would need to be updated each sample. This evens out the computational load of the algorithm and makes it much more practical. It does throw up one interesting question though, which is how we efficiently generate the treelike structure that is required to determine which output should be updated.
A further refinement is to add a white noise source at the full sample rate. This helps “fill in” some of the nulls in the frequency response and smooths the performance somewhat.
How good is the VossMcCartney algorithm?
A theoretical pink noise source produces noise down to 0Hz and up to infinity (although exponentially decreasing), so the first thing to say is that any *actual* noise source, white or pink, is designed for a given frequency range and to given degree of accuracy. For musical purposes, we’re looking at the audio range from 20Hz to 20KHz, and while we might want our white noise to be reasonably flat across that range and our pink noise to be reasonably even, we’re not going to worry about a few decibels here or there. This is not a piece of test equipment, and having a superhighaccuracy pink noise source won’t make your synth sound better. It’s more important that it sounds good and is useful for music.
With that said, let’s have a look at the response of the VossMcCartney algorithm. Allen Herriman points out that one way to think about the algorithm is that it is a white noise source being sampled by a sampleandhold.
This gives us a way of getting a grip on the frequency response. The samplingandholding process gives a frequency response of (sin(x) / x). We can plot this response for the different octaves and see how they add together. Here’s an example at a sample rate X:
Halving the sample rate squashes the spectrum to the left. This is significant because this squashing means more of the lumpy part on the right moves down into the region we’re interested in. Here’s what happens when we reduce the sample rate to X/2:
As we move down the octaves, more of the noise power gets pushed lower and lower, but more little lumps get introduced in the higher frequencies. This is the next octave down, with a sample rate of X/4:
If we keep adding lower and lower octaves, we can build up our pink noise response. On this graph, the theoretical slope is shown in magenta, and the final response is shown in blue. This theoretical result matches our actual response shown at the top of the page rather well. The magenta vertical line is at 25KHz, the highest audio frequency we care about. The final result is basically within +/2dB of the theoretical slope, apart from at the very highest audio frequencies, where it starts to droop a little bit by 4db or so.
It’s clear that the response is still a bit “lumpy”. Unfortunately, adding more generators doesn’t help. The lumps happen because the generator’s sample rates are all related in neat octaves. We can avoid the lumps by setting up the generators at nonmultiple sample rates. This works, but generating several primenumber sample rates is a computational nightmare. Alternatively, we could randomise the output sample rates a bit, or a lot, even. This is the basis of Larry Trammell’s Stochastic VossMcCartney Algorithm, which I’m not going to describe here because it’s beyond what we can realistically manage, or what we realistically need. There’s a link for it in the references at the bottom, and it’s definitely worth a read.
Are there alternative approaches?
The other obvious way to generate pink noise is to copy the analog approach of filtering white noise, but to do it digitally. This can provide a very accurate pink noise response if you have a filter with enough poles and zeros. Unfortunately, there is no way a PIC is going to be able to calculate such a filter at the kind of rates necessary. This is a nonstarter.
There’s another method presented by Stefan Stenzel of Waldorf Music, but again, although his method is clever and efficient on an ASIC, it’s not suitable for a lowend processor.
Can VossMcCartney be done on a PIC?
Ok, so we’ve established that the algorithm produces decent, if not perfect, quality pink noise. The next question is “is it practical on a PIC processor?” This is not simple to work out ahead of time, but we can do some backoftheenvelope calculations to see if it’s “easy”, “close”, or “no chance”. Let’s assume we want a 100KHz output sample rate. This gives us theoretical bandwidth out to 50KHz, which should be more than enough to keep any weirdness at the high end away from the part we care about. We’re going to need a fast processor, so I started by looking at the 16F18313 that I used for the StompLFO project since it can run with a 32MHz internal clock, giving a 8MHz instruction rate. This enables us to work out how many instructions we have available per sample: 8MHz/100KHz = 80 instructions. Ouch. That’s a few, but it’s not many, and this algorithm might eat them up pretty fast. So this definitely gets filed under “Going to be close”!
Breaking the algorithm down a bit, there are various stages:

 Update the LFSRs
 Update one of the outputs
 Add a constant white noise source
 Add up the various outputs
 Send the result to the outside world
Simple, right?! Let’s see.
Updating the LFSRs
Firstly, it’s worth pointing out that we only need two LFSRs, despite having a lot of generators. That’s because by using the McCartney trick of shifting the updates, we only ever update one octave generator and one white noise sample each time.
The code for our two LFSRs looks like this:
; Update the two LFSRs ; ; 31bit LFSR with taps at 31 and 28 ; ; This is our white noise source, and is also the fixed white ; noise element of the pink noise source. swapf LFSR1_4, W ; Get tap 28 movwf TEMP rlf LFSR1_4, W ; Get tap 31 xorwf TEMP, F ; Shift the XORd bit into carry rlf TEMP, F ; Shift the register rlf LFSR1_1, F rlf LFSR1_2, F rlf LFSR1_3, F rlf LFSR1_4, F ; 21bit LFSR with taps at 21 and 19 ; ; This is used for the lower octaves rrf LFSR2_3, W ; Get tap 19 movwf TEMP rrf TEMP, F swapf LFSR2_3, W ; Get tap 21 xorwf TEMP, F ; Shift the XORd bit into carry rrf TEMP, F ; Shift the register rlf LFSR2_1, F rlf LFSR2_2, F rlf LFSR2_3, F
Updating one of the outputs
The next problem is how to work out which one of the shifted outputs we should update. How do we generate that interesting treelike structure?
Simple! We don’t! Whenever I see anything vaguely complicated, I go running for a lookup table, and this is no different.
; Update one of the LFSRs ; ; First, we need to know which one we're updating SelectOutput: ; Update the tree structure counter movlw D'1' addwf COUNT_LO, f movlw D'0' addwfc COUNT_HI, f ; Find out which output we need to update movf COUNT_LO, w call TreeTable ; Update the correct output brw goto Octave0 ; Updated every 2nd sample goto Octave1 ; Updated every 4th sample goto Octave2 ; Updated every 8th sample goto Octave3 ; etc.. goto Octave4 goto Octave5 goto Octave6 goto Octave7 goto Octaves8to13 ; These only come around every 256th sample Octave0: ; We assume the bit is cleared, and then set it if neccessary bcf OUTPUT_LO, 0 btfsc LFSR2_2, 0 ; Doesn't really matter which LFSR bit we use bsf OUTPUT_LO, 0 ; The other outputs are done in exactly the same way goto Octaves8to13Compensation Octave1: bcf OUTPUT_LO, 1 btfsc LFSR2_2, 0 bsf OUTPUT_LO, 1 goto Octaves8to13Compensation
You can guess what Octave2 to Octave7 look like. If you can’t, check the entire code. The Octaves8to13 routine repeats what’s above, but only gets called once every 256 samples, so it provides all the lower octaves. The fact that there’s a variable length here (Octaves 0 to 7 only do one set of branching, where Octaves 8 to 13 do two) explains the need for the Octaves8to13Compensation routine, which is just a bunch of NOP (“No Operation”) instructions to keep the two paths the same length in terms of instruction cycles.
Add the constant white noise
This is simple. We just take the output from our white noise LFSR and stick it into a spare bit in the output bytes.
; Add white noise every sample to fill in the nulls ; AddWhiteNoise: ; This uses the other LFSR, but is otherwise identical bcf OUTPUT_HI, 6 btfsc LFSR1_4, 0 bsf OUTPUT_HI, 6
Add up the various outputs
Ok, so we’ve got two bytes, OUTPUT_LO and OUTPUT_HI, containing the values of our random generators. We need to add up the output of all the generators and send it to the DAC. This is a basic “bit counting” task. I’ve organised things so that there are a maximum of 15 bits (14 octave generators and the constant white noise generator).
Again, the quickest way is a lookup table. We can use each byte as the index into a table which tells us how many bits are set in that number. We do this twice for the OUTPUT_LO and the OUTPUT_HI and add them together.
; Add up how many of the outputs are set ; ; We do this with an 8bit lookup to save actual adding AddUpBits: ; Add up the number of bits from Octaves 07 movf OUTPUT_LO, w call NumOfBitsSet movwf TEMP ; Store it in TEMP ; Add up the number of bits from Octaves 815 movf OUTPUT_HI, w call NumOfBitsSet addwf TEMP, f ; Add the number in TEMP to get the total ; We have the total number of bits in TEMP
Send the result to the outside world
This is simple too. We just copy the TEMP value we just generated into the DAC output register. It’s a 5bit DAC, so we shift it over one bit first to use the most significant bits not the least significant.
OutputToDAC: lslf TEMP, w ; Shift up to 030 range movwf DACCON1
The entire thing runs in very close to the 80 instructions we were aiming at, so we basically get our 100KHz sample rate. We can output the white noise source to a pin too, and then we have a chip which provides both white and pink noise outputs on a single 8pin chip. Just add 5V. Actually, sometimes it’s not quite that simple. The pink noise DAC output can’t source much current, so if it’s not feeding a high impedance, it’ll need buffering. This is because the resistor string DAC used has a high output impedance (and one that depends on the value set, too).
Fantastic! I want white and pink noise!
Well, there’s the usual options for Druid chips – program your own, or we’ll have some in the shop in a few weeks.
 PIC 16F18313 assembly code NOISE2.ASM
 Compiled version of the above, ready to program NOISE2.HEX
 NOISE2 datasheet, including schematic diagram
The schematic diagram is very simple. I added simple RC rolloff at 25KHz just to turn the digital pulse white noise into something more analoglooking. It sounds just the same though, but it makes a difference if you’re modulating things with it. Both outputs have been given opamp buffers to protect them. As mentioned above, the Pink output cannot drive significant loads, so this buffer is a good idea. For the White output, it prevents subsequent circuits affecting the filter.
Credits and Feedback
Many thanks to Richie Burnett for bringing this algorithm to my attention in the first place, and for all the help via email, both on this project and others. It’s much appreciated, Richie.
Thanks also to Robin Whittle for his excellent page about the topic, which taught me a lot, and the other people mentioned in the references below, all of which I’ve found very useful and interesting.
Any mistakes spotted, feedback, or ideas for further development are always appreciated. Please get in touch.
References:
The original Voss and Clarke paper:
Voss, R. F., & Clarke, J. (1978). “1/f noise in music: Music from 1/f noise”. Journal of the Acoustical Society of America 63: 258–263.
Martin Gardner’s article:
Gardner, M. (1978). “Mathematical Games—White and brown music, fractal curves and oneoverf fluctuations”. Scientific American 238: 16–32.
Robin Whittle’s discussion of the history of the algorithm on the musicdip list:
http://www.firstpr.com.au/dsp/pinknoise/
Larry Trammell’s description of the development of his “Stochastic VossMcCartney Algorithm”:
http://www.ridgerattech.us/tech/pinkalg.htm
Stefan Stenzel’s “new shade of pink” algorithm on Github. You can also read his paper.
https://github.com/Stenzel/newshadeofpink
Jukka Seittenranta
Dear Sir´s
Please be so kind an inform us by @mail when You NOISE2 programmed generator chip is available in Your shop.
Tom Wiltshire
No problem, we’ll let you know. It should be available shortly.
ben
I’d be interested too!
ben
..as well as OneShot Event/LFO generator 🙂