wav概述

WAV为微软公司(Microsoft)开发的一种声音文件格式,它符合RIFF(Resource
Interchange File Format)文件规范,用于保存Windows平台的音频信息资源,被Windows平台及其应用程序所广泛支持,该格式也支持MSADPCM,CCITT
A LAW等多种压缩运算法,支持多种音频数字,取样频率和声道,标准格式化的WAV文件和CD格式一样,也是44.1K的取样频率,16位量化数字,因此在声音文件质量和CD相差无几! WAV打开工具是WINDOWS的媒体播放器

通常使用三个参数来表示声音,量化位数,取样频率和采样点振幅。量化位数分为8位,16位,24位三种,声道有单声道和立体声之分,单声道振幅数据为n*1矩阵点,立体声为n*2矩阵点,取样频率一般有11025Hz(11kHz)
,22050Hz(22kHz)和44100Hz(44kHz) 三种,不过尽管音质出色,但在压缩后的文件体积过大!相对其他音频格式而言是一个缺点,其文件大小的计算方式为:WAV格式文件所占容量(B)
= (取样频率 X量化位数X 声道) X 时间 / 8 (字节=
8bit) 每一分钟WAV格式的音频文件的大小为10MB,其大小不随音量大小及清晰度的变化而变化。

支持WAV设计的手机主要为智能手机,如索尼爱立信P910和诺基亚N90以及采用Windows Moblie的多普达等手机还有微软Windows
Phone系列手机,而其它一些非智能手机的产品,如果宣传支持WAV格式则多半属于只是支持单声道的。

格式解析

WAVE文件是非常简单的一种RIFF文件,它的格式类型为"WAVE"。RIFF块包含两个子块,这两个子块的ID分别是"fmt"和"data",其中"fmt"子块由结构PCMWAVEFORMAT所组成,其子块的大小就是sizeofof(PCMWAVEFORMAT),数据组成就是PCMWAVEFORMAT结构中的数据。
整个头长度44byte.

标志符(RIFF)
余下所有数据的长度
格式类型("WAVE")
"fmt"
PCMWAVEFORMAT的长度
PCMWAVEFORMAT
"data"
声音数据大小
声音数据

wav头结构体定义

  1. /* RIFF WAVE file struct.
  2. * For details see WAVE file format documentation
  3. * (for example at <a href="http://www.wotsit.org)." target="_blank">http://www.wotsit.org).</a>  */
  4. typedef struct WAV_HEADER_S
  5. {
  6. char            riffType[4];    //4byte,资源交换文件标志:RIFF
  7. unsigned int    riffSize;       //4byte,从下个地址到文件结尾的总字节数
  8. char            waveType[4];    //4byte,wav文件标志:WAVE
  9. char            formatType[4];  //4byte,波形文件标志:FMT(最后一位空格符)
  10. unsigned int    formatSize;     //4byte,音频属性(compressionCode,numChannels,sampleRate,bytesPerSecond,blockAlign,bitsPerSample)所占字节数
  11. unsigned short  compressionCode;//2byte,格式种类(1-线性pcm-WAVE_FORMAT_PCM,WAVEFORMAT_ADPCM)
  12. unsigned short  numChannels;    //2byte,通道数
  13. unsigned int    sampleRate;     //4byte,采样率
  14. unsigned int    bytesPerSecond; //4byte,传输速率
  15. unsigned short  blockAlign;     //2byte,数据块的对齐,即DATA数据块长度
  16. unsigned short  bitsPerSample;  //2byte,采样精度-PCM位宽
  17. char            dataType[4];    //4byte,数据标志:data
  18. unsigned int    dataSize;       //4byte,从下个地址到文件结尾的总字节数,即除了wav header以外的pcm data length
  19. }WAV_HEADER;

头解析程序示例

wav.h

#ifndef __WAV_H__
#define __WAV_H__ #define debug(fmt...) do \
{ \
printf("[%s::%d] ", __func__, __LINE__);\
printf(fmt); \
}while() /* RIFF WAVE file struct.
* For details see WAVE file format documentation
* (for example at <a href="http://www.wotsit.org)." target="_blank">http://www.wotsit.org).</a> */
typedef struct WAV_HEADER_S
{
char riffType[]; //4byte,资源交换文件标志:RIFF
unsigned int riffSize; //4byte,从下个地址到文件结尾的总字节数
char waveType[]; //4byte,wave文件标志:WAVE
char formatType[]; //4byte,波形文件标志:FMT
unsigned int formatSize; //4byte,音频属性(compressionCode,numChannels,sampleRate,bytesPerSecond,blockAlign,bitsPerSample)所占字节数
unsigned short compressionCode;//2byte,编码格式(1-线性pcm-WAVE_FORMAT_PCM,WAVEFORMAT_ADPCM)
unsigned short numChannels; //2byte,通道数
unsigned int sampleRate; //4byte,采样率
unsigned int bytesPerSecond; //4byte,传输速率
unsigned short blockAlign; //2byte,数据块的对齐
unsigned short bitsPerSample; //2byte,采样精度
char dataType[]; //4byte,数据标志:data
unsigned int dataSize; //4byte,从下个地址到文件结尾的总字节数,即除了wav header以外的pcm data length
}WAV_HEADER; typedef struct WAV_INFO_S
{
WAV_HEADER header;
FILE *fp;
unsigned int channelMask;
}WAV_INFO; #endif

wav.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "wav.h" /* func : endian judge
* return : 0-big-endian othes-little-endian
*/
int IS_LITTLE_ENDIAN(void)
{
int __dummy = 1;
return ( *( (unsigned char*)(&(__dummy) ) ) );
} unsigned int readHeader(void *dst, signed int size, signed int nmemb, FILE *fp)
{
unsigned int n, s0, s1, err;
unsigned char tmp, *ptr; if ((err = fread(dst, size, nmemb, fp)) != nmemb)
{
return err;
}
if (!IS_LITTLE_ENDIAN() && size > 1)
{
//debug("big-endian \n");
ptr = (unsigned char*)dst;
for (n=0; n<nmemb; n++)
{
for (s0=0, s1=size-1; s0 < s1; s0++, s1--)
{
tmp = ptr[s0];
ptr[s0] = ptr[s1];
ptr[s1] = tmp;
}
ptr += size;
}
}
else
{
//debug("little-endian \n");
} return err;
} void dumpWavInfo(WAV_INFO wavInfo)
{
debug("compressionCode:%d \n",wavInfo.header.compressionCode);
debug("numChannels:%d \n",wavInfo.header.numChannels);
debug("sampleRate:%d \n",wavInfo.header.sampleRate);
debug("bytesPerSecond:%d \n",wavInfo.header.bytesPerSecond);
debug("blockAlign:%d \n",wavInfo.header.blockAlign);
debug("bitsPerSample:%d \n",wavInfo.header.bitsPerSample); } int wavInputOpen(WAV_INFO *pWav, const char *filename)
{
signed int offset;
WAV_INFO *wav = pWav ; if (wav == NULL)
{
debug("Unable to allocate WAV struct.\n");
goto error;
}
wav->fp = fopen(filename, "rb");
if (wav->fp == NULL)
{
debug("Unable to open wav file. %s\n", filename);
goto error;
} /* RIFF标志符判断 */
if (fread(&(wav->header.riffType), 1, 4, wav->fp) != 4)
{
debug("couldn't read RIFF_ID\n");
goto error; /* bad error "couldn't read RIFF_ID" */
}
if (strncmp("RIFF", wav->header.riffType, 4))
{
debug("RIFF descriptor not found.\n") ;
goto error;
}
debug("Find RIFF \n"); /* Read RIFF size. Ignored. */
readHeader(&(wav->header.riffSize), 4, 1, wav->fp);
debug("wav->header.riffSize:%d \n",wav->header.riffSize); /* WAVE标志符判断 */
if (fread(&wav->header.waveType, 1, 4, wav->fp) !=4)
{
debug("couldn't read format\n");
goto error; /* bad error "couldn't read format" */
}
if (strncmp("WAVE", wav->header.waveType, 4))
{
debug("WAVE chunk ID not found.\n") ;
goto error;
}
debug("Find WAVE \n"); /* fmt标志符判断 */
if (fread(&(wav->header.formatType), 1, 4, wav->fp) != 4)
{
debug("couldn't read format_ID\n");
goto error; /* bad error "couldn't read format_ID" */
}
if (strncmp("fmt", wav->header.formatType, 3))
{
debug("fmt chunk format not found.\n") ;
goto error;
}
debug("Find fmt \n"); readHeader(&wav->header.formatSize, 4, 1, wav->fp); // Ignored
debug("wav->header.formatSize:%d \n",wav->header.formatSize); /* read info */
readHeader(&(wav->header.compressionCode), 2, 1, wav->fp);
readHeader(&(wav->header.numChannels), 2, 1, wav->fp);
readHeader(&(wav->header.sampleRate), 4, 1, wav->fp);
readHeader(&(wav->header.bytesPerSecond), 4, 1, wav->fp);
readHeader(&(wav->header.blockAlign), 2, 1, wav->fp);
readHeader(&(wav->header.bitsPerSample), 2, 1, wav->fp); offset = wav->header.formatSize - 16; /* Wav format extensible */
if (wav->header.compressionCode == 0xFFFE)
{
static const unsigned char guidPCM[16] = {
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71
};
unsigned short extraFormatBytes, validBitsPerSample;
unsigned char guid[16];
signed int i; /* read extra bytes */
readHeader(&(extraFormatBytes), 2, 1, wav->fp);
offset -= 2; if (extraFormatBytes >= 22)
{
readHeader(&(validBitsPerSample), 2, 1, wav->fp);
readHeader(&(wav->channelMask), 4, 1, wav->fp);
readHeader(&(guid), 16, 1, wav->fp); /* check for PCM GUID */
for (i = 0; i < 16; i++) if (guid[i] != guidPCM[i]) break;
if (i == 16) wav->header.compressionCode = 0x01; offset -= 22;
}
}
debug("wav->header.compressionCode:%d \n",wav->header.compressionCode); /* Skip rest of fmt header if any. */
for (;offset > 0; offset--)
{
fread(&wav->header.formatSize, 1, 1, wav->fp);
} #if 1
do
{
/* Read data chunk ID */
if (fread(wav->header.dataType, 1, 4, wav->fp) != 4)
{
debug("Unable to read data chunk ID.\n");
free(wav);
goto error;
}
/* Read chunk length. */
readHeader(&offset, 4, 1, wav->fp); /* Check for data chunk signature. */
if (strncmp("data", wav->header.dataType, 4) == 0)
{
debug("Find data \n");
wav->header.dataSize = offset;
break;
} /* Jump over non data chunk. */
for (;offset > 0; offset--)
{
fread(&(wav->header.dataSize), 1, 1, wav->fp);
}
} while (!feof(wav->fp));
debug("wav->header.dataSize:%d \n",wav->header.dataSize);
#endif /* return success */
return 0; /* Error path */
error:
if (wav)
{
if (wav->fp)
{
fclose(wav->fp);
wav->fp = NULL;
}
//free(wav);
}
return -1;
} #if 0
int main(int argc,char **argv) {
WAV_INFO wavInfo;
char fileName[128];
if(argc<2 || strlen(&argv[1][0])>=sizeof(fileName))
{
debug("argument error !!! \n");
return -1 ;
}
debug("size : %d \n",sizeof(WAV_HEADER));
strcpy(fileName,argv[1]);
wavInputOpen(&wavInfo, fileName);
return 0;
}
#endif

附:FIFF文件知识点

1. 简介RIFF全称为资源互换文件格式ResourcesInterchange FileFormat),RIFF文件是windows环境下大部分多媒体文件遵循的一种文件结构,RIFF文件所包含的数据类型由该文件的扩展名来标识,能以RIFF文件存储的数据包括:音频视频交错格式数据(.AVI)
波形格式数据(.WAV) 位图格式数据(.RDI) MIDI格式数据(.RMI)调色板格式(.PAL)多媒体电影(.RMN)动画光标(.ANI)其它RIFF文件(.BND)

2. CHUNK

chunk是组成RIFF文件的基本单元,它的基本结构如下:

struct chunk{

u32 id; /* 块标志 */

u32 size; /* 块大小 */

u8 dat[size]; /* 块内容 */

};

id 由4个ASCII字符组成,用以识别块中所包含的数据。如:'RIFF','LIST','fmt','data','WAV','AVI'等等,由于这种文件结构最初是由Microsoft和IBM为PC机所定义,RIFF文件是按照little-endian[2] 字节顺序写入的。

size(块大小) 是存储在data域中数据的长度,id与size域的大小则不包括在该值内。

dat(块内容) 中所包含的数据是以字(WORD)为单位排列的,如果该数据结构长度是奇数,则在最后添加一个空(NULL)字节。

chunk块中有且仅有两种类型块:'RIFF'和'LIST'类型可以包含其他块,而其它块仅能含有数据。

'RIFF'和'LIST'类型的chunk结构如下

structchunk{

u32 id; /* 块标志 */

u32 size; /* 块大小 */

/*此时的dat = type + restdat */

u32 type ; /* 类型 */

u8 restdat[size] /* dat中除type4个字节后剩余的数据*/

};

可以看出,'RIFF'和'LIST'也是chunk,只是它的dat由两部分组成type和restdat。

type,由4个ASCII字符组成,代表RIFF文件的类型,如'WAV','AVI ';或者'LIST'块的类型,如avi文件中的列表'hdrl','movi'。

restdat,dat中除type4个字节后剩余的数据,包括块内容,包含若干chunk和'LIST'

2.1 FOURCC 一个FOURCC(fourcharacter
code
)是一个占4个字节的数据,一般表示4个ASCII字符。在RIFF文件格式中,FOURCC非常普遍,structchunk
中的id成员,'LIST','RIFF'的type成员,起始标识等信息都是用FOURCC表示的。FOURCC一般是四个字符,如'abcd'这样的形式,也可以三个字符包含一个空格,如'abc'这样的形式。

RIFF文件的FileData部分由若干个'LIST'和chunk组成,而'LIST'的ListData又可以由若干个'LIST'和chunk组成,即'LIST'是可以嵌套的。

'RIFF',FileType,'LIST',ListType,ChunkID都是FOURCC,即使用4字节的ASIIC字符标识类型。

FileSize,ListSize,ChunkSize为little-endian32-bit正整数,表示Type(只有'RIFF','LIST'chunk有Type)+Data一起的大小,注意它是little-endian表示,如:0x00123456,存储地址由低到高,在little-endian系统中的存储表示为0x56341200(字节由低位到高位存储),而在big-endian为0x00123456(字节由高位到低位存储)。32bit整数0x00123456存储地址低--------->;高little-endian(字节由低位到高位存储)56341200big-endian(字节由高位到低位存储)00123456

wav音频文件头解析的更多相关文章

  1. 解析WAV音频文件----》生成WAV音频文件头

    前言:请各大网友尊重本人原创知识分享,谨记本人博客:南国以南i WAV音频文件介绍: WAV文件是在PC机平台上很常见的.最经典的多媒体音频文件,最早于1991年8月出现在Windows3.1操作系统 ...

  2. DEX文件解析---1、dex文件头解析

    DEX文件解析---1.dex文件头解析 一.dex文件     dex文件是Android平台上可执行文件的一种文件类型.它的文件格式可以下面这张图概括:     dex文件头一般固定为0x70个字 ...

  3. JPEG解码——(3)文件头解析

    与具体的编码数据空间相比,jpeg文件头占据非常小乃至可以忽略不计的大小. 仍然拿JPEG解码--(1)JPEG文件格式概览中的<animal park>这张图片来举例,从跳过SOS(FF ...

  4. S3C2416裸机开发系列19_Fatfs播放录像wav音频文件

    S3C2416裸机开发系列19 Fatfs播放录像wav音频文件 国际象棋男孩    1048272975 多媒体资源,一般都是以文件的形式存储在固化存储器中.Fatfs所支持的fat32为windo ...

  5. 常用文件的文件头(附JAVA测试类)

    1. MIDI (mid),文件头:4D546864 2. JPEG (jpg),文件头:FFD8FF 3. PNG (png),文件头:89504E47 4. GIF (gif),文件头:47494 ...

  6. 【CTF杂项】常见文件文件头文件尾格式总结及各类文件头

    文件头文件尾总结 JPEG (jpg), 文件头:FFD8FF 文件尾:FF D9PNG (png), 文件头:89504E47 文件尾:AE 42 60 82GIF (gif), 文件头:47494 ...

  7. 【杂项】各类文件头结合winhex使用-转载

    ———常用文件头——— JPEG (jpg),文件头:FFD8FFE1 PNG (png),文件头:89504E47 (0D0A1A0A) GIF (gif),文件头:47494638 ZIP Arc ...

  8. 音频文件解析(一):WAV格式文件头部解析

    WAV为微软公司(Microsoft)开发的一种声音文件格式,它符合RIFF(Resource Interchange File Format)文件规范,用于保存Windows平台的音频信息资源. 文 ...

  9. wav音频文件格式解析【个人笔记】(自用)

    1. WAV格式 wav是微软开发的一种音频文件格式,注意,wav文件格式是无损音频文件格式,相对于其他音频格式文件数据是没有经过压缩的,通常文件也相对比较大些.. 支持多种音频数字,取样频率和声道, ...

随机推荐

  1. vue v-on:click传递动态参数

    最近项目中要为一个循环列表动态传送当前点击列的数据,查了很久资料也没有一个完美的解决方案, 新手只能用vue的事件处理器与jquery的选择器做了一个不伦不类的方案,居然也能解决这个问题,作此记录留待 ...

  2. Network | sk_buff

    sk_buff结构可能是linux网络代码中最重要的数据结构,它表示接收或发送数据包的包头信息.它在中定义,并包含很多成员变量供网络代码中的各子系统使用.    这个结构被不同的网络层(MAC或者其他 ...

  3. CDOJ 879 摩天轮 dp+斜率优化

    原题链接:http://www.acm.uestc.edu.cn/#/problem/show/879 题意: 中文题 题解: 这是一道斜率dp的题. 先把$a$数组排个序. 令$dp[i][j]$表 ...

  4. 作为一个新人,怎样学习嵌入式Linux?

        作为一个新人,怎样学习嵌入式Linux?   在学习嵌入式Linux之前,肯定要有C语言基础.汇编基础有没有无所谓(就那么几条汇编指令,用到了一看就会).尝试着写一些C语言竞赛的题目.它们是纯 ...

  5. Windows Server 2008R2 设置SMTP邮件转发服务

    最近因业务需求在Windows Server 2008R2server上设置SMTP转发服务,主要是在业务审批过程中邮件通知相关人员审批情况, 1.在server上加入服务 2.打开服务 3.新建一个 ...

  6. intellij idea 提示找不到default activivty

      更换环境之后 ,intellij idea 提示找不到默认的activity.   而查看源代码. 在代码中明显已经设置了默认activity了. 后来发现.程序中有个库工程中的AndroidMe ...

  7. iOS 推送 获取手机设备的 deviceToken

    第一步:申请证书: 第二步:申请app ids,应用名字必须一致.然后再进入进行编辑.使其enable,绿灯. 第三步:申请provisioning profile,生成.mobileprovisio ...

  8. select中分割多组option

    <optgroup style="color:gray; font-style:normal" label="——雪佛兰(五菱)——"></o ...

  9. ORACLE 11G 单实例 磁盘文件系统 DG 归档日志删除脚本 基于RED HAT LINUX 5.3 X86 64BIT

    近期做个DG的归档日志删除, [oracle@.local logs]crontab -l * 8 * * * sh /home/oracle/dbscripts/del_arc.sh 该脚本分别调用 ...

  10. 获取EF查询的SQL语句

    在EF编程中我们能够通过lamda表达式能够进行查询数据.获取到IQueryable<T>结果,我们要想知道详细的SQL语句是什么须要使用ObjectQuery<T>进行处理 ...