mirror of
https://github.com/GTAmodding/re3.git
synced 2024-11-15 11:59:02 +00:00
Add support of PS2 audio streams to OpenAL
This commit is contained in:
parent
2e734a4750
commit
fd4c2172f5
3 changed files with 255 additions and 11 deletions
|
@ -147,6 +147,12 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
// 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
|
class CMP3File : public IDecoder
|
||||||
{
|
{
|
||||||
mpg123_handle *m_pMH;
|
mpg123_handle *m_pMH;
|
||||||
|
@ -163,8 +169,9 @@ public:
|
||||||
m_pMH = mpg123_new(nil, nil);
|
m_pMH = mpg123_new(nil, nil);
|
||||||
if ( m_pMH )
|
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, 0.0);
|
||||||
|
#endif
|
||||||
long rate = 0;
|
long rate = 0;
|
||||||
int channels = 0;
|
int channels = 0;
|
||||||
int encoding = 0;
|
int encoding = 0;
|
||||||
|
@ -245,6 +252,233 @@ public:
|
||||||
return (uint32)size;
|
return (uint32)size;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define VAG_LINE_SIZE (0x10)
|
||||||
|
#define VAG_SAMPLES_IN_LINE (28)
|
||||||
|
|
||||||
|
class CVagDecoder
|
||||||
|
{
|
||||||
|
const double f[5][2] = { { 0.0, 0.0 },
|
||||||
|
{ 60.0 / 64.0, 0.0 },
|
||||||
|
{ 115.0 / 64.0, -52.0 / 64.0 },
|
||||||
|
{ 98.0 / 64.0, -55.0 / 64.0 },
|
||||||
|
{ 122.0 / 64.0, -60.0 / 64.0 } };
|
||||||
|
|
||||||
|
double s_1;
|
||||||
|
double s_2;
|
||||||
|
public:
|
||||||
|
CVagDecoder()
|
||||||
|
{
|
||||||
|
ResetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResetState()
|
||||||
|
{
|
||||||
|
s_1 = s_2 = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static short quantize(double sample)
|
||||||
|
{
|
||||||
|
int a = int(sample + 0.5);
|
||||||
|
return short(clamp(int(sample + 0.5), -32768, 32767));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Decode(void* _inbuf, int16* _outbuf, size_t size)
|
||||||
|
{
|
||||||
|
uint8* inbuf = (uint8*)_inbuf;
|
||||||
|
int16* outbuf = _outbuf;
|
||||||
|
size &= ~(VAG_LINE_SIZE - 1);
|
||||||
|
|
||||||
|
while (size > 0) {
|
||||||
|
double samples[VAG_SAMPLES_IN_LINE];
|
||||||
|
|
||||||
|
int predict_nr, shift_factor, flags;
|
||||||
|
predict_nr = *(inbuf++);
|
||||||
|
shift_factor = predict_nr & 0xf;
|
||||||
|
predict_nr >>= 4;
|
||||||
|
flags = *(inbuf++);
|
||||||
|
if (flags == 7) // TODO: ignore?
|
||||||
|
break;
|
||||||
|
for (int i = 0; i < VAG_SAMPLES_IN_LINE; i += 2) {
|
||||||
|
int d = *(inbuf++);
|
||||||
|
int16 s = int16((d & 0xf) << 12);
|
||||||
|
samples[i] = (double)(s >> shift_factor);
|
||||||
|
s = int16((d & 0xf0) << 8);
|
||||||
|
samples[i + 1] = (double)(s >> shift_factor);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < VAG_SAMPLES_IN_LINE; i++) {
|
||||||
|
samples[i] = samples[i] + s_1 * f[predict_nr][0] + s_2 * f[predict_nr][1];
|
||||||
|
s_2 = s_1;
|
||||||
|
s_1 = samples[i];
|
||||||
|
*(outbuf++) = quantize(samples[i] + 0.5);
|
||||||
|
}
|
||||||
|
size -= VAG_LINE_SIZE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#define VB_BLOCK_SIZE (0x2000)
|
||||||
|
#define NUM_VAG_LINES_IN_BLOCK (VB_BLOCK_SIZE / VAG_LINE_SIZE)
|
||||||
|
#define NUM_VAG_SAMPLES_IN_BLOCK (NUM_VAG_LINES_IN_BLOCK * VAG_SAMPLES_IN_LINE)
|
||||||
|
|
||||||
|
class CVbFile : public IDecoder
|
||||||
|
{
|
||||||
|
FILE* pFile;
|
||||||
|
size_t m_FileSize;
|
||||||
|
size_t m_nNumberOfBlocks;
|
||||||
|
CVagDecoder* decoders;
|
||||||
|
|
||||||
|
uint32 m_nSampleRate;
|
||||||
|
uint8 m_nChannels;
|
||||||
|
bool m_bBlockRead;
|
||||||
|
uint16 m_LineInBlock;
|
||||||
|
size_t m_CurrentBlock;
|
||||||
|
|
||||||
|
uint8** ppTempBuffers;
|
||||||
|
|
||||||
|
void ReadBlock(int32 block = -1)
|
||||||
|
{
|
||||||
|
// just read next block if -1
|
||||||
|
if (block != -1)
|
||||||
|
fseek(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);
|
||||||
|
m_bBlockRead = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
CVbFile(const char* path, uint32 nSampleRate = 32000, uint8 nChannels = 2) : m_nSampleRate(nSampleRate), m_nChannels(nChannels)
|
||||||
|
{
|
||||||
|
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];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~CVbFile()
|
||||||
|
{
|
||||||
|
if (pFile)
|
||||||
|
{
|
||||||
|
fclose(pFile);
|
||||||
|
delete decoders;
|
||||||
|
for (int i = 0; i < m_nChannels; i++)
|
||||||
|
delete ppTempBuffers[i];
|
||||||
|
delete ppTempBuffers;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsOpened()
|
||||||
|
{
|
||||||
|
return pFile != nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 GetSampleSize()
|
||||||
|
{
|
||||||
|
return sizeof(uint16);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 GetSampleCount()
|
||||||
|
{
|
||||||
|
if (!IsOpened()) return 0;
|
||||||
|
return m_nNumberOfBlocks * NUM_VAG_LINES_IN_BLOCK * VAG_SAMPLES_IN_LINE;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 GetSampleRate()
|
||||||
|
{
|
||||||
|
return m_nSampleRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 GetChannels()
|
||||||
|
{
|
||||||
|
return m_nChannels;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Seek(uint32 milliseconds)
|
||||||
|
{
|
||||||
|
if (!IsOpened()) return;
|
||||||
|
uint32 samples = ms2samples(milliseconds);
|
||||||
|
int32 block = samples / NUM_VAG_SAMPLES_IN_BLOCK;
|
||||||
|
if (block > m_nNumberOfBlocks)
|
||||||
|
{
|
||||||
|
samples = 0;
|
||||||
|
block = 0;
|
||||||
|
}
|
||||||
|
if (block != m_CurrentBlock)
|
||||||
|
ReadBlock(block);
|
||||||
|
|
||||||
|
uint32 remainingSamples = samples - block * NUM_VAG_SAMPLES_IN_BLOCK;
|
||||||
|
uint32 newLine = remainingSamples / VAG_SAMPLES_IN_LINE / VAG_LINE_SIZE;
|
||||||
|
|
||||||
|
if (m_CurrentBlock != block || m_LineInBlock != newLine)
|
||||||
|
{
|
||||||
|
m_CurrentBlock = block;
|
||||||
|
m_LineInBlock = newLine;
|
||||||
|
for (int i = 0; i < GetChannels(); i++)
|
||||||
|
decoders[i].ResetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 Tell()
|
||||||
|
{
|
||||||
|
if (!IsOpened()) return 0;
|
||||||
|
uint32 pos = (m_CurrentBlock * NUM_VAG_LINES_IN_BLOCK + m_LineInBlock) * VAG_SAMPLES_IN_LINE;
|
||||||
|
return samples2ms(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 Decode(void* buffer)
|
||||||
|
{
|
||||||
|
if (!IsOpened()) return 0;
|
||||||
|
|
||||||
|
if (!m_bBlockRead)
|
||||||
|
ReadBlock(m_CurrentBlock);
|
||||||
|
|
||||||
|
if (m_CurrentBlock == m_nNumberOfBlocks) return 0;
|
||||||
|
int size = 0;
|
||||||
|
|
||||||
|
int numberOfRequiredLines = GetBufferSamples() / GetChannels() / 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()] };
|
||||||
|
|
||||||
|
while (size < bufSizePerChannel)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < GetChannels(); i++)
|
||||||
|
{
|
||||||
|
decoders[i].Decode(ppTempBuffers[i] + m_LineInBlock * VAG_LINE_SIZE, buffers[i], VAG_LINE_SIZE);
|
||||||
|
buffers[i] += VAG_SAMPLES_IN_LINE;
|
||||||
|
}
|
||||||
|
size += VAG_SAMPLES_IN_LINE * GetSampleSize();
|
||||||
|
m_LineInBlock++;
|
||||||
|
if (m_LineInBlock >= NUM_VAG_LINES_IN_BLOCK)
|
||||||
|
{
|
||||||
|
m_CurrentBlock++;
|
||||||
|
if (m_CurrentBlock >= m_nNumberOfBlocks)
|
||||||
|
break;
|
||||||
|
m_LineInBlock = 0;
|
||||||
|
ReadBlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bufSizePerChannel * GetChannels();
|
||||||
|
}
|
||||||
|
};
|
||||||
#else
|
#else
|
||||||
class COpusFile : public IDecoder
|
class COpusFile : public IDecoder
|
||||||
{
|
{
|
||||||
|
@ -341,6 +575,8 @@ public:
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef MP3_USE_FUZZY_SEEK
|
||||||
|
#endif
|
||||||
void CStream::Initialise()
|
void CStream::Initialise()
|
||||||
{
|
{
|
||||||
#ifndef AUDIO_OPUS
|
#ifndef AUDIO_OPUS
|
||||||
|
@ -355,7 +591,7 @@ void CStream::Terminate()
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
CStream::CStream(char *filename, ALuint *sources, ALuint (&buffers)[NUM_STREAMBUFFERS]) :
|
CStream::CStream(char *filename, ALuint *sources, ALuint (&buffers)[NUM_STREAMBUFFERS], uint32 overrideSampleRate) :
|
||||||
m_pAlSources(sources),
|
m_pAlSources(sources),
|
||||||
m_alBuffers(buffers),
|
m_alBuffers(buffers),
|
||||||
m_pBuffer(nil),
|
m_pBuffer(nil),
|
||||||
|
@ -388,6 +624,8 @@ CStream::CStream(char *filename, ALuint *sources, ALuint (&buffers)[NUM_STREAMBU
|
||||||
m_pSoundFile = new CMP3File(m_aFilename);
|
m_pSoundFile = new CMP3File(m_aFilename);
|
||||||
else if (!strcasecmp(&m_aFilename[strlen(m_aFilename) - strlen(".wav")], ".wav"))
|
else if (!strcasecmp(&m_aFilename[strlen(m_aFilename) - strlen(".wav")], ".wav"))
|
||||||
m_pSoundFile = new CSndFile(m_aFilename);
|
m_pSoundFile = new CSndFile(m_aFilename);
|
||||||
|
else if (!strcasecmp(&m_aFilename[strlen(m_aFilename) - strlen(".vb")], ".VB"))
|
||||||
|
m_pSoundFile = new CVbFile(m_aFilename, overrideSampleRate);
|
||||||
#else
|
#else
|
||||||
if (!strcasecmp(&m_aFilename[strlen(m_aFilename) - strlen(".opus")], ".opus"))
|
if (!strcasecmp(&m_aFilename[strlen(m_aFilename) - strlen(".opus")], ".opus"))
|
||||||
m_pSoundFile = new COpusFile(m_aFilename);
|
m_pSoundFile = new COpusFile(m_aFilename);
|
||||||
|
|
|
@ -86,7 +86,7 @@ public:
|
||||||
static void Initialise();
|
static void Initialise();
|
||||||
static void Terminate();
|
static void Terminate();
|
||||||
|
|
||||||
CStream(char *filename, ALuint *sources, ALuint (&buffers)[NUM_STREAMBUFFERS]);
|
CStream(char *filename, ALuint *sources, ALuint (&buffers)[NUM_STREAMBUFFERS], uint32 overrideSampleRate = 32000);
|
||||||
~CStream();
|
~CStream();
|
||||||
void Delete();
|
void Delete();
|
||||||
|
|
||||||
|
|
|
@ -393,6 +393,12 @@ set_new_provider(int index)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
IsThisTrackAt16KHz(uint32 track)
|
||||||
|
{
|
||||||
|
return track == STREAMED_SOUND_RADIO_CHAT;
|
||||||
|
}
|
||||||
|
|
||||||
cSampleManager::cSampleManager(void)
|
cSampleManager::cSampleManager(void)
|
||||||
{
|
{
|
||||||
;
|
;
|
||||||
|
@ -974,7 +980,7 @@ cSampleManager::Initialise(void)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for(int32 i = 0; i < TOTAL_STREAMED_SOUNDS; i++) {
|
for(int32 i = 0; i < TOTAL_STREAMED_SOUNDS; i++) {
|
||||||
aStream[0] = new CStream(StreamedNameTable[i], ALStreamSources[0], ALStreamBuffers[0]);
|
aStream[0] = new CStream(StreamedNameTable[i], ALStreamSources[0], ALStreamBuffers[0], IsThisTrackAt16KHz(i) ? 16000 : 32000);
|
||||||
|
|
||||||
if(aStream[0] && aStream[0]->IsOpened()) {
|
if(aStream[0] && aStream[0]->IsOpened()) {
|
||||||
uint32 tatalms = aStream[0]->GetLengthMS();
|
uint32 tatalms = aStream[0]->GetLengthMS();
|
||||||
|
@ -1661,7 +1667,7 @@ cSampleManager::PreloadStreamedFile(uint8 nFile, uint8 nStream)
|
||||||
|
|
||||||
strcpy(filename, StreamedNameTable[nFile]);
|
strcpy(filename, StreamedNameTable[nFile]);
|
||||||
|
|
||||||
CStream *stream = new CStream(filename, ALStreamSources[nStream], ALStreamBuffers[nStream]);
|
CStream *stream = new CStream(filename, ALStreamSources[nStream], ALStreamBuffers[nStream], IsThisTrackAt16KHz(nFile) ? 16000 : 32000);
|
||||||
ASSERT(stream != NULL);
|
ASSERT(stream != NULL);
|
||||||
|
|
||||||
aStream[nStream] = stream;
|
aStream[nStream] = stream;
|
||||||
|
@ -1736,7 +1742,7 @@ cSampleManager::StartStreamedFile(uint8 nFile, uint32 nPos, uint8 nStream)
|
||||||
nFile = 0;
|
nFile = 0;
|
||||||
strcat(filename, StreamedNameTable[nFile]);
|
strcat(filename, StreamedNameTable[nFile]);
|
||||||
|
|
||||||
CStream* stream = new CStream(filename, ALStreamSources[nStream], ALStreamBuffers[nStream]);
|
CStream* stream = new CStream(filename, ALStreamSources[nStream], ALStreamBuffers[nStream], IsThisTrackAt16KHz(nFile) ? 16000 : 32000);
|
||||||
ASSERT(stream != NULL);
|
ASSERT(stream != NULL);
|
||||||
|
|
||||||
aStream[nStream] = stream;
|
aStream[nStream] = stream;
|
||||||
|
@ -1760,12 +1766,12 @@ cSampleManager::StartStreamedFile(uint8 nFile, uint32 nPos, uint8 nStream)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mp3->pLinkPath != NULL)
|
if (mp3->pLinkPath != NULL)
|
||||||
aStream[nStream] = new CStream(mp3->pLinkPath, ALStreamSources[nStream], ALStreamBuffers[nStream]);
|
aStream[nStream] = new CStream(mp3->pLinkPath, ALStreamSources[nStream], ALStreamBuffers[nStream], IsThisTrackAt16KHz(nFile) ? 16000 : 32000);
|
||||||
else {
|
else {
|
||||||
strcpy(filename, _mp3DirectoryPath);
|
strcpy(filename, _mp3DirectoryPath);
|
||||||
strcat(filename, mp3->aFilename);
|
strcat(filename, mp3->aFilename);
|
||||||
|
|
||||||
aStream[nStream] = new CStream(filename, ALStreamSources[nStream], ALStreamBuffers[nStream]);
|
aStream[nStream] = new CStream(filename, ALStreamSources[nStream], ALStreamBuffers[nStream], IsThisTrackAt16KHz(nFile) ? 16000 : 32000);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aStream[nStream]->IsOpened()) {
|
if (aStream[nStream]->IsOpened()) {
|
||||||
|
@ -1792,7 +1798,7 @@ cSampleManager::StartStreamedFile(uint8 nFile, uint32 nPos, uint8 nStream)
|
||||||
{
|
{
|
||||||
nFile = 0;
|
nFile = 0;
|
||||||
strcat(filename, StreamedNameTable[nFile]);
|
strcat(filename, StreamedNameTable[nFile]);
|
||||||
CStream* stream = new CStream(filename, ALStreamSources[nStream], ALStreamBuffers[nStream]);
|
CStream* stream = new CStream(filename, ALStreamSources[nStream], ALStreamBuffers[nStream], IsThisTrackAt16KHz(nFile) ? 16000 : 32000);
|
||||||
ASSERT(stream != NULL);
|
ASSERT(stream != NULL);
|
||||||
|
|
||||||
aStream[nStream] = stream;
|
aStream[nStream] = stream;
|
||||||
|
@ -1816,7 +1822,7 @@ cSampleManager::StartStreamedFile(uint8 nFile, uint32 nPos, uint8 nStream)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e->pLinkPath != NULL)
|
if (e->pLinkPath != NULL)
|
||||||
aStream[nStream] = new CStream(e->pLinkPath, ALStreamSources[nStream], ALStreamBuffers[nStream]);
|
aStream[nStream] = new CStream(e->pLinkPath, ALStreamSources[nStream], ALStreamBuffers[nStream], IsThisTrackAt16KHz(nFile) ? 16000 : 32000);
|
||||||
else {
|
else {
|
||||||
strcpy(filename, _mp3DirectoryPath);
|
strcpy(filename, _mp3DirectoryPath);
|
||||||
strcat(filename, e->aFilename);
|
strcat(filename, e->aFilename);
|
||||||
|
@ -1849,7 +1855,7 @@ cSampleManager::StartStreamedFile(uint8 nFile, uint32 nPos, uint8 nStream)
|
||||||
|
|
||||||
strcpy(filename, StreamedNameTable[nFile]);
|
strcpy(filename, StreamedNameTable[nFile]);
|
||||||
|
|
||||||
CStream *stream = new CStream(filename, ALStreamSources[nStream], ALStreamBuffers[nStream]);
|
CStream *stream = new CStream(filename, ALStreamSources[nStream], ALStreamBuffers[nStream], IsThisTrackAt16KHz(nFile) ? 16000 : 32000);
|
||||||
ASSERT(stream != NULL);
|
ASSERT(stream != NULL);
|
||||||
|
|
||||||
aStream[nStream] = stream;
|
aStream[nStream] = stream;
|
||||||
|
|
Loading…
Reference in a new issue