Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2084 lines
50 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: trklst.c
  3. *
  4. * This module manipulates the cdrom track list. The table of contents MUST
  5. * be locked for ALL cdrom devices before calling any functions in this module.
  6. *
  7. * Created: 02-11-93
  8. * Author: Stephen Estrop [StephenE]
  9. *
  10. * Copyright (c) 1993 Microsoft Corporation
  11. \**************************************************************************/
  12. #pragma warning( once : 4201 4214 )
  13. #define NOOLE
  14. #include <windows.h> /* required for all Windows applications */
  15. #include <windowsx.h>
  16. #include <stdlib.h>
  17. #include <string.h>
  18. #include <tchar.h> /* contains portable ascii/unicode macros */
  19. #include "resource.h"
  20. #include "cdplayer.h"
  21. #include "cdapi.h"
  22. #include "scan.h"
  23. #include "database.h"
  24. #include "trklst.h"
  25. /******************************Public*Routine******************************\
  26. * ComputeDriveComboBox
  27. *
  28. * This routine deletes and then reads all the drive (artist) selections
  29. * to the drive combobox.
  30. *
  31. *
  32. * History:
  33. * 18-11-93 - StephenE - Created
  34. *
  35. \**************************************************************************/
  36. void
  37. ComputeDriveComboBox(
  38. void
  39. )
  40. {
  41. int i,index;
  42. HWND hwnd;
  43. hwnd = g_hwndControls[INDEX(IDC_ARTIST_NAME)];
  44. SetWindowRedraw( hwnd, FALSE );
  45. ComboBox_ResetContent( hwnd );
  46. index = 0;
  47. for( i = 0; i < g_NumCdDevices; i++ ) {
  48. ComboBox_InsertString( hwnd, -1, i );
  49. if ( i == g_CurrCdrom ) {
  50. index = i;
  51. }
  52. }
  53. SetWindowRedraw( hwnd, TRUE );
  54. ComboBox_SetCurSel( hwnd, index );
  55. RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE );
  56. UpdateWindow( hwnd );
  57. }
  58. /*****************************Private*Routine******************************\
  59. * SwitchToCdrom
  60. *
  61. * This routine is called when the used selects a new cdrom device
  62. * to access. It handles reset the state of both the "old" and "new"
  63. * chosen cdroms.
  64. *
  65. *
  66. * History:
  67. * 18-11-93 - StephenE - Created
  68. *
  69. \**************************************************************************/
  70. void
  71. SwitchToCdrom(
  72. int NewCdrom,
  73. BOOL prompt
  74. )
  75. {
  76. int oldState, oldState2;
  77. TCHAR s1[256], s2[256];
  78. oldState = g_Devices[g_LastCdrom]->State;
  79. oldState2 = g_Devices[g_CurrCdrom]->State;
  80. if (NewCdrom != g_LastCdrom) {
  81. if (prompt) {
  82. if (g_Devices[g_CurrCdrom]->State & CD_PLAYING) {
  83. _tcscpy( s1, IdStr( STR_CANCEL_PLAY ) );
  84. _tcscpy( s2, IdStr( STR_CHANGE_CDROM ) );
  85. if ( MessageBox( g_hwndApp, s1, s2,
  86. MB_APPLMODAL | MB_DEFBUTTON1 |
  87. MB_ICONQUESTION | MB_YESNO) != IDYES ) {
  88. return;
  89. }
  90. }
  91. }
  92. /*
  93. ** stop the drive we're leaving
  94. */
  95. g_CurrCdrom = g_LastCdrom;
  96. if (prompt && (g_State & (CD_PLAYING | CD_PAUSED)) ) {
  97. HWND hwndButton;
  98. hwndButton = g_hwndControls[INDEX(IDM_PLAYBAR_STOP)];
  99. SendMessage( hwndButton, WM_LBUTTONDOWN, 0, 0L );
  100. SendMessage( hwndButton, WM_LBUTTONUP, 0, 0L );
  101. } else {
  102. if ( StopTheCdromDrive( g_LastCdrom ) ) {
  103. g_State &= (~(CD_PLAYING | CD_PAUSED));
  104. g_State |= CD_STOPPED;
  105. }
  106. }
  107. /*
  108. ** Set new cdrom drive and initialize time fields
  109. */
  110. g_LastCdrom = g_CurrCdrom = NewCdrom;
  111. TimeAdjustInitialize( g_CurrCdrom );
  112. if ( (oldState & CD_PAUSED) || (oldState2 & CD_PAUSED) ) {
  113. SendMessage( g_hwndApp, WM_COMMAND, IDM_PLAYBAR_PLAY, 0L );
  114. SendMessage( g_hwndApp, WM_COMMAND, IDM_PLAYBAR_PAUSE, 0L );
  115. }
  116. }
  117. }
  118. /*****************************Private*Routine******************************\
  119. * FindTrackNodeFromTocIndex
  120. *
  121. * This routine returns the node in the listed pointed to by listhead which
  122. * has the TocIndex equal to tocindex. NULL is returned if it is not
  123. * found. Returning NULL can easily bomb out the program -- but we should
  124. * never be calling this routine with an invalid tocindex, and thus really
  125. * never SHOULD return NULL.
  126. *
  127. *
  128. * History:
  129. * 18-11-93 - StephenE - Created
  130. *
  131. \**************************************************************************/
  132. PTRACK_INF
  133. FindTrackNodeFromTocIndex(
  134. int tocindex,
  135. PTRACK_INF listhead
  136. )
  137. {
  138. PTRACK_INF t;
  139. for( t = listhead; ((t!=NULL) && (t->TocIndex!=tocindex)); t=t->next );
  140. return t;
  141. }
  142. /*****************************Private*Routine******************************\
  143. * FindFirstTrack
  144. *
  145. * This routine computes the first "playable" track on a disc by
  146. * scanning the the play order of the tracks
  147. *
  148. *
  149. * History:
  150. * 18-11-93 - StephenE - Created
  151. *
  152. \**************************************************************************/
  153. PTRACK_PLAY
  154. FindFirstTrack(
  155. int cdrom
  156. )
  157. {
  158. if ( (g_Devices[cdrom]->State & CD_NO_CD) ||
  159. (g_Devices[cdrom]->State & CD_DATA_CD_LOADED) ) {
  160. return NULL;
  161. }
  162. return PLAYLIST(cdrom);
  163. }
  164. /*****************************Private*Routine******************************\
  165. * FindLastTrack
  166. *
  167. * This routine computes the last "playable" track on a disc by
  168. * scanning the the play order of the tracks
  169. *
  170. *
  171. * History:
  172. * 18-11-93 - StephenE - Created
  173. *
  174. \**************************************************************************/
  175. PTRACK_PLAY
  176. FindLastTrack(
  177. IN INT cdrom
  178. )
  179. {
  180. PTRACK_PLAY tr;
  181. if ( PLAYLIST(cdrom) == NULL ) {
  182. return NULL;
  183. }
  184. for( tr = PLAYLIST(cdrom); tr->nextplay != NULL; tr = tr->nextplay );
  185. return tr;
  186. }
  187. /*****************************Private*Routine******************************\
  188. * AllTracksPlayed
  189. *
  190. * This routine searches the play lists for all cdrom drives and
  191. * returns a flag as to whether all tracks on all cdrom drives have
  192. * been played.
  193. *
  194. * History:
  195. * 18-11-93 - StephenE - Created
  196. *
  197. \**************************************************************************/
  198. BOOL
  199. AllTracksPlayed(
  200. void
  201. )
  202. {
  203. INT i;
  204. BOOL result = TRUE;
  205. for( i = 0; i < g_NumCdDevices; i++ ) {
  206. result &= (CURRTRACK(i) == NULL);
  207. }
  208. return result;
  209. }
  210. /*****************************Private*Routine******************************\
  211. * FindNextTrack
  212. *
  213. * This routine computes the next "playable" track. This is a
  214. * one way door...i.e., the structures are manipulated. It uses
  215. * the following algorithms:
  216. *
  217. * Single Disc Play:
  218. *
  219. * * if next track is not NULL, return next track
  220. * * If next track is NULL, and wrap==TRUE, return
  221. * first track
  222. * * return NULL
  223. *
  224. * Multi-Disc Play:
  225. *
  226. * * if we're in random play, select a random drive to play from.
  227. * * if next track on current cdrom != NULL, return next track
  228. * * if it is NULL:
  229. *
  230. * * check next cdrom device, if current track is not NULL
  231. * return CURRTRACK for that device and set gCurrCdrom to
  232. * that device
  233. * * if NULL, go to next drive
  234. * * last drive, check wrap
  235. *
  236. * History:
  237. * 18-11-93 - StephenE - Created
  238. *
  239. \**************************************************************************/
  240. PTRACK_PLAY
  241. FindNextTrack(
  242. BOOL wrap
  243. )
  244. {
  245. int i;
  246. /*
  247. ** First, bump current track pointer
  248. */
  249. if ( CURRTRACK(g_CurrCdrom) != NULL ) {
  250. CURRTRACK(g_CurrCdrom) = CURRTRACK(g_CurrCdrom)->nextplay;
  251. }
  252. else {
  253. if ( g_fSingleDisk ) {
  254. return NULL;
  255. }
  256. }
  257. /*
  258. ** Do we need to switch drives?
  259. */
  260. if ( (!g_fSelectedOrder) && (!g_fSingleDisk) ) {
  261. /*
  262. ** Need to random to new cdrom
  263. */
  264. g_CurrCdrom = rand() % g_NumCdDevices;
  265. }
  266. /*
  267. ** Is chosen track playable?
  268. */
  269. if ( CURRTRACK(g_CurrCdrom) != NULL ) {
  270. /*
  271. ** Yep, so this is the easy case
  272. */
  273. return CURRTRACK(g_CurrCdrom);
  274. }
  275. /*
  276. ** Ok, CURRENT track on this device is not defined,
  277. ** so are we in multi-disc mode?
  278. */
  279. if ( !g_fSingleDisk ) {
  280. /*
  281. ** have all tracks played?
  282. */
  283. if ( AllTracksPlayed() ) {
  284. /*
  285. ** if wrap, reset all drives to front of their playlist
  286. */
  287. if ( wrap ) {
  288. /*
  289. ** If we are in random play mode we need to re-shuffle the
  290. ** track list so that people don't get the same tracks repeated
  291. ** again.
  292. */
  293. if (!g_fSelectedOrder) {
  294. RestorePlayListsFromShuffleLists();
  295. ComputeAndUseShufflePlayLists();
  296. }
  297. for ( i = 0; i < g_NumCdDevices; i++ ) {
  298. CURRTRACK(i) = FindFirstTrack(i);
  299. }
  300. }
  301. else {
  302. /*
  303. ** All tracks on all drives have played, and we are NOT
  304. ** in continuous mode, so we are done playing. Signify
  305. ** this by returning NULL (no playable tracks left).
  306. */
  307. return NULL;
  308. }
  309. }
  310. /*
  311. ** We're in mulit-disc play mode, and all the play lists should
  312. ** be reset now. Cycle through cdrom drives looking for a playable
  313. ** track.
  314. */
  315. i = g_CurrCdrom;
  316. do {
  317. g_CurrCdrom++;
  318. if ( g_CurrCdrom >= g_NumCdDevices ) {
  319. /*
  320. ** We hit the end of the list of devices, if we're
  321. ** in continuous play mode, we need to wrap to the
  322. ** first cdrom drive. Otherwise, we are done playing
  323. ** as there are no tracks left to play.
  324. */
  325. if ( wrap || (!g_fSelectedOrder) ) {
  326. g_CurrCdrom = 0;
  327. }
  328. else {
  329. g_CurrCdrom--;
  330. return NULL;
  331. }
  332. }
  333. } while( (CURRTRACK(g_CurrCdrom) == NULL) && (i != g_CurrCdrom) );
  334. /*
  335. ** At this point we either have a playable track, or we
  336. ** are back where we started from and we're going to return
  337. ** NULL because there are no playable tracks left.
  338. */
  339. return CURRTRACK(g_CurrCdrom);
  340. }
  341. else {
  342. /*
  343. ** We're in single disc mode, and current track is NULL,
  344. ** which means we hit the end of the playlist. So, check
  345. ** to see if we should wrap back to the first track, or
  346. ** return NULL to show that we're done playing.
  347. */
  348. if (wrap) {
  349. /*
  350. ** If we are in random play mode we need to re-shuffle the
  351. ** track list so that people don't get the same tracks repeated
  352. ** again.
  353. */
  354. if (!g_fSelectedOrder) {
  355. RestorePlayListsFromShuffleLists();
  356. ComputeAndUseShufflePlayLists();
  357. }
  358. /*
  359. ** wrap to start of the play list
  360. */
  361. CURRTRACK(g_CurrCdrom) = FindFirstTrack(g_CurrCdrom);
  362. }
  363. return CURRTRACK(g_CurrCdrom);
  364. }
  365. }
  366. /*****************************Private*Routine******************************\
  367. * FindPrevTrack
  368. *
  369. * This routine computes the previous "playable" track on a disc by
  370. * scanning the play order of the tracks from the current
  371. * track to the start of the play list. If we are at the start
  372. * of the play list, then move to the end of the list if we
  373. * are in "wrap" (i.e., continuous) play mode, otherwise return
  374. * the current track.
  375. *
  376. *
  377. * History:
  378. * 18-11-93 - StephenE - Created
  379. *
  380. \**************************************************************************/
  381. PTRACK_PLAY
  382. FindPrevTrack(
  383. int cdrom,
  384. BOOL wrap
  385. )
  386. {
  387. /*
  388. ** Is current track valid?
  389. */
  390. if ( CURRTRACK(cdrom) == NULL ) {
  391. return NULL;
  392. }
  393. /*
  394. ** If we're in multi disc play && random, the previous track
  395. ** is undefined since we could be jumping around on
  396. ** multiple discs.
  397. **
  398. ** Should Fix -- do we want to allow users to back up in the random
  399. ** list of a particular drive?
  400. */
  401. if ((!g_fSingleDisk) && (!g_fSelectedOrder)) {
  402. return CURRTRACK(cdrom);
  403. }
  404. /*
  405. ** Did we hit the start of the play list?
  406. */
  407. if ( CURRTRACK(cdrom)->prevplay == NULL ) {
  408. /*
  409. ** We hit the start of the list, check to see if we should
  410. ** wrap to end of list or not...
  411. */
  412. if ( wrap && g_fSingleDisk ) {
  413. return FindLastTrack(cdrom);
  414. }
  415. else {
  416. return CURRTRACK(cdrom);
  417. }
  418. }
  419. return CURRTRACK(cdrom)->prevplay;
  420. }
  421. /*****************************Private*Routine******************************\
  422. * FindContiguousEnd
  423. *
  424. * This routine returns the node of the track within PlayList which makes
  425. * the largest contiguous block of tracks starting w/the track pointed
  426. * to by "tr." It is used to play multiple tracks at as one track
  427. * when they are programmed to be played in sequence.
  428. *
  429. *
  430. * History:
  431. * 18-11-93 - StephenE - Created
  432. *
  433. \**************************************************************************/
  434. int
  435. FindContiguousEnd(
  436. int cdrom,
  437. PTRACK_PLAY tr
  438. )
  439. {
  440. int i;
  441. PTRACK_PLAY trend;
  442. /*
  443. ** If we're in muti-disc random play, we only play
  444. ** one track at a time, so just return next track.
  445. */
  446. if ( (!g_fSelectedOrder) && (!g_fSingleDisk) ) {
  447. return tr->TocIndex + 1;
  448. }
  449. /*
  450. ** go forward in the play list looking for contiguous blocks
  451. ** of tracks to play together. We need to check the TocIndex
  452. ** of each track to see if they are in a "run" [ like 2-5, etc. ]
  453. */
  454. i= tr->TocIndex + 1;
  455. trend = tr;
  456. while ( (trend->nextplay != NULL) && (trend->nextplay->TocIndex == i) ) {
  457. trend = trend->nextplay;
  458. i++;
  459. }
  460. return trend->TocIndex + 1;
  461. }
  462. /*****************************Private*Routine******************************\
  463. * FlipBetweenShuffleAndOrder
  464. *
  465. * This routine handles going from ordered play to shuffle play and vica\versa.
  466. *
  467. * History:
  468. * 18-11-93 - StephenE - Created
  469. *
  470. \**************************************************************************/
  471. void
  472. FlipBetweenShuffleAndOrder(
  473. void
  474. )
  475. {
  476. if ( (!g_fSelectedOrder) ) {
  477. /*
  478. ** Transitioning from Random to Ordered Play
  479. */
  480. RestorePlayListsFromShuffleLists();
  481. }
  482. else {
  483. /*
  484. ** Transitioning from Ordered to Random Play
  485. */
  486. ComputeAndUseShufflePlayLists();
  487. }
  488. /*
  489. ** If we were playing, we need to restart the play to make sure
  490. ** we don't play past where we should.
  491. */
  492. if ( g_State & CD_PLAYING ) {
  493. SeekToCurrSecond( g_CurrCdrom );
  494. }
  495. ResetTrackComboBox( g_CurrCdrom);
  496. }
  497. /*****************************Private*Routine******************************\
  498. * ComputeAndUseShufflePlayLists
  499. *
  500. * This routine computes shuffled play lists for each drive, and sets
  501. * the current PLAYLIST for erach drive to the newly computed shuffled
  502. * PLAYLIST. The old PLAYLIST for each drive is saved in SAVELIST.
  503. *
  504. *
  505. * History:
  506. * 18-11-93 - StephenE - Created
  507. *
  508. \**************************************************************************/
  509. void
  510. ComputeAndUseShufflePlayLists(
  511. void
  512. )
  513. {
  514. int i;
  515. for ( i = 0; i < g_NumCdDevices; i++ ) {
  516. ComputeSingleShufflePlayList( i );
  517. }
  518. }
  519. /*****************************Private*Routine******************************\
  520. * ComputeSingleShufflePlayList
  521. *
  522. * This routine computes shuffled play lists for drive i, and sets
  523. * the current PLAYLIST for it the newly computed shuffled
  524. * PLAYLIST. The old PLAYLIST is saved in SAVELIST.
  525. *
  526. * History:
  527. * 18-11-93 - StephenE - Created
  528. *
  529. \**************************************************************************/
  530. void
  531. ComputeSingleShufflePlayList(
  532. int i
  533. )
  534. {
  535. int j, index, numnodes;
  536. PTRACK_PLAY temp, temp1, duplist, prev, OldPlayList;
  537. /*
  538. ** First, delete the existing playlist
  539. */
  540. OldPlayList = PLAYLIST(i);
  541. PLAYLIST(i) = NULL;
  542. /*
  543. ** Now, go through each drive and create a shuffled play list
  544. ** First step is to duplicate the old play list, then we will
  545. ** randomly pick off nodes and put them on the shuffle play list.
  546. */
  547. duplist = prev = NULL;
  548. numnodes = 0;
  549. for( temp = SAVELIST(i); temp != NULL; temp = temp->nextplay ) {
  550. temp1 = AllocMemory( sizeof(TRACK_PLAY) );
  551. *temp1 = *temp;
  552. temp1->nextplay = NULL;
  553. if (duplist) {
  554. temp1->prevplay = prev;
  555. prev->nextplay = temp1;
  556. prev = temp1;
  557. }
  558. else {
  559. duplist = temp1;
  560. temp1->prevplay = NULL;
  561. prev = temp1;
  562. }
  563. numnodes++;
  564. }
  565. /*
  566. ** Now, randomly pick off nodes
  567. */
  568. prev = NULL;
  569. for( j = 0; j < numnodes; j++ ) {
  570. index = rand() % (numnodes - j + 1);
  571. temp = duplist;
  572. while( --index>0 ) {
  573. temp = temp->nextplay;
  574. }
  575. /*
  576. ** Got the node to transfer to playlist (temp),
  577. ** so we need to detach it from duplist so we
  578. ** can tack it onto the end of the playlist.
  579. */
  580. if ( temp != NULL ) {
  581. /*
  582. ** Detach temp from playlist.
  583. */
  584. if ( temp == duplist ) {
  585. duplist = temp->nextplay;
  586. }
  587. if ( temp->nextplay ) {
  588. temp->nextplay->prevplay = temp->prevplay;
  589. }
  590. if ( temp->prevplay ) {
  591. temp->prevplay->nextplay = temp->nextplay;
  592. }
  593. /*
  594. ** Now, tack it onto the end of the PLAYLIST
  595. */
  596. if ( PLAYLIST(i) ) {
  597. prev->nextplay = temp;
  598. temp->prevplay = prev;
  599. temp->nextplay = NULL;
  600. prev = temp;
  601. }
  602. else {
  603. PLAYLIST(i) = temp;
  604. temp->prevplay = NULL;
  605. prev = temp;
  606. temp->nextplay = NULL;
  607. }
  608. }
  609. }
  610. /*
  611. ** we need to reset the CURRTRACK pointer so
  612. ** that it points to a node in PLAYLIST instead of SAVELIST
  613. */
  614. if ( (g_Devices[i]->State & CD_PLAYING) && (CURRTRACK(i) != NULL) ) {
  615. index = CURRTRACK(i)->TocIndex;
  616. for( temp = PLAYLIST(i); temp->TocIndex!=index; temp=temp->nextplay );
  617. CURRTRACK(i) = temp;
  618. }
  619. else {
  620. CURRTRACK(i) = PLAYLIST(i);
  621. if ( PLAYLIST(i) != NULL ) {
  622. CDTIME(i).TrackTotalMin = PLAYLIST(i)->min;
  623. CDTIME(i).TrackTotalSec = PLAYLIST(i)->sec;
  624. CDTIME(i).TrackRemMin = PLAYLIST(i)->min;
  625. CDTIME(i).TrackRemSec = PLAYLIST(i)->sec;
  626. }
  627. }
  628. /*
  629. ** if this is the current drive, we need to redo the tracks in
  630. ** the track list combobox.
  631. */
  632. if ( i == g_CurrCdrom ) {
  633. ResetTrackComboBox( i );
  634. }
  635. /*
  636. ** Finally, free up the memory from the old playlist.
  637. */
  638. temp = OldPlayList;
  639. while ( temp != NULL ) {
  640. temp1 = temp->nextplay;
  641. LocalFree( (HLOCAL)temp );
  642. temp = temp1;
  643. }
  644. }
  645. /*****************************Private*Routine******************************\
  646. * RestorePlayListsFromShuffleLists
  647. *
  648. * This routine restores the PLAYLIST for each drive to it's "pre-shuffled"
  649. * state. This should be stored in SAVELIST. Once the restoration is done,
  650. * un-needed node are released.
  651. *
  652. * History:
  653. * 18-11-93 - StephenE - Created
  654. *
  655. \**************************************************************************/
  656. void
  657. RestorePlayListsFromShuffleLists(
  658. void
  659. )
  660. {
  661. int i,index;
  662. PTRACK_PLAY temp;
  663. for ( i = 0; i < g_NumCdDevices; i++ ) {
  664. if ( SAVELIST(i) ) {
  665. if ( CURRTRACK(i) != NULL ) {
  666. index = CURRTRACK(i)->TocIndex;
  667. }
  668. else {
  669. index = -1;
  670. }
  671. ErasePlayList(i);
  672. PLAYLIST(i) = CopyPlayList( SAVELIST(i) );
  673. /*
  674. ** Reset CURRTRACK pointer
  675. */
  676. if ( (g_Devices[i]->State & CD_PLAYING) && (index != -1) ) {
  677. for( temp = PLAYLIST(i);
  678. temp->TocIndex != index; temp=temp->nextplay );
  679. CURRTRACK(i) = temp;
  680. }
  681. else {
  682. CURRTRACK(i) = PLAYLIST(i);
  683. if ( PLAYLIST(i) != NULL ) {
  684. CDTIME(i).TrackRemMin = PLAYLIST(i)->min;
  685. CDTIME(i).TrackRemSec = PLAYLIST(i)->sec;
  686. CDTIME(i).TrackTotalMin = PLAYLIST(i)->min;
  687. CDTIME(i).TrackTotalSec = PLAYLIST(i)->sec;
  688. }
  689. }
  690. }
  691. if ( i == g_CurrCdrom ) {
  692. ResetTrackComboBox( i );
  693. }
  694. }
  695. }
  696. /*****************************Private*Routine******************************\
  697. * FigureTrackTime
  698. *
  699. * This routine computes the length of a given track, in terms
  700. * of minutes and seconds.
  701. *
  702. * cdrom - supplies an index into the global structure gDevices
  703. *
  704. * index - supplies an index to the track which should have its
  705. * length computed. This is an index into the
  706. * gDevices[cdrom]->CdInfo.Tracks[...] structure
  707. *
  708. * min - supplies a pointer to an INT which will hold the minute
  709. * portion of the track length.
  710. *
  711. * sec - supplies a pointer to an INT which will hold the seconds
  712. * portion of the track length.
  713. *
  714. * History:
  715. * 18-11-93 - StephenE - Created
  716. *
  717. \**************************************************************************/
  718. void
  719. FigureTrackTime(
  720. int cdrom,
  721. int index,
  722. int * min,
  723. int * sec
  724. )
  725. {
  726. DWORD start, end, diff;
  727. start = ((TRACK_M(cdrom,index) * FRAMES_PER_MINUTE) +
  728. (TRACK_S(cdrom,index) * FRAMES_PER_SECOND) +
  729. TRACK_F(cdrom,index));
  730. end = ((TRACK_M(cdrom,index+1) * FRAMES_PER_MINUTE) +
  731. (TRACK_S(cdrom,index+1) * FRAMES_PER_SECOND) +
  732. TRACK_F(cdrom,index+1));
  733. diff = end - start;
  734. (*min) = (diff / FRAMES_PER_MINUTE);
  735. (*sec) = (diff % FRAMES_PER_MINUTE) / FRAMES_PER_SECOND;
  736. }
  737. /*****************************Private*Routine******************************\
  738. * TimeAdjustInitialize
  739. *
  740. * Initializes the time, track, and title fields of a given
  741. * disc.
  742. *
  743. * History:
  744. * 18-11-93 - StephenE - Created
  745. *
  746. \**************************************************************************/
  747. void
  748. TimeAdjustInitialize(
  749. int cdrom
  750. )
  751. {
  752. int m, s, mtemp, stemp, ts, tm;
  753. PTRACK_PLAY tr;
  754. /*
  755. ** Is there even a cd loaded?
  756. */
  757. if (g_Devices[cdrom]->State &
  758. (CD_BEING_SCANNED | CD_IN_USE | CD_NO_CD | CD_DATA_CD_LOADED)) {
  759. /*
  760. ** Fake some information
  761. */
  762. g_Devices[cdrom]->CdInfo.NumTracks = 0;
  763. g_Devices[cdrom]->toc.FirstTrack = 0;
  764. g_Devices[cdrom]->CdInfo.Id = 0;
  765. if (g_Devices[cdrom]->State & CD_IN_USE) {
  766. _tcscpy( (LPTSTR)TITLE(cdrom), IdStr(STR_WAITING) );
  767. _tcscpy( (LPTSTR)ARTIST(cdrom), IdStr(STR_DISC_INUSE) );
  768. }
  769. else if (g_Devices[cdrom]->State & CD_BEING_SCANNED) {
  770. _tcscpy( (LPTSTR)TITLE(cdrom), IdStr(STR_WAITING) );
  771. _tcscpy( (LPTSTR)ARTIST(cdrom), IdStr(STR_BEING_SCANNED) );
  772. }
  773. else {
  774. _tcscpy( (LPTSTR)TITLE(cdrom), IdStr(STR_INSERT_DISC) );
  775. _tcscpy( (LPTSTR)ARTIST(cdrom), IdStr(STR_DATA_NO_DISC) );
  776. }
  777. /*
  778. ** Kill off play list
  779. */
  780. ErasePlayList( cdrom );
  781. EraseSaveList( cdrom );
  782. EraseTrackList( cdrom );
  783. tr = NULL;
  784. }
  785. else {
  786. /*
  787. ** Find track to use as first track
  788. */
  789. tr = FindFirstTrack( cdrom );
  790. }
  791. /*
  792. ** Set current position information
  793. */
  794. CURRTRACK(cdrom) = tr;
  795. CDTIME(cdrom).TrackCurMin = 0;
  796. CDTIME(cdrom).TrackCurSec = 0;
  797. /*
  798. ** Compute PLAY length
  799. */
  800. mtemp = stemp = m = s = ts = tm =0;
  801. for( tr = PLAYLIST(cdrom); tr != NULL; tr = tr->nextplay ) {
  802. FigureTrackTime( cdrom, tr->TocIndex, &mtemp, &stemp );
  803. m+=mtemp;
  804. s+=stemp;
  805. tr->min = mtemp;
  806. tr->sec = stemp;
  807. }
  808. /*
  809. ** to be safe, recalculate the SAVE list each time as well.
  810. */
  811. for( tr = SAVELIST(cdrom); tr != NULL; tr = tr->nextplay ) {
  812. FigureTrackTime( cdrom, tr->TocIndex, &mtemp, &stemp );
  813. tr->min = mtemp;
  814. tr->sec = stemp;
  815. }
  816. m += (s / 60);
  817. s = (s % 60);
  818. CDTIME(cdrom).TotalMin = m;
  819. CDTIME(cdrom).TotalSec = s;
  820. CDTIME(cdrom).RemMin = m;
  821. CDTIME(cdrom).RemSec = s;
  822. /*
  823. ** Fill in track length and information
  824. */
  825. if ( CURRTRACK(cdrom) != NULL ) {
  826. CDTIME(cdrom).TrackTotalMin = CDTIME(cdrom).TrackRemMin =
  827. CURRTRACK(cdrom)->min;
  828. CDTIME(cdrom).TrackTotalSec = CDTIME(cdrom).TrackRemSec =
  829. CURRTRACK(cdrom)->sec;
  830. }
  831. else {
  832. CDTIME(cdrom).TrackTotalMin = CDTIME(cdrom).TrackRemMin = 0;
  833. CDTIME(cdrom).TrackTotalSec = CDTIME(cdrom).TrackRemSec = 0;
  834. }
  835. /*
  836. ** Fill in track list combo box
  837. */
  838. if ( cdrom == g_CurrCdrom ) {
  839. ResetTrackComboBox( cdrom );
  840. /*
  841. ** Update display if this is the disc currently
  842. ** being displayed.
  843. */
  844. UpdateDisplay( DISPLAY_UPD_LED |
  845. DISPLAY_UPD_DISC_TIME |
  846. DISPLAY_UPD_TRACK_TIME |
  847. DISPLAY_UPD_TITLE_NAME |
  848. DISPLAY_UPD_TRACK_NAME );
  849. }
  850. }
  851. /*****************************Private*Routine******************************\
  852. * TimeAdjustIncSecond
  853. *
  854. * Adds one second onto current position ("time") of disc
  855. *
  856. * History:
  857. * 18-11-93 - StephenE - Created
  858. *
  859. \**************************************************************************/
  860. void
  861. TimeAdjustIncSecond(
  862. int cdrom
  863. )
  864. {
  865. PTRACK_PLAY tr;
  866. /*
  867. ** If there is no current track just return
  868. */
  869. if ( CURRTRACK(g_CurrCdrom) == NULL ) {
  870. return;
  871. }
  872. /*
  873. ** Update current track time
  874. */
  875. CDTIME(cdrom).TrackCurSec++;
  876. if ( CDTIME(cdrom).TrackCurSec > 59 ) {
  877. CDTIME(cdrom).TrackCurMin++;
  878. CDTIME(cdrom).TrackCurSec = 0;
  879. }
  880. /*
  881. ** Now, check to see if we skipped any track boundaries
  882. */
  883. if (
  884. ((CDTIME(cdrom).TrackCurMin >= CDTIME(cdrom).TrackTotalMin) &&
  885. (CDTIME(cdrom).TrackCurSec >= CDTIME(cdrom).TrackTotalSec))
  886. ||
  887. ((g_fIntroPlay) &&
  888. ((CDTIME(cdrom).TrackCurMin > 0) ||
  889. (CDTIME(cdrom).TrackCurSec > g_IntroPlayLength)) )
  890. ) {
  891. /*
  892. ** We did, so skip to next track
  893. */
  894. /*
  895. ** Should Fix for new FindNextTrack
  896. */
  897. tr = FindNextTrack( g_fContinuous );
  898. if ( tr == NULL ) {
  899. /*
  900. ** Hit end of playlist, so stay at end of current
  901. ** track.
  902. */
  903. if (!g_fIntroPlay) {
  904. CDTIME(cdrom).TrackCurMin = CDTIME(cdrom).TrackTotalMin;
  905. CDTIME(cdrom).TrackCurSec = CDTIME(cdrom).TrackTotalSec;
  906. }
  907. else {
  908. CDTIME(cdrom).TrackCurMin = 0;
  909. CDTIME(cdrom).TrackCurSec = g_IntroPlayLength;
  910. }
  911. return;
  912. }
  913. if ( g_CurrCdrom != g_LastCdrom) {
  914. SwitchToCdrom(g_CurrCdrom, FALSE );
  915. }
  916. TimeAdjustSkipToTrack( cdrom, tr );
  917. }
  918. else {
  919. /*
  920. ** Update current track remaining time
  921. */
  922. CDTIME(cdrom).TrackRemSec--;
  923. if ( CDTIME(cdrom).TrackRemSec < 0 ) {
  924. CDTIME(cdrom).TrackRemMin--;
  925. CDTIME(cdrom).TrackRemSec = 59;
  926. }
  927. /*
  928. ** Update total remaining time
  929. */
  930. CDTIME(cdrom).RemSec--;
  931. if ( CDTIME(cdrom).RemSec < 0 ) {
  932. CDTIME(cdrom).RemMin--;
  933. CDTIME(cdrom).RemSec = 59;
  934. }
  935. }
  936. /*
  937. ** Update Display
  938. */
  939. UpdateDisplay( DISPLAY_UPD_LED );
  940. }
  941. /*****************************Private*Routine******************************\
  942. * TimeAdjustDecSecond
  943. *
  944. * Subtracts one second from current position ("time") of disc
  945. *
  946. * History:
  947. * 18-11-93 - StephenE - Created
  948. *
  949. \**************************************************************************/
  950. void
  951. TimeAdjustDecSecond(
  952. int cdrom
  953. )
  954. {
  955. int min,sec;
  956. PTRACK_PLAY prev,tr;
  957. /*
  958. ** If there is no current track, just return
  959. */
  960. if ( CURRTRACK(g_CurrCdrom) == NULL ) {
  961. return;
  962. }
  963. /*
  964. ** Update current track
  965. */
  966. CDTIME(cdrom).TrackCurSec--;
  967. if ( CDTIME(cdrom).TrackCurSec < 0 ) {
  968. CDTIME(cdrom).TrackCurMin--;
  969. CDTIME(cdrom).TrackCurSec = 59;
  970. }
  971. /*
  972. ** Update current track remaining
  973. */
  974. CDTIME(cdrom).TrackRemSec++;
  975. if ( CDTIME(cdrom).TrackRemSec > 59 ) {
  976. CDTIME(cdrom).TrackRemMin++;
  977. CDTIME(cdrom).TrackRemSec = 0;
  978. }
  979. /*
  980. ** Update total remaining time
  981. */
  982. CDTIME(cdrom).RemSec++;
  983. if ( CDTIME(cdrom).RemSec > 59 ) {
  984. CDTIME(cdrom).RemMin++;
  985. CDTIME(cdrom).RemSec = 0;
  986. }
  987. /*
  988. ** Now, check to see if we skipped any boundaries we shouldn't have!
  989. */
  990. if ( CDTIME(cdrom).TrackCurMin < 0 ) {
  991. /*
  992. ** We went "off" the front end of the track,
  993. ** so we need to see what to do now. Options
  994. ** are:
  995. **
  996. ** (1) Go to end of track before us.
  997. ** (2) If intro play, go to 0:10 of
  998. ** track before us.
  999. ** (3) If not in continuous play, and
  1000. ** this is the first track, then
  1001. ** just sit at 0:00
  1002. */
  1003. prev = FindPrevTrack( cdrom, g_fContinuous );
  1004. if ( prev == CURRTRACK(cdrom) ) {
  1005. /*
  1006. ** We are on the first track, and not in
  1007. ** continuous mode, so just go to 0:00
  1008. */
  1009. CDTIME(cdrom).TrackCurSec = 0;
  1010. CDTIME(cdrom).TrackCurMin = 0;
  1011. CDTIME(cdrom).TrackRemMin = CDTIME(cdrom).TrackTotalMin;
  1012. CDTIME(cdrom).TrackRemSec = CDTIME(cdrom).TrackTotalSec;
  1013. min = sec = 0;
  1014. for( tr = PLAYLIST( cdrom ); tr != NULL; tr = tr->nextplay ) {
  1015. min += tr->min;
  1016. sec += tr->sec;
  1017. }
  1018. min += (sec / 60);
  1019. sec = (sec % 60);
  1020. CDTIME(cdrom).RemMin = min;
  1021. CDTIME(cdrom).RemSec = sec;
  1022. UpdateDisplay( DISPLAY_UPD_LED );
  1023. }
  1024. else {
  1025. /*
  1026. ** Valid previous track
  1027. */
  1028. if ( !g_fIntroPlay ) {
  1029. /*
  1030. ** We need to place the current play position
  1031. ** at the end of the previous track.
  1032. */
  1033. CDTIME(cdrom).TrackCurMin = CDTIME(cdrom).TrackTotalMin = prev->min;
  1034. CDTIME(cdrom).TrackCurSec = CDTIME(cdrom).TrackTotalSec = prev->sec;
  1035. CDTIME(cdrom).TrackRemMin = CDTIME(cdrom).TrackRemSec = 0;
  1036. min = sec = 0;
  1037. for( tr = prev->nextplay; tr != NULL; tr = tr->nextplay ) {
  1038. min += tr->min;
  1039. sec += tr->sec;
  1040. }
  1041. min += (sec / 60);
  1042. sec = (sec % 60);
  1043. CDTIME(cdrom).RemMin = min;
  1044. CDTIME(cdrom).RemSec = sec;
  1045. }
  1046. else {
  1047. /*
  1048. ** Intro play -- instead of end of track,
  1049. ** jump to 00:10...
  1050. */
  1051. CDTIME(cdrom).TrackCurMin = 0;
  1052. CDTIME(cdrom).TrackCurSec =
  1053. min( g_IntroPlayLength, prev->sec );
  1054. CDTIME(cdrom).TrackTotalMin = prev->min;
  1055. CDTIME(cdrom).TrackTotalSec = prev->sec;
  1056. CDTIME(cdrom).TrackRemMin = CDTIME(cdrom).TrackTotalMin;
  1057. CDTIME(cdrom).TrackRemSec = CDTIME(cdrom).TrackTotalSec -
  1058. min( g_IntroPlayLength, prev->sec );
  1059. if ( CDTIME(cdrom).TrackRemSec < 0 ) {
  1060. CDTIME(cdrom).TrackRemSec += 60;
  1061. CDTIME(cdrom).TrackRemMin--;
  1062. }
  1063. min = sec = 0;
  1064. for( tr = prev; tr != NULL; tr = tr->nextplay ) {
  1065. min += tr->min;
  1066. sec += tr->sec;
  1067. }
  1068. sec -= min( g_IntroPlayLength, prev->sec );
  1069. if ( sec < 0 ) {
  1070. sec+=60;
  1071. min--;
  1072. }
  1073. min += (sec / 60);
  1074. sec = (sec % 60);
  1075. CDTIME(cdrom).RemMin = min;
  1076. CDTIME(cdrom).RemSec = sec;
  1077. }
  1078. CURRTRACK(cdrom) = prev;
  1079. UpdateDisplay( DISPLAY_UPD_LED |
  1080. DISPLAY_UPD_TRACK_NAME |
  1081. DISPLAY_UPD_TRACK_TIME );
  1082. }
  1083. }
  1084. else {
  1085. UpdateDisplay( DISPLAY_UPD_LED );
  1086. }
  1087. }
  1088. /*****************************Private*Routine******************************\
  1089. * InitializeNewTrackTime
  1090. *
  1091. * Updates track/time information for gDevices array.
  1092. *
  1093. * History:
  1094. * 18-11-93 - StephenE - Created
  1095. *
  1096. \**************************************************************************/
  1097. void
  1098. InitializeNewTrackTime(
  1099. int cdrom,
  1100. PTRACK_PLAY tr,
  1101. BOOL fUpdateDisplay
  1102. )
  1103. {
  1104. int min,sec;
  1105. /*
  1106. ** Update time information in gDevices structure
  1107. */
  1108. CDTIME(cdrom).CurrTrack = tr;
  1109. CDTIME(cdrom).TrackCurMin = 0;
  1110. CDTIME(cdrom).TrackCurSec = 0;
  1111. if (tr == NULL) {
  1112. CDTIME(cdrom).TrackTotalMin = 0;
  1113. CDTIME(cdrom).TrackTotalSec = 0;
  1114. }
  1115. else {
  1116. CDTIME(cdrom).TrackTotalMin = CDTIME(cdrom).TrackRemMin = tr->min;
  1117. CDTIME(cdrom).TrackTotalSec = CDTIME(cdrom).TrackRemSec = tr->sec;
  1118. }
  1119. min = sec = 0;
  1120. for( tr = PLAYLIST(cdrom); tr!=NULL; tr = tr->nextplay ) {
  1121. min += tr->min;
  1122. sec += tr->sec;
  1123. }
  1124. min += (sec / 60);
  1125. sec = (sec % 60);
  1126. CDTIME(cdrom).RemMin = min;
  1127. CDTIME(cdrom).RemSec = sec;
  1128. /*
  1129. ** Update LED box
  1130. */
  1131. if (fUpdateDisplay) {
  1132. UpdateDisplay( DISPLAY_UPD_LED | DISPLAY_UPD_TRACK_NAME |
  1133. DISPLAY_UPD_TRACK_TIME );
  1134. }
  1135. }
  1136. /*****************************Private*Routine******************************\
  1137. * TimeAdjustSkipToTrack
  1138. *
  1139. * Updates time/track information for gDevices array and then
  1140. * issues skip to track commands to cdrom device.
  1141. *
  1142. * History:
  1143. * 18-11-93 - StephenE - Created
  1144. *
  1145. \**************************************************************************/
  1146. void
  1147. TimeAdjustSkipToTrack(
  1148. int cdrom,
  1149. PTRACK_PLAY tr
  1150. )
  1151. {
  1152. /*
  1153. ** Update time information in gDevices structure
  1154. */
  1155. InitializeNewTrackTime( cdrom, tr, TRUE );
  1156. /*
  1157. ** Actually seek to the track, and play it if appropriate
  1158. */
  1159. if ((g_Devices[cdrom]->State & CD_PLAYING) ||
  1160. (g_Devices[cdrom]->State & CD_PAUSED)) {
  1161. PlayCurrTrack( cdrom );
  1162. if (g_Devices[cdrom]->State & CD_PAUSED) {
  1163. PauseTheCdromDrive( cdrom );
  1164. }
  1165. }
  1166. else if (tr) {
  1167. SeekToTrackAndHold( cdrom, tr->TocIndex );
  1168. }
  1169. }
  1170. /*****************************Private*Routine******************************\
  1171. * SyncDisplay
  1172. *
  1173. * Queries the cdrom device for its current position, and then
  1174. * updates the display accordingly. Also, detects when a track has
  1175. * finished playing, or when intro segment is over, and skips to the
  1176. * next track.
  1177. *
  1178. * History:
  1179. * 18-11-93 - StephenE - Created
  1180. *
  1181. \**************************************************************************/
  1182. void
  1183. SyncDisplay(
  1184. void
  1185. )
  1186. {
  1187. int m,s;
  1188. PTRACK_PLAY next;
  1189. CURRPOS cp;
  1190. PCURRPOS pCurr = &cp;
  1191. /*
  1192. ** If there isn't a disc in the drive, ignore this
  1193. ** request
  1194. */
  1195. if ( (g_Devices[g_CurrCdrom]->State & CD_NO_CD) ||
  1196. (g_Devices[g_CurrCdrom]->State & CD_DATA_CD_LOADED) ) {
  1197. return;
  1198. }
  1199. /*
  1200. ** Query cdrom device for current position
  1201. */
  1202. if ( !GetCurrPos( g_CurrCdrom, pCurr ) ) {
  1203. /*
  1204. ** If there was an error, it will already have been
  1205. ** reported in CheckStatus of cdapi.c...so, we don't need
  1206. ** to tell anything more here. When an error occurs, the
  1207. ** fields of the pCurr structure are zeroed, so we don't
  1208. ** need to clean those up either
  1209. */
  1210. return;
  1211. }
  1212. /*
  1213. ** Has the current play selection finished playing?
  1214. */
  1215. #ifdef USE_IOCTLS
  1216. if ((pCurr->AudioStatus == AUDIO_STATUS_PLAY_COMPLETE) &&
  1217. ( !(g_State & CD_SEEKING) )) {
  1218. #else
  1219. if ((pCurr->AudioStatus == MCI_MODE_STOP) &&
  1220. ( !(g_State & CD_SEEKING) )) {
  1221. #endif
  1222. Play_Complete:
  1223. /*
  1224. ** Yep, so skip to the next track.
  1225. */
  1226. next = FindNextTrack( g_fContinuous );
  1227. if ( next == NULL ) {
  1228. /*
  1229. ** There are no more tracks to play, so
  1230. ** fake a press on the "stop" button. But,
  1231. ** we want to set gCurrCdrom back to the "playing"
  1232. ** drive 'cause it may have changed in our call
  1233. ** to FindNextTrack.
  1234. */
  1235. g_CurrCdrom = g_LastCdrom;
  1236. SendMessage( g_hwndApp, WM_COMMAND, IDM_PLAYBAR_STOP, 0L );
  1237. }
  1238. else {
  1239. if ( g_CurrCdrom != g_LastCdrom ) {
  1240. SwitchToCdrom( g_CurrCdrom, FALSE );
  1241. /*
  1242. ** We use to start the disc play by sending the play command.
  1243. ** SendMessage( g_hwndApp, WM_COMMAND, IDM_PLAYBAR_PLAY, 0L );
  1244. ** However, all we realy need to put the drives state into
  1245. ** playing and let TimeAdjustSkipToTrack take care of starting
  1246. ** playing. If we don't do this when the app is in multi-disc
  1247. ** random play mode, we get a fraction of a second of the
  1248. ** first track in the playlist played before we seek to the
  1249. ** the correct track and start playing it. This sounds really
  1250. ** bad.
  1251. */
  1252. g_State &= ~CD_STOPPED;
  1253. g_State |= CD_PLAYING;
  1254. }
  1255. TimeAdjustSkipToTrack( g_CurrCdrom, next );
  1256. }
  1257. return;
  1258. }
  1259. /*
  1260. ** Check to see if we need to update the display
  1261. */
  1262. if ( (pCurr->Track < 100) && ( pCurr->Track >
  1263. (CURRTRACK(g_CurrCdrom)->TocIndex + FIRSTTRACK(g_CurrCdrom)) )) {
  1264. /*
  1265. ** We got to the next track in a multi-track
  1266. ** play, so mark per track information for
  1267. ** new track
  1268. */
  1269. if ((CURRTRACK(g_CurrCdrom)->nextplay != NULL) &&
  1270. ((CURRTRACK(g_CurrCdrom)->TocIndex + 1) ==
  1271. CURRTRACK(g_CurrCdrom)->nextplay->TocIndex)) {
  1272. next = FindNextTrack( g_fContinuous );
  1273. if ( next == NULL ) {
  1274. /*
  1275. ** There are no more tracks to play, so
  1276. ** fake a press on the "stop" button. But,
  1277. ** we want to set gCurrCdrom back to the "playing"
  1278. ** drive 'cause it may have changed in our call
  1279. ** to FindNextTrack.
  1280. */
  1281. g_CurrCdrom = g_LastCdrom;
  1282. SendMessage( g_hwndControls[INDEX(IDM_PLAYBAR_STOP)],
  1283. WM_LBUTTONDOWN, 0, 0L );
  1284. SendMessage( g_hwndControls[INDEX(IDM_PLAYBAR_STOP)],
  1285. WM_LBUTTONUP, 0, 0L );
  1286. }
  1287. else {
  1288. if ( g_CurrCdrom != g_LastCdrom ) {
  1289. SwitchToCdrom( g_CurrCdrom, FALSE );
  1290. SendMessage( g_hwndControls[INDEX(IDM_PLAYBAR_PLAY)],
  1291. WM_LBUTTONDOWN, 0, 0L );
  1292. SendMessage( g_hwndControls[INDEX(IDM_PLAYBAR_PLAY)],
  1293. WM_LBUTTONUP, 0, 0L );
  1294. }
  1295. InitializeNewTrackTime( g_CurrCdrom, next, FALSE );
  1296. UpdateDisplay( DISPLAY_UPD_TRACK_NAME | DISPLAY_UPD_TRACK_TIME );
  1297. }
  1298. }
  1299. else {
  1300. /*
  1301. ** If we get here it is probably the result of starting
  1302. ** CD Player whislt the current disc was still playing.
  1303. ** We look for the currently playing track in the current
  1304. ** playlist.
  1305. */
  1306. next = FindFirstTrack(g_CurrCdrom);
  1307. while ( (next != NULL)
  1308. && (pCurr->Track != (next->TocIndex + 1)) ) {
  1309. #if DBG
  1310. dprintf("trying track %d", (next->TocIndex + 1));
  1311. #endif
  1312. next = next->nextplay;
  1313. }
  1314. /*
  1315. ** If next is NULL it means that we are playing a track that
  1316. ** is currently not on the users playlist. So, we put up a
  1317. ** message box informing the user of this fact and that we are
  1318. ** going to temporarily add the track to the current playlist
  1319. ** as the first track. Otherwise, we found the track in the
  1320. ** playlist so just update the track time for this track.
  1321. */
  1322. if (next == NULL) {
  1323. //<mwetzel:08.28.97> Removed this line of code, so that tracks don't get
  1324. //accidentally added. After a track is played, the STOP state is sensed,
  1325. //and this function (see above) advances the track. However, under a rare
  1326. //(about 1-5% of time) circumstance, this thread will sense that the cd's
  1327. //time value means it's on the next track, and the cd is still in play mode.
  1328. //This code used to interpret that as a new play command, and added the track
  1329. //to the playlist. Hence, I commented out the following line. If the actual
  1330. //case where a new play command is received, the new track is added to the
  1331. //playlist in the HandlePassedCommandLine() call.
  1332. //AddTemporaryTrackToPlayList(pCurr);
  1333. }
  1334. else {
  1335. InitializeNewTrackTime( g_CurrCdrom, next, TRUE );
  1336. }
  1337. }
  1338. return;
  1339. }
  1340. if ( pCurr->Track <
  1341. (CURRTRACK(g_CurrCdrom)->TocIndex + FIRSTTRACK(g_CurrCdrom)) )
  1342. return;
  1343. if ( (pCurr->Index != 0)
  1344. && (pCurr->m <= CDTIME(g_CurrCdrom).TrackCurMin)
  1345. && (pCurr->s <= CDTIME(g_CurrCdrom).TrackCurSec) )
  1346. return;
  1347. /*
  1348. ** Set track elapsed time
  1349. */
  1350. CDTIME(g_CurrCdrom).TrackCurMin = pCurr->m;
  1351. CDTIME(g_CurrCdrom).TrackCurSec = pCurr->s;
  1352. /*
  1353. ** Set track remaining time
  1354. */
  1355. m = pCurr->m;
  1356. if ( (pCurr->s) <= CDTIME(g_CurrCdrom).TrackTotalSec ) {
  1357. s = CDTIME(g_CurrCdrom).TrackTotalSec - pCurr->s;
  1358. }
  1359. else {
  1360. s = 60 - (pCurr->s - CDTIME(g_CurrCdrom).TrackTotalSec);
  1361. m++;
  1362. }
  1363. CDTIME(g_CurrCdrom).TrackRemMin = CDTIME(g_CurrCdrom).TrackTotalMin - m;
  1364. CDTIME(g_CurrCdrom).TrackRemSec = s;
  1365. /*
  1366. ** Set disc remaining time
  1367. **
  1368. ** Should Fix -- for now, just decrement by 1 second
  1369. */
  1370. CDTIME(g_CurrCdrom).RemSec--;
  1371. if (CDTIME(g_CurrCdrom).RemSec < 0) {
  1372. CDTIME(g_CurrCdrom).RemSec = 59;
  1373. CDTIME(g_CurrCdrom).RemMin--;
  1374. }
  1375. /*
  1376. ** Update LED box
  1377. */
  1378. if ( (pCurr->Index != 0) || ((pCurr->m == 0) && (pCurr->s == 0)) ) {
  1379. UpdateDisplay( DISPLAY_UPD_LED );
  1380. }
  1381. else {
  1382. UpdateDisplay( DISPLAY_UPD_LED | DISPLAY_UPD_LEADOUT_TIME );
  1383. }
  1384. /*
  1385. ** Check to see if we are intro play and have played
  1386. ** intro segment...if so, skip to next track
  1387. */
  1388. if ( ((pCurr->s >= (g_IntroPlayLength + 1)) || (pCurr->m > 0))
  1389. && g_fIntroPlay ) {
  1390. goto Play_Complete;
  1391. }
  1392. }
  1393. /*****************************Private*Routine******************************\
  1394. * ValidatePosition
  1395. *
  1396. * Checks the current position on the CD, then verifies that the
  1397. * relative offset in the track + the beginning of the track's
  1398. * position is the same as the absolute position on the CD.
  1399. *
  1400. * History:
  1401. * 18-11-93 - StephenE - Created
  1402. *
  1403. \**************************************************************************/
  1404. void
  1405. ValidatePosition(
  1406. int cdrom
  1407. )
  1408. {
  1409. int Mult, Frames;
  1410. CURRPOS cp;
  1411. PCURRPOS pCurr = &cp;
  1412. LPTSTR s1,s2;
  1413. if (!GetCurrPos( cdrom, pCurr ))
  1414. /*
  1415. ** If there was an error, it will already have been
  1416. ** reported in CheckStatus of cdapi.c...so, we don't need
  1417. ** to tell anything more here. When an error occurs, the
  1418. ** fields of the pCurr structure are zeroed, so we don't
  1419. ** need to clean those up either
  1420. */
  1421. return;
  1422. /*
  1423. ** Make sure the position returned is consistent with
  1424. ** what we know about the CD. By comparing the relative time
  1425. ** on this track to the absolute time on the CD, we should be
  1426. ** able to make sure we're still on the right disc. This is
  1427. ** a failsafe for when polling fails to notice an ejected
  1428. ** disc.
  1429. */
  1430. if ((cp.Track > 0)&&(cp.Track < 101)) {
  1431. Frames = cp.ab_m * 60 * 75;
  1432. Frames += cp.ab_s * 75;
  1433. Frames += cp.ab_f;
  1434. Frames -= TRACK_M(cdrom,cp.Track-1) * 60 * 75;
  1435. Frames -= TRACK_S(cdrom,cp.Track-1) * 75;
  1436. Frames -= TRACK_F(cdrom,cp.Track-1);
  1437. if (pCurr->Index) {
  1438. Mult = 1;
  1439. }
  1440. else {
  1441. Mult = -1;
  1442. }
  1443. Frames -= Mult*cp.m * 60 * 75;
  1444. Frames -= Mult*cp.s * 75;
  1445. Frames -= Mult*cp.f;
  1446. if (g_Devices[cdrom]->CdInfo.iFrameOffset == NEW_FRAMEOFFSET) {
  1447. g_Devices[cdrom]->CdInfo.iFrameOffset = Frames;
  1448. }
  1449. if ((ABS(Frames - g_Devices[ cdrom ]->CdInfo.iFrameOffset) > 4) &&
  1450. (ABS(Frames) > 4)) {
  1451. HWND hwndStop;
  1452. hwndStop = g_hwndControls[INDEX(IDM_PLAYBAR_STOP)];
  1453. s1 = AllocMemory( _tcslen(IdStr(STR_BAD_DISC)) + 1 );
  1454. _tcscpy( s1, IdStr(STR_BAD_DISC) );
  1455. s2 = AllocMemory( _tcslen(IdStr(STR_CDPLAYER)) + 1);
  1456. _tcscpy(s2,IdStr(STR_CDPLAYER));
  1457. MessageBox( g_hwndApp, s1, s2, MB_APPLMODAL|MB_ICONSTOP|MB_OK );
  1458. SendMessage( hwndStop,WM_LBUTTONDOWN, 1,0L );
  1459. SendMessage( hwndStop,WM_LBUTTONUP, 1, 0L );
  1460. RescanDevice(g_hwndApp, cdrom );
  1461. LocalFree( (HLOCAL)s1 );
  1462. LocalFree( (HLOCAL)s2 );
  1463. return;
  1464. }
  1465. }
  1466. }
  1467. /*****************************Private*Routine******************************\
  1468. * ResetTrackComboBox
  1469. *
  1470. * This routine deletes and then resets the track name combobox based
  1471. * on the contents of the PLAYLIST for the specified cdrom drive.
  1472. *
  1473. * History:
  1474. * 18-11-93 - StephenE - Created
  1475. *
  1476. \**************************************************************************/
  1477. VOID
  1478. ResetTrackComboBox(
  1479. int cdrom
  1480. )
  1481. {
  1482. int j,index;
  1483. PTRACK_PLAY temp;
  1484. HWND hwnd;
  1485. hwnd = g_hwndControls[INDEX(IDC_TRACK_LIST)];
  1486. SetWindowRedraw( hwnd, FALSE );
  1487. ComboBox_ResetContent( hwnd );
  1488. /*
  1489. ** Add new playlist, and select correct entry for current track
  1490. */
  1491. j = index = 0;
  1492. for( temp = PLAYLIST(cdrom); temp != NULL; temp = temp->nextplay ) {
  1493. ComboBox_InsertString( hwnd, -1, temp->TocIndex );
  1494. if ( temp == CURRTRACK(cdrom) ) {
  1495. index = j;
  1496. }
  1497. j++;
  1498. }
  1499. ComboBox_SetCurSel( hwnd, index );
  1500. SetWindowRedraw( hwnd, TRUE );
  1501. RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE );
  1502. UpdateWindow( hwnd );
  1503. UpdateDisplay( DISPLAY_UPD_LED | DISPLAY_UPD_TRACK_TIME );
  1504. }
  1505. /******************************Public*Routine******************************\
  1506. * PlayListMatchesAvailList
  1507. *
  1508. * Compares the current play list with the default play list to if they match.
  1509. *
  1510. * History:
  1511. * dd-mm-94 - StephenE - Created
  1512. *
  1513. \**************************************************************************/
  1514. BOOL
  1515. PlayListMatchesAvailList(
  1516. void
  1517. )
  1518. {
  1519. PTRACK_PLAY pl = SAVELIST(g_CurrCdrom);
  1520. int i = 0;
  1521. while (pl && i < NUMTRACKS(g_CurrCdrom)) {
  1522. if ( pl->TocIndex != i) {
  1523. return FALSE;
  1524. }
  1525. pl = pl->nextplay;
  1526. i++;
  1527. }
  1528. return pl == NULL && i == NUMTRACKS(g_CurrCdrom);
  1529. }
  1530. /*****************************Private*Routine******************************\
  1531. * AddTemporaryTrackToPlayList
  1532. *
  1533. * This functions adds the currently playing track to the playlist.
  1534. * pCurr contains the toc index of the track that is required to be added.
  1535. *
  1536. * History:
  1537. * dd-mm-94 - StephenE - Created
  1538. *
  1539. \**************************************************************************/
  1540. void
  1541. AddTemporaryTrackToPlayList(
  1542. PCURRPOS pCurr
  1543. )
  1544. {
  1545. // LPTSTR lpstrTitle;
  1546. // LPTSTR lpstrText;
  1547. PTRACK_PLAY tr;
  1548. int m, s;
  1549. /*
  1550. ** Add track to the current playlist.
  1551. */
  1552. tr = AllocMemory( sizeof(TRACK_PLAY) );
  1553. tr->TocIndex = pCurr->Track - 1;
  1554. FigureTrackTime(g_CurrCdrom, tr->TocIndex, &tr->min, &tr->sec);
  1555. tr->nextplay = PLAYLIST(g_CurrCdrom);
  1556. tr->prevplay = NULL;
  1557. PLAYLIST(g_CurrCdrom)->prevplay = tr;
  1558. PLAYLIST(g_CurrCdrom) = tr;
  1559. /*
  1560. ** Update the display.
  1561. */
  1562. InitializeNewTrackTime( g_CurrCdrom, tr, TRUE );
  1563. ResetTrackComboBox( g_CurrCdrom );
  1564. m = CDTIME(g_CurrCdrom).TotalMin + tr->min;
  1565. s = CDTIME(g_CurrCdrom).TotalSec + tr->sec;
  1566. m += (s / 60);
  1567. s = (s % 60);
  1568. CDTIME(g_CurrCdrom).TotalMin = m;
  1569. CDTIME(g_CurrCdrom).TotalSec = s;
  1570. UpdateDisplay(DISPLAY_UPD_DISC_TIME);
  1571. /*
  1572. ** Now modify the current saved playlist. We do this so that transitions
  1573. ** from/to random mode work correctly.
  1574. */
  1575. tr = AllocMemory( sizeof(TRACK_PLAY) );
  1576. tr->TocIndex = pCurr->Track - 1;
  1577. FigureTrackTime(g_CurrCdrom, tr->TocIndex, &tr->min, &tr->sec);
  1578. tr->nextplay = SAVELIST(g_CurrCdrom);
  1579. tr->prevplay = NULL;
  1580. SAVELIST(g_CurrCdrom)->prevplay = tr;
  1581. SAVELIST(g_CurrCdrom) = tr;
  1582. #if 0
  1583. /*
  1584. ** Now, tell the user what we have just done. Note that we disable the
  1585. ** the Heart beat timer so that we don't renenter ourselves.
  1586. */
  1587. lpstrTitle = AllocMemory( STR_MAX_STRING_LEN * sizeof(TCHAR) );
  1588. lpstrText = AllocMemory( STR_MAX_STRING_LEN * sizeof(TCHAR) );
  1589. _tcscpy( lpstrText, IdStr(STR_NOT_IN_PLAYLIST) );
  1590. _tcscpy( lpstrTitle, IdStr(STR_CDPLAYER) );
  1591. KillTimer( g_hwndApp, HEARTBEAT_TIMER_ID );
  1592. MessageBox( NULL, lpstrText, lpstrTitle,
  1593. MB_APPLMODAL | MB_ICONINFORMATION | MB_OK );
  1594. SetTimer( g_hwndApp, HEARTBEAT_TIMER_ID, HEARTBEAT_TIMER_RATE,
  1595. HeartBeatTimerProc );
  1596. LocalFree( (HLOCAL)lpstrText );
  1597. LocalFree( (HLOCAL)lpstrTitle );
  1598. #endif
  1599. }