Issue playing sound

I am using an Adafruit PAM8302A connected to the DAC of a Particle Photon, reading .wav files from an SD card. Sounds are playing except if a .wav file finishes there is a glitch grinding sound - this doesn’t happen when skipping file to file. The only library I can find for playing sound in particle.io is the speaker library.
Can anyone see a reason this is happening? or can recommend another sound library that works with particle photon?

GitHub - monkbroc/particle-speaker: Generate audio output for a speaker with a Particle device. The glitch occurs in the example code of this library as well.

// This #include statement was automatically added by the Particle IDE.
#include <FastLED.h>
#include <speaker.h>
#include <SdFat.h>
FASTLED_USING_NAMESPACE;

#define NUM_LEDS 20
#define LED_PIN 0
#define STRIP_PIN 6
#define BUT_PIN 1
#define UPDATES_PER_SECOND  60

String file_name [17]{ "1.wav","2.wav", "3.wav", "4.wav", "5.wav", "6.wav", "7.wav", "8.wav","9.wav",
                       "10.wav", "11.wav", "12.wav", "13.wav","14.wav","15.wav","16.wav","17.wav"};

SerialLogHandler logHandler(LOG_LEVEL_NONE, {   // Logging level for non-app messages
    { "app", LOG_LEVEL_INFO }                   // Logging level for application messages
});

// Define the array of leds
CRGB leds[NUM_LEDS];
typedef struct wav_header {
  // RIFF Header
  char     riff_header[4];   // Contains "RIFF"
  uint32_t wav_size;         // Size of the wav portion of the file, which follows the first 8 bytes. File size - 8
  char     wave_header[4];   // Contains "WAVE"
    
  // Format Header
  char     fmt_header[4];    // Contains "fmt " (includes trailing space)
  uint32_t fmt_chunk_size;   // Should be 16 for PCM
  uint16_t audio_format;     // Should be 1 for PCM. 3 for IEEE Float
  uint16_t num_channels;
  uint32_t sample_rate;
  uint32_t byte_rate;        // Number of bytes per second. sample_rate * num_channels * Bytes Per Sample
  uint16_t sample_alignment; // num_channels * Bytes Per Sample
  uint16_t bit_depth;        // Number of bits per sample
    
  // Data
  char     data_header[4];   // Contains "data"
  uint32_t data_bytes;       // Number of bytes in data. Number of samples * num_channels * sample byte size
  // uint8_t bytes[];        // Remainder of wave file is bytes
  
} WavHeader_t;

const int    SD_SS      = A2; 
const size_t BUFFERSIZE = 1024;
uint16_t     data[2][BUFFERSIZE];

SdFat        sd;
File         wavFile;
WavHeader_t  wh;

int buttonCount = 0;
int buttonState;     
int lastButtonState = LOW;   
unsigned long lastDebounceTime = 0;  
unsigned long debounceDelay = 50;  

static uint8_t hue;

Speaker speaker(data[0], data[1], BUFFERSIZE);


void setup() { 
    delay( 3000 );
    Serial.begin(57600);
	Serial.println("resetting");
    FastLED.addLeds<NEOPIXEL, STRIP_PIN>(leds, NUM_LEDS);  // GRB ordering is assumed
    //FastLED.setMaxPowerInVoltsAndMilliamps(5,10000); // limit my draw to 10A at 5v of power draw
    LEDS.setBrightness(100);
    pinMode(BUT_PIN, INPUT_PULLUP);
    pinMode(LED_PIN, OUTPUT);
    digitalWrite(LED_PIN, HIGH);
    Particle.function("playWav", selectFile);
     for(int i = 0; i < NUM_LEDS; i++) leds[i] = CHSV(hue,255,255);
 
  if (sd.begin(SD_SS)) Log.info("SD initialised");
  else Log.warn("failed to open card");
}


//_______________________________________________________________________________
void loop() { 
    
    int reading = digitalRead(BUT_PIN);
    if (reading != lastButtonState) lastDebounceTime = millis();
    if ((millis() - lastDebounceTime) > debounceDelay) {
        if (reading != buttonState) {
            buttonState = reading;
            if (buttonState == HIGH) {
                buttonCount++;
    	        //String newSTR = buttonCount + ".wav";
                 selectFile(file_name[buttonCount]);
                for(int i = 0; i < NUM_LEDS; i++) leds[i] = CHSV(hue++,255,255);
                }
            }
  }
    lastButtonState = reading;
    if(buttonCount > 16) buttonCount = 0;
    FastLED.show();
    FastLED.delay(1000 / UPDATES_PER_SECOND);
    if (speaker.ready()) readChunk();
}

//_______________________________________________________________________________
int selectFile(const char* filename) {
  int retVal = 0;
  
  if (!strcmp("ls", filename) || !strcmp("dir", filename)) {
    sd.ls("/", LS_R);
    return 0;
  }
  
  if (wavFile.isOpen()) wavFile.close();
  
  wavFile = sd.open(filename);
 
 
  if (wavFile) {
    memset((uint8_t*)data, 0x80, sizeof(data)); // reset buffer to bias value 0x8080 (quicker via memset() than writing 0x8000 in a loop)
    if (sizeof(wh) == wavFile.read((uint8_t*)&wh, sizeof(wh))) {
      Log.printf("%s\n\r\t%.4s\r\n\tsize: %lu\r\n\t%.4s\r\n\t%.4s\r\n\tchunk size (16?): %lu\r\n\taudio format (1?): %u\r\n\tchannels: %u"
                , filename
                , wh.riff_header
                , wh.wav_size
                , wh.wave_header
                , wh.fmt_header
                , wh.fmt_chunk_size
                , wh.audio_format
                , wh.num_channels
                );
      // two chunks since Log only supports limited length output
      Log.printf("\r\n\tsample rate: %lu\r\n\tbyte rate: %lu\r\n\tsample alignment: %u\r\n\tbit depth: %u\r\n\t%.4s\r\n\tdata bytes: %u"
                , wh.sample_rate
                , wh.byte_rate
                , wh.sample_alignment
                , wh.bit_depth
                , wh.data_header
                , wh.data_bytes
                );
      retVal = wh.data_bytes;
      readChunk();
      speaker.begin(wh.sample_rate);
    }
  } 
  else {
    Log.error("%s not found", filename);
  }

  return retVal;
}

int readChunk() {
  int retVal = 0;
  if (wavFile.isOpen()) {
    uint16_t* wav = speaker.getBuffer();
    uint8_t   buf[BUFFERSIZE * 2 * wh.num_channels];
    int       n = wavFile.read(buf, sizeof(buf));
   if (n < sizeof(buf)) wavFile.close();               // when all data is read close the file
    
    memset((uint8_t*)wav, 0x80, BUFFERSIZE);            // reset buffer to bias value 0x8080
    for(int b = 0; b < n; b += wh.sample_alignment) {
       wav[retVal++] = *(uint16_t*)&buf[b] + 32768;      // convert int16_t to uin16_t with bias 0x8000
     }
  } else speaker.end();
  return retVal;
}
//_______________________________________________________________________________

void fadeall() { for(int i = 0; i < NUM_LEDS; i++) { leds[i].nscale8(250); } }


Thanks for reaching out. I’m having no luck recreating it locally so I’m inclined to think this may be an issue with the speaker itself. Do you have any other speakers you can use to test this theory?

@jvanier have you encountered any glitching sounds at the end of .wav files with your library before?

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.