|
|
/******************************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. ** ** Should Fix -- 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 */
/*
** Should Fix 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) {
//<mwetzel:08.28.97> Removed this line of code, so that tracks don't get
//accidentally added. After a track is played, the STOP state is sensed,
//and this function (see above) advances the track. However, under a rare
//(about 1-5% of time) circumstance, this thread will sense that the cd's
//time value means it's on the next track, and the cd is still in play mode.
//This code used to interpret that as a new play command, and added the track
//to the playlist. Hence, I commented out the following line. If the actual
//case where a new play command is received, the new track is added to the
//playlist in the HandlePassedCommandLine() call.
//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 ** ** Should Fix -- 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
}
|