I have some Genelec 8020A studio monitors in my living room. Basically, they are nice looking high-end active speakers with balanced inputs. But how do you switch inputs? control the volume? (without spending a fortune on a professional monitor controller) Well – time to build an audio crossbar/mixer volume control!
Goals: Use multiple sources, support more than 2 speakers, build a flexible but small solution
As I don’t have the equipment to measure high-end analog audio performance, I decided to go digital. There are ready-made AD/DA audio converters that deal with balanced signals, amplification and protection. At 200 Euro the Behringer Ultragain ADA8000 is cheaper than anything I could build (think of multiple design iterations, PCBs, power supply and housing) and suited my needs. I agree – it is not the best high-end device available, but this component could later be upgraded easily. Instead of a balanced audio signal I now have a digital ADAT signal: 8 Channels, 24 Bits/Sample, 48kHz with a total bitrate of ~12 Mbit/sec over an optical TOSLINK connector:
This signal goes into an FPGA, is processed and sent back to the DA converter. Here is an overview of the complete system:
First Hardware Version (Demoboard)
The first version is based on a Digilent Basys2 FPGA board with a Xilinx Spartan-3E-100 FPGA.
The following additions were made:
- 24.576 MHz oscillator is added as user-clock (G6)
- 2 optical receivers, Sharp GP1FAV31RK0F
- 2 optical transmitters, Sharp GP1FAV31TK0F
- max3232 for RS232 connection to the PC, conveniently available on a small PCB for 1 Euro/piece on ebay
Second Hardware Version (standalone)
In the second version I wanted to use a larger and cheaper FPGA board. I found the Waveshare Core3S250E board with a Xilinx Spartan 3E-250 FPGA. For programming I also bought the Waveshare USB programmer which is conveniently compatible with the Xilinx Platform Cable USB.
My perfboard contains the following components:
- 2 receivers, 2 transmitters
- 24.576 MHz oscillator
- MAX3232 level shifter and RS232 connector
- USB B socket for power supply
User interface (Python GUI)
With RS232 I could test my FPGA code, but typing the values into a console was still not “user friendly”. This example shows a 16 by 8 matrix. Input 3 is connected to output 2, input 4 is connected to output 3 and output 5 carries the sum of input 3 and 4 (at reduced volume).
User interface (IR remote)
For interfacing an infrared remote, I used this test setup:
- AtMega328p module
- TSOP31238 infrared receiver
- 3 WS2812 RGB leds
- 2 regular LEDs
I used the regular gcc linux toolchain and the IRMP infrared library, which is hosted on microcontroller.net. This way I can detect the signals from my Samsung TV (mute, volume up/down) and send the corresponding messages to the FPGA. The color LEDs are used for displaying the status with the help of the light_ws2812 library.
Current hardware version
The final version contains all the components in a single enclosure. With a wall power supply the system is finally ready!
The enclosure contains:
- TSOP31238 infrared receiver (lower left)
- 3 WS2812 RGB leds (left)
- an AtMega328p board
- the Core3S250E FPGA board
- only a single receiver and transmitter (I still have only one AD/DA converter)
- 24.576 MHz oscillator
The main processing of this project happens in the FPGA. For this I built ADAT receiver and transmitter modules that write/read to/from a dual-ported ram. Right now, the design has two receivers (for testing the locking behavior) and a single transmitter. This way, the mixer can operate at a different frequency and could even run in parallel.
I found that the pipelined mixing module does not even need a multiplication. The upper bits of the coefficients are directly used for signed shifting the signal to the right. The lower two bits of the coefficient are used for subtracting 1/8, 1/4 or 3/4. This gives nice and fine-grained volume levels without requiring many resources.
The main bottleneck of the design is the mixer, as it needs to go through every input for each output. However, at a maximum word clock of 48 kHz the design has plenty of time for calculating the output. I believe that the design could scale to 64×64 channels with mixer parallelization (but I have no idea why I could need this). Currently, the design utilizes 25% of the LUTs and 15% of the FFs of the Spartan-3E-250.
The AD converter is locked to the incoming ADAT signal (generated in the FPGA). This way, there is no drift of the incoming ADAT signal in the FPGA. As most audio AD converters support this mode, no interpolation between samples and so on is required.
Digital Volume – But you will loose accuracy!
Setting the volume corresponds to throwing away the lower bits – so you loose dynamic range. However, I found that the range of typical listening volumes is not that large. At maximum volume the digital signal is passed through unaltered and and lower volumes it is not that loud any more – at least it can’t hear the quantization. The solution is fine for me but YMMV.
Controlling the audio volume and mixing signals is possible and the chosen setup operates without distortions, glitches as intended – I was expecting more debugging of weird behavior. The sound quality is much better than the loudspeakers in the TV so the setup is accepted and used. On the other hand, the user interface is hard – right now, the remote can be used to control the TV volume – but any more settings are not accessible (I didn’t want to include yet another remote). A nice solution still needs to be found! The Behringer ADC is bulky and consumes quite some power (it gets warm) – for controlling volume only this is certainly overkill.