😎 作者介绍:欢迎来到我的主页👈,我是程序员行者孙,一个热爱分享技术的制能工人。计算机本硕,人工制能研究生。公众号:AI Sun(领取大厂面经等资料),欢迎加我的微信交流:sssun902
🎈 本文专栏:本文收录于《音视频》系列专栏,相信一份耕耘一份收获,我会分享音视频相关学习内容,不说废话,祝大家都offer拿到手软
🤓 欢迎大家关注其他专栏,我将分享Web前后端开发、人工智能、机器学习、深度学习从0到1系列文章。
🖥随时欢迎您跟我沟通,一起交流,一起成长、进步!
PCM音频数据解析与原理分析
引言
脉冲编码调制(Pulse Code Modulation,简称PCM)是一种模拟信号的数字化方法,广泛应用于音频领域。PCM通过将连续的模拟信号转换为一系列离散的数字值,使得音频信号可以被数字设备处理和存储。本文将深入分析PCM的过程和原理,帮助读者理解这一基础而关键的技术。
PCM的基本概念
PCM是一种将模拟信号转换为数字信号的技术。它通过以下三个步骤实现:
- 采样:在固定的时间间隔内测量模拟信号的幅度。
- 量化:将采样得到的连续幅度值映射到最接近的有限数量的离散值。
- 编码:将量化后的离散值转换为数字代码。
PCM的关键参数
- 采样率(Sampling Rate):每秒采样的次数,单位是Hz(赫兹)。常见的采样率有44.1kHz(CD音质)、48kHz(专业音频)等。
- 量化位数(Bit Depth):每个采样值的比特数,常见的有16位、24位等。量化位数越多,能表示的动态范围越大,音质越好。
- 声道数(Channels):音频信号的通道数量,如单声道(Mono)、立体声(Stereo)等。
PCM的工作原理
采样
采样是PCM过程中的第一步。在这个过程中,模拟音频信号在特定的时间间隔(由采样率决定)被转换成离散的样本。采样定理(Nyquist定理)指出,为了避免混叠现象,采样率应至少是信号最高频率的两倍。
量化
量化是将采样得到的连续幅度值映射到离散值的过程。这个过程涉及到量化位数的选择,量化位数决定了可以表示的最小幅度变化。量化位数越高,动态范围越大,但同时也需要更多的存储空间和处理能力。
编码
编码是将量化后的离散值转换为二进制数字代码的过程。这些数字代码随后可以被数字设备存储和处理。
PCM的常见格式
- 线性PCM(LPCM):未压缩的PCM数据,通常用于高质量音频存储。
- DSD(Direct Stream Digital):一种特殊的PCM格式,使用1位量化,但采样率非常高。
PCM的优势与局限
优势
- 高质量:高采样率和量化位数可以提供非常接近原始模拟信号的音质。
- 兼容性:PCM是许多音频设备的通用格式,易于处理和转换。
局限
- 存储需求:高采样率和量化位数意味着PCM数据需要较大的存储空间。
- 带宽需求:在传输过程中,PCM数据需要较高的带宽。
代码示例
在C++中实现PCM采样通常需要使用一些外部库来处理音频硬件的输入。例如,可以使用PortAudio
库来捕获音频输入,并使用libsamplerate
(也称为Secret Rabbit Code,SRC)来改变采样率。以下是一个使用PortAudio
和libsamplerate
的C++代码示例,展示了如何进行PCM采样。
环境准备
- 确保你的开发环境中安装了
PortAudio
和libsamplerate
库。 - 包含这些库的开发头文件和库文件到你的项目中。
C++代码示例
#include <iostream>
#include <vector>
#include <portaudio.h>
#include <samplerate.h>
#define SAMPLE_RATE 44100 // 原始采样率
#define NEW_SAMPLE_RATE 44100 // 新采样率
#define FRAMES_PER_BUFFER 1024
#define NUM_SECONDS 5
#define NUM_CHANNELS 2 // 立体声
// 回调函数,PortAudio调用此函数获取音频数据
int paCallback(const void* inputBuffer, void* outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags,
void* userData) {
std::vector<float>* recordedSamples = static_cast<std::vector<float>*>(userData);
const float* in = static_cast<const float*>(inputBuffer);
for (unsigned int i = 0; i < framesPerBuffer; i++) {
// 将采样数据存储在向量中
recordedSamples->push_back(in[i*NUM_CHANNELS]); // 假设我们只记录第一个通道的数据
}
return paContinue;
}
int main() {
PaStream* stream;
PaError err;
std::vector<float> recordedSamples;
// 初始化PortAudio
err = Pa_Initialize();
if (err != paNoError) {
std::cerr << "PortAudio 初始化失败!" << std::endl;
return -1;
}
// 打开流
Pa_OpenStreamParameters inputParameters;
inputParameters.device = Pa_GetDefaultInputDevice(); // 默认输入设备
inputParameters.channelCount = NUM_CHANNELS;
inputParameters.sampleFormat = paFloat32; // 32位浮点
inputParameters.suggestedLatency = Pa_GetDeviceInfo(inputParameters.device)->defaultLowInputLatency;
inputParameters.hostApiSpecificStreamInfo = nullptr;
err = Pa_OpenStream(
&stream,
&inputParameters,
nullptr, // 无输出
SAMPLE_RATE,
FRAMES_PER_BUFFER,
paClipOff, // 我们不处理峰值
paCallback,
&recordedSamples);
if (err != paNoError) {
std::cerr << "打开流失败!" << std::endl;
return -1;
}
err = Pa_StartStream(stream);
if (err != paNoError) {
std::cerr << "开始流失败!" << std::endl;
return -1;
}
std::cout << "录制音频..." << std::endl;
// 录制指定时间的音频
Pa_Sleep((NUM_SECONDS * 1000) / (FRAMES_PER_BUFFER / NUM_CHANNELS));
err = Pa_StopStream(stream);
if (err != paNoError) {
std::cerr << "停止流失败!" << std::endl;
return -1;
}
err = Pa_CloseStream(stream);
if (err != paNoError) {
std::cerr << "关闭流失败!" << std::endl;
return -1;
}
Pa_Terminate();
// 此处可以添加代码来处理recordedSamples,例如保存到文件或进行重采样
std::cout << "录制完成!" << std::endl;
return 0;
}
编译说明
- 使用
g++
编译时,需要链接PortAudio
和libsamplerate
库,例如:g++ -o pcm_record pcm_record.cpp -lportaudio -lsamplerate
。 - 根据你的环境和库的安装方式,可能需要指定库文件的路径。
注意事项
- 这个示例程序只是展示了如何使用
PortAudio
来录制音频,并存储采样数据到一个std::vector<float>
中。 - 为了简化示例,我们只存储了第一个通道的数据。在实际应用中,你可能需要根据需要处理所有通道的数据。
- 这个示例没有展示如何使用
libsamplerate
进行重采样。如果需要改变采样率,可以在录制完成后使用SRC转换采样率。
示例提供了一个基本的框架,展示了如何在C++中使用PortAudio
库进行PCM采样。
结论
PCM是音频数字化的基础技术,它通过采样、量化和编码三个步骤将模拟信号转换为数字信号。虽然PCM数据提供了高质量的音频体验,但同时也带来了存储和带宽的挑战。随着技术的发展,出现了许多基于PCM的压缩技术,如AAC、MP3等,它们在保持音质的同时,降低了存储和传输的需求。
PCM的原理和过程是理解现代音频技术的关键,无论是在音频编辑、音乐制作还是多媒体应用中,PCM都扮演着重要的角色。
祝大家学习顺利~
如有任何错误,恳请批评指正~~
以上是我通过各种方式得出的经验和方法,欢迎大家评论区留言讨论呀,如果文章对你们产生了帮助,也欢迎点赞收藏,我会继续努力分享更多干货~
🎈关注我的公众号AI Sun可以获取Chatgpt最新发展报告以及腾讯字节等众多大厂面经。
😎也欢迎大家和我交流,相互学习,提升技术,风里雨里,我在等你~