New Library: RF24Audio - Realtime Audio Streaming, Multicasting and More

I mentioned a little while back in a couple posts that I was developing a wireless audio library for Arduino, and it has finally come to fruition. Many people are familiar with my WAV Audio library for playing audio from SD cards using Arduino, and I've developed another related library for wireless audio streaming.

The new library relies on my optimized RF24 library fork which enhances the speed and reliability of NRF24L01 radio modules, and is required for proper use of the RF24Audio library. The integration with the core radio library allows additional features like streaming wireless audio directly to a PC for analysis and/or recording of the audio.

Beginner Arduino users can create simple radios or intercom devices at very low cost, simply by connecting a microphone, speaker and radio module, and running one of the example sketches. The audio can be broadcast in realtime to one or more groups of radios running the RF24Audio library.

The library also integrates directly with the TMRpcm audio library, so users can also broadcast audio from SD card wirelessly in the case of such things like halloween displays etc, where everything can be timed and broadcast wirelessly from a single Arduino.

Documentation/Downloads can be found here: http://tmrh20.github.io/RF24Audio/

Optimized RF24 Radio Library: GitHub - nRF24/RF24: OSI Layer 2 driver for nRF24L01 on Arduino & Raspberry Pi/Linux Devices
TMRpcm SD Audio Library: GitHub - TMRh20/TMRpcm: Arduino library for asynchronous playback of PCM/WAV files direct from SD card. Arduino Uno,Nano,Mega etc supported

*Edit to add youtube demonstration : Technologic - Wireless Digital Audio Multicasting with Arduino: RF24Audio library released - YouTube

1 Like

impressive!
well written libs !
+1

Can you use any kind of arduinos to transmit and receive?

Thanks robtillaart!

tsunamy_boy: Yeah, pretty much any board with an ATmel 328 chip like the Uno should work fine. I've specifically tested with Arduino Duemilanove, Nano, Pro-mini (5v 16mhz), and Mega2560 boards. Arduino Due is not supported currently.

TMRh20:
Thanks robtillaart!

tsunamy_boy: Yeah, pretty much any board with an ATmel 328 chip like the Uno should work fine. I've specifically tested with Arduino Duemilanove, Nano, Pro-mini (5v 16mhz), and Mega2560 boards. Arduino Due is not supported currently.

ok i just found out that you are the same guy from a video that i found out yesterday. So i have to ask you: do you have a schematic for this one Wireless Digital Audio Streaming Realtime with Arduino and an NRF24 Module - YouTube ?
I'm trying to do the same thing, but i'm not having any results, just noise :frowning:

Other question: Why do you need a SDcard module since you are streaming it from your audio jack phone?

Heh, that would be me.
I've posted some initial board/wiring info here: http://tmrh20.github.io/RF24Audio/Setup.html and attached a few pictures here, including schematic type diagrams, which will likely get added to the main documentation page eventually. I couldn't seem to find a good fritzing part for NRF24L01 modules, so that is probably not the best example. The buttons aren't needed if using serial commands for testing etc.

The SD module in the video is only really there because it was just easier to not disconnect it, since I was also experimenting with improvements when streaming audio from SD card at the time. You can probably tell that video production is not one of my strong points.

Please keep in mind the current schematics are designed to be about as simple as possible, while producing OK results, and have just been put together (Hopefully no errors). During development, I generally just grab the closest parts that will work, and stick them together. I'm sure that adding some low-pass filters etc would increase sound quality a fair bit, and that there are at least a few folks on these forums who could provide much better advice on that type of thing than I.

Cool thanks.
Can you do me a quick favor (i believe you already did that in this project), tell me please the source to convert from the analog port to PWM port (analog to digital) cuz i already tried it and i just got noise coming out :frowning:

tsunamy_boy:
... tell me please the source to convert from the analog port to PWM port (analog to digital) cuz i already tried it and i just got noise coming out :frowning:

Not sure what you are asking here? In my video, I used an iPod connected to the preamp circuit. If using a microphone breakout, they usually have an opamp or something to manage the pre-amp function, and the gain would need to be adjusted. It uses the onboard ADC reading pin A0 to convert from analog to digital, then uses timer1 pwm functions to reproduce the PCM audio. The default volume might be a bit high, so adding rfAudio.setVolume(4); may resolve the issue also.

I was asking if you have source code to redirect sound from the A0 port to the PWM port you have used, but just that thing.

Oh, in that case, yup. The library has the feature of redirecting directly to pwm output while transmitting, and this is that same code simplified in sketch form:
I kind of hate to say it, but if you need assistance with this code, read the datasheet. That is about the only way to learn.

#define SAMPLE_RATE 32000
volatile unsigned int sampleData;



void setup() {
  
  pinMode(9,OUTPUT);
  pinMode(10,OUTPUT);
  
  /******* Set up timer1 ********/
  ICR1 = 10 * (1600000/SAMPLE_RATE);                 // For PWM generation. Timer TOP value.
  TCCR1A = _BV(COM1A1) | _BV(COM1B0) | _BV(COM1B1);  //Enable the timer port/pin as output
  TCCR1A |= _BV(WGM11);                              //WGM11,12,13 all set to 1 = fast PWM/w ICR TOP
  TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10);      //CS10 = no prescaling
  
  /******** Set up the ADC ******/
  ADMUX = _BV(REFS0);                                // Set analog reference to 5v
  ADCSRB |= _BV(ADTS1) | _BV(ADTS2);                 // Attach ADC to TIMER1 Overflow interrupt
    
  byte prescaleByte = 0;                             // Adjusts the ADC prescaler depending on sample rate for best quality audio

  if(      SAMPLE_RATE < 8900){  prescaleByte = B00000111;} //128
  else if( SAMPLE_RATE < 18000){ prescaleByte = B00000110;} //ADC division factor 64 (16MHz / 64 / 13clock cycles = 19230 Hz Max Sample Rate )
  else if( SAMPLE_RATE < 27000){ prescaleByte = B00000101;} //32  (38461Hz Max)
  else if( SAMPLE_RATE < 65000){ prescaleByte = B00000100;} //16  (76923Hz Max)
  else   {                       prescaleByte = B00000011;} //8  (fast as hell)

  ADCSRA = prescaleByte;                        // Set the prescaler
  ADCSRA |= _BV(ADEN) | _BV(ADATE);             // ADC Enable, Auto-trigger enable


  TIMSK1 = _BV(TOIE1);          //Enable the TIMER1 interrupt to begin everything
}




ISR(TIMER1_OVF_vect){
  
  OCR1A = OCR1B = ADCL | ADCH << 8;  // Read the ADC values directly into the timer compare register.
  
}



void loop() {


}

Cool! That works just fine. But one quick question, how can i get the values that you are sending throw the PWM 9 and 10 would you please println those 2 variable on the loop() function?

You either read the ADC registers, or the TIMER1 compare registers. As I said, you're going to have to read the data sheet if you need more help with that code.

Its not as simple as just printing the values in the loop function, since timing is generally important. If I had some idea of what you were trying to do, I could provide an example, but I'm not going to write your code for you.

TMRh20:
You either read the ADC registers, or the TIMER1 compare registers. As I said, you're going to have to read the data sheet if you need more help with that code.

Its not as simple as just printing the values in the loop function, since timing is generally important. If I had some idea of what you were trying to do, I could provide an example, but I'm not going to write your code for you.

I understand, i wouldn't ask you for code, i just need a push of understanding.
My project is really similar to yours (audio throw RF and 2 arduinos), i could just use your code but i wouldn't learn how to do it and i love electronics, i can't just copy-upload your source and that's it.

I have some questions if you could tell me i would be thankful (its about your provided source):

  • Where did you say to the arduino to work with port 9 an 10, besides defining them as output, where are you using them?
  • Why 2 ports instead of just 1 and GND?

Its not as simple as just printing the values in the loop function, since timing is generally important. If I had some idea of what you were trying to do, I could provide an example, but I'm not going to write your code for you.

I just wanted the ADC values somewhere so i could work with them because i don't know where to get them, what should i do?

tsunamy_boy:

  • Where did you say to the arduino to work with port 9 an 10, besides defining them as output, where are you using them?
TCCR1A = _BV(COM1A1)  | _BV(COM1B0) | _BV(COM1B1);  //Enable the timer port/pins as output
OCR1A = OCR1B = ADCL | ADCH << 8;  // Read the ADC values directly into the timer compare register.

Why 2 ports instead of just 1 and GND?

To enable complimentary (push/pull) speaker output instead of push/null.

I just wanted the ADC values somewhere so i could work with them because i don't know where to get them, what should i do?

Either use analogRead() to get the ADC values, or learn how to work with the registers.

I would recommend checking out Arduino - Home and looking at the bitwise &, | and << >> (bitshift) operators if you are not already familiar with them. That will help to understand how to work with binary data.

From there, read the datasheet if you really do want to learn. If you can understand the concepts of working with bits and bytes via the above operators, then its just a matter of writing/reading the correct values to/from the registers to work with or control any aspect of the MCU.

I can lead you to water, but I cannot force you to drink...

ok so just one last question:

ISR(TIMER1_OVF_vect){
// Read the ADC values directly into the timer compare register.
OCR1A = OCR1B = ADCL | ADCH << 8;
}

OCR1A would be Port 9, OCR1B would be Port 10, and ADCL | ADCH << 8; would be the Bitwise OR with the adding of 8 zero bits on the left, this represent the wave values for each clock circle, right? So i should send this calculation ADCL | ADCH << 8; throw RF.

Can i put on this ISR function my usual source to send the bits throw my RF24 like if i was sending something else? Or i also need to take a look on the RF24 datasheet to send this data?

Which is the one last question?

]:smiley:

TMRh20:
Which is the one last question?
]:smiley:

Ok, the last questions :frowning:
If you could answer them i would be grateful.
Thanks for your time

Well the answer is yes and no because again, it depends on what exactly you are doing.

I use two separate ISRs along with 'nested interrupts' to due to timing issues.

The TX_0 sketch found here GitHub - TMRh20/Sketches: Arduino Audio Streaming Realtime, NTSC Video may be easier to look at than the library code, and shows how this is done. This is the sketch I used to develop the libary initially.

All my library documentation can be found here: http://tmrh20.github.io/
My blog is here: http://TMRh20.blogspot.com
The datasheet is here: http://www.atmel.com/dyn/resources/prod_documents/doc8161.pdf
Arduino Reference: Arduino - Home

All the information you need is there. Not trying to be rude, but you really need to understand what is going on if you ever hope to write this type of code yourself, and the only way to do that is to put in the effort, and read the documentation and examples provided.

Ok thank you, i'll do my best to understand and do it by myself.
Have a great day and thanks for your time once again.

Best of luck with your projects

Hello,

I'd like to know if it is possible to send information during the audio streaming. For example, pressing a button on the transmitter card that turns on an LED on the receiver board.

Thanks for this project and for the help.
Emile