home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: SysTools / SysTools.zip / sysba021.zip / SRC.ZIP / sysbar2 / CD_Player / CDengine.cpp next >
C/C++ Source or Header  |  2003-01-03  |  17KB  |  599 lines

  1. /*
  2.  
  3.   SysBar/2 Utility Set  version 0.21
  4.  
  5.   CD-player engine for IOCtl
  6.  
  7.   ..................................................................
  8.  
  9.   Copyright (c) 1995-99  Dmitry I. Platonoff <dip@platonoff.com>
  10.   Copyright (c) 2002,03  Max Alekseyev       <relf@os2.ru>
  11.  
  12.                            All rights reserved
  13.  
  14.   ..................................................................
  15.  
  16.   LICENSE
  17.   ~~~~~~~
  18.   Redistribution and use in source and binary forms, with or without
  19.   modification, are permitted provided that the following conditions
  20.   are met:
  21.  
  22.   1. Redistributions of source code must retain the above copyright
  23.      notice, this list of conditions and the following disclaimer.
  24.  
  25.   2. Redistributions in binary form must reproduce the above
  26.      copyright notice, this list of conditions and the following
  27.      disclaimer in the documentation and/or other materials provided
  28.      with the distribution.
  29.  
  30.   3. Redistributions of any form whatsoever, as well as all
  31.      advertising materials mentioning features or use of this
  32.      software (if any), must include the following acknowledgment:
  33.      "This product includes software developed by Dmitry I. Platonoff".
  34.  
  35.   4. The names "SysBar/2" and "Dmitry I. Platonoff" must not be
  36.      used to endorse or promote products derived from this software
  37.      without prior written permission. For such permission, please
  38.      contact dplatonoff@canada.com.
  39.  
  40.   5. Products derived from this software may not be called
  41.      "SysBar/2" nor may "Dmitry I. Platonoff" appear in their
  42.      contributor lists without prior written permission.
  43.  
  44.   ..................................................................
  45.  
  46.   DISCLAIMER
  47.   ~~~~~~~~~~
  48.   THIS SOFTWARE IS PROVIDED BY THE AUTHOR OR CONTRIBUTORS "AS IS"
  49.   AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  50.   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  51.   FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  52.   AUTHOR OR THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  53.   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  54.   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  55.   SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  56.   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  57.   STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  58.   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  59.   ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  60.  
  61. */
  62.  
  63.  
  64. #include <stdio.h>
  65. #include <string.h>
  66. #include <stdlib.h>
  67. #include "CDengine.h"
  68.  
  69.  
  70. // IOCTL definitions ---------------------------------------------------------
  71. #define IOCTL_CDROMDISK 0x0080
  72. #define IOCTL_CDROMAUDIO 0x0081
  73. #define DSK_UNLOCKEJECTMEDIA 0x0040
  74. #define DSK_GETLOCKSTATUS 0x0066
  75. #define CDROMDISK_SEEK 0x0050
  76. #define CDROMDISK_DEVICESTATUS 0x0060
  77. #define CDROMDISK_GETDRIVER 0x0061
  78. #define CDROMDISK_GETHEADLOC 0x0070
  79. #define CDROMAUDIO_SETCHANNELCTRL 0x0040
  80. #define CDROMAUDIO_PLAYAUDIO 0x0050
  81. #define CDROMAUDIO_STOPAUDIO 0x0051
  82. #define CDROMAUDIO_RESUMEAUDIO 0x0052
  83. #define CDROMAUDIO_GETAUDIODISK 0x0061
  84. #define CDROMAUDIO_GETAUDIOTRACK 0x0062
  85.  
  86.  
  87. // CD device finder ----------------------------------------------------------
  88. int CDDeviceFinder( CDROMDeviceMap& CDMap )
  89. {
  90.   HFILE hf;
  91.   ULONG ulAction = 0;
  92.   ULONG ulParamSize = sizeof ( ulAction );
  93.   ULONG ulDataSize = sizeof ( CDROMDeviceMap );
  94.  
  95.   if ( DosOpen( "CD-ROM2$", &hf, &ulAction, 0, FILE_NORMAL,
  96.     OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS,
  97.     OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE, NULL ) ) return 0;
  98.   DosDevIOCtl( hf, 0x82, 0x60, NULL, 0, &ulParamSize,
  99.     ( PVOID ) &CDMap, sizeof ( CDROMDeviceMap ), &ulDataSize );
  100.   DosClose( hf );
  101.   return CDMap.usDriveCount;
  102. }
  103.  
  104.  
  105. //  CD Drive class -----------------------------------------------------------
  106. typedef struct _NullHandleParams
  107. {
  108.   UCHAR ucCommand;
  109.   USHORT usDrive;
  110. } NullHandleParams;
  111.  
  112. typedef struct _CDSignature
  113. {
  114.   UCHAR sSignature[4];
  115. } CDSignature;
  116.  
  117. typedef struct _CDAudioTracks
  118. {
  119.   UCHAR ucFirstTrack;
  120.   UCHAR ucLastTrack;
  121.   ULONG ulLeadOutAddress;
  122. } CDAudioTracks;
  123.  
  124. typedef struct _CDSeekParam
  125. {
  126.   CDSignature CD01;
  127.   UCHAR ucAddrMode;
  128.   ULONG ulPosition;
  129. } CDSeekParam;
  130.  
  131. typedef struct _CDPlayParam
  132. {
  133.   CDSignature CD01;
  134.   UCHAR ucAddrMode;
  135.   ULONG ulFromPosition;
  136.   ULONG ulTillPosition;
  137. } CDPlayParam;
  138.  
  139. typedef struct _CDGetLocParam
  140. {
  141.   CDSignature CD01;
  142.   UCHAR ucAddrMode;
  143. } CDGetLocParam;
  144.  
  145. typedef struct _CDTrackParam
  146. {
  147.   CDSignature CD01;
  148.   UCHAR ucTrack;
  149. } CDTrackParam;
  150.  
  151. typedef struct _CDTrackData
  152. {
  153.   ULONG ulAddress;
  154.   UCHAR ucControl;
  155. } CDTrackData;
  156.  
  157. typedef struct _CDChanCtrlData
  158. {
  159.   UCHAR ucInput0;
  160.   UCHAR ucVolume0;
  161.   UCHAR ucInput1;
  162.   UCHAR ucVolume1;
  163.   UCHAR ucInput2;
  164.   UCHAR ucVolume2;
  165.   UCHAR ucInput3;
  166.   UCHAR ucVolume3;
  167. } CDChanCtrlData;
  168.  
  169.  
  170. CDDrive::CDDrive( USHORT usDriveLetter )
  171. {
  172.   usDrive = ( usDriveLetter & 0x5F ) - 'A';
  173.   hCD = NULLHANDLE;
  174.   usStatus = CDS_NoMedia;
  175.   ulCurrentPosition = 0;
  176.   iCurrentTrack = -1;
  177.   Tracks = 0;
  178.   iTrackCount = 0;
  179.   iFirstTrack = 0;
  180. }
  181.  
  182. APIRET CDDrive::Open( void )
  183. {
  184.   FillDevice();
  185.  
  186.   ulCurrentPosition = 0;
  187.   iCurrentTrack = -1;
  188.  
  189.   ULONG ulAction = 0;
  190.   APIRET rc;
  191.   // open CD-ROM drive device
  192.   if ( ! ( rc = DosOpen( szDevice, &hCD, &ulAction, 0L, 0L,
  193.     OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS, OPEN_FLAGS_DASD |
  194.     OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_NOINHERIT | OPEN_SHARE_DENYNONE,
  195.     0L ) ) )
  196.   {
  197.     CDSignature cds1 = { 'C', 'D', '0', '1' };
  198.     CDSignature cds2 = { 0 };
  199.     ULONG ulParamSize = sizeof ( CDSignature );
  200.     ULONG ulDataSize = sizeof ( CDSignature );
  201.     // check for proper driver signature
  202.     if ( ! ( rc = DosDevIOCtl( hCD, IOCTL_CDROMDISK, CDROMDISK_GETDRIVER,
  203.       ( PVOID ) &cds1, sizeof( CDSignature ), &ulParamSize,
  204.       ( PVOID ) &cds2, sizeof( CDSignature ), &ulDataSize ) ) )
  205.     {
  206.       if ( memcmp( &cds1, &cds2, sizeof ( CDSignature ) ) ) rc = -1;
  207.       else
  208.       {
  209.         CDAudioTracks cdat = { 0 };
  210.         ulDataSize = sizeof ( CDAudioTracks );
  211.         // get track count
  212.         if ( ! ( rc = DosDevIOCtl( hCD,
  213.           IOCTL_CDROMAUDIO, CDROMAUDIO_GETAUDIODISK,
  214.           ( PVOID ) &cds1, sizeof( CDSignature ), &ulParamSize,
  215.           ( PVOID ) &cdat, sizeof( CDAudioTracks ), &ulDataSize ) ) )
  216.         {
  217.           iFirstTrack = cdat.ucFirstTrack;
  218.           iTrackCount = cdat.ucLastTrack - cdat.ucFirstTrack + 1;
  219.           if ( ( Tracks = new CDTrack[iTrackCount] ) )
  220.           {
  221.             int iPlayableTracks = 0;
  222.             // build TOC
  223.             for ( int i = 0; i < iTrackCount; i++ )
  224.             {
  225.               CDTrackParam cdtp =
  226.                 { { 'C', 'D', '0', '1' }, ( UCHAR ) i + cdat.ucFirstTrack };
  227.               ulParamSize = sizeof ( CDTrackParam );
  228.               CDTrackData cdtd = { 0 };
  229.               ulDataSize = sizeof ( CDTrackData );
  230.               if ( ! ( rc = DosDevIOCtl( hCD,
  231.                 IOCTL_CDROMAUDIO, CDROMAUDIO_GETAUDIOTRACK,
  232.                 ( PVOID ) &cdtp, sizeof( CDTrackParam ), &ulParamSize,
  233.                 ( PVOID ) &cdtd, sizeof( CDTrackData ), &ulDataSize ) ) )
  234.               {
  235.                 Tracks[i].ulStartingTime = cdtd.ulAddress;
  236.                 Tracks[i].bPlayable = ( ( cdtd.ucControl & 64 ) == 0 );
  237.                 iPlayableTracks += Tracks[i].bPlayable;
  238.               }
  239.               Tracks[i].iTrackNumber = i + cdat.ucFirstTrack;
  240.               if ( i ) Tracks[i - 1].ulEndingTime = Tracks[i].ulStartingTime;
  241.             }
  242.             Tracks[iTrackCount - 1].ulEndingTime = cdat.ulLeadOutAddress;
  243.  
  244.             usStatus = CDS_MediaPresent;
  245.  
  246.             // stop drive
  247.             if ( iPlayableTracks )
  248.             {
  249.               rc = Stop();
  250.  
  251.               // reset volume
  252.               CDSignature cds = { 'C', 'D', '0', '1' };
  253.               ulParamSize = sizeof ( CDSignature );
  254.               CDChanCtrlData cdccd = { 0, 255, 1, 255, 2, 255, 3, 255 };
  255.               ulDataSize = sizeof ( CDChanCtrlData );
  256.               DosDevIOCtl( hCD, IOCTL_CDROMAUDIO, CDROMAUDIO_SETCHANNELCTRL,
  257.                 ( PVOID ) &cds, sizeof( CDTrackParam ), &ulParamSize,
  258.                 ( PVOID ) &cdccd, sizeof( CDTrackData ), &ulDataSize );
  259.             }
  260.             else
  261.             {
  262.               // close the device if there's no playable tracks
  263.               rc = Pause();
  264.               Close();
  265.             }
  266.           }
  267.           else rc = -1;
  268.         }
  269.       }
  270.     }
  271.   }
  272.  
  273.   if ( rc ) Close();
  274.   return rc;
  275. }
  276.  
  277. void CDDrive::FillDevice( void )
  278. {
  279.   szDevice[0] = usDrive + 'A';
  280.   szDevice[1] = ':';
  281.   szDevice[2] = 0;
  282. }
  283.  
  284. CDDrive::~CDDrive( void )
  285. {
  286.   Close();
  287. }
  288.  
  289. CDStatusChanges CDDrive::CheckStatus( void )
  290. {
  291.   CDStatusChanges iStatusChange = CDS_Unchanged;
  292.  
  293.   NullHandleParams glsp = { 0, usDrive };
  294.   ULONG ulParamSize = sizeof ( NullHandleParams );
  295.   USHORT usData = 0;
  296.   ULONG ulDataSize = sizeof ( USHORT );
  297.  
  298.   // look for media presence
  299.   if ( DosDevIOCtl( ( HFILE ) -1, IOCTL_DISK, DSK_GETLOCKSTATUS,
  300.     ( PVOID ) &glsp, sizeof( NullHandleParams ), &ulParamSize,
  301.     ( PVOID ) &usData, sizeof( USHORT ), &ulDataSize ) == 0 )
  302.   {
  303.     // if media is present
  304.     if ( usData & 4 )
  305.     {
  306.       // if there was no media
  307.       if ( usStatus <= CDS_NoMedia )
  308.       {
  309.         // try to open the device
  310.         if ( Open() == 0 ) iStatusChange = CDS_MediaInserted;
  311.       }
  312.       // if the media was already in drive and it has been opened
  313.       else if ( hCD )
  314.       {
  315.         CDSignature cds1 = { 'C', 'D', '0', '1' };
  316.         ULONG ulParamSize = sizeof ( CDSignature );
  317.         ULONG ulData = 0L;
  318.         ULONG ulDataSize = sizeof ( ULONG );
  319.         if ( DosDevIOCtl( hCD, IOCTL_CDROMDISK, CDROMDISK_DEVICESTATUS,
  320.           ( PVOID ) &cds1, sizeof( CDSignature ), &ulParamSize,
  321.           ( PVOID ) &ulData, sizeof ( ULONG ), &ulDataSize ) == 0 )
  322.         {
  323.           // if the device is currently playing
  324.           if ( ulData & 0x1000 )
  325.           {
  326.             CDGetLocParam cdglp = { { 'C', 'D', '0', '1' }, ( UCHAR ) 1 };
  327.             ULONG ulParamSize = sizeof ( CDGetLocParam );
  328.             ULONG ulPosition = 0L;
  329.             ULONG ulDataSize = sizeof ( ULONG );
  330.             if ( DosDevIOCtl( hCD, IOCTL_CDROMDISK, CDROMDISK_GETHEADLOC,
  331.               ( PVOID ) &cdglp, sizeof( CDGetLocParam ), &ulParamSize,
  332.               ( PVOID ) &ulPosition, sizeof ( ULONG ), &ulDataSize ) == 0 )
  333.             {
  334.               if ( ulPosition > Tracks[iCurrentTrack].ulEndingTime ||
  335.                 ( ulPosition & 0xFFFF00 ) != ( ulCurrentPosition & 0xFFFF00 ) )
  336.               {
  337.                 ulCurrentPosition = ulPosition;
  338.                 int iOldTrack = iCurrentTrack;
  339.                 iStatusChange = ( iOldTrack == AdjustTrack() ) ?
  340.                   CDS_PositionChanged : CDS_TrackChanged;
  341.               }
  342.             }
  343.  
  344.             if ( usStatus != CDS_Playing )
  345.             {
  346.               usStatus = CDS_Playing;
  347.               iStatusChange = CDS_PlayingStarted;
  348.             }
  349.           }
  350.           else
  351.           {
  352.             if ( usStatus == CDS_Playing )
  353.             {
  354.               usStatus = CDS_MediaPresent;
  355.               iStatusChange = CDS_PlayingStopped;
  356.             }
  357.           }
  358.         }
  359.       }
  360.     }
  361.     // if there's no media
  362.     else
  363.     {
  364.       // if there was a media removal
  365.       if ( usStatus > CDS_NoMedia )
  366.       {
  367.         Close();
  368.         usStatus = CDS_NoMedia;
  369.         iStatusChange = CDS_MediaRemoved;
  370.       }
  371.     }
  372.   }
  373.  
  374.   return iStatusChange;
  375. }
  376.  
  377. APIRET CDDrive::Pause( void )
  378. {
  379.   APIRET rc = -1;
  380.   if ( hCD )
  381.   {
  382.     CDSignature cds1 = { 'C', 'D', '0', '1' };
  383.     ULONG ulParamSize = sizeof ( CDSignature );
  384.     if ( ( rc = DosDevIOCtl( hCD, IOCTL_CDROMAUDIO, CDROMAUDIO_STOPAUDIO,
  385.       ( PVOID ) &cds1, sizeof( CDSignature ), &ulParamSize,
  386.       NULL, 0, NULL ) ) == 0 ) usStatus = CDS_Paused;
  387.   }
  388.   return rc;
  389. }
  390.  
  391. APIRET CDDrive::Close( void )
  392. {
  393.   APIRET rc = -1;
  394.   if ( hCD && ! ( rc = DosClose( hCD ) ) ) hCD = NULLHANDLE;
  395.  
  396.   if ( Tracks )
  397.   {
  398.     delete[] Tracks;
  399.     Tracks = 0;
  400.     iTrackCount = 0;
  401.   }
  402.  
  403.   if ( usStatus > CDS_MediaPresent ) usStatus = CDS_MediaPresent;
  404.   ulCurrentPosition = 0;
  405.   iCurrentTrack = -1;
  406.  
  407.   return rc;
  408. }
  409.  
  410. APIRET CDDrive::TrayAction( UCHAR ucCommand )
  411. {
  412.   NullHandleParams nhp = { ucCommand, usDrive };
  413.   ULONG ulParamSize = sizeof ( NullHandleParams );
  414.  
  415.   return DosDevIOCtl( ( HFILE ) -1, IOCTL_DISK, DSK_UNLOCKEJECTMEDIA,
  416.     ( PVOID ) &nhp, sizeof( NullHandleParams ), &ulParamSize, NULL, 0, NULL );
  417. }
  418.  
  419. APIRET CDDrive::Seek( ULONG ulPosition )
  420. {
  421.   APIRET rc = -1;
  422.   if ( hCD )
  423.   {
  424.     CDSeekParam cdsp = { { 'C', 'D', '0', '1' }, ( UCHAR ) 1, ulPosition };
  425.     ULONG ulParamSize = sizeof ( CDSeekParam );
  426.     if ( ( rc = DosDevIOCtl( hCD, IOCTL_CDROMDISK, CDROMDISK_SEEK,
  427.       ( PVOID ) &cdsp, sizeof( CDSeekParam ), &ulParamSize,
  428.       NULL, 0, NULL ) ) == 0 )
  429.     {
  430.       ulCurrentPosition = ulPosition;
  431.       AdjustTrack();
  432.     }
  433.   }
  434.   return rc;
  435. }
  436.  
  437. int CDDrive::AdjustTrack( void )
  438. {
  439.   iCurrentTrack = -1;
  440.   for ( int i = 0; i < iTrackCount; i++ )
  441.     if ( ulCurrentPosition >= Tracks[i].ulStartingTime &&
  442.       ulCurrentPosition < Tracks[i].ulEndingTime )
  443.     {
  444.       iCurrentTrack = i;
  445.       break;
  446.     }
  447.   return iCurrentTrack;
  448. }
  449.  
  450. APIRET CDDrive::Stop( void )
  451. {
  452.   APIRET rc = Pause();
  453.   if ( ! rc ) for ( int i = 0; i < iTrackCount; i++ ) if ( Tracks[i].bPlayable )
  454.   {
  455.     if ( ( rc = Seek( Tracks[i].ulStartingTime ) ) == 0 )
  456.       usStatus = CDS_MediaPresent;
  457.     break;
  458.   }
  459.   return rc;
  460. }
  461.  
  462. APIRET CDDrive::Play( )
  463. {
  464.   APIRET rc = -1;
  465.   if ( hCD )
  466.   {
  467.     AdjustTrack();
  468.     CDPlayParam cdpp =
  469.       { { 'C', 'D', '0', '1' }, ( UCHAR ) 1, ulCurrentPosition, 0L };
  470.  
  471.     int i;
  472.     //if ( bCurrentTrackOnly ) i = iCurrentTrack; else
  473.        for ( i = iTrackCount - 1; i >= 0; i-- ) if ( Tracks[i].bPlayable ) break;
  474.     cdpp.ulTillPosition = Tracks[i].ulEndingTime;
  475.       
  476.     ULONG ulParamSize = sizeof ( CDPlayParam );
  477.     rc = DosDevIOCtl( hCD, IOCTL_CDROMAUDIO, CDROMAUDIO_PLAYAUDIO,
  478.       ( PVOID ) &cdpp, sizeof( CDPlayParam ), &ulParamSize,
  479.       NULL, 0, NULL );
  480.   }
  481.   return rc;
  482. }
  483.  
  484. APIRET CDDrive::Resume( void )
  485. {
  486.   APIRET rc = -1;
  487.   if ( hCD )
  488.   {
  489.     CDSignature cds1 = { 'C', 'D', '0', '1' };
  490.     ULONG ulParamSize = sizeof ( CDSignature );
  491.     rc = DosDevIOCtl( hCD, IOCTL_CDROMAUDIO, CDROMAUDIO_RESUMEAUDIO,
  492.       ( PVOID ) &cds1, sizeof( CDSignature ), &ulParamSize,
  493.       NULL, 0, NULL );
  494.   }
  495.   return rc;
  496. }
  497.  
  498. APIRET CDDrive::EjectTray( void )
  499. {
  500.   APIRET rc = TrayAction( 2 );
  501.   if ( ! rc )
  502.   {
  503.     Close();
  504.     usStatus = CDS_TrayOpened;
  505.   }
  506.   return rc;
  507. }
  508.  
  509. APIRET CDDrive::LoadTray( void )
  510. {
  511.   APIRET rc = TrayAction( 3 );
  512.   if ( ! rc ) usStatus = CDS_NoMedia;
  513.   return rc;
  514. }
  515.  
  516. APIRET CDDrive::SkipToTrack( int iTrack )
  517. {
  518.   USHORT usOldStatus = usStatus;
  519.   APIRET rc = 0;
  520.   if ( ! iTrackCount ) return -1;
  521.   if ( usOldStatus == CDS_Playing ) rc = Pause();
  522.   while ( ! Tracks[iTrack].bPlayable )
  523.   {
  524.     if ( ++iTrack == iTrackCount ) iTrack = 0;
  525.   }
  526.   if ( ! rc ) rc = Seek( Tracks[iTrack].ulStartingTime );
  527.   if ( ! rc ) switch ( usOldStatus )
  528.   {
  529.     case CDS_Playing:
  530.       rc = Play();
  531.       break;
  532.     case CDS_Paused:
  533.       usStatus = CDS_MediaPresent;
  534.       break;
  535.   }
  536.   return rc;
  537. }
  538.  
  539. APIRET CDDrive::NextTrack()
  540. {
  541.   if ( ! iTrackCount ) return -1;
  542.   int n = iCurrentTrack;
  543.   do
  544.   {
  545.     if ( ++n == iTrackCount ) n = 0;
  546.   }
  547.   while ( ! Tracks[n].bPlayable );
  548.   return SkipToTrack( n );
  549. }
  550.  
  551. APIRET CDDrive::PrevTrack()
  552. {
  553.   if ( ! iTrackCount ) return -1;
  554.   int n = iCurrentTrack;
  555.   do
  556.   {
  557.     if ( --n < 0 ) n = iTrackCount - 1;
  558.   }
  559.   while ( ! Tracks[n].bPlayable );
  560.   return SkipToTrack( n );
  561. }
  562.  
  563. static ULONG CDDrive::MSFAdd( ULONG ulValue1, ULONG ulValue2 )
  564. {
  565.   ULONG ulResult = ulValue1 + ulValue2;
  566.   if ( ( ulResult & 255 ) >= 75 ) ulResult += 0x100 - 75;
  567.   if ( ( ulResult & 0xFF00 ) >= 0x3C00 ) ulResult += 0x10000 - 0x3C00;
  568.   return ulResult;
  569. }
  570.  
  571. static ULONG CDDrive::MSFSub( ULONG ulValue1, ULONG ulValue2 )
  572. {
  573.   ULONG ulResult = ulValue1 - ulValue2;
  574.   if ( ( ulResult & 255 ) >= 75 ) ulResult -= 0x100 - 75;
  575.   if ( ( ulResult & 0xFF00 ) >= 0x3C00 ) ulResult -= 0x10000 - 0x3C00;
  576.   return ulResult;
  577. }
  578.  
  579. void CDDrive::Shuffle( bool chaos )
  580. {
  581.   if( chaos ) {
  582.     for(int i=0; i<iTrackCount-1; i++) {
  583.       int j = i + rand()%(iTrackCount-i);
  584.       CDTrack temp = Tracks[i];
  585.       Tracks[i] = Tracks[j];
  586.       Tracks[j] = temp;
  587.     }
  588.   }
  589.   else {
  590.     CDTrack *newTracks = new CDTrack[iTrackCount];
  591.     for(int i=0;i<iTrackCount;i++) newTracks[Tracks[i].iTrackNumber-iFirstTrack] = Tracks[i];
  592.     delete[] Tracks;
  593.     Tracks = newTracks;
  594.   }
  595.   SkipToTrack(0);
  596. }
  597.  
  598.  
  599.