• Advertisement
Sign in to follow this  

OpenAL Queuing and Unqueuing buffers.

This topic is 4544 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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.

Share this post


Link to post
Share on other sites
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--

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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]

Share this post


Link to post
Share on other sites
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 source
while (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 processed
remove processed buffers
delete 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.

Share this post


Link to post
Share on other sites
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 source
while (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 processed
remove processed buffers
delete 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);
}





[

Share this post


Link to post
Share on other sites
What I would first check for is that the stuff making the noise that is filling the buffer is not putting any silence in there.

I would suggest simplifing and try filling it completely with white noise to see if there is any break in the white noise or not. Either that or logging each byte created by that

[source lang="c++]
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();
}



... block of code, and checking that for silence.

Share this post


Link to post
Share on other sites
Ugh... I found the problem; as usual it wasn’t my logic but some stupid little thing.

alBufferData(buffers,AL_FORMAT_MONO16,Data16,samplesPerBuffer,sampleFreq)

The samplesPerBuffer field isn’t actually “samples per buffer” but size in bytes which means that code works for AL_FORMAT_MONO8, for AL_FORMAT_MONO16 I need samplesPerBuffer*2 since every sample is 2 bytes.

No where in any Open AL documentation or example tutorial was that made clear.
I feel like I need to strangle somebody.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement