Възпроизвеждане на поток в библиотеката OpenAL

Трябва да пусна поток в 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);
    }

какво правя грешно В високоговорителите слушам повтарящи се щракания. Моля, кажете ми какво трябва да направя с буферите, за да възпроизведа звука си?


person Alexander Mashin    schedule 25.02.2013    source източник


Отговори (1)


4 буфера (882 проби всеки) и 44kHz източник дават само (4 * 882/ (2 * 44100) ) = 0,04 секунди възпроизвеждане - това е просто едно "щракване".

За да произведете по-дълги звуци, трябва да заредите повече данни (макар че обикновено са достатъчни само два буфера).

Представете си, че имате 100Mb некомпресиран .wav файл. Просто прочетете, да речем, 22050 проби (това е 44100 байта данни) и ги поставете в опашката на OpenAL, свързана с източника. След това прочетете още 22050 проби във втория буфер и ги поставете в опашка. След това просто превключете буферите (както правите сега при NumberOfSampleSet == 4) и повторете, докато файлът не приключи.

Ако искате чиста синусоида на напр. 440Hz, след което с помощта на същите буфери от 22050 проби просто ги запълнете със стойностите на синусоида:

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 );
        }
    }

    ....
}
person Viktor Latypov    schedule 25.02.2013
comment
Добре. Но ти не отговаряш на въпроса ми. Не знам как трябва да поставя буферите си в опашка. И не е необходимо да изпращам 22050 проби, защото трябва латентността на звука в моята VoIP програма да е по-малка. Ако взема буфер с размер 882 байта, вземам 10 ms звук. Тази латентност ми харесва. Моля, кажете ми как мога да поставя тези буфери на опашка, за да играя. Наистина не разбирам това :(. - person Alexander Mashin; 25.02.2013
comment
@EXTRAM: Надявам се моята редакция да изясни нещата малко. Просто проверявате колко буфери все още са в опашката и добавяте още буфери, ако има нужда от повече данни. - person Viktor Latypov; 25.02.2013
comment
@ВикторЛатипов. Благодаря. Сега опитвам това. - person Alexander Mashin; 25.02.2013
comment
@Victor Latypov: в while(Processed--) какъв индекс на BufferID трябва да използвам? И ако разбирам правилно, трябва да има FBufferID, а не BufferID - person Alexander Mashin; 25.02.2013
comment
За съжаление, това трябва да е буферът от alSourceUnqueue, локалната променлива BufID. - person Viktor Latypov; 25.02.2013
comment
@EXTRAM: просто извличате друг буфер, който току-що е играл (BufID) и го запълвате с повече данни. - person Viktor Latypov; 25.02.2013
comment
тоест поставих в опашката, която току-що беше излязла от нея? - person Alexander Mashin; 25.02.2013
comment
Буферът на пръстена. Получавате буфера от източника, който току-що е възпроизвеждан и няма да се възпроизвежда повече. След това попълвате този буфер с новите данни и го добавяте в края на опашката - по този начин той ще бъде възпроизведен веднага след като всичко останало (което вече е там) бъде възпроизведено. - person Viktor Latypov; 25.02.2013
comment
ако направя това, слушам с едно щракване и мълчание. - person Alexander Mashin; 25.02.2013
comment
нека да продължим тази дискусия в чата - person Viktor Latypov; 25.02.2013