dxx-rebirth/unused/bios/rbaudio.new
Bradley Bell f05dc678f0 This commit was generated by cvs2svn to compensate for changes in r5,
which included commits to RCS files with non-trunk default branches.
2001-01-19 03:34:09 +00:00

737 lines
18 KiB
Plaintext

/*
* $Source: /cvs/cvsroot/d2x/unused/bios/rbaudio.new,v $
* $Revision: 1.1.1.2 $
* $Author: bradleyb $
* $Date: 2001-01-19 03:33:50 $
*
* Redbook Audio Library
*
* $Log: not supported by cvs2svn $
* Revision 1.18 1996/04/15 15:27:40 samir
* Play multiple tracks and PeekPlayStatus uses timer method!
*
* Revision 1.17 1996/04/12 20:08:42 samir
* Added debugging info and Redbook / HSG detection
*
* Revision 1.16 1996/04/12 19:13:29 matt
* Changed parameter name and added comments
*
* Revision 1.15 1996/04/12 18:08:02 samir
* We now pass a cd drive letter to RBAInit.
*
* Revision 1.14 1996/02/14 13:31:29 samir
* Fixed stupid bug that caused last track to never be played
*
* Revision 1.13 1996/02/13 17:16:04 samir
* Added Pause and Resume Caps.
*
* Revision 1.12 1996/01/11 10:08:01 matt
* RBARegisterCD wasn't checking SendRequest error code, so it was reporting
* CD tracks when there was no CD in the drive.
*
* Revision 1.11 1996/01/10 20:15:45 samir
* Changed behavior of RBACheckMediaChange to work
* correctly, as well as calling this function in critical
* RBA functions to take care of CD changes.
*
* Revision 1.10 1996/01/10 18:30:49 samir
* Changed property of RBCheckMediaChange which would
* not disable RBA if media had changed. GetNumberOfTracks
* returns num. of tracks or if media changed, re-registers
* CD and then returns number of tracks. If media has changed
* RBAPlayTrack will return an error.
*
* Revision 1.9 1995/08/01 19:30:11 samir
* Added ability to get number of tracks on CD via call.
*
* Revision 1.8 1995/07/20 16:13:56 samir
* Doesn't quit if CD isn't Redbook.
*
* Revision 1.7 1995/05/10 11:37:51 samir
* Checks whether CD-ROM in drive at start of game
*
* Revision 1.6 1995/05/09 18:00:08 samir
* Error cleaned.
*
* Revision 1.5 1995/05/09 17:57:43 samir
* No CD in Drive, then diable RBA
*
* Revision 1.4 1995/05/09 17:12:24 samir
* Added user detection of Redbook Audio.
*
* Revision 1.3 1995/05/09 12:04:57 samir
* Added ability to known when a CD is playing
* and when it's stopped.
*
* Revision 1.2 1995/05/08 11:33:37 samir
* Initial revision
*
*
*/
char rbaudio_rcsid[] = "$Id: rbaudio.new,v 1.1.1.2 2001-01-19 03:33:50 bradleyb Exp $";
#include <dos.h>
#include <dpmi.h>
#include <string.h>
#include "mono.h"
#include "error.h"
#include "rbaudio.h"
#include "fix.h"
#include "timer.h"
#define HSG_CD_PLAYBACK 0
#define MSF_CD_PLAYBACK 1
#define RBERR_WRITEPROTVIOL 0
#define RBERR_UNKNOWNUNIT 1
#define RBERR_DRIVENOTREADY 2
#define RBERR_UNKNOWNCOMMAND 3
#define RBERR_CRCERROR 4
#define RBERR_BADDRIVEREQ 5
#define RBERR_SEEKERROR 6
#define RBERR_UNKNOWNMEDIA 7
#define RBERR_SECTORNOTFOUND 8
#define RBERR_WRITEFAULT 10
#define RBERR_READFAULT 12
#define RBERR_GENERALFAILURE 13
#define RBERR_BADDISKCHANGE 15
#define RBSTAT_ERROR 0x8000
#define RBSTAT_BUSY 0x0200
#define RBSTAT_DONE 0x0100
#pragma pack(1)
// Request Header -----------------------------------------------------
typedef struct _REQHDR {
unsigned char length;
unsigned char subunit;
unsigned char func;
unsigned short status;
char array[8];
} REQHDR;
typedef struct _IOCTL {
char bpb;
unsigned short buffer_realoff;
unsigned short buffer_realseg;
unsigned short xferlen;
unsigned short sector;
unsigned long id;
} IOCTL;
// CD Information -----------------------------------------------------
static struct {
char code; // Control Block Code
char track; // Track Number
long start; // Start of Track in MSF (Redbook)
unsigned char info; // Track Control Info
} CDTrackInfo = {11,2,0L,0};
static struct {
REQHDR reqheader;
IOCTL ioctl;
} TrackInfoREQ = {{13,0,3,0,""}, {0,0,0,0,0}};
static struct {
unsigned char code;
unsigned long devstat;
} DevStat = {6,0};
static struct {
REQHDR reqhdr;
IOCTL ioctl;
} DevStatREQ = {{13,0,3,0,""}, {0,0,0,0,0}};
static struct {
unsigned char code;
char byte;
} MedChg = {9,0};
static struct {
REQHDR reqhdr;
IOCTL ioctl;
} MedChgREQ = {{13,0,3,0,""}, {0,0,0,0,0}};
static struct {
REQHDR reqhdr;
} StopREQ = {{13,0,133,0,""}};
static struct {
REQHDR reqhdr;
} ResumeREQ = {{13,0,136,0,""}};
static struct {
unsigned char code;
unsigned char first;
unsigned char last;
unsigned long lead_out;
} CDInfo = {10,0,0,0L};
static struct {
REQHDR reqhdr;
IOCTL ioctl;
} CDInfoREQ = {{13,0,3,0,""},{0,0,0,0,0}};
static struct {
REQHDR reqheader;
char mode; // Play in HSG or MSF(RedBook)
unsigned long playbeg;
unsigned long playlen; // HSG Format
char empty; // Empty byte used so that all requests have same size
} PlayREQ = {{13,0,132,0,""},0,0,0,0};
static struct {
unsigned char code;
unsigned char out0in;
unsigned char out0vol;
unsigned char out1in;
unsigned char out1vol;
unsigned char out2in;
unsigned char out2vol;
unsigned char out3in;
unsigned char out3vol;
} AUDChannelCtl = {3,0,0,0,0,0,0,0,0};
static struct {
REQHDR reqhdr;
IOCTL ioctl;
} AUDChannelCtlREQ = {{13,0,12,0,""},{0,0,0,0,0}};
static struct {
unsigned char code;
unsigned char out0in;
unsigned char out0vol;
unsigned char out1in;
unsigned char out1vol;
unsigned char out2in;
unsigned char out2vol;
unsigned char out3in;
unsigned char out3vol;
} AUDChannelInfo = {4,0,0,0,0,0,0,0,0};
static struct {
REQHDR reqhdr;
IOCTL ioctl;
} AUDChannelInfoREQ = {{13,0,3,0,""},{0,0,0,0,0}};
static struct {
unsigned char code;
unsigned char mode;
unsigned long headloc;
} HeadInfo = {1,MSF_CD_PLAYBACK,0L};
static struct {
REQHDR reqhdr;
IOCTL ioctl;
} HeadInfoREQ = {{13,0,3,0,""},{0,0,0,0,0}};
//@@static struct {
//@@ ubyte code;
//@@ ubyte adr;
//@@ ubyte tno;
//@@ ubyte point;
//@@ ubyte min;
//@@ ubyte sec;
//@@ ubyte frame;
//@@ ubyte zero;
//@@ ubyte pmin;
//@@ ubyte psec;
//@@ ubyte pframe;
//@@} QChannelInfo = {12, MSF_CD_PLAYBACK, 2,0,0,0,0,0,0,0,0 };
//@@
//@@static struct {
//@@ REQHDR reqhdr;
//@@ IOCTL ioctl;
//@@} QChannelInfoREQ = {{13, 0, 3, 0, ""}, {0,0,0,0,0}};
// Translation from RealMode->Protected mode buffer
typedef struct _REQ_xlatbuf { // Buffer for Real Mode Callback
REQHDR reqheader;
char ioctl[10];
} REQ_xlatbuf;
// Other Data ---------------------------------------------------------
static unsigned char CDDriveLetter;
static unsigned long CDNumTracks,CDTrackStart[101];
static int RedBookEnabled = 0;
static int RedBookPlaybackType = MSF_CD_PLAYBACK;
static fix Playback_Start_Time = 0;
static fix Playback_Pause_Time = 0;
static fix Playback_Length = 0;
// Prototypes ---------------------------------------------------------
int RBSendRequest(char *request, char *xferptr, int xferlen);
unsigned long msf_to_lsn(unsigned long msf);
unsigned long lsn_to_msf(unsigned long lsn);
// --------------------------------------------------------------------
void RBAInit(ubyte cd_drive_num) //drive a == 0, drive b == 1
{
union REGS regs;
// Detect presence of CD-ROM
regs.x.eax = 0x1500;
regs.x.ebx = 0;
int386(0x2f, &regs, &regs);
if (regs.x.ebx == 0)
RBADisable(); // Disable RedBook
// Error("RBA Error: MSCDEX.EXE compatible driver couldn't be found.");
else {
CDDriveLetter = cd_drive_num;
// CDDriveLetter = (unsigned char)regs.x.ecx;
RBAEnable();
RBACheckMediaChange();
RBSendRequest((char*)&DevStatREQ, (char*)&DevStat, sizeof(DevStat));
// If Door drive open, or no disc in CD-ROM, then Redbook is Disabled.
if ((DevStat.devstat&2048) || (DevStat.devstat&1) || RBAEnabled() == 0)
RBADisable();
//@@ if (DevStat.devstat&4)
//@@ mprintf((0, "supports cooked and raw reading.\n"));
//@@ else
//@@ mprintf((0, "supports only cooked reading.\n"));
//@@
//@@ if (DevStat.devstat&256)
//@@ mprintf((0, "audio channel manipulation.\n"));
//@@ else
//@@ mprintf((0, "no audio channel manipulation.\n"));
if (DevStat.devstat&512) {
// RedBookPlaybackType = MSF_CD_PLAYBACK;
mprintf((0, "supports HSG and RedBook addressing mode.\n"));
}
else {
// RedBookPlaybackType = HSG_CD_PLAYBACK;
mprintf((0, "supports HSG addressing only.\n"));
}
RedBookPlaybackType = MSF_CD_PLAYBACK;
}
}
//find out how many tracks on the CD, and their starting locations
void RBARegisterCD(void)
{
int i;
int error;
// Get CD Information First
RBACheckMediaChange();
error = RBSendRequest((char*)&CDInfoREQ, (char*)&CDInfo, sizeof(CDInfo));
if (error & RBSTAT_ERROR) { //error!
CDNumTracks = 0;
return;
}
CDNumTracks = (CDInfo.last-CDInfo.first)+1;
// Define Track Starts
for (i=CDInfo.first; i<=CDNumTracks; i++)
{
CDTrackInfo.track = i;
RBSendRequest((char *)&TrackInfoREQ, (char*)&CDTrackInfo, sizeof(CDTrackInfo));
CDTrackStart[i] = CDTrackInfo.start;
}
CDTrackStart[i] = CDInfo.lead_out;
}
long RBAGetDeviceStatus()
{
RBSendRequest((char*)&DevStatREQ, (char*)&DevStat, sizeof(DevStat));
return (long)DevStat.devstat;
}
int RBAGetNumberOfTracks(void)
{
// Get CD Information
if (RBACheckMediaChange())
RBARegisterCD();
return CDNumTracks;
}
int RBAPlayTrack(int track)
{
unsigned long playlen;
int min, sec;
Playback_Start_Time = 0;
Playback_Length = 0;
if (track < CDInfo.first || track > CDInfo.last) {
mprintf((0,"CD not Redbook Compatible. Will not play track.\n"));
}
// Error("RBA Error: Track %d doesn't exist on CD!!!", track);
if (RBACheckMediaChange()) {
mprintf((0, "Unable to play track due to CD change.\n"));
return 0;
}
// Play the track now!!!
PlayREQ.mode = RedBookPlaybackType;
PlayREQ.playbeg = CDTrackStart[track];
if (RedBookPlaybackType == MSF_CD_PLAYBACK) {
PlayREQ.playlen =
msf_to_lsn(CDTrackStart[track+1]) - msf_to_lsn(CDTrackStart[track]);
}
else {
mprintf((1, "RBERR: No! No! No! This shouldn't happen (HSG_CD_PLAYBACK).\n"));
Int3();
PlayREQ.playlen = CDTrackStart[track+1] - CDTrackStart[track];
}
RBSendRequest((char *)&PlayREQ,NULL,0);
playlen = msf_to_lsn(CDTrackStart[track+1]) - msf_to_lsn(CDTrackStart[track]);
playlen = lsn_to_msf(playlen);
min = (int)((playlen >> 16) & 0xFF);
sec = (int)((playlen >> 8) & 0xFF);
Playback_Start_Time = timer_get_fixed_seconds();
Playback_Length = i2f(min*60+sec);
mprintf( (0,"Playing Track %d (len: %d secs)\n", track, min*60+sec) );
return 1;
}
//plays tracks first through last, inclusive
int RBAPlayTracks(int first, int last)
{
unsigned long playlen;
int min, sec;
Playback_Start_Time = 0;
Playback_Length = 0;
if (first < CDInfo.first || last > CDInfo.last) {
mprintf((0,"Invalid start or end track.\n"));
}
// Error("RBA Error: Track %d doesn't exist on CD!!!", track);
if (RBACheckMediaChange()) {
mprintf((0, "Unable to play track due to CD change.\n"));
return 0;
}
// Play the track now!!!
PlayREQ.mode = RedBookPlaybackType;
PlayREQ.playbeg = CDTrackStart[first];
if (RedBookPlaybackType == MSF_CD_PLAYBACK) {
PlayREQ.playlen =
msf_to_lsn(CDTrackStart[last+1]) - msf_to_lsn(CDTrackStart[first]);
}
else {
mprintf((1, "RBERR: No! No! No! This shouldn't happen (HSG_CD_PLAYBACK).\n"));
Int3();
PlayREQ.playlen = CDTrackStart[last+1] - CDTrackStart[first];
}
RBSendRequest((char *)&PlayREQ,NULL,0);
playlen = msf_to_lsn(CDTrackStart[last+1]) - msf_to_lsn(CDTrackStart[first]);
playlen = lsn_to_msf(playlen);
min = (int)((playlen >> 16) & 0xFF);
sec = (int)((playlen >> 8) & 0xFF);
Playback_Start_Time = timer_get_fixed_seconds();
Playback_Length = i2f(min*60+sec);
mprintf( (0,"Playing Tracks %d-%d (len: %d secs)\n", first,last,min*60+sec) );
return 1;
}
void RBAPause()
{
RBSendRequest((char *)&StopREQ, NULL, 0);
Playback_Pause_Time = timer_get_fixed_seconds();
}
int RBAResume()
{
if (RBACheckMediaChange()) {
RBARegisterCD();
return RBA_MEDIA_CHANGED;
}
RBSendRequest((char *)&ResumeREQ, NULL, 0);
Playback_Start_Time += timer_get_fixed_seconds() - Playback_Pause_Time;
return 1;
}
void RBAStop()
{
if (RBACheckMediaChange())
RBARegisterCD();
RBSendRequest((char *)&StopREQ,NULL,0);
}
void RBASetStereoAudio(RBACHANNELCTL *channels)
{
AUDChannelCtl.out0in = channels->out0in;
AUDChannelCtl.out0vol = channels->out0vol;
AUDChannelCtl.out1in = channels->out1in;
AUDChannelCtl.out1vol = channels->out1vol;
AUDChannelCtl.out2in = AUDChannelCtl.out2vol = 0;
AUDChannelCtl.out3in = AUDChannelCtl.out3vol = 0;
RBSendRequest((char*)&AUDChannelCtlREQ, (char*)&AUDChannelCtl, sizeof(AUDChannelCtl));
}
void RBASetQuadAudio(RBACHANNELCTL *channels)
{
AUDChannelCtl.out0in = (unsigned char)channels->out0in;
AUDChannelCtl.out0vol = (unsigned char)channels->out0vol;
AUDChannelCtl.out1in = (unsigned char)channels->out1in;
AUDChannelCtl.out1vol = (unsigned char)channels->out1vol;
AUDChannelCtl.out2in = (unsigned char)channels->out2in;
AUDChannelCtl.out2vol = (unsigned char)channels->out2vol;
AUDChannelCtl.out3in = (unsigned char)channels->out3in;
AUDChannelCtl.out3vol = (unsigned char)channels->out3vol;
RBSendRequest((char*)&AUDChannelCtlREQ, (char*)&AUDChannelCtl, sizeof(AUDChannelCtl));
}
void RBAGetAudioInfo(RBACHANNELCTL *channels)
{
RBSendRequest((char*)&AUDChannelInfoREQ, (char*)&AUDChannelInfo, sizeof(AUDChannelInfo));
channels->out0in = (int)AUDChannelInfo.out0in;
channels->out0vol = (int)AUDChannelInfo.out0vol;
channels->out1in = (int)AUDChannelInfo.out1in;
channels->out1vol = (int)AUDChannelInfo.out1vol;
channels->out2in = (int)AUDChannelInfo.out2in;
channels->out2vol = (int)AUDChannelInfo.out2vol;
channels->out3in = (int)AUDChannelInfo.out3in;
channels->out3vol = (int)AUDChannelInfo.out3vol;
}
void RBASetChannelVolume(int channel, int volume)
{
//RBACHANNELCTL channels;
RBSendRequest((char*)&AUDChannelInfoREQ, (char*)&AUDChannelInfo, sizeof(AUDChannelInfo));
AUDChannelCtl.out0in = AUDChannelInfo.out0in;
AUDChannelCtl.out0vol = AUDChannelInfo.out0vol;
AUDChannelCtl.out1in = AUDChannelInfo.out1in;
AUDChannelCtl.out1vol = AUDChannelInfo.out1vol;
AUDChannelCtl.out2in = AUDChannelInfo.out2in;
AUDChannelCtl.out2vol = AUDChannelInfo.out2vol;
AUDChannelCtl.out3in = AUDChannelInfo.out3in;
AUDChannelCtl.out3vol = AUDChannelInfo.out3vol;
if (channel == 0) AUDChannelCtl.out0vol = (unsigned char)volume;
if (channel == 1) AUDChannelCtl.out1vol = (unsigned char)volume;
if (channel == 2) AUDChannelCtl.out2vol = (unsigned char)volume;
if (channel == 3) AUDChannelCtl.out3vol = (unsigned char)volume;
RBSendRequest((char*)&AUDChannelCtlREQ,(char*)&AUDChannelCtl, sizeof(AUDChannelCtl));
}
void RBASetVolume(int volume)
{
RBASetChannelVolume(0,volume);
RBASetChannelVolume(1,volume);
}
long RBAGetHeadLoc(int *min, int *sec, int *frame)
{
unsigned long loc;
if (RBACheckMediaChange())
return RBA_MEDIA_CHANGED;
HeadInfo.mode = RedBookPlaybackType;
RBSendRequest((char*)&HeadInfoREQ, (char*)&HeadInfo, sizeof(HeadInfo));
if (RedBookPlaybackType == MSF_CD_PLAYBACK)
loc = HeadInfo.headloc;
else
loc = lsn_to_msf(HeadInfo.headloc);
*min = (int)((loc >> 16) & 0xFF);
*sec = (int)((loc >> 8) & 0xFF);
*frame = (int)((loc >> 0) & 0xFF);
return loc;
}
int RBAPeekPlayStatus()
{
if ((timer_get_fixed_seconds()-Playback_Start_Time) > Playback_Length) return 0;
else return 1;
}
int RBAEnabled()
{
if (RedBookEnabled < 1) return 0;
else return 1;
}
void RBAEnable()
{
RedBookEnabled = 1;
mprintf((0, "Enabling Redbook...\n"));
}
void RBADisable()
{
RedBookEnabled = 0;
mprintf((0, "Disabling Redbook...\n"));
}
// RB functions: Internal to RBA library -----------------------------
//returns 1 if media has changed, else 0
int RBACheckMediaChange()
{
RBSendRequest((char *)&MedChgREQ, (char*)&MedChg, sizeof(MedChg));
if (MedChg.byte == 255 || MedChg.byte == 0) {
// New media in drive (or maybe no media in drive)
mprintf((0,"CD-ROM Media change detected\n"));
return 1;
}
return 0;
}
// Send Request
//returns 16-bit value. Bit 15 means error.
//WE NEED SYMBOLOIC CONSTANTS FOR ALL RETURN CODES & STATUS BITS
int RBSendRequest(char *request, char *xferptr, int xferlen)
{
//union REGS regs;
dpmi_real_regs rregs;
IOCTL *ioctl;
REQ_xlatbuf *xlat_req; // Translated Buffer Request
char *xlat_xferptr; // Translated Buffer Transfer Buffer Ptr
unsigned short status;
if (!RedBookEnabled) return 0; // Don't send request if no RBA
memset(&rregs,0,sizeof(dpmi_real_regs));
// Get Temporary Real Mode Buffer for request translation
xlat_req = (REQ_xlatbuf *)dpmi_get_temp_low_buffer(128+xferlen);
memcpy(xlat_req, request, sizeof(REQHDR)+sizeof(IOCTL));
ioctl = (IOCTL *)(((char*)xlat_req)+sizeof(REQHDR));
// Set Transfer Buffer in IOCTL reqion of 'request'
if (xferlen && xferptr) {
xlat_xferptr = ((char*)xlat_req) + 128;
memcpy(xlat_xferptr, xferptr, xferlen);
ioctl->buffer_realoff = DPMI_real_offset(xlat_xferptr);
ioctl->buffer_realseg = DPMI_real_segment(xlat_xferptr);
ioctl->xferlen = xferlen;
}
// Setup and Send Request Packet
rregs.eax = 0x1510;
rregs.ecx = (unsigned)(CDDriveLetter);
rregs.es = DPMI_real_segment(xlat_req);
rregs.ebx = DPMI_real_offset(xlat_req);
dpmi_real_int386x(0x2f, &rregs);
// Return Translate Buffer to Protected mode 'xferptr'
if (xferlen && xferptr) {
memcpy(xferptr, xlat_xferptr, xferlen);
}
memcpy(request, xlat_req, sizeof(REQHDR)+sizeof(IOCTL));
// Check for Errors.
status = ((REQHDR *)request)->status;
if (status & RBSTAT_ERROR) {
mprintf((0,"Error in SendRequest: %x.\n", status));
}
return status;
}
// Converts Logical Sector Number to Minutes Seconds Frame Format
unsigned long lsn_to_msf(unsigned long lsn)
{
unsigned long min,sec,frame;
lsn += 150;
min = lsn / (60*75);
lsn = lsn % (60*75);
sec = lsn / 75;
lsn = lsn % 75;
frame = lsn;
return((min << 16) + (sec << 8) + (frame << 0));
}
// convert minutes seconds frame format to a logical sector number.
unsigned long msf_to_lsn(unsigned long msf)
{
unsigned long min,sec,frame;
min = (msf >> 16) & 0xFF;
sec = (msf >> 8) & 0xFF;
frame = (msf >> 0) & 0xFF;
return( (min * 60*75) + (sec * 75) + frame - 150 );
}