TDM Matrix mixer

Status
Not open for further replies.

palmerr

Well-known member
I'm writing a TDM 8x8 matrix mixer.

The basic pattern is

mixer pattern.jpg

All goes well up to 4 replications of the Mixer 1-2-3 pattern. Any higher number (I've tested 5, 6 & 8), produces an output (green trace) like this:

6 mixers.png

Here's the code:
Code:
/*
 * 8 channels TDM into matrix of 8 x 2 4-channel mixers
 * Down mix to 8 single output channels to TDM outs
 */
 
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>

#define MIXRS 5
#define CHANS 8
#define ABLOX 36

AudioMixer4           Amixer[MIXRS][2];     // pairs of 4 input Amixers, summed by a Bmixer
AudioMixer4           Bmixer[MIXRS];        // mix down pairs of Amixers 
AudioConnection     * Apatch[MIXRS][CHANS]; // TDM to Amixers
AudioConnection     * Bpatch[MIXRS][2];     // Amixers to Bmixers
AudioConnection     * Cpatch[MIXRS];        // Bmixers to outputs. Insert tone/FX here.
AudioInputTDM         TDM_in;       
AudioOutputTDM        TDM_out;       
AudioControlCS42448   cs42448_1;      

AudioAnalyzePeak peak1, peak2;
AudioConnection p1(TDM_in, 0, peak1, 0); 
AudioConnection p2(Bmixer[0], 0, peak2, 0); 
  
void setup() {
  // put your setup code here, to run once:
  AudioMemory(ABLOX);
  Serial.begin(115200);
  delay(1000);
  Serial.println("Starting T4 TDM multi mixer test");
  
  for(int i = 0; i < MIXRS; i++)
  {
    for(int j = 0; j < CHANS; j++)
    {
      // set up TDM to A mixer patches - only every second TDM in/out is used
      if(j < CHANS/2)
      {
        Apatch[i][j] = new AudioConnection(TDM_in, i*2, Amixer[i][0], i);
        Amixer[i][0].gain(j, 1.0); // unity gain for the mixer channel
      }
      else // second half TDM go to the other Amixer in the pair
      {
        Apatch[i][j] = new AudioConnection(TDM_in, i*2, Amixer[i][1], i - CHANS/2);
        Amixer[i][1].gain(j, 1.0); // unity gain for the mixer channel
      }     
    }
    // pacth Amixers to Bmixers
    Bpatch[i][0] = new AudioConnection(Amixer[i][0], 0, Bmixer[i], 0);  
    Bpatch[i][1] = new AudioConnection(Amixer[i][1], 0, Bmixer[i], 1); 
    Bmixer[i].gain(0, 1.0); // unity gain for the mixer channel 
    Bmixer[i].gain(1, 1.0); 
    // Bmixers to TDM outputs
    Cpatch[i]    = new AudioConnection(Bmixer[i], 0, TDM_out, i*2);  
  }
  Serial.println("Done setup");
}
uint32_t loops;

void loop() {
  float Again = 1.0;
  int procUse = AudioProcessorUsageMax();
  AudioProcessorUsageMaxReset();
  int memUse = AudioMemoryUsage();
  float peakA = peak1.read();
  float peakB =  peak2.read();
  Again = (float)random(200, 1000) / 1000.0;    // gain 0.2 .. 1.0
  Amixer[0][0].gain(0, Again); // vary gain for mixer channel 0

  Serial.printf("%i: proc %i, mem %i, gain %3.2f, peak1 %3.2f, peak2 %3.2f\n",loops, procUse, memUse, Again, peakA, peakB);
 
  delay(5000);
  loops++;
}

Output is as follows, so I'm not running out of CPU or AudioMemory.
...
137: proc 1, mem 21, gain 0.43, peak1 0.54, peak2 0.25
138: proc 1, mem 21, gain 0.81, peak1 0.54, peak2 0.23
139: proc 1, mem 10, gain 0.77, peak1 0.54, peak2 0.44
...
 
You should create objects and connections in the correct order - otherwise you'll get strange behaviour and
unwanted latencies. Specifically here you should create TDM_in, then 2 mixers and the first peak, connect them,
then add the final mixer and peak, connect them, then create TDM_out and connect it. All the signal processing
that's interrupt-driven currently goes in the order objects are created, irrespective of the dataflow, so you need
to follow these rules if you code the audio signal graph yourself.
(the Audio design tool specifically manages this for you - I'd run it and copy/paste/renumber the results for
multiply banks for instance)

Whenever you see missing audio blocks like this (they are 2.9ms long), in a cyclic fashion, its a strong indicator
the blocks are being handled in the wrong order, which can produce hidden latencies, or audible artifacts. It
can also, of course, be due to inadequate number of blocks being initialized in AudioMemory, or processor load.

Here the first object you create, one of the mixers, is getting audio blocks left over from the last time, not from TDM_in,
since TDM_in doesn't exist when that mixer is created. As you added more copies of your graph the pattern of use changed
and its the fourth one that triggered the gross error - careful investigation should show that it was already misbehaving.
 
Thanks - both of you.

Mark - the app is actually an 8x8 matrix mixer - so I'll take the creation order from the Audio Tool, as you suggest, and build it into the code that generates the mixer objects and connections.

Manicksan - I searched the forum for "matrix" mixer rather than "crosspoint" - so thanks for the link. It's pretty much exactly what I want and has the benefit of one less processing stage (though if I follow Mark's advice it shouldn't cost me anything in added latency). I'll have a go at making the number of inputs/outputs an argument for the constructor, to reduce processing time and resource use.

Richard
 
That looks quite exciting! I wanna do something similiar with teensy. May I ask what kind of hardware you use for getting 8 inputs and outputs?

EDIT: Ah you combine this https://oshpark.com/shared_projects/2Yj6rFaW with the regular teensy audio board?

How is it with bit debth? can you use the 24bit of the tdm board still?
 
Last edited:
Hi,

I use a variant of Paul's CS42448 board - see https://forum.pjrc.com/threads/58836-CS42448-board-update-for-T4-pinouts-and-improved-performance it provides 8x8 with a CS5341 ADC for the extra two input channels, it also provides balanced ins and outs, raising the noise floor (potentially) by 6dB and CMRR by substantially more. Electrolytics isolate the inputs and outputs, to avoid the frequency dependent capacitance of large MLCCs. I'll be happy to share the Gerbers once it's fully tested (see above).

Paul's new 8x8 (6+2 x 8) board is at https://hackaday.io/project/2984-teensy-audio-library/log/187557-updated-cs42448-pcb-for-teensy-4x and https://oshpark.com/profiles/PaulStoffregen

My main use for Teensy audio is live performance (I have 16 channels of 24 bit/96kHz pro gear for recording), so I haven't played with changing bit depth or sample rate as 44.1kHz/16 bits works just fine for this use.

While you can use 24 bit mode, you would need to split them across two 16 streams, as each of the 16 TDM object's ins and outs are 16 bit.

I agree with Paul's logic of why it's not worth the effort https://www.pjrc.com/teensy/td_libs_AudioRoadmap.html, though there have been several streams of discussion around 24 bit and 48kHz operation. I haven't followed them in any detail.

BTW, if you're going to try 24 bit - you could use the 16 x 16 matrix mixer that manicksan notes, ganging two channels together (above).
 
Hi,

I use a variant of Paul's CS42448 board - see https://forum.pjrc.com/threads/58836-CS42448-board-update-for-T4-pinouts-and-improved-performance it provides 8x8 with a CS5341 ADC for the extra two input channels, it also provides balanced ins and outs, raising the noise floor (potentially) by 6dB and CMRR by substantially more. Electrolytics isolate the inputs and outputs, to avoid the frequency dependent capacitance of large MLCCs. I'll be happy to share the Gerbers once it's fully tested (see above).

Thanks for your answer! That looks very promising! I have no experience in soldering these smd chips with many pins. So I would need to find someone that can do the job, but I'd be happy to get the gerber files and try my luck.

My main use for Teensy audio is live performance (I have 16 channels of 24 bit/96kHz pro gear for recording), so I haven't played with changing bit depth or sample rate as 44.1kHz/16 bits works just fine for this use.

While you can use 24 bit mode, you would need to split them across two 16 streams, as each of the 16 TDM object's ins and outs are 16 bit.

BTW, if you're going to try 24 bit - you could use the 16 x 16 matrix mixer that manicksan notes, ganging two channels together (above).

Allright. My Idea with this would be connecting my live Instruments and DIY gear (a couple of axoloti boards) with my pro gear (RME UCX) via ADAT, and be able to route several inputs to several (axoloti) fx devices. So 24bit would be a huge bonus, allthough I wouldn't mind starting with 16bit.

May I ask what you are using this setup for more specifically? Just out of curiosity...
 
Sure,

Live monitor matrix mixing, quite like the venerable Aviom setups in concept, other than the audio is not (yet) routed over the network cables, instead delivered via spare multicore channels (for now), as I haven't yet managed to get low latency/high reliability WiFi audio delivery working as well as I'd like.

I'll get back to that, and improving my UDP/IP transport layer for Teensy Audio at some point!

8 inputs from main desk channel inserts or sends, matrix mixed to 8 line outputs for personal/stage monitors, all using Teensy Audio. Control is via a serial link from one of a set of ESP32 touch screen controllers. User selects channel with touch button, encoder knob controls fader levels. Red and white buttons are channel on and PFL. Cycle through the different output mixes using the encoder press switch.
proto.jpg
Each player has a personal monitor, and as many controllers are spread around as makes sense - as any controller can manage any (all) of the mixes (or just the one for that player).
 
An update on this project...

The core is a CS42448/CS5343 8x8 Teensy 4.x audio Board with balanced inputs and outputs available on headers, rather than through TRS jacks.
csboard-s.jpg

Inputs and outputs are processed by daughter boards to provide flexibility.

Currently I have two input options and a balanced output board
  • a combo jack XLR/TRS input board using a TS472 (sadly, out of stock everywhere until 2022!) that provides balanced Line in (TRS) bypassing the TS472, and 10-40dB mic gain controlled via I2C.
  • a TRS balanced input board with 6-20dB gain, also controlled via I2C (pictured below)
  • the output board provides balanced outputs at normal line (0dbV) outputs
input TRS-s.png

There's also a little distribution board that has I2C level converters (to 5V), fans out the I2C to the daughter boards that need it, and provides a suitable driver for a string of WS2812Bs @ 5V. The WS2812's are peak indicators in my 8x8 mixer design.
i2c-s.png

The previous (messy) revision of the prototype for an 8x8 matrix mixer has fairly impressive specs: dynamic range (N&D) in the 80-95 dB range, and it all runs off 5V via USB or a plug-pack.
RevC proto.jpg

The 8x8 mixer teams up with any number of ESP32-based graphical remote controllers, that communicate via WiFi with the audio Teensy, to produce an 8x8 live monitor mixer with individual controls for each musician (a bit like the Aviom products that have been in recording studios for decades).
controller.png

I'm hoping for a few more dB here and there with the latest version of the boards, which have a few layout improvements.

Once they're fully tested, I'll be releasing schematics and board files for others to use and improve.
 
Status
Not open for further replies.
Back
Top