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 >
Text File  |  1999-05-11  |  39KB  |  1,081 lines

  1. /*******************************************************************************
  2.  * File Name   : DOUPLAY.C
  3.  *
  4.  * Description : This file contains the C source code required for the Double
  5.  *               Buffering Playlist sample program.  This sample allows
  6.  *               the user to play a wave file continuously by pushing the
  7.  *               play button.  The user can stop playing the wave file by
  8.  *               pushing the stop button.  Both of these push buttons are
  9.  *               animated.
  10.  *
  11.  * Concepts    : This program illustrates how to use a Memory
  12.  *               Playlist in a double buffering manner for reading and playing
  13.  *               a wave file at the same time.
  14.  *               This concept can be used in a lot of real time recording
  15.  *               applications such as:
  16.  *               1. Real Time recording and playing of the wave file
  17.  *               2. Censoring a Speech being transmitted.
  18.  *               The sample also shows how to use MMIO API's used in opening,
  19.  *               reading, seeking, and closing files.
  20.  *
  21.  * MMPM/2 API's: List of all MMPM/2 API's that are used in this module.
  22.  *
  23.  *               mciSendCommand
  24.  *                  MCI_ACQUIREDEVICE
  25.  *                  MCI_OPEN
  26.  *                  MCI_PLAY
  27.  *                  MCI_SET
  28.  *               mciGetErrorString
  29.  *               mmioOpen
  30.  *               mmioGetHeader
  31.  *               mmioRead
  32.  *               mmioSeek
  33.  *               mmioClose
  34.  *
  35.  * Required
  36.  *    Files    : doubplay.c         Source Code.
  37.  *               doubapp.c          Source Code.
  38.  *               doubplay.h         Include file.
  39.  *               doubplay.dlg       Dialog definition.
  40.  *               doubplay.rc        Resources.
  41.  *               makefile           Make file.
  42.  *               doubplay.def       Linker definition file.
  43.  *               doubplay.ico       Doubplay icon.
  44.  *               mywave.wav         Wave File Played.
  45.  *               play0.bmp          Play PushButton Bitmap 0
  46.  *               play1.bmp          Play PushButton Bitmap 1
  47.  *               play2.bmp          Play PushButton Bitmap 2
  48.  *               play3.bmp          Play PushButton Bitmap 3
  49.  *               play4.bmp          Play PushButton Bitmap 4
  50.  *               stop.bmp           Stop PushButton Bitmap
  51.  *
  52.  * Copyright (C) IBM  1993
  53.  ******************************************************************************/
  54.  
  55. #define  INCL_DOS                   /* required to use Dos APIs.           */
  56. #define  INCL_WIN                   /* required to use Win APIs.           */
  57. #define  INCL_PM                    /* required to use PM APIs.            */
  58. #define  INCL_OS2MM                 /* required for MCI and MMIO headers   */
  59. #define  INCL_WINSTDSLIDER          /* required for using slider control   */
  60. #define  INCL_SECONDARYWINDOW       /* required for secondary window       */
  61. #define  INCL_GRAPHICBUTTON         /* required for graphic button control */
  62.  
  63. #include <os2.h>
  64. #include <stdio.h>
  65. #include <os2me.h>
  66. #include <stdlib.h>
  67. #include <string.h>
  68.  
  69. #include <sw.h>
  70.  
  71. #include "doubplay.h"               /* Dialog Ids, Resource Ids etc        */
  72.  
  73.  
  74. #define WAVE_FILE_NAME "mywave.wav"
  75. /*******************************************************************/
  76.  
  77. /* Procedure / Function prototypes */
  78.  
  79. #pragma linkage( MainDialogProc, system)
  80. MRESULT EXPENTRY MainDialogProc(HWND, ULONG, MPARAM, MPARAM);
  81. VOID APIENTRY PlayThread ( ULONG parm1 );
  82. VOID main(int i,char *p[]);
  83. VOID InitializeDialog(void);
  84. VOID Finalize(void);
  85. ULONG InitializePlayList( VOID );
  86. VOID OpenAudioDevice(HWND hwnd);
  87. VOID CloseAll( VOID );
  88. ULONG PlayTheWave( VOID );
  89.  
  90. /*******************************************************************/
  91.  
  92. /* Global Variables */
  93.  
  94. HAB      hab;                                 /* anchor block handle         */
  95. QMSG     qmsg;                                /* Message Que                 */
  96. HMQ      hmq;
  97. HWND     hwndDiag;                            /* Application Dialog handle   */
  98. HWND     hwndFrame;                           /* Application Frame handle    */
  99. BOOL     fPassedDevice = FALSE;               /* Do we own the Audio device  */
  100. TID      tidPlayThread;                       /* Id for the PlayWave Thread  */
  101. USHORT   usWaveDeviceId = 0;                  /* Id for the Wave Device      */
  102. CHAR     achDataBuffer[MAXBUFF][MAXSIZE];     /* Data Buffer which will hold */
  103.                                               /* wave for Memory Playlist    */
  104. HEV      hevSem[MAXBUFF];
  105. HMMIO    hmmioFileHandle;                     /* Handle to the Wave File     */
  106. LONG     lState = STATE_IS_STOP;              /* state of the application    */
  107.                                               /* Can be STOP or PLAYING      */
  108. BOOL     fEndPlay;                            /* Used to end the play thread */
  109.  
  110.  
  111. PLAY_LIST_STRUCTURE_T aplayList[2*MAXBUFF+1]; /* Play List memory Structure  */
  112.  
  113. /******************************************************************************
  114.  * Name         : main
  115.  *
  116.  * Description  : This function calls the Intialize procedure to prepare
  117.  *                everything for the program's operation, enters the
  118.  *                message loop, then call Finalize to shut everything down
  119.  *                when the program is terminated.
  120.  *
  121.  * Concepts     : None.
  122.  *
  123.  * MMPM/2 API's : None.
  124.  *
  125.  * Parameters   : argc - Number of parameters passed into the program.
  126.  *                argv - Command line parameters.
  127.  *
  128.  * Return       : None.
  129.  *
  130.  *************************************************************************/
  131. void main(int argc, char *argv[])
  132. {
  133. InitializeDialog();
  134.  
  135. /* Handle the messages: */
  136. while(WinGetMsg(hab,&qmsg,0,0,0))
  137.         WinDispatchMsg(hab,&qmsg);
  138.  
  139. Finalize();
  140.  
  141. }
  142.  
  143. /*************************************************************************
  144.  * Name         : InitializeDialog
  145.  *
  146.  * Description  : This function performs the necessary initializations and
  147.  *                setups that are required to show/run a dialog box as a
  148.  *                main window.  The message queue will be created, as will
  149.  *                the dialog box.
  150.  *
  151.  * Concepts     : Secondary Windows is used to create and show a dialog box.
  152.  *                A system clock is displayed till the application is loaded.
  153.  *
  154.  * MMPM/2 API's : WinLoadSecondaryWindow
  155.  *                WinQuerySecondaryHWND
  156.  *
  157.  * Parameters   : None.
  158.  *
  159.  * Return       : None.
  160.  *
  161.  *************************************************************************/
  162. void InitializeDialog()
  163. {
  164. CHAR achTitle[STRING_SIZE] = "";
  165. CHAR achDefaultSize[STRING_SIZE] = "";
  166.  
  167.  
  168.    /* Initialize the Dialog window */
  169.    hab = WinInitialize(0);
  170.  
  171.    /* create a message queue for the window */
  172.    hmq = WinCreateMsgQueue(hab,0);
  173.  
  174.  
  175.    /* Load the Dialog - This will return the Handle to the Frame */
  176.    hwndFrame =
  177.        WinLoadSecondaryWindow(HWND_DESKTOP
  178.                             ,HWND_DESKTOP
  179.                             ,(PFNWP)MainDialogProc
  180.                             ,(HMODULE)NULL
  181.                             ,ID_SAMPLE
  182.                             ,(PVOID)NULL);
  183.  
  184.  
  185.    /*
  186.     * By specifying the QS_DIALOG flag we will get the handle to the Dialog of
  187.     * the frame
  188.     */
  189.    hwndDiag = WinQuerySecondaryHWND(hwndFrame,QS_DIALOG);
  190.  
  191.    /* Get the string for default size */
  192.    WinLoadString(
  193.       hab,
  194.       (HMODULE) NULL,
  195.       IDS_DEFAULT_SIZE,
  196.       (SHORT) sizeof( achDefaultSize),
  197.       achDefaultSize);
  198.  
  199.    /* Add Default Size menu item to system menu of the secondary window. */
  200.    WinInsertDefaultSize(hwndFrame, achDefaultSize);
  201.  
  202.    /*
  203.     * Get the window title string from the Resource string table
  204.     * and set it as the window text for the dialog window.
  205.     */
  206.    WinLoadString(
  207.       hab,
  208.       (HMODULE) NULL,
  209.       IDS_MAIN_WINDOW_TITLE,
  210.       (SHORT) sizeof( achTitle),
  211.       achTitle);
  212.  
  213.    /* Set the Title of the Dialog */
  214.    WinSetWindowText( hwndFrame, achTitle);
  215.  
  216. }
  217.  
  218. /******************************************************************************
  219.  * Name         : CloseAll
  220.  *
  221.  * Description  : This function is called when the current Thread finishes
  222.  *                execution and is placed in DosExitList during the WM_INITDLG
  223.  *                message.  This function allows to terminate itself and all
  224.  *                of its children processes.
  225.  *
  226.  * Concepts     : None.
  227.  *
  228.  * MMPM/2 API's : None.
  229.  *
  230.  * Parameters   : None
  231.  *
  232.  * Return       : None.
  233.  *
  234.  *************************************************************************/
  235. void CloseAll()
  236. {
  237.      DosExit(EXIT_PROCESS, 0);
  238.      DosExitList(EXLST_EXIT, NULL);
  239. }
  240.  
  241. /*************************************************************************
  242.  * Name         : Finalize
  243.  *
  244.  * Description  : This routine is called after the message dispatch loop
  245.  *                has ended because of a WM_QUIT message.  The code will
  246.  *                destroy the messages queue, and window.
  247.  *
  248.  * Concepts     : None.
  249.  *
  250.  * MMPM/2 API's : None.
  251.  *
  252.  * Parameters   : None.
  253.  *
  254.  * Return       : None.
  255.  *
  256.  *************************************************************************/
  257. VOID Finalize( VOID )
  258. {
  259.    WinDestroySecondaryWindow( hwndFrame );
  260.    WinDestroyMsgQueue( hmq );
  261.    WinTerminate( hab );
  262.  
  263. }  /* End of Finalize */
  264. /*******************************************************************************
  265.  * Name        : MainDialogProc
  266.  *
  267.  * Description : This function controls the main dialog box.  It will handle
  268.  *               received messages such as pushbutton notifications, playlist
  269.  *               messages, etc
  270.  *
  271.  *               The following messages are handled specifically by this
  272.  *               routine.
  273.  *
  274.  *                  WM_INITDLG
  275.  *                  WM_CLOSE
  276.  *                  WM_COMMAND
  277.  *                  MM_MCIPASSDEVICE
  278.  *                  WM_ACTIVATE
  279.  *
  280.  *
  281.  * MMPM/2 API's : mciSendCommand
  282.  *                   MCI_ACQUIREDEVICE
  283.  *                mmioClose
  284.  *                mmioRead
  285.  *                mmioSeek
  286.  *
  287.  * Parameters   : hwnd - Handle for the Main dialog box.
  288.  *                msg  - Message received by the dialog box.
  289.  *                mp1  - Parameter 1 for the just recieved message.
  290.  *                mp2  - Parameter 2 for the just recieved message.
  291.  *
  292.  * Return       :
  293.  *
  294.  *
  295.  ******************************************************************************/
  296. MRESULT EXPENTRY MainDialogProc(
  297.                 HWND hwnd,
  298.                  ULONG msg,
  299.                  MPARAM mp1,
  300.                  MPARAM mp2)
  301. {
  302. static MCI_GENERIC_PARMS  lpWaveGeneric; /* Used for MCI_ACQUIREDEVICE      */
  303. ULONG                     ulReturn;      /* Ret Code for Dos and MCI calls  */
  304.  
  305.  
  306. switch (msg)
  307.    {
  308.  
  309.     case WM_CLOSE:
  310.  
  311.        if ( usWaveDeviceId > 0 )
  312.             mciSendCommand(
  313.                usWaveDeviceId,               /* Device to play the chimes.    */
  314.                MCI_CLOSE,                    /* MCI message.                  */
  315.                MCI_WAIT,                     /* Flags for the MCI message.    */
  316.                (ULONG) NULL,                 /* Parameters for the message.   */
  317.                (ULONG) NULL );               /* Parameter for notify message. */
  318.  
  319.        WinPostMsg( hwnd, WM_QUIT, 0L, 0L );
  320.        return ((MRESULT) NULL);
  321.  
  322.     case WM_INITDLG:
  323.  
  324.        /*
  325.         * Put the Playlist Instructions into the Playlist structure.
  326.         */
  327.        ulReturn = InitializePlayList();
  328.  
  329.        if( ulReturn )
  330.          {
  331.          ShowAMessage(
  332.              IDS_ERROR_TITLE,
  333.              IDS_CANT_CREATE_SEMAPHORE,
  334.              MB_OK | MB_INFORMATION | MB_MOVEABLE | MB_HELP |
  335.              MB_APPLMODAL,
  336.              FALSE );
  337.  
  338.          WinPostMsg( hwnd, WM_QUIT, 0L, 0L );
  339.          }
  340.  
  341.        /* Opens the Audio device for playlist */
  342.        OpenAudioDevice(hwnd);
  343.  
  344.        /*
  345.         * Since the play button is an animated button, we need to initialize it
  346.         */
  347.        WinSendMsg (
  348.            WinWindowFromID(
  349.                 hwnd,             /* Dialog window handle             */
  350.                 ID_PLAY),         /* Id - Play graphic button         */
  351.            GBM_SETANIMATIONRATE,  /* Animation rate control           */
  352.            MPFROMLONG(100L),      /* Update play bitmap every .1 sec  */
  353.            NULL);                 /* Ignore return data               */
  354.  
  355.        break;
  356.  
  357.  
  358.     /*  Service all of the button pushes */
  359.     case WM_COMMAND:
  360.        switch (SHORT1FROMMP(mp1))
  361.          {
  362.          case ID_END:
  363.  
  364.             /*
  365.              * Send command to MCI to stop the playlist
  366.              */
  367.             mciSendCommand( usWaveDeviceId,  /* Device to play the chimes.    */
  368.                             MCI_STOP,        /* MCI message.                  */
  369.                             MCI_WAIT,        /* Flags for the MCI message.    */
  370.                             (ULONG) NULL,    /* Parameters for the message.   */
  371.                             (ULONG) NULL );  /* Parameter for notify message. */
  372.  
  373.             fEndPlay = TRUE;
  374.  
  375.             /*
  376.              * Disable the animation of the Play button
  377.              */
  378.             WinSendMsg (   WinWindowFromID(
  379.                              hwnd,            /* Dialog window handle        */
  380.                              ID_PLAY),        /* Id - Play graphic button    */
  381.                            GBM_ANIMATE,       /* Animation control           */
  382.                            MPFROMSHORT(FALSE),/* Animation flag              */
  383.                            NULL);             /* Ignore return data          */
  384.  
  385.             lState = STATE_IS_STOP;
  386.  
  387.             break;
  388.  
  389.  
  390.          case ID_PLAY:
  391.  
  392.             /*
  393.              * If we are not playing the playlist only then Play it
  394.              */
  395.             if (lState == STATE_IS_STOP)
  396.                {
  397.                if (fPassedDevice)
  398.                   {
  399.                   /*
  400.                    * If we don't have the device then display a message.
  401.                    * FALSE is passed because this is not a MCI error.
  402.                    */
  403.  
  404.                   ShowAMessage(
  405.                        IDS_ERROR_TITLE,
  406.                        IDS_CANT_PROCESS_MESSAGE,
  407.                        MB_OK | MB_INFORMATION | MB_MOVEABLE | MB_HELP |
  408.                        MB_APPLMODAL ,
  409.                        FALSE);
  410.                   }
  411.                else
  412.                   /*
  413.                    * We have the device so no problem.
  414.                    * Call the subroutine that starts the audio playlist.
  415.                    */
  416.                   ulReturn = PlayTheWave();
  417.  
  418.                if ( ulReturn )
  419.                   {
  420.                   /*
  421.                    * Play failed so display an error message
  422.                    */
  423.                   ShowAMessage(
  424.                       IDS_ERROR_TITLE,
  425.                       IDS_CANT_PROCESS_MESSAGE,
  426.                       MB_OK | MB_INFORMATION | MB_MOVEABLE | MB_HELP |
  427.                       MB_APPLMODAL,
  428.                       FALSE );
  429.                   }
  430.                else
  431.                   {
  432.                   /*
  433.                    * Play was successful so update the flag and animate
  434.                    * the play button.
  435.                    */
  436.                   lState = STATE_IS_PLAYING;
  437.  
  438.                   WinSendMsg (
  439.                      WinWindowFromID(
  440.                        hwndDiag,         /* Dialog window handle      */
  441.                        ID_PLAY),         /* Id - Play graphic button  */
  442.                      GBM_ANIMATE,        /* Animation control         */
  443.                      MPFROMSHORT(TRUE),  /* Animation flag            */
  444.                      NULL);              /* Ignore return data        */
  445.  
  446.                   }
  447.  
  448.  
  449.                }
  450.  
  451.             break;
  452.  
  453.          } /* end switch */
  454.        return((MRESULT)NULL);
  455.  
  456.    /*
  457.     * This message is used to set a flag that indicates wether this
  458.     * application has position of the audio device. This information
  459.     * is used to implement device sharing.
  460.     */
  461.  
  462.     case MM_MCIPASSDEVICE:
  463.        if( SHORT1FROMMP( mp2 ) == MCI_GAINING_USE )
  464.           fPassedDevice = FALSE;
  465.        else
  466.        {
  467.           fPassedDevice = TRUE;
  468.           if( lState == STATE_IS_PLAYING )
  469.  
  470.             mciSendCommand( usWaveDeviceId,  /* Device to play the chimes.    */
  471.                             MCI_PAUSE,       /* MCI message.                  */
  472.                             MCI_WAIT,        /* Flags for the MCI message.    */
  473.                             (ULONG) NULL,    /* Parameters for the message.   */
  474.                             (ULONG) NULL );  /* Parameter for notify message. */
  475.  
  476.        } /* end else */
  477.        break;
  478.  
  479.  
  480.     /*
  481.      * We use the WM_ACTIVATE message to participate in device sharing.
  482.      * We first check to see if this is an activate or a deactivate
  483.      * message (indicated by mp1). Then, we check to see if we've passed
  484.      * control of the device that we use.  If these conditions are true,
  485.      * then we issue an acquire device command to regain control of the
  486.      * device, since we're now the active window on the screen.
  487.      *
  488.      * This is one possible method that can be used to implement
  489.      * device sharing. For applications that are more complex
  490.      * than this sample program, developers may wish to take
  491.      * advantage of a more robust method of device sharing.
  492.      * This can be done by using the MCI_ACQUIRE_QUEUE flag on
  493.      * the MCI_ACQUIREDEVICE command.  Please refer to the MMPM/2
  494.      * documentation for more information on this flag.
  495.      */
  496.     case WM_ACTIVATE:
  497.        /* First we check to see if we've passed control of the device */
  498.        if ((BOOL)mp1 && fPassedDevice == TRUE)
  499.        {
  500.           lpWaveGeneric.hwndCallback =   hwnd;
  501.           ulReturn = mciSendCommand( usWaveDeviceId,
  502.                                      MCI_ACQUIREDEVICE,
  503.                                      (ULONG)MCI_WAIT,
  504.                                      (PVOID)&lpWaveGeneric,
  505.                                      (USHORT)NULL );
  506.           if (ulReturn != 0)
  507.              /*
  508.               * This is an MCI Error so show the message by passing TRUE
  509.               */
  510.              ShowAMessage(
  511.                      IDS_ERROR_TITLE,
  512.                      ulReturn,
  513.                      MB_OK | MB_INFORMATION | MB_MOVEABLE | MB_HELP |
  514.                      MB_APPLMODAL,
  515.                      TRUE);
  516.  
  517.           if( lState == STATE_IS_PLAYING )
  518.  
  519.             mciSendCommand( usWaveDeviceId,  /* Device to play the chimes.    */
  520.                             MCI_RESUME,      /* MCI message.                  */
  521.                             MCI_WAIT,        /* Flags for the MCI message.    */
  522.                             (ULONG) NULL,    /* Parameters for the message.   */
  523.                             (ULONG) NULL );  /* Parameter for notify message. */
  524.  
  525.        } /* end if */
  526.  
  527.        break;
  528.     } /* end switch */
  529.  
  530.     return ( WinDefDlgProc( hwnd, msg, mp1, mp2 ) );
  531. }
  532.  
  533.  
  534.  
  535. /******************************************************************************
  536.  * Name        : InitializePlayList
  537.  *
  538.  * Description : This procedure will initialize the playlist structure with
  539.  *               playlist instructions.
  540.  *               Every even number of the playlist structure subscript contains
  541.  *               a DATA_OPERATION.  Operand One of the data instruction
  542.  *               is pointing to the pre-allocated buffer where the wave file
  543.  *               will be copied into.  Operand two of the data instruction
  544.  *               contains the maximum size of the buffer.
  545.  *               Every odd number of the playlist structure subscript contains
  546.  *               a SEMPOST_OPERATION. Operand one contains the handle to the
  547.  *               semaphore to be posted. Each buffer in the playlist is
  548.  *               associated with a unique semaphore. These semaphores are
  549.  *               used by another thread to determine when the buffer needs
  550.  *               to be refilled with new wave data.
  551.  *               The last entry in the playlist is a branch command that
  552.  *               causes the playlist to jump to the begining. Thus, the wav
  553.  *               file is played continuously.
  554.  *
  555.  *
  556.  *
  557.  * Concepts    : Initialize the memory playlist data structure.
  558.  *
  559.  * MMPM/2 API's: None.
  560.  *
  561.  * Parameters  : None.
  562.  *
  563.  * Return      : None.
  564.  *
  565.  *************************************************************************/
  566.  ULONG InitializePlayList()
  567.  {
  568.  ULONG ulNumber;
  569.  ULONG ulReturn;
  570.  
  571.    for (ulNumber=0; ulNumber<MAXBUFF; ulNumber++)
  572.    {
  573.  
  574.       /*
  575.        * Create a semaphore for each buffer in the playlist.
  576.        * These semaphores will be used to control the thread
  577.        * that updates the buffers in the playlist.
  578.        */
  579.       ulReturn = DosCreateEventSem ( NULL, &hevSem[ulNumber], 0L, FALSE );
  580.  
  581.       if ( ulReturn )
  582.          return ( ulReturn );
  583.  
  584.  
  585.       /*
  586.        * every 0, 2, 4, 6 etc index of the playlist contains the
  587.        * DATA instruction.  Operand one contains the buffer of the data
  588.        * Operand two contains the maxmimum size for the data buffer.
  589.        * Operand three is ignored.
  590.        */
  591.       aplayList[2*ulNumber].ulCommand = DATA_OPERATION;
  592.       aplayList[2*ulNumber].ulOperandOne = (ULONG) achDataBuffer[ulNumber];
  593.       aplayList[2*ulNumber].ulOperandTwo = (ULONG) MAXSIZE;
  594.  
  595.       /*
  596.        * Every 1, 3, 5, 7 etc index of the playlist contains the
  597.        * SEMPOST instruction. Operand one contains the id of the
  598.        * semaphore to post.
  599.        */
  600.       aplayList[2*ulNumber+1].ulCommand = SEMPOST_OPERATION;
  601.       aplayList[2*ulNumber+1].ulOperandOne = (ULONG) hevSem[ulNumber];
  602.  
  603.    }
  604.  
  605.    /*
  606.     * The last playlist command is a BRANCH command that
  607.     * loops back to the begining of the playlist.
  608.     */
  609.    aplayList[2*MAXBUFF].ulCommand = BRANCH_OPERATION;
  610.    aplayList[2*MAXBUFF].ulOperandTwo = 0;
  611.  
  612.    return ( 0 );
  613.  
  614.  }
  615.  
  616.  
  617.  
  618.  
  619. /************************************************************************
  620.  * Name        : OpenAudioDevice
  621.  *
  622.  * Description : This procedure will open the device for Playlist.
  623.  *
  624.  *
  625.  * Concepts    : How to Open a Device to play a wave file from Playlist.
  626.  *
  627.  * MMPM/2 API's:  mciSendCommand         MCI_OPEN
  628.  *
  629.  * Parameters  : None.
  630.  *
  631.  * Return      : None.
  632.  *
  633.  *************************************************************************/
  634.  
  635. void  OpenAudioDevice(HWND hwnd)
  636. {
  637.  
  638. MCI_OPEN_PARMS          lpWaveOpen;        /* Used for MCI_OPEN messages */
  639. ULONG                   ulReturn;          /* Used for ret code for API  */
  640.  
  641.  
  642.    /*
  643.     * Initialize the MCI_OPEN_PARMS data structure with hwndMainDialogBox
  644.     * as callback handle for MM_MCIPASSDEVICE, then issue the MCI_OPEN
  645.     * command with the mciSendCommand function.  No alias is used.
  646.     */
  647.  
  648.    lpWaveOpen.hwndCallback       =  hwnd;
  649.    lpWaveOpen.pszAlias       = (PSZ) NULL;
  650.  
  651.  
  652.    /*
  653.     * Open the correct waveform device with the MCI_OPEN message to MCI.
  654.     * Use 0 instead of 1 because this will then use the default audio device.
  655.     */
  656.    lpWaveOpen.pszDeviceType  =
  657.          (PSZ) (MAKEULONG(MCI_DEVTYPE_WAVEFORM_AUDIO,0));
  658.  
  659.    /*
  660.     * The address of the buffer which will record and play the wave.
  661.     */
  662.    lpWaveOpen.pszElementName = (PSZ) &aplayList[0];
  663.  
  664.  
  665.    /*
  666.     * Open the waveform file in the playlist mode.
  667.     */
  668.    ulReturn =
  669.        mciSendCommand(0,
  670.                       MCI_OPEN,
  671.                       MCI_WAIT | MCI_OPEN_PLAYLIST |
  672.                       MCI_OPEN_TYPE_ID | MCI_OPEN_SHAREABLE,
  673.                       (PVOID) &lpWaveOpen,
  674.                       (USHORT) NULL);
  675.  
  676.    if (ulReturn != 0)
  677.       {
  678.       /* MCI Open was not successfull so show a message by passing a TRUE */
  679.        ShowAMessage(
  680.              IDS_ERROR_TITLE,
  681.              ulReturn,
  682.              MB_OK | MB_INFORMATION | MB_MOVEABLE | MB_HELP | MB_APPLMODAL,
  683.              TRUE);
  684.       }
  685.  
  686.    /* Save the Device Id in the global variable to be used later */
  687.    usWaveDeviceId = lpWaveOpen.usDeviceID;
  688. }
  689.  
  690.  
  691. /******************************************************************************
  692.  * Name        : ShowAMessage
  693.  *
  694.  * Description : This function will show text in a message box.
  695.  *               If the Message is an MCI Error then the text is pulled
  696.  *               by issuing a mciGetErrorString.  The text is retrieved by the
  697.  *               Return code of the mci call which failed.
  698.  *               If the Message is not an MCI Error then the text
  699.  *               is pulled from the string table that is originally kept
  700.  *               in the resource file .  The text is retrieved by the
  701.  *               message id that is passed into this function.  This id is
  702.  *               used in the WinLoadString OS/2 API to get the correct
  703.  *               string from the table.
  704.  *
  705.  * Concepts    : None.
  706.  *
  707.  * MMPM/2 API's: mciGetErrorString
  708.  *
  709.  * Parameters  : usTitleId         - The tile id that identifies which string
  710.  *                                   to retrieve from the string table.
  711.  *               usTextId          - The message text to be placed in the
  712.  *                                   message box.  This value is the Return
  713.  *                                   value for the failed MCI call if fMCIError
  714.  *                                   is true and is the Message id (application
  715.  *                                   owned) if fMCIError is False.
  716.  *               ulMessageBoxStyle - The style of the message box.  Which
  717.  *                                   icons, buttons, etc., to show.
  718.  *               fMCIError         - If the Error is an MCIError (TRUE) or
  719.  *                                   if it is an application message id (FALSE).
  720.  *
  721.  * Return      : The result from the message box.
  722.  *
  723.  ******************************************************************************/
  724. USHORT ShowAMessage( USHORT usTitleId,
  725.                      USHORT usTextId,
  726.                      ULONG  ulMessageBoxStyle,
  727.                      BOOL   fMCIError)
  728. {
  729.  
  730.    CHAR   achStringBuffer[ STRING_SIZE ];       /* Title String Buffer.      */
  731.    USHORT usMessageBoxResult;                   /* RC from WinMessageBox.    */
  732.    CHAR   achMessageText[STRING_SIZE];          /* Message String Buffer     */
  733.    ULONG  ulReturn;                             /* Return from MCI ERROR     */
  734.  
  735.    /*
  736.     * Load the Title for the message box from the string table defined in
  737.     * the resources.
  738.     */
  739.  
  740.    WinLoadString(
  741.       hab,                           /* HAB for this dialog box.            */
  742.       (HMODULE) NULL,                /* Get the string from the .exe file.  */
  743.       usTitleId,                     /* Which string to get.                */
  744.       (SHORT) STRING_SIZE,           /* The size of the buffer.             */
  745.       achStringBuffer );             /* The buffer to place the string.     */
  746.  
  747.    /* If we are to show a MCIERROR, then load it by mciGetErrorString API */
  748.    if (fMCIError)
  749.      {
  750.         ulReturn =
  751.             mciGetErrorString(
  752.                             usTextId,
  753.                             (PSZ)achMessageText,
  754.                             (USHORT) STRING_SIZE );
  755.  
  756.  
  757.            /*
  758.             * Make sure that the retrieving of the error string was successfull.
  759.             */
  760.            if ( ulReturn != MCIERR_SUCCESS )
  761.              {
  762.               WinLoadString(
  763.                     hab,                       /* HAB for this dialog box.   */
  764.                     (HMODULE) NULL,            /* Get string from .exe file. */
  765.                     IDS_CANT_PROCESS_MESSAGE,  /* Which string to get.       */
  766.                     (SHORT) STRING_SIZE,       /* The size of the buffer.    */
  767.                     achMessageText);           /* Buffer to place the string.*/
  768.  
  769.               ulMessageBoxStyle = MB_OK | MB_INFORMATION | MB_MOVEABLE | MB_HELP |
  770.                                   MB_APPLMODAL;
  771.              }  /* End of IF testing for failed Get Error String API. */
  772.  
  773.      }
  774.    else
  775.      {
  776.      /*
  777.       This is not an MCIError so load the Text for Message Box from
  778.       the string table defined in the resources.
  779.       */
  780.        WinLoadString(
  781.            hab,                     /* HAB for this dialog box.   */
  782.            (HMODULE) NULL,          /* Get string from .exe file. */
  783.            usTextId,                /* Which string to get.       */
  784.            (SHORT) STRING_SIZE,     /* The size of the buffer.    */
  785.            achMessageText );        /* Buffer to place the string.*/
  786.      }
  787.  
  788.    usMessageBoxResult =
  789.       WinMessageBox(
  790.          HWND_DESKTOP,              /* Parent handle of the message box.   */
  791.          hwndDiag,                  /* Owner handle of the message box.    */
  792.          achMessageText,            /* String to show in the message box.  */
  793.          achStringBuffer,           /* Title to shown in the message box.  */
  794.          ID_MESSAGE_BOX,            /* Message Box Id.                     */
  795.          ulMessageBoxStyle );       /* The style of the message box.       */
  796.  
  797.    return( usMessageBoxResult );
  798.  
  799. }  /* End of ShowAMessage */
  800.  
  801.  
  802.  
  803. /*************************************************************************
  804.  * Name         : PlayTheWave
  805.  *
  806.  * Description : This function initially opens the wave file to be played
  807.  *               and tells the MCD information about the file
  808.  *               that is about to be played.  The Samples Per Second,
  809.  *               Bits Per Sample, and the number of channels with which
  810.  *               the waveform file was created has to be told to the MCD.
  811.  *               This function initially fills up the allocated buffer
  812.  *               of the playlist with the wave file.  For 0 - MAXBUFF
  813.  *               the wave file is filled into the memory.  The Wave file
  814.  *               is read in continously from 0 -MAXBUFF.
  815.  *               This same buffer is dynamically re-filled again and again
  816.  *               by the PlayThread thread.
  817.  *
  818.  * Concepts     : The wave file is first opened and then continuously read
  819.  *                into the buffer.  If the end of the wave file is reached
  820.  *                then we seek to the starting of the wave and keep on reading
  821.  *                the wave file till the buffer fills up. This displays the
  822.  *                double buffering concept because, while the playlist is
  823.  *                continuously looping and playing the wave file, the
  824.  *                playlist buffers are constantly being filled with data from
  825.  *                the wave file in the PlayThread thread.
  826.  *
  827.  *
  828.  *
  829.  * MMPM/2 API's : mmioOpen
  830.  *                mmioGetHeader
  831.  *                mmioRead
  832.  *                mmioSeek
  833.  *                mciSendCommand
  834.  *                  MCI_SET
  835.  *                  MCI_CUE
  836.  *
  837.  * Parameters   : None.
  838.  *
  839.  * Return       : ulReturn
  840.  *
  841.  *************************************************************************/
  842. ULONG PlayTheWave()
  843. {
  844.  
  845.    MCI_WAVE_SET_PARMS    lpWaveSet;
  846.    ULONG                 ulReturn;
  847.    MMAUDIOHEADER         mmHeader;
  848.    int i;
  849.    long                  ulBytesRead;
  850.  
  851.  
  852.    memset ( &lpWaveSet,
  853.             0,
  854.             sizeof( MCI_WAVE_SET_PARMS ) );
  855.  
  856.    /* Open the Wave File MyWave.Wav for Reading */
  857.    hmmioFileHandle = mmioOpen(WAVE_FILE_NAME,
  858.                              (PMMIOINFO) NULL,
  859.                              MMIO_READ);
  860.  
  861.    /* If the Wave File could not be opened */
  862.    if (!hmmioFileHandle)
  863.       {
  864.  
  865.       ShowAMessage(
  866.          IDS_ERROR_TITLE,
  867.          IDS_CANT_OPEN_WAVE,
  868.          MB_OK | MB_INFORMATION | MB_MOVEABLE | MB_HELP |
  869.          MB_APPLMODAL,
  870.          FALSE );
  871.  
  872.       return ( TRUE );
  873.       }
  874.  
  875.    /*
  876.     * Get the Header Information for the file so that we can set the channels,
  877.     * Samples Per Second and Bits Per Sample to play the memory playlist.
  878.     */
  879.  
  880.    ulReturn = mmioGetHeader(hmmioFileHandle,
  881.                             (PVOID) &mmHeader,
  882.                             sizeof(MMAUDIOHEADER),
  883.                             (PLONG) &ulBytesRead,
  884.                             (ULONG) NULL,
  885.                             (ULONG) NULL);
  886.    if (ulReturn != 0 )
  887.      return ( ulReturn );
  888.  
  889.    /* Set the WaveSet Structure */
  890.  
  891.    lpWaveSet.ulLevel = 100;
  892.    lpWaveSet.ulSamplesPerSec = mmHeader.mmXWAVHeader.WAVEHeader.ulSamplesPerSec;
  893.    lpWaveSet.usBitsPerSample = mmHeader.mmXWAVHeader.WAVEHeader.usBitsPerSample;
  894.    lpWaveSet.usChannels = mmHeader.mmXWAVHeader.WAVEHeader.usChannels;
  895.    lpWaveSet.ulAudio = MCI_SET_AUDIO_ALL;
  896.    lpWaveSet.hwndCallback = (HWND) NULL;
  897.  
  898.    /* Set the Channels for the MCD */
  899.    ulReturn
  900.         = mciSendCommand(usWaveDeviceId,
  901.                          MCI_SET,
  902.                          MCI_WAIT | MCI_WAVE_SET_CHANNELS,
  903.                          (PVOID) &lpWaveSet,
  904.                          (USHORT)NULL);
  905.    if (ulReturn != 0 )
  906.      return ( ulReturn );
  907.  
  908.    /* Set the Samples Per Second */
  909.    ulReturn
  910.         = mciSendCommand(usWaveDeviceId,
  911.                          MCI_SET,
  912.                          MCI_WAIT | MCI_WAVE_SET_SAMPLESPERSEC,
  913.                          (PVOID) &lpWaveSet,
  914.                          (USHORT)NULL);
  915.  
  916.    if (ulReturn != 0 )
  917.      return ( ulReturn );
  918.  
  919.    /* Set the Bits per Sample */
  920.    ulReturn
  921.         = mciSendCommand(usWaveDeviceId,
  922.                          MCI_SET,
  923.                          MCI_WAIT | MCI_WAVE_SET_BITSPERSAMPLE,
  924.                          (PVOID) &lpWaveSet,
  925.                          (USHORT)NULL);
  926.  
  927.    if (ulReturn != 0 )
  928.      return ( ulReturn );
  929.  
  930.  
  931.   /* From 0 - MAXBUFF, fill the memory Playlist buffer with the wave file. */
  932.  
  933.    for (i=0; i<MAXBUFF; i++)
  934.    {
  935.  
  936.      ulBytesRead =
  937.            mmioRead(hmmioFileHandle,
  938.                     (HPSTR) achDataBuffer[i],
  939.                     MAXSIZE);
  940.      /*
  941.       * If the end of the wave file is reached then Seek to the starting
  942.       * of the wave file and start reading the wave into the appropriate
  943.       * buffer
  944.      */
  945.      if (ulBytesRead < MAXSIZE)
  946.         {
  947.          mmioSeek(hmmioFileHandle, 0, SEEK_SET);
  948.  
  949.          ulBytesRead =
  950.            mmioRead(hmmioFileHandle,
  951.                     (HPSTR) achDataBuffer[i],
  952.                     MAXSIZE);
  953.          }
  954.  
  955.  
  956.    }
  957.  
  958.  
  959.    /*
  960.     * Create the thread that will maintain the playlist buffer
  961.     */
  962.    fEndPlay = FALSE;
  963.    if ( DosCreateThread ( &tidPlayThread,
  964.                          (PFNTHREAD) PlayThread,
  965.                          0L, 0L, 8192L))
  966.       return ( TRUE );
  967.  
  968.    return ( FALSE );
  969.  
  970. }
  971.  
  972.  
  973.  
  974.  
  975.  
  976.  
  977.  
  978. /*************************************************************************
  979.  *   Name PlayThread
  980.  *
  981.  *   Description:    This thread first starts the playlist by sending
  982.  *                   an MCI_PLAY command. The thread then executes a
  983.  *                   DosWaitEventSem using the first semaphore in the
  984.  *                   playlist. When the first buffer in the playlist is
  985.  *                   consumed, this semaphore gets posted by the
  986.  *                   SEMPOST_OPERATION command in the playlist. This is
  987.  *                   the queue to begin refilling this buffer.
  988.  *                   Once the buffer is full, the thread repeates the
  989.  *                   same procedure for the next semaphore. This
  990.  *                   procedure is repeated for each semaphore until
  991.  *                   each buffer has been refilled and then starts over
  992.  *                   with the first semaphore.
  993.  *                     In this way, the entire wav file is played
  994.  *                   continuously until the user either closes the
  995.  *                   application or selects the stop button.
  996.  *
  997.  *
  998.  *
  999.  *************************************************************************/
  1000.  
  1001. VOID  APIENTRY PlayThread ( ULONG parm1 )
  1002. {
  1003.  
  1004.    ULONG    ulBytesRead;
  1005.    ULONG    ulBufferNum;
  1006.    ULONG    ulPostCount;
  1007.    ULONG    ulReturn;
  1008.    MCI_PLAY_PARMS        mciPlayParameters;
  1009.  
  1010.  
  1011.  
  1012.    mciPlayParameters.hwndCallback =  hwndDiag;
  1013.  
  1014.    /*
  1015.     * Send the Play Command to begin the playing of the memory playlist.
  1016.     */
  1017.    ulReturn = mciSendCommand(usWaveDeviceId,
  1018.                              MCI_PLAY,
  1019.                              MCI_NOTIFY,
  1020.                              (PVOID) &mciPlayParameters,
  1021.                              0);
  1022.  
  1023.    /*
  1024.     * Loop until the playlist is stopped.
  1025.     */
  1026.    while( !fEndPlay )
  1027.    {
  1028.  
  1029.       for( ulBufferNum = 0; ulBufferNum < MAXBUFF; ulBufferNum++ )
  1030.       {
  1031.  
  1032.          /*
  1033.           * Use DosWaitEventSem to pause util the playlist plays this
  1034.           * buffer. Then refill the buffer and post the semaphore.
  1035.           */
  1036.          ulReturn = DosWaitEventSem ( hevSem[ulBufferNum], 5000L );
  1037.  
  1038.          DosResetEventSem ( hevSem[ulBufferNum], &ulPostCount );
  1039.  
  1040.          if( fEndPlay ) break;
  1041.  
  1042.             /*
  1043.              * Read the Next MAXSIZE bytes of the wave file
  1044.              */
  1045.             ulBytesRead =
  1046.                    mmioRead(hmmioFileHandle,
  1047.                             (HPSTR) achDataBuffer[ulBufferNum],
  1048.                             MAXSIZE);
  1049.  
  1050.  
  1051.             /*
  1052.              * If we have reached the end of the wave file then set the file marker
  1053.              * to the begining of the file and start reading into the bufferno.
  1054.              * This causes the continuous filling and playing of the data buffer
  1055.              * again and again as long as the END push button is not pressed.
  1056.              * The wave file is going to keep on playing without any interruptions
  1057.              * util ther user selects the stop button.
  1058.              */
  1059.             if (ulBytesRead < MAXSIZE)
  1060.               {
  1061.                /* Seek to the starting of the wave file */
  1062.                mmioSeek(hmmioFileHandle, 0, SEEK_SET);
  1063.  
  1064.                /* Read the Next MAXSIZE bytes of the wave file */
  1065.                mmioRead(hmmioFileHandle,
  1066.                        (HPSTR) achDataBuffer[ulBufferNum],
  1067.                        MAXSIZE);
  1068.  
  1069.  
  1070.               }
  1071.  
  1072.  
  1073.       } /* End of for loop */
  1074.  
  1075.  
  1076.    } /* End of while loop */
  1077.  
  1078.  
  1079. }   /* End of function PlayThread */
  1080.  
  1081.