Pages: 1 ... 3 4 [5] 6 7 ... 14   Go Down
Author Topic: New library for PWM playback from SD cards: SimpleSDAudio  (Read 32183 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 66
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Opps, i think I dumped my first post... appologies if this ends up being a duplicate.

I am having some unexpected behavior with some SimpleSDAudio code. I am basically working on a lightsaber and I want the code to play a HUM.AFM file whenever something else isn't playing.

Simple enough. The issue I am running in to is that SdPlay.isStopped() returns false (0) when the code goes in to the first "loop(void)" even though nothing is playing. While that is easy enough to code around it seems it should in fact return true (1). Once kicked over through one loop it seems to work fine.

Code:
void loop(void)
{
Serial.println(F("Loopy"));
 Serial.println(SdPlay.isStopped());
  if (SdPlay.isStopped()) {
    SdPlay.setFile("Hum.afm");
    SdPlay.play();
}
 while(!SdPlay.isStopped()) {
    SdPlay.worker();
   }
}

Anyway.... not a huge deal, it just seemed odd.
Logged

0
Offline Offline
Jr. Member
**
Karma: 0
Posts: 66
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Further details..... my "fix" was just calling to

    SdPlay.setFile("");

In the void setup() section. That seems to get the ball rolling too.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 15
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Pin 44 on my mega 2560 is committed to another function that I cannot change. So is it possible to use a different timer (like timer4) for PWM output with this code?
Logged

Offline Offline
Jr. Member
**
Karma: 6
Posts: 73
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,
for performance reasons, audio pins are fixed in the library. But the library is written in a way, that all that must be defined to use a certain timer is placed in the file SimpleSDAudioDefs.h, so take a look in that file, maybe you can patch it for your purposes. All defines there are used from assembly as well as c-files, so there should no need to touch any other files.
Logged

Offline Offline
Jr. Member
**
Karma: 6
Posts: 73
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

@TroyO
Hi, I've analysed your stop-issue, I think you are right, there is a little bug in the library that clears the stop-flag in the init-function. Calling SdPlay.stop(); after .init should also solve the issue.
Logged

0
Offline Offline
Edison Member
*
Karma: 7
Posts: 1221
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

good to know tuttut-


@TroyO-

I saw the 'double press' in the video..

glad it can all be 'fixed' with a line of code.  smiley

I'll be using this heavily in a project over the next 3-4 weeks..

I have high hopes for this lib. smiley


(will be starting next week hopefully!)  smiley

Logged


East Texas
Offline Offline
Newbie
*
Karma: 0
Posts: 14
It doesn't take a genius to break anything!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

This is a really good lib. Been playing with it all morning, really should be doing work on my other project, and I've had no problem playing files converted with:
Code:
$ sox inputfile -b 8 -r 64000 -c 1 -t raw outputfile

Good work on getting all this together, I bought an arduino with a few projects in mind, but never thought
I'd be playing music off of the thing. Keep up the awesome progress!
Logged

"Hold my rootbeer and watch this" - Charlie and I

New York
Offline Offline
Sr. Member
****
Karma: 3
Posts: 362
xronosclock.com
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Fantastic library, got it working within few minutes!  smiley
Is it possible to play Audio in parallel while Arduino does other things?  I wasn't able to figure out how. I wanted to see if I can dump WaveShield in favor of this library. WaveShield allows me to play Audio regardless of other things I'm doing, which is essential for my Alarm clock (shows time, blinking dots while playing alarm audio file).
I did some testing with SimpleSDAudio and it looks like if delay between calling SdPlay.worker() greater than 5 milliseconds, playback slows down and becomes choppy... Even calling Serial.println ("test") slows down playback noticeably. Here's example of code from loop:
Code:
void loop(void) {
  Serial.println ("running");
  //delay (5);
   if (!SdPlay.isPlaying() ) SdPlay.play();
  // Let the worker work until playback is finished
  SdPlay.worker();
 }
Let me know if there's a trick to it smiley
Maybe buffer can be auto-filled by Interrupt?
« Last Edit: January 02, 2013, 08:02:59 pm by bratan » Logged

Xronos Clock - A talking arduino based alarm clock is now available. Check out xronosclock.com for pictures, source code, schematics, and purchasing info smiley

East Texas
Offline Offline
Newbie
*
Karma: 0
Posts: 14
It doesn't take a genius to break anything!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Fantastic library, got it working within few minutes!  smiley
Is it possible to play Audio in parallel while Arduino does other things?  I wasn't able to figure out how. I wanted to see if I can dump WaveShield in favor of this library. WaveShield allows me to play Audio regardless of other things I'm doing, which is essential for my Alarm clock (shows time, blinking dots while playing alarm audio file).
I did some testing with SimpleSDAudio and it looks like if delay between calling SdPlay.worker() greater than 5 milliseconds, playback slows down and becomes choppy... Even calling Serial.println ("test") slows down playback noticeably. Here's example of code from loop:
Code:
void loop(void) {
  Serial.println ("running");
  //delay (5);
   if (!SdPlay.isPlaying() ) SdPlay.play();
  // Let the worker work until playback is finished
  SdPlay.worker();
 }
Let me know if there's a trick to it smiley
Maybe buffer can be auto-filled by Interrupt?


Don't quote me on this, but from looking at the code, I think you could do such given that you make a call to the SdPlay.worker() function often enough to keep the buffer filled. I'm not sure how much of the processor is left once playing audio, but it seems you could squeeze in a few other non time dependent things. (Like adding up time or checking for a button and updating its state...simple things)

From what I have gathered, the SdPlay.worker() function reads the next sector of the sdcard into a buffer. So if you call it often enough, you should be okay, just don't ask for anything that needs a ton of resources while playing audio.

Feel free to correct me if I'm wrong, but this is what I have gathered so far.

Edit: Just from playing with the serial I can see what you are saying, but I haven't come up with a solution.
Edit2: If you hear the skip when using serial at 9600, move it to a higher speed. I'm running at 115200 just to see, and there isn't a noticeable skip when using the serial commands in the demo.
« Last Edit: January 02, 2013, 09:09:22 pm by timberwolf9 » Logged

"Hold my rootbeer and watch this" - Charlie and I

Offline Offline
Newbie
*
Karma: 0
Posts: 27
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi

I'm exited about this library. I might have a troublesome SD Card module.
I keep getting an error code: 49. I cant find out what code 49 is.
If I use Arduino's standard SD example listfiles, I get a correct list of files on the SD card. The SdFat library from http://code.google.com/p/sdfatlib/ also read the SD Card with the same wiring. So the wiring must be correct. And I use SdPlay.setSDCSPin(10); as pin 10 is my CS pin.
Then I commented the line: SPSR |= (1 << SPI2X);
Same result.

My sd module is this one http://www.lipoly.de/index.php?main_page=product_info&products_id=213383

I really hope someone can with this problem.

EDIT ----
It was not the SD Card Module but the SD Card itself. I tried with another one. Now it works.
« Last Edit: January 03, 2013, 03:25:07 pm by AllanB » Logged

New York
Offline Offline
Sr. Member
****
Karma: 3
Posts: 362
xronosclock.com
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset


Don't quote me on this, but from looking at the code, I think you could do such given that you make a call to the SdPlay.worker() function often enough to keep the buffer filled. I'm not sure how much of the processor is left once playing audio, but it seems you could squeeze in a few other non time dependent things. (Like adding up time or checking for a button and updating its state...simple things)

From what I have gathered, the SdPlay.worker() function reads the next sector of the sdcard into a buffer. So if you call it often enough, you should be okay, just don't ask for anything that needs a ton of resources while playing audio.

Feel free to correct me if I'm wrong, but this is what I have gathered so far.

Edit: Just from playing with the serial I can see what you are saying, but I haven't come up with a solution.
Edit2: If you hear the skip when using serial at 9600, move it to a higher speed. I'm running at 115200 just to see, and there isn't a noticeable skip when using the serial commands in the demo.
No you are right, my thoughts exactly (about buffer). I also guessed that increasing baud rate will improve things, but never tested it so you just proved it smiley It makes sense. However I'm just wondering how did they pull off the trick with WaveShield? I can do lots of heavy things with microprocessor while wave is playing, it never skips a beat... Can same be accomplished with this library? smiley  Or because there's no DAC it's impossible to do?  I'm curious to hear what author thinks.
Logged

Xronos Clock - A talking arduino based alarm clock is now available. Check out xronosclock.com for pictures, source code, schematics, and purchasing info smiley

East Texas
Offline Offline
Newbie
*
Karma: 0
Posts: 14
It doesn't take a genius to break anything!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi

I'm exited about this library. I might have a troublesome SD Card module.
I keep getting an error code: 49. I cant find out what code 49 is.
If I use Arduino's standard SD example listfiles, I get a correct list of files on the SD card. The SdFat library from http://code.google.com/p/sdfatlib/ also read the SD Card with the same wiring. So the wiring must be correct. And I use SdPlay.setSDCSPin(10); as pin 10 is my CS pin.
Then I commented the line: SPSR |= (1 << SPI2X);
Same result.

My sd module is this one http://www.lipoly.de/index.php?main_page=product_info&products_id=213383

I really hope someone can with this problem.

EDIT ----
It was not the SD Card Module but the SD Card itself. I tried with another one. Now it works.

Just my two cents, I had this same error and was to fix it by reformatting the sd as FAT. You may be able to do the same with your sd, but don't use the quick format or the card will give the same error.
Logged

"Hold my rootbeer and watch this" - Charlie and I

Offline Offline
Jr. Member
**
Karma: 6
Posts: 73
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi, I will try answer some of your questions:

@timberwolf9:
Why the argument -r 64000? If you use a 16 MHz Arduino, it should be 16 MHz / 256 = 62500. But anyway, the sound is just a little bit to slow then...

@bratan & timberwolf9:
I will tell you some internal details about my library: The library uses a ring buffer of 1024 bytes when no work buffer is set manually. As the buffer is filled in one sector blocks of 512 bytes each, the buffer became a ping-pong buffer in most cases. With 512 bytes, at 8-Bit/Mono/62.5kHz that is about 8ms time, because the data reading from sd-card also takes some time, your observation of 5ms max delay between worker()-calls is very realistic.

On mega-arduinos is still a lot of RAM availible, so you can try to increase the audiobuffer by calling setWorkBuffer(...) before calling init(). With an increased buffer you will get more time between worker-calls.

By using the function isUnderrunOccured() you can detect if you even had a slight buffer underrun. But beware, I think this function returns true on every first call after calling play().

I also thought about calling the worker-function automatically in a timer interrupt. This should be possible, but only if that interrupt is set to non-blocking to guarantee the main audio interrupt the maximum priority. Maybe I will try to implement such in a next version of my lib, so that calling worker() is not necessary then anymore.

@AllanB:
Error code 49, which is 0x31, indicates that something is wrong with the bootsector on that cards. Maybe there is more than one partition on the card or something else is wrong. That explains why other cards work for you.

@bratan:
Yes, rising the baud-rate should solve issues with print-functions, as then the worker-calls are called more often.

To your question about other Audio-Playback-Shields: As far as I have seen it, all other audio-shields contain a dedicated processor that reads the audio-data from storage and feed it to an audio-DAC. For a good sound the DAC must be feed with low jitter at the audio rate of the audio material, otherwise you may recognize audio distortions like slowdowns or stuttering. With a dedicated processor it doesn't matter what your Arduino does while audio is playing, but my library is for all those who don't want to spend extra money to such a thing. SimpleSDAudio get the most out of the AVR's by pushing the Arduino processor strongly to its limits - that's the price you have to pay if you want nice audio from that little thing.

And one detail on top: The magic trick of getting a good sound out of the AVR's PWM is that mainly PWM-frequency matters more than anything else. It is the sampling rate of >32kHz that make the big difference between this lib and the well known bad telephone-like audio-playbacks often sampled at only 8 kHz of other approaches. With PWM frequency as high as 31/62kHz a low-pass is often not necessary. And you only need more than 8-bit if you want to listen to something that has not been as diddling dynamic compressed as most of the actual radio stuff nowadays is.
Logged

East Texas
Offline Offline
Newbie
*
Karma: 0
Posts: 14
It doesn't take a genius to break anything!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi, I will try answer some of your questions:

@timberwolf9:
Why the argument -r 64000? If you use a 16 MHz Arduino, it should be 16 MHz / 256 = 62500. But anyway, the sound is just a little bit to slow then...

@bratan & timberwolf9:
I will tell you some internal details about my library: The library uses a ring buffer of 1024 bytes when no work buffer is set manually. As the buffer is filled in one sector blocks of 512 bytes each, the buffer became a ping-pong buffer in most cases. With 512 bytes, at 8-Bit/Mono/62.5kHz that is about 8ms time, because the data reading from sd-card also takes some time, your observation of 5ms max delay between worker()-calls is very realistic.


@Tuttut
"-r 64000" gives reasonably good audio on my arduino uno, it may be my setup that has gone wonk, but when converting using the rate you gave, the audio was always really high pitched and fast moving. So I played around with the terminal options for sox and found that to be a sweet spot where the audio tone and play speed are warm and spot on.

If I read the internals correctly, we could get away with performing micro task once the audio is playing. 704 is not a lot of RAM to play with, but for listening to the network and flashing a light, it may be enough. (704 is more than enough for flashing a light...I would think)

Also, Tuttut, I ran into the 49 error code on my card until I did a FAT format. Once that was done, everything else went smooth as butter.
Logged

"Hold my rootbeer and watch this" - Charlie and I

New York
Offline Offline
Sr. Member
****
Karma: 3
Posts: 362
xronosclock.com
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I also thought about calling the worker-function automatically in a timer interrupt. This should be possible, but only if that interrupt is set to non-blocking to guarantee the main audio interrupt the maximum priority. Maybe I will try to implement such in a next version of my lib, so that calling worker() is not necessary then anymore.

That would be awesome! smiley

To your question about other Audio-Playback-Shields: As far as I have seen it, all other audio-shields contain a dedicated processor that reads the audio-data from storage and feed it to an audio-DAC. For a good sound the DAC must be feed with low jitter at the audio rate of the audio material, otherwise you may recognize audio distortions like slowdowns or stuttering. With a dedicated processor it doesn't matter what your Arduino does while audio is playing, but my library is for all those who don't want to spend extra money to such a thing. SimpleSDAudio get the most out of the AVR's by pushing the Arduino processor strongly to its limits - that's the price you have to pay if you want nice audio from that little thing.

Thanks for the info!
I think MP3 decoder shield might have such processor, but not WaveShield. From description they only have DAC with some basic low pass filters.
BTW, I'm just trying to understand how things work, not in any way implying anything bad about your library. In fact I think it's brilliant work, nobody else did anything like this with no external hardware (other than SD card)!
Logged

Xronos Clock - A talking arduino based alarm clock is now available. Check out xronosclock.com for pictures, source code, schematics, and purchasing info smiley

Pages: 1 ... 3 4 [5] 6 7 ... 14   Go Up
Jump to: