home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Professional Developers Kit 1992 November / Disc01 / Disc01.mdf / runnable / mmos2 / mmtoolkt / samples / cdmct / cdaudutl.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-05-06  |  51.9 KB  |  1,145 lines

  1. /*static char *SCCSID = "@(#)cdaudutl.c    13.7 92/04/23";*/
  2. /****************************************************************************/
  3. /*                                                                          */
  4. /* SOURCE FILE NAME:  CDAUDUTL.C                                            */
  5. /*                                                                          */
  6. /* DESCRIPTIVE NAME:  CD AUDIO MCI DRIVER UTILITIES                         */
  7. /*                                                                          */
  8. /* COPYRIGHT:  (c) IBM Corp. 1991, 1992                                     */
  9. /*                                                                          */
  10. /* FUNCTION:  This file contains the hardware independent code that         */
  11. /*            supplement the PROCESS commands in CDAUDPRO.C for the         */
  12. /*            CD Audio MCI Driver uses.  The entry point to the DLL is      */
  13. /*            in CDAUDIO.C                                                  */
  14. /*                                                                          */
  15. /* NOTES:  The hardware dependent code is found in file IBMCDROM.C.         */
  16. /*                                                                          */
  17. /* OTHER FUNCTIONS:                                                         */
  18. /*       SetAudio      - Set audio information from MCI_SET.                */
  19. /*       SetConnector  - Enable or disable connection.                      */
  20. /*       SetCuePoint   - Enable cue point.                                  */
  21. /*       StatusMCD     - Get status from MCD information.                   */
  22. /*       StatusMCDDef  - Get status from MCD information.                   */
  23. /*       StatusVSD     - Get status from VSD information.                   */
  24. /*       DisableEvents - Disable cuepoints and position advise.             */
  25. /*       GetTimeAddr   - Convert a time format to/from MMTIME               */
  26. /*       GetTimeAddrRC - Colinize return code to time format.               */
  27. /*       GetTrackInfo  - Get Track info for specified track or address.     */
  28. /*       ValAddress    - validate address for play and seek commands.       */
  29. /*       ValState      - validate state, has disc and not suspended.        */
  30. /*       vsdResponse   - process VSD Response.                              */
  31. /*                                                                          */
  32. /*                                                                          */
  33. /****************************************************************************/
  34.  
  35. #define INCL_DOSERRORS
  36. #define INCL_DOSPROCESS
  37. #define INCL_DOSMEMMGR
  38. #define INCL_DOSMODULEMGR
  39. #define INCL_DOSSEMAPHORES
  40. #include <os2.h>
  41. #include <string.h>
  42. #include <os2me.h>
  43. #include <mcd.h>
  44. #include <cdaudio.h>
  45. #include "cdaudibm.h"
  46. #include <ctype.h>
  47. #include <hhpheap.h>
  48.  
  49. extern PVOID          CDMC_hHeap;
  50.  
  51. /****************************************************************************/
  52. /*                                                                          */
  53. /* SUBROUTINE NAME:  SetAudio                                               */
  54. /*                                                                          */
  55. /* DESCRIPTIVE NAME:  Set Audio                                             */
  56. /*                                                                          */
  57. /* FUNCTION:  Set Audio information when MCI_SET_AUDIO flag is used with    */
  58. /*            MCI_SET command.  This function is called by ProcSet().       */
  59. /*                                                                          */
  60. /* PARAMETERS:                                                              */
  61. /*      PINST pInst    -- pointer to instance.                              */
  62. /*      DWORD *pParam1 -- flag for this message.                            */
  63. /*      MCI_SET_PARMS *dwParam2 -- pointer to local SET structure.          */
  64. /*      ULONG *pulMode  -- mode flags.                                      */
  65. /*      DWORD *pdwLevel -- volume level.                                    */
  66. /*                                                                          */
  67. /* EXIT CODES:                                                              */
  68. /*      MCIERR_SUCCESS    -- action completed without error.                */
  69. /*      MCIERR_FLAGS_NOT_COMPATIBLE -- Flags not compatible.                */
  70. /*      MCIERR_INVALID_AUDIO_FLAG   -- Unknown audio flag specified.        */
  71. /*                                                                          */
  72. /* NOTES:                                                                   */
  73. /*                                                                          */
  74. /****************************************************************************/
  75.  
  76. DWORD SetAudio(PINST pInst, DWORD *pParam1, MCI_SET_PARMS *dwParam2,
  77.                ULONG *pulMode, DWORD *pdwLevel)
  78. {
  79.    DWORD rc = MCIERR_SUCCESS;          // assume the best
  80.    USHORT usFlag = 0;
  81.    ULONG  ulChan = 0;
  82.    WORD left, right;
  83.  
  84.    if (*pParam1 & MCI_SET_ON && *pParam1 & MCI_SET_OFF)
  85.       rc = MCIERR_FLAGS_NOT_COMPATIBLE;
  86.    else
  87.       switch (dwParam2->dwAudio)
  88.       {
  89.          case MCI_SET_AUDIO_LEFT :
  90.             ulChan = CDMC_LFT_CH;
  91.             break;
  92.          case MCI_SET_AUDIO_RIGHT :
  93.             ulChan = CDMC_RGT_CH;
  94.             break;
  95.          case MCI_SET_AUDIO_ALL :
  96.             ulChan = CDMC_ALL_CH;
  97.             break;
  98.          default : rc = MCIERR_INVALID_AUDIO_FLAG;
  99.       }  /* of switch */
  100.  
  101.  
  102.    if (!rc)
  103.    {
  104.       *pParam1 ^= MCI_SET_AUDIO;       // remove non VSD flag
  105.       if (*pParam1 & MCI_OVER)
  106.          *pParam1 ^= MCI_OVER;         // vectored volume not supported
  107.  
  108.       if (*pParam1 & MCI_SET_ON)
  109.       {
  110.          usFlag = 1;
  111.          *pParam1 ^= MCI_SET_ON;       // remove non VSD flag
  112.          *pulMode |= ulChan;
  113.       }  /* of else if ON */
  114.       else if (*pParam1 & MCI_SET_OFF)
  115.       {
  116.          usFlag = 1;
  117.          *pParam1 ^= MCI_SET_OFF;      // remove non VSD flag
  118.          if (ulChan & CDMC_LFT_CH)
  119.             *pulMode &= CHAN_MODE_SET | CDMC_RGT_CH;
  120.          if (ulChan & CDMC_RGT_CH)
  121.             *pulMode &= CHAN_MODE_SET | CDMC_LFT_CH;
  122.       }  /* of else if OFF */
  123.  
  124.       if (*pParam1 & MCI_SET_VOLUME)
  125.       {
  126.          usFlag = 1;
  127.          /* get requested volume levels */
  128.          left  = (WORD) dwParam2->dwLevel;
  129.          right = (WORD) dwParam2->dwLevel;
  130.  
  131.          if (ulChan & CDMC_LFT_CH)
  132.             if (left > 100)
  133.                VOL_LEFT(*pdwLevel) = 100;
  134.             else
  135.                VOL_LEFT(*pdwLevel) = left;
  136.          if (ulChan & CDMC_RGT_CH)
  137.             if (right > 100)
  138.                VOL_RIGHT(*pdwLevel) = 100;
  139.             else
  140.                VOL_RIGHT(*pdwLevel) = right;
  141.       }  /* of setting volume */
  142.  
  143.       if (usFlag)                // CHANGE, SET VOLUME
  144.       {
  145.          /* Go ahead and prepare for call to VSD */
  146.          if (*pulMode & CDMC_LFT_CH && pInst->ulMode & CDMC_HEADPHONE)
  147.             left = (WORD)((DWORD)VOL_LEFT(*pdwLevel) *
  148.                    pInst->dwMasterVolume / 100);
  149.          else           /* else channel is muted */
  150.             left = 0;
  151.          if (*pulMode & CDMC_RGT_CH && pInst->ulMode & CDMC_HEADPHONE)
  152.             right = (WORD)((DWORD)VOL_RIGHT(*pdwLevel) *
  153.                    pInst->dwMasterVolume / 100);
  154.          else           /* else channel is muted */
  155.             right = 0;
  156.          dwParam2->dwLevel = MAKEULONG(left, right);
  157.          *pParam1 |= MCI_SET_VOLUME;      //make sure VSD flag is set
  158.  
  159.       }  /* of if change */
  160.       else
  161.          rc = MCIERR_MISSING_FLAG;
  162.    }  /* of if no error with flags */
  163.  
  164.    return(rc);
  165.  
  166. }  /* of SetAudio() */
  167.  
  168.  
  169. /****************************************************************************/
  170. /*                                                                          */
  171. /* SUBROUTINE NAME:  SetConnector                                           */
  172. /*                                                                          */
  173. /* DESCRIPTIVE NAME:  Set Connector                                         */
  174. /*                                                                          */
  175. /* FUNCTION:  Enable or disable connectors from the MCI_CONNECTOR command.  */
  176. /*            This function is called by ProcConnector().                   */
  177. /*                                                                          */
  178. /* PARAMETERS:                                                              */
  179. /*      PINST pInst    -- pointer to instance.                              */
  180. /*      DWORD dwParam1 -- flag for this message.                            */
  181. /*                                                                          */
  182. /* EXIT CODES:                                                              */
  183. /*      MCIERR_SUCCESS    -- action completed without error.                */
  184. /*      MCIERR_DEVICE_NOT_READY  -- No Disc is present.                     */
  185. /*      MCIERR_UNSUPPORTED_FLAG     -- cannot process constant.             */
  186. /*      MCIERR_FLAGS_NOT_COMPATIBLE -- Invalid flag combinations.           */
  187. /*      MCIERR_INVALID_FLAG         -- Unknown or unsupported flag.         */
  188. /*      MCIERR_CANNOT_LOAD_DRIVER -- Unable to load VSD.                    */
  189. /*                                                                          */
  190. /* NOTES:   ProcConnector() calls this function only when                   */
  191. /*          MCI_ENABLE_CONNECTOR or MCI_DISABLE_CONNECTOR flags were used.  */
  192. /*                                                                          */
  193. /****************************************************************************/
  194.  
  195. DWORD SetConnector(PINST pInst, DWORD dwParam1)
  196. {
  197.    DWORD rsp, rc = MCIERR_SUCCESS;          // assume the best
  198.    MCI_STATUS_PARMS recStatus;
  199.  
  200.    /* get current position -- will be placed in pInst->dwCur_pos */
  201.    /* don't use recStatus.dwReturn, it will be adjusted with     */
  202.    /*   sync offset and current time format setting              */
  203.    recStatus.dwItem = MCI_STATUS_POSITION;
  204.    rsp = ProcStatus(pInst, MCI_STATUS_ITEM, &recStatus);
  205.  
  206.    if (dwParam1 & MCI_ENABLE_CONNECTOR)          // *** ENABLE DAC ***
  207.    {
  208.       if (pInst->ulMode & CDMC_CAN_DAC)
  209.       {
  210.          /* do it if not already playing internally */
  211.          if (!(pInst->ulMode & CDMC_INTDAC))
  212.             pInst->ulMode = pInst->ulMode & STREAM_MODE_SET | CDMC_INTDAC;
  213.  
  214.       }  /* of if can enable DAC */
  215.       else
  216.          rc = MCIERR_UNSUPPORTED_FLAG;           //no internal DAC
  217.    }  /* of if enable */
  218.    else                             // *** DISABLE DAC ***
  219.    {
  220.       if (pInst->ulMode & CDMC_INTDAC)
  221.       {
  222.          ProcStop(pInst, MCI_WAIT);
  223.          pInst->ulMode ^= CDMC_INTDAC;
  224.       }   /* of if playing internal DAC */
  225.    }  /* of if disable */
  226.  
  227.    return(rc);
  228.  
  229. }  /* of SetConnector() */
  230.  
  231.  
  232. /****************************************************************************/
  233. /*                                                                          */
  234. /* SUBROUTINE NAME:  SetCuePoint                                            */
  235. /*                                                                          */
  236. /* DESCRIPTIVE NAME:  Set Cue Point                                         */
  237. /*                                                                          */
  238. /* FUNCTION:  Set Cue Point from the MCI_SET_CUEPOINT command.              */
  239. /*                                                                          */
  240. /* PARAMETERS:                                                              */
  241. /*      PINST pInst    -- pointer to instance.                              */
  242. /*      DWORD dwParam1 -- flag for this message.                            */
  243. /*      DWORD dwParam2 -- pointer to structure (message dependent).         */
  244. /*                                                                          */
  245. /* EXIT CODES:                                                              */
  246. /*      MCIERR_SUCCESS    -- action completed without error.                */
  247. /*      MCIERR_OUTOFRANGE -- invalid cuepoint position.                     */
  248. /*      MCIERR_DEVICE_NOT_READY -- No Disc is present.                      */
  249. /*      MCIERR_CUEPOINT_LIMIT_REACHED --  no more room to add events.       */
  250. /*      MCIERR_DUPLICATE_CUEPOINT     --  duplicate cuepoint.               */
  251. /*                                                                          */
  252. /* NOTES:                                                                   */
  253. /*                                                                          */
  254. /****************************************************************************/
  255.  
  256. DWORD SetCuePoint(PINST pInst, MCI_CUEPOINT_PARMS *dwParam2)
  257. {
  258.    DWORD rc, dwTime, dwFlags;
  259.    int i, found = -1;
  260.    MCI_CUEPOINT_PARMS recCuePoint;
  261.  
  262.    /* validate time */
  263.    dwTime = GetTimeAddr(pInst, dwParam2->dwCuepoint, TRUE);
  264.    if (dwTime == (DWORD) -1L)
  265.       rc = MCIERR_OUTOFRANGE;         // invalid track number
  266.    else
  267.    {
  268.       dwTime += pInst->dwOffset;
  269.       if (dwTime < pInst->dwStart_disk ||
  270.           dwTime > pInst->dwEnd_disk)
  271.          rc = MCIERR_OUTOFRANGE;
  272.       else
  273.          rc = MCIERR_SUCCESS;
  274.    }
  275.  
  276.    /* make sure cuepoint is unique */
  277.    if (!rc)
  278.    {
  279.       for (i=0; i < CDMCD_CUEPOINT_MAX; i++)
  280.       {
  281.          if (pInst->arrCuePoint[i] == (DWORD) -1L)
  282.          {
  283.             if (found < 0)
  284.                found = i;      // save first available entry
  285.          }
  286.          else
  287.             if (pInst->arrCuePoint[i] == dwTime)
  288.             {
  289.                rc = MCIERR_DUPLICATE_CUEPOINT;
  290.                break;               // error end for loop
  291.             }
  292.       }  /* of for loop */
  293.  
  294.       if (!rc)
  295.          if (found < 0)
  296.             rc = MCIERR_CUEPOINT_LIMIT_REACHED;
  297.    }  /* of if no error, test uniqueness */
  298.  
  299.    /* init record and relay message */
  300.    if (!rc)
  301.    {
  302.       pInst->arrCuePoint[found] = dwTime;
  303.       /* copy record so as not to change original from application */
  304.       memcpy(&recCuePoint, dwParam2, sizeof(MCI_CUEPOINT_PARMS));
  305.       dwParam2->dwCuepoint = dwTime;
  306.       dwFlags = MCI_SET_CUEPOINT_ON | MCI_WAIT;
  307.       rc = pInst->pMCIDriver(pInst->hHWMCID, MCI_SET_CUEPOINT,
  308.                              (DWORD) &dwFlags, (DWORD) dwParam2, 0);
  309.  
  310.       if (rc)                            // clear entry
  311.          pInst->arrCuePoint[found] = -1L;
  312.  
  313.    }  /* of if no error, init record */
  314.  
  315.    return(rc);
  316.  
  317. }  /* of SetCuePoint() */
  318.  
  319.  
  320. /****************************************************************************/
  321. /*                                                                          */
  322. /* SUBROUTINE NAME:  StatusMCD                                              */
  323. /*                                                                          */
  324. /* DESCRIPTIVE NAME:  Status MCD                                            */
  325. /*                                                                          */
  326. /* FUNCTION:  Query the Status of MCD flags.  This function is called       */
  327. /*            by ProcStatus().                                              */
  328. /*                                                                          */
  329. /* PARAMETERS:                                                              */
  330. /*      PINST pInst     -- pointer to instance.                             */
  331. /*      DWORD dwParam1  -- flag for this message.                           */
  332. /*      DWORD dwParam2  -- pointer to structure (message dependent).        */
  333. /*      DWORD rsp       -- state response.                                  */
  334. /*      USHORT usIgnore -- ignore invalid media type.                       */
  335. /*                                                                          */
  336. /* EXIT CODES:                                                              */
  337. /*      MCIERR_SUCCESS    -- action completed without error.                */
  338. /*      MCIERR_OUTOFRANGE -- invalid track supplied.                        */
  339. /*      MCIERR_FLAGS_NOT_COMPATIBLE -- Flags not compatible.                */
  340. /*      MCIERR_UNSUPPORTED_FUNCTION -- Unknown flag or value used.          */
  341. /*      MCIERR_DEVICE_NOT_READY   -- device was not ready, no disc.         */
  342. /*      MCIERR_INVALID_MEDIA_TYPE -- No audio tracks were found.            */
  343. /*                                                                          */
  344. /* NOTES: dwParam1 = MCI_STATUS_ITEM or MCI_STATUS_ITEM | MCI_TRACK         */
  345. /*                                   or MCI_STATUS_ITEM | MCI_STATUS_START  */
  346. /*                                                                          */
  347. /****************************************************************************/
  348.  
  349. DWORD StatusMCD(PINST pInst, DWORD dwParam1, MCI_STATUS_PARMS *dwParam2,
  350.                 DWORD rsp, USHORT usIgnore)
  351. {
  352.    DWORD rc;
  353.    DWORD dwAddr, dwTrack, dwFlags;
  354.    MCI_CD_REGTRACK_REC *ptr1, *ptr2;
  355.    MCI_STATUS_PARMS recStatus;
  356.    ULONG ulMode;
  357.  
  358.    /* Make sure disc is present before you rely on cache */
  359.    if (rsp)
  360.    {
  361.       if (rsp == MCIERR_INSTANCE_INACTIVE)
  362.          if (pInst->usStatus - SUSPEND == REGTRACK)
  363.             rc = MCIERR_INVALID_MEDIA_TYPE;
  364.          else if (pInst->usStatus - SUSPEND <= NODISC)
  365.             rc = MCIERR_DEVICE_NOT_READY;
  366.          else
  367.          {
  368.             rc = MCIERR_SUCCESS;    // process inactive command
  369.             recStatus.dwReturn = pInst->dwCur_pos;
  370.          }
  371.       else
  372.          rc = rsp;
  373.    }  /* of if known error */
  374.    else
  375.    {
  376.       recStatus.dwItem = MCI_STATUS_POSITION;
  377.       dwFlags = MCI_STATUS_ITEM | MCI_WAIT;
  378.       rc = pInst->pMCIDriver(pInst->hHWMCID, MCI_STATUS,
  379.                              (DWORD) &dwFlags, (DWORD) &recStatus, 0);
  380.       if (DWORD_LOWD(rc))
  381.       {
  382.          rc = vsdResponse(pInst, rc);
  383.          if (!rc)                    //Disc Change, get starting address
  384.             recStatus.dwReturn = pInst->dwStart_disk;
  385.       }  /* of if error */
  386.  
  387.       if (!DWORD_LOWD(rc))
  388.          pInst->dwCur_pos = recStatus.dwReturn;    // valid value, keep it
  389.    }  /* of else no error so check disc */
  390.  
  391.    if (rc == MCIERR_INVALID_MEDIA_TYPE && usIgnore)
  392.       rc = MCIERR_SUCCESS;
  393.  
  394.    if (DWORD_LOWD(rc))
  395.       return(rc);
  396.  
  397.    /*----------- End of checking presents of Disc -----------------*/
  398.  
  399.    switch (dwParam1)
  400.    {
  401.       case MCI_STATUS_ITEM | MCI_TRACK :
  402.          rc = StatusMCDDef(pInst, dwParam1, dwParam2, recStatus.dwReturn);
  403.          break;
  404.       case MCI_STATUS_ITEM | MCI_STATUS_START :
  405.          /* item must be MCI_STATUS_POSITION from ProcStatus() */
  406.          dwParam2->dwReturn =  GetTimeAddr(pInst, pInst->dwStart_disk, FALSE);
  407.          rc = GetTimeAddrRC(pInst, rc);
  408.          break;
  409.       default :                            // must be MCI_STATUS_ITEM alone
  410.          switch(dwParam2->dwItem)
  411.          {
  412.             case MCI_STATUS_POSITION :
  413.                dwParam2->dwReturn =  GetTimeAddr(pInst,
  414.                          (DWORD)(recStatus.dwReturn - pInst->dwOffset), FALSE);
  415.                rc = GetTimeAddrRC(pInst, rc);
  416.                break;
  417.             case MCI_STATUS_LENGTH :
  418.                dwTrack = pInst->recTrack.dwBufSize /
  419.                          sizeof(MCI_CD_REGTRACK_REC);
  420.                dwAddr = (pInst->recTrack.TrackRecArr + dwTrack-1)->dwEndAddr -
  421.                          pInst->recTrack.TrackRecArr->dwStartAddr;
  422.                /* return MSF format for length if in TMSF format */
  423.                if ((pInst->ulMode & TIME_MODE) == CDMC_TMSF)
  424.                {
  425.                   ulMode = pInst->ulMode;
  426.                   pInst->ulMode = pInst->ulMode & TIME_MODE_SET | CDMC_REDBOOK;
  427.                   dwParam2->dwReturn = GetTimeAddr(pInst, dwAddr, FALSE);
  428.                   rc = GetTimeAddrRC(pInst, rc);
  429.                   pInst->ulMode = ulMode;
  430.                }
  431.                else
  432.                {
  433.                   dwParam2->dwReturn = GetTimeAddr(pInst, dwAddr, FALSE);
  434.                   rc = GetTimeAddrRC(pInst, rc);
  435.                }
  436.                break;
  437.             case MCI_STATUS_NUMBER_OF_TRACKS :
  438.                ptr1 = GetTrackInfo(pInst, 0, pInst->dwStart_disk);
  439.                ptr2 = GetTrackInfo(pInst, 0, pInst->dwEnd_disk - 1);
  440.                if (ptr1 && ptr2)         //if both pointers are valid
  441.                   dwParam2->dwReturn = ptr2->TrackNum - ptr1->TrackNum + 1;
  442.                else
  443.                   dwParam2->dwReturn = 0L;
  444.                DWORD_HIWD(rc) = MCI_INTEGER_RETURNED;
  445.                break;
  446.             default :
  447.                rc = StatusMCDDef(pInst, dwParam1, dwParam2, recStatus.dwReturn);
  448.  
  449.          }  /* of switch, known items */
  450.    }  /* of switch, flags */
  451.  
  452.    return(rc);
  453.  
  454. }  /* of StatusMCD() */
  455.  
  456.  
  457. /****************************************************************************/
  458. /*                                                                          */
  459. /* SUBROUTINE NAME:  StatusMCDDef                                           */
  460. /*                                                                          */
  461. /* DESCRIPTIVE NAME:  Status MCD Default                                    */
  462. /*                                                                          */
  463. /* FUNCTION:  Query the Status of MCD default flags.  This function is      */
  464. /*            called by ProcStatus().                                       */
  465. /*                                                                          */
  466. /* PARAMETERS:                                                              */
  467. /*      PINST pInst    -- pointer to instance.                              */
  468. /*      DWORD dwParam1 -- flag for this message.                            */
  469. /*      DWORD dwParam2 -- pointer to structure (message dependent).         */
  470. /*      DWORD dwAddr   -- current address.                                  */
  471. /*                                                                          */
  472. /* EXIT CODES:                                                              */
  473. /*      MCIERR_SUCCESS    -- action completed without error.                */
  474. /*      MCIERR_OUTOFRANGE -- invalid track supplied.                        */
  475. /*      MCIERR_FLAGS_NOT_COMPATIBLE -- Flags not compatible.                */
  476. /*      MCIERR_UNSUPPORTED_FUNCTION -- Unknown flag or value used.          */
  477. /*      MCIERR_DEVICE_NOT_READY   -- device was not ready, no disc.         */
  478. /*      MCIERR_INVALID_MEDIA_TYPE -- No audio tracks were found.            */
  479. /*                                                                          */
  480. /* NOTES: dwParam1 = MCI_STATUS_ITEM or MCI_STATUS_ITEM | MCI_TRACK         */
  481. /*                                   or MCI_STATUS_ITEM | MCI_STATUS_START  */
  482. /*                                                                          */
  483. /****************************************************************************/
  484.  
  485. DWORD StatusMCDDef(PINST pInst, DWORD dwParam1,
  486.                    MCI_STATUS_PARMS *dwParam2, DWORD dwAddr)
  487. {
  488.    DWORD rc = MCIERR_SUCCESS;
  489.    DWORD dwTrack;
  490.    ULONG ulMode;
  491.    MCI_CD_REGTRACK_REC *ptr1;
  492.  
  493.  
  494.    /****************** get track number and info ********************/
  495.  
  496.    if (dwParam1 & MCI_TRACK)
  497.    {
  498.       dwTrack = dwParam2->dwTrack;
  499.       ptr1 = GetTrackInfo(pInst, (BYTE) dwTrack, 0);
  500.       if (ptr1 == NULL)
  501.          rc = MCIERR_OUTOFRANGE;
  502.    }
  503.    else   /* get current track */
  504.    {
  505.       ptr1 = GetTrackInfo(pInst, 0, dwAddr);   //valid addr from drive
  506.       dwTrack = ptr1->TrackNum;
  507.    }  /* of else get current track */
  508.  
  509.    if (!DWORD_LOWD(rc))
  510.       switch(dwParam2->dwItem)
  511.       {
  512.          case MCI_STATUS_NUMBER_OF_TRACKS : // with MCI_TRACK, w/o already done
  513.             rc = MCIERR_FLAGS_NOT_COMPATIBLE;
  514.          case MCI_STATUS_POSITION :     // with MCI_TRACK, w/o already done
  515.             dwParam2->dwReturn = GetTimeAddr(pInst,
  516.                  (DWORD)(ptr1->dwStartAddr - pInst->dwOffset), FALSE);
  517.             rc = GetTimeAddrRC(pInst, rc);
  518.             break;
  519.          case MCI_STATUS_POSITION_IN_TRACK :
  520.             if (dwParam1 & MCI_TRACK)
  521.                rc = MCIERR_FLAGS_NOT_COMPATIBLE;
  522.             else
  523.             {
  524.                dwAddr -= ptr1->dwStartAddr + pInst->dwOffset;
  525.                dwParam2->dwReturn = GetTimeAddr(pInst, dwAddr, FALSE);
  526.                rc = GetTimeAddrRC(pInst, rc);
  527.             }
  528.             break;
  529.          case MCI_STATUS_LENGTH :       // with MCI_TRACK, w/o already done
  530.             dwAddr = ptr1->dwEndAddr - ptr1->dwStartAddr;
  531.             /* return MSF format for length if in TMSF format */
  532.             if ((pInst->ulMode & TIME_MODE) == CDMC_TMSF)
  533.             {
  534.                ulMode = pInst->ulMode;
  535.                pInst->ulMode = (pInst->ulMode & TIME_MODE_SET) | CDMC_REDBOOK;
  536.                dwParam2->dwReturn = GetTimeAddr(pInst, dwAddr, FALSE);
  537.                rc = GetTimeAddrRC(pInst, rc);
  538.                pInst->ulMode = ulMode;
  539.             }
  540.             else
  541.             {
  542.                dwParam2->dwReturn = GetTimeAddr(pInst, dwAddr, FALSE);
  543.                rc = GetTimeAddrRC(pInst, rc);
  544.             }
  545.             break;
  546.          case MCI_STATUS_CURRENT_TRACK :
  547.             if (dwParam1 & MCI_TRACK)
  548.                rc = MCIERR_FLAGS_NOT_COMPATIBLE;
  549.             else
  550.             {
  551.                dwParam2->dwReturn = dwTrack;
  552.                DWORD_HIWD(rc) = MCI_INTEGER_RETURNED;
  553.             }
  554.             break;
  555.          case MCI_CD_STATUS_TRACK_TYPE :
  556.             if (!(ptr1->TrackControl & IS_DATA_TRK))
  557.                dwParam2->dwReturn = MCI_CD_TRACK_AUDIO;
  558.             else if (ptr1->TrackControl & IS_OTHER_TRK)
  559.                dwParam2->dwReturn = MCI_CD_TRACK_OTHER;
  560.             else
  561.                dwParam2->dwReturn = MCI_CD_TRACK_DATA;
  562.             DWORD_HIWD(rc) = MCI_TRACK_TYPE_RETURN;
  563.             break;
  564.          case MCI_CD_STATUS_TRACK_COPYPERMITTED :
  565.             if (ptr1->TrackControl & IS_COPYABLE)
  566.                dwParam2->dwReturn = MCI_TRUE;
  567.             else
  568.                dwParam2->dwReturn = MCI_FALSE;
  569.             DWORD_HIWD(rc) = MCI_TRUE_FALSE_RETURN;
  570.             break;
  571.          case MCI_CD_STATUS_TRACK_CHANNELS :
  572.             if (!(ptr1->TrackControl & IS_DATA_TRK))      /* Is Audio ? */
  573.                if (ptr1->TrackControl & HAS_4_CHANS)
  574.                   dwParam2->dwReturn = 4L;
  575.                else
  576.                   dwParam2->dwReturn = 2L;
  577.             else                                          /* Data */
  578.                dwParam2->dwReturn = 0L;
  579.             DWORD_HIWD(rc) = MCI_INTEGER_RETURNED;
  580.             break;
  581.          case MCI_CD_STATUS_TRACK_PREEMPHASIS :
  582.             if (!(ptr1->TrackControl & IS_DATA_TRK))      /* Is Audio ? */
  583.                if (ptr1->TrackControl & IS_PRE_EMPH)
  584.                   dwParam2->dwReturn = MCI_TRUE;
  585.                else
  586.                   dwParam2->dwReturn = MCI_FALSE;
  587.             else                                          /* Data */
  588.                dwParam2->dwReturn = MCI_FALSE;
  589.             DWORD_HIWD(rc) = MCI_TRUE_FALSE_RETURN;
  590.             break;
  591.          /* no default value, all values were filtered in procStatus() */
  592.       }  /* of switch, track info needed */
  593.  
  594.    return(rc);
  595.  
  596. }  /* of StatusMCDDef() */
  597.  
  598.  
  599. /****************************************************************************/
  600. /*                                                                          */
  601. /* SUBROUTINE NAME:  StatusVSD                                              */
  602. /*                                                                          */
  603. /* DESCRIPTIVE NAME:  Status VSD                                            */
  604. /*                                                                          */
  605. /* FUNCTION:  Query the Status of VSD only flags.  This function is called  */
  606. /*            by ProcStatus().                                              */
  607. /*                                                                          */
  608. /* PARAMETERS:                                                              */
  609. /*      PINST pInst    -- pointer to instance.                              */
  610. /*      DWORD dwParam1 -- flag for this message.                            */
  611. /*      DWORD dwParam2 -- pointer to structure (message dependent).         */
  612. /*      DWORD rc       -- initial state, inactive, not ready, etc.          */
  613. /*                                                                          */
  614. /* EXIT CODES:                                                              */
  615. /*      MCIERR_SUCCESS    -- action completed without error.                */
  616. /*      MCIERR_DEVICE_NOT_READY   -- device was not ready, no disc.         */
  617. /*      MCIERR_INVALID_MEDIA_TYPE -- No audio tracks were found.            */
  618. /*                                                                          */
  619. /* NOTES: dwParam1 = MCI_STATUS_ITEM or MCI_STATUS_ITEM | MCI_TRACK         */
  620. /*                                                                          */
  621. /****************************************************************************/
  622.  
  623. DWORD StatusVSD(PINST pInst, DWORD dwParam1, MCI_STATUS_PARMS *dwParam2,
  624.                 DWORD rc)
  625. {
  626.    ULONG ulVol;
  627.    USHORT usStatus;
  628.    DWORD dwFlags, rsp = 0L;
  629.    MCI_STATUS_PARMS recStatus;
  630.  
  631.    if (!rc)
  632.    {
  633.       /* Query position to release any Disc Changes in VSD */
  634.       recStatus.dwItem = MCI_STATUS_POSITION;
  635.       dwFlags = MCI_STATUS_ITEM | MCI_WAIT;
  636.       rc = pInst->pMCIDriver(pInst->hHWMCID, MCI_STATUS,
  637.                              (DWORD) &dwFlags, (DWORD) &recStatus, 0);
  638.       if (DWORD_LOWD(rc))
  639.          rc = vsdResponse(pInst, rc);
  640.    }  /* of if no error */
  641.  
  642.    if (rc == MCIERR_INVALID_MEDIA_TYPE)
  643.    {
  644.       rsp = MCIERR_INVALID_MEDIA_TYPE;
  645.       rc = MCIERR_SUCCESS;
  646.    }
  647.  
  648.    if (!rc)
  649.    {
  650.       dwParam1 |= MCI_WAIT;
  651.       rc = pInst->pMCIDriver(pInst->hHWMCID, MCI_STATUS, (DWORD) &dwParam1,
  652.                          (DWORD) dwParam2, 0);
  653.       if (DWORD_LOWD(rc))
  654.          rc = vsdResponse(pInst, rc);       //if error, process response
  655.    }  /* of if no error */
  656.  
  657.    if (!(dwParam1 & MCI_TRACK))          //process known combinations flags
  658.       switch(dwParam2->dwItem)
  659.       {
  660.          case MCI_STATUS_MEDIA_PRESENT :
  661.             switch DWORD_LOWD(rc)
  662.             {
  663.                case MCIERR_SUCCESS :                //vsd already set dwReturn
  664.                   DWORD_HIWD(rc) = MCI_TRUE_FALSE_RETURN;
  665.                   if (dwParam2->dwReturn == MCI_FALSE)
  666.                      pInst->usStatus = NODISC;
  667.                   else if (rsp)
  668.                      rc = rsp;                     //report invalid media
  669.                   break;
  670.                case MCIERR_INSTANCE_INACTIVE :
  671.                   rc = MCIERR_SUCCESS;
  672.                   DWORD_HIWD(rc) = MCI_TRUE_FALSE_RETURN;
  673.                   usStatus = (USHORT)(pInst->usStatus - SUSPEND);
  674.                   if (usStatus == REGTRACK)
  675.                      rc = MCIERR_INVALID_MEDIA_TYPE;
  676.                   else if (usStatus <= NODISC)
  677.                      dwParam2->dwReturn = MCI_FALSE;
  678.                   else
  679.                      dwParam2->dwReturn = MCI_TRUE;
  680.                   break;
  681.                default :                            //return not present
  682.                   rc = MCIERR_SUCCESS;
  683.                   DWORD_HIWD(rc) = MCI_TRUE_FALSE_RETURN;
  684.                   dwParam2->dwReturn = MCI_FALSE;
  685.             }  /* of switch */
  686.             DWORD_HIWD(rc) = MCI_TRUE_FALSE_RETURN;
  687.             break;
  688.          case MCI_STATUS_MODE :
  689.             if (DWORD_LOWD(rc))
  690.             {
  691.                dwParam2->dwReturn = MCI_MODE_NOT_READY;
  692.                rc = MCIERR_SUCCESS;
  693.             }
  694.             else
  695.                if (dwParam2->dwReturn == MCI_MODE_STOP)
  696.                {
  697.                   if (pInst->usStatus == PAUSED)
  698.                      dwParam2->dwReturn = MCI_MODE_PAUSE;
  699.                }
  700.                else
  701.                   if (dwParam2->dwReturn == MCI_MODE_NOT_READY)
  702.                      pInst->usStatus = NODISC;
  703.  
  704.             DWORD_HIWD(rc) = MCI_MODE_RETURN;
  705.             break;
  706.          case MCI_STATUS_READY :
  707.             if (DWORD_LOWD(rc))
  708.             {
  709.                dwParam2->dwReturn = MCI_FALSE;
  710.                rc = MCIERR_SUCCESS;
  711.             }
  712.             else
  713.                if (dwParam2->dwReturn == MCI_FALSE)
  714.                   pInst->usStatus = NODISC;
  715.  
  716.             DWORD_HIWD(rc) = MCI_TRUE_FALSE_RETURN;
  717.             break;
  718.          case MCI_STATUS_VOLUME :
  719.             if (DWORD_LOWD(rc))          // if error
  720.                rsp = TRUE;
  721.             else
  722.             {
  723.                rsp = FALSE;
  724.                DWORD_HIWD(rc) = MCI_COLONIZED2_RETURN;
  725.  
  726.                /* adjust device volume to component volume */
  727.                if (pInst->dwMasterVolume && pInst->ulMode & CDMC_HEADPHONE)
  728.                {
  729.                   ulVol = (DWORD)VOL_LEFT(dwParam2->dwReturn) *
  730.                         100 / pInst->dwMasterVolume;
  731.                   if (ulVol > 100)
  732.                      VOL_LEFT(dwParam2->dwReturn) = 100;
  733.                   else
  734.                      VOL_LEFT(dwParam2->dwReturn) = (BYTE)ulVol;
  735.  
  736.                   ulVol = (DWORD)VOL_RIGHT(dwParam2->dwReturn) *
  737.                            100 / pInst->dwMasterVolume;
  738.                   if (ulVol > 100)
  739.                      VOL_RIGHT(dwParam2->dwReturn) = 100;
  740.                   else
  741.                      VOL_RIGHT(dwParam2->dwReturn) = (BYTE)ulVol;
  742.  
  743.                }  /* of if non-zero */
  744.                else
  745.                   /* master volume is 0%, return requested volume */
  746.                   rsp = TRUE;
  747.  
  748.             }  /* of else no error */
  749.  
  750.             if (rsp)  //unknown volume, ask VSD what component volume should be
  751.             {
  752.                if (rc == MCIERR_INSTANCE_INACTIVE)
  753.                   dwParam2->dwReturn = pInst->recSave.dwLevel;
  754.                else
  755.                {
  756.                   dwFlags = MCI_WAIT;
  757.                   recStatus.dwReturn = pInst->dwLevel;
  758.                   pInst->pMCIDriver(pInst->hHWMCID, MCIDRV_CD_STATUS_CVOL,
  759.                                     (DWORD) &dwFlags, (DWORD) &recStatus, 0);
  760.                   dwParam2->dwReturn = recStatus.dwReturn;
  761.                }
  762.                rc = (DWORD) MAKEULONG(MCIERR_SUCCESS, MCI_COLONIZED2_RETURN);
  763.             }
  764.  
  765.             break;
  766.       }  /* of switch */
  767.  
  768.    return(rc);
  769.  
  770. }  /* of StatusVSD() */
  771.  
  772.  
  773. /****************************************************************************/
  774. /*                                                                          */
  775. /* SUBROUTINE NAME:  DisableEvents             DEVELOPER:  Garry Lewis      */
  776. /*                                                                          */
  777. /* DESCRIPTIVE NAME:  Disable Events                                        */
  778. /*                                                                          */
  779. /* FUNCTION:  Disable cuepoint and position advise events from the VSD.     */
  780. /*            This is a requirement when the disc is changed.               */
  781. /*                                                                          */
  782. /* PARAMETERS:                                                              */
  783. /*      PINST pInst    -- pointer to instance.                              */
  784. /*                                                                          */
  785. /* EXIT CODES:  None                                                        */
  786. /*                                                                          */
  787. /* NOTES:                                                                   */
  788. /*                                                                          */
  789. /****************************************************************************/
  790.  
  791. VOID DisableEvents(PINST pInst)
  792. {
  793.    int i;
  794.    DWORD dwParam1;
  795.    MCI_CUEPOINT_PARMS recCuePoint;
  796.  
  797.    /* disable cuepoints */
  798.    dwParam1 = MCI_SET_CUEPOINT_OFF | MCI_WAIT;
  799.    for (i=0; i < CDMCD_CUEPOINT_MAX; i++)
  800.    {
  801.       if (pInst->arrCuePoint[i] != -1L)
  802.       {
  803.          recCuePoint.dwCuepoint = pInst->arrCuePoint[i];
  804.          pInst->pMCIDriver(pInst->hHWMCID, MCI_SET_CUEPOINT,
  805.                            (DWORD) &dwParam1, (DWORD) &recCuePoint, 0);
  806.          pInst->arrCuePoint[i] = (DWORD) -1L;
  807.       }  /* of if cuepoint is set */
  808.    }  /* of for loop of cuepoints */
  809.  
  810.    /* disable position advise */
  811.    dwParam1 = MCI_SET_POSITION_ADVISE_OFF | MCI_WAIT;
  812.    pInst->pMCIDriver(pInst->hHWMCID, MCI_SET_POSITION_ADVISE,
  813.                      (DWORD) &dwParam1, 0L, 0);
  814.  
  815. }  /* of DisableEvents() */
  816.  
  817.  
  818. /****************************************************************************/
  819. /*                                                                          */
  820. /* SUBROUTINE NAME:  GetTimeAddr                                            */
  821. /*                                                                          */
  822. /* DESCRIPTIVE NAME:  Get Time Address                                      */
  823. /*                                                                          */
  824. /* FUNCTION:  Convert to and from MMTime and other time formats.            */
  825. /*                                                                          */
  826. /* PARAMETERS:                                                              */
  827. /*      PINST pInst    -- pointer to instance.                              */
  828. /*      DWORD dwAddr   -- input address.                                    */
  829. /*      USHORT usTO    -- TRUE if to MMTime, FALSE if from MMTime.          */
  830. /*                                                                          */
  831. /* EXIT CODES:  DWORD  dwReturn -- the converted address.                   */
  832. /*                                                                          */
  833. /* NOTES:                                                                   */
  834. /*                                                                          */
  835. /*                                                                          */
  836. /****************************************************************************/
  837.  
  838. DWORD GetTimeAddr(PINST pInst, DWORD dwAddr, USHORT usTO)
  839. {
  840.    DWORD dwReturn;
  841.    MCI_CD_REGTRACK_REC *ptr;
  842.  
  843.    switch (pInst->ulMode & TIME_MODE)
  844.    {
  845.       case CDMC_MILLSEC :                          // milliseconds
  846.          if (usTO)
  847.             dwReturn = MSECTOMM(dwAddr);
  848.          else
  849.             dwReturn = MSECFROMMM(dwAddr);
  850.          break;
  851.       case CDMC_REDBOOK :                          // Red Book / MSF
  852.          if (usTO)
  853.             dwReturn = REDBOOKTOMM(dwAddr);
  854.          else
  855.             dwReturn = REDBOOKFROMMM(dwAddr);
  856.          break;
  857.       case CDMC_TMSF :                             // Track:Min:Sec:Frame
  858.          if (usTO)
  859.          {
  860.             ptr = GetTrackInfo(pInst, TMSF_TRACK(dwAddr), 0L);
  861.             if (ptr == NULL)
  862.                dwReturn = (DWORD) -1L;            // invalid track number
  863.             else
  864.             {
  865.                dwAddr = (dwAddr >> 8) & 0x00FFFFFF;     //TMSF -> MSF
  866.                dwReturn = ptr->dwStartAddr + REDBOOKTOMM(dwAddr);
  867.             }
  868.          }  /* of TO MMTIME */
  869.          else
  870.          {
  871.             ptr = GetTrackInfo(pInst, 0, dwAddr);
  872.             if (ptr == NULL)
  873.                dwReturn = (DWORD) -1L;            // invalid track number
  874.             else
  875.             {
  876.                dwAddr -= ptr->dwStartAddr;
  877.                dwReturn = (REDBOOKFROMMM(dwAddr) << 8) | (DWORD) ptr->TrackNum;
  878.             }
  879.          }  /* of else FROM MMTIME */
  880.          break;
  881.       case CDMC_MMTIME :                          // Multimedia Time
  882.       default :
  883.          dwReturn = dwAddr;
  884.    }  /* on switch */
  885.  
  886.    return(dwReturn);
  887.  
  888. }  /* of GetTimeAddr() */
  889.  
  890.  
  891. /****************************************************************************/
  892. /*                                                                          */
  893. /* SUBROUTINE NAME:  GetTimeAddrRC                                          */
  894. /*                                                                          */
  895. /* DESCRIPTIVE NAME:  Get Time Address Return Code                          */
  896. /*                                                                          */
  897. /* FUNCTION:  Return correct time format in the colinized code,             */
  898. /*            high word of the return code.                                 */
  899. /*                                                                          */
  900. /* PARAMETERS:                                                              */
  901. /*      PINST pInst    -- pointer to instance.                              */
  902. /*      DWORD dwAddr   -- input address.                                    */
  903. /*      USHORT usTO    -- TRUE if to MMTime, FALSE if from MMTime.          */
  904. /*                                                                          */
  905. /* EXIT CODES:  DWORD  rc  -- the converted return code.                    */
  906. /*                                                                          */
  907. /* NOTES:                                                                   */
  908. /*                                                                          */
  909. /*                                                                          */
  910. /****************************************************************************/
  911.  
  912. DWORD GetTimeAddrRC(PINST pInst, DWORD rc)
  913. {
  914.    switch (pInst->ulMode & TIME_MODE)
  915.    {
  916.       case CDMC_REDBOOK :                          // Red Book / MSF
  917.          DWORD_HIWD(rc) = MCI_COLONIZED3_RETURN;
  918.          break;
  919.       case CDMC_TMSF :                             // Track:Min:Sec:Frame
  920.          DWORD_HIWD(rc) = MCI_COLONIZED4_RETURN;
  921.          break;
  922.       case CDMC_MILLSEC :                          // milliseconds
  923.       case CDMC_MMTIME :                           // Multimedia Time
  924.       default :
  925.          DWORD_HIWD(rc) = MCI_INTEGER_RETURNED;
  926.    }  /* on switch */
  927.  
  928.    return(rc);
  929.  
  930. }  /* of GetTimeAddrRC() */
  931.  
  932.  
  933. /****************************************************************************/
  934. /*                                                                          */
  935. /* SUBROUTINE NAME:  GetTrackInfo                                           */
  936. /*                                                                          */
  937. /* DESCRIPTIVE NAME:  Get Track Information                                 */
  938. /*                                                                          */
  939. /* FUNCTION:  Find the Track entry for the given track or absolute address. */
  940. /*                                                                          */
  941. /* PARAMETERS:                                                              */
  942. /*      PINST pInst    -- pointer to instance.                              */
  943. /*      BYTE  Track    -- specified track number.                           */
  944. /*      DWORD dwAddr   -- specified absolute address, ignored if dwTrack    */
  945. /*                        is non-zero.                                      */
  946. /*                                                                          */
  947. /* EXIT CODES:  MCI_CD_REGTRACK_REC *pRet -- return pointer of track info,  */
  948. /*                                           NULL if error (invalid input). */
  949. /* NOTES:                                                                   */
  950. /*                                                                          */
  951. /*                                                                          */
  952. /****************************************************************************/
  953.  
  954. MCI_CD_REGTRACK_REC * GetTrackInfo(PINST pInst, BYTE Track, DWORD dwAddr)
  955. {
  956.    MCI_CD_REGTRACK_REC *pRet;
  957.    USHORT i, usOffset;                  //Number of Tracks - 1
  958.  
  959.    if (Track)                                         // if a track was used
  960.       if (pInst->recDisc.LowestTrackNum <= Track &&      // and is valid
  961.           pInst->recDisc.HighestTrackNum >= Track)
  962.          pRet = pInst->recTrack.TrackRecArr +            // get track info
  963.                   (Track - pInst->recDisc.LowestTrackNum);
  964.       else
  965.          pRet = NULL;                                    // else error
  966.    else                                                // otherwise an address
  967.    {
  968.       usOffset = pInst->recDisc.HighestTrackNum - pInst->recDisc.LowestTrackNum;
  969.  
  970.       /* check if address is in a valid range */
  971.       if (pInst->recTrack.TrackRecArr->dwStartAddr <= dwAddr &&
  972.           (pInst->recTrack.TrackRecArr + usOffset)->dwEndAddr >= dwAddr)
  973.       {
  974.          /* for every track, check address bounds until dwAddr is found */
  975.          /* if not found it must be the last track since the addr is valid */
  976.          for (i= 0; i < usOffset; i++)
  977.             if ((pInst->recTrack.TrackRecArr + i)->dwStartAddr <= dwAddr &&
  978.                 (pInst->recTrack.TrackRecArr + i)->dwEndAddr > dwAddr)
  979.                break;
  980.          pRet = pInst->recTrack.TrackRecArr + i;
  981.  
  982.       }  /* of if a valid address */
  983.       else
  984.          pRet = NULL;                                    // else error
  985.    }  /* of else an address is used */
  986.  
  987.    return(pRet);
  988.  
  989. }  /* of GetTrackInfo() */
  990.  
  991.  
  992. /****************************************************************************/
  993. /*                                                                          */
  994. /* SUBROUTINE NAME:  ValAddress                                             */
  995. /*                                                                          */
  996. /* DESCRIPTIVE NAME:  Validate Address                                      */
  997. /*                                                                          */
  998. /* FUNCTION:  Validate Redbook Audio address in MMTIME format.              */
  999. /*                                                                          */
  1000. /* PARAMETERS:                                                              */
  1001. /*      PINST pInst    -- pointer to instance.                              */
  1002. /*      DWORD *pwFrom  -- address to be tested and returned.                */
  1003. /*      DWORD *pwTo    -- address to be tested and returned.                */
  1004. /*      USHORT isPlay  -- type of check (TRUE = play, FALSE - seek).        */
  1005. /*                                                                          */
  1006. /* EXIT CODES:                                                              */
  1007. /*      MCIERR_SUCCESS    -- action completed without error.                */
  1008. /*      MCIERR_OUTOFRANGE -- cannot play in reverse.                        */
  1009. /*                                                                          */
  1010. /* NOTES:                                                                   */
  1011. /*                                                                          */
  1012. /*                                                                          */
  1013. /****************************************************************************/
  1014.  
  1015. DWORD ValAddress(PINST pInst, DWORD *pdwFrom, DWORD *pdwTo, USHORT isPlay)
  1016. {
  1017.    DWORD rc;
  1018.  
  1019.    rc = MCIERR_SUCCESS;
  1020.  
  1021.    /* validate TO */
  1022.    if (*pdwTo < pInst->dwStart_disk)
  1023.       rc = MCIERR_OUTOFRANGE;
  1024.    else
  1025.       if (isPlay)
  1026.       {
  1027.          if (*pdwTo > pInst->dwEnd_disk)
  1028.             rc = MCIERR_OUTOFRANGE;
  1029.       }
  1030.       else
  1031.          /* dwEnd_disk is really the starting frame or sector of the next */
  1032.          /* track, usually the Lead Out Track.  Valid seeks should be     */
  1033.          /* contained within playable tracks.                             */
  1034.          if (*pdwTo > pInst->dwEnd_disk - MMT_FRAME)
  1035.             rc = MCIERR_OUTOFRANGE;
  1036.  
  1037.    /* Validate from address if needed */
  1038.    if (!rc && isPlay)
  1039.    {
  1040.       if (*pdwFrom < pInst->dwStart_disk)
  1041.          rc = MCIERR_OUTOFRANGE;
  1042.       else if (*pdwTo > pInst->dwEnd_disk)
  1043.          rc = MCIERR_OUTOFRANGE;
  1044.  
  1045.       /* validate direction */
  1046.       /* can only go forward if HW can't play in reverse or if streaming */
  1047.       if (*pdwFrom > *pdwTo &&
  1048.              (!(pInst->wCaps & CDVSD_CAP_CAN_REVERSE) ||
  1049.                (pInst->ulMode & CDMC_STREAM)))
  1050.          rc = MCIERR_OUTOFRANGE;
  1051.  
  1052.    }  /* of if validating FROM */
  1053.  
  1054.    return(rc);
  1055.  
  1056. }  /* of ValAddress() */
  1057.  
  1058.  
  1059. /****************************************************************************/
  1060. /*                                                                          */
  1061. /* SUBROUTINE NAME:  ValState                                               */
  1062. /*                                                                          */
  1063. /* DESCRIPTIVE NAME:  Validate State                                        */
  1064. /*                                                                          */
  1065. /* FUNCTION:  Validate State of an Instance.  Most commands need to have    */
  1066. /*            a disc and not be suspended.                                  */
  1067. /*                                                                          */
  1068. /* PARAMETERS:                                                              */
  1069. /*      PINST pInst     -- pointer to instance.                             */
  1070. /*                                                                          */
  1071. /* EXIT CODES:                                                              */
  1072. /*      MCIERR_SUCCESS    -- action completed without error.                */
  1073. /*      MCIERR_DEVICE_NOT_READY -- No Disc is present.                      */
  1074. /*      MCIERR_INSTANCE_INACTIVE -- Instance is suspended.                  */
  1075. /*      MCIERR_INVALID_MEDIA_TYPE -- No audio tracks were found.            */
  1076. /*                                                                          */
  1077. /* NOTES:                                                                   */
  1078. /*                                                                          */
  1079. /*                                                                          */
  1080. /****************************************************************************/
  1081.  
  1082. DWORD ValState(PINST pInst)
  1083. {
  1084.    DWORD rc;
  1085.  
  1086.    /* if tracks were registered then we should be stopped, */
  1087.    /*    unless no audio tracks exists.                    */
  1088.    if (pInst->usStatus == REGTRACK)
  1089.       rc = MCIERR_INVALID_MEDIA_TYPE;
  1090.    else if (pInst->usStatus <= NODISC)
  1091.       rc = MCIERR_DEVICE_NOT_READY;
  1092.    else if (pInst->usStatus >= SUSPEND)
  1093.       rc = MCIERR_INSTANCE_INACTIVE;
  1094.    else
  1095.       rc = MCIERR_SUCCESS;
  1096.  
  1097.    return(rc);
  1098.  
  1099. }  /* of ValState() */
  1100.  
  1101.  
  1102. /****************************************************************************/
  1103. /*                                                                          */
  1104. /* SUBROUTINE NAME:  vsdResponse                                            */
  1105. /*                                                                          */
  1106. /* DESCRIPTIVE NAME:  Vendor Supplied Driver Response                       */
  1107. /*                                                                          */
  1108. /* FUNCTION:  Process the response from a VSD.                              */
  1109. /*                                                                          */
  1110. /* PARAMETERS:                                                              */
  1111. /*      PINST pInst    -- pointer to instance.                              */
  1112. /*      DWORD dwResponse -- received response.                              */
  1113. /*                                                                          */
  1114. /* EXIT CODES:                                                              */
  1115. /*      MCIERR_DEVICE_NOT_READY   -- device was not ready, no disc.         */
  1116. /*      MCIERR_INVALID_MEDIA_TYPE -- No audio tracks were found.            */
  1117. /*                                                                          */
  1118. /* NOTES:                                                                   */
  1119. /*                                                                          */
  1120. /*                                                                          */
  1121. /****************************************************************************/
  1122.  
  1123. DWORD vsdResponse(PINST pInst, DWORD dwResponse)
  1124. {
  1125.    DWORD rc;
  1126.  
  1127.    switch (DWORD_LOWD(dwResponse))
  1128.    {
  1129.       case MCIERR_DEVICE_NOT_READY :
  1130.          pInst->usStatus = NODISC;
  1131.          rc = dwResponse;
  1132.          break;
  1133.       case MCIERR_MEDIA_CHANGED :
  1134.          rc = ReRegister(pInst);
  1135.          break;
  1136.       default :
  1137.          rc = dwResponse;
  1138.    }   /* of switch */
  1139.  
  1140.    return(rc);
  1141.  
  1142. }  /* of vsdResponse() */
  1143.  
  1144.  
  1145.