C语言解析wav文件的信息

wav文件格式

wav的文件格式如下图所示,这张图在很多地方都有,这张图完整的说明了wav文件的数据组成情况
C语言解析wav文件的信息_第1张图片
按照图上的描述,一个wav文件的数据组成,应该如下所示

chunk名称 偏移地址 数据长度(byte) 字段名称 字段说明
RIFF 00H 4 ChunkID 固定为大写字符串"RIFF"
RIFF 04H 4 Chunk Size 从下一个字段首地址开始到文件末尾的总字节数。该字段的数值加 8 为当前文件的实际长度
RIFF 08H 4 Format 所有 WAV 格式的文件此处为字符串"WAVE",标明该文件是 WAV 格式文件
fmt 0CH 4 Subchank ID 固定为小写字符串"fmt "
fmt 10H 4 Subchank Size fmt这个chunk的长度
fmt 14H 2 AudioFormat 这个文件中的音频编码格式见后面的表
fmt 16H 2 NumChannels 声道数量
fmt 18H 4 SampleRate 采样率例如48000,44100等
fmt 1CH 4 ByteRate 数据传输速率,播放这个文件时缓冲区的最小大小 = NumChannels * BitsPerSample/8
fmt 20H 2 BlockAlign 每个采样所需的字节数 = NumChannels * BitsPerSample / 8
fmt 22H 2 BitsPerSample 采样位数,8bit,16bit,32bit等
RIFF 24H 4 Subchank2 ID 固定为字符串data
RIFF 28H 4 Subchank2 Size 整个datachunk的长度
RIFF 2CH 4 data 原始的PCM数据

对于AudioFormat,一般有以下几种,不同的AudioFormat, fmt的长度是不一样的

enum Encod_format_PCM{          //fmt lenth
    PCM = 0x01,                 //16
    Microsoft_ADPCM,            //18
    IEEE_float,                 //18
    ITU_G_711_a_law = 0x06,     //18
    ITU_G_711_u_law,            //18
    GSM_6_10 = 0x31,            //20
    ITU_G_721_ADPCM = 0x40,     //
};

PCM数据的存放方式

PCM音频格式就是没有经过压缩的格式,这种格式解析起来比较方便,但占用存储空间较大.
在PCM编码的wav文件中,PCM数据就是存储在data里面的,以小端方式存储,数据的低位保存在内存的低地址中,而数据的高位保存在内存的高地址中.
PCM数据类型
8Bit 单声道

低地址---------------------------------->高地址
声道1数据0	声道1数据1	声道1数据2	声道1数据3  

8Bit 双声道

声道1数据0	声道2数据0	声道1数据1	声道2数据1

16Bit 单声道

低地址---------------------------------->高地址
声道0低位,声道0高位	声道0低位,声道0高位

16Bit 双声道

低地址---------------------------------->高地址
声道0低位,声道0高位	声道1低位,声道1高位

C语言解析代码

wav_parse.h
头文件,包含了数据结构的定义

#ifndef WAV_TEST
#define WAV_TEST

#include "string"

using namespace std;

class Wav_File{
//RIFF chunk
public:
    Wav_File(char *paths);
    //int Save_wav_file(char *paths, WAV_file *wav_file);
    //int Modify_Volume(WAV_file *wav_file, int change_val);

private:
    string paths;
    /* chunk "riff" */
    char Wav_RIFF_ChunkID[4];     /* "RIFF" */
    /* sub-chunk-size */
    unsigned int  Wav_RIFF_ChunkSize;  /* 36 + Subchunk2Size */
    /* sub-chunk-data */
    char Wav_RIFF_Type[4];      /* "WAVE" */

    /* sub-chunk "fmt" */
    char Wav_Fmt_ID[4];    /* "fmt " */
    /* sub-chunk-size */
    unsigned int Wav_Fmt_ChunkSize; /* 16 for PCM */
    /* sub-chunk-data */
    unsigned int Wav_Fmt_AudioFormat;   /* PCM = 1*/
    unsigned int Wav_Fmt_NumChannels;   /* Mono = 1, Stereo = 2, etc. */
    unsigned int Wav_Fmt_SampleRate;    /* 8000, 44100, 48000, etc. */
    unsigned int Wav_Fmt_ByteRate;      /* = SampleRate * NumChannels * BitsPerSample/8 */
    short Wav_Fmt_BlockAlign;    /* = NumChannels * BitsPerSample/8 */
    unsigned int Wav_Fmt_BitsPerSample; /* 8bits, 16bits, 32bits, etc. */

    /* sub-chunk "data" */
    char Wav_Data_ID[4];    /* "data" */
    /* sub-chunk-size */
    unsigned int Wav_Data_Size; /* data size */
    /* sub-chunk-data */
//    Data_block_t block;
    char *Wav_Data_RawData;

};
#endif // WAV_TEST

wav_parse.cpp
真正的解析代码,可以解析出wav的数据头,以及获取到data的指针,可以对data直接进行操作.

#include "stdio.h"
#include "stdlib.h"
#include "wav_parse.h"
#include "string.h"
#include "math.h"

static int Find_str(const char *str_orig,const char *obj_str)
{
    int i = 0;
    for(i = 0;i >= 0;i++)
    {
        if( (*(str_orig+i)) == (*obj_str))
        {
            {
                if((*(str_orig+i+1)) == (*(obj_str+1)))
                    break;
            }
        }
    }
    return i;
}

Wav_File::Wav_File(char *paths)
{
    FILE *wav_file = NULL;
    unsigned int current_file_pos = 0;
	unsigned int file_size;
    char *orig_buffer;
    int data_pos = 0;
    int fmt_pos = 0;

    this->paths = paths;

	fprintf(stderr,"zrh_test\n");

	wav_file = fopen(paths,"rb");
	if (wav_file == NULL)
    {
        //
        fprintf(stderr,"%s open failed\n",paths);
        goto out2;
    }

//get file size
	current_file_pos = ftell(wav_file);
	fseek(wav_file,0,SEEK_END);
	file_size = ftell(wav_file);
	fseek( wav_file,current_file_pos,SEEK_SET );    //back to 0 pos
	fprintf(stderr,"file_size = %d\n",file_size);

	orig_buffer = (char *)malloc(file_size);
	fread(orig_buffer,file_size,1,wav_file);

    data_pos = Find_str(orig_buffer,"data");
    fmt_pos = Find_str(orig_buffer,"fmt");

    fprintf(stderr, "Find fmt pos i = %d\n",fmt_pos);
    fprintf(stderr, "Find data pos i = %d\n",data_pos);

//get riff chunk data	全是魔鬼数字,根据前面的长度定义,取出各个数据
    memcpy(Wav_RIFF_ChunkID ,orig_buffer ,4);                  //ID
    Wav_RIFF_ChunkSize = *((unsigned int*)(orig_buffer+4));    //SIZE
    fprintf(stderr, "Wav_RIFF_ChunkSize = %d\n",Wav_RIFF_ChunkSize);    //TYPE
    memcpy(Wav_RIFF_Type ,orig_buffer+8 ,4);

//get format chunk data	
    memcpy(Wav_Fmt_ID,orig_buffer+fmt_pos ,4);                         //ID
    Wav_Fmt_ChunkSize = *((unsigned int*)(orig_buffer+fmt_pos+4));     //Size
    Wav_Fmt_AudioFormat = *((short*)(orig_buffer+fmt_pos+4+4));        //AudioFormat
    Wav_Fmt_NumChannels = *((short*)(orig_buffer+fmt_pos+4+4+2));      //NumChannels
    Wav_Fmt_SampleRate = *((unsigned int*)(orig_buffer+fmt_pos+4+4+2+2));    //SampleRate
    Wav_Fmt_BlockAlign = *((short*)(orig_buffer+fmt_pos+4+4+2+2+4+4));    //BlockAlign
    Wav_Fmt_ByteRate = *((unsigned int*)(orig_buffer+fmt_pos+4+4+2+2+4));    //ByteRate



    Wav_Fmt_BitsPerSample = *((short*)(orig_buffer+fmt_pos+4+4+2+2+4+4+2));    //BitsPerSample

//get data chunk data
    memcpy(Wav_Data_ID,orig_buffer+data_pos ,4);                         //ID
    fprintf(stderr,"Wav_Fmt_ID = %x\n",*((unsigned int*)(orig_buffer+data_pos)));
    Wav_Data_Size = *((unsigned int*)(orig_buffer+data_pos+4));//Size
    Wav_Data_RawData = (char *)malloc(Wav_Data_Size);		//给data分配内存,太大的wav文件会失败
    if(Wav_Data_RawData == NULL)
    {
        fprintf(stderr,"Alloc Wav_Data_RawData failed\n");
        goto out1;
    }
    memcpy(Wav_Data_RawData, orig_buffer+data_pos+4+4,Wav_Data_Size);	//将data的数据全部拷贝到结构体中

//printf Wav file message
    fprintf(stderr,"Wav_Fmt_AudioFormat = %d\n",Wav_Fmt_AudioFormat);
    fprintf(stderr,"Wav_Fmt_NumChannels = %d\n",Wav_Fmt_NumChannels);
    fprintf(stderr,"Wav_Fmt_SampleRate = %d\n",Wav_Fmt_SampleRate);
    fprintf(stderr,"Wav_Fmt_ByteRate = %d\n",Wav_Fmt_ByteRate);
    fprintf(stderr,"Wav_Fmt_BlockAlign = %d\n",Wav_Fmt_BlockAlign);
    fprintf(stderr,"Wav_Fmt_BitsPerSample = %d\n",Wav_Fmt_BitsPerSample);
    fprintf(stderr,"Wav_Data_Size = %x\n",Wav_Data_Size);

    fclose(wav_file);
	free(orig_buffer);
	return;
out1:
    fclose(wav_file);
    fprintf(stderr, "zrh_test:exit -1");
out2:
    fprintf(stderr, "zrh_test:exit -2");
}
/*将读取到的数据重新保存为一个wav,可以在对data进行一系列操作之后,再重新另存为文件
int Save_wav_file(char *paths, WAV_file *wav_file)
{
    FILE *save_wav_file = NULL;
    int i,j;

    unsigned int current_file_pos = 0;
	unsigned int file_size;
    char *orig_buffer = NULL;


    printf("%s:wav_file addr  = %p\n",__func__,wav_file);
    fprintf(stderr,"%s:enter\n",__func__);
    fprintf(stderr,"%s:file_size = %d\n",__func__, (wav_file->riff.ChunkSize+8));

    orig_buffer = malloc((wav_file->riff.ChunkSize)+8);
    if(orig_buffer == NULL)
    {
        fprintf(stderr,"%s:failed to malloc orig_buffer!!!\n",__func__);
        return -1;
    }

    fprintf(stderr, "%s:Ready to open file:\n",__func__);
//restore data from WAV_file
//riff
    memcpy(orig_buffer, wav_file->riff.ChunkID,4);                  //ID
    *((unsigned int*)(orig_buffer+4)) = wav_file->riff.ChunkSize ;    //SIZE
    memcpy(orig_buffer+8 ,wav_file->riff.Type ,4);

//get format chunk data
    memcpy(orig_buffer+fmt_pos,wav_file->fmt.ID ,4);                         //ID
    *((unsigned int*)(orig_buffer+fmt_pos+4)) = wav_file->fmt.ChunkSize ;     //Size
    *((short*)(orig_buffer+fmt_pos+4+4)) = wav_file->fmt.AudioFormat;        //AudioFormat
    *((short*)(orig_buffer+fmt_pos+4+4+2)) = wav_file->fmt.NumChannels;      //NumChannels
    *((unsigned int*)(orig_buffer+fmt_pos+4+4+2+2)) = wav_file->fmt.SampleRate;    //SampleRate
     *((short*)(orig_buffer+fmt_pos+4+4+2+2+4+4)) = wav_file->fmt.BlockAlign;    //BlockAlign
    *((unsigned int*)(orig_buffer+fmt_pos+4+4+2+2+4)) = wav_file->fmt.ByteRate;    //ByteRate
    *((short*)(orig_buffer+fmt_pos+4+4+2+2+4+4+2)) = wav_file->fmt.BitsPerSample;    //BitsPerSample

    memcpy(orig_buffer+data_pos,wav_file->data.ID,4);                         //ID
    *((unsigned int*)(orig_buffer+data_pos+4)) = wav_file->data.Size;//Size
     int t_val = 0;
     t_val = memcpy(orig_buffer+data_pos+4+4, wav_file->data.RawData,wav_file->data.Size);
     fprintf(stderr, "%s:wave data size = %d,malloc succeed in %d\n",__func__,wav_file->data.Size, t_val);

     fprintf(stderr, "%s:start to write file:\n",__func__);

//restore end
    save_wav_file = fopen(paths,"wb+");

    float max = 100,tmp = 0;
    for(i = 0;i < wav_file->data.Size; )
    {
        //fprintf(stderr, "%s:zrh_test:before = %x\n",__func__, *((int*)(orig_buffer+data_pos+4+4+i)));
        //fprintf(stderr, "%s:zrh_test:before = %d\n",__func__, Get_Volume (*((int*)(orig_buffer+data_pos+4+4+i))));
        //Get_Volume (*((int*)(orig_buffer+data_pos+4+4+i)));
        for(j=0;j<20;j++)
        {

            if(*((short*)(orig_buffer+data_pos+4+4+i)) == 0)
            {
                i = i+2;
                continue;
            }
            tmp = Get_Volume(*((short*)(orig_buffer+data_pos+4+4+i)));
            i = i+2;
        }
        if(max > (tmp/20))
                max = tmp;
        tmp=0;
        //fprintf(stderr, "%s:zrh_test:before = %d\n",__func__, (*(( int*)(orig_buffer+data_pos+4+4+i))));           //int
        //*((float*)(orig_buffer+data_pos+4+4+i)) = ((*((float*)(orig_buffer+data_pos+4+4+i))) * 8);        //195553 383999
        //fprintf(stderr, "%s:zrh_test:after = %d\n",__func__, *((int*)(orig_buffer+data_pos+4+4+(i/4))));
    }
    fprintf(stderr, "Max volume = %f\n", max);

    fwrite(orig_buffer, (wav_file->riff.ChunkSize)+8, 1, save_wav_file);



    fclose(save_wav_file);
	return 0;
}
*/

/*
float Get_Volume( short value)
{
    if(value == 0)
        return 0;
    float db = 0;
    value = abs(value);
    db = 20.0*(log10(32767) - log10(value));
    //fprintf(stderr, "%s:zrh_test:value = %d\n",__func__, value);
    //fprintf(stderr, "%s:zrh_test:value = %f\n",__func__, db);     //190820720
    return db;
}
*/

还有就是main函数

#include 
#include 
#include "wav_parse.h"
#include 
#include 
#include 

// 256
// 768

int main()
{
    Wav_File *z1 = new Wav_File("wave.wav");
    //fprintf(stderr,"%s:orig_wav_file addr  = %p\n",__func__,orig_wav_file);

    return 0;
}

你可能感兴趣的:(安卓音频)