Плохая производительность с waveOut synth

Я провел некоторые исследования по синтезу звука и сумел написать очень простой синтезатор. Я использовал Microsoft WaveOut API. Я написал интерфейс, чтобы упростить весь процесс. Теперь я могу инициализировать (моно) аудиопоток и вызвать setSample. Таким образом, при частоте дискретизации 44100 выборок в секунду setSample необходимо вызывать как минимум 44100 раз в секунду.

Это прекрасно работает на моем (четырехъядерном) ноутбуке, но на старой двухъядерной картине моих родителей это действительно плохо заикается. Это довольно странно: FL Studio работает довольно плавно на компьютере моих родителей, даже когда я использую несколько эффектов на более сложном синтезаторе, в то время как мой код довольно прост.

Я понятия не имею, что вызывает такое поведение. Мой код далеко не оптимизирован, но настолько прост, что я не могу себе представить, что проблема заключается только в оптимизации (если я не делаю что-то, что действительно замедляет синтез).

Кусок кода, который может быть проблемой:

void AudioStream::setSample(float sample)
{
unsigned int discreteSample = ((sampleSize > 1) ? 0 : amplitude) + ((float)amplitude * sample);

for (unsigned int i = 0; i < sampleSize; i++)
{
data[pointr++] = (char)(discreteSample & 255);
discreteSample = discreteSample >> 8;
}

if (pointr >= maxSize)
{
if (waveOutWrite(hWaveOut, firstHeader ? &header1 : &header2, firstHeader ? sizeof(header1) : sizeof(header2)) != MMSYSERR_NOERROR)
{ throw("Error writing to sound card!"); return; }

pointr = 0;
firstHeader = !firstHeader;

if (WaitForSingleObject(handle, INFINITE) != WAIT_OBJECT_0) { throw("An error occured while waiting for sound to finish"); return; }

unsigned char *temp;
temp = data;
data = play;
play = temp;

first = false;
}
}

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

Я также слышал, что waveOut может быть программно эмулированным (что могло бы многое объяснить), но я не уверен, что (или когда, например, в каких версиях Windows или при каких обстоятельствах) это имеет место и какова производительность разница это будет иметь.

Я надеюсь, что кто-то может помочь мне.

Изменить: источник может быть найден Вот, исполнимый Вот.

0

Решение

WaveOut API и хорошая производительность невозможны вместе. Используйте что-нибудь более подходящее, ASIO или WASAPI, если вы используете Windows, или попробуйте Portaudio, если вы хотите быть кроссплатформенным.

2

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

Передача по одному образцу за раз в waveOutWrite будет ужасно неэффективной, как на уровне вашего кода, так и в драйвере. Он устанавливает DMA-передачу буфера, и если этот буфер имеет длину в один байт, он переносит все накладные расходы на переключение буферов для каждой выборки. Я бы отправлял по крайней мере одну десятую секунды отсчетов при каждом вызове waveOutWrite.

3

Если вы ищете очень простую аудио-библиотеку для создания простого синтезатора, я настоятельно рекомендую audiere http://audiere.sourceforge.net/ или же BASS http://www.un4seen.com/.

Первый довольно устарел, но в то же время один из самых простых (что не делает его плохим). Я смог написать не такой простой синтезатор. Второй, BASS, пойдет вам на пользу и в более сложных проектах. Это идет с очень легкими примерами (и синтезатор — один из них). Это очень легко настроить тоже.

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