New library for PWM playback from SD cards: SimpleSDAudio

No, I have not changed the library yet. Maybe I will do it later after documenting it better - you only need the new batch file. We should try level-shifters or buffers (anything that is very cheap and easy available) to improve the sound (should be placed between Arduino outputs 9/10 and resistor stuff.

I haven't messed out with the library source yet, but do you think it would be possible to get a more instant playback and re-play by setting an initial file, and just have it play, and re-play when requested? This way I could use this to playback long drum sounds. (crashes and cymbals) I need this for a small project I'm doing. :wink: Maybe an option to open the file and have it used until said to open a new one? Also, an option to re-start the file, even if its not done yet, for when you play a drum sound, you are in the middle, but needs to re-trigger the sound.

I wonder one thing, would it be possible to handle 16-bit stereo files? Using 4 x pwm outputs for 2 x 16-bit hybrid dacs? What's the limitation them? I see that a 5Mb SD Card can handle it without problems, is the bottle-neck the SPI or the ATmega itself? Maybe running at 20Mhz would help? Just wondering, as it would be KILLER to be able to play 16-bit stereo files.

In any event, it should be possible to handle mono 16-bit 31khz .WAV files now, right? I know how to handle WAV files, so I will see if I can be of any help on this...

With this I got a perfect loop:

 while (1)
  {
    // Start playback
    SdPlay.play();
  
    // Let the worker work until playback is finished
    while(!SdPlay.isStopped()) {
      SdPlay.worker();
    }
  }

I just tested the 16-bit hybrid dac with your code, as explained, and I love it, great quality! 8) I hear a strange buzz on the background, is that the PWM? I'm using an external power-adapter and running the ATmega328 at 3.3V, to keep the SD Card connections simpler.

I haven't done your full 16-bit dac specs, I used a 256k and just one 1k resistor, so now I will try the way you did, to see if the buzz goes away. :wink:

Thank you so much for the hard work on this lib!! :grin:

The project I'm working requires 4 loops to be played, not at the same time, but with the option to go from one to another. So I wonder if I could do some sort of pre-buffering for all 4 files, in a way I could just go from one to another with min. gaps?

Ok, I found the buzz sound problem. It was the 3.3 V thingy. Now I'm running at 5V and using a proper SD Card adapter for Arduino (it has all the voltage converters) and it sounds GREAT! Thanks again! 8) 8)

Darn, the buzzing sound is still there, its from the PWM output. But its much lower now, compared to before.

Ok, assuming you can also hear the buzzing sound there, how about using 2 timers? One for the DAC and another one for the sample-rate. For instance, Timer1, which you already use now for both sample-out and sample-buffering, you could leave just for the DAC and setup for 9 bits, so the frequency of PWM is much faster. Then another timer for the rest, lets say, Timer2.

I will check the code when possible to see if I could just hack it and hear the result.

At least on my 6-voice sampler I did it with a higher frequency PWM using Timer1 and there's no buzzing sound. Unless my chip is faulty. I will test my 6-voice sampler on this same setup, just in case. :wink: Here's the link: https://github.com/Beat707/BeatVox

Again, thanks for doing this lib, I'm really loving it! 8)

Darn, I can't figure out this buzzing sound, no idea where its coming from, maybe the SPI interface? (doubt that) What I see you did different from my 6-voice thingy, is that you take a bit to update the PWM outputs, I do it first-thing, from a 2-byte buffer, maybe that could help? I will try that. :wink:

Darn thing, it does sound like the SPI. Here's a simple test.

uint8_t bufferL = 80, bufferR = 80;
 
void SdPlayClass::interrupt(void) 
{
	//SSDA_OC1L = bufferL;
	//SSDA_OC2L = bufferR;
	
	SSDA_OC1L = 255;
	SSDA_OC2L = 255;	

  uint8_t  flags = _flags;  // local copy for faster access
 
...
void setup()
{ 
  SdPlay.init(SSDA_MODE_HALFRATE | SSDA_MODE_STEREO);
  SdPlay.setFile("Loop5.a16"); // 16-bit mono file - half rate
   
   while (1)
   {
     SdPlay.play(); while(!SdPlay.isStopped()) { SdPlay.worker(); }
   
     pinMode(SCK, INPUT);
     digitalWrite(SCK, HIGH); 
     delay(1000);
     pinMode(SCK, OUTPUT);    
   }
...

I can hear the buzzing sound, once the loop is done, it will pause for 1 second without the buzz sound.

Unless I'm doing this test wrong. :wink:

Well, it does seem to be the SPI clock leaking somewhere, not sure what to do... any ideas? :blush:

Hi,

the buzzing sound can come from anything on the Arduino or stuff connected to it. I don't think that you can get rid of it just by optimizing the software - increasing sample rate will not change things. The quality out of the PWM is already superior, but get's damaged by the noise on the supply lines.
Therefore as I proposed before try to use something that "isolates" the digital PWM lines from power source. Use a buffer or a level shifter. Then filter the supply for that level shifter very thouroughly using an own linear regulator or at least a serial resistor with a capacitor to gnd between VCC-digital and VCC-analog.

Regarding 4channel mode: If I translate the interrupt function to assembler then it should be possible to have enough computing power for stereo 16 bit playback...

Regarding pre-load: The function setFile stores internally something about the file in a small structure. By using that struct it should be possible to playback any file with very little latency. Maybe I will add this feature later to the library.

Tuttut:
the buzzing sound can come from anything on the Arduino or stuff connected to it. I don't think that you can get rid of it just by optimizing the software - increasing sample rate will not change things. The quality out of the PWM is already superior, but get's damaged by the noise on the supply lines.
Therefore as I proposed before try to use something that "isolates" the digital PWM lines from power source. Use a buffer or a level shifter. Then filter the supply for that level shifter very thouroughly using an own linear regulator or at least a serial resistor with a capacitor to gnd between VCC-digital and VCC-analog.

For now I will ignore the buzz sound, I deal with that later on. :wink: Txs bud.

Tuttut:
Regarding 4channel mode: If I translate the interrupt function to assembler then it should be possible to have enough computing power for stereo 16 bit playback...

Oh! oh! oh! That would rock!!!!!!!

Tuttut:
Regarding pre-load: The function setFile stores internally something about the file in a small structure. By using that struct it should be possible to playback any file with very little latency. Maybe I will add this feature later to the library.

Indeed, shouldn't be too hard for me to just hack the thing out if I really need. So far I'm just using the setFile and it still works great!

Thanks again!

Cheers, WilliamK

Just wanted to thank you again for such great library. 8)

I managed to find the buzzing sound, it was my wiring, a friend told me to not use too long wires to connect to the SD Card, that was the reason of why the SPI Clock was leaking to the PWM outputs. Its solved now.

I still wonder if it would be possible to handle WAV files (saved at the right sample-rate) but its not a big deal to convert things up, just wondering. (one less step for newbies)

The 16-bit mono support is great, but yes, stereo support would put this lib in a new position.

I plan on using 4 loopers running side-by-side, already got extra ATmega328 + Crystals here to do so. :wink: Just need some extra time, prob next week...

hey guys...

I dusted off my 2009 board.. and want to give this library a try and compare it to the output Im getting using dedicated hardware and the WaveHC library (.wav files)

what is the wiring set-up you guys have going?

I have an SD card (made a little break out board for it).. and plugs into my Arduino 2009 board.. with the correct resistors for level shifting..etc..

reads/writes fine using SDFat libraries to test..

what else is there? what pins are you using for the speaker output? what other components are needed?

off to download library now..

thanks!

The wiring is described on the website. If you are using a shield already for SD card connection, all you need is a capacitor (take anything you get between 100nF and 100uF), connect positive end of capacitor to Arduino-Audio-Outputpin (as described in library documentation) and connect the other to your active speaker/line in. Then also connect GNDs of active speaker/line in and Arduino and you are done. That way you can play back the example file or any other files converted to MONO and FULLRATE or HALFRATE.

HI I just downloaded your lib to finally play with it..

I (finally) noticed everything is .ino or for Arduino 1.0 only?

I tried to put your lib in my libraries folder..but it never showed up (Im still using IDE v.23)

is there a version for older IDEs?

update:

installed IDE v1.0 justto try this..

did minimal (10uF cap, speaker approach)..

sounds great!.. awesome job on using minimal components..with default Arduino!!!

this adds so much more ability/options for projects..

question (since Im a noobie)..

are we free to do whatever we want during the audio playing? any restrictions?

what about having other components on the SPI bus?

thanks.. =)

thanks

Hello,

is there a version for older IDEs?
No, currently you need at least Arduino 1.0 IDE.

are we free to do whatever we want during the audio playing? any restrictions?
It depends... You have to call the worker()-function frequently enough to avoid buffer underruns. This function reads the next sector from SD card into a ringbuffer to keep audio playing running.

The library uses timer1 on most Arduinos (timer5 on mega arduino). This should be no issues for standard libraries, but libraries which uses those timers may not work correctly. analogWrite() functions should work even with that modified timer. The timer's interrupt is used to for audio playback, disabling interrupts for more than 10 micro seconds could result in playback distortions. In general, very much of the available computing power of the Arduino is used during playback...

what about having other components on the SPI bus?
The lib could work with other stuff on the SPI bus as long as it has its own chip-select and does not need to change the spi transfer parameters (SD lib uses full speed). It seems to work with the Ethernet-Shield - also an example to start playback via webbrowser is included in the examples. For other SPI stuff it depends - just try it...