Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 4 of 4

Thread: USB interface for multi channel outputs, not just stereo

  1. #1
    Junior Member
    Join Date
    Feb 2021

    USB interface for multi channel outputs, not just stereo

    Hi folks,

    I'd like to update the USB audio for Teensy 4 to handle more than 2 channels (starting with 4 but eventually 8) which it only currently supports, so that I can play 4/8 different channels from my computer and use them as outputs on the Teensy.

    It seems that some people have worked on it:
    But never got to the end of it.

    I've been trying as well, but I'm a bit stuck as I don't really understand what the code does in some places.

    Here's what I've done so far:

    - Update to the AUDIO_INTERFACE descriptor
    usb_desc.c line 1574 (USB 2 480mb), updated bNrChannels to 4 (was 2)
    This change allows the Teensyduino interface in Windows to show 4 outputs
    Now I'm not sure if anything else needs updating in the descriptor.

    - Update to USB audio library
    usb_audio.h and usb_audio.cpp:
    Updated the size of rx_buffer to double it:
    DMAMEM static uint8_t rx_buffer[AUDIO_RX_SIZE] __attribute__ ((aligned(64)));
    Then I've updated the code to duplicate everywhere possible where right and left are being used.
    void usb_audio_receive_callback(unsigned int len)
    	unsigned int count, avail;
    	audio_block_t *left, *right, *three, *four;
    	const uint32_t *data;
    	AudioInputUSB::receive_flag = 1;
    	len >>= 4; // 1 sample = 4 bytes: 2 left, 2 right
    	data = (const uint32_t *)rx_buffer;
    	count = AudioInputUSB::incoming_count;
    	left = AudioInputUSB::incoming_left;
    	right = AudioInputUSB::incoming_right;
    	three = AudioInputUSB::incoming_three;
    	four = AudioInputUSB::incoming_four;
    	if (left == NULL) {
    		left = AudioStream::allocate();
    		if (left == NULL) return;
    		AudioInputUSB::incoming_left = left;
    	if (right == NULL) {
    		right = AudioStream::allocate();
    		if (right == NULL) return;
    		AudioInputUSB::incoming_right = right;
    	if (three == NULL) {
    		three = AudioStream::allocate();
    		if (three == NULL) return;
    		AudioInputUSB::incoming_three = three;
    	if (four == NULL) {
    		four = AudioStream::allocate();
    		if (four == NULL) return;
    		AudioInputUSB::incoming_four = four;
    However I do not understand enough what happens in some functions e.g copy_to_buffers with the bitwise operations.

    Also I am unsure if there are other places in the libraries that will need updating e.g usb.c

    Any help would be MUCH appreciated, even just some hints to know if I'm going in the right direction!

    I'd be happy to collaborate if you are interested in this update.



  2. #2
    Junior Member
    Join Date
    Feb 2021
    If someone who understands could explain what the bitwise operations do in the following function.... e.g why "left & 0x02"?!

    static void copy_to_buffers(const uint32_t *src, int16_t *left, int16_t *right, unsigned int len)
    	uint32_t *target = (uint32_t*) src + len; 
    	while ((src < target) && (((uintptr_t) left & 0x02) != 0)) {
    		uint32_t n = *src++;
    		*left++ = n & 0xFFFF;
    		*right++ = n >> 16;
    	while ((src < target - 2)) {
    		uint32_t n2 = *src++;
    		uint32_t n1 = *src++;
    		uint32_t n = *src++;
    		*(uint32_t *)left = (n1 & 0xFFFF) | ((n & 0xFFFF) << 16);
    		*(uint32_t *)right = (n1 >> 16) | ((n & 0xFFFF0000)) ;
    	while ((src < target)) {
    		uint32_t n = *src++;
    		*left++ = n & 0xFFFF;
    		*right++ = n >> 16;

  3. #3
    Junior Member
    Join Date
    Feb 2021
    I made a custom board with the CS42448 for the same purpose and I'm also stuck at the same place as you. I managed to show more outputs in Windows too, but that was it. I still have hope this will be possible soon with Teensy. Understanding those bitwise operations would be a good new step and any progress on this will be very much appreciated!

  4. #4
    I’m currently working on a project that requires at least 16 channels out over a single cable… and if anyone’s goals are similar—precisely synchronized timing to interface every individual channel with a DAW—USB 2.0 simply isn’t an option. The polling nature of USB 2.0 doesn’t allow for precision timing. IEEE 1588 compliance is necessary, which means either using NativeEthernet or going all out with an FPGA.

    I’m very much hoping to avoid the FPGA route, especially as what are now next-gen MCUs by dint of current supply chain issues using the i.MX RT1176 offer a co-processor and multiple 1Gbps Ethernet interfaces make this exceptionally easy: AES67 implementation —> Ethernet —> drivers for a couple of common Ethernet to USB 3.2 chips used in adapters and USB hubs.

    I’m currently working on an AES67 implementation for the Teensy 4.1, which can theoretically handle 48 bidirectional, 24 bit/48KHz audio channels over a 100Mbps connection, though due to some limitations of the 4.1 and i.MX RT1062, somewhere between 16 to 24 channels is more realistic. As long as I can achieve 16 channels while leaving plenty of memory/CPU overhead for other operations, I’ll be happy, and will write drivers for the two most common Ethernet to USB 3.2 chips used in existing devices.

    If not, due to time constraints, there will be an FPGA involved, but regardless, all software/hardware will be open source.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts