Refactor memory handling in audio sources

This commit is contained in:
Ted John 2018-01-19 00:09:42 +00:00
parent 104419f6b2
commit 0b8575270c
2 changed files with 60 additions and 81 deletions

View File

@ -14,10 +14,12 @@
*****************************************************************************/
#pragma endregion
#include <algorithm>
#include <list>
#include <vector>
#include <openrct2/common.h>
#include <SDL.h>
#include <speex/speex_resampler.h>
#include <list>
#include <openrct2/Context.h>
#include <openrct2/core/Guard.hpp>
#include <openrct2/core/Math.hpp>
@ -37,38 +39,6 @@
namespace OpenRCT2 { namespace Audio
{
struct Buffer
{
private:
void * _data = nullptr;
size_t _capacity = 0;
public:
void * GetData() const { return _data; }
void * GetData() { return _data; }
size_t GetCapacity() const { return _capacity; }
~Buffer()
{
Free();
}
void Free()
{
SafeFree(_data);
_capacity = 0;
}
void EnsureCapacity(size_t capacity)
{
if (_capacity < capacity)
{
_capacity = capacity;
_data = Memory::Reallocate(_data, capacity);
}
}
};
class AudioMixerImpl final : public IAudioMixer
{
private:
@ -86,9 +56,9 @@ namespace OpenRCT2 { namespace Audio
IAudioSource * _css1Sources[SOUND_MAXID] = { nullptr };
IAudioSource * _musicSources[PATH_ID_END] = { nullptr };
Buffer _channelBuffer;
Buffer _convertBuffer;
Buffer _effectBuffer;
std::vector<uint8> _channelBuffer;
std::vector<uint8> _convertBuffer;
std::vector<uint8> _effectBuffer;
public:
AudioMixerImpl()
@ -159,9 +129,12 @@ namespace OpenRCT2 { namespace Audio
}
// Free buffers
_channelBuffer.Free();
_convertBuffer.Free();
_effectBuffer.Free();
_channelBuffer.clear();
_channelBuffer.shrink_to_fit();
_convertBuffer.clear();
_convertBuffer.shrink_to_fit();
_effectBuffer.clear();
_effectBuffer.shrink_to_fit();
}
void Lock() override
@ -252,7 +225,7 @@ namespace OpenRCT2 { namespace Audio
UpdateAdjustedSound();
// Zero the output buffer
Memory::Set(dst, 0, length);
std::fill_n(dst, length, 0);
// Mix channels onto output buffer
auto it = _channels.begin();
@ -318,15 +291,15 @@ namespace OpenRCT2 { namespace Audio
// Read raw PCM from channel
sint32 readSamples = (sint32)(numSamples * rate);
size_t readLength = (size_t)(readSamples / cvt.len_ratio) * byteRate;
_channelBuffer.EnsureCapacity(readLength);
size_t bytesRead = channel->Read(_channelBuffer.GetData(), readLength);
_channelBuffer.resize(readLength);
size_t bytesRead = channel->Read(_channelBuffer.data(), readLength);
// Convert data to required format if necessary
void * buffer = nullptr;
size_t bufferLen = 0;
if (mustConvert)
{
if (Convert(&cvt, _channelBuffer.GetData(), bytesRead))
if (Convert(&cvt, _channelBuffer.data(), bytesRead))
{
buffer = cvt.buf;
bufferLen = cvt.len_cvt;
@ -338,7 +311,7 @@ namespace OpenRCT2 { namespace Audio
}
else
{
buffer = _channelBuffer.GetData();
buffer = _channelBuffer.data();
bufferLen = bytesRead;
}
@ -352,9 +325,9 @@ namespace OpenRCT2 { namespace Audio
inRate = _format.freq;
outRate = _format.freq * (1 / rate);
}
_effectBuffer.EnsureCapacity(length);
_effectBuffer.resize(length);
bufferLen = ApplyResample(channel, buffer, (sint32)(bufferLen / byteRate), numSamples, inRate, outRate);
buffer = _effectBuffer.GetData();
buffer = _effectBuffer.data();
}
// Apply panning and volume
@ -391,7 +364,7 @@ namespace OpenRCT2 { namespace Audio
resampler,
(const spx_int16_t *)srcBuffer,
&inLen,
(spx_int16_t *)_effectBuffer.GetData(),
(spx_int16_t *)_effectBuffer.data(),
&outLen);
return outLen * byteRate;
@ -523,11 +496,11 @@ namespace OpenRCT2 { namespace Audio
if (len != 0 && cvt->len_mult != 0)
{
size_t reqConvertBufferCapacity = len * cvt->len_mult;
_convertBuffer.EnsureCapacity(reqConvertBufferCapacity);
Memory::Copy(_convertBuffer.GetData(), src, len);
_convertBuffer.resize(reqConvertBufferCapacity);
std::copy_n((const uint8 *)src, len, _convertBuffer.data());
cvt->len = (sint32)len;
cvt->buf = (uint8 *)_convertBuffer.GetData();
cvt->buf = (uint8 *)_convertBuffer.data();
if (SDL_ConvertAudio(cvt) >= 0)
{
result = true;

View File

@ -14,6 +14,8 @@
*****************************************************************************/
#pragma endregion
#include <algorithm>
#include <vector>
#include <openrct2/common.h>
#include <SDL.h>
#include <openrct2/core/Math.hpp>
@ -32,10 +34,15 @@ namespace OpenRCT2 { namespace Audio
class MemoryAudioSource final : public ISDLAudioSource
{
private:
AudioFormat _format = { 0 };
uint8 * _data = nullptr;
size_t _length = 0;
bool _isSDLWav = false;
AudioFormat _format = { 0 };
std::vector<uint8> _data;
uint8 * _dataSDL = nullptr;
size_t _length = 0;
const uint8 * GetData()
{
return _dataSDL != nullptr ? _dataSDL : _data.data();
}
public:
~MemoryAudioSource()
@ -59,7 +66,12 @@ namespace OpenRCT2 { namespace Audio
if (offset < _length)
{
bytesToRead = (size_t)Math::Min<uint64>(len, _length - offset);
Memory::Copy<void>(dst, _data + offset, bytesToRead);
auto src = GetData();
if (src != nullptr)
{
std::copy_n(src + offset, bytesToRead, (uint8 *)dst);
}
}
return bytesToRead;
}
@ -76,14 +88,13 @@ namespace OpenRCT2 { namespace Audio
{
SDL_AudioSpec audiospec = { 0 };
uint32 audioLen;
SDL_AudioSpec * spec = SDL_LoadWAV_RW(rw, false, &audiospec, &_data, &audioLen);
SDL_AudioSpec * spec = SDL_LoadWAV_RW(rw, false, &audiospec, &_dataSDL, &audioLen);
if (spec != nullptr)
{
_format.freq = spec->freq;
_format.format = spec->format;
_format.channels = spec->channels;
_length = audioLen;
_isSDLWav = true;
result = true;
}
else
@ -129,13 +140,13 @@ namespace OpenRCT2 { namespace Audio
_format.format = AUDIO_S16LSB;
_format.channels = waveFormat.channels;
_data = new (std::nothrow) uint8[_length];
if (_data != nullptr)
try
{
SDL_RWread(rw, _data, _length, 1);
_data.resize(_length);
SDL_RWread(rw, _data.data(), _length, 1);
result = true;
}
else
catch (const std::bad_alloc &)
{
log_verbose("Unable to allocate data");
}
@ -156,21 +167,21 @@ namespace OpenRCT2 { namespace Audio
SDL_AudioCVT cvt;
if (SDL_BuildAudioCVT(&cvt, _format.format, _format.channels, _format.freq, format->format, format->channels, format->freq) >= 0)
{
auto src = GetData();
auto cvtBuffer = std::vector<uint8>(_length * cvt.len_mult);
std::copy_n(src, _length, cvtBuffer.data());
cvt.len = (sint32)_length;
cvt.buf = new uint8[cvt.len * cvt.len_mult];
Memory::Copy(cvt.buf, _data, _length);
cvt.buf = cvtBuffer.data();
if (SDL_ConvertAudio(&cvt) >= 0)
{
cvtBuffer.resize(cvt.len_cvt);
Unload();
_data = cvt.buf;
_data = std::move(cvtBuffer);
_length = cvt.len_cvt;
_format = *format;
return true;
}
else
{
delete[] cvt.buf;
}
}
}
return false;
@ -179,19 +190,14 @@ namespace OpenRCT2 { namespace Audio
private:
void Unload()
{
if (_data != nullptr)
{
if (_isSDLWav)
{
SDL_FreeWAV(_data);
}
else
{
delete[] _data;
}
_data = nullptr;
}
_isSDLWav = false;
// Free our data
_data.clear();
_data.shrink_to_fit();
// Free SDL2's data
SDL_FreeWAV(_dataSDL);
_dataSDL = nullptr;
_length = 0;
}
};