2 * $Source: /cvs/cvsroot/d2x/unused/bios/rbaudio.new,v $
\r
3 * $Revision: 1.1.1.1 $
\r
4 * $Author: bradleyb $
\r
5 * $Date: 2001-01-19 03:30:14 $
\r
7 * Redbook Audio Library
\r
9 * $Log: not supported by cvs2svn $
\r
10 * Revision 1.18 1996/04/15 15:27:40 samir
\r
11 * Play multiple tracks and PeekPlayStatus uses timer method!
\r
13 * Revision 1.17 1996/04/12 20:08:42 samir
\r
14 * Added debugging info and Redbook / HSG detection
\r
16 * Revision 1.16 1996/04/12 19:13:29 matt
\r
17 * Changed parameter name and added comments
\r
19 * Revision 1.15 1996/04/12 18:08:02 samir
\r
20 * We now pass a cd drive letter to RBAInit.
\r
22 * Revision 1.14 1996/02/14 13:31:29 samir
\r
23 * Fixed stupid bug that caused last track to never be played
\r
25 * Revision 1.13 1996/02/13 17:16:04 samir
\r
26 * Added Pause and Resume Caps.
\r
28 * Revision 1.12 1996/01/11 10:08:01 matt
\r
29 * RBARegisterCD wasn't checking SendRequest error code, so it was reporting
\r
30 * CD tracks when there was no CD in the drive.
\r
32 * Revision 1.11 1996/01/10 20:15:45 samir
\r
33 * Changed behavior of RBACheckMediaChange to work
\r
34 * correctly, as well as calling this function in critical
\r
35 * RBA functions to take care of CD changes.
\r
37 * Revision 1.10 1996/01/10 18:30:49 samir
\r
38 * Changed property of RBCheckMediaChange which would
\r
39 * not disable RBA if media had changed. GetNumberOfTracks
\r
40 * returns num. of tracks or if media changed, re-registers
\r
41 * CD and then returns number of tracks. If media has changed
\r
42 * RBAPlayTrack will return an error.
\r
44 * Revision 1.9 1995/08/01 19:30:11 samir
\r
45 * Added ability to get number of tracks on CD via call.
\r
47 * Revision 1.8 1995/07/20 16:13:56 samir
\r
48 * Doesn't quit if CD isn't Redbook.
\r
50 * Revision 1.7 1995/05/10 11:37:51 samir
\r
51 * Checks whether CD-ROM in drive at start of game
\r
53 * Revision 1.6 1995/05/09 18:00:08 samir
\r
56 * Revision 1.5 1995/05/09 17:57:43 samir
\r
57 * No CD in Drive, then diable RBA
\r
59 * Revision 1.4 1995/05/09 17:12:24 samir
\r
60 * Added user detection of Redbook Audio.
\r
62 * Revision 1.3 1995/05/09 12:04:57 samir
\r
63 * Added ability to known when a CD is playing
\r
64 * and when it's stopped.
\r
66 * Revision 1.2 1995/05/08 11:33:37 samir
\r
72 char rbaudio_rcsid[] = "$Id: rbaudio.new,v 1.1.1.1 2001-01-19 03:30:14 bradleyb Exp $";
\r
81 #include "rbaudio.h"
\r
86 #define HSG_CD_PLAYBACK 0
\r
87 #define MSF_CD_PLAYBACK 1
\r
89 #define RBERR_WRITEPROTVIOL 0
\r
90 #define RBERR_UNKNOWNUNIT 1
\r
91 #define RBERR_DRIVENOTREADY 2
\r
92 #define RBERR_UNKNOWNCOMMAND 3
\r
93 #define RBERR_CRCERROR 4
\r
94 #define RBERR_BADDRIVEREQ 5
\r
95 #define RBERR_SEEKERROR 6
\r
96 #define RBERR_UNKNOWNMEDIA 7
\r
97 #define RBERR_SECTORNOTFOUND 8
\r
98 #define RBERR_WRITEFAULT 10
\r
99 #define RBERR_READFAULT 12
\r
100 #define RBERR_GENERALFAILURE 13
\r
101 #define RBERR_BADDISKCHANGE 15
\r
103 #define RBSTAT_ERROR 0x8000
\r
104 #define RBSTAT_BUSY 0x0200
\r
105 #define RBSTAT_DONE 0x0100
\r
110 // Request Header -----------------------------------------------------
\r
112 typedef struct _REQHDR {
\r
113 unsigned char length;
\r
114 unsigned char subunit;
\r
115 unsigned char func;
\r
116 unsigned short status;
\r
120 typedef struct _IOCTL {
\r
122 unsigned short buffer_realoff;
\r
123 unsigned short buffer_realseg;
\r
124 unsigned short xferlen;
\r
125 unsigned short sector;
\r
130 // CD Information -----------------------------------------------------
\r
133 char code; // Control Block Code
\r
134 char track; // Track Number
\r
135 long start; // Start of Track in MSF (Redbook)
\r
136 unsigned char info; // Track Control Info
\r
137 } CDTrackInfo = {11,2,0L,0};
\r
142 } TrackInfoREQ = {{13,0,3,0,""}, {0,0,0,0,0}};
\r
145 unsigned char code;
\r
146 unsigned long devstat;
\r
152 } DevStatREQ = {{13,0,3,0,""}, {0,0,0,0,0}};
\r
155 unsigned char code;
\r
162 } MedChgREQ = {{13,0,3,0,""}, {0,0,0,0,0}};
\r
166 } StopREQ = {{13,0,133,0,""}};
\r
170 } ResumeREQ = {{13,0,136,0,""}};
\r
173 unsigned char code;
\r
174 unsigned char first;
\r
175 unsigned char last;
\r
176 unsigned long lead_out;
\r
177 } CDInfo = {10,0,0,0L};
\r
182 } CDInfoREQ = {{13,0,3,0,""},{0,0,0,0,0}};
\r
186 char mode; // Play in HSG or MSF(RedBook)
\r
187 unsigned long playbeg;
\r
188 unsigned long playlen; // HSG Format
\r
189 char empty; // Empty byte used so that all requests have same size
\r
190 } PlayREQ = {{13,0,132,0,""},0,0,0,0};
\r
193 unsigned char code;
\r
194 unsigned char out0in;
\r
195 unsigned char out0vol;
\r
196 unsigned char out1in;
\r
197 unsigned char out1vol;
\r
198 unsigned char out2in;
\r
199 unsigned char out2vol;
\r
200 unsigned char out3in;
\r
201 unsigned char out3vol;
\r
202 } AUDChannelCtl = {3,0,0,0,0,0,0,0,0};
\r
207 } AUDChannelCtlREQ = {{13,0,12,0,""},{0,0,0,0,0}};
\r
210 unsigned char code;
\r
211 unsigned char out0in;
\r
212 unsigned char out0vol;
\r
213 unsigned char out1in;
\r
214 unsigned char out1vol;
\r
215 unsigned char out2in;
\r
216 unsigned char out2vol;
\r
217 unsigned char out3in;
\r
218 unsigned char out3vol;
\r
219 } AUDChannelInfo = {4,0,0,0,0,0,0,0,0};
\r
224 } AUDChannelInfoREQ = {{13,0,3,0,""},{0,0,0,0,0}};
\r
227 unsigned char code;
\r
228 unsigned char mode;
\r
229 unsigned long headloc;
\r
230 } HeadInfo = {1,MSF_CD_PLAYBACK,0L};
\r
235 } HeadInfoREQ = {{13,0,3,0,""},{0,0,0,0,0}};
\r
237 //@@static struct {
\r
249 //@@} QChannelInfo = {12, MSF_CD_PLAYBACK, 2,0,0,0,0,0,0,0,0 };
\r
251 //@@static struct {
\r
252 //@@ REQHDR reqhdr;
\r
254 //@@} QChannelInfoREQ = {{13, 0, 3, 0, ""}, {0,0,0,0,0}};
\r
257 // Translation from RealMode->Protected mode buffer
\r
259 typedef struct _REQ_xlatbuf { // Buffer for Real Mode Callback
\r
266 // Other Data ---------------------------------------------------------
\r
268 static unsigned char CDDriveLetter;
\r
269 static unsigned long CDNumTracks,CDTrackStart[101];
\r
270 static int RedBookEnabled = 0;
\r
271 static int RedBookPlaybackType = MSF_CD_PLAYBACK;
\r
272 static fix Playback_Start_Time = 0;
\r
273 static fix Playback_Pause_Time = 0;
\r
274 static fix Playback_Length = 0;
\r
277 // Prototypes ---------------------------------------------------------
\r
279 int RBSendRequest(char *request, char *xferptr, int xferlen);
\r
280 unsigned long msf_to_lsn(unsigned long msf);
\r
281 unsigned long lsn_to_msf(unsigned long lsn);
\r
284 // --------------------------------------------------------------------
\r
286 void RBAInit(ubyte cd_drive_num) //drive a == 0, drive b == 1
\r
290 // Detect presence of CD-ROM
\r
291 regs.x.eax = 0x1500;
\r
293 int386(0x2f, ®s, ®s);
\r
295 if (regs.x.ebx == 0)
\r
296 RBADisable(); // Disable RedBook
\r
297 // Error("RBA Error: MSCDEX.EXE compatible driver couldn't be found.");
\r
299 CDDriveLetter = cd_drive_num;
\r
300 // CDDriveLetter = (unsigned char)regs.x.ecx;
\r
303 RBACheckMediaChange();
\r
305 RBSendRequest((char*)&DevStatREQ, (char*)&DevStat, sizeof(DevStat));
\r
307 // If Door drive open, or no disc in CD-ROM, then Redbook is Disabled.
\r
308 if ((DevStat.devstat&2048) || (DevStat.devstat&1) || RBAEnabled() == 0)
\r
311 //@@ if (DevStat.devstat&4)
\r
312 //@@ mprintf((0, "supports cooked and raw reading.\n"));
\r
314 //@@ mprintf((0, "supports only cooked reading.\n"));
\r
316 //@@ if (DevStat.devstat&256)
\r
317 //@@ mprintf((0, "audio channel manipulation.\n"));
\r
319 //@@ mprintf((0, "no audio channel manipulation.\n"));
\r
321 if (DevStat.devstat&512) {
\r
322 // RedBookPlaybackType = MSF_CD_PLAYBACK;
\r
323 mprintf((0, "supports HSG and RedBook addressing mode.\n"));
\r
326 // RedBookPlaybackType = HSG_CD_PLAYBACK;
\r
327 mprintf((0, "supports HSG addressing only.\n"));
\r
330 RedBookPlaybackType = MSF_CD_PLAYBACK;
\r
335 //find out how many tracks on the CD, and their starting locations
\r
336 void RBARegisterCD(void)
\r
341 // Get CD Information First
\r
342 RBACheckMediaChange();
\r
344 error = RBSendRequest((char*)&CDInfoREQ, (char*)&CDInfo, sizeof(CDInfo));
\r
346 if (error & RBSTAT_ERROR) { //error!
\r
351 CDNumTracks = (CDInfo.last-CDInfo.first)+1;
\r
353 // Define Track Starts
\r
354 for (i=CDInfo.first; i<=CDNumTracks; i++)
\r
356 CDTrackInfo.track = i;
\r
357 RBSendRequest((char *)&TrackInfoREQ, (char*)&CDTrackInfo, sizeof(CDTrackInfo));
\r
358 CDTrackStart[i] = CDTrackInfo.start;
\r
361 CDTrackStart[i] = CDInfo.lead_out;
\r
365 long RBAGetDeviceStatus()
\r
367 RBSendRequest((char*)&DevStatREQ, (char*)&DevStat, sizeof(DevStat));
\r
368 return (long)DevStat.devstat;
\r
372 int RBAGetNumberOfTracks(void)
\r
374 // Get CD Information
\r
375 if (RBACheckMediaChange())
\r
378 return CDNumTracks;
\r
382 int RBAPlayTrack(int track)
\r
384 unsigned long playlen;
\r
387 Playback_Start_Time = 0;
\r
388 Playback_Length = 0;
\r
390 if (track < CDInfo.first || track > CDInfo.last) {
\r
391 mprintf((0,"CD not Redbook Compatible. Will not play track.\n"));
\r
393 // Error("RBA Error: Track %d doesn't exist on CD!!!", track);
\r
395 if (RBACheckMediaChange()) {
\r
396 mprintf((0, "Unable to play track due to CD change.\n"));
\r
400 // Play the track now!!!
\r
401 PlayREQ.mode = RedBookPlaybackType;
\r
402 PlayREQ.playbeg = CDTrackStart[track];
\r
404 if (RedBookPlaybackType == MSF_CD_PLAYBACK) {
\r
406 msf_to_lsn(CDTrackStart[track+1]) - msf_to_lsn(CDTrackStart[track]);
\r
409 mprintf((1, "RBERR: No! No! No! This shouldn't happen (HSG_CD_PLAYBACK).\n"));
\r
411 PlayREQ.playlen = CDTrackStart[track+1] - CDTrackStart[track];
\r
413 RBSendRequest((char *)&PlayREQ,NULL,0);
\r
415 playlen = msf_to_lsn(CDTrackStart[track+1]) - msf_to_lsn(CDTrackStart[track]);
\r
416 playlen = lsn_to_msf(playlen);
\r
417 min = (int)((playlen >> 16) & 0xFF);
\r
418 sec = (int)((playlen >> 8) & 0xFF);
\r
420 Playback_Start_Time = timer_get_fixed_seconds();
\r
421 Playback_Length = i2f(min*60+sec);
\r
423 mprintf( (0,"Playing Track %d (len: %d secs)\n", track, min*60+sec) );
\r
428 //plays tracks first through last, inclusive
\r
429 int RBAPlayTracks(int first, int last)
\r
431 unsigned long playlen;
\r
434 Playback_Start_Time = 0;
\r
435 Playback_Length = 0;
\r
437 if (first < CDInfo.first || last > CDInfo.last) {
\r
438 mprintf((0,"Invalid start or end track.\n"));
\r
440 // Error("RBA Error: Track %d doesn't exist on CD!!!", track);
\r
442 if (RBACheckMediaChange()) {
\r
443 mprintf((0, "Unable to play track due to CD change.\n"));
\r
447 // Play the track now!!!
\r
448 PlayREQ.mode = RedBookPlaybackType;
\r
449 PlayREQ.playbeg = CDTrackStart[first];
\r
451 if (RedBookPlaybackType == MSF_CD_PLAYBACK) {
\r
453 msf_to_lsn(CDTrackStart[last+1]) - msf_to_lsn(CDTrackStart[first]);
\r
456 mprintf((1, "RBERR: No! No! No! This shouldn't happen (HSG_CD_PLAYBACK).\n"));
\r
458 PlayREQ.playlen = CDTrackStart[last+1] - CDTrackStart[first];
\r
460 RBSendRequest((char *)&PlayREQ,NULL,0);
\r
462 playlen = msf_to_lsn(CDTrackStart[last+1]) - msf_to_lsn(CDTrackStart[first]);
\r
463 playlen = lsn_to_msf(playlen);
\r
464 min = (int)((playlen >> 16) & 0xFF);
\r
465 sec = (int)((playlen >> 8) & 0xFF);
\r
467 Playback_Start_Time = timer_get_fixed_seconds();
\r
468 Playback_Length = i2f(min*60+sec);
\r
470 mprintf( (0,"Playing Tracks %d-%d (len: %d secs)\n", first,last,min*60+sec) );
\r
478 RBSendRequest((char *)&StopREQ, NULL, 0);
\r
479 Playback_Pause_Time = timer_get_fixed_seconds();
\r
485 if (RBACheckMediaChange()) {
\r
487 return RBA_MEDIA_CHANGED;
\r
489 RBSendRequest((char *)&ResumeREQ, NULL, 0);
\r
491 Playback_Start_Time += timer_get_fixed_seconds() - Playback_Pause_Time;
\r
499 if (RBACheckMediaChange())
\r
502 RBSendRequest((char *)&StopREQ,NULL,0);
\r
506 void RBASetStereoAudio(RBACHANNELCTL *channels)
\r
508 AUDChannelCtl.out0in = channels->out0in;
\r
509 AUDChannelCtl.out0vol = channels->out0vol;
\r
510 AUDChannelCtl.out1in = channels->out1in;
\r
511 AUDChannelCtl.out1vol = channels->out1vol;
\r
512 AUDChannelCtl.out2in = AUDChannelCtl.out2vol = 0;
\r
513 AUDChannelCtl.out3in = AUDChannelCtl.out3vol = 0;
\r
515 RBSendRequest((char*)&AUDChannelCtlREQ, (char*)&AUDChannelCtl, sizeof(AUDChannelCtl));
\r
519 void RBASetQuadAudio(RBACHANNELCTL *channels)
\r
521 AUDChannelCtl.out0in = (unsigned char)channels->out0in;
\r
522 AUDChannelCtl.out0vol = (unsigned char)channels->out0vol;
\r
523 AUDChannelCtl.out1in = (unsigned char)channels->out1in;
\r
524 AUDChannelCtl.out1vol = (unsigned char)channels->out1vol;
\r
525 AUDChannelCtl.out2in = (unsigned char)channels->out2in;
\r
526 AUDChannelCtl.out2vol = (unsigned char)channels->out2vol;
\r
527 AUDChannelCtl.out3in = (unsigned char)channels->out3in;
\r
528 AUDChannelCtl.out3vol = (unsigned char)channels->out3vol;
\r
530 RBSendRequest((char*)&AUDChannelCtlREQ, (char*)&AUDChannelCtl, sizeof(AUDChannelCtl));
\r
534 void RBAGetAudioInfo(RBACHANNELCTL *channels)
\r
536 RBSendRequest((char*)&AUDChannelInfoREQ, (char*)&AUDChannelInfo, sizeof(AUDChannelInfo));
\r
538 channels->out0in = (int)AUDChannelInfo.out0in;
\r
539 channels->out0vol = (int)AUDChannelInfo.out0vol;
\r
540 channels->out1in = (int)AUDChannelInfo.out1in;
\r
541 channels->out1vol = (int)AUDChannelInfo.out1vol;
\r
542 channels->out2in = (int)AUDChannelInfo.out2in;
\r
543 channels->out2vol = (int)AUDChannelInfo.out2vol;
\r
544 channels->out3in = (int)AUDChannelInfo.out3in;
\r
545 channels->out3vol = (int)AUDChannelInfo.out3vol;
\r
550 void RBASetChannelVolume(int channel, int volume)
\r
552 //RBACHANNELCTL channels;
\r
554 RBSendRequest((char*)&AUDChannelInfoREQ, (char*)&AUDChannelInfo, sizeof(AUDChannelInfo));
\r
556 AUDChannelCtl.out0in = AUDChannelInfo.out0in;
\r
557 AUDChannelCtl.out0vol = AUDChannelInfo.out0vol;
\r
558 AUDChannelCtl.out1in = AUDChannelInfo.out1in;
\r
559 AUDChannelCtl.out1vol = AUDChannelInfo.out1vol;
\r
560 AUDChannelCtl.out2in = AUDChannelInfo.out2in;
\r
561 AUDChannelCtl.out2vol = AUDChannelInfo.out2vol;
\r
562 AUDChannelCtl.out3in = AUDChannelInfo.out3in;
\r
563 AUDChannelCtl.out3vol = AUDChannelInfo.out3vol;
\r
565 if (channel == 0) AUDChannelCtl.out0vol = (unsigned char)volume;
\r
566 if (channel == 1) AUDChannelCtl.out1vol = (unsigned char)volume;
\r
567 if (channel == 2) AUDChannelCtl.out2vol = (unsigned char)volume;
\r
568 if (channel == 3) AUDChannelCtl.out3vol = (unsigned char)volume;
\r
570 RBSendRequest((char*)&AUDChannelCtlREQ,(char*)&AUDChannelCtl, sizeof(AUDChannelCtl));
\r
575 void RBASetVolume(int volume)
\r
577 RBASetChannelVolume(0,volume);
\r
578 RBASetChannelVolume(1,volume);
\r
582 long RBAGetHeadLoc(int *min, int *sec, int *frame)
\r
586 if (RBACheckMediaChange())
\r
587 return RBA_MEDIA_CHANGED;
\r
589 HeadInfo.mode = RedBookPlaybackType;
\r
590 RBSendRequest((char*)&HeadInfoREQ, (char*)&HeadInfo, sizeof(HeadInfo));
\r
592 if (RedBookPlaybackType == MSF_CD_PLAYBACK)
\r
593 loc = HeadInfo.headloc;
\r
595 loc = lsn_to_msf(HeadInfo.headloc);
\r
597 *min = (int)((loc >> 16) & 0xFF);
\r
598 *sec = (int)((loc >> 8) & 0xFF);
\r
599 *frame = (int)((loc >> 0) & 0xFF);
\r
605 int RBAPeekPlayStatus()
\r
607 if ((timer_get_fixed_seconds()-Playback_Start_Time) > Playback_Length) return 0;
\r
614 if (RedBookEnabled < 1) return 0;
\r
621 RedBookEnabled = 1;
\r
622 mprintf((0, "Enabling Redbook...\n"));
\r
628 RedBookEnabled = 0;
\r
629 mprintf((0, "Disabling Redbook...\n"));
\r
634 // RB functions: Internal to RBA library -----------------------------
\r
636 //returns 1 if media has changed, else 0
\r
637 int RBACheckMediaChange()
\r
639 RBSendRequest((char *)&MedChgREQ, (char*)&MedChg, sizeof(MedChg));
\r
641 if (MedChg.byte == 255 || MedChg.byte == 0) {
\r
642 // New media in drive (or maybe no media in drive)
\r
643 mprintf((0,"CD-ROM Media change detected\n"));
\r
652 //returns 16-bit value. Bit 15 means error.
\r
653 //WE NEED SYMBOLOIC CONSTANTS FOR ALL RETURN CODES & STATUS BITS
\r
654 int RBSendRequest(char *request, char *xferptr, int xferlen)
\r
657 dpmi_real_regs rregs;
\r
660 REQ_xlatbuf *xlat_req; // Translated Buffer Request
\r
661 char *xlat_xferptr; // Translated Buffer Transfer Buffer Ptr
\r
663 unsigned short status;
\r
665 if (!RedBookEnabled) return 0; // Don't send request if no RBA
\r
667 memset(&rregs,0,sizeof(dpmi_real_regs));
\r
669 // Get Temporary Real Mode Buffer for request translation
\r
670 xlat_req = (REQ_xlatbuf *)dpmi_get_temp_low_buffer(128+xferlen);
\r
671 memcpy(xlat_req, request, sizeof(REQHDR)+sizeof(IOCTL));
\r
672 ioctl = (IOCTL *)(((char*)xlat_req)+sizeof(REQHDR));
\r
674 // Set Transfer Buffer in IOCTL reqion of 'request'
\r
675 if (xferlen && xferptr) {
\r
676 xlat_xferptr = ((char*)xlat_req) + 128;
\r
677 memcpy(xlat_xferptr, xferptr, xferlen);
\r
679 ioctl->buffer_realoff = DPMI_real_offset(xlat_xferptr);
\r
680 ioctl->buffer_realseg = DPMI_real_segment(xlat_xferptr);
\r
681 ioctl->xferlen = xferlen;
\r
684 // Setup and Send Request Packet
\r
685 rregs.eax = 0x1510;
\r
686 rregs.ecx = (unsigned)(CDDriveLetter);
\r
687 rregs.es = DPMI_real_segment(xlat_req);
\r
688 rregs.ebx = DPMI_real_offset(xlat_req);
\r
689 dpmi_real_int386x(0x2f, &rregs);
\r
691 // Return Translate Buffer to Protected mode 'xferptr'
\r
692 if (xferlen && xferptr) {
\r
693 memcpy(xferptr, xlat_xferptr, xferlen);
\r
695 memcpy(request, xlat_req, sizeof(REQHDR)+sizeof(IOCTL));
\r
697 // Check for Errors.
\r
698 status = ((REQHDR *)request)->status;
\r
700 if (status & RBSTAT_ERROR) {
\r
701 mprintf((0,"Error in SendRequest: %x.\n", status));
\r
708 // Converts Logical Sector Number to Minutes Seconds Frame Format
\r
710 unsigned long lsn_to_msf(unsigned long lsn)
\r
712 unsigned long min,sec,frame;
\r
715 min = lsn / (60*75);
\r
716 lsn = lsn % (60*75);
\r
721 return((min << 16) + (sec << 8) + (frame << 0));
\r
724 // convert minutes seconds frame format to a logical sector number.
\r
726 unsigned long msf_to_lsn(unsigned long msf)
\r
728 unsigned long min,sec,frame;
\r
730 min = (msf >> 16) & 0xFF;
\r
731 sec = (msf >> 8) & 0xFF;
\r
732 frame = (msf >> 0) & 0xFF;
\r
734 return( (min * 60*75) + (sec * 75) + frame - 150 );
\r