我目前正在将libsndfile与PortAudio V19结合使用,以便从文件中读取音频数据并进行播放。 (请注意我在运行Raspbian的Raspberry Pi上执行此操作。)我遇到的问题是我需要为以这种方式播放的每个音频样本实时动态控制播放音量。我试图通过alsamixer使用系统调用来操作全局播放音量,这在我的用例中是一个可接受的解决方案,但延迟太高而无法工作。
我正在寻求的是两件事之一:
一个可以实时修改音频音量的库,可以通过对libsndfile检索的原始音频数据进行操作,也可以通过设置最小延迟(亚毫秒)的全局播放音量来实现。图书馆必须免费(免费)并可在Raspbian上使用;许可证不是问题。
需要应用于libsndfile检索的音频数据的数学变换,以便修改数据的音量级别,最好是目标音量在[0.0f,1.0f]范围内, 0.0f为静音,1.0f为文件的原始音量。
我试图在这个主题上寻找有用的(免费)材料并找不到任何有用的东西。非常感谢任何帮助!
答案 0 :(得分:3)
您可以通过对每个样本应用乘数来操纵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的值附加到用户界面(如滑块小部件),则差别很明显。
您可以将此算法应用于任何数据类型。