ErnstMLuebeck
Member
Dear all,
Backstory below.
What already works
High quality (16 bit @ 44.1 kHz), low latency (~6 ms) audio stream from one Teensy to another using NRF24L01 modules.
What's my issue
Naturally, the sample rates of both Teensys are not synchronized and also not exactly the same. For the audio stream this means that they are slowly drifting apart and every 3.5 s or so, a few buffers are lost (I reduced the buffer size to 64 samples to achieve a lower latency, using the 128 sample buffer, the short drop-outs happen every 7 s - latency increases to ~12 ms).
The short drop-outs are clearly audible while transmitting a sine signal, however for music it's not even a big problem (music is basically just noise - hehe).
Anyway, if possible I'd like to fix or at least reduce it and here I need your help.
I think there are 2 ways of fixing this issue:
1. Synchronizing the sample rate of the receiver to the incoming data packets
2. Accurately measuring both sample rates and resampling the data using Sample Rate Conversion (This is typically used in DSPs to align digital audio data)
Looking into the AudioStream library, I don't see a way to alter the sample rate, or is there?
Also sample rate conversion is a quite involved operation. What do you think?
Hardware Transmitter (picture attached)
Teensy 4.0 with AudioShield and NRF24L01 module
Hardware Receiver
Teensy 3.5 with AudioShield and NRF24L01 module
(Just for testing I added a LiPo battery that I could walk around with it and a mute button)
Software Transmitter
I implemented an audio object (AudioNrf24Tx) which is connected to the I2S input of the audio shield (external 3.5 mm TRS socket). In the update() method, I just copy the buffer into a global vector. The buffer is then transmitted in 16 sample packets (NRF24 has a 32 byte payload = 16 sample á 16 bit, 2 bytes) with a delay of 300 us. The delay is necessary for the NRF24 to operate stable, I saw some weird carrier frequency drifting when the delay was shorter. Fortunately, 300 us is just enough to transmit all 4 packets before the next update() (buffer has 64 samples @ 44.1 kHz, update is triggered every 1.45 ms). The audio source can be switched between a sine synth block or the line input using a button. There is also a simple frequency hopping algorithm implemented which would allow higher RF power (at least in my region, EU), but it is currently disabled for easier testing (works however).
Software Receiver
The NRF24 module pulls the interrupt pin LOW whenever data is ready to read by the Teensy. Since 1 buffer is split into 4 transmission packets, I'm using a ping-pong buffer too handle the incoming data. If one buffer is filled with valid samples, it is released to the custom audio object (AudioNrf24Rx) to be output while the incoming packets are filling the second buffer in the meantime. In the update() method not much happens, only the data is copied into audio_block_t and the buffer is set to all 0.0. This helps a lot during debugging on the oscilloscope, however might not be the best way to mask missing buffers.
Backstory
Being frustrated with the "cheaper" (200-300€) UHF in-ear monitoring systems, I started to experiment a bit with the stuff I had on hand. Honestly, I was surprised that these data rates were even possible with the NRF24 modules. For in-ear monitoring on stage, a low latency is probably most important, since you are hearing your voice in your head and also through the headphones. In my experience <10 ms is fine but above that you get phasing issues and it sounds very unnatural. My cheap system not only has a lot of drop-outs and distortions, but also the audio quality is very poor. The current stage of this project is already much better and should work for band practice, where I need about 3 m/10 ft of range. Since I have now more time for such projects (thanks to covid19), I thought about using a second NRF24 module at the receiver to build a poor-persons diversity receiver. With a certain distance between the antennas, it could help to improve transmission stability. Any thoughts on that?
I'm looking forward reading your ideas and suggestions!
Best wishes,
Ernst.
Backstory below.
What already works
High quality (16 bit @ 44.1 kHz), low latency (~6 ms) audio stream from one Teensy to another using NRF24L01 modules.
What's my issue
Naturally, the sample rates of both Teensys are not synchronized and also not exactly the same. For the audio stream this means that they are slowly drifting apart and every 3.5 s or so, a few buffers are lost (I reduced the buffer size to 64 samples to achieve a lower latency, using the 128 sample buffer, the short drop-outs happen every 7 s - latency increases to ~12 ms).
The short drop-outs are clearly audible while transmitting a sine signal, however for music it's not even a big problem (music is basically just noise - hehe).
Anyway, if possible I'd like to fix or at least reduce it and here I need your help.
I think there are 2 ways of fixing this issue:
1. Synchronizing the sample rate of the receiver to the incoming data packets
2. Accurately measuring both sample rates and resampling the data using Sample Rate Conversion (This is typically used in DSPs to align digital audio data)
Looking into the AudioStream library, I don't see a way to alter the sample rate, or is there?
Also sample rate conversion is a quite involved operation. What do you think?
Hardware Transmitter (picture attached)
Teensy 4.0 with AudioShield and NRF24L01 module
Hardware Receiver
Teensy 3.5 with AudioShield and NRF24L01 module
(Just for testing I added a LiPo battery that I could walk around with it and a mute button)
Software Transmitter
I implemented an audio object (AudioNrf24Tx) which is connected to the I2S input of the audio shield (external 3.5 mm TRS socket). In the update() method, I just copy the buffer into a global vector. The buffer is then transmitted in 16 sample packets (NRF24 has a 32 byte payload = 16 sample á 16 bit, 2 bytes) with a delay of 300 us. The delay is necessary for the NRF24 to operate stable, I saw some weird carrier frequency drifting when the delay was shorter. Fortunately, 300 us is just enough to transmit all 4 packets before the next update() (buffer has 64 samples @ 44.1 kHz, update is triggered every 1.45 ms). The audio source can be switched between a sine synth block or the line input using a button. There is also a simple frequency hopping algorithm implemented which would allow higher RF power (at least in my region, EU), but it is currently disabled for easier testing (works however).
Software Receiver
The NRF24 module pulls the interrupt pin LOW whenever data is ready to read by the Teensy. Since 1 buffer is split into 4 transmission packets, I'm using a ping-pong buffer too handle the incoming data. If one buffer is filled with valid samples, it is released to the custom audio object (AudioNrf24Rx) to be output while the incoming packets are filling the second buffer in the meantime. In the update() method not much happens, only the data is copied into audio_block_t and the buffer is set to all 0.0. This helps a lot during debugging on the oscilloscope, however might not be the best way to mask missing buffers.
Backstory
Being frustrated with the "cheaper" (200-300€) UHF in-ear monitoring systems, I started to experiment a bit with the stuff I had on hand. Honestly, I was surprised that these data rates were even possible with the NRF24 modules. For in-ear monitoring on stage, a low latency is probably most important, since you are hearing your voice in your head and also through the headphones. In my experience <10 ms is fine but above that you get phasing issues and it sounds very unnatural. My cheap system not only has a lot of drop-outs and distortions, but also the audio quality is very poor. The current stage of this project is already much better and should work for band practice, where I need about 3 m/10 ft of range. Since I have now more time for such projects (thanks to covid19), I thought about using a second NRF24 module at the receiver to build a poor-persons diversity receiver. With a certain distance between the antennas, it could help to improve transmission stability. Any thoughts on that?
I'm looking forward reading your ideas and suggestions!
Best wishes,
Ernst.