c语言wavhdr参数,PCM转WAV格式 Wav数据格式的44个字节头部信息汇总

本文详细介绍了如何将通过麦克风采集的PCM格式录音数据转换为可播放的WAV格式,包括WAV文件头部信息的构成及如何手动添加。文中提供了一个C++实现的示例代码,用于创建符合WAV格式规范的头部信息,并给出了Java版本的实现。此外,还提供了使用示例,帮助理解转换过程。
摘要由CSDN通过智能技术生成

和 http://ikinglai.blog.51cto.com/6220785/1224481

一般通过麦克风采集的录音数据都是PCM格式的,即不包含头部信息,这样导致很多播放器都播放不了,你只能用像Audition这样的专业工具才能进行播放,显然是非常不方便的。为了得到wav格式的录音数据,我们在保存录音数据的时候就要自己手工加上44个字节的头部信息。

wav格式的音频数据的头部信息基本上是固定不变的,总共44个字节,包括以下内容:

1.    "RIFF"(4个字节)

固定字符串

2.    录音数据长度 +(44 -8) (4个字节)

类型可以是int或long,但必须保证类型占4个字节大小

3.    "WAVE "(4个字节)

固定字符串

4.    "fmt "  (4个字节)

固定字符串,注意最后有一个空格

5.     size1(4个字节)

值为16

6.    format tag(2个字节)

值为1

7.    channel(2个字节)

声道数,1为单声道,2为多声道

8.    sampleRate(4个字节)

采样率,值为8000,16000等

9.    bytePerSec(4个字节)

每秒所需的字节数

10.   blockAlign(2个字节)

每个采样需要的字节数,计算公式:声道数 * 每个采样需要的bit  / 8

11.    bitPerSample(2个字节)

每个采样需要的bit数,一般为8或16

12.    "data"(4个字节)

固定字符串

13.    size2(4个字节)

录音数据的长度,不包括头部长度

PCM录音数据转Wav格式

#include

#include "WaveHeader.h"

// wav头部结构体

struct wave_header {

char riff[4];

unsignedlong fileLength;

char wavTag[4];

char fmt[4];

unsignedlong size;

unsignedshort formatTag;

unsignedshort channel;

unsignedlong sampleRate;

unsignedlong bytePerSec;

unsignedshort blockAlign;

unsignedshort bitPerSample;

char data[4];

unsignedlong dataSize;

};

void *createWaveHeader(int fileLength, short channel, int sampleRate, short bitPerSample)

{

structwave_header *header = malloc(sizeof(structwave_header));

if (header == NULL) {

return NULL;

}

// RIFF

header->riff[0] = 'R';

header->riff[1] = 'I';

header->riff[2] = 'F';

header->riff[3] = 'F';

// file length

header->fileLength = fileLength + (44 - 8);

// WAVE

header->wavTag[0] = 'W';

header->wavTag[1] = 'A';

header->wavTag[2] = 'V';

header->wavTag[3] = 'E';

// fmt

header->fmt[0] = 'f';

header->fmt[1] = 'm';

header->fmt[2] = 't';

header->fmt[3] = ' ';

header->size = 16;

header->formatTag = 1;

header->channel = channel;

header->sampleRate = sampleRate;

header->bitPerSample = bitPerSample;

header->blockAlign = (short)(header->channel * header->bitPerSample / 8);

header->bytePerSec = header->blockAlign * header->sampleRate;

// data

header->data[0] = 'd';

header->data[1] = 'a';

header->data[2] = 't';

header->data[3] = 'a';

// data size

header->dataSize = fileLength;

return header;

}

使用示例:

// fileLength 原始录音数据长度

// 1 表示 单声道

// 16000 采样率

// 16 表示每个采样点是16个bit

void *header = createWaveHeader(fileLength, 1, 16000, 16);

// 使用。。。。

free(header);

package com.example.pcm2wave;

import java.io.ByteArrayOutputStream;

import java.io.IOException;

public class WaveHeader {

private char fileID[] = { 'R', 'I', 'F', 'F' };

private int fileLength;

private char wavTag[] = { 'W', 'A', 'V', 'E' };

private char fmtHdrID[] = { 'f', 'm', 't', ' ' };

private int fmtHdrLeth = 16;

private short formatTag = 1;

public short channels = 1;

public short sampleRate = 16000;

public short bitsPerSample = 16;

private short blockAlign = (short)(channels * bitsPerSample / 8);

private int avgBytesPerSec = blockAlign * sampleRate;

private char dataHdrID[] = { 'd', 'a', 't', 'a' };

private int dataHdrLeth;

public WaveHeader (int fileLength){

this.fileLength = fileLength + (44 - 8);

dataHdrLeth = fileLength;

}

public WaveHeader (int fileLength, short channels, short sampleRate, short bitsPerSample){

this.fileLength = fileLength + (44 - 8);

dataHdrLeth = fileLength;

this.channels = channels;

this.sampleRate = sampleRate;

this.bitsPerSample = bitsPerSample;

blockAlign = (short)(channels * bitsPerSample / 8);

avgBytesPerSec = blockAlign * sampleRate;

}

/**

* @return byte[] 44个字节

* @throws IOException

*/

public byte[] getHeader() throws IOException {

ByteArrayOutputStream bos = new ByteArrayOutputStream();

WriteChar(bos, fileID);

WriteInt(bos, fileLength);

WriteChar(bos, wavTag);

WriteChar(bos, fmtHdrID);

WriteInt(bos, fmtHdrLeth);

WriteShort(bos, formatTag);

WriteShort(bos, channels);

WriteInt(bos, sampleRate);

WriteInt(bos, avgBytesPerSec);

WriteShort(bos, blockAlign);

WriteShort(bos, bitsPerSample);

WriteChar(bos, dataHdrID);

WriteInt(bos, dataHdrLeth);

bos.flush();

byte[] r = bos.toByteArray();

bos.close();

return r;

}

private void WriteShort(ByteArrayOutputStream bos, int s)

throws IOException {

byte[] mybyte = new byte[2];

mybyte[1] = (byte) ((s << 16) >> 24);

mybyte[0] = (byte) ((s << 24) >> 24);

bos.write(mybyte);

}

private void WriteInt(ByteArrayOutputStream bos, int n) throws IOException {

byte[] buf = new byte[4];

buf[3] = (byte) (n >> 24);

buf[2] = (byte) ((n << 8) >> 24);

buf[1] = (byte) ((n << 16) >> 24);

buf[0] = (byte) ((n << 24) >> 24);

bos.write(buf);

}

private void WriteChar(ByteArrayOutputStream bos, char[] id) {

for (int i = 0; i < id.length; i++) {

char c = id[i];

bos.write(c);

}

}

}

使用方法:

// fileLength 录音数据的长度

WaveHeader header = new WaveHeader(fileLength);

// 返回44个字节的数组

byte[] waveHeaderBytes = header.getHeader();

本文同步分享在 博客“oncealong”(CSDN)。

如有侵权,请联系 support@oschina.cn 删除。

本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值