mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2026-01-19 21:13:05 +01:00
Move contents of src into project sub directory
This commit is contained in:
245
src/openrct2/audio/MemoryAudioSource.cpp
Normal file
245
src/openrct2/audio/MemoryAudioSource.cpp
Normal file
@@ -0,0 +1,245 @@
|
||||
#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers
|
||||
/*****************************************************************************
|
||||
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
|
||||
*
|
||||
* OpenRCT2 is the work of many authors, a full list can be found in contributors.md
|
||||
* For more information, visit https://github.com/OpenRCT2/OpenRCT2
|
||||
*
|
||||
* OpenRCT2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* A full copy of the GNU General Public License can be found in licence.txt
|
||||
*****************************************************************************/
|
||||
#pragma endregion
|
||||
|
||||
#include "../core/Math.hpp"
|
||||
#include "../core/Memory.hpp"
|
||||
#include "AudioMixer.h"
|
||||
#include "AudioSource.h"
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct WaveFormatEx
|
||||
{
|
||||
uint16 encoding;
|
||||
uint16 channels;
|
||||
uint32 frequency;
|
||||
uint32 byterate;
|
||||
uint16 blockalign;
|
||||
uint16 bitspersample;
|
||||
uint16 extrasize;
|
||||
};
|
||||
assert_struct_size(WaveFormatEx, 18);
|
||||
#pragma pack(pop)
|
||||
|
||||
/**
|
||||
* An audio source where raw PCM data is initially loaded into RAM from
|
||||
* a file and then streamed.
|
||||
*/
|
||||
class MemoryAudioSource : public IAudioSource
|
||||
{
|
||||
private:
|
||||
AudioFormat _format = { 0 };
|
||||
uint8 * _data = nullptr;
|
||||
size_t _length = 0;
|
||||
bool _isSDLWav = false;
|
||||
|
||||
public:
|
||||
~MemoryAudioSource()
|
||||
{
|
||||
Unload();
|
||||
}
|
||||
|
||||
uint64 GetLength() override
|
||||
{
|
||||
return _length;
|
||||
}
|
||||
|
||||
AudioFormat GetFormat() override
|
||||
{
|
||||
return _format;
|
||||
}
|
||||
|
||||
size_t Read(void * dst, uint64 offset, size_t len) override
|
||||
{
|
||||
size_t bytesToRead = 0;
|
||||
if (offset < _length)
|
||||
{
|
||||
bytesToRead = (size_t)Math::Min<uint64>(len, _length - offset);
|
||||
Memory::Copy<void>(dst, _data + offset, bytesToRead);
|
||||
}
|
||||
return bytesToRead;
|
||||
}
|
||||
|
||||
bool LoadWAV(const utf8 * path)
|
||||
{
|
||||
log_verbose("MemoryAudioSource::LoadWAV(%s)", path);
|
||||
|
||||
Unload();
|
||||
|
||||
bool result = false;
|
||||
SDL_RWops * rw = SDL_RWFromFile(path, "rb");
|
||||
if (rw != nullptr)
|
||||
{
|
||||
SDL_AudioSpec audiospec = { 0 };
|
||||
uint32 audioLen;
|
||||
SDL_AudioSpec * spec = SDL_LoadWAV_RW(rw, false, &audiospec, &_data, &audioLen);
|
||||
if (spec != nullptr)
|
||||
{
|
||||
_format.freq = spec->freq;
|
||||
_format.format = spec->format;
|
||||
_format.channels = spec->channels;
|
||||
_length = audioLen;
|
||||
_isSDLWav = true;
|
||||
result = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
log_verbose("Error loading %s, unsupported WAV format", path);
|
||||
}
|
||||
SDL_RWclose(rw);
|
||||
}
|
||||
else
|
||||
{
|
||||
log_verbose("Error loading %s", path);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool LoadCSS1(const utf8 * path, size_t index)
|
||||
{
|
||||
log_verbose("MemoryAudioSource::LoadCSS1(%s, %d)", path, index);
|
||||
|
||||
Unload();
|
||||
|
||||
bool result = false;
|
||||
SDL_RWops * rw = SDL_RWFromFile(path, "rb");
|
||||
if (rw != nullptr)
|
||||
{
|
||||
uint32 numSounds;
|
||||
SDL_RWread(rw, &numSounds, sizeof(numSounds), 1);
|
||||
if (index < numSounds)
|
||||
{
|
||||
SDL_RWseek(rw, index * 4, RW_SEEK_CUR);
|
||||
|
||||
uint32 pcmOffset;
|
||||
SDL_RWread(rw, &pcmOffset, sizeof(pcmOffset), 1);
|
||||
SDL_RWseek(rw, pcmOffset, RW_SEEK_SET);
|
||||
|
||||
uint32 pcmSize;
|
||||
SDL_RWread(rw, &pcmSize, sizeof(pcmSize), 1);
|
||||
_length = pcmSize;
|
||||
|
||||
WaveFormatEx waveFormat;
|
||||
SDL_RWread(rw, &waveFormat, sizeof(waveFormat), 1);
|
||||
_format.freq = waveFormat.frequency;
|
||||
_format.format = AUDIO_S16LSB;
|
||||
_format.channels = waveFormat.channels;
|
||||
|
||||
_data = new (std::nothrow) uint8[_length];
|
||||
if (_data != nullptr)
|
||||
{
|
||||
SDL_RWread(rw, _data, _length, 1);
|
||||
result = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
log_verbose("Unable to allocate data");
|
||||
}
|
||||
}
|
||||
SDL_RWclose(rw);
|
||||
}
|
||||
else
|
||||
{
|
||||
log_verbose("Unable to load %s", path);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Convert(const AudioFormat * format)
|
||||
{
|
||||
if (*format != _format)
|
||||
{
|
||||
SDL_AudioCVT cvt;
|
||||
if (SDL_BuildAudioCVT(&cvt, _format.format, _format.channels, _format.freq, format->format, format->channels, format->freq) >= 0)
|
||||
{
|
||||
cvt.len = (int)_length;
|
||||
cvt.buf = new uint8[cvt.len * cvt.len_mult];
|
||||
Memory::Copy(cvt.buf, _data, _length);
|
||||
if (SDL_ConvertAudio(&cvt) >= 0)
|
||||
{
|
||||
Unload();
|
||||
_data = cvt.buf;
|
||||
_length = cvt.len_cvt;
|
||||
_format = *format;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
delete[] cvt.buf;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
void Unload()
|
||||
{
|
||||
if (_data != nullptr)
|
||||
{
|
||||
if (_isSDLWav)
|
||||
{
|
||||
SDL_FreeWAV(_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
delete[] _data;
|
||||
}
|
||||
_data = nullptr;
|
||||
}
|
||||
_isSDLWav = false;
|
||||
_length = 0;
|
||||
}
|
||||
};
|
||||
|
||||
IAudioSource * AudioSource::CreateMemoryFromCSS1(const utf8 * path, size_t index, const AudioFormat * targetFormat)
|
||||
{
|
||||
auto source = new MemoryAudioSource();
|
||||
if (source->LoadCSS1(path, index))
|
||||
{
|
||||
if (targetFormat != nullptr)
|
||||
{
|
||||
if (!source->Convert(targetFormat))
|
||||
{
|
||||
SafeDelete(source);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SafeDelete(source);
|
||||
}
|
||||
return source;
|
||||
}
|
||||
|
||||
IAudioSource * AudioSource::CreateMemoryFromWAV(const utf8 * path, const AudioFormat * targetFormat)
|
||||
{
|
||||
auto source = new MemoryAudioSource();
|
||||
if (source->LoadWAV(path))
|
||||
{
|
||||
if (targetFormat != nullptr)
|
||||
{
|
||||
if (!source->Convert(targetFormat))
|
||||
{
|
||||
SafeDelete(source);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SafeDelete(source);
|
||||
}
|
||||
return source;
|
||||
}
|
||||
Reference in New Issue
Block a user