diff --git a/src/engine/audio/Audio_WavFile.cpp b/src/engine/audio/Audio_WavFile.cpp index 9991aaaa..c9e3a923 100644 --- a/src/engine/audio/Audio_WavFile.cpp +++ b/src/engine/audio/Audio_WavFile.cpp @@ -19,13 +19,13 @@ #endif typedef struct { - WORD wFormatTag; - WORD nChannels; - DWORD nSamplesPerSec; - DWORD nAvgBytesPerSec; - WORD nBlockAlign; - WORD wBitsPerSample; - WORD cbSize; + WORD wFormatTag; + WORD nChannels; + DWORD nSamplesPerSec; + DWORD nAvgBytesPerSec; + WORD nBlockAlign; + WORD wBitsPerSample; + WORD cbSize; } WaveFormatEx; @@ -39,9 +39,9 @@ using namespace Audio; // ---------------------- WavFileReader ------------------------- WavFileReader::WavFileReader() -:mHandle(nullptr), mRate(0), mLastError(0) + :mHandle(nullptr), mSamplerate(0), mLastError(0) { - mDataOffset = 0; + mDataOffset = 0; } WavFileReader::~WavFileReader() @@ -52,207 +52,221 @@ WavFileReader::~WavFileReader() std::string WavFileReader::readChunk() { - char name[5]; - if (fread(name, 1, 4, mHandle) != 4) - THROW_READERROR; + char name[5]; + if (fread(name, 1, 4, mHandle) != 4) + THROW_READERROR; - name[4] = 0; - std::string result = name; - unsigned size; - if (fread(&size, 4, 1, mHandle) != 1) - THROW_READERROR; + name[4] = 0; + std::string result = name; + unsigned size; + if (fread(&size, 4, 1, mHandle) != 1) + THROW_READERROR; - if (result == "fact") - fread(&mDataLength, 4, 1, mHandle); - else - if (result != "data") - fseek(mHandle, size, SEEK_CUR); - else - mDataLength = size; - - return result; + if (result == "fact") + fread(&mDataLength, 4, 1, mHandle); + else + if (result != "data") + fseek(mHandle, size, SEEK_CUR); + else + mDataLength = size; + + return result; } bool WavFileReader::open(const std::tstring& filename) { - LOCK; - try - { - #ifdef WIN32 - mHandle = _wfopen(filename.c_str(), L"rb"); - #else - mHandle = fopen(strx::makeUtf8(filename).c_str(), "rb"); - #endif - if (NULL == mHandle) + LOCK; + try { +#ifdef WIN32 + mHandle = _wfopen(filename.c_str(), L"rb"); +#else + mHandle = fopen(strx::makeUtf8(filename).c_str(), "rb"); +#endif + if (NULL == mHandle) + { #if defined(TARGET_ANDROID) || defined(TARGET_LINUX) || defined(TARGET_OSX) - mLastError = errno; + mLastError = errno; #endif #if defined(TARGET_WIN) - mLastError = GetLastError(); + mLastError = GetLastError(); #endif - return false; + return false; + } + mLastError = 0; + + // Read the .WAV header + char riff[4]; + if (fread(riff, 4, 1, mHandle) < 1) + THROW_READERROR; + + if (!(riff[0] == 'R' && riff[1] == 'I' && riff[2] == 'F' && riff[3] == 'F')) + THROW_READERROR; + + // Read the file size + unsigned int filesize = 0; + if (fread(&filesize, 4, 1, mHandle) < 1) + THROW_READERROR; + + char wavefmt[9]; + if (fread(wavefmt, 8, 1, mHandle) < 1) + THROW_READERROR; + + wavefmt[8] = 0; + if (strcmp(wavefmt, "WAVEfmt ") != 0) + THROW_READERROR; + + unsigned fmtSize = 0; + if (fread(&fmtSize, 4, 1, mHandle) < 1) + THROW_READERROR; + + unsigned fmtStart = ftell(mHandle); + + unsigned short formattag = 0; + if (fread(&formattag, 2, 1, mHandle) < 1) + THROW_READERROR; + + if (formattag != 1/*WAVE_FORMAT_PCM*/) + THROW_READERROR; + + mChannels = 0; + if (fread(&mChannels, 2, 1, mHandle) < 1) + THROW_READERROR; + + mSamplerate = 0; + if (fread(&mSamplerate, 4, 1, mHandle) < 1) + THROW_READERROR; + + unsigned int avgbytespersec = 0; + if (fread(&avgbytespersec, 4, 1, mHandle) < 1) + THROW_READERROR; + + unsigned short blockalign = 0; + if (fread(&blockalign, 2, 1, mHandle) < 1) + THROW_READERROR; + + mBits = 0; + if (fread(&mBits, 2, 1, mHandle) < 1) + THROW_READERROR; + + if (mBits !=8 && mBits != 16) + THROW_READERROR; + + // Read the "chunk" + fseek(mHandle, fmtStart + fmtSize, SEEK_SET); + //unsigned pos = ftell(mHandle); + mDataLength = 0; + while (readChunk() != "data") + ; + + mFileName = filename; + mDataOffset = ftell(mHandle); + + mResampler.start(AUDIO_CHANNELS, mSamplerate, AUDIO_SAMPLERATE); } - mLastError = 0; - - // Read the .WAV header - char riff[4]; - if (fread(riff, 4, 1, mHandle) < 1) - THROW_READERROR; - - if (!(riff[0] == 'R' && riff[1] == 'I' && riff[2] == 'F' && riff[3] == 'F')) - THROW_READERROR; - - // Read the file size - unsigned int filesize = 0; - if (fread(&filesize, 4, 1, mHandle) < 1) - THROW_READERROR; - - char wavefmt[9]; - if (fread(wavefmt, 8, 1, mHandle) < 1) - THROW_READERROR; - - wavefmt[8] = 0; - if (strcmp(wavefmt, "WAVEfmt ") != 0) - THROW_READERROR; - - unsigned fmtSize = 0; - if (fread(&fmtSize, 4, 1, mHandle) < 1) - THROW_READERROR; - - unsigned fmtStart = ftell(mHandle); - - unsigned short formattag = 0; - if (fread(&formattag, 2, 1, mHandle) < 1) - THROW_READERROR; - - if (formattag != 1/*WAVE_FORMAT_PCM*/) - THROW_READERROR; - - mChannels = 0; - if (fread(&mChannels, 2, 1, mHandle) < 1) - THROW_READERROR; - - mRate = 0; - if (fread(&mRate, 4, 1, mHandle) < 1) - THROW_READERROR; - - unsigned int avgbytespersec = 0; - if (fread(&avgbytespersec, 4, 1, mHandle) < 1) - THROW_READERROR; - - unsigned short blockalign = 0; - if (fread(&blockalign, 2, 1, mHandle) < 1) - THROW_READERROR; - - mBits = 0; - if (fread(&mBits, 2, 1, mHandle) < 1) - THROW_READERROR; - - if (mBits !=8 && mBits != 16) - THROW_READERROR; - - // Read the "chunk" - fseek(mHandle, fmtStart + fmtSize, SEEK_SET); - //unsigned pos = ftell(mHandle); - mDataLength = 0; - while (readChunk() != "data") - ; - - mFileName = filename; - mDataOffset = ftell(mHandle); - - mResampler.start(AUDIO_CHANNELS, mRate, AUDIO_SAMPLERATE); - } - catch(...) - { - fclose(mHandle); mHandle = nullptr; - mLastError = static_cast(-1); - } - return isOpened(); + catch(...) + { + fclose(mHandle); mHandle = nullptr; + mLastError = static_cast(-1); + } + return isOpened(); } void WavFileReader::close() { - LOCK; + LOCK; - if (nullptr != mHandle) - fclose(mHandle); - mHandle = nullptr; + if (nullptr != mHandle) + fclose(mHandle); + mHandle = nullptr; } -int WavFileReader::rate() const +int WavFileReader::samplerate() const { - return mRate; + return mSamplerate; } -unsigned WavFileReader::read(void* buffer, unsigned bytes) +int WavFileReader::channels() const { - return read((short*)buffer, bytes / (AUDIO_CHANNELS * 2)) * AUDIO_CHANNELS * 2; + return mChannels; } -unsigned WavFileReader::read(short* buffer, unsigned samples) +unsigned WavFileReader::read(void* buffer, unsigned bytes, bool resample) { - LOCK; + if (resample) + return read((short*)buffer, bytes / (AUDIO_CHANNELS * 2), true) * AUDIO_CHANNELS * 2; + else + return read((short*)buffer, bytes / channels() / sizeof(short), false) * channels() * sizeof(short); +} - if (!mHandle) - return 0; +unsigned WavFileReader::read(short* buffer, unsigned samples, bool resample) +{ + LOCK; - // Get number of samples that must be read from source file - int requiredBytes = mResampler.getSourceLength(samples) * mChannels * mBits / 8; - void* temp = alloca(requiredBytes); - memset(temp, 0, requiredBytes); + if (!mHandle) + return 0; - // Find required size of input buffer - if (mDataLength) - { - unsigned filePosition = ftell(mHandle); - // Check how much data we can read - unsigned fileAvailable = mDataLength + mDataOffset - filePosition; - requiredBytes = (int)fileAvailable < requiredBytes ? (int)fileAvailable : requiredBytes; - } + // Get number of samples that must be read from source file + int requiredBytes = resample ? mResampler.getSourceLength(samples) * mChannels * mBits / 8 : samples * mChannels * sizeof(short); + void* temp = alloca(requiredBytes); + memset(temp, 0, requiredBytes); - /*int readSamples = */fread(temp, 1, requiredBytes, mHandle);// / mChannels / (mBits / 8); - size_t processedBytes = 0; - size_t result = mResampler.processBuffer(temp, requiredBytes, processedBytes, - buffer, samples * 2 * AUDIO_CHANNELS); + // Find required size of input buffer + if (mDataLength) + { + unsigned filePosition = ftell(mHandle); - return result / 2 / AUDIO_CHANNELS; + // Check how much data we can read + unsigned fileAvailable = mDataLength + mDataOffset - filePosition; + requiredBytes = (int)fileAvailable < requiredBytes ? (int)fileAvailable : requiredBytes; + } + + /*int readSamples = */fread(temp, 1, requiredBytes, mHandle);// / mChannels / (mBits / 8); + if (resample) + { + size_t processedBytes = 0; + size_t result = mResampler.processBuffer(temp, requiredBytes, processedBytes, + buffer, samples * 2 * AUDIO_CHANNELS); + + return result / 2 / AUDIO_CHANNELS; + } + else + return requiredBytes / channels() / sizeof(short); } bool WavFileReader::isOpened() { - LOCK; + LOCK; - return (mHandle != 0); + return (mHandle != 0); } void WavFileReader::rewind() { - LOCK; - - if (mHandle) - fseek(mHandle, mDataOffset, SEEK_SET); + LOCK; + + if (mHandle) + fseek(mHandle, mDataOffset, SEEK_SET); } std::tstring WavFileReader::filename() const { - LOCK; + LOCK; - return mFileName; + return mFileName; } unsigned WavFileReader::size() const { - LOCK; + LOCK; - return mDataLength; + return mDataLength; } unsigned WavFileReader::lastError() const { - return mLastError; + return mLastError; } // ------------------------- WavFileWriter ------------------------- #define LOG_SUBSYTEM "WavFileWriter" @@ -260,135 +274,135 @@ unsigned WavFileReader::lastError() const #define BITS_PER_CHANNEL 16 WavFileWriter::WavFileWriter() -:mHandle(nullptr), mLengthOffset(0), mRate(AUDIO_SAMPLERATE), mChannels(1), mWritten(0) + :mHandle(nullptr), mLengthOffset(0), mRate(AUDIO_SAMPLERATE), mChannels(1), mWritten(0) { } WavFileWriter::~WavFileWriter() { - close(); + close(); } void WavFileWriter::checkWriteResult(int result) { - if (result < 1) - throw Exception(ERR_WAVFILE_FAILED, errno); + if (result < 1) + throw Exception(ERR_WAVFILE_FAILED, errno); } bool WavFileWriter::open(const std::tstring& filename, int rate, int channels) { - LOCK; + LOCK; - close(); - - mRate = rate; - mChannels = channels; + close(); + + mRate = rate; + mChannels = channels; #ifdef WIN32 - mHandle = _wfopen(filename.c_str(), L"wb"); + mHandle = _wfopen(filename.c_str(), L"wb"); #else - mHandle = fopen(strx::makeUtf8(filename).c_str(), "wb"); + mHandle = fopen(strx::makeUtf8(filename).c_str(), "wb"); #endif - if (nullptr == mHandle) - { - ICELogError(<< "Failed to create .wav file: filename = " << strx::makeUtf8(filename) << " , error = " << errno); - return false; - } + if (nullptr == mHandle) + { + ICELogError(<< "Failed to create .wav file: filename = " << strx::makeUtf8(filename) << " , error = " << errno); + return false; + } - // Write the .WAV header - const char* riff = "RIFF"; - checkWriteResult( fwrite(riff, 4, 1, mHandle) ); - - // Write the file size - unsigned int filesize = 0; - checkWriteResult( fwrite(&filesize, 4, 1, mHandle) ); + // Write the .WAV header + const char* riff = "RIFF"; + checkWriteResult( fwrite(riff, 4, 1, mHandle) ); - const char* wavefmt = "WAVEfmt "; - checkWriteResult( fwrite(wavefmt, 8, 1, mHandle) ); + // Write the file size + unsigned int filesize = 0; + checkWriteResult( fwrite(&filesize, 4, 1, mHandle) ); - // Set the format description - DWORD dwFmtSize = 16; /*= 16L*/; - checkWriteResult( fwrite(&dwFmtSize, sizeof(dwFmtSize), 1, mHandle) ); + const char* wavefmt = "WAVEfmt "; + checkWriteResult( fwrite(wavefmt, 8, 1, mHandle) ); - WaveFormatEx format; - format.wFormatTag = WAVE_FORMAT_PCM; - checkWriteResult( fwrite(&format.wFormatTag, sizeof(format.wFormatTag), 1, mHandle) ); - - format.nChannels = mChannels; - checkWriteResult( fwrite(&format.nChannels, sizeof(format.nChannels), 1, mHandle) ); + // Set the format description + DWORD dwFmtSize = 16; /*= 16L*/; + checkWriteResult( fwrite(&dwFmtSize, sizeof(dwFmtSize), 1, mHandle) ); - format.nSamplesPerSec = mRate; - checkWriteResult( fwrite(&format.nSamplesPerSec, sizeof(format.nSamplesPerSec), 1, mHandle) ); - - format.nAvgBytesPerSec = mRate * 2 * mChannels; - checkWriteResult( fwrite(&format.nAvgBytesPerSec, sizeof(format.nAvgBytesPerSec), 1, mHandle) ); + WaveFormatEx format; + format.wFormatTag = WAVE_FORMAT_PCM; + checkWriteResult( fwrite(&format.wFormatTag, sizeof(format.wFormatTag), 1, mHandle) ); - format.nBlockAlign = 2 * mChannels; - checkWriteResult( fwrite(&format.nBlockAlign, sizeof(format.nBlockAlign), 1, mHandle) ); - - format.wBitsPerSample = BITS_PER_CHANNEL; - checkWriteResult( fwrite(&format.wBitsPerSample, sizeof(format.wBitsPerSample), 1, mHandle) ); - - const char* data = "data"; - checkWriteResult( fwrite(data, 4, 1, mHandle)); + format.nChannels = mChannels; + checkWriteResult( fwrite(&format.nChannels, sizeof(format.nChannels), 1, mHandle) ); - mFileName = filename; - mWritten = 0; + format.nSamplesPerSec = mRate; + checkWriteResult( fwrite(&format.nSamplesPerSec, sizeof(format.nSamplesPerSec), 1, mHandle) ); - mLengthOffset = ftell(mHandle); - checkWriteResult( fwrite(&mWritten, 4, 1, mHandle) ); + format.nAvgBytesPerSec = mRate * 2 * mChannels; + checkWriteResult( fwrite(&format.nAvgBytesPerSec, sizeof(format.nAvgBytesPerSec), 1, mHandle) ); - return isOpened(); + format.nBlockAlign = 2 * mChannels; + checkWriteResult( fwrite(&format.nBlockAlign, sizeof(format.nBlockAlign), 1, mHandle) ); + + format.wBitsPerSample = BITS_PER_CHANNEL; + checkWriteResult( fwrite(&format.wBitsPerSample, sizeof(format.wBitsPerSample), 1, mHandle) ); + + const char* data = "data"; + checkWriteResult( fwrite(data, 4, 1, mHandle)); + + mFileName = filename; + mWritten = 0; + + mLengthOffset = ftell(mHandle); + checkWriteResult( fwrite(&mWritten, 4, 1, mHandle) ); + + return isOpened(); } void WavFileWriter::close() { - LOCK; + LOCK; - if (mHandle) - { - fclose(mHandle); - mHandle = nullptr; - } + if (mHandle) + { + fclose(mHandle); + mHandle = nullptr; + } } size_t WavFileWriter::write(const void* buffer, size_t bytes) { - LOCK; + LOCK; - if (!mHandle) - return 0; + if (!mHandle) + return 0; - // Seek the end of file - fseek(mHandle, 0, SEEK_END); - mWritten += bytes; + // Seek the end of file + fseek(mHandle, 0, SEEK_END); + mWritten += bytes; - // Write the data - fwrite(buffer, bytes, 1, mHandle); + // Write the data + fwrite(buffer, bytes, 1, mHandle); - // Write file length - fseek(mHandle, 4, SEEK_SET); - int32_t fl = mWritten + 36; - fwrite(&fl, sizeof(fl), 1, mHandle); - - // Write data length - fseek(mHandle, static_cast(mLengthOffset), SEEK_SET); - checkWriteResult( fwrite(&mWritten, 4, 1, mHandle) ); + // Write file length + fseek(mHandle, 4, SEEK_SET); + int32_t fl = mWritten + 36; + fwrite(&fl, sizeof(fl), 1, mHandle); - return bytes; + // Write data length + fseek(mHandle, static_cast(mLengthOffset), SEEK_SET); + checkWriteResult( fwrite(&mWritten, 4, 1, mHandle) ); + + return bytes; } bool WavFileWriter::isOpened() { - LOCK; + LOCK; - return (mHandle != nullptr); + return (mHandle != nullptr); } std::tstring WavFileWriter::filename() { - LOCK; + LOCK; - return mFileName; + return mFileName; } diff --git a/src/engine/audio/Audio_WavFile.h b/src/engine/audio/Audio_WavFile.h index 35ed71f1..a3a6ecdd 100644 --- a/src/engine/audio/Audio_WavFile.h +++ b/src/engine/audio/Audio_WavFile.h @@ -20,16 +20,17 @@ namespace Audio class WavFileReader { protected: - FILE* mHandle; - short mChannels; - short mBits; - int mRate; - std::tstring mFileName; - mutable std::recursive_mutex mFileMtx; - unsigned mDataOffset; - unsigned mDataLength; - Resampler mResampler; - unsigned mLastError; + FILE* mHandle; + short mChannels; + short mBits; + int mSamplerate; + std::tstring mFileName; + mutable std::recursive_mutex + mFileMtx; + unsigned mDataOffset; + unsigned mDataLength; + Resampler mResampler; + unsigned mLastError; std::string readChunk(); public: @@ -40,13 +41,14 @@ namespace Audio void close(); bool isOpened(); void rewind(); - int rate() const; + int samplerate() const; + int channels() const; // This method returns number of read bytes - unsigned read(void* buffer, unsigned bytes); + unsigned read(void* buffer, unsigned bytes, bool resample = true); // This method returns number of read samples - unsigned read(short* buffer, unsigned samples); + unsigned read(short* buffer, unsigned samples, bool resample = true); std::tstring filename() const; unsigned size() const;