Wednesday, September 28, 2016

Automatic volume tracking for a TV

A couple of years ago I was given a non-working 50" Philips flat-panel TV.  As is often the case with these things, there was actually very little wrong with it and in this instance it was a pair of bad capacitors in the power supply, costing about $3 to fix.

With the working TV, I now had another problem that is all too common:  The internal speakers sounded terrible!

Rummaging around my storage room I found an old JVC 35 watt/channel audio amplifier/tuner from the 1980's and using the "audio output" on the back of the TV I connected it to the amplifier and that to a pair of high-efficiency JBL 12" 4-way speakers:  It sounded pretty good - lots of volume, good highs and thundering bass with "only" 35 watts (I wouldn't need a subwoofer!) - but the volume control had no effect.  Finding another cable, I then tried the headphone jack on the side of the TV, but its volume wasn't affected even though the speaker was muted!

WTH, Philips?!?

Figure 1:
A view of the volume tracker showing the connections,
indicator and controls.
I've seen this same issue on at least one other TV, but with some of TVs one can find an option - often deep in a configuration - that makes the audio line output track the volume control - but not this one.  What this meant was that if I was using an external audio amplifier and I wanted to be able to adjust the TV volume with a remote I would need either two remotes, or program a universal remote to do the task.  This latter point isn't too much of a problem as there are many universal remotes that can be configured to split tasks amongst different boxes, but the audio amplifier that I was planning to use (and the only one that I had that would fit in the TV stand)  - the 1984 JVC tuner/amplifier - did not have a remote.

So, I did what any nerd type would do:  I threw a computer at it!

It occurred to me that I did have a reference on which I could base an outboard volume control:  The internal speakers of the TV.  I surmised that I could "listen" to the audio level coming out of the speakers, compare it to the fixed-level audio line output from the TV and based on that, adjust the volume of an outboard amplifier based on the difference.

I figured that this could work if I could place a sense microphone very close to the speaker and in this way the sound level at the microphone would be very high as compared to the room volume of the external loudspeakers and I could make it so that not only would the TV's internal speakers still be quite low for a fairly high volume from the outboard speakers.  Doing this would also minimize the effect of the sound from the outboard speakers being picked up by the microphone which could cause the volume to increase even more in a feedback loop.

Instead of using a microphone I could have tapped into the audio from the internal speakers, but moving this heavy TV and taking it apart is quite difficult with just one person - and I wanted to try out the "microphone" approach, first.
If I have reason to take this TV apart in the future I may add an external connection to one of the speakers via a resistive pad and 1:1 isolation transformer.

To test this theory I hacked together a bit of code that did nothing but measure the audio level from two sources:  A microphone and the audio line output and then dump those levels, in dB, to the serial port where I could see what was going on.  It seemed to look pretty good as the two audio sources seemed to track fairly well.

I could now get down to the task of writing some software and building a dedicated board.

Using 5 MIPS of computing power to adjust a volume control

I chose a PIC16F88 for this task.  This processor has a whopping 368 bytes of RAM and 8 kwords for program space and it also has an onboard 10 bit A/D converter and UART so that it can both accumulate analog data (audio, in this case) and send out statistics to a serial port so that the results could be analyzed.

Several years ago I'd written some code for the PIC (in C) that took audio fed into the A/D port. calculated the average level and spat it out in dB below "full scale" of the A/D converter - all based on integer math - and in comparing it to a genuine, mechanical VU meter I found that it matched quite closely.  In testing, this code seemed to be perfectly capable of providing accurate readings (to within better than 1dB) to about 100 kHz - a frequency well above the actual sample rate.  With 10 bits of A/D conversion and the use of  (at least)16 bit integer math, I had a usable dynamic range of a bit over 60dB due to "oversampling".

Starting with that code I rewrote it so that it would be able to take two separate channels of audio and produce the sound level, in dB, at an update rate of about 10 readings per second.

In a nutshell, the code works like this:
  • In an interrupt, an A/D reading is taken from audio channel A and converted to a signed integer.
  • At the next interrupt, an A/D reading is taken from audio channel B and converted to a signed integer.
  • On the fly, after each channel is taken the following "pre-processing" is done to each channel.
    • The absolute value of that A/D reading is taken and summed with past readings from this same channel using a 32 bit accumulator.
    • Any instances of hitting "at or near maximum" on an A/D converter set a flag to indicate that we have "clipped" our audio and that the results may be suspected to be bad.
    • This "interleaving" of A/D accumulation and readings helps assure that both channels are treated the same way and get similar results.
  • Once the sum of 500 pairs of data had been taken the code signals via a flag that new results are ready.  Since we have only one A/D converter, we can't digitize both channels simultaneously so spreading the readings over time helps assure that the readings would be very similar if the same audio were present in both channels.
  • The main code copies the results of the accumulated data, clears the summing registers and restarts the interrupt so that new data can be gathered.
  • The sums of the absolute values of each audio channel are then converted into two separate dB readings using a set of lookup tables and interpolation, the result being accurate to within 1dB.  Obtaining a numerical reading in a logarithmic scale such as deciBels is important since ratiometric differences in the two channels can be easily compared regardless of the absolute amplitude.
  • Knowing the difference between the two audio sources (e.g. the "line in" from the TV and the audio level being detected from the speaker) a lookup table is referenced to set the digital potentiometer in the the line level audio path to the power amplifier as needed to provide the appropriate change of audio being applied to the amplifier:  The higher the detected amplitude from the speaker with respect to the audio on the line in, the lower the attenuation between the line in and the amplifier and the louder the amplified sound.
As noted above the audio is being "undersampled" since the frequency of the audio content exceeds half the actual sampling rate - and also that because there is only one A/D converter that is multiplexed, the two audio sources, the microphone and program audio, are not being sampled at exactly the same time.

For our purposes, this is irrelevant as audio is generally redundant in the nature - and we are looking at absolute voltage levels rather than anything having to do with spectral content.  What this means is that if you feed the same content into both inputs at the same time, you get completely identical results from the VU meter readings with the amplitude staying flat within 1 dB to about 100 kHz - the frequency that is (more or less) limited by circuit capacitance.
Because we are comparing two ostensibly identical audio sources there isn't any need to apply any "weighting" to the readings other than what is done already.
Having converted the audio levels to dB readings actually makes the task of comparing audio levels much simpler as our two audio sources - a sample of the line out from the TV and the audio from the TV's speaker - should following each other, differing only in the loudness difference between the two sources.  In other words, all I really needed to do was to adjust the audio line output level so that it tracked the audio level difference between the two sources:  If I increased the audio level to the speaker by 6 dB, I would see that in the output from the microphone and know to increase the line output to the audio amplifier by 6dB as well.

Figure 2:
The "guts" of the volume controller.  In the upper left one can see U1, the input and output buffers and to its
right U2, the electronic potentiometers.  In the lower left is U3, the microphone and comparison
filter/amplifiers and in the upper-right, U4, the PIC16F88 processor.  Just below U4 are the
power supply components.
Click on the image for a larger version.

Sounds simple, right?

Actually, it's fairly tricky when you get right down to it.

While 60dB sounds like a lot of audio range - and it is, in fact, a million-to-one level difference - it turns out that we can easily experience this in normal TV programming between a loud explosion and very quiet parts of the audio, particularly when you take into account the fact that one could easily use at least 30dB of that range in the volume control alone!

Since this PIC has only a 10 bit A/D converter, the range was theoretically limited to about 60 dB so I configured each audio channel to have a switchable "high/low" gain setting so that an extra 20 dB or so could be measured.  Since that amount of gain difference was always the same when I switched settings, I could simply add that gain into the appropriate dB reading to compensate for the difference.  The way this worked was that if I saw an audio level that near the bottom of the usable range (say, 40-50 dB below full scale), I would switch in the extra gain but if it was too high (perhaps within 10-20 dB of full scale) I would switch it out.  The result was that I now had about 80 dB of usable measurement range - not bad for a cheap computer chip with only 10 bits of A/D and a couple of op amps!

Knowing when not to act:

There's yet another problem to consider.  If we have audio from both the line input and the speaker, we can easily make a comparison and determine which is louder/quieter, but what if the audio from one source - or both sources - is too low to make a valid comparison?

An obvious example of this would be during a brief pause at the time of a commercial break - or, perhaps, when you are loading a video disc or waiting for a program stream to start.  If you didn't detect the "silence" and prevent the unit from adjusting the volume control, it would probably go out into the weeds whenever it was "too quiet."  The work-around is, of course, to have the computer detect quiet parts and not make adjustments at those times.

Another time during which we should not act is, as noted above, during those instance when we suspect that one or both the input channels is clipping:  That's easy - just set a threshold above which you do not make any decisions to adjust the volume.

Another concern is clipping - which can come from several sources.  As noted previously, too high an input level could exceed the dynamic range of the A/D converter on the PIC and if this happens, two things can occur:
  • Our readings are bogus since we don't know by how much the audio exceeded the range.
  • On the PIC - as is the case with many CMOS analog MUXes - if you exceed the voltage range of the input by going above the supply voltage or below ground you can affect the other A/D channels - even if they are not selected.  In other words, clipping in one channel will probably wreck the readings in the other channels as well!
If the gain of an audio channel has already been set to "low" and we are still clipping in that channel, the proper course of action would be to simply ignore that reading:  If the clipping is happening fairly infrequently, we can afford to do this as we will soon get another reading that we can use.

Figure 3:
The automatic volume tracking box, sitting behind and under the TV.
Another source of clipping can be the TV's own speaker amplifier and/or the microphone near it.  Since the sense microphone is placed right in front of the speaker it is possible that on audio peaks we could hit the maximum level of which it is capable.  This condition is a bit harder to detect since we aren't actually causing clipping of the A/D converter in this case so all we can really do is to be careful in the initial setup of the system so that we don't encounter either instance.

Differences in audio sources:

One problem with using a microphone to pick up speaker audio is that the audio detected via that route will not sound the same as the "pristine" audio output from the back of the TV.  This inevitable result is due to neither the speaker or microphone being perfect in their ability to faithfully produce their outputs:  There will always be at least a small difference due to frequency response differences and mechanical resonances.

In order to minimize these differences I decided to purposely limit the frequency range over which the audio from either the microphone or the line out would be analyzed and this was done using a low-Q 1 kHz bandpass filter.  The idea here is to pass audio only in the low-middle range of what can be heard and the general audio range in which most of the audio is actually present.  The "low Q" audio filter means that while its passband is centered at 1 kHz, it doesn't attenuate lower or higher frequency particularly quickly - but it is sure to knock down the low bass or the highest treble significantly - those being the frequencies at which the speaker/microphone combination is likely to have the least fidelity and depart from the sample from the line input.

Putting it all together:

The schematic diagram of this circuit is shown below.

Figure 4: 
Schematic diagram of the automatic volume tracker.
Click on an image for a larger version.

Only the left channel audio path will be described:  The right channel audio path is identical.

The audio from the TV's LINE OUT is fed in via C101 to a unity-gain follower op amp circuit (U1a) which is biased by R101 at a mid supply voltage, 2.5 volts.  The output of U1a is then fed to an electronic potentiometer, U2a which is also biased from the mid-supply voltage so that variations in U2a's settings do not cause a DC offset to occur.  The "wiper" of the U2a potentiometer is connected to another unity-gain follower, U1d which is then connected to the audio output.

Because unity-gain followers are used, there is no audio gain provided in this circuit, but setting the electronic potentiometer to "full scale" will result in very little attenuation of the audio being passed through the system, pretty much as if this entire circuit were bypassed.  When the electronic potentiometer is at the bottom end of its scale the attenuation is over 50 dB - more than enough range for our purposes.

Because there is only one "sense" microphone, jumper JP1 is used to select the corresponding LINE IN audio channel for the channel being monitored with the microphone:  Since it it is common for the left/right channel content to differ quite considerably in stereo programs, it is important to make sure that JP1 is set to match the speaker being monitored by the microphone.

From JP1 the selected signal goes to a 20-ish dB pad consisting of R301/R302 and then to a non-inverting amplifier built around U3a.  It may seem odd to attenuate a signal just to amplify it again, but this configuration was made during the initial design stages when it wasn't certain what the absolute audio levels would be.  It was also desired that both channels have similar circuitry and as such, amplifier U3a's gain adjustment mechanism would work only if it had a fairly high gain to begin with.

If the processor detects that the line level audio is too low, it sets the PROG_GAIN line to a LOW state, effectively grounding it and the bottom end of R304 and causing the gain to increase by nearly 20dB.  C302 is used to prevent this action from causing a DC bias offset and R305 provides a bit of constant leakage to prevent C302 from discharging if the amplifier is in the "Low gain" mode (e.g. the "PROG_GAIN" pin set to a high-impedance state.)  Conversely, if the audio is high enough that the extra 20dB is not needed, this pin is switched to be a digital input where it may float.
Figure 5:
Placement of the "sense" microphone:  Against the speaker!
Surprisingly, the microphone doesn't seem to be very prone
to "clipping" or saturation even at high speaker volume
levels - something that could skew the comparison. The
microphone is taped at the edge of the cone using
polyimide tape, mostly out of sight.

In testing, it was noted that better performance was obtained by setting the PIC's input to a "Digital input" mode rather than an "A/D" input mode, this being due to the fact that because of C302, the signals on this pin swing below ground potential.  When this happened while in "A/D input" mode the other A/D channels (on the same MUX) were badly disrupted and excessive clipping on the input of that pin caused audio distortion on U3a as well as affected the apparent gain of the stage as well.

From U3a the LINE audio signal passes through a low-Q audio bandpass filter consisting of U3d centered at about 1 kHz.  This filter's passband is (more or less) in the middle of the audio spectrum in which much of the energy of speech and music is contained and the thought is that discrepancies between the qualities of the audio directly coupled from the LINE input and those picked up by the microphone after they have first been reproduced by the speaker will be reduced.

By the time the audio leaves U3d, the bandpass filter, its level is close-ish to 5 volts peak-peak for the highest level audio that would be present with U3a in the "low" gain mode - this being done to maximize the dynamic range of the PIC's A/D converter.  By virtue of the AC coupling of the bandpass filter (via C303) and the 2.5 volt bias on U3d, pin 12, the output of the filter is also centered at 2.5 volts, mid-scale for the PIC's A/D converter.

The audio from the microphone follows a similar path except that its variable-gain amplifier, U3b, has more maximum gain to compensate for the relatively low level from the microphone as compared to the LINE input.  As with the LINE audio, it too is bandpass-filtered at 1 kHz, this time by U3c, the output of which is sent to the PIC.

Monitoring and adjustment:

One may notice that there is also a serial port (output) shown on the diagram, the DE-9 connector being just visible in Figure 3 along with "Gain+", "Gain-" buttons and a dual-color LED.  In operation the serial output is constantly sending the detected microphone audio level, the program audio level, the difference between the two, the difference between the actual audio level and the level predicted based on it and the gain setting and whether or not the A/D was at or near clipping.

During TV program audio - particularly at a high volume level - this "telemetry" data is used to determine how well the device is tracking the audio and whether adjustments are needed using the "Gain+" and "Gain-" buttons which adjust how speaker audio correlates with the attenuation that the processor applies to U2, the digital potentiometer and save the settings in the processor's nonvolatile (flash) memory. The LED is used to provide a visual indication of what the devices is doing:  Red indicates that the audio "gain" is being increased (e.g. the attenuation of U2 decreased) while green indicates a decrease in audio gain while a yellow color - created by the processor switching between red and green rapidly - is used to indicate that U2 as at minimum attenuation - which is the same as maximum volume.

How well does it work?

I've been using this on the TV for nearly 3 years now and only tweaked the code slightly after installing it.  At low volume levels it does tend to "hunt" a little bit (e.g. volume go up and down several dB - usually not noticeable) with differing program material - likely due to some "spillover" from the large, room speakers into the sense microphone, but at normal volume levels it is quite consistent.  There are a few instances that do still cause it to "hunt" (some types of music, a few specific voices) but its not been severe enough for me to record such clips to the DVR and try to figure out what, exactly is happening.


This page stolen from "".