I’ve been curious about Chorus for a while, since I’ve been working on and off with chorus design myself. There were a few things I didn’t understand, like what the relationshp is between the modulation LFO’s waveshape and the frequency modulation of signals going through the chorus. You’d think that if you use a sinewave to modulate the BBD clock, you’d get a sinewave modulation of frequency, right? Wrong! So what do you get? At this point, I realised that it was a bit more complicated than I was giving it credit for and I’d have to really think about it. This page is some of the results of those studies.
Simulation of BBD chorus
So what did I do? Well, I did what I always do when I don’t understand something. I wrote a simulation of it. If I can write a sim of a situation, then I know that I understand it. If the sim doesn’t work, there’s something I’m still missing. Often the process of thinking about how to simulate something, and seeing how and why the simulation doesn’t work gives me an insight into the real situation. If that doesn’t work, playing with the simulation gives me a useful way to perform repeatable experiments that would often be awkward to do in reality.
My simulated delayline has 1024 stages, just like the SAD1024, MN3007, or MN3207 chip. Of these, only the last one is still available, so it’s the chip likely to turn up in modern analog chorus designs.
My chorus has linear clock modulation like the typical chorus effects. More about the problems this causes later – for now, we’re just simulating a typical chorus. The clock frequency at any given moment is:
$clock_freq = $clock_centre_freq + ($lfo * $mod_depth * 10000); // 10KHz mod range
Here’s the LFO waveform (blue) and the Clock rate (green). The horizontal green line is the clock centre frequency with no modulation applied. You can see that with a modulation depth of 20KHz, the clock frequency goes up to 60KHz, and down to 20KHz. The LFO rate and Clock rate are just chosen to give a reasonable display. We can see 400msecs of signal here.
Ok, so far, so good. Let’s feed some audio into it and see if we can see anything happening. Remember this is just the signal through the BBD (the “Wet only” signal), so it’s not a full chorus. In fact, it’s just a vibrato unit. But mixing the dry and wet signals together is easy, and that’s not the bit I don’t understand, so I’m ignoring the dry signal. This next graph adds a low audio ramp wave (red). You can easily see the pitch change caused by the clock modulation. Notice the initial delay before any signal comes through the delay line is clearly visible on the left hand side of the graph.
Now this is where things start to get interesting. What do you think is happening to that audio frequency? It should be varying up and down, following the changes in the clock rate, right? Let’s have a look. The next graph uses the slope of the output ramp wave to give an estimate of the audio output frequency at each moment. This is only possible with ramp waves of fixed amplitude, but it’s handy for our demo. This is plotted in red. I’ve taken the LFO off to stop it getting too cluttered.
Interesting, don’t you think? The frequency modulation produced isn’t a simple sine wave – it’s distorted. Let’s have better look at that without the audio:
So what’s going on here? Think about how the BBD makes a pitch change. When the LFO output is rising, the clock frequency is increasing, and samples are being read out faster than they were read in – their pitch is shifted up. Likewise, when the LFO is falling, the clock frequency is decreasing, and samples are read out more slowly than they were read in – the pitch is decreased. The key here is that the pitch shift is not caused by a high clock frequency or a low clock frequency, but by an increasing or decreasing clock frequency. It’s the rate–of–change of clock frequency that’s important.
For a sine wave LFO input like we’ve been using, the point of maximum increase is the middle of the upwards slope, where our clock rate crosses the horizontal red line. Similarly, the maximum decrease is on the downwards slope where it crosses the red line. If we plot this rate of increase, we’re plotting the differential of sin(x), which is just cos(x) – the same thing shifted forwards a bit.
But hang on a minute! Our frequency modulation isn’t following cos(x) for our sin(x) LFO! That curve isn’t a cosine curve any more than it’s a sine curve. Where’s that distortion coming from?
Why does the modulation get distorted?
Let’s back up for a moment and consider the delay. How would we measure the delay at any moment in time? Well, the total amount of delay is just the amount of delay provided by each bucket, all added together, and how much delay you get depends on how fast the clock was going for each of the previous buckets. The delay for a single bucket is the length of time since the last clock pulse – e.g. the clock period. The total delay is the sum of all the last X clock periods, where X is the number of BBD stages. Put another way, we’re integrating the area under the clock period curve for the last X samples.
Let’s plot the clock period curve. Here it is, added to the graph in green:
The first thing to notice about this is that it’s already slightly distorted, since we’re now looking at 1/sin(x) rather than sin(x). But the distortion is all in the vertical direction, not in the time axis. To say that another way, the waveform is still symmetrical left-to-right. Ok, now let’s see what shape curve the delay makes if we add up the last X periods of that clock period graph. Here it is in blue:
Now we see where the rest of the distortion comes from. Although the clock frequency matches the LFO, the actual delay doesn’t directly, because it is the sum of all the clock periods for the whole length of the delay line. Incidentally, with the clock frequency we choose originally, the blue line goes from slightly below 10msecs to slighty above 20msecs, so we’re pretty much in chorus territory here.
But it still doesn’t look like the frequency modulation!
Well, no, true. It doesn’t. But you remember when we talked about it being the rate-of-change of delay that was important? We were thinking that for a sin(x) LFO, we’d see a cos(x) frequency modulation? It isn’t that simple, since as we’ve shown, the total delay follows a much more complicated curve than the clock frequency. But the point still stands – it’s the rate-of-change of delay that matters. Here’s the plot with the rate-of-change added in pale blue:
Now at last we’ve got a waveform that looks like our frequency modulation! The frequency modulation follows the rate-of-change of the total delay, and that waveform isn’t anything like the modulation LFO’s waveform.
Great! So what frequency modulation do I get with other LFO waveforms?
Ok, let’s have a look at a few in isolation. First we’ve got the sine wave LFO that we’ve just seen:
A triangle wave LFO is probably even more common, since they’re easy to build:
And square wave LFOs are even easier to build, but rarely used for chorus:
Now, there’s an interesting result! Although the LFO jumps between two levels, the output frequency jumps between three!
Linear versus Exponential clock modulation for BBD chorus
One of the problems with a typical chorus unit is the pitch modulation gets deeper as the BBD clock rate is reduced (e.g. as the delay is made longer). This makes the pitch variation very obvious – “seasick” or “warbley” are words often used to describe the sound. A typical chorus unit uses an LFO to modify its clock frequency, and that clock modulation is linear, so a given modulation depth will give (for example) +/-25KHz of clock modulation. This is how our simulation has operated thus far. When I considered this, it seemed to me that must be the reason why the depth seems to go up. If you consider a high clock frequency of 200KHz, a modulation of +/-25KHz is about 12%, or about 2 semitones. If you then consider what happens at a low modulation rate of 50KHz, the same modulation of +/-25KHz now shifts the clock by about 50%, or roughly an octave (50-25 = 25, which is 50% of 50KHz, 50+25 = 75, which is 150% of 50KHz).
So what’s the solution? Use exponential frequency modulation like a synth VCO of course! Then the LFO mod depth would be specified as “an octave” or “4 semitones” and an octave shift at 50KHz is the same as an octave shift at 200KHz.
An Update – some further thoughts
A while after posting this article, I had an email discussion about it with Brian Neunaber of Neunaber Audio Effects. Brian was initially slightly sceptical about the effect I claimed to have found and thought it might be an effect of the simulation or the frequency measurement method. This challenge pushed me to ensure that the method and results were sound. Once I’d convinced him that the effect was real, he wrote out the equations for what I’ve stated above and modelled them in Wolfram Alpha. I’ll reproduce his working below.
Firstly, we know that the total delay is related to the number of stages and the clock frequency:
total_delay = 1024 / (2 * clock_freq)
Note that clock_freq doesn’t have to be a constant. It could vary.
We also know that the change in pitch is related to the rate-of-change of the total delay:
change_in_pitch = d/dt (1024 / (2*clock_freq) )
Now, how about we make our clock have a base frequency of 40KHz, and modulate by +/-20KHz:
clock_freq = (40000 + 20000 * sin(2*pi*2*t) )
Put that into the pitch change equation:
change in pitch = d/dt (1024 / (2 * (40000 + 20000 * sin(2*pi*2*t) ) ) )
We can plot that in Wolfram Alpha. This shows us our by-now-familiar distorted curve. Brian wondered how much actual pitch change that represents, so he also plotted log2(1+x) in Wolfram Alpha to see how much shift in octaves that is. The maximum pitch change is around 0.2 octaves, or approximately 2.4 semitones. That’s quite a lot for a chorus, and another plot shows that if we reduce the modulation depth, the distortion also decreases. It seems reasonable to me to suspect that slower LFO rates also decrease the distortion, since it usually reduces the waveform’s rate of change (though not for a sharp square wave). On this basis, the effect won’t show up on slow, shallow chorus waveforms like I initially thought, but will definitely be present on deep, fast flangers. Perhaps this article should have been titled “Investigations into what a BBD Flanger unit *really* does” instead!
My thanks to Brian for the discussion and his thoughts on the matter.