Почему процесс внутри аудиопрерывания/обратного вызова медленнее, чем в цикле?C++

Программы на C++. Форум разработчиков
Ответить
Anonymous
 Почему процесс внутри аудиопрерывания/обратного вызова медленнее, чем в цикле?

Сообщение Anonymous »

Я пишу аудиоприложение в реальном времени на C++, которое выполняет огромную обработку фрагментов звука длительностью 10 мс. Я использую miniaudio для обработки аудио ввода-вывода. При измерении времени, которое занимает обработка, т. е. записи чисел из следующих значений внутри функции обратного вызова:
std::chrono::high_resolution_clock::time_point begin = std::chrono::high_resolution_clock::now();
process_audio(input, output);
std::chrono::high_resolution_clock::time_point end = std::chrono::high_resolution_clock::now();

float elapsed_microseconds = (float)std::chrono::duration_cast(end - begin).count();

Один процесс обычно занимает около 2,5 мс, но иногда время сокращается до 1,7 мс и до 4 мс.
Однако, если я сделаю то же самое в сценарии, не работающем в реальном времени (т. е. при загрузке аудиофайла и его обработке в цикле for без функции прерывания/обратного вызова), я получаю числа стабильно около 1,8 мс с очень небольшим отклонением.
Сначала я думал, что это может быть связано с операционной системой, но я наблюдаю то же самое в Windows, Mac и Linux. Я также думал, что это может быть как-то связано с miniaudio, но то же самое происходит и с RtAudio.
Что приводит к тому, что это происходит медленнее и более непредсказуемо внутри функции обратного вызова, и могу ли я что-нибудь сделать, чтобы улучшить его?
РЕДАКТИРОВАТЬ: Вот минимальный пример:
// https://github.com/mackron/miniaudio
#define MINIAUDIO_IMPLEMENTATION
#include "miniaudio.h"

#include
#include

ma_device_config m_mic_path_config;
ma_device m_mic_device;

int discardCount;
float average_execution_time_usec;
float max_execution_time_usec;
float min_execution_time_usec;
int samples_collected;

float temp = 0;

void zero_vars() {
discardCount = 0;
average_execution_time_usec = 0.0f;
max_execution_time_usec = 0;
min_execution_time_usec = 1000000;
samples_collected = 0;
}

void log_measurement(float elapsed_microseconds) {
// Discard measurements during the first second
if (discardCount < 10){
discardCount++;
}
else {

average_execution_time_usec += elapsed_microseconds;
if (elapsed_microseconds > max_execution_time_usec){
max_execution_time_usec = elapsed_microseconds;
}
if (elapsed_microseconds < min_execution_time_usec){
min_execution_time_usec = elapsed_microseconds;
}

samples_collected++;

}
}

void print_stats() {

printf("Min execution time: %0.2f\n", min_execution_time_usec);
printf("Average execution time: %0.2f\n", average_execution_time_usec / (float) samples_collected);
printf("Max execution time: %0.2f\n", max_execution_time_usec);
printf("Samples collected: %d\n", samples_collected);

}

float beefy_process(float num) {

std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();

for(int i = 0; i < 200000; i++){
num = num * 1.55;
num = num + 5;
num = num / 2.3;
}

std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();

float elapsed_microseconds = (float)std::chrono::duration_cast(end - begin).count();

log_measurement(elapsed_microseconds);
return num;
}

void microphone_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) {
temp += beefy_process(5);
}

int start_microphone() {
ma_result result;

m_mic_path_config = ma_device_config_init(ma_device_type_capture);
m_mic_path_config.sampleRate = 48000;
m_mic_path_config.pUserData = nullptr;
m_mic_path_config.capture.pDeviceID = NULL; /* system default microphone */
m_mic_path_config.capture.format = ma_format_s16;
m_mic_path_config.capture.channels = 1;
m_mic_path_config.capture.shareMode = ma_share_mode_shared;
m_mic_path_config.dataCallback = microphone_callback;
result = ma_device_init(NULL, &m_mic_path_config, &m_mic_device);
if (result != MA_SUCCESS)
{
printf("Failed to set up microphone path. Error: %d", result);
assert(0);
return result;
}

result = ma_device_start(&m_mic_device);
if (result != MA_SUCCESS)
{
printf("Failed to start microphone path. Error: %d", result);
assert(0);
return result;
}

return 0;
}

int stop_microphone() {
ma_result result = ma_device_stop(&m_mic_device);
if (result != MA_SUCCESS)
{
printf("Failed to stop microphone path. Error: %d", result);
assert(0);
return result;
}

ma_device_uninit(&m_mic_device);

return 0;
}

int main(int argc, char** argv) {

printf("NON-REALTIME:\n");

zero_vars();

for (int i = 0; i < 300; i++){
temp += beefy_process(5);
}

print_stats();
printf("%f\n", temp); //prevents compiler from optimizing away beefy_process

printf("\nREALTIME:\n");

zero_vars();

start_microphone();
std::this_thread::sleep_for(std::chrono::milliseconds(3 * 1000));
stop_microphone();

print_stats();
printf("%f\n", temp);

return 0;
}

В результате я получаю следующий результат:
NON-REALTIME:
Min execution time: 2004.00
Average execution time: 2494.63
Max execution time: 2987.00
Samples collected: 290
1999.995239

REALTIME:
Min execution time: 2551.00
Average execution time: 3893.67
Max execution time: 4362.00
Samples collected: 291
4006.685547


Подробнее здесь: https://stackoverflow.com/questions/786 ... -to-a-loop
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C++»