1.5. Microsoft Windows Waveform Audio

The exhaustive information about WaveForm Audio can be found in [8]. Windows API mechanisms used here are described in [11].

WaveForm Audio is a standard member of Windows and Windows NT/2000. Even though all the routines are the components of a separate library (winmm.dll), these function set may be treated as the "sound system call set". As a basic set of functions, the module requires filling large structures. Consequently, the simplest program using this mechanisms would have more than fifty lines, but it gives programmer almost full control over sound devices. The control, that is portable among all the sound devices having drivers for the OS. WaveForm Audio was chosen by the author to be the engine of multimedia terminal's Audio Engine.

1.5.1. WaveForm Audio Overview

WaveForm Audio is the set of functions as well as data structures. To manage sound devices over WaveForm Audio one can use a kind of virtual device called waveform-audio device (further called just a "device"). There are two types of such devices: input device used while recording, and output device used while playing sounds. These devices are treated independently. Every device is represented by a special handle: of the type HWAVEOUT for the output device, and of the type HWAVEIN for the input device. The variable of these types are used to identity the sound devices. The full list of Waveform functions and the example how they are used is in Appendix B.

WaveForm Audio contains mechanisms that should be used as the body of initial procedures. They allow to check if sound devices are present in the system, and to find out how many of them may be used. Programmer can get their capabilities and choose one of them. If none of them can be used, further procedures could not be performed.

Before usage, waveform-audio device must be opened. waveInOpen and waveOutOpen functions are needed to open input and output device. Parameters such as sampling rate, number of channels, bits per sample, the type of encoding, etc. are specified when calling these functions. The other parameter passed to the functions is the type of signallization between OS the sound functions. It can be:

Event mechanism
Callback mechanism
Thread Messages mechanism
Windows Messages mechanism
No signallization

If something goes wrong calling the functions (no free memory, bad parameters, not supported capabilities, ..) functions fail. Otherwise, the proper handle is returned and device can be controlled over this handle. The type of the returned handle is HWAVEIN for waveInOpen and HWAVEOUT for waveOutOpen.

1.5.2. Capturing

Capturing is organized as follows:

When in the capturing loop all headers are already prepared. So just waveInAddBuffer must be called to add the current buffer to the system buffer set.

The fragment of the capturing (recording) procedures is illustrated in Figure 1-2. In this version Event mechanism is used.


int i=0, No_SYSTEM_BUFFFERS;

if (waveInOpen(&hwi, 
	 0, (LPWAVEFORMATEX)&pwf,
        (DWORD) rip->eventh, 0, CALLBACK_EVENT )) {
	/* ... error handling  ... */
} 

/* ... Preparing system buffers (sb) ... */

for(i=0; i<No_SYSTEM_BUFFERS; i++){

    sb[i]->lpData = (LPBYTE) malloc(system_buf_len);
    sb[i]->dwBufferLength = system_buf_len;
    sb[i]->dwBytesRecorded = 0;
    sb[i]->dwUser = 0;
    sb[i]->dwFlags = 0;
    sb[i]->dwLoops = 0;

	if(!sb[i]->lpData)
		/* ... error handling  ... */

        if (waveInPrepareHeader(hwi, sb[i], 
		sizeof(WAVEHDR))) {
	/* ... error handling  ... */
        } 
        if (waveInAddBuffer(hwi, sb[i], 
		sizeof(WAVEHDR))) {
	/* ... error handling  ... */
	}
}

waveInStart(hwi);
ResetEvent(eventh);

while(1)
{
	WaitForSingleObject(eventh, INFINITE);
		/* ... sb[i] processing ... */
       	if (ret = waveInAddBuffer(hwi, sb[i],
		sizeof(WAVEHDR))) {
		/* ... error handling ... */
	}

	if(i == No_SYSTEM_BUFFFERS - 1)
	    i=0;
	else
	    i++;
	if(stop_thread_flag)
	    break;
}

Figure 1-2. The C-code of the capturing loop.

1.5.3. Playing

Playing can be organized in simpler way:

The fragment of the playing loop is illustrated in Figure 1-3. In this version Event mechanism is used.

int i=0, No_SYSTEM_BUFFFERS, BUFFER_LEN;

if (waveOutOpen(&hwo, 
	 0 /*default*/, (LPWAVEFORMATEX)&pwf,
        (DWORD) eventh, 0, CALLBACK_EVENT )) {
	/* ... error handling */
} 

/* .... allocation of sb buffers .... */

for(i=0; i<NoSYSTEM_BUFFERS; i++){ /*  header preparation  */

   sb[i]->lpData = (LPBYTE) malloc(BUFFER_LEN);
   sb[i]->dwBufferLength = system_buf_len;
   sb[i]->dwBytesRecorded = 0;
   sb[i]->dwUser = 0;
   sb[i]->dwFlags = 0;
   sb[i]->dwLoops = 1;

  	if(!sb[i]->lpData)
	/* ... error handling  ... */

   if (waveOutPrepareHeader(rip->hwo, 
	sb[i], sizeof(WAVEHDR))) {
	/* ... error handling */
   }
}

while(1)
{
/* ... process previous sound block ... */
/* ... prepare lacking frames if needed */

if (waveOutWrite(hwo, sb[i], sizeof(WAVEHDR))) {
	/* ... error handling ... */
}

if(i == No_SYSTEM_BUFFFERS-1)
    i=0;
else
    i++;

if(stop_thread_flag)
	break;

WaitForSingleObject(risp->eventh, INFINITE);
}		

Figure 1-3. The C-code of the playing loop

1.5.4. Shutting Down

When we want to stop playing or recording we must: