Compaq Multimedia Services
for OpenVMS Alpha
Programmer's Guide


Previous Contents Index

3.3.3 Specifying Waveform Audio Data Output Format

The waveform audio data output format is specified during a call to the waveOutOpen function, which opens a device driver for playback or queries the driver for the data formats it supports. Use the lpFormat argument of the function to specify the format of the waveform audio output data. This argument takes a pointer to a WAVEFORMAT data structure that identifies the waveform audio data output format.

See Section 3.3.6, Section 3.6.2, and the description of the waveOutOpen function in Section 3.8 for more information about specifying the waveform audio data output format.

3.3.4 Using Callback Functions to Manage Waveform Audio Playback

Multimedia Services for OpenVMS supports the use of callback functions to manage playback of audio data. See the description of the waveOutOpen function in Section 3.8 for more information about using callback functions to manage waveform audio playback.

3.3.5 Modifying Waveform Audio Playback Volume

Use the waveOutGetVolume and waveOutSetVolume functions to retrieve and set the current volume level for a specified waveform audio device. Not all waveform audio devices support volume changes. Some devices support individual volume control on both the left and right channels. See Section 3.3.1 for information about determining the volume-control capabilities of waveform audio devices.

Note

Unless an application is designed to be a master volume-control application providing the user with volume control for all audio devices in a system, open an audio device before changing its volume. Also, query the volume level before changing it, and restore the volume level to its previous level as soon as possible.

The volume is specified in a DWORD data type; the upper 16 bits specify the relative volume of the right channel, and the lower 16 bits specify the relative volume of the left channel, as shown in Figure 3-2.

Figure 3-2 DWORD Packing for Waveform Volume Levels


For devices that do not support left- and right-channel volume control, the lower 16 bits specify the volume level and the upper 16 bits are ignored. Volume-level values range from 0x0 (full muting or silence) to 0xFFFF (full volume) and are interpreted logarithmically. The perceived volume increase is the same when increasing the volume level from 0x5000 to 0x6000 as it is from 0x4000 to 0x5000. Most devices do not support the full 16 bits of volume control and do not use the low-order bits of the requested volume setting.

For example, for a device that supports 4 bits of volume control, requested volume level values of 0x4000, 0x4fff, and 0x43be produce the same physical volume setting, 0x4000. The waveOutGetVolume function returns the full 16-bit setting that is set with the waveOutSetVolume function.

When querying with the waveOutGetVolume function, the volume is returned in a DWORD location specified by a pointer argument.

See the descriptions of the waveOutGetVolume and waveOutSetVolume functions in Section 3.8 for more information about modifying waveform audio playback volume.

3.3.6 Writing Waveform Audio Data to a Waveform Audio Output Device

After successfully opening a waveform audio output device, an application can write data to the device. Use the waveOutWrite function to write a data block to a waveform audio output device. Use the WAVEHDR data structure to specify the waveform data block you are sending using the waveOutWrite function. This data structure contains a pointer to a data block, the length of the data block, and assorted flags. See Section 3.6.4 for more information about the WAVEHDR data structure.

After an application sends a data block to an audio output device using the waveOutWrite function, it must wait until the device is finished with the data block before freeing it. When an application is sending multiple data blocks, it must monitor the completion of data blocks to know when to send additional blocks and when it can reuse old blocks.

Example 3-4 shows the steps required to allocate and set up a WAVEHDR data structure and to write a block of data to a waveform audio output device.

Example 3-4 Writing Waveform Audio Data

#include <mme/mme_api.h> 
 
/* Global variables --- Must be visible to callback function so it */ 
/* can unlock and free the data block after it has been played. */ 
 
HPSTR       lpData      = NULL;  /* ptr to waveform data memory */ 
 
void ReversePlay(HMMIO hmmio) 
{ 
    HWAVEOUT      hWaveOut; 
    LPWAVEHDR     lpWaveHdr; 
    MMCKINFO      mmckinfoParent; 
    MMCKINFO      mmckinfoSubchunk; 
 
    MMRESULT      wResult; 
    LPWAVEFORMAT  lpFormat; 
    DWORD         dwDataSize; 
                  . 
                  . 
                  . 
    /* Allocate memory for pFormat structure.  Pointers passed */ 
    /* to wave routines  must be allocated using mmeAllocMem */ 
    lpFormat = (LPWAVEFORMAT)mmeAllocMem(sizeof(WAVEFORMAT)); 
    if (lpFormat == (LPWAVEFORMAT)NULL ) return; 
 
    /* Open a waveform device for output using function callback. */ 
    if (waveOutOpen((LPHWAVEOUT)&hWaveOut, WAVE_MAPPER, 
                    lpFormat, 
                    (LONG)hwndApp, 0L, CALLBACK_FUNCTION)) 
    { 
        fprintf(stderr, "Failed to open waveform output device."); 
        mmeFreeMem(lpFormat); 
        return; 
    }                     
 
    /* Allocate memory for the waveform data. The memory for */ 
    /* waveform data must be globally allocated using mmeAllocBuffer */ 
    lpdata = mmeAllocBuffer(dwDataSize); 
    if (!lpData) 
    { 
       fprintf(stderr, "Failed to allocate memory for format chunk."); 
       mmeFreeMem(lpFormat); 
       return; 
    }                          
    /* Read the waveform data subchunk. */ 
    if(mmioRead(hmmio, (HPSTR) lpData, dwDataSize) != dwDataSize) 
    { 
       fprintf(stderr, "Failed to read data chunk."); 
       mmeFreeMem(lpFormat); 
       mmeFreeBuffer(lpData); 
       return; 
    }                          
    /* Allocate memory for the header. This memory must also be */ 
    /* globally allocated with mmeAlloc* routines. */ 
    lpWaveHdr = (LPWAVEHDR)mmeAllocMem(sizeof(WAVEHDR)); 
    if (!lpWaveHdr) 
    { 
       mmeFreeMem(lpFormat); 
       mmeFreeBuffer(lpData); 
       fprintf(stderr, "Failed to allocate memory for header."); 
       return; 
    } 
 
    /* After allocation, the header must be set up and prepared */ 
    /* for use. */ 
    lpWaveHdr->lpData = lpData; 
    lpWaveHdr->dwBufferLength = dwDataSize; 
    lpWaveHdr->dwFlags = 0L; 
    lpWaveHdr->dwLoops = 0L; 
 
    /* Then the data block can be sent to the output device. The */ 
    /* waveOutWrite function returns immediately and waveform data */ 
    /* is sent to the output device in the background. */ 
    wResult = waveOutWrite(hWaveOut, lpWaveHdr, sizeof(WAVEHDR)); 
 
    if (wResult != MMSYSERR_NOERROR) 
    { 
       mmeFreeMem(lpFormat); 
       mmeFreeBuffer(lpData); 
       fprintf(stderr, "Failed to write block to device"); 
       return; 
    } 
    . 
    . 
    . 
} 

3.3.7 Getting the Current Playback Position

While a waveform is playing, you can monitor the current playback position within the waveform. Use the waveOutGetPosition function to retrieve the current playback position of a waveform audio output device.

The waveOutGetPosition function takes three arguments: a handle to a waveform output device, a pointer to an MMTIME data structure, and a UINT data type specifying the size of the MMTIME data structure.

For waveform audio devices, the preferred time format to represent the current position is in samples. Specify the current position of a waveform audio device as the number of samples for one channel from the beginning of the waveform.

To query the current position of a waveform audio device, set the wType field of the MMTIME data structure to the constant TIME_SAMPLES and pass this data structure to the waveOutGetPosition function.

See Section 2.3 and the description of the waveOutGetPosition function in Section 3.8 for more information about determining the current playback position.

3.3.8 Stopping, Pausing, and Restarting Audio Playback

While a waveform is playing, an application can stop or pause playback. Once playback has been paused, it can be restarted. Use the waveOutPause function to pause playback on a waveform audio output device. Use the waveOutRestart function to resume playback on a waveform audio output device that was paused using the waveOutPause function.

Use the waveOutReset function to cancel playback on a waveform audio output device and mark all pending data blocks as done. This terminates playback.

These functions take a single argument: the waveform audio output device handle returned by the waveOutOpen function. Pausing a waveform audio device may not be instantaneous; the device driver finishes playing the current data block before pausing playback.

As soon as the first waveform audio data block is sent using the waveOutWrite function, the waveform audio output device begins playing the audio data. To delay the start of playback, call the waveOutPause function before calling the waveOutWrite function. Then, to begin playback, call the waveOutRestart function.

To stop a waveform from playing, use the waveOutReset function. This function differs from the waveOutPause function because it marks all pending data blocks as done. To resume playback on a device that was stopped using the waveOutReset function, use the waveOutWrite function to send the first audio data block to the device.

Note

Do not use the waveOutRestart function to restart playback on a device that was stopped using the waveOutReset function.

See the descriptions of the waveOutPause , waveOutReset , and waveOutRestart functions in Section 3.8 for more information about stopping, pausing, and restarting waveform audio playback.

3.3.9 Closing a Waveform Audio Output Device

After waveform audio playback is complete, call the waveOutClose function to close a waveform audio output device. If the waveOutClose function is called while a waveform is playing, the close operation fails, and the function returns an error code indicating that the device is not closed.

To close a waveform audio output device before playback is completed, call the waveOutReset function. The waveOutReset function terminates audio playback by marking all buffers as done and returning them to the calling application. Then, call the waveOutClose function to close the device.

See the descriptions of the waveOutClose and waveOutReset functions in Section 3.8 for more information about closing a waveform audio output device.

3.4 Recording Waveform Audio Data

This section contains information about the waveform audio input functions that do the following:

An application uses waveform audio input functions to record audio data.

3.4.1 Querying a Waveform Audio Input Device

Before recording a waveform, call the waveInFormatDetails , waveInGetDevCaps , waveInGetDevCapsEx , or waveInGetFormatInfo function to determine the waveform audio input capabilities of the system.

The waveInGetDevCaps and waveInGetDevCapsEx functions take a pointer to a WAVEINCAPS data structure, then fill the data structure with information about the capabilities of the specified device. The information returned in the WAVEINCAPS data structure includes the manufacturer and product IDs, the product name for the device, and the version number of the device driver. In addition, the WAVEINCAPS data structure provides information about the standard waveform formats that the device supports.

The waveInGetFormatInfo function takes a pointer to a WAVEFORMATINFO data structure and returns high-level information common to all formats supported by the device.

The waveInFormatDetails function takes a pointer to a ACMFORMATDETAILS function.

See Section 3.6.5 and the function descriptions in Section 3.8 for more information about querying a waveform audio input device.

3.4.2 Opening a Waveform Audio Input Device

Use the waveInOpen function to open a waveform audio input device for recording. The waveInOpen function opens the device associated with the specified device ID and returns a handle to the open device by writing the handle to a specified memory location. See the description of the waveInOpen function in Section 3.8 for more information about opening a waveform audio input device.

3.4.3 Selecting a Waveform Audio Input Device

Some multimedia computers have multiple waveform audio input devices. If the specific waveform audio device to open is not known, use the WAVE_MAPPER flag as the device ID when opening an audio device for recording. This flag causes the waveInOpen function to select the audio device in the system that is best capable of recording audio data in the specified format.

3.4.4 Specifying Waveform Audio Input Data Format

For PCM format audio data, use the PCMWAVEFORMAT data structure to specify the data format. The PCMWAVEFORMAT data structure includes a WAVEFORMAT data structure with an additional field containing information specific to the PCM waveform data format.

For MULAW format audio data, use the WAVEFORMAT data structure to specify the data format.

Example 3-5 shows how to set up a PCMWAVEFORMAT data structure for 11.025 kHz 8-bit mono and for 44.1 kHz 16-bit stereo. After setting up the data structure, the example shows how to verify that the PCM waveform audio output device supports the format using the IsFormatSupported function.

Example 3-5 Specifying Data Format for PCM Waveform Audio Data

*/ 
 
#include <stdio.h> 
#include <mme/mme_api.h> 
 
MMRESULT IsFormatSupported(LPPCMWAVEFORMAT lpPCMWaveFormat, 
      UINT uDeviceID); 
main() 
{ 
 
    UINT                wReturn; 
    LPPCMWAVEFORMAT lppcmWaveFormat; 
 
    /* Allocate memory for wave format structure */ 
    lppcmWaveFormat = 
        (LPPCMWAVEFORMAT)mmeAllocMem(sizeof(PCMWAVEFORMAT)); 
    if ( lppcmWaveFormat == (LPPCMWAVEFORMAT)NULL )  { 
        fprintf(stderr,"Cannot allocate memory\n"); 
        exit(1); 
    } 
 
    /* Set up PCMWAVEFORMAT for 11 kHz 8-bit mono */ 
    lppcmWaveFormat->wf.wFormatTag = WAVE_FORMAT_PCM; 
    lppcmWaveFormat->wf.nChannels = 1; 
    lppcmWaveFormat->wf.nSamplesPerSec = 11025L; 
    lppcmWaveFormat->wf.nAvgBytesPerSec = 11025L; 
    lppcmWaveFormat->wf.nBlockAlign = 1; 
    lppcmWaveFormat->wBitsPerSample = 8; 
 
    /* See if format is supported by any device in system */ 
    wReturn = IsFormatSupported(lppcmWaveFormat, WAVE_MAPPER); 
 
    /* Report results */ 
    if (wReturn == MMSYSERR_NOERROR) 
        fprintf(stderr, "11 kHz 8-bit mono is supported.\n"); 
    else if (wReturn == WAVERR_BADFORMAT) 
        fprintf(stderr, "11 kHz 8-bit mono is NOT supported.\n"); 
    else 
        fprintf(stderr, "Error opening waveform device.\n"); 
 
    /* Set up PCMWAVEFORMAT for 44.1 kHz 16-bit stereo */ 
    lppcmWaveFormat->wf.wFormatTag = WAVE_FORMAT_PCM; 
    lppcmWaveFormat->wf.nChannels = 2; 
    lppcmWaveFormat->wf.nSamplesPerSec = 44100L; 
    lppcmWaveFormat->wf.nAvgBytesPerSec = 176400L; 
    lppcmWaveFormat->wf.nBlockAlign = 4; 
    lppcmWaveFormat->wBitsPerSample = 16; 
 
    /* See if format is supported by any device in system */ 
    wReturn = IsFormatSupported(lppcmWaveFormat, WAVE_MAPPER); 
 
    /* Report results */ 
    if (wReturn == MMSYSERR_NOERROR) 
        fprintf(stderr, "44.1 kHz 16-bit stereo is supported.\n"); 
    else if (wReturn == WAVERR_BADFORMAT) 
        fprintf(stderr, "44.1 kHz 16-bit stereo is NOT supported.\n"); 
    else 
        fprintf(stderr, "Error opening waveform device.\n"); 
 
    /* Free memory */ 
    mmeFreeMem(lppcmWaveFormat); 
    
} 

3.4.5 PCM Waveform Audio Data Formats

The lpData field in the WAVEHDR data structure points to the waveform data samples. For 8-bit PCM data, each sample is represented by a single unsigned data byte. For 16-bit PCM data, each sample is represented by a 16-bit signed value.

Table 3-1 summarizes the maximum, minimum, and midpoint values for PCM waveform data.

Table 3-1 PCM Waveform Audio Data Value Summary
  Data Values
Format Maximum Minimum Midpoint
8-bit 255 (0xFF) 0 128 (0x80)
16-bit 32767 (0x7FFF) -32768 (0x8000) 0

The order of the data bytes varies between 8 bit and 16 bit, and mono and stereo formats. Figure 3-3, Figure 3-4, Figure 3-5, and Figure 3-6 show data packing for the first four words of different PCM waveform data formats.

Figure 3-3 Data Packing for 8-Bit Mono PCM


Figure 3-4 Data Packing for 8-Bit Stereo PCM


Figure 3-5 Data Packing for 16-Bit Mono PCM


Figure 3-6 Data Packing for 16-Bit Stereo PCM


3.4.6 Using Callback Functions to Manage Waveform Audio Recording

Multimedia Services for OpenVMS supports the use of callback functions to manage the recording of audio data. See the description of the waveInOpen function in Section 3.8 for more information about using callback functions to manage waveform audio recording.

3.4.7 Modifying Waveform Audio Record Volume

Use the waveInGetVolume and waveInSetVolume functions to retrieve and set the current input volume of an audio device opened for recording.

Note

Data can be clipped from your application if the volume is set too high.

See Section 3.3.5 and the descriptions of the waveInGetVolume and waveInSetVolume functions in Section 3.8 for more information about modifying waveform audio record volume.

3.4.8 Reading Data from a Waveform Audio Input Device

Once you open a waveform audio input device, you can begin recording waveform audio data. Waveform audio data is recorded into buffers supplied by an application and specified by a WAVEHDR data structure. This is the same data structure used for waveform audio playback described in Section 3.3.6. Memory for the WAVEHDR data structure and its accompanying data buffer must be allocated and prepared as described in Section 3.2.5.

Use the waveInStart function to start waveform audio recording. Before starting the recording operation, send at least one buffer to the driver or incoming data might be lost.

Use the waveInAddBuffer function to send a buffer to the device so it can be filled with recorded waveform audio data. As the buffers are filled with the waveform audio data, the application is notified with a callback message, which is specified when the device is opened.

See the descriptions of the waveInAddBuffer and waveInStart functions in Section 3.8 for more information about reading data from a waveform audio input device.


Previous Next Contents Index