Teensy 4 Multi-pin TDM audio, Multi-channel USB, and variable sample rates

caleb

Active member
Hi all I just submitted the following pull requests and wanted to get your take on them.


These two pull requests do the following:
  • Allows for the TDM interface to use all 4 pins for either play or record. This means you can play or record up to 64 channels on 4 TDM busses (well, 4 pins of the same TDM bus)
  • Allows the USB interface to have a configurable number of channels. Yes, you can stream 32 channels of audio to or from your teensy.
  • Allows you to set the sample rate to 44100, 48000, 32000, 16000, 8000.

This does seem to work for my purposes, but needs review and further testing.


-Caleb
 
Thanks for the works !
Out of sheer curiosity, what is the maximum number of in/out did you manage to get working in your test
At a quick glance on the code the audio samples bit depth is still hardcoded in 16bits right ?
I ask because some codecs only handle 32bits samples which makes it incompatible with the TDM driver as it is.
(https://forum.pjrc.com/index.php?threads/tdm512.73977/ for reference)
 
Finally got round to trying the multi-channel USB, in the hope you found something @mcginty and I missed. No such luck, I'm afraid, I still get glitches:
2024-03-03 20_40_06-GoldWave.png


My test code is this:
C++:
#include <Audio.h>

#define AUDIO_kHz ((int) AUDIO_SAMPLE_RATE / 1000)
#define AUDIO_CHANNELS USB_AUDIO_TX_CHANNELS

extern "C"
{
    struct usb_string_descriptor_struct
    {
        uint8_t bLength;
        uint8_t bDescriptorType;
        uint16_t wString[6+1+1+2+1];
    };
   
  usb_string_descriptor_struct usb_string_serial_number={
    2+(6+1+1+2+1)*2,3,
    {'A','u','d','i','o','-','0'+AUDIO_CHANNELS,'/','0'+(AUDIO_kHz / 10),'0' + (AUDIO_kHz % 10),'B'}
  };
}

// GUItool: begin automatically generated code
AudioSynthWaveform       wav1; //xy=479,580
AudioSynthWaveform       wav2;      //xy=484,616
AudioSynthWaveform       wav3; //xy=486,654
AudioSynthWaveform       wav4; //xy=490,691
AudioSynthWaveform       wav5; //xy=494,729
AudioSynthWaveform       wav6; //xy=499,765
AudioSynthWaveform       wav7; //xy=503,802
AudioSynthWaveform       wav8; //xy=507,840
AudioInputUSB         usb_oct_in;       //xy=524,931
AudioMixer4              mixer1;         //xy=728,896
AudioMixer4              mixer2; //xy=733,968
AudioMixer4              mixer3; //xy=870,946
AudioOutputI2S           i2sOut;           //xy=939,684
AudioOutputUSB        usb_oct_out;       //xy=942,589

AudioConnection          patchCord1(wav1, 0, usb_oct_out, 0);
AudioConnection          patchCord2(wav1, 0, i2sOut, 0);
AudioConnection          patchCord3(wav2, 0, usb_oct_out, 1);
AudioConnection          patchCord4(wav3, 0, usb_oct_out, 2);
AudioConnection          patchCord5(wav4, 0, usb_oct_out, 3);
AudioConnection          patchCord6(wav5, 0, usb_oct_out, 4);
AudioConnection          patchCord7(wav6, 0, usb_oct_out, 5);
AudioConnection          patchCord8(wav7, 0, usb_oct_out, 6);
AudioConnection          patchCord9(wav8, 0, usb_oct_out, 7);
AudioConnection          patchCord10(usb_oct_in, 0, mixer1, 0);
AudioConnection          patchCord11(usb_oct_in, 1, mixer1, 1);
AudioConnection          patchCord12(usb_oct_in, 2, mixer1, 2);
AudioConnection          patchCord13(usb_oct_in, 3, mixer1, 3);
AudioConnection          patchCord14(usb_oct_in, 4, mixer2, 0);
AudioConnection          patchCord15(usb_oct_in, 5, mixer2, 1);
AudioConnection          patchCord16(usb_oct_in, 6, mixer2, 2);
AudioConnection          patchCord17(usb_oct_in, 7, mixer2, 3);
AudioConnection          patchCord18(mixer1, 0, mixer3, 0);
AudioConnection          patchCord19(mixer2, 0, mixer3, 1);
AudioConnection          patchCord20(mixer3, 0, i2sOut, 1);

AudioControlSGTL5000     sgtl5000;     //xy=946,745
// GUItool: end automatically generated code



AudioSynthWaveform* wavs[] = {
  &wav1,
  &wav2,
  &wav3,
  &wav4,
  &wav5,
  &wav6,
  &wav7,
  &wav8
};

AudioMixer4* mixers[] = {&mixer1,&mixer2};

uint32_t ledOff;

void setup()
{
  pinMode(LED_BUILTIN,OUTPUT);
  AudioMemory(80);

  while (!Serial)
    ;

  if (CrashReport)
    Serial.print(CrashReport);
 
  // sgtl5000.setAddress(HIGH);
  sgtl5000.enable();
  sgtl5000.volume(0.05f);

  for (int i=0;i<8;i++)
  {
    wavs[i]->begin(0.5f,220.0f + 110.0f*i,WAVEFORM_TRIANGLE);
    wavs[i]->phase(15.0f*i);
  }

  Serial.printf("Audio block size %d samples; sample rate %.2f; %d channels\n",AUDIO_BLOCK_SAMPLES,AUDIO_SAMPLE_RATE_EXACT,AUDIO_CHANNELS);
  Serial.println("Running");
}

void loop()
{
  if (millis() > ledOff)
  {
    digitalWrite(LED_BUILTIN,0); // ignore this, left from previous test!
  }
}
Teensy 4.1 + audio adaptor (modified to alternate I²C address); Windows 10 x64; Arduino 1.8.19; Teensyduino 1.59 + your USB modifications; USB Type is set to Serial+MIDI+Audio.

To reproduce, I record 10s of the 8-channel output in Goldwave, then play it back through the Teensy. It can take a couple of go-rounds for the glitches to start happening in the recorded audio.
 
Just trying the multi-pin TDM, and it looks as if output_tdm.cpp only has some of the required modifications; the register bit-twiddling code is all in there, but the N-pin setup in begin() isn't, and neither are the changes in isr() or the associated interleaving function.

If you can sort that out, I have a Frankenaudio lash-up ready to test - one CS42448 and one PCM3168 for a first crack at 14i16o TDM magic!

IMG_1091-sm.JPG
 
Back
Top