Copy WAV from SD Card to SDRAM

I am trying to create a class to store and play a wav file read from an SD card. The wav data is stored on the SDRAM. I had this working with the same code that is in SampleVoice in the main loop and the audio call back using global variables. I’ve seen some posts about FIL fp having to be global and not on the stack but I’ve made SampleVoice sample global.
When I run the code below it returns 1 and seems to be failing on the first read.
Any help would be greatly appreciated pretty stuck on this one.

#include <stdio.h>
#include <string.h>
#include "daisy_seed.h"
#include "sys/fatfs.h"
#include "daisysp.h"

using namespace daisy;
using namespace daisy::seed;
using namespace daisysp;
DaisySeed hw;
SdmmcHandler   sd;
FatFSInterface fsi;
DIR dir;
FILINFO fil;

Switch play;

class SampleVoice {
	private:
	
	uint32_t bufferLength;
	size_t length;
	size_t position;
	bool playing;
	int16_t *buffer;
	FIL fp;


	public:
	// buffer should be predefined in SDRAM
	void Init(int16_t *buffer, uint32_t bufferLength) {
		this->buffer = buffer;
		this->bufferLength = bufferLength;
		length = 0;
		position = 0;
		playing = false;
	}

	// starts sample playing. need to add handling of sample already playing.
	void Play() {
		playing = true;
	}


	float Stream() {
		if (playing) {
			if (position >= length) {
				playing = false;
				position = 0;
				return 0;
			}
			return s162f(buffer[position++]);
		}
		return 0;
	}

	/* adds given file to the buffer. Only supports 16bit PCM 48kHz.
	 * return 
	 * 0: succesful
	 * 1: file read failed
	 * 2: invalid format
	 * 3: file too large
	*/ 
	int SetSample(TCHAR *fname) {
		UINT bytesread;
		WAV_FormatTypeDef wav_data; 
		
		if(f_open(&fp, fname, (FA_OPEN_EXISTING | FA_READ)) == FR_OK) {
			// Populate the WAV Info
			if(f_read(&fp, (void *)&wav_data, sizeof(WAV_FormatTypeDef), &bytesread) != FR_OK) {
				return 1;
			}
		} else return 1;

		if (wav_data.SampleRate != 48000 || wav_data.BitPerSample != 16) return 2;
		if (wav_data.SubCHunk2Size > bufferLength) return 3;

		if (f_lseek(&fp, sizeof(WAV_FormatTypeDef) + wav_data.SubChunk1Size) != FR_OK) return 1;
		if(f_read(&fp, (void *)&buffer, wav_data.SubCHunk2Size, &bytesread) != FR_OK)return 1;
		length = wav_data.SubCHunk2Size;

		f_close(&fp);
		return 0;
	}
};

bool endsWith(const char *str, const char *suffix);

#define MAX_SAMPLE_LENGTH 4000000
int16_t DSY_SDRAM_BSS sampleBuffer[MAX_SAMPLE_LENGTH];
SampleVoice sample;

void AudioCallback(AudioHandle::InputBuffer in, AudioHandle::OutputBuffer out, size_t size)
{
	play.Debounce();
	if (play.RisingEdge()){
		hw.PrintLine("Play");
		sample.Play();
	} 


	for (size_t i = 0; i < size; i++)
	{
		out[0][i] = sample.Stream()*0.25;
		out[1][i] = sample.Stream()*0.25;
	}
}


int main(void)
{
	
	hw.Init();
	hw.SetAudioBlockSize(4); // number of samples handled per callback
	hw.SetAudioSampleRate(SaiHandle::Config::SampleRate::SAI_48KHZ);
	
	play.Init(D29);	
	hw.StartLog(true);

	SdmmcHandler::Config sd_cfg;
    sd_cfg.Defaults();
    sd_cfg.width = daisy::SdmmcHandler::BusWidth::BITS_4;
    sd_cfg.speed = daisy::SdmmcHandler::Speed::FAST;
    sd.Init(sd_cfg);
	fsi.Init(FatFSInterface::Config::MEDIA_SD);
	f_mount(&fsi.GetSDFileSystem(), "/", 1);

	f_opendir(&dir, fsi.GetSDPath());

	FRESULT result;
	while(1) {
		result = f_readdir(&dir, &fil);
		if (result == F_OK) hw.PrintLine("SD OK");
		else hw.PrintLine("SD FAIL");

		if (endsWith(fil.fname, ".wav")){
			hw.PrintLine("Wav: %s", fil.fname);
			break;
		} 
	}	

	f_closedir(&dir);

	sample.Init(sampleBuffer, MAX_SAMPLE_LENGTH);
	int ret = sample.SetSample(fil.fname);
	hw.PrintLine("SetSample return %d", ret);

	while(1) {

	}

}

bool endsWith(const char *str, const char *suffix) {
  size_t str_len = strlen(str);
  size_t suffix_len = strlen(suffix);

  return (str_len >= suffix_len) && (!memcmp(str + str_len - suffix_len, suffix, suffix_len));
}

I’ve noticed that big files fail to read when using SdmmcHandler::Speed faster than SLOW. So try using SLOW and see if that helps.

That didn’t work for me. This is for a sample based drum machine so the files I’ve been using are quite small ~100KB.

Alright.

On row 142, you have f_closedir(&dir). Should be after reading the files, right?

Yeah that’s it haha I was too busy checking the code in the class to look at the main loop, well spotted.

Here is the working Class for anyone looking at this thread. Currently works for 16bit PCM at 48KHz. The card must be initialized using f_mount before calling SetSample.

#include <stdio.h>
#include <string.h>
#include "sys/fatfs.h"

class SampleVoice {
private:
	uint32_t bufferLength;
	size_t length;
	size_t position;
	bool playing;
	int16_t *buffer;
	FIL fp;
	bool stereo;
public:
	
	// buffer should be predefined in SDRAM
	void Init(int16_t *buffer, uint32_t bufferLength) {
		this->buffer = buffer;
		this->bufferLength = bufferLength;
		length = 0;
		position = 0;
		playing = false;
	}

	// starts sample playing. need to add handling of sample already playing.
	void Play() {
		playing = true;
	}


	float Stream() {
		if (playing) {
			if (position >= length) {
				playing = false;
				position = 0;
				return 0.0;
			}
			return s162f(buffer[position++]);
		}
		return 0.0;
	}

	void SetLength(size_t length) {this->length = length;}

	void *GetBuffer() {return (void *)buffer;}

	uint32_t GetBufferLength() {return bufferLength;}

	bool IsStereo() {return stereo;}
	bool IsMono() {return !stereo;}

	/* adds given file to the buffer. Only supports 16bit PCM 48kHz. 
	 * If Stereo samples are interleaved left then right.
	 * return 0: succesful, 1: file read failed, 2: invalid format, 3: file too large
	*/ 
	int SetSample(TCHAR *fname) {
		UINT bytesread;
		WAV_FormatTypeDef wav_data; 
		
		memset(buffer, 0, bufferLength);
		
		if(f_open(&fp, fname, (FA_OPEN_EXISTING | FA_READ)) == FR_OK) {
			// Populate the WAV Info
			if(f_read(&fp, (void *)&wav_data, sizeof(WAV_FormatTypeDef), &bytesread) != FR_OK) return 1;	
		} else return 1;

		if (wav_data.SampleRate != 48000 || wav_data.BitPerSample != 16) return 2;
		if (wav_data.SubCHunk2Size > bufferLength || wav_data.NbrChannels > 2) return 3;
		stereo = wav_data.NbrChannels == 2;

		if (f_lseek(&fp, sizeof(WAV_FormatTypeDef)) != FR_OK) return 1;
		if(f_read(&fp, buffer, wav_data.SubCHunk2Size, &bytesread) != FR_OK)return 1;
		length = bytesread / (wav_data.BitPerSample/8);

		f_close(&fp);
		return 0;
	}
};