DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

WaveFile.cpp (17450B)


      1 /*
      2 ===========================================================================
      3 
      4 Doom 3 BFG Edition GPL Source Code
      5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 
      6 
      7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").  
      8 
      9 Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
     10 it under the terms of the GNU General Public License as published by
     11 the Free Software Foundation, either version 3 of the License, or
     12 (at your option) any later version.
     13 
     14 Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
     15 but WITHOUT ANY WARRANTY; without even the implied warranty of
     16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17 GNU General Public License for more details.
     18 
     19 You should have received a copy of the GNU General Public License
     20 along with Doom 3 BFG Edition Source Code.  If not, see <http://www.gnu.org/licenses/>.
     21 
     22 In addition, the Doom 3 BFG Edition 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 BFG Edition Source Code.  If not, please request a copy in writing from id Software at the address below.
     23 
     24 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.
     25 
     26 ===========================================================================
     27 */
     28 #pragma hdrstop
     29 #include "../idlib/precompiled.h"
     30 
     31 /*
     32 ================================================================================================
     33 Contains the WaveFile implementation.
     34 ================================================================================================
     35 */
     36 
     37 #include "WaveFile.h"
     38 
     39 /*
     40 ========================
     41 idWaveFile::Open
     42 
     43 Returns true if the Open was successful and the file matches the expected format. If this 
     44 returns false, there is no need to call Close.
     45 ========================
     46 */
     47 bool idWaveFile::Open( const char * filename ) {
     48 	Close();
     49 
     50 	if ( filename == NULL || filename[0] == 0 ) {
     51 		return false;
     52 	}
     53 
     54 	if ( file == NULL ) {
     55 		file = fileSystem->OpenFileReadMemory( filename );
     56 		if ( file == NULL ) {
     57 			return false;
     58 		}
     59 	}
     60 
     61 	if ( file->Length() == 0 ) {
     62 		Close();
     63 		return false;
     64 	}
     65 
     66 	struct header_t {
     67 		uint32 id;
     68 		uint32 size;
     69 		uint32 format;
     70 	} header;
     71 
     72 	file->Read( &header, sizeof( header ) );
     73 	idSwap::Big( header.id );
     74 	idSwap::Little( header.size );
     75 	idSwap::Big( header.format );
     76 
     77 	if ( header.id != 'RIFF' || header.format != 'WAVE' || header.size < 4 ) {
     78 		Close();
     79 		idLib::Warning( "Header is not RIFF WAVE in %s", filename );
     80 		return false;
     81 	}
     82 
     83 	uint32 riffSize = header.size + 8;
     84 	uint32 offset = sizeof( header );
     85 
     86 	// Scan the file collecting chunks
     87 	while ( offset < riffSize ) {
     88 		struct chuckHeader_t {
     89 			uint32 id;
     90 			uint32 size;
     91 		} chunkHeader;
     92 		if ( file->Read( &chunkHeader, sizeof( chunkHeader ) ) != sizeof( chunkHeader ) ) {
     93 			// It seems like some tools have extra data after the last chunk for no apparent reason
     94 			// so don't treat this as an error
     95 			return true;
     96 		}
     97 		idSwap::Big( chunkHeader.id );
     98 		idSwap::Little( chunkHeader.size );
     99 		offset += sizeof( chunkHeader );
    100 
    101 		if ( chunks.Num() >= chunks.Max() ) {
    102 			Close();
    103 			idLib::Warning( "More than %d chunks in %s", chunks.Max(), filename );
    104 			return false;
    105 		}
    106 
    107 		chunk_t * chunk = chunks.Alloc();
    108 		chunk->id = chunkHeader.id;
    109 		chunk->size = chunkHeader.size;
    110 		chunk->offset = offset;
    111 		offset += chunk->size;
    112 
    113 		file->Seek( offset, FS_SEEK_SET );
    114 	}
    115 
    116 	return true;
    117 }
    118 
    119 /*
    120 ========================
    121 idWaveFile::SeekToChunk
    122 
    123 Seeks to the specified chunk and returns the size of the chunk or 0 if the chunk wasn't found.
    124 ========================
    125 */
    126 uint32 idWaveFile::SeekToChunk( uint32 id ) {
    127 	for ( int i = 0; i < chunks.Num(); i++ ) {
    128 		if ( chunks[i].id == id ) {
    129 			file->Seek( chunks[i].offset, FS_SEEK_SET );
    130 			return chunks[i].size;
    131 		}
    132 	}
    133 	return 0;
    134 }
    135 
    136 /*
    137 ========================
    138 idWaveFile::GetChunkOffset
    139 
    140 Seeks to the specified chunk and returns the size of the chunk or 0 if the chunk wasn't found.
    141 ========================
    142 */
    143 uint32 idWaveFile::GetChunkOffset( uint32 id ) {
    144 	for ( int i = 0; i < chunks.Num(); i++ ) {
    145 		if ( chunks[i].id == id ) {
    146 			return chunks[i].offset;
    147 		}
    148 	}
    149 	return 0;
    150 }
    151 
    152 // Used in XMA2WAVEFORMAT for per-stream data
    153 typedef struct XMA2STREAMFORMAT {
    154     byte Channels;			// Number of channels in the stream (1 or 2)
    155     byte RESERVED;			// Reserved for future use
    156     uint16 ChannelMask;		// Spatial positions of the channels in the stream
    157 } XMA2STREAMFORMAT;
    158 
    159 // Legacy XMA2 format structure (big-endian byte ordering)
    160 typedef struct XMA2WAVEFORMAT {
    161     byte Version;			// XMA encoder version that generated the file.
    162 							// Always 3 or higher for XMA2 files.
    163     byte NumStreams;		// Number of interleaved audio streams
    164     byte RESERVED;			// Reserved for future use
    165     byte LoopCount;			// Number of loop repetitions; 255 = infinite
    166     uint32 LoopBegin;		// Loop begin point, in samples
    167     uint32 LoopEnd;			// Loop end point, in samples
    168     uint32 SampleRate;		// The file's decoded sample rate
    169     uint32 EncodeOptions;		// Options for the XMA encoder/decoder
    170     uint32 PsuedoBytesPerSec;	// Used internally by the XMA encoder
    171     uint32 BlockSizeInBytes;	// Size in bytes of this file's XMA blocks (except
    172 								// possibly the last one).  Always a multiple of
    173 								// 2Kb, since XMA blocks are arrays of 2Kb packets.
    174     uint32 SamplesEncoded;		// Total number of PCM samples encoded in this file
    175     uint32 SamplesInSource;		// Actual number of PCM samples in the source
    176 								// material used to generate this file
    177     uint32 BlockCount;			// Number of XMA blocks in this file (and hence
    178 								// also the number of entries in its seek table)
    179 } XMA2WAVEFORMAT;
    180 
    181 /*
    182 ========================
    183 idWaveFile::ReadWaveFormat
    184 
    185 Reads a wave format header, returns NULL if it found one and read it.
    186 otherwise, returns a human-readable error message.
    187 ========================
    188 */
    189 const char * idWaveFile::ReadWaveFormat( waveFmt_t & format ) {
    190 	memset( &format, 0, sizeof( format ) );
    191 
    192 	uint32 formatSize = SeekToChunk( waveFmt_t::id );
    193 	if ( formatSize == 0 ) {
    194 		return "No format chunk";
    195 	}
    196 	if ( formatSize < sizeof( format.basic ) ) {
    197 		return "Format chunk too small";
    198 	}
    199 
    200 	Read( &format.basic, sizeof( format.basic ) );
    201 
    202 	idSwapClass<waveFmt_t::basic_t> swap;
    203 	swap.Little( format.basic.formatTag );
    204 	swap.Little( format.basic.numChannels );
    205 	swap.Little( format.basic.samplesPerSec );
    206 	swap.Little( format.basic.avgBytesPerSec );
    207 	swap.Little( format.basic.blockSize );
    208 	swap.Little( format.basic.bitsPerSample );
    209 
    210 	if ( format.basic.formatTag == FORMAT_PCM ) {
    211 	} else if ( format.basic.formatTag == FORMAT_ADPCM ) {
    212 		Read( &format.extraSize, sizeof( format.extraSize ) );
    213 		idSwap::Little( format.extraSize );
    214 		if ( format.extraSize != sizeof( waveFmt_t::extra_t::adpcm_t ) ) {
    215 			return "Incorrect number of coefficients in ADPCM file";
    216 		}
    217 		Read( &format.extra.adpcm, sizeof( format.extra.adpcm ) );
    218 		idSwapClass<waveFmt_t::extra_t::adpcm_t> swap;
    219 		swap.Little( format.extra.adpcm.samplesPerBlock );
    220 		swap.Little( format.extra.adpcm.numCoef );
    221 		for ( int i = 0; i < format.extra.adpcm.numCoef; i++ ) {
    222 			swap.Little( format.extra.adpcm.aCoef[ i ].coef1 );
    223 			swap.Little( format.extra.adpcm.aCoef[ i ].coef2 );
    224 		}
    225 	} else if ( format.basic.formatTag == FORMAT_XMA2 ) {
    226 		Read( &format.extraSize, sizeof( format.extraSize ) );
    227 		idSwap::Little( format.extraSize );
    228 		if ( format.extraSize != sizeof( waveFmt_t::extra_t::xma2_t ) ) {
    229 			return "Incorrect chunk size in XMA2 file";
    230 		}
    231 		Read( &format.extra.xma2, sizeof( format.extra.xma2 ) );
    232 		idSwapClass<waveFmt_t::extra_t::xma2_t> swap;
    233 		swap.Little( format.extra.xma2.numStreams );
    234 		swap.Little( format.extra.xma2.channelMask );
    235 		swap.Little( format.extra.xma2.samplesEncoded );
    236 		swap.Little( format.extra.xma2.bytesPerBlock );
    237 		swap.Little( format.extra.xma2.playBegin );
    238 		swap.Little( format.extra.xma2.playLength );
    239 		swap.Little( format.extra.xma2.loopBegin );
    240 		swap.Little( format.extra.xma2.loopLength );
    241 		swap.Little( format.extra.xma2.loopCount );
    242 		swap.Little( format.extra.xma2.encoderVersion );
    243 		swap.Little( format.extra.xma2.blockCount );
    244 	} else if ( format.basic.formatTag == FORMAT_EXTENSIBLE ) {
    245 		Read( &format.extraSize, sizeof( format.extraSize ) );
    246 		idSwap::Little( format.extraSize );
    247 		if ( format.extraSize != sizeof( waveFmt_t::extra_t::extensible_t ) ) {
    248 			return "Incorrect chunk size in extensible wave file";
    249 		}
    250 		Read( &format.extra.extensible, sizeof( format.extra.extensible ) );
    251 		idSwapClass<waveFmt_t::extra_t::extensible_t> swap;
    252 		swap.Little( format.extra.extensible.validBitsPerSample );
    253 		swap.Little( format.extra.extensible.channelMask );
    254 		swap.Little( format.extra.extensible.subFormat.data1 );
    255 		swap.Little( format.extra.extensible.subFormat.data2 );
    256 		swap.Little( format.extra.extensible.subFormat.data3 );
    257 		swap.Little( format.extra.extensible.subFormat.data4 );
    258 		swap.LittleArray( format.extra.extensible.subFormat.data5, 6 );
    259 		waveFmt_t::extra_t::extensible_t::guid_t pcmGuid = {
    260 			FORMAT_PCM,
    261 			0x0000,
    262 			0x0010,
    263 			0x8000,
    264 			{ 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 }
    265 		};
    266 		if ( memcmp( &pcmGuid, &format.extra.extensible.subFormat, sizeof( pcmGuid ) ) != 0 ) {
    267 			return "Unsupported Extensible format";
    268 		}
    269 	} else {
    270 		return "Unknown wave format tag";
    271 	}
    272 
    273 	return NULL;
    274 }
    275 
    276 /*
    277 ========================
    278 idWaveFile::ReadWaveFormatDirect
    279 
    280 Reads a wave format header from a file ptr, 
    281 ========================
    282 */
    283 bool idWaveFile::ReadWaveFormatDirect( waveFmt_t & format, idFile *file ) {
    284 	
    285 	file->Read( &format.basic, sizeof( format.basic ) );
    286 	idSwapClass<waveFmt_t::basic_t> swap;
    287 	swap.Little( format.basic.formatTag );
    288 	swap.Little( format.basic.numChannels );
    289 	swap.Little( format.basic.samplesPerSec );
    290 	swap.Little( format.basic.avgBytesPerSec );
    291 	swap.Little( format.basic.blockSize );
    292 	swap.Little( format.basic.bitsPerSample );
    293 
    294 	if ( format.basic.formatTag == FORMAT_PCM ) {
    295 	} else if ( format.basic.formatTag == FORMAT_ADPCM ) {
    296 		file->Read( &format.extraSize, sizeof( format.extraSize ) );
    297 		idSwap::Little( format.extraSize );
    298 		if ( format.extraSize != sizeof( waveFmt_t::extra_t::adpcm_t ) ) {
    299 			return false;
    300 		}
    301 		file->Read( &format.extra.adpcm, sizeof( format.extra.adpcm ) );
    302 		idSwapClass<waveFmt_t::extra_t::adpcm_t> swap;
    303 		swap.Little( format.extra.adpcm.samplesPerBlock );
    304 		swap.Little( format.extra.adpcm.numCoef );
    305 		for ( int i = 0; i < format.extra.adpcm.numCoef; i++ ) {
    306 			swap.Little( format.extra.adpcm.aCoef[ i ].coef1 );
    307 			swap.Little( format.extra.adpcm.aCoef[ i ].coef2 );
    308 		}
    309 	} else if ( format.basic.formatTag == FORMAT_XMA2 ) {
    310 		file->Read( &format.extraSize, sizeof( format.extraSize ) );
    311 		idSwap::Little( format.extraSize );
    312 		if ( format.extraSize != sizeof( waveFmt_t::extra_t::xma2_t ) ) {
    313 			return false;
    314 		}
    315 		file->Read( &format.extra.xma2, sizeof( format.extra.xma2 ) );
    316 		idSwapClass<waveFmt_t::extra_t::xma2_t> swap;
    317 		swap.Little( format.extra.xma2.numStreams );
    318 		swap.Little( format.extra.xma2.channelMask );
    319 		swap.Little( format.extra.xma2.samplesEncoded );
    320 		swap.Little( format.extra.xma2.bytesPerBlock );
    321 		swap.Little( format.extra.xma2.playBegin );
    322 		swap.Little( format.extra.xma2.playLength );
    323 		swap.Little( format.extra.xma2.loopBegin );
    324 		swap.Little( format.extra.xma2.loopLength );
    325 		swap.Little( format.extra.xma2.loopCount );
    326 		swap.Little( format.extra.xma2.encoderVersion );
    327 		swap.Little( format.extra.xma2.blockCount );
    328 	} else if ( format.basic.formatTag == FORMAT_EXTENSIBLE ) {
    329 		file->Read( &format.extraSize, sizeof( format.extraSize ) );
    330 		idSwap::Little( format.extraSize );
    331 		if ( format.extraSize != sizeof( waveFmt_t::extra_t::extensible_t ) ) {
    332 			return false;
    333 		}
    334 		file->Read( &format.extra.extensible, sizeof( format.extra.extensible ) );
    335 		idSwapClass<waveFmt_t::extra_t::extensible_t> swap;
    336 		swap.Little( format.extra.extensible.validBitsPerSample );
    337 		swap.Little( format.extra.extensible.channelMask );
    338 		swap.Little( format.extra.extensible.subFormat.data1 );
    339 		swap.Little( format.extra.extensible.subFormat.data2 );
    340 		swap.Little( format.extra.extensible.subFormat.data3 );
    341 		swap.Little( format.extra.extensible.subFormat.data4 );
    342 		swap.LittleArray( format.extra.extensible.subFormat.data5, 6 );
    343 		waveFmt_t::extra_t::extensible_t::guid_t pcmGuid = {
    344 			FORMAT_PCM,
    345 			0x0000,
    346 			0x0010,
    347 			0x8000,
    348 			{ 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 }
    349 		};
    350 		if ( memcmp( &pcmGuid, &format.extra.extensible.subFormat, sizeof( pcmGuid ) ) != 0 ) {
    351 			return false;
    352 		}
    353 	} else {
    354 		return false;
    355 	}
    356 
    357 	return true;
    358 }
    359 
    360 /*
    361 ========================
    362 idWaveFile::WriteWaveFormatDirect
    363 
    364 Writes a wave format header to a file ptr, 
    365 ========================
    366 */
    367 bool idWaveFile::WriteWaveFormatDirect( waveFmt_t & format, idFile *file ) {
    368 	//idSwapClass<waveFmt_t::basic_t> swap;
    369 	//swap.Little( format.basic.formatTag );
    370 	//swap.Little( format.basic.numChannels );
    371 	//swap.Little( format.basic.samplesPerSec );
    372 	//swap.Little( format.basic.avgBytesPerSec );
    373 	//swap.Little( format.basic.blockSize );
    374 	//swap.Little( format.basic.bitsPerSample );
    375 	file->Write( &format.basic, sizeof( format.basic ) );
    376 	if ( format.basic.formatTag == FORMAT_PCM ) {
    377 		//file->Write( &format.basic, sizeof( format.basic ) );	
    378 	} else if ( format.basic.formatTag == FORMAT_ADPCM ) {
    379 		//file->Write( &format.basic, sizeof( format.basic ) );
    380 		file->Write( &format.extraSize, sizeof( format.extraSize ) );
    381 		file->Write( &format.extra.adpcm, sizeof( format.extra.adpcm ) );
    382 	} else if ( format.basic.formatTag == FORMAT_XMA2 ) {
    383 		//file->Write( &format.basic, sizeof( format.basic ) );
    384 		file->Write( &format.extraSize, sizeof( format.extraSize ) );
    385 		file->Write( &format.extra.xma2, sizeof( format.extra.xma2 ) );
    386 	} else if ( format.basic.formatTag == FORMAT_EXTENSIBLE ) {
    387 		//file->Write( &format.basic, sizeof( format.basic ) );
    388 		file->Write( &format.extraSize, sizeof( format.extraSize ) );
    389 		file->Write( &format.extra.extensible, sizeof( format.extra.extensible ) );
    390 	} else {
    391 		return false;
    392 	}
    393 	return true;
    394 }
    395 
    396 /*
    397 ========================
    398 idWaveFile::WriteWaveFormatDirect
    399 
    400 Writes a wave format header to a file ptr, 
    401 ========================
    402 */
    403 
    404 bool idWaveFile::WriteSampleDataDirect( idList< sampleData_t > & sampleData, idFile * file ) {
    405 	static const uint32 sample = 'smpl';
    406 	file->WriteBig( sample );
    407 	uint32 samplerData = sampleData.Num() * 24;
    408 	uint32 chunkSize = 36 + samplerData;
    409 	uint32 zero = 0;
    410 	uint32 numSamples = sampleData.Num();
    411 
    412 	file->Write( &chunkSize, sizeof( uint32 ) );
    413 	file->Write( &zero, sizeof( uint32 ) );
    414 	file->Write( &zero, sizeof( uint32 ) );
    415 	file->Write( &zero, sizeof( uint32 ) );
    416 	file->Write( &zero, sizeof( uint32 ) );
    417 	file->Write( &zero, sizeof( uint32 ) );
    418 	file->Write( &zero, sizeof( uint32 ) );
    419 	file->Write( &zero, sizeof( uint32 ) );
    420 	file->Write( &numSamples, sizeof( uint32 ) );
    421 	file->Write( &samplerData, sizeof( uint32 ) );
    422 
    423 	for ( int i = 0; i < sampleData.Num(); ++i ) {
    424 		file->Write( &zero, sizeof( uint32 ) );
    425 		file->Write( &zero, sizeof( uint32 ) );
    426 		file->Write( &sampleData[ i ].start, sizeof( uint32 ) );
    427 		file->Write( &sampleData[ i ].end, sizeof( uint32 ) );
    428 		file->Write( &zero, sizeof( uint32 ) );
    429 		file->Write( &zero, sizeof( uint32 ) );
    430 	}
    431 	return true;
    432 }
    433 
    434 /*
    435 ========================
    436 idWaveFile::WriteWaveFormatDirect
    437 
    438 Writes a data chunk to a file ptr
    439 ========================
    440 */
    441 
    442 bool idWaveFile::WriteDataDirect( char * _data, uint32 size, idFile * file ) {
    443 	static const uint32 data = 'data';
    444 	file->WriteBig( data );
    445 	file->Write( &size, sizeof( uint32 ) );
    446 	file->WriteBigArray( _data, size );
    447 	return true;
    448 }
    449 
    450 /*
    451 ========================
    452 idWaveFile::WriteWaveFormatDirect
    453 
    454 Writes a wave header to a file ptr, 
    455 ========================
    456 */
    457 
    458 bool idWaveFile::WriteHeaderDirect( uint32 fileSize, idFile * file ) {
    459 	static const uint32 riff = 'RIFF';
    460 	static const uint32 wave = 'WAVE';
    461 	file->WriteBig( riff );
    462 	file->WriteBig( fileSize );
    463 	file->WriteBig( wave );
    464 	return true;
    465 }
    466 
    467 /*
    468 ========================
    469 idWaveFile::ReadLoopPoint
    470 
    471 Reads a loop point from a 'smpl' chunk in a wave file, returns 0 if none are found.
    472 ========================
    473 */
    474 bool idWaveFile::ReadLoopData( int & start, int & end ) {
    475 	uint32 chunkSize = SeekToChunk( samplerChunk_t::id );
    476 	if ( chunkSize < sizeof( samplerChunk_t ) ) {
    477 		return false;
    478 	}
    479 
    480 	samplerChunk_t smpl;
    481 	Read( &smpl, sizeof( smpl ) );
    482 	idSwap::Little( smpl.numSampleLoops );
    483 
    484 	if ( smpl.numSampleLoops < 1 ) {
    485 		return false; // this is possible returning false lets us know there are more then 1 sample look in the file and is not appropriate for traditional looping
    486 	}
    487 
    488 	sampleData_t smplData;
    489 	Read( &smplData, sizeof( smplData ) );
    490 	idSwap::Little( smplData.start );
    491 	idSwap::Little( smplData.end );
    492 
    493 	if ( smplData.type != 0 ) {
    494 		idLib::Warning( "Invalid loop type in %s", file->GetName() );
    495 		return false;
    496 	}
    497 
    498 	start = smplData.start;
    499 	end = smplData.end;
    500 	return true;
    501 }
    502 
    503 /*
    504 ========================
    505 idWaveFile::Close
    506 
    507 Closes the file and frees resources.
    508 ========================
    509 */
    510 void idWaveFile::Close() { 
    511 	if ( file != NULL ) {
    512 		delete file;
    513 		file = NULL;
    514 	}
    515 	chunks.SetNum( 0 );
    516 }