News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

How do I get access to my soundcard's output?

Started by NoCforMe, June 03, 2025, 11:13:30 AM

Previous topic - Next topic

NoCforMe

I figured out how to do Wave Audio recording. Nailed it.
I'm planning on writing a tutorial on it; the one that Timo posted here is pretty good, but it has nothing about buffer management, which is important for any kind of practical recording app.

Here are some details:

The crucial functions here are waveInPrepareHeader(), waveInAddBuffer() and waveInUnprepareHeader(). So just what all do those do?

Well, to make things clearer I'm going to temporarily rename those two "prepare" functions:
  • waveInPrepareHeader()--> LockDownBufferSoIcanRecordIntoIt()
  • waveInUnrepareHeader()--> UnLockBufferSoIcanAccessIt()

because that's what these unfortunately-named functions actually do.

The overall idea is this: to do any kind of serious audio processing, you need at least two buffers for audio data. (I made my testbed work with just two.) While one buffer is being recorded into by the Wave device driver, you can access the other buffer, process it, copy it into another buffer to save to a file, etc.

All this is controlled by the 3 functions listed above.

With just 2 buffers, the sequence is this:
  • "Prepare" both buffers and add them both to the device driver;
    waveInPrepareHeader() locks the buffer memory down so the driver can stream data into it;
    waveInAddBuffer() adds the buffer to the list of active buffers.
  • Start the recording with waveInStart(); this kicks off the recording process, with the driver streaming data into the first buffer.
  • Twiddle your thumbs (i.e., loop) while looking at the dwFlags element of the active buffer's WAVEHDR structure. When the WHDR_DONE bit is set, that means the device driver has finished filling that buffer and is now starting to fill the next buffer.
  • Now's your chance to access that buffer data. Before you do so you must call waveInUnprepareHeader(), which unlocks the buffer memory so you can access it. (In my testbed I just copied the buffer into another larger buffer to later be written to disk.)
  • When you're finished accessing the buffer data, you must now add this buffer to the end of the chain, by first calling waveInPrepareHeader(), then waveInAddBuffer(). (Can you see now how a circular buffer structure works?)
  • Now you do the same thing--twiddle your thumbs waiting for the current buffer to be done--on the second buffer. And so on ...

To keep track of things I used two WAVEHDR structures, one for each buffer, and two variables, CurrRecHdr and NextRecHdr; Curr always points to the one currently being filled by the driver, and Next is the one warming up in the bullpen. When the current buffer is done and I'm done with its data, I just swap Curr & Next and continue on my merry way.

Make sense? Yes, it's fairly "low level", which I suppose is why the whole API is now deprecated. But it's not hard to program at all.

Of course, you need to make sure you're done processing the one buffer before the next one fills up, or else some of your recorded data will be lost.

BTW, although I showed how to do this using polling (twiddling your thumbs while waiting for a flag to be set), you can also use callbacks so you don't have to keep checking that flag. The callback can either be to a regular window procedure, or to a special proc only used by this API. However, the latter is pretty useless, because that proc can only call a very limited set of functions, otherwise the whole thing will deadlock. (Apparently it does work with certain Windows versions.) So best to just avoid that method, unless all you're doing is setting some flags or other global variables.

And it's best to put all this into a separate thread for better performance.
32-bit code and Windows 7 foreva!

NoCforMe

I wrote up a tutorial on how to do recording with Windows Waveform Audio, attached here.
Wish I had a website to publish this on, but this'll have to do. I think it pretty much covers the subject. Could even be used by non-assembly-language programmers.

(This was inspired by the tutorial that Timo posted a link to earlier in this thread.)
32-bit code and Windows 7 foreva!

FORTRANS

Hi,

   I read through your tutorial, briefly.  Seems well written
and explains things reasonably.

Regards,

Steve N.

sinsi