C++ 多线程环境中值的平滑转换
如何以另一个线程确定的速度平滑地将值从x转换为y 让我试着用我的具体问题来解释,因为它很好地说明了这一点 我正在开发一个音频播放应用程序。当您突然暂停到声音API的采样流,从而在随后的采样之间创建一个大值差(即,将正弦波更改为零),您将获得一个弹出声音 为了避免这种情况,您需要将音量从当前值平滑过渡到零 PortAudio,im使用的库,在后台线程上处理音频,该线程在需要数据或有数据时使用回调函数。带有声音样本和音量值的缓冲区都是此回调的参数,因此我无法控制读取它们的频率。 在以下情况下,您如何实现音量转换:C++ 多线程环境中值的平滑转换,c++,multithreading,concurrency,thread-priority,C++,Multithreading,Concurrency,Thread Priority,如何以另一个线程确定的速度平滑地将值从x转换为y 让我试着用我的具体问题来解释,因为它很好地说明了这一点 我正在开发一个音频播放应用程序。当您突然暂停到声音API的采样流,从而在随后的采样之间创建一个大值差(即,将正弦波更改为零),您将获得一个弹出声音 为了避免这种情况,您需要将音量从当前值平滑过渡到零 PortAudio,im使用的库,在后台线程上处理音频,该线程在需要数据或有数据时使用回调函数。带有声音样本和音量值的缓冲区都是此回调的参数,因此我无法控制读取它们的频率。 在以下情况下,您如何
- 音频线程上没有线程优先级控制(可能是最高线程之一),因此无法控制读取频率。
- 无法真正阻止回调,因为它会导致音频错误
- 数据保护不是必需的-不会产生明显的错误
Loader(异步生产者)->Buffer->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只会在感觉上和感觉上消耗尽可能多的缓冲区。回调在准备好处理数据时调用,具体取决于底层主机api、操作系统和硬件,然后仅消耗由上述因素确定的数量,并且只有在回调中我才能获得它想要消耗的数量。您正在提供音频数据。与突然将其设置为零不同,您需要提供振幅稳定减小的采样(直到它们达到零)。这些值可以通过将正常采样值乘以一个系数来生成,该系数从1.0开始,随着时间的推移平滑地变为0.0(您应该能够计算自请求“停止”后经过的时间)。其中一个常见的功能是“smoothstep”;另一个是“smootherstep”-您提供了经过的总淡出时间间隔的一部分,它返回一个乘数。是否可以控制您提供的缓冲区的大小?缓冲区大小不相关。我指的是音频的音量。缓冲区包含音频数据,对吗?根据比特率,可以计算从缓冲区播放的实际音频的长度,这可以控制调用回调函数的频率。我误解了什么吗?啊,我明白了。不幸的是,PortAudio只会在感觉上和感觉上消耗尽可能多的缓冲区。回调在准备好处理数据时调用,具体取决于底层主机api、操作系统和硬件,然后仅消耗由上述因素确定的数量,并且只有在回调中我才能获得它想要消耗的数量。您正在提供音频数据。与突然将其设置为零不同,您需要提供振幅稳定减小的采样(直到它们达到零)。这些值可以通过将正常采样值乘以一个系数来生成,该系数从1.0开始,随着时间的推移平滑地变为0.0(您应该能够计算自请求“停止”后经过的时间)。其中一个常见的功能是“smoothstep”;另一个是“smootherstep”-您提供已通过的总淡出时间间隔的一部分,它返回一个乘数。
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;
}