Плавный переход значений в многопоточной среде

Как вы переводите значение из Икс в 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;
}

1

Решение

Задача ещё не решена.

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]