2 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
3 SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
4 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
5 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
6 IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
7 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
8 FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
9 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
10 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
11 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
15 #pragma off (unreferenced)
16 static char rcsid[] = "$Id: rbaudio.c,v 1.1.1.1 2001-01-19 03:30:15 bradleyb Exp $";
17 #pragma on (unreferenced)
20 #define WIN32_LEAN_AND_MEAN
36 #define HSG_CD_PLAYBACK 0
37 #define MSF_CD_PLAYBACK 1
42 typedef struct CDTrack {
47 int RBCDROM_State = 0; // CD is not used = 0
49 // CD is already used = -1
51 static CDTrack CDTrackInfo[255];
52 static UINT CDDiscID = 0;
54 static int RedBookEnabled=0, RedBookInstalled = 0;
55 static UINT CDDeviceID = 0;
56 static DWORD CDNumTracks = 0;
57 static fix Playback_Start_Time = 0;
58 static fix Playback_Pause_Time = 0;
59 static fix Playback_Length = 0;
60 static int Playback_first_track,Playback_last_track;
61 static int AUXDevice = -1;
62 static char MCIErrorMsg[256];
64 // Function Prototypes
66 unsigned long lsn_to_msf(unsigned long lsn);
67 unsigned long msf_to_lsn(unsigned long msf);
68 unsigned long msf_add(unsigned long msf1, unsigned long msf2);
69 unsigned long msf_sub(unsigned long msf1, unsigned long msf2);
71 UINT MakeCDDiscID(int tracks, unsigned long msflen, unsigned long msftrack1);
79 if (RedBookInstalled) {
80 mciSendCommand(CDDeviceID, MCI_CLOSE, 0, NULL);
89 MCI_OPEN_PARMS mciOpenParms;
90 MCI_SET_PARMS mciSetParms;
96 num_devs = auxGetNumDevs();
98 // Find CD-AUDIO device if there is one.
99 for (i = 0; i < num_devs; i++)
102 auxGetDevCaps(i, &caps, sizeof(caps));
103 if (caps.wTechnology == AUXCAPS_CDAUDIO) {
105 mprintf((0, "CD operating on AUX %d.\n", AUXDevice));
110 if (AUXDevice == -1) {
111 mprintf((1, "Unable to find CD-AUDIO device. No Redbook music.\n"));
116 // We need to identify that a cd audio driver exists
117 mciOpenParms.lpstrDeviceType = "cdaudio";
119 retval = mciSendCommand(NULL, MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_SHAREABLE, (DWORD)(LPVOID)&mciOpenParms);
121 if (retval == MCIERR_MUST_USE_SHAREABLE) RBCDROM_State = -1;
122 else RBCDROM_State = 0;
123 mciGetErrorString(retval, MCIErrorMsg, 256);
124 mprintf((1,"RBA (%x) MCI:%s.\n", retval, MCIErrorMsg));
128 // Now we need to set the time format to MSF for Redbook Compatablity.
129 RedBookInstalled = 1;
131 CDDeviceID = mciOpenParms.wDeviceID;
133 logentry("Initializing Redbook device %d.\n", CDDeviceID);
135 mciSetParms.dwTimeFormat = MCI_FORMAT_MSF;
136 retval = mciSendCommand(CDDeviceID, MCI_SET, MCI_SET_TIME_FORMAT, (DWORD)(LPVOID)&mciSetParms);
138 mciSendCommand(CDDeviceID, MCI_CLOSE, 0, NULL);
139 mprintf((0, "Error %d. Unable to set Redbook Format.\n", retval));
142 else RedBookEnabled = 1;
147 void RBARegisterCD(void)
149 DWORD i, numtracks, retval = 0;
150 MCI_STATUS_PARMS mciStatusParms;
152 // Insure that CD is Redbook, then get track information
153 mciStatusParms.dwItem = MCI_STATUS_NUMBER_OF_TRACKS;
154 retval = mciSendCommand(CDDeviceID, MCI_STATUS, MCI_STATUS_ITEM,
155 (DWORD)(LPVOID)&mciStatusParms);
157 mciGetErrorString(retval, MCIErrorMsg, 256);
158 mprintf((1,"RBA MCI:%s.\n", MCIErrorMsg));
163 CDNumTracks = numtracks = mciStatusParms.dwReturn;
165 for (i = 0; i < numtracks; i++)
167 mciStatusParms.dwTrack = i+1;
168 mciStatusParms.dwItem = MCI_STATUS_POSITION;
169 retval = mciSendCommand(CDDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK, (DWORD)(LPVOID)&mciStatusParms);
171 mprintf((0, "Could not retrieve information on track %d.\n", i+1));
173 CDTrackInfo[i].msf = mciStatusParms.dwReturn;
175 mciStatusParms.dwTrack = i+1;
176 mciStatusParms.dwItem = MCI_STATUS_LENGTH;
177 retval = mciSendCommand(CDDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK, (DWORD)(LPVOID)&mciStatusParms);
179 mprintf((0, "Couldn't get length of track %d.\n", i+1));
181 CDTrackInfo[i].length = mciStatusParms.dwReturn;
183 // logentry("[%d] (%d:%d):(%d:%d)\n", i+1, MCI_MSF_MINUTE(CDTrackInfo[i].msf), MCI_MSF_SECOND(CDTrackInfo[i].msf), MCI_MSF_MINUTE(CDTrackInfo[i].length), MCI_MSF_SECOND(CDTrackInfo[i].length));
186 CDDiscID = GetCDDiscID();
190 long RBAGetDeviceStatus()
196 int get_track_time(int first,int last)
198 unsigned long playlen;
201 playlen = msf_sub(msf_add(CDTrackInfo[last-1].msf,CDTrackInfo[last-1].length), CDTrackInfo[first-1].msf);
203 min = MCI_MSF_MINUTE(playlen);
204 sec = MCI_MSF_SECOND(playlen);
210 int RBAPlayTrack(int track)
212 MCI_PLAY_PARMS mciPlayParms;
216 // Register CD if media has changed
217 if (!RedBookEnabled) return 0;
218 if (RBACheckMediaChange()) {
219 mprintf((0, "Unable to play track due to CD change.\n"));
224 min = min + MCI_MSF_MINUTE(CDTrackInfo[track-1].msf) + MCI_MSF_MINUTE(CDTrackInfo[track-1].length);
225 mciPlayParms.dwFrom = CDTrackInfo[track-1].msf; // MCI_MAKE_TMSF(track, 0, 0, 0);
226 mciPlayParms.dwTo = msf_add(CDTrackInfo[track-1].msf, CDTrackInfo[track-1].length);
227 retval = mciSendCommand(CDDeviceID, MCI_PLAY, MCI_FROM | MCI_TO, (DWORD)(LPVOID)&mciPlayParms);
230 mciGetErrorString(retval, MCIErrorMsg, 256);
231 mprintf((1,"RBA MCI:%s.\n", MCIErrorMsg));
232 mprintf((0, "Unable to play CD track %d.\n", track));
236 Playback_Length = i2f(get_track_time(track,track));
237 Playback_Start_Time = timer_get_fixed_seconds();
239 Playback_first_track = Playback_last_track = track;
241 mprintf( (0,"Playing Track %d (len: %d secs)\n", track, f2i(Playback_Length)) );
248 int RBAPlayTracks(int start, int end)
250 MCI_PLAY_PARMS mciPlayParms;
253 Playback_Start_Time = 0;
256 // Register CD if media has changed
257 if (!RedBookEnabled) return 0;
258 if (RBACheckMediaChange()) {
259 mprintf((0, "Unable to play track due to CD change.\n"));
264 mciPlayParms.dwFrom = CDTrackInfo[start-1].msf; // MCI_MAKE_TMSF(track, 0, 0, 0);
265 mciPlayParms.dwTo = msf_add(CDTrackInfo[end-1].msf, CDTrackInfo[end-1].length);
266 retval = mciSendCommand(CDDeviceID, MCI_PLAY, MCI_FROM | MCI_TO, (DWORD)(LPVOID)&mciPlayParms);
269 mciGetErrorString(retval, MCIErrorMsg, 256);
270 mprintf((1,"RBA MCI:%s.\n", MCIErrorMsg));
271 mprintf((0, "Unable to play CD tracks %d-%d.\n", start,end));
275 Playback_Length = i2f(get_track_time(start,end));
276 Playback_Start_Time = timer_get_fixed_seconds();
278 Playback_first_track = start;
279 Playback_last_track = end;
281 mprintf( (0,"Playing Tracks %d-%d (len: %d secs)\n", start,end,f2i(Playback_Length)) );
292 if (!RedBookEnabled) return;
294 retval = mciSendCommand(CDDeviceID, MCI_STOP,0,NULL);
296 mciGetErrorString(retval, MCIErrorMsg, 256);
297 mprintf((1,"RBA MCI:%s.\n", MCIErrorMsg));
298 mprintf((0, "CD Stop command failed.\n"));
303 void RBASetStereoAudio(RBACHANNELCTL *channels)
309 void RBASetQuadAudio(RBACHANNELCTL *channels)
315 void RBAGetAudioInfo(RBACHANNELCTL *channels)
321 static unsigned rba_paused_head_loc = 0;
326 MCI_GENERIC_PARMS mciGenParms;
330 if (!RedBookEnabled) return;
332 rba_paused_head_loc = RBAGetHeadLoc(&min, &sec, &frame);
334 mciGenParms.dwCallback = GetLibraryWindow();
335 retval = mciSendCommand(CDDeviceID, MCI_PAUSE, MCI_NOTIFY,
336 (DWORD)(LPVOID)&mciGenParms);
338 mprintf((1,"ERROR: Unable to pause CD.\n"));
341 mprintf((0, "Pausing CD...\n"));
342 Playback_Pause_Time = timer_get_fixed_seconds();
351 MCI_PLAY_PARMS mciPlayParms;
353 if (!RedBookEnabled) return 0;
355 if (RBACheckMediaChange()) {
357 return RBA_MEDIA_CHANGED;
360 mciPlayParms.dwFrom = rba_paused_head_loc; // MCI_MAKE_TMSF(track, 0, 0, 0);
361 mciPlayParms.dwTo = msf_add(CDTrackInfo[Playback_last_track-1].msf,
362 CDTrackInfo[Playback_last_track-1].length);
363 retval = mciSendCommand(CDDeviceID, MCI_PLAY, MCI_FROM | MCI_TO, (DWORD)(LPVOID)&mciPlayParms);
366 mprintf((1, "ERROR: Resume CD play failed.\n"));
369 Playback_Start_Time += timer_get_fixed_seconds() - Playback_Pause_Time;
375 void RBASetChannelVolume(int channel, int volume)
379 volume = volume << 8;
382 vol = MAKELONG(0,volume);
383 else if (channel == 1)
384 vol = MAKELONG(volume,0);
386 auxSetVolume(AUXDevice, vol);
390 void RBASetVolume(int volume)
395 wvol = (WORD)(volume) << 8;
397 vol = MAKELONG(wvol, wvol);
398 auxSetVolume(AUXDevice, vol);
402 long RBAGetHeadLoc(int *min, int *sec, int *frame)
404 MCI_STATUS_PARMS mciStatusParms;
407 if (!RedBookEnabled) return 0;
409 if (RBACheckMediaChange())
410 return RBA_MEDIA_CHANGED;
412 mciStatusParms.dwItem = MCI_STATUS_POSITION;
413 retval = mciSendCommand(CDDeviceID, MCI_STATUS, MCI_STATUS_ITEM, (DWORD)(LPVOID)&mciStatusParms);
416 mprintf((0, "Couldn't get location of CD head.\n"));
419 *min = MCI_MSF_MINUTE(mciStatusParms.dwReturn);
420 *sec = MCI_MSF_SECOND(mciStatusParms.dwReturn);
421 *frame = MCI_MSF_FRAME(mciStatusParms.dwReturn);
423 return mciStatusParms.dwReturn;
430 int delta_time; //in seconds
432 if (!RBAPeekPlayStatus())
435 delta_time = f2i(timer_get_fixed_seconds()-Playback_Start_Time+f1_0/2);
437 for (track=Playback_first_track;track<=Playback_last_track && delta_time>0;track++) {
439 delta_time -= get_track_time(track,track);
445 Assert(track <= Playback_last_track);
451 int RBAPeekPlayStatus()
453 //@@ MCI_STATUS_PARMS mciStatusParms;
456 if (!RedBookEnabled) return 0;
459 if ((timer_get_fixed_seconds()-Playback_Start_Time) > Playback_Length) return 0;
463 //@@ mciStatusParms.dwItem = MCI_STATUS_MODE;
464 //@@ retval = mciSendCommand(CDDeviceID, MCI_STATUS, MCI_STATUS_ITEM, (DWORD)(LPVOID)&mciStatusParms);
466 //@@ mprintf((0, "Unable to obtain current status of CD.\n"));
469 //@@ if (mciStatusParms.dwReturn == MCI_MODE_PLAY) return 1;
477 if (RedBookEnabled < 1) return 0;
485 mprintf((0, "Enabling Redbook...\n"));
492 mprintf((0, "Disabling Redbook...\n"));
496 int RBAGetNumberOfTracks(void)
498 MCI_STATUS_PARMS mciStatusParms;
501 if (!RedBookEnabled) return 0;
503 if (RBACheckMediaChange())
506 mciStatusParms.dwItem = MCI_STATUS_NUMBER_OF_TRACKS;
507 retval = mciSendCommand(CDDeviceID, MCI_STATUS, MCI_STATUS_ITEM,
508 (DWORD)(LPVOID)&mciStatusParms);
511 mprintf((0, "Get number of CD tracks failed.\n"));
515 return mciStatusParms.dwReturn;
519 // RB functions: Internal to RBA library -----------------------------
521 int RBACheckMediaChange()
523 if (!RedBookEnabled) return 0;
525 if (CDDiscID != GetCDDiscID() || !CDDiscID) return 1;
530 // Converts Logical Sector Number to Minutes Seconds Frame Format
532 unsigned long lsn_to_msf(unsigned long lsn)
534 unsigned long min,sec,frame;
543 return((min << 16) + (sec << 8) + (frame << 0));
546 // convert minutes seconds frame format to a logical sector number.
548 unsigned long msf_to_lsn(unsigned long msf)
550 unsigned long min,sec,frame;
552 min = (msf >> 16) & 0xFF;
553 sec = (msf >> 8) & 0xFF;
554 frame = (msf >> 0) & 0xFF;
556 return( (min * 60*75) + (sec * 75) + frame - 150 );
559 unsigned long msf_add(unsigned long msf1, unsigned long msf2)
561 uint min1, sec1, frame1;
562 uint min2, sec2, frame2;
564 // we don't take frames into account, which may not be right.
565 min1 = MCI_MSF_MINUTE(msf1);
566 sec1 = MCI_MSF_SECOND(msf1);
567 frame1 = MCI_MSF_FRAME(msf1);
572 if ((sec1 + MCI_MSF_SECOND(msf2)) > 59) {
573 sec2 = (sec1+MCI_MSF_SECOND(msf2)) - 60;
576 else sec2 = sec1 + MCI_MSF_SECOND(msf2);
577 min2 = min1+MCI_MSF_MINUTE(msf2);
580 // logentry("msf_add:(%d:%d)\n", min2, sec2);
582 return MCI_MAKE_MSF(min2, sec2, 0);
586 unsigned long msf_sub(unsigned long msf1, unsigned long msf2)
588 int min1, sec1, frame1;
589 int min2, sec2, frame2;
591 // we don't take frames into account, which may not be right.
592 min1 = MCI_MSF_MINUTE(msf1);
593 sec1 = MCI_MSF_SECOND(msf1);
594 frame1 = MCI_MSF_FRAME(msf1);
599 if ((sec1 - (int)MCI_MSF_SECOND(msf2)) < 0) {
600 sec2 = 60 - ((int)MCI_MSF_SECOND(msf2)-sec1);
601 min1--; // This is a shortcut to min2 = min1-(MSF_MIN(msf2)-1)
603 else sec2 = sec1 - (int)MCI_MSF_SECOND(msf2);
604 min2 = min1-(int)MCI_MSF_MINUTE(msf2);
607 // logentry("msf_sub:(%d:%d)\n", min2, sec2);
609 return MCI_MAKE_MSF(min2, sec2, 0);
613 unsigned long msf_to_sec(unsigned long msf)
615 unsigned long min,sec,frame;
617 min = (msf >> 16) & 0xFF;
618 sec = (msf >> 8) & 0xFF;
619 frame = (msf >> 0) & 0xFF;
621 return (min*60) + sec;
627 MCI_STATUS_PARMS mciStatusParms;
629 unsigned long msflen, tracks, msftrack1;
631 mciStatusParms.dwItem = MCI_STATUS_NUMBER_OF_TRACKS;
632 if (retval = mciSendCommand(CDDeviceID, MCI_STATUS, MCI_STATUS_ITEM,
633 (DWORD)(LPVOID)&mciStatusParms)) {
634 mprintf((1, "RBA: Get number of CD tracks failed.\n"));
637 tracks = mciStatusParms.dwReturn;
639 mciStatusParms.dwItem = MCI_STATUS_LENGTH;
640 if (retval = mciSendCommand(CDDeviceID, MCI_STATUS, MCI_STATUS_ITEM,
641 (DWORD)(LPVOID)&mciStatusParms)) {
642 mprintf((1, "RBA: Get media length failed.\n"));
645 msflen = mciStatusParms.dwReturn;
647 mciStatusParms.dwTrack = 1;
648 mciStatusParms.dwItem = MCI_STATUS_POSITION;
649 if (retval = mciSendCommand(CDDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK, (DWORD)(LPVOID)&mciStatusParms)) {
650 mprintf((1, "Could not retrieve information on track %d.\n", 1));
653 msftrack1 = mciStatusParms.dwReturn;
655 return MakeCDDiscID(tracks, msflen, msftrack1);
659 UINT MakeCDDiscID(int tracks, unsigned long msflen, unsigned long msftrack1)
663 code = (UINT)(msf_to_sec(msftrack1) << 19);
664 code |= (UINT)(msf_to_sec(msflen) << 6);
666 code |= (UINT)(tracks&0xffffffc0);