mirror of https://github.com/OpenRCT2/OpenRCT2.git
Refactor memory handling in audio sources
This commit is contained in:
parent
104419f6b2
commit
0b8575270c
|
@ -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;
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
*****************************************************************************/
|
||||
#pragma endregion
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include <openrct2/common.h>
|
||||
#include <SDL.h>
|
||||
#include <openrct2/core/Math.hpp>
|
||||
|
@ -33,9 +35,14 @@ namespace OpenRCT2 { namespace Audio
|
|||
{
|
||||
private:
|
||||
AudioFormat _format = { 0 };
|
||||
uint8 * _data = nullptr;
|
||||
std::vector<uint8> _data;
|
||||
uint8 * _dataSDL = nullptr;
|
||||
size_t _length = 0;
|
||||
bool _isSDLWav = false;
|
||||
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue