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