0

我需要在 OpenAL 中播放流。但我不明白我需要用缓冲区和源做什么。我的伪代码:

    FirstTime = true;

        while (true)
        {
        if (!FirstTime)
                {
                    alSourceUnqueueBuffers(alSource, 1, &unbuf);
                }
        //get buffer to play in boost::array buf (882 elements) (MONO16).
                if (NumberOfSampleSet >=3)
                {
                    alBufferData(alSampleSet[NumberOfSampleSet], AL_FORMAT_MONO16, buf.data(), buf.size(), 44100);
                    alSourceQueueBuffers(alSource, 1, &alSampleSet[NumberOfSampleSet++]);
                    if (NumberOfSampleSet == 4)
                    {
                        FirstTime = false;
                        NumberOfSampleSet = 0;
                    }
                }
alSourcePlay(alSource);
    }

我究竟做错了什么?在扬声器中,我听到重复的点击声。请告诉我我需要用缓冲区做什么来播放我的声音?

4

1 回答 1

4

4 个缓冲区(每个 882 个样本)和 44kHz 源仅提供 (4 * 882/ (2 * 44100) ) = 0.04 秒的播放时间 - 这只是一个“点击”。

要产生更长的声音,您应该加载更多数据(尽管通常只有两个缓冲区就足够了)。

想象一下,您有一个 100Mb 的未压缩 .wav 文件。只需读取 22050 个样本(即 44100 字节的数据)并将它们排入与 Source 关联的 OpenAL 队列。然后将另外 22050 个样本读入第二个缓冲区并将它们也加入队列。然后只需切换缓冲区(就像您现在在 NumberOfSampleSet == 4 处所做的那样)并重复直到文件未完成。

如果你想要一个例如 440Hz 的纯正弦波,那么使用相同的 22050-sample 缓冲区只需用正弦波的值填充它们:

const int BufferSize = 22050;
const int NumSamples = 44100;
// phase offset to avoid "clicks" between buffers
int LastOffset = 0;
const float Omega = 440.0f;
for(int i = 0 ; i < BufferSize ; i++)
{
    float t = ( 2.0f * PI * Omega * ( i + LastOffset ) ) / static_cast<float>( NumSamples );

    short VV = (short)(volume * sin(t));;

    // 16-bit sample: 2 bytes
    buffers[CurrentBuffer][i * 2 + 0] = VV & 0xFF;
    buffers[CurrentBuffer][i * 2 + 1] = VV >> 8;
}
LastOffset += BufferSize / 2;
LastOffset %= FSignalFreq;

编辑1:

要实时处理某些事情(不幸的是,延迟很严重),您必须创建缓冲区,推送一些初始数据,然后检查 OpenAL 需要多少数据:

int StreamBuffer( ALuint BufferID )
{
    // get sound to the buffer somehow - load from file, read from input channel (queue), generate etc.

    // do the custom sound processing here in buffers[CurrentBuffer]

    // submit more data to OpenAL
    alBufferData( BufferID, Format, buffers[CurrentBuffer].data(), buffers[CurrentBuffer].size(), SamplesPerSec );
}

int main()
{
    ....

    ALuint FBufferID[2];

    alGenBuffers( 2, &FBufferID[0] );

    StreamBuffer( FBufferID[0], BUFFER_SIZE );
    StreamBuffer( FBufferID[1], BUFFER_SIZE );

    alSourceQueueBuffers( FSourceID, 2, &FBufferID[0] );

    while(true)
    {
        // Check how much data is processed in OpenAL's internal queue
        ALint Processed;
        alGetSourcei( FSourceID, AL_BUFFERS_PROCESSED, &Processed );

        // add more buffers while we need them
        while ( Processed-- )
        {
            Luint BufID;

            alSourceUnqueueBuffers( SourceID, 1, &BufID );

            StreamBuffer(BufID);

            alSourceQueueBuffers( SourceID, 1, &BufID );
        }
    }

    ....
}
于 2013-02-25T11:12:23.643 回答