DSPRelated.com
Forums

Audio Compressor/AGC in C or C++

Started by __GG December 9, 2005
On Fri, 09 Dec 2005 21:16:34 -0500, robert bristow-johnson
<rbj@audioimagination.com> wrote:

>in article e1ckp11umqqr60cls9tu8j07spvn30nmss@4ax.com, __GG at >__GG@nomail.com wrote on 12/09/2005 20:43:
>> ... I'm wondering about fast envelope/peak detection >> and signal averaging. That seems to be one of the keys, esp as >> regards CPU cycles. > >what does the speed and smoothing (averaging) of your envelope/peak >detection have anything to do with CPU cycles?
More sophisticated detection probably requires conversion to float. RMS requires square and square root, which would be computationally expensive. I'm thinking that there may be much faster algorithms that stay in int domain and still work well. By the way, I'm just trying to get max energy from the input channel for a speech-rec app. I want to avoid spikes and other harmonic-rich artifacts, hence the desired lookahead buffer.
>> to the traditional diode/cap peak detector still has a finite ramp-up time, >> so buffer 'look ahead' is desirable. On the other hand, I don't >> want to delay any longer than necessary. So the lookahead >> interval should be roughly sync'd (or greater than) the attack >> response of the envelope filter. > >sounds to me that you understand the issues quite well. so why is it that >you need help? you should be telling us how to do it! :-)
Yeah, right! <g> I've seen some of the tech posts on this group. Besides, there is a big difference between knowing how it works and having good intuition for algorithms. You guys live there.
>pretty easy to write. 50 lines of code or less.
I was hoping that's the case. Surprising that there isn't more code floating around then.
>> Back to the envelope detector: How is this usually done? > >how about an analog to the diode/capacitor/load peak detector? or how about >squaring, LPFing, and square root (last step usually not necessary) for an >RMS envelope?
Still talking 50 lines of code? I do like this stuff, but unfortunately I can't schedule play time. Otherwise I'd try to write each of those building blocks and play with configurations. That would take a while. The comp is a small block in a large non-DSP app. That's the reason I'm trying to minimize cycles, and why I'm looking for a starting point for the code.
>> I think >> peak is the way to go in general (don't want to waste cycles on RMS >> if it's not going to help). > >it depends on what you're trying to do? are you trying to maintain a >certain perceptual loudness characteristic (then you need to do >"A-weighting" or "C-weighting" or even "E-weighting" (if you have the CPU >cycles) and RMS envelope detection. if you're trying to limit peak >excursions into the forbidden saturation region, then it's >diode/capacitor/resistor peak detection.
All this depends on a very temperamental speech-rec module. I have no idea what will make it barf, but I'm pretty sure it won't like artifacts from spikes or clipping. I bet some breathing or other normal compressor side-effects won't bother it.
>> I seem to remember some algorithms that >> simply added each new sample into a running tally of absolute values. >> There was a 'magic number' multiplier in the picture, 0.999, I >> believe. Anyone know about that? > >never seen it. why is 999/1000 so "magic"?
No idea. I've seen it in a couple different programs, but maybe it's coincidence. I guess they both chose to average 1000 samples. That averaging window would have direct bearing on the attack response, so I would have expected it to be a variable rather than a #define. I'll have to find that code again and take a closer look, but I thought that attack and release settings would directly affect the length of that averaged buffer.
On Fri, 09 Dec 2005 23:02:38 -0500, Jerry Avins <jya@ieee.org> wrote:

>There's no assurance that a any sample in a modest number rill be near a >peak unless the oversampling ratio is high. That's why envelope >detection is often done with a Hilbert transform and computing I^2 + >Q^2. Even without bothering to take the square root, that's not cheap. > >Jerry
Not sure about the CPU expense of a Hilbert transform, but that's why I thought RMS may not work (and may be overkill anyway). Given that I (probably) don't need to maintain perceived loudness, can you think of a faster approach for the detector? If memory serves, you worked on compressors for NASA, right? Maybe analog, but the same general approach should work here: just deliver loud intelligible energy without clipping. The envelope detector has to be the most complicated component, so it's worth some thought. In simplistic form, it seems like you'd want to average X number of samples for the attack (depending on designated attack time) and Y number of samples for release. X and Y could be derived by dividing designated attack and release times (resp) by 1/sample rate. Now that I think about this, it seems that it could still be prone to clipping unless there was another mechanism akin to a non-slew-limited diode/cap. That limiter would have to be integral to the compressor's control path so it could override the gain structure.
__GG wrote:

   ...

> More sophisticated detection probably requires conversion to float. > RMS requires square and square root, which would be computationally > expensive. I'm thinking that there may be much faster algorithms that > stay in int domain and still work well.
No square root is needed, If you know the target root, you know the target square. ... Jerry -- Engineering is the art of making what you want from things you can get. &#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;
__GG wrote:
> On Fri, 09 Dec 2005 23:02:38 -0500, Jerry Avins <jya@ieee.org> wrote: > > >>There's no assurance that a any sample in a modest number rill be near a >>peak unless the oversampling ratio is high. That's why envelope >>detection is often done with a Hilbert transform and computing I^2 + >>Q^2. Even without bothering to take the square root, that's not cheap. >> >>Jerry > > > Not sure about the CPU expense of a Hilbert transform, but that's why > I thought RMS may not work (and may be overkill anyway). Given that I > (probably) don't need to maintain perceived loudness, can you think of > a faster approach for the detector? > > If memory serves, you worked on compressors for NASA, right? Maybe > analog, but the same general approach should work here: just deliver > loud intelligible energy without clipping.
You have a long memory, and that was a long time ago. Mercury orbital flights. The compressor used only diodes, resistors and capacitors. The design wasn't mine, but I built plenty of them. I don't know that good RMS (MS is enough) is easy either, but I think that Parcival's Theorem might say it is. There's the same energy in sin(xt) + sin(3xt) as there is in sin(xt) - sin(3xt), but the peaks are very different. If you want to control the peaks, you have to sense peaks, not power.
> The envelope detector has to be the most complicated component, so > it's worth some thought. In simplistic form, it seems like you'd want > to average X number of samples for the attack (depending on designated > attack time) and Y number of samples for release. X and Y could be > derived by dividing designated attack and release times (resp) by > 1/sample rate. > > Now that I think about this, it seems that it could still be prone to > clipping unless there was another mechanism akin to a non-slew-limited > diode/cap. That limiter would have to be integral to the compressor's > control path so it could override the gain structure.
Analog Devices makes at least one analog audio compressor. I can dig out the number if you need it. A look at the data sheet will give you some good ideas about what's worth doing. What to do is at least as important as the implementation method. Jerry -- Engineering is the art of making what you want from things you can get. &#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;
On Fri, 09 Dec 2005 21:52:25 GMT, Richard Dobson
<richarddobson@blueyonder.co.uk> wrote:

>__GG wrote: > >> I'd like to find source for audio compression classes or functions >> in C or C++. It would be nice if it had lookahead (slight delay is >> OK). >> >There's a few in the musicdsp archive. One has just been added using C++: > >http://www.musicdsp.org/archive.php?classid=4#204 > >Richard Dobson
Here's another thought: If I were to use instantaneous peak detection instead of RMS or other slower envelope, then lookahead would not be necessary. The attack would track instantly. ref: http://www.musicdsp.org/archive.php?classid=0#19 That should use very few cycles. Questions: What is the flaw here? If I don't need musical-sounding output, just maximized clean signal, is there any drawback to simply feed-forwarding the peak-detected, slower-decay envelope to a virtual VCA? What is the best way to control decay/release? Given that the release does not have to be micro-second accurate, I could add groups of, say, 100 sample abs values, then feed each into a fifo. Accumulate the total in the FIFO by adding each new value, subtracting each old value as it gets bumped. The groups of 100 would eliminate the need for a long buffer. Possible stepping noise due to time granularity from grouping? This may also help with noise gating. I'd have x milliseconds of amplitudes in the fifo. If the total is below the noise threshold, turn off output. ?
__GG wrote:

..
> Here's another thought: If I were to use instantaneous peak detection > instead of RMS or other slower envelope, then lookahead would not be > necessary. The attack would track instantly. > > ref: http://www.musicdsp.org/archive.php?classid=0#19 > > That should use very few cycles. > > Questions: > > What is the flaw here? If I don't need musical-sounding output, just > maximized clean signal, is there any drawback to simply > feed-forwarding the peak-detected, slower-decay envelope to a virtual > VCA? >
Any compressor is a non-linear effect, that modulates the source (watch out for aliasing if the "corners" of the envelope are too sharp) and one way or another will always have some sort of personality, which may or may not be deemed "musical". I think you really need to try all these ideas out for yourself, and decide! I doubt you will get a complete answer here "do it this way" (but I do suggest you ask on the music-dsp list, and check the list archives, there were major discussions about compressors a few months ago). Different sources and requirements indicate different compression techniques, so that in a practical compressor you will need to offer at least peak and RMS options, and very possibly average too. Offering Peak and average might be OK, especially if you want minimum CPU cost. The high-end models of course offer multi-band compression, and/or seek to emulate analog optical compressors, but the basic algorithms such as you find in the music-dsp archive are very useful starting points.
> What is the best way to control decay/release? Given that the release > does not have to be micro-second accurate, I could add groups of, say, > 100 sample abs values, then feed each into a fifo. Accumulate the > total in the FIFO by adding each new value, subtracting each old value > as it gets bumped. The groups of 100 would eliminate the need for a > long buffer. Possible stepping noise due to time granularity from > grouping? >
Yes, that is a standard "closed-form" of averaging. Envelope detection is a form of filtering, and filters can have all sorts of slopes. The answers you seek may not be solely technical ones. For some material, one style will work, for another it won't. The window over which samples are scanned is itelf an important parameter, when doing averaging or RMS. You need an envelope extractor, which is a filter of one form or another, and an envelope synthesiser that generates the final envelope to be applied to the source sound. There is more than one way of designing both, and the criteria may be CPU load, etc, but may also likely be aesthetic ("hey this works on drums but is bad on a voice/sax/whatever"), so you really will have to try ideas out the hard way. One approach you might like to consider is to start by inspecting the behaviour of some published compressors (download a few demos!), by feeding in a special stereo source: one track contains simple dynamically changing waveforms (even a signal modulated with a plain LF square wave is useful; but it can be even more useful to have steps at a range of amplitudes, especially when evaluating the relationship between A/R slopes and threshold); the other a constant-amplitude sine, and make sure the compressor links the channels. The output on channel 2 will effectively show the envelope the compressor is applying, and you can check it directly against the source on the other channel. Then correlate your observations with musical evaluation. This is simple to do in an offline editor hosting VST plugins; load in your custom file, run the effect, and inspect the output waveform at your leisure. How the host manages (or not) delay compensation naturally matters too. And (ahem) when the product is launched for which I was commissioned to supply a "simple" compressor, you will be able to analyse that too! As a primarily classically-oriented musician, I don't make much use of compressors, so it was always a bit nerve-wracking designing something destined for unfamiliar musical styles, but I was told by my commissioner that the result was very good, and especially so on drums <grin>. For me in the end the hardest part was simply finding a wide enough range of sound sources (voice, slap bass guitar, Bach?) to test the da*** thing with; with synthetic test waveforms it all ~looked~ OK... Richard Dobson
__GG wrote:

   ...

> Here's another thought: If I were to use instantaneous peak detection > instead of RMS or other slower envelope, then lookahead would not be > necessary. The attack would track instantly.
That's probably not what you want. A very large signal following a small one where the compressor is working at high gain will be clipped in the first cycle, generating audible harmonics. Look-ahead gives you time to ramp the gain down more slowly. You should also keep the gain low when the input signal is negligible. That keeps background noise from becoming prominent in the absence of real signal. ... Jerry -- Engineering is the art of making what you want from things you can get. &#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;
Jerry Avins wrote:

..
> That's probably not what you want. A very large signal following a small > one where the compressor is working at high gain will be clipped in the > first cycle, generating audible harmonics. Look-ahead gives you time to > ramp the gain down more slowly. > > You should also keep the gain low when the input signal is negligible. > That keeps background noise from becoming prominent in the absence of > real signal. >
In music applications this is almost always done by means of a separate expander/gate stage. The canonical operation of a compressor is to progrssively reduce signals above a threshold, while leaving signals below it unchanged. There are plugins that offerthe use of arbitrary (and even hand-drawn) transfer functions, to do both, but even here they will still tend to be thought of as a "compressor/gate" compound device. Usually a compressor will be extended to offer hard/soft limiting/clipping, while an expander (reduces below a threshold) will be extended to a full gate. Richard Dobson
Richard Dobson wrote:
> Jerry Avins wrote:
...
>> You should also keep the gain low when the input signal is negligible. >> That keeps background noise from becoming prominent in the absence of >> real signal. >> > > In music applications this is almost always done by means of a separate > expander/gate stage. The canonical operation of a compressor is to > progrssively reduce signals above a threshold, while leaving signals > below it unchanged. There are plugins that offerthe use of arbitrary > (and even hand-drawn) transfer functions, to do both, but even here they > will still tend to be thought of as a "compressor/gate" compound device. > Usually a compressor will be extended to offer hard/soft > limiting/clipping, while an expander (reduces below a threshold) will > be extended to a full gate.
Everything is a separate module in software. I was thinking of the facilities provided in Analog Devices' SSM2166 "Microphone Preamplifier with Variable Compression & Noise Gating". (I couldn't get their demo board to stop oscillating, but I eventually got one working with my own layout.) I wish car radios had compressors so I could ride over road noise with open windows without blasting myself on louder passages. It's not a great way to listen to music, but it's better than not listening. Jerry -- Engineering is the art of making what you want from things you can get. &#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;&#4294967295;

Jerry Avins wrote:


> I wish car radios had compressors so I could ride over road > noise with open windows without blasting myself on louder passages. It's > not a great way to listen to music, but it's better than not listening.
The modern car radios have the compressors as well as the modern TVs. The trick is how to get to the service mode so you can adjust the parameters. The FM broadcast is usually heavily compressed too. Vladimir Vassilevsky DSP and Mixed Signal Design Consultant http://www.abvolt.com