home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / mmpm21tk.zip / TK / ADMCT / AUDIOSUB.C < prev    next >
C/C++ Source or Header  |  1993-04-26  |  59KB  |  1,816 lines

  1. /*******************************************************************
  2. *
  3. * SOURCE FILE NAME: AUDIOSUB.C
  4. *
  5. * DESCRIPTIVE NAME: Support functions for waveaudio MCI Driver.
  6. *
  7. *              Copyright (c) IBM Corporation  1991, 1993
  8. *                        All Rights Reserved
  9. *
  10. * NOTES: This source illustrates the following concepts.
  11. *         A. Correct processing of notifications.
  12. *         B. Handling calls the are neither MCI_WAIT or
  13. *            MCI_NOTIFY (PostMDMMessage).
  14. *         C.
  15. *         D. Using mmioGetHeader to obtain audio settings from a file (GetHeader).
  16. *         E. Creating a playlist stream (AssociatePlaylist).
  17. *         F. Installing an IO Proc (InstallIOProc).
  18. *         G. Communicating with IO Procs with different capabilites (OpenFile).
  19. *         H. Processing audio files with various file formats (OpenFile).
  20. *         H. Time format conversion (ConvertToMM + ConvertTimeFormat).
  21. *         I. Creating an SPI stream (CreateNAssociateStream)
  22. *         J. Associating an SPI stream (CreateNAssociateStream)
  23. *         I. Setting an event for use in play to/record to (DoTillEvent).
  24.  
  25. * FUNCTION: PostMDMMessage
  26. *           InstallIOProc
  27. *           OpenFile
  28. *           ConvertToMM
  29. *           ConvertTimeUnits
  30. *           CreateNAssocStream
  31. *           DoTillEvent
  32. *
  33. *********************** END OF SPECIFICATIONS ***********************/
  34.  
  35. #define INCL_BASE
  36. #define INCL_DOSMODULEMGR
  37. #define INCL_DOSSEMAPHORES
  38.  
  39. #include <os2.h>                        // OS2 defines.
  40. #include <string.h>                     // String functions.
  41. #include <os2medef.h>                   // MME includes files.
  42. #include <math.h>                       // Standard Math Lib
  43. #include <stdlib.h>                     // Standard Library
  44. #include <audio.h>                      // Audio Device defines
  45. #include <ssm.h>                        // SSM spi includes.
  46. #include <meerror.h>                    // MM Error Messages.
  47. #include <mmioos2.h>                    // MMIO Include.
  48. #include <mcios2.h>                     // MM System Include.
  49. #include <mmdrvos2.h>                   // MCI Driver include.
  50. #include <mcd.h>                        // AudioIFDriverInterface.
  51. #include <hhpheap.h>                    // Heap Manager Definitions
  52. #include <admcdat.h>
  53. #include <qos.h>
  54. #include <audiomcd.h>                   // Component Definitions.
  55. #include <admcfunc.h>
  56.  
  57. /********************* START OF SPECIFICATIONS *******************************
  58. *
  59. * SUBROUTINE NAME: DestroyStream()
  60. *
  61. * DESCRIPTIVE NAME:
  62. *
  63. * FUNCTION: call SpiDestroyStream
  64. *
  65. *
  66. * NOTES:
  67. * ENTRY POINTS:
  68. *
  69. * INPUT:
  70. *
  71. * EXIT-NORMAL: Return Code 0.
  72. *
  73. * EXIT_ERROR:  Error Code.
  74. *
  75. * EFFECTS:
  76. *
  77. * INTERNAL REFERENCES: None
  78. *
  79. * EXTERNAL REFERENCES: None
  80. *
  81. *********************** END OF SPECIFICATIONS *******************************/
  82.  
  83. RC DestroyStream ( HSTREAM   *phStream)
  84. {
  85.  
  86.   ULONG ulrc = MCIERR_SUCCESS;
  87.  
  88.   /************************************
  89.   * Call SpiDestroyStream
  90.   *************************************/
  91.   if ( *phStream != (ULONG) NULL)
  92.      {
  93.      ulrc = SpiDestroyStream ( *phStream);
  94.      }
  95.  
  96.   /* Ensure that this stream is removed from our instance */
  97.  
  98.   *phStream = 0;
  99.  
  100.   return ulrc;
  101. }
  102.  
  103.  
  104.  
  105. /********************* START OF SPECIFICATIONS *******************************
  106. *
  107. * SUBROUTINE NAME: PostMDMMessage()
  108. *
  109. * DESCRIPTIVE NAME:
  110. *
  111. * FUNCTION: This function informs the caller that a given command
  112. *           has completed (either succesfully or with an error).
  113. *           All MCI functions that this MCD handles process their
  114. *           notifications here.
  115. *
  116. *           This function uses mdmDriverNotify to inform the caller
  117. *           of completion.
  118. *
  119. *
  120. * NOTES:
  121. * ENTRY POINTS:
  122. *
  123. * INPUT:
  124. *
  125. * EXIT-NORMAL: MCIERR_SUCCESS.
  126. *
  127. * EXIT_ERROR:  Error Code.
  128. *
  129. * EFFECTS:
  130. *
  131. * INTERNAL REFERENCES:
  132. *
  133. * EXTERNAL REFERENCES: mdmDriverNotify
  134. *
  135. *********************** END OF SPECIFICATIONS *******************************/
  136.  
  137. RC PostMDMMessage ( ULONG                ulErrCode,
  138.                     USHORT               usMessage,
  139.                     FUNCTION_PARM_BLOCK  *pFuncBlock)
  140.  
  141. {
  142.  
  143.   USHORT  usNotifyType;
  144.   USHORT  usUserParm;
  145.   HWND    hWnd;
  146.  
  147.  
  148.  
  149.   /***************************************************************
  150.   * Determine the MCI Notification Code for this message
  151.   ****************************************************************/
  152.  
  153.   switch ( ULONG_LOWD(ulErrCode) )
  154.   {
  155.  
  156.   case MCI_NOTIFY_SUCCESSFUL:
  157.         usNotifyType = MCI_NOTIFY_SUCCESSFUL;
  158.        break;
  159.  
  160.   case MCI_NOTIFY_SUPERSEDED:
  161.         usNotifyType = MCI_NOTIFY_SUPERSEDED;
  162.        break;
  163.  
  164.   case MCI_NOTIFY_ABORTED:
  165.         usNotifyType = MCI_NOTIFY_ABORTED;
  166.        break;
  167.  
  168.   default:
  169.         usNotifyType = (USHORT)ulErrCode;
  170.        break;
  171.   }
  172.  
  173.  
  174.   /*******************************************************************
  175.   * MCI Messages PLAY and RECORD call this routine to notify the
  176.   * application asynchronously. The user parameter from the instance
  177.   * block is used for notifying play/record message status. All
  178.   * other messages use the function block user parameter.
  179.   *******************************************************************/
  180.  
  181.   if (usMessage != MCI_PLAY && usMessage != MCI_RECORD)
  182.      {
  183.      usUserParm = pFuncBlock->usUserParm;
  184.      hWnd = pFuncBlock->hwndCallBack;
  185.      }
  186.   else
  187.      {
  188.      usUserParm = pFuncBlock->pInstance->usUserParm;
  189.      hWnd = pFuncBlock->pInstance->hwndCallBack;
  190.      }
  191.  
  192.   /* Inform the application of the event */
  193.  
  194.   mdmDriverNotify (pFuncBlock->pInstance->usWaveDeviceID,
  195.                    hWnd,
  196.                    MM_MCINOTIFY,
  197.                    usUserParm,
  198.                    MAKEULONG (usMessage, usNotifyType));
  199.  
  200.  
  201.   return ( MCIERR_SUCCESS );
  202. }
  203.  
  204.  
  205.  
  206.  
  207. /********************* START OF SPECIFICATIONS *******************************
  208. *
  209. * SUBROUTINE NAME:              SetAudioDevice()
  210. *
  211. * DESCRIPTIVE NAME:
  212. *
  213. * FUNCTION: Set AudioDevice Attributes
  214. *
  215. *
  216. * NOTES:   This Request is Routed to the Audio Device Via
  217. *          the AudioIf Interface.
  218. *
  219. * ENTRY POINTS:
  220. *     LINKAGE:   CALL FAR
  221. *
  222. * INPUT:
  223. *
  224. * EXIT-NORMAL: Return Code 0.
  225. *
  226. * EXIT_ERROR:  Error Code.
  227. *
  228. * EFFECTS:
  229. *
  230. * INTERNAL REFERENCES: AudioIFDriverEntry().
  231. *
  232. * EXTERNAL REFERENCES:
  233. *
  234. *********************** END OF SPECIFICATIONS *******************************/
  235.  
  236. RC SetAudioDevice (INSTANCE             *ulpInstance,
  237.                    PMCI_WAVE_SET_PARMS  pSetParms,
  238.                    ULONG                ulParam1 )
  239.  
  240.  
  241. {
  242.  
  243.   ULONG       ulrc;
  244.   extern     HID                 hidBTarget;
  245.  
  246.  
  247.   /*---------------------------------------------- 
  248.   * When we perform this command, it is possible
  249.   * that we could lose use (i.e. the amp mixer may
  250.   * change resource units calling MDM on this
  251.   * thread AFTER the MCIDRV_SAVE came through.
  252.   * Therefore, release
  253.   * the data access semaphore so that MCIDRV_SAVE
  254.   * will not hang.
  255.   *-----------------------------------------------*/
  256.  
  257.   MCD_ExitCrit( ulpInstance );
  258.  
  259.   /*********************************
  260.    * Send A Set Across the AudioIF
  261.    * Driver Interface
  262.    ********************************/
  263.  
  264.    ulrc = ulpInstance->pfnVSD (&MIX,
  265.                                MCI_SET,
  266.                                ulParam1,
  267.                                (LONG)pSetParms,
  268.                                0L);
  269.    /*--------------------------------------------------
  270.    * It is no longer possible to lose use.  Therefore,
  271.    * reacquire the semaphore.  Note: we will always be
  272.    * able to acquire this since it is protected by the
  273.    * save access semaphore which everyone goes through
  274.    * besides save and close_exit.
  275.    *--------------------------------------------------*/
  276.    MCD_EnterCrit( ulpInstance );
  277.  
  278.    /*---------------------------------------------------------
  279.    * Retrieve the block sizes from the stream protocol.  We will
  280.    * use these values for time conversions and seeks.
  281.    *-------------------------------------------------------------*/
  282.  
  283.    if ( !ulrc )
  284.       {
  285.       ulpInstance->StreamInfo.SpcbKey.ulDataType    = AMPMIX.ulDataType;
  286.       ulpInstance->StreamInfo.SpcbKey.ulDataSubType = AMPMIX.ulSubType;
  287.       ulpInstance->StreamInfo.SpcbKey.ulIntKey = 0;
  288.  
  289.       /*------------------------------------------------------
  290.       * Get certain streaming information from the stream handler
  291.       * we have loaded.
  292.       *--------------------------------------------------------*/
  293.       ulrc = SpiGetProtocol( hidBTarget, 
  294.                              &ulpInstance->StreamInfo.SpcbKey,
  295.                              &ulpInstance->StreamInfo.spcb );
  296.  
  297.       if ( ulrc )
  298.          {
  299.          return ( ulrc );
  300.          }
  301.  
  302.       ulpInstance->ulBytes   = ulpInstance->StreamInfo.spcb.ulBytesPerUnit;
  303.       ulpInstance->ulMMTime  = ulpInstance->StreamInfo.spcb.mmtimePerUnit;
  304.  
  305.       }
  306.  
  307.    return (ulrc);
  308. }
  309.  
  310. /********************* START OF SPECIFICATIONS *********************
  311. *
  312. * SUBROUTINE NAME:              AbortWait
  313. *
  314. * DESCRIPTIVE NAME: Release a Wait Thread
  315. *
  316. * FUNCTION: Release a wait Thread
  317. *
  318. * NOTES:
  319. *
  320. * ENTRY POINTS:
  321. *
  322. * INPUT: MCI_INFO message.
  323. *
  324. * EXIT-NORMAL: Return Code 0.
  325. *
  326. * EXIT_ERROR:  Error Code.
  327. *
  328. * EFFECTS:
  329. *
  330. * INTERNAL REFERENCES:
  331. *
  332. * EXTERNAL REFERENCES:
  333. *
  334. *********************** END OF SPECIFICATIONS **********************/
  335. RC AbortWaitOperation (INSTANCE * ulpInstance)
  336.  {
  337.  
  338.   ULONG           ulrc;
  339.   ULONG           lCnt;
  340.  
  341.   /*******************************************************
  342.   * Check to see if the wait pending flag is set.
  343.   * If this flag is set, then there is another thread
  344.   * processing a command with the MCI_WAIT flag.  Since
  345.   * it is done with a wait, there is no "official" means
  346.   * to abort it.  Therefore, we will perform an artificial
  347.   * SpiStop on the stream so the WAIT thread will think
  348.   * that it is finished processing.
  349.   ********************************************************/
  350.  
  351.   if (ulpInstance->usWaitPending == TRUE)
  352.      {
  353.      if ( ulpInstance->usWaitMsg != MCI_SAVE )
  354.         {
  355.         DosResetEventSem (ulpInstance->hEventSem, &lCnt);
  356.         
  357.         ulrc = SpiStopStream ( ulpInstance->StreamInfo.hStream,
  358.                                SPI_STOP_DISCARD);
  359.         
  360.         /*********************************************
  361.         * Wait for the Stopped event . Notice that
  362.         * more than one thread will be released and
  363.         * free to run as a result of the stop event
  364.         *********************************************/
  365.         
  366.         if (!ulrc)
  367.            DosWaitEventSem (ulpInstance->hEventSem, -1 );
  368.         }
  369.  
  370.      } /* If there is a wait operation alive */
  371.  
  372.   return (MCIERR_SUCCESS);
  373.  
  374. } /* AbortWaitOperation */
  375.  
  376.  
  377. /********************* START OF SPECIFICATIONS *********************
  378. *
  379. * SUBROUTINE NAME:      GetAudioHeader
  380. *
  381. * DESCRIPTIVE NAME: Get Audio Header From The IO Proc.
  382. *
  383. * FUNCTION: Obtain Wave Header information.
  384. *
  385. * NOTES:
  386. *
  387. * ENTRY POINTS:
  388. *     LINKAGE:   CALL FAR
  389. *
  390. * INPUT: MCI_INFO message.
  391. *
  392. * EXIT-NORMAL: Return Code 0.
  393. *
  394. * EXIT_ERROR:  Error Code.
  395. *
  396. * NOTES: This function will usually be called either when
  397. *        the file is first loaded or after a record (which
  398. *        can change the settings of the file--like the length).
  399. *
  400. * INTERNAL REFERENCES:
  401. *
  402. * EXTERNAL REFERENCES: mmioGetHeader ()   -  MMIO API
  403. *
  404. *********************** END OF SPECIFICATIONS **********************/
  405. RC   GetAudioHeader (INSTANCE * ulpInstance)
  406. {
  407.   ULONG  ulrc;
  408.   LONG   BytesRead;
  409.  
  410.   /*******************************************************
  411.   * A streaming MCD should utilize MMIO to perform all
  412.   * file manipulations.  If we use MMIO, then the MCD
  413.   * will be free from file dependencies (i.e. if a RIFF
  414.   * io proc or a VOC io proc is loaded will be irrelevant.
  415.   ********************************************************/
  416.  
  417.   ulrc = mmioGetHeader ( ulpInstance->hmmio,
  418.                          (PVOID) &ulpInstance->mmAudioHeader ,
  419.                          sizeof( ulpInstance->mmAudioHeader ),
  420.                          (PLONG) &BytesRead,
  421.                          (ULONG) NULL,
  422.                          (ULONG) NULL);
  423.  
  424.   if ( ulrc == MMIO_SUCCESS )
  425.       {
  426.  
  427.       /******************************************
  428.       * Copy the data from the call into the instance
  429.       * so that we can set the amp/mixer up with the
  430.       * values that the file specifies.
  431.       ******************************************/
  432.  
  433.       AMPMIX.sMode            = WAVEHDR.usFormatTag;
  434.       AMPMIX.sChannels        = WAVEHDR.usChannels;
  435.       AMPMIX.lSRate           = WAVEHDR.ulSamplesPerSec;
  436.       AMPMIX.lBitsPerSRate    = WAVEHDR.usBitsPerSample;
  437.       ulpInstance->ulDataSize = XWAVHDR.ulAudioLengthInBytes;
  438.       AMPMIX.ulBlockAlignment = ( ULONG )WAVEHDR.usBlockAlign;
  439.       ulpInstance->ulAverageBytesPerSec = WAVEHDR.usChannels * WAVEHDR.ulSamplesPerSec * ( WAVEHDR.usBitsPerSample / 8 );
  440.  
  441.       } /* SuccesFul GetHeader */
  442.  
  443.     else
  444.       {
  445.       ulrc = mmioGetLastError( ulpInstance->hmmio );
  446.  
  447.       }
  448.       return (ulrc);
  449.  
  450. }  /* GetAudioHeader */
  451.  
  452. /********************* START OF SPECIFICATIONS *********************
  453. *
  454. * SUBROUTINE NAME: SetAudioHeader
  455. *
  456. * DESCRIPTIVE NAME: Set Audio Header in a file.
  457. *
  458. * FUNCTION: Save device settings (like bits/sample) in a file.
  459. *
  460. * NOTES:
  461. *
  462. * ENTRY POINTS:
  463. *     LINKAGE:   CALL FAR
  464. *
  465. * INPUT: MCI_INFO message.
  466. *
  467. * EXIT-NORMAL: MCIERR_SUCCESS.
  468. *
  469. * EXIT_ERROR:  Error Code.
  470. *
  471. * EFFECTS:
  472. *
  473. * INTERNAL REFERENCES:
  474. *
  475. * EXTERNAL REFERENCES: mmioGetHeader ()   -  MMIO API
  476. *
  477. *********************** END OF SPECIFICATIONS **********************/
  478. RC   SetAudioHeader (INSTANCE * ulpInstance)
  479. {
  480.   ULONG  ulrc;
  481.   LONG   lBogus;
  482.  
  483.   /* Fill in the necessary parameters for the setheader call */
  484.  
  485.   WAVEHDR.usFormatTag       = AMPMIX.sMode;
  486.   WAVEHDR.usChannels        = AMPMIX.sChannels;
  487.   WAVEHDR.ulSamplesPerSec   = AMPMIX.lSRate;
  488.   XWAVHDR.ulAudioLengthInMS = 0;
  489.   WAVEHDR.usBitsPerSample   = (USHORT) AMPMIX.lBitsPerSRate;
  490.   WAVEHDR.usBlockAlign      = (USHORT) AMPMIX.ulBlockAlignment;
  491.   WAVEHDR.ulAvgBytesPerSec  = ulpInstance->ulAverageBytesPerSec;
  492.  
  493.   /***********************************************
  494.   * Tell the io proc that is manipulating the file
  495.   * to set the file header with the values that
  496.   * we are sending.
  497.   ***********************************************/
  498.  
  499.   ulrc = mmioSetHeader( ulpInstance->hmmio,
  500.                         &ulpInstance->mmAudioHeader,
  501.                         sizeof( MMAUDIOHEADER ),
  502.                         &lBogus,
  503.                         0,
  504.                         0 );
  505.  
  506.  
  507.  
  508.   if (ulrc)
  509.      {
  510.      /*------------------------------------------
  511.      * MMIO returns failure (-1), GetLastError
  512.      * should be called for additional info
  513.      *-----------------------------------------*/
  514.  
  515.      return ( mmioGetLastError( ulpInstance->hmmio ) );
  516.      }
  517.  
  518.  
  519.   return (ulrc);
  520. } /* SetAudioHeader
  521.  
  522.  
  523. /********************* START OF SPECIFICATIONS *******************************
  524. *
  525. * SUBROUTINE NAME: SetWaveDeviceDefaults()
  526. *
  527. * DESCRIPTIVE NAME:
  528. *
  529. * FUNCTION: Allocate Memory for MCI Message parameter.
  530. *
  531. *
  532. * NOTES:
  533. * ENTRY POINTS:
  534. *
  535. * INPUT:
  536. *
  537. * EXIT-NORMAL: Return Code 0.
  538. *
  539. * EXIT_ERROR:  Error Code.
  540. *
  541. * EFFECTS:
  542. *
  543. * INTERNAL REFERENCES:
  544. *
  545. * EXTERNAL REFERENCES:
  546. *
  547. *********************** END OF SPECIFICATIONS *******************************/
  548. VOID SetWaveDeviceDefaults (INSTANCE * ulpInstance, ULONG ulOperation)
  549. {
  550.  
  551.   AMPMIX.sMode            = ulpInstance->lDefaultFormat;   // DATATYPE_WAVEFORM
  552.   AMPMIX.lSRate           = ulpInstance->lDefaultSRate;    // 22 Khz
  553.   AMPMIX.ulOperation      = ulOperation;                   // Play or Record
  554.   AMPMIX.sChannels        = ulpInstance->lDefaultChannels; // Stereo
  555.   AMPMIX.lBitsPerSRate    = ulpInstance->lDefaultBPS;      // 8 bits/sam
  556.   AMPMIX.ulBlockAlignment = DEFAULT_BLOCK_ALIGN;           // bogus value
  557.   ulpInstance->ulAverageBytesPerSec =  ulpInstance->lDefaultChannels *
  558.                                        ( ulpInstance->lDefaultBPS / 8 ) *
  559.                                        ulpInstance->lDefaultSRate;
  560.   AMPMIX.ulFlags = FIXED|VOLUME|TREBLE|BASS;
  561. }
  562.  
  563. /********************* START OF SPECIFICATIONS *******************************
  564. *
  565. * SUBROUTINE NAME: VSDInstToWaveSetParms
  566. *
  567. * DESCRIPTIVE NAME:
  568. *
  569. * FUNCTION: copy parameters from VSD Instance struct to MCI_WAVE_SET_PARMS
  570. *
  571. *
  572. * NOTES:
  573. * ENTRY POINTS:
  574. *     LINKAGE:   CALL FAR
  575. *
  576. * INPUT:
  577. *
  578. * EXIT-NORMAL: Return Code 0.
  579. *
  580. * EXIT_ERROR:  Error Code.
  581. *
  582. * EFFECTS:
  583. *
  584. * EXTERNAL REFERENCES:
  585. *
  586. *********************** END OF SPECIFICATIONS *******************************/
  587. VOID VSDInstToWaveSetParms ( PMCI_WAVE_SET_PARMS pWaveSetParms,
  588.                              INSTANCE            *ulpInstance)
  589. {
  590.  
  591.   pWaveSetParms->usChannels       = AMPMIX.sChannels;
  592.   pWaveSetParms->usFormatTag      = AMPMIX.sMode;
  593.   pWaveSetParms->ulSamplesPerSec  = AMPMIX.lSRate;
  594.   pWaveSetParms->usBitsPerSample  = (USHORT) AMPMIX.lBitsPerSRate;
  595. }
  596.  
  597.  
  598. /********************* START OF SPECIFICATIONS *******************************
  599. *
  600. * SUBROUTINE NAME:AssocMemPlayToAudioStrm ()
  601. *
  602. * DESCRIPTIVE NAME:
  603. *
  604. * FUNCTION: Associate The Memory Play List Stream Handler with
  605. *           the currently connected audio stream handler.
  606. *
  607. *
  608. * NOTES:
  609. * ENTRY POINTS:
  610. *
  611. * INPUT:
  612. *
  613. * EXIT-NORMAL: MCIERR_SUCCESS.
  614. *
  615. * EXIT_ERROR:  Error Code.
  616. *
  617. * EFFECTS:
  618. *
  619. * INTERNAL REFERENCES:SpiAssociate()
  620. *
  621. * EXTERNAL REFERENCES:
  622. *
  623. *********************** END OF SPECIFICATIONS *******************************/
  624. RC AssociatePlayList (INSTANCE * ulpInstance, ULONG Operation)
  625.  
  626. {
  627.   ULONG ulrc;
  628.  
  629.   /******************************************************
  630.   * Fill in the Playlist Access Control Block (ACB)
  631.   * with the correct information to set up a stream.
  632.   ******************************************************/
  633.  
  634.   ulpInstance->StreamInfo.acbPlayList.ulObjType   = ACBTYPE_MEM_PLAYL;
  635.   ulpInstance->StreamInfo.acbPlayList.ulACBLen    = sizeof(ACB_MEM_PLAYL);
  636.   ulpInstance->StreamInfo.acbPlayList.pMemoryAddr = (PVOID)ulpInstance->pPlayList;
  637.  
  638.   /*********************************************
  639.   * If this is a playback request, then the
  640.   * memory stream handler will be the source
  641.   * and the audio stream handler will be the
  642.   * target.
  643.   *********************************************/
  644.  
  645.   if (Operation == PLAY_STREAM)
  646.       {
  647.       ulrc = SpiAssociate (ulpInstance->StreamInfo.hStream,
  648.                            ulpInstance->StreamInfo.hidASource,
  649.                            (PVOID) &(ulpInstance->StreamInfo.acbPlayList));
  650.       }
  651.  
  652.   /*********************************************
  653.   * If this is record request, then the
  654.   * memory stream handler will be the target
  655.   * and the audio stream handler will be the
  656.   * source (i.e. we are recording to memory)
  657.   *********************************************/
  658.  
  659.     else
  660.       {
  661.       ulrc = SpiAssociate ( ulpInstance->StreamInfo.hStream,
  662.                             ulpInstance->StreamInfo.hidATarget,
  663.                             (PVOID)&ulpInstance->StreamInfo.acbPlayList);
  664.       }
  665.  
  666.   return (ulrc);
  667.  
  668. } /* AssociatePlaylist */
  669.  
  670. /************************** START OF SPECIFICATIONS ***********************
  671. *                                                                          *
  672. * SUBROUTINE NAME: MCD_EnterCrit                                           *
  673. *                                                                          *
  674. * FUNCTION: This routine acquires access to the common areas via a         *
  675. *           system semaphore.                                              *
  676. *                                                                          *
  677. * NOTES:    This routine contains OS/2 system specific functions.          *
  678. *           DosRequestMutexSem                                             *
  679. *                                                                          *
  680. * INPUT:    None.                                                          *
  681. *                                                                          *
  682. * OUTPUT:   rc = error return code is failure to acquire semaphore.        *
  683. *                                                                          *
  684. * SIDE EFFECTS: Access acquired.                                           *
  685. *                                                                          *
  686. *************************** END OF SPECIFICATIONS **************************/
  687.  
  688. ULONG MCD_EnterCrit (INSTANCE * ulpInstance )
  689. {
  690.   /*****************************************************************
  691.   * Request the system semaphore for the common data area.
  692.   *****************************************************************/
  693.  
  694.   return( DosRequestMutexSem (ulpInstance->hmtxDataAccess, -1));  // wait for semaphore
  695. }
  696.  
  697.  
  698.  
  699.  
  700.  
  701. /************************** START OF SPECIFICATIONS ***********************
  702. *                                                                          *
  703. * SUBROUTINE NAME: MCD_ExitCrit                                            *
  704. *                                                                          *
  705. * FUNCTION: This routine releases access to the common areas via a         *
  706. *           system semaphore.                                              *
  707. *                                                                          *
  708. * NOTES:    This routine contains OS/2 system specific functions.          *
  709. *           DosReleaseMutexSem                                             *
  710. *                                                                          *
  711. * INPUT:    None.                                                          *
  712. *                                                                          *
  713. * OUTPUT:   rc = error return code is failure to release semaphore.        *
  714. *                                                                          *
  715. * SIDE EFFECTS: Access released.                                           *
  716. *                                                                          *
  717. *************************** END OF SPECIFICATIONS **************************/
  718.  
  719. ULONG MCD_ExitCrit (INSTANCE * ulpInstance)
  720. {
  721.   /************************************************************
  722.   * Release the system semaphore for the common data area.
  723.   *************************************************************/
  724.  
  725.   return( DosReleaseMutexSem (ulpInstance->hmtxDataAccess));
  726. }
  727.  
  728.  
  729. /************************** START OF SPECIFICATIONS ***********************
  730. *                                                                          *
  731. * SUBROUTINE NAME: MCD_EnterCrit                                           *
  732. *                                                                          *
  733. * FUNCTION: This routine acquires access to the common areas via a         *
  734. *           system semaphore.                                              *
  735. *                                                                          *
  736. * NOTES:    This routine contains OS/2 system specific functions.          *
  737. *           DosRequestMutexSem                                             *
  738. *                                                                          *
  739. * INPUT:    None.                                                          *
  740. *                                                                          *
  741. * OUTPUT:   rc = error return code is failure to acquire semaphore.        *
  742. *                                                                          *
  743. * SIDE EFFECTS: Access acquired.                                           *
  744. *                                                                          *
  745. *************************** END OF SPECIFICATIONS **************************/
  746.  
  747. ULONG GetSaveSem (INSTANCE * ulpInstance )
  748. {
  749.   /*****************************************************************
  750.   * Request the system semaphore for MCIDRV_SAVE access
  751.   *****************************************************************/
  752.  
  753.   return( DosRequestMutexSem (ulpInstance->hmtxSaveAccess, -1));  // wait for semaphore
  754. }
  755.  
  756.  
  757.  
  758.  
  759.  
  760. /************************** START OF SPECIFICATIONS ***********************
  761. *                                                                          *
  762. * SUBROUTINE NAME: MCD_ExitCrit                                            *
  763. *                                                                          *
  764. * FUNCTION: This routine releases access to the common areas via a         *
  765. *           system semaphore.                                              *
  766. *                                                                          *
  767. * NOTES:    This routine contains OS/2 system specific functions.          *
  768. *           DosReleaseMutexSem                                             *
  769. *                                                                          *
  770. * INPUT:    None.                                                          *
  771. *                                                                          *
  772. * OUTPUT:   rc = error return code is failure to release semaphore.        *
  773. *                                                                          *
  774. * SIDE EFFECTS: Access released.                                           *
  775. *                                                                          *
  776. *************************** END OF SPECIFICATIONS **************************/
  777.  
  778. ULONG GiveUpSaveSem (INSTANCE * ulpInstance)
  779. {
  780.   /************************************************************
  781.   * Release the system semaphore for MCIDRV_SAVE access.
  782.   *************************************************************/
  783.  
  784.   return( DosReleaseMutexSem (ulpInstance->hmtxSaveAccess));
  785. }
  786.  
  787.  
  788.  
  789.  
  790.  
  791. /************************** START OF SPECIFICATIONS ************************
  792. *                                                                          *
  793. * SUBROUTINE NAME: AcquireProcSem                                          *
  794. *                                                                          *
  795. * FUNCTION: This routine acquires access to the common areas via a         *
  796. *           system semaphore.                                              *
  797. *                                                                          *
  798. * NOTES:    This routine contains OS/2 system specific functions.          *
  799. *           DosRequestMutexSem                                             *
  800. *                                                                          *
  801. * INPUT:    None.                                                          *
  802. *                                                                          *
  803. * OUTPUT:   rc = error return code is failure to acquire semaphore.        *
  804. *                                                                          *
  805. * SIDE EFFECTS: Access acquired.                                           *
  806. *                                                                          *
  807. *************************** END OF SPECIFICATIONS **************************/
  808.  
  809. ULONG AcquireProcSem ( void )
  810. {
  811.   extern HMTX   hmtxProcSem;
  812.  
  813.   /**************************************************************
  814.   * Request the system semaphore for the common data area.
  815.   ***************************************************************/
  816.  
  817.   return( DosRequestMutexSem (hmtxProcSem, -1));
  818. }
  819.  
  820. /************************** START OF SPECIFICATIONS ************************
  821. *                                                                          *
  822. * SUBROUTINE NAME: ReleaseProcSem                                          *
  823. *                                                                          *
  824. * FUNCTION: This routine releases access to the common areas via a         *
  825. *           system semaphore.                                              *
  826. *                                                                          *
  827. * NOTES:    This routine contains OS/2 system specific functions.          *
  828. *           DosReleaseMutexSem                                             *
  829. *                                                                          *
  830. * INPUT:    None.                                                          *
  831. *                                                                          *
  832. * OUTPUT:   rc = error return code is failure to release semaphore.        *
  833. *                                                                          *
  834. * SIDE EFFECTS: Access released.                                           *
  835. *                                                                          *
  836. *************************** END OF SPECIFICATIONS **************************/
  837.  
  838. ULONG ReleaseProcSem ( void )
  839. {
  840.    extern HMTX  hmtxProcSem;
  841.  
  842.   /**********************************************************
  843.   * Release the system semaphore for the common data area.
  844.   ***********************************************************/
  845.  
  846.   return( DosReleaseMutexSem (hmtxProcSem) );
  847. }
  848.  
  849. /********************* START OF SPECIFICATIONS *******************************
  850. *
  851. * SUBROUTINE NAME: CleanUp ()
  852. *
  853. * DESCRIPTIVE NAME:
  854. *
  855. * FUNCTION: Call HhpFreeMem to dealocatte memory from global heap.
  856. *
  857. *
  858. * NOTES:    Release Memory.
  859. * ENTRY POINTS:
  860. *
  861. * INPUT:
  862. *
  863. * EXIT-NORMAL: Return Code 0.
  864. *
  865. * EXIT_ERROR:  Error Code.
  866. *
  867. * EFFECTS:
  868. *
  869. * INTERNAL REFERENCES: HhpFreeMem().
  870. *
  871. * EXTERNAL REFERENCES:
  872. *
  873. *********************** END OF SPECIFICATIONS *******************************/
  874.  
  875. RC CleanUp (PVOID MemToFree)
  876. {
  877.   extern HHUGEHEAP heap;
  878.  
  879.   /****************************
  880.   * Enter Data Critical Section
  881.   *****************************/
  882.   AcquireProcSem ();
  883.  
  884.   /***************************
  885.   * Free Memory off of the heap
  886.   ****************************/
  887.  
  888.   HhpFreeMem (heap, MemToFree);
  889.  
  890.   /****************************
  891.   * Exit Data Critical Section
  892.   *****************************/
  893.  
  894.   ReleaseProcSem ();
  895.  
  896.   return (MCIERR_SUCCESS);
  897.  
  898. } /* CleanUp */
  899.  
  900.  
  901.  
  902.  
  903. /********************* START OF SPECIFICATIONS *******************************
  904. *
  905. * SUBROUTINE NAME: OpenFile
  906. *
  907. * DESCRIPTIVE NAME: OpenFile
  908. *
  909. * FUNCTION: Open Element , Install IO Procs, Get Header Information
  910. *
  911. *
  912. * NOTES:
  913. * ENTRY POINTS:
  914. *     LINKAGE:   CALL FAR
  915. *
  916. * INPUT:
  917. *
  918. * EXIT-NORMAL: Return Code 0.
  919. *
  920. * EXIT_ERROR:  Error Code.
  921. *
  922. * NOTES: Concepts this functions illustrates.
  923. *          A. Why MMIO_TRANSLATE_HEADER is used.
  924. *          B.
  925. *
  926. * INTERNAL REFERENCES: None
  927. *
  928. * EXTERNAL REFERENCES: None
  929. *
  930. *********************** END OF SPECIFICATIONS *******************************/
  931. RC OpenFile(INSTANCE * pInstance, ULONG ulFlags )
  932. {
  933.  
  934.   MMIOINFO         mmioinfo;             // mmioInfo Structure
  935.   MMFORMATINFO     mmformatinfo;         /* io proc cap struct */
  936.   PSZ              pFileName;            // Element Name
  937.   LONG             lNumFormats;          /* Number of format info structs */
  938.  
  939.  
  940.   /********************************
  941.   * Intialize data structures
  942.   ********************************/
  943.  
  944.   ULONG ulrc = MCIERR_SUCCESS;
  945.  
  946.  
  947.    memset( &mmioinfo, '\0', sizeof( MMIOINFO ));
  948.    mmioinfo.fccIOProc = mmioFOURCC( 'W', 'A', 'V', 'E' ) ;
  949.  
  950.  
  951.    /**************************************************
  952.    * Set header translation flag on. It is imporatant
  953.    * that we do this because the loaded io proc has
  954.    * to communicate with us via the standard audio
  955.    * header.  Until we get device capabilities, we
  956.    * must assume that the audio device can handle
  957.    * the raw data.
  958.    **************************************************/
  959.  
  960.    mmioinfo.ulTranslate = MMIO_TRANSLATEHEADER;
  961.  
  962.  
  963.    pFileName = pInstance->pszAudioFile;
  964.    pInstance->fFileExists = FALSE;
  965.  
  966.  
  967.     /********************************************
  968.     * When we called the mmio api for temp files,
  969.     * it returned a DOS handle to the file.  The
  970.     * mmioOpen api allows one to pass in a Dos
  971.     * handle rather than a filename if you place
  972.     * the handle in adwInfo[ 0 ] and make the
  973.     * name NULL.
  974.     *********************************************/
  975.  
  976.     if ( pInstance->ulCreatedName )
  977.        {
  978.        mmioinfo.aulInfo[ 0 ] = pInstance->hTempFile;
  979.        pFileName = ( PSZ ) NULL;
  980.        }
  981.  
  982.     /***********************************************
  983.     * Try to open the file.  Note: the first
  984.     * open attempt will always specifically
  985.     * try to open the file with the RIFF IO Proc.
  986.     * We do this for speed reasons--if this fails
  987.     * we let mmio do an auto identify on the file,
  988.     * mmio will ask every io proc in the system if
  989.     * it can load the file.
  990.     ***********************************************/
  991.  
  992.     pInstance->hmmio = mmioOpen ( pFileName,
  993.                                   &mmioinfo,
  994.                                   ulFlags );
  995.  
  996.     /*********************************************************
  997.     * If we have no file handle--the RIFF IO Proc failed to
  998.     * open the file for one ofthe following reasons:
  999.     *  1. Sharing violation.
  1000.     *  2. Path/File errors.
  1001.     *********************************************************/
  1002.  
  1003.     if ( pInstance->hmmio == (ULONG) NULL )
  1004.         {
  1005.  
  1006.         /*********************************************
  1007.         * We will get a sharing violation if we are
  1008.         * writing to a read-only device (CD), if the
  1009.         * file is readonly or other misc. problems.
  1010.         *********************************************/
  1011.  
  1012.         if (mmioinfo.ulErrorRet == ERROR_ACCESS_DENIED ||
  1013.             mmioinfo.ulErrorRet == ERROR_WRITE_PROTECT ||
  1014.             mmioinfo.ulErrorRet == ERROR_NETWORK_ACCESS_DENIED ||
  1015.             mmioinfo.ulErrorRet == ERROR_SHARING_VIOLATION )
  1016.             {
  1017.  
  1018.             /*********************************************************
  1019.             * If the wave fails the open, we should still try w/o the
  1020.             * exclusive flag so that another IO can possibly load it.
  1021.             * We do this because a sharing violation could occur if
  1022.             * we tried exclusively to open the file and other process
  1023.             * has it open.
  1024.             **********************************************************/
  1025.  
  1026.             ulFlags &= ~MMIO_EXCLUSIVE;
  1027.  
  1028.             pInstance->hmmio = mmioOpen ( pFileName,
  1029.                                           &mmioinfo,
  1030.                                           ulFlags );
  1031.  
  1032.             if ( mmioinfo.ulErrorRet == ERROR_ACCESS_DENIED ||
  1033.                  mmioinfo.ulErrorRet == ERROR_WRITE_PROTECT ||
  1034.                  mmioinfo.ulErrorRet == ERROR_NETWORK_ACCESS_DENIED ||
  1035.                  mmioinfo.ulErrorRet == ERROR_SHARING_VIOLATION )
  1036.                {
  1037.                return MCIERR_FILE_ATTRIBUTE;
  1038.                }
  1039.  
  1040.             pInstance->hmmio = 0;
  1041.  
  1042.             } /* if a file attribute error occurred */
  1043.  
  1044.         /*********************************************
  1045.         * We will get a file not found or an open
  1046.         * failure if the path does not exist, or the
  1047.         * file DNE or the drive is invalid.
  1048.         *********************************************/
  1049.  
  1050.  
  1051.         if (mmioinfo.ulErrorRet == ERROR_FILE_NOT_FOUND ||
  1052.             mmioinfo.ulErrorRet == ERROR_PATH_NOT_FOUND ||
  1053.             mmioinfo.ulErrorRet == ERROR_OPEN_FAILED )
  1054.            {
  1055.            return ( ERROR_FILE_NOT_FOUND );
  1056.            } /* Error File Not Found */
  1057.  
  1058.         /*********************************************
  1059.         * Map OS/2 errors to MCI or MMIO errors
  1060.         *********************************************/
  1061.  
  1062.  
  1063.         if (mmioinfo.ulErrorRet == ERROR_FILENAME_EXCED_RANGE )
  1064.            {
  1065.            return ( MMIOERR_INVALID_FILENAME );
  1066.            } /* Error File Not Found */
  1067.  
  1068.  
  1069. //        /* Ask mmio to get info about the file */
  1070. //
  1071. //        ulrc = mmioIdentifyFile( pFileName,
  1072. //                                 (ULONG) NULL,
  1073. //                                 &mmformatinfo,
  1074. //                                 &fccStorageSystem,
  1075. //                                 0,
  1076. //                                 0 );
  1077. //
  1078. //        /* if the call worked, interegate the io proc */
  1079. //
  1080. //        if ( ulrc == MMIO_SUCCESS )
  1081. //
  1082. //           {
  1083. //           /***********************************************
  1084. //           * If this is a non audio I/O proc, don't open
  1085. //           ************************************************/
  1086. //
  1087. //         if ( mmformatinfo.ulMediaType != MMIO_MEDIATYPE_AUDIO )
  1088. //               {
  1089. //               return (MCIERR_INVALID_MEDIA_TYPE);
  1090. //               }
  1091.  
  1092.            /***********************************************
  1093.            * The current release does not support opening
  1094.            * IO Procs other that RIFF format in write mode.
  1095.            * Therefore, temporary files are impossible.
  1096.            ************************************************/
  1097.            ulFlags = MMIO_READ | MMIO_DENYNONE;
  1098.            pInstance->ulOpenTemp = FALSE;
  1099.  
  1100.  
  1101.            memset( &mmioinfo, '\0', sizeof( mmioinfo ) );
  1102.  
  1103.            // need to find out why a mmioinfo struct cause identify to fail
  1104.  
  1105.            mmioinfo.ulTranslate = MMIO_TRANSLATEDATA;
  1106.            mmioinfo.aulInfo[ 3 ] = MMIO_MEDIATYPE_AUDIO;
  1107.  
  1108.  
  1109.            /* Open the file */
  1110.  
  1111.            pInstance->hmmio = mmioOpen ( pFileName,
  1112.                                          &mmioinfo,
  1113.                                          ulFlags);
  1114.  
  1115.            /* Check for errors--see comments from above */
  1116.  
  1117.            if (pInstance->hmmio == (ULONG) NULL)
  1118.              {
  1119.              if ( mmioinfo.ulErrorRet == MMIOERR_MEDIA_NOT_FOUND )
  1120.                {
  1121.                return  ( MCIERR_INVALID_MEDIA_TYPE );
  1122.                }
  1123.  
  1124.              return  ( mmioinfo.ulErrorRet );
  1125.              }
  1126.  
  1127.            memset( &mmformatinfo, '\0', sizeof( MMFORMATINFO ) );
  1128.            mmformatinfo.fccIOProc = mmioinfo.fccIOProc;
  1129.  
  1130.            ulrc = mmioGetFormats( &mmformatinfo,
  1131.                                      1,
  1132.                                      &mmformatinfo,
  1133.                                      &lNumFormats,
  1134.                                      0,
  1135.                                      0 );
  1136.  
  1137.            pInstance->ulCapabilities = 0;
  1138.  
  1139.            if ( !ulrc )
  1140.               {
  1141.               /*--------------------------------------------------
  1142.               * Determine what capabilities the current io
  1143.               * proc really has (i.e. can it record, save etc.)
  1144.               *-------------------------------------------------*/
  1145.  
  1146.               if (mmformatinfo.ulFlags & MMIO_CANSAVETRANSLATED)
  1147.                  {
  1148.                  pInstance->ulCapabilities = CAN_SAVE;
  1149.                  pInstance->ulOpenTemp = TRUE;
  1150.                  }
  1151.  
  1152.               if (mmformatinfo.ulFlags & MMIO_CANINSERTTRANSLATED )
  1153.                  {
  1154.                  pInstance->ulCapabilities |= CAN_INSERT;
  1155.                  }
  1156.  
  1157.               if ( mmformatinfo.ulFlags & MMIO_CANWRITETRANSLATED)
  1158.                  {
  1159.                  pInstance->ulCapabilities |= CAN_RECORD;
  1160.                  }
  1161.  
  1162.               /*-------------------------------------------------
  1163.               * If the io proc has the ability to record, close
  1164.               * and reopen the file with the flags necessary to
  1165.               * do this
  1166.               *-------------------------------------------------*/
  1167.  
  1168.               if ( pInstance->ulCapabilities )
  1169.                  {
  1170.                  mmioClose( pInstance->hmmio, 0 );
  1171.  
  1172.                  /***********************************************
  1173.                  * The current release does not support opening
  1174.                  * IO Procs other that RIFF format in write mode.
  1175.                  * Therefore, temporary files are impossible.
  1176.                  ************************************************/
  1177.                  ulFlags = MMIO_READWRITE | MMIO_EXCLUSIVE;
  1178.                 
  1179.                  memset( &mmioinfo, '\0', sizeof( mmioinfo ) );
  1180.                 
  1181.                  // need to find out why a mmioinfo struct cause identify to fail
  1182.                 
  1183.                  mmioinfo.ulTranslate = MMIO_TRANSLATEDATA;
  1184.                  mmioinfo.aulInfo[ 3 ] = MMIO_MEDIATYPE_AUDIO;
  1185.                 
  1186.                  /* Open the file */
  1187.                  pInstance->hmmio = mmioOpen ( pFileName,
  1188.                                                &mmioinfo,
  1189.                                                ulFlags);
  1190.  
  1191.                  if ( !pInstance->hmmio )
  1192.                     {
  1193.                     return ( mmioinfo.ulErrorRet );
  1194.                     }
  1195.                  } /* if we must close and reopen the file */
  1196.  
  1197.               }
  1198.            else
  1199.               {
  1200.               ulrc = MCIERR_SUCCESS;
  1201.               }
  1202. //           } /* if identify was successful */
  1203. //        else
  1204. //           {
  1205. //           return ( ulrc );
  1206. //           }
  1207.         } /* If the file was not opened with OPEN_MMIO */
  1208.  
  1209.     else
  1210.         {
  1211.         /************************************************
  1212.         * Since the wave IO Proc opened the file, we know
  1213.         * that it has the following capabilities.
  1214.         *************************************************/
  1215.         pInstance->ulCapabilities =  ( CAN_INSERT | CAN_DELETE | CAN_UNDOREDO +
  1216.                                        CAN_SAVE   | CAN_INSERT | CAN_RECORD  );
  1217.         }
  1218.  
  1219.   /******************************************
  1220.   * Get The Header Information
  1221.   *******************************************/
  1222.  
  1223.   if ( !(ulFlags & MMIO_CREATE) )
  1224.      {
  1225.  
  1226.       ulrc = GetAudioHeader (pInstance);
  1227.  
  1228.      } /* Not Create Flag */
  1229.   else
  1230.      {
  1231.      pInstance->ulDataSize = 0;
  1232.      }
  1233.  
  1234.   pInstance->fFileExists = TRUE;
  1235.  
  1236.  
  1237.   /*******************************************************************
  1238.   * You cannot do the set header immediately after file creation
  1239.   * because future sets on samples, bitpersample, channels may follow
  1240.   ********************************************************************/
  1241.  
  1242.   return (ulrc);
  1243.  
  1244. } /* OpenFile */
  1245.  
  1246.  
  1247. /********************* START OF SPECIFICATIONS *******************************
  1248. *
  1249. * SUBROUTINE NAME: ConvertToMM ()
  1250. *
  1251. * DESCRIPTIVE NAME:
  1252. *
  1253. * FUNCTION: Convert Time values from MMTIME units to current time format.
  1254. *
  1255. *
  1256. * ENTRY POINTS:
  1257. *
  1258. * INPUT:
  1259. *
  1260. * EXIT-NORMAL: MCIERR_SUCCESS.
  1261. *
  1262. * EXIT_ERROR:  Error Code.
  1263. *
  1264. * EFFECTS:
  1265. *
  1266. * INTERNAL REFERENCES:
  1267. *
  1268. * EXTERNAL REFERENCES:
  1269. *
  1270. *********************** END OF SPECIFICATIONS *******************************/
  1271.  
  1272. RC   ConvertToMM ( INSTANCE  *ulpInstance,
  1273.                    PULONG    pulSeekPoint,
  1274.                    ULONG     ulValue)
  1275. {
  1276. /*also use floats are reverse the division/multiplications.
  1277. *  why does this function have a return value? */
  1278.  
  1279.   ULONG      ulBytesPerSample;
  1280.   ULONG      ulTemp1;
  1281.  
  1282.  
  1283.   switch (ulpInstance->ulTimeUnits)
  1284.   {
  1285.  
  1286.   case lMMTIME:
  1287.        *pulSeekPoint = ulValue;
  1288.       break;
  1289.  
  1290.   case lMILLISECONDS:
  1291.        *pulSeekPoint = MSECTOMM ( ulValue);
  1292.       break;
  1293.  
  1294.   case lSAMPLES:
  1295.        ulBytesPerSample = (AMPMIX.lBitsPerSRate / 8);
  1296.        ulTemp1 = ulValue * ulBytesPerSample;
  1297.  
  1298.        ulTemp1 /= ulpInstance->ulBytes ;
  1299.        *pulSeekPoint = ulTemp1 * ulpInstance->ulMMTime;
  1300.  
  1301.       break;
  1302.   default:  /* the time value must be bytes */
  1303.  
  1304.        ulTemp1 = ulValue / ulpInstance->ulBytes ;
  1305.        *pulSeekPoint = ulTemp1 * ulpInstance->ulMMTime;
  1306. //       Bytes2Mmtime( ulpInstance->ulBytes,  (LONG) ulValue, ( LONG ) ulpInstance->ulMMTime, ( PLONG ) pulSeekPoint);
  1307.  
  1308.       break;
  1309.   } /* switch time units */
  1310.  
  1311.   return ( MCIERR_SUCCESS );
  1312.  
  1313. } /* ConvertToMM */
  1314.  
  1315. /********************* START OF SPECIFICATIONS *******************************
  1316. *
  1317. * SUBROUTINE NAME: ConvertTimeUnits ()
  1318. *
  1319. * DESCRIPTIVE NAME:
  1320. *
  1321. * FUNCTION: Convert Time values from the current base to MMTIME units.
  1322. *           We obtained the conversion factors from SpiGetProtocol which
  1323. *           has the smallest breakdowns of mmtime per block of time and
  1324. *           bytes per block of time.
  1325. *
  1326. *
  1327. * ENTRY POINTS:
  1328. *
  1329. * INPUT:
  1330. *
  1331. * EXIT-NORMAL: MCIERR_SUCCESS.
  1332. *
  1333. * EXIT_ERROR:  Error Code.
  1334. *
  1335. * EFFECTS:
  1336. *
  1337. * INTERNAL REFERENCES:
  1338. *
  1339. * EXTERNAL REFERENCES:
  1340. *
  1341. *********************** END OF SPECIFICATIONS *******************************/
  1342.  
  1343. RC  ConvertTimeUnits ( INSTANCE    *ulpInstance,
  1344.                        PULONG      pulSeekPoint,
  1345.                        ULONG       ulValue)
  1346. {
  1347. /* add a flag and remove this file length kludge */
  1348.  
  1349.   ULONG      ulBytesPerSample;
  1350.   ULONG      ulTemp1;
  1351.  
  1352.  
  1353.   /*---------------------------------------------------
  1354.   * due to inaccuracies in the conversions, if the request is bytes or samples
  1355.   *  simply return the number
  1356.   *  this file length stuff is garbarge, add a new flag
  1357.   *---------------------------------------------------*/
  1358.   /**************************************
  1359.   * Computation of Media Element Length
  1360.   * This routine is called with FILE LENGTH
  1361.   * value to signify Total length is
  1362.   * requested.
  1363.   ***************************************/
  1364.   if ( ulValue == FILE_LENGTH)
  1365.       {
  1366.  
  1367.       /* due to inaccuracies in the conversions, if the request is bytes or samples
  1368.       *  simply return the number itself
  1369.       */
  1370.  
  1371.       if ( ulpInstance->ulTimeUnits == lBYTES )
  1372.          {
  1373.          *pulSeekPoint = ulpInstance->ulDataSize;
  1374.          return ( MCIERR_SUCCESS );
  1375.          }
  1376.       else if ( ulpInstance->ulTimeUnits == lSAMPLES )
  1377.          {
  1378.          ulBytesPerSample = (AMPMIX.lBitsPerSRate / 8);
  1379.          *pulSeekPoint = ulpInstance->ulDataSize / ulBytesPerSample;
  1380.          return ( MCIERR_SUCCESS );
  1381.          }
  1382.  
  1383.       /***********************************************
  1384.       * Get the number of blocks of audio information the
  1385.       * desired number of bytes consumes.
  1386.       *************************************************/
  1387.       ulTemp1 = ulpInstance->ulDataSize / ulpInstance->ulBytes;
  1388.  
  1389.  
  1390.  
  1391.       /***********************************************
  1392.       * Multiply the blocks above by the length in time
  1393.       * of a block.
  1394.       *************************************************/
  1395.  
  1396.       ulValue = ulTemp1 * ulpInstance->ulMMTime;
  1397.  
  1398.       } /* Return File Length */
  1399.  
  1400.  
  1401.   switch (ulpInstance->ulTimeUnits)
  1402.   {
  1403.   case lMMTIME:
  1404.        *pulSeekPoint = ulValue;
  1405.       break;
  1406.  
  1407.   case lMILLISECONDS:
  1408.        *pulSeekPoint = MSECFROMMM ( ulValue );
  1409.       break;
  1410.  
  1411.   case lSAMPLES:
  1412.        ulBytesPerSample = (AMPMIX.lBitsPerSRate / 8);
  1413.  
  1414.        ulTemp1 = ulValue / ulpInstance->ulMMTime ;
  1415.        ulTemp1 *= ulpInstance->ulBytes;
  1416.        *pulSeekPoint = ulTemp1 / ulBytesPerSample;
  1417.       break;
  1418.  
  1419.   default: // time value must be bytes
  1420.        ulTemp1 = ulValue / ulpInstance->ulMMTime ;
  1421.       *pulSeekPoint = ulTemp1 * ulpInstance->ulBytes;
  1422. //       Mmtime2Bytes( ulpInstance->ulBytes,  (LONG) ulValue, ( LONG ) ulpInstance->ulMMTime, ( PLONG ) pulSeekPoint);
  1423.       
  1424.       break;
  1425.  
  1426.   } /* Of Switch */
  1427.  
  1428.   return ( MCIERR_SUCCESS );
  1429.  
  1430. } /* ConvertTimeUnits */
  1431.  
  1432. /********************* START OF SPECIFICATIONS *******************************
  1433. *
  1434. * SUBROUTINE NAME: CreateNAssocStream
  1435. *
  1436. * DESCRIPTIVE NAME:
  1437. *
  1438. * FUNCTION: Create a stream and associate this stream with its data
  1439. *           object.
  1440. *
  1441. *
  1442. * NOTES: This function illustrates how one can create a custom event
  1443. *        structure and have SSM return events in this structure.
  1444. *        This allows one to place information like window callback handles
  1445. *        in the event structure, so that when a certain event occurs,
  1446. *        a message can be sent via this window call back handle.
  1447. *
  1448. *        The creation of this custom structure can be found in audiomcd.h
  1449. *        and the use of this structure can be found in admcplay.c and
  1450. *        admcrecd.c.  The initialization of this structure can be
  1451. *        found in admcopen.c
  1452. *
  1453. * INPUT:
  1454. *
  1455. * EXIT-NORMAL: MCIERR_SUCCESS.
  1456. *
  1457. * EXIT_ERROR:  Error Code (from SPI).
  1458. *
  1459. * EFFECTS:
  1460. *
  1461. * INTERNAL REFERENCES:
  1462. *
  1463. * EXTERNAL REFERENCES:  SpiCreateStream ()      - SSM SPI
  1464. *                       SpiAssociate ()         - SSM SPI
  1465. *
  1466. *********************** END OF SPECIFICATIONS *******************************/
  1467.  
  1468. RC CreateNAssocStream ( HID       hidSrc,         /* Source Handler HID */
  1469.                         HID       hidTgt,         /* Target Handler HID */
  1470.                         HSTREAM   *hStream,       /* Stream Handle ()   */
  1471.                         INSTANCE  *pInstance,     /* Instance Pointer   */
  1472.                         ULONG     Operation,      /* Play or Record     */
  1473.                         PEVFN     EventProc)      /* Event Entry Point  */
  1474.  
  1475. {
  1476.  
  1477.   ULONG     ulrc;
  1478.  
  1479.   /*********************************************************
  1480.   * Create the stream that play/record/cue will use.
  1481.   * The caller supplies the source and target stream
  1482.   * handlers and the audio device control block should
  1483.   * have been filled in previously ( see InitAudioDevice )
  1484.   * The caller also supplies the EventProc(edure)
  1485.   * where all of the stream events will be reported.
  1486.   *
  1487.   * Note: pInstance->StreamInfo.Evcb contains the
  1488.   *********************************************************/
  1489.  
  1490.  
  1491.   ulrc = SpiCreateStream ( hidSrc,
  1492.                            hidTgt,
  1493.                            &pInstance->StreamInfo.SpcbKey,
  1494.                            (PDCB) &pInstance->StreamInfo.AudioDCB,
  1495.                            (PDCB) &pInstance->StreamInfo.AudioDCB,
  1496.                            (PIMPL_EVCB) &pInstance->StreamInfo.Evcb,
  1497.                            (PEVFN) EventProc,
  1498.                            (ULONG) NULL,
  1499.                            hStream,
  1500.                            &pInstance->StreamInfo.hEvent);
  1501.  
  1502.   if (ulrc)
  1503.       return (ulrc);
  1504.  
  1505.   /**********************************************************
  1506.   * The stream must be associated with a data object
  1507.   * in our case a mmio file handle.  The file system
  1508.   * stream handler (FSSH) will always be the stream handler
  1509.   * that we want to associate the data object with,
  1510.   * therefore, if we have created a playback stream then
  1511.   * FSSH is the source, so associate with the source.  On a
  1512.   * record stream, FSSH is the target, so associate with
  1513.   * the target.
  1514.   **********************************************************/
  1515.  
  1516.  
  1517.   pInstance->StreamInfo.acbmmio.ulObjType = ACBTYPE_MMIO;
  1518.   pInstance->StreamInfo.acbmmio.ulACBLen = sizeof (ACB_MMIO);
  1519.   pInstance->StreamInfo.acbmmio.hmmio = pInstance->hmmio;
  1520.  
  1521.   if (Operation == PLAY_STREAM)
  1522.       {
  1523.  
  1524.       ulrc = SpiAssociate ( (HSTREAM)*hStream,
  1525.                             hidSrc,
  1526.                             (PVOID) &pInstance->StreamInfo.acbmmio);
  1527.  
  1528.       }  /* Associating play stream */
  1529.  
  1530.   else if ( Operation == RECORD_STREAM )
  1531.       {
  1532.       ulrc = SpiAssociate ( (HSTREAM) *hStream,
  1533.                             hidTgt,
  1534.                             (PVOID) &pInstance->StreamInfo.acbmmio);
  1535.  
  1536.       } /* Associating record stream */
  1537.  
  1538.  
  1539.   return (ulrc);
  1540.  
  1541. } /* CreateStream */
  1542.  
  1543. /********************* START OF SPECIFICATIONS *******************************
  1544. *
  1545. * SUBROUTINE NAME: DoTillEvent()
  1546. *
  1547. * DESCRIPTIVE NAME:
  1548. *
  1549. * FUNCTION: Enable a Time Event to process MCI_PLAY or MCI_RECORD with
  1550. *           the MCI_TO Flag on.
  1551. *
  1552. * NOTES: This function will create a cue time pause event.  When the
  1553. *        stream reaches the event during a play or record, the
  1554. *        audio stream handler will signal the MCD--note, the stream
  1555. *        will not be stopped, it is the MCD's responsibility.
  1556. *
  1557. * ENTRY POINTS:
  1558. *
  1559. * INPUT:
  1560. *
  1561. * EXIT-NORMAL: MCIERR_SUCCESS.
  1562. *
  1563. * EXIT_ERROR:  Error Code.
  1564. *
  1565. * EFFECTS:
  1566. *
  1567. * INTERNAL REFERENCES: SpiEnableEvent()
  1568. *
  1569. * EXTERNAL REFERENCES:
  1570. *
  1571. *********************** END OF SPECIFICATIONS *******************************/
  1572. RC CreateToEvent (INSTANCE *ulpInstance, ULONG ulTo)
  1573. {
  1574. /* rename this function CreateToEvent */
  1575.  
  1576.  
  1577.   ULONG ulrc;
  1578.  
  1579.   /*********************************************************
  1580.   * Set up a cue time pause event at the place in
  1581.   * the stream where the caller wants us to play/record
  1582.   * to.  Note: this event will pause the stream and
  1583.   * will be considerably more accurate than just
  1584.   * setting a cue point, receiving the event and stopping
  1585.   * the stream (since a normal cue point will force
  1586.   * bleed over).
  1587.   *********************************************************/
  1588.  
  1589.   ulpInstance->StreamInfo.TimeEvcb.hwndCallback      = ulpInstance->hwndCallBack;
  1590.   ulpInstance->StreamInfo.TimeEvcb.usDeviceID         = ulpInstance->usWaveDeviceID;
  1591.   ulpInstance->StreamInfo.TimeEvcb.evcb.ulType       = EVENT_CUE_TIME_PAUSE;
  1592.   ulpInstance->StreamInfo.TimeEvcb.evcb.ulFlags      = EVENT_SINGLE;
  1593.   ulpInstance->StreamInfo.TimeEvcb.evcb.hstream      = ulpInstance->StreamInfo.hStream;
  1594.   ulpInstance->StreamInfo.TimeEvcb.ulpInstance       = (ULONG) ulpInstance;
  1595.   ulpInstance->StreamInfo.TimeEvcb.evcb.mmtimeStream = ulTo;
  1596.  
  1597.   /* Enable the cue time pause event. */
  1598.  
  1599.   ulrc = SpiEnableEvent((PEVCB) &ulpInstance->StreamInfo.TimeEvcb.evcb,
  1600.                         (PHEVENT) &ulpInstance->StreamInfo.hPlayToEvent);
  1601.  
  1602.   return ( ulrc );
  1603.  
  1604. } /* CreateToEvent */
  1605.  
  1606. /********************* START OF SPECIFICATIONS *********************
  1607. *
  1608. * SUBROUTINE NAME:              GetPDDName
  1609. *
  1610. * DESCRIPTIVE NAME:
  1611. *
  1612. * FUNCTION:     Retrieves the PDD name (AUDIO1$, etc.) based
  1613. *               on which AmpMixer we're connected to
  1614. *
  1615. * NOTES:        DCR 104
  1616. *
  1617. * INPUT:
  1618. *         ULONG         ulDeviceType
  1619. *         CHAR          szPDDName [MAX_PDD_NAME]        - OUTPUT
  1620. *
  1621. * EXIT-NORMAL:  NO_ERROR
  1622. *
  1623. * EXIT_ERROR:
  1624. *
  1625. *********************** END OF SPECIFICATIONS *********************************/
  1626.  
  1627. RC GetPDDName (ULONG ulDeviceType, CHAR szPDDName [MAX_PDD_NAME])
  1628. {
  1629.  
  1630.    ULONG                   rc;
  1631.  
  1632.    CHAR                    szIndex[2];
  1633.    CHAR                    szAmpMix[9] = "AMPMIX0";
  1634.  
  1635.    MCI_SYSINFO_PARMS       SysInfo;
  1636.    MCI_SYSINFO_LOGDEVICE   SysInfoParm;
  1637.    MCI_SYSINFO_QUERY_NAME  QueryNameParm;
  1638.  
  1639.    memset (&SysInfo, '\0', sizeof(SysInfo));
  1640.    memset (&SysInfoParm, '\0', sizeof(SysInfoParm));
  1641.    memset (&QueryNameParm, '\0', sizeof(QueryNameParm));
  1642.  
  1643.    SysInfo.ulItem       = MCI_SYSINFO_QUERY_NAMES;
  1644.    SysInfo.usDeviceType  = LOUSHORT(ulDeviceType);
  1645.    SysInfo.pSysInfoParm = &QueryNameParm;
  1646.  
  1647.    itoa (HIUSHORT(ulDeviceType), szIndex, 10);
  1648.  
  1649.    szIndex[1] = '\0';
  1650.  
  1651.    strncat (szAmpMix, szIndex, 2);
  1652.    strcpy (QueryNameParm.szLogicalName, szAmpMix);
  1653.  
  1654.    if (rc = mciSendCommand (0,
  1655.                             MCI_SYSINFO,
  1656.                             MCI_SYSINFO_ITEM | MCI_WAIT,
  1657.                             (PVOID) &SysInfo,
  1658.                             0))
  1659.            return (rc);
  1660.  
  1661.  
  1662.  
  1663.  
  1664.    /*******************************************
  1665.    * Get PDD associated with our AmpMixer
  1666.    * Device name is in pSysInfoParm->szPDDName
  1667.    ********************************************/
  1668.  
  1669.    SysInfo.ulItem       = MCI_SYSINFO_QUERY_DRIVER;
  1670.    SysInfo.usDeviceType  = (USHORT) ulDeviceType;
  1671.    SysInfo.pSysInfoParm = &SysInfoParm;
  1672.  
  1673.    strcpy (SysInfoParm.szInstallName, QueryNameParm.szInstallName);
  1674.  
  1675.    if (rc = mciSendCommand (0,
  1676.                             MCI_SYSINFO,
  1677.                             MCI_SYSINFO_ITEM | MCI_WAIT,
  1678.                             (PVOID) &SysInfo,
  1679.                             0))
  1680.        return (rc);
  1681.  
  1682.    strcpy (szPDDName, SysInfoParm.szPDDName);
  1683.  
  1684.    return ( MCIERR_SUCCESS );
  1685.  
  1686. } /* GetPDDName */
  1687.  
  1688.  
  1689. /********************* START OF SPECIFICATIONS *********************
  1690. *
  1691. * SUBROUTINE NAME: Generic thread abort
  1692. *
  1693. * DESCRIPTIVE NAME:
  1694. *
  1695. * FUNCTION: This will abort any waiting command on another thread.
  1696. *
  1697. *
  1698. * EXIT-NORMAL:  NO_ERROR
  1699. *
  1700. * EXIT_ERROR:
  1701. *
  1702. *********************** END OF SPECIFICATIONS *********************************/
  1703.  
  1704.  
  1705. void GenericThreadAbort( INSTANCE             *ulpInstance,
  1706.                          FUNCTION_PARM_BLOCK  *pFuncBlock, 
  1707.                          ULONG                ulCloseFlag )
  1708.  
  1709.  
  1710. {
  1711. BOOL     fForceDiscard = FALSE;
  1712.  
  1713.   if ( ulpInstance->usNotPendingMsg == MCI_SAVE )
  1714.      {
  1715.      /****************************************
  1716.      ** Save is a non-interruptible operation
  1717.      ** wait for completion
  1718.      *****************************************/
  1719.  
  1720.      DosWaitEventSem( ulpInstance->hThreadSem, (ULONG ) -1 );
  1721.      }
  1722.    else
  1723.      {
  1724.      PostMDMMessage ( MCI_NOTIFY_ABORTED, 
  1725.                       ulpInstance->usNotPendingMsg,
  1726.                       pFuncBlock);
  1727.  
  1728.  
  1729.      /* Stop the pending thread */
  1730.  
  1731.      if ( !(ulCloseFlag & MCI_CLOSE_EXIT) )
  1732.         {
  1733.         if ( pFuncBlock->usMessage == MCI_CLOSE )
  1734.            {
  1735.            /*****************************************
  1736.            * create a fake event so the thread we are
  1737.            * waiting on will have a chance to clean
  1738.            * up.  It is important that we do not do
  1739.            * an spistop since the instance may not
  1740.            * be currently active.
  1741.            *****************************************/
  1742.  
  1743.            ulpInstance->StreamEvent = EVENT_STREAM_STOPPED;
  1744.            DosPostEventSem (ulpInstance->hEventSem);
  1745.  
  1746.            DosWaitEventSem (ulpInstance->hThreadSem, (ULONG) -1);
  1747.            }
  1748.  
  1749.         else
  1750.            {
  1751.            ThreadedStop ( ulpInstance );
  1752.            }
  1753.         }
  1754.  
  1755.      } /* if !save pending */
  1756.  
  1757. } /* GenericThreadAbort */
  1758.  
  1759.  
  1760.  
  1761. /********************* START OF SPECIFICATIONS *********************
  1762. *
  1763. * SUBROUTINE NAME: ThreadedStop
  1764. *
  1765. * DESCRIPTIVE NAME:
  1766. *
  1767. * FUNCTION: Stop pending plays or records
  1768. *
  1769. * INPUT:
  1770. *
  1771. * EXIT-NORMAL:  NO_ERROR
  1772. *
  1773. * EXIT_ERROR:
  1774. *
  1775. *********************** END OF SPECIFICATIONS *********************************/
  1776.  
  1777. void ThreadedStop( INSTANCE     *ulpInstance )
  1778.  
  1779.  
  1780. {
  1781. ULONG   ulrc;
  1782. ULONG   ulCount;
  1783. ULONG   ulSpiFlags;
  1784.  
  1785.  
  1786.  
  1787.  
  1788.    if ( AMPMIX.ulOperation == OPERATION_PLAY )
  1789.       {
  1790.       ulSpiFlags = SPI_STOP_DISCARD;
  1791.       }
  1792.    else
  1793.       {
  1794.       ulSpiFlags = SPI_STOP_FLUSH;
  1795.       }
  1796.  
  1797.    /*****************************************************
  1798.    * Stop discard for play because data loss is not
  1799.    * important.
  1800.    * Stop flush a record stream so that no data will be
  1801.    * lost.
  1802.    *****************************************************/
  1803.  
  1804.    ulrc = SpiStopStream (ulpInstance->StreamInfo.hStream, ulSpiFlags);
  1805.  
  1806.    if (!ulrc)
  1807.      {
  1808.      DosWaitEventSem (ulpInstance->hThreadSem, (ULONG) -1);
  1809.      }
  1810.  
  1811.    STRMSTATE = MCI_STOP;
  1812.  
  1813.   return;
  1814.  
  1815. } /* ThreadedStop */
  1816.