OpenAL Queuing and Unqueuing buffers.

Started by
11 comments, last by paulecoyote 18 years, 7 months ago
What I am trying to do is have an continuous audio stream (infinite). The method I am using is to have a small array 3 of buffers: buffers[NUM_BUFFERS]; created with alGenBuffers(NUM_BUFFERS, buffers) I have 2 indexes in to that array. playBuffer and loadBuffer. loadBuffer is the buffer I am filling with data, playBuffer is the one that gets queued. Once a buffer is filled I increment loadBuffer and check loadBuffer % NUM_BUFFERS so that is cycles through the array continuously. I have a condition that if(loadBuffer == playBuffer) I don’t increment and don’t load in to the buffer. so it waits for playBuffer to increment What I want is to have playBuffer operate in the same way, increment when the buffer has been played. Then unqueue the buffer so that it can have data load into again. But I don’t know how to check if the buffer has been played by the source.
Advertisement
just query the AL_BUFFERS_PROCESSED attribute of your source, it well return the numbers of the buffer had been processed. if the value >=0. just unqueue the buffers . then do what you need do.(i do it in a while loop, use the above value as a loop counter, then unqueque the buffer and load the sound data, queque it again)

// Pseudo code
// processed = AL_BUFFERS_PROCESSED
// while (processed)
// Unqueue a buffer
// Load audio data
// Queue buffer
// processed--
I get a stuttering sound when I try that. Is there any way to make it go from one to buffer to the next smoothly.
if you only need one buffer, why you have to use "queue and unqueue" methods. I think perform smooth streaming need multibuffer. I our game, i use thread and mutibuffer to play BGM and one buffer each to play SE sound.
if it stutters try increasing the size of each of the buffers in the queue.
Anything posted is personal opinion which does not in anyway reflect or represent my employer. Any code and opinion is expressed “as is” and used at your own risk – it does not constitute a legal relationship of any kind.
I tried that already it just increases the time between stutters.

I use:
int sampleFreq = 44100; float BufferLength = 1.0f;int samplesPerBuffer = sampleFreq *  BufferLength;

to set my buffer length. If BufferLength is 1.0 seconds I get stutters once every second. If it’s 0.1 I get them 10 times a second.
sounds like you need to fill up a buffer while the other is playing. Start off with filling both, then as one needs to be unqueued fill up another and queue it.
Anything posted is personal opinion which does not in anyway reflect or represent my employer. Any code and opinion is expressed “as is” and used at your own risk – it does not constitute a legal relationship of any kind.
Thats what Im doing.
            alGetSourcei(*source,AL_BUFFERS_PROCESSED,&BUFFERS_PROCESSED);            while(BUFFERS_PROCESSED)            {                                alSourceUnqueueBuffers(*source, 1, &buffers[loadBuffer]);                                for(int i = 0; i < samplesPerBuffer ; i++)                {                    DelayA.push_front(-DecayFactor * DelayB.front()); DelayB.pop_front();                    DelayB.push_back(-DecayFactor * DelayA.back());   DelayA.pop_back();                    PickUpA--;  PickUpB++;                                        Data16 = (*PickUpA + *PickUpB) * 32767;                    Fin.push_front(*PickUpA + *PickUpB); Fin.pop_back();                }                alBufferData(buffers[loadBuffer],AL_FORMAT_MONO16,Data16,samplesPerBuffer,sampleFreq);                alSourceQueueBuffers(*source, 1,&buffers[loadBuffer]);                loadBuffer++; loadBuffer = loadBuffer % NUM_BUFFERS;                BUFFERS_PROCESSED--;            }


[Edited by - Grain on September 8, 2005 3:14:23 PM]
If the source is running out of buffers, expect it to stutter. Increasing the size wont help, but increasing the number of buffers will. Two 1 second buffers is far better than a single 1 second buffer that will stop before the next buffer is is created and queued. If you have ten 1 second buffers, this should fix any (if not all) of your stuttering problems. The buffers don't have to be 1 second long, but if the app/game slows down, it could cause problems if the buffers start to be used faster than they're added (the stuttering you encountered).

Anyway, here's how it should be done in pseudocode:



create sourcewhile (queued buffers < buffers to queue){  create buffer  queue buffer}while (run){  num buffers to add = 0  get the number of buffers processed  if (processed buffers > 0){    remove processed buffers (you know how to do this already)    increment buffers to add  }  while (buffers to add > 0){    create buffer    queue buffer    decrement buffers to add  }  if (source is not playing){//this CAN happen, so don't assume it wont    play source  }}stop source//this will class all queued buffers as processedremove processed buffersdelete source




NOTE: You don't have to add all of the buffers at once if it causes the app/game to lag. Instead, you can add 1-2 every loop, rather than the entire number of missing buffers.

[EDIT]
Sorry if this is what you're doing, but your code's kinda hard to follow.
Quote:Original post by Gorax
If the source is running out of buffers, expect it to stutter. Increasing the size wont help, but increasing the number of buffers will. Two 1 second buffers is far better than a single 1 second buffer that will stop before the next buffer is is created and queued. If you have ten 1 second buffers, this should fix any (if not all) of your stuttering problems. The buffers don't have to be 1 second long, but if the app/game slows down, it could cause problems if the buffers start to be used faster than they're added (the stuttering you encountered).

Anyway, here's how it should be done in pseudocode:



create sourcewhile (queued buffers < buffers to queue){  create buffer  queue buffer}while (run){  num buffers to add = 0  get the number of buffers processed  if (processed buffers > 0){    remove processed buffers (you know how to do this already)    increment buffers to add  }  while (buffers to add > 0){    create buffer    queue buffer    decrement buffers to add  }  if (source is not playing){//this CAN happen, so don't assume it wont    play source  }}stop source//this will class all queued buffers as processedremove processed buffersdelete source




NOTE: You don't have to add all of the buffers at once if it causes the app/game to lag. Instead, you can add 1-2 every loop, rather than the entire number of missing buffers.

[EDIT]
Sorry if this is what you're doing, but your code's kinda hard to follow.
That looks like what I'm doing already. And increasing the number of buffers didn’t help at all.

I'll post my entire code so you guys can compile and run it to see what I'm mean. It’s just one file.

/************************** * Includes * **************************/#include <windows.h>#include <cmath>#include <gl/gl.h>#include <al.h>#include <alut.h>#include <list>/************************** * Global Constants * **************************/    const float Pi = 3.14159f;    const int sampleFreq = 11025;     const float freq = 765.0f;         const float BufferLength = 0.2; //Length of Buffer in seconds    const float DecayFactor = 0.999f;      const int wavesPerString = 1;    const int maxPoints = ( sampleFreq / freq ) * wavesPerString; //Points Per Wave     const float X_step = 1.0f/maxPoints;      const int samplesPerBuffer = sampleFreq *  BufferLength;        const float PickupPosition = 0.85;    const ALuint NUM_BUFFERS = 10;    const ALuint NUM_SOURCES = 1;    ALuint buffers[NUM_BUFFERS];    ALuint source[NUM_SOURCES];    float g_Mouse_Down = false;    float Y_Mouse_Pos = 0;    float X_Mouse_Pos = 0;    HWND *g_Hwnd;/************************** * Functions * **************************/LRESULT CALLBACK WndProc (HWND hWnd, UINT message,WPARAM wParam, LPARAM lParam);void EnableOpenGL (HWND hWnd, HDC *hDC, HGLRC *hRC);void DisableOpenGL (HWND hWnd, HDC hDC, HGLRC hRC);void PluckString(float Position, float MaxAmp, float endpoint, int maxPoints, std::list<float> &DelayLineA, std::list<float> &DelayLineB){    float x = 0;    float mid = X_step* 0.0f;    std::list<float>::iterator A =  DelayLineA.begin();    std::list<float>::iterator B =  DelayLineB.begin();    float Slope_A = (MaxAmp)/(Position),          Slope_B = (MaxAmp)/(Position-endpoint);     for(int I = 0;  I < maxPoints; I++, A++, B++, x+=X_step)     {        if(x < Position)        {            *B = (x+mid)*Slope_A;            *A = (x+mid)*Slope_A;        }        else if(x > Position)        {            *B = MaxAmp + ((x-mid)-Position)*Slope_B;            *A = MaxAmp + ((x-mid)-Position)*Slope_B;        }        else        {                *B = MaxAmp;            *A = MaxAmp;        }    }}void InitOpenAL(void){    alutInit(0, NULL);	alGenBuffers(NUM_BUFFERS, buffers);		alGenSources(NUM_SOURCES, source);    ALfloat P[] = {0,0,0};	alSourcefv (*source, AL_POSITION, P);	alSourcefv (*source, AL_VELOCITY, P);	alSourcefv (*source, AL_DIRECTION, P);		alListenerfv(AL_POSITION,P);	alListenerfv(AL_VELOCITY,P);	alListenerfv(AL_ORIENTATION,P);	}/************************** * WinMain * **************************/int WINAPI WinMain (HINSTANCE hInstance,                    HINSTANCE hPrevInstance,                    LPSTR lpCmdLine,                    int iCmdShow){    WNDCLASS wc;    HWND hWnd;    HDC hDC;    HGLRC hRC;            MSG msg;    bool bQuit = false;    float theta = 0.0f;    int WindowSizeY = 480, WindowSizeX = 640;    /* register window class */    wc.style = CS_OWNDC;    wc.lpfnWndProc = WndProc;    wc.cbClsExtra = 0;    wc.cbWndExtra = 0;    wc.hInstance = hInstance;    wc.hIcon = LoadIcon (NULL, IDI_APPLICATION);    wc.hCursor = LoadCursor (NULL, IDC_ARROW);    wc.hbrBackground = (HBRUSH) GetStockObject (BLACK_BRUSH);    wc.lpszMenuName = NULL;    wc.lpszClassName = "GLSample";    RegisterClass (&wc);    /* create main window */    hWnd = CreateWindow (      "GLSample", "OpenGL Sample",       WS_CAPTION | WS_POPUPWINDOW | WS_VISIBLE,      WindowSizeX, WindowSizeY, WindowSizeX, WindowSizeY,      NULL, NULL, hInstance, NULL);    g_Hwnd = &hWnd;    /* enable OpenGL for the window */    EnableOpenGL (hWnd, &hDC, &hRC);    InitOpenAL();        /************** local vars *******************/            float *Delay_B, *Delay_A, *FIN, *Delay_C;    std::list<float> DelayA, DelayB, Fin, DelayC;    for(int i = 0; i < maxPoints; i++)    {   DelayA.push_back(0.0f); DelayB.push_back(0.0f); DelayC.push_back(0.0f); Fin.push_back(0.0f);}    float endpoint = 1;        float MaxAmp = 0.1f;    float PluckPosition = Pi*.1;     std::list<float>::iterator PickUpA, PickUpB;    PickUpA = DelayA.begin();    PickUpB = DelayB.begin();    for(int i = 0; i < (maxPoints*PickupPosition); i++)    {        PickUpA++;        PickUpB++;    }            /* program main loop */    int loadBuffer = 0, playBuffer = 0; //    ALvoid *Data;    ALubyte *Data8;    ALshort *Data16;    Data8 = new ALubyte[samplesPerBuffer];    Data16 = new ALshort[samplesPerBuffer];    for(int i = 0; i < NUM_BUFFERS; i++)    {        alBufferData(buffers,AL_FORMAT_MONO16,Data16,samplesPerBuffer,sampleFreq);        alSourceQueueBuffers(*source, 1,&buffers[loadBuffer]);         loadBuffer++;    }       loadBuffer = loadBuffer % NUM_BUFFERS;        alSourcePlay(*source);    int BUFFERS_PROCESSED = 0;    bool presed = false;    while (!bQuit)    {        /* check for messages */        if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))        {            /* handle or dispatch messages */            if (msg.message == WM_QUIT)            {                bQuit = TRUE;            }            else            {                TranslateMessage (&msg);                DispatchMessage (&msg);            }        }        else        {            //******************   Step WaveGuide     ***********************               int Pickupindex = maxPoints*PickupPosition;            int StepsPerSample = 2;                       alGetSourcei(*source,AL_BUFFERS_PROCESSED,&BUFFERS_PROCESSED);            while(BUFFERS_PROCESSED)            {                                alSourceUnqueueBuffers(*source, 1, &buffers[loadBuffer]);                playBuffer++; playBuffer = playBuffer % NUM_BUFFERS;                for(int i = 0; i < samplesPerBuffer ; i++)                {                    DelayA.push_front(-DecayFactor * DelayB.front()); DelayB.pop_front();                    DelayB.push_back(-DecayFactor * DelayA.back());   DelayA.pop_back();                    PickUpA--;  PickUpB++;                                        Data16 = (*PickUpA + *PickUpB) * 32767;                    Fin.push_front(*PickUpA + *PickUpB); Fin.pop_back();                }                alBufferData(buffers[loadBuffer],AL_FORMAT_MONO16,Data16,samplesPerBuffer,sampleFreq);                alSourceQueueBuffers(*source, 1,&buffers[loadBuffer]);                loadBuffer++; loadBuffer = loadBuffer % NUM_BUFFERS;                BUFFERS_PROCESSED--;            }            if(g_Mouse_Down && !presed)            {                presed = true;                float ScreenPercentage =  1.0f - ((float)Y_Mouse_Pos/(float)WindowSizeY);                PluckPosition = ScreenPercentage;                MaxAmp =  0.5f * ((float)X_Mouse_Pos/(float)WindowSizeX);                PluckString(PluckPosition,MaxAmp,endpoint,maxPoints,DelayB,DelayA);            }            if(!g_Mouse_Down)                presed = false;                                                     /***** OpenGL animation code *****/            glClearColor (0.0f, 0.0f, 0.0f, 0.0f);            glClear (GL_COLOR_BUFFER_BIT);            glPushMatrix ();            glTranslatef(-.75, -.75f, 0.0f);                 glScalef(1.5f,1.5f,1.5f);                  float x = 0;            std::list<float>::iterator F = DelayB.begin();            glColor3f(0,0,.7f); // Blue            glBegin (GL_LINE_STRIP);                 for(int i = 0; i < maxPoints; F++,i++, x+=X_step)    // Draw Delay_B in Blue                {                               glVertex2f ( *F, x);                }            glEnd ();            F = DelayA.begin();            x = 0;            glColor3f(0.7f,0,0); // Red            glBegin (GL_LINE_STRIP);                 for(int i = 0; i < maxPoints; F++, i++, x+=X_step)   // Draw Delay_A in Red                {                                glVertex2f ( *F, x);                }            glEnd ();/**/            F = Fin.begin();            glColor3f(1,1,1); // White            x = 0;                        glBegin (GL_LINE_STRIP);                                 for(int i = 0; i < maxPoints; i++, F++, x+=X_step)  // Draw Outputwave white.                {                               //glVertex2f (x, FIN+PickupPosition);                    glVertex2f (x, *F);                }            glEnd();                        glPopMatrix ();            SwapBuffers (hDC);        }    }        delete []Data8;    delete []Data16;        for(int i = 0; i < NUM_BUFFERS; i++)        alSourceUnqueueBuffers(*source, 1, &buffers);    alDeleteSources(NUM_SOURCES, source);    alDeleteBuffers(NUM_BUFFERS, buffers);    alutExit();       /* shutdown OpenGL */    DisableOpenGL (hWnd, hDC, hRC);    /* destroy the window explicitly */    DestroyWindow (hWnd);    return msg.wParam;}/******************** * Window Procedure * ********************/LRESULT CALLBACK WndProc (HWND hWnd, UINT message,                          WPARAM wParam, LPARAM lParam){    switch (message)    {    case WM_CREATE:        return 0;    case WM_CLOSE:        PostQuitMessage (0);        return 0;    case WM_DESTROY:        return 0;    case WM_KEYDOWN:        switch (wParam)        {        case VK_ESCAPE:            PostQuitMessage(0);            return 0;        }        return 0;    case WM_LBUTTONDOWN:        switch(wParam)        {        case MK_LBUTTON:            POINT P;                             RECT R;            GetWindowRect(*g_Hwnd,&R);            GetCursorPos(&P);                        Y_Mouse_Pos = P.y - R.top;            X_Mouse_Pos = P.x - R.left;;            g_Mouse_Down = true;                break;        default:            break;        }        break;    case WM_LBUTTONUP:        g_Mouse_Down = false;        break;    case WM_MOUSEMOVE:        POINT P;                  RECT R;        GetWindowRect(*g_Hwnd,&R);        GetCursorPos(&P);                 Y_Mouse_Pos = P.y - R.top;        X_Mouse_Pos = P.x - R.left;;        break;    default:        return DefWindowProc (hWnd, message, wParam, lParam);    }}/******************* * Enable OpenGL * *******************/void EnableOpenGL (HWND hWnd, HDC *hDC, HGLRC *hRC){    PIXELFORMATDESCRIPTOR pfd;    int iFormat;    /* get the device context (DC) */    *hDC = GetDC (hWnd);    /* set the pixel format for the DC */    ZeroMemory (&pfd, sizeof (pfd));    pfd.nSize = sizeof (pfd);    pfd.nVersion = 1;    pfd.dwFlags = PFD_DRAW_TO_WINDOW |       PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;    pfd.iPixelType = PFD_TYPE_RGBA;    pfd.cColorBits = 24;    pfd.cDepthBits = 16;    pfd.iLayerType = PFD_MAIN_PLANE;    iFormat = ChoosePixelFormat (*hDC, &pfd);    SetPixelFormat (*hDC, iFormat, &pfd);    /* create and enable the render context (RC) */    *hRC = wglCreateContext( *hDC );    wglMakeCurrent( *hDC, *hRC );}/****************** * Disable OpenGL * ******************/void DisableOpenGL (HWND hWnd, HDC hDC, HGLRC hRC){    wglMakeCurrent (NULL, NULL);    wglDeleteContext (hRC);    ReleaseDC (hWnd, hDC);}


[

This topic is closed to new replies.

Advertisement