Page MenuHomePhabricator

WaveFile.cpp
No OneTemporary

WaveFile.cpp

#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <errno.h>
#if WIN32
#else
#include <inttypes.h>
#endif
#include "WaveFile.h"
#define SPEAKER_FRONT_LEFT 0x1
#define SPEAKER_FRONT_RIGHT 0x2
#define SPEAKER_FRONT_CENTER 0x4
#define SPEAKER_LOW_FREQUENCY 0x8
#define SPEAKER_BACK_LEFT 0x10
#define SPEAKER_BACK_RIGHT 0x20
#define SPEAKER_FRONT_LEFT_OF_CENTER 0x40
#define SPEAKER_FRONT_RIGHT_OF_CENTER 0x80
#define SPEAKER_BACK_CENTER 0x100
#define SPEAKER_SIDE_LEFT 0x200
#define SPEAKER_SIDE_RIGHT 0x400
#define SPEAKER_TOP_CENTER 0x800
#define SPEAKER_TOP_FRONT_LEFT 0x1000
#define SPEAKER_TOP_FRONT_CENTER 0x2000
#define SPEAKER_TOP_FRONT_RIGHT 0x4000
#define SPEAKER_TOP_BACK_LEFT 0x8000
#define SPEAKER_TOP_BACK_CENTER 0x10000
#define SPEAKER_TOP_BACK_RIGHT 0x20000
#define SPEAKER_RESERVED 0x80000000
#define SPEAKER_REAR_CENTER_SURROUND SPEAKER_BACK_CENTER
#define DCA_MONO 0
#define DCA_CHANNEL 1
#define DCA_STEREO 2
#define DCA_STEREO_SUMDIFF 3
#define DCA_STEREO_TOTAL 4
#define DCA_3F 5
#define DCA_2F1R 6
#define DCA_3F1R 7
#define DCA_2F2R 8
#define DCA_3F2R 9
#define DCA_4F2R 10
#define DCA_DOLBY 101 /* FIXME */
#define DCA_CHANNEL_MAX DCA_3F2R /* We don't handle anything above that */
#define DCA_CHANNEL_BITS 6
#define DCA_CHANNEL_MASK 0x3F
#define DCA_LFE 0x80
#define DCA_ADJUST_LEVEL 0x100
#define WAVE_FORMAT_PCM 0x0001
#define WAVE_FORMAT_IEEE_FLOAT 0x0003
#define WAVE_FORMAT_EXTENSIBLE 0xFFFE
static uint8_t wav_header[] = {
'R', 'I', 'F', 'F', 0xfc, 0xff, 0xff, 0xff, 'W', 'A', 'V', 'E',
'f', 'm', 't', ' ', 16, 0, 0, 0,
WAVE_FORMAT_PCM, WAVE_FORMAT_PCM >> 8,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0,
'd', 'a', 't', 'a', 0xd8, 0xff, 0xff, 0xff
};
static uint8_t wavmulti_header[] = {
'R', 'I', 'F', 'F', 0xf0, 0xff, 0xff, 0xff, 'W', 'A', 'V', 'E',
'f', 'm', 't', ' ', 40, 0, 0, 0,
(uint8_t)(WAVE_FORMAT_EXTENSIBLE & 0xFF), WAVE_FORMAT_EXTENSIBLE >> 8,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 22, 0,
0, 0, 0, 0, 0, 0,
WAVE_FORMAT_IEEE_FLOAT, WAVE_FORMAT_IEEE_FLOAT >> 8,
0, 0, 0, 0, 0x10, 0x00, 0x80, 0, 0, 0xaa, 0, 0x38, 0x9b, 0x71,
'd', 'a', 't', 'a', 0xb4, 0xff, 0xff, 0xff
};
static void store4 (uint8_t * buf, int value)
{
buf[0] = value;
buf[1] = value >> 8;
buf[2] = value >> 16;
buf[3] = value >> 24;
}
static void store2 (uint8_t * buf, int value)
{
buf[0] = value;
buf[1] = value >> 8;
}
static uint32_t find_chunk(FILE * file, const uint8_t chunk_id[4])
{
uint8_t buffer[8];
while (1) {
size_t chunksize;
size_t s = fread(buffer, 1, 8, file);
if (s < 8)
return 0;
chunksize = (uint32_t)buffer[4] | ((uint32_t)buffer[5] << 8) |
((uint32_t)buffer[6] << 16) | ((uint32_t)buffer[7] << 24);
if (!memcmp(buffer, chunk_id, 4))
return chunksize;
fseek(file, chunksize, SEEK_CUR);
}
}
CWaveFile::CWaveFile(const char* Filename, bool Write)
: Duration(0), ReadOnly(false), m_bOK(false)
{
Channels = 0;
/* 打开文件 **/
File = fopen(Filename, Write ? "wb":"rb");
if ( !File )
return;
/* 设置写文件初始参数 **/
if ( Write )
{
SampleRate = 44100;
Channels = 2;
Format = SF_S16;
SampleSize = 16;
ChannelMask = 0;
m_bOK = true;
return;
}
ReadOnly = true;
size_t s;
uint8_t buffer[8];
uint8_t *fmt = NULL;
uint32_t v;
uint32_t avg_bps;
uint32_t block_align;
unsigned short FormatType;
unsigned short SampleType;
static const uint8_t riff[4] = { 'R', 'I', 'F', 'F' };
static const uint8_t wave[4] = { 'W', 'A', 'V', 'E' };
static const uint8_t fmt_[4] = { 'f', 'm', 't', ' ' };
static const uint8_t data[4] = { 'd', 'a', 't', 'a' };
/* 前四个字节为 riff **/
s = fread(buffer, 1, 8, File);
if (s < 8)
goto err2;
if (memcmp(buffer, riff, 4))
goto err2;
/* 8~12为wave **/
/* TODO: check size (in buffer[4..8]) */
s = fread(buffer, 1, 4, File);
if (s < 4)
goto err2;
if (memcmp(buffer, wave, 4))
goto err2;
s = find_chunk(File, fmt_);
if ( s != 16 && s != 18 && s != 40 )
goto err2;
fmt = (uint8_t*)malloc(s);
if (!fmt)
goto err2;
if (fread(fmt, 1, s, File) != s)
goto err3;
/* wFormatTag */
v = (uint32_t)fmt[0] | ((uint32_t)fmt[1] << 8);
if (v != WAVE_FORMAT_PCM && v != WAVE_FORMAT_IEEE_FLOAT && v != WAVE_FORMAT_EXTENSIBLE)
goto err3;
FormatType = v;
if (s == 40 && 0xfffe == v)
{
// fmt begins at 0x14 of the wave file
v = *(unsigned short*)&fmt[0x2C - 0x14];
}
SampleType = v;
/* wChannels */
v = (uint32_t)fmt[2] | ((uint32_t)fmt[3] << 8);
Channels = v;
if (v < 1 || v > 32)
goto err3;
/* dwSamplesPerSec */
SampleRate = (uint32_t)fmt[4] | ((uint32_t)fmt[5] << 8) |
((uint32_t)fmt[6] << 16) | ((uint32_t)fmt[7] << 24);
/* dwAvgBytesPerSec */
avg_bps = (uint32_t)fmt[8] | ((uint32_t)fmt[9] << 8) |
((uint32_t)fmt[10] << 16) | ((uint32_t)fmt[11] << 24);
/* wBlockAlign */
block_align = (uint32_t)fmt[12] | ((uint32_t)fmt[13] << 8);
/* wBitsPerSample */
SampleSize = (uint32_t)fmt[14] | ((uint32_t)fmt[15] << 8);
if (SampleSize != 8 && SampleSize != 16 && SampleSize != 32 && SampleSize != 24 && SampleSize != 64)
goto err3;
switch (SampleSize)
{
case 8:
Format = SF_U8;
break;
case 16:
Format = SF_S16;
break;
case 24:
Format = SF_S24;
break;
case 32:
{
if (SampleType == WAVE_FORMAT_IEEE_FLOAT)
Format = SF_IEEE_FLOAT;
else
Format = SF_S32;
}
break;
case 64:
if (SampleType != WAVE_FORMAT_IEEE_FLOAT)
goto err3;
Format = SF_IEEE_DOUBLE;
break;
}
// Handle 24-bit samples individually
#if 0
if (SampleSize == 24 && Channels <= 2)
{
int ba24 = Channels * (SampleSize / 8); // Align to 4x
ba24 = (ba24 + 3) / 4 * 4;
if (block_align != ba24)
goto err3;
}
else
#endif
{
if (block_align != Channels * (SampleSize / 8))
goto err3;
}
if (avg_bps != block_align * SampleRate)
goto err3;
v = find_chunk(File, data);
if (v == 0 || v % block_align != 0)
goto err3;
TotalFrames = v / block_align;
FramesRead = 0;
if (FormatType == WAVE_FORMAT_EXTENSIBLE)
{
ChannelMask = *(unsigned int*)(&fmt[0x14]);
}
else
{
ChannelMask = 0;
}
FrameStartPos = ftell(File);
free(fmt);
m_bOK = true;
return;
err3:
free(fmt);
err2:
fclose(File);
File = NULL;
}
bool CWaveFile::GetStatus()
{
return m_bOK;
}
SAMPLE_FORMAT CWaveFile::GetFormat()
{
return Format;
}
int CWaveFile::GetTotalFrames()
{
return TotalFrames;
}
int CWaveFile::GetFramesRead()
{
return FramesRead;
}
CWaveFile::~CWaveFile()
{
if (File != NULL)
{
if (!ReadOnly)
{
unsigned int Size = ftell(File) - FrameStartPos;// 44;
fseek(File, FrameStartPos - 4, SEEK_SET);
fwrite(&Size, 4, 1, File);
Size += FrameStartPos - 8;
fseek(File, 4, SEEK_SET);
fwrite(&Size, 4, 1, File);
}
fclose(File);
}
}
int CWaveFile::GetSampleRate()
{
return SampleRate;
}
void CWaveFile::SetSampleRate(int SampleRate)
{
this->SampleRate = SampleRate;
}
void CWaveFile::SetupDone()
{
unsigned char Header[68];
fseek(File, 0, SEEK_SET);
SampleSize = Format & 0xFF;
if (ChannelMask)
{
memcpy(Header, wavmulti_header, sizeof(wavmulti_header));
if (Format < SF_IEEE_FLOAT)
{
// store2(Header + 20, WAVE_FORMAT_PCM);
store2(Header + 44, WAVE_FORMAT_PCM);
}
store2(Header + 22, Channels);
store4(Header + 24, SampleRate);
store4(Header + 28, SampleSize / 8 * SampleRate * Channels);
store2(Header + 32, SampleSize / 8 * Channels);
store2(Header + 34, SampleSize / 8 * 8);
store2(Header + 38, SampleSize / 8 * 8);
store4(Header + 40, ChannelMask);
fwrite(Header, sizeof(wavmulti_header), 1, File);
}
else
{
memcpy(Header, wav_header, sizeof(wav_header));
if (Format >= SF_IEEE_FLOAT)
{
store2(Header + 20, WAVE_FORMAT_IEEE_FLOAT);
}
store2(Header + 22, Channels);
store4(Header + 24, SampleRate);
store4(Header + 28, SampleSize / 8 * SampleRate * Channels);
store2(Header + 32, SampleSize / 8 * Channels);
store2(Header + 34, SampleSize / 8 * 8);
fwrite(Header, sizeof(wav_header), 1, File);
}
FrameStartPos = ftell(File);
}
void CWaveFile::Seek(int FramePos, int Where)
{
// Ignoring Where
fseek(File, FrameStartPos + FramePos * Channels* (SampleSize / 8), Where);
FramesRead = FramePos;
}
int CWaveFile::GetChannels()
{
return Channels;
}
void CWaveFile::SetChannels(int Channels)
{
this->Channels = Channels;
}
void CWaveFile::SetSampleFormat(SAMPLE_FORMAT Format)
{
this->Format = Format;
}
uint32_t CWaveFile::GetChannelMask()
{
return ChannelMask;
}
void CWaveFile::SetChannelMask(uint32_t Mask)
{
ChannelMask = Mask;
}
bool CWaveFile::ReadFrameAsS16(short* FrameSamples, int Frames)
{
if (FramesRead >= TotalFrames)
return false;
FramesRead += Frames;
switch (Format)
{
case SF_U8:
{
for (int frame = 0; frame < Frames; frame++)
{
for (int ch = 0; ch < Channels; ch++)
{
short DirectSample = 0;
if (1 == fread(&DirectSample, 1, 1, File))
{
FrameSamples[ch + frame*Channels] = (DirectSample - 128) << 8;
}
else
{
return false;
}
}
}
return true;
}
case SF_S16:
return Frames == fread(FrameSamples, sizeof(FrameSamples[0])*Channels, Frames, File);
case SF_S24:
{
for (int frame = 0; frame < Frames; frame++)
{
for (int ch = 0; ch < Channels; ch++)
{
unsigned int DirectSample = 0;
if (1 == fread(&DirectSample, 3, 1, File))
{
FrameSamples[ch + frame*Channels] = (short)(unsigned short)(DirectSample >> 8); // (short)(DirectSample * 32767.0 / ((1 << 24) - 1));
}
else
{
return false;
}
}
}
return true;
}
case SF_S32:
{
for (int frame = 0; frame < Frames; frame++)
{
for (int ch = 0; ch < Channels; ch++)
{
unsigned int DirectSample = 0;
if (1 == fread(&DirectSample, 4, 1, File))
{
FrameSamples[ch + frame*Channels] = (short)(unsigned short)(DirectSample >> 16); // (short)(DirectSample * 32767.0 / ((1 << 24) - 1));
}
else
{
return false;
}
}
}
return true;
}
case SF_IEEE_FLOAT:
{
float DirectSamples[32];
if (Frames == fread(DirectSamples, sizeof(DirectSamples[0]) * Channels, Frames, File))
{
for (int frame = 0; frame < Frames; frame++)
{
for (int ch = 0; ch < Channels; ch++)
{
FrameSamples[ch + frame*Channels] = (short)(DirectSamples[ch + frame*Channels] * 32768);
}
}
return true;
}
return false;
}
case SF_IEEE_DOUBLE:
{
double DirectSamples[32];
if (Frames == fread(DirectSamples, sizeof(DirectSamples[0]) * Channels, Frames, File))
{
for (int frame = 0; frame < Frames; frame++)
{
for (int ch = 0; ch < Channels; ch++)
{
FrameSamples[ch + frame*Channels] = (short)(DirectSamples[ch + frame*Channels] * 32768);
}
}
return true;
}
return false;
}
}
return false;
}
bool CWaveFile::ReadFrameAsfloat(float* FrameSamples, int Frames)
{
if (FramesRead >= TotalFrames)
return false;
FramesRead += Frames;
switch (Format)
{
case SF_U8:
{
for (int frame = 0; frame < Frames; frame++)
{
for (int ch = 0; ch < Channels; ch++)
{
short DirectSample = 0;
if (1 == fread(&DirectSample, 1, 1, File))
{
FrameSamples[ch + frame*Channels] = (DirectSample - 128) / 128.0; // (short)(DirectSample * 32767.0 / ((1 << 24) - 1));
}
else
{
return false;
}
}
}
return true;
}
case SF_S16:
{
for (int frame = 0; frame < Frames; frame++)
{
for (int ch = 0; ch < Channels; ch++)
{
short DirectSample = 0;
if (1 == fread(&DirectSample, 2, 1, File))
{
FrameSamples[ch + frame*Channels] = DirectSample / 32768.0; // (short)(DirectSample * 32767.0 / ((1 << 24) - 1));
}
else
{
return false;
}
}
}
return true;
}
case SF_S24:
{
for (int frame = 0; frame < Frames; frame++)
{
for (int ch = 0; ch < Channels; ch++)
{
uint32_t DirectSample = 0;
if (1 == fread(&DirectSample, 3, 1, File))
{
FrameSamples[ch + frame*Channels] = ((int32_t)((uint32_t)(DirectSample << 8))) /
(double)(((uint32_t)(1 << 31))); // (short)(DirectSample * 32767.0 / ((1 << 24) - 1));
}
else
{
return false;
}
}
}
return true;
}
case SF_S32:
{
for (int frame = 0; frame < Frames; frame++)
{
for (int ch = 0; ch < Channels; ch++)
{
uint32_t DirectSample = 0;
if (1 == fread(&DirectSample, 4, 1, File))
{
FrameSamples[ch + frame*Channels] = ((int32_t)((uint32_t)(DirectSample))) /
(double)(((uint32_t)(1 << 31))); // (short)(DirectSample * 32767.0 / ((1 << 24) - 1));
}
else
{
return false;
}
}
}
return true;
}
case SF_IEEE_FLOAT:
{
if(fread(FrameSamples, sizeof(FrameSamples[0]) * Channels, Frames, File))
{
return true;
}
return false;
// float DirectSamples[32];
//
// if (Frames == fread(DirectSamples, sizeof(DirectSamples[0]) * Channels, Frames, File))
// {
// for (int frame = 0; frame < Frames; frame++)
// {
// for (int ch = 0; ch < Channels; ch++)
// {
// FrameSamples[ch + frame*Channels] = (double)(DirectSamples[ch + frame*Channels]);
// }
// }
// return true;
// }
// return false;
}
case SF_IEEE_DOUBLE:
{
if (Frames == fread(FrameSamples, sizeof(FrameSamples[0]) * Channels, Frames, File))
{
return true;
}
return false;
}
}
return false;
}
bool CWaveFile::ReadFrameAsDouble(double* FrameSamples, int Frames)
{
if (FramesRead >= TotalFrames)
return false;
FramesRead += Frames;
switch (Format)
{
case SF_U8:
{
for (int frame = 0; frame < Frames; frame++)
{
for (int ch = 0; ch < Channels; ch++)
{
short DirectSample = 0;
if (1 == fread(&DirectSample, 1, 1, File))
{
FrameSamples[ch + frame*Channels] = (DirectSample - 128) / 128.0; // (short)(DirectSample * 32767.0 / ((1 << 24) - 1));
}
else
{
return false;
}
}
}
return true;
}
case SF_S16:
{
for (int frame = 0; frame < Frames; frame++)
{
for (int ch = 0; ch < Channels; ch++)
{
short DirectSample = 0;
if (1 == fread(&DirectSample, 2, 1, File))
{
FrameSamples[ch + frame*Channels] = DirectSample / 32768.0; // (short)(DirectSample * 32767.0 / ((1 << 24) - 1));
}
else
{
return false;
}
}
}
return true;
}
case SF_S24:
{
for (int frame = 0; frame < Frames; frame++)
{
for (int ch = 0; ch < Channels; ch++)
{
uint32_t DirectSample = 0;
if (1 == fread(&DirectSample, 3, 1, File))
{
FrameSamples[ch + frame*Channels] = ((int32_t)((uint32_t)(DirectSample << 8))) /
(double)(((uint32_t)(1 << 31))); // (short)(DirectSample * 32767.0 / ((1 << 24) - 1));
}
else
{
return false;
}
}
}
return true;
}
case SF_S32:
{
for (int frame = 0; frame < Frames; frame++)
{
for (int ch = 0; ch < Channels; ch++)
{
uint32_t DirectSample = 0;
if (1 == fread(&DirectSample, 4, 1, File))
{
FrameSamples[ch + frame*Channels] = ((int32_t)((uint32_t)(DirectSample ))) /
(double)(((uint32_t)(1 << 31))); // (short)(DirectSample * 32767.0 / ((1 << 24) - 1));
}
else
{
return false;
}
}
}
return true;
}
case SF_IEEE_FLOAT:
{
float DirectSamples[32];
if (Frames == fread(DirectSamples, sizeof(DirectSamples[0]) * Channels, Frames, File))
{
for (int frame = 0; frame < Frames; frame++)
{
for (int ch = 0; ch < Channels; ch++)
{
FrameSamples[ch + frame*Channels] = (double)(DirectSamples[ch + frame*Channels]);
}
}
return true;
}
return false;
}
case SF_IEEE_DOUBLE:
{
if (Frames == fread(FrameSamples, sizeof(FrameSamples[0]) * Channels, Frames, File))
{
return true;
}
return false;
}
}
return false;
}
void CWaveFile::WriteRaw(void* Raw, int Size)
{
fwrite(Raw, Size, 1, File);
}
void CWaveFile::WriteFrame(uint8_t* FrameSamples, int Frames)
{
fwrite(FrameSamples, sizeof(FrameSamples[0]) * Channels, Frames, File);
}
void CWaveFile::WriteFrame(short* FrameSamples, int Frames)
{
fwrite(FrameSamples, sizeof(FrameSamples[0]) * Channels, Frames, File);
}
void CWaveFile::WriteFrame(int32_t* FrameSamples, int Frames)
{
fwrite(FrameSamples, sizeof(FrameSamples[0]) * Channels, Frames, File);
}
void CWaveFile::WriteFrameS24(int32_t* FrameSamples, int Frames)
{
for (int c = 0; c < Channels; c++)
{
fwrite(&FrameSamples[c], 3, 1, File);
}
}
void CWaveFile::WriteFrame(double* FrameSamples, int Frames)
{
fwrite(FrameSamples, sizeof(FrameSamples[0]) * Channels, Frames, File);
}
void CWaveFile::WriteFrame(float* FrameSamples, int Frames)
{
fwrite(FrameSamples, sizeof(FrameSamples[0]) * Channels, Frames, File);
}
double CWaveFile::GetDuration()
{
return Duration;
}

File Metadata

Mime Type
text/x-c
Expires
Sun, Jan 12, 01:52 (1 d, 4 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1347128
Default Alt Text
WaveFile.cpp (19 KB)

Event Timeline