本文来自:

http://blog.csdn.net/jtlyr/article/details/5321884

这里还有介绍一些wav文件的其他网站,记录下:

https://ccrma.stanford.edu/courses/422/projects/WaveFormat/

http://blog.csdn.net/zhihu008/article/details/7854529

PCM音频文件压缩成adpcm格式的文件有多中方法(如使用ms ACM、sox等),本文主要介绍使用公开的算法(如下所示,如果需要可到网上搜一下:

=======================================

** Intel/DVI ADPCM coder/decoder.
**
** The algorithm for this coder was taken from the IMA Compatability Project
** proceedings, Vol 2, Number 2; May 1992.
**
** Version 1.2, 18-Dec-92.

=======================================)进行PCM到ADPCM转换的方法。

首先,要了解一下PCM格式和ADPCM格式的.wav文件的构成,可参考:

非PCM格式的文件会至少多加入一个“fact”块,它用来记录数据解压缩后的大小。(注意是数据而不是文件)这个“fact”块一般加在“data”块的前面。

1.PCM格式的wav文件的内部结构

2.WAVEFORMAT结构的认识

PCM和非PCM的主要区别是声音数据的组织不同,这些区别可以通过两者的WAVEFORMAT结构来区分。下面以PCM和IMA-ADPCM来进行对比:

WAVE的基本结构WAVEFORMATEX结构定义如下:

typedef struct

{

WORD wFormatag;  //编码格式,包括WAVE_FORMAT_PCM,//WAVEFORMAT_ADPCM等

WORD  nChannls;       //声道数,单声道为1,双声道为2;

DWORD nSamplesPerSec;//采样频率;

DWORD nAvgBytesperSec;//每秒的数据量;

WORD  nBlockAlign;//块对齐;

WORD  wBitsPerSample;//WAVE文件的采样大小;

WORD  sbSize;        //PCM中忽略此值

}WAVEFORMATEX;

PCM的结构就是这个基本结构;

IMAADPCMWAVEFORMAT结构定义如下:

Typedef struct

{

WAVEFORMATEX wfmt;

WORD nSamplesPerBlock;

}IMAADPCMWAVEFORMAT;

IMA-ADPCM的wfmt->cbsize不能忽略,一般取值为2,表示此类型的WAVEFORMAT比一般的WAVEFORMAT多出2个字节。这两个字符也就是nSamplesPerBlock。

3.“fact”chunk的内部组织

在非PCM格式的文件中,一般会在WAVEFORMAT结构后面加入一个“fact”chunk,结构如下:

typedef struct{

char[4];          //“fact”字符串

DWORD chunksize;

DWORD datafactsize;    //数据转换为PCM格式后的大小。

}factchunk;

datafactsize是这个chunk中最重要的数据,如果这是某种压缩格式的声音文件,那么从这里就可以知道他解压缩后的大小。对于解压时的计算会有很大的好处!

4.“data”chunk的内部组织

从“data”chunk的第9个字节开始,存储的就是声音信息的数据了,(前八个字节存储的是标志符“data”和后接数据大小size(DWORD)。这些数据可能是压缩的,也可能是没有压缩的。

PCM中的声音数据没有被压缩,如果是单声道的文件,采样数据按时间的先后顺序依次存入。(它的基本组织单位是BYTE(8bit)或WORD(16bit))如果是双声道的文件,采样数据按时间先后顺序交叉地存入。

IMA-ADPCM是压缩格式,它是从PCM的16位采样压缩成4位的。对于单声道的IMA-ADPCM来说,它是将PCM的数据按时间次序依次压缩并写入文件中的,每个byte中含两个采样,低四位对应第一个采样,高四位对应第二个采样。而对于双声道的IMA-ADPCM来说,它的存储相对就麻烦一些了,它是将PCM的左声道的前8个采样依次压缩并写入到一个DWORD中,然后写入“data”chunk里。紧接着是右声道的前8个采样。以此循环,当采样数不足8时(到数据尾端),应该把多出来的采样用0填充。

在IMA-ADPCM中,“data”chuck中的数据是以block形式来组织的,我把它叫做“段”,也就是说在进行压缩时,并不是依次把所有的数据进行压缩保存,而是分段进行的,这样有一个十分重要的好处:那就是在只需要文件中的某一段信息时,可以在解压缩时可以只解所需数据所在的段就行了,没有必要再从文件开始起一个一个地解压缩。这对于处理大文件将有相当的优势。同时,这样也可以保证声音效果。

Block一般是由block header (block头) 和 data 两者组成的。其中block header是一个结构,它在单声道下的定义如下:

Typedef struct

{

short  sample0;    //block中第一个采样值(未压缩)

BYTE  index;     //上一个block最后一个index,第一个block的index=0;

BYTE  reserved;   //尚未使用

}MonoBlockHeader;

有了blockheader的信息后,就可以不需要知道这个block前面和后面的数据而轻松地解出本block中的压缩数据。对于双声道,它的blockheader应该包含两个MonoBlockHeader其定义如下:

typedaf struct

{

MonoBlockHeader leftbher;

MonoBlockHeader rightbher;

}StereoBlockHeader;

在解压缩时,左右声道是分开处理的,所以必须有两个MonoBlockHeader;

以上内容参考http://blog.csdn.net/kindyb/archive/2005/10/13/503024.aspx,对此表示感谢。

==========================华丽的分割线=========================================

接下来,就是要实现从PCM到ADPCM的转换了。(以8KHz,16Bits,单声道为例)

定义结构:

#define ADPCM_BLOCKSIZE 252  //256 - 4;typedef unsigned long  ULONG;
typedef unsigned short USHORT;
typedef unsigned char  BYTE;typedef struct {long           chunkid;long           chunksize;long     wave_id;
} RIFFCHUNK;typedef struct tagDATA
{long ID;unsigned long Size;
}DATA;typedef struct
{long          chunkid;unsigned long  chunksize;unsigned long  timelength;
} FACTCHUNK;typedef struct tagWaveFormat{//long chunkSize;short          wFormatTag;unsigned short wChannels;unsigned long  dwSamplesPerSec;unsigned long  awAvgBytesPerSec;unsigned short wBlockAlign;unsigned short wBitsPerSample;unsigned short cbsize;int  headerSize ;long dataLength ;
} WAVEFMT;typedef struct
{RIFFCHUNK      riff;long          chunkid;unsigned long  chunksize;USHORT wformattag; /* format type */USHORT nchannels; /* number of channels (i.e. mono, stereo...) */ULONG nsamplespersec; /* sample rate */ULONG navgbytespersec; /* for buffer estimation */USHORT nblockalign; /* block size of data */USHORT wbitspersample; /* number of bits per sample of mono data */USHORT cbsize; /* the count in bytes of the extra size */USHORT wsamplesperblock;FACTCHUNK fact;DATA   data;
}INTELADPCM_HEADER;

关键部分代码:

void adpcmEncoder()
{FILE *inFile, *outFile;inFile = fopen("c://input.wav", "rb");if (!inFile){printf("can't open the input file.");return -2;}WAVEFMT waveFmt;if(!checkWaveFileHeaderFormat(inFile, &waveFmt)) {printf("input file's format is wrong.");return -1;}outFile = fopen("c://output.wav", "wb+");if (!outFile){printf("can't open the output file.");return -2;}setAdpcmHeader(outFile, waveFmt.dataLength);int len;short inData[ADPCM_BLOCKSIZE * 2];BYTE outData[ADPCM_BLOCKSIZE];adpcm_state state;state.index = 0;state.valprev = 0;long samples = waveFmt.dataLength;while (samples > 0){/* Read two frames worth of samples */len = fread(inData, (size_t )1, sizeof (inData), inFile);if (len <= 0){perror("error reading input");exit(1);}samples -= len;if (len < sizeof (inData)){printf("memset. /n");memset((char *)inData + len, 0, sizeof (inData) - len);}fwrite(&state, 4, 1, outFile);len = adpcm_coder(inData, outData, len / 2, &state);writeFile(outFile, outData, len);// 此处高低位要互换}fclose(inFile);fclose(outFile);return 0;
}void setAdpcmHeader( FILE *outFile, ULONG dataSize)
{ULONG   flen = 0;INTELADPCM_HEADER   adpcmhead;adpcmhead.riff.chunkid = WAV_ID_RIFF;//4BYTEadpcmhead.riff.wave_id = WAV_ID_WAVE;//4BYTEadpcmhead.chunkid = WAV_ID_FMT;//4BYTEadpcmhead.chunksize = 0x14;//2BYTEadpcmhead.wformattag = 0x11;//2BYTEadpcmhead.nchannels = 1;//2BYTEadpcmhead.nsamplespersec = 8000;//4BYTEadpcmhead.navgbytespersec = 4055;// = nsamplespersec / wsamplesperblock  *nblockalign, 可调,我用4064效果更好adpcmhead.nblockalign = 0x100;//2BYTEadpcmhead.wbitspersample = 4;//2BYTE  adpcmhead.cbsize = 2;//2BYTEadpcmhead.wsamplesperblock = 505;// 为什么是这个数?没搞明白adpcmhead.fact.chunkid = WAV_ID_FACT;adpcmhead.fact.chunksize = 4;adpcmhead.data.ID = WAV_ID_DATA;int adpcmDataSize = (dataSize / (ADPCM_BLOCKSIZE * 4)) * (ADPCM_BLOCKSIZE + 4); //blockcount * 256// 判断最后的一个block是否是1008(252*4)byte,如果不是,按实际大小设置int lastBlockSize = dataSize % (ADPCM_BLOCKSIZE * 4);if(lastBlockSize > 0){adpcmDataSize += lastBlockSize / 4 + 4(sizeof(state));}adpcmhead.riff.chunksize = adpcmDataSize + sizeof(INTELADPCM_HEADER) - 8 ;adpcmhead.fact.timelength = dataSize / 2;adpcmhead.data.Size = adpcmDataSize;fwrite( &adpcmhead, sizeof(adpcmhead), 1, outFile);
}

PCM音频文件(.wav)压缩成ADPCM(.wav) ,wav文件分析,wav 文件格式相关推荐

  1. PCM音频文件(.wav)压缩成ADPCM(.wav)

    PCM音频文件压缩成adpcm格式的文件有多中方法(如使用ms ACM.sox等),本文主要介绍使用公开的算法(如下所示,如果需要可到网上搜一下: ========================== ...

  2. java压缩zip文件夹错误_Java将文件或者文件夹压缩成zip(修复文件夹中存在多个文件报Stream Closed错误问题)...

    项目场景: Java将文件或者文件夹压缩成zip(修复文件夹中存在多个文件报Stream Closed错误问题) 问题描述: 最近的项目需要将多级文件夹压缩成zip,网上找了几个工具类,都会报错,所以 ...

  3. 如何将一个大文件打包压缩成几个小的文件及其解压缩打开方法

    在用百度网盘备份资料时由于文件过大而无法上传,因此需要将大文件分卷压缩成多个小文件以便操作使用. 1.选择该"大文件",右键如下图所示,选择"添加到压缩文件", ...

  4. python pcm,python pcm音频添加头转成Wav格式文件的方法

    如下所示: ''''' add Head Infomation for pcm file ''' import sys import struct import os __author__ = 'bo ...

  5. 【Auto.js】[zip压缩] 将文件夹压缩成zip包

    将一个文件夹压缩成一个zip包,可应用于项目文件夹打包成zip, 文件夹过滤了目录中的空文件夹,因此,空文件夹不会被打包到zip包中. 由于本人JS知识有限,JAVA也不懂, 导致该函数, 打包大型文 ...

  6. Java实现将文件或者文件夹压缩成zip

    Java实现将文件或者文件夹压缩成zip 最近碰到个需要下载zip压缩包的需求,于是我在网上找了下别人写好的zip工具类.但找了好多篇博客,总是发现有bug.因此就自己来写了个工具类. 这个工具类的功 ...

  7. Windows下如何将文件打包压缩成 .tar.gz格式

    Windows下将文件打包压缩成 .tar.gz格式步骤如下: 1.百度搜索7-zip,第一个条目,下载并安装. 2.在桌面新建一个test测试文件夹,右击,选择压缩. 3.这里我们只需要改压缩格式参 ...

  8. 如何将大的视频文件压缩成小的视频文件?

    如何将大的视频文件压缩成小的视频文件?视频是我们在生活中不可或缺的一部分,随着制作视频的小伙伴越来越多,大家都想把制作好的视频上传到一些平台或传给别人,有时候我们会遇到视频内存过大的问题,今天我给大家 ...

  9. 将文件夹压缩成zip文件

    一 代码 package ZipFile;import org.apache.commons.io.FileUtils; import org.apache.commons.lang.StringUt ...

最新文章

  1. Python 2.7 学习笔记 内置语句、函数、标准库
  2. postman测试传入json
  3. 苹果如果无法弹出⏏️
  4. RSA加解密算法的Java实现
  5. mysql存储引擎的方式_Mysql转换表存储引擎的三种方式
  6. Android MediaPlayer 音频倍速播放,调整播放速度
  7. java setmessage_Java Message.setTitle方法代码示例
  8. SmartDial - 简单你的生活
  9. Apache的下载安装(主要说的 64位)及问题
  10. PHP生成HTML的技术原理
  11. Docker从理论到实践(三)------配置你的DaoCloud的Docker镜像源加速器
  12. C++结构体变量的初始化和结构体char数组成员初始化
  13. 屏蔽KEmulator的内存查看功能
  14. win10添加开机启动项_Windows系统注册表添加开机启动项
  15. 【自己看的笔记】Unity基础操作认识
  16. 【各学校通用】5分钟刷完天津科技大学雨课堂视频
  17. matlab矩阵运算中只对部分数值进行计算的技巧
  18. 2022小米红米手机最新最全MIUI刷机教程内测版到稳定版 不清除数据(线刷、卡刷)
  19. php odbc informix,Informix CLI 与 ODBC
  20. 山东理工ACM【2761】编码

热门文章

  1. Kali Linux安装与配置
  2. 近 100 个 Linux 常用命令大全
  3. uniapp之APP/微信小程序/公众号支付
  4. 国产操作系统第一股,杨涛的麒麟信安是否名副其实?
  5. 看看资深程序员是如何教你破解图形验证码!这不很简单嘛!
  6. Android开发学习(4)简单登录界面
  7. 国内外安全网站网址大集合
  8. 音视频基础(7)录音实现
  9. UPUPWANK配置SSL证书教程
  10. SharePoint Fundation 2013中SecurityTokenServiceApplication错误