diff options
author | Nikolay Korolev <nickvnuk@gmail.com> | 2020-04-23 18:12:20 +0200 |
---|---|---|
committer | Nikolay Korolev <nickvnuk@gmail.com> | 2020-04-23 18:12:20 +0200 |
commit | 05ddc80ea22cee3c97f274b1d5c3d3d1d5cafdbd (patch) | |
tree | d1b9a842f2d767a0d05b1a23c3a0a4746d2b5e70 /src/audio/openal | |
parent | Merge remote-tracking branch 'upstream/master' (diff) | |
parent | removed fix that made no sense (diff) | |
download | re3-05ddc80ea22cee3c97f274b1d5c3d3d1d5cafdbd.tar re3-05ddc80ea22cee3c97f274b1d5c3d3d1d5cafdbd.tar.gz re3-05ddc80ea22cee3c97f274b1d5c3d3d1d5cafdbd.tar.bz2 re3-05ddc80ea22cee3c97f274b1d5c3d3d1d5cafdbd.tar.lz re3-05ddc80ea22cee3c97f274b1d5c3d3d1d5cafdbd.tar.xz re3-05ddc80ea22cee3c97f274b1d5c3d3d1d5cafdbd.tar.zst re3-05ddc80ea22cee3c97f274b1d5c3d3d1d5cafdbd.zip |
Diffstat (limited to 'src/audio/openal')
-rw-r--r-- | src/audio/openal/samp_oal.cpp | 1404 | ||||
-rw-r--r-- | src/audio/openal/samp_oal.h | 340 |
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" +}; |