mirror of
https://github.com/halpz/re3.git
synced 2025-06-30 09:26:24 +00:00
Merge branch 'miami' into lcs
* miami: wtf fix small cleanup Fix gOneShotCol Fix garage messages position Fix font on green screen counter Add MPG123_QUIET to mp3 files Make opus available alongside other formats Fix pickup text Fix char in stats Add missing GXT line fail minor refactoring Fix 16KHz track GET_WHEELIE_STATS fix Cleanup and fixes for new decoders Fixes for CVbFile Small fixes for new wav decoder Remove fastmath from premake's config Implementing our own WAV decoder to replace SndFile
This commit is contained in:
@ -219,7 +219,9 @@ static const int32 gOneShotCol[] = {SFX_COL_TARMAC_1,
|
||||
SFX_TYRE_BUMP,
|
||||
SFX_COL_CARDBOARD_1,
|
||||
SFX_COL_TARMAC_1,
|
||||
SFX_COL_GATE};
|
||||
SFX_COL_GATE,
|
||||
SFX_COL_SAND_1,
|
||||
SFX_COL_TARMAC_1 };
|
||||
|
||||
void
|
||||
cAudioManager::SetUpOneShotCollisionSound(const cAudioCollision &col)
|
||||
|
@ -4,16 +4,23 @@
|
||||
#include "stream.h"
|
||||
#include "sampman.h"
|
||||
|
||||
#ifdef AUDIO_OPUS
|
||||
#include <opusfile.h>
|
||||
#else
|
||||
#ifdef _WIN32
|
||||
#ifdef AUDIO_OAL_USE_SNDFILE
|
||||
#pragma comment( lib, "libsndfile-1.lib" )
|
||||
#endif
|
||||
#ifdef AUDIO_OAL_USE_MPG123
|
||||
#pragma comment( lib, "libmpg123-0.lib" )
|
||||
#endif
|
||||
#endif
|
||||
#ifdef AUDIO_OAL_USE_SNDFILE
|
||||
#include <sndfile.h>
|
||||
#endif
|
||||
#ifdef AUDIO_OAL_USE_MPG123
|
||||
#include <mpg123.h>
|
||||
#endif
|
||||
#ifdef AUDIO_OAL_USE_OPUS
|
||||
#include <opusfile.h>
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
#include "crossplatform.h"
|
||||
@ -77,7 +84,315 @@ public:
|
||||
|
||||
CSortStereoBuffer SortStereoBuffer;
|
||||
|
||||
#ifndef AUDIO_OPUS
|
||||
class CImaADPCMDecoder
|
||||
{
|
||||
const uint16 StepTable[89] = {
|
||||
7, 8, 9, 10, 11, 12, 13, 14,
|
||||
16, 17, 19, 21, 23, 25, 28, 31,
|
||||
34, 37, 41, 45, 50, 55, 60, 66,
|
||||
73, 80, 88, 97, 107, 118, 130, 143,
|
||||
157, 173, 190, 209, 230, 253, 279, 307,
|
||||
337, 371, 408, 449, 494, 544, 598, 658,
|
||||
724, 796, 876, 963, 1060, 1166, 1282, 1411,
|
||||
1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024,
|
||||
3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484,
|
||||
7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
|
||||
15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794,
|
||||
32767
|
||||
};
|
||||
|
||||
int16 Sample, StepIndex;
|
||||
|
||||
public:
|
||||
CImaADPCMDecoder()
|
||||
{
|
||||
Init(0, 0);
|
||||
}
|
||||
|
||||
void Init(int16 _Sample, int16 _StepIndex)
|
||||
{
|
||||
Sample = _Sample;
|
||||
StepIndex = _StepIndex;
|
||||
}
|
||||
|
||||
void Decode(uint8 *inbuf, int16 *_outbuf, size_t size)
|
||||
{
|
||||
int16* outbuf = _outbuf;
|
||||
for (size_t i = 0; i < size; i++)
|
||||
{
|
||||
*(outbuf++) = DecodeSample(inbuf[i] & 0xF);
|
||||
*(outbuf++) = DecodeSample(inbuf[i] >> 4);
|
||||
}
|
||||
}
|
||||
|
||||
int16 DecodeSample(uint8 adpcm)
|
||||
{
|
||||
uint16 step = StepTable[StepIndex];
|
||||
|
||||
if (adpcm & 4)
|
||||
StepIndex += ((adpcm & 3) + 1) * 2;
|
||||
else
|
||||
StepIndex--;
|
||||
|
||||
StepIndex = clamp(StepIndex, 0, 88);
|
||||
|
||||
int delta = step >> 3;
|
||||
if (adpcm & 1) delta += step >> 2;
|
||||
if (adpcm & 2) delta += step >> 1;
|
||||
if (adpcm & 4) delta += step;
|
||||
if (adpcm & 8) delta = -delta;
|
||||
|
||||
int newSample = Sample + delta;
|
||||
Sample = clamp(newSample, -32768, 32767);
|
||||
return Sample;
|
||||
}
|
||||
};
|
||||
|
||||
class CWavFile : public IDecoder
|
||||
{
|
||||
enum
|
||||
{
|
||||
WAVEFMT_PCM = 1,
|
||||
WAVEFMT_IMA_ADPCM = 0x11,
|
||||
WAVEFMT_XBOX_ADPCM = 0x69,
|
||||
};
|
||||
|
||||
struct tDataHeader
|
||||
{
|
||||
uint32 ID;
|
||||
uint32 Size;
|
||||
};
|
||||
|
||||
struct tFormatHeader
|
||||
{
|
||||
uint16 AudioFormat;
|
||||
uint16 NumChannels;
|
||||
uint32 SampleRate;
|
||||
uint32 ByteRate;
|
||||
uint16 BlockAlign;
|
||||
uint16 BitsPerSample;
|
||||
uint16 extra[2]; // adpcm only
|
||||
|
||||
tFormatHeader() { memset(this, 0, sizeof(*this)); }
|
||||
};
|
||||
|
||||
FILE *m_pFile;
|
||||
bool m_bIsOpen;
|
||||
|
||||
tFormatHeader m_FormatHeader;
|
||||
|
||||
uint32 m_DataStartOffset; // TODO: 64 bit?
|
||||
uint32 m_nSampleCount;
|
||||
uint32 m_nSamplesPerBlock;
|
||||
|
||||
// ADPCM things
|
||||
uint8 *m_pAdpcmBuffer;
|
||||
int16 **m_ppPcmBuffers;
|
||||
CImaADPCMDecoder *m_pAdpcmDecoders;
|
||||
|
||||
void Close()
|
||||
{
|
||||
if (m_pFile) {
|
||||
fclose(m_pFile);
|
||||
m_pFile = nil;
|
||||
}
|
||||
delete[] m_pAdpcmBuffer;
|
||||
delete[] m_ppPcmBuffers;
|
||||
delete[] m_pAdpcmDecoders;
|
||||
}
|
||||
|
||||
uint32 GetCurrentSample() const
|
||||
{
|
||||
// TODO: 64 bit?
|
||||
uint32 FilePos = ftell(m_pFile);
|
||||
if (FilePos <= m_DataStartOffset)
|
||||
return 0;
|
||||
return (FilePos - m_DataStartOffset) / m_FormatHeader.BlockAlign * m_nSamplesPerBlock;
|
||||
}
|
||||
|
||||
public:
|
||||
CWavFile(const char* path) : m_bIsOpen(false), m_DataStartOffset(0), m_nSampleCount(0), m_nSamplesPerBlock(0), m_pAdpcmBuffer(nil), m_ppPcmBuffers(nil), m_pAdpcmDecoders(nil)
|
||||
{
|
||||
m_pFile = fopen(path, "rb");
|
||||
if (!m_pFile) return;
|
||||
|
||||
#define CLOSE_ON_ERROR(op)\
|
||||
if (op) { \
|
||||
Close(); \
|
||||
return; \
|
||||
}
|
||||
|
||||
tDataHeader DataHeader;
|
||||
|
||||
CLOSE_ON_ERROR(fread(&DataHeader, sizeof(DataHeader), 1, m_pFile) == 0);
|
||||
CLOSE_ON_ERROR(DataHeader.ID != 'FFIR');
|
||||
|
||||
// TODO? validate filesizes
|
||||
|
||||
int WAVE;
|
||||
CLOSE_ON_ERROR(fread(&WAVE, 4, 1, m_pFile) == 0);
|
||||
CLOSE_ON_ERROR(WAVE != 'EVAW')
|
||||
CLOSE_ON_ERROR(fread(&DataHeader, sizeof(DataHeader), 1, m_pFile) == 0);
|
||||
CLOSE_ON_ERROR(DataHeader.ID != ' tmf');
|
||||
|
||||
CLOSE_ON_ERROR(fread(&m_FormatHeader, Min(DataHeader.Size, sizeof(tFormatHeader)), 1, m_pFile) == 0);
|
||||
CLOSE_ON_ERROR(DataHeader.Size > sizeof(tFormatHeader));
|
||||
|
||||
switch (m_FormatHeader.AudioFormat)
|
||||
{
|
||||
case WAVEFMT_XBOX_ADPCM:
|
||||
m_FormatHeader.AudioFormat = WAVEFMT_IMA_ADPCM;
|
||||
case WAVEFMT_IMA_ADPCM:
|
||||
m_nSamplesPerBlock = (m_FormatHeader.BlockAlign / m_FormatHeader.NumChannels - 4) * 2 + 1;
|
||||
m_pAdpcmBuffer = new uint8[m_FormatHeader.BlockAlign];
|
||||
m_ppPcmBuffers = new int16*[m_FormatHeader.NumChannels];
|
||||
m_pAdpcmDecoders = new CImaADPCMDecoder[m_FormatHeader.NumChannels];
|
||||
break;
|
||||
case WAVEFMT_PCM:
|
||||
m_nSamplesPerBlock = 1;
|
||||
if (m_FormatHeader.BitsPerSample != 16)
|
||||
{
|
||||
debug("Unsupported PCM (%d bits), only signed 16-bit is supported (%s)\n", m_FormatHeader.BitsPerSample, path);
|
||||
Close();
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
debug("Unsupported wav format 0x%x (%s)\n", m_FormatHeader.AudioFormat, path);
|
||||
Close();
|
||||
return;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
CLOSE_ON_ERROR(fread(&DataHeader, sizeof(DataHeader), 1, m_pFile) == 0);
|
||||
if (DataHeader.ID == 'atad')
|
||||
break;
|
||||
fseek(m_pFile, DataHeader.Size, SEEK_CUR);
|
||||
// TODO? validate data size
|
||||
// maybe check if there no extreme custom headers that might break this
|
||||
}
|
||||
|
||||
m_DataStartOffset = ftell(m_pFile);
|
||||
m_nSampleCount = DataHeader.Size / m_FormatHeader.BlockAlign * m_nSamplesPerBlock;
|
||||
|
||||
m_bIsOpen = true;
|
||||
#undef CLOSE_ON_ERROR
|
||||
}
|
||||
|
||||
~CWavFile()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
bool IsOpened()
|
||||
{
|
||||
return m_bIsOpen;
|
||||
}
|
||||
|
||||
uint32 GetSampleSize()
|
||||
{
|
||||
return sizeof(uint16);
|
||||
}
|
||||
|
||||
uint32 GetSampleCount()
|
||||
{
|
||||
return m_nSampleCount;
|
||||
}
|
||||
|
||||
uint32 GetSampleRate()
|
||||
{
|
||||
return m_FormatHeader.SampleRate;
|
||||
}
|
||||
|
||||
uint32 GetChannels()
|
||||
{
|
||||
return m_FormatHeader.NumChannels;
|
||||
}
|
||||
|
||||
void Seek(uint32 milliseconds)
|
||||
{
|
||||
if (!IsOpened()) return;
|
||||
fseek(m_pFile, m_DataStartOffset + ms2samples(milliseconds) / m_nSamplesPerBlock * m_FormatHeader.BlockAlign, SEEK_SET);
|
||||
}
|
||||
|
||||
uint32 Tell()
|
||||
{
|
||||
if (!IsOpened()) return 0;
|
||||
return samples2ms(GetCurrentSample());
|
||||
}
|
||||
|
||||
#define SAMPLES_IN_LINE (8)
|
||||
|
||||
uint32 Decode(void* buffer)
|
||||
{
|
||||
if (!IsOpened()) return 0;
|
||||
|
||||
if (m_FormatHeader.AudioFormat == WAVEFMT_PCM)
|
||||
{
|
||||
// just read the file and sort the samples
|
||||
uint32 size = fread(buffer, 1, GetBufferSize(), m_pFile);
|
||||
if (m_FormatHeader.NumChannels == 2)
|
||||
SortStereoBuffer.SortStereo(buffer, size);
|
||||
return size;
|
||||
}
|
||||
else if (m_FormatHeader.AudioFormat == WAVEFMT_IMA_ADPCM)
|
||||
{
|
||||
// trim the buffer size if we're at the end of our file
|
||||
uint32 nMaxSamples = GetBufferSamples() / m_FormatHeader.NumChannels;
|
||||
uint32 nSamplesLeft = m_nSampleCount - GetCurrentSample();
|
||||
nMaxSamples = Min(nMaxSamples, nSamplesLeft);
|
||||
|
||||
// align sample count to our block
|
||||
nMaxSamples = nMaxSamples / m_nSamplesPerBlock * m_nSamplesPerBlock;
|
||||
|
||||
// count the size of output buffer
|
||||
uint32 OutBufSizePerChannel = nMaxSamples * GetSampleSize();
|
||||
uint32 OutBufSize = OutBufSizePerChannel * m_FormatHeader.NumChannels;
|
||||
|
||||
// calculate the pointers to individual channel buffers
|
||||
for (uint32 i = 0; i < m_FormatHeader.NumChannels; i++)
|
||||
m_ppPcmBuffers[i] = (int16*)((int8*)buffer + OutBufSizePerChannel * i);
|
||||
|
||||
uint32 samplesRead = 0;
|
||||
while (samplesRead < nMaxSamples)
|
||||
{
|
||||
// read the file
|
||||
uint8 *pAdpcmBuf = m_pAdpcmBuffer;
|
||||
if (fread(m_pAdpcmBuffer, 1, m_FormatHeader.BlockAlign, m_pFile) == 0)
|
||||
return 0;
|
||||
|
||||
// get the first sample in adpcm block and initialise the decoder(s)
|
||||
for (uint32 i = 0; i < m_FormatHeader.NumChannels; i++)
|
||||
{
|
||||
int16 Sample = *(int16*)pAdpcmBuf;
|
||||
pAdpcmBuf += sizeof(int16);
|
||||
int16 Step = *(int16*)pAdpcmBuf;
|
||||
pAdpcmBuf += sizeof(int16);
|
||||
m_pAdpcmDecoders[i].Init(Sample, Step);
|
||||
*(m_ppPcmBuffers[i]) = Sample;
|
||||
m_ppPcmBuffers[i]++;
|
||||
}
|
||||
samplesRead++;
|
||||
|
||||
// decode the rest of the block
|
||||
for (uint32 s = 1; s < m_nSamplesPerBlock; s += SAMPLES_IN_LINE)
|
||||
{
|
||||
for (uint32 i = 0; i < m_FormatHeader.NumChannels; i++)
|
||||
{
|
||||
m_pAdpcmDecoders[i].Decode(pAdpcmBuf, m_ppPcmBuffers[i], SAMPLES_IN_LINE / 2);
|
||||
pAdpcmBuf += SAMPLES_IN_LINE / 2;
|
||||
m_ppPcmBuffers[i] += SAMPLES_IN_LINE;
|
||||
}
|
||||
samplesRead += SAMPLES_IN_LINE;
|
||||
}
|
||||
}
|
||||
return OutBufSize;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef AUDIO_OAL_USE_SNDFILE
|
||||
class CSndFile : public IDecoder
|
||||
{
|
||||
SNDFILE *m_pfSound;
|
||||
@ -146,12 +461,11 @@ public:
|
||||
return size;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef AUDIO_OAL_USE_MPG123
|
||||
// fuzzy seek eliminates stutter when playing ADF but spams errors a lot (nothing breaks though)
|
||||
#define MP3_USE_FUZZY_SEEK
|
||||
#endif // _WIN32
|
||||
|
||||
|
||||
class CMP3File : public IDecoder
|
||||
{
|
||||
@ -177,7 +491,7 @@ public:
|
||||
if ( m_pMH )
|
||||
{
|
||||
#ifdef MP3_USE_FUZZY_SEEK
|
||||
mpg123_param(m_pMH, MPG123_FLAGS, MPG123_FUZZY | MPG123_SEEKBUFFER | MPG123_GAPLESS, 0.0);
|
||||
mpg123_param(m_pMH, MPG123_FLAGS, MPG123_FUZZY | MPG123_SEEKBUFFER | MPG123_GAPLESS | MPG123_QUIET, 0.0);
|
||||
#endif
|
||||
long rate = 0;
|
||||
int channels = 0;
|
||||
@ -260,6 +574,55 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class CADFFile : public CMP3File
|
||||
{
|
||||
static ssize_t r_read(void* fh, void* buf, size_t size)
|
||||
{
|
||||
size_t bytesRead = fread(buf, 1, size, (FILE*)fh);
|
||||
uint8* _buf = (uint8*)buf;
|
||||
for (size_t i = 0; i < size; i++)
|
||||
_buf[i] ^= 0x22;
|
||||
return bytesRead;
|
||||
}
|
||||
static off_t r_seek(void* fh, off_t pos, int seekType)
|
||||
{
|
||||
fseek((FILE*)fh, pos, seekType);
|
||||
return ftell((FILE*)fh);
|
||||
}
|
||||
static void r_close(void* fh)
|
||||
{
|
||||
fclose((FILE*)fh);
|
||||
}
|
||||
public:
|
||||
CADFFile(const char* path)
|
||||
{
|
||||
m_pMH = mpg123_new(nil, nil);
|
||||
if (m_pMH)
|
||||
{
|
||||
#ifdef MP3_USE_FUZZY_SEEK
|
||||
mpg123_param(m_pMH, MPG123_FLAGS, MPG123_FUZZY | MPG123_SEEKBUFFER | MPG123_GAPLESS | MPG123_QUIET, 0.0);
|
||||
#endif
|
||||
long rate = 0;
|
||||
int channels = 0;
|
||||
int encoding = 0;
|
||||
|
||||
FILE* f = fopen(path, "rb");
|
||||
|
||||
m_bOpened = mpg123_replace_reader_handle(m_pMH, r_read, r_seek, r_close) == MPG123_OK
|
||||
&& mpg123_open_handle(m_pMH, f) == MPG123_OK && mpg123_getformat(m_pMH, &rate, &channels, &encoding) == MPG123_OK;
|
||||
m_nRate = rate;
|
||||
m_nChannels = channels;
|
||||
|
||||
if (IsOpened())
|
||||
{
|
||||
mpg123_format_none(m_pMH);
|
||||
mpg123_format(m_pMH, rate, channels, encoding);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
#define VAG_LINE_SIZE (0x10)
|
||||
#define VAG_SAMPLES_IN_LINE (28)
|
||||
|
||||
@ -287,7 +650,7 @@ public:
|
||||
static short quantize(double sample)
|
||||
{
|
||||
int a = int(sample + 0.5);
|
||||
return short(clamp(int(sample + 0.5), -32768, 32767));
|
||||
return short(clamp(a, -32768, 32767));
|
||||
}
|
||||
|
||||
void Decode(void* _inbuf, int16* _outbuf, size_t size)
|
||||
@ -331,64 +694,68 @@ public:
|
||||
|
||||
class CVbFile : public IDecoder
|
||||
{
|
||||
FILE* pFile;
|
||||
size_t m_FileSize;
|
||||
size_t m_nNumberOfBlocks;
|
||||
CVagDecoder* decoders;
|
||||
FILE *m_pFile;
|
||||
CVagDecoder *m_pVagDecoders;
|
||||
|
||||
uint32 m_nSampleRate;
|
||||
uint8 m_nChannels;
|
||||
bool m_bBlockRead;
|
||||
uint16 m_LineInBlock;
|
||||
size_t m_CurrentBlock;
|
||||
size_t m_FileSize;
|
||||
size_t m_nNumberOfBlocks;
|
||||
|
||||
uint8** ppTempBuffers;
|
||||
uint32 m_nSampleRate;
|
||||
uint8 m_nChannels;
|
||||
bool m_bBlockRead;
|
||||
uint16 m_LineInBlock;
|
||||
size_t m_CurrentBlock;
|
||||
|
||||
uint8 **m_ppVagBuffers; // buffers that cache actual ADPCM file data
|
||||
int16 **m_ppPcmBuffers;
|
||||
|
||||
void ReadBlock(int32 block = -1)
|
||||
{
|
||||
// just read next block if -1
|
||||
if (block != -1)
|
||||
fseek(pFile, block * m_nChannels * VB_BLOCK_SIZE, SEEK_SET);
|
||||
fseek(m_pFile, block * m_nChannels * VB_BLOCK_SIZE, SEEK_SET);
|
||||
|
||||
for (int i = 0; i < m_nChannels; i++)
|
||||
fread(ppTempBuffers[i], VB_BLOCK_SIZE, 1, pFile);
|
||||
fread(m_ppVagBuffers[i], VB_BLOCK_SIZE, 1, m_pFile);
|
||||
m_bBlockRead = true;
|
||||
}
|
||||
|
||||
public:
|
||||
CVbFile(const char* path, uint32 nSampleRate = 32000, uint8 nChannels = 2) : m_nSampleRate(nSampleRate), m_nChannels(nChannels)
|
||||
CVbFile(const char* path, uint32 nSampleRate = 32000, uint8 nChannels = 2) : m_nSampleRate(nSampleRate), m_nChannels(nChannels), m_pVagDecoders(nil), m_ppVagBuffers(nil), m_ppPcmBuffers(nil),
|
||||
m_FileSize(0), m_nNumberOfBlocks(0), m_bBlockRead(false), m_LineInBlock(0), m_CurrentBlock(0)
|
||||
{
|
||||
pFile = fopen(path, "rb");
|
||||
if (pFile) {
|
||||
fseek(pFile, 0, SEEK_END);
|
||||
m_FileSize = ftell(pFile);
|
||||
fseek(pFile, 0, SEEK_SET);
|
||||
m_nNumberOfBlocks = m_FileSize / (nChannels * VB_BLOCK_SIZE);
|
||||
decoders = new CVagDecoder[nChannels];
|
||||
m_CurrentBlock = 0;
|
||||
m_LineInBlock = 0;
|
||||
m_bBlockRead = false;
|
||||
ppTempBuffers = new uint8 * [nChannels];
|
||||
for (uint8 i = 0; i < nChannels; i++)
|
||||
ppTempBuffers[i] = new uint8[VB_BLOCK_SIZE];
|
||||
}
|
||||
m_pFile = fopen(path, "rb");
|
||||
if (!m_pFile) return;
|
||||
|
||||
fseek(m_pFile, 0, SEEK_END);
|
||||
m_FileSize = ftell(m_pFile);
|
||||
fseek(m_pFile, 0, SEEK_SET);
|
||||
|
||||
m_nNumberOfBlocks = m_FileSize / (nChannels * VB_BLOCK_SIZE);
|
||||
m_pVagDecoders = new CVagDecoder[nChannels];
|
||||
m_ppVagBuffers = new uint8*[nChannels];
|
||||
m_ppPcmBuffers = new int16*[nChannels];
|
||||
for (uint8 i = 0; i < nChannels; i++)
|
||||
m_ppVagBuffers[i] = new uint8[VB_BLOCK_SIZE];
|
||||
}
|
||||
|
||||
~CVbFile()
|
||||
{
|
||||
if (pFile)
|
||||
if (m_pFile)
|
||||
{
|
||||
fclose(pFile);
|
||||
delete decoders;
|
||||
fclose(m_pFile);
|
||||
|
||||
delete[] m_pVagDecoders;
|
||||
for (int i = 0; i < m_nChannels; i++)
|
||||
delete ppTempBuffers[i];
|
||||
delete ppTempBuffers;
|
||||
delete[] m_ppVagBuffers[i];
|
||||
delete[] m_ppVagBuffers;
|
||||
delete[] m_ppPcmBuffers;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsOpened()
|
||||
{
|
||||
return pFile != nil;
|
||||
return m_pFile != nil;
|
||||
}
|
||||
|
||||
uint32 GetSampleSize()
|
||||
@ -416,15 +783,18 @@ public:
|
||||
{
|
||||
if (!IsOpened()) return;
|
||||
uint32 samples = ms2samples(milliseconds);
|
||||
int32 block = samples / NUM_VAG_SAMPLES_IN_BLOCK;
|
||||
|
||||
// find the block of our sample
|
||||
uint32 block = samples / NUM_VAG_SAMPLES_IN_BLOCK;
|
||||
if (block > m_nNumberOfBlocks)
|
||||
{
|
||||
samples = 0;
|
||||
block = 0;
|
||||
}
|
||||
if (block != m_CurrentBlock)
|
||||
ReadBlock(block);
|
||||
m_bBlockRead = false;
|
||||
|
||||
// find a line of our sample within our block
|
||||
uint32 remainingSamples = samples - block * NUM_VAG_SAMPLES_IN_BLOCK;
|
||||
uint32 newLine = remainingSamples / VAG_SAMPLES_IN_LINE / VAG_LINE_SIZE;
|
||||
|
||||
@ -432,8 +802,8 @@ public:
|
||||
{
|
||||
m_CurrentBlock = block;
|
||||
m_LineInBlock = newLine;
|
||||
for (int i = 0; i < GetChannels(); i++)
|
||||
decoders[i].ResetState();
|
||||
for (uint32 i = 0; i < GetChannels(); i++)
|
||||
m_pVagDecoders[i].ResetState();
|
||||
}
|
||||
|
||||
}
|
||||
@ -449,44 +819,48 @@ public:
|
||||
{
|
||||
if (!IsOpened()) return 0;
|
||||
|
||||
if (m_CurrentBlock >= m_nNumberOfBlocks) return 0;
|
||||
|
||||
// cache current ADPCM block
|
||||
if (!m_bBlockRead)
|
||||
ReadBlock(m_CurrentBlock);
|
||||
|
||||
if (m_CurrentBlock == m_nNumberOfBlocks) return 0;
|
||||
int size = 0;
|
||||
|
||||
int numberOfRequiredLines = GetBufferSamples() / GetChannels() / VAG_SAMPLES_IN_LINE;
|
||||
// trim the buffer size if we're at the end of our file
|
||||
int numberOfRequiredLines = GetBufferSamples() / m_nChannels / VAG_SAMPLES_IN_LINE;
|
||||
int numberOfRemainingLines = (m_nNumberOfBlocks - m_CurrentBlock) * NUM_VAG_LINES_IN_BLOCK - m_LineInBlock;
|
||||
int bufSizePerChannel = Min(numberOfRequiredLines, numberOfRemainingLines) * VAG_SAMPLES_IN_LINE * GetSampleSize();
|
||||
|
||||
if (numberOfRequiredLines > numberOfRemainingLines)
|
||||
numberOfRemainingLines = numberOfRemainingLines;
|
||||
|
||||
int16* buffers[2] = { (int16*)buffer, &((int16*)buffer)[bufSizePerChannel / GetSampleSize()] };
|
||||
// calculate the pointers to individual channel buffers
|
||||
for (uint32 i = 0; i < m_nChannels; i++)
|
||||
m_ppPcmBuffers[i] = (int16*)((int8*)buffer + bufSizePerChannel * i);
|
||||
|
||||
int size = 0;
|
||||
while (size < bufSizePerChannel)
|
||||
{
|
||||
for (int i = 0; i < GetChannels(); i++)
|
||||
// decode the VAG lines
|
||||
for (uint32 i = 0; i < m_nChannels; i++)
|
||||
{
|
||||
decoders[i].Decode(ppTempBuffers[i] + m_LineInBlock * VAG_LINE_SIZE, buffers[i], VAG_LINE_SIZE);
|
||||
buffers[i] += VAG_SAMPLES_IN_LINE;
|
||||
m_pVagDecoders[i].Decode(m_ppVagBuffers[i] + m_LineInBlock * VAG_LINE_SIZE, m_ppPcmBuffers[i], VAG_LINE_SIZE);
|
||||
m_ppPcmBuffers[i] += VAG_SAMPLES_IN_LINE;
|
||||
}
|
||||
size += VAG_SAMPLES_IN_LINE * GetSampleSize();
|
||||
m_LineInBlock++;
|
||||
|
||||
// block is over, read the next block
|
||||
if (m_LineInBlock >= NUM_VAG_LINES_IN_BLOCK)
|
||||
{
|
||||
m_CurrentBlock++;
|
||||
if (m_CurrentBlock >= m_nNumberOfBlocks)
|
||||
if (m_CurrentBlock >= m_nNumberOfBlocks) // end of file
|
||||
break;
|
||||
m_LineInBlock = 0;
|
||||
ReadBlock();
|
||||
}
|
||||
}
|
||||
|
||||
return bufSizePerChannel * GetChannels();
|
||||
return bufSizePerChannel * m_nChannels;
|
||||
}
|
||||
};
|
||||
#else
|
||||
#ifdef AUDIO_OAL_USE_OPUS
|
||||
class COpusFile : public IDecoder
|
||||
{
|
||||
OggOpusFile *m_FileH;
|
||||
@ -582,64 +956,16 @@ public:
|
||||
};
|
||||
#endif
|
||||
|
||||
class CADFFile : public CMP3File
|
||||
{
|
||||
static ssize_t r_read(void* fh, void* buf, size_t size)
|
||||
{
|
||||
size_t bytesRead = fread(buf, 1, size, (FILE*)fh);
|
||||
uint8* _buf = (uint8*)buf;
|
||||
for (size_t i = 0; i < size; i++)
|
||||
_buf[i] ^= 0x22;
|
||||
return bytesRead;
|
||||
}
|
||||
static off_t r_seek(void* fh, off_t pos, int seekType)
|
||||
{
|
||||
fseek((FILE*)fh, pos, seekType);
|
||||
return ftell((FILE*)fh);
|
||||
}
|
||||
static void r_close(void* fh)
|
||||
{
|
||||
fclose((FILE*)fh);
|
||||
}
|
||||
public:
|
||||
CADFFile(const char* path)
|
||||
{
|
||||
m_pMH = mpg123_new(nil, nil);
|
||||
if (m_pMH)
|
||||
{
|
||||
#ifdef MP3_USE_FUZZY_SEEK
|
||||
mpg123_param(m_pMH, MPG123_FLAGS, MPG123_FUZZY | MPG123_SEEKBUFFER | MPG123_GAPLESS, 0.0);
|
||||
#endif
|
||||
long rate = 0;
|
||||
int channels = 0;
|
||||
int encoding = 0;
|
||||
|
||||
FILE* f = fopen(path, "rb");
|
||||
|
||||
m_bOpened = mpg123_replace_reader_handle(m_pMH, r_read, r_seek, r_close) == MPG123_OK
|
||||
&& mpg123_open_handle(m_pMH, f) == MPG123_OK && mpg123_getformat(m_pMH, &rate, &channels, &encoding) == MPG123_OK;
|
||||
m_nRate = rate;
|
||||
m_nChannels = channels;
|
||||
|
||||
if (IsOpened())
|
||||
{
|
||||
mpg123_format_none(m_pMH);
|
||||
mpg123_format(m_pMH, rate, channels, encoding);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void CStream::Initialise()
|
||||
{
|
||||
#ifndef AUDIO_OPUS
|
||||
#ifdef AUDIO_OAL_USE_MPG123
|
||||
mpg123_init();
|
||||
#endif
|
||||
}
|
||||
|
||||
void CStream::Terminate()
|
||||
{
|
||||
#ifndef AUDIO_OPUS
|
||||
#ifdef AUDIO_OAL_USE_MPG123
|
||||
mpg123_exit();
|
||||
#endif
|
||||
}
|
||||
@ -672,17 +998,22 @@ CStream::CStream(char *filename, ALuint *sources, ALuint (&buffers)[NUM_STREAMBU
|
||||
|
||||
DEV("Stream %s\n", m_aFilename);
|
||||
|
||||
#ifndef AUDIO_OPUS
|
||||
if (!strcasecmp(&m_aFilename[strlen(m_aFilename) - strlen(".mp3")], ".mp3"))
|
||||
m_pSoundFile = new CMP3File(m_aFilename);
|
||||
else if (!strcasecmp(&m_aFilename[strlen(m_aFilename) - strlen(".wav")], ".wav"))
|
||||
if (!strcasecmp(&m_aFilename[strlen(m_aFilename) - strlen(".wav")], ".wav"))
|
||||
#ifdef AUDIO_OAL_USE_SNDFILE
|
||||
m_pSoundFile = new CSndFile(m_aFilename);
|
||||
#else
|
||||
m_pSoundFile = new CWavFile(m_aFilename);
|
||||
#endif
|
||||
#ifdef AUDIO_OAL_USE_MPG123
|
||||
else if (!strcasecmp(&m_aFilename[strlen(m_aFilename) - strlen(".mp3")], ".mp3"))
|
||||
m_pSoundFile = new CMP3File(m_aFilename);
|
||||
else if (!strcasecmp(&m_aFilename[strlen(m_aFilename) - strlen(".adf")], ".adf"))
|
||||
m_pSoundFile = new CADFFile(m_aFilename);
|
||||
#endif
|
||||
else if (!strcasecmp(&m_aFilename[strlen(m_aFilename) - strlen(".vb")], ".VB"))
|
||||
m_pSoundFile = new CVbFile(m_aFilename, overrideSampleRate);
|
||||
#else
|
||||
if (!strcasecmp(&m_aFilename[strlen(m_aFilename) - strlen(".opus")], ".opus"))
|
||||
#ifdef AUDIO_OAL_USE_OPUS
|
||||
else if (!strcasecmp(&m_aFilename[strlen(m_aFilename) - strlen(".opus")], ".opus"))
|
||||
m_pSoundFile = new COpusFile(m_aFilename);
|
||||
#endif
|
||||
else
|
||||
@ -979,12 +1310,15 @@ void CStream::Update()
|
||||
|
||||
// Relying a lot on left buffer states in here
|
||||
|
||||
//alSourcef(m_pAlSources[0], AL_ROLLOFF_FACTOR, 0.0f);
|
||||
alGetSourcei(m_pAlSources[0], AL_SOURCE_STATE, &sourceState[0]);
|
||||
alGetSourcei(m_pAlSources[0], AL_BUFFERS_PROCESSED, &buffersProcessed[0]);
|
||||
//alSourcef(m_pAlSources[1], AL_ROLLOFF_FACTOR, 0.0f);
|
||||
alGetSourcei(m_pAlSources[1], AL_SOURCE_STATE, &sourceState[1]);
|
||||
alGetSourcei(m_pAlSources[1], AL_BUFFERS_PROCESSED, &buffersProcessed[1]);
|
||||
do
|
||||
{
|
||||
//alSourcef(m_pAlSources[0], AL_ROLLOFF_FACTOR, 0.0f);
|
||||
alGetSourcei(m_pAlSources[0], AL_SOURCE_STATE, &sourceState[0]);
|
||||
alGetSourcei(m_pAlSources[0], AL_BUFFERS_PROCESSED, &buffersProcessed[0]);
|
||||
//alSourcef(m_pAlSources[1], AL_ROLLOFF_FACTOR, 0.0f);
|
||||
alGetSourcei(m_pAlSources[1], AL_SOURCE_STATE, &sourceState[1]);
|
||||
alGetSourcei(m_pAlSources[1], AL_BUFFERS_PROCESSED, &buffersProcessed[1]);
|
||||
} while (buffersProcessed[0] != buffersProcessed[1]);
|
||||
|
||||
ALint looping = AL_FALSE;
|
||||
alGetSourcei(m_pAlSources[0], AL_LOOPING, &looping);
|
||||
|
@ -240,7 +240,7 @@ public:
|
||||
extern cSampleManager SampleManager;
|
||||
extern uint32 BankStartOffset[MAX_SFX_BANKS];
|
||||
|
||||
#ifdef AUDIO_OPUS
|
||||
#if defined(OPUS_AUDIO_PATHS)
|
||||
static char StreamedNameTable[][25] = {
|
||||
"AUDIO\\HEAD.OPUS", "AUDIO\\CLASS.OPUS", "AUDIO\\KJAH.OPUS", "AUDIO\\RISE.OPUS", "AUDIO\\LIPS.OPUS", "AUDIO\\GAME.OPUS",
|
||||
"AUDIO\\MSX.OPUS", "AUDIO\\FLASH.OPUS", "AUDIO\\CHAT.OPUS", "AUDIO\\HEAD.OPUS", "AUDIO\\POLICE.OPUS", "AUDIO\\CITY.OPUS",
|
||||
@ -275,8 +275,7 @@ static char StreamedNameTable[][25] = {
|
||||
"AUDIO\\h5_b.OPUS", "AUDIO\\h5_c.OPUS", "AUDIO\\ammu_a.OPUS", "AUDIO\\ammu_b.OPUS", "AUDIO\\ammu_c.OPUS", "AUDIO\\door_1.OPUS",
|
||||
"AUDIO\\door_2.OPUS", "AUDIO\\door_3.OPUS", "AUDIO\\door_4.OPUS", "AUDIO\\door_5.OPUS", "AUDIO\\door_6.OPUS", "AUDIO\\t3_a.OPUS",
|
||||
"AUDIO\\t3_b.OPUS", "AUDIO\\t3_c.OPUS", "AUDIO\\k1_b.OPUS", "AUDIO\\cat1.OPUS"};
|
||||
#else
|
||||
#ifdef PS2_AUDIO
|
||||
#elif defined(PS2_AUDIO_PATHS)
|
||||
static char StreamedNameTable[][40] =
|
||||
{
|
||||
"AUDIO\\MUSIC\\WILD.VB",
|
||||
@ -1610,5 +1609,4 @@ static char StreamedNameTable[][25] =
|
||||
"AUDIO\\BUST_26.WAV",
|
||||
"AUDIO\\BUST_27.WAV",
|
||||
"AUDIO\\BUST_28.WAV",
|
||||
};
|
||||
#endif
|
||||
};
|
@ -30,7 +30,7 @@
|
||||
#include "MusicManager.h"
|
||||
#include "Frontend.h"
|
||||
#include "Timer.h"
|
||||
#ifdef AUDIO_OPUS
|
||||
#ifdef AUDIO_OAL_USE_OPUS
|
||||
#include <opusfile.h>
|
||||
#endif
|
||||
|
||||
@ -83,7 +83,7 @@ char SampleBankDescFilename[] = "audio/sfx.SDT";
|
||||
char SampleBankDataFilename[] = "audio/sfx.RAW";
|
||||
|
||||
FILE *fpSampleDescHandle;
|
||||
#ifdef AUDIO_OPUS
|
||||
#ifdef OPUS_SFX
|
||||
OggOpusFile *fpSampleDataHandle;
|
||||
#else
|
||||
FILE *fpSampleDataHandle;
|
||||
@ -396,7 +396,7 @@ set_new_provider(int index)
|
||||
static bool
|
||||
IsThisTrackAt16KHz(uint32 track)
|
||||
{
|
||||
return track == STREAMED_SOUND_RADIO_KCHAT || track == STREAMED_SOUND_RADIO_VCPR || track == STREAMED_SOUND_AMBSIL_AMBIENT;
|
||||
return track == STREAMED_SOUND_RADIO_KCHAT || track == STREAMED_SOUND_RADIO_VCPR || track == STREAMED_SOUND_RADIO_POLICE;
|
||||
}
|
||||
|
||||
cSampleManager::cSampleManager(void)
|
||||
@ -1245,7 +1245,7 @@ cSampleManager::LoadSampleBank(uint8 nBank)
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef AUDIO_OPUS
|
||||
#ifdef OPUS_SFX
|
||||
int samplesRead = 0;
|
||||
int samplesSize = nSampleBankSize[nBank] / 2;
|
||||
op_pcm_seek(fpSampleDataHandle, 0);
|
||||
@ -1350,7 +1350,7 @@ cSampleManager::LoadPedComment(uint32 nComment)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef AUDIO_OPUS
|
||||
#ifdef OPUS_SFX
|
||||
int samplesRead = 0;
|
||||
int samplesSize = m_aSamples[nComment].nSize / 2;
|
||||
op_pcm_seek(fpSampleDataHandle, m_aSamples[nComment].nOffset / 2);
|
||||
@ -2007,7 +2007,7 @@ cSampleManager::InitialiseSampleBanks(void)
|
||||
fpSampleDescHandle = fcaseopen(SampleBankDescFilename, "rb");
|
||||
if ( fpSampleDescHandle == NULL )
|
||||
return false;
|
||||
#ifndef AUDIO_OPUS
|
||||
#ifndef OPUS_SFX
|
||||
fpSampleDataHandle = fcaseopen(SampleBankDataFilename, "rb");
|
||||
if ( fpSampleDataHandle == NULL )
|
||||
{
|
||||
@ -2025,7 +2025,7 @@ cSampleManager::InitialiseSampleBanks(void)
|
||||
fpSampleDataHandle = op_open_file(SampleBankDataFilename, &e);
|
||||
#endif
|
||||
fread(m_aSamples, sizeof(tSample), TOTAL_AUDIO_SAMPLES, fpSampleDescHandle);
|
||||
#ifdef AUDIO_OPUS
|
||||
#ifdef OPUS_SFX
|
||||
int32 _nSampleDataEndOffset = m_aSamples[TOTAL_AUDIO_SAMPLES - 1].nOffset + m_aSamples[TOTAL_AUDIO_SAMPLES - 1].nSize;
|
||||
#endif
|
||||
fclose(fpSampleDescHandle);
|
||||
|
Reference in New Issue
Block a user