With the working TV, I now had another problem: The internal speakers sounded terrible!
Rummaging around I found an old JVC 35 watt/channel audio amplifier/tuner from the 1980's, found the "audio output" on the back of the TV and 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 controll had no effect. Finding another cable, I then tried the headphone jack on the side of the TV, but its volume wasn't affected by the volume control, either!
A view of the volume tracker showing the connections,
indicator and controls.
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 and based on that, adjust the volume of an outboard amplifier. 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, but also prevent sound from the outboard speakers from being picked up by the microphone and cause the volume to increase even more in a feedback loop.
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. 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 and calculated the average volume and spit 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 and 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, 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 number.
- The absolute value of that A/D reading is taken an summed with past readings from this same channel.
- An A/D reading is taken from audio channel B and processed separately in the same way as channel A. This "interleaving" of readings helps assure that both channels are treated the same way and get similar results.
- 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.
- Once the sum of 500 readings has been taken, the code signals 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 accumulation of 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 with 1dB. The numerical reading in deciBels is important since ratio differences in the two channels remain constant regardless of the absolute amplitude.
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.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.
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.
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 - and 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 dB reading to compensate for the difference. The way this worked was that if I saw an audio level that was too low, I would switch in the extra gain but if it was too high, 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!
The automatic volume tracking box, sitting behind and under the TV.
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 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 properly!
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 to a LOW state, effectively ground 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.
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.
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 due to the fact that because of C302, the signals on this pin go 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 would 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 much 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.