Improves sound - blip_buf was altering the audio output quite a bit compared to the DSP's raw output
154 lines
No EOL
3.4 KiB
C++
154 lines
No EOL
3.4 KiB
C++
#include "stdafx.h"
|
|
#include "PcmReader.h"
|
|
#include "../Utilities/VirtualFile.h"
|
|
#include "../Utilities/HermiteResampler.h"
|
|
|
|
PcmReader::PcmReader()
|
|
{
|
|
_done = true;
|
|
_loop = false;
|
|
_prevLeft = 0;
|
|
_prevRight = 0;
|
|
_loopOffset = 8;
|
|
_sampleRate = 0;
|
|
_outputBuffer = new int16_t[20000];
|
|
}
|
|
|
|
PcmReader::~PcmReader()
|
|
{
|
|
delete[] _outputBuffer;
|
|
}
|
|
|
|
bool PcmReader::Init(string filename, bool loop, uint32_t startOffset)
|
|
{
|
|
if(_file) {
|
|
_file.close();
|
|
}
|
|
|
|
_file.open(filename, ios::binary);
|
|
if(_file) {
|
|
_file.seekg(0, ios::end);
|
|
_fileSize = (uint32_t)_file.tellg();
|
|
if(_fileSize < 12) {
|
|
return false;
|
|
}
|
|
|
|
_file.seekg(4, ios::beg);
|
|
uint32_t loopOffset = (uint8_t)_file.get();
|
|
loopOffset |= ((uint8_t)_file.get()) << 8;
|
|
loopOffset |= ((uint8_t)_file.get()) << 16;
|
|
loopOffset |= ((uint8_t)_file.get()) << 24;
|
|
|
|
_loopOffset = (uint32_t)loopOffset;
|
|
|
|
_prevLeft = 0;
|
|
_prevRight = 0;
|
|
_done = false;
|
|
_loop = loop;
|
|
_fileOffset = startOffset;
|
|
_file.seekg(_fileOffset, ios::beg);
|
|
|
|
_leftoverSampleCount = 0;
|
|
_pcmBuffer.clear();
|
|
_resampler.Reset();
|
|
|
|
return true;
|
|
} else {
|
|
_done = true;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool PcmReader::IsPlaybackOver()
|
|
{
|
|
return _done;
|
|
}
|
|
|
|
void PcmReader::SetSampleRate(uint32_t sampleRate)
|
|
{
|
|
if(sampleRate != _sampleRate) {
|
|
_sampleRate = sampleRate;
|
|
|
|
_resampler.SetSampleRates(PcmReader::PcmSampleRate, _sampleRate);
|
|
}
|
|
}
|
|
|
|
void PcmReader::SetLoopFlag(bool loop)
|
|
{
|
|
_loop = loop;
|
|
}
|
|
|
|
void PcmReader::ReadSample(int16_t &left, int16_t &right)
|
|
{
|
|
uint8_t val[4];
|
|
_file.get(((char*)val)[0]);
|
|
_file.get(((char*)val)[1]);
|
|
_file.get(((char*)val)[2]);
|
|
_file.get(((char*)val)[3]);
|
|
|
|
left = val[0] | (val[1] << 8);
|
|
right = val[2] | (val[3] << 8);
|
|
}
|
|
|
|
void PcmReader::LoadSamples(uint32_t samplesToLoad)
|
|
{
|
|
uint32_t samplesRead = 0;
|
|
|
|
int16_t left = 0;
|
|
int16_t right = 0;
|
|
for(uint32_t i = _fileOffset; i < _fileSize && samplesRead < samplesToLoad; i+=4) {
|
|
ReadSample(left, right);
|
|
|
|
_pcmBuffer.push_back(left);
|
|
_pcmBuffer.push_back(right);
|
|
|
|
_prevLeft = left;
|
|
_prevRight = right;
|
|
|
|
_fileOffset += 4;
|
|
samplesRead++;
|
|
|
|
if(samplesRead < samplesToLoad && i + 4 >= _fileSize) {
|
|
if(_loop) {
|
|
i = _loopOffset * 4 + 8;
|
|
_fileOffset = i;
|
|
_file.seekg(_fileOffset, ios::beg);
|
|
} else {
|
|
_done = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void PcmReader::ApplySamples(int16_t *buffer, size_t sampleCount, uint8_t volume)
|
|
{
|
|
if(_done) {
|
|
return;
|
|
}
|
|
|
|
int32_t samplesNeeded = (int32_t)sampleCount - _leftoverSampleCount;
|
|
if(samplesNeeded > 0) {
|
|
uint32_t samplesToLoad = samplesNeeded * PcmReader::PcmSampleRate / _sampleRate + 2;
|
|
LoadSamples(samplesToLoad);
|
|
}
|
|
|
|
uint32_t samplesRead = _resampler.Resample(_pcmBuffer.data(), (uint32_t)_pcmBuffer.size() / 2, _outputBuffer + _leftoverSampleCount*2);
|
|
_pcmBuffer.clear();
|
|
|
|
uint32_t samplesToProcess = std::min<uint32_t>((uint32_t)sampleCount * 2, (samplesRead + _leftoverSampleCount) * 2);
|
|
for(uint32_t i = 0; i < samplesToProcess; i++) {
|
|
buffer[i] += (int16_t)((int32_t)_outputBuffer[i] * volume / 255);
|
|
}
|
|
|
|
//Calculate count of extra samples that couldn't be mixed with the rest of the audio and copy them to the beginning of the buffer
|
|
//These will be mixed on the next call to ApplySamples
|
|
_leftoverSampleCount = std::max(0, (int32_t)(samplesRead + _leftoverSampleCount) - (int32_t)sampleCount);
|
|
for(uint32_t i = 0; i < _leftoverSampleCount*2; i++) {
|
|
_outputBuffer[i] = _outputBuffer[samplesToProcess + i];
|
|
}
|
|
}
|
|
|
|
uint32_t PcmReader::GetOffset()
|
|
{
|
|
return _fileOffset;
|
|
} |