2075 lines
49 KiB
C
2075 lines
49 KiB
C
/******************************Module*Header*******************************\
|
|
* Module Name: trklst.c
|
|
*
|
|
* This module manipulates the cdrom track list. The table of contents MUST
|
|
* be locked for ALL cdrom devices before calling any functions in this module.
|
|
*
|
|
* Created: 02-11-93
|
|
* Author: Stephen Estrop [StephenE]
|
|
*
|
|
* Copyright (c) 1993 Microsoft Corporation
|
|
\**************************************************************************/
|
|
#pragma warning( once : 4201 4214 )
|
|
|
|
#define NOOLE
|
|
|
|
#include <windows.h> /* required for all Windows applications */
|
|
#include <windowsx.h>
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <tchar.h> /* contains portable ascii/unicode macros */
|
|
|
|
|
|
#include "resource.h"
|
|
#include "cdplayer.h"
|
|
#include "cdapi.h"
|
|
#include "scan.h"
|
|
#include "database.h"
|
|
#include "trklst.h"
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* ComputeDriveComboBox
|
|
*
|
|
* This routine deletes and then reads all the drive (artist) selections
|
|
* to the drive combobox.
|
|
*
|
|
*
|
|
* History:
|
|
* 18-11-93 - StephenE - Created
|
|
*
|
|
\**************************************************************************/
|
|
void
|
|
ComputeDriveComboBox(
|
|
void
|
|
)
|
|
{
|
|
int i,index;
|
|
HWND hwnd;
|
|
|
|
hwnd = g_hwndControls[INDEX(IDC_ARTIST_NAME)];
|
|
|
|
SetWindowRedraw( hwnd, FALSE );
|
|
ComboBox_ResetContent( hwnd );
|
|
|
|
index = 0;
|
|
for( i = 0; i < g_NumCdDevices; i++ ) {
|
|
|
|
ComboBox_InsertString( hwnd, -1, i );
|
|
|
|
if ( i == g_CurrCdrom ) {
|
|
|
|
index = i;
|
|
}
|
|
|
|
}
|
|
|
|
SetWindowRedraw( hwnd, TRUE );
|
|
ComboBox_SetCurSel( hwnd, index );
|
|
|
|
RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE );
|
|
UpdateWindow( hwnd );
|
|
}
|
|
|
|
|
|
|
|
/*****************************Private*Routine******************************\
|
|
* SwitchToCdrom
|
|
*
|
|
* This routine is called when the used selects a new cdrom device
|
|
* to access. It handles reset the state of both the "old" and "new"
|
|
* chosen cdroms.
|
|
*
|
|
*
|
|
* History:
|
|
* 18-11-93 - StephenE - Created
|
|
*
|
|
\**************************************************************************/
|
|
void
|
|
SwitchToCdrom(
|
|
int NewCdrom,
|
|
BOOL prompt
|
|
)
|
|
{
|
|
int oldState, oldState2;
|
|
TCHAR s1[256], s2[256];
|
|
|
|
oldState = g_Devices[g_LastCdrom]->State;
|
|
oldState2 = g_Devices[g_CurrCdrom]->State;
|
|
|
|
if (NewCdrom != g_LastCdrom) {
|
|
|
|
if (prompt) {
|
|
|
|
if (g_Devices[g_CurrCdrom]->State & CD_PLAYING) {
|
|
|
|
_tcscpy( s1, IdStr( STR_CANCEL_PLAY ) );
|
|
_tcscpy( s2, IdStr( STR_CHANGE_CDROM ) );
|
|
|
|
if ( MessageBox( g_hwndApp, s1, s2,
|
|
MB_APPLMODAL | MB_DEFBUTTON1 |
|
|
MB_ICONQUESTION | MB_YESNO) != IDYES ) {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
** stop the drive we're leaving
|
|
*/
|
|
|
|
g_CurrCdrom = g_LastCdrom;
|
|
|
|
if (prompt && (g_State & (CD_PLAYING | CD_PAUSED)) ) {
|
|
|
|
HWND hwndButton;
|
|
|
|
hwndButton = g_hwndControls[INDEX(IDM_PLAYBAR_STOP)];
|
|
|
|
SendMessage( hwndButton, WM_LBUTTONDOWN, 0, 0L );
|
|
SendMessage( hwndButton, WM_LBUTTONUP, 0, 0L );
|
|
|
|
} else {
|
|
|
|
if ( StopTheCdromDrive( g_LastCdrom ) ) {
|
|
|
|
g_State &= (~(CD_PLAYING | CD_PAUSED));
|
|
g_State |= CD_STOPPED;
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Set new cdrom drive and initialize time fields
|
|
*/
|
|
|
|
g_LastCdrom = g_CurrCdrom = NewCdrom;
|
|
|
|
TimeAdjustInitialize( g_CurrCdrom );
|
|
|
|
if ( (oldState & CD_PAUSED) || (oldState2 & CD_PAUSED) ) {
|
|
|
|
SendMessage( g_hwndApp, WM_COMMAND, IDM_PLAYBAR_PLAY, 0L );
|
|
SendMessage( g_hwndApp, WM_COMMAND, IDM_PLAYBAR_PAUSE, 0L );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*****************************Private*Routine******************************\
|
|
* FindTrackNodeFromTocIndex
|
|
*
|
|
* This routine returns the node in the listed pointed to by listhead which
|
|
* has the TocIndex equal to tocindex. NULL is returned if it is not
|
|
* found. Returning NULL can easily bomb out the program -- but we should
|
|
* never be calling this routine with an invalid tocindex, and thus really
|
|
* never SHOULD return NULL.
|
|
*
|
|
*
|
|
* History:
|
|
* 18-11-93 - StephenE - Created
|
|
*
|
|
\**************************************************************************/
|
|
PTRACK_INF
|
|
FindTrackNodeFromTocIndex(
|
|
int tocindex,
|
|
PTRACK_INF listhead
|
|
)
|
|
{
|
|
PTRACK_INF t;
|
|
|
|
for( t = listhead; ((t!=NULL) && (t->TocIndex!=tocindex)); t=t->next );
|
|
return t;
|
|
}
|
|
|
|
|
|
/*****************************Private*Routine******************************\
|
|
* FindFirstTrack
|
|
*
|
|
* This routine computes the first "playable" track on a disc by
|
|
* scanning the the play order of the tracks
|
|
*
|
|
*
|
|
* History:
|
|
* 18-11-93 - StephenE - Created
|
|
*
|
|
\**************************************************************************/
|
|
PTRACK_PLAY
|
|
FindFirstTrack(
|
|
int cdrom
|
|
)
|
|
{
|
|
if ( (g_Devices[cdrom]->State & CD_NO_CD) ||
|
|
(g_Devices[cdrom]->State & CD_DATA_CD_LOADED) ) {
|
|
|
|
return NULL;
|
|
}
|
|
|
|
return PLAYLIST(cdrom);
|
|
}
|
|
|
|
|
|
|
|
/*****************************Private*Routine******************************\
|
|
* FindLastTrack
|
|
*
|
|
* This routine computes the last "playable" track on a disc by
|
|
* scanning the the play order of the tracks
|
|
*
|
|
*
|
|
* History:
|
|
* 18-11-93 - StephenE - Created
|
|
*
|
|
\**************************************************************************/
|
|
PTRACK_PLAY
|
|
FindLastTrack(
|
|
IN INT cdrom
|
|
)
|
|
{
|
|
PTRACK_PLAY tr;
|
|
|
|
if ( PLAYLIST(cdrom) == NULL ) {
|
|
return NULL;
|
|
}
|
|
|
|
for( tr = PLAYLIST(cdrom); tr->nextplay != NULL; tr = tr->nextplay );
|
|
|
|
return tr;
|
|
}
|
|
|
|
|
|
/*****************************Private*Routine******************************\
|
|
* AllTracksPlayed
|
|
*
|
|
* This routine searches the play lists for all cdrom drives and
|
|
* returns a flag as to whether all tracks on all cdrom drives have
|
|
* been played.
|
|
*
|
|
* History:
|
|
* 18-11-93 - StephenE - Created
|
|
*
|
|
\**************************************************************************/
|
|
BOOL
|
|
AllTracksPlayed(
|
|
void
|
|
)
|
|
{
|
|
|
|
INT i;
|
|
BOOL result = TRUE;
|
|
|
|
for( i = 0; i < g_NumCdDevices; i++ ) {
|
|
|
|
result &= (CURRTRACK(i) == NULL);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
/*****************************Private*Routine******************************\
|
|
* FindNextTrack
|
|
*
|
|
* This routine computes the next "playable" track. This is a
|
|
* one way door...i.e., the structures are manipulated. It uses
|
|
* the following algorithms:
|
|
*
|
|
* Single Disc Play:
|
|
*
|
|
* * if next track is not NULL, return next track
|
|
* * If next track is NULL, and wrap==TRUE, return
|
|
* first track
|
|
* * return NULL
|
|
*
|
|
* Multi-Disc Play:
|
|
*
|
|
* * if we're in random play, select a random drive to play from.
|
|
* * if next track on current cdrom != NULL, return next track
|
|
* * if it is NULL:
|
|
*
|
|
* * check next cdrom device, if current track is not NULL
|
|
* return CURRTRACK for that device and set gCurrCdrom to
|
|
* that device
|
|
* * if NULL, go to next drive
|
|
* * last drive, check wrap
|
|
*
|
|
* History:
|
|
* 18-11-93 - StephenE - Created
|
|
*
|
|
\**************************************************************************/
|
|
PTRACK_PLAY
|
|
FindNextTrack(
|
|
BOOL wrap
|
|
)
|
|
{
|
|
int i;
|
|
|
|
/*
|
|
** First, bump current track pointer
|
|
*/
|
|
|
|
if ( CURRTRACK(g_CurrCdrom) != NULL ) {
|
|
|
|
CURRTRACK(g_CurrCdrom) = CURRTRACK(g_CurrCdrom)->nextplay;
|
|
}
|
|
else {
|
|
|
|
if ( g_fSingleDisk ) {
|
|
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Do we need to switch drives?
|
|
*/
|
|
|
|
if ( (!g_fSelectedOrder) && (!g_fSingleDisk) ) {
|
|
|
|
/*
|
|
** Need to random to new cdrom
|
|
*/
|
|
|
|
g_CurrCdrom = rand() % g_NumCdDevices;
|
|
|
|
}
|
|
|
|
/*
|
|
** Is chosen track playable?
|
|
*/
|
|
|
|
if ( CURRTRACK(g_CurrCdrom) != NULL ) {
|
|
|
|
/*
|
|
** Yep, so this is the easy case
|
|
*/
|
|
|
|
return CURRTRACK(g_CurrCdrom);
|
|
}
|
|
|
|
/*
|
|
** Ok, CURRENT track on this device is not defined,
|
|
** so are we in multi-disc mode?
|
|
*/
|
|
if ( !g_fSingleDisk ) {
|
|
|
|
/*
|
|
** have all tracks played?
|
|
*/
|
|
|
|
if ( AllTracksPlayed() ) {
|
|
|
|
/*
|
|
** if wrap, reset all drives to front of their playlist
|
|
*/
|
|
|
|
if ( wrap ) {
|
|
|
|
/*
|
|
** If we are in random play mode we need to re-shuffle the
|
|
** track list so that people don't get the same tracks repeated
|
|
** again.
|
|
*/
|
|
if (!g_fSelectedOrder) {
|
|
RestorePlayListsFromShuffleLists();
|
|
ComputeAndUseShufflePlayLists();
|
|
}
|
|
|
|
for ( i = 0; i < g_NumCdDevices; i++ ) {
|
|
|
|
CURRTRACK(i) = FindFirstTrack(i);
|
|
}
|
|
}
|
|
else {
|
|
|
|
/*
|
|
** All tracks on all drives have played, and we are NOT
|
|
** in continuous mode, so we are done playing. Signify
|
|
** this by returning NULL (no playable tracks left).
|
|
*/
|
|
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
** We're in mulit-disc play mode, and all the play lists should
|
|
** be reset now. Cycle through cdrom drives looking for a playable
|
|
** track.
|
|
*/
|
|
|
|
i = g_CurrCdrom;
|
|
do {
|
|
|
|
g_CurrCdrom++;
|
|
if ( g_CurrCdrom >= g_NumCdDevices ) {
|
|
|
|
/*
|
|
** We hit the end of the list of devices, if we're
|
|
** in continuous play mode, we need to wrap to the
|
|
** first cdrom drive. Otherwise, we are done playing
|
|
** as there are no tracks left to play.
|
|
*/
|
|
|
|
if ( wrap || (!g_fSelectedOrder) ) {
|
|
|
|
g_CurrCdrom = 0;
|
|
|
|
}
|
|
else {
|
|
|
|
g_CurrCdrom--;
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
} while( (CURRTRACK(g_CurrCdrom) == NULL) && (i != g_CurrCdrom) );
|
|
|
|
/*
|
|
** At this point we either have a playable track, or we
|
|
** are back where we started from and we're going to return
|
|
** NULL because there are no playable tracks left.
|
|
*/
|
|
|
|
return CURRTRACK(g_CurrCdrom);
|
|
|
|
}
|
|
else {
|
|
|
|
/*
|
|
** We're in single disc mode, and current track is NULL,
|
|
** which means we hit the end of the playlist. So, check
|
|
** to see if we should wrap back to the first track, or
|
|
** return NULL to show that we're done playing.
|
|
*/
|
|
|
|
if (wrap) {
|
|
|
|
/*
|
|
** If we are in random play mode we need to re-shuffle the
|
|
** track list so that people don't get the same tracks repeated
|
|
** again.
|
|
*/
|
|
if (!g_fSelectedOrder) {
|
|
RestorePlayListsFromShuffleLists();
|
|
ComputeAndUseShufflePlayLists();
|
|
}
|
|
|
|
/*
|
|
** wrap to start of the play list
|
|
*/
|
|
|
|
CURRTRACK(g_CurrCdrom) = FindFirstTrack(g_CurrCdrom);
|
|
}
|
|
|
|
return CURRTRACK(g_CurrCdrom);
|
|
}
|
|
}
|
|
|
|
|
|
/*****************************Private*Routine******************************\
|
|
* FindPrevTrack
|
|
*
|
|
* This routine computes the previous "playable" track on a disc by
|
|
* scanning the play order of the tracks from the current
|
|
* track to the start of the play list. If we are at the start
|
|
* of the play list, then move to the end of the list if we
|
|
* are in "wrap" (i.e., continuous) play mode, otherwise return
|
|
* the current track.
|
|
*
|
|
*
|
|
* History:
|
|
* 18-11-93 - StephenE - Created
|
|
*
|
|
\**************************************************************************/
|
|
PTRACK_PLAY
|
|
FindPrevTrack(
|
|
int cdrom,
|
|
BOOL wrap
|
|
)
|
|
{
|
|
/*
|
|
** Is current track valid?
|
|
*/
|
|
|
|
if ( CURRTRACK(cdrom) == NULL ) {
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
** If we're in multi disc play && random, the previous track
|
|
** is undefined since we could be jumping around on
|
|
** multiple discs.
|
|
**
|
|
** FIXFIX -- do we want to allow users to back up in the random
|
|
** list of a particular drive?
|
|
*/
|
|
|
|
if ((!g_fSingleDisk) && (!g_fSelectedOrder)) {
|
|
|
|
return CURRTRACK(cdrom);
|
|
}
|
|
|
|
|
|
/*
|
|
** Did we hit the start of the play list?
|
|
*/
|
|
|
|
if ( CURRTRACK(cdrom)->prevplay == NULL ) {
|
|
|
|
/*
|
|
** We hit the start of the list, check to see if we should
|
|
** wrap to end of list or not...
|
|
*/
|
|
|
|
if ( wrap && g_fSingleDisk ) {
|
|
|
|
return FindLastTrack(cdrom);
|
|
}
|
|
else {
|
|
return CURRTRACK(cdrom);
|
|
}
|
|
}
|
|
|
|
return CURRTRACK(cdrom)->prevplay;
|
|
}
|
|
|
|
|
|
/*****************************Private*Routine******************************\
|
|
* FindContiguousEnd
|
|
*
|
|
* This routine returns the node of the track within PlayList which makes
|
|
* the largest contiguous block of tracks starting w/the track pointed
|
|
* to by "tr." It is used to play multiple tracks at as one track
|
|
* when they are programmed to be played in sequence.
|
|
*
|
|
*
|
|
* History:
|
|
* 18-11-93 - StephenE - Created
|
|
*
|
|
\**************************************************************************/
|
|
int
|
|
FindContiguousEnd(
|
|
int cdrom,
|
|
PTRACK_PLAY tr
|
|
)
|
|
{
|
|
int i;
|
|
PTRACK_PLAY trend;
|
|
|
|
/*
|
|
** If we're in muti-disc random play, we only play
|
|
** one track at a time, so just return next track.
|
|
*/
|
|
|
|
if ( (!g_fSelectedOrder) && (!g_fSingleDisk) ) {
|
|
|
|
return tr->TocIndex + 1;
|
|
}
|
|
|
|
/*
|
|
** go forward in the play list looking for contiguous blocks
|
|
** of tracks to play together. We need to check the TocIndex
|
|
** of each track to see if they are in a "run" [ like 2-5, etc. ]
|
|
*/
|
|
|
|
i= tr->TocIndex + 1;
|
|
trend = tr;
|
|
|
|
while ( (trend->nextplay != NULL) && (trend->nextplay->TocIndex == i) ) {
|
|
|
|
trend = trend->nextplay;
|
|
i++;
|
|
}
|
|
|
|
return trend->TocIndex + 1;
|
|
}
|
|
|
|
|
|
/*****************************Private*Routine******************************\
|
|
* FlipBetweenShuffleAndOrder
|
|
*
|
|
* This routine handles going from ordered play to shuffle play and vica\versa.
|
|
*
|
|
* History:
|
|
* 18-11-93 - StephenE - Created
|
|
*
|
|
\**************************************************************************/
|
|
void
|
|
FlipBetweenShuffleAndOrder(
|
|
void
|
|
)
|
|
{
|
|
if ( (!g_fSelectedOrder) ) {
|
|
|
|
/*
|
|
** Transitioning from Random to Ordered Play
|
|
*/
|
|
|
|
RestorePlayListsFromShuffleLists();
|
|
}
|
|
else {
|
|
/*
|
|
** Transitioning from Ordered to Random Play
|
|
*/
|
|
|
|
ComputeAndUseShufflePlayLists();
|
|
}
|
|
|
|
/*
|
|
** If we were playing, we need to restart the play to make sure
|
|
** we don't play past where we should.
|
|
*/
|
|
|
|
if ( g_State & CD_PLAYING ) {
|
|
|
|
SeekToCurrSecond( g_CurrCdrom );
|
|
}
|
|
|
|
ResetTrackComboBox( g_CurrCdrom);
|
|
}
|
|
|
|
|
|
/*****************************Private*Routine******************************\
|
|
* ComputeAndUseShufflePlayLists
|
|
*
|
|
* This routine computes shuffled play lists for each drive, and sets
|
|
* the current PLAYLIST for erach drive to the newly computed shuffled
|
|
* PLAYLIST. The old PLAYLIST for each drive is saved in SAVELIST.
|
|
*
|
|
*
|
|
* History:
|
|
* 18-11-93 - StephenE - Created
|
|
*
|
|
\**************************************************************************/
|
|
void
|
|
ComputeAndUseShufflePlayLists(
|
|
void
|
|
)
|
|
{
|
|
int i;
|
|
|
|
for ( i = 0; i < g_NumCdDevices; i++ ) {
|
|
|
|
ComputeSingleShufflePlayList( i );
|
|
}
|
|
}
|
|
|
|
|
|
/*****************************Private*Routine******************************\
|
|
* ComputeSingleShufflePlayList
|
|
*
|
|
* This routine computes shuffled play lists for drive i, and sets
|
|
* the current PLAYLIST for it the newly computed shuffled
|
|
* PLAYLIST. The old PLAYLIST is saved in SAVELIST.
|
|
*
|
|
* History:
|
|
* 18-11-93 - StephenE - Created
|
|
*
|
|
\**************************************************************************/
|
|
void
|
|
ComputeSingleShufflePlayList(
|
|
int i
|
|
)
|
|
{
|
|
int j, index, numnodes;
|
|
PTRACK_PLAY temp, temp1, duplist, prev, OldPlayList;
|
|
|
|
/*
|
|
** First, delete the existing playlist
|
|
*/
|
|
OldPlayList = PLAYLIST(i);
|
|
PLAYLIST(i) = NULL;
|
|
|
|
/*
|
|
** Now, go through each drive and create a shuffled play list
|
|
** First step is to duplicate the old play list, then we will
|
|
** randomly pick off nodes and put them on the shuffle play list.
|
|
*/
|
|
|
|
duplist = prev = NULL;
|
|
numnodes = 0;
|
|
for( temp = SAVELIST(i); temp != NULL; temp = temp->nextplay ) {
|
|
|
|
temp1 = AllocMemory( sizeof(TRACK_PLAY) );
|
|
*temp1 = *temp;
|
|
temp1->nextplay = NULL;
|
|
if (duplist) {
|
|
|
|
temp1->prevplay = prev;
|
|
prev->nextplay = temp1;
|
|
prev = temp1;
|
|
}
|
|
else {
|
|
|
|
duplist = temp1;
|
|
temp1->prevplay = NULL;
|
|
prev = temp1;
|
|
}
|
|
|
|
numnodes++;
|
|
}
|
|
|
|
/*
|
|
** Now, randomly pick off nodes
|
|
*/
|
|
|
|
prev = NULL;
|
|
for( j = 0; j < numnodes; j++ ) {
|
|
|
|
index = rand() % (numnodes - j + 1);
|
|
temp = duplist;
|
|
while( --index>0 ) {
|
|
temp = temp->nextplay;
|
|
}
|
|
|
|
/*
|
|
** Got the node to transfer to playlist (temp),
|
|
** so we need to detach it from duplist so we
|
|
** can tack it onto the end of the playlist.
|
|
*/
|
|
|
|
if ( temp != NULL ) {
|
|
|
|
/*
|
|
** Detach temp from playlist.
|
|
*/
|
|
|
|
if ( temp == duplist ) {
|
|
|
|
duplist = temp->nextplay;
|
|
}
|
|
|
|
if ( temp->nextplay ) {
|
|
|
|
temp->nextplay->prevplay = temp->prevplay;
|
|
}
|
|
|
|
if ( temp->prevplay ) {
|
|
|
|
temp->prevplay->nextplay = temp->nextplay;
|
|
}
|
|
|
|
/*
|
|
** Now, tack it onto the end of the PLAYLIST
|
|
*/
|
|
|
|
if ( PLAYLIST(i) ) {
|
|
|
|
prev->nextplay = temp;
|
|
temp->prevplay = prev;
|
|
temp->nextplay = NULL;
|
|
prev = temp;
|
|
}
|
|
else {
|
|
|
|
PLAYLIST(i) = temp;
|
|
temp->prevplay = NULL;
|
|
prev = temp;
|
|
temp->nextplay = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
** we need to reset the CURRTRACK pointer so
|
|
** that it points to a node in PLAYLIST instead of SAVELIST
|
|
*/
|
|
|
|
if ( (g_Devices[i]->State & CD_PLAYING) && (CURRTRACK(i) != NULL) ) {
|
|
|
|
index = CURRTRACK(i)->TocIndex;
|
|
for( temp = PLAYLIST(i); temp->TocIndex!=index; temp=temp->nextplay );
|
|
CURRTRACK(i) = temp;
|
|
}
|
|
else {
|
|
|
|
CURRTRACK(i) = PLAYLIST(i);
|
|
|
|
if ( PLAYLIST(i) != NULL ) {
|
|
|
|
CDTIME(i).TrackTotalMin = PLAYLIST(i)->min;
|
|
CDTIME(i).TrackTotalSec = PLAYLIST(i)->sec;
|
|
CDTIME(i).TrackRemMin = PLAYLIST(i)->min;
|
|
CDTIME(i).TrackRemSec = PLAYLIST(i)->sec;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
/*
|
|
** if this is the current drive, we need to redo the tracks in
|
|
** the track list combobox.
|
|
*/
|
|
|
|
if ( i == g_CurrCdrom ) {
|
|
|
|
ResetTrackComboBox( i );
|
|
|
|
}
|
|
|
|
/*
|
|
** Finally, free up the memory from the old playlist.
|
|
*/
|
|
temp = OldPlayList;
|
|
while ( temp != NULL ) {
|
|
|
|
temp1 = temp->nextplay;
|
|
LocalFree( (HLOCAL)temp );
|
|
temp = temp1;
|
|
}
|
|
}
|
|
|
|
|
|
/*****************************Private*Routine******************************\
|
|
* RestorePlayListsFromShuffleLists
|
|
*
|
|
* This routine restores the PLAYLIST for each drive to it's "pre-shuffled"
|
|
* state. This should be stored in SAVELIST. Once the restoration is done,
|
|
* un-needed node are released.
|
|
*
|
|
* History:
|
|
* 18-11-93 - StephenE - Created
|
|
*
|
|
\**************************************************************************/
|
|
void
|
|
RestorePlayListsFromShuffleLists(
|
|
void
|
|
)
|
|
{
|
|
int i,index;
|
|
PTRACK_PLAY temp;
|
|
|
|
for ( i = 0; i < g_NumCdDevices; i++ ) {
|
|
|
|
if ( SAVELIST(i) ) {
|
|
|
|
if ( CURRTRACK(i) != NULL ) {
|
|
|
|
index = CURRTRACK(i)->TocIndex;
|
|
}
|
|
else {
|
|
|
|
index = -1;
|
|
}
|
|
|
|
ErasePlayList(i);
|
|
PLAYLIST(i) = CopyPlayList( SAVELIST(i) );
|
|
|
|
/*
|
|
** Reset CURRTRACK pointer
|
|
*/
|
|
|
|
if ( (g_Devices[i]->State & CD_PLAYING) && (index != -1) ) {
|
|
|
|
for( temp = PLAYLIST(i);
|
|
temp->TocIndex != index; temp=temp->nextplay );
|
|
|
|
CURRTRACK(i) = temp;
|
|
}
|
|
else {
|
|
|
|
CURRTRACK(i) = PLAYLIST(i);
|
|
|
|
if ( PLAYLIST(i) != NULL ) {
|
|
CDTIME(i).TrackRemMin = PLAYLIST(i)->min;
|
|
CDTIME(i).TrackRemSec = PLAYLIST(i)->sec;
|
|
CDTIME(i).TrackTotalMin = PLAYLIST(i)->min;
|
|
CDTIME(i).TrackTotalSec = PLAYLIST(i)->sec;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( i == g_CurrCdrom ) {
|
|
|
|
ResetTrackComboBox( i );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*****************************Private*Routine******************************\
|
|
* FigureTrackTime
|
|
*
|
|
* This routine computes the length of a given track, in terms
|
|
* of minutes and seconds.
|
|
*
|
|
* cdrom - supplies an index into the global structure gDevices
|
|
*
|
|
* index - supplies an index to the track which should have its
|
|
* length computed. This is an index into the
|
|
* gDevices[cdrom]->CdInfo.Tracks[...] structure
|
|
*
|
|
* min - supplies a pointer to an INT which will hold the minute
|
|
* portion of the track length.
|
|
*
|
|
* sec - supplies a pointer to an INT which will hold the seconds
|
|
* portion of the track length.
|
|
*
|
|
* History:
|
|
* 18-11-93 - StephenE - Created
|
|
*
|
|
\**************************************************************************/
|
|
void
|
|
FigureTrackTime(
|
|
int cdrom,
|
|
int index,
|
|
int * min,
|
|
int * sec
|
|
)
|
|
{
|
|
|
|
DWORD start, end, diff;
|
|
|
|
start = ((TRACK_M(cdrom,index) * FRAMES_PER_MINUTE) +
|
|
(TRACK_S(cdrom,index) * FRAMES_PER_SECOND) +
|
|
TRACK_F(cdrom,index));
|
|
|
|
end = ((TRACK_M(cdrom,index+1) * FRAMES_PER_MINUTE) +
|
|
(TRACK_S(cdrom,index+1) * FRAMES_PER_SECOND) +
|
|
TRACK_F(cdrom,index+1));
|
|
|
|
diff = end - start;
|
|
|
|
(*min) = (diff / FRAMES_PER_MINUTE);
|
|
(*sec) = (diff % FRAMES_PER_MINUTE) / FRAMES_PER_SECOND;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*****************************Private*Routine******************************\
|
|
* TimeAdjustInitialize
|
|
*
|
|
* Initializes the time, track, and title fields of a given
|
|
* disc.
|
|
*
|
|
* History:
|
|
* 18-11-93 - StephenE - Created
|
|
*
|
|
\**************************************************************************/
|
|
void
|
|
TimeAdjustInitialize(
|
|
int cdrom
|
|
)
|
|
{
|
|
int m, s, mtemp, stemp, ts, tm;
|
|
PTRACK_PLAY tr;
|
|
|
|
|
|
/*
|
|
** Is there even a cd loaded?
|
|
*/
|
|
|
|
if (g_Devices[cdrom]->State &
|
|
(CD_BEING_SCANNED | CD_IN_USE | CD_NO_CD | CD_DATA_CD_LOADED)) {
|
|
|
|
/*
|
|
** Fake some information
|
|
*/
|
|
|
|
g_Devices[cdrom]->CdInfo.NumTracks = 0;
|
|
g_Devices[cdrom]->toc.FirstTrack = 0;
|
|
g_Devices[cdrom]->CdInfo.Id = 0;
|
|
|
|
if (g_Devices[cdrom]->State & CD_IN_USE) {
|
|
_tcscpy( (LPTSTR)TITLE(cdrom), IdStr(STR_WAITING) );
|
|
_tcscpy( (LPTSTR)ARTIST(cdrom), IdStr(STR_DISC_INUSE) );
|
|
}
|
|
else if (g_Devices[cdrom]->State & CD_BEING_SCANNED) {
|
|
_tcscpy( (LPTSTR)TITLE(cdrom), IdStr(STR_WAITING) );
|
|
_tcscpy( (LPTSTR)ARTIST(cdrom), IdStr(STR_BEING_SCANNED) );
|
|
}
|
|
else {
|
|
_tcscpy( (LPTSTR)TITLE(cdrom), IdStr(STR_INSERT_DISC) );
|
|
_tcscpy( (LPTSTR)ARTIST(cdrom), IdStr(STR_DATA_NO_DISC) );
|
|
}
|
|
|
|
/*
|
|
** Kill off play list
|
|
*/
|
|
|
|
ErasePlayList( cdrom );
|
|
EraseSaveList( cdrom );
|
|
EraseTrackList( cdrom );
|
|
|
|
tr = NULL;
|
|
}
|
|
else {
|
|
|
|
/*
|
|
** Find track to use as first track
|
|
*/
|
|
|
|
tr = FindFirstTrack( cdrom );
|
|
}
|
|
|
|
/*
|
|
** Set current position information
|
|
*/
|
|
|
|
CURRTRACK(cdrom) = tr;
|
|
CDTIME(cdrom).TrackCurMin = 0;
|
|
CDTIME(cdrom).TrackCurSec = 0;
|
|
|
|
/*
|
|
** Compute PLAY length
|
|
*/
|
|
|
|
mtemp = stemp = m = s = ts = tm =0;
|
|
|
|
for( tr = PLAYLIST(cdrom); tr != NULL; tr = tr->nextplay ) {
|
|
|
|
FigureTrackTime( cdrom, tr->TocIndex, &mtemp, &stemp );
|
|
|
|
m+=mtemp;
|
|
s+=stemp;
|
|
|
|
tr->min = mtemp;
|
|
tr->sec = stemp;
|
|
}
|
|
|
|
/*
|
|
** to be safe, recalculate the SAVE list each time as well.
|
|
*/
|
|
for( tr = SAVELIST(cdrom); tr != NULL; tr = tr->nextplay ) {
|
|
|
|
FigureTrackTime( cdrom, tr->TocIndex, &mtemp, &stemp );
|
|
|
|
tr->min = mtemp;
|
|
tr->sec = stemp;
|
|
}
|
|
|
|
|
|
m += (s / 60);
|
|
s = (s % 60);
|
|
|
|
CDTIME(cdrom).TotalMin = m;
|
|
CDTIME(cdrom).TotalSec = s;
|
|
CDTIME(cdrom).RemMin = m;
|
|
CDTIME(cdrom).RemSec = s;
|
|
|
|
/*
|
|
** Fill in track length and information
|
|
*/
|
|
|
|
if ( CURRTRACK(cdrom) != NULL ) {
|
|
|
|
CDTIME(cdrom).TrackTotalMin = CDTIME(cdrom).TrackRemMin =
|
|
CURRTRACK(cdrom)->min;
|
|
|
|
CDTIME(cdrom).TrackTotalSec = CDTIME(cdrom).TrackRemSec =
|
|
CURRTRACK(cdrom)->sec;
|
|
}
|
|
else {
|
|
|
|
CDTIME(cdrom).TrackTotalMin = CDTIME(cdrom).TrackRemMin = 0;
|
|
CDTIME(cdrom).TrackTotalSec = CDTIME(cdrom).TrackRemSec = 0;
|
|
}
|
|
|
|
/*
|
|
** Fill in track list combo box
|
|
*/
|
|
|
|
if ( cdrom == g_CurrCdrom ) {
|
|
|
|
ResetTrackComboBox( cdrom );
|
|
|
|
/*
|
|
** Update display if this is the disc currently
|
|
** being displayed.
|
|
*/
|
|
|
|
UpdateDisplay( DISPLAY_UPD_LED |
|
|
DISPLAY_UPD_DISC_TIME |
|
|
DISPLAY_UPD_TRACK_TIME |
|
|
DISPLAY_UPD_TITLE_NAME |
|
|
DISPLAY_UPD_TRACK_NAME );
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*****************************Private*Routine******************************\
|
|
* TimeAdjustIncSecond
|
|
*
|
|
* Adds one second onto current position ("time") of disc
|
|
*
|
|
* History:
|
|
* 18-11-93 - StephenE - Created
|
|
*
|
|
\**************************************************************************/
|
|
void
|
|
TimeAdjustIncSecond(
|
|
int cdrom
|
|
)
|
|
{
|
|
|
|
PTRACK_PLAY tr;
|
|
|
|
/*
|
|
** If there is no current track just return
|
|
*/
|
|
if ( CURRTRACK(g_CurrCdrom) == NULL ) {
|
|
return;
|
|
}
|
|
|
|
/*
|
|
** Update current track time
|
|
*/
|
|
|
|
CDTIME(cdrom).TrackCurSec++;
|
|
if ( CDTIME(cdrom).TrackCurSec > 59 ) {
|
|
|
|
CDTIME(cdrom).TrackCurMin++;
|
|
CDTIME(cdrom).TrackCurSec = 0;
|
|
}
|
|
|
|
/*
|
|
** Now, check to see if we skipped any track boundaries
|
|
*/
|
|
|
|
if (
|
|
((CDTIME(cdrom).TrackCurMin >= CDTIME(cdrom).TrackTotalMin) &&
|
|
(CDTIME(cdrom).TrackCurSec >= CDTIME(cdrom).TrackTotalSec))
|
|
|
|
||
|
|
|
|
((g_fIntroPlay) &&
|
|
((CDTIME(cdrom).TrackCurMin > 0) ||
|
|
(CDTIME(cdrom).TrackCurSec > g_IntroPlayLength)) )
|
|
|
|
) {
|
|
|
|
/*
|
|
** We did, so skip to next track
|
|
*/
|
|
|
|
/*
|
|
** FIXFIX for new FindNextTrack
|
|
*/
|
|
|
|
tr = FindNextTrack( g_fContinuous );
|
|
|
|
if ( tr == NULL ) {
|
|
|
|
/*
|
|
** Hit end of playlist, so stay at end of current
|
|
** track.
|
|
*/
|
|
|
|
if (!g_fIntroPlay) {
|
|
|
|
CDTIME(cdrom).TrackCurMin = CDTIME(cdrom).TrackTotalMin;
|
|
CDTIME(cdrom).TrackCurSec = CDTIME(cdrom).TrackTotalSec;
|
|
}
|
|
else {
|
|
|
|
CDTIME(cdrom).TrackCurMin = 0;
|
|
CDTIME(cdrom).TrackCurSec = g_IntroPlayLength;
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if ( g_CurrCdrom != g_LastCdrom) {
|
|
|
|
SwitchToCdrom(g_CurrCdrom, FALSE );
|
|
}
|
|
|
|
TimeAdjustSkipToTrack( cdrom, tr );
|
|
}
|
|
else {
|
|
|
|
/*
|
|
** Update current track remaining time
|
|
*/
|
|
|
|
CDTIME(cdrom).TrackRemSec--;
|
|
if ( CDTIME(cdrom).TrackRemSec < 0 ) {
|
|
|
|
CDTIME(cdrom).TrackRemMin--;
|
|
CDTIME(cdrom).TrackRemSec = 59;
|
|
}
|
|
|
|
/*
|
|
** Update total remaining time
|
|
*/
|
|
|
|
CDTIME(cdrom).RemSec--;
|
|
if ( CDTIME(cdrom).RemSec < 0 ) {
|
|
|
|
CDTIME(cdrom).RemMin--;
|
|
CDTIME(cdrom).RemSec = 59;
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Update Display
|
|
*/
|
|
|
|
UpdateDisplay( DISPLAY_UPD_LED );
|
|
}
|
|
|
|
|
|
/*****************************Private*Routine******************************\
|
|
* TimeAdjustDecSecond
|
|
*
|
|
* Subtracts one second from current position ("time") of disc
|
|
*
|
|
* History:
|
|
* 18-11-93 - StephenE - Created
|
|
*
|
|
\**************************************************************************/
|
|
void
|
|
TimeAdjustDecSecond(
|
|
int cdrom
|
|
)
|
|
{
|
|
|
|
int min,sec;
|
|
PTRACK_PLAY prev,tr;
|
|
|
|
/*
|
|
** If there is no current track, just return
|
|
*/
|
|
if ( CURRTRACK(g_CurrCdrom) == NULL ) {
|
|
return;
|
|
}
|
|
|
|
/*
|
|
** Update current track
|
|
*/
|
|
|
|
CDTIME(cdrom).TrackCurSec--;
|
|
if ( CDTIME(cdrom).TrackCurSec < 0 ) {
|
|
|
|
CDTIME(cdrom).TrackCurMin--;
|
|
CDTIME(cdrom).TrackCurSec = 59;
|
|
}
|
|
|
|
/*
|
|
** Update current track remaining
|
|
*/
|
|
|
|
CDTIME(cdrom).TrackRemSec++;
|
|
if ( CDTIME(cdrom).TrackRemSec > 59 ) {
|
|
|
|
CDTIME(cdrom).TrackRemMin++;
|
|
CDTIME(cdrom).TrackRemSec = 0;
|
|
}
|
|
|
|
/*
|
|
** Update total remaining time
|
|
*/
|
|
|
|
CDTIME(cdrom).RemSec++;
|
|
if ( CDTIME(cdrom).RemSec > 59 ) {
|
|
|
|
CDTIME(cdrom).RemMin++;
|
|
CDTIME(cdrom).RemSec = 0;
|
|
}
|
|
|
|
/*
|
|
** Now, check to see if we skipped any boundaries we shouldn't have!
|
|
*/
|
|
|
|
if ( CDTIME(cdrom).TrackCurMin < 0 ) {
|
|
|
|
/*
|
|
** We went "off" the front end of the track,
|
|
** so we need to see what to do now. Options
|
|
** are:
|
|
**
|
|
** (1) Go to end of track before us.
|
|
** (2) If intro play, go to 0:10 of
|
|
** track before us.
|
|
** (3) If not in continuous play, and
|
|
** this is the first track, then
|
|
** just sit at 0:00
|
|
*/
|
|
|
|
prev = FindPrevTrack( cdrom, g_fContinuous );
|
|
|
|
if ( prev == CURRTRACK(cdrom) ) {
|
|
|
|
/*
|
|
** We are on the first track, and not in
|
|
** continuous mode, so just go to 0:00
|
|
*/
|
|
|
|
CDTIME(cdrom).TrackCurSec = 0;
|
|
CDTIME(cdrom).TrackCurMin = 0;
|
|
CDTIME(cdrom).TrackRemMin = CDTIME(cdrom).TrackTotalMin;
|
|
CDTIME(cdrom).TrackRemSec = CDTIME(cdrom).TrackTotalSec;
|
|
min = sec = 0;
|
|
|
|
for( tr = PLAYLIST( cdrom ); tr != NULL; tr = tr->nextplay ) {
|
|
|
|
min += tr->min;
|
|
sec += tr->sec;
|
|
}
|
|
|
|
min += (sec / 60);
|
|
sec = (sec % 60);
|
|
|
|
CDTIME(cdrom).RemMin = min;
|
|
CDTIME(cdrom).RemSec = sec;
|
|
|
|
UpdateDisplay( DISPLAY_UPD_LED );
|
|
|
|
}
|
|
else {
|
|
|
|
/*
|
|
** Valid previous track
|
|
*/
|
|
|
|
if ( !g_fIntroPlay ) {
|
|
|
|
/*
|
|
** We need to place the current play position
|
|
** at the end of the previous track.
|
|
*/
|
|
|
|
CDTIME(cdrom).TrackCurMin = CDTIME(cdrom).TrackTotalMin = prev->min;
|
|
CDTIME(cdrom).TrackCurSec = CDTIME(cdrom).TrackTotalSec = prev->sec;
|
|
CDTIME(cdrom).TrackRemMin = CDTIME(cdrom).TrackRemSec = 0;
|
|
|
|
min = sec = 0;
|
|
for( tr = prev->nextplay; tr != NULL; tr = tr->nextplay ) {
|
|
|
|
min += tr->min;
|
|
sec += tr->sec;
|
|
}
|
|
|
|
min += (sec / 60);
|
|
sec = (sec % 60);
|
|
|
|
CDTIME(cdrom).RemMin = min;
|
|
CDTIME(cdrom).RemSec = sec;
|
|
}
|
|
else {
|
|
|
|
/*
|
|
** Intro play -- instead of end of track,
|
|
** jump to 00:10...
|
|
*/
|
|
|
|
CDTIME(cdrom).TrackCurMin = 0;
|
|
CDTIME(cdrom).TrackCurSec =
|
|
min( g_IntroPlayLength, prev->sec );
|
|
|
|
CDTIME(cdrom).TrackTotalMin = prev->min;
|
|
CDTIME(cdrom).TrackTotalSec = prev->sec;
|
|
|
|
CDTIME(cdrom).TrackRemMin = CDTIME(cdrom).TrackTotalMin;
|
|
CDTIME(cdrom).TrackRemSec = CDTIME(cdrom).TrackTotalSec -
|
|
min( g_IntroPlayLength, prev->sec );
|
|
|
|
if ( CDTIME(cdrom).TrackRemSec < 0 ) {
|
|
|
|
CDTIME(cdrom).TrackRemSec += 60;
|
|
CDTIME(cdrom).TrackRemMin--;
|
|
}
|
|
|
|
min = sec = 0;
|
|
for( tr = prev; tr != NULL; tr = tr->nextplay ) {
|
|
|
|
min += tr->min;
|
|
sec += tr->sec;
|
|
}
|
|
|
|
sec -= min( g_IntroPlayLength, prev->sec );
|
|
if ( sec < 0 ) {
|
|
sec+=60;
|
|
min--;
|
|
}
|
|
|
|
min += (sec / 60);
|
|
sec = (sec % 60);
|
|
|
|
CDTIME(cdrom).RemMin = min;
|
|
CDTIME(cdrom).RemSec = sec;
|
|
}
|
|
|
|
CURRTRACK(cdrom) = prev;
|
|
|
|
UpdateDisplay( DISPLAY_UPD_LED |
|
|
DISPLAY_UPD_TRACK_NAME |
|
|
DISPLAY_UPD_TRACK_TIME );
|
|
|
|
}
|
|
}
|
|
else {
|
|
|
|
UpdateDisplay( DISPLAY_UPD_LED );
|
|
}
|
|
}
|
|
|
|
|
|
/*****************************Private*Routine******************************\
|
|
* InitializeNewTrackTime
|
|
*
|
|
* Updates track/time information for gDevices array.
|
|
*
|
|
* History:
|
|
* 18-11-93 - StephenE - Created
|
|
*
|
|
\**************************************************************************/
|
|
void
|
|
InitializeNewTrackTime(
|
|
int cdrom,
|
|
PTRACK_PLAY tr,
|
|
BOOL fUpdateDisplay
|
|
)
|
|
{
|
|
int min,sec;
|
|
|
|
/*
|
|
** Update time information in gDevices structure
|
|
*/
|
|
|
|
CDTIME(cdrom).CurrTrack = tr;
|
|
CDTIME(cdrom).TrackCurMin = 0;
|
|
CDTIME(cdrom).TrackCurSec = 0;
|
|
|
|
if (tr == NULL) {
|
|
|
|
CDTIME(cdrom).TrackTotalMin = 0;
|
|
CDTIME(cdrom).TrackTotalSec = 0;
|
|
|
|
}
|
|
else {
|
|
|
|
CDTIME(cdrom).TrackTotalMin = CDTIME(cdrom).TrackRemMin = tr->min;
|
|
CDTIME(cdrom).TrackTotalSec = CDTIME(cdrom).TrackRemSec = tr->sec;
|
|
|
|
}
|
|
|
|
min = sec = 0;
|
|
for( tr = PLAYLIST(cdrom); tr!=NULL; tr = tr->nextplay ) {
|
|
|
|
min += tr->min;
|
|
sec += tr->sec;
|
|
}
|
|
|
|
min += (sec / 60);
|
|
sec = (sec % 60);
|
|
|
|
CDTIME(cdrom).RemMin = min;
|
|
CDTIME(cdrom).RemSec = sec;
|
|
|
|
/*
|
|
** Update LED box
|
|
*/
|
|
if (fUpdateDisplay) {
|
|
UpdateDisplay( DISPLAY_UPD_LED | DISPLAY_UPD_TRACK_NAME |
|
|
DISPLAY_UPD_TRACK_TIME );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************Private*Routine******************************\
|
|
* TimeAdjustSkipToTrack
|
|
*
|
|
* Updates time/track information for gDevices array and then
|
|
* issues skip to track commands to cdrom device.
|
|
*
|
|
* History:
|
|
* 18-11-93 - StephenE - Created
|
|
*
|
|
\**************************************************************************/
|
|
void
|
|
TimeAdjustSkipToTrack(
|
|
int cdrom,
|
|
PTRACK_PLAY tr
|
|
)
|
|
{
|
|
|
|
/*
|
|
** Update time information in gDevices structure
|
|
*/
|
|
|
|
InitializeNewTrackTime( cdrom, tr, TRUE );
|
|
|
|
/*
|
|
** Actually seek to the track, and play it if appropriate
|
|
*/
|
|
|
|
if ((g_Devices[cdrom]->State & CD_PLAYING) ||
|
|
(g_Devices[cdrom]->State & CD_PAUSED)) {
|
|
|
|
PlayCurrTrack( cdrom );
|
|
if (g_Devices[cdrom]->State & CD_PAUSED) {
|
|
PauseTheCdromDrive( cdrom );
|
|
}
|
|
}
|
|
else if (tr) {
|
|
SeekToTrackAndHold( cdrom, tr->TocIndex );
|
|
}
|
|
}
|
|
|
|
|
|
/*****************************Private*Routine******************************\
|
|
* SyncDisplay
|
|
*
|
|
* Queries the cdrom device for its current position, and then
|
|
* updates the display accordingly. Also, detects when a track has
|
|
* finished playing, or when intro segment is over, and skips to the
|
|
* next track.
|
|
*
|
|
* History:
|
|
* 18-11-93 - StephenE - Created
|
|
*
|
|
\**************************************************************************/
|
|
void
|
|
SyncDisplay(
|
|
void
|
|
)
|
|
{
|
|
int m,s;
|
|
PTRACK_PLAY next;
|
|
CURRPOS cp;
|
|
PCURRPOS pCurr = &cp;
|
|
|
|
|
|
/*
|
|
** If there isn't a disc in the drive, ignore this
|
|
** request
|
|
*/
|
|
|
|
if ( (g_Devices[g_CurrCdrom]->State & CD_NO_CD) ||
|
|
(g_Devices[g_CurrCdrom]->State & CD_DATA_CD_LOADED) ) {
|
|
return;
|
|
}
|
|
|
|
/*
|
|
** Query cdrom device for current position
|
|
*/
|
|
|
|
if ( !GetCurrPos( g_CurrCdrom, pCurr ) ) {
|
|
|
|
/*
|
|
** If there was an error, it will already have been
|
|
** reported in CheckStatus of cdapi.c...so, we don't need
|
|
** to tell anything more here. When an error occurs, the
|
|
** fields of the pCurr structure are zeroed, so we don't
|
|
** need to clean those up either
|
|
*/
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
** Has the current play selection finished playing?
|
|
*/
|
|
#ifdef USE_IOCTLS
|
|
if ((pCurr->AudioStatus == AUDIO_STATUS_PLAY_COMPLETE) &&
|
|
( !(g_State & CD_SEEKING) )) {
|
|
#else
|
|
|
|
if ((pCurr->AudioStatus == MCI_MODE_STOP) &&
|
|
( !(g_State & CD_SEEKING) )) {
|
|
#endif
|
|
|
|
Play_Complete:
|
|
|
|
/*
|
|
** Yep, so skip to the next track.
|
|
*/
|
|
next = FindNextTrack( g_fContinuous );
|
|
|
|
if ( next == NULL ) {
|
|
|
|
/*
|
|
** There are no more tracks to play, so
|
|
** fake a press on the "stop" button. But,
|
|
** we want to set gCurrCdrom back to the "playing"
|
|
** drive 'cause it may have changed in our call
|
|
** to FindNextTrack.
|
|
*/
|
|
|
|
g_CurrCdrom = g_LastCdrom;
|
|
SendMessage( g_hwndApp, WM_COMMAND, IDM_PLAYBAR_STOP, 0L );
|
|
}
|
|
else {
|
|
|
|
if ( g_CurrCdrom != g_LastCdrom ) {
|
|
|
|
SwitchToCdrom( g_CurrCdrom, FALSE );
|
|
|
|
/*
|
|
** We use to start the disc play by sending the play command.
|
|
** SendMessage( g_hwndApp, WM_COMMAND, IDM_PLAYBAR_PLAY, 0L );
|
|
** However, all we realy need to put the drives state into
|
|
** playing and let TimeAdjustSkipToTrack take care of starting
|
|
** playing. If we don't do this when the app is in multi-disc
|
|
** random play mode, we get a fraction of a second of the
|
|
** first track in the playlist played before we seek to the
|
|
** the correct track and start playing it. This sounds really
|
|
** bad.
|
|
*/
|
|
|
|
g_State &= ~CD_STOPPED;
|
|
g_State |= CD_PLAYING;
|
|
|
|
}
|
|
|
|
TimeAdjustSkipToTrack( g_CurrCdrom, next );
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
** Check to see if we need to update the display
|
|
*/
|
|
|
|
if ( (pCurr->Track < 100) && ( pCurr->Track >
|
|
(CURRTRACK(g_CurrCdrom)->TocIndex + FIRSTTRACK(g_CurrCdrom)) )) {
|
|
|
|
/*
|
|
** We got to the next track in a multi-track
|
|
** play, so mark per track information for
|
|
** new track
|
|
*/
|
|
if ((CURRTRACK(g_CurrCdrom)->nextplay != NULL) &&
|
|
((CURRTRACK(g_CurrCdrom)->TocIndex + 1) ==
|
|
CURRTRACK(g_CurrCdrom)->nextplay->TocIndex)) {
|
|
|
|
next = FindNextTrack( g_fContinuous );
|
|
if ( next == NULL ) {
|
|
|
|
/*
|
|
** There are no more tracks to play, so
|
|
** fake a press on the "stop" button. But,
|
|
** we want to set gCurrCdrom back to the "playing"
|
|
** drive 'cause it may have changed in our call
|
|
** to FindNextTrack.
|
|
*/
|
|
|
|
g_CurrCdrom = g_LastCdrom;
|
|
|
|
SendMessage( g_hwndControls[INDEX(IDM_PLAYBAR_STOP)],
|
|
WM_LBUTTONDOWN, 0, 0L );
|
|
|
|
SendMessage( g_hwndControls[INDEX(IDM_PLAYBAR_STOP)],
|
|
WM_LBUTTONUP, 0, 0L );
|
|
|
|
}
|
|
else {
|
|
|
|
if ( g_CurrCdrom != g_LastCdrom ) {
|
|
|
|
SwitchToCdrom( g_CurrCdrom, FALSE );
|
|
SendMessage( g_hwndControls[INDEX(IDM_PLAYBAR_PLAY)],
|
|
WM_LBUTTONDOWN, 0, 0L );
|
|
|
|
SendMessage( g_hwndControls[INDEX(IDM_PLAYBAR_PLAY)],
|
|
WM_LBUTTONUP, 0, 0L );
|
|
}
|
|
|
|
InitializeNewTrackTime( g_CurrCdrom, next, FALSE );
|
|
UpdateDisplay( DISPLAY_UPD_TRACK_NAME | DISPLAY_UPD_TRACK_TIME );
|
|
}
|
|
}
|
|
else {
|
|
|
|
/*
|
|
** If we get here it is probably the result of starting
|
|
** CD Player whislt the current disc was still playing.
|
|
** We look for the currently playing track in the current
|
|
** playlist.
|
|
*/
|
|
|
|
next = FindFirstTrack(g_CurrCdrom);
|
|
while ( (next != NULL)
|
|
&& (pCurr->Track != (next->TocIndex + 1)) ) {
|
|
|
|
#if DBG
|
|
dprintf("trying track %d", (next->TocIndex + 1));
|
|
#endif
|
|
next = next->nextplay;
|
|
}
|
|
|
|
/*
|
|
** If next is NULL it means that we are playing a track that
|
|
** is currently not on the users playlist. So, we put up a
|
|
** message box informing the user of this fact and that we are
|
|
** going to temporarily add the track to the current playlist
|
|
** as the first track. Otherwise, we found the track in the
|
|
** playlist so just update the track time for this track.
|
|
*/
|
|
if (next == NULL) {
|
|
|
|
AddTemporaryTrackToPlayList(pCurr);
|
|
}
|
|
else {
|
|
|
|
InitializeNewTrackTime( g_CurrCdrom, next, TRUE );
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
if ( pCurr->Track <
|
|
(CURRTRACK(g_CurrCdrom)->TocIndex + FIRSTTRACK(g_CurrCdrom)) )
|
|
return;
|
|
|
|
if ( (pCurr->Index != 0)
|
|
&& (pCurr->m <= CDTIME(g_CurrCdrom).TrackCurMin)
|
|
&& (pCurr->s <= CDTIME(g_CurrCdrom).TrackCurSec) )
|
|
|
|
return;
|
|
|
|
/*
|
|
** Set track elapsed time
|
|
*/
|
|
|
|
CDTIME(g_CurrCdrom).TrackCurMin = pCurr->m;
|
|
CDTIME(g_CurrCdrom).TrackCurSec = pCurr->s;
|
|
|
|
/*
|
|
** Set track remaining time
|
|
*/
|
|
|
|
m = pCurr->m;
|
|
|
|
if ( (pCurr->s) <= CDTIME(g_CurrCdrom).TrackTotalSec ) {
|
|
|
|
s = CDTIME(g_CurrCdrom).TrackTotalSec - pCurr->s;
|
|
}
|
|
else {
|
|
|
|
s = 60 - (pCurr->s - CDTIME(g_CurrCdrom).TrackTotalSec);
|
|
m++;
|
|
}
|
|
|
|
CDTIME(g_CurrCdrom).TrackRemMin = CDTIME(g_CurrCdrom).TrackTotalMin - m;
|
|
CDTIME(g_CurrCdrom).TrackRemSec = s;
|
|
|
|
/*
|
|
** Set disc remaining time
|
|
**
|
|
** BUGBUG -- for now, just decrement by 1 second
|
|
*/
|
|
|
|
CDTIME(g_CurrCdrom).RemSec--;
|
|
if (CDTIME(g_CurrCdrom).RemSec < 0) {
|
|
|
|
CDTIME(g_CurrCdrom).RemSec = 59;
|
|
CDTIME(g_CurrCdrom).RemMin--;
|
|
}
|
|
|
|
|
|
/*
|
|
** Update LED box
|
|
*/
|
|
|
|
if ( (pCurr->Index != 0) || ((pCurr->m == 0) && (pCurr->s == 0)) ) {
|
|
|
|
UpdateDisplay( DISPLAY_UPD_LED );
|
|
}
|
|
else {
|
|
|
|
UpdateDisplay( DISPLAY_UPD_LED | DISPLAY_UPD_LEADOUT_TIME );
|
|
}
|
|
|
|
/*
|
|
** Check to see if we are intro play and have played
|
|
** intro segment...if so, skip to next track
|
|
*/
|
|
|
|
if ( ((pCurr->s >= (g_IntroPlayLength + 1)) || (pCurr->m > 0))
|
|
&& g_fIntroPlay ) {
|
|
|
|
goto Play_Complete;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************Private*Routine******************************\
|
|
* ValidatePosition
|
|
*
|
|
* Checks the current position on the CD, then verifies that the
|
|
* relative offset in the track + the beginning of the track's
|
|
* position is the same as the absolute position on the CD.
|
|
*
|
|
* History:
|
|
* 18-11-93 - StephenE - Created
|
|
*
|
|
\**************************************************************************/
|
|
void
|
|
ValidatePosition(
|
|
int cdrom
|
|
)
|
|
{
|
|
int Mult, Frames;
|
|
CURRPOS cp;
|
|
PCURRPOS pCurr = &cp;
|
|
LPTSTR s1,s2;
|
|
|
|
|
|
if (!GetCurrPos( cdrom, pCurr ))
|
|
|
|
/*
|
|
** If there was an error, it will already have been
|
|
** reported in CheckStatus of cdapi.c...so, we don't need
|
|
** to tell anything more here. When an error occurs, the
|
|
** fields of the pCurr structure are zeroed, so we don't
|
|
** need to clean those up either
|
|
*/
|
|
|
|
return;
|
|
|
|
|
|
/*
|
|
** Make sure the position returned is consistent with
|
|
** what we know about the CD. By comparing the relative time
|
|
** on this track to the absolute time on the CD, we should be
|
|
** able to make sure we're still on the right disc. This is
|
|
** a failsafe for when polling fails to notice an ejected
|
|
** disc.
|
|
*/
|
|
|
|
if ((cp.Track > 0)&&(cp.Track < 101)) {
|
|
|
|
Frames = cp.ab_m * 60 * 75;
|
|
Frames += cp.ab_s * 75;
|
|
Frames += cp.ab_f;
|
|
|
|
Frames -= TRACK_M(cdrom,cp.Track-1) * 60 * 75;
|
|
Frames -= TRACK_S(cdrom,cp.Track-1) * 75;
|
|
Frames -= TRACK_F(cdrom,cp.Track-1);
|
|
if (pCurr->Index) {
|
|
|
|
Mult = 1;
|
|
}
|
|
else {
|
|
|
|
Mult = -1;
|
|
}
|
|
|
|
Frames -= Mult*cp.m * 60 * 75;
|
|
Frames -= Mult*cp.s * 75;
|
|
Frames -= Mult*cp.f;
|
|
|
|
if (g_Devices[cdrom]->CdInfo.iFrameOffset == NEW_FRAMEOFFSET) {
|
|
|
|
g_Devices[cdrom]->CdInfo.iFrameOffset = Frames;
|
|
}
|
|
|
|
if ((ABS(Frames - g_Devices[ cdrom ]->CdInfo.iFrameOffset) > 4) &&
|
|
(ABS(Frames) > 4)) {
|
|
|
|
HWND hwndStop;
|
|
|
|
hwndStop = g_hwndControls[INDEX(IDM_PLAYBAR_STOP)];
|
|
|
|
s1 = AllocMemory( _tcslen(IdStr(STR_BAD_DISC)) + 1 );
|
|
_tcscpy( s1, IdStr(STR_BAD_DISC) );
|
|
|
|
s2 = AllocMemory( _tcslen(IdStr(STR_CDPLAYER)) + 1);
|
|
_tcscpy(s2,IdStr(STR_CDPLAYER));
|
|
|
|
MessageBox( g_hwndApp, s1, s2, MB_APPLMODAL|MB_ICONSTOP|MB_OK );
|
|
|
|
SendMessage( hwndStop,WM_LBUTTONDOWN, 1,0L );
|
|
SendMessage( hwndStop,WM_LBUTTONUP, 1, 0L );
|
|
|
|
RescanDevice(g_hwndApp, cdrom );
|
|
|
|
LocalFree( (HLOCAL)s1 );
|
|
LocalFree( (HLOCAL)s2 );
|
|
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*****************************Private*Routine******************************\
|
|
* ResetTrackComboBox
|
|
*
|
|
* This routine deletes and then resets the track name combobox based
|
|
* on the contents of the PLAYLIST for the specified cdrom drive.
|
|
*
|
|
* History:
|
|
* 18-11-93 - StephenE - Created
|
|
*
|
|
\**************************************************************************/
|
|
VOID
|
|
ResetTrackComboBox(
|
|
int cdrom
|
|
)
|
|
{
|
|
int j,index;
|
|
PTRACK_PLAY temp;
|
|
HWND hwnd;
|
|
|
|
hwnd = g_hwndControls[INDEX(IDC_TRACK_LIST)];
|
|
|
|
SetWindowRedraw( hwnd, FALSE );
|
|
ComboBox_ResetContent( hwnd );
|
|
|
|
/*
|
|
** Add new playlist, and select correct entry for current track
|
|
*/
|
|
|
|
j = index = 0;
|
|
for( temp = PLAYLIST(cdrom); temp != NULL; temp = temp->nextplay ) {
|
|
|
|
ComboBox_InsertString( hwnd, -1, temp->TocIndex );
|
|
|
|
if ( temp == CURRTRACK(cdrom) ) {
|
|
|
|
index = j;
|
|
}
|
|
|
|
j++;
|
|
|
|
}
|
|
|
|
ComboBox_SetCurSel( hwnd, index );
|
|
SetWindowRedraw( hwnd, TRUE );
|
|
|
|
RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE );
|
|
UpdateWindow( hwnd );
|
|
|
|
UpdateDisplay( DISPLAY_UPD_LED | DISPLAY_UPD_TRACK_TIME );
|
|
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* PlayListMatchesAvailList
|
|
*
|
|
* Compares the current play list with the default play list to if they match.
|
|
*
|
|
* History:
|
|
* dd-mm-94 - StephenE - Created
|
|
*
|
|
\**************************************************************************/
|
|
BOOL
|
|
PlayListMatchesAvailList(
|
|
void
|
|
)
|
|
{
|
|
|
|
PTRACK_PLAY pl = SAVELIST(g_CurrCdrom);
|
|
int i = 0;
|
|
|
|
while (pl && i < NUMTRACKS(g_CurrCdrom)) {
|
|
|
|
if ( pl->TocIndex != i) {
|
|
return FALSE;
|
|
}
|
|
pl = pl->nextplay;
|
|
i++;
|
|
}
|
|
|
|
return pl == NULL && i == NUMTRACKS(g_CurrCdrom);
|
|
}
|
|
|
|
|
|
/*****************************Private*Routine******************************\
|
|
* AddTemporaryTrackToPlayList
|
|
*
|
|
* This functions adds the currently playing track to the playlist.
|
|
* pCurr contains the toc index of the track that is required to be added.
|
|
*
|
|
* History:
|
|
* dd-mm-94 - StephenE - Created
|
|
*
|
|
\**************************************************************************/
|
|
void
|
|
AddTemporaryTrackToPlayList(
|
|
PCURRPOS pCurr
|
|
)
|
|
{
|
|
// LPTSTR lpstrTitle;
|
|
// LPTSTR lpstrText;
|
|
PTRACK_PLAY tr;
|
|
int m, s;
|
|
|
|
|
|
/*
|
|
** Add track to the current playlist.
|
|
*/
|
|
tr = AllocMemory( sizeof(TRACK_PLAY) );
|
|
tr->TocIndex = pCurr->Track - 1;
|
|
FigureTrackTime(g_CurrCdrom, tr->TocIndex, &tr->min, &tr->sec);
|
|
|
|
tr->nextplay = PLAYLIST(g_CurrCdrom);
|
|
tr->prevplay = NULL;
|
|
|
|
PLAYLIST(g_CurrCdrom)->prevplay = tr;
|
|
PLAYLIST(g_CurrCdrom) = tr;
|
|
|
|
/*
|
|
** Update the display.
|
|
*/
|
|
InitializeNewTrackTime( g_CurrCdrom, tr, TRUE );
|
|
ResetTrackComboBox( g_CurrCdrom );
|
|
|
|
m = CDTIME(g_CurrCdrom).TotalMin + tr->min;
|
|
s = CDTIME(g_CurrCdrom).TotalSec + tr->sec;
|
|
|
|
m += (s / 60);
|
|
s = (s % 60);
|
|
|
|
CDTIME(g_CurrCdrom).TotalMin = m;
|
|
CDTIME(g_CurrCdrom).TotalSec = s;
|
|
UpdateDisplay(DISPLAY_UPD_DISC_TIME);
|
|
|
|
|
|
/*
|
|
** Now modify the current saved playlist. We do this so that transitions
|
|
** from/to random mode work correctly.
|
|
*/
|
|
tr = AllocMemory( sizeof(TRACK_PLAY) );
|
|
tr->TocIndex = pCurr->Track - 1;
|
|
FigureTrackTime(g_CurrCdrom, tr->TocIndex, &tr->min, &tr->sec);
|
|
|
|
tr->nextplay = SAVELIST(g_CurrCdrom);
|
|
tr->prevplay = NULL;
|
|
|
|
SAVELIST(g_CurrCdrom)->prevplay = tr;
|
|
SAVELIST(g_CurrCdrom) = tr;
|
|
|
|
#if 0
|
|
/*
|
|
** Now, tell the user what we have just done. Note that we disable the
|
|
** the Heart beat timer so that we don't renenter ourselves.
|
|
*/
|
|
lpstrTitle = AllocMemory( STR_MAX_STRING_LEN * sizeof(TCHAR) );
|
|
lpstrText = AllocMemory( STR_MAX_STRING_LEN * sizeof(TCHAR) );
|
|
|
|
_tcscpy( lpstrText, IdStr(STR_NOT_IN_PLAYLIST) );
|
|
_tcscpy( lpstrTitle, IdStr(STR_CDPLAYER) );
|
|
|
|
KillTimer( g_hwndApp, HEARTBEAT_TIMER_ID );
|
|
|
|
MessageBox( NULL, lpstrText, lpstrTitle,
|
|
MB_APPLMODAL | MB_ICONINFORMATION | MB_OK );
|
|
|
|
SetTimer( g_hwndApp, HEARTBEAT_TIMER_ID, HEARTBEAT_TIMER_RATE,
|
|
HeartBeatTimerProc );
|
|
LocalFree( (HLOCAL)lpstrText );
|
|
LocalFree( (HLOCAL)lpstrTitle );
|
|
#endif
|
|
}
|