/* * Copyright (c) 2006, Creative Labs Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided * that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of conditions and * the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions * and the following disclaimer in the documentation and/or other materials provided with the distribution. * * Neither the name of Creative Labs Inc. nor the names of its contributors may be used to endorse or * promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "stdneb.h" #include "CWaves.h" #include #include "io/stream.h" #ifdef __WIN32__ #include #include #include #else typedef long HRESULT; #define SUCCEEDED(hr) (((HRESULT)(hr)) >= 0) #define _MAX_PATH 260 #define _stricmp strcasecmp #define _strnicmp strncasecmp #define _strdup strdup #define WAVE_FORMAT_PCM 1 #define WAVE_FORMAT_EXTENSIBLE 0xFFFE #define SPEAKER_FRONT_LEFT 0x1 #define SPEAKER_FRONT_RIGHT 0x2 #define SPEAKER_FRONT_CENTER 0x4 #define SPEAKER_LOW_FREQUENCY 0x8 #define SPEAKER_BACK_LEFT 0x10 #define SPEAKER_BACK_RIGHT 0x20 #define SPEAKER_FRONT_LEFT_OF_CENTER 0x40 #define SPEAKER_FRONT_RIGHT_OF_CENTER 0x80 #define SPEAKER_BACK_CENTER 0x100 #define SPEAKER_SIDE_LEFT 0x200 #define SPEAKER_SIDE_RIGHT 0x400 #define SPEAKER_TOP_CENTER 0x800 #define SPEAKER_TOP_FRONT_LEFT 0x1000 #define SPEAKER_TOP_FRONT_CENTER 0x2000 #define SPEAKER_TOP_FRONT_RIGHT 0x4000 #define SPEAKER_TOP_BACK_LEFT 0x8000 #define SPEAKER_TOP_BACK_CENTER 0x10000 #define SPEAKER_TOP_BACK_RIGHT 0x20000 typedef struct waveformat_tag { WORD wFormatTag; /* format type */ WORD nChannels; /* number of channels (i.e. mono, stereo, etc.) */ DWORD nSamplesPerSec; /* sample rate */ DWORD nAvgBytesPerSec; /* for buffer estimation */ WORD nBlockAlign; /* block size of data */ } WAVEFORMAT; typedef struct pcmwaveformat_tag { WAVEFORMAT wf; WORD wBitsPerSample; } PCMWAVEFORMAT; #endif //__ANDROID__ #pragma pack(push, 4) typedef struct { char szRIFF[4]; unsigned long ulRIFFSize; char szWAVE[4]; } WAVEFILEHEADER; typedef struct { char szChunkName[4]; unsigned long ulChunkSize; } RIFFCHUNK; typedef struct { unsigned short usFormatTag; unsigned short usChannels; unsigned long ulSamplesPerSec; unsigned long ulAvgBytesPerSec; unsigned short usBlockAlign; unsigned short usBitsPerSample; unsigned short usSize; unsigned short usReserved; unsigned long ulChannelMask; GUID guidSubFormat; } WAVEFMT; #pragma pack(pop) #if _MSC_VER <= 1310 // Wrap around the deprecated functions for VS2003 support int fopen_s( FILE** pFile, const char *filename, const char *mode ) { *pFile = fopen( filename, mode ); return *pFile ? 0 : EBADF; } int strncpy_s( char *strDest, size_t numberOfElements, const char *strSource, size_t count ) { strncpy( strDest, strSource, count ); return 0; } #endif ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// CWaves::CWaves() { memset(&m_WaveIDs, 0, sizeof(m_WaveIDs)); } CWaves::~CWaves() { long lLoop; for (lLoop = 0; lLoop < MAX_NUM_WAVEID; lLoop++) { if (m_WaveIDs[lLoop]) { if (m_WaveIDs[lLoop]->pData) delete m_WaveIDs[lLoop]->pData; if (m_WaveIDs[lLoop]->pFile) fclose(m_WaveIDs[lLoop]->pFile); delete m_WaveIDs[lLoop]; m_WaveIDs[lLoop] = 0; } } } WAVERESULT CWaves::LoadWaveFile(const char* nameOrData, SizeT dataSize, WAVEID *pWaveID, bool bOpenMemory) { WAVERESULT wr = WR_OUTOFMEMORY; LPWAVEFILEINFO pWaveInfo; pWaveInfo = new WAVEFILEINFO; if (pWaveInfo) { if ( bOpenMemory ) { GPtr pData = IO::MemoryStream::Create(); pData->SetAccessMode( IO::Stream::ReadWriteAccess ); pData->Open(); pData->Write(nameOrData, dataSize); pData->Seek(0,IO::Stream::Begin); if (SUCCEEDED(wr = ParseFile(pData, pWaveInfo))) { // Allocate memory for sample data pWaveInfo->pData = new char[pWaveInfo->ulDataSize]; if (pWaveInfo->pData) { // Seek to start of audio data pData->Seek(pWaveInfo->ulDataOffset, IO::Stream::Begin); // Read Sample Data if (pData->Read(pWaveInfo->pData, pWaveInfo->ulDataSize) == pWaveInfo->ulDataSize) { long lLoop = 0; for (lLoop = 0; lLoop < MAX_NUM_WAVEID; lLoop++) { if (!m_WaveIDs[lLoop]) { m_WaveIDs[lLoop] = pWaveInfo; *pWaveID = lLoop; wr = WR_OK; break; } } if (lLoop == MAX_NUM_WAVEID) { delete pWaveInfo->pData; wr = WR_OUTOFMEMORY; } } else { delete pWaveInfo->pData; wr = WR_BADWAVEFILE; } } else { wr = WR_OUTOFMEMORY; } pData->Close(); } } else { if (SUCCEEDED(wr = ParseFile(nameOrData, pWaveInfo))) { // Allocate memory for sample data pWaveInfo->pData = new char[pWaveInfo->ulDataSize]; if (pWaveInfo->pData) { // Seek to start of audio data fseek(pWaveInfo->pFile, pWaveInfo->ulDataOffset, SEEK_SET); // Read Sample Data if (fread(pWaveInfo->pData, 1, pWaveInfo->ulDataSize, pWaveInfo->pFile) == pWaveInfo->ulDataSize) { long lLoop = 0; for (lLoop = 0; lLoop < MAX_NUM_WAVEID; lLoop++) { if (!m_WaveIDs[lLoop]) { m_WaveIDs[lLoop] = pWaveInfo; *pWaveID = lLoop; wr = WR_OK; break; } } if (lLoop == MAX_NUM_WAVEID) { delete pWaveInfo->pData; wr = WR_OUTOFMEMORY; } } else { delete pWaveInfo->pData; wr = WR_BADWAVEFILE; } } else { wr = WR_OUTOFMEMORY; } fclose(pWaveInfo->pFile); pWaveInfo->pFile = 0; } } if (wr != WR_OK) delete pWaveInfo; } return wr; } #ifdef zhaohang WAVERESULT CWaves::OpenWaveFile(const char* nameOrData, SizeT dataSize, WAVEID *pWaveID, bool bOpenMemory) { WAVERESULT wr = WR_OUTOFMEMORY; LPWAVEFILEINFO pWaveInfo; pWaveInfo = new WAVEFILEINFO; if (pWaveInfo) { if ( !bOpenMemory ) { if (SUCCEEDED(wr = ParseFile(nameOrData, pWaveInfo))) { long lLoop = 0; for (lLoop = 0; lLoop < MAX_NUM_WAVEID; lLoop++) { if (!m_WaveIDs[lLoop]) { m_WaveIDs[lLoop] = pWaveInfo; *pWaveID = lLoop; wr = WR_OK; break; } } if (lLoop == MAX_NUM_WAVEID) wr = WR_OUTOFMEMORY; } } if (wr != WR_OK) delete pWaveInfo; } return wr; } WAVERESULT CWaves::ReadWaveData(WAVEID WaveID, void *pData, unsigned long ulDataSize, unsigned long *pulBytesWritten) { LPWAVEFILEINFO pWaveInfo; WAVERESULT wr = WR_BADWAVEFILE; if (!pData || !pulBytesWritten || ulDataSize == 0) return WR_INVALIDPARAM; if (IsWaveID(WaveID)) { pWaveInfo = m_WaveIDs[WaveID]; if (pWaveInfo->pFile) { unsigned long ulOffset = ftell(pWaveInfo->pFile); if ((ulOffset - pWaveInfo->ulDataOffset + ulDataSize) > pWaveInfo->ulDataSize) ulDataSize = pWaveInfo->ulDataSize - (ulOffset - pWaveInfo->ulDataOffset); *pulBytesWritten = (unsigned long)fread(pData, 1, ulDataSize, pWaveInfo->pFile); wr = WR_OK; } } else { wr = WR_INVALIDWAVEID; } return wr; } WAVERESULT CWaves::SetWaveDataOffset(WAVEID WaveID, unsigned long ulOffset) { LPWAVEFILEINFO pWaveInfo; WAVERESULT wr = WR_INVALIDPARAM; if (IsWaveID(WaveID)) { pWaveInfo = m_WaveIDs[WaveID]; if (pWaveInfo->pFile) { // Seek into audio data fseek(pWaveInfo->pFile, pWaveInfo->ulDataOffset + ulOffset, SEEK_SET); wr = WR_OK; } } else { wr = WR_INVALIDWAVEID; } return wr; } WAVERESULT CWaves::GetWaveDataOffset(WAVEID WaveID, unsigned long *pulOffset) { LPWAVEFILEINFO pWaveInfo; WAVERESULT wr = WR_INVALIDPARAM; if (IsWaveID(WaveID)) { pWaveInfo = m_WaveIDs[WaveID]; if ((pWaveInfo->pFile) && (pulOffset)) { // Get current position *pulOffset = ftell(pWaveInfo->pFile); *pulOffset -= pWaveInfo->ulDataOffset; wr = WR_OK; } } else { wr = WR_INVALIDWAVEID; } return wr; } #endif WAVERESULT CWaves::ParseFile(const char *szFilename, LPWAVEFILEINFO pWaveInfo) { WAVEFILEHEADER waveFileHeader; RIFFCHUNK riffChunk; WAVEFMT waveFmt; WAVERESULT wr = WR_BADWAVEFILE; if (!szFilename || !pWaveInfo) return WR_INVALIDPARAM; memset(pWaveInfo, 0, sizeof(WAVEFILEINFO)); // Open the wave file for reading fopen_s(&pWaveInfo->pFile, szFilename, "rb"); if (pWaveInfo->pFile) { // Read Wave file header fread(&waveFileHeader, 1, sizeof(WAVEFILEHEADER), pWaveInfo->pFile); if (!_strnicmp(waveFileHeader.szRIFF, "RIFF", 4) && !_strnicmp(waveFileHeader.szWAVE, "WAVE", 4)) { while (fread(&riffChunk, 1, sizeof(RIFFCHUNK), pWaveInfo->pFile) == sizeof(RIFFCHUNK)) { if (!_strnicmp(riffChunk.szChunkName, "fmt ", 4)) { if (riffChunk.ulChunkSize <= sizeof(WAVEFMT)) { fread(&waveFmt, 1, riffChunk.ulChunkSize, pWaveInfo->pFile); // Determine if this is a WAVEFORMATEX or WAVEFORMATEXTENSIBLE wave file if (waveFmt.usFormatTag == WAVE_FORMAT_PCM) { pWaveInfo->wfType = WF_EX; memcpy(&pWaveInfo->wfEXT.Format, &waveFmt, sizeof(PCMWAVEFORMAT)); } else if (waveFmt.usFormatTag == WAVE_FORMAT_EXTENSIBLE) { pWaveInfo->wfType = WF_EXT; memcpy(&pWaveInfo->wfEXT, &waveFmt, sizeof(WAVEFORMATEXTENSIBLE)); } } else { fseek(pWaveInfo->pFile, riffChunk.ulChunkSize, SEEK_CUR); } } else if (!_strnicmp(riffChunk.szChunkName, "data", 4)) { pWaveInfo->ulDataSize = riffChunk.ulChunkSize; pWaveInfo->ulDataOffset = ftell(pWaveInfo->pFile); fseek(pWaveInfo->pFile, riffChunk.ulChunkSize, SEEK_CUR); } else { fseek(pWaveInfo->pFile, riffChunk.ulChunkSize, SEEK_CUR); } // Ensure that we are correctly aligned for next chunk if (riffChunk.ulChunkSize & 1) fseek(pWaveInfo->pFile, 1, SEEK_CUR); } if (pWaveInfo->ulDataSize && pWaveInfo->ulDataOffset && ((pWaveInfo->wfType == WF_EX) || (pWaveInfo->wfType == WF_EXT))) wr = WR_OK; else fclose(pWaveInfo->pFile); } } else { wr = WR_INVALIDFILENAME; } return wr; } WAVERESULT CWaves::ParseFile(GPtr& data, LPWAVEFILEINFO pWaveInfo) { WAVEFILEHEADER waveFileHeader; RIFFCHUNK riffChunk; WAVEFMT waveFmt; WAVERESULT wr = WR_BADWAVEFILE; if (!data.isvalid() || !pWaveInfo) return WR_INVALIDPARAM; memset(pWaveInfo, 0, sizeof(WAVEFILEINFO)); // Read Wave file header data->Read(&waveFileHeader, sizeof(WAVEFILEHEADER)); if (!_strnicmp(waveFileHeader.szRIFF, "RIFF", 4) && !_strnicmp(waveFileHeader.szWAVE, "WAVE", 4)) { while (data->Read(&riffChunk, sizeof(RIFFCHUNK)) == sizeof(RIFFCHUNK)) { if (!_strnicmp(riffChunk.szChunkName, "fmt ", 4)) { if (riffChunk.ulChunkSize <= sizeof(WAVEFMT)) { data->Read(&waveFmt, riffChunk.ulChunkSize); // Determine if this is a WAVEFORMATEX or WAVEFORMATEXTENSIBLE wave file if (waveFmt.usFormatTag == WAVE_FORMAT_PCM) { pWaveInfo->wfType = WF_EX; memcpy(&pWaveInfo->wfEXT.Format, &waveFmt, sizeof(PCMWAVEFORMAT)); } else if (waveFmt.usFormatTag == WAVE_FORMAT_EXTENSIBLE) { pWaveInfo->wfType = WF_EXT; memcpy(&pWaveInfo->wfEXT, &waveFmt, sizeof(WAVEFORMATEXTENSIBLE)); } } else { data->Seek(riffChunk.ulChunkSize, IO::Stream::Current); } } else if (!_strnicmp(riffChunk.szChunkName, "data", 4)) { pWaveInfo->ulDataSize = riffChunk.ulChunkSize; pWaveInfo->ulDataOffset = data->GetPosition(); data->Seek(riffChunk.ulChunkSize, IO::Stream::Current); } else { data->Seek(riffChunk.ulChunkSize, IO::Stream::Current); } // Ensure that we are correctly aligned for next chunk if (riffChunk.ulChunkSize & 1) { data->Seek(1, IO::Stream::Current); } } if (pWaveInfo->ulDataSize && pWaveInfo->ulDataOffset && ((pWaveInfo->wfType == WF_EX) || (pWaveInfo->wfType == WF_EXT))) wr = WR_OK; else data->Close(); } return wr; } #ifdef zhaohang WAVERESULT CWaves::GetWaveType(WAVEID WaveID, WAVEFILETYPE *wfType) { if (!IsWaveID(WaveID)) return WR_INVALIDWAVEID; if (!wfType) return WR_INVALIDPARAM; *wfType = m_WaveIDs[WaveID]->wfType; return WR_OK; } WAVERESULT CWaves::GetWaveFormatExHeader(WAVEID WaveID, WAVEFORMATEX *wfex) { if (!IsWaveID(WaveID)) return WR_INVALIDWAVEID; if (!wfex) return WR_INVALIDPARAM; memcpy(wfex, &(m_WaveIDs[WaveID]->wfEXT.Format), sizeof(WAVEFORMATEX)); return WR_OK; } WAVERESULT CWaves::GetWaveFormatExtensibleHeader(WAVEID WaveID, WAVEFORMATEXTENSIBLE *wfext) { if (!IsWaveID(WaveID)) return WR_INVALIDWAVEID; if (m_WaveIDs[WaveID]->wfType != WF_EXT) return WR_NOTWAVEFORMATEXTENSIBLEFORMAT; if (!wfext) return WR_INVALIDPARAM; memcpy(wfext, &(m_WaveIDs[WaveID]->wfEXT), sizeof(WAVEFORMATEXTENSIBLE)); return WR_OK; } char *CWaves::GetErrorString(WAVERESULT wr, char *szErrorString, unsigned long nSizeOfErrorString) { switch (wr) { case WR_OK: strncpy_s(szErrorString, nSizeOfErrorString, "Success\n", nSizeOfErrorString-1); break; case WR_INVALIDFILENAME: strncpy_s(szErrorString, nSizeOfErrorString, "Invalid file name or file does not exist\n", nSizeOfErrorString-1); break; case WR_BADWAVEFILE: strncpy_s(szErrorString, nSizeOfErrorString, "Invalid Wave file\n", nSizeOfErrorString-1); break; case WR_INVALIDPARAM: strncpy_s(szErrorString, nSizeOfErrorString, "Invalid parameter passed to function\n", nSizeOfErrorString-1); break; case WR_FILEERROR: strncpy_s(szErrorString, nSizeOfErrorString, "File I/O error\n", nSizeOfErrorString-1); break; case WR_INVALIDWAVEID: strncpy_s(szErrorString, nSizeOfErrorString, "Invalid WAVEID\n", nSizeOfErrorString-1); break; case WR_NOTSUPPORTEDYET: strncpy_s(szErrorString, nSizeOfErrorString, "Function not supported yet\n", nSizeOfErrorString-1); break; case WR_WAVEMUSTBEMONO: strncpy_s(szErrorString, nSizeOfErrorString, "Input wave files must be mono\n", nSizeOfErrorString-1); break; case WR_WAVEMUSTBEWAVEFORMATPCM: strncpy_s(szErrorString, nSizeOfErrorString, "Input wave files must be in Wave Format PCM\n", nSizeOfErrorString-1); break; case WR_WAVESMUSTHAVESAMEBITRESOLUTION: strncpy_s(szErrorString, nSizeOfErrorString, "Input wave files must have the same Bit Resolution\n", nSizeOfErrorString-1); break; case WR_WAVESMUSTHAVESAMEFREQUENCY: strncpy_s(szErrorString, nSizeOfErrorString, "Input wave files must have the same Frequency\n", nSizeOfErrorString-1); break; case WR_WAVESMUSTHAVESAMEBITRATE: strncpy_s(szErrorString, nSizeOfErrorString, "Input wave files must have the same Bit Rate\n", nSizeOfErrorString-1); break; case WR_WAVESMUSTHAVESAMEBLOCKALIGNMENT: strncpy_s(szErrorString, nSizeOfErrorString, "Input wave files must have the same Block Alignment\n", nSizeOfErrorString-1); break; case WR_OFFSETOUTOFDATARANGE: strncpy_s(szErrorString, nSizeOfErrorString, "Wave files Offset is not within audio data\n", nSizeOfErrorString-1); break; case WR_INVALIDSPEAKERPOS: strncpy_s(szErrorString, nSizeOfErrorString, "Invalid Speaker Destinations\n", nSizeOfErrorString-1); break; case WR_OUTOFMEMORY: strncpy_s(szErrorString, nSizeOfErrorString, "Out of memory\n", nSizeOfErrorString-1); break; case WR_INVALIDWAVEFILETYPE: strncpy_s(szErrorString, nSizeOfErrorString, "Invalid Wave File Type\n", nSizeOfErrorString-1); break; case WR_NOTWAVEFORMATEXTENSIBLEFORMAT: strncpy_s(szErrorString, nSizeOfErrorString, "Wave file is not in WAVEFORMATEXTENSIBLE format\n", nSizeOfErrorString-1); break; default: strncpy_s(szErrorString, nSizeOfErrorString, "Undefined error\n", nSizeOfErrorString-1); } szErrorString[nSizeOfErrorString-1] = '\0'; return szErrorString; } #endif WAVERESULT CWaves::GetWaveData(WAVEID WaveID, void **lplpAudioData) { if (!IsWaveID(WaveID)) return WR_INVALIDWAVEID; if (!lplpAudioData) return WR_INVALIDPARAM; *lplpAudioData = m_WaveIDs[WaveID]->pData; return WR_OK; } WAVERESULT CWaves::GetWaveSize(WAVEID WaveID, unsigned long *size) { if (!IsWaveID(WaveID)) return WR_INVALIDWAVEID; if (!size) return WR_INVALIDPARAM; *size = m_WaveIDs[WaveID]->ulDataSize; return WR_OK; } WAVERESULT CWaves::GetWaveFrequency(WAVEID WaveID, unsigned long *pulFrequency) { WAVERESULT wr = WR_OK; if (IsWaveID(WaveID)) { if (pulFrequency) *pulFrequency = m_WaveIDs[WaveID]->wfEXT.Format.nSamplesPerSec; else wr = WR_INVALIDPARAM; } else { wr = WR_INVALIDWAVEID; } return wr; } bool CWaves::IsWaveID(WAVEID WaveID) { bool bReturn = false; if ((WaveID >= 0) && (WaveID < MAX_NUM_WAVEID)) { if (m_WaveIDs[WaveID]) bReturn = true; } return bReturn; } WAVERESULT CWaves::GetWaveALBufferFormat(WAVEID WaveID, PFNALGETENUMVALUE pfnGetEnumValue, unsigned long *pulFormat) { WAVERESULT wr = WR_OK; if (IsWaveID(WaveID)) { if (pfnGetEnumValue && pulFormat) { *pulFormat = 0; if (m_WaveIDs[WaveID]->wfType == WF_EX) { if (m_WaveIDs[WaveID]->wfEXT.Format.nChannels == 1) { switch (m_WaveIDs[WaveID]->wfEXT.Format.wBitsPerSample) { case 4: *pulFormat = pfnGetEnumValue("AL_FORMAT_MONO_IMA4"); break; case 8: *pulFormat = pfnGetEnumValue("AL_FORMAT_MONO8"); break; case 16: *pulFormat = pfnGetEnumValue("AL_FORMAT_MONO16"); break; } } else if (m_WaveIDs[WaveID]->wfEXT.Format.nChannels == 2) { switch (m_WaveIDs[WaveID]->wfEXT.Format.wBitsPerSample) { case 4: *pulFormat = pfnGetEnumValue("AL_FORMAT_STEREO_IMA4"); break; case 8: *pulFormat = pfnGetEnumValue("AL_FORMAT_STEREO8"); break; case 16: *pulFormat = pfnGetEnumValue("AL_FORMAT_STEREO16"); break; } } else if ((m_WaveIDs[WaveID]->wfEXT.Format.nChannels == 4) && (m_WaveIDs[WaveID]->wfEXT.Format.wBitsPerSample == 16)) *pulFormat = pfnGetEnumValue("AL_FORMAT_QUAD16"); } else if (m_WaveIDs[WaveID]->wfType == WF_EXT) { if ((m_WaveIDs[WaveID]->wfEXT.Format.nChannels == 1) && ((m_WaveIDs[WaveID]->wfEXT.dwChannelMask == SPEAKER_FRONT_CENTER) || (m_WaveIDs[WaveID]->wfEXT.dwChannelMask == (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT)) || (m_WaveIDs[WaveID]->wfEXT.dwChannelMask == 0))) { switch (m_WaveIDs[WaveID]->wfEXT.Format.wBitsPerSample) { case 4: *pulFormat = pfnGetEnumValue("AL_FORMAT_MONO_IMA4"); break; case 8: *pulFormat = pfnGetEnumValue("AL_FORMAT_MONO8"); break; case 16: *pulFormat = pfnGetEnumValue("AL_FORMAT_MONO16"); break; } } else if ((m_WaveIDs[WaveID]->wfEXT.Format.nChannels == 2) && (m_WaveIDs[WaveID]->wfEXT.dwChannelMask == (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT))) { switch (m_WaveIDs[WaveID]->wfEXT.Format.wBitsPerSample) { case 4: *pulFormat = pfnGetEnumValue("AL_FORMAT_STEREO_IMA4"); break; case 8: *pulFormat = pfnGetEnumValue("AL_FORMAT_STEREO8"); break; case 16: *pulFormat = pfnGetEnumValue("AL_FORMAT_STEREO16"); break; } } else if ((m_WaveIDs[WaveID]->wfEXT.Format.nChannels == 2) && (m_WaveIDs[WaveID]->wfEXT.Format.wBitsPerSample == 16) && (m_WaveIDs[WaveID]->wfEXT.dwChannelMask == (SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT))) *pulFormat = pfnGetEnumValue("AL_FORMAT_REAR16"); else if ((m_WaveIDs[WaveID]->wfEXT.Format.nChannels == 4) && (m_WaveIDs[WaveID]->wfEXT.Format.wBitsPerSample == 16) && (m_WaveIDs[WaveID]->wfEXT.dwChannelMask == (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT))) *pulFormat = pfnGetEnumValue("AL_FORMAT_QUAD16"); else if ((m_WaveIDs[WaveID]->wfEXT.Format.nChannels == 6) && (m_WaveIDs[WaveID]->wfEXT.Format.wBitsPerSample == 16) && (m_WaveIDs[WaveID]->wfEXT.dwChannelMask == (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT))) *pulFormat = pfnGetEnumValue("AL_FORMAT_51CHN16"); else if ((m_WaveIDs[WaveID]->wfEXT.Format.nChannels == 7) && (m_WaveIDs[WaveID]->wfEXT.Format.wBitsPerSample == 16) && (m_WaveIDs[WaveID]->wfEXT.dwChannelMask == (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT|SPEAKER_BACK_CENTER))) *pulFormat = pfnGetEnumValue("AL_FORMAT_61CHN16"); else if ((m_WaveIDs[WaveID]->wfEXT.Format.nChannels == 8) && (m_WaveIDs[WaveID]->wfEXT.Format.wBitsPerSample == 16) && (m_WaveIDs[WaveID]->wfEXT.dwChannelMask == (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT))) *pulFormat = pfnGetEnumValue("AL_FORMAT_71CHN16"); } if (*pulFormat == 0) wr = WR_INVALIDWAVEFILETYPE; } else { wr = WR_INVALIDPARAM; } } else { wr = WR_INVALIDWAVEID; } return wr; } WAVERESULT CWaves::DeleteWaveFile(WAVEID WaveID) { WAVERESULT wr = WR_OK; if (IsWaveID(WaveID)) { if (m_WaveIDs[WaveID]->pData) delete[] m_WaveIDs[WaveID]->pData; if (m_WaveIDs[WaveID]->pFile) fclose(m_WaveIDs[WaveID]->pFile); delete m_WaveIDs[WaveID]; m_WaveIDs[WaveID] = 0; } else { wr = WR_INVALIDWAVEID; } return wr; }