0

私は音声合成についていくつかの調査を行い、非常に単純なシンセサイザーを作成することができました。Microsoft waveOut API を使用しました。プロセス全体を簡素化するためのインターフェースを作成しました。(モノラル) オーディオ ストリームを初期化し、setSample を呼び出すことができるようになりました。したがって、1 秒あたり 44100 サンプルのサンプリング レートでは、setSample を 1 秒あたり少なくとも 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 で、どのような状況で)、どの程度のパフォーマンスが得られるかはわかりません。これがもたらす違い。

誰かが私を助けてくれることを願っています。

編集: ソースはここにあります。実行可能ファイルはここにあります。

4

3 に答える 3

3

一度に 1 つのサンプルを waveOutWrite に渡すことは、コードのレベルとドライバー内の両方で非常に非効率的です。バッファの DMA 転送をセットアップし、そのバッファが 1 バイト長の場合、サンプルごとにバッファを切り替えるすべてのオーバーヘッドが発生します。waveOutWrite を呼び出すたびに、少なくとも 10 分の 1 秒のサンプルを送信します。

于 2013-08-01T20:30:17.083 に答える
2

WaveOut API と優れたパフォーマンスの両立は不可能です。Windows を使用している場合は ASIO または WASAPI など、より適切なものを使用してください。クロスプラットフォームを使用する場合は、Portaudio を試してください。

于 2013-08-01T18:47:26.410 に答える