2015-10-16 2 views
2

Я пытаюсь получить входную информацию от своей гитары, которую можно воспроизвести через мой компьютер, используя библиотеку portaudio и ASIO sdk.Задержка ввода с обратным вызовом PortAudio и ASIO sdk

Я слежу за некоторыми учебными материалами на официальном сайте, чтобы получить основы. В настоящее время я получил это работает так, что Portaudio слушает входного и выходного устройства правого и у меня есть установка обратного вызова только выводить входной и ничего не делать с ним, как это:

static int paTestCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags, void *userData) 
{ 
    float *out = (float*)outputBuffer; 
    float* in = (float*)inputBuffer; 

    for (int i = 0; i<framesPerBuffer; i++) 
    { 
     *out++ = *in++; /* left */ 
     *out++ = *in++; /* right */ 
    } 
    return 0; 
} 

Этот обратный вызов установки путем вызова этого :

PaError error = Pa_OpenDefaultStream(&stream, 2, 2, paFloat32, 44100, paFramesPerBufferUnspecified, paTestCallback, &data); 
Pa_StartStream(stream); 

Теперь, это делает работу, но у меня есть много задержки (около 0,5с), когда я бью строку на моей гитаре, и когда я слышу его через мониторы.

Есть ли способ решить эту задержку? Нужно ли переписывать метод обратного вызова?

EDIT:

Итак, я получил задержку быть намного лучше, используя этот код вместо основного Pa_OpenDefaultStream()

int defaultIn = Pa_GetDefaultInputDevice(); 
int defaultOut = Pa_GetDefaultOutputDevice(); 

PaStreamParameters *inParam = new PaStreamParameters(); 
inParam->channelCount = 2; 
inParam->device = defaultIn; 
inParam->sampleFormat = paFloat32; 
inParam->suggestedLatency = 0.05; 

PaStreamParameters *outParam = new PaStreamParameters(); 
outParam->channelCount = 2; 
outParam->device = defaultOut; 
outParam->sampleFormat = paFloat32; 
outParam->suggestedLatency = 0; 

error = Pa_OpenStream(&stream, inParam, outParam, 44100, paFramesPerBufferUnspecified, paNoFlag, paTestCallback, &data); 
if (error != paNoError) { 
    Logger::log("[PortAudioManager] Could not open default stream. Exiting function..."); 
    return; 
} 

Pa_StartStream(stream); 

Существует еще немного задержки, хотя, в основном заметно при воспроизведении более чем одно примечание.

EDIT:

я понял, с помощью Ross-Bencina, что устройство ввода окна по умолчанию и устройство вывода не меняет ничего в индексе хоста API, в Portaudio. Кажется, я все время использовал MME. Я сделал следующее, чтобы получить правильный индекс для устройства ASIO:

int hostNr = Pa_GetHostApiCount(); 

std::vector<const PaHostApiInfo*> infoVertex; 
for (int t = 0; t < hostNr; ++t) { 
    infoVertex.push_back(Pa_GetHostApiInfo(t)); 
} 

Тогда я только что проверил, который является один с ASIO и установить suggestedLatency в обоих PaStreamParameters до 0, а задержка в настоящее время нет, и звук хороший (хотя сейчас это моно).

ответ

4

Вы на правильном пути, используя paFramesPerBufferUnspecified.

Задержка ASIO зависит от драйвера. Есть две возможности:

  1. Драйвер ASIO позволяет код (т.е. Portaudio) запроса латентный (возможно, с некоторыми ограничениями). PortAudio находит наилучшее соответствие между поддерживаемым размером буфера драйвера и задержкой, которую вы запрашиваете.

  2. Другая возможность заключается в том, что ваш аудиоинтерфейс не обеспечивает программный контроль за настройками задержки. Вместо этого латентность выбирается только из пользовательского интерфейса панели управления ASIO драйвера (и драйвер заставит фиксированный размер буфера на PortAudio). В этом случае вы должны изучить пользовательский интерфейс панели управления драйвером, чтобы установить минимальную работоспособную задержку.

В любом случае, ваш подход с Pa_OpenStream близок к оптимальному, но вы должны запросить нулевую задержку для входа и выхода (в вашем редактировании вы запрашивающий 50ms входной задержку, нулевая выходная задержки). Конечным результатом будет то, что PortAudio выбирает самый низкий доступный размер буфера ASIO. Если это окажется нестабильным (звуковые сбои), вам потребуется увеличить запрошенную задержку.

include/pa_asio.h предоставляет интерфейс, специфичный для хоста-API, для запроса размеров буфера ASIO, разрешенных драйвером (помните, что это может измениться при изменении настроек на панели управления). Он также предоставляет функцию для отображения пользовательского интерфейса панели управления водителя.

EDIT: Обратите внимание, что Pa_GetDefaultInputDevice() и Pa_GetDefaultOutputDevice() будет возвращать только устройства ASIO, если вы построили Portaudio только для ASIO. Если вы включили какие-либо другие более распространенные API в сборку (например, WMME или DirectSound), им будет присвоен приоритет как устройство с наименьшим общим знаменателем. Вы можете добавить проверку, что вы на самом деле доступ к устройству ASIO:

assert(Pa_GetHostApiInfo(Pa_GetDeviceInfo(Pa_GetDefaultOutputDevice())->hostApi)->type == paASIO); 

Если Portaudio скомпилирован с поддержкой нескольких интерфейсов хоста: Для того, чтобы получить устройство ASIO по умолчанию: перечислить интерфейсы хоста с использованием Pa_GetHostApiCount и Pa_GetHostApiInfo найти ASIO хост API. Затем потяните индексы устройства ASIO по умолчанию из возвращаемой структуры PaHostApiInfo.

+0

Замечательно знать о тех вещах, о которых я думал. Я попытался установить обе задержки на ноль, и это дает мне реальный звук нарезанного звука. О панели управления Asio: нет устройства, когда устройство загружается с помощью portaudio. Он не отображается на панели задач, как если бы я начал играть в Guitar Rig. – Dries

+0

Я также пробовал 'PaAsio_ShowControlPanel (defaultIn, hwnd)', но я получаю сообщение об ошибке, что мое устройство недействительно. Любые мысли по этому поводу? – Dries

+1

Хм. 'Pa_GetDefaultInputDevice' вернет только устройство ASIO, если вы создали PortAudio для * только * ASIO. Если вы также создали, например, WMME или DirectSound, то Pa_GetDefaultInputDevice вернет те, что относятся к ASIO. Возможно, вам нужно будет решить, какое устройство является вашим устройством ASIO. например запустив pa_devs или извлекая устройство ASIO по умолчанию (подробнее просмотрите API перечисления устройств). –