实时控制音频音量

Chr*_*yes 4 c portaudio libsndfile audio-processing raspberry-pi

我目前正在将libsndfile与PortAudio V19结合使用,从文件中读取音频数据并进行播放。(请注意,我是在运行 Raspbian 的 Raspberry Pi 上执行此操作。)我遇到的问题是,我需要实时动态控制以这种方式播放的每个音频样本的播放音量。我尝试使用系统调用通过 alsamixer 来操纵全局播放音量,这在我的用例中是一个可接受的解决方案,但延迟太高,无法正常工作。

我正在寻找的是两件事之一:

  • 一个可以实时修改音频音量的库,可以通过作用于 libsndfile 检索到的原始音频数据,或者以最小延迟(亚毫秒)设置全局播放音量。该库必须是免费的并且可以在 Raspbian 上使用;许可不是问题。

  • 需要对 libsndfile 检索到的音频数据应用数学变换,以便修改数据的音量级别,最好目标音量在 [0.0f, 1.0f] 范围内,其中 0.0f 表示无声, 1.0f 是文件的原始卷。

我尝试全面查找有关此主题的有用(免费)材料,但未能找到任何有帮助的内容。非常感谢任何帮助!

tru*_*kvl 6

您可以通过对每个样本应用乘数来控制 PCM 音频流的幅度。您可以在将每个缓冲区(样本集)传递到 PortAudio 之前执行此操作。它很简单:

float buffer[SAMPLES_PER_BUFFER];
const float volumeMultiplier = 0.2f;
for(int i = 0; i < SAMPLES_PER_BUFFER; ++i)
{
   buffer[i] *= volumeMultiplier;
}
Run Code Online (Sandbox Code Playgroud)

然而,诀窍在于如何计算乘数。通常,在将整体信号电平减半之前,您不会注意到信号电平有太大变化volumeMultiplier = 0.5f。您可能知道,人耳感知的音量变化不是线性的,而是对数的。以下链接可能有助于解释这个概念:

使用此信息可能会更改上面的代码,如下所示:

float buffer[SAMPLES_PER_BUFFER];
//volume in dB 0db = unity gain, no attenuation, full amplitude signal
//           -20db = 10x attenuation, significantly more quiet
float volumeLevelDb = -6.f; //cut amplitude in half; same as 0.5 above
const float VOLUME_REFERENCE = 1.f;
const float volumeMultiplier = (VOLUME_REFERENCE * pow(10, (volumeLevelDb / 20.f);
for(int i = 0; i < SAMPLES_PER_BUFFER; ++i)
{
   buffer[i] *= volumeMultiplier;
}
Run Code Online (Sandbox Code Playgroud)

对于您的目的来说,这可能并不重要,但如果您要将volumeLevelDb或volumeMultiplier的值附加到用户界面(例如滑块小部件),则差异将很明显。

您可以将此算法应用于任何数据类型。