Forum Rule: Always post complete source code & details to reproduce any issue!
Page 2 of 2 FirstFirst 1 2
Results 26 to 42 of 42

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

  1. #26
    Member mcginty's Avatar
    Join Date
    Nov 2022
    Location
    The vast midwest, USA
    Posts
    20
    Excellent work @acumartini! Apologies for my quietness the last week, I'm back on working on these software changes and my schematics for the mixer this week. I'll start by refactoring these changes into an easy-to-consume fork of the "cores" repository to open up contributions and experimentation for folks.

    For what it's worth, the deinterlacing/memcpy code could almost certainly be optimized significantly (it's a pretty naive implementation right now), so I'm still optimistic that 8-in/8-out is achievable.

    Glad to hear @UHF - as the project matures, this is exactly my target. I'm designing them with the hopeful target of keeping the cost of manufacture under $100 and offering them as kits.

    @celoranta: I believe some others on the forum had been working on boards that had 2 codec chips (and two TDM lines) for 16 channels of input or output. Not sure of the status of it though. I'm personally sticking to 8 with the hopes of keeping the board and design cost lower, but if you don't need USB Audio for example, you'll have a larger performance margin for higher-bandwidth TDM communication. It all depends on your application.

  2. #27
    Senior Member h4yn0nnym0u5e's Avatar
    Join Date
    Apr 2021
    Location
    Cambridgeshire, UK
    Posts
    730
    Quote Originally Posted by mcginty View Post
    Excellent work @acumartini! Apologies for my quietness the last week, I'm back on working on these software changes and my schematics for the mixer this week. I'll start by refactoring these changes into an easy-to-consume fork of the "cores" repository to open up contributions and experimentation for folks.

    For what it's worth, the deinterlacing/memcpy code could almost certainly be optimized significantly (it's a pretty naive implementation right now), so I'm still optimistic that 8-in/8-out is achievable.

    Glad to hear @UHF - as the project matures, this is exactly my target. I'm designing them with the hopeful target of keeping the cost of manufacture under $100 and offering them as kits.

    @celoranta: I believe some others on the forum had been working on boards that had 2 codec chips (and two TDM lines) for 16 channels of input or output. Not sure of the status of it though. I'm personally sticking to 8 with the hopes of keeping the board and design cost lower, but if you don't need USB Audio for example, you'll have a larger performance margin for higher-bandwidth TDM communication. It all depends on your application.
    Really looking forward to seeing this!

    It's possible the (de)interlacing code could make use of the DSP instructions - it's a pretty common need in the audio library, though I can't say I've looked closely at whether it's consistently been optimised. Happy to take a look at this, if no-one gets to it before me.

    Paul Stoffregen did start a hardware project to interleave two CS42448 parts together to get 16 in + 16 out, though that seems to have stalled. Can't think why...

  3. #28
    Junior Member
    Join Date
    Sep 2021
    Posts
    13
    @mcginty;

    You are correct: I have no need for USB connections. This is for live gigs, and I’ll be playing my guitars on stage while the processing will be in the mixer rack at front of house. USB doesn’t travel so well!

    I will see if I can locate the threads you’re referencing. I’m working with two Cirrus CS5368 for 16 channels, with hopes of muxing them together to use just one Teensy TDM input, and then adding a second of these devices to input #2 for a total of 32 channels.

    (Theoretically this system will power a doubleneck six-string bass / guitar, each with hexaphonic electromagnetic pickups plus two standard monophonic pickups each; plus hexaphonic piezo pickups on each as well… with four channels to spare. OR a doubleneck 8-string guitar/8-string extended-range bass, each with piezo hex and EM hex sets. )

  4. #29
    Member mcginty's Avatar
    Join Date
    Nov 2022
    Location
    The vast midwest, USA
    Posts
    20
    Alrighty, I've refactored the work and now have the cores fork at https://github.com/mcginty/teensy-cores. I'll continue to update it with changes as we go.

    @h4yn0nnym0u5e, if you're interested in doing some performance research and optimization that would be most most welcome! I'm sure there are some clever uses of the Arithmetic and SIMD instructions that could help us out here.

    @acumartini, I'm assuming you also modified the AudioOutputUSB::update() function, but you didn't include it in your code block. Would need that for your modifications to compile and drop it into the fork!

  5. #30
    Senior Member h4yn0nnym0u5e's Avatar
    Join Date
    Apr 2021
    Location
    Cambridgeshire, UK
    Posts
    730
    I've done a "first try" pull request, though for some reason there's a conflict because git thinks I've made your changes, too! For some reason I can't fork your repo as well as the PJRC one, so it's all a bit weird.

    As you'll see, I tend to work on branches and then merge to master when the branch looks stable - it may be helpful if you create a branch for me to make PRs to, which would avoid possibly polluting your master if I drop a goolie we don't spot before the pull is done...

    EDIT: just put a 'scope on the receive and de-interlacing code (usb_audio_receive_callback), and it's only taking 4 to 5µs to run, so probably not worth tinkering with right now.
    Last edited by h4yn0nnym0u5e; 11-26-2022 at 03:08 PM.

  6. #31
    Senior Member h4yn0nnym0u5e's Avatar
    Join Date
    Apr 2021
    Location
    Cambridgeshire, UK
    Posts
    730
    Done a PR with 8-channel AudioOutputUSB - only briefly tested.

  7. #32
    @mcginty I have my own audio framework that processes a single sample at a time and only buffers at IO boundaries. Here is my equivalent to the Audio lib update function, which handles both input and output (hopefully this will be of some use to your impl):

    Code:
    void USBAudio::process()
    {
        Module::process();
    
    	// input
    	// if (PLATFORM_SWITCH1_LOW) Serial.printf("DEBUG RX %d %d\n", usb_audio_buffer_in_read_idx, usb_audio_buffer_in_write_idx);
    	if (usb_audio_buffer_in_read_idx < usb_audio_buffer_in_write_idx || (usb_audio_buffer_in_rollover && usb_audio_buffer_in_read_idx != usb_audio_buffer_in_write_idx)) {
    		if (usb_audio_rx) {
    			uint16_t diff = usb_audio_buffer_in_rollover ? 
    				(AUDIO_RX_BUFFER_SIZE - usb_audio_buffer_in_read_idx) + usb_audio_buffer_in_write_idx : 
    				usb_audio_buffer_in_write_idx - usb_audio_buffer_in_read_idx;
    			if (diff < AUDIO_RX_BUFFER_SIZE / 2) { // prevent overrun
    				usb_audio_feedback_acc -= AUDIO_RX_BUFFER_SIZE / 2 - diff;
    			} else { // prevent underrun
    				usb_audio_feedback_acc += diff - AUDIO_RX_BUFFER_SIZE / 2;
    			}
    			usb_audio_rx = false;
    		}
    
    		for (uint8_t i = 0; i < AUDIO_CHANNELS; i++) {
    			out[i].value = ((float)usb_audio_buffer_in[i][usb_audio_buffer_in_read_idx] / (float)INT16_MAX) * gain[i];
    		}
    		usb_audio_buffer_in_read_idx++;
    
    		if (usb_audio_buffer_in_read_idx >= AUDIO_RX_BUFFER_SIZE) {
    			usb_audio_buffer_in_read_idx = 0;
    			usb_audio_buffer_in_rollover = false;
    		}
    	} else if (usb_audio_rx) {
    		// Serial.println("DEBUG RX: underrun");
    		usb_audio_feedback_acc += AUDIO_RX_BUFFER_SIZE * 4; // buffer underrun
    		usb_audio_rx = false;
    	}
    
    	// ouptut
    	uint8_t buffer_idx = usb_audio_buffer_out_ping ? 0 : 1;
    	if (usb_audio_buffer_out_idx[buffer_idx] < AUDIO_TX_BUFFER_SIZE) {
    		for (uint8_t i = 0; i < AUDIO_CHANNELS; i++) {
    			usb_audio_buffer_out[buffer_idx][i][usb_audio_buffer_out_idx[buffer_idx]] = (int16_t)(ctrl_d[i].value() * ctrl_d[i + AUDIO_CHANNELS].value() * (float)INT16_MAX);
    		}
    		usb_audio_buffer_out_idx[buffer_idx]++;
    	}
    }

  8. #33
    Member mcginty's Avatar
    Join Date
    Nov 2022
    Location
    The vast midwest, USA
    Posts
    20
    Awesome! This is really coming together. I'll review the PRs when I'm back home later today @h4yn0nnym0u5e!

    That makes sense @acumartini, and very likely where my mixer's code is going to end up too to minimize latency. Thanks for the code samples, this makes sense. And also going back to your original posting's comments, a big TODO before "production-worthiness" is a correctly implemented accumulator feedback for the asynchronous endpoint in both directions, lest we drop frames.

  9. #34
    Senior Member h4yn0nnym0u5e's Avatar
    Join Date
    Apr 2021
    Location
    Cambridgeshire, UK
    Posts
    730
    Great, thanks @mcginty. I’m hopeful the “conflicts” are actually pretty minor.

    Had to stop for today, getting late in the UK, but I think there could be issues with high sample rates and/or small audio blocks. As it stands there can be at most two blocks queued for transmission, so sample rates higher than 256k will break the system, or similarly over 64k if the block size is reduced from 128 to 32 samples, for example. This probably needs addressing…

    I looked at the feedback accumulator… then looked away! Over to you on that…

  10. #35
    Senior Member h4yn0nnym0u5e's Avatar
    Join Date
    Apr 2021
    Location
    Cambridgeshire, UK
    Posts
    730
    Another PR done, this time on your Audio library fork, which implements and documents 4-, 6- and 8-input and output USB objects in the design GUI, and adds them to keywords.txt. For these you'll need this afternoon's cores update, too.

  11. #36
    Senior Member h4yn0nnym0u5e's Avatar
    Join Date
    Apr 2021
    Location
    Cambridgeshire, UK
    Posts
    730
    Meanwhile, another PR for cores, with some mostly minor fixes, but one that is vital for other sample rates. Tested so far only at 48kHz and 96kHz on a High-speed USB port.

    For information, my current test code is below. USB audio output from the PC is routed to outputs 1-7 of a CS42448 TDM audio adaptor; the Teensy generates 8 sine waves from 110Hz up to 880Hz, and feeds them to the PC's USB audio inputs, and the 110Hz goes to audio adaptor output 0, so you can tell the code is running.
    Code:
    #include <Audio.h>
    
    // GUItool: begin automatically generated code
    AudioInputUSBOct         usb_oct_in;       //xy=482,409
    AudioSynthWaveform       wav1;      //xy=483,298
    AudioSynthWaveform       wav2;           //xy=485,620
    AudioSynthWaveform       wav3;           //xy=485,665
    AudioSynthWaveform       wav4;           //xy=485,710
    AudioSynthWaveform       wav5;           //xy=485,755
    AudioSynthWaveform       wav6;           //xy=485,800
    AudioSynthWaveform       wav7;           //xy=485,845
    AudioSynthWaveform       wav8;           //xy=485,890
    AudioOutputTDM           tdm;           //xy=693,396
    AudioOutputUSBOct        usb_oct_out;       //xy=696,744
    
    AudioConnection          patchCord1(usb_oct_in, 0, tdm, 2);
    AudioConnection          patchCord2(usb_oct_in, 1, tdm, 4);
    AudioConnection          patchCord3(usb_oct_in, 2, tdm, 6);
    AudioConnection          patchCord4(usb_oct_in, 3, tdm, 8);
    AudioConnection          patchCord5(usb_oct_in, 4, tdm, 10);
    AudioConnection          patchCord6(usb_oct_in, 5, tdm, 12);
    AudioConnection          patchCord7(usb_oct_in, 6, tdm, 14);
    AudioConnection          patchCord8(wav1, 0, tdm, 0);
    AudioConnection          patchCord9(wav1, 0, usb_oct_out, 0);
    AudioConnection          patchCord10(wav2, 0, usb_oct_out, 1);
    AudioConnection          patchCord11(wav3, 0, usb_oct_out, 2);
    AudioConnection          patchCord12(wav4, 0, usb_oct_out, 3);
    AudioConnection          patchCord13(wav5, 0, usb_oct_out, 4);
    AudioConnection          patchCord14(wav6, 0, usb_oct_out, 5);
    AudioConnection          patchCord15(wav7, 0, usb_oct_out, 6);
    AudioConnection          patchCord16(wav8, 0, usb_oct_out, 7);
    
    AudioControlCS42448      cs42448;      //xy=688,547
    // GUItool: end automatically generated code
    
    AudioSynthWaveform* waves[] = 
      {&wav1, &wav2, &wav3, &wav4, 
       &wav5, &wav6, &wav7, &wav8};
       
    extern uint32_t feedback_accumulator;
       
    void setup() 
    {
      Serial.begin(115200);
    /*
      while (!Serial)
        ;
    */
    
      Serial.println(AUDIO_SAMPLE_RATE_EXACT);
      Serial.println(feedback_accumulator);
      
      AudioMemory(50); // needs plenty, as blocks are used for USB buffering
      
      cs42448.enable();
      cs42448.volume(1.0f);
      
      for (int i=0;i<8;i++)
        waves[i]->begin(0.25f,(i+1)*110.0f,WAVEFORM_SINE);
    
      pinMode(0,OUTPUT);
     // pinMode(1,OUTPUT);
    
      pinMode(LED_BUILTIN,OUTPUT);
    }
    
    void loop() 
    {
      digitalWriteFast(LED_BUILTIN,1);
      delay(10);
      digitalWriteFast(LED_BUILTIN,0);
      delay(240);
      digitalWriteFast(LED_BUILTIN,1);
      delay(10);
      digitalWriteFast(LED_BUILTIN,0);
      delay(240);
      digitalWriteFast(LED_BUILTIN,1);
      delay(10);
      digitalWriteFast(LED_BUILTIN,0);
      delay(240);
      digitalWriteFast(LED_BUILTIN,1);
      delay(10);
      digitalWriteFast(LED_BUILTIN,0);
      delay(990);
    
    }
    Last edited by h4yn0nnym0u5e; 11-28-2022 at 10:09 AM.

  12. #37
    Senior Member h4yn0nnym0u5e's Avatar
    Join Date
    Apr 2021
    Location
    Cambridgeshire, UK
    Posts
    730
    Looks like some work is definitely needed on the feedback accumulator stuff. I found this post which looked hopeful, but implementing a version of it supposedly tailored to my current 96k setup (it's a pain to get Windows to change it, and I may as well torture test as I go!) doesn't seem to be working. I get an underrun and audible glitch every 30s or so, which is probably more a reflection of the clock mismatch I happen to have in my system than any reproducible result.

    A couple of points occur to me, though I freely confess I'm no expert on the USB internals:
    • nothing ever actually seems to call sync_event() after the initial configuration
    • feedback_accumulator only ever seems to get modified in the input code, so USB transmit-only systems will likely have issues

  13. #38
    Member mcginty's Avatar
    Join Date
    Nov 2022
    Location
    The vast midwest, USA
    Posts
    20
    @h4yn0nnym0u5e, I've started the arduous work of reading through the USB Audio Spec and comparing it to the descriptor as well as documenting more: https://github.com/mcginty/teensy-cores/pull/4

    Interestingly, while the input side of the Teensy's USB descriptor is an Asynchronous Isochronous endpoint with a feedback synch endpoint, the output side of the descriptor does not in fact have an asynchronous synch endpoint, and reports itself as an Adaptive Isochronous endpoint, with no feedback synch endpoint...

  14. #39
    Senior Member h4yn0nnym0u5e's Avatar
    Join Date
    Apr 2021
    Location
    Cambridgeshire, UK
    Posts
    730
    Great, thanks for taking that on. Looks like quite a mountain to climb... Hopeful that someone might respond to my re-opening of this thread, though one of the major contributors seems to have disappeared about a year back

  15. #40
    Interestingly, while the input side of the Teensy's USB descriptor is an Asynchronous Isochronous endpoint with a feedback synch endpoint, the output side of the descriptor does not in fact have an asynchronous synch endpoint, and reports itself as an Adaptive Isochronous endpoint, with no feedback synch endpoint...
    I was wondering about this and am really interested to see what your investigation digs up!

  16. #41
    Quote Originally Posted by mcginty View Post
    Hi all!

    As a side note, I had 5 PCBs made of that CS42448 test board, and have... 4 left, and am happy to mail them to anybody else in North America that want to try their hand at soldering one (can send my Digikey cart to show you what to order too). Feel free to message me.

    Would be happy to collaborate if anybody else is working on similar projects. I'm doing this work to start on a DJ/DIY-focused mixer (kind of similar to the Teenage Engineering TX-6, but hackier of course . I made my first prototype with an STM32, and damn, so much respect to Paul and everybody who's worked on the Teensy and its libraries for creating such a fantastic playground.
    A little late on the draw here, but if you still have any CS42448 boards you’d like to divest yourself of I’d happily cover shipping and any other handling costs.

    Our goals are nearly in parity and I’d love to collaborate, though in the interest of full disclosure I’m a little over-encumbered at the moment. I’m happy to help with the caveat that it would be a bit haphazard. The likelihood is very high I have code to contribute that doesn’t crossover with your own - this might prove to be a productive start.

    Feel free to reply or DM.

  17. #42
    Senior Member h4yn0nnym0u5e's Avatar
    Join Date
    Apr 2021
    Location
    Cambridgeshire, UK
    Posts
    730
    It would be good to complete this, though @mcginty seems to have gone AWOL in 2023. I think we got to the point that a lot of stuff was working, or very nearly so, with the following on my radar as needing completion:
    • USB sync - I was getting the occasional glitches using Windows, though mcginty seemed to be having better luck on Linux
    • working and valid packet sizes at all sample rates and channel counts; at the moment invalid packet sizes of >1024 bytes are working with 1ms intervals, but changing them to <1024 bytes at (say) 500µs intervals doesn't work
    • do something sensible for the relevant USB descriptors when more bandwidth is specified than full-speed USB can provide

    This is all quite deep USB stuff which I don't understand - if you do, it would be great to have your input!

Posting Permissions

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