如何将值从 x 平滑地转换为 y ,并以另一个线程确定的速度转换。
让我试着解释一下我的具体问题,因为它很好地说明了这一点。
我正在制作音频播放应用程序。当您突然暂停样本流到声音API时,从而在后续样本之间创建大值差异(即将正弦波更改为零),您将获得弹出声音
为避免这种情况,您需要将音量从当前值平滑过渡到零。
PortAudio ,我正在使用的库,处理后台线程上的音频,当需要数据或有数据时,它使用回调功能我。具有声音样本和音量值的缓冲区都是此回调的参数,因此我无法控制它们的读取频率。
如何在这些情况下实现音量转换:
感谢。
修改
我觉得我没有详细说明,因为担心过度指定问题。我想更多地具体化它。
基本上,数据流可以用:
来描述 Loader (async producer) -> Buffer -> Player (async consumer)
增加难度的是缓冲区像队列一样运行(为了将来实现无锁队列和数据完整性),所以我无法触摸音频数据来修改部分它是传统的。
这可能是我的设计缺陷,疏忽或只是隧道视觉,所以这可能会有所改变。
此外,我想让缓冲区只处理原始数据,因为Player对象负责实际播放,我觉得音量控制是它的责任。
可以使用此示例代码描述简化的回调:
static int bufferCallback(const void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo *timeInfo,
PaStreamCallbackFlags statusFlags,
void *userData)
{
/* Cast data passed through stream to our structure. */
simple_player<float> *data = (simple_player<float> *)userData;
float *out = (float *)outputBuffer;
unsigned int i;
(void)inputBuffer; /* Prevent unused variable warning. */
float into;
i = 0;
unsigned int more;
while (i < framesPerBuffer)
{
more = data->buffer->get(into);
if (!more)
{
return paContinue;
}
*out = clip::soft_clip(into*data->volume);
out++;
more = data->buffer->get(into);
if (!more)
{
return paContinue;
}
*out = clip::soft_clip(into*data->volume);
out++;
i++;
}
return paContinue;
}
注意:经过进一步考虑,我不认为我可以将一个线程同步到PortAudio处理线程。相反,我会让回调本身通过扩展播放器并在回调中进行计算来转换音量,例如:
static int bufferCallback(const void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo *timeInfo,
PaStreamCallbackFlags statusFlags,
void *userData)
{
/*Callback body*/
if(data->volume!=data->target_volume)
{
data->volume+=data->volume_delta;
}
return paContinue;
}