多线程环境中值的平滑过渡

时间:2016-10-17 18:11:57

标签: c++ multithreading concurrency thread-priority

如何将值从 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;
}

0 个答案:

没有答案