• PCM音频数据格式介绍


    http://blog.csdn.net/ljxt523/article/details/52068241

    1. What is PCM?

    PCM(Pulse-code-modulation)是模拟信号以固定的采样频率转换成数字信号后的表现形式。

    Sample Rate : 
    采样频率单位为:Hz。采样频率越高,音频质量越好,占用空间也越大。

    Sign : 
    音频数据是否是有符号的。通常情况下都是有符号的。若是将有符号的数据当做无符号的数据来处理将会使声音听来很刺

    Sample Size : 
    表示每一个采样数据的大小。通常该值为16-bit。

    Byte Ordering : 
    字节序指的是little-endian还是big-endian。表示音频数据的存储字节序。通常均为little-endian。

    Number of Channels : 
    标识音频是单声道(mono,1 channel)还是立体声(stereo,2 channels)。

    通过以上五个数据我们就可以描述一个PCM数据,播放一个PCM数据需要的就是以上五个数据。

    2. What does a PCM stream look like?

    单声道:

    1.  
      +------+------+------+------+------+------+------+------+------+
    2.  
      | 500 | 300 | -100 | -20 | -300 | 900 | -200 | -50 | 250 |
    3.  
      +------+------+------+------+------+------+------+------+------+
    • 1
    • 2
    • 3

    每个整数占据2个字节(16-bit),9个采样也就是18字节的数据。每个采样的整数大小最小为 -32768,最大为 32768 。根据采样数据的位置和值画一个图的话,就会得到像播放器上那样的波浪形图。

    我们可以像下面伪代码示例这样将数据读入一个C语言数组 :

    1.  
      FILE *pcmfile
    2.  
      int16_t *pcmdata;
    3.  
      pcmfile = fopen(your pcm data file);
    4.  
      pcmdata = malloc(size of the file);
    5.  
      fread(pcmdata, sizeof(int16_t), size of file / sizeof(int16_t), pcmfile);
    • 1
    • 2
    • 3
    • 4
    • 5

    如果我们将这些数据送入声卡,我们就可以听到声音。当然我们需要告诉声卡这些数据的采样率。若我们告知声卡的采样率大于数据本身的采样率,那么这些数据的播放速度会高于其原始的速度。就是快放的功能。

    立体声:

    1.  
      +----------+----------+---------+----------+---------+----------+---------+----------+----------+
    2.  
      | LFrame1 | RFrame1 | LFrame2 | RFrame2 | LFrame3 | RFrame3 | LFrame4 | RFrame4 | LFrame5 |
    3.  
      +----------+----------+---------+----------+---------+----------+---------+----------+----------+
    • 1
    • 2
    • 3

    每一个frame是一个16-bit的采样点。左右声道的数据交叉存放。

    3. Basic Audio Effects – Volume Control

    现在让我们来看一下一些真实的波形图。最简单的就是正弦波了。 
    这里写图片描述

    我们将波形的振幅扩大五倍,图形如下: 
    这里写图片描述

    所以如果要增加PCM数据的音量,只需要将每一个采样的数据乘以一个系数就行了。如果我们的PCM数据有2048个字节,则包含了1024个采样。我们用如下的伪代码来扩大音量 :

    1.  
      int16_t pcm[1024] = read in some pcm data;
    2.  
      for (ctr = 0; ctr < 1024; ctr++) {
    3.  
      pcm[ctr] *= 2;
    4.  
      }
    • 1
    • 2
    • 3
    • 4

    音量控制就是这么简单,但是要注意两点:

    1. 若采样点的数据乘以扩大系数之后的值 小于 -32768 或 大于 32768 ,则此处采样的数值只能取 -32768 或 32768
    1.  
      int16_t pcm[1024] = read in some pcm data;
    2.  
      int32_t pcmval;
    3.  
      for (ctr = 0; ctr < 1024; ctr++) {
    4.  
      pcmval = pcm[ctr] * 2;
    5.  
      if (pcmval < 32767 && pcmval > -32768) {
    6.  
      pcm[ctr] = pcmval
    7.  
      } else if (pcmval > 32767) {
    8.  
      pcm[ctr] = 32767;
    9.  
      } else if (pcmval < -32768) {
    10.  
      pcm[ctr] = -32768;
    11.  
      }
    12.  
      }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    1. 我们将采样点的数据乘以2并不代表将声音的音量扩大了两倍,事实上也的确如此。声音音量的增益系数与音量的关系如图: 
      这里写图片描述

    以上内容翻译自:http://www.ypass.net/blog/2010/01/pcm-audio-part-3-basic-audio-effects-volume-control/

    4. How to change PCM Sample Rate

    根据定义,Sample Rate表示每秒钟的采样个数,所以若是要改变音频的采样频率,我们只需要对采样点做适当的丢弃或者复制就可以。

    比如:原始音频为opus编码,单声道,采样率为48kHz,采样点大小为16-bit。如何得到编码为speex,采样率为16kHz,采样大小为16-bit的音频? 
    我们需要以下几步:

      1. 将opus解码为PCM格式数据(叫做PCM1),此时的PCM1的采样率为48kHz
      2. 将PCM1的数据中第 3*n(n为从0开始的自然数) 个位置的采样点,丢弃3*n+1 和3*n+2位置的采样点。得到PCM2,此时的PCM2采样率为48kHz / 3 = 16kHz
      3. 将PCM2编码为speex数据
  • 相关阅读:
    Android中的内部类引起的内存泄露
    Android的消息机制: Message/MessageQueue/Handler/Looper
    ArrayList/Vector的原理、线程安全和迭代Fail-Fast
    JVM中的Stack和Frame
    JVM中的垃圾收集算法和Heap分区简记
    无锁编程以及CAS
    简述Java内存模型的由来、概念及语义
    MQTT协议简记
    RabbitMQ的工作队列和路由
    RabbitMQ 入门
  • 原文地址:https://www.cnblogs.com/zxc2man/p/11272564.html
Copyright © 2020-2023  润新知