PCM转WAV格式 Wav数据格式的44个字节头部信息汇总

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 <stdlib.h>
#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();



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值