I'll listen to the sines at work; don't want to wake the dog.
>
I can see the "click" on the 100Hz wave.
I was expecting something more like as shown on the right:
A hole or spike in the audio. A steep part of the wave is "perfect", as perfect as a discrete-step system can be.
>
I use different '51 clones.
Ah! Stripped-down souped-up 8080s! Most popular CPU on the planet. Lovely non-orthagonal instruction-set similar-to (but not same-as) the charming 8080.
>
If you could provide some suggestions (how fast should the level be adjusted, how much etc.)
Gosh. It was some years back when I was thinking of it, and don't seem to have a scrap of pseudo-code laying around now. Anyway I had some clever ideas that were probably over-clever. But that is part of the charm of doing AGC control in the digital domain: some things that are hard in analog peak detectors and time-constants are easy in digital (and vice-versa) so the "ideal" PIC/CPU/Stamp would be easily modified in a jiffy, not a write-once ROM programable.
Basically:
We probably still need an analog peak-holder, a rectifier and a cap. And a comparator: if the voltage on the cap exceeds (say) 2.0V, then we are close to our 2.8V maximum allowed level and need to reduce gain.
Although if the CPU has proper hardware interrupts, we might get away with a real-time no-cap comparator: if the instantaneous signal level exceeds 2.0V, an interrupt is thrown.
Before the concert starts, the operator dials-in a gain, based on sound-check, experience, or counting the players on stage. If signal level never goes over 2.0V, then this is the gain that stays in effect for the whole take.
If the signal level "surprise!" exceeds 2.0V, the CPU should reduce gain. Say 1dB.
If the level still exceeds 2.0V, CPU should reduce gain again.
Conceptually we have two variables: User_set, and GR.
BUT: if the CPU can check the level every microsecond, and the relays take a millisecond to flip, then the CPU could turn gain down 1,000dB before the relays respond to the first command.
Also if using a peak-hold level detector, the detector should be discharged when relay-setting changes, so it does not retain the now-invalid level but has to acquire the new reduced-gain level. (In analog GR processing, the cap must retail the level because this is the Release function too. In digital we will compute the release action digitally.)
So: if level is Over, reduce gain, wait for relays and peak-hold to settle, check level, repeat as needed.
When gain is reduced enough (or peak passes), the CPU defaults to holding the last gain setting. i.e. if User_set was 40, and gain had to be reduced 3dB to avoid going Over (GR=3), then gain stays at 40-3= 37.
Normally we want gain to recover when the loud part passes. Just as an example: if not-Over, and GR is not zero, then decrement GR one per second until it is zero. (That gives a slow release: in many applications we want faster than 1dB/second, but never more than 1dB per step to avoid volume-jump, so this decrementing has to happen more than once a second.)
That gives a constant dB/Second release, different from basic analog limiters which have nearly the same release time from 2dB or 20dB of gain reduction. I think a dB/Sec rule makes sense psychoacoustically, but we might discover otherwise.
One problem: if for relay and peak-hold settling reasons, GR is only incremented say every 2mS, Attack will be slow on large over-voltages. And if gain is reduced 1dB every 2mS, that is equivalent to a 500Hz -20dB buzz under the transient.
It might be nice if the settling time between GR increments were semi-random, to spread that pure 500Hz over the 300-700Hz band, so it does not stand-out to the ear as a tone.
Also if large over-level is common, we might add a 4V threshold, and if this is triggered we reduce gain 3dB in one step. Then large peaks are quickly knocked-down.
The release time should perhaps vary with signal. If the level has been low, goes high for a few mS, then goes low for a while, we should probably recover quickly from this unusual event. But if level has been loud, peaks, then goes back to loud, maybe we should recover very slowly to avoid pumping effect. We might even hold a fixed level.
So I had in mind a 3 threshold detector: 2V as the goal-level, 4V as the drastic-action level, and a 0.3V (-15dB) detector to indicate if historical (last second or two) levels have been high or low.
The old CBS designs had another feature: if GR was in effect, but level dropped to "nothing" (-40dB), then hold that last GR setting for a while: it is either a musical pause or an operator screw-up, and the program may come back at the same level, and should probably be at the same GR as before. (But if the "nothing" continues for many seconds, maybe it is supposed to be soft but maybe not THAT soft, and GR should be released slowly.)
So there are many "clever things that could be done. Some, like holding through pauses, are very hard to do on leaky caps and very easy on a CPU ("do nothing").
Oh: and while checking for over-level (top priority) and recovering from passed peaks, we need to check the knob/buttons for user input (maybe the operator has realized the mistake and wants to take the rest of the take at lower gain), and update the display (so the operator knows the GR and User_set values).
Your existing board has just one numeric display. Obviously a deluxe product would have separate User_set and GR displays. But one might be enough: if GR is zero, display User_set; if GR is happening, display GR. In many cases the difference is clear: User_set is generally 30 to 63, and GR is usually 1 to 20; User_set is fixed and GR will change with the signal. Also one LED could indicate that GR is being displayed. Changing the User_set should display the new User_set for one second, then go back to GR if it is non-Zero.
Just getting gain to drop if threshold is exceeded, and recover smoothly afterward, would of course be enough to try, see how it sounds.