Wav header structure
typedef struct WAV_HEADER{
char RIFF[4]; // RIFF Header Magic header
unsigned long ChunkSize; // RIFF Chunk Size
char WAVE[4]; // WAVE Header
char fmt[4]; // FMT header
unsigned long Subchunk1Size; // Size of the fmt chunk
unsigned short AudioFormat; // Audio format 1=PCM,6=mulaw,7=alaw, 257=IBM Mu-Law, 258=IBM A-Law, 259=ADPCM
unsigned short NumOfChan; // Number of channels 1=Mono 2=Sterio
unsigned long SamplesPerSec; // Sampling Frequency in Hz
unsigned long bytesPerSec; // bytes per second
unsigned short blockAlign; // 2=16-bit mono, 4=16-bit stereo
unsigned short bitsPerSample; // Number of bits per sample
char Subchunk2ID[4]; // "data" string
unsigned long Subchunk2Size; // Sampled data length
}wav_hdr;
Write wav file
template <typename T> void AudioManager::write(std::ofstream &stream, const T &t)
{
stream.write((const char*)&t, sizeof(T));
}
template <typename SampleType> //Normally, SampleType is "short"
void AudioManager::writeWAVData(const char *outFile, SampleType *buf, size_t bufSize, int sampleRate, short channels)
{
std::ofstream stream(outFile, std::ios::binary);
stream.write("RIFF", 4);
write<int>(stream, 36 + bufSize);
stream.write("WAVE", 4);
stream.write("fmt ", 4);
write<int>(stream, 16);
write<short>(stream, 1); // Format (1 = PCM)
write<short>(stream, channels); // Channels //mono
write<int>(stream, sampleRate);
write<int>(stream, sampleRate * channels * sizeof(SampleType)); // Byterate
write<short>(stream, channels * sizeof(SampleType)); // Frame size
write<short>(stream, 8 * sizeof(SampleType)); // Bits per sample
stream.write("data", 4);
uint32_t sz = bufSize;
stream.write((const char*)&sz, 4);
stream.write((const char*)buf, bufSize);
//Calculate length of the sound
int numSamples = sz / (channels * sizeof(SampleType));
lenInSec_ = numSamples / sampleRate;
}
Get sound length in .wav file
if (filename.endsWith(".wav"))
{
//Read wav header to get the NumChannels, SampleRate, and data size
char wavv[5];
fseek(fhandle, 8, SEEK_SET); // seek to begin of file
fread(&wavv, sizeof(char), 4, fhandle);
wavv[4] = '\0';
if (strcmp(wavv, "WAVE") != 0)
return -1;
fseek(fhandle, 22, SEEK_SET);//get to NumChannels
fread(&numChannel, sizeof(short), 1, fhandle);
if (numChannel != 1)
return -1;
fread(&sampleRate, sizeof(int), 1, fhandle);
fseek(fhandle, 40, SEEK_SET);
fread(&bufSize, sizeof(unsigned long), 1, fhandle);
}
LitleEndian to BigEndian
/* Write a uint_32 in big-endian order. */
#define WRITE_U32(buf, x) \
*(buf) = (unsigned char)(((x)>>24)&0xff);\
*((buf)+1) = (unsigned char)(((x)>>16)&0xff);\
*((buf)+2) = (unsigned char)(((x)>>8)&0xff);\
*((buf)+3) = (unsigned char)((x)&0xff);
// can be used for short, unsigned short, word, unsigned word (2-byte types)
#define BYTESWAP16(n) (((n&0xFF00)>>8)|((n&0x00FF)<<8))
#define BYTESWAP32(n) ((n & 0xFF) << 24)\
| ((n & 0xFF00) << 8)\
| ((n >> 8) & 0xFF00)\
| (n >> 24);\
Write .au file:
void AudioManager::writeAUData(QString outfile, short *buf, size_t bufSize, int sampleRate, short channels)
{
char hbuf[28];
short mbuf[bufSize];
u_int32_t off = 24, encoding = 3, dataSize = 0xffffffff;
char info[] = "info";
std::ofstream stream(outfile.toStdString().c_str(), std::ios::binary);
/* Write the header in big-endian order */
WRITE_U32(hbuf, (u_int32_t)0x2e736e64);
WRITE_U32(hbuf + 4, off);
WRITE_U32(hbuf + 8, dataSize);
WRITE_U32(hbuf + 12, encoding);
WRITE_U32(hbuf + 16, sampleRate);
WRITE_U32(hbuf + 20, channels);
strncpy (&hbuf[24], info, 4);
stream.write((const char*)hbuf, 28);//sound data
//inverse the buffer sound
/*
short *p = buf;
int i = 0;
while (p != NULL){
uint16_t val = BYTESWAP16(*p);
mbuf[i] = val;
i++;
p++;
if (i == bufSize)
break;
}
*/
//apparently, no need to reverse in big endian.
//QAudioOutput and Camera player read them perfectly, but not vlc.
stream.write((const char*)buf, bufSize);//sound data
}
Mulaw encoding
int8_t MuLaw_Encode(int16_t number){ const uint16_t MULAW_MAX = 0x1FFF; const uint16_t MULAW_BIAS = 33; uint16_t mask = 0x1000; uint8_t sign = 0; uint8_t position = 12; uint8_t lsb = 0; if (number < 0) { number = -number; sign = 0x80; } number += MULAW_BIAS; if (number > MULAW_MAX) { number = MULAW_MAX; } for (; ((number & mask) != mask && position >= 5); mask >>= 1, position--) ; lsb = (number >> (position - 4)) & 0x0f; return (~(sign | ((position - 5) << 4) | lsb));}