Refactor resampling code

This commit is contained in:
Ted John 2017-01-03 19:47:38 +00:00
parent cb592726d9
commit 983c59c9ff
2 changed files with 50 additions and 53 deletions

View File

@ -33,6 +33,11 @@ struct AudioFormat
{
return (SDL_AUDIO_BITSIZE(format)) / 8;
}
int GetByteRate() const
{
return BytesPerSample() * channels;
}
};
inline bool operator ==(const AudioFormat& lhs, const AudioFormat& rhs)

View File

@ -253,14 +253,13 @@ private:
_adjustMusicVolume = powf(_settingMusicVolume / 100.f, 10.f / 6.f);
}
int sampleSize = _format.channels * _format.BytesPerSample();
int numSamples = length / sampleSize;
int byteRate = _format.GetByteRate();
int numSamples = length / byteRate;
double rate = 1;
if (_format.format == AUDIO_S16SYS)
{
rate = channel->GetRate();
}
int samplesToRead = (int)(numSamples * rate);
bool mustConvert = false;
SDL_AudioCVT cvt;
@ -277,13 +276,14 @@ private:
}
// Read raw PCM from channel
size_t toread = (size_t)(samplesToRead / cvt.len_ratio) * sampleSize;
if (_channelBuffer == nullptr || _channelBufferCapacity < toread)
int readSamples = (int)(numSamples * rate);
size_t readLength = (size_t)(readSamples / cvt.len_ratio) * byteRate;
if (_channelBuffer == nullptr || _channelBufferCapacity < readLength)
{
_channelBuffer = realloc(_channelBuffer, toread);
_channelBufferCapacity = toread;
_channelBuffer = realloc(_channelBuffer, readLength);
_channelBufferCapacity = readLength;
}
size_t bytesRead = channel->Read(_channelBuffer, toread);
size_t bytesRead = channel->Read(_channelBuffer, readLength);
// Convert data to required format if necessary
void * buffer = nullptr;
@ -307,16 +307,16 @@ private:
}
// Apply effects
size_t effectBufferLen;
bool useBufferLengthForRatio = (bytesRead == toread);
if (ApplyResample(channel, numSamples, sampleSize, buffer, bufferLen, &effectBufferLen, useBufferLengthForRatio))
if (rate != 1)
{
int srcSamples = (int)(bufferLen / byteRate);
int dstSamples = numSamples;
bufferLen = ApplyResample(channel, buffer, srcSamples, dstSamples);
buffer = _effectBuffer;
bufferLen = effectBufferLen;
}
// Apply panning and volume
ApplyPan(channel, buffer, bufferLen, sampleSize);
ApplyPan(channel, buffer, bufferLen, byteRate);
int mixVolume = ApplyVolume(channel, buffer, bufferLen);
// Finally mix on to destination buffer
@ -326,49 +326,41 @@ private:
channel->UpdateOldVolume();
}
bool ApplyResample(IAudioChannel * channel, int samples, int sampleSize, const void * buffer, size_t bufferLen, size_t * newLength, bool useBufferLengthForRatio)
/**
* Resample the given buffer into _effectBuffer.
* Assumes that srcBuffer is the same format as _format.
*/
size_t ApplyResample(IAudioChannel * channel, const void * srcBuffer, int srcSamples, int dstSamples)
{
bool applied = false;
double rate = channel->GetRate();
if (rate != 1 && _format.format == AUDIO_S16SYS)
int byteRate = _format.GetByteRate();
// Create resampler
SpeexResamplerState * resampler = channel->GetResampler();
if (resampler == nullptr)
{
int inLen = (int)((double)bufferLen / sampleSize);
int outLen = samples;
SpeexResamplerState * resampler = channel->GetResampler();
if (resampler == nullptr)
{
resampler = speex_resampler_init(_format.channels, _format.freq, _format.freq, 0, 0);
channel->SetResampler(resampler);
}
if (useBufferLengthForRatio)
{
// use buffer lengths for conversion ratio so that it fits exactly
speex_resampler_set_rate(resampler, inLen, samples);
}
else
{
// reached end of stream so we cant use buffer length as resampling ratio
speex_resampler_set_rate(resampler, _format.freq, (int)(_format.freq * (1 / rate)));
}
size_t effectBufferReqLen = outLen * sampleSize;
if (_effectBuffer == nullptr || _effectBufferCapacity < effectBufferReqLen)
{
_effectBuffer = realloc(_effectBuffer, effectBufferReqLen);
_effectBufferCapacity = effectBufferReqLen;
}
speex_resampler_process_interleaved_int(
resampler,
(const spx_int16_t *)buffer,
(spx_uint32_t *)&inLen,
(spx_int16_t *)_effectBuffer,
(spx_uint32_t *)&outLen);
*newLength = effectBufferReqLen;
applied = true;
resampler = speex_resampler_init(_format.channels, _format.freq, _format.freq, 0, 0);
channel->SetResampler(resampler);
}
return applied;
speex_resampler_set_rate(resampler, srcSamples, dstSamples);
// Ensure destination buffer is large enough
size_t effectBufferReqLen = dstSamples * byteRate;
if (_effectBuffer == nullptr || _effectBufferCapacity < effectBufferReqLen)
{
_effectBuffer = realloc(_effectBuffer, effectBufferReqLen);
_effectBufferCapacity = effectBufferReqLen;
}
uint32 inLen = srcSamples;
uint32 outLen = dstSamples;
speex_resampler_process_interleaved_int(
resampler,
(const spx_int16_t *)srcBuffer,
&inLen,
(spx_int16_t *)_effectBuffer,
&outLen);
return outLen * byteRate;
}
void ApplyPan(const IAudioChannel * channel, void * buffer, size_t len, size_t sampleSize)