代码之家  ›  专栏  ›  技术社区  ›  Paige Ruten

音频如何用数字表示?

  •  42
  • Paige Ruten  · 技术社区  · 16 年前

    我喜欢思考每件事是如何被数字所代表的。例如,纯文本由类似ASCII的代码表示,图像由RGB值表示。这些是表示文本和图像的最简单方法。

    用数字表示音频最简单的方法是什么?我想学习如何编写与音频一起工作的程序,并认为这是一个很好的开始方式。不过,我在网上找不到任何好的解释。

    10 回复  |  直到 16 年前
        1
  •  86
  •   derobert    16 年前

    物理上,正如你可能知道的,音频是一种振动。通常,我们 谈论空气在大约20Hz和20000Hz之间的振动。 也就是说空气在来回移动20到20000次 第二。

    如果你测量振动并把它转换成电信号 (比如说,用麦克风),你会得到一个电信号 与声音波形相同的电压变化。以我们纯净的语气 假设,该波形将与正弦函数相匹配。

    现在,我们有一个模拟信号,电压。仍然不是数字。但是,我们 知道这个电压在(例如)1V和+1V之间变化,我们可以 当然,在电线上安装一个电压表并读取电压。

    擅自改变电压表的刻度。我们将多重 电压是32767。它现在呼叫-1V - 32767 +1V 三万二千七百六十七 . 哦,还有 它将四舍五入到最接近的整数。

    现在,我们把电压表挂在电脑上,并指示电脑 每秒读表44100次。添加第二个电压表(用于 其他立体声频道),现在我们有了音频上的数据 光盘。

    此格式称为 立体声44100赫兹,16位线性PCM . 它真的是 只是一堆电压测量。

        2
  •  8
  •   devin    16 年前

    音频可以用数字样本表示。从本质上讲,取样器(也称为模数转换器)每1/fs获取一个音频信号的值,fs是采样频率。然后,ADC对信号进行量化,这是一个舍入操作。因此,如果您的信号范围从0到3伏(满刻度范围),那么样本将被四舍五入为,例如16位数字。在本例中,每1/fs记录一次16位数字/

    例如,大多数wav/mp3都是以44 kHz的频率采样的音频信号。我不知道你想要什么样的细节,但是有一个叫做“奈奎斯特采样率”的东西说采样频率必须至少是期望频率的两倍。所以在你的wav/mp3文件中,你最多只能听到tp22kHz的频率。

    在这方面你可以深入了解很多细节。最简单的形式当然是wav格式。它是未压缩的音频。格式如mp3和ogg必须先解压缩,然后才能使用它们。

        3
  •  5
  •   Ciro Santilli OurBigBook.com    6 年前

    最小C音频生成示例

    下面的示例以原始格式生成纯1000kHz的窦。在44.1KHz采样率下,它将持续4秒。

    主要内容:

    #include <math.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdint.h>
    
    int main(void) {
        FILE *f;
        const double PI2 = 2 * acos(-1.0);
        const double SAMPLE_FREQ = 44100;
        const unsigned int NSAMPLES = 4 * SAMPLE_FREQ;
        uint16_t ampl;
        uint8_t bytes[2];
        unsigned int t;
    
        f = fopen("out.raw", "wb");
        for (t = 0; t < NSAMPLES; ++t) {
            ampl = UINT16_MAX * 0.5 * (1.0 + sin(PI2 * t * 1000.0 / SAMPLE_FREQ));
            bytes[0] = ampl >> 8;
            bytes[1] = ampl & 0xFF;
            fwrite(bytes, 2, sizeof(uint8_t), f);
        }
        fclose(f);
        return EXIT_SUCCESS;
    }
    

    生成 out.raw :

    gcc -std=c99 -o main main.c -lm
    ./main
    

    游戏 生的 直接:

    sudo apt-get install ffmpeg
    ffplay -autoexit -f u16be -ar 44100 -ac 1 out.raw
    

    或者转换为更常见的音频格式,然后使用更常见的音频播放器播放:

    ffmpeg -f u16be -ar 44100 -ac 1 -i out.raw out.flac
    vlc out.flac
    

    参数解释位置: https://superuser.com/a/1063230/128124

    以下是D合成器中更有趣的佳能: Programmatically synthesizing programming music?

    在Ubuntu 18.04上测试。 GitHub upstream .

    物理

    音频在每一时刻都被编码为一个数字。将其与视频进行比较,后者需要每一时刻的宽度*高度数字。

    然后将该数字转换为 diaphragm 您的演讲者:

    |   /
    |  /
    |-/
    | | A   I   R
    |-\
    |  \
    |   \
    <-> displacement
    
    |     /
    |    /
    |---/
    |   | A I   R
    |---\
    |    \
    |     \
    <---> displacement
    
    |       /
    |      /
    |-----/
    |     | A I R
    |-----\
    |      \
    |       \
    <-----> displacement
    

    位移将空气前后推,产生压差,压差通过空气 P-waves .

    只有位移才重要:一个恒定的信号,即使是最大的,也不会产生声音:横膈膜只是停留在一个固定的位置。

    这个 sampling frequency 确定应以多快的速度进行位移。

    44,1kHz 是一种常见的采样频率,因为人类可以听到高达20kHz的声音 Nyquist–Shannon sampling theorem .

    采样频率类似于视频的fps,尽管与我们通常看到的25(影院)-144(硬核游戏监视器)范围相比,它的值要高得多。

    格式

    .raw 是一种未指定的格式,只包含振幅字节,没有元数据。

    我们必须在命令行上传递一些元数据参数,比如采样频率,因为格式不包含这些数据。

    还有其他未压缩格式,其中包含所有需要的元数据,例如 .wav 见: WAV File Synthesis From Scratch - C

    然而,在实践中,大多数人只处理压缩格式,这使得文件/流媒体更小。其中一些格式考虑了人耳的特性,以有损的方式进一步压缩音频。

    生物

    人类主要通过频率分解来感知声音(亦称 Fourier transform )

    我认为这是因为内耳的某些部分会与不同的频率产生共振(Todo证实)。

    因此,在合成音乐时,我们更多地考虑的是增加频率而不是时间点。这是说明 in this example .

    这导致了对每个时间点在20Hz和20kHz之间的1d矢量的思考。

    数学傅立叶变换失去了时间的概念,所以我们在合成时要做的是取点的组,并求出该组的频率,然后在那里进行傅立叶变换。

    幸运的是,傅立叶变换是线性的,所以我们可以直接求和归一化位移。

    每一组点的大小都会导致时间-频率精度的权衡,这种权衡由与 Heisenberg's uncertainty principle .

    Wavelets 可能是一个更精确的数学描述这个中间时间-频率的描述。

        4
  •  4
  •   Guffa    16 年前

    将声音表示为数字的最简单方法是PCM(脉冲编码调制)。这意味着声音的振幅是以设定的频率记录的(每个振幅值称为样本)。例如,CD质量的声音是频率为44100赫兹的16位采样(立体声)。

    样本可以表示为整数(通常为8、12、16、24或32位)或浮点数(16位浮点或32位双精度)。号码可以是有符号的,也可以是无符号的。

    对于16位有符号样本,值0将在中间,而-32768和32767将是最大振幅。对于16位无符号样本,值32768位于中间,0和65535为最大振幅。

    对于浮点样本,通常的格式是0在中间,而-1.0和1.0是最大振幅。

    然后可以压缩PCM数据,例如使用MP3。

        5
  •  3
  •   Jimmy    16 年前

    我认为特定采样频率下的波形样本将是最基本的表示。

        6
  •  2
  •   Chris    16 年前

    你看过波形特写吗?Y轴简单地表示为整数,通常为16位。

        7
  •  2
  •   sybreon    16 年前

    查找类似模拟数字转换的内容。你应该开始了。这些设备可以将音频信号(正弦波)转换为数字表示。所以,一个16位的ADC可以表示一个介于-32768到32768之间的正弦。这是定点的。也可以在浮点中执行(尽管出于性能原因不推荐,但出于范围原因可能需要)。相反的(数模转换)发生在我们把数字转换成正弦波的时候。这是由一个称为DAC的东西处理的。

        8
  •  2
  •   Nathan    16 年前

    我认为开始播放音频的一个好方法是 Processing Minim . 这个程序将从你的麦克风中提取声音的频谱!

    import ddf.minim.*;
    import ddf.minim.analysis.*;
    
    AudioInput in;
    FFT fft;
    
    void setup()
    {
      size(1024, 600);
      noSmooth();
      Minim.start(this);
      in = Minim.getLineIn();
      fft = new FFT(in.bufferSize(), in.sampleRate());
    }
    
    void draw()
    {
      background(0);
      fft.forward(in.mix);
      stroke(255);
      for(int i = 0; i < fft.specSize(); i++)
        line(i*2+1, height, i*2+1, height - fft.getBand(i)*10);
    }
    
    void stop()
    {
      in.close();
      Minim.stop();
      super.stop();
    }
    
        9
  •  1
  •   Joel Menezes    8 年前

    将实际的模拟音频转换为数字形式涉及两个步骤。

    1. 抽样
    2. 量化

    抽样

    连续波形(在本例中为音频)的采样率称为采样率。人类感知到的频率范围是20-20000赫兹。然而,CDS使用了奈奎斯特采样定理,即44100Hz的采样率,覆盖了0-22050Hz范围内的频率。

    量化

    从“采样”阶段接收的离散值集现在需要转换为有限数量的值。8位量化提供256个可能值,而16位量化提供多达65536个值。

        10
  •  0
  •   curious    8 年前

    答案都与采样频率有关,但没有解决这个问题。我想,一个声音的特定快照会包括许多不同频率的单独振幅(比如说,在键盘上同时敲击A和C,A的声音更大)。如何以16位数字记录?如果你所做的只是测量振幅(声音有多大),你是如何得到不同的音符的?

    啊!我想我是从这句话中得到的:“这个数字被转换成扬声器振膜的线性位移。”音符的出现取决于振膜振动的速度。这就是为什么你每秒需要44000个不同的值。一个音符大约在1000赫兹左右,所以纯音符会使光圈每秒移动1000次左右。一个完整的管弦乐的录音在整个地方都有许多不同的音符,奇迹般地,可以转换成单时间的横膈膜运动史。每秒44000次,横膈膜被指示移入或移出一点,这个简单(长)的数字列表可以代表碧昂斯对贝多芬!