home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
tolkit45.zip
/
os2tk45
/
samples
/
mm
/
doubplay
/
doubplay.c
next >
Wrap
Text File
|
1999-05-11
|
39KB
|
1,081 lines
/*******************************************************************************
* File Name : DOUPLAY.C
*
* Description : This file contains the C source code required for the Double
* Buffering Playlist sample program. This sample allows
* the user to play a wave file continuously by pushing the
* play button. The user can stop playing the wave file by
* pushing the stop button. Both of these push buttons are
* animated.
*
* Concepts : This program illustrates how to use a Memory
* Playlist in a double buffering manner for reading and playing
* a wave file at the same time.
* This concept can be used in a lot of real time recording
* applications such as:
* 1. Real Time recording and playing of the wave file
* 2. Censoring a Speech being transmitted.
* The sample also shows how to use MMIO API's used in opening,
* reading, seeking, and closing files.
*
* MMPM/2 API's: List of all MMPM/2 API's that are used in this module.
*
* mciSendCommand
* MCI_ACQUIREDEVICE
* MCI_OPEN
* MCI_PLAY
* MCI_SET
* mciGetErrorString
* mmioOpen
* mmioGetHeader
* mmioRead
* mmioSeek
* mmioClose
*
* Required
* Files : doubplay.c Source Code.
* doubapp.c Source Code.
* doubplay.h Include file.
* doubplay.dlg Dialog definition.
* doubplay.rc Resources.
* makefile Make file.
* doubplay.def Linker definition file.
* doubplay.ico Doubplay icon.
* mywave.wav Wave File Played.
* play0.bmp Play PushButton Bitmap 0
* play1.bmp Play PushButton Bitmap 1
* play2.bmp Play PushButton Bitmap 2
* play3.bmp Play PushButton Bitmap 3
* play4.bmp Play PushButton Bitmap 4
* stop.bmp Stop PushButton Bitmap
*
* Copyright (C) IBM 1993
******************************************************************************/
#define INCL_DOS /* required to use Dos APIs. */
#define INCL_WIN /* required to use Win APIs. */
#define INCL_PM /* required to use PM APIs. */
#define INCL_OS2MM /* required for MCI and MMIO headers */
#define INCL_WINSTDSLIDER /* required for using slider control */
#define INCL_SECONDARYWINDOW /* required for secondary window */
#define INCL_GRAPHICBUTTON /* required for graphic button control */
#include <os2.h>
#include <stdio.h>
#include <os2me.h>
#include <stdlib.h>
#include <string.h>
#include <sw.h>
#include "doubplay.h" /* Dialog Ids, Resource Ids etc */
#define WAVE_FILE_NAME "mywave.wav"
/*******************************************************************/
/* Procedure / Function prototypes */
#pragma linkage( MainDialogProc, system)
MRESULT EXPENTRY MainDialogProc(HWND, ULONG, MPARAM, MPARAM);
VOID APIENTRY PlayThread ( ULONG parm1 );
VOID main(int i,char *p[]);
VOID InitializeDialog(void);
VOID Finalize(void);
ULONG InitializePlayList( VOID );
VOID OpenAudioDevice(HWND hwnd);
VOID CloseAll( VOID );
ULONG PlayTheWave( VOID );
/*******************************************************************/
/* Global Variables */
HAB hab; /* anchor block handle */
QMSG qmsg; /* Message Que */
HMQ hmq;
HWND hwndDiag; /* Application Dialog handle */
HWND hwndFrame; /* Application Frame handle */
BOOL fPassedDevice = FALSE; /* Do we own the Audio device */
TID tidPlayThread; /* Id for the PlayWave Thread */
USHORT usWaveDeviceId = 0; /* Id for the Wave Device */
CHAR achDataBuffer[MAXBUFF][MAXSIZE]; /* Data Buffer which will hold */
/* wave for Memory Playlist */
HEV hevSem[MAXBUFF];
HMMIO hmmioFileHandle; /* Handle to the Wave File */
LONG lState = STATE_IS_STOP; /* state of the application */
/* Can be STOP or PLAYING */
BOOL fEndPlay; /* Used to end the play thread */
PLAY_LIST_STRUCTURE_T aplayList[2*MAXBUFF+1]; /* Play List memory Structure */
/******************************************************************************
* Name : main
*
* Description : This function calls the Intialize procedure to prepare
* everything for the program's operation, enters the
* message loop, then call Finalize to shut everything down
* when the program is terminated.
*
* Concepts : None.
*
* MMPM/2 API's : None.
*
* Parameters : argc - Number of parameters passed into the program.
* argv - Command line parameters.
*
* Return : None.
*
*************************************************************************/
void main(int argc, char *argv[])
{
InitializeDialog();
/* Handle the messages: */
while(WinGetMsg(hab,&qmsg,0,0,0))
WinDispatchMsg(hab,&qmsg);
Finalize();
}
/*************************************************************************
* Name : InitializeDialog
*
* Description : This function performs the necessary initializations and
* setups that are required to show/run a dialog box as a
* main window. The message queue will be created, as will
* the dialog box.
*
* Concepts : Secondary Windows is used to create and show a dialog box.
* A system clock is displayed till the application is loaded.
*
* MMPM/2 API's : WinLoadSecondaryWindow
* WinQuerySecondaryHWND
*
* Parameters : None.
*
* Return : None.
*
*************************************************************************/
void InitializeDialog()
{
CHAR achTitle[STRING_SIZE] = "";
CHAR achDefaultSize[STRING_SIZE] = "";
/* Initialize the Dialog window */
hab = WinInitialize(0);
/* create a message queue for the window */
hmq = WinCreateMsgQueue(hab,0);
/* Load the Dialog - This will return the Handle to the Frame */
hwndFrame =
WinLoadSecondaryWindow(HWND_DESKTOP
,HWND_DESKTOP
,(PFNWP)MainDialogProc
,(HMODULE)NULL
,ID_SAMPLE
,(PVOID)NULL);
/*
* By specifying the QS_DIALOG flag we will get the handle to the Dialog of
* the frame
*/
hwndDiag = WinQuerySecondaryHWND(hwndFrame,QS_DIALOG);
/* Get the string for default size */
WinLoadString(
hab,
(HMODULE) NULL,
IDS_DEFAULT_SIZE,
(SHORT) sizeof( achDefaultSize),
achDefaultSize);
/* Add Default Size menu item to system menu of the secondary window. */
WinInsertDefaultSize(hwndFrame, achDefaultSize);
/*
* Get the window title string from the Resource string table
* and set it as the window text for the dialog window.
*/
WinLoadString(
hab,
(HMODULE) NULL,
IDS_MAIN_WINDOW_TITLE,
(SHORT) sizeof( achTitle),
achTitle);
/* Set the Title of the Dialog */
WinSetWindowText( hwndFrame, achTitle);
}
/******************************************************************************
* Name : CloseAll
*
* Description : This function is called when the current Thread finishes
* execution and is placed in DosExitList during the WM_INITDLG
* message. This function allows to terminate itself and all
* of its children processes.
*
* Concepts : None.
*
* MMPM/2 API's : None.
*
* Parameters : None
*
* Return : None.
*
*************************************************************************/
void CloseAll()
{
DosExit(EXIT_PROCESS, 0);
DosExitList(EXLST_EXIT, NULL);
}
/*************************************************************************
* Name : Finalize
*
* Description : This routine is called after the message dispatch loop
* has ended because of a WM_QUIT message. The code will
* destroy the messages queue, and window.
*
* Concepts : None.
*
* MMPM/2 API's : None.
*
* Parameters : None.
*
* Return : None.
*
*************************************************************************/
VOID Finalize( VOID )
{
WinDestroySecondaryWindow( hwndFrame );
WinDestroyMsgQueue( hmq );
WinTerminate( hab );
} /* End of Finalize */
/*******************************************************************************
* Name : MainDialogProc
*
* Description : This function controls the main dialog box. It will handle
* received messages such as pushbutton notifications, playlist
* messages, etc
*
* The following messages are handled specifically by this
* routine.
*
* WM_INITDLG
* WM_CLOSE
* WM_COMMAND
* MM_MCIPASSDEVICE
* WM_ACTIVATE
*
*
* MMPM/2 API's : mciSendCommand
* MCI_ACQUIREDEVICE
* mmioClose
* mmioRead
* mmioSeek
*
* Parameters : hwnd - Handle for the Main dialog box.
* msg - Message received by the dialog box.
* mp1 - Parameter 1 for the just recieved message.
* mp2 - Parameter 2 for the just recieved message.
*
* Return :
*
*
******************************************************************************/
MRESULT EXPENTRY MainDialogProc(
HWND hwnd,
ULONG msg,
MPARAM mp1,
MPARAM mp2)
{
static MCI_GENERIC_PARMS lpWaveGeneric; /* Used for MCI_ACQUIREDEVICE */
ULONG ulReturn; /* Ret Code for Dos and MCI calls */
switch (msg)
{
case WM_CLOSE:
if ( usWaveDeviceId > 0 )
mciSendCommand(
usWaveDeviceId, /* Device to play the chimes. */
MCI_CLOSE, /* MCI message. */
MCI_WAIT, /* Flags for the MCI message. */
(ULONG) NULL, /* Parameters for the message. */
(ULONG) NULL ); /* Parameter for notify message. */
WinPostMsg( hwnd, WM_QUIT, 0L, 0L );
return ((MRESULT) NULL);
case WM_INITDLG:
/*
* Put the Playlist Instructions into the Playlist structure.
*/
ulReturn = InitializePlayList();
if( ulReturn )
{
ShowAMessage(
IDS_ERROR_TITLE,
IDS_CANT_CREATE_SEMAPHORE,
MB_OK | MB_INFORMATION | MB_MOVEABLE | MB_HELP |
MB_APPLMODAL,
FALSE );
WinPostMsg( hwnd, WM_QUIT, 0L, 0L );
}
/* Opens the Audio device for playlist */
OpenAudioDevice(hwnd);
/*
* Since the play button is an animated button, we need to initialize it
*/
WinSendMsg (
WinWindowFromID(
hwnd, /* Dialog window handle */
ID_PLAY), /* Id - Play graphic button */
GBM_SETANIMATIONRATE, /* Animation rate control */
MPFROMLONG(100L), /* Update play bitmap every .1 sec */
NULL); /* Ignore return data */
break;
/* Service all of the button pushes */
case WM_COMMAND:
switch (SHORT1FROMMP(mp1))
{
case ID_END:
/*
* Send command to MCI to stop the playlist
*/
mciSendCommand( usWaveDeviceId, /* Device to play the chimes. */
MCI_STOP, /* MCI message. */
MCI_WAIT, /* Flags for the MCI message. */
(ULONG) NULL, /* Parameters for the message. */
(ULONG) NULL ); /* Parameter for notify message. */
fEndPlay = TRUE;
/*
* Disable the animation of the Play button
*/
WinSendMsg ( WinWindowFromID(
hwnd, /* Dialog window handle */
ID_PLAY), /* Id - Play graphic button */
GBM_ANIMATE, /* Animation control */
MPFROMSHORT(FALSE),/* Animation flag */
NULL); /* Ignore return data */
lState = STATE_IS_STOP;
break;
case ID_PLAY:
/*
* If we are not playing the playlist only then Play it
*/
if (lState == STATE_IS_STOP)
{
if (fPassedDevice)
{
/*
* If we don't have the device then display a message.
* FALSE is passed because this is not a MCI error.
*/
ShowAMessage(
IDS_ERROR_TITLE,
IDS_CANT_PROCESS_MESSAGE,
MB_OK | MB_INFORMATION | MB_MOVEABLE | MB_HELP |
MB_APPLMODAL ,
FALSE);
}
else
/*
* We have the device so no problem.
* Call the subroutine that starts the audio playlist.
*/
ulReturn = PlayTheWave();
if ( ulReturn )
{
/*
* Play failed so display an error message
*/
ShowAMessage(
IDS_ERROR_TITLE,
IDS_CANT_PROCESS_MESSAGE,
MB_OK | MB_INFORMATION | MB_MOVEABLE | MB_HELP |
MB_APPLMODAL,
FALSE );
}
else
{
/*
* Play was successful so update the flag and animate
* the play button.
*/
lState = STATE_IS_PLAYING;
WinSendMsg (
WinWindowFromID(
hwndDiag, /* Dialog window handle */
ID_PLAY), /* Id - Play graphic button */
GBM_ANIMATE, /* Animation control */
MPFROMSHORT(TRUE), /* Animation flag */
NULL); /* Ignore return data */
}
}
break;
} /* end switch */
return((MRESULT)NULL);
/*
* This message is used to set a flag that indicates wether this
* application has position of the audio device. This information
* is used to implement device sharing.
*/
case MM_MCIPASSDEVICE:
if( SHORT1FROMMP( mp2 ) == MCI_GAINING_USE )
fPassedDevice = FALSE;
else
{
fPassedDevice = TRUE;
if( lState == STATE_IS_PLAYING )
mciSendCommand( usWaveDeviceId, /* Device to play the chimes. */
MCI_PAUSE, /* MCI message. */
MCI_WAIT, /* Flags for the MCI message. */
(ULONG) NULL, /* Parameters for the message. */
(ULONG) NULL ); /* Parameter for notify message. */
} /* end else */
break;
/*
* We use the WM_ACTIVATE message to participate in device sharing.
* We first check to see if this is an activate or a deactivate
* message (indicated by mp1). Then, we check to see if we've passed
* control of the device that we use. If these conditions are true,
* then we issue an acquire device command to regain control of the
* device, since we're now the active window on the screen.
*
* This is one possible method that can be used to implement
* device sharing. For applications that are more complex
* than this sample program, developers may wish to take
* advantage of a more robust method of device sharing.
* This can be done by using the MCI_ACQUIRE_QUEUE flag on
* the MCI_ACQUIREDEVICE command. Please refer to the MMPM/2
* documentation for more information on this flag.
*/
case WM_ACTIVATE:
/* First we check to see if we've passed control of the device */
if ((BOOL)mp1 && fPassedDevice == TRUE)
{
lpWaveGeneric.hwndCallback = hwnd;
ulReturn = mciSendCommand( usWaveDeviceId,
MCI_ACQUIREDEVICE,
(ULONG)MCI_WAIT,
(PVOID)&lpWaveGeneric,
(USHORT)NULL );
if (ulReturn != 0)
/*
* This is an MCI Error so show the message by passing TRUE
*/
ShowAMessage(
IDS_ERROR_TITLE,
ulReturn,
MB_OK | MB_INFORMATION | MB_MOVEABLE | MB_HELP |
MB_APPLMODAL,
TRUE);
if( lState == STATE_IS_PLAYING )
mciSendCommand( usWaveDeviceId, /* Device to play the chimes. */
MCI_RESUME, /* MCI message. */
MCI_WAIT, /* Flags for the MCI message. */
(ULONG) NULL, /* Parameters for the message. */
(ULONG) NULL ); /* Parameter for notify message. */
} /* end if */
break;
} /* end switch */
return ( WinDefDlgProc( hwnd, msg, mp1, mp2 ) );
}
/******************************************************************************
* Name : InitializePlayList
*
* Description : This procedure will initialize the playlist structure with
* playlist instructions.
* Every even number of the playlist structure subscript contains
* a DATA_OPERATION. Operand One of the data instruction
* is pointing to the pre-allocated buffer where the wave file
* will be copied into. Operand two of the data instruction
* contains the maximum size of the buffer.
* Every odd number of the playlist structure subscript contains
* a SEMPOST_OPERATION. Operand one contains the handle to the
* semaphore to be posted. Each buffer in the playlist is
* associated with a unique semaphore. These semaphores are
* used by another thread to determine when the buffer needs
* to be refilled with new wave data.
* The last entry in the playlist is a branch command that
* causes the playlist to jump to the begining. Thus, the wav
* file is played continuously.
*
*
*
* Concepts : Initialize the memory playlist data structure.
*
* MMPM/2 API's: None.
*
* Parameters : None.
*
* Return : None.
*
*************************************************************************/
ULONG InitializePlayList()
{
ULONG ulNumber;
ULONG ulReturn;
for (ulNumber=0; ulNumber<MAXBUFF; ulNumber++)
{
/*
* Create a semaphore for each buffer in the playlist.
* These semaphores will be used to control the thread
* that updates the buffers in the playlist.
*/
ulReturn = DosCreateEventSem ( NULL, &hevSem[ulNumber], 0L, FALSE );
if ( ulReturn )
return ( ulReturn );
/*
* every 0, 2, 4, 6 etc index of the playlist contains the
* DATA instruction. Operand one contains the buffer of the data
* Operand two contains the maxmimum size for the data buffer.
* Operand three is ignored.
*/
aplayList[2*ulNumber].ulCommand = DATA_OPERATION;
aplayList[2*ulNumber].ulOperandOne = (ULONG) achDataBuffer[ulNumber];
aplayList[2*ulNumber].ulOperandTwo = (ULONG) MAXSIZE;
/*
* Every 1, 3, 5, 7 etc index of the playlist contains the
* SEMPOST instruction. Operand one contains the id of the
* semaphore to post.
*/
aplayList[2*ulNumber+1].ulCommand = SEMPOST_OPERATION;
aplayList[2*ulNumber+1].ulOperandOne = (ULONG) hevSem[ulNumber];
}
/*
* The last playlist command is a BRANCH command that
* loops back to the begining of the playlist.
*/
aplayList[2*MAXBUFF].ulCommand = BRANCH_OPERATION;
aplayList[2*MAXBUFF].ulOperandTwo = 0;
return ( 0 );
}
/************************************************************************
* Name : OpenAudioDevice
*
* Description : This procedure will open the device for Playlist.
*
*
* Concepts : How to Open a Device to play a wave file from Playlist.
*
* MMPM/2 API's: mciSendCommand MCI_OPEN
*
* Parameters : None.
*
* Return : None.
*
*************************************************************************/
void OpenAudioDevice(HWND hwnd)
{
MCI_OPEN_PARMS lpWaveOpen; /* Used for MCI_OPEN messages */
ULONG ulReturn; /* Used for ret code for API */
/*
* Initialize the MCI_OPEN_PARMS data structure with hwndMainDialogBox
* as callback handle for MM_MCIPASSDEVICE, then issue the MCI_OPEN
* command with the mciSendCommand function. No alias is used.
*/
lpWaveOpen.hwndCallback = hwnd;
lpWaveOpen.pszAlias = (PSZ) NULL;
/*
* Open the correct waveform device with the MCI_OPEN message to MCI.
* Use 0 instead of 1 because this will then use the default audio device.
*/
lpWaveOpen.pszDeviceType =
(PSZ) (MAKEULONG(MCI_DEVTYPE_WAVEFORM_AUDIO,0));
/*
* The address of the buffer which will record and play the wave.
*/
lpWaveOpen.pszElementName = (PSZ) &aplayList[0];
/*
* Open the waveform file in the playlist mode.
*/
ulReturn =
mciSendCommand(0,
MCI_OPEN,
MCI_WAIT | MCI_OPEN_PLAYLIST |
MCI_OPEN_TYPE_ID | MCI_OPEN_SHAREABLE,
(PVOID) &lpWaveOpen,
(USHORT) NULL);
if (ulReturn != 0)
{
/* MCI Open was not successfull so show a message by passing a TRUE */
ShowAMessage(
IDS_ERROR_TITLE,
ulReturn,
MB_OK | MB_INFORMATION | MB_MOVEABLE | MB_HELP | MB_APPLMODAL,
TRUE);
}
/* Save the Device Id in the global variable to be used later */
usWaveDeviceId = lpWaveOpen.usDeviceID;
}
/******************************************************************************
* Name : ShowAMessage
*
* Description : This function will show text in a message box.
* If the Message is an MCI Error then the text is pulled
* by issuing a mciGetErrorString. The text is retrieved by the
* Return code of the mci call which failed.
* If the Message is not an MCI Error then the text
* is pulled from the string table that is originally kept
* in the resource file . The text is retrieved by the
* message id that is passed into this function. This id is
* used in the WinLoadString OS/2 API to get the correct
* string from the table.
*
* Concepts : None.
*
* MMPM/2 API's: mciGetErrorString
*
* Parameters : usTitleId - The tile id that identifies which string
* to retrieve from the string table.
* usTextId - The message text to be placed in the
* message box. This value is the Return
* value for the failed MCI call if fMCIError
* is true and is the Message id (application
* owned) if fMCIError is False.
* ulMessageBoxStyle - The style of the message box. Which
* icons, buttons, etc., to show.
* fMCIError - If the Error is an MCIError (TRUE) or
* if it is an application message id (FALSE).
*
* Return : The result from the message box.
*
******************************************************************************/
USHORT ShowAMessage( USHORT usTitleId,
USHORT usTextId,
ULONG ulMessageBoxStyle,
BOOL fMCIError)
{
CHAR achStringBuffer[ STRING_SIZE ]; /* Title String Buffer. */
USHORT usMessageBoxResult; /* RC from WinMessageBox. */
CHAR achMessageText[STRING_SIZE]; /* Message String Buffer */
ULONG ulReturn; /* Return from MCI ERROR */
/*
* Load the Title for the message box from the string table defined in
* the resources.
*/
WinLoadString(
hab, /* HAB for this dialog box. */
(HMODULE) NULL, /* Get the string from the .exe file. */
usTitleId, /* Which string to get. */
(SHORT) STRING_SIZE, /* The size of the buffer. */
achStringBuffer ); /* The buffer to place the string. */
/* If we are to show a MCIERROR, then load it by mciGetErrorString API */
if (fMCIError)
{
ulReturn =
mciGetErrorString(
usTextId,
(PSZ)achMessageText,
(USHORT) STRING_SIZE );
/*
* Make sure that the retrieving of the error string was successfull.
*/
if ( ulReturn != MCIERR_SUCCESS )
{
WinLoadString(
hab, /* HAB for this dialog box. */
(HMODULE) NULL, /* Get string from .exe file. */
IDS_CANT_PROCESS_MESSAGE, /* Which string to get. */
(SHORT) STRING_SIZE, /* The size of the buffer. */
achMessageText); /* Buffer to place the string.*/
ulMessageBoxStyle = MB_OK | MB_INFORMATION | MB_MOVEABLE | MB_HELP |
MB_APPLMODAL;
} /* End of IF testing for failed Get Error String API. */
}
else
{
/*
This is not an MCIError so load the Text for Message Box from
the string table defined in the resources.
*/
WinLoadString(
hab, /* HAB for this dialog box. */
(HMODULE) NULL, /* Get string from .exe file. */
usTextId, /* Which string to get. */
(SHORT) STRING_SIZE, /* The size of the buffer. */
achMessageText ); /* Buffer to place the string.*/
}
usMessageBoxResult =
WinMessageBox(
HWND_DESKTOP, /* Parent handle of the message box. */
hwndDiag, /* Owner handle of the message box. */
achMessageText, /* String to show in the message box. */
achStringBuffer, /* Title to shown in the message box. */
ID_MESSAGE_BOX, /* Message Box Id. */
ulMessageBoxStyle ); /* The style of the message box. */
return( usMessageBoxResult );
} /* End of ShowAMessage */
/*************************************************************************
* Name : PlayTheWave
*
* Description : This function initially opens the wave file to be played
* and tells the MCD information about the file
* that is about to be played. The Samples Per Second,
* Bits Per Sample, and the number of channels with which
* the waveform file was created has to be told to the MCD.
* This function initially fills up the allocated buffer
* of the playlist with the wave file. For 0 - MAXBUFF
* the wave file is filled into the memory. The Wave file
* is read in continously from 0 -MAXBUFF.
* This same buffer is dynamically re-filled again and again
* by the PlayThread thread.
*
* Concepts : The wave file is first opened and then continuously read
* into the buffer. If the end of the wave file is reached
* then we seek to the starting of the wave and keep on reading
* the wave file till the buffer fills up. This displays the
* double buffering concept because, while the playlist is
* continuously looping and playing the wave file, the
* playlist buffers are constantly being filled with data from
* the wave file in the PlayThread thread.
*
*
*
* MMPM/2 API's : mmioOpen
* mmioGetHeader
* mmioRead
* mmioSeek
* mciSendCommand
* MCI_SET
* MCI_CUE
*
* Parameters : None.
*
* Return : ulReturn
*
*************************************************************************/
ULONG PlayTheWave()
{
MCI_WAVE_SET_PARMS lpWaveSet;
ULONG ulReturn;
MMAUDIOHEADER mmHeader;
int i;
long ulBytesRead;
memset ( &lpWaveSet,
0,
sizeof( MCI_WAVE_SET_PARMS ) );
/* Open the Wave File MyWave.Wav for Reading */
hmmioFileHandle = mmioOpen(WAVE_FILE_NAME,
(PMMIOINFO) NULL,
MMIO_READ);
/* If the Wave File could not be opened */
if (!hmmioFileHandle)
{
ShowAMessage(
IDS_ERROR_TITLE,
IDS_CANT_OPEN_WAVE,
MB_OK | MB_INFORMATION | MB_MOVEABLE | MB_HELP |
MB_APPLMODAL,
FALSE );
return ( TRUE );
}
/*
* Get the Header Information for the file so that we can set the channels,
* Samples Per Second and Bits Per Sample to play the memory playlist.
*/
ulReturn = mmioGetHeader(hmmioFileHandle,
(PVOID) &mmHeader,
sizeof(MMAUDIOHEADER),
(PLONG) &ulBytesRead,
(ULONG) NULL,
(ULONG) NULL);
if (ulReturn != 0 )
return ( ulReturn );
/* Set the WaveSet Structure */
lpWaveSet.ulLevel = 100;
lpWaveSet.ulSamplesPerSec = mmHeader.mmXWAVHeader.WAVEHeader.ulSamplesPerSec;
lpWaveSet.usBitsPerSample = mmHeader.mmXWAVHeader.WAVEHeader.usBitsPerSample;
lpWaveSet.usChannels = mmHeader.mmXWAVHeader.WAVEHeader.usChannels;
lpWaveSet.ulAudio = MCI_SET_AUDIO_ALL;
lpWaveSet.hwndCallback = (HWND) NULL;
/* Set the Channels for the MCD */
ulReturn
= mciSendCommand(usWaveDeviceId,
MCI_SET,
MCI_WAIT | MCI_WAVE_SET_CHANNELS,
(PVOID) &lpWaveSet,
(USHORT)NULL);
if (ulReturn != 0 )
return ( ulReturn );
/* Set the Samples Per Second */
ulReturn
= mciSendCommand(usWaveDeviceId,
MCI_SET,
MCI_WAIT | MCI_WAVE_SET_SAMPLESPERSEC,
(PVOID) &lpWaveSet,
(USHORT)NULL);
if (ulReturn != 0 )
return ( ulReturn );
/* Set the Bits per Sample */
ulReturn
= mciSendCommand(usWaveDeviceId,
MCI_SET,
MCI_WAIT | MCI_WAVE_SET_BITSPERSAMPLE,
(PVOID) &lpWaveSet,
(USHORT)NULL);
if (ulReturn != 0 )
return ( ulReturn );
/* From 0 - MAXBUFF, fill the memory Playlist buffer with the wave file. */
for (i=0; i<MAXBUFF; i++)
{
ulBytesRead =
mmioRead(hmmioFileHandle,
(HPSTR) achDataBuffer[i],
MAXSIZE);
/*
* If the end of the wave file is reached then Seek to the starting
* of the wave file and start reading the wave into the appropriate
* buffer
*/
if (ulBytesRead < MAXSIZE)
{
mmioSeek(hmmioFileHandle, 0, SEEK_SET);
ulBytesRead =
mmioRead(hmmioFileHandle,
(HPSTR) achDataBuffer[i],
MAXSIZE);
}
}
/*
* Create the thread that will maintain the playlist buffer
*/
fEndPlay = FALSE;
if ( DosCreateThread ( &tidPlayThread,
(PFNTHREAD) PlayThread,
0L, 0L, 8192L))
return ( TRUE );
return ( FALSE );
}
/*************************************************************************
* Name PlayThread
*
* Description: This thread first starts the playlist by sending
* an MCI_PLAY command. The thread then executes a
* DosWaitEventSem using the first semaphore in the
* playlist. When the first buffer in the playlist is
* consumed, this semaphore gets posted by the
* SEMPOST_OPERATION command in the playlist. This is
* the queue to begin refilling this buffer.
* Once the buffer is full, the thread repeates the
* same procedure for the next semaphore. This
* procedure is repeated for each semaphore until
* each buffer has been refilled and then starts over
* with the first semaphore.
* In this way, the entire wav file is played
* continuously until the user either closes the
* application or selects the stop button.
*
*
*
*************************************************************************/
VOID APIENTRY PlayThread ( ULONG parm1 )
{
ULONG ulBytesRead;
ULONG ulBufferNum;
ULONG ulPostCount;
ULONG ulReturn;
MCI_PLAY_PARMS mciPlayParameters;
mciPlayParameters.hwndCallback = hwndDiag;
/*
* Send the Play Command to begin the playing of the memory playlist.
*/
ulReturn = mciSendCommand(usWaveDeviceId,
MCI_PLAY,
MCI_NOTIFY,
(PVOID) &mciPlayParameters,
0);
/*
* Loop until the playlist is stopped.
*/
while( !fEndPlay )
{
for( ulBufferNum = 0; ulBufferNum < MAXBUFF; ulBufferNum++ )
{
/*
* Use DosWaitEventSem to pause util the playlist plays this
* buffer. Then refill the buffer and post the semaphore.
*/
ulReturn = DosWaitEventSem ( hevSem[ulBufferNum], 5000L );
DosResetEventSem ( hevSem[ulBufferNum], &ulPostCount );
if( fEndPlay ) break;
/*
* Read the Next MAXSIZE bytes of the wave file
*/
ulBytesRead =
mmioRead(hmmioFileHandle,
(HPSTR) achDataBuffer[ulBufferNum],
MAXSIZE);
/*
* If we have reached the end of the wave file then set the file marker
* to the begining of the file and start reading into the bufferno.
* This causes the continuous filling and playing of the data buffer
* again and again as long as the END push button is not pressed.
* The wave file is going to keep on playing without any interruptions
* util ther user selects the stop button.
*/
if (ulBytesRead < MAXSIZE)
{
/* Seek to the starting of the wave file */
mmioSeek(hmmioFileHandle, 0, SEEK_SET);
/* Read the Next MAXSIZE bytes of the wave file */
mmioRead(hmmioFileHandle,
(HPSTR) achDataBuffer[ulBufferNum],
MAXSIZE);
}
} /* End of for loop */
} /* End of while loop */
} /* End of function PlayThread */