文档目录

一、音频怎么变成数据

声卡以固定的频率采样声波的电压值,每次采样得到一个数值。这些数值按时间顺序排列就是 PCM 数据。

声波(模拟信号):  ╱╲    ╱╲    ╱╲    ╱╲
                 ╱  ╲  ╱  ╲  ╱  ╲  ╱  ╲
采样(数字信号):  █   █   █   █   █   █
                  ↑   ↑   ↑   ↑   ↑   ↑
                 t0  t1  t2  t3  t4  t5
                 每隔 1/44100 秒采一次

二、三个关键参数

// 采样率(Sample Rate):每秒采多少次
// 44100 Hz = CD 音质
// 48000 Hz = 视频/DVD 标准
// 96000 Hz = 高解析度音频

// 位深(Bit Depth):每次采样用多少 bit 表示
// 16 bit = CD 音质,每个样本范围 -32768 ~ 32767
// 24 bit = 录音室级别
// float 32 = 音频处理内部格式

// 声道数(Channels):
// 1 = Mono
// 2 = Stereo(左右声道交织)
// 6 = 5.1 环绕声

// PCM 数据量计算
void calc_pcm_size(int sample_rate, int bit_depth, int channels, int duration_sec) {
    int bytes_per_sample = bit_depth / 8;
    int bytes_per_sec = sample_rate * bytes_per_sample * channels;
    int total_bytes = bytes_per_sec * duration_sec;

    printf("PCM 参数: %dHz/%dbit/%dch\n", sample_rate, bit_depth, channels);
    printf("每秒: %d bytes (%.1f KB)\n", bytes_per_sec, bytes_per_sec / 1024.0);
    printf("1 分钟: %d bytes (%.1f MB)\n", total_bytes, total_bytes / 1024.0 / 1024);
}

// calc_pcm_size(48000, 16, 2, 60);
// 输出:
// 每秒: 192000 bytes (187.5 KB)
// 1 分钟: 11520000 bytes (11.0 MB)
// 对比:同样的 1 分钟 AAC 128kbps → 约 1MB,压缩率约 11x

三、音频在内存中的布局

// Stereo 16-bit PCM 的内存布局(交织模式 Interleaved):
// [L][R][L][R][L][R]...
//  采样0  采样1  采样2
// 每个样本是 int16_t(小端序)

#include <cstdint>

struct Stereo16Sample {
    int16_t left;
    int16_t right;
};

// 生成一个 440Hz 的正弦波测试音(A4 音)
void generate_sine_wave(int16_t* buffer, int num_samples, int sample_rate) {
    double freq = 440.0;  // A4
    for (int i = 0; i < num_samples; i++) {
        double t = (double)i / sample_rate;
        double value = sin(2.0 * M_PI * freq * t) * 32767.0;  // 归一化到 16bit 范围
        buffer[i] = (int16_t)value;
    }
}

// 混音:把两个音频叠加(注意防止溢出)
void mix_audio(const int16_t* a, const int16_t* b, int16_t* out, int count) {
    for (int i = 0; i < count; i++) {
        int mixed = (int)a[i] + (int)b[i];
        // 防止溢出:钳制到 int16_t 范围
        if (mixed > 32767) mixed = 32767;
        if (mixed < -32768) mixed = -32768;
        out[i] = (int16_t) mixed;
    }
}