Files
soundcube-firmware/soundcube-firmware/wavestream.h

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