Chat freely about anything...

User avatar
By Redmayne
#42505 Hi all!

I've been toying with the ESP for a few days now (programming in lua), and was wondering if anyone has successfully played a WAV file stored in flash memory via a DAC?

I'm very experienced with lua, but most SDK'S carry their own audio libraries. Any advice would be greatly appreciated.

Cheers!
User avatar
By phando
#44557 Have you had any luck playing wavs?
It seems possible with pwm or the sigma-delta module.
If you have made any progress please let me know what you did.

Thanks
User avatar
By kirchnet
#50665 The below code plays a wave file from SPIFFS. Emphasis on "works". Sound quality is terrible and clearly there are more elegant ways to do it. But again, it works.
File Requirement:: Wav file needs to be 8 bit, one/mono channel, 8000 samples per second or 64kbps. Higher bitrates should be possible if you change analogWriteFrequency to a multiple of the sample per second rate and also change the wait time in the while loop near the end to match the duration of each sample minus an allowance for other background processes.
Code: Select all#include "FS.h"
char buffer[1024];

void setup() {
  Serial.begin(115200);
  pinMode(5, OUTPUT);
  SPIFFS.begin();

}

void loop() {
  Serial.println(F("Starting loop..."));
  File   f = SPIFFS.open("/ImpTwBlu.wav", "r");
  if (!f) {
      Serial.println("file open failed");
  } //- See more at: http://www.esp8266.com/viewtopic.php?f=29&t=8194#sthash.u5P6kDr6.ycI23aTr.dpuf
  analogWriteRange(256);
  analogWriteFreq(32000);
  while(f.position()<(f.size()-1)){
    int numBytes=_min(1024,f.size()-f.position()-1);
    f.readBytes(buffer, numBytes);
    for(int i=0; i<numBytes;i++){
      int old=micros();
      analogWrite(5,buffer[i]);
      while(micros()-old<120);//125usec = 1sec/8000 and assume 5us for overhead like wifi
    }
Serial.print("Position ");Serial.println(f.position());
  }
  f.close();
}

If I get some free time I'll try to port the TMRpcm library from Arduino to esp.
User avatar
By kirchnet
#51386 Here is an improvement to the above code to play a wav file from SPIFFS. It uses the microsecond timer which allows you to execute other code while the wav file is playing.

In order to activate the microsecond timer, as others have noted in other posts on this forum, you need to call system_timer_reinit (); in the function user_init(void) {} which is located in the file core_esp8266_main.cpp in the cores directory. On my Windows installation of the Arduino IDE 1.6.9 this file is located in this path: C:\Users..\UserName\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266 This change will set the timer from milliseconds to microseconds.

To test whether your timer has been set to microseconds you can uncomment the debugging section in the callback function timerCallback. An difference of 2250 between two subsequently printed numbers means the timer is in microseconds, a large number means it runs in milliseconds.

The code works for audio filed with 8000 samples per seconds, one channel and 8 bits.

Code: Select allextern "C" {
#include "os_type.h"
}

//use GPIO5
#define speakerPin 5 
#define BufferSize 1

#include "FS.h"

File   f;
os_timer_t PMCtimer;
int oldmicros;
bool bPlaying;
char buffer1[BufferSize];

void timerCallback(void *pArg) {
      if (f.position()>=(f.size()-1)) {
            stopPlayback();
            //Serial.println("Finished");
            return;
        }
      /*if (micros()-oldmicros>500000)//Uncomment for debugging
      {
        Serial.print(oldmicros);Serial.print(" Pos ");Serial.print(f.position());
        Serial.print(" Size ");Serial.println(f.size());
        oldmicros=micros();
      }*/
      analogWrite(speakerPin,buffer1[0]);
      f.readBytes(buffer1,1);
} // End of timerCallback

void startPlayback()
{
  //oldmicros=0;
  analogWriteRange(255);//8 Bit
  analogWriteFreq(32000);//Multiple of the sample rate
  bPlaying=true;
  os_timer_setfn(&PMCtimer, timerCallback, NULL);
  ets_timer_arm_new(&PMCtimer,125,1,0);//125us corresponds to 8000 samples/sec
  Serial.println("timer started");//For debugging only
  //Serial.print("File size in startPlayback");Serial.println(f.size());//For debugging only
}
void stopPlayback()
{
  os_timer_disarm(&PMCtimer);
  Serial.println("timer disarmed");//For debugging only
  analogWrite(speakerPin, 0);
  bPlaying=false;
}
void setup() {
  Serial.begin(115200);
  Serial.println("start");
  SPIFFS.begin();
  Serial.println("SPIFFS started");
  bPlaying=false;
}

void loop() {
  f = SPIFFS.open("/Regal.wav", "r");
  if (!f) {
      Serial.println("file open failed");
  } else {Serial.println("file opened");}
  analogWriteRange(255);//8 Bit
  analogWriteFreq(32000);//Multiple of the sample rate
  Serial.print("File size ");Serial.println(f.size());//For debugging only
  startPlayback();
  //Insert code here that will be executed while the sound file is played in the background
  while(bPlaying) delay(40);  //use this to make sure playback is finished before closing the file
  f.close();
}