语音文件的格式、字节计算、PCM头信息 2019-04-26

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了语音文件的格式、字节计算、PCM头信息 2019-04-26相关的知识,希望对你有一定的参考价值。

参考技术A PCM

我们在音频处理的时候经常会接触到 PCM 数据:它是模拟音频信号经 模数转换 (A/D变换)直接形成的 二进制序列 ,该文件 没有附加的文件头 和 文件结束 标志。

声音本身是模拟信号,而计算机只能识别数字信号,要在计算机中处理声音,就需要将声音数字化,这个过程叫经模数转换(A/D变换)。最常见的方式是透过脉冲编码调制PCM (Pulse Code Modulation) 。

运作原理如下:首先我们考虑声音经过麦克风,转换成一连串电压变化的信号,如下图所示。这张图的横座标为秒,纵座标为电压大小。

要将这样的信号转为 PCM 时,需要将声音量化,我们一般从如下几个维度描述一段声音:

采样频率: 即取样频率,指每秒钟取得声音样本的次数。采样频率越高,声音的质量也就越好,声音的还原也就越真实,但同时它占的资源比较多。由于人耳的分辨率很有限,太高的频率并不能分辨出来。在16位声卡中有22KHz、44KHz等几级,其中,22KHz相当于普通FM广播的音质,44KHz已相当于CD音质了,目前的常用采样频率都不超过48KHz。

采样位数: 即采样值或取样值(就是将采样样本幅度量化)。它是用来衡量声音波动变化的一个参数,也可以说是声卡的分辨率。它的数值越大,分辨率也就越高,所发出声音的能力越强。

声道数: 很好理解,有单声道和立体声之分,单声道的声音只能使用一个喇叭发声(有的也处理成两个喇叭输出同一个声道的声音),立体声的PCM 可以使两个喇叭都发声(一般左右声道有分工) ,更能感受到空间效果。

时长:  采样的时长

下面再用图解来看看采样位数和采样频率的概念。让我们来看看这几幅图。

图中的黑色曲线表示的是PCM 文件录制的自然界的声波,

红色曲线表示的是PCM 文件输出的声波,

这个图中,采样点是离散的,每一个点对应pcm一个单元的数据。

采样频率越高,x轴采样点就越密集,声音越接近原始数据

采样位数越高,y轴采样点就越密集,声音越接近原始数据

采样频率单位为Hz,表示每秒采样的次数:

一般有11025HZ(11KHz)、22050HZ(22KHz)、44100Hz(44KHz)三种。

采样位数单位为bit(位),一般有 8bit 和 16bit 。8bit 表示用 8bit 空间量化某时刻的声音,这一点基本是和图片用r、g、b三单位共 24bit 量化颜色一样。

综上所述,我们可以得到pcm文件的体积计算公式(这里我们把 采样位数/8 是因为电脑上是将bit转化为byte):

存储量 = (采样频率 × 采样位数/8) × 声道 × 时间.

例如,数字激光唱盘(CD-DA,红皮书标准)的标准采样频率为44.l kHz,采样数位为16 位,立体声(2声道),可以几乎无失真地播出频率高达22 kHz的声音,这也是人类所能听到的最高频率声音。激光唱盘一分钟音乐需要的存储量为:

(44.1*1000* l6 *2)*60/8=10,584,000(字节)=10.584 M Bytes

这个数值就是 PCM 声音文件在硬盘中所占磁盘空间的存储量。

 数据以 二进制序列 储存在文件里

双声道音频的存储方式是LRLRLRLR,16bit音频是每个声道都是16bit(2字节)么?PCM是interleaved的方式存储,具体存储的时候还有小端(little endian)和 (big endian)的问题,一般的存储是小端的,也就是2字节,低位在前,高位在后一个采样点16位是0x 1234 存储的时候是 0x34 和 0x12 , 如果是大端就反过来。

一个单声道的pcm无头音频1M ,转成 双声道就变成2M了,就算是有一条声道没信息(或者微弱信号噪声),但是 转成双声道的时候就算是静音,数据大小是0x0000他也是要占着位数的,所以不管怎样,只要是双声道就会变成2倍大小。

前面也介绍到了,PCM 数据本身只是一个 裸码流 ,它是由 声道、采样位数、采样频率、时长 共同决定的,因此我们至少要知道其中的三个才能将 PCM 所代表的数据提取出来。

因此,纯PCM数据是无法播放的,因此还需要一段 描述数据 。计算机系统中的一个比较常见的做法是将 pcm码流和描述信息封装在一起 ,形成一个音频文件。这样就可以直接播放了。

一种常见的方式是使用wav格式定义的规范将pcm码流和描述信息封装起来。 查看 pcm 和对应wav文件的 hex(16进制)文件,可以发现,wav文件只是在pcm文件的开头多了44字节 ,来表征其声道数、采样频率和采样位数等信息。 这个其实和bmp非常类似。

WAV、G729、G723 、MP3 等音频格式都是8k 16bit wav音频经过压缩的格式。

由于厂商众多、 很多音频格式 应运而生,比如nice公司出品的 nmf 其实音频,其实就是一个经过多层再包装的g729;vox 格式是华为公司出品的音频。

vox 格式是华为的格式、他的后缀一种是 V3 的,直接把后缀改成vox就可以听;还有一种后缀就是vox。

vox格式因为本身是没有头信息的看不到,所以不知道采样率不能转码、这时候用 cooledit 打开听一下,选择8k的采样率打开如果语速很快音频实际是6k;如果选择6k的采样率打开如果语速很快音频实际是8k。现在 得知采样率之后就可以用工具转码,下面会说到工具ffmpeg以及他的轻量版sox。

G729以10字节作为一个解码单元,G729转码时先把头去掉再转。

G729是十六倍压缩。8k 16bit 8kb/s (正常是128kb/s 压缩16倍)

和g729一样是16倍压缩,但是由于压缩算法不一样,G729的频谱是光滑的、而MP3音频的损失很多。是最差的一种音频格式。

8k 8bit stereo 128kb/s音频格式,应该是非压缩的格式

首先音频格式之间转码,比如g729 转 mp3 流程是g729->8k、16bit wav -> mp3,都是要先经过wav的。

一般会内置的轻量级ffmpeg工具。

sox 1.wav 2.wav 3.wav 1_2_3.wav

hexdump -Cv in.wav | less

标准音频的头字节是44位 

查看音频字节信息是:hexdump -C in.wav

看红色部分

其中音频大小可以在第 40-43 位(从0位开始)倒着看是音频大小: 0x 00 02 53 a0  

转换成 十进制 是152480 加上 标准头字节  44 是152524字节

查看音频的 文件大小 是 152524字节  与计算结果吻合

其实看4-7位也行,4-7位查看下来是152516字节

152516+8=152524字节其实这个152516就是除了头字节的八个字节后面的字节数

看蓝色部分

第 24-25 位是 0x 40 1f  = 8k 这个位置标记的是音频的采样率大小标准音频的头字节是44位 

一个裸的PCM格式音频数据,如果不带头信息,不知道其采样率等相关信息,就无法用播放器播放出来。下面是默认的头信息格式:

//音频头部格式

struct wave_pcm_hdr



    char                      riff[4];                           // = "RIFF"

    SR_DWORD        size_8;                        // = FileSize - 8

    char                      wave[4];                      // = "WAVE"

    char                       fmt[4];                        // = "fmt "

    SR_DWORD        dwFmtSize;                // = 下一个结构体的大小 : 16

    SR_WORD          format_tag;                  // = PCM : 1

    SR_WORD          channels;                    // = 通道数 : 1

    SR_DWORD       samples_per_sec;      // = 采样率 : 8000 | 6000 | 11025 | 16000

    SR_DWORD       avg_bytes_per_sec;    // = 每秒字节数 : dwSamplesPerSec *wBitsPerSample / 8

    SR_WORD          block_align;                // = 每采样点字节数 : wBitsPerSample / 8

    SR_WORD          bits_per_sample;        // = 量化比特数: 8 | 16

    char                     data[4];                       // = "data";

    SR_DWORD       data_size;                 // = 纯数据长度 : FileSize - 44

;

//默认音频头部数据

struct wave_pcm_hdr default_pcmwavhdr =



    'R', 'I', 'F', 'F' ,

    0,

    'W', 'A', 'V', 'E',

    'f', 'm', 't', ' ',

    16,

    1,

    1,

    16000,

    32000,

    2,

    16,

    'd', 'a', 't', 'a',

    0 

;

PCM 音频到文件

【中文标题】PCM 音频到文件【英文标题】:PCM Audio to File 【发布时间】:2019-09-24 00:14:59 【问题描述】:

我想在 Discord 语音频道中录制音频并使用 Discord Bot 将其保存到文件中。

我每 20 毫秒接收一次音频,作为 pcm 编码的字节 [],我想将其保存到文件中。 MP3 是首选,但我对 ogg 等其他文件格式也没有问题(它可能更容易)。

我正在使用 JDA 版本 4.ALPHA.0_82 并且我还包括 lavaplayer 版本 1.3.17 用于其他功能。如果这些库足够的话会很有帮助,但如果我必须包含更多库也没问题。

【问题讨论】:

我将 PCM 转储到一个文件中,然后通过 discord 将其发回以听到它。当然,这些文件很大,但它可以工作:^) 另请注意,JDA 为您提供 PCM 数据,而不是作品(除非他们在 v4 中更改了某些内容) 我想到了同样的方法,难道没有一种简单的方法可以将其保存为压缩音频格式吗? 我曾经被告知要通过 ffmpeg 进行管道传输。我假设你想要一个跨平台/独立的解决方案 【参考方案1】:

This question 解释了如何将 pcm 转换为 wav。 我通过覆盖方法 AudioReceiveHandler#handleCombinedAudio 将 Discord 音频复制到 List<byte[]>

private List<byte[]> rescievedBytes=new ArrayList<>();
@Override
public void handleCombinedAudio(CombinedAudio combinedAudio) 
    try 
        rescievedBytes.add(combinedAudio.getAudioData(VOLUME));
    catch (OutOfMemoryError e) 
        //close connection
    

之后,我将List 复制到byte[] 并创建了wav 文件。

try 
        int size=0;
        for (byte[] bs : rescievedBytes) 
            size+=bs.length;
        
        byte[] decodedData=new byte[size];
        int i=0;
        for (byte[] bs : rescievedBytes) 
            for (int j = 0; j < bs.length; j++) 
                decodedData[i++]=bs[j];
            
        
        getWavFile(getNextFile(), decodedData);
     catch (IOException|OutOfMemoryError e) 
        e.printStackTrace();
    

private void getWavFile(File outFile, byte[] decodedData) throws IOException 
    AudioFormat format = new AudioFormat(8000, 16, 1, true, false);
    AudioSystem.write(new AudioInputStream(new ByteArrayInputStream(
            decodedData), format, decodedData.length), AudioFileFormat.Type.WAVE, outFile);

如果恢复的音频太大 (OutOfMemoryError),转换将中止。

【讨论】:

你忘了增加 i。 为什么不使用AudioReceiveHandler提供的格式?

以上是关于语音文件的格式、字节计算、PCM头信息 2019-04-26的主要内容,如果未能解决你的问题,请参考以下文章

iOS开发——WAVE音频文件解析

[WPF 学习] 15.播放百度合成的语音

PCM 音频到文件

Swift iOS实现把PCM语音转成MP3格式

wav格式和pcm格式怎么相互转换?

Android 逆向ELF 文件格式 ( ELF 文件当前版本号 | 操作系统 ABI 信息 | ABI 版本 | 文件头校验 | 文件头长度信息 )