forked from W4D/soundcube-firmware
217 lines
4.3 KiB
C++
217 lines
4.3 KiB
C++
#pragma once
|
|
|
|
#include <SD.h>
|
|
#include "ringbuffer.h"
|
|
|
|
struct WaveFile{
|
|
File file;
|
|
|
|
char cstart[4];
|
|
char cwave[4];
|
|
char cfmt[4];
|
|
|
|
bool load(File _file){
|
|
file = _file;
|
|
|
|
// RIFF Header
|
|
uint8_t start[4];
|
|
uint8_t size[4];
|
|
uint8_t wave[4];
|
|
|
|
file.seek(0, SeekSet);
|
|
file.read(start, 4);
|
|
|
|
memcpy(cstart, start, 4);
|
|
|
|
if(strcmp("RIFF", cstart) != 0) return false;
|
|
|
|
file.seek(4, SeekSet);
|
|
file.read(size, 4);
|
|
length = (size[3] << 24) + (size[2] << 16) + (size[1] << 8) + size[3] - 8;
|
|
|
|
file.seek(8, SeekSet);
|
|
file.read(wave, 4);
|
|
memcpy(cwave, wave, 4);
|
|
if(strcmp("WAVE", cwave) != 0) return false;
|
|
|
|
// FORMAT
|
|
uint8_t fmt[4];
|
|
uint8_t fmtLen[4];
|
|
uint8_t fmtTag[2];
|
|
uint8_t fmtChannels[2];
|
|
uint8_t fmtSamplerate[4];
|
|
uint8_t fmtBytesPerSecond[4];
|
|
uint8_t fmtBlockalign[2];
|
|
uint8_t fmtBitsPerSample[2];
|
|
|
|
file.seek(12, SeekSet);
|
|
file.read(fmt, 4);
|
|
memcpy(cfmt, fmt, 4);
|
|
|
|
if(strcmp("fmt ", cfmt) != 0) return false;
|
|
|
|
file.seek(20, SeekSet);
|
|
file.read(fmtTag, 4);
|
|
format = (fmtTag[1] << 8) + fmtTag[0];
|
|
if(format != 0x0001) return false;
|
|
|
|
file.seek(22, SeekSet);
|
|
file.read(fmtChannels, 2);
|
|
channels = (fmtChannels[1] << 8) + fmtChannels[0];
|
|
|
|
file.seek(24, SeekSet);
|
|
file.read(fmtSamplerate, 4);
|
|
samplerate = (fmtSamplerate[3] << 24) + (fmtSamplerate[2] << 16) + (fmtSamplerate[1] << 8) + fmtSamplerate[0];
|
|
|
|
file.seek(32, SeekSet);
|
|
file.read(fmtBlockalign, 2);
|
|
blockalign = (fmtBlockalign[1] << 8) + fmtBlockalign[0];
|
|
|
|
file.seek(34, SeekSet);
|
|
file.read(fmtBitsPerSample, 2);
|
|
bitspersample = (fmtBitsPerSample[1] << 8) + fmtBitsPerSample[0];
|
|
|
|
return true;
|
|
}
|
|
|
|
bool readblock(){
|
|
uint8_t samplebyte[blockalign];
|
|
|
|
file.read(samplebyte, blockalign);
|
|
|
|
if(!file.available() && loop) file.seek(44, SeekSet);
|
|
if(!file.available() && !loop) {
|
|
file.seek(44, SeekSet);
|
|
return false;
|
|
}
|
|
|
|
for(int i = 0; i < blockalign; i+=2){
|
|
int16_t sample = (samplebyte[i+1] << 8) + samplebyte[i];
|
|
buffer.push(sample);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool readblockDMA(){
|
|
void *bufferStart = buffer.getWritePointer();
|
|
|
|
file.read((uint8_t*)bufferStart, 4);
|
|
buffer.advance(4);
|
|
|
|
if(!file.available() && loop) file.seek(44, SeekSet);
|
|
if(!file.available() && !loop) {
|
|
file.seek(44, SeekSet);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool readblockDMA128(){
|
|
void *bufferStart = buffer.getWritePointer();
|
|
|
|
int adv = 128;
|
|
adv = file.read((uint8_t*)bufferStart, 128);
|
|
buffer.advance(adv);
|
|
|
|
if(!file.available() && loop) file.seek(44, SeekSet);
|
|
if(!file.available() && !loop) {
|
|
file.seek(44, SeekSet);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
int16_t get(){
|
|
return buffer.pop();
|
|
}
|
|
|
|
void stop(){
|
|
file.seek(44, SeekSet);
|
|
}
|
|
|
|
void reset(){
|
|
file.seek(44, SeekSet);
|
|
}
|
|
|
|
bool loop = false;
|
|
uint16_t format = 0;
|
|
uint32_t length = 0;
|
|
uint16_t channels = 0;
|
|
uint32_t samplerate = 0;
|
|
uint16_t blockalign = 0;
|
|
uint16_t bitspersample = 0;
|
|
|
|
RingBuffer buffer;
|
|
};
|
|
|
|
class WaveStream{
|
|
public:
|
|
WaveStream(){}
|
|
|
|
void begin(){
|
|
wavefile.buffer.setSize(1024);
|
|
wavefile.buffer.begin();
|
|
}
|
|
|
|
bool load(File _wavefile){
|
|
if(!wavefile.load(_wavefile)) return false;
|
|
return true;
|
|
}
|
|
|
|
void toggle(){playing = !playing;}
|
|
|
|
void play(bool reset = false){
|
|
if(reset) wavefile.reset();
|
|
playing = true;
|
|
}
|
|
|
|
void stop(){
|
|
playing = false;
|
|
wavefile.stop();
|
|
}
|
|
|
|
void pause(){playing = false;}
|
|
|
|
void stream(){
|
|
int cnt = 0;
|
|
while (!wavefile.buffer.isFull() && cnt < 128) {
|
|
bool ok = wavefile.readblockDMA();
|
|
if(!ok) playing = false;
|
|
cnt += 2;
|
|
}
|
|
}
|
|
|
|
void streamChunk(){
|
|
if(!wavefile.buffer.isFull()){
|
|
bool ok = wavefile.readblockDMA128();
|
|
if(!ok) playing = false;
|
|
}
|
|
}
|
|
|
|
int16_t get(){
|
|
return playing ? wavefile.get() : 0;
|
|
}
|
|
|
|
int16_t* getPointer(){
|
|
int16_t* p = wavefile.buffer.getReadPointer();
|
|
wavefile.buffer.pointerPop(2);
|
|
return p;
|
|
}
|
|
|
|
void getDMA(int32_t *samples){
|
|
if(playing) wavefile.buffer.popDMA(samples);
|
|
}
|
|
|
|
bool isPlaying(){
|
|
return playing;
|
|
}
|
|
|
|
//private:
|
|
|
|
WaveFile wavefile;
|
|
|
|
bool playing = false;
|
|
|
|
|
|
};
|