summaryrefslogtreecommitdiffstats
path: root/src/audio/openal
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/audio/openal/samp_oal.cpp1404
-rw-r--r--src/audio/openal/samp_oal.h340
2 files changed, 1744 insertions, 0 deletions
diff --git a/src/audio/openal/samp_oal.cpp b/src/audio/openal/samp_oal.cpp
new file mode 100644
index 00000000..e8213cd9
--- /dev/null
+++ b/src/audio/openal/samp_oal.cpp
@@ -0,0 +1,1404 @@
+#include <al.h>
+#include <alc.h>
+#include <mpg123_pre.h>
+//#include <mpg123.h>
+#include <time.h>
+#include <io.h>
+#include "samp_oal.h"
+#include "AudioManager.h"
+#include "MusicManager.h"
+#include "Frontend.h"
+#include "Timer.h"
+
+#pragma comment( lib, "libmpg123.lib" )
+#pragma comment( lib, "OpenAL32.lib" )
+
+cSampleManager SampleManager;
+int32 BankStartOffset[MAX_SAMPLEBANKS];
+
+
+///////////////////////////////////////////////////////////////
+class MP3Stream
+{
+public:
+ mpg123_handle *m_pMPG;
+ FILE *m_fpFile;
+ unsigned char *m_pBuf;
+ char m_aFilename[128];
+ size_t m_nBufSize;
+ size_t m_nLengthInBytes;
+ long m_nRate;
+ int m_nBitRate;
+ int m_nChannels;
+ int m_nEncoding;
+ int m_nLength;
+ int m_nBlockSize;
+ int m_nNumBlocks;
+ ALuint m_alSource;
+ ALuint m_alBuffers[5];
+ unsigned char *m_pBlocks;
+ bool m_bIsFree;
+ bool m_bIsOpened;
+ bool m_bIsPaused;
+ int m_nVolume;
+
+ void Initialize(void);
+ bool FillBuffer(ALuint alBuffer);
+ void Update(void);
+ void SetPos(uint32 nPos);
+ int32 FillBuffers();
+ MP3Stream(char *filename, ALuint source, ALuint *buffers);
+ ~MP3Stream() { Delete(); }
+ void Delete();
+
+};
+///////////////////////////////////////////////////////////////
+
+char SampleBankDescFilename[] = "AUDIO\\SFX.SDT";
+char SampleBankDataFilename[] = "AUDIO\\SFX.RAW";
+
+FILE *fpSampleDescHandle;
+FILE *fpSampleDataHandle;
+bool bSampleBankLoaded [MAX_SAMPLEBANKS];
+int32 nSampleBankDiscStartOffset [MAX_SAMPLEBANKS];
+int32 nSampleBankSize [MAX_SAMPLEBANKS];
+int32 nSampleBankMemoryStartAddress[MAX_SAMPLEBANKS];
+int32 _nSampleDataEndOffset;
+
+int32 nPedSlotSfx [MAX_PEDSFX];
+int32 nPedSlotSfxAddr[MAX_PEDSFX];
+uint8 nCurrentPedSlot;
+
+
+
+uint32 nStreamLength[TOTAL_STREAMED_SOUNDS];
+
+///////////////////////////////////////////////////////////////
+ALuint alChannel[MAXCHANNELS+MAX2DCHANNELS];
+ALuint ALStreamSources[MAX_STREAMS];
+ALuint ALStreamBuffers[MAX_STREAMS][5];
+struct
+{
+ ALuint buffer;
+ ALuint timer;
+}ALBuffers[SAMPLEBANK_MAX];
+
+ALuint pedBuffers[MAX_PEDSFX];
+//bank0Buffers
+
+uint32 nNumMP3s;
+
+MP3Stream *mp3Stream[MAX_STREAMS];
+int8 nStreamPan [MAX_STREAMS];
+int8 nStreamVolume[MAX_STREAMS];
+
+float ChannelPitch[MAXCHANNELS+MAX2DCHANNELS];
+uint8 nChannelVolume[MAXCHANNELS+MAX2DCHANNELS];
+uint32 ChannelSample[MAXCHANNELS+MAX2DCHANNELS];
+int32 currentChannelMaxFrontDistance[MAXCHANNELS+MAX2DCHANNELS];
+int32 currentChannelFrequency[MAXCHANNELS+MAX2DCHANNELS];
+int32 currentChannelVolume[MAXCHANNELS+MAX2DCHANNELS];
+
+
+cSampleManager::cSampleManager(void)
+{
+ ;
+}
+
+cSampleManager::~cSampleManager(void)
+{
+ ASSERT((void *)nSampleBankMemoryStartAddress[SAMPLEBANK_PED] == NULL);
+ free((void *)nSampleBankMemoryStartAddress[SAMPLEBANK_PED]);
+
+ if ( fpSampleDescHandle != NULL )
+ {
+ fclose(fpSampleDescHandle);
+ fpSampleDescHandle = NULL;
+ }
+
+ if ( fpSampleDataHandle != NULL )
+ {
+ fclose(fpSampleDataHandle);
+ fpSampleDataHandle = NULL;
+ }
+}
+
+void cSampleManager::SetSpeakerConfig(int32 nConfig)
+{
+
+}
+
+uint32 cSampleManager::GetMaximumSupportedChannels(void)
+{
+ return 20;
+}
+
+uint32 cSampleManager::GetNum3DProvidersAvailable()
+{
+ return 1;
+}
+
+void cSampleManager::SetNum3DProvidersAvailable(uint32 num)
+{
+ ;
+}
+
+char *cSampleManager::Get3DProviderName(uint8 id)
+{
+ static char PROVIDER[256] = "OpenAL";
+ return PROVIDER;
+}
+
+void cSampleManager::Set3DProviderName(uint8 id, char *name)
+{
+ ;
+}
+
+int8 cSampleManager::GetCurrent3DProviderIndex(void)
+{
+ return 0;
+}
+
+int8 cSampleManager::SetCurrent3DProvider(uint8 which)
+{
+ return 0;
+}
+
+bool
+cSampleManager::IsMP3RadioChannelAvailable(void)
+{
+ return nNumMP3s != 0;
+}
+
+
+void cSampleManager::ReleaseDigitalHandle(void)
+{
+
+}
+
+void cSampleManager::ReacquireDigitalHandle(void)
+{
+
+}
+
+bool
+cSampleManager::Initialise(void)
+{
+ ALCint attr[] = {ALC_FREQUENCY,MAX_FREQ,0};
+
+ m_pDevice = alcOpenDevice(NULL);
+ ASSERT(m_pDevice != NULL);
+
+ m_pContext = alcCreateContext(m_pDevice, attr);
+ ASSERT(m_pContext != NULL);
+
+ alcMakeContextCurrent(m_pContext);
+
+ mpg123_init();
+
+
+
+ for ( int32 i = 0; i < TOTAL_AUDIO_SAMPLES; i++ )
+ {
+ m_aSamples[i].nOffset = 0;
+ m_aSamples[i].nSize = 0;
+ m_aSamples[i].nFrequency = MAX_FREQ;
+ m_aSamples[i].nLoopStart = 0;
+ m_aSamples[i].nLoopEnd = -1;
+ }
+
+ for ( int32 i = 0; i < TOTAL_STREAMED_SOUNDS; i++ )
+ nStreamLength[i] = 3600000;
+
+ for ( int32 i = 0; i < MAX_STREAMS; i++ )
+ {
+ mp3Stream[i] = NULL;
+ nStreamVolume[i] = 100;
+ nStreamPan[i] = 63;
+ }
+
+ alGenSources(MAX_STREAMS, (ALuint *)ALStreamSources);
+ alGenBuffers(MAX_STREAMS*5, (ALuint *)ALStreamBuffers);
+
+ m_nMonoMode = 0;
+
+ m_nEffectsVolume = MAX_VOLUME;
+ m_nMusicVolume = MAX_VOLUME;
+ m_nEffectsFadeVolume = MAX_VOLUME;
+ m_nMusicFadeVolume = MAX_VOLUME;
+
+
+ memset(alChannel, 0, sizeof(alChannel));
+ memset(nChannelVolume, 0, sizeof(nChannelVolume));
+ memset(ChannelSample, 0, sizeof(ChannelSample));
+
+ for ( int32 i = 0; i < ARRAY_SIZE(ChannelPitch); i++ )
+ ChannelPitch[i] = 1.0f;
+
+
+ fpSampleDescHandle = NULL;
+ fpSampleDataHandle = NULL;
+
+ for ( int32 i = 0; i < MAX_SAMPLEBANKS; i++ )
+ {
+ bSampleBankLoaded[i] = false;
+ nSampleBankDiscStartOffset[i] = 0;
+ nSampleBankSize[i] = 0;
+ nSampleBankMemoryStartAddress[i] = 0;
+ }
+
+ alGenBuffers(MAX_PEDSFX, pedBuffers);
+
+ for ( int32 i = 0; i < MAX_PEDSFX; i++ )
+ {
+ nPedSlotSfx[i] = NO_SAMPLE;
+ nPedSlotSfxAddr[i] = 0;
+ }
+
+ nCurrentPedSlot = 0;
+
+ for ( int32 i = 0; i < SAMPLEBANK_MAX; i++ )
+ {
+ ALBuffers[i].buffer = 0;
+ ALBuffers[i].timer = 0;
+ }
+
+ alListenerf (AL_GAIN, 1.0f);
+ alListener3f(AL_POSITION, 0.0f, 0.0f, 0.0f);
+ alListener3f(AL_VELOCITY, 0.0f, 0.0f, 0.0f);
+ ALfloat orientation[6] = { 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f };
+ alListenerfv(AL_ORIENTATION, orientation);
+
+ if ( !InitialiseSampleBanks() )
+ {
+ Terminate();
+ return false;
+ }
+
+ nSampleBankMemoryStartAddress[SAMPLEBANK_MAIN] = (int32)malloc(nSampleBankSize[SAMPLEBANK_MAIN]);
+ ASSERT(nSampleBankMemoryStartAddress[SAMPLEBANK_MAIN] != NULL);
+
+ if ( nSampleBankMemoryStartAddress[SAMPLEBANK_MAIN] == NULL )
+ {
+ Terminate();
+ return false;
+ }
+
+ nSampleBankMemoryStartAddress[SAMPLEBANK_PED] = (int32)malloc(PED_BLOCKSIZE*MAX_PEDSFX);
+ ASSERT(nSampleBankMemoryStartAddress[SAMPLEBANK_PED] != NULL);
+
+ alGenSources(MAXCHANNELS, alChannel);
+ for ( int32 i = 0; i < MAXCHANNELS; i++ )
+ {
+ if ( alChannel[i] )
+ alSourcei(alChannel[i], AL_SOURCE_RELATIVE, AL_TRUE);
+ }
+
+ alGenSources(MAX2DCHANNELS, &alChannel[CHANNEL2D]);
+ if ( alChannel[CHANNEL2D] )
+ {
+ alSourcei (alChannel[CHANNEL2D], AL_SOURCE_RELATIVE, AL_TRUE);
+ alSource3f(alChannel[CHANNEL2D], AL_POSITION, 0.0f, 0.0f, 0.0f);
+ alSourcef (alChannel[CHANNEL2D], AL_GAIN, 1.0f);
+ }
+
+ LoadSampleBank(SAMPLEBANK_MAIN);
+
+ return true;
+}
+
+void
+cSampleManager::Terminate(void)
+{
+ mpg123_exit();
+ alcMakeContextCurrent(NULL);
+ alcDestroyContext(m_pContext);
+ alcCloseDevice(m_pDevice);
+}
+
+void
+cSampleManager::UpdateSoundBuffers(void)
+{
+ for ( int32 i = 0; i < SAMPLEBANK_MAX; i++ )
+ {
+ if ( ALBuffers[i].timer > 0 )
+ {
+ ALBuffers[i].timer -= ALuint(CTimer::GetTimeStep() * 20.0f);
+
+ if ( ALBuffers[i].timer <= 0 )
+ {
+ if ( ALBuffers[i].buffer != 0 && alIsBuffer(ALBuffers[i].buffer) )
+ {
+ alDeleteBuffers(1, &ALBuffers[i].buffer);
+
+ if ( alGetError() == AL_NO_ERROR )
+ ALBuffers[i].buffer = 0;
+ else
+ ALBuffers[i].buffer = 120000;
+ }
+ }
+ }
+ }
+}
+
+bool cSampleManager::CheckForAnAudioFileOnCD(void)
+{
+ return true;
+}
+
+char cSampleManager::GetCDAudioDriveLetter(void)
+{
+ return '\0';
+}
+
+void
+cSampleManager::SetEffectsMasterVolume(uint8 nVolume)
+{
+ m_nEffectsVolume = nVolume;
+}
+
+void
+cSampleManager::SetMusicMasterVolume(uint8 nVolume)
+{
+ m_nMusicVolume = nVolume;
+}
+
+void
+cSampleManager::SetEffectsFadeVolume(uint8 nVolume)
+{
+ m_nEffectsFadeVolume = nVolume;
+}
+
+void
+cSampleManager::SetMusicFadeVolume(uint8 nVolume)
+{
+ m_nMusicFadeVolume = nVolume;
+}
+
+void
+cSampleManager::SetMonoMode(uint8 nMode)
+{
+ m_nMonoMode = nMode;
+}
+
+bool
+cSampleManager::LoadSampleBank(uint8 nBank)
+{
+ ASSERT( nBank < MAX_SAMPLEBANKS );
+
+ if ( CTimer::GetIsCodePaused() )
+ return false;
+
+ if ( MusicManager.IsInitialised()
+ && MusicManager.GetMusicMode() == MUSICMODE_CUTSCENE
+ && nBank != SAMPLEBANK_MAIN )
+ {
+ return false;
+ }
+
+ if ( fseek(fpSampleDataHandle, nSampleBankDiscStartOffset[nBank], SEEK_SET) != 0 )
+ return false;
+
+ if ( fread((void *)nSampleBankMemoryStartAddress[nBank], 1, nSampleBankSize[nBank], fpSampleDataHandle) != nSampleBankSize[nBank] )
+ return false;
+
+ bSampleBankLoaded[nBank] = true;
+
+ return true;
+}
+
+void
+cSampleManager::UnloadSampleBank(uint8 nBank)
+{
+ ASSERT( nBank < MAX_SAMPLEBANKS );
+
+ ; // NOIMP
+}
+
+bool
+cSampleManager::IsSampleBankLoaded(uint8 nBank)
+{
+ ASSERT( nBank < MAX_SAMPLEBANKS );
+ return true;
+}
+
+bool
+cSampleManager::IsPedCommentLoaded(uint32 nComment)
+{
+ ASSERT( nComment < TOTAL_AUDIO_SAMPLES );
+
+ uint8 slot;
+
+ for ( int32 i = 0; i < _TODOCONST(3); i++ )
+ {
+ slot = nCurrentPedSlot - i - 1;
+ if ( nComment == nPedSlotSfx[slot] )
+ return true;
+ }
+
+ return false;
+}
+
+
+int32
+cSampleManager::_GetPedCommentSlot(uint32 nComment)
+{
+ uint8 slot;
+
+ for (int32 i = 0; i < _TODOCONST(3); i++)
+ {
+ slot = nCurrentPedSlot - i - 1;
+ if (nComment == nPedSlotSfx[slot])
+ return slot;
+ }
+
+ return -1;
+}
+
+bool
+cSampleManager::LoadPedComment(uint32 nComment)
+{
+ ASSERT( nComment < TOTAL_AUDIO_SAMPLES );
+
+ if ( CTimer::GetIsCodePaused() )
+ return false;
+
+ // no talking peds during cutsenes or the game end
+ if ( MusicManager.IsInitialised() )
+ {
+ switch ( MusicManager.GetMusicMode() )
+ {
+ case MUSICMODE_CUTSCENE:
+ {
+ return false;
+
+ break;
+ }
+
+ case MUSICMODE_FRONTEND:
+ {
+ if ( MusicManager.GetCurrentTrack() == STREAMED_SOUND_GAME_COMPLETED )
+ return false;
+
+ break;
+ }
+ }
+ }
+
+ if ( fseek(fpSampleDataHandle, m_aSamples[nComment].nOffset, SEEK_SET) != 0 )
+ return false;
+
+ if ( fread((void *)(nSampleBankMemoryStartAddress[SAMPLEBANK_PED] + PED_BLOCKSIZE*nCurrentPedSlot), 1, m_aSamples[nComment].nSize, fpSampleDataHandle) != m_aSamples[nComment].nSize )
+ return false;
+
+ nPedSlotSfx[nCurrentPedSlot] = nComment;
+
+ alBufferData(pedBuffers[nCurrentPedSlot],
+ AL_FORMAT_MONO16,
+ (void *)(nSampleBankMemoryStartAddress[SAMPLEBANK_PED] + PED_BLOCKSIZE*nCurrentPedSlot),
+ m_aSamples[nComment].nSize,
+ MAX_FREQ);
+
+ if ( ++nCurrentPedSlot >= MAX_PEDSFX )
+ nCurrentPedSlot = 0;
+
+ return true;
+}
+
+int32
+cSampleManager::GetBankContainingSound(uint32 offset)
+{
+ if ( offset >= BankStartOffset[SAMPLEBANK_PED] )
+ return SAMPLEBANK_PED;
+
+ if ( offset >= BankStartOffset[SAMPLEBANK_MAIN] )
+ return SAMPLEBANK_MAIN;
+
+ return SAMPLEBANK_INVALID;
+}
+
+int32
+cSampleManager::GetSampleBaseFrequency(uint32 nSample)
+{
+ ASSERT( nSample < TOTAL_AUDIO_SAMPLES );
+ return m_aSamples[nSample].nFrequency;
+}
+
+int32
+cSampleManager::GetSampleLoopStartOffset(uint32 nSample)
+{
+ ASSERT( nSample < TOTAL_AUDIO_SAMPLES );
+ return m_aSamples[nSample].nLoopStart;
+}
+
+int32
+cSampleManager::GetSampleLoopEndOffset(uint32 nSample)
+{
+ ASSERT( nSample < TOTAL_AUDIO_SAMPLES );
+ return m_aSamples[nSample].nLoopEnd;
+}
+
+uint32
+cSampleManager::GetSampleLength(uint32 nSample)
+{
+ ASSERT( nSample < TOTAL_AUDIO_SAMPLES );
+ return m_aSamples[nSample].nSize >> 1;
+}
+
+bool cSampleManager::UpdateReverb(void)
+{
+ return false;
+}
+
+void
+cSampleManager::SetChannelReverbFlag(uint32 nChannel, uint8 nReverbFlag)
+{
+ ; // NOIMP
+}
+
+bool
+cSampleManager::InitialiseChannel(uint32 nChannel, uint32 nSfx, uint8 nBank)
+{
+ ASSERT( nChannel < MAXCHANNELS+MAX2DCHANNELS );
+
+ ALuint buffer;
+
+ if ( nSfx < SAMPLEBANK_MAX )
+ {
+ int32 offset = (m_aSamples[nSfx].nLoopStart > 0) ? (m_aSamples[nSfx].nOffset - m_aSamples[nSfx].nLoopStart) : m_aSamples[nSfx].nOffset;
+ int32 size = (m_aSamples[nSfx].nLoopStart > 0) ? (m_aSamples[nSfx].nLoopEnd - m_aSamples[nSfx].nLoopStart) : m_aSamples[nSfx].nSize;
+
+ void *data = malloc(size);
+ ASSERT(data != NULL);
+
+ if ( fseek(fpSampleDataHandle, offset + nSampleBankDiscStartOffset[nBank], SEEK_SET) != 0 )
+ {
+ free(data);
+ return false;
+ }
+
+ if ( fread(data, 1, size, fpSampleDataHandle) != size )
+ {
+ free(data);
+ return false;
+ }
+
+ ALuint buf;
+ alGenBuffers(1, &buf);
+ alBufferData(buf, AL_FORMAT_MONO16, data, size, MAX_FREQ);
+ free(data);
+
+ if ( !IsSampleBankLoaded(nBank) )
+ return false;
+
+ ALBuffers[nSfx].buffer = buf;
+ ALBuffers[nSfx].timer = 120000;
+
+ buffer = ALBuffers[nSfx].buffer;
+
+ ChannelSample[nChannel] = nSfx;
+ }
+ else
+ {
+ if ( !IsPedCommentLoaded(nSfx) )
+ return false;
+
+ int32 slot = _GetPedCommentSlot(nSfx);
+
+ buffer = pedBuffers[slot];
+ }
+
+ if ( buffer == 0 )
+ {
+ TRACE("No buffer to play id %d", nSfx);
+ return false;
+ }
+
+ if ( GetChannelUsedFlag(nChannel) )
+ {
+ TRACE("Stopping channel %d - really!!!", nChannel);
+ StopChannel(nChannel);
+ }
+
+ alSourcei(alChannel[nChannel], AL_BUFFER, 0);
+ currentChannelVolume [nChannel] = -1;
+ currentChannelFrequency [nChannel] = -1;
+ currentChannelMaxFrontDistance[nChannel] = -1;
+
+ if ( alChannel[nChannel] )
+ {
+ alSourcei(alChannel[nChannel], AL_BUFFER, buffer);
+ alSourcef(alChannel[nChannel], AL_PITCH, 1.0f);
+ ChannelPitch[nChannel] = 1.0f;
+ return true;
+ }
+
+ return false;
+}
+
+void
+cSampleManager::SetChannelEmittingVolume(uint32 nChannel, uint32 nVolume)
+{
+ ASSERT( nChannel < MAXCHANNELS+MAX2DCHANNELS );
+
+ uint32 vol = nVolume;
+ if ( vol > MAX_VOLUME ) vol = MAX_VOLUME;
+
+ nChannelVolume[nChannel] = vol;
+
+ // reduce the volume for JB.MP3 and S4_BDBD.MP3
+ if ( MusicManager.GetMusicMode() == MUSICMODE_CUTSCENE
+ && MusicManager.GetCurrentTrack() != STREAMED_SOUND_NEWS_INTRO
+ && MusicManager.GetCurrentTrack() != STREAMED_SOUND_CUTSCENE_SAL4_BDBD )
+ {
+ nChannelVolume[nChannel] >>= 2;
+ }
+
+ uint32 channelVol = m_nEffectsFadeVolume*nChannelVolume[nChannel]*m_nEffectsVolume >> 14;
+ if ( ChannelSample[nChannel] >= SFX_CAR_REV_1 && SFX_CAR_REV_10 >= ChannelSample[nChannel] ) // nice hack
+ channelVol >>= 1;
+
+ if ( alChannel[nChannel] )
+ {
+ if ( currentChannelVolume[nChannel] != channelVol )
+ {
+ ALfloat gain = ALfloat(channelVol) / MAX_VOLUME;
+ alSourcef(alChannel[nChannel], AL_GAIN, gain);
+ currentChannelVolume[nChannel] = channelVol;
+ }
+ }
+}
+
+void
+cSampleManager::SetChannel3DPosition(uint32 nChannel, float fX, float fY, float fZ)
+{
+ ASSERT( nChannel < MAXCHANNELS+MAX2DCHANNELS );
+
+ if ( alChannel[nChannel] )
+ {
+ alSource3f(alChannel[nChannel], AL_POSITION, -fX, fY, fZ);
+ }
+}
+
+void
+cSampleManager::SetChannel3DDistances(uint32 nChannel, float fMax, float fMin)
+{
+ ASSERT( nChannel < MAXCHANNELS+MAX2DCHANNELS );
+
+ if ( alChannel[nChannel] )
+ {
+ if ( float(currentChannelMaxFrontDistance[nChannel]) != fMax )
+ {
+ alSourcef(alChannel[nChannel], AL_MAX_DISTANCE, fMax);
+ alSourcef(alChannel[nChannel], AL_REFERENCE_DISTANCE, 5.0f);
+ alSourcef(alChannel[nChannel], AL_MAX_GAIN, 1.0f);
+ currentChannelMaxFrontDistance[nChannel] = int32(fMax);
+ }
+ }
+}
+
+void
+cSampleManager::SetChannelVolume(uint32 nChannel, uint32 nVolume)
+{
+ ASSERT( nChannel < MAXCHANNELS+MAX2DCHANNELS );
+
+ if ( nChannel == CHANNEL2D )
+ {
+ uint32 vol = nVolume;
+ if ( vol > MAX_VOLUME ) vol = MAX_VOLUME;
+
+ nChannelVolume[nChannel] = vol;
+
+ // increase the volume for JB.MP3 and S4_BDBD.MP3
+ if ( MusicManager.GetMusicMode() == MUSICMODE_CUTSCENE
+ && MusicManager.GetCurrentTrack() != STREAMED_SOUND_NEWS_INTRO
+ && MusicManager.GetCurrentTrack() != STREAMED_SOUND_CUTSCENE_SAL4_BDBD )
+ {
+ nChannelVolume[nChannel] >>= 2;
+ }
+
+ uint32 channelVol = m_nEffectsFadeVolume*nChannelVolume[nChannel]*m_nEffectsVolume >> 14;
+ if ( ChannelSample[nChannel] >= SFX_CAR_REV_1 && SFX_CAR_IDLE_10 >= ChannelSample[nChannel] ) // nice hack
+ channelVol >>= 1;
+
+ if ( alChannel[nChannel] )
+ {
+ if ( currentChannelVolume[nChannel] != channelVol )
+ {
+ ALfloat gain = ALfloat(channelVol) / MAX_VOLUME;
+ alSourcef(alChannel[nChannel], AL_GAIN, gain);
+ currentChannelVolume[nChannel] = channelVol;
+ }
+ }
+ }
+}
+
+void
+cSampleManager::SetChannelPan(uint32 nChannel, uint32 nPan)
+{
+ ASSERT( nChannel < MAXCHANNELS+MAX2DCHANNELS );
+ ; // NOIMP
+}
+
+void
+cSampleManager::SetChannelFrequency(uint32 nChannel, uint32 nFreq)
+{
+ ASSERT( nChannel < MAXCHANNELS+MAX2DCHANNELS );
+
+ if ( alChannel[nChannel] )
+ {
+ if ( currentChannelFrequency[nChannel] != nFreq )
+ {
+ ALfloat pitch = ALfloat(nFreq) / MAX_FREQ;
+ alSourcef(alChannel[nChannel], AL_PITCH, pitch);
+ currentChannelFrequency[nChannel] = nFreq;
+
+ if ( Abs(1.0f - pitch) < 0.01f )
+ ChannelPitch[nChannel] = 1.0f;
+ else
+ ChannelPitch[nChannel] = pitch;
+ }
+ }
+}
+
+void
+cSampleManager::SetChannelLoopPoints(uint32 nChannel, uint32 nLoopStart, int32 nLoopEnd)
+{
+ ASSERT( nChannel < MAXCHANNELS+MAX2DCHANNELS );
+
+ ; // NOIMP
+}
+
+void
+cSampleManager::SetChannelLoopCount(uint32 nChannel, uint32 nLoopCount)
+{
+ ASSERT( nChannel < MAXCHANNELS+MAX2DCHANNELS );
+
+ if ( nLoopCount != 0 )
+ alSourcei(alChannel[nChannel], AL_LOOPING, AL_FALSE);
+ else
+ alSourcei(alChannel[nChannel], AL_LOOPING, AL_TRUE);
+}
+
+bool
+cSampleManager::GetChannelUsedFlag(uint32 nChannel)
+{
+ ASSERT( nChannel < MAXCHANNELS+MAX2DCHANNELS );
+
+ if ( alChannel[nChannel] )
+ {
+ ALint sourceState;
+ alGetSourcei(alChannel[nChannel], AL_SOURCE_STATE, &sourceState);
+ return sourceState == AL_PLAYING;
+ }
+
+ return false;
+}
+
+void
+cSampleManager::StartChannel(uint32 nChannel)
+{
+ ASSERT( nChannel < MAXCHANNELS+MAX2DCHANNELS );
+
+ if ( alChannel[nChannel] )
+ {
+ if ( ChannelSample[nChannel] > SAMPLEBANK_END ) // PED's Bank
+ {
+ if ( ChannelPitch[nChannel] != 1.0f )
+ ChannelPitch[nChannel] = 1.0f;
+ }
+
+ alSourcef (alChannel[nChannel], AL_PITCH, ChannelPitch[nChannel]);
+ alSourcePlay(alChannel[nChannel]);
+ }
+}
+
+void
+cSampleManager::StopChannel(uint32 nChannel)
+{
+ ASSERT( nChannel < MAXCHANNELS+MAX2DCHANNELS );
+
+ if ( alChannel[nChannel] )
+ {
+ alSourceStop(alChannel[nChannel]);
+
+ currentChannelVolume [nChannel] = -1;
+ currentChannelFrequency [nChannel] = -1;
+ currentChannelMaxFrontDistance[nChannel] = -1;
+ ChannelPitch [nChannel] = 1.0f;
+ }
+}
+
+void
+cSampleManager::PreloadStreamedFile(uint8 nFile, uint8 nStream)
+{
+ char filename[256];
+
+ ASSERT( nStream < MAX_STREAMS );
+
+ if ( nFile < TOTAL_STREAMED_SOUNDS )
+ {
+ if ( mp3Stream[nStream] )
+ {
+ delete mp3Stream[nStream];
+ mp3Stream[nStream] = NULL;
+ }
+
+ strcpy(filename, StreamedNameTable[nFile]);
+
+ MP3Stream *stream = new MP3Stream(filename, ALStreamSources[nStream], ALStreamBuffers[nStream]);
+ ASSERT(stream != NULL);
+
+ mp3Stream[nStream] = stream;
+
+ if ( stream->m_bIsOpened )
+ {
+ ;
+ }
+ else
+ {
+ delete stream;
+ mp3Stream[nStream] = NULL;
+ }
+ }
+}
+
+void
+cSampleManager::PauseStream(uint8 nPauseFlag, uint8 nStream)
+{
+ ASSERT( nStream < MAX_STREAMS );
+
+ MP3Stream *stream = mp3Stream[nStream];
+
+ if ( stream )
+ {
+ if ( nPauseFlag != 0 )
+ {
+ if ( !stream->m_bIsPaused )
+ {
+ alSourcePause(stream->m_alSource);
+ stream->m_bIsPaused = true;
+ }
+ }
+ else
+ {
+ if ( stream->m_bIsPaused )
+ {
+ alSourcef(stream->m_alSource, AL_PITCH, 1.0f);
+ alSourcePlay(stream->m_alSource);
+ stream->m_bIsPaused = false;
+ }
+ }
+ }
+}
+
+void
+cSampleManager::StartPreloadedStreamedFile(uint8 nStream)
+{
+ ASSERT( nStream < MAX_STREAMS );
+
+ MP3Stream *stream = mp3Stream[nStream];
+
+ if ( stream )
+ {
+ stream->Initialize();
+ if ( stream->m_bIsOpened )
+ {
+ //NOTE: set pos here on mobile
+
+ if ( stream->FillBuffers() != 0 )
+ {
+ alSourcef(stream->m_alSource, AL_PITCH, 1.0f);
+ alSourcePlay(stream->m_alSource);
+ stream->m_bIsFree = false;
+ }
+ }
+ }
+}
+
+bool
+cSampleManager::StartStreamedFile(uint8 nFile, uint32 nPos, uint8 nStream)
+{
+ char filename[256];
+
+ ASSERT( nStream < MAX_STREAMS );
+
+ if ( nFile < TOTAL_STREAMED_SOUNDS )
+ {
+ if ( mp3Stream[nStream] )
+ {
+ delete mp3Stream[nStream];
+ mp3Stream[nStream] = NULL;
+ }
+
+ strcpy(filename, StreamedNameTable[nFile]);
+
+ MP3Stream *stream = new MP3Stream(filename, ALStreamSources[nStream], ALStreamBuffers[nStream]);
+ ASSERT(stream != NULL);
+
+ mp3Stream[nStream] = stream;
+
+ if ( stream->m_bIsOpened )
+ {
+ stream->Initialize();
+ nStreamLength[nFile] = stream->m_nLength;
+ //MusicManager.SetTrackInfoLength(nFile, stream->m_nLength);
+
+ if ( stream->m_bIsOpened )
+ {
+ if ( nPos != 0 )
+ {
+ stream->SetPos(nPos);
+ }
+
+ if ( stream->FillBuffers() != 0 )
+ {
+ alSourcef(stream->m_alSource, AL_PITCH, 1.0f);
+ alSourcePlay(stream->m_alSource);
+ stream->m_bIsFree = false;
+ }
+ }
+
+ return true;
+ }
+ else
+ {
+ delete stream;
+ mp3Stream[nStream] = NULL;
+ }
+ }
+
+ return false;
+}
+
+void
+cSampleManager::StopStreamedFile(uint8 nStream)
+{
+ ASSERT( nStream < MAX_STREAMS );
+
+ MP3Stream *stream = mp3Stream[nStream];
+
+ if ( stream )
+ {
+ delete stream;
+ mp3Stream[nStream] = NULL;
+ }
+}
+
+int32
+cSampleManager::GetStreamedFilePosition(uint8 nStream)
+{
+ ASSERT( nStream < MAX_STREAMS );
+
+ MP3Stream *stream = mp3Stream[nStream];
+
+ if ( stream )
+ {
+ return (ftell(stream->m_fpFile) * 8) / stream->m_nBitRate;
+ }
+
+ return 0;
+}
+
+void
+cSampleManager::SetStreamedVolumeAndPan(uint8 nVolume, uint8 nPan, uint8 nEffectFlag, uint8 nStream)
+{
+ ASSERT( nStream < MAX_STREAMS );
+
+ if ( nVolume > MAX_VOLUME )
+ nVolume = MAX_VOLUME;
+
+ if ( nPan > MAX_VOLUME )
+ nPan = MAX_VOLUME;
+
+ nStreamVolume[nStream] = m_nMusicFadeVolume * nVolume;
+ nStreamPan [nStream] = nPan;
+
+ MP3Stream *stream = mp3Stream[nStream];
+
+ if ( stream )
+ {
+ uint32 vol;
+ if ( nEffectFlag )
+ vol = m_nEffectsFadeVolume*nVolume*m_nEffectsVolume >> 14;
+ else
+ vol = m_nMusicFadeVolume*nVolume*m_nMusicVolume >> 14;
+
+ if ( stream->m_nVolume != vol )
+ {
+ if ( stream->m_bIsOpened )
+ {
+ ALuint source = stream->m_alSource;
+ if ( source )
+ {
+ ALfloat gain = ALfloat(vol) / MAX_VOLUME;
+ alSourcef(source, AL_GAIN, gain);
+ stream = mp3Stream[nStream];
+ }
+ }
+
+ stream->m_nVolume = vol;
+ }
+ }
+}
+
+int32
+cSampleManager::GetStreamedFileLength(uint8 nStream)
+{
+ ASSERT( nStream < TOTAL_STREAMED_SOUNDS );
+
+ return nStreamLength[nStream];
+}
+
+bool
+cSampleManager::IsStreamPlaying(uint8 nStream)
+{
+ ASSERT( nStream < MAX_STREAMS );
+
+ MP3Stream *stream = mp3Stream[nStream];
+
+ if ( stream && stream->m_bIsOpened && !stream->m_bIsPaused )
+ {
+ ALint sourceState;
+ alGetSourcei(stream->m_alSource, AL_SOURCE_STATE, &sourceState);
+ if ( !stream->m_bIsFree || sourceState == AL_PLAYING )
+ return true;
+ }
+
+ return false;
+}
+
+void
+cSampleManager::Service(void)
+{
+ for ( int32 i = 0; i < MAX_STREAMS; i++ )
+ {
+ if ( mp3Stream[i] )
+ mp3Stream[i]->Update();
+ }
+
+ UpdateSoundBuffers();
+}
+
+bool
+cSampleManager::InitialiseSampleBanks(void)
+{
+ int32 nBank = SAMPLEBANK_MAIN;
+
+ fpSampleDescHandle = fopen(SampleBankDescFilename, "rb");
+ if ( fpSampleDescHandle == NULL )
+ return false;
+
+ fpSampleDataHandle = fopen(SampleBankDataFilename, "rb");
+ if ( fpSampleDataHandle == NULL )
+ {
+ fclose(fpSampleDescHandle);
+ fpSampleDescHandle = NULL;
+
+ return false;
+ }
+
+ fseek(fpSampleDataHandle, 0, SEEK_END);
+ int32 _nSampleDataEndOffset = ftell(fpSampleDataHandle);
+ rewind(fpSampleDataHandle);
+
+ fread(m_aSamples, sizeof(tSample), TOTAL_AUDIO_SAMPLES, fpSampleDescHandle);
+
+ fclose(fpSampleDescHandle);
+ fpSampleDescHandle = NULL;
+
+ for ( int32 i = 0; i < TOTAL_AUDIO_SAMPLES; i++ )
+ {
+ if ( BankStartOffset[nBank] == BankStartOffset[SAMPLEBANK_MAIN] + i )
+ {
+ nSampleBankDiscStartOffset[nBank] = m_aSamples[i].nOffset;
+ nBank++;
+ }
+ }
+
+ nSampleBankSize[SAMPLEBANK_MAIN] = nSampleBankDiscStartOffset[SAMPLEBANK_PED] - nSampleBankDiscStartOffset[SAMPLEBANK_MAIN];
+ nSampleBankSize[SAMPLEBANK_PED] = _nSampleDataEndOffset - nSampleBankDiscStartOffset[SAMPLEBANK_PED];
+
+ return true;
+}
+
+/*
+sub_1D8D40
+PreloadSoundBank(tSample *,uchar)
+CheckOpenALChannels(void)
+*/
+
+void MP3Stream::Initialize(void)
+{
+ if ( !m_bIsOpened )
+ return;
+
+ mpg123_format_none(m_pMPG);
+
+ mpg123_format(m_pMPG, 11000, MPG123_MONO|MPG123_STEREO, MPG123_ENC_SIGNED_16);
+ mpg123_format(m_pMPG, 24000, MPG123_MONO|MPG123_STEREO, MPG123_ENC_SIGNED_16);
+ mpg123_format(m_pMPG, 32000, MPG123_MONO|MPG123_STEREO, MPG123_ENC_SIGNED_16);
+ mpg123_format(m_pMPG, 44100, MPG123_MONO|MPG123_STEREO, MPG123_ENC_SIGNED_16);
+
+ if ( mpg123_open_feed(m_pMPG) != MPG123_OK )
+ return;
+
+ const uint32 CHUNK_SIZE = 1024*5;
+
+ if ( fread(m_pBuf, 1, CHUNK_SIZE, m_fpFile) != CHUNK_SIZE )
+ {
+ Delete();
+ return;
+ }
+
+ m_nBufSize -= CHUNK_SIZE;
+
+ mpg123_feed(m_pMPG, m_pBuf, CHUNK_SIZE);
+
+ if ( mpg123_getformat(m_pMPG, &m_nRate, &m_nChannels, &m_nEncoding) != MPG123_OK )
+ {
+ Delete();
+ return;
+ }
+
+ mpg123_frameinfo info;
+ if ( mpg123_info(m_pMPG, &info) != MPG123_OK )
+ {
+ Delete();
+ return;
+ }
+
+ m_nBitRate = info.bitrate;
+ m_nLength = 8 * m_nLengthInBytes / info.bitrate;
+ m_nBlockSize = mpg123_outblock(m_pMPG);
+ m_nNumBlocks = 5;
+ m_pBlocks = (unsigned char *)malloc(m_nNumBlocks * m_nBlockSize);
+}
+
+bool MP3Stream::FillBuffer(ALuint alBuffer)
+{
+ size_t done;
+
+ uint8 *pBlockBuff = (uint8 *)m_pBlocks;
+
+ bool fail = !(m_nBufSize > 1);
+
+ int err = mpg123_read(m_pMPG, m_pBlocks, m_nBlockSize, &done);
+ if ( alBuffer == 0 )
+ {
+ if ( err == MPG123_OK )
+ {
+ while ( mpg123_read(m_pMPG, pBlockBuff, m_nBlockSize, &done) == MPG123_OK )
+ ;
+ }
+
+ return true;
+ }
+
+ int32 blocks = 0;
+ for ( blocks = 0; blocks < m_nNumBlocks; blocks++ )
+ {
+ if ( err == MPG123_NEED_MORE )
+ {
+ if ( fail )
+ break;
+
+ size_t readSize = m_nBufSize;
+ if ( readSize > 0x4000 )
+ {
+ if ( fread(m_pBuf, 1, 0x4000, m_fpFile) != 0x4000 )
+ {
+ fail = true;
+ TRACE("MP3 ************* : MP3 read unsuccessful mid file, stopping queuing");
+ break;
+ }
+
+ m_nBufSize -= 0x4000;
+ mpg123_feed(m_pMPG, m_pBuf, 0x4000);
+ }
+ else
+ {
+ if ( fread(m_pBuf, 1, readSize, m_fpFile) != readSize )
+ {
+ fail = true;
+ break;
+ }
+
+ m_nBufSize -= readSize;
+ mpg123_feed(m_pMPG, m_pBuf, readSize);
+ }
+ }
+ else if ( err == MPG123_OK )
+ {
+ pBlockBuff += m_nBlockSize;
+ }
+ else
+ {
+ fail = true;
+ break;
+ }
+
+ err = mpg123_read(m_pMPG, pBlockBuff, m_nBlockSize, &done);
+ }
+
+ if ( blocks != 0 )
+ {
+ if ( m_nChannels == 1 )
+ alBufferData(alBuffer, AL_FORMAT_MONO16, m_pBlocks, m_nBlockSize*blocks, m_nRate);
+ else
+ alBufferData(alBuffer, AL_FORMAT_STEREO16, m_pBlocks, m_nBlockSize*blocks, m_nRate);
+ }
+
+ if ( fail && blocks < m_nNumBlocks )
+ m_bIsFree = true;
+
+ return blocks != 0;
+}
+
+void MP3Stream::Update(void)
+{
+ if ( !m_bIsOpened )
+ return;
+
+ if ( m_bIsFree )
+ return;
+
+ if ( !m_bIsPaused )
+ {
+ ALint sourceState;
+ ALint buffersProcessed = 0;
+
+ alGetSourcei(m_alSource, AL_SOURCE_STATE, &sourceState);
+ alGetSourcei(m_alSource, AL_BUFFERS_PROCESSED, &buffersProcessed);
+
+ ALint looping = AL_FALSE;
+ alGetSourcei(m_alSource, AL_LOOPING, &looping);
+
+ if ( looping == AL_TRUE )
+ {
+ TRACE("stream set looping");
+ alSourcei(m_alSource, AL_LOOPING, AL_TRUE);
+ }
+
+ while( buffersProcessed-- )
+ {
+ ALuint buffer;
+
+ alSourceUnqueueBuffers(m_alSource, 1, &buffer);
+
+ if ( !m_bIsFree && FillBuffer(buffer) )
+ alSourceQueueBuffers(m_alSource, 1, &buffer);
+ }
+
+ if ( sourceState != AL_PLAYING )
+ {
+ alSourcef(m_alSource, AL_PITCH, 1.0f);
+ alSourcePlay(m_alSource);
+ }
+ }
+}
+
+void MP3Stream::SetPos(uint32 nPos)
+{
+ uint32 pos = nPos;
+ if ( nPos > m_nLength )
+ pos %= m_nLength;
+
+ uint32 blockPos = m_nBitRate * pos / 8;
+ if ( blockPos > m_nLengthInBytes )
+ blockPos %= m_nLengthInBytes;
+
+ fseek(m_fpFile, blockPos, SEEK_SET);
+
+ size_t done;
+ while ( mpg123_read(m_pMPG, m_pBlocks, m_nBlockSize, &done) == MPG123_OK )
+ ;
+}
+
+int32 MP3Stream::FillBuffers()
+{
+ int32 i = 0;
+ for ( i = 0; i < ARRAY_SIZE(m_alBuffers); i++ )
+ {
+ if ( !FillBuffer(m_alBuffers[i]) )
+ break;
+ alSourceQueueBuffers(m_alSource, 1, &m_alBuffers[i]);
+ }
+
+ return i;
+}
+
+MP3Stream::MP3Stream(char *filename, ALuint source, ALuint *buffers)
+{
+ strcpy(m_aFilename, filename);
+ memset(m_alBuffers, 0, sizeof(m_alBuffers));
+ m_alSource = source;
+ memcpy(m_alBuffers, buffers, sizeof(m_alBuffers));
+ m_nVolume = -1;
+ m_pBlocks = NULL;
+ m_pBuf = NULL;
+ m_pMPG = NULL;
+ m_bIsPaused = false;
+ m_bIsOpened = true;
+ m_bIsFree = true;
+ m_fpFile = fopen(m_aFilename, "rb");
+
+ if ( m_fpFile )
+ {
+ m_nBufSize = filelength(fileno(m_fpFile));
+ m_nLengthInBytes = m_nBufSize;
+ m_pMPG = mpg123_new(NULL, NULL);
+ m_pBuf = (unsigned char *)malloc(0x4000);
+ }
+ else
+ {
+ m_bIsOpened = false;
+ Delete();
+ }
+}
+
+void MP3Stream::Delete()
+{
+ if ( m_pMPG )
+ {
+ mpg123_delete(m_pMPG);
+ m_pMPG = NULL;
+ }
+
+ if ( m_fpFile )
+ {
+ fclose(m_fpFile);
+ m_fpFile = NULL;
+ }
+
+ if ( m_alSource )
+ {
+ ALint sourceState = AL_STOPPED;
+ alGetSourcei(m_alSource, AL_SOURCE_STATE, &sourceState);
+ if (sourceState != AL_STOPPED )
+ alSourceStop(m_alSource);
+
+ ALint buffersQueued;
+ alGetSourcei(m_alSource, AL_BUFFERS_QUEUED, &buffersQueued);
+
+ ALuint value;
+ while (buffersQueued--)
+ alSourceUnqueueBuffers(m_alSource, 1, &value);
+
+ m_alSource = 0;
+ }
+
+ if ( m_pBlocks )
+ {
+ free(m_pBlocks);
+ m_pBlocks = NULL;
+ }
+
+ if ( m_pBuf )
+ {
+ free(m_pBuf);
+ m_pBuf = NULL;
+ }
+
+ m_bIsOpened = false;
+} \ No newline at end of file
diff --git a/src/audio/openal/samp_oal.h b/src/audio/openal/samp_oal.h
new file mode 100644
index 00000000..8bbdbcc9
--- /dev/null
+++ b/src/audio/openal/samp_oal.h
@@ -0,0 +1,340 @@
+#pragma once
+#include "common.h"
+#include "AudioSamples.h"
+
+#define MAX_VOLUME 127
+//#define MAX_FREQ 22050
+#define MAX_FREQ 32000
+
+struct tSample {
+ int32 nOffset;
+ uint32 nSize;
+ int32 nFrequency;
+ int32 nLoopStart;
+ int32 nLoopEnd;
+};
+
+enum
+{
+ SAMPLEBANK_MAIN,
+ SAMPLEBANK_PED,
+ MAX_SAMPLEBANKS,
+ SAMPLEBANK_INVALID
+};
+
+#define MAX_PEDSFX 7
+#define PED_BLOCKSIZE 79000
+
+
+//#define MAXCHANNELS 21 android
+#define MAXCHANNELS 28
+#define MAX2DCHANNELS 1
+#define CHANNEL2D MAXCHANNELS
+
+#define MAX_STREAMS 2
+
+struct ALCdevice_struct;
+struct ALCcontext_struct;
+typedef struct ALCdevice_struct ALCdevice;
+typedef struct ALCcontext_struct ALCcontext;
+
+class cSampleManager
+{
+ int field_0;
+ ALCdevice *m_pDevice;
+ ALCcontext *m_pContext;
+
+ uint8 m_nEffectsVolume;
+ uint8 m_nMusicVolume;
+ uint8 m_nEffectsFadeVolume;
+ uint8 m_nMusicFadeVolume;
+ uint8 m_nMonoMode;
+ char _pad0[3];
+ tSample m_aSamples[TOTAL_AUDIO_SAMPLES];
+
+public:
+
+
+
+ cSampleManager(void);
+ ~cSampleManager(void);
+
+ void SetSpeakerConfig(int32 nConfig);
+ uint32 GetMaximumSupportedChannels(void);
+
+ uint32 GetNum3DProvidersAvailable();
+ void SetNum3DProvidersAvailable(uint32 num);
+
+ char *Get3DProviderName(uint8 id);
+ void Set3DProviderName(uint8 id, char *name);
+
+ int8 GetCurrent3DProviderIndex(void);
+ int8 SetCurrent3DProvider(uint8 which);
+
+ bool IsMP3RadioChannelAvailable(void);
+
+ void ReleaseDigitalHandle (void);
+ void ReacquireDigitalHandle(void);
+
+ bool Initialise(void);
+ void Terminate (void);
+
+ void UpdateSoundBuffers(void);
+
+ bool CheckForAnAudioFileOnCD(void);
+ char GetCDAudioDriveLetter (void);
+
+ void UpdateEffectsVolume(void);
+
+ void SetEffectsMasterVolume(uint8 nVolume);
+ void SetMusicMasterVolume (uint8 nVolume);
+ void SetEffectsFadeVolume (uint8 nVolume);
+ void SetMusicFadeVolume (uint8 nVolume);
+ void SetMonoMode (uint8 nMode);
+
+ bool LoadSampleBank (uint8 nBank);
+ void UnloadSampleBank (uint8 nBank);
+ bool IsSampleBankLoaded(uint8 nBank);
+
+ bool IsPedCommentLoaded(uint32 nComment);
+ bool LoadPedComment (uint32 nComment);
+ int32 GetBankContainingSound(uint32 offset);
+
+ int32 _GetPedCommentSlot(uint32 nComment);
+
+ int32 GetSampleBaseFrequency (uint32 nSample);
+ int32 GetSampleLoopStartOffset(uint32 nSample);
+ int32 GetSampleLoopEndOffset (uint32 nSample);
+ uint32 GetSampleLength (uint32 nSample);
+
+ bool UpdateReverb(void);
+
+ void SetChannelReverbFlag (uint32 nChannel, uint8 nReverbFlag);
+ bool InitialiseChannel (uint32 nChannel, uint32 nSfx, uint8 nBank);
+ void SetChannelEmittingVolume(uint32 nChannel, uint32 nVolume);
+ void SetChannel3DPosition (uint32 nChannel, float fX, float fY, float fZ);
+ void SetChannel3DDistances (uint32 nChannel, float fMax, float fMin);
+ void SetChannelVolume (uint32 nChannel, uint32 nVolume);
+ void SetChannelPan (uint32 nChannel, uint32 nPan);
+ void SetChannelFrequency (uint32 nChannel, uint32 nFreq);
+ void SetChannelLoopPoints (uint32 nChannel, uint32 nLoopStart, int32 nLoopEnd);
+ void SetChannelLoopCount (uint32 nChannel, uint32 nLoopCount);
+ bool GetChannelUsedFlag (uint32 nChannel);
+ void StartChannel (uint32 nChannel);
+ void StopChannel (uint32 nChannel);
+
+ void PreloadStreamedFile (uint8 nFile, uint8 nStream);
+ void PauseStream (uint8 nPauseFlag, uint8 nStream);
+ void StartPreloadedStreamedFile (uint8 nStream);
+ bool StartStreamedFile (uint8 nFile, uint32 nPos, uint8 nStream);
+ void StopStreamedFile (uint8 nStream);
+ int32 GetStreamedFilePosition (uint8 nStream);
+ void SetStreamedVolumeAndPan(uint8 nVolume, uint8 nPan, uint8 nEffectFlag, uint8 nStream);
+ int32 GetStreamedFileLength (uint8 nStream);
+ bool IsStreamPlaying (uint8 nStream);
+ void Service(void);
+ bool InitialiseSampleBanks(void);
+};
+
+extern cSampleManager SampleManager;
+extern int32 BankStartOffset[MAX_SAMPLEBANKS];
+
+static char StreamedNameTable[][25]=
+{
+ "AUDIO\\HEAD.MP3",
+ "AUDIO\\CLASS.MP3",
+ "AUDIO\\KJAH.MP3",
+ "AUDIO\\RISE.MP3",
+ "AUDIO\\LIPS.MP3",
+ "AUDIO\\GAME.MP3",
+ "AUDIO\\MSX.MP3",
+ "AUDIO\\FLASH.MP3",
+ "AUDIO\\CHAT.MP3",
+ "AUDIO\\HEAD.MP3",
+ "AUDIO\\POLICE.MP3",
+ "AUDIO\\CITY.MP3",
+ "AUDIO\\WATER.MP3",
+ "AUDIO\\COMOPEN.MP3",
+ "AUDIO\\SUBOPEN.MP3",
+ "AUDIO\\JB.MP3",
+ "AUDIO\\BET.MP3",
+ "AUDIO\\L1_LG.MP3",
+ "AUDIO\\L2_DSB.MP3",
+ "AUDIO\\L3_DM.MP3",
+ "AUDIO\\L4_PAP.MP3",
+ "AUDIO\\L5_TFB.MP3",
+ "AUDIO\\J0_DM2.MP3",
+ "AUDIO\\J1_LFL.MP3",
+ "AUDIO\\J2_KCL.MP3",
+ "AUDIO\\J3_VH.MP3",
+ "AUDIO\\J4_ETH.MP3",
+ "AUDIO\\J5_DST.MP3",
+ "AUDIO\\J6_TBJ.MP3",
+ "AUDIO\\T1_TOL.MP3",
+ "AUDIO\\T2_TPU.MP3",
+ "AUDIO\\T3_MAS.MP3",
+ "AUDIO\\T4_TAT.MP3",
+ "AUDIO\\T5_BF.MP3",
+ "AUDIO\\S0_MAS.MP3",
+ "AUDIO\\S1_PF.MP3",
+ "AUDIO\\S2_CTG.MP3",
+ "AUDIO\\S3_RTC.MP3",
+ "AUDIO\\S5_LRQ.MP3",
+ "AUDIO\\S4_BDBA.MP3",
+ "AUDIO\\S4_BDBB.MP3",
+ "AUDIO\\S2_CTG2.MP3",
+ "AUDIO\\S4_BDBD.MP3",
+ "AUDIO\\S5_LRQB.MP3",
+ "AUDIO\\S5_LRQC.MP3",
+ "AUDIO\\A1_SSO.MP3",
+ "AUDIO\\A2_PP.MP3",
+ "AUDIO\\A3_SS.MP3",
+ "AUDIO\\A4_PDR.MP3",
+ "AUDIO\\A5_K2FT.MP3",
+ "AUDIO\\K1_KBO.MP3",
+ "AUDIO\\K2_GIS.MP3",
+ "AUDIO\\K3_DS.MP3",
+ "AUDIO\\K4_SHI.MP3",
+ "AUDIO\\K5_SD.MP3",
+ "AUDIO\\R0_PDR2.MP3",
+ "AUDIO\\R1_SW.MP3",
+ "AUDIO\\R2_AP.MP3",
+ "AUDIO\\R3_ED.MP3",
+ "AUDIO\\R4_GF.MP3",
+ "AUDIO\\R5_PB.MP3",
+ "AUDIO\\R6_MM.MP3",
+ "AUDIO\\D1_STOG.MP3",
+ "AUDIO\\D2_KK.MP3",
+ "AUDIO\\D3_ADO.MP3",
+ "AUDIO\\D5_ES.MP3",
+ "AUDIO\\D7_MLD.MP3",
+ "AUDIO\\D4_GTA.MP3",
+ "AUDIO\\D4_GTA2.MP3",
+ "AUDIO\\D6_STS.MP3",
+ "AUDIO\\A6_BAIT.MP3",
+ "AUDIO\\A7_ETG.MP3",
+ "AUDIO\\A8_PS.MP3",
+ "AUDIO\\A9_ASD.MP3",
+ "AUDIO\\K4_SHI2.MP3",
+ "AUDIO\\C1_TEX.MP3",
+ "AUDIO\\EL_PH1.MP3",
+ "AUDIO\\EL_PH2.MP3",
+ "AUDIO\\EL_PH3.MP3",
+ "AUDIO\\EL_PH4.MP3",
+ "AUDIO\\YD_PH1.MP3",
+ "AUDIO\\YD_PH2.MP3",
+ "AUDIO\\YD_PH3.MP3",
+ "AUDIO\\YD_PH4.MP3",
+ "AUDIO\\HD_PH1.MP3",
+ "AUDIO\\HD_PH2.MP3",
+ "AUDIO\\HD_PH3.MP3",
+ "AUDIO\\HD_PH4.MP3",
+ "AUDIO\\HD_PH5.MP3",
+ "AUDIO\\MT_PH1.MP3",
+ "AUDIO\\MT_PH2.MP3",
+ "AUDIO\\MT_PH3.MP3",
+ "AUDIO\\MT_PH4.MP3",
+ "AUDIO\\MISCOM.MP3",
+ "AUDIO\\END.MP3",
+ "AUDIO\\lib_a1.MP3",
+ "AUDIO\\lib_a2.MP3",
+ "AUDIO\\lib_a.MP3",
+ "AUDIO\\lib_b.MP3",
+ "AUDIO\\lib_c.MP3",
+ "AUDIO\\lib_d.MP3",
+ "AUDIO\\l2_a.MP3",
+ "AUDIO\\j4t_1.MP3",
+ "AUDIO\\j4t_2.MP3",
+ "AUDIO\\j4t_3.MP3",
+ "AUDIO\\j4t_4.MP3",
+ "AUDIO\\j4_a.MP3",
+ "AUDIO\\j4_b.MP3",
+ "AUDIO\\j4_c.MP3",
+ "AUDIO\\j4_d.MP3",
+ "AUDIO\\j4_e.MP3",
+ "AUDIO\\j4_f.MP3",
+ "AUDIO\\j6_1.MP3",
+ "AUDIO\\j6_a.MP3",
+ "AUDIO\\j6_b.MP3",
+ "AUDIO\\j6_c.MP3",
+ "AUDIO\\j6_d.MP3",
+ "AUDIO\\t4_a.MP3",
+ "AUDIO\\s1_a.MP3",
+ "AUDIO\\s1_a1.MP3",
+ "AUDIO\\s1_b.MP3",
+ "AUDIO\\s1_c.MP3",
+ "AUDIO\\s1_c1.MP3",
+ "AUDIO\\s1_d.MP3",
+ "AUDIO\\s1_e.MP3",
+ "AUDIO\\s1_f.MP3",
+ "AUDIO\\s1_g.MP3",
+ "AUDIO\\s1_h.MP3",
+ "AUDIO\\s1_i.MP3",
+ "AUDIO\\s1_j.MP3",
+ "AUDIO\\s1_k.MP3",
+ "AUDIO\\s1_l.MP3",
+ "AUDIO\\s3_a.MP3",
+ "AUDIO\\s3_b.MP3",
+ "AUDIO\\el3_a.MP3",
+ "AUDIO\\mf1_a.MP3",
+ "AUDIO\\mf2_a.MP3",
+ "AUDIO\\mf3_a.MP3",
+ "AUDIO\\mf3_b.MP3",
+ "AUDIO\\mf3_b1.MP3",
+ "AUDIO\\mf3_c.MP3",
+ "AUDIO\\mf4_a.MP3",
+ "AUDIO\\mf4_b.MP3",
+ "AUDIO\\mf4_c.MP3",
+ "AUDIO\\a1_a.MP3",
+ "AUDIO\\a3_a.MP3",
+ "AUDIO\\a5_a.MP3",
+ "AUDIO\\a4_a.MP3",
+ "AUDIO\\a4_b.MP3",
+ "AUDIO\\a4_c.MP3",
+ "AUDIO\\a4_d.MP3",
+ "AUDIO\\k1_a.MP3",
+ "AUDIO\\k3_a.MP3",
+ "AUDIO\\r1_a.MP3",
+ "AUDIO\\r2_a.MP3",
+ "AUDIO\\r2_b.MP3",
+ "AUDIO\\r2_c.MP3",
+ "AUDIO\\r2_d.MP3",
+ "AUDIO\\r2_e.MP3",
+ "AUDIO\\r2_f.MP3",
+ "AUDIO\\r2_g.MP3",
+ "AUDIO\\r2_h.MP3",
+ "AUDIO\\r5_a.MP3",
+ "AUDIO\\r6_a.MP3",
+ "AUDIO\\r6_a1.MP3",
+ "AUDIO\\r6_b.MP3",
+ "AUDIO\\lo2_a.MP3",
+ "AUDIO\\lo6_a.MP3",
+ "AUDIO\\yd2_a.MP3",
+ "AUDIO\\yd2_b.MP3",
+ "AUDIO\\yd2_c.MP3",
+ "AUDIO\\yd2_c1.MP3",
+ "AUDIO\\yd2_d.MP3",
+ "AUDIO\\yd2_e.MP3",
+ "AUDIO\\yd2_f.MP3",
+ "AUDIO\\yd2_g.MP3",
+ "AUDIO\\yd2_h.MP3",
+ "AUDIO\\yd2_ass.MP3",
+ "AUDIO\\yd2_ok.MP3",
+ "AUDIO\\h5_a.MP3",
+ "AUDIO\\h5_b.MP3",
+ "AUDIO\\h5_c.MP3",
+ "AUDIO\\ammu_a.MP3",
+ "AUDIO\\ammu_b.MP3",
+ "AUDIO\\ammu_c.MP3",
+ "AUDIO\\door_1.MP3",
+ "AUDIO\\door_2.MP3",
+ "AUDIO\\door_3.MP3",
+ "AUDIO\\door_4.MP3",
+ "AUDIO\\door_5.MP3",
+ "AUDIO\\door_6.MP3",
+ "AUDIO\\t3_a.MP3",
+ "AUDIO\\t3_b.MP3",
+ "AUDIO\\t3_c.MP3",
+ "AUDIO\\k1_b.MP3",
+ "AUDIO\\cat1.MP3"
+};