From: Larry on
Hi,

I am still stuck at programming with the waveForm API on windows.
Actually, I managed to write some code to record the audio from the mic real
time. Yet, I'd like to use more then one buffer to do it in order to avoid
choppy recording.

In a nutshell, I should pass the waveInPrepareHeader and waveInAddBuffer
more then one single buffer, something like this:

[code]
// Define WAVEHDR Structure:
WAVEHDR *buff = new WAVEHDR[num_buffers];
for (int i = 0; i<num_buffers; i++)
{
buff[i].lpData = (LPSTR) malloc(system_buf_len);
buff[i].dwBufferLength = system_buf_len;
buff[i].dwBytesRecorded = 0;
buff[i].dwUser = 0;
buff[i].dwFlags = 0;
buff[i].dwLoops = 0;

if(waveInPrepareHeader(hwi, &buff[i], sizeof(WAVEHDR)) !=
MMSYSERR_NOERROR)
printf("waveInPrepareHedare: ERROR!\n"); // return -1;

if(waveInAddBuffer(hwi, &buff[i], sizeof(WAVEHDR)) != MMSYSERR_NOERROR)
printf("waveInAddBuffer: ERROR!\n"); // return -1;
}

if(waveInStart(hwi) != MMSYSERR_NOERROR)
printf("waveInStart: ERROR!\n"); // return -1;
[/code]

The system sends me messages about the filling of a buffer by using a
CALLBACK_EVENT, so I have to wait for it with WaitForSingleObject()
function.

Now, I am stuck at guessing how to capture the single filled buffer from the
array of buffers...I tried something like this:

[code]
// Loop...
while(1)
{
if(stop_thread_flag)
break;
// CALLBACK EVENT
WaitForSingleObject(hevent, INFINITE);
for (int k = 0; k<num_buffers; k++)
{
if(buff[k].dwFlags & WHDR_DONE)
{
save_buffer(&buff[k]);
waveInAddBuffer(hwi, &buff[k], sizeof(WAVEHDR));
}
}
}
for (int u = 0; u<num_buffers; u++)
{
waveInUnprepareHeader(hwi, &buff[u], sizeof(WAVEHDR));
}
waveInClose(hwi);
return 0;
[/code]

Although it seems to be working, I am not sure wheter it is the right way to
deal with that. Do you think I shoud add a "last" after I check for the
flags to be WHDR_DONE? How can I make sure I am not getting the same single
buffer twice or more?

The whole code is avaible here:
http://theartofweb.net/cpp/waveform_recorder_05.txt

thanks

From: Tim Roberts on
"Larry" <dontmewithme(a)got.it> wrote:
>
> I am still stuck at programming with the waveForm API on windows.
>Actually, I managed to write some code to record the audio from the mic real
>time. Yet, I'd like to use more then one buffer to do it in order to avoid
>choppy recording.
>...
> // CALLBACK EVENT
> WaitForSingleObject(hevent, INFINITE);
> for (int k = 0; k<num_buffers; k++)
> {
> if(buff[k].dwFlags & WHDR_DONE)
> {
> save_buffer(&buff[k]);
> waveInAddBuffer(hwi, &buff[k], sizeof(WAVEHDR));
> }
> }
> }
> for (int u = 0; u<num_buffers; u++)
> {
> waveInUnprepareHeader(hwi, &buff[u], sizeof(WAVEHDR));
> }
> waveInClose(hwi);
> return 0;
>[/code]
>
>Although it seems to be working, I am not sure wheter it is the right way to
>deal with that. Do you think I shoud add a "last" after I check for the
>flags to be WHDR_DONE? How can I make sure I am not getting the same single
>buffer twice or more?

This is basically the right idea. If it were me, I would clear the
WHDR_DONE flag in the header as soon as I saw it was set, to avoid the
duplicate buffer problem. I suspect that waveInAddBuffer will do that for
you, but no harm in being safe.

The only other problem has to do with wraparound. If there were a delay
such that two buffers completed before you got around to enumerating the
list, you might get a case where the very last and the very first buffer
were the ones filled. Your code, because it starts at 0 each time, would
get them in the wrong order. The way I would solve that is to use a
std::list to hold the headers. Pop the finished ones off the top, push
empty ones back in the bottom.
--
Tim Roberts, timr(a)probo.com
Providenza & Boekelheide, Inc.
From: Larry on
"Tim Roberts" <timr(a)probo.com> ha scritto nel messaggio
news:1f7jj5h0jtomiss0b3ajc9qjpbabsk6ate(a)4ax.com...

> This is basically the right idea. If it were me, I would clear the
> WHDR_DONE flag in the header as soon as I saw it was set, to avoid the
> duplicate buffer problem. I suspect that waveInAddBuffer will do that for
> you, but no harm in being safe.

I am sure the waveInAddBuffer is doing that for me.

> The only other problem has to do with wraparound. If there were a delay
> such that two buffers completed before you got around to enumerating the
> list, you might get a case where the very last and the very first buffer
> were the ones filled. Your code, because it starts at 0 each time, would
> get them in the wrong order. The way I would solve that is to use a
> std::list to hold the headers. Pop the finished ones off the top, push
> empty ones back in the bottom.

Ok this is how I push the buffers to the waveIn functions before actually
staring recording:

//
WAVEHDR *buff = new WAVEHDR[num_buffers];
for (int i = 0; i<num_buffers; i++)
{
buff[i].lpData = (LPSTR) malloc(system_buf_len);
buff[i].dwBufferLength = system_buf_len;
buff[i].dwBytesRecorded = 0;
buff[i].dwFlags = 0;
waveInPrepareHeader(hwi, &buff[i], sizeof(WAVEHDR));
waveInAddBuffer(hwi, &buff[i], sizeof(WAVEHDR));
}
waveInStart(hwi);
//

So, if I set up 3 buffers I'll have: buff[0], buff[1], buff[2] pushed in the
waveInPrepareHeader() and waveInAddBuffer() in that order. Now, I am almost
sure I should get the buffers from the system in that order as well, so I
came up with something like this:

// Loop...
int k = 0;
while(1)
{
// CALLBACK EVENT
WaitForSingleObject(hevent, INFINITE);

if(buff[k].dwFlags & WHDR_DONE)
{
save_buffer(&buff[k]);
waveInAddBuffer(hwi, &buff[k], sizeof(WAVEHDR));
}

if(k == num_buffers -1)
k = 0;
else
k++;

}
for (int u = 0; u<num_buffers; u++)
{
waveInUnprepareHeader(hwi, &buff[u], sizeof(WAVEHDR));
}
waveInClose(hwi);
//

I guess this time I got it right! I get the buff[0] then I push it again to
the waveInAddBuffer() and so forth...what do you think about it?

thanks

From: Tim Roberts on
"Larry" <dontmewithme(a)got.it> wrote:
>
>I guess this time I got it right! I get the buff[0] then I push it again to
>the waveInAddBuffer() and so forth...what do you think about it?

This looks pretty much right to me. Does it work?
--
Tim Roberts, timr(a)probo.com
Providenza & Boekelheide, Inc.
From: Larry on

"Tim Roberts" <timr(a)probo.com> ha scritto nel messaggio
news:i39oj5tfsfvcmo5ql1geusho7oq5p9dm8r(a)4ax.com...

> This looks pretty much right to me. Does it work?

Yes it is!!!!