PCM
音频原始数据格式PCM
(纯音频数据)
存储格式解析
了解PCM
存在单、双信道
,8位、16位等采样率
,其他基本就是纯音频数据流。(小端模式)
大小分析
采样大小
: 一个采样用多少bit存放,通常是16bit采样率
: 每秒采样的频率, 一般有8k, 16k, 32, 44.1k, 48k(接近原声)声道数
: 单声道,双声道,立体声(多声道)
原始音频数据的大小 = 采样大小
* 采样率
* 声道数
* 时间
js获取方式
使用MediaRecorder
API可以使用设备麦克风录制音频,得到PCM数据
if (navigator.mediaDevices) {
const constraints = { audio: true };
navigator.mediaDevices.getUserMedia(constraints)
.then((stream) => {
// 传对应的mimeType
this.mediaRecorder = new MediaRecorder(stream, { mimeType: "audio/webm; codecs=pcm" });
this.mediaRecorder.ondataavailable = async (e) => {
// e.data就是录制的PCM数据
console.log(e.data)
}
})
.catch((err) => {
this.$message.warning("浏览器不支持媒体操作" + err);
})
}
WAV
WAV
其实就是带了一些数据头(44字节)的PCM
数据,可以使用类似哈夫曼之类的无损压缩。
WAV结构分析
头部树数据分析
typedef struct {
char ChunkID[4]; //内容为"RIFF"
unsigned long ChunkSize; //存储文件的字节数(不包含ChunkID和ChunkSize这8个字节)
char Format[4]; //内容为"WAVE“
} WAVE_HEADER;
typedef struct {
char Subchunk1ID[4]; //内容为"fmt"
unsigned long Subchunk1Size; //存储该子块的字节数(不含前面的Subchunk1ID和Subchunk1Size这8个字节)
unsigned short AudioFormat; //存储音频文件的编码格式,例如若为PCM则其存储值为1。
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;
typedef struct {
char Subchunk2ID[4]; //内容为“data”
unsigned long Subchunk2Size; //接下来的正式的数据部分的字节数,其值 = NumSamples * NumChannels * BitsPerSample / 8
} WAVE_DATA;
(图片 摘取自 zhuanlan.zhihu.com/p/512791706…
自己生成一段WAV
数据,使用DataView分析,确实和上面的数据一致
js获取方式
既然知道WAV
就比PCM
数据多一个头部,那么就一一添加就好。
使用audiobuffer-to-wav将PCM
转为WAV
,使用方式很简单,根据npmjs上的说明就行。
可以看看他的源码:
也就是在给
PCM
添加上了对应的头部信息
MP3
MP3
为有损编码方式,去除了部分数据,体积比无损压缩的WAV
更小。
js获取方式
使用lamejs,将WAV
转成MP3
。按照官网提供的转化案例复制过来就行,单声道(MONO)和立体声(stereo)都有。有一定的计算耗时,可以使用worker处理。