New library for PWM playback from SD cards: SimpleSDAudio

I think the next improvement I will make is to use a 256R-R network to go from 8 bit to 16 bit with just another port and 3 resistors.

Niiice, I wonder about that.

Plus, I wonder about the ATtiny85 too.

Thanks! 8)

Question about the ATtiny85, as I also use those and have a few to test out, what kind of bit-depth are we talking with those? I'm not talking about SD card playback, just internal flash playback, as I'm doing another project, and all I need is to be able to play a single drum sound from the ATtiny85, but I need better quality, as better possible. :wink:

Thanks again! :grin:

Maybe this could help you getting 16-bit using 2 PWM outputs?

Resistor/PWM hybrid DAC

This is a good explanation on how to combine two PWM outputs in order to double the bit resolution. So combining two 8-bit arduino PWM outputs you can get a 16-bit PWM output! Remember Arduino's limits if you plan on going down this road. I mean, the Atmega chip is just 8-bit...

Hi,
now I tried the 16-bit thing with the R256-R DAC and it gives a big advantage. It is not as good as you would expect from 16-Bit because it is hard to get rid of all those digital noise in such a circuit. The problem with all those circuits is to keep away the digital noise from supply from audio output. As long as a digital output pin that is supplied from uC is used, you also hear all the uC noise. Maybe it gets better if you decouple the uC better or use something like a buffer. But simply said, using just those two additional resistors you get rid of those hiss noise. After playing a little bit around it seems that most noise comes from the USB port - maybe you get acceptable results by using battery power.

What I did is the following: I set the following mode in software:

SdPlay.init(SSDA_MODE_HALFRATE | SSDA_MODE_STEREO)

Then I prepared my file with the following modified batch-file:

@echo off
cd %~dp0
mkdir converted
FOR %%A IN (%*) DO sox %%A --norm=-1 -e unsigned-integer -b 16 -r 31250 -c 1 -t raw "converted\%%~nA.ahd"  
pause

Connections I made:

Pin 9  ----[220k]------+
                       |  100nF
Pin 10 -[1k trimmer]---+---||----[10k]--AudioOut--[1k]--GND

With trimmer the sound can adjusted for minimum hiss, I prepared also a special audio-file for easier trimming.

Ohhh, very nice! I need to download a library update, right? Thanks again for such hard work! 8)

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