我对声音合成进行了一些研究,并设法编写了一个非常简单的合成器。我使用过微软的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可能是软件模拟的(这可以解释很多),但我不确定是否(或何时,如在什么版本的窗口或在什么情况下)是这样,以及这会对性能产生多大影响。
我希望有人能帮助我。
编辑:源代码可以在这里找到,可在这里执行。
一次将一个样本传递给waveOutWrite将是非常低效的,无论是在代码级别还是在驱动程序中。它设置了一个缓冲区的DMA传输,如果该缓冲区有一个字节长,则会导致为每个样本切换缓冲区的所有开销。我会在每次调用waveOutWrite时向它发送至少十分之一秒的样本。
WaveOut API和良好的性能是不可能结合在一起的。如果使用Windows,请使用更合适的东西,ASIO或WASAPI,如果您想跨平台,请尝试Portaudio。
如果你正在寻找一些非常简单的音频库来制作一个简单的合成器,我强烈推荐audierehttp://audiere.sourceforge.net/或BASShttp://www.un4seen.com/.
第一个已经过时了,但同时也是最简单的一个(这并不会让它变得糟糕)。我可以用它写不那么简单的合成器。第二个,BASS,在更复杂的项目中也会对你有好处。它提供了非常简单的例子(合成器就是其中之一)。设置起来也很容易。