wave 头 c语言 csdn,(转载)PCM、WAV格式介绍及用C语言实现PCM转WAV

转载:https://blog.csdn.net/u010011236/article/details/53026127

1、PCM格式介绍:

PCM(Pulse Code Modulation)也被称为 脉码编码调制。PCM中的声音数据没有被压缩,如果是单声道的文件,采样数据按时间的先后顺序依次存入。(它的基本组织单位是BYTE(8bit)或WORD(16bit))

参考文献http://blog.csdn.net/ownwell/article/details/8114121/

2、WAV格式

1)格式介绍:

WAVE文件格式是Microsoft的RIFF规范的一个子集,用于存储多媒体文件。WAVE文件通常只是一个具有单个“WAVE”块的RIFF文件,该块由两个子块(”fmt”子数据块和”data”子数据块)组成。

如下图所示:

1bcbf3c5c889ac76f390d1cc9d17db56.png

2)每个字段的含义介绍

long在64位平台占用8个字节,此处修改long为int

typedef struct{char ChunkID[4];//内容为"RIFF"

unsigned long ChunkSize;//存储文件的字节数(不包含ChunkID和ChunkSize这8个字节)

char Format[4];//内容为"WAVE"

}WAVE_HEADER;

typedefstruct{char Subchunk1ID[4];//内容为"fmt"

unsigned long Subchunk1Size;//存储该子块的字节数(不含前面的Subchunk1ID和Subchunk1Size这8个字节)

unsigned short AudioFormat;//存储音频文件的编码格式,例如若为PCM则其存储值为1,若为其他非PCM格式的则有一定的压缩。

unsigned short NumChannels;//通道数,单通道(Mono)值为1,双通道(Stereo)值为2,等等

unsigned long SampleRate;//采样率,如8k,44.1k等

unsigned long ByteRate;//每秒存储的bit数,其值=SampleRate * NumChannels * BitsPerSample/8

unsigned short BlockAlign;//块对齐大小,其值=NumChannels * BitsPerSample/8

unsigned short BitsPerSample;//每个采样点的bit数,一般为8,16,32等。

}WAVE_FMT;

typedefstruct{char Subchunk2ID[4];//内容为“data”

unsigned long Subchunk2Size;//内容为接下来的正式的数据部分的字节数,其值=NumSamples * NumChannels * BitsPerSample/8

}WAVE_DATA;

3)一个WAVE例子

这里是一个WAVE文件的开头72字节,字节显示为十六进制数字:

52 49 46 46 24 08 00 00 57 41 56 45 66 6d 74 20 10 00 00 00 01 00 02 00

22 56 00 00 88 58 01 00 04 00 10 00 64 61 74 61 00 08 00 00 00 00 00 00

24 17 1e f3 3c 13 3c 14 16 f9 18 f9 34 e7 23 a6 3c f2 24 f2 11 ce 1a 0d

字段解析:

fa86d7c48e1d2f10cac168d279b67fab.png

3、用C语言实现PCM转WAVE

#include

#include

/**

* Convert PCM16LE raw data to WAVE format

* @param pcmpath Input PCM file.

* @param channels Channel number of PCM file.

* @param sample_rate Sample rate of PCM file.

* @param wavepath Output WAVE file.

*/

int simplest_pcm16le_to_wave(const char *pcmpath, int channels, int sample_rate, const char *wavepath)

{

typedef struct WAVE_HEADER{

char fccID[4]; //内容为""RIFF

unsigned int dwSize; //最后填写,WAVE格式音频的大小//unsigned long dwSize;

char fccType[4]; //内容为"WAVE"

}WAVE_HEADER;

typedef struct WAVE_FMT{

char fccID[4]; //内容为"fmt "

unsigned int dwSize; //内容为WAVE_FMT占的字节数,为16

unsigned short wFormatTag; //如果为PCM,改值为 1

unsigned short wChannels; //通道数,单通道=1,双通道=2

unsigned int dwSamplesPerSec;//采用频率

unsigned int dwAvgBytesPerSec;/* ==dwSamplesPerSec*wChannels*uiBitsPerSample/8 */

unsigned short wBlockAlign;//==wChannels*uiBitsPerSample/8

unsigned short uiBitsPerSample;//每个采样点的bit数,8bits=8, 16bits=16

}WAVE_FMT;

typedef struct WAVE_DATA{

char fccID[4]; //内容为"data"

unsigned int dwSize; //==NumSamples*wChannels*uiBitsPerSample/8

}WAVE_DATA;

if(channels==2 || sample_rate==0)

{

channels = 2;

sample_rate = 44100;

}

int bits = 16;

WAVE_HEADER pcmHEADER;

WAVE_FMT pcmFMT;

WAVE_DATA pcmDATA;

unsigned short m_pcmData;

FILE *fp, *fpout;

fp = fopen(pcmpath, "rb+");

if(fp==NULL)

{

printf("Open pcm file error.

");

return -1;

}

fpout = fopen(wavepath, "wb+");

if(fpout==NULL)

{

printf("Create wav file error.

");

return -1;

}

/* WAVE_HEADER */

memcpy(pcmHEADER.fccID, "RIFF", strlen("RIFF"));

memcpy(pcmHEADER.fccType, "WAVE", strlen("WAVE"));

//移动指针位置,否写入二进制流时,会覆盖之前写入的数据。

fseek(fpout, sizeof(WAVE_HEADER), 1); //1=SEEK_CUR modify by cheyang at 2019.0412

/* WAVE_FMT */

memcpy(pcmFMT.fccID, "fmt ", strlen("fmt "));

pcmFMT.dwSize = 16;

pcmFMT.wFormatTag = 1;

pcmFMT.wChannels = 1;//2此处声道需要要根据实际的文件填写

pcmFMT.dwSamplesPerSec = sample_rate;

pcmFMT.uiBitsPerSample = bits;

/* ==dwSamplesPerSec*wChannels*uiBitsPerSample/8 */

pcmFMT.dwAvgBytesPerSec = pcmFMT.dwSamplesPerSec*pcmFMT.wChannels*pcmFMT.uiBitsPerSample/8;//**

/* ==wChannels*uiBitsPerSample/8 */

pcmFMT.wBlockAlign = pcmFMT.wChannels*pcmFMT.uiBitsPerSample/8;//**

//1.写入FMT结构数据

fwrite(&pcmFMT, sizeof(WAVE_FMT), 1, fpout);

/* WAVE_DATA */

memcpy(pcmDATA.fccID, "data", strlen("data"));

pcmDATA.dwSize = 0;

fseek(fpout, sizeof(WAVE_DATA), SEEK_CUR);//modify by cheyang at 2019.0412

//2.写入数据文件(先读文件,再判断是否eof,是eof那之前读取的数据就无效了)

fread(&m_pcmData, sizeof(unsigned short), 1, fp);

while(!feof(fp))

{

pcmDATA.dwSize += 2;

fwrite(&m_pcmData, sizeof(unsigned short), 1, fpout);

fread(&m_pcmData, sizeof(unsigned short), 1, fp);

}

//pcmHEADER.dwSize = 44 + pcmDATA.dwSize;

//修改时间:2018年1月5日

pcmHEADER.dwSize = 36 + pcmDATA.dwSize;

//3.写入Head头结构

rewind(fpout);

fwrite(&pcmHEADER, sizeof(WAVE_HEADER), 1, fpout);

fseek(fpout, sizeof(WAVE_FMT), SEEK_CUR);

fwrite(&pcmDATA, sizeof(WAVE_DATA), 1, fpout);

fclose(fp);

fclose(fpout);

return 0;

}

int main()

{

simplest_pcm16le_to_wave("dam9_r48000_FMT_S16_c2.pcm", 1, 8000, "output_chy.wav");

return 0;

}

结果如图所示:

9ed261b1907bdce929be4669ea342345.png

2017年10月26日 星期四 修改

原74行代码:**pcmFMT.dwAvgBytesPerSec = pcmFMT.dwSamplesPerSec*pcmFMT.wChannels*pcmFMT.uiBitsPerSample/8;**改为

pcmFMT.dwAvgBytesPerSec= pcmFMT.dwSamplesPerSec*pcmFMT.wChannels*pcmFMT.uiBitsPerSample/8;原76行:**pcmFMT.wBlockAlign = pcmFMT.wChannels*pcmFMT.uiBitsPerSample/8;**改为:

pcmFMT.wBlockAlign= pcmFMT.wChannels*pcmFMT.uiBitsPerSample/8;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值