[音频格式] WAV音频格式

目录

这一周都在看音频加速播放的源代码,就了解下最简单的音频格式——WAV。wav格式和bmp格式差不多,文件开头是一个比较短的文件头,之后是大段的数据。wav中每采样点的数据是未经处理的

PCM值,就像bmp格式的每个像素点的数据是调色板的编号或者是该点的RGB颜色值一样。音频数据每个采样点通常使用float类型处理(32bit?)。
文件格式示例:

WAVE文件格式说明

简单来说,WAVE音频文件可以看作一个块(chunk)中包含两个或三个子块(sub-chunk)。
起始的是RIFF主块,描述块(chunk)信息,包括文件类型和整个文件的大小等。
接着是fmt子块(Format Chunk),描述数据的格式,例如采样频率、通道、每样本位数等等。其中某些编码方式还有一些额外的参数。
接下来,非PCM格式的文件中有个fact子块。至少有一项,文件中的样本个数。
最后是data子块,包含所有的音频数据。若最后的地址是奇数,就加上1字节0值对齐。
详细资料参见下面两个网页,写得十分详细:
WAVE PCM soundfile format
Audio File Format Specifications
至于读取WAVE文件,我还没学会用windows或者DirectSound提供的方法,只是简单的定义几个结构,从wav文件中一一读出来,chunk头结构从网上找的。
前几天看SoundTouch的代码,发现其中的SoundStretch项目中提供一个简单的wav文件读取类,可以作为参考。参见SoundTouch的项目主页:<//www.surina.net/soundtouch/index.html>
wavefile.h
[cpp]
////////////////////////////////////////////////////////////////////////////////
///
/// Classes for easy reading & writing of WAV sound files.
///
/// For big-endian CPU, define BIG_ENDIAN during compile-time to correctly
/// parse the WAV files with such processors.
///
/// Admittingly, more complete WAV reader routines may exist in public domain, but
/// the reason for ‘yet another’ one is that those generic WAV reader libraries are
/// exhaustingly large and cumbersome! Wanted to have something simpler here, i.e.
/// something that’s not already larger than rest of the SoundTouch/SoundStretch program…
///
/// Author : Copyright © Olli Parviainen
/// Author e-mail : oparviai ‘at’ iki.fi
/// SoundTouch WWW: //www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date: 2009-02-21 18:00:14 +0200 (Sat, 21 Feb 2009) $
// File revision : $Revision: 4 $
//
// $Id: WavFile.h 63 2009-02-21 16:00:14Z oparviai $
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright © Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#ifndef WAVFILE_H
#define WAVFILE_H
#include
#ifndef uint
typedef unsigned int uint;
#endif
/// WAV audio file ‘riff’ section header
typedef struct
{
char riff_char[4];
int package_len;
char wave[4];
} WavRiff;
/// WAV audio file ‘format’ section header
typedef struct
{
char fmt[4];
int format_len;
short fixed;
short channel_number;
int sample_rate;
int byte_rate;
short byte_per_sample;
short bits_per_sample;
} WavFormat;
/// WAV audio file ‘data’ section header
typedef struct
{
char data_field[4];
uint data_len;
} WavData;
/// WAV audio file header
typedef struct
{
WavRiff riff;
WavFormat format;
WavData data;
} WavHeader;
/// Class for reading WAV audio files.
class WavInFile
{
private:
/// File pointer.
FILE *fptr;
/// Counter of how many bytes of sample data have been read from the file.
uint dataRead;
/// WAV header information
WavHeader header;
/// Init the WAV file stream
void init();
/// Read WAV file headers.
/// \return zero if all ok, nonzero if file format is invalid.
int readWavHeaders();
/// Checks WAV file header tags.
/// \return zero if all ok, nonzero if file format is invalid.
int checkCharTags() const;
/// Reads a single WAV file header block.
/// \return zero if all ok, nonzero if file format is invalid.
int readHeaderBlock();
/// Reads WAV file ‘riff’ block
int readRIFFBlock();
public:
/// Constructor: Opens the given WAV file. If the file can’t be opened,
/// throws ‘runtime_error’ exception.
WavInFile(const char *filename);
WavInFile(FILE *file);
/// Destructor: Closes the file.
~WavInFile();
/// Rewind to beginning of the file
void rewind();
/// Get sample rate.
uint getSampleRate() const;
/// Get number of bits per sample, i.e. 8 or 16.
uint getNumBits() const;
/// Get sample data size in bytes. Ahem, this should return same information as
/// ‘getBytesPerSample’…
uint getDataSizeInBytes() const;
/// Get total number of samples in file.
uint getNumSamples() const;
/// Get number of bytes per audio sample (e.g. 16bit stereo = 4 bytes/sample)
uint getBytesPerSample() const;
/// Get number of audio channels in the file (1=mono, 2=stereo)
uint getNumChannels() const;
/// Get the audio file length in milliseconds
uint getLengthMS() const;
/// Reads audio samples from the WAV file. This routine works only for 8 bit samples.
/// Reads given number of elements from the file or if end-of-file reached, as many
/// elements as are left in the file.
///
/// \return Number of 8-bit integers read from the file.
int read(char *buffer, int maxElems);
/// Reads audio samples from the WAV file to 16 bit integer format. Reads given number
/// of elements from the file or if end-of-file reached, as many elements as are
/// left in the file.
///
/// \return Number of 16-bit integers read from the file.
int read(short *buffer, ///< Pointer to buffer where to read data. int maxElems ///< Size of ‘buffer’ array (number of array elements). ); /// Reads audio samples from the WAV file to floating point format, converting /// sample values to range [-1,1[. Reads given number of elements from the file /// or if end-of-file reached, as many elements as are left in the file. /// /// \return Number of elements read from the file. int read(float *buffer, ///< Pointer to buffer where to read data. int maxElems ///< Size of ‘buffer’ array (number of array elements). ); /// Check end-of-file. /// /// \return Nonzero if end-of-file reached. int eof() const; }; /// Class for writing WAV audio files. class WavOutFile { private: /// Pointer to the WAV file FILE *fptr; /// WAV file header data. WavHeader header; /// Counter of how many bytes have been written to the file so far. int bytesWritten; /// Fills in WAV file header information. void fillInHeader(const uint sampleRate, const uint bits, const uint channels); /// Finishes the WAV file header by supplementing information of amount of /// data written to file etc void finishHeader(); /// Writes the WAV file header. void writeHeader(); public: /// Constructor: Creates a new WAV file. Throws a ‘runtime_error’ exception /// if file creation fails. WavOutFile(const char *fileName, ///< Filename int sampleRate, ///< Sample rate (e.g. 44100 etc) int bits, ///< Bits per sample (8 or 16 bits) int channels ///< Number of channels (1=mono, 2=stereo) ); WavOutFile(FILE *file, int sampleRate, int bits, int channels); /// Destructor: Finalizes & closes the WAV file. ~WavOutFile(); /// Write data to WAV file. This function works only with 8bit samples. /// Throws a ‘runtime_error’ exception if writing to file fails. void write(const char *buffer, ///< Pointer to sample data buffer. int numElems ///< How many array items are to be written to file. ); /// Write data to WAV file. Throws a ‘runtime_error’ exception if writing to /// file fails. void write(const short *buffer, ///< Pointer to sample data buffer. int numElems ///< How many array items are to be written to file. ); /// Write data to WAV file in floating point format, saturating sample values to range /// [-1..+1[. Throws a ‘runtimeerror’ exception if writing to file fails. void write(const float *buffer, ///< Pointer to sample data buffer. int numElems ///< How many array items are to be written to file. ); }; #endif [/cpp] wavefile.cpp [cpp] //////////////////////////////////////////////////////////////////////////////// /// /// Classes for easy reading & writing of WAV sound files. /// /// For big-endian CPU, define _BIG_ENDIAN during compile-time to correctly /// parse the WAV files with such processors. /// /// Admittingly, more complete WAV reader routines may exist in public domain, /// but the reason for ‘yet another’ one is that those generic WAV reader /// libraries are exhaustingly large and cumbersome! Wanted to have something /// simpler here, i.e. something that’s not already larger than rest of the /// SoundTouch/SoundStretch program… /// /// Author : Copyright © Olli Parviainen /// Author e-mail : oparviai ‘at’ iki.fi /// SoundTouch WWW: //www.surina.net/soundtouch /// //////////////////////////////////////////////////////////////////////////////// // // Last changed : $Date: 2011-07-16 11:46:37 +0300 (Sat, 16 Jul 2011) $ // File revision : $Revision: 4 $ // // $Id: WavFile.cpp 120 2011-07-16 08:46:37Z oparviai $ // //////////////////////////////////////////////////////////////////////////////// // // License : // // SoundTouch audio processing library // Copyright © Olli Parviainen // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library 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 // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //////////////////////////////////////////////////////////////////////////////// #include
#include
#include
#include
#include
#include #include “WavFile.h”
using namespace std;
static const char riffStr[] = “RIFF”;
static const char waveStr[] = “WAVE”;
static const char fmtStr[] = “fmt “;
static const char dataStr[] = “data”;
//////////////////////////////////////////////////////////////////////////////
//
// Helper functions for swapping byte order to correctly read/write WAV files
// with big-endian CPU’s: Define compile-time definition _BIG_ENDIAN_ to
// turn-on the conversion if it appears necessary.
//
// For example, Intel x86 is little-endian and doesn’t require conversion,
// while PowerPC of Mac’s and many other RISC cpu’s are big-endian.
#ifdef BYTEORDER
// In gcc compiler detect the byte order automatically
#if BYTE_ORDER == BIG_ENDIAN
// big-endian platform.
#define _BIG_ENDIAN

#endif
#endif
#ifdef _BIG_ENDIAN_
// big-endian CPU, swap bytes in 16 & 32 bit words
// helper-function to swap byte-order of 32bit integer
static inline void _swap32(unsigned int &dwData)
{
dwData = ((dwData >> 24) & 0x000000FF) |
((dwData >> 8) & 0x0000FF00) |
((dwData << 8) & 0x00FF0000) | ((dwData << 24) & 0xFF000000); } // helper-function to swap byte-order of 16bit integer static inline void _swap16(unsigned short &wData) { wData = ((wData >> 8) & 0x00FF) |
((wData << 8) & 0xFF00); } // helper-function to swap byte-order of buffer of 16bit integers static inline void _swap16Buffer(unsigned short pData, unsigned int dwNumWords) { unsigned long i; for (i = 0; i < dwNumWords; i ++) { _swap16(pData[i]); } } #else // BIG_ENDIAN // little-endian CPU, WAV file is ok as such // dummy helper-function static inline void _swap32(unsigned int &dwData) { // do nothing } // dummy helper-function static inline void _swap16(unsigned short &wData) { // do nothing } // dummy helper-function static inline void _swap16Buffer(unsigned short *pData, unsigned int dwNumBytes) { // do nothing } #endif // BIG_ENDIAN ////////////////////////////////////////////////////////////////////////////// // // Class WavInFile // WavInFile::WavInFile(const char *fileName) { // Try to open the file for reading fptr = fopen(fileName, “rb”); if (fptr == NULL) { // didn’t succeed string msg = “Error : Unable to open file \“”; msg += fileName; msg += “\” for reading.“; throw runtime_error(msg); } init(); } WavInFile::WavInFile(FILE *file) { // Try to open the file for reading fptr = file; if (!file) { // didn’t succeed string msg = “Error : Unable to access input stream for reading”; throw runtime_error(msg); } init(); } /// Init the WAV file stream void WavInFile::init() { int hdrsOk; // assume file stream is already open assert(fptr); // Read the file headers hdrsOk = readWavHeaders(); if (hdrsOk != 0) { // Something didn’t match in the wav file headers string msg = “Input file is corrupt or not a WAV file”; throw runtime_error(msg); } if (header.format.fixed != 1) { string msg = “Input file uses unsupported encoding.”; throw runtime_error(msg); } dataRead = 0; } WavInFile::~WavInFile() { if (fptr) fclose(fptr); fptr = NULL; } void WavInFile::rewind() { int hdrsOk; fseek(fptr, 0, SEEK_SET); hdrsOk = readWavHeaders(); assert(hdrsOk == 0); dataRead = 0; } int WavInFile::checkCharTags() const { // header.format.fmt should equal to ‘fmt ’ if (memcmp(fmtStr, header.format.fmt, 4) != 0) return -1; // header.data.data_field should equal to ‘data’ if (memcmp(dataStr, header.data.data_field, 4) != 0) return -1; return 0; } int WavInFile::read(char *buffer, int maxElems) { int numBytes; uint afterDataRead; // ensure it’s 8 bit format if (header.format.bits_per_sample != 8) { throw runtime_error(“Error: WavInFile::read(char, int) works only with 8bit samples.“); } assert(sizeof(char) == 1); numBytes = maxElems; afterDataRead = dataRead + numBytes; if (afterDataRead > header.data.data_len)
{
// Don’t read more samples than are marked available in header
numBytes = (int)header.data.data_len – (int)dataRead;
assert(numBytes >= 0);
}
assert(buffer);
numBytes = (int)fread(buffer, 1, numBytes, fptr);
dataRead += numBytes;
return numBytes;
}
int WavInFile::read(short *buffer, int maxElems)
{
unsigned int afterDataRead;
int numBytes;
int numElems;
assert(buffer);
if (header.format.bits_per_sample == 8)
{
// 8 bit format
char *temp = new char[maxElems];
int i;
numElems = read(temp, maxElems);
// convert from 8 to 16 bit
for (i = 0; i < numElems; i ++) { buffer[i] = temp[i] << 8; } delete[] temp; } else { // 16 bit format if (header.format.bits_per_sample != 16) { string msg = “WAV file bits per sample format not supported: “; msg += (int)header.format.bits_per_sample; msg += “ bits per sample.”; throw runtime_error(msg); } assert(sizeof(short) == 2); numBytes = maxElems * 2; afterDataRead = dataRead + numBytes; if (afterDataRead > header.data.data_len)
{
// Don’t read more samples than are marked available in header
numBytes = (int)header.data.data_len – (int)dataRead;
assert(numBytes >= 0);
}
numBytes = (int)fread(buffer, 1, numBytes, fptr);
dataRead += numBytes;
numElems = numBytes / 2;
// 16bit samples, swap byte order if necessary
_swap16Buffer((unsigned short *)buffer, numElems);
}
return numElems;
}
int WavInFile::read(float *buffer, int maxElems)
{
short *temp = new short[maxElems];
int num;
int i;
double fscale;
num = read(temp, maxElems);
fscale = 1.0 / 32768.0;
// convert to floats, scale to range [-1..+1[
for (i = 0; i < num; i ++) { buffer[i] = (float)(fscale * (double)temp[i]); } delete[] temp; return num; } int WavInFile::eof() const { // return true if all data has been read or file eof has reached return (dataRead == header.data.data_len || feof(fptr)); } // test if character code is between a white space ‘ ’ and little ‘z’ static int isAlpha(char c) { return (c >= ‘ ‘ && c <= ‘z’) ? 1 : 0; } // test if all characters are between a white space ‘ ’ and little ‘z’ static int isAlphaStr(const char *str) { char c; c = str[0]; while © { if (isAlpha© == 0) return 0; str ++; c = str[0]; } return 1; } int WavInFile::readRIFFBlock() { if (fread(&(header.riff), sizeof(WavRiff), 1, fptr) != 1) return -1; // swap 32bit data byte order if necessary _swap32((unsigned int &)header.riff.package_len); // header.riff.riff_char should equal to ‘RIFF’); if (memcmp(riffStr, header.riff.riff_char, 4) != 0) return -1; // header.riff.wave should equal to ‘WAVE’ if (memcmp(waveStr, header.riff.wave, 4) != 0) return -1; return 0; } int WavInFile::readHeaderBlock() { char label[5]; string sLabel; // lead label string if (fread(label, 1, 4, fptr) !=4) return -1; label[4] = 0; if (isAlphaStr(label) == 0) return -1; // not a valid label // Decode blocks according to their label if (strcmp(label, fmtStr) == 0) { int nLen, nDump; // ‘fmt ’ block memcpy(header.format.fmt, fmtStr, 4); // read length of the format field if (fread(&nLen, sizeof(int), 1, fptr) != 1) return -1; // swap byte order if necessary _swap32((unsigned int &)nLen); // int format_len; header.format.format_len = nLen; // calculate how much length differs from expected nDump = nLen - ((int)sizeof(header.format) - 8); // if format_len is larger than expected, read only as much data as we’ve space for if (nDump > 0)
{
nLen = sizeof(header.format) – 8;
}
// read data
if (fread(&(header.format.fixed), nLen, 1, fptr) != 1) return -1;
// swap byte order if necessary
_swap16((unsigned short &)header.format.fixed); // short int fixed;
_swap16((unsigned short &)header.format.channel_number); // short int channel_number;
_swap32((unsigned int &)header.format.sample_rate); // int sample_rate;
_swap32((unsigned int &)header.format.byte_rate); // int byte_rate;
_swap16((unsigned short &)header.format.byte_per_sample); // short int byte_per_sample;
_swap16((unsigned short &)header.format.bits_per_sample); // short int bits_per_sample;
// if format_len is larger than expected, skip the extra data
if (nDump > 0)
{
fseek(fptr, nDump, SEEK_CUR);
}
return 0;
}
else if (strcmp(label, dataStr) == 0)
{
// ‘data’ block
memcpy(header.data.data_field, dataStr, 4);
if (fread(&(header.data.data_len), sizeof(uint), 1, fptr) != 1) return -1;
// swap byte order if necessary
_swap32((unsigned int &)header.data.data_len);
return 1;
}
else
{
uint len, i;
uint temp;
// unknown block
// read length
if (fread(&len, sizeof(len), 1, fptr) != 1) return -1;
// scan through the block
for (i = 0; i < len; i ++) { if (fread(&temp, 1, 1, fptr) != 1) return -1; if (feof(fptr)) return -1; // unexpected eof } } return 0; } int WavInFile::readWavHeaders() { int res; memset(&header, 0, sizeof(header)); res = readRIFFBlock(); if (res) return 1; // read header blocks until data block is found do { // read header blocks res = readHeaderBlock(); if (res < 0) return 1; // error in file structure } while (res == 0); // check that all required tags are legal return checkCharTags(); } uint WavInFile::getNumChannels() const { return header.format.channel_number; } uint WavInFile::getNumBits() const { return header.format.bits_per_sample; } uint WavInFile::getBytesPerSample() const { return getNumChannels() * getNumBits() / 8; } uint WavInFile::getSampleRate() const { return header.format.sample_rate; } uint WavInFile::getDataSizeInBytes() const { return header.data.data_len; } uint WavInFile::getNumSamples() const { if (header.format.byte_per_sample == 0) return 0; return header.data.data_len / (unsigned short)header.format.byte_per_sample; } uint WavInFile::getLengthMS() const { uint numSamples; uint sampleRate; numSamples = getNumSamples(); sampleRate = getSampleRate(); assert(numSamples < UINT_MAX / 1000); return (1000 * numSamples / sampleRate); } ////////////////////////////////////////////////////////////////////////////// // // Class WavOutFile // WavOutFile::WavOutFile(const char *fileName, int sampleRate, int bits, int channels) { bytesWritten = 0; fptr = fopen(fileName, “wb”); if (fptr == NULL) { string msg = “Error : Unable to open file \“”; msg += fileName; msg += “\” for writing.“; //pmsg = msg.c_str; throw runtime_error(msg); } fillInHeader(sampleRate, bits, channels); writeHeader(); } WavOutFile::WavOutFile(FILE *file, int sampleRate, int bits, int channels) { bytesWritten = 0; fptr = file; if (fptr == NULL) { string msg = “Error : Unable to access output file stream.“; throw runtime_error(msg); } fillInHeader(sampleRate, bits, channels); writeHeader(); } WavOutFile::~WavOutFile() { finishHeader(); if (fptr) fclose(fptr); fptr = NULL; } void WavOutFile::fillInHeader(uint sampleRate, uint bits, uint channels) { // fill in the ‘riff’ part.. // copy string ‘RIFF’ to riff_char memcpy(&(header.riff.riff_char), riffStr, 4); // package_len unknown so far header.riff.package_len = 0; // copy string ‘WAVE’ to wave memcpy(&(header.riff.wave), waveStr, 4); // fill in the ‘format’ part.. // copy string ‘fmt ’ to fmt memcpy(&(header.format.fmt), fmtStr, 4); header.format.format_len = 0x10; header.format.fixed = 1; header.format.channel_number = (short)channels; header.format.sample_rate = (int)sampleRate; header.format.bits_per_sample = (short)bits; header.format.byte_per_sample = (short)(bits * channels / 8); header.format.byte_rate = header.format.byte_per_sample * (int)sampleRate; header.format.sample_rate = (int)sampleRate; // fill in the ‘data’ part.. // copy string ‘data’ to data_field memcpy(&(header.data.data_field), dataStr, 4); // data_len unknown so far header.data.data_len = 0; } void WavOutFile::finishHeader() { // supplement the file length into the header structure header.riff.package_len = bytesWritten + 36; header.data.data_len = bytesWritten; writeHeader(); } void WavOutFile::writeHeader() { WavHeader hdrTemp; int res; // swap byte order if necessary hdrTemp = header; _swap32((unsigned int &)hdrTemp.riff.package_len); _swap32((unsigned int &)hdrTemp.format.format_len); _swap16((unsigned short &)hdrTemp.format.fixed); _swap16((unsigned short &)hdrTemp.format.channel_number); _swap32((unsigned int &)hdrTemp.format.sample_rate); _swap32((unsigned int &)hdrTemp.format.byte_rate); _swap16((unsigned short &)hdrTemp.format.byte_per_sample); _swap16((unsigned short &)hdrTemp.format.bits_per_sample); _swap32((unsigned int &)hdrTemp.data.data_len); // write the supplemented header in the beginning of the file fseek(fptr, 0, SEEK_SET); res = (int)fwrite(&hdrTemp, sizeof(hdrTemp), 1, fptr); if (res != 1) { throw runtime_error(“Error while writing to a wav file.”); } // jump back to the end of the file fseek(fptr, 0, SEEK_END); } void WavOutFile::write(const char *buffer, int numElems) { int res; if (header.format.bits_per_sample != 8) { throw runtime_error(“Error: WavOutFile::write(const char*, int) accepts only 8bit samples.“); } assert(sizeof(char) == 1); res = (int)fwrite(buffer, 1, numElems, fptr); if (res != numElems) { throw runtime_error(“Error while writing to a wav file.”); } bytesWritten += numElems; } void WavOutFile::write(const short *buffer, int numElems) { int res; // 16 bit samples if (numElems < 1) return; // nothing to do if (header.format.bits_per_sample == 8) { int i; char *temp = new char[numElems]; // convert from 16bit format to 8bit format for (i = 0; i < numElems; i ++) { temp[i] = buffer[i] >> 8;
}
// write in 8bit format
write(temp, numElems);
delete[] temp;
}
else
{
// 16bit format
unsigned short *pTemp = new unsigned short[numElems];
if (header.format.bits_per_sample != 16)
{
string msg = “WAV file bits per sample format not supported: “;
msg += (int)header.format.bits_per_sample;
msg += ” bits per sample.”;
throw runtime_error(msg);
}
// allocate temp buffer to swap byte order if necessary
memcpy(pTemp, buffer, numElems * 2);
_swap16Buffer(pTemp, numElems);
res = (int)fwrite(pTemp, 2, numElems, fptr);
delete[] pTemp;
if (res != numElems)
{
throw runtime_error(“Error while writing to a wav file.”);
}
bytesWritten += 2 * numElems;
}
}
void WavOutFile::write(const float *buffer, int numElems)
{
int i;
short *temp = new short[numElems];
int iTemp;
// convert to 16 bit integer
for (i = 0; i < numElems; i ++) { // convert to integer iTemp = (int)(32768.0f * buffer[i]); // saturate if (iTemp < -32768) iTemp = -32768; if (iTemp > 32767) iTemp = 32767;
temp[i] = (short)iTemp;
}
write(temp, numElems);
delete[] temp;
}
[/cpp]