Sound lagging problem with Arduino mega 2560

I am working on a project to play WAV files on an Arduino Mega 2560 using an SD card, without any sound-related libraries. I am converting the PCM data from the WAV file to PWM signals, then using a low-pass filter (LPF), amplifier (AMP), and speaker to produce sound.

Currently, it can produce sound, and the There is also a slight loss in tone, and there is an big issue with the tempo lagging. The timer interrupt (OCR1A) is set to 44.1kHz, and PCM data is uploaded to OCRnx at every interrupt. Then OCRnx generates the PWM signal (using Timer2 & Timer4 at 62.5kHz, 8-bit fast PWM). The WAV files also have a 44.1kHz sampling rate.

Additionally, not only is the sound lagging in tempo, but noise is also generated, and eventually, the Arduino resets itself.

#include <SD.h>
#include <SPI.h>

#define SD_CS 53
#define SAMPLE_RATE 44.1e3

File root, wav;
unsigned char buf[6000];
volatile uint16_t playing_Index = 0;
volatile uint16_t write_Index = 3000; 
volatile bool bufferFlag = false;
uint32_t dataSize;
uint16_t endTime;
volatile uint16_t audioSum = 0;

void setup() {
  SD.begin(SD_CS);
  initializeWav(0);
  initializePins();
  initializeTimerInterrupt();
}

void loop() {
  if (playing_Index >= 6000) {
    playing_Index = 0;
  } else if (playing_Index == 3000 || playing_Index == 0) {
    updateBuffer();
  }
}

void initializeWav(int8_t fileIndex) {
  playing_Index = 0;
  dataSize = 0;

  wav = SD.open("LIGHT441.WAV");
  wav.seek(40);
  for (uint8_t i = 0; i < 4; i++)
    dataSize += (uint32_t)wav.read() << (8 * i);
  endTime = dataSize / (4 * SAMPLE_RATE);

  wav.read(buf, 6000);
}

void initializePins() {
  DDRB |= 0b00010000;
  DDRH |= 0b01011000;
}

void initializeTimerInterrupt() {
  TCCR4B &= ~_BV(WGM43);
  TCCR4B |= _BV(WGM42);
  TCCR4A &= ~_BV(WGM41);
  TCCR4A |= _BV(WGM40);

  TCCR4A |= _BV(COM4A1);
  TCCR4A &= ~_BV(COM4A0);

  TCCR4A |= _BV(COM4B1);
  TCCR4A &= ~_BV(COM4B0);

  TCCR4B &= ~_BV(CS42);
  TCCR4B &= ~_BV(CS41);
  TCCR4B |= _BV(CS40);

  TCCR2B &= ~_BV(WGM22);
  TCCR2A |= _BV(WGM21);
  TCCR2A |= _BV(WGM20);

  TCCR2A |= _BV(COM2A1);
  TCCR2A &= ~_BV(COM2A0);

  TCCR2A |= _BV(COM2B1);
  TCCR2A &= ~_BV(COM2B0);

  TCCR2B &= ~_BV(CS22);
  TCCR2B &= ~_BV(CS21);
  TCCR2B |= _BV(CS20);

  TCCR1B &= ~_BV(WGM13);
  TCCR1B |= _BV(WGM12);
  TCCR1A &= ~_BV(WGM11);
  TCCR1A &= ~_BV(WGM10);

  TCCR1B &= ~_BV(CS12);
  TCCR1B &= ~_BV(CS11);
  TCCR1B |= _BV(CS10);

  OCR1A = 362;
  TCNT1 = 0;
  TIMSK1 |= _BV(OCIE1A);
  TIFR1 |= _BV(OCF1A);

  sei();
}

void updateBuffer() {
  bufferFlag = false;
  wav.read(&buf[write_Index], 3000);
  write_Index = (write_Index == 0) ? 3000 : 0;
}

ISR(TIMER1_COMPA_vect) {
  audioSum = (buf[playing_Index] | (buf[playing_Index + 1] << 8)) + 0x8000;
  OCR2B = audioSum & 0x00FF;
  OCR2A = (audioSum & 0xFF00) >> 8;

  audioSum = (buf[playing_Index + 2] | (buf[playing_Index + 3] << 8)) + 0x8000;
  OCR4B = audioSum & 0x00FF;
  OCR4A = (audioSum & 0xFF00) >> 8;

  playing_Index += 4; 
}

Have you made sure that there is no period of silence at the start of the sample and end of a sample? In other words lag can be due to the sample not being topped and tailed.

To find this out load your sample into a program called Audacity and see if it starts immediately.

Also the line:-

Will not work with all types of .wav files where there could be additional information in the file, examine your sample file to make sure the samples do start 40 bytes in.

I've modified the text. Sorry, I'm aware that the sample starts at 40 bytes and can't perform other types of wav files! However, I updated the OCRnX value through 44.1 kHz interrupts and I think pwm is 62.5 kHz, so I think it's fast enough, but I'm wondering if it's not running well.

44kHz is typically too fast for an AVR device. I wrote a similar library (TMRpcm) and it can handle about 16-24kHz audio, maybe 32kHz on a good day. Anything faster will typically cause the issues you are seeing.

Well I can get a Uno R3 to produce PWM signals at above 100 KHz, rock solid all day every day.

Can you produce decent audio by changing the duty cycle at 44 kHz update rate, which is the topic actually under discussion?

Ya but not with input from an SD card. SPI speed is the limiting factor.

Well you will probably say this is not "decent audio" but it sounds fine to me.

This was using the samples stored in internal memory.

True as that example was internal memory storage. But you could transfer your SD card memory into internal memory first, or failing that external SDRAM storage. Or even examine the sort of SD card you are using, as there are newer types these days with faster access speed.

I solved it! The solution was to use an older version of the IDE. However, I changed the timer interrupt to OCR1C, but there was no sound, and it only worked with OCR1A. I'm frustrated because I can't figure out the reason.