0

我对声音合成做了一些研究,并设法编写了一个非常简单的合成器。我使用了 microsoft waveOut API。我写了一个界面来简化整个过程。我现在可以初始化(单声道)音频流并调用 setSample。因此,对于每秒 44100 个样本的采样率,setSample 需要每秒至少调用 44100 次。

这在我的(四核)笔记本电脑上运行良好,但在我父母的旧双核 vista 上,它非常糟糕。这很奇怪: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 或在什么情况下)是这种情况以及性能有多大这会有所不同。

我希望有一个人可以帮助我。

编辑:源代码可以在这里找到,可执行在这里

4

3 回答 3

3

一次将一个样本传递给 waveOutWrite 将非常低效,无论是在代码级别还是在驱动程序中。它建立一个缓冲区的 DMA 传输,如果该缓冲区是一个字节长,它会产生为每个样本切换缓冲区的所有开销。在每次调用waveOutWrite 时,我都会向它发送至少十分之一秒的样本。

于 2013-08-01T20:30:17.083 回答
2

WaveOut API 和良好的性能是不可能在一起的。如果使用 Windows,请使用更合适的东西,ASIO 或 WASAPI,或者如果您想跨平台,请尝试 Portaudio。

于 2013-08-01T18:47:26.410 回答
0

如果您正在寻找一些非常简单的音频库来制作简单的合成器,我强烈推荐audiere http://audiere.sourceforge.net/BASS http://www.un4seen.com/

第一个已经过时了,但同时也是最简单的一个(这并不会让它变坏)。我能够用它写出不那么简单的合成器。第二个,BASS,在更复杂的项目中也会对你有好处。它带有非常简单的示例(合成器就是其中之一)。它也很容易设置。

于 2013-08-01T19:04:14.807 回答