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.

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