Go Down

Topic: New Library: RF24Audio - Realtime Audio Streaming, Multicasting and More (Read 41582 times) previous topic - next topic

TMRh20

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: https://github.com/TMRh20/RF24
TMRpcm SD Audio Library:  https://github.com/TMRh20/TMRpcm

*Edit to add youtube demonstration : https://www.youtube.com/watch?v=eTFsQIXMXA0

robtillaart

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

tsunamy_boy


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.

tsunamy_boy

#4
Apr 19, 2014, 11:16 pm Last Edit: Apr 19, 2014, 11:18 pm by tsunamy_boy Reason: 1

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 https://www.youtube.com/watch?v=2ZK6dcBTeT0 ?
I'm trying to do the same thing, but i'm not having any results, just noise :(

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

TMRh20

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. 

tsunamy_boy

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 :(

TMRh20


... 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 :(


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.

tsunamy_boy

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.

TMRh20

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.

Code: [Select]



#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() {


}


tsunamy_boy

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?

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.

tsunamy_boy



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?

Quote
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?

TMRh20


- Where did you say to the arduino to work with port 9 an 10, besides defining them as output, where are you using them?

Code: [Select]

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.


Quote
Why 2 ports instead of just 1 and GND?


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

Quote
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 http://arduino.cc/en/Reference/HomePage  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...

tsunamy_boy

#14
Apr 21, 2014, 09:07 pm Last Edit: Apr 21, 2014, 09:43 pm by tsunamy_boy Reason: 1
ok so just one last question:
Quote
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?

Go Up