- Documentation Home
- GitHub Repository
- Dreamachine #1 : Background
- Dreamachine #3 : Progress
- Dreamachine #4 : Squeeze!
I’ve made quite a lot of progress with Dreamachine, more on that soon. I’m pausing to jot notes because of something I was just trying is quite interesting while implementing a DSP Pink Noise Generator.
As well as the flashing lights, I also want sound pulsing at the same frequency. White and pink noise seem likely to be the most inoffensive.
White noise is more or less just a stream of random values. A key feature is that it has equal intensity at all frequencies. A hiss.
Pink noise is similar, but has intensity inversely proportional to the frequency of the signal. In general it can be any 1/f^α, but typically around music synthesis it’s the 1/f people talk about. It’s more muted, softer. Very common in nature – think waterfalls. “An accessible introduction to the significance of pink noise is one given by Martin Gardner (1978) in his Scientific American column “Mathematical Games”. In this column, Gardner asked for the sense in which music imitates nature.”.
I’ve made one or two analog pink noise generators in the past. The usual way is to generate white noise and filter it. (It should be possible to generate pink noise directly from certain kinds of flicker noise, but I’ve never seen this done in practice).
Generating the white noise is easy, eg.
(The output of this is very low, have to amplify quite a bit).
However, there’s a snag in the filtering. Standard low pass analog filters have a response of -6dB/octave. Pink noise drops off at -3dB/octave. So typically a series of 2 or 3 leaky -6dB/octave filters are chained together to approximate the -3dB/octave. Even a very poor approximation is acceptable for music applications, the ear doesn’t care too much.
What I don’t think I’ve tried in the past is making a digital pink noise generator. The literature is very thin on the ground for this. As far as I can see, two main approaches have emerged. One is simply to follow the same method as the analog above, string together approximate filters. The other is to use the Voss-McCartney algorithm. This is kind-of derived from the Martin Gardner article, and mostly seems to be documented in scattered newsgroup posts. Here are some links that try to pull those together:
The algorithm is very nifty, basically involves merging sampled white noise with noise of half that sample rate, noise of quarter that rate, etc.
But has a flaw in that it produces big notches in the frequencies. A way to get over this is to randomise the resampling, leading to the Stochastic Voss-McCartney algorithm (see those links ^^^).
I’ve yet to integrate it properly, I’ve a timer interrupt issue. But was able to get it running.
Ok, here is white noise (green, lol), generated just using
rand() and pink (yellow) derived from that with the algorithm :
The white noise is clearly jumping around a lot, the pink less so.
In the frequency domain, here’s the white, averaged over a few seconds (I’d guess the scales are linear, Bitscope doesn’t make that very clear) :
The marker is at 40kHz, where I set the sample rate. I’m a little confused about that, here it appears to be the Nyquist frequency, Fs/2. I can’t immediately explain the rolloff either.
But here’s something I found interesting. The spectrum of the pink noise by comparison :
There is a little dip at 40kHz, but then the trajectory continues pretty much the same up into much higher frequencies. That puzzles me.
I’ll maybe come back to this once I’ve got this running with the rest of the code properly. It’s proving a bit tricky. Although you can trigger events from timer interrupts to generate waveforms on the ESP32, you can’t do the calculations inline, have to use a semaphore or similar. As well as the noise gen working this way, the light strobing is too. I’ve also got an interrupt triggered when a rotary encoder is moved and also a queue running between core 0 (UI) and core 1 (generators) of the ESP32. Concurrency hell!
PS. Concurrency heaven!
After writing that ^^^ I had a wash and found a clean shirt, Marinella due to pick me up for a coffee & go shopping. I had 15 mins to wait so I had another look at my code. Ha! Fool Danny. I had the queue between cores waiting a tick when receiving a message. Drop that to 0, the pink noise thread ran on time!
There are various little bits still to implement and a good bit of tidying to do, but getting that bit going is a huge step forward. It means that I’ve essentially cracked the concurrency bits I thought would take a good while longer.
A good point to pause and do some documentation, will help with the tidying.