354 lines
11 KiB
C++
354 lines
11 KiB
C++
/*
|
|
===========================================================================
|
|
|
|
Doom 3 GPL Source Code
|
|
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
|
|
|
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
|
|
|
|
Doom 3 Source Code is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
Doom 3 Source Code is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
|
|
|
|
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
|
|
|
===========================================================================
|
|
*/
|
|
|
|
#include "../idlib/precompiled.h"
|
|
#pragma hdrstop
|
|
|
|
#include "snd_local.h"
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: idWaveFile::idWaveFile()
|
|
// Desc: Constructs the class. Call Open() to open a wave file for reading.
|
|
// Then call Read() as needed. Calling the destructor or Close()
|
|
// will close the file.
|
|
//-----------------------------------------------------------------------------
|
|
idWaveFile::idWaveFile( void ) {
|
|
memset( &mpwfx, 0, sizeof( waveformatextensible_t ) );
|
|
mhmmio = NULL;
|
|
mdwSize = 0;
|
|
mseekBase = 0;
|
|
mbIsReadingFromMemory = false;
|
|
mpbData = NULL;
|
|
ogg = NULL;
|
|
isOgg = false;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: idWaveFile::~idWaveFile()
|
|
// Desc: Destructs the class
|
|
//-----------------------------------------------------------------------------
|
|
idWaveFile::~idWaveFile( void ) {
|
|
Close();
|
|
|
|
if ( mbIsReadingFromMemory && mpbData ) {
|
|
Mem_Free( mpbData );
|
|
}
|
|
|
|
memset( &mpwfx, 0, sizeof( waveformatextensible_t ) );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: idWaveFile::Open()
|
|
// Desc: Opens a wave file for reading
|
|
//-----------------------------------------------------------------------------
|
|
int idWaveFile::Open( const char* strFileName, waveformatex_t* pwfx ) {
|
|
|
|
mbIsReadingFromMemory = false;
|
|
|
|
mpbData = NULL;
|
|
mpbDataCur = mpbData;
|
|
|
|
if( strFileName == NULL ) {
|
|
return -1;
|
|
}
|
|
|
|
idStr name = strFileName;
|
|
|
|
// note: used to only check for .wav when making a build
|
|
name.SetFileExtension( ".ogg" );
|
|
if ( fileSystem->ReadFile( name, NULL, NULL ) != -1 ) {
|
|
return OpenOGG( name, pwfx );
|
|
}
|
|
|
|
memset( &mpwfx, 0, sizeof( waveformatextensible_t ) );
|
|
|
|
mhmmio = fileSystem->OpenFileRead( strFileName );
|
|
if ( !mhmmio ) {
|
|
mdwSize = 0;
|
|
return -1;
|
|
}
|
|
if ( mhmmio->Length() <= 0 ) {
|
|
mhmmio = NULL;
|
|
return -1;
|
|
}
|
|
if ( ReadMMIO() != 0 ) {
|
|
// ReadMMIO will fail if its an not a wave file
|
|
Close();
|
|
return -1;
|
|
}
|
|
|
|
mfileTime = mhmmio->Timestamp();
|
|
|
|
if ( ResetFile() != 0 ) {
|
|
Close();
|
|
return -1;
|
|
}
|
|
|
|
// After the reset, the size of the wav file is mck.cksize so store it now
|
|
mdwSize = mck.cksize / sizeof( short );
|
|
mMemSize = mck.cksize;
|
|
|
|
if ( mck.cksize != 0xffffffff ) {
|
|
if ( pwfx ) {
|
|
memcpy( pwfx, (waveformatex_t *)&mpwfx, sizeof(waveformatex_t));
|
|
}
|
|
return 0;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: idWaveFile::OpenFromMemory()
|
|
// Desc: copy data to idWaveFile member variable from memory
|
|
//-----------------------------------------------------------------------------
|
|
int idWaveFile::OpenFromMemory( short* pbData, int ulDataSize, waveformatextensible_t* pwfx ) {
|
|
mpwfx = *pwfx;
|
|
mulDataSize = ulDataSize;
|
|
mpbData = pbData;
|
|
mpbDataCur = mpbData;
|
|
mdwSize = ulDataSize / sizeof( short );
|
|
mMemSize = ulDataSize;
|
|
mbIsReadingFromMemory = true;
|
|
|
|
return 0;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: idWaveFile::ReadMMIO()
|
|
// Desc: Support function for reading from a multimedia I/O stream.
|
|
// mhmmio must be valid before calling. This function uses it to
|
|
// update mckRiff, and mpwfx.
|
|
//-----------------------------------------------------------------------------
|
|
int idWaveFile::ReadMMIO( void ) {
|
|
mminfo_t ckIn; // chunk info. for general use.
|
|
pcmwaveformat_t pcmWaveFormat; // Temp PCM structure to load in.
|
|
|
|
memset( &mpwfx, 0, sizeof( waveformatextensible_t ) );
|
|
|
|
mhmmio->Read( &mckRiff, 12 );
|
|
assert( !isOgg );
|
|
mckRiff.ckid = LittleLong( mckRiff.ckid );
|
|
mckRiff.cksize = LittleLong( mckRiff.cksize );
|
|
mckRiff.fccType = LittleLong( mckRiff.fccType );
|
|
mckRiff.dwDataOffset = 12;
|
|
|
|
// Check to make sure this is a valid wave file
|
|
if( (mckRiff.ckid != fourcc_riff) || (mckRiff.fccType != mmioFOURCC('W', 'A', 'V', 'E') ) ) {
|
|
return -1;
|
|
}
|
|
|
|
// Search the input file for for the 'fmt ' chunk.
|
|
ckIn.dwDataOffset = 12;
|
|
do {
|
|
if (8 != mhmmio->Read( &ckIn, 8 ) ) {
|
|
return -1;
|
|
}
|
|
assert( !isOgg );
|
|
ckIn.ckid = LittleLong( ckIn.ckid );
|
|
ckIn.cksize = LittleLong( ckIn.cksize );
|
|
ckIn.dwDataOffset += ckIn.cksize-8;
|
|
} while (ckIn.ckid != mmioFOURCC('f', 'm', 't', ' '));
|
|
|
|
// Expect the 'fmt' chunk to be at least as large as <PCMWAVEFORMAT>;
|
|
// if there are extra parameters at the end, we'll ignore them
|
|
if( ckIn.cksize < sizeof(pcmwaveformat_t) ) {
|
|
return -1;
|
|
}
|
|
|
|
// Read the 'fmt ' chunk into <pcmWaveFormat>.
|
|
if( mhmmio->Read( &pcmWaveFormat, sizeof(pcmWaveFormat) ) != sizeof(pcmWaveFormat) ) {
|
|
return -1;
|
|
}
|
|
assert( !isOgg );
|
|
pcmWaveFormat.wf.wFormatTag = LittleShort( pcmWaveFormat.wf.wFormatTag );
|
|
pcmWaveFormat.wf.nChannels = LittleShort( pcmWaveFormat.wf.nChannels );
|
|
pcmWaveFormat.wf.nSamplesPerSec = LittleLong( pcmWaveFormat.wf.nSamplesPerSec );
|
|
pcmWaveFormat.wf.nAvgBytesPerSec = LittleLong( pcmWaveFormat.wf.nAvgBytesPerSec );
|
|
pcmWaveFormat.wf.nBlockAlign = LittleShort( pcmWaveFormat.wf.nBlockAlign );
|
|
pcmWaveFormat.wBitsPerSample = LittleShort( pcmWaveFormat.wBitsPerSample );
|
|
|
|
// Copy the bytes from the pcm structure to the waveformatex_t structure
|
|
memcpy( &mpwfx, &pcmWaveFormat, sizeof(pcmWaveFormat) );
|
|
|
|
// Allocate the waveformatex_t, but if its not pcm format, read the next
|
|
// word, and thats how many extra bytes to allocate.
|
|
if( pcmWaveFormat.wf.wFormatTag == WAVE_FORMAT_TAG_PCM ) {
|
|
mpwfx.Format.cbSize = 0;
|
|
} else {
|
|
return -1; // we don't handle these (32 bit wavefiles, etc)
|
|
#if 0
|
|
// Read in length of extra bytes.
|
|
word cbExtraBytes = 0L;
|
|
if( mhmmio->Read( (char*)&cbExtraBytes, sizeof(word) ) != sizeof(word) )
|
|
return -1;
|
|
|
|
mpwfx.Format.cbSize = cbExtraBytes;
|
|
|
|
// Now, read those extra bytes into the structure, if cbExtraAlloc != 0.
|
|
if( mhmmio->Read( (char*)(((byte*)&(mpwfx.Format.cbSize))+sizeof(word)), cbExtraBytes ) != cbExtraBytes ) {
|
|
memset( &mpwfx, 0, sizeof( waveformatextensible_t ) );
|
|
return -1;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: idWaveFile::ResetFile()
|
|
// Desc: Resets the internal mck pointer so reading starts from the
|
|
// beginning of the file again
|
|
//-----------------------------------------------------------------------------
|
|
int idWaveFile::ResetFile( void ) {
|
|
if( mbIsReadingFromMemory ) {
|
|
mpbDataCur = mpbData;
|
|
} else {
|
|
if( mhmmio == NULL ) {
|
|
return -1;
|
|
}
|
|
|
|
// Seek to the data
|
|
if( -1 == mhmmio->Seek( mckRiff.dwDataOffset + sizeof(fourcc), FS_SEEK_SET ) ) {
|
|
return -1;
|
|
}
|
|
|
|
// Search the input file for for the 'fmt ' chunk.
|
|
mck.ckid = 0;
|
|
do {
|
|
byte ioin;
|
|
if ( !mhmmio->Read( &ioin, 1 ) ) {
|
|
return -1;
|
|
}
|
|
mck.ckid = (mck.ckid>>8) | (ioin<<24);
|
|
} while (mck.ckid != mmioFOURCC('d', 'a', 't', 'a'));
|
|
|
|
mhmmio->Read( &mck.cksize, 4 );
|
|
assert( !isOgg );
|
|
mck.cksize = LittleLong( mck.cksize );
|
|
mseekBase = mhmmio->Tell();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: idWaveFile::Read()
|
|
// Desc: Reads section of data from a wave file into pBuffer and returns
|
|
// how much read in pdwSizeRead, reading not more than dwSizeToRead.
|
|
// This uses mck to determine where to start reading from. So
|
|
// subsequent calls will be continue where the last left off unless
|
|
// Reset() is called.
|
|
//-----------------------------------------------------------------------------
|
|
int idWaveFile::Read( byte* pBuffer, int dwSizeToRead, int *pdwSizeRead ) {
|
|
|
|
if ( ogg != NULL ) {
|
|
|
|
return ReadOGG( pBuffer, dwSizeToRead, pdwSizeRead );
|
|
|
|
} else if ( mbIsReadingFromMemory ) {
|
|
|
|
if( mpbDataCur == NULL ) {
|
|
return -1;
|
|
}
|
|
if( (byte*)(mpbDataCur + dwSizeToRead) > (byte*)(mpbData + mulDataSize) ) {
|
|
dwSizeToRead = mulDataSize - (int)(mpbDataCur - mpbData);
|
|
}
|
|
SIMDProcessor->Memcpy( pBuffer, mpbDataCur, dwSizeToRead );
|
|
mpbDataCur += dwSizeToRead;
|
|
|
|
if ( pdwSizeRead != NULL ) {
|
|
*pdwSizeRead = dwSizeToRead;
|
|
}
|
|
|
|
return dwSizeToRead;
|
|
|
|
} else {
|
|
|
|
if( mhmmio == NULL ) {
|
|
return -1;
|
|
}
|
|
if( pBuffer == NULL ) {
|
|
return -1;
|
|
}
|
|
|
|
dwSizeToRead = mhmmio->Read( pBuffer, dwSizeToRead );
|
|
// this is hit by ogg code, which does it's own byte swapping internally
|
|
if ( !isOgg ) {
|
|
LittleRevBytes( pBuffer, 2, dwSizeToRead / 2 );
|
|
}
|
|
|
|
if ( pdwSizeRead != NULL ) {
|
|
*pdwSizeRead = dwSizeToRead;
|
|
}
|
|
|
|
return dwSizeToRead;
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: idWaveFile::Close()
|
|
// Desc: Closes the wave file
|
|
//-----------------------------------------------------------------------------
|
|
int idWaveFile::Close( void ) {
|
|
if ( ogg != NULL ) {
|
|
return CloseOGG();
|
|
}
|
|
if( mhmmio != NULL ) {
|
|
fileSystem->CloseFile( mhmmio );
|
|
mhmmio = NULL;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: idWaveFile::Seek()
|
|
//-----------------------------------------------------------------------------
|
|
int idWaveFile::Seek( int offset ) {
|
|
|
|
if ( ogg != NULL ) {
|
|
|
|
common->FatalError( "idWaveFile::Seek: cannot seek on an OGG file\n" );
|
|
|
|
} else if( mbIsReadingFromMemory ) {
|
|
|
|
mpbDataCur = mpbData + offset;
|
|
|
|
} else {
|
|
if( mhmmio == NULL ) {
|
|
return -1;
|
|
}
|
|
|
|
if ((int)(offset+mseekBase) == mhmmio->Tell()) {
|
|
return 0;
|
|
}
|
|
mhmmio->Seek( offset + mseekBase, FS_SEEK_SET );
|
|
return 0;
|
|
}
|
|
return -1;
|
|
}
|