- allow WavFileReader to read audio without resampling
This commit is contained in:
parent
21fb865d80
commit
2aba79353a
|
|
@ -19,13 +19,13 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
WORD wFormatTag;
|
WORD wFormatTag;
|
||||||
WORD nChannels;
|
WORD nChannels;
|
||||||
DWORD nSamplesPerSec;
|
DWORD nSamplesPerSec;
|
||||||
DWORD nAvgBytesPerSec;
|
DWORD nAvgBytesPerSec;
|
||||||
WORD nBlockAlign;
|
WORD nBlockAlign;
|
||||||
WORD wBitsPerSample;
|
WORD wBitsPerSample;
|
||||||
WORD cbSize;
|
WORD cbSize;
|
||||||
}
|
}
|
||||||
WaveFormatEx;
|
WaveFormatEx;
|
||||||
|
|
||||||
|
|
@ -39,9 +39,9 @@ using namespace Audio;
|
||||||
|
|
||||||
// ---------------------- WavFileReader -------------------------
|
// ---------------------- WavFileReader -------------------------
|
||||||
WavFileReader::WavFileReader()
|
WavFileReader::WavFileReader()
|
||||||
:mHandle(nullptr), mRate(0), mLastError(0)
|
:mHandle(nullptr), mSamplerate(0), mLastError(0)
|
||||||
{
|
{
|
||||||
mDataOffset = 0;
|
mDataOffset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
WavFileReader::~WavFileReader()
|
WavFileReader::~WavFileReader()
|
||||||
|
|
@ -52,207 +52,221 @@ WavFileReader::~WavFileReader()
|
||||||
|
|
||||||
std::string WavFileReader::readChunk()
|
std::string WavFileReader::readChunk()
|
||||||
{
|
{
|
||||||
char name[5];
|
char name[5];
|
||||||
if (fread(name, 1, 4, mHandle) != 4)
|
if (fread(name, 1, 4, mHandle) != 4)
|
||||||
THROW_READERROR;
|
THROW_READERROR;
|
||||||
|
|
||||||
name[4] = 0;
|
name[4] = 0;
|
||||||
std::string result = name;
|
std::string result = name;
|
||||||
unsigned size;
|
unsigned size;
|
||||||
if (fread(&size, 4, 1, mHandle) != 1)
|
if (fread(&size, 4, 1, mHandle) != 1)
|
||||||
THROW_READERROR;
|
THROW_READERROR;
|
||||||
|
|
||||||
if (result == "fact")
|
if (result == "fact")
|
||||||
fread(&mDataLength, 4, 1, mHandle);
|
fread(&mDataLength, 4, 1, mHandle);
|
||||||
else
|
else
|
||||||
if (result != "data")
|
if (result != "data")
|
||||||
fseek(mHandle, size, SEEK_CUR);
|
fseek(mHandle, size, SEEK_CUR);
|
||||||
else
|
else
|
||||||
mDataLength = size;
|
mDataLength = size;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WavFileReader::open(const std::tstring& filename)
|
bool WavFileReader::open(const std::tstring& filename)
|
||||||
{
|
{
|
||||||
LOCK;
|
LOCK;
|
||||||
try
|
try
|
||||||
{
|
|
||||||
#ifdef WIN32
|
|
||||||
mHandle = _wfopen(filename.c_str(), L"rb");
|
|
||||||
#else
|
|
||||||
mHandle = fopen(strx::makeUtf8(filename).c_str(), "rb");
|
|
||||||
#endif
|
|
||||||
if (NULL == mHandle)
|
|
||||||
{
|
{
|
||||||
|
#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)
|
#if defined(TARGET_ANDROID) || defined(TARGET_LINUX) || defined(TARGET_OSX)
|
||||||
mLastError = errno;
|
mLastError = errno;
|
||||||
#endif
|
#endif
|
||||||
#if defined(TARGET_WIN)
|
#if defined(TARGET_WIN)
|
||||||
mLastError = GetLastError();
|
mLastError = GetLastError();
|
||||||
#endif
|
#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;
|
catch(...)
|
||||||
|
{
|
||||||
// Read the .WAV header
|
fclose(mHandle); mHandle = nullptr;
|
||||||
char riff[4];
|
mLastError = static_cast<unsigned>(-1);
|
||||||
if (fread(riff, 4, 1, mHandle) < 1)
|
}
|
||||||
THROW_READERROR;
|
return isOpened();
|
||||||
|
|
||||||
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<unsigned>(-1);
|
|
||||||
}
|
|
||||||
return isOpened();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WavFileReader::close()
|
void WavFileReader::close()
|
||||||
{
|
{
|
||||||
LOCK;
|
LOCK;
|
||||||
|
|
||||||
if (nullptr != mHandle)
|
if (nullptr != mHandle)
|
||||||
fclose(mHandle);
|
fclose(mHandle);
|
||||||
mHandle = nullptr;
|
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)
|
unsigned WavFileReader::read(short* buffer, unsigned samples, bool resample)
|
||||||
return 0;
|
{
|
||||||
|
LOCK;
|
||||||
|
|
||||||
// Get number of samples that must be read from source file
|
if (!mHandle)
|
||||||
int requiredBytes = mResampler.getSourceLength(samples) * mChannels * mBits / 8;
|
return 0;
|
||||||
void* temp = alloca(requiredBytes);
|
|
||||||
memset(temp, 0, requiredBytes);
|
|
||||||
|
|
||||||
// Find required size of input buffer
|
|
||||||
if (mDataLength)
|
|
||||||
{
|
|
||||||
unsigned filePosition = ftell(mHandle);
|
|
||||||
|
|
||||||
// Check how much data we can read
|
// Get number of samples that must be read from source file
|
||||||
unsigned fileAvailable = mDataLength + mDataOffset - filePosition;
|
int requiredBytes = resample ? mResampler.getSourceLength(samples) * mChannels * mBits / 8 : samples * mChannels * sizeof(short);
|
||||||
requiredBytes = (int)fileAvailable < requiredBytes ? (int)fileAvailable : requiredBytes;
|
void* temp = alloca(requiredBytes);
|
||||||
}
|
memset(temp, 0, requiredBytes);
|
||||||
|
|
||||||
/*int readSamples = */fread(temp, 1, requiredBytes, mHandle);// / mChannels / (mBits / 8);
|
// Find required size of input buffer
|
||||||
size_t processedBytes = 0;
|
if (mDataLength)
|
||||||
size_t result = mResampler.processBuffer(temp, requiredBytes, processedBytes,
|
{
|
||||||
buffer, samples * 2 * AUDIO_CHANNELS);
|
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()
|
bool WavFileReader::isOpened()
|
||||||
{
|
{
|
||||||
LOCK;
|
LOCK;
|
||||||
|
|
||||||
return (mHandle != 0);
|
return (mHandle != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WavFileReader::rewind()
|
void WavFileReader::rewind()
|
||||||
{
|
{
|
||||||
LOCK;
|
LOCK;
|
||||||
|
|
||||||
if (mHandle)
|
if (mHandle)
|
||||||
fseek(mHandle, mDataOffset, SEEK_SET);
|
fseek(mHandle, mDataOffset, SEEK_SET);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tstring WavFileReader::filename() const
|
std::tstring WavFileReader::filename() const
|
||||||
{
|
{
|
||||||
LOCK;
|
LOCK;
|
||||||
|
|
||||||
return mFileName;
|
return mFileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned WavFileReader::size() const
|
unsigned WavFileReader::size() const
|
||||||
{
|
{
|
||||||
LOCK;
|
LOCK;
|
||||||
|
|
||||||
return mDataLength;
|
return mDataLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned WavFileReader::lastError() const
|
unsigned WavFileReader::lastError() const
|
||||||
{
|
{
|
||||||
return mLastError;
|
return mLastError;
|
||||||
}
|
}
|
||||||
// ------------------------- WavFileWriter -------------------------
|
// ------------------------- WavFileWriter -------------------------
|
||||||
#define LOG_SUBSYTEM "WavFileWriter"
|
#define LOG_SUBSYTEM "WavFileWriter"
|
||||||
|
|
@ -260,135 +274,135 @@ unsigned WavFileReader::lastError() const
|
||||||
#define BITS_PER_CHANNEL 16
|
#define BITS_PER_CHANNEL 16
|
||||||
|
|
||||||
WavFileWriter::WavFileWriter()
|
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()
|
WavFileWriter::~WavFileWriter()
|
||||||
{
|
{
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WavFileWriter::checkWriteResult(int result)
|
void WavFileWriter::checkWriteResult(int result)
|
||||||
{
|
{
|
||||||
if (result < 1)
|
if (result < 1)
|
||||||
throw Exception(ERR_WAVFILE_FAILED, errno);
|
throw Exception(ERR_WAVFILE_FAILED, errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WavFileWriter::open(const std::tstring& filename, int rate, int channels)
|
bool WavFileWriter::open(const std::tstring& filename, int rate, int channels)
|
||||||
{
|
{
|
||||||
LOCK;
|
LOCK;
|
||||||
|
|
||||||
close();
|
close();
|
||||||
|
|
||||||
mRate = rate;
|
mRate = rate;
|
||||||
mChannels = channels;
|
mChannels = channels;
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
mHandle = _wfopen(filename.c_str(), L"wb");
|
mHandle = _wfopen(filename.c_str(), L"wb");
|
||||||
#else
|
#else
|
||||||
mHandle = fopen(strx::makeUtf8(filename).c_str(), "wb");
|
mHandle = fopen(strx::makeUtf8(filename).c_str(), "wb");
|
||||||
#endif
|
#endif
|
||||||
if (nullptr == mHandle)
|
if (nullptr == mHandle)
|
||||||
{
|
{
|
||||||
ICELogError(<< "Failed to create .wav file: filename = " << strx::makeUtf8(filename) << " , error = " << errno);
|
ICELogError(<< "Failed to create .wav file: filename = " << strx::makeUtf8(filename) << " , error = " << errno);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write the .WAV header
|
// Write the .WAV header
|
||||||
const char* riff = "RIFF";
|
const char* riff = "RIFF";
|
||||||
checkWriteResult( fwrite(riff, 4, 1, mHandle) );
|
checkWriteResult( fwrite(riff, 4, 1, mHandle) );
|
||||||
|
|
||||||
// Write the file size
|
|
||||||
unsigned int filesize = 0;
|
|
||||||
checkWriteResult( fwrite(&filesize, 4, 1, mHandle) );
|
|
||||||
|
|
||||||
const char* wavefmt = "WAVEfmt ";
|
// Write the file size
|
||||||
checkWriteResult( fwrite(wavefmt, 8, 1, mHandle) );
|
unsigned int filesize = 0;
|
||||||
|
checkWriteResult( fwrite(&filesize, 4, 1, mHandle) );
|
||||||
|
|
||||||
// Set the format description
|
const char* wavefmt = "WAVEfmt ";
|
||||||
DWORD dwFmtSize = 16; /*= 16L*/;
|
checkWriteResult( fwrite(wavefmt, 8, 1, mHandle) );
|
||||||
checkWriteResult( fwrite(&dwFmtSize, sizeof(dwFmtSize), 1, mHandle) );
|
|
||||||
|
|
||||||
WaveFormatEx format;
|
// Set the format description
|
||||||
format.wFormatTag = WAVE_FORMAT_PCM;
|
DWORD dwFmtSize = 16; /*= 16L*/;
|
||||||
checkWriteResult( fwrite(&format.wFormatTag, sizeof(format.wFormatTag), 1, mHandle) );
|
checkWriteResult( fwrite(&dwFmtSize, sizeof(dwFmtSize), 1, mHandle) );
|
||||||
|
|
||||||
format.nChannels = mChannels;
|
|
||||||
checkWriteResult( fwrite(&format.nChannels, sizeof(format.nChannels), 1, mHandle) );
|
|
||||||
|
|
||||||
format.nSamplesPerSec = mRate;
|
WaveFormatEx format;
|
||||||
checkWriteResult( fwrite(&format.nSamplesPerSec, sizeof(format.nSamplesPerSec), 1, mHandle) );
|
format.wFormatTag = WAVE_FORMAT_PCM;
|
||||||
|
checkWriteResult( fwrite(&format.wFormatTag, sizeof(format.wFormatTag), 1, mHandle) );
|
||||||
format.nAvgBytesPerSec = mRate * 2 * mChannels;
|
|
||||||
checkWriteResult( fwrite(&format.nAvgBytesPerSec, sizeof(format.nAvgBytesPerSec), 1, mHandle) );
|
|
||||||
|
|
||||||
format.nBlockAlign = 2 * mChannels;
|
format.nChannels = mChannels;
|
||||||
checkWriteResult( fwrite(&format.nBlockAlign, sizeof(format.nBlockAlign), 1, mHandle) );
|
checkWriteResult( fwrite(&format.nChannels, sizeof(format.nChannels), 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;
|
format.nSamplesPerSec = mRate;
|
||||||
mWritten = 0;
|
checkWriteResult( fwrite(&format.nSamplesPerSec, sizeof(format.nSamplesPerSec), 1, mHandle) );
|
||||||
|
|
||||||
mLengthOffset = ftell(mHandle);
|
format.nAvgBytesPerSec = mRate * 2 * mChannels;
|
||||||
checkWriteResult( fwrite(&mWritten, 4, 1, mHandle) );
|
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()
|
void WavFileWriter::close()
|
||||||
{
|
{
|
||||||
LOCK;
|
LOCK;
|
||||||
|
|
||||||
if (mHandle)
|
if (mHandle)
|
||||||
{
|
{
|
||||||
fclose(mHandle);
|
fclose(mHandle);
|
||||||
mHandle = nullptr;
|
mHandle = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t WavFileWriter::write(const void* buffer, size_t bytes)
|
size_t WavFileWriter::write(const void* buffer, size_t bytes)
|
||||||
{
|
{
|
||||||
LOCK;
|
LOCK;
|
||||||
|
|
||||||
if (!mHandle)
|
if (!mHandle)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// Seek the end of file
|
// Seek the end of file
|
||||||
fseek(mHandle, 0, SEEK_END);
|
fseek(mHandle, 0, SEEK_END);
|
||||||
mWritten += bytes;
|
mWritten += bytes;
|
||||||
|
|
||||||
// Write the data
|
// Write the data
|
||||||
fwrite(buffer, bytes, 1, mHandle);
|
fwrite(buffer, bytes, 1, mHandle);
|
||||||
|
|
||||||
// Write file length
|
// Write file length
|
||||||
fseek(mHandle, 4, SEEK_SET);
|
fseek(mHandle, 4, SEEK_SET);
|
||||||
int32_t fl = mWritten + 36;
|
int32_t fl = mWritten + 36;
|
||||||
fwrite(&fl, sizeof(fl), 1, mHandle);
|
fwrite(&fl, sizeof(fl), 1, mHandle);
|
||||||
|
|
||||||
// Write data length
|
|
||||||
fseek(mHandle, static_cast<long>(mLengthOffset), SEEK_SET);
|
|
||||||
checkWriteResult( fwrite(&mWritten, 4, 1, mHandle) );
|
|
||||||
|
|
||||||
return bytes;
|
// Write data length
|
||||||
|
fseek(mHandle, static_cast<long>(mLengthOffset), SEEK_SET);
|
||||||
|
checkWriteResult( fwrite(&mWritten, 4, 1, mHandle) );
|
||||||
|
|
||||||
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WavFileWriter::isOpened()
|
bool WavFileWriter::isOpened()
|
||||||
{
|
{
|
||||||
LOCK;
|
LOCK;
|
||||||
|
|
||||||
return (mHandle != nullptr);
|
return (mHandle != nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tstring WavFileWriter::filename()
|
std::tstring WavFileWriter::filename()
|
||||||
{
|
{
|
||||||
LOCK;
|
LOCK;
|
||||||
|
|
||||||
return mFileName;
|
return mFileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,16 +20,17 @@ namespace Audio
|
||||||
class WavFileReader
|
class WavFileReader
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
FILE* mHandle;
|
FILE* mHandle;
|
||||||
short mChannels;
|
short mChannels;
|
||||||
short mBits;
|
short mBits;
|
||||||
int mRate;
|
int mSamplerate;
|
||||||
std::tstring mFileName;
|
std::tstring mFileName;
|
||||||
mutable std::recursive_mutex mFileMtx;
|
mutable std::recursive_mutex
|
||||||
unsigned mDataOffset;
|
mFileMtx;
|
||||||
unsigned mDataLength;
|
unsigned mDataOffset;
|
||||||
Resampler mResampler;
|
unsigned mDataLength;
|
||||||
unsigned mLastError;
|
Resampler mResampler;
|
||||||
|
unsigned mLastError;
|
||||||
|
|
||||||
std::string readChunk();
|
std::string readChunk();
|
||||||
public:
|
public:
|
||||||
|
|
@ -40,13 +41,14 @@ namespace Audio
|
||||||
void close();
|
void close();
|
||||||
bool isOpened();
|
bool isOpened();
|
||||||
void rewind();
|
void rewind();
|
||||||
int rate() const;
|
int samplerate() const;
|
||||||
|
int channels() const;
|
||||||
|
|
||||||
// This method returns number of read bytes
|
// 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
|
// 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;
|
std::tstring filename() const;
|
||||||
unsigned size() const;
|
unsigned size() const;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue