home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / VSCPPv8.zip / VACPP / IBMCPP / samples / TOOLKIT / MM / CDMCIDRV / CDAUDUTL.C < prev    next >
C/C++ Source or Header  |  1994-11-17  |  53KB  |  1,145 lines

  1. /****************************************************************************/
  2. /*                                                                          */
  3. /* SOURCE FILE NAME:  CDAUDUTL.C                                            */
  4. /*                                                                          */
  5. /* DESCRIPTIVE NAME:  CD AUDIO MCI DRIVER UTILITIES                         */
  6. /*                                                                          */
  7. /* COPYRIGHT:  (c) IBM Corp. 1991 - 1993                                    */
  8. /*                                                                          */
  9. /* FUNCTION:  This file contains the hardware independent code that         */
  10. /*            supplement the PROCESS commands in CDAUDPRO.C for the         */
  11. /*            CD Audio MCI Driver uses.  The entry point to the DLL is      */
  12. /*            in CDAUDIO.C                                                  */
  13. /*                                                                          */
  14. /* NOTES:  The hardware dependent code is found in file IBMCDROM.C.         */
  15. /*                                                                          */
  16. /* OTHER FUNCTIONS:                                                         */
  17. /*       SetAudio      - Set audio information from MCI_SET.                */
  18. /*       SetConnector  - Enable or disable connection.                      */
  19. /*       SetCuePoint   - Enable cue point.                                  */
  20. /*       StatusMCD     - Get status from MCD information.                   */
  21. /*       StatusMCDDef  - Get status from MCD default information.           */
  22. /*       StatusVSD     - Get status from VSD information.                   */
  23. /*       DisableEvents - Disable cuepoints and position advise.             */
  24. /*       GetTimeAddr   - Convert a time format to/from MMTIME.              */
  25. /*       GetTimeAddrRC - Colinize return code to time format.               */
  26. /*       GetTrackInfo  - Get Track info for specified track or address.     */
  27. /*       ValAddress    - Validate address for play and seek commands.       */
  28. /*       ValState      - Validate state, has disc and not suspended.        */
  29. /*       vsdResponse   - Process VSD Response.                              */
  30. /*                                                                          */
  31. /*                                                                          */
  32. /****************************************************************************/
  33.  
  34. #define INCL_DOSERRORS
  35. #define INCL_DOSPROCESS
  36. #define INCL_DOSMEMMGR
  37. #define INCL_DOSMODULEMGR
  38. #define INCL_DOSSEMAPHORES
  39. #include <os2.h>
  40. #include <string.h>
  41. #define INCL_MCIOS2
  42. #include <os2me.h>
  43. #include <cdaudos2.h>
  44. #include "cdaudibm.h"
  45. #include <ctype.h>
  46.  
  47.  
  48. /****************************************************************************/
  49. /*                                                                          */
  50. /* SUBROUTINE NAME:  SetAudio                                               */
  51. /*                                                                          */
  52. /* DESCRIPTIVE NAME:  Set Audio                                             */
  53. /*                                                                          */
  54. /* FUNCTION:  Set Audio information when MCI_SET_AUDIO flag is used with    */
  55. /*            MCI_SET command.  This function is called by ProcSet().       */
  56. /*                                                                          */
  57. /* PARAMETERS:                                                              */
  58. /*      PINST pInst      -- pointer to instance.                            */
  59. /*      ULONG *pulParam1 -- flag for this message.                          */
  60. /*      MCI_SET_PARMS *pParam2 -- pointer to local SET structure.           */
  61. /*      ULONG *pulMode   -- mode flags.                                     */
  62. /*      ULONG *pulLevel  -- volume level.                                   */
  63. /*                                                                          */
  64. /* EXIT CODES:                                                              */
  65. /*      MCIERR_SUCCESS    -- action completed without error.                */
  66. /*      MCIERR_FLAGS_NOT_COMPATIBLE -- Flags not compatible.                */
  67. /*      MCIERR_INVALID_AUDIO_FLAG   -- Unknown audio flag specified.        */
  68. /*                                                                          */
  69. /* NOTES:                                                                   */
  70. /*                                                                          */
  71. /****************************************************************************/
  72.  
  73. ULONG SetAudio(PINST pInst, ULONG *pulParam1, MCI_SET_PARMS *pParam2,
  74.                ULONG *pulMode, ULONG *pulLevel)
  75. {
  76.    ULONG rc = MCIERR_SUCCESS;          // assume the best
  77.    USHORT usFlag = 0;
  78.    ULONG  ulChan = 0;
  79.    USHORT left, right;
  80.  
  81.    if (*pulParam1 & MCI_SET_ON && *pulParam1 & MCI_SET_OFF)
  82.       rc = MCIERR_FLAGS_NOT_COMPATIBLE;
  83.    else
  84.       switch (pParam2->ulAudio)
  85.       {
  86.          case MCI_SET_AUDIO_LEFT :
  87.             ulChan = CDMC_LFT_CH;
  88.             break;
  89.          case MCI_SET_AUDIO_RIGHT :
  90.             ulChan = CDMC_RGT_CH;
  91.             break;
  92.          case MCI_SET_AUDIO_ALL :
  93.             ulChan = CDMC_ALL_CH;
  94.             break;
  95.          default : rc = MCIERR_INVALID_AUDIO_FLAG;
  96.       }  /* of switch */
  97.  
  98.  
  99.    if (!rc)
  100.    {
  101.       *pulParam1 ^= MCI_SET_AUDIO;       // remove non VSD flag
  102.  
  103.       /* Remove flag for vectored volume, not supported in this example */
  104.       if (*pulParam1 & MCI_OVER)
  105.          *pulParam1 ^= MCI_OVER;
  106.  
  107.       if (*pulParam1 & MCI_SET_ON)
  108.       {
  109.          usFlag = 1;
  110.          *pulParam1 ^= MCI_SET_ON;       // remove non VSD flag
  111.          *pulMode |= ulChan;
  112.       }  /* of else if ON */
  113.       else if (*pulParam1 & MCI_SET_OFF)
  114.       {
  115.          usFlag = 1;
  116.          *pulParam1 ^= MCI_SET_OFF;      // remove non VSD flag
  117.          if (ulChan & CDMC_LFT_CH)
  118.             *pulMode &= CHAN_MODE_SET | CDMC_RGT_CH;
  119.          if (ulChan & CDMC_RGT_CH)
  120.             *pulMode &= CHAN_MODE_SET | CDMC_LFT_CH;
  121.       }  /* of else if OFF */
  122.  
  123.       if (*pulParam1 & MCI_SET_VOLUME)
  124.       {
  125.          usFlag = 1;
  126.          /* get requested volume levels */
  127.          left  = (USHORT) pParam2->ulLevel;
  128.          right = (USHORT) pParam2->ulLevel;
  129.  
  130.          if (ulChan & CDMC_LFT_CH)
  131.             if (left > 100)
  132.                VOL_LEFT(*pulLevel) = 100;
  133.             else
  134.                VOL_LEFT(*pulLevel) = left;
  135.          if (ulChan & CDMC_RGT_CH)
  136.             if (right > 100)
  137.                VOL_RIGHT(*pulLevel) = 100;
  138.             else
  139.                VOL_RIGHT(*pulLevel) = right;
  140.       }  /* of setting volume */
  141.  
  142.       if (usFlag)                // CHANGE, SET VOLUME
  143.       {
  144.          /* Go ahead and prepare for call to VSD */
  145.          if (*pulMode & CDMC_LFT_CH && pInst->ulMode & CDMC_HEADPHONE)
  146.             left = (USHORT)((ULONG)VOL_LEFT(*pulLevel) *
  147.                    pInst->ulMasterVolume / 100);
  148.          else           /* else channel is muted */
  149.             left = 0;
  150.          if (*pulMode & CDMC_RGT_CH && pInst->ulMode & CDMC_HEADPHONE)
  151.             right = (USHORT)((ULONG)VOL_RIGHT(*pulLevel) *
  152.                    pInst->ulMasterVolume / 100);
  153.          else           /* else channel is muted */
  154.             right = 0;
  155.          pParam2->ulLevel = MAKEULONG(left, right);
  156.          *pulParam1 |= MCI_SET_VOLUME;      //make sure VSD flag is set
  157.  
  158.       }  /* of if change */
  159.       else
  160.          rc = MCIERR_MISSING_FLAG;
  161.    }  /* of if no error with flags */
  162.  
  163.    return(rc);
  164.  
  165. }  /* of SetAudio() */
  166.  
  167.  
  168. /****************************************************************************/
  169. /*                                                                          */
  170. /* SUBROUTINE NAME:  SetConnector                                           */
  171. /*                                                                          */
  172. /* DESCRIPTIVE NAME:  Set Connector                                         */
  173. /*                                                                          */
  174. /* FUNCTION:  Enable or disable connectors from the MCI_CONNECTOR command.  */
  175. /*            This function is called by ProcConnector().                   */
  176. /*                                                                          */
  177. /* PARAMETERS:                                                              */
  178. /*      PINST pInst    -- pointer to instance.                              */
  179. /*      ULONG ulParam1 -- flag for this message.                            */
  180. /*                                                                          */
  181. /* EXIT CODES:                                                              */
  182. /*      MCIERR_SUCCESS    -- action completed without error.                */
  183. /*      MCIERR_DEVICE_NOT_READY  -- No Disc is present.                     */
  184. /*      MCIERR_UNSUPPORTED_FLAG     -- cannot process constant.             */
  185. /*      MCIERR_FLAGS_NOT_COMPATIBLE -- Invalid flag combinations.           */
  186. /*      MCIERR_INVALID_FLAG         -- Unknown or unsupported flag.         */
  187. /*      MCIERR_CANNOT_LOAD_DRIVER -- Unable to load VSD.                    */
  188. /*                                                                          */
  189. /* NOTES:   ProcConnector() calls this function only when                   */
  190. /*          MCI_ENABLE_CONNECTOR or MCI_DISABLE_CONNECTOR flags were used.  */
  191. /*                                                                          */
  192. /****************************************************************************/
  193.  
  194. ULONG SetConnector(PINST pInst, ULONG ulParam1)
  195. {
  196.    ULONG rsp, rc = MCIERR_SUCCESS;          // assume the best
  197.    MCI_STATUS_PARMS recStatus;
  198.  
  199.    /* get current position -- will be placed in pInst->ulCur_pos */
  200.    /* don't use recStatus.ulReturn, it will be adjusted with     */
  201.    /*   sync offset and current time format setting              */
  202.    recStatus.ulItem = MCI_STATUS_POSITION;
  203.    rsp = ProcStatus(pInst, MCI_STATUS_ITEM, &recStatus);
  204.  
  205.    if (ulParam1 & MCI_ENABLE_CONNECTOR)          // *** ENABLE DAC ***
  206.    {
  207.       if (pInst->ulMode & CDMC_CAN_DAC)
  208.       {
  209.          /* do it if not already playing internally */
  210.          if (!(pInst->ulMode & CDMC_INTDAC))
  211.             pInst->ulMode = pInst->ulMode & STREAM_MODE_SET | CDMC_INTDAC;
  212.  
  213.       }  /* of if can enable DAC */
  214.       else
  215.          rc = MCIERR_UNSUPPORTED_FLAG;           //no internal DAC
  216.    }  /* of if enable */
  217.    else                             // *** DISABLE DAC ***
  218.    {
  219.       if (pInst->ulMode & CDMC_INTDAC)
  220.       {
  221.          ProcStop(pInst, MCI_WAIT);
  222.          pInst->ulMode ^= CDMC_INTDAC;
  223.       }   /* of if playing internal DAC */
  224.    }  /* of if disable */
  225.  
  226.    return(rc);
  227.  
  228. }  /* of SetConnector() */
  229.  
  230.  
  231. /****************************************************************************/
  232. /*                                                                          */
  233. /* SUBROUTINE NAME:  SetCuePoint                                            */
  234. /*                                                                          */
  235. /* DESCRIPTIVE NAME:  Set Cue Point                                         */
  236. /*                                                                          */
  237. /* FUNCTION:  Set Cue Point from the MCI_SET_CUEPOINT command.              */
  238. /*                                                                          */
  239. /* PARAMETERS:                                                              */
  240. /*      PINST pInst    -- pointer to instance.                              */
  241. /*      ULONG ulParam1 -- flag for this message.                            */
  242. /*      PVOID pParam2  -- pointer to structure (message dependent).         */
  243. /*                                                                          */
  244. /* EXIT CODES:                                                              */
  245. /*      MCIERR_SUCCESS    -- action completed without error.                */
  246. /*      MCIERR_OUTOFRANGE -- invalid cuepoint position.                     */
  247. /*      MCIERR_DEVICE_NOT_READY -- No Disc is present.                      */
  248. /*      MCIERR_CUEPOINT_LIMIT_REACHED --  no more room to add events.       */
  249. /*      MCIERR_DUPLICATE_CUEPOINT     --  duplicate cuepoint.               */
  250. /*                                                                          */
  251. /* NOTES:                                                                   */
  252. /*                                                                          */
  253. /****************************************************************************/
  254.  
  255. ULONG SetCuePoint(PINST pInst, MCI_CUEPOINT_PARMS *pParam2)
  256. {
  257.    ULONG rc, ulTime, ulFlags;
  258.    int i, found = -1;
  259.    MCI_CUEPOINT_PARMS recCuePoint;
  260.  
  261.    /* validate time */
  262.    ulTime = GetTimeAddr(pInst, pParam2->ulCuepoint, TRUE);
  263.    if (ulTime == (ULONG) -1L)
  264.       rc = MCIERR_OUTOFRANGE;         // invalid track number
  265.    else
  266.    {
  267.       ulTime += pInst->ulOffset;
  268.       if (ulTime < pInst->ulStart_disk ||
  269.           ulTime > pInst->ulEnd_disk)
  270.          rc = MCIERR_OUTOFRANGE;
  271.       else
  272.          rc = MCIERR_SUCCESS;
  273.    }
  274.  
  275.    /* make sure cuepoint is unique */
  276.    if (!rc)
  277.    {
  278.       for (i=0; i < CDMCD_CUEPOINT_MAX; i++)
  279.       {
  280.          if (pInst->arrCuePoint[i] == (ULONG) -1L)
  281.          {
  282.             if (found < 0)
  283.                found = i;      // save first available entry
  284.          }
  285.          else
  286.             if (pInst->arrCuePoint[i] == ulTime)
  287.             {
  288.                rc = MCIERR_DUPLICATE_CUEPOINT;
  289.                break;               // error end for loop
  290.             }
  291.       }  /* of for loop */
  292.  
  293.       if (!rc)
  294.          if (found < 0)
  295.             rc = MCIERR_CUEPOINT_LIMIT_REACHED;
  296.    }  /* of if no error, test uniqueness */
  297.  
  298.    /* init record and relay message */
  299.    if (!rc)
  300.    {
  301.       pInst->arrCuePoint[found] = ulTime;
  302.       /* copy record so as not to change original from application */
  303.       memcpy(&recCuePoint, pParam2, sizeof(MCI_CUEPOINT_PARMS));
  304.       pParam2->ulCuepoint = ulTime;
  305.       ulFlags = MCI_SET_CUEPOINT_ON | MCI_WAIT;
  306.       rc = pInst->pMCIDriver(pInst->hHWMCID, MCI_SET_CUEPOINT,
  307.                              &ulFlags, pParam2, 0);
  308.  
  309.       if (rc)                            // clear entry
  310.          pInst->arrCuePoint[found] = -1L;
  311.  
  312.    }  /* of if no error, init record */
  313.  
  314.    return(rc);
  315.  
  316. }  /* of SetCuePoint() */
  317.  
  318.  
  319. /****************************************************************************/
  320. /*                                                                          */
  321. /* SUBROUTINE NAME:  StatusMCD                                              */
  322. /*                                                                          */
  323. /* DESCRIPTIVE NAME:  Status MCD                                            */
  324. /*                                                                          */
  325. /* FUNCTION:  Query the Status of MCD flags.  This function is called       */
  326. /*            by ProcStatus().                                              */
  327. /*                                                                          */
  328. /* PARAMETERS:                                                              */
  329. /*      PINST  pInst    -- pointer to instance.                             */
  330. /*      ULONG  ulParam1 -- flag for this message.                           */
  331. /*      PVOID  pParam2  -- pointer to structure (message dependent).        */
  332. /*      ULONG  rsp      -- state response.                                  */
  333. /*      USHORT usIgnore -- ignore invalid media type.                       */
  334. /*                                                                          */
  335. /* EXIT CODES:                                                              */
  336. /*      MCIERR_SUCCESS    -- action completed without error.                */
  337. /*      MCIERR_OUTOFRANGE -- invalid track supplied.                        */
  338. /*      MCIERR_FLAGS_NOT_COMPATIBLE -- Flags not compatible.                */
  339. /*      MCIERR_UNSUPPORTED_FUNCTION -- Unknown flag or value used.          */
  340. /*      MCIERR_DEVICE_NOT_READY   -- device was not ready, no disc.         */
  341. /*      MCIERR_INVALID_MEDIA_TYPE -- No audio tracks were found.            */
  342. /*                                                                          */
  343. /* NOTES: ulParam1 = MCI_STATUS_ITEM or MCI_STATUS_ITEM | MCI_TRACK         */
  344. /*                                   or MCI_STATUS_ITEM | MCI_STATUS_START  */
  345. /*                                                                          */
  346. /****************************************************************************/
  347.  
  348. ULONG StatusMCD(PINST pInst, ULONG ulParam1, MCI_STATUS_PARMS *pParam2,
  349.                 ULONG rsp, USHORT usIgnore)
  350. {
  351.    ULONG rc;
  352.    ULONG ulAddr, ulTrack, ulFlags;
  353.    MCI_CD_REGTRACK_REC *ptr1, *ptr2;
  354.    MCI_STATUS_PARMS recStatus;
  355.    ULONG ulMode;
  356.  
  357.    /* Make sure disc is present before you rely on cache */
  358.    if (rsp)
  359.    {
  360.       if (rsp == MCIERR_INSTANCE_INACTIVE)
  361.          if (pInst->usStatus - SUSPEND == REGTRACK)
  362.             rc = MCIERR_INVALID_MEDIA_TYPE;
  363.          else if (pInst->usStatus - SUSPEND <= NODISC)
  364.             rc = MCIERR_DEVICE_NOT_READY;
  365.          else
  366.          {
  367.             rc = MCIERR_SUCCESS;    // process inactive command
  368.             recStatus.ulReturn = pInst->ulCur_pos;
  369.          }
  370.       else
  371.          rc = rsp;
  372.    }  /* of if known error */
  373.    else
  374.    {
  375.       recStatus.ulItem = MCI_STATUS_POSITION;
  376.       ulFlags = MCI_STATUS_ITEM | MCI_WAIT;
  377.       rc = pInst->pMCIDriver(pInst->hHWMCID, MCI_STATUS,
  378.                              &ulFlags, &recStatus, 0);
  379.       if (ULONG_LOWD(rc))
  380.       {
  381.          rc = vsdResponse(pInst, rc);
  382.          if (!rc)                    //Disc Change, get starting address
  383.             recStatus.ulReturn = pInst->ulStart_disk;
  384.       }  /* of if error */
  385.  
  386.       if (!ULONG_LOWD(rc))
  387.          pInst->ulCur_pos = recStatus.ulReturn;    // valid value, keep it
  388.    }  /* of else no error so check disc */
  389.  
  390.    if (rc == MCIERR_INVALID_MEDIA_TYPE && usIgnore)
  391.       rc = MCIERR_SUCCESS;
  392.  
  393.    if (ULONG_LOWD(rc))
  394.       return(rc);
  395.  
  396.    /*----------- End of checking presents of Disc -----------------*/
  397.  
  398.    switch (ulParam1)
  399.    {
  400.       case MCI_STATUS_ITEM | MCI_TRACK :
  401.          rc = StatusMCDDef(pInst, ulParam1, pParam2, recStatus.ulReturn);
  402.          break;
  403.       case MCI_STATUS_ITEM | MCI_STATUS_START :
  404.          /* item must be MCI_STATUS_POSITION from ProcStatus() */
  405.          pParam2->ulReturn =  GetTimeAddr(pInst, pInst->ulStart_disk, FALSE);
  406.          rc = GetTimeAddrRC(pInst, rc);
  407.          break;
  408.       default :                            // must be MCI_STATUS_ITEM alone
  409.          switch(pParam2->ulItem)
  410.          {
  411.             case MCI_STATUS_POSITION :
  412.                pParam2->ulReturn =  GetTimeAddr(pInst,
  413.                          (ULONG)(recStatus.ulReturn - pInst->ulOffset), FALSE);
  414.                rc = GetTimeAddrRC(pInst, rc);
  415.                break;
  416.             case MCI_STATUS_LENGTH :
  417.                ulTrack = pInst->recTrack.ulBufSize /
  418.                          sizeof(MCI_CD_REGTRACK_REC);
  419.                ulAddr = (pInst->recTrack.TrackRecArr + ulTrack-1)->ulEndAddr -
  420.                          pInst->recTrack.TrackRecArr->ulStartAddr;
  421.                /* return MSF format for length if in TMSF format */
  422.                if ((pInst->ulMode & TIME_MODE) == CDMC_TMSF)
  423.                {
  424.                   ulMode = pInst->ulMode;
  425.                   pInst->ulMode = pInst->ulMode & TIME_MODE_SET | CDMC_REDBOOK;
  426.                   pParam2->ulReturn = GetTimeAddr(pInst, ulAddr, FALSE);
  427.                   rc = GetTimeAddrRC(pInst, rc);
  428.                   pInst->ulMode = ulMode;
  429.                }
  430.                else
  431.                {
  432.                   pParam2->ulReturn = GetTimeAddr(pInst, ulAddr, FALSE);
  433.                   rc = GetTimeAddrRC(pInst, rc);
  434.                }
  435.                break;
  436.             case MCI_STATUS_NUMBER_OF_TRACKS :
  437.                ptr1 = GetTrackInfo(pInst, 0, pInst->ulStart_disk);
  438.                ptr2 = GetTrackInfo(pInst, 0, pInst->ulEnd_disk - 1);
  439.                if (ptr1 && ptr2)         //if both pointers are valid
  440.                   pParam2->ulReturn = ptr2->TrackNum - ptr1->TrackNum + 1;
  441.                else
  442.                   pParam2->ulReturn = 0L;
  443.                ULONG_HIWD(rc) = MCI_INTEGER_RETURNED;
  444.                break;
  445.             default :
  446.                rc = StatusMCDDef(pInst, ulParam1, pParam2, recStatus.ulReturn);
  447.  
  448.          }  /* of switch, known items */
  449.    }  /* of switch, flags */
  450.  
  451.    return(rc);
  452.  
  453. }  /* of StatusMCD() */
  454.  
  455.  
  456. /****************************************************************************/
  457. /*                                                                          */
  458. /* SUBROUTINE NAME:  StatusMCDDef                                           */
  459. /*                                                                          */
  460. /* DESCRIPTIVE NAME:  Status MCD Default                                    */
  461. /*                                                                          */
  462. /* FUNCTION:  Query the Status of MCD default flags.  This function is      */
  463. /*            called by ProcStatus().                                       */
  464. /*                                                                          */
  465. /* PARAMETERS:                                                              */
  466. /*      PINST pInst    -- pointer to instance.                              */
  467. /*      ULONG ulParam1 -- flag for this message.                            */
  468. /*      PVOID pParam2  -- pointer to structure (message dependent).         */
  469. /*      ULONG ulAddr   -- current address.                                  */
  470. /*                                                                          */
  471. /* EXIT CODES:                                                              */
  472. /*      MCIERR_SUCCESS    -- action completed without error.                */
  473. /*      MCIERR_OUTOFRANGE -- invalid track supplied.                        */
  474. /*      MCIERR_FLAGS_NOT_COMPATIBLE -- Flags not compatible.                */
  475. /*      MCIERR_UNSUPPORTED_FUNCTION -- Unknown flag or value used.          */
  476. /*      MCIERR_DEVICE_NOT_READY   -- device was not ready, no disc.         */
  477. /*      MCIERR_INVALID_MEDIA_TYPE -- No audio tracks were found.            */
  478. /*                                                                          */
  479. /* NOTES: ulParam1 = MCI_STATUS_ITEM or MCI_STATUS_ITEM | MCI_TRACK         */
  480. /*                                   or MCI_STATUS_ITEM | MCI_STATUS_START  */
  481. /*                                                                          */
  482. /****************************************************************************/
  483.  
  484. ULONG StatusMCDDef(PINST pInst, ULONG ulParam1,
  485.                    MCI_STATUS_PARMS *pParam2, ULONG ulAddr)
  486. {
  487.    ULONG rc = MCIERR_SUCCESS;
  488.    ULONG ulTrack;
  489.    ULONG ulMode;
  490.    MCI_CD_REGTRACK_REC *ptr1;
  491.  
  492.  
  493.    /****************** get track number and info ********************/
  494.  
  495.    if (ulParam1 & MCI_TRACK)
  496.    {
  497.       ulTrack = pParam2->ulValue;
  498.       ptr1 = GetTrackInfo(pInst, (BYTE) ulTrack, 0);
  499.       if (ptr1 == NULL)
  500.          rc = MCIERR_OUTOFRANGE;
  501.    }
  502.    else   /* get current track */
  503.    {
  504.       ptr1 = GetTrackInfo(pInst, 0, ulAddr);   //valid addr from drive
  505.       ulTrack = ptr1->TrackNum;
  506.    }  /* of else get current track */
  507.  
  508.    if (!ULONG_LOWD(rc))
  509.       switch(pParam2->ulItem)
  510.       {
  511.          case MCI_STATUS_NUMBER_OF_TRACKS : // with MCI_TRACK, w/o already done
  512.             rc = MCIERR_FLAGS_NOT_COMPATIBLE;
  513.          case MCI_STATUS_POSITION :     // with MCI_TRACK, w/o already done
  514.             pParam2->ulReturn = GetTimeAddr(pInst,
  515.                  (ULONG)(ptr1->ulStartAddr - pInst->ulOffset), FALSE);
  516.             rc = GetTimeAddrRC(pInst, rc);
  517.             break;
  518.          case MCI_STATUS_POSITION_IN_TRACK :
  519.             if (ulParam1 & MCI_TRACK)
  520.                rc = MCIERR_FLAGS_NOT_COMPATIBLE;
  521.             else
  522.             {
  523.                ulAddr -= ptr1->ulStartAddr + pInst->ulOffset;
  524.                pParam2->ulReturn = GetTimeAddr(pInst, ulAddr, FALSE);
  525.                rc = GetTimeAddrRC(pInst, rc);
  526.             }
  527.             break;
  528.          case MCI_STATUS_LENGTH :       // with MCI_TRACK, w/o already done
  529.             ulAddr = ptr1->ulEndAddr - ptr1->ulStartAddr;
  530.             /* return MSF format for length if in TMSF format */
  531.             if ((pInst->ulMode & TIME_MODE) == CDMC_TMSF)
  532.             {
  533.                ulMode = pInst->ulMode;
  534.                pInst->ulMode = (pInst->ulMode & TIME_MODE_SET) | CDMC_REDBOOK;
  535.                pParam2->ulReturn = GetTimeAddr(pInst, ulAddr, FALSE);
  536.                rc = GetTimeAddrRC(pInst, rc);
  537.                pInst->ulMode = ulMode;
  538.             }
  539.             else
  540.             {
  541.                pParam2->ulReturn = GetTimeAddr(pInst, ulAddr, FALSE);
  542.                rc = GetTimeAddrRC(pInst, rc);
  543.             }
  544.             break;
  545.          case MCI_STATUS_CURRENT_TRACK :
  546.             if (ulParam1 & MCI_TRACK)
  547.                rc = MCIERR_FLAGS_NOT_COMPATIBLE;
  548.             else
  549.             {
  550.                pParam2->ulReturn = ulTrack;
  551.                ULONG_HIWD(rc) = MCI_INTEGER_RETURNED;
  552.             }
  553.             break;
  554.          case MCI_CD_STATUS_TRACK_TYPE :
  555.             if (!(ptr1->TrackControl & IS_DATA_TRK))
  556.                pParam2->ulReturn = MCI_CD_TRACK_AUDIO;
  557.             else if (ptr1->TrackControl & IS_OTHER_TRK)
  558.                pParam2->ulReturn = MCI_CD_TRACK_OTHER;
  559.             else
  560.                pParam2->ulReturn = MCI_CD_TRACK_DATA;
  561.             ULONG_HIWD(rc) = MCI_TRACK_TYPE_RETURN;
  562.             break;
  563.          case MCI_CD_STATUS_TRACK_COPYPERMITTED :
  564.             if (ptr1->TrackControl & IS_COPYABLE)
  565.                pParam2->ulReturn = MCI_TRUE;
  566.             else
  567.                pParam2->ulReturn = MCI_FALSE;
  568.             ULONG_HIWD(rc) = MCI_TRUE_FALSE_RETURN;
  569.             break;
  570.          case MCI_CD_STATUS_TRACK_CHANNELS :
  571.             if (!(ptr1->TrackControl & IS_DATA_TRK))      /* Is Audio ? */
  572.                if (ptr1->TrackControl & HAS_4_CHANS)
  573.                   pParam2->ulReturn = 4L;
  574.                else
  575.                   pParam2->ulReturn = 2L;
  576.             else                                          /* Data */
  577.                pParam2->ulReturn = 0L;
  578.             ULONG_HIWD(rc) = MCI_INTEGER_RETURNED;
  579.             break;
  580.          case MCI_CD_STATUS_TRACK_PREEMPHASIS :
  581.             if (!(ptr1->TrackControl & IS_DATA_TRK))      /* Is Audio ? */
  582.                if (ptr1->TrackControl & IS_PRE_EMPH)
  583.                   pParam2->ulReturn = MCI_TRUE;
  584.                else
  585.                   pParam2->ulReturn = MCI_FALSE;
  586.             else                                          /* Data */
  587.                pParam2->ulReturn = MCI_FALSE;
  588.             ULONG_HIWD(rc) = MCI_TRUE_FALSE_RETURN;
  589.             break;
  590.          /* no default value, all values were filtered in procStatus() */
  591.       }  /* of switch, track info needed */
  592.  
  593.    return(rc);
  594.  
  595. }  /* of StatusMCDDef() */
  596.  
  597.  
  598. /****************************************************************************/
  599. /*                                                                          */
  600. /* SUBROUTINE NAME:  StatusVSD                                              */
  601. /*                                                                          */
  602. /* DESCRIPTIVE NAME:  Status VSD                                            */
  603. /*                                                                          */
  604. /* FUNCTION:  Query the Status of VSD only flags.  This function is called  */
  605. /*            by ProcStatus().                                              */
  606. /*                                                                          */
  607. /* PARAMETERS:                                                              */
  608. /*      PINST pInst    -- pointer to instance.                              */
  609. /*      ULONG ulParam1 -- flag for this message.                            */
  610. /*      PVOID pParam2  -- pointer to structure (message dependent).         */
  611. /*      ULONG rc       -- initial state, inactive, not ready, etc.          */
  612. /*                                                                          */
  613. /* EXIT CODES:                                                              */
  614. /*      MCIERR_SUCCESS    -- action completed without error.                */
  615. /*      MCIERR_DEVICE_NOT_READY   -- device was not ready, no disc.         */
  616. /*      MCIERR_INVALID_MEDIA_TYPE -- No audio tracks were found.            */
  617. /*                                                                          */
  618. /* NOTES: ulParam1 = MCI_STATUS_ITEM or MCI_STATUS_ITEM | MCI_TRACK         */
  619. /*                                                                          */
  620. /****************************************************************************/
  621.  
  622. ULONG StatusVSD(PINST pInst, ULONG ulParam1, MCI_STATUS_PARMS *pParam2,
  623.                 ULONG rc)
  624. {
  625.    ULONG ulVol;
  626.    USHORT usStatus;
  627.    ULONG ulFlags, rsp = 0L;
  628.    MCI_STATUS_PARMS recStatus;
  629.  
  630.    if (!rc)
  631.    {
  632.       /* Query position to release any Disc Changes in VSD */
  633.       recStatus.ulItem = MCI_STATUS_POSITION;
  634.       ulFlags = MCI_STATUS_ITEM | MCI_WAIT;
  635.       rc = pInst->pMCIDriver(pInst->hHWMCID, MCI_STATUS,
  636.                              &ulFlags, &recStatus, 0);
  637.       if (ULONG_LOWD(rc))
  638.          rc = vsdResponse(pInst, rc);
  639.    }  /* of if no error */
  640.  
  641.    if (rc == MCIERR_INVALID_MEDIA_TYPE)
  642.    {
  643.       rsp = MCIERR_INVALID_MEDIA_TYPE;
  644.       rc = MCIERR_SUCCESS;
  645.    }
  646.  
  647.    if (!rc)
  648.    {
  649.       ulParam1 |= MCI_WAIT;
  650.       rc = pInst->pMCIDriver(pInst->hHWMCID, MCI_STATUS, &ulParam1,
  651.                              pParam2, 0);
  652.       if (ULONG_LOWD(rc))
  653.          rc = vsdResponse(pInst, rc);       //if error, process response
  654.    }  /* of if no error */
  655.  
  656.    if (!(ulParam1 & MCI_TRACK))          //process known combinations flags
  657.       switch(pParam2->ulItem)
  658.       {
  659.          case MCI_STATUS_MEDIA_PRESENT :
  660.             switch ULONG_LOWD(rc)
  661.             {
  662.                case MCIERR_SUCCESS :                //vsd already set ulReturn
  663.                   ULONG_HIWD(rc) = MCI_TRUE_FALSE_RETURN;
  664.                   if (pParam2->ulReturn == MCI_FALSE)
  665.                      pInst->usStatus = NODISC;
  666.                   else if (rsp)
  667.                      rc = rsp;                     //report invalid media
  668.                   break;
  669.                case MCIERR_INSTANCE_INACTIVE :
  670.                   rc = MCIERR_SUCCESS;
  671.                   ULONG_HIWD(rc) = MCI_TRUE_FALSE_RETURN;
  672.                   usStatus = (USHORT)(pInst->usStatus - SUSPEND);
  673.                   if (usStatus == REGTRACK)
  674.                      rc = MCIERR_INVALID_MEDIA_TYPE;
  675.                   else if (usStatus <= NODISC)
  676.                      pParam2->ulReturn = MCI_FALSE;
  677.                   else
  678.                      pParam2->ulReturn = MCI_TRUE;
  679.                   break;
  680.                default :                            //return not present
  681.                   rc = MCIERR_SUCCESS;
  682.                   ULONG_HIWD(rc) = MCI_TRUE_FALSE_RETURN;
  683.                   pParam2->ulReturn = MCI_FALSE;
  684.             }  /* of switch */
  685.             ULONG_HIWD(rc) = MCI_TRUE_FALSE_RETURN;
  686.             break;
  687.          case MCI_STATUS_MODE :
  688.             if (ULONG_LOWD(rc))
  689.             {
  690.                pParam2->ulReturn = MCI_MODE_NOT_READY;
  691.                rc = MCIERR_SUCCESS;
  692.             }
  693.             else
  694.                if (pParam2->ulReturn == MCI_MODE_STOP)
  695.                {
  696.                   if (pInst->usStatus == PAUSED)
  697.                      pParam2->ulReturn = MCI_MODE_PAUSE;
  698.                }
  699.                else
  700.                   if (pParam2->ulReturn == MCI_MODE_NOT_READY)
  701.                      pInst->usStatus = NODISC;
  702.  
  703.             ULONG_HIWD(rc) = MCI_MODE_RETURN;
  704.             break;
  705.          case MCI_STATUS_READY :
  706.             if (ULONG_LOWD(rc))
  707.             {
  708.                pParam2->ulReturn = MCI_FALSE;
  709.                rc = MCIERR_SUCCESS;
  710.             }
  711.             else
  712.                if (pParam2->ulReturn == MCI_FALSE)
  713.                   pInst->usStatus = NODISC;
  714.  
  715.             ULONG_HIWD(rc) = MCI_TRUE_FALSE_RETURN;
  716.             break;
  717.          case MCI_STATUS_VOLUME :
  718.             if (ULONG_LOWD(rc))          // if error
  719.                rsp = TRUE;
  720.             else
  721.             {
  722.                rsp = FALSE;
  723.                ULONG_HIWD(rc) = MCI_COLONIZED2_RETURN;
  724.  
  725.                /* adjust device volume to component volume */
  726.                if (pInst->ulMasterVolume && pInst->ulMode & CDMC_HEADPHONE)
  727.                {
  728.                   ulVol = (ULONG)VOL_LEFT(pParam2->ulReturn) *
  729.                         100 / pInst->ulMasterVolume;
  730.                   if (ulVol > 100)
  731.                      VOL_LEFT(pParam2->ulReturn) = 100;
  732.                   else
  733.                      VOL_LEFT(pParam2->ulReturn) = (BYTE)ulVol;
  734.  
  735.                   ulVol = (ULONG)VOL_RIGHT(pParam2->ulReturn) *
  736.                            100 / pInst->ulMasterVolume;
  737.                   if (ulVol > 100)
  738.                      VOL_RIGHT(pParam2->ulReturn) = 100;
  739.                   else
  740.                      VOL_RIGHT(pParam2->ulReturn) = (BYTE)ulVol;
  741.  
  742.                }  /* of if non-zero */
  743.                else
  744.                   /* master volume is 0%, return requested volume */
  745.                   rsp = TRUE;
  746.  
  747.             }  /* of else no error */
  748.  
  749.             if (rsp)  //unknown volume, ask VSD what component volume should be
  750.             {
  751.                if (rc == MCIERR_INSTANCE_INACTIVE)
  752.                   pParam2->ulReturn = pInst->recSave.ulLevel;
  753.                else
  754.                {
  755.                   ulFlags = MCI_WAIT;
  756.                   recStatus.ulReturn = pInst->ulLevel;
  757.                   pInst->pMCIDriver(pInst->hHWMCID, MCIDRV_CD_STATUS_CVOL,
  758.                                     &ulFlags, &recStatus, 0);
  759.                   pParam2->ulReturn = recStatus.ulReturn;
  760.                }
  761.                rc = MAKEULONG(MCIERR_SUCCESS, MCI_COLONIZED2_RETURN);
  762.  
  763.             }  /* of if unknown volume */
  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.    ULONG ulParam1;
  795.    MCI_CUEPOINT_PARMS recCuePoint;
  796.  
  797.    /* disable cuepoints */
  798.    ulParam1 = 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.ulCuepoint = pInst->arrCuePoint[i];
  804.          pInst->pMCIDriver(pInst->hHWMCID, MCI_SET_CUEPOINT,
  805.                            &ulParam1, &recCuePoint, 0);
  806.          pInst->arrCuePoint[i] = (ULONG) -1L;
  807.       }  /* of if cuepoint is set */
  808.    }  /* of for loop of cuepoints */
  809.  
  810.    /* disable position advise */
  811.    ulParam1 = MCI_SET_POSITION_ADVISE_OFF | MCI_WAIT;
  812.    pInst->pMCIDriver(pInst->hHWMCID, MCI_SET_POSITION_ADVISE,
  813.                      &ulParam1, 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. /*      ULONG  ulAddr  -- input address.                                    */
  829. /*      USHORT usTO    -- TRUE if to MMTime, FALSE if from MMTime.          */
  830. /*                                                                          */
  831. /* EXIT CODES:  ULONG  ulReturn -- the converted address.                   */
  832. /*                                                                          */
  833. /* NOTES:                                                                   */
  834. /*                                                                          */
  835. /*                                                                          */
  836. /****************************************************************************/
  837.  
  838. ULONG GetTimeAddr(PINST pInst, ULONG ulAddr, USHORT usTO)
  839. {
  840.    ULONG ulReturn;
  841.    MCI_CD_REGTRACK_REC *ptr;
  842.  
  843.    switch (pInst->ulMode & TIME_MODE)
  844.    {
  845.       case CDMC_MILLSEC :                          // milliseconds
  846.          if (usTO)
  847.             ulReturn = MSECTOMM(ulAddr);
  848.          else
  849.             ulReturn = MSECFROMMM(ulAddr);
  850.          break;
  851.       case CDMC_REDBOOK :                          // Red Book / MSF
  852.          if (usTO)
  853.             ulReturn = REDBOOKTOMM(ulAddr);
  854.          else
  855.             ulReturn = REDBOOKFROMMM(ulAddr);
  856.          break;
  857.       case CDMC_TMSF :                             // Track:Min:Sec:Frame
  858.          if (usTO)
  859.          {
  860.             ptr = GetTrackInfo(pInst, TMSF_TRACK(ulAddr), 0L);
  861.             if (ptr == NULL)
  862.                ulReturn = (ULONG) -1L;            // invalid track number
  863.             else
  864.             {
  865.                ulAddr = (ulAddr >> 8) & 0x00FFFFFF;     //TMSF -> MSF
  866.                ulReturn = ptr->ulStartAddr + REDBOOKTOMM(ulAddr);
  867.             }
  868.          }  /* of TO MMTIME */
  869.          else
  870.          {
  871.             ptr = GetTrackInfo(pInst, 0, ulAddr);
  872.             if (ptr == NULL)
  873.                ulReturn = (ULONG) -1L;            // invalid track number
  874.             else
  875.             {
  876.                ulAddr -= ptr->ulStartAddr;
  877.                ulReturn = (REDBOOKFROMMM(ulAddr) << 8) | (ULONG) ptr->TrackNum;
  878.             }
  879.          }  /* of else FROM MMTIME */
  880.          break;
  881.       case CDMC_MMTIME :                          // Multimedia Time
  882.       default :
  883.          ulReturn = ulAddr;
  884.    }  /* on switch */
  885.  
  886.    return(ulReturn);
  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. /*      ULONG  ulAddr  -- input address.                                    */
  903. /*      USHORT usTO    -- TRUE if to MMTime, FALSE if from MMTime.          */
  904. /*                                                                          */
  905. /* EXIT CODES:  ULONG  rc  -- the converted return code.                    */
  906. /*                                                                          */
  907. /* NOTES:                                                                   */
  908. /*                                                                          */
  909. /*                                                                          */
  910. /****************************************************************************/
  911.  
  912. ULONG GetTimeAddrRC(PINST pInst, ULONG rc)
  913. {
  914.    switch (pInst->ulMode & TIME_MODE)
  915.    {
  916.       case CDMC_REDBOOK :                          // Red Book / MSF
  917.          ULONG_HIWD(rc) = MCI_COLONIZED3_RETURN;
  918.          break;
  919.       case CDMC_TMSF :                             // Track:Min:Sec:Frame
  920.          ULONG_HIWD(rc) = MCI_COLONIZED4_RETURN;
  921.          break;
  922.       case CDMC_MILLSEC :                          // milliseconds
  923.       case CDMC_MMTIME :                           // Multimedia Time
  924.       default :
  925.          ULONG_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. /*      ULONG ulAddr   -- specified absolute address, ignored if ulTrack    */
  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, ULONG ulAddr)
  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->ulStartAddr <= ulAddr &&
  972.           (pInst->recTrack.TrackRecArr + usOffset)->ulEndAddr >= ulAddr)
  973.       {
  974.          /* for every track, check address bounds until ulAddr 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)->ulStartAddr <= ulAddr &&
  978.                 (pInst->recTrack.TrackRecArr + i)->ulEndAddr > ulAddr)
  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. /*      ULONG  *pusFrom -- address to be tested and returned.               */
  1003. /*      ULONG  *pusTo   -- 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. ULONG ValAddress(PINST pInst, ULONG *pulFrom, ULONG *pulTo, USHORT isPlay)
  1016. {
  1017.    ULONG rc;
  1018.  
  1019.    rc = MCIERR_SUCCESS;
  1020.  
  1021.    /* validate TO */
  1022.    if (*pulTo < pInst->ulStart_disk)
  1023.       rc = MCIERR_OUTOFRANGE;
  1024.    else
  1025.       if (isPlay)
  1026.       {
  1027.          if (*pulTo > pInst->ulEnd_disk)
  1028.             rc = MCIERR_OUTOFRANGE;
  1029.       }
  1030.       else
  1031.          /* ulEnd_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 (*pulTo > pInst->ulEnd_disk - MMT_FRAME)
  1035.             rc = MCIERR_OUTOFRANGE;
  1036.  
  1037.    /* Validate from address if needed */
  1038.    if (!rc && isPlay)
  1039.    {
  1040.       if (*pulFrom < pInst->ulStart_disk)
  1041.          rc = MCIERR_OUTOFRANGE;
  1042.       else if (*pulTo > pInst->ulEnd_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 (*pulFrom > *pulTo &&
  1048.              (!(pInst->usCaps & 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. ULONG ValState(PINST pInst)
  1083. {
  1084.    ULONG 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. /*      ULONG ulResponse -- 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. ULONG vsdResponse(PINST pInst, ULONG ulResponse)
  1124. {
  1125.    ULONG rc;
  1126.  
  1127.    switch (ULONG_LOWD(ulResponse))
  1128.    {
  1129.       case MCIERR_DEVICE_NOT_READY :
  1130.          pInst->usStatus = NODISC;
  1131.          rc = ulResponse;
  1132.          break;
  1133.       case MCIERR_MEDIA_CHANGED :
  1134.          rc = ReRegister(pInst);
  1135.          break;
  1136.       default :
  1137.          rc = ulResponse;
  1138.    }   /* of switch */
  1139.  
  1140.    return(rc);
  1141.  
  1142. }  /* of vsdResponse() */
  1143.  
  1144.  
  1145.