2019-12-31 20:23:26 -05:00
|
|
|
#include "stdafx.h"
|
|
|
|
#include "WavReader.h"
|
|
|
|
|
|
|
|
shared_ptr<WavReader> WavReader::Create(uint8_t* wavData, uint32_t length)
|
|
|
|
{
|
|
|
|
//Basic WAV file read checks (should be using FourCC logic instead, but this will do for now)
|
|
|
|
if(!wavData || length < 100) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
if(memcmp(wavData, "RIFF", 4) || memcmp(wavData + 8, "WAVE", 4) || memcmp(wavData + 12, "fmt ", 4)) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2020-01-01 19:29:54 -05:00
|
|
|
uint32_t riffSize = wavData[4] | (wavData[5] << 8) | (wavData[6] << 16) | (wavData[7] << 24);
|
|
|
|
if(riffSize + 8 != length) {
|
|
|
|
//Invalid RIFF header (length does not match file size)
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2019-12-31 20:23:26 -05:00
|
|
|
uint32_t channelCount = wavData[22] | (wavData[23] << 8);
|
|
|
|
if(channelCount != 1) {
|
|
|
|
//Only mono files are supported at the moment
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t fmtSize = wavData[16] | (wavData[17] << 8) | (wavData[18] << 16) | (wavData[19] << 24);
|
|
|
|
if(memcmp(wavData + 20 + fmtSize, "data", 4)) {
|
|
|
|
//Couldn't find data chunk
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2020-01-01 19:29:54 -05:00
|
|
|
uint32_t dataSize = wavData[24 + fmtSize] | (wavData[25 + fmtSize] << 8) | (wavData[26 + fmtSize] << 16) | (wavData[27 + fmtSize] << 24);
|
|
|
|
if(dataSize + 28 + fmtSize > length) {
|
|
|
|
//data chunk is too big
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2019-12-31 20:23:26 -05:00
|
|
|
uint32_t bitsPerSample = wavData[34] | (wavData[35] << 8);
|
|
|
|
if(bitsPerSample != 16) {
|
|
|
|
//Only support 16-bit samples for now
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t sampleRate = wavData[24] | (wavData[25] << 8) | (wavData[26] << 16) | (wavData[27] << 24);
|
|
|
|
|
|
|
|
shared_ptr<WavReader> r(new WavReader());
|
|
|
|
r->_fileData = wavData;
|
|
|
|
r->_fileSize = length;
|
|
|
|
r->_fileSampleRate = sampleRate;
|
|
|
|
r->_dataStartOffset = 28 + fmtSize;
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
WavReader::WavReader()
|
|
|
|
{
|
|
|
|
_done = true;
|
|
|
|
_prevSample = 0;
|
|
|
|
_sampleRate = 0;
|
|
|
|
_blip = blip_new(10000);
|
|
|
|
_outputBuffer = new int16_t[20000];
|
|
|
|
}
|
|
|
|
|
|
|
|
WavReader::~WavReader()
|
|
|
|
{
|
|
|
|
blip_delete(_blip);
|
|
|
|
delete[] _outputBuffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
void WavReader::Play(uint32_t startSample)
|
|
|
|
{
|
|
|
|
_prevSample = 0;
|
|
|
|
_done = false;
|
|
|
|
_fileOffset = _dataStartOffset + startSample * 2;
|
|
|
|
|
|
|
|
blip_clear(_blip);
|
|
|
|
blip_set_rates(_blip, _fileSampleRate, _sampleRate);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool WavReader::IsPlaybackOver()
|
|
|
|
{
|
|
|
|
return _done;
|
|
|
|
}
|
|
|
|
|
|
|
|
void WavReader::SetSampleRate(uint32_t sampleRate)
|
|
|
|
{
|
2020-01-01 18:47:55 -05:00
|
|
|
if(_sampleRate != sampleRate) {
|
|
|
|
_sampleRate = sampleRate;
|
|
|
|
blip_clear(_blip);
|
|
|
|
blip_set_rates(_blip, _fileSampleRate, _sampleRate);
|
|
|
|
}
|
2019-12-31 20:23:26 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void WavReader::LoadSamples(uint32_t samplesToLoad)
|
|
|
|
{
|
|
|
|
uint32_t samplesRead = 0;
|
|
|
|
|
|
|
|
for(uint32_t i = _fileOffset; i < _fileSize && samplesRead < samplesToLoad; i+=2) {
|
|
|
|
int16_t sample = _fileData[i] | (_fileData[i + 1] << 8);
|
|
|
|
|
|
|
|
blip_add_delta(_blip, samplesRead, sample - _prevSample);
|
|
|
|
|
|
|
|
_prevSample = sample;
|
|
|
|
|
|
|
|
_fileOffset += 2;
|
|
|
|
samplesRead++;
|
|
|
|
|
|
|
|
if(samplesRead < samplesToLoad && i + 2 >= _fileSize) {
|
|
|
|
_done = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
blip_end_frame(_blip, samplesRead);
|
|
|
|
}
|
|
|
|
|
|
|
|
void WavReader::ApplySamples(int16_t *buffer, size_t sampleCount, double volume)
|
|
|
|
{
|
|
|
|
if(_done) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Volume is set to 10 when volume is set to 100% in the UI
|
|
|
|
volume /= 10.0;
|
|
|
|
|
2020-01-01 18:47:55 -05:00
|
|
|
int32_t samplesToLoad = (int32_t)sampleCount * _fileSampleRate / _sampleRate + 1 - blip_samples_avail(_blip);
|
|
|
|
|
|
|
|
if(samplesToLoad > 0) {
|
|
|
|
LoadSamples(samplesToLoad);
|
|
|
|
}
|
2019-12-31 20:23:26 -05:00
|
|
|
|
|
|
|
int samplesRead = blip_read_samples(_blip, _outputBuffer, (int)sampleCount, 0);
|
|
|
|
for(size_t i = 0, len = samplesRead; i < len; i++) {
|
|
|
|
int16_t sample = (int16_t)((int32_t)_outputBuffer[i] * volume);
|
|
|
|
|
|
|
|
//Apply to both left and right channels
|
|
|
|
buffer[i*2] += sample;
|
|
|
|
buffer[i*2+1] += sample;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t WavReader::GetPosition()
|
|
|
|
{
|
|
|
|
return _done ? -1 : (_fileOffset - _dataStartOffset) / 2;
|
|
|
|
}
|