I am looking for a way to apply dynamic loudness to my signal in ADAU1701. I have found the dynamic bass boost block but that only adds gain to the lower frequencies. I want to add a dynamic "Fletcher Munson" type loudness curve which includes both low and high frequencies.
I have found the loudness block which adds gain to both low frequencies and high frequencies but this is not dynamically controlled.
Please let me know if there is a good solution to this available!
The attached circuit may fill your needs. It takes advantage of a recent addition to the ADAU1701's toolbox, the log-spaced lookup table. This greatly simplifies dynamic controls like this one, by providing a numerical index that varies with the log of its input (a dB-sensitive table). There has always been a base-2 log function built into the ADAU1701, now we can finally get at it.
All else that's needed is to set up two General Second-Order Index Selectable filters, one for bass and the other for treble. Varying level chooses different filters, as shown in the Real-Time Display. Built-in slewing renders the transitions inaudible, as long as the filters are closely-spaced. I used ten filters plus flat. Of course you can add more filters and adjust them in line with published curves; I just made it sound good to me. Wish my stereo had one of these.
Thanks for the nice schematic! I wonder if it would be possible to use the same setup (monitoring the input signal RMS) but instead using the available Loudness block with externall control.
How can I create the dynamic control signal [0-1.0] with the Log lock up table? I am not familiar with the different formats so I need some guidance :-)!
The dynamic range I am aiming for is about 20dB (-50dB->0.0 ..-40dB->0.5... -30dB->1.0dB).
How do I implement that?
Thanks and best regards
The trouble with using the Loudness (Lo & Hi) External Control block is that it already controls the volume as well as the compensating filters. For example, suppose that the level drops from full scale to 20 dB down. The RMS detector's output would also drop a corresponding amount. The Loudness block then has both 20 dB reduced level and 20 dB reduced control input, resulting in 40 dB lower output level. In other words, we have a 2:1 expansion we can't get rid of. Or, can we?
I thought of one way to do it and it seems to work, albeit over a limited (about 40 dB) range. We can go ahead and construct the dynamic loudness described above, but add a compensating gain to make up for the effect of its built-in volume control. That is, we take the reciprocal of the measured level and drive a gain block with it, to bring the level back up.
That's how the schematic shown works, except with one important refinement. After measuring the incoming level, we take its square root before the reciprocal, then apply the resulting control signal to two volume blocks -- one before and one after the loudness block. This overcomes to some extent some serious limitations imposed by the hardware and blocks. First, the -1701's 5.23 number system limits decimal values to 15.99, so a gain block cannot boost more than 16 x (about 24 dB). Second, the ADAU1701's divide block only works for denominators larger than (1/15.99), for much the same reason. The square root turns a 0.01 (-40 dB) value into 0.10 (-20 dB), effectively doubling the available dynamic range. Using two volume control blocks, one before and one after the attenuation of the loudness control, produces a safer system less likely to overload. This arrangement tests out rather well within its limitations.
The above project uses over 200 instructions; it needs to go on a diet. Replacing its Divide block with an "implicit" one (using feedback around a multiplier) helps. The Approximate Square Root block is already implicit, working on the principle described at https://ez.analog.com/message/77517#77517
Thus there's no reason why we can't merge the divide and square root functions together, as shown below. This simplification saves 45 instructions.
In a A-B test, the two projects perform identically. One strange problem -- Usually I include a DC Block filter after the ADCs to prevent any stray DC from affecting the level measurements. For some reason, however, this version would not work with a filter there. The DC block filter caused weak, tinny sound. Substituting a high-pass filter made the thing hiss like a cat. This seems to happen to me sometimes when using more than two feedback blocks in a project. To fix it I moved the DC Block before the peak detector (where it's actually needed anyway).
EDIT: I have not used the Log Lookup Table in these examples because it appeared to lack interpolation -- the ability to "read between the lines" of its table entries to produce a smooth output curve. However, a test I just tried shows that in fact, it does interpolate (even though neither its name nor its block symbol suggests interpolation). This changes everything! Perhaps, then, it could replace some of the math I've been doing above. Problem is, there seems to be no documentation for this block (at least, I cannot find any in the wiki). Thus, unless its designers can provide some preliminary docs, we will need to characterize it -- that is, run enough tests with known inputs to rough out its transfer function. I'll start by requesting docs in a separate post.
The Log Table checks out quite well, as described at:
Likely you can use it to simplify or replace the math I have used above.