RiffFile RiffFile::Create(const wstring& filePath) { unsigned int dataSize, fileType; const auto riffData = Tools::ReadFileToVector(filePath); #if DEBUG unsigned int bufferPosition = 0; auto fileFourCC = Tools::BufferReader::ReadUInt(riffData, bufferPosition); Assert(fileFourCC = RiffFourCC::RIFF); #else unsigned int bufferPosition = 4; #endif dataSize = Tools::BufferReader::ReadUInt(riffData, bufferPosition); fileType = Tools::BufferReader::ReadUInt(riffData, bufferPosition); RiffFile riff(fileType); while (bufferPosition < dataSize + 8) { auto chunkFourCC = Tools::BufferReader::ReadUInt(riffData, bufferPosition); //Assert(chunkFourCC != RiffFourCC::LIST); // Lists currently not supported auto chunkSize = Tools::BufferReader::ReadUInt(riffData, bufferPosition); riff.AddChunk(chunkFourCC, chunkSize, &riffData[bufferPosition]); bufferPosition += chunkSize + (chunkSize % 2); } return riff; }
bool CSoundCombiner::LoadSentenceFromWavFileUsingIO( char const *wavfile, CSentence& sentence, IFileReadBinary& io ) { sentence.Reset(); InFileRIFF riff( wavfile, io ); // UNDONE: Don't use printf to handle errors if ( riff.RIFFName() != RIFF_WAVE ) { return false; } // set up the iterator for the whole file (root RIFF is a chunk) IterateRIFF walk( riff, riff.RIFFSize() ); // This chunk must be first as it contains the wave's format // break out when we've parsed it bool found = false; while ( walk.ChunkAvailable() && !found ) { switch( walk.ChunkName() ) { case WAVE_VALVEDATA: { found = true; CSoundCombiner::ParseSentence( sentence, walk ); } break; } walk.ChunkNext(); } return true; }
//----------------------------------------------------------------------------- // Purpose: Create a wave audio source (streaming or in memory) // Input : *pName - file name // streaming - if true, don't load, stream each instance // Output : CAudioSource * - a new source //----------------------------------------------------------------------------- // UNDONE : Pool these and check for duplicates? CAudioSource *CreateWave( const char *pName ) { char formatBuffer[1024]; InFileRIFF riff( pName, io ); // UNDONE: Don't use printf to handle errors if ( riff.RIFFName() != RIFF_WAVE ) { printf("Bad RIFF file type %s\n", pName ); return NULL; } // set up the iterator for the whole file (root RIFF is a chunk) IterateRIFF walk( riff, riff.RIFFSize() ); int format = 0; int formatSize = 0; // This chunk must be first as it contains the wave's format // break out when we've parsed it while ( walk.ChunkAvailable() && format == 0 ) { switch( walk.ChunkName() ) { case WAVE_FMT: { if ( walk.ChunkSize() <= 1024 ) { walk.ChunkRead( formatBuffer ); formatSize = walk.ChunkSize(); format = ((WAVEFORMATEX *)formatBuffer)->wFormatTag; } } break; default: { ChunkError( walk.ChunkName() ); } break; } walk.ChunkNext(); } // Not really a WAVE file or no format chunk, bail if ( !format ) return NULL; CAudioSourceWave *pWave; // create the source from this file pWave = new CAudioSourceMemWave(); // init the wave source pWave->Setup( formatBuffer, formatSize, walk ); return pWave; }
//----------------------------------------------------------------------------- // xZipComputeWAVPreload // // Returns the number of bytes from a xbox compliant WAV file that should go into // the preload section: //----------------------------------------------------------------------------- unsigned xZipComputeWAVPreload( char *pFileName ) { InFileRIFF riff( pFileName, *g_pSndIO ); if ( riff.RIFFName() != RIFF_WAVE ) { return 0; } IterateRIFF walk( riff, riff.RIFFSize() ); while ( walk.ChunkAvailable() ) { // xbox compliant wavs have a single PADD chunk if ( walk.ChunkName() == PADD_ID ) { // want to preload data up through PADD chunk header // and not the actual pad bytes return walk.ChunkFilePosition() + 2*sizeof( int ); } walk.ChunkNext(); } return 0; }
//----------------------------------------------------------------------------- // Returns the duration of a wav file //----------------------------------------------------------------------------- float GetWavSoundDuration( const char *pWavFile ) { InFileRIFF riff( pWavFile, *g_pFSIOReadBinary ); // UNDONE: Don't use printf to handle errors if ( riff.RIFFName() != RIFF_WAVE ) return 0.0f; int nDataSize = 0; // set up the iterator for the whole file (root RIFF is a chunk) IterateRIFF walk( riff, riff.RIFFSize() ); // This chunk must be first as it contains the wave's format // break out when we've parsed it char pFormatBuffer[ 1024 ]; int nFormatSize; bool bFound = false; for ( ; walk.ChunkAvailable( ); walk.ChunkNext() ) { switch ( walk.ChunkName() ) { case WAVE_FMT: bFound = true; if ( walk.ChunkSize() > sizeof(pFormatBuffer) ) { Warning( "oops, format tag too big!!!" ); return 0.0f; } nFormatSize = walk.ChunkSize(); walk.ChunkRead( pFormatBuffer ); break; case WAVE_DATA: nDataSize += walk.ChunkSize(); break; } } if ( !bFound ) return 0.0f; const WAVEFORMATEX *pHeader = (const WAVEFORMATEX *)pFormatBuffer; int format = pHeader->wFormatTag; int nBits = pHeader->wBitsPerSample; int nRate = pHeader->nSamplesPerSec; int nChannels = pHeader->nChannels; int nSampleSize = ( nBits * nChannels ) / 8; // this can never be zero -- other functions divide by this. // This should never happen, but avoid crashing if ( nSampleSize <= 0 ) { nSampleSize = 1; } int nSampleCount = 0; float flTrueSampleSize = nSampleSize; if ( format == WAVE_FORMAT_ADPCM ) { nSampleSize = 1; ADPCMWAVEFORMAT *pFormat = (ADPCMWAVEFORMAT *)pFormatBuffer; int blockSize = ((pFormat->wSamplesPerBlock - 2) * pFormat->wfx.nChannels ) / 2; blockSize += 7 * pFormat->wfx.nChannels; int blockCount = nSampleCount / blockSize; int blockRem = nSampleCount % blockSize; // total samples in complete blocks nSampleCount = blockCount * pFormat->wSamplesPerBlock; // add remaining in a short block if ( blockRem ) { nSampleCount += pFormat->wSamplesPerBlock - (((blockSize - blockRem) * 2) / nChannels); } flTrueSampleSize = 0.5f; } else { nSampleCount = nDataSize / nSampleSize; } float flDuration = (float)nSampleCount / (float)nRate; return flDuration; }