Windows NT Systems Programming

[ Home | Syllabus |Course Notes]


Intro to MultiMedia


What is Multimedia?


Analog/Digitial Conversion Drivers


Looking at Audio


Low Level Audio APIs

 


Wave Header

typedef struct { 
    LPSTR  lpData; 
    DWORD  dwBufferLength; 
    DWORD  dwBytesRecorded; 
    DWORD  dwUser; 
    DWORD  dwFlags; 
    DWORD  dwLoops; 
    struct wavehdr_tag * lpNext; 
    DWORD  reserved; 
} WAVEHDR; 
 

Flags supplying information about the buffer. The following values are defined:

WHDR_BEGINLOOP

This buffer is the first buffer in a loop. This flag is used only with output buffers.

WHDR_DONE

Set by the device driver to indicate that it is finished with the buffer and is returning it to the application.

WHDR_ENDLOOP

This buffer is the last buffer in a loop. This flag is used only with output buffers.

WHDR_INQUEUE

Set by Windows to indicate that the buffer is queued for playback.

WHDR_PREPARED

Set by Windows to indicate that the buffer has been prepared with the waveInPrepareHeader or waveOutPrepareHeader function.


WAVEFORMATEX

typedef struct { 
    WORD  wFormatTag; 
    WORD  nChannels; 
    DWORD nSamplesPerSec; 
    DWORD nAvgBytesPerSec; 
    WORD  nBlockAlign; 
    WORD  wBitsPerSample; 
    WORD  cbSize; 
} WAVEFORMATEX; 

Examples:

Telephone quality, mono, 8 bit PCM

WAVEFORMATEX PCMWaveFmtRecord;
	
	PCMWaveFmtRecord.wFormatTag = WAVE_FORMAT_PCM;
	PCMWaveFmtRecord.nChannels = 1;
	PCMWaveFmtRecord.nSamplesPerSec = 8000;
	PCMWaveFmtRecord.wBitsPerSample = 8;
	PCMWaveFmtRecord.nAvgBytesPerSec = PCMWaveFmtRecord.nSamplesPerSec
		* PCMWaveFmtRecord.wBitsPerSample / 8;
	PCMWaveFmtRecord.nBlockAlign = PCMWaveFmtRecord.nChannels *
		PCMWaveFmtRecord.wBitsPerSample / 8;

Audio API functions

First Examine a simple playback program.

bool playBack(char* buffer,int numrcv)
{
	//Handle for the WAVE device.
	HWAVEOUT hWaveOut;
	WAVEFORMATEX PCMWaveFmtRecord;
	int errorCode;
	
	PCMWaveFmtRecord.wFormatTag = WAVE_FORMAT_PCM;
	PCMWaveFmtRecord.nChannels = 1;
	PCMWaveFmtRecord.nSamplesPerSec = 8000;
	PCMWaveFmtRecord.nAvgBytesPerSec = 8000;
	PCMWaveFmtRecord.nBlockAlign = 1;
	PCMWaveFmtRecord.wBitsPerSample = 8;
	errorCode = waveOutOpen(NULL, WAVE_MAPPER,
							 &PCMWaveFmtRecord, 
							 0L, 0L, WAVE_FORMAT_QUERY);
	if (errorCode)
	{
		//MessageBox(" Device Cannot handle this format");
		return false;
	}
	
	waveOutOpen(&hWaveOut, WAVE_MAPPER,
		&PCMWaveFmtRecord,
		0L, 0L, 0L);
	
	//Prepare the header.
	WaveHeader.lpData = (LPSTR) buffer;
	WaveHeader.dwBufferLength = numrcv;
	WaveHeader.dwFlags = WaveHeader.reserved = 0;
	WaveHeader.dwLoops = 0;
	WaveHeader.lpNext = NULL;
	
	waveOutPrepareHeader(hWaveOut, &WaveHeader, sizeof(WaveHeader));
	
	//Write data to WAVE device.
	waveOutWrite(hWaveOut, &WaveHeader, sizeof(WaveHeader));
	
	//Loop until playback is finished.
	do {}
	while (!(WaveHeader.dwFlags & WHDR_DONE)); // inefficient busy wait!
	
	//Unprepare the wave output header.
	waveOutUnprepareHeader(hWaveOut, &WaveHeader, sizeof(WaveHeader));
	
	//Close the WAVE device.
	waveOutClose(hWaveOut);
	
	return true;	
}

rainbow.gif (2243 bytes)


Call Backs


Setup Function

HANDLE recordDone;		// event of audio input completion 
HWAVEIN hWaveIn;		// onput WAVE audio device handle 
char inbuf[BUFSIZE];	// WAVE input data buffer area 
HANDLE audioFileHandle;		// handle for audio file

WAVEHDR WaveHeader;	
// . . . 
void CMessage::RecordMessage()
// Records Message to file
// for testing name is hardcoded in.
{
	
	DWORD threadid;
	HANDLE RecordHandle;
	
	audioFileHandle = CreateFile("TestRecord", GENERIC_WRITE,
		0,0, CREATE_ALWAYS, 0, 0);
	
	recordDone = CreateEvent(0, FALSE, FALSE, 0);
	ResetEvent(recordDone);
	RecordHandle = CreateThread(NULL, 0,
		(LPTHREAD_START_ROUTINE) Recorder, NULL, 0,
		&threadid);
	openWaveDev();
	msgApp.m_pMainWnd->SetWindowText("Start Recording"); hptrd_left.gif (955 bytes)
	WaitForSingleObject(RecordHandle, INFINITE);
	waveInClose(hWaveIn);
	msgApp.m_pMainWnd->SetWindowText("Done Recording"); hptrd_left.gif (955 bytes)
	CloseHandle(audioFileHandle);
    return;
}

 

rainbow.gif (2243 bytes)


openWaveDev

void openWaveDev()
{
	MMRESULT Rc;
	WAVEFORMATEX PCMWaveFmtRecord;
	
	PCMWaveFmtRecord.wFormatTag = WAVE_FORMAT_PCM;
	PCMWaveFmtRecord.nChannels = 1;
	PCMWaveFmtRecord.nSamplesPerSec = 8000;
	PCMWaveFmtRecord.wBitsPerSample = 8;
	PCMWaveFmtRecord.nAvgBytesPerSec = PCMWaveFmtRecord.nSamplesPerSec
		* PCMWaveFmtRecord.wBitsPerSample / 8;
	PCMWaveFmtRecord.nBlockAlign = PCMWaveFmtRecord.nChannels *
		PCMWaveFmtRecord.wBitsPerSample / 8;
	
	Rc = waveInOpen(&hWaveIn, WAVE_MAPPER, &PCMWaveFmtRecord,
		(DWORD) recordCallBack, 0L,
		CALLBACK_FUNCTION);
	if (Rc)
	{ // must not be an audio recording device
		return;
	}
	WaveHeader.dwBufferLength = BUFSIZE;
	WaveHeader.lpData = (LPSTR) (inbuf);
	WaveHeader.dwFlags = WaveHeader.reserved = 0;
	WaveHeader.dwLoops = 0;
	WaveHeader.lpNext = 0;
	Rc = waveInPrepareHeader(hWaveIn, &WaveHeader,
		sizeof(WAVEHDR));
	
	Rc = waveInAddBuffer(hWaveIn, &WaveHeader,
			     sizeof(WAVEHDR));
		
	ResetEvent(recordDone);
	
	if (Rc = waveInStart(hWaveIn))
	{
		waveInClose(hWaveIn);
	}
}

 rainbow.gif (2243 bytes)


CallBack Function

void CALLBACK recordCallBack(HWAVEIN hWaveIn, UINT uMsg,
						 DWORD p1, DWORD p2, DWORD p3)
{
	if (uMsg != WIM_DATA)
		return;
	SetEvent(recordDone);
}

 rainbow.gif (2243 bytes)


Thread Functions

UINT Recorder(void *p)
{
	int i; // number of BUFSIZ buffers to record before reaching MAXBUF
	BOOL success;
	DWORD numWrite;
	
	for(i = 0; i < MAXBUF/BUFSIZE; i++) // just record a little bit
	{
		WaitForSingleObject(recordDone, INFINITE); // wait till device has called back
		if (!(WaveHeader.dwFlags & WHDR_DONE))  // just make sure really done
		{
			continue;
		}
		
		if(success = WriteFile(audioFileHandle, WaveHeader.lpData,
			WaveHeader.dwBytesRecorded, &numWrite, 0))
		{
		}
		if (waveInUnprepareHeader(hWaveIn, &WaveHeader,
			sizeof(WAVEHDR)))
		{
		}
		WaveHeader.dwFlags = 0;
		
		if (waveInPrepareHeader(hWaveIn, &WaveHeader,
			sizeof(WAVEHDR)))
		{
		}
		if (waveInAddBuffer(hWaveIn, &WaveHeader,
			sizeof(WAVEHDR)))
		{
		}
		
	}
	waveInReset(hWaveIn); 
	waveInClose(hWaveIn);
	return 0;
}

 rainbow.gif (2243 bytes)


AudioDemo Program

// main.h

#include <afxwin.h>
#include "Message.h"


// Define an application object
class CMsgApp : public CWinApp
{
public:
	virtual BOOL InitInstance(); // everybody overrides this one
	CMessage msg;
};

Main.cpp

#include "main.h"
#include "CMsgDlg.h"
#include "resource.h"
// Create an instance of the application

CMsgApp msgApp;  

// Init the application and the main window
BOOL CMsgApp::InitInstance()
{
	CMsgDlg dlg;
	m_pMainWnd = &dlg;
	dlg.DoModal();
	
	// Since the dialog has been closed, return FALSE so that we exit the
	//  application, rather than start the application's message pump.
	return FALSE;

}

(source code here)


Copyright chris wild 1997.
For problems or questions regarding this web contact [Dr. Wild].
Last updated: November 03, 1997.