我目前正在使用 libsndfile结合 PortAudio V19从文件中读取音频数据并播放。 (请注意,我是在运行 Raspbian 的 Raspberry Pi 上执行此操作的。)我遇到的问题是我需要为以这种方式播放的每个音频样本实时动态控制播放音量。我尝试使用系统调用通过 alsamixer 来操纵全局播放音量,这在我的用例中是一个可以接受的解决方案,但是延迟太高而无法工作。
我正在寻找的是两件事之一:
我试图到处寻找有关此主题的有用(免费) Material ,但未能找到任何有帮助的东西。非常感谢任何帮助!
最佳答案
您可以通过对每个样本应用乘数来控制 PCM 音频流的幅度。您可以在将每个缓冲区(样本集)传递给 PortAudio 之前执行此操作。它很简单:
float buffer[SAMPLES_PER_BUFFER];
const float volumeMultiplier = 0.2f;
for(int i = 0; i < SAMPLES_PER_BUFFER; ++i)
{
buffer[i] *= volumeMultiplier;
}
但是,诀窍在于如何计算乘数。通常,在将整体信号电平减半之前,您不会注意到信号电平的太大变化
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;
}
出于您的目的,这可能并不重要,但是如果您要将 volumeLevelDb 或 volumeMultiplier 的值附加到像 slider 小部件这样的用户界面,则差异会很明显。
您可以将此算法应用于任何数据类型。
关于实时控制音量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15776390/