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));
}