DSPs

The heart of the audio-processing are two Analog Devices ADSP-21371 SHARC DSPs, while SHARC stands for Super-Harvard-Architecture. The first DSP is used for the general channel-processing, including low-pass-filter, noise-gate, dynamic-compression, EQ and general mixing. This DSP receives 40 audio-channels from the FPGA and sends 40 channels back.

The second DSP is used for the effects and receives 24 audio-channels from the first DSP. 16 channels are used for 8 stereo-effects, while the additional 8 channels are used for USB-audio and the AES/EBU-outputs. The FX-DSP sends back 24 channels to the first DSP, containing the outputs of the 8 stereo-effects, the USB-audio and two channels for the sinewave or noise-generator.

Within both DSPs we are using the high-speed serial-ports of the DSPs called „SPORT“. They are able to synchronize to the 12.288 MHz TDM-Bitclock and the 48kHz TDM-FrameSync. We are using DMA-Chains to automatically write received 32-bit audio-samples into the RAM of the DSP. We set the buffer-size to 16 samples so that we have a good compromise between delay (16 x 1/48kHz = 333µs) and samples to process.

After converting the 32-bit signed-integer-samples into 32-bit floating-point-values we process the samples. First we are processing an DSP-internal signal-routing so that we are able to set the output of one channel as input of another for instance. We are able to use different tap-points as well.

As shown in the picture on the left, we are then processing the samples using a simple low-cut-filter, a noise-gate, a dynamic compressor and EQ and finally the volume to the main-mix and the individual mix-bus-sends.

The SHARC-DSPs support some enhanced and accelerated commands for common processing like FFT and Biquad-filters. The following picture shows our implementation of an 48-channel 4-band EQ:

Next to the mixing-DSP, the second DSP contains the heart of the effects. We are using C++ and implemented an FX-baseclass. This FX-main-class inherits all basic properties to the child-classes. That allows us to implement a nice FX-plugin-system where the user can select between individual effects on the fly.

So every effect has a common set of functions for processing stereo-audio and receive control-data from the i.MX25-main-processor to adjust individual FX-parameters from the GUI.

When the user selects a new effect, we are removing the current effect from one of the eight FX-slots and create a new instance of the desired effect-class in this specific effect-slot.

Here is an example of our first implementation of an overdrive-effect:

Based on the work of Geraint Luff we implemented a very nice sounding reverb-plugin. You can find more about this reverb on Geraint’s blog.

The reverb takes around 600 lines of code and uses an optimized hadamard-matrix to diffuse the sound. Our implementation allows a rich-sounding and round reverb without the „mechanic“ rebound. In my opinion this is a huge improvement compared to the original X32-implementation.

Up to now we allow only a single instance of this reverb-plugin due to the higher processing-demand. But compared to more simple implementation this is worth it.

The next picture shows the general processing. Source: Geraint Luff (https://signalsmith-audio.co.uk)

Based on the work of Sebastian Kraft we implemented a stereo-2-surround-upmixing plugin. Using FFT-processing, a panning-estimation and a direct/ambience-decomposition this allows us to upmix any stereo-source to a 5.1 signal.

As this process uses most of the processing-power of the second DSP we can enable this function using pre-compiler-switches so that we can offer a separated bitstream-file for the DSP. So its possible to switch the second DSP on the fly with a new firmware and use the upmixer instead of the regular effects.

The picture shows the general process. Source: Sebastian Kraft, „Stereo Signal Decomposition and Upmixing to Surround and 3D Audio“

While working on the DSP I figured out, that the used CrossCore EmbeddedStudio by Analog Devices had no nice overview of the used memory. So we implemented a new graphical memory-map-viewert for this tool, that displays the used memory right after each compilation.

If you are interested, you can have a look at the GitHub-project: CCES_MMV

After working 6 months on the DSPs, we implemented a couple of nice effects, but there’s still work-in-progress. The AES3 output as well as the audio-interface to the i.MX25 is still not working as expected. As we are using C-functions we are losing some performance and are able to process only half of the mixbusses (8 instead of 16) and are not able to implement the 6-band EQs or the 24db/oct EQ-filters of the matrices at the moment.

But for a hobby project – developed in our spare time – we’ve actually managed to achieve quite a lot over the past few months. If you have some experience on programming DSPs and are searching for new challenges, feel free to join us and support us with pull-requests or ideas.