Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ideal WAV format #724

Open
burnedsap opened this issue Dec 27, 2024 · 3 comments
Open

Ideal WAV format #724

burnedsap opened this issue Dec 27, 2024 · 3 comments

Comments

@burnedsap
Copy link

Hello,

I'm trying to play music (WAV files) using a ESP32-S2 + PCM5102A + SD Card Reader using the following code. I often get the error:

AudioGeneratorWAV::ReadWAVInfo: cannot read WAV, invalid RIFF header
AudioGeneratorWAV::begin: failed during ReadWAVInfo

The only wav file which worked for me is the file which was included in one of the examples: test_8u_16.wav (8 bits per sample, 16Khz, Mono)-No error when playing this file.

I'm assuming I'm using incorrect kinds of WAV files. I'm only using 16-bit files, but still unable to get them to work. What settings should I use when exporting audio from Audacity? Or perhaps there's something wrong with the code?

thank you!

#include <Arduino.h>
#include <SPI.h>
#include <SD.h>
#include "AudioFileSourceSD.h"
#include "AudioGeneratorWAV.h"
#include "AudioOutputI2S.h"

// Pin definitions
#define SD_CS 33
#define I2S_BCLK 7
#define I2S_LRC 5
#define I2S_DOUT 3

AudioGeneratorWAV *wav;
AudioFileSourceSD *file;
AudioOutputI2S *out;

// Global variables for tracking files
File root;
bool newFileNeeded = true;
int loopCount = 1;
int fileCount = 0;
int currentFileIndex = 0;

// Function to check if a file is a WAV file
bool isWAVFile(const char* filename) {
  String fname = String(filename);
  fname.toLowerCase();
  return fname.endsWith(".wav");
}

// Function to count WAV files
int countWAVFiles() {
  int count = 0;
  root = SD.open("/");
  if (!root) {
    Serial.println("Failed to open root for counting");
    return 0;
  }
  
  root.rewindDirectory();
  while (true) {
    File entry = root.openNextFile();
    if (!entry) {
      break;
    }
    if (!entry.isDirectory() && isWAVFile(entry.name())) {
      count++;
      Serial.print("Found WAV file: ");
      Serial.println(entry.name());
    }
    entry.close();
  }
  root.close();
  return count;
}

// Function to get the next WAV file
bool getNextWAVFile(char* filename) {
  // Open/reopen root directory if needed
  if (!root || !root.isDirectory()) {
    root = SD.open("/");
    if (!root) {
      Serial.println("Failed to open root directory");
      return false;
    }
  }

  File entry;
  bool foundFile = false;
  
  while (!foundFile) {
    entry = root.openNextFile();
    
    // If no more files, increment loop count and rewind
    if (!entry) {
      Serial.println("\n=== Completed loop " + String(loopCount) + " ===");
      loopCount++;
      Serial.println("=== Starting loop " + String(loopCount) + " ===\n");
      
      // Close and reopen root to ensure proper rewind
      root.close();
      root = SD.open("/");
      if (!root) {
        Serial.println("Failed to reopen root directory");
        return false;
      }
      currentFileIndex = 0;
      entry = root.openNextFile();
      
      if (!entry) {
        Serial.println("No files found in directory!");
        return false;
      }
    }
    
    if (!entry.isDirectory() && isWAVFile(entry.name())) {
      currentFileIndex++;
      strcpy(filename, "/");
      strcat(filename, entry.name());
      foundFile = true;
    }
    
    entry.close();
  }
  
  return true;
}

void setup() {
  Serial.begin(115200);
  delay(1000);
  Serial.println("\n=== Starting Looping WAV Player ===");

  // Initialize SPI for SD card
  Serial.println("Initializing SPI...");
  SPI.begin(39, 37, 35, SD_CS);
  SPI.setFrequency(8000000);

  // Initialize SD card
  Serial.print("Initializing SD card...");
  if (!SD.begin(SD_CS)) {
    Serial.println("\nSD Card initialization failed!");
    return;
  }
  Serial.println("OK!");

  // Count and list WAV files
  fileCount = countWAVFiles();
  Serial.print("Found ");
  Serial.print(fileCount);
  Serial.println(" WAV files");
  
  if (fileCount == 0) {
    Serial.println("No WAV files found on SD card!");
    Serial.println("Please add some .wav files and restart");
    return;
  }

  // Set up I2S output
  Serial.println("\nInitializing I2S output...");
  out = new AudioOutputI2S();
  out->SetPinout(I2S_BCLK, I2S_LRC, I2S_DOUT);
  out->SetGain(1.0);

  wav = new AudioGeneratorWAV();
  Serial.println("Setup complete!");
  Serial.println("\n=== Starting loop 1 ===");
}

void loop() {
  if (wav->isRunning()) {
    if (!wav->loop()) {
      wav->stop();
      if (file) {
        delete file;
        file = nullptr;
      }
      Serial.print("Playback finished (File ");
      Serial.print(currentFileIndex);
      Serial.print(" of ");
      Serial.print(fileCount);
      Serial.println(")");
      newFileNeeded = true;
      delay(500);
    }
  } else if (newFileNeeded) {
    char filename[256];
    if (getNextWAVFile(filename)) {
      Serial.print("Playing: ");
      Serial.println(filename);
      
      file = new AudioFileSourceSD(filename);
      if (file && wav->begin(file, out)) {
        Serial.println("Playback started successfully!");
        newFileNeeded = false;
      } else {
        Serial.println("Failed to start playback");
        if (file) {
          delete file;
          file = nullptr;
        }
        delay(1000);
      }
    } else {
      Serial.println("Error accessing files, attempting to recover...");
      // Close everything and try to remount
      if (root) root.close();
      SD.end();
      delay(100);
      SD.begin(SD_CS);
      delay(1000);
    }
  }
}
@earlephilhower
Copy link
Owner

Can you attach a WAV that's failing? It's probably in a non-linear PCM format or has some other quirk the parser doesn't grok. The app you're using should be immaterial for that...

@burnedsap
Copy link
Author

Yes, here's a bunch of files I've been testing with (got them from freesound.org). Gotcha, I'll check for the non-linear PCM format.

test WAV files.zip

@earlephilhower
Copy link
Owner

The files seem fine, indicating this is an issue with your app or the SD filesystem, I think.

A quick look at the hex dump of the files shows they're plain linear PCM, nothing fancy, and in a good format.

I uploaded the tram9.wav from your ZIP to LittleFS (no handy boards w/SD cards wired up but it's the same code paths) and made a dumb player and it runs fine here:

#include <Arduino.h>
#include "AudioFileSourceLittleFS.h"
#include "AudioGeneratorWAV.h"
#include "AudioOutputI2SNoDAC.h"

AudioGeneratorWAV *wav;
AudioFileSourceLittleFS *file;
AudioOutputI2SNoDAC *out;

void setup() {
  Serial.begin(115200);
  delay(1000);
  Serial.printf("WAV start\n");

  audioLogger = &Serial;
  file = new AudioFileSourceLittleFS("714804__jumpparallaa__tram-9.wav");
  out = new AudioOutputI2SNoDAC();
  wav = new AudioGeneratorWAV();
  wav->begin(file, out);
}

void loop() {
  if (wav->isRunning()) {
    if (!wav->loop()) wav->stop();
  } else {
    Serial.printf("WAV done\n");
    delay(1000);
  }
}

I see the "WAV start" and ~5 seconds later get tehe "WAV done" printout.

The error you're seeing is "cannot read WAV, invalid RIFF header" and that's saying the absolute 1st data read is not right.

if (!ReadU32(&u32)) {
Serial.printf_P(PSTR("AudioGeneratorWAV::ReadWAVInfo: failed to read WAV data\n"));
return false;
};
if (u32 != 0x46464952) {
Serial.printf_P(PSTR("AudioGeneratorWAV::ReadWAVInfo: cannot read WAV, invalid RIFF header\n"));
return false;
}

From my reading the ESP32S2 is little endian, like other ESP32s, so the ReadU32 should still be valid.

Given that, I'd try something basic like my sketch above. Use the FileSourceSD and try your file that way. If that conks out, then I'd suggest just opening the file normally and doing a hex dump on the device to verify it's read out correctly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants