参考资料:
https://www.cnblogs.com/guojun-junguo/p/10129548.html
http://www.topherlee.com/software/pcm-tut-wavformat.html
http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/Samples.html
https://datatracker.ietf.org/doc/html/draft-ema-vpim-wav-00.txt
https://blog.ibaoger.com/2016/09/21/waveform-audio-file-format/
Wave文件包括Header和Data,其中Header结构如下:
The header of a WAV (RIFF) file is 44 bytes long and has the following format:
Positions | Sample Value | Description |
---|---|---|
1 - 4 | “RIFF” | Marks the file as a riff file. Characters are each 1 byte long. |
5 - 8 | File size (integer) | Size of the overall file - 8 bytes, in bytes (32-bit integer). Typically, you’d fill this in after creation. |
9 -12 | “WAVE” | File Type Header. For our purposes, it always equals “WAVE”. |
13-16 | "fmt " | Format chunk marker. Includes trailing null |
17-20 | 16 | Length of format data as listed above |
21-22 | 1 | Type of format (1 is PCM) - 2 byte integer |
23-24 | 2 | Number of Channels - 2 byte integer |
25-28 | 44100 | Sample Rate - 32 byte integer. Common values are 44100 (CD), 48000 (DAT). Sample Rate = Number of Samples per second, or Hertz. |
29-32 | 176400 | (Sample Rate * BitsPerSample * Channels) / 8. |
33-34 | 4 | (BitsPerSample * Channels) / 8.1 - 8 bit mono2 - 8 bit stereo/16 bit mono4 - 16 bit stereo |
35-36 | 16 | Bits per sample |
37-40 | “data” | “data” chunk header. Marks the beginning of the data section. |
41-44 | File size (data) | Size of the data section. |
Sample values are given above for a 16-bit stereo source.
具体结构体定义如下:
typedef struct WAV_RIFF {
/* chunk "riff" */
char ChunkID[4]; /* "RIFF" */
/* sub-chunk-size */
uint32_t ChunkSize; /* 36 + Subchunk2Size */
/* sub-chunk-data */
char Format[4]; /* "WAVE" */
} RIFF_t;
typedef struct WAV_FMT {
/* sub-chunk "fmt" */
char Subchunk1ID[4]; /* "fmt " */
/* sub-chunk-size */
uint32_t Subchunk1Size; /* 16 for PCM */
/* sub-chunk-data */
uint16_t AudioFormat; /* PCM = 1*/
uint16_t NumChannels; /* Mono = 1, Stereo = 2, etc. */
uint32_t SampleRate; /* 8000, 44100, etc. */
uint32_t ByteRate; /* = SampleRate * NumChannels * BitsPerSample/8 */
uint16_t BlockAlign; /* = NumChannels * BitsPerSample/8 */
uint16_t BitsPerSample; /* 8bits, 16bits, etc. */
} FMT_t;
typedef struct WAV_data {
/* sub-chunk "data" */
char Subchunk2ID[4]; /* "data" */
/* sub-chunk-size */
uint32_t Subchunk2Size; /* data size */
/* sub-chunk-data */
// Data_block_t block;
} Data_t;
typedef struct WAV_fotmat {
RIFF_t riff;
FMT_t fmt;
Data_t data;
} Wav;
一个标准的wave文件header示例:
const Wav wav = {
{
"RIFF", //RIFF marker
9356, //file-size (equals file-size - 8)
"WAVE", //Mark it as type "WAVE"
},
{
"fmt", //Mark the format section.
16, //Length of format data. Always 16
1, //Wave type PCM
1, //1 channel(or 2 channels)
44100, //44.1 kHz Sample Rate (CD-Quality)
88200, //(Sample Rate * Bit Size * Channels) / 8
2, //(Bit Size * Channels) / 8
16, //Bits per sample (=Bit Size * Samples)
},
{
"data", //"data" marker
9320, //data-size (equals file-size - 44).
}
};
将wave文件数据保存在头文件中:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <stdbool.h>
#include <gulliver.h>
#include <sys/stat.h>
#define u8 unsigned char
#define u16 unsigned short
#define u32 unsigned long
#define FILE_SCALE 8 //音频文件质量 8或16
//44字节
typedef struct {
u8 riff_mark[4]; //
u32 file_size;
u8 wave_str[4];
u8 fmt_str[4];
u32 pcm_bit_num;
u16 pcm_encode;
u16 sound_channel;
u32 pcm_sample_freq;
u32 byte_freq;
u16 block_alin;
u16 sample_bits;
u8 data_str[4];
u32 sound_size;
} WAV_Typedef;
WAV_Typedef WAVFile_Array;
u16 *Sound_Data;
u8 *Read_Sound_Data;
/* wave head */
struct RIFF_CHUNK
{
char riffid[4];
int32_t dwSize;
char riffType[4];
};
typedef struct RIFF_CHUNK WAVE_HEADER;
struct FORMAT_CHUNK
{
char fccid[4];
int32_t dwSize;
short wFormatTag;
short wChannels;
int32_t dwSamplesPerSec;
int32_t dwAvgBytePerSec;
short wBlockAlign;
short uiBitsPerSample;
};
typedef struct FORMAT_CHUNK WAVE_FORMAT;
struct DATA_CHUNK
{
char fccid[4];
int32_t dwSize;
};
typedef struct DATA_CHUNK WAVE_DATA;
char *mWaveDataBuffer;
typedef struct WAV_RIFF {
/* chunk "riff" */
char ChunkID[4]; /* "RIFF" */
/* sub-chunk-size */
uint32_t ChunkSize; /* 36 + Subchunk2Size */
/* sub-chunk-data */
char Format[4]; /* "WAVE" */
} RIFF_t;
typedef struct WAV_FMT {
/* sub-chunk "fmt" */
char Subchunk1ID[4]; /* "fmt " */
/* sub-chunk-size */
uint32_t Subchunk1Size; /* 16 for PCM */
/* sub-chunk-data */
uint16_t AudioFormat; /* PCM = 1*/
uint16_t NumChannels; /* Mono = 1, Stereo = 2, etc. */
uint32_t SampleRate; /* 8000, 44100, etc. */
uint32_t ByteRate; /* = SampleRate * NumChannels * BitsPerSample/8 */
uint16_t BlockAlign; /* = NumChannels * BitsPerSample/8 */
uint16_t BitsPerSample; /* 8bits, 16bits, etc. */
} FMT_t;
typedef struct WAV_data {
/* sub-chunk "data" */
char Subchunk2ID[4]; /* "data" */
/* sub-chunk-size */
uint32_t Subchunk2Size; /* data size */
/* sub-chunk-data */
// Data_block_t block;
} Data_t;
//typedef struct WAV_data_block {
//} Data_block_t;
typedef struct WAV_fotmat {
RIFF_t riff;
FMT_t fmt;
Data_t data;
} Wav;
int main()
{
FILE *fp,*fw;
int ret;
int i;
int numOfword;
WAVE_HEADER WaveHeader;
WAVE_FORMAT WaveFormat;
WAVE_DATA WaveData;
Wav wav;
RIFF_t riff;
FMT_t fmt;
Data_t data;
if((fp=fopen("/fs/mmc2/touch1.wav","rb"))==NULL) //打开操作不成功
return 1;
if((fw=fopen("/fs/mmc2/wav_out.h","w"))==NULL) //打开操作不成功
return 1;
/*
fread(&wav, 1, sizeof(wav), fp);
riff = wav.riff;
fmt = wav.fmt;
data = wav.data;
printf("ChunkID \t%c%c%c%c\n", riff.ChunkID[0], riff.ChunkID[1], riff.ChunkID[2], riff.ChunkID[3]);
printf("ChunkSize \t%d\n", riff.ChunkSize);
printf("Format \t\t%c%c%c%c\n", riff.Format[0], riff.Format[1], riff.Format[2], riff.Format[3]);
printf("\n");
printf("Subchunk1ID \t%c%c%c%c\n", fmt.Subchunk1ID[0], fmt.Subchunk1ID[1], fmt.Subchunk1ID[2], fmt.Subchunk1ID[3]);
printf("Subchunk1Size \t%d\n", fmt.Subchunk1Size);
printf("AudioFormat \t%d\n", fmt.AudioFormat);
printf("NumChannels \t%d\n", fmt.NumChannels);
printf("SampleRate \t%d\n", fmt.SampleRate);
printf("ByteRate \t%d\n", fmt.ByteRate);
printf("BlockAlign \t%d\n", fmt.BlockAlign);
printf("BitsPerSample \t%d\n", fmt.BitsPerSample);
printf("\n");
printf("blockID \t%c%c%c%c\n", data.Subchunk2ID[0], data.Subchunk2ID[1], data.Subchunk2ID[2], data.Subchunk2ID[3]);
printf("blockSize \t%d\n", data.Subchunk2Size);
printf("\n");
printf("duration \t%d\n", data.Subchunk2Size / fmt.ByteRate);
*/
printf("sizeof(WaveHeader)=%d\n",sizeof(WaveHeader));
printf("sizeof(WaveFormat)=%d\n",sizeof(WaveFormat));
printf("sizeof(WaveData)=%d\n",sizeof(WaveData));
if(fread(&WaveHeader,sizeof(WaveHeader),1,fp)==1)
printf("WaveHeader read ok!\n");
if(fread(&WaveFormat,sizeof(WaveFormat),1,fp)==1)
printf("WaveFormat read ok!\n");
if(fread(&WaveData,sizeof(WaveData),1,fp)==1)
printf("WaveData read ok!\n");
printf("资源交换文件标志: %.4s\n",WaveHeader.riffid);
printf("文件大小: %d\n",WaveHeader.dwSize);
printf("文件格式: %.4s\n",WaveHeader.riffType);
printf("波形格式: %.4s\n",WaveFormat.fccid);
printf("PCM: %dbits\n",WaveFormat.dwSize);
printf("声道: %s\n",WaveFormat.wChannels==1?"单声道":"双声道");
printf("采样速率: %d\n",WaveFormat.dwSamplesPerSec);
printf("码率: %d Bps\n",WaveFormat.dwAvgBytePerSec);
printf("块对齐: %d\n",WaveFormat.wBlockAlign);
printf("采样位宽: %d\n",WaveFormat.uiBitsPerSample);
printf("Data标志: %.4s\n",WaveData.fccid);
printf("声音数据大小: %d\n",WaveData.dwSize);
mWaveDataBuffer = malloc(WaveData.dwSize);
numOfword = fread(mWaveDataBuffer,sizeof(char),WaveData.dwSize/sizeof(char),fp);
printf("WaveData.dwSize/sizeof(short): %d\n",WaveData.dwSize/sizeof(char));
printf("numOfword: %d\n",numOfword);
//fwrite(&WaveHeader,sizeof(WAVE_HEADER),1,fw);
//fwrite(&WaveFormat,sizeof(WAVE_FORMAT),1,fw);
//fwrite(&WaveData,sizeof(WAVE_DATA),1,fw);
//fwrite(mWaveDataBuffer,sizeof(short),numOfword,fw);
{
int idx=0;
int line_count=0;
fprintf(fw,"#ifndef __SOUND_DATA_H__\n");
fprintf(fw,"#define __SOUND_DATA_H__\n\n");
fprintf(fw,"#define SOUND_LENGTH\t%d\n\n",WaveData.dwSize);
fprintf(fw,"const unsigned char WAVE_DATA[SOUND_LENGTH] = {\n\t");
for(i = 0;i < WaveData.dwSize/sizeof(char); i++)
{
fprintf(fw,"%02x, ",(mWaveDataBuffer[idx] & 0xff));
idx++;
line_count++;
if(line_count>8-1)
{
line_count=0;
fprintf(fw,"\n\t");
}
}
fprintf(fw,"\n};\n#endif\n");
printf("\n ***** 已转换成头文件 wav_out.h *****\n");
}
if(mWaveDataBuffer){
free(mWaveDataBuffer);
mWaveDataBuffer = NULL;
}
if(fp!=NULL)
fclose(fp);
if(fw!=NULL)
fclose(fw);
return 0;
}