Noise Gate Pt. 7
Lucky number seven! Woohoo! Okay, enough of that. We’ve got to get moving on this noise gate, as it’s approximately a page on the JUCE tutorials yet I’ve managed to expound eight and a half thousand words on this sucker. Let’s see how big-ass we can make this little ass plugin. We’ve still got to do the GUI, so I’ll dump a bajillion words on that, I’m sure.
If you’re just joining us on this project, boy have you missed out. But you can pretend to follow along with this link. You’ve just got to download the github repository. Don’t clone it or branch it or commit or whatever, as I haven’t the foggiest what that means, and I’m sure it’ll end up with my source control more fucked than the time I tried to use Perforce.
I even tried to get the Github desktop app, and my what a waste that was. I got it all worked out but none of my currently existing repos are in there. So instead of re-writing the others, MEH, i’ll keep doing it the way I meant to for now, and hope that there’s some overarching folder structure I can fit it in to later.
According to our JUCE tutorial;
: If this coefficient is greater than or equal to the threshold, we reset the sample countdown to the sample rate.
So for some reason they have picked an EXTREMELY CPU intensive version. Or rather, of course they have, like most bloody audio tutorials. 'I’m going to see how another noise gate works.
How does this one actually f*&king work?
So we set our mono sidechain and our alpha to be our lowpass coefficient. Then if our coefficient is higher than the threshold, we print the incoming samples to our outgoing buffer to be passed to the engine. If it’s lower, we literally just keep printing 0’s to the buffer.
ARGGG WHY SHOW ME A CRAP WAY TO DO THIS.
For each channel;
We getWritePointer(channel, sample), and write it to;
IF the sampleCountDown is greater than 0, then get the readPointer
If not, we write 0’s to the buffer. (resulting in silence)
The ? and : ternary operators let us get this all done in one line, which is rad.
sampleCountDown > 0 ? *mainInputOutput.getReadPointer (i,j) : 0.0f
Here’s a bit from Miller Puckette’s book (or my hackjobbed abbreviation of it) on companders and noise gates. I think it’d be interesting to take this same example and turn this into a compressor. I’d say we’d just do this by multiplying the end result of the writePointer to the inverse of the threshold control, so maybe it’s worth jumping into a bit of DSP knowledge, as I haven’t looked at that yet.
A compander is a tool that amplifies a signal with a variable gain, depending on the signal’s measured amplitude. The term is a contraction of “compressor” and “expander”. A compressor’s gain decreases as the input level increases, so that the dynamic range, that is, the overall variation in signal level, is reduced. An expander does the reverse, increasing the dynamic range. Frequently the gain depends not only on the immediate signal level but on its history; for instance the rate of change might be limited or there might be a time delay.
By using Fourier analysis and resynthesis, we can do companding individu- ally on narrow-band channels.
This technique is useful for removing noise from a recorded sound. We either measure or guess values of the noise floor f[k]. Because of the design of the gain function g[m,k], only amplitudes which are above the noise floor reach the output. Since this is done on narrow frequency bands, it is sometimes possible to remove most of the noise even while the signal itself, in the frequency ranges where it is louder than the noise floor, is mostly preserved.
The technique is also useful as preparation before applying a non-linear operation, such as distortion, to a sound. It is often best to distort only the most salient frequencies of the sound. Subtracting the noise-gated sound from the original then gives a residual signal which can be passed through undistorted.
It’s interesting to see how similar a lot of this stuff is. Though it’s also got a slab of this;
How Miller Puckette is as good at this as he is at music is mindblowing for me. Fuck he’s so good. I got to see his opera at the Bendigo Festival of Exploratory Music and it was fucking rad.
I also looked for information on how to actually write a noise gate plugin in a more effective way than described here (as JUCE just loved to tell me about how shit their idea was). But having looked through these three books;
Miller Puckette’s book
Understanding Digital Signal Processing
It’s good. So good.
So if someone could enlighten me what better ways there are. That’d be swell.
A Better Solution
There’s a solution on KVR here, that we could use, with a hardcoded version. It’s not quite JUCE, but probably wouldn’t be hard to adapt.
Finally, we’ve got to make sure that as long as we’re writing the write buffer, we’re decrementing sampleCountDown by 1 each sample to make sure it doesn’t get all fucked up.
Not entirely sure what’s the best way to tackle it.
I’ve found Fabian’s original thoughts as the author of the code in terms of what he meant by it being inefficient code, and it’s not as bad as I thought.
Isn’t it easier to just call getArrayOfWritePointers() at the start and work with data[chan][sampleNumber] anyway?
Apparently this is the answer, though I’m not sure how you are supposed to know how many 0’s you’d like to get.
This apparently works by using a SIMD implementation.
With that, we’re actually finishing up the processing side of what we have!
There’s probably some cool things we could do here. I’d really like to get an Attack and Release envelope working, as at the moment it really hammers down the volume completely once it hits lower than the threshold. We’ll probably be able to fine tune this a smidge once we get the GUI going.
If we load this bad boi up, we get the desired behaviour! It’s loud up to a certain point, and then it totally cuts off, depending on the level of the sidechain.
Let’s make it look less like poo in the next blog.