123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346 |
- /* Copyright (c) 2002-2012 Croteam Ltd.
- This program is free software; you can redistribute it and/or modify
- it under the terms of version 2 of the GNU General Public License as published by
- the Free Software Foundation
- This program 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 this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
- #include "stdh.h"
- #include <Engine/Base/Stream.h>
- #include <Engine/Base/ErrorReporting.h>
- #include <Engine/Sound/Wave.h>
- /* ====================================================
- *
- * CONVERSION FUNCTIONS
- *
- */
- // check wave format
- void PCMWaveInput::CheckWaveFormat_t(WAVEFORMATEX wfeCheck, char *pcErrorString)
- {
- // check format tag
- if (wfeCheck.wFormatTag != 1) {
- ThrowF_t(TRANS("%s: Invalid format tag, not a PCM Wave file!"), pcErrorString);
- }
- // check bits per sample
- if (wfeCheck.wBitsPerSample != 8 &&
- wfeCheck.wBitsPerSample != 16) {
- ThrowF_t(TRANS("%s: Unknown Bits Per Sample value!"), pcErrorString);
- }
- // check number of channels
- if (wfeCheck.nChannels != 1 &&
- wfeCheck.nChannels != 2) {
- ThrowF_t(TRANS("%s: Invalid number of channels!"), pcErrorString);
- }
- //ASSERT( wfeCheck.wBitsPerSample==16);
- }
- // Get next data
- inline ULONG PCMWaveInput::GetData_t(CTStream *pCstrInput)
- {
- ASSERT(pwi_bInfoLoaded);
- // read data according to bits per sample value
- if (pwi_wfeWave.wBitsPerSample==8) {
- // read UBYTE
- UBYTE ubData;
- *pCstrInput >> ubData;
- return ((ULONG)ubData) <<16; // (shift) prepare data for shrink/expand operation
- } else {
- // read UWORD
- SWORD swData;
- *pCstrInput >> swData;
- return ((ULONG)(swData+0x8000)) <<8; // (shift) prepare data for shrink/expand operation
- }
- }
- // Store data
- inline void PCMWaveInput::StoreData(ULONG ulData)
- {
- ASSERT( pwi_wfeDesired.wBitsPerSample==16);
- *pwi_pswMemory++ = ((SWORD)(ulData>>8) -0x8000); // (shift) restore data format
- }
- /*
- * Copy data
- */
- void PCMWaveInput::CopyData_t(CTStream *pCstrInput)
- {
- // for all input data (mono and stereo)
- ULONG ulDataCount = GetDataLength() * pwi_wfeWave.nChannels;
- while (ulDataCount > 0) {
- StoreData(GetData_t(pCstrInput)); // read and store data from input (hidden BitsPerSample conversion!)
- ulDataCount--; // to next data
- }
- }
- /*
- * Shrink data
- */
- // Shrink data
- void PCMWaveInput::ShrinkData_t(CTStream *pCstrInput)
- {
- ASSERT(pwi_dRatio>1.0);
- // *** MONO ***
- if (pwi_wfeWave.nChannels == 1) {
- DOUBLE dInterData, dTempData, dRatio;
- ULONG ulDataCount;
- // data intermediate value
- dInterData = 0.0;
- // for all input data (mono)
- ulDataCount = GetDataLength();
- dRatio = pwi_dRatio;
- while (ulDataCount > 0) {
- // read part of data (<100%)
- if (dRatio<1.0) {
- dTempData = GetData_t(pCstrInput);
- dInterData += dTempData*dRatio;
- StoreData(ULONG(dInterData/pwi_dRatio));
- // new intermediate value
- dRatio = 1 - dRatio;
- dInterData = dTempData*dRatio;
- dRatio = pwi_dRatio - dRatio;
- // read complete data (100%)
- } else {
- dInterData += GetData_t(pCstrInput);
- dRatio -= 1.0;
- }
- ulDataCount--; // to next data
- }
- StoreData(ULONG(dInterData/(pwi_dRatio-dRatio)));
- // *** STEREO ***
- } else if (pwi_wfeWave.nChannels == 2) {
- DOUBLE dLInterData, dRInterData, dLTempData, dRTempData, dRatio;
- ULONG ulDataCount;
- // data intermediate value
- dLInterData = 0.0;
- dRInterData = 0.0;
- // for all input data (mono)
- ulDataCount = GetDataLength();
- dRatio = pwi_dRatio;
- while (ulDataCount > 0) {
- // read part of data (<100%)
- if (dRatio<1.0) {
- dLTempData = GetData_t(pCstrInput);
- dRTempData = GetData_t(pCstrInput);
- dLInterData += dLTempData*dRatio;
- dRInterData += dRTempData*dRatio;
- StoreData(ULONG(dLInterData/pwi_dRatio));
- StoreData(ULONG(dRInterData/pwi_dRatio));
- // new intermediate value
- dRatio = 1 - dRatio;
- dLInterData = dLTempData*dRatio;
- dRInterData = dRTempData*dRatio;
- dRatio = pwi_dRatio - dRatio;
- // read complete data (100%)
- } else {
- dLInterData += GetData_t(pCstrInput);
- dRInterData += GetData_t(pCstrInput);
- dRatio -= 1.0;
- }
- ulDataCount--; // to next data
- }
- StoreData(ULONG(dLInterData/(pwi_dRatio-dRatio)));
- StoreData(ULONG(dRInterData/(pwi_dRatio-dRatio)));
- }
- }
- /* ====================================================
- *
- * WAVE FUNCTIONS
- *
- */
- /*
- * Load Wave info
- */
- WAVEFORMATEX PCMWaveInput::LoadInfo_t(CTStream *pCstrInput)
- {
- // if already loaded -> exception
- if (pwi_bInfoLoaded) {
- throw (TRANS("PCM Wave Input: Info already loaded."));
- }
- /* Read Riff */
- pCstrInput->ExpectID_t(CChunkID("RIFF")); // ID "RIFF"
- (*pCstrInput) >> pwi_ulRiffLength; // Ucitaj duljinu file-a
- /* Read Wave */
- pCstrInput->ExpectID_t(CChunkID("WAVE")); // ID "WAVE"
- pCstrInput->ExpectID_t(CChunkID("fmt ")); // ID "fmt "
- // read Format Chunk length
- SLONG slFmtLength;
- (*pCstrInput) >> slFmtLength;
- // read WAVE format
- (*pCstrInput) >> pwi_wfeWave.wFormatTag;
- (*pCstrInput) >> pwi_wfeWave.nChannels;
- (*pCstrInput) >> pwi_wfeWave.nSamplesPerSec;
- (*pCstrInput) >> pwi_wfeWave.nAvgBytesPerSec;
- (*pCstrInput) >> pwi_wfeWave.nBlockAlign;
- (*pCstrInput) >> pwi_wfeWave.wBitsPerSample;
- pwi_wfeWave.cbSize = 0; // Only for PCM Wave !!!
- // WARNING !!! - Only for PCM Wave - Skip extra information if exists
- if( slFmtLength > 16) {
- //WarningMessage("PCM Wave Input: Wave format Extra information skipped!");
- pCstrInput->Seek_t(slFmtLength - 16, CTStream::SD_CUR);
- }
- // WARNING - If exist Fact chunk skip it (purpose unknown)
- if( pCstrInput->GetID_t() == CChunkID("fact")) {
- //WarningMessage("PCM Wave Input: Fact Chunk skipped!");
- SLONG slSkipLength;
- (*pCstrInput) >> slSkipLength;
- pCstrInput->Seek_t(slSkipLength, CTStream::SD_CUR);
- // seek back on Chunk ID
- } else {
- pCstrInput->Seek_t(-CID_LENGTH, CTStream::SD_CUR);
- }
- /* Read Data */
- pCstrInput->ExpectID_t(CChunkID("data")); // ID "data"
- // read Data length (in bytes)
- (*pCstrInput) >> pwi_ulDataLength;
- /* Check PCM format */
- CheckWaveFormat_t(pwi_wfeWave, "PCM Wave Input (input)");
- // mark Info loaded
- pwi_bInfoLoaded = TRUE;
- // ASSERT( pwi_wfeWave.wBitsPerSample==16);
- // return Wave Format
- return pwi_wfeWave;
- }
- /*
- * Load and convert Wave data
- */
- void PCMWaveInput::LoadData_t(CTStream *pCstrInput, SWORD *pswMemory, WAVEFORMATEX &SwfeDesired)
- {
- // if info not loaded -> exception
- if (!pwi_bInfoLoaded) {
- throw (TRANS("PCM Wave Input: Info not loaded."));
- }
- // if already loaded -> exception
- if (pwi_bDataLoaded) {
- throw (TRANS("PCM Wave Input: Data already loaded"));
- }
- // set memory pointer
- pwi_pswMemory = pswMemory;
- // store and check desired sound format
- CheckWaveFormat_t(SwfeDesired, "PCM Wave Input (desired)");
- pwi_wfeDesired = SwfeDesired;
- // calculate expand/shrink ratio (number of channels remain the same)
- pwi_dRatio = (DOUBLE)pwi_wfeDesired.nSamplesPerSec / (DOUBLE)pwi_wfeWave.nSamplesPerSec;
- // determine converion type from input and desired sound frequency, and convert sound
- if (pwi_dRatio < 1) {
- pwi_dRatio = 1/pwi_dRatio;
- ShrinkData_t(pCstrInput);
- } else if (pwi_dRatio > 1) {
- ASSERTALWAYS("Can't expand wave data");
- memset(pwi_pswMemory, 0, DetermineBufferSize(pwi_wfeDesired));
- // copy data
- } else {
- ASSERT(pwi_dRatio==1.0f);
- CopyData_t(pCstrInput);
- }
- // data is loaded (and maybe converted from 16-bits)
- if( pwi_wfeWave.wBitsPerSample==8) SwfeDesired.nBlockAlign *= 2;
- pwi_bDataLoaded = TRUE;
- }
- /*
- * Length in bytes
- */
- ULONG PCMWaveInput::GetByteLength(void)
- {
- ASSERT(pwi_bInfoLoaded);
- return pwi_ulDataLength;
- }
- /*
- * Length in blocks
- */
- ULONG PCMWaveInput::GetDataLength(void)
- {
- ASSERT(pwi_bInfoLoaded);
- return GetByteLength() / (pwi_wfeWave.nChannels * pwi_wfeWave.wBitsPerSample/8);
- }
- ULONG PCMWaveInput::GetDataLength(WAVEFORMATEX SwfeDesired)
- {
- ASSERT(pwi_bInfoLoaded);
- // return buffer size
- return DetermineBufferSize(SwfeDesired) / (SwfeDesired.nChannels * SwfeDesired.wBitsPerSample/8);
- }
- /*
- * Length in seconds
- */
- DOUBLE PCMWaveInput::GetSecondsLength(void)
- {
- ASSERT(pwi_bInfoLoaded);
- return (DOUBLE)GetDataLength() / (DOUBLE)pwi_wfeWave.nSamplesPerSec;
- }
- /*
- * Buffer length in bytes
- */
- ULONG PCMWaveInput::DetermineBufferSize(void)
- {
- return DetermineBufferSize(pwi_wfeWave);
- }
- ULONG PCMWaveInput::DetermineBufferSize( WAVEFORMATEX SwfeDesired)
- {
- ASSERT(pwi_bInfoLoaded);
- DOUBLE dRatio;
- // calculate ratio between formats
- dRatio = (DOUBLE)SwfeDesired.nSamplesPerSec / (DOUBLE)pwi_wfeWave.nSamplesPerSec
- * (DOUBLE)SwfeDesired.wBitsPerSample / (DOUBLE)pwi_wfeWave.wBitsPerSample;
- // return buffer size (must calculate with data length to avoid miss align data, for example:
- // 16 bit sound with 2 channels must be aligned to 4 bytes boundary and a multiply with
- // random ratio can as result give any possible number
- DOUBLE ret = ceil(dRatio*GetDataLength()) * (pwi_wfeWave.nChannels*(pwi_wfeWave.wBitsPerSample/8));
- return (ULONG)ret;
- }
|