mirror of https://github.com/OpenRCT2/OpenRCT2.git
Move Source to an interface
This commit is contained in:
parent
6b2ad98a07
commit
ca7bbdfbcc
|
@ -18,68 +18,92 @@
|
|||
#include <list>
|
||||
#include "../core/Guard.hpp"
|
||||
#include "../core/Math.hpp"
|
||||
#include "../core/Memory.hpp"
|
||||
#include "../core/Util.hpp"
|
||||
#include "mixer.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "../config.h"
|
||||
#include "../localisation/localisation.h"
|
||||
#include "../OpenRCT2.h"
|
||||
#include "../platform/platform.h"
|
||||
#include "../rct2.h"
|
||||
#include "audio.h"
|
||||
#include "../config.h"
|
||||
#include "../localisation/localisation.h"
|
||||
#include "../OpenRCT2.h"
|
||||
#include "../platform/platform.h"
|
||||
#include "../rct2.h"
|
||||
#include "audio.h"
|
||||
}
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct WaveFormat
|
||||
{
|
||||
Uint16 encoding;
|
||||
Uint16 channels;
|
||||
Uint32 frequency;
|
||||
Uint32 byterate;
|
||||
Uint16 blockalign;
|
||||
Uint16 bitspersample;
|
||||
};
|
||||
assert_struct_size(WaveFormat, 16);
|
||||
|
||||
struct WaveFormatEx
|
||||
{
|
||||
uint16 encoding;
|
||||
uint16 channels;
|
||||
uint32 frequency;
|
||||
uint32 byterate;
|
||||
uint16 blockalign;
|
||||
uint16 bitspersample;
|
||||
uint16 extrasize;
|
||||
};
|
||||
assert_struct_size(WaveFormatEx, 18);
|
||||
#pragma pack(pop)
|
||||
|
||||
IAudioMixer * gMixer;
|
||||
|
||||
Source::~Source()
|
||||
{
|
||||
// unsigned long Source::GetSome(unsigned long offset, const uint8** data, unsigned long length)
|
||||
// {
|
||||
// if (offset >= Length()) {
|
||||
// return 0;
|
||||
// }
|
||||
// unsigned long size = length;
|
||||
// if (offset + length > Length()) {
|
||||
// size = Length() - offset;
|
||||
// }
|
||||
// return Read(offset, data, size);
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
unsigned long Source::GetSome(unsigned long offset, const uint8** data, unsigned long length)
|
||||
{
|
||||
if (offset >= Length()) {
|
||||
return 0;
|
||||
}
|
||||
unsigned long size = length;
|
||||
if (offset + length > Length()) {
|
||||
size = Length() - offset;
|
||||
}
|
||||
return Read(offset, data, size);
|
||||
}
|
||||
|
||||
unsigned long Source::Length()
|
||||
{
|
||||
return length;
|
||||
}
|
||||
|
||||
const AudioFormat& Source::Format()
|
||||
{
|
||||
return format;
|
||||
}
|
||||
|
||||
class Source_Null : public Source
|
||||
/**
|
||||
* An audio source representing silence.
|
||||
*/
|
||||
class Source_Null : public IAudioSource
|
||||
{
|
||||
public:
|
||||
Source_Null()
|
||||
size_t GetLength() override
|
||||
{
|
||||
length = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected:
|
||||
unsigned long Read(unsigned long offset, const uint8 * * data, unsigned long length) override
|
||||
AudioFormat GetFormat() override
|
||||
{
|
||||
return { 0 };
|
||||
}
|
||||
|
||||
size_t Read(void * dst, size_t offset, size_t len) override
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
class Source_Sample : public Source
|
||||
/**
|
||||
* An audio source where raw PCM data is initially loaded into RAM from
|
||||
* a file and then streamed.
|
||||
*/
|
||||
class Source_Sample : public IAudioSource
|
||||
{
|
||||
private:
|
||||
uint8 * data = nullptr;
|
||||
bool issdlwav = false;
|
||||
AudioFormat _format = { 0 };
|
||||
uint8 * _data = nullptr;
|
||||
size_t _length = 0;
|
||||
bool _isSDLWav = false;
|
||||
|
||||
public:
|
||||
~Source_Sample()
|
||||
|
@ -87,118 +111,137 @@ public:
|
|||
Unload();
|
||||
}
|
||||
|
||||
bool LoadWAV(const char * filename)
|
||||
size_t GetLength() override
|
||||
{
|
||||
log_verbose("Source_Sample::LoadWAV(%s)", filename);
|
||||
return _length;
|
||||
}
|
||||
|
||||
AudioFormat GetFormat() override
|
||||
{
|
||||
return _format;
|
||||
}
|
||||
|
||||
size_t Read(void * dst, size_t offset, size_t len) override
|
||||
{
|
||||
size_t bytesToRead = 0;
|
||||
if (offset < _length)
|
||||
{
|
||||
bytesToRead = Math::Min(len, _length - offset);
|
||||
Memory::Copy<void>(dst, _data + offset, bytesToRead);
|
||||
}
|
||||
return bytesToRead;
|
||||
}
|
||||
|
||||
bool LoadWAV(const utf8 * path)
|
||||
{
|
||||
log_verbose("Source_Sample::LoadWAV(%s)", path);
|
||||
|
||||
Unload();
|
||||
SDL_RWops* rw = SDL_RWFromFile(filename, "rb");
|
||||
if (rw == NULL)
|
||||
{
|
||||
log_verbose("Error loading %s", filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
SDL_AudioSpec audiospec;
|
||||
memset(&audiospec, 0, sizeof(audiospec));
|
||||
SDL_AudioSpec* spec = SDL_LoadWAV_RW(rw, false, &audiospec, &data, (Uint32*)&length);
|
||||
SDL_RWclose(rw);
|
||||
|
||||
if (spec != NULL)
|
||||
bool result = false;
|
||||
SDL_RWops * rw = SDL_RWFromFile(path, "rb");
|
||||
if (rw != nullptr)
|
||||
{
|
||||
format.freq = spec->freq;
|
||||
format.format = spec->format;
|
||||
format.channels = spec->channels;
|
||||
issdlwav = true;
|
||||
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, unsupported WAV format", filename);
|
||||
return false;
|
||||
log_verbose("Error loading %s", path);
|
||||
}
|
||||
|
||||
return true;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool LoadCSS1(const char * filename, unsigned int offset)
|
||||
bool LoadCSS1(const utf8 * path, size_t index)
|
||||
{
|
||||
log_verbose("Source_Sample::LoadCSS1(%s, %d)", filename, offset);
|
||||
log_verbose("Source_Sample::LoadCSS1(%s, %d)", path, index);
|
||||
|
||||
Unload();
|
||||
SDL_RWops * rw = SDL_RWFromFile(filename, "rb");
|
||||
if (rw == nullptr)
|
||||
{
|
||||
log_verbose("Unable to load %s", filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
Uint32 numsounds;
|
||||
SDL_RWread(rw, &numsounds, sizeof(numsounds), 1);
|
||||
if (offset > numsounds)
|
||||
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);
|
||||
return false;
|
||||
}
|
||||
SDL_RWseek(rw, offset * 4, RW_SEEK_CUR);
|
||||
Uint32 soundoffset;
|
||||
SDL_RWread(rw, &soundoffset, sizeof(soundoffset), 1);
|
||||
SDL_RWseek(rw, soundoffset, RW_SEEK_SET);
|
||||
Uint32 soundsize;
|
||||
SDL_RWread(rw, &soundsize, sizeof(soundsize), 1);
|
||||
length = soundsize;
|
||||
#pragma pack(push, 1)
|
||||
struct WaveFormatEx
|
||||
else
|
||||
{
|
||||
Uint16 encoding;
|
||||
Uint16 channels;
|
||||
Uint32 frequency;
|
||||
Uint32 byterate;
|
||||
Uint16 blockalign;
|
||||
Uint16 bitspersample;
|
||||
Uint16 extrasize;
|
||||
} waveformat;
|
||||
#pragma pack(pop)
|
||||
assert_struct_size(waveformat, 18);
|
||||
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)
|
||||
{
|
||||
log_verbose("Unable to allocate data");
|
||||
SDL_RWclose(rw);
|
||||
return false;
|
||||
log_verbose("Unable to load %s", path);
|
||||
}
|
||||
SDL_RWread(rw, data, length, 1);
|
||||
SDL_RWclose(rw);
|
||||
return true;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Convert(AudioFormat format)
|
||||
bool Convert(const AudioFormat * format)
|
||||
{
|
||||
if (Source_Sample::format.format != format.format ||
|
||||
Source_Sample::format.channels != format.channels ||
|
||||
Source_Sample::format.freq != format.freq)
|
||||
if (_format.format != format->format ||
|
||||
_format.channels != format->channels ||
|
||||
_format.freq != format->freq)
|
||||
{
|
||||
SDL_AudioCVT cvt;
|
||||
if (SDL_BuildAudioCVT(&cvt, Source_Sample::format.format, Source_Sample::format.channels, Source_Sample::format.freq, format.format, format.channels, format.freq) < 0)
|
||||
if (SDL_BuildAudioCVT(&cvt, _format.format, _format.channels, _format.freq, format->format, format->channels, format->freq) >= 0)
|
||||
{
|
||||
return false;
|
||||
cvt.len = (int)_length;
|
||||
cvt.buf = (Uint8*)new uint8[cvt.len * cvt.len_mult];
|
||||
memcpy(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;
|
||||
}
|
||||
}
|
||||
cvt.len = length;
|
||||
cvt.buf = (Uint8*)new uint8[cvt.len * cvt.len_mult];
|
||||
memcpy(cvt.buf, data, length);
|
||||
if (SDL_ConvertAudio(&cvt) < 0)
|
||||
{
|
||||
delete[] cvt.buf;
|
||||
return false;
|
||||
}
|
||||
Unload();
|
||||
data = cvt.buf;
|
||||
length = cvt.len_cvt;
|
||||
Source_Sample::format = format;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -206,37 +249,34 @@ public:
|
|||
private:
|
||||
void Unload()
|
||||
{
|
||||
if (data != nullptr)
|
||||
if (_data != nullptr)
|
||||
{
|
||||
if (issdlwav)
|
||||
if (_isSDLWav)
|
||||
{
|
||||
SDL_FreeWAV(data);
|
||||
SDL_FreeWAV(_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
delete[] data;
|
||||
delete[] _data;
|
||||
}
|
||||
data = nullptr;
|
||||
_data = nullptr;
|
||||
}
|
||||
issdlwav = false;
|
||||
length = 0;
|
||||
}
|
||||
|
||||
protected:
|
||||
unsigned long Read(unsigned long offset, const uint8 * * data, unsigned long length) override
|
||||
{
|
||||
*data = &Source_Sample::data[offset];
|
||||
return length;
|
||||
_isSDLWav = false;
|
||||
_length = 0;
|
||||
}
|
||||
};
|
||||
|
||||
class Source_SampleStream : public Source
|
||||
/**
|
||||
* An audio source where raw PCM data is streamed directly from
|
||||
* a file.
|
||||
*/
|
||||
class Source_SampleStream : public IAudioSource
|
||||
{
|
||||
private:
|
||||
SDL_RWops * rw = nullptr;
|
||||
uint64 databegin = 0;
|
||||
uint8 * buffer = nullptr;
|
||||
unsigned long buffersize = 0;
|
||||
AudioFormat _format = { 0 };
|
||||
SDL_RWops * _rw = nullptr;
|
||||
uint64 _dataBegin = 0;
|
||||
uint64 _dataLength = 0;
|
||||
|
||||
public:
|
||||
~Source_SampleStream()
|
||||
|
@ -244,97 +284,132 @@ public:
|
|||
Unload();
|
||||
}
|
||||
|
||||
bool LoadWAV(SDL_RWops* rw)
|
||||
size_t GetLength() override
|
||||
{
|
||||
return _dataLength;
|
||||
}
|
||||
|
||||
AudioFormat GetFormat() override
|
||||
{
|
||||
return _format;
|
||||
}
|
||||
|
||||
size_t Read(void * dst, size_t offset, size_t len) override
|
||||
{
|
||||
size_t bytesRead = 0;
|
||||
sint64 currentPosition = SDL_RWtell(_rw);
|
||||
if (currentPosition != -1)
|
||||
{
|
||||
size_t bytesToRead = Math::Min(len, _dataLength - offset);
|
||||
if (currentPosition != _dataBegin + offset)
|
||||
{
|
||||
sint64 newPosition = SDL_RWseek(_rw, _dataBegin + offset, SEEK_SET);
|
||||
if (newPosition == -1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
bytesRead = SDL_RWread(_rw, dst, 1, bytesToRead);
|
||||
}
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
bool LoadWAV(SDL_RWops * rw)
|
||||
{
|
||||
const uint32 DATA = 0x61746164;
|
||||
const Uint32 FMT = 0x20746D66;
|
||||
const Uint32 RIFF = 0x46464952;
|
||||
const Uint32 WAVE = 0x45564157;
|
||||
const Uint16 pcmformat = 0x0001;
|
||||
|
||||
Unload();
|
||||
if (rw == NULL) {
|
||||
|
||||
if (rw == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
Source_SampleStream::rw = rw;
|
||||
_rw = rw;
|
||||
|
||||
Uint32 chunk_id = SDL_ReadLE32(rw);
|
||||
const Uint32 RIFF = 0x46464952;
|
||||
if (chunk_id != RIFF) {
|
||||
if (chunk_id != RIFF)
|
||||
{
|
||||
log_verbose("Not a WAV file");
|
||||
return false;
|
||||
}
|
||||
Uint32 chunk_size = SDL_ReadLE32(rw);
|
||||
(void)chunk_size;
|
||||
Uint32 chunk_format = SDL_ReadLE32(rw);
|
||||
const Uint32 WAVE = 0x45564157;
|
||||
if (chunk_format != WAVE) {
|
||||
|
||||
Uint32 chunkSize = SDL_ReadLE32(rw);
|
||||
Uint32 chunkFormat = SDL_ReadLE32(rw);
|
||||
if (chunkFormat != WAVE)
|
||||
{
|
||||
log_verbose("Not in WAVE format");
|
||||
return false;
|
||||
}
|
||||
const Uint32 FMT = 0x20746D66;
|
||||
Uint32 fmtchunk_size = FindChunk(rw, FMT);
|
||||
if (!fmtchunk_size) {
|
||||
|
||||
Uint32 fmtChunkSize = FindChunk(rw, FMT);
|
||||
if (!fmtChunkSize)
|
||||
{
|
||||
log_verbose("Could not find FMT chunk");
|
||||
return false;
|
||||
}
|
||||
Uint64 chunkstart = SDL_RWtell(rw);
|
||||
#pragma pack(push, 1)
|
||||
struct WaveFormat
|
||||
{
|
||||
Uint16 encoding;
|
||||
Uint16 channels;
|
||||
Uint32 frequency;
|
||||
Uint32 byterate;
|
||||
Uint16 blockalign;
|
||||
Uint16 bitspersample;
|
||||
} waveformat;
|
||||
#pragma pack(pop)
|
||||
assert_struct_size(waveformat, 16);
|
||||
SDL_RWread(rw, &waveformat, sizeof(waveformat), 1);
|
||||
SDL_RWseek(rw, chunkstart + fmtchunk_size, RW_SEEK_SET);
|
||||
const Uint16 pcmformat = 0x0001;
|
||||
if (waveformat.encoding != pcmformat) {
|
||||
|
||||
uint64 chunkStart = SDL_RWtell(rw);
|
||||
|
||||
WaveFormat waveFormat;
|
||||
SDL_RWread(rw, &waveFormat, sizeof(waveFormat), 1);
|
||||
SDL_RWseek(rw, chunkStart + fmtChunkSize, RW_SEEK_SET);
|
||||
if (waveFormat.encoding != pcmformat) {
|
||||
log_verbose("Not in proper format");
|
||||
return false;
|
||||
}
|
||||
format.freq = waveformat.frequency;
|
||||
switch (waveformat.bitspersample) {
|
||||
|
||||
_format.freq = waveFormat.frequency;
|
||||
switch (waveFormat.bitspersample) {
|
||||
case 8:
|
||||
format.format = AUDIO_U8;
|
||||
_format.format = AUDIO_U8;
|
||||
break;
|
||||
case 16:
|
||||
format.format = AUDIO_S16LSB;
|
||||
_format.format = AUDIO_S16LSB;
|
||||
break;
|
||||
default:
|
||||
log_verbose("Invalid bits per sample");
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
format.channels = waveformat.channels;
|
||||
const Uint32 DATA = 0x61746164;
|
||||
Uint32 datachunk_size = FindChunk(rw, DATA);
|
||||
if (!datachunk_size) {
|
||||
_format.channels = waveFormat.channels;
|
||||
|
||||
uint32 dataChunkSize = FindChunk(rw, DATA);
|
||||
if (dataChunkSize == 0)
|
||||
{
|
||||
log_verbose("Could not find DATA chunk");
|
||||
return false;
|
||||
}
|
||||
length = datachunk_size;
|
||||
databegin = SDL_RWtell(rw);
|
||||
|
||||
_dataLength = dataChunkSize;
|
||||
_dataBegin = SDL_RWtell(rw);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
Uint32 FindChunk(SDL_RWops* rw, Uint32 wanted_id)
|
||||
uint32 FindChunk(SDL_RWops * rw, uint32 wantedId)
|
||||
{
|
||||
Uint32 subchunk_id = SDL_ReadLE32(rw);
|
||||
Uint32 subchunk_size = SDL_ReadLE32(rw);
|
||||
if (subchunk_id == wanted_id)
|
||||
uint32 subchunkId = SDL_ReadLE32(rw);
|
||||
uint32 subchunkSize = SDL_ReadLE32(rw);
|
||||
if (subchunkId == wantedId)
|
||||
{
|
||||
return subchunk_size;
|
||||
return subchunkSize;
|
||||
}
|
||||
const Uint32 FACT = 0x74636166;
|
||||
const Uint32 LIST = 0x5453494c;
|
||||
const Uint32 BEXT = 0x74786562;
|
||||
const Uint32 JUNK = 0x4B4E554A;
|
||||
while (subchunk_id == FACT || subchunk_id == LIST || subchunk_id == BEXT || subchunk_id == JUNK) {
|
||||
SDL_RWseek(rw, subchunk_size, RW_SEEK_CUR);
|
||||
subchunk_id = SDL_ReadLE32(rw);
|
||||
subchunk_size = SDL_ReadLE32(rw);
|
||||
if (subchunk_id == wanted_id) {
|
||||
return subchunk_size;
|
||||
while (subchunkId == FACT || subchunkId == LIST || subchunkId == BEXT || subchunkId == JUNK)
|
||||
{
|
||||
SDL_RWseek(rw, subchunkSize, RW_SEEK_CUR);
|
||||
subchunkId = SDL_ReadLE32(rw);
|
||||
subchunkSize = SDL_ReadLE32(rw);
|
||||
if (subchunkId == wantedId)
|
||||
{
|
||||
return subchunkSize;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
@ -342,59 +417,20 @@ private:
|
|||
|
||||
void Unload()
|
||||
{
|
||||
if (rw != nullptr)
|
||||
if (_rw != nullptr)
|
||||
{
|
||||
SDL_RWclose(rw);
|
||||
rw = nullptr;
|
||||
SDL_RWclose(_rw);
|
||||
_rw = nullptr;
|
||||
}
|
||||
length = 0;
|
||||
SafeDelete(buffer);
|
||||
buffersize = 0;
|
||||
}
|
||||
|
||||
protected:
|
||||
unsigned long Read(unsigned long offset, const uint8** data, unsigned long length) override
|
||||
{
|
||||
if (length > buffersize)
|
||||
{
|
||||
if (buffer)
|
||||
{
|
||||
delete[] buffer;
|
||||
}
|
||||
buffer = new (std::nothrow) uint8[length];
|
||||
if (!buffer)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
buffersize = length;
|
||||
}
|
||||
Sint64 currentposition = SDL_RWtell(rw);
|
||||
if (currentposition == -1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (currentposition - databegin != offset)
|
||||
{
|
||||
Sint64 newposition = SDL_RWseek(rw, databegin + offset, SEEK_SET);
|
||||
if (newposition == -1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
*data = buffer;
|
||||
size_t read = SDL_RWread(rw, buffer, 1, length);
|
||||
if (read == (size_t)-1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return (unsigned long)read;
|
||||
_dataBegin = 0;
|
||||
_dataLength = 0;
|
||||
}
|
||||
};
|
||||
|
||||
class AudioChannel : public IAudioChannel
|
||||
{
|
||||
private:
|
||||
Source * _source = nullptr;
|
||||
IAudioSource * _source = nullptr;
|
||||
SpeexResamplerState * _resampler = nullptr;
|
||||
|
||||
int _group = MIXER_GROUP_SOUND;
|
||||
|
@ -436,7 +472,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
Source * GetSource() const override
|
||||
IAudioSource * GetSource() const override
|
||||
{
|
||||
return _source;
|
||||
}
|
||||
|
@ -478,9 +514,9 @@ public:
|
|||
|
||||
bool SetOffset(unsigned long offset)
|
||||
{
|
||||
if (_source != nullptr && offset < _source->Length())
|
||||
if (_source != nullptr && offset < _source->GetLength())
|
||||
{
|
||||
AudioFormat format = _source->Format();
|
||||
AudioFormat format = _source->GetFormat();
|
||||
int samplesize = format.channels * format.BytesPerSample();
|
||||
_offset = (offset / samplesize) * samplesize;
|
||||
return true;
|
||||
|
@ -595,9 +631,9 @@ public:
|
|||
return !_done;
|
||||
}
|
||||
|
||||
void Play(Source& source, int loop)
|
||||
void Play(IAudioSource * source, int loop)
|
||||
{
|
||||
_source = &source;
|
||||
_source = source;
|
||||
_loop = loop;
|
||||
_offset = 0;
|
||||
_done = false;
|
||||
|
@ -615,7 +651,7 @@ public:
|
|||
AudioFormat result = { 0 };
|
||||
if (_source != nullptr)
|
||||
{
|
||||
result = _source->Format();
|
||||
result = _source->GetFormat();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -626,18 +662,15 @@ public:
|
|||
size_t bytesToRead = len;
|
||||
while (bytesToRead > 0 && !_done)
|
||||
{
|
||||
const uint8 * src = nullptr;
|
||||
unsigned long someLen = _source->GetSome((unsigned long)_offset, &src, (unsigned long)bytesToRead);
|
||||
if (someLen > 0)
|
||||
size_t readLen = _source->Read(dst, _offset, bytesToRead);
|
||||
if (readLen > 0)
|
||||
{
|
||||
size_t copyLen = Math::Min((size_t)someLen, bytesToRead);
|
||||
memcpy(dst, src, copyLen);
|
||||
dst = (void *)((uintptr_t)dst + copyLen);
|
||||
bytesToRead -= copyLen;
|
||||
bytesRead += copyLen;
|
||||
_offset += copyLen;
|
||||
dst = (void *)((uintptr_t)dst + readLen);
|
||||
bytesToRead -= readLen;
|
||||
bytesRead += readLen;
|
||||
_offset += readLen;
|
||||
}
|
||||
if (_offset >= _source->Length())
|
||||
if (_offset >= _source->GetLength())
|
||||
{
|
||||
if (_loop == 0)
|
||||
{
|
||||
|
@ -671,8 +704,8 @@ private:
|
|||
uint8 _setting_sound_vol = 0xFF;
|
||||
uint8 _setting_music_vol = 0xFF;
|
||||
|
||||
Source * _css1sources[SOUND_MAXID] = { nullptr };
|
||||
Source * _musicsources[PATH_ID_END] = { nullptr };
|
||||
IAudioSource * _css1sources[SOUND_MAXID] = { nullptr };
|
||||
IAudioSource * _musicsources[PATH_ID_END] = { nullptr };
|
||||
|
||||
void * _channelBuffer = nullptr;
|
||||
size_t _channelBufferCapacity = 0;
|
||||
|
@ -710,7 +743,7 @@ public:
|
|||
for (int i = 0; i < (int)Util::CountOf(_css1sources); i++) {
|
||||
Source_Sample* source_sample = new Source_Sample;
|
||||
if (source_sample->LoadCSS1(filename, i)) {
|
||||
source_sample->Convert(_format); // convert to audio output format, saves some cpu usage but requires a bit more memory, optional
|
||||
source_sample->Convert(&_format); // convert to audio output format, saves some cpu usage but requires a bit more memory, optional
|
||||
_css1sources[i] = source_sample;
|
||||
} else {
|
||||
_css1sources[i] = &_source_null;
|
||||
|
@ -765,7 +798,7 @@ public:
|
|||
SDL_UnlockAudioDevice(_deviceid);
|
||||
}
|
||||
|
||||
IAudioChannel * Play(Source& source, int loop, bool deleteondone, bool deletesourceondone) override
|
||||
IAudioChannel * Play(IAudioSource * source, int loop, bool deleteondone, bool deletesourceondone) override
|
||||
{
|
||||
Lock();
|
||||
IAudioChannel * newchannel = new (std::nothrow) AudioChannel;
|
||||
|
@ -820,12 +853,12 @@ public:
|
|||
_volume = volume;
|
||||
}
|
||||
|
||||
Source * GetSoundSource(int id) override
|
||||
IAudioSource * GetSoundSource(int id) override
|
||||
{
|
||||
return _css1sources[id];
|
||||
}
|
||||
|
||||
Source * GetMusicSource(int id) override
|
||||
IAudioSource * GetMusicSource(int id) override
|
||||
{
|
||||
return _musicsources[id];
|
||||
}
|
||||
|
@ -1161,8 +1194,8 @@ void * Mixer_Play_Effect(size_t id, int loop, int volume, float pan, double rate
|
|||
{
|
||||
IAudioMixer * mixer = gMixer;
|
||||
mixer->Lock();
|
||||
Source * source = mixer->GetSoundSource((int)id);
|
||||
channel = mixer->Play(*source, loop, deleteondone != 0, false);
|
||||
IAudioSource * source = mixer->GetSoundSource((int)id);
|
||||
channel = mixer->Play(source, loop, deleteondone != 0, false);
|
||||
if (channel != nullptr)
|
||||
{
|
||||
channel->SetVolume(volume);
|
||||
|
@ -1267,7 +1300,7 @@ void * Mixer_Play_Music(int pathId, int loop, int streaming)
|
|||
Source_SampleStream * source_samplestream = new Source_SampleStream;
|
||||
if (source_samplestream->LoadWAV(rw))
|
||||
{
|
||||
channel = mixer->Play(*source_samplestream, loop, false, true);
|
||||
channel = mixer->Play(source_samplestream, loop, false, true);
|
||||
if (channel == nullptr)
|
||||
{
|
||||
delete source_samplestream;
|
||||
|
@ -1283,8 +1316,8 @@ void * Mixer_Play_Music(int pathId, int loop, int streaming)
|
|||
{
|
||||
if (mixer->LoadMusic(pathId))
|
||||
{
|
||||
Source * source = mixer->GetMusicSource(pathId);
|
||||
channel = mixer->Play(*source, MIXER_LOOP_INFINITE, false, false);
|
||||
IAudioSource * source = mixer->GetMusicSource(pathId);
|
||||
channel = mixer->Play(source, MIXER_LOOP_INFINITE, false, false);
|
||||
}
|
||||
}
|
||||
if (channel != nullptr)
|
||||
|
|
|
@ -44,6 +44,10 @@ enum MIXER_GROUP
|
|||
|
||||
#ifdef __cplusplus
|
||||
|
||||
/**
|
||||
* Represents the size, frequency and number of channels for
|
||||
* an audio stream or buffer.
|
||||
*/
|
||||
struct AudioFormat
|
||||
{
|
||||
int freq;
|
||||
|
@ -56,26 +60,27 @@ struct AudioFormat
|
|||
}
|
||||
};
|
||||
|
||||
class Source
|
||||
/**
|
||||
* Represents a readable source of audio PCM data.
|
||||
*/
|
||||
interface IAudioSource
|
||||
{
|
||||
public:
|
||||
virtual ~Source();
|
||||
unsigned long GetSome(unsigned long offset, const uint8** data, unsigned long length);
|
||||
unsigned long Length();
|
||||
const AudioFormat& Format();
|
||||
virtual ~IAudioSource() = default;
|
||||
|
||||
protected:
|
||||
virtual unsigned long Read(unsigned long offset, const uint8** data, unsigned long length) = 0;
|
||||
|
||||
AudioFormat format;
|
||||
unsigned long length = 0;
|
||||
virtual size_t GetLength() abstract;
|
||||
virtual AudioFormat GetFormat() abstract;
|
||||
virtual size_t Read(void * dst, size_t offset, size_t len) abstract;
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents an audio channel that represents an audio source
|
||||
* and a number of properties such as volume, pan and loop information.
|
||||
*/
|
||||
interface IAudioChannel
|
||||
{
|
||||
virtual ~IAudioChannel() = default;
|
||||
|
||||
virtual Source * GetSource() const abstract;
|
||||
virtual IAudioSource * GetSource() const abstract;
|
||||
|
||||
virtual SpeexResamplerState * GetResampler() const abstract;
|
||||
virtual void SetResampler(SpeexResamplerState * value) abstract;
|
||||
|
@ -116,13 +121,16 @@ interface IAudioChannel
|
|||
|
||||
virtual bool IsPlaying() const abstract;
|
||||
|
||||
virtual void Play(Source& source, int loop = MIXER_LOOP_NONE) abstract;
|
||||
virtual void Play(IAudioSource * source, int loop = MIXER_LOOP_NONE) abstract;
|
||||
virtual void UpdateOldVolume() abstract;
|
||||
|
||||
virtual AudioFormat GetFormat() const abstract;
|
||||
virtual size_t Read(void * dst, size_t len) abstract;
|
||||
};
|
||||
|
||||
/**
|
||||
* Provides an audio stream by mixing multiple audio channels together.
|
||||
*/
|
||||
interface IAudioMixer
|
||||
{
|
||||
virtual ~IAudioMixer() = default;
|
||||
|
@ -131,13 +139,13 @@ interface IAudioMixer
|
|||
virtual void Close() abstract;
|
||||
virtual void Lock() abstract;
|
||||
virtual void Unlock() abstract;
|
||||
virtual IAudioChannel * Play(Source& source, int loop, bool deleteondone, bool deletesourceondone) abstract;
|
||||
virtual IAudioChannel * Play(IAudioSource * source, int loop, bool deleteondone, bool deletesourceondone) abstract;
|
||||
virtual void Stop(IAudioChannel * channel) abstract;
|
||||
virtual bool LoadMusic(size_t pathid) abstract;
|
||||
virtual void SetVolume(float volume) abstract;
|
||||
|
||||
virtual Source * GetSoundSource(int id) abstract;
|
||||
virtual Source * GetMusicSource(int id) abstract;
|
||||
virtual IAudioSource * GetSoundSource(int id) abstract;
|
||||
virtual IAudioSource * GetMusicSource(int id) abstract;
|
||||
};
|
||||
|
||||
extern "C"
|
||||
|
|
Loading…
Reference in New Issue