Alternate USB Audio Code

shaynal

New member
Hi Group,

We are using the Teensy 4.0 as a morse code keyer for a software-defined amateur radio transceiver. Basically we connect a CW key to the Teensy 4.0, port (or some group members write new code for) a keyer program and then connect this to a Hermes-Lite 2.0 software-defined amateur radio transceiver. The Teensy 4.0 is attractive given the existing USB audio code and audio libraries. The receiver audio is sent to the Teensy 4.0 and then MIDI key signals are sent from the Teensy 4.0 back to the host. The important point is that when an operator presses the key, he or she should hear a tone with very low latency. The Teensy 4.0 provides this low latency key-to-ear path as well as mixing in the received audio at the same time. This project is already usable and working code can be found here and here.

In implementing this project, we ended up rewriting portions of the USB audio code. We wanted to share this fork for feedback. Maybe there are better ways to achieve what we needed. Maybe others can benefit from the code. We forked cores and the Audio library. Here is a summary of our changes:

** 48kHz. For a better match to the audio from the radio, we switched to 48kHz. Search for USB_AUDIO_48KHZ in the code. The top-level defines are in usb_desc.h and AudioStream.h. (We'd like a single define if easily possible.) The 44.1kHz code still exists. This may be a helpful template for others wanting to implement a different sampling rate.

** At least on the Teensy 4.0, we saw that at startup the Audio graph, usb_audio and Audio buffer memory pool being ready all started at various times. This variation along with the line "if (f) feedback_accumulator += 3500;" caused the feedback_accumulator to be way off right after power on. This would cause overruns, underruns, clicks, until the feedback_accumulator settled, sometimes after tens of seconds. We bounded the valid range of the feedback_accumulator as well as added a 2 second delay before feedback_accumulator calculations start. See usb_audio.cpp.

** Once the feedback_accumulator settled, we still saw more oscillation in the feedback_accumulator than we liked. We implemented a feedback calculation based on the USB SOF interval. This separates the feedback_accumulator calculations from the actual input/output rates and is what is recommended by the USB standard. We also developed a second method which is still based on the actual incoming/outgoing rates but includes an additional term for dampening. See USB_AUDIO_FEEDBACK_SOF and USB_AUDIO_FEEDBACK_DL1YCF usb_audio.h.

** The changes to the feedback_accumulator worked well and we see no over/underrun after hours of operation on Linux and Mac. But the feedback had no effect on Windows. The Teensy 4.0 is a UAC 1 device operating at high speed and uses a 16.16 feedback value. It turns out that the default UAC 1 Windows 10 driver will operate at high speed but still expects 10.14 feedback. There is some discussion about that here. We switched to 10.14 feedback even at high speed to accommodate Windows. We tested on Mac and Linux and both also work with 10.14 feedback at high speed.

** Since we want low latency from key press to audio, we added a ring buffer of buffers to usb_audio.cpp. With this, we can reduce AUDIO_BLOCK_SAMPLES to 32 and even 16 and still have USB audio (at least host to Teensy has been tested) work. See USB_AUDIO_INPUT_BUFFERS in usb_audio.cpp.


We would like to make some custom capes for the keyer application, or even use a RT101X or RT102X with the licensed Teensy bootloader. Does the bootloader already support RT101X/RT102X, or if not, would it be easy to add support?

Best Regards,

Steve Haynal
 
We would like to make some custom capes for the keyer application, or even use a RT101X or RT102X with the licensed Teensy bootloader. Does the bootloader already support RT101X/RT102X, or if not, would it be easy to add support?

While I have no idea what RT101X/RT102X is, I would be very surprised if PJRC licenses the bootloader chip code, which, however, is not a question to the forum.
All what I wanted to say is that, at least according to my observation, Paul is extremely careful to implement on Bootloader chip only the code that is required to boot-load the different teensies.
 
While I have no idea what RT101X/RT102X is, I would be very surprised if PJRC licenses the bootloader chip code, which, however, is not a question to the forum.
All what I wanted to say is that, at least according to my observation, Paul is extremely careful to implement on Bootloader chip only the code that is required to boot-load the different teensies.

I'm interested in the bootloader chip for the i.MX RT101X/RT102X as already available for the RT1062. I'm not asking to license the code. The i.MX RT101X and RT102X are members of the same family as the Teensy's i.MX RT1062 as seen in this family table. The RT101X/RT102X are a little less expensive with packaging more amenable to inexpensive assembly. How generic is the i.MX bootloader chip? Will it work with other members of the family?

Best Regards,

Steve Haynal
 
Hi Group,

Just a quick update on this. The teensy->host audio path now supports AUDIO_BLOCK_SAMPLES of 32 and 16 via a ring of buffers. Also, the number of samples sent to the host will fluctuate to keep the buffers about half full and prevent clicks, etc. of recorded audio. These changes support both the original 44.1kHz and the 48kHz used in the keyer project. The forked repositories are:
https://github.com/softerhardware/cores
https://github.com/softerhardware/Audio

Best Regards,

Steve Haynal
 
How generic is the i.MX bootloader chip? Will it work with other members of the family?
Ahh, you mean IMXRT10xx, that makes more sense.
Concerning Bootloader chip, history showed that Paul is only supporting (hard coded) MCU chips he is using for Teensies. Different models of the same family are not supported.
Only deviation from teensy could be different formfactor of the same chip, where Paul typically replies along the line: "could work but have not tested".
 
Back
Top