Monday, September 08, 2008

C语言读写wav文件的程序

下面是一个C语言写的读写Wav文件的演示程序代码。
给出了常用的PCM格式WAV头的类型定义,可以直接拿去使用。
程序有两个部分,第一个部分读取一个WAV文件并且给出该WAV文件的基本信息(声道数,采样率...)
第二个部分生成了一个 16K,双声道,每个采样点用16bits量化的WAV文件。
/*********************************************************/
// WaveHeader.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
// Microsoft wav pcm sound file format. Normal 44 bytes header
typedef struct _tagMsWavPcmHeader44{
unsigned char ChunkID[4]; // "RIFF"; The "RIFF" the mainchunk;
unsigned long ChunkSize; // FileSize - 8; The size following this data
unsigned char Format[4]; // "WAVE"; The "WAVE" format consists of two subchunks: "fmt " and "data"
unsigned char SubChunk1ID[4]; // "fmt "
unsigned long SubChunk1Size; // 16 for PCM. This is the size of the rest of the subchunk which follows this data.
unsigned short AudioFormat; // 1 for PCM. Linear quantization
unsigned short NumChannels; // 1->Mono, 2->stereo, etc..
unsigned long SampleRate; // 8000, 11025, 16000, 44100, 48000, etc..
unsigned long ByteRate; // = SampleRate * NumChannels * BitsPerSample/8
unsigned short BlockAlign; // = NumChannels * BitsPerSample / 8
unsigned short BitsPerSample; // 8->8bits, 16->16bits, etc..
unsigned char SubChunk2ID[4]; // "data"
unsigned long SubChun2Size; // = NumSamples * NumChannels * BitsPerSample / 8. The size of data
} wav_pcm_header44;
void wave_generator(FILE *fpwav, wav_pcm_header44 *phwav);
void main(int argc, char **argv)
{
FILE *fpWav=NULL;
unsigned long size;
wav_pcm_header44 hwav;
if (argc < 3)
{
printf("Missing parameters:\nFormat: WaveIn.wav WaveOut.wav\n");
return ;
}
/*
* 1. Get wave header information demo
*/
fpWav = fopen(argv[1], "rb");
if (fpWav)
{
fread(&hwav, sizeof(wav_pcm_header44), 1, fpWav);
/* Check wave header */
if ( (0==memcmp(hwav.ChunkID, "RIFF", 4)) &&
(0==memcmp(hwav.Format, "WAVE", 4)) &&
(0==memcmp(hwav.SubChunk1ID, "fmt ", 4)) &&
(0==memcmp(hwav.SubChunk2ID, "data", 4)) &&
(1==hwav.AudioFormat))
{
printf("Wave audio data format:\n");
printf("Channel number: %d\n", hwav.NumChannels);
printf("SampleRate: %dHz\n", hwav.SampleRate);
printf("BitsPerSample: %dbits\n", hwav.BitsPerSample);
printf("Audio data size:%d\n", hwav.SubChun2Size);
}
fclose(fpWav);
fpWav = NULL;
}
else
{
printf("Open wave file %s failed!\n", argv[1]);
}
/*
* 2. Generate wave file demo
*/
fpWav = fopen(argv[2], "wb+");
if (fpWav)
{
/* initial wave file header */
memcpy(hwav.ChunkID, "RIFF", 4);
hwav.ChunkSize = sizeof(wav_pcm_header44) - 8;
memcpy(hwav.Format, "WAVE", 4);
memcpy(hwav.SubChunk1ID, "fmt ", 4);
hwav.SubChunk1Size = 16;
hwav.AudioFormat = 1;
hwav.NumChannels = 2; // set channels as stereo
hwav.SampleRate = 16000; // set sample rate as 16KHz
hwav.BitsPerSample = 16; // set one sample use 16bits
hwav.ByteRate = hwav.SampleRate * hwav.NumChannels * hwav.BitsPerSample / 8;
hwav.BlockAlign = hwav.NumChannels * hwav.BitsPerSample / 8;
memcpy(hwav.SubChunk2ID, "data", 4);
hwav.SubChun2Size = 0;
// 1. pre write wave header
fwrite(&hwav, sizeof(wav_pcm_header44), 1, fpWav);
// 2. write wave data
wave_generator(fpWav, &hwav);
// 3. rewrite wave header
fseek(fpWav, 0, SEEK_END);
size = ftell(fpWav); // get file size
fseek(fpWav, 0, SEEK_SET);
hwav.ChunkSize = size - 8; // update size
hwav.SubChun2Size = size - sizeof(wav_pcm_header44);
fwrite(&hwav, sizeof(wav_pcm_header44), 1, fpWav);
fclose(fpWav);
}
else
{
printf("Create wave file %s failed!\n", argv[2]);
}
}
#define PI 3.1415926535897932384626433832795
void wave_generator(FILE *fpwav, wav_pcm_header44 *phwav)
{
int i, j;
double phase = 0;
double inc = 0, fout;
short vout;
if (16 != phwav->BitsPerSample)
{
printf("Wave generator don't support this format\n");
return;
}
// Generate 1Khz
inc = 2*PI*1000/phwav->SampleRate;
for (i=0; i<65536; i++) // generate 65536 blocks
{
phase += inc;
if (phase >= 2*PI)
{
phase -= 2*PI;
}
fout = sin(phase); // get 1KHz sin wave
for(j=0; j<phwav->NumChannels; j++) // for NumChannels
{
vout = (short)(32767 * fout);
fwrite(&vout, sizeof(short), 1, fpwav);
fout *= fout; // for next channel
}
}
}