pschatzmann / arduino-audio-tools

Arduino Audio Tools (a powerful Audio library not only for Arduino)
GNU General Public License v3.0
1.51k stars 233 forks source link

Seeking in a WAV file randomly causes white noise and distortions #1580

Closed jwktje closed 5 months ago

jwktje commented 5 months ago

Problem Description

When I try to seek to a position in a WAV file it randomly causes the audio to become white noise. I feel like there must be a reason for this that I'm missing. I checked almost all examples and other issues but can't find a good reference for how to do this. My best effort to make this work is shown below. And this works 2/3 of the time.

Device Description

Olimex ESP32-ADF

Sketch

#include "AudioLibs/AudioSourceSD.h"
#include "AudioLibs/I2SCodecStream.h"
#include "AudioCodecs/CodecWAV.h"

// I2C
#define SDAPIN 18        // I2C Data
#define SCLPIN 23        // I2C Clock
#define I2CSPEED 100000  // Clock Rate
#define ES8388ADDR 0x10  // Address of ES8388 I2C port

// I2S, your configuration for the ES8388 board
#define MCLKPIN 0  // Master Clock
#define BCLKPIN 5  // Bit Clock
#define WSPIN 25   // Word select
#define DOPIN 26   // This is connected to DI on ES8388 (MISO)
#define DIPIN 35   // This is connected to DO on ES8388 (MOSI)

// SD
#define SD_CS 21
#define SD_SCK 14
#define SD_MISO 12
#define SD_MOSI 13
#define SD_SS 15

DriverPins my_pins;                                  // board pins
AudioBoard audio_board(AudioDriverES8388, my_pins);  // audio board
I2SCodecStream i2s_out_stream(audio_board);          // i2s coded
TwoWire myWire = TwoWire(0);                         // universal I2C interface

WAVDecoder decoder;
File file;                                // final output stream
StreamCopy copier(i2s_out_stream, file);  // copies data

bool audio_is_playing = false;

void audio_init() {
  AudioLogger::instance().begin(Serial, AudioLogger::Warning);
  LOGLEVEL_AUDIODRIVER = AudioDriverWarning;
  Serial.println("Setup starting...");

  // Set SD pins?
  SPI.begin(SD_SCK, SD_MISO, SD_MOSI, SD_SS);
  if (!SD.begin(SD_CS)) {
    Serial.println("Card Mount Failed");
    return;
  }
  Serial.println("Card Mounted Successfully");

  Serial.println("I2C pin ...");
  my_pins.addI2C(PinFunction::CODEC, SCLPIN, SDAPIN, ES8388ADDR, I2CSPEED, myWire);
  Serial.println("I2S pin ...");
  my_pins.addI2S(PinFunction::CODEC, MCLKPIN, BCLKPIN, WSPIN, DOPIN, DIPIN);

  Serial.println("Pins begin ...");
  my_pins.begin();

  Serial.println("Board begin ...");
  audio_board.begin();

  Serial.println("I2S begin ...");
  auto i2s_config = i2s_out_stream.defaultConfig();
  i2s_out_stream.begin(i2s_config);  // this should apply I2C and I2S configuration

  // set volume
  audio_board.setVolume(20);  //Sets the DAC volume. 0-100
}

void audio_handle() {
  if (audio_is_playing) {
    copier.copy();

    // Check if the end of the file is reached
    if (file.position() >= file.size()) {
      audio_stop();
    }
  }
}

void audio_play_file(const String& filename) {
  if (SD.exists(filename.c_str())) {
    Serial.println("Playing audio file...");
    file = SD.open(filename, FILE_READ);
    audio_is_playing = true;
  } else {
    Serial.println("File does not exist.");
  }
}

void audio_seek(uint32_t timecodeMs) {
  // Constants for the WAV file format
  const uint32_t wavHeaderSize = 44;
  const float bytesPerMillisecond = 176.4;

  // Calculate the byte position considering the header offset
  uint32_t bytePosition = static_cast<uint32_t>(timecodeMs * bytesPerMillisecond) + wavHeaderSize;

  // Seek to the byte position in the file
  file.seek(bytePosition);
}

void audio_stop() {
  Serial.println("Stopping audio playback...");
  audio_is_playing = false;
  file.close();
}

void setup() {
  Serial.begin(115200);
  audio_play_file("test.wav");
  audio_seek(3500);
}

void loop() {
  audio_handle();
}

Other Steps to Reproduce

No response

What is your development environment

Arduino

I have checked existing issues, discussions and online documentation

pschatzmann commented 5 months ago

I think it is quite obvious what you do wrong: You need to move to a position where a sample (or better a frame) starts!

E.g. if you have int16_t data (2 bytes) with 2 channels it needs to be a multiple of 4

jwktje commented 5 months ago

Thanks Phil! I will test with that. I had a feeling it was something simple I was missing. Huge respect for the amount of upkeep and communication that you are managing for this great library.