📄 i_cdmus.c
字号:
&cd_UPCCode, &cd_UPCCodeSeg, &cd_UPCCodeSel
},
{
sizeof(struct AudStat_s),
&cd_AudStat, &cd_AudStatSeg, &cd_AudStatSel
},
{
0, NULL, NULL, NULL
}
};
// CODE --------------------------------------------------------------------
//==========================================================================
//
// I_CDMusInit
//
// Initializes the CD audio system. Must be called before using any
// other I_CDMus functions.
//
// Returns: 0 (ok) or -1 (error, in cd_Error).
//
//==========================================================================
int I_CDMusInit(void)
{
int i;
int sect;
int maxTrack;
S_BYTE startMin1 = 0;
S_BYTE startSec1 = 0;
S_BYTE startMin2 = 0;
S_BYTE startSec2 = 0;
S_BYTE lengthMin = 0;
S_BYTE lengthSec = 0;
if(OkInit != 1)
{ // Only execute if uninitialized
// Get number of CD-ROM drives and first drive
memset(&RegBlock, 0, sizeof(RegBlock));
RegBlock.eax = CDROM_GETDRIVECOUNT;
RegBlock.ebx = 0;
DPMI_SimRealInt(MULTIPLEX_INT, &RegBlock);
cd_DriveCount = RegBlock.ebx;
// MSCDEX not installed if number of drives = 0
if(cd_DriveCount == 0)
{
cd_Error = CDERR_NOTINSTALLED;
return -1;
}
cd_FirstDrive = RegBlock.ecx;
cd_CurDrive = cd_FirstDrive;
// Allocate the IOCTL buffers
if(AllocIOCTLBuffers() == -1)
{
cd_Error = CDERR_IOCTLBUFFMEM;
return -1;
}
// Get MSCDEX version
// Major version in upper byte, minor version in lower byte
memset(&RegBlock, 0, sizeof(RegBlock));
RegBlock.eax = CDROM_GETVERSION;
DPMI_SimRealInt(MULTIPLEX_INT, &RegBlock);
cd_Version = RegBlock.ebx;
// Check device status to make sure we can read Audio CD's
InputIOCTL(DEVICESTATUS, cd_DevStatSeg);
if((cd_DevStat->devParams & 0x0010) == 0)
{
cd_Error = CDERR_NOAUDIOSUPPORT;
return -1;
}
}
// Force audio to stop playing
I_CDMusStop();
// Make sure we have the current TOC
InputIOCTL(MEDIACHANGED, cd_MedChngSeg);
// Set track variables
InputIOCTL(AUDIODISKINFO, cd_DiskInfoSeg);
cd_FirstTrack = cd_DiskInfo->lowTrack;
cd_LastTrack = cd_DiskInfo->highTrack;
if(cd_FirstTrack == 0 && cd_FirstTrack == cd_LastTrack)
{
cd_Error = CDERR_NOAUDIOTRACKS;
return -1;
}
cd_TrackCount = cd_LastTrack-cd_FirstTrack+1;
cd_LeadOutMin = cd_DiskInfo->startLeadOut>>16 & 0xFF;
cd_LeadOutSec = cd_DiskInfo->startLeadOut>>8 & 0xFF;
cd_LeadOutRed = cd_DiskInfo->startLeadOut;
cd_LeadOutSector = RedToSectors(cd_DiskInfo->startLeadOut);
// Create Red Book start, sector start, and sector length
// for all tracks
sect = cd_LeadOutSector;
for(i = cd_LastTrack; i >= cd_FirstTrack; i--)
{
cd_TrackInfo->track = i;
InputIOCTL(AUDIOTRACKINFO, cd_TrackInfoSeg);
if(i < MAX_AUDIO_TRACKS)
{
cd_AudioTracks[i].redStart = cd_TrackInfo->start;
cd_AudioTracks[i].sectorStart =
RedToSectors(cd_TrackInfo->start);
cd_AudioTracks[i].sectorLength =
sect-RedToSectors(cd_TrackInfo->start);
}
sect = RedToSectors(cd_TrackInfo->start);
}
// Create track lengths in minutes and seconds
if(cd_LastTrack >= MAX_AUDIO_TRACKS)
{
maxTrack = MAX_AUDIO_TRACKS-1;
}
else
{
maxTrack = cd_LastTrack;
}
cd_TrackInfo->track = cd_FirstTrack;
InputIOCTL(AUDIOTRACKINFO, cd_TrackInfoSeg);
startMin1 = (cd_TrackInfo->start >> 16);
startSec1 = (cd_TrackInfo->start >> 8);
for(i = cd_FirstTrack; i <= maxTrack; i++)
{
cd_TrackInfo->track = i+1;
if(i < cd_LastTrack)
{
InputIOCTL(AUDIOTRACKINFO, cd_TrackInfoSeg);
startMin2 = (cd_TrackInfo->start >> 16);
startSec2 = (cd_TrackInfo->start >> 8);
}
else
{
startMin2 = cd_LeadOutRed>>16;
startSec2 = cd_LeadOutRed>>8;
}
lengthSec = startSec2 - startSec1;
lengthMin = startMin2 - startMin1;
if(lengthSec < 0)
{
lengthSec += 60;
lengthMin--;
}
cd_AudioTracks[i].lengthMin = lengthMin;
cd_AudioTracks[i].lengthSec = lengthSec;
startMin1 = startMin2;
startSec1 = startSec2;
}
// Clip high tracks
cd_LastTrack = maxTrack;
OkInit = 1;
return 0;
}
//==========================================================================
//
// I_CDMusPlay
//
// Play an audio CD track.
//
// Returns: 0 (ok) or -1 (error, in cd_Error).
//
//==========================================================================
int I_CDMusPlay(int track)
{
int start;
int len;
if(track < cd_FirstTrack || track > cd_LastTrack)
{
cd_Error = CDERR_BADTRACK;
return(-1);
}
I_CDMusStop();
start = cd_AudioTracks[track].redStart;
len = cd_AudioTracks[track].sectorLength;
cd_PlayReq->addressMode = RED_MODE;
cd_PlayReq->startSector = start;
cd_PlayReq->numberToRead = len;
memset(&RegBlock, 0, sizeof(RegBlock));
RegBlock.eax = CDROM_SENDDEVICEREQ;
RegBlock.ecx = cd_CurDrive;
RegBlock.ebx = 0;
RegBlock.es = cd_PlayReqSeg;
DPMI_SimRealInt(MULTIPLEX_INT, &RegBlock);
if(cd_PlayReq->status&0x8000)
{
cd_Error = CDERR_DEVREQBASE+(cd_PlayReq->status)&0x00ff;
return(-1);
}
return(0);
}
//==========================================================================
//
// I_CDMusStop
//
// Stops the playing of an audio CD.
//
// Returns: 0 (ok) or -1 (error, in cd_Error).
//
//==========================================================================
int I_CDMusStop(void)
{
memset(&RegBlock, 0, sizeof(RegBlock));
RegBlock.eax = CDROM_SENDDEVICEREQ;
RegBlock.ecx = cd_CurDrive;
RegBlock.ebx = 0;
RegBlock.es = cd_StopReqSeg;
DPMI_SimRealInt(MULTIPLEX_INT, &RegBlock);
if(cd_StopReq->status&0x8000)
{
cd_Error = CDERR_DEVREQBASE+(cd_StopReq->status)&0x00ff;
return -1;
}
return 0;
}
//==========================================================================
//
// I_CDMusResume
//
// Resumes the playing of an audio CD.
//
// Returns: 0 (ok) or -1 (error, in cd_Error).
//
//==========================================================================
int I_CDMusResume(void)
{
memset(&RegBlock, 0, sizeof(RegBlock));
RegBlock.eax = CDROM_SENDDEVICEREQ;
RegBlock.ecx = cd_CurDrive;
RegBlock.ebx = 0;
RegBlock.es = cd_ResumeReqSeg;
DPMI_SimRealInt(MULTIPLEX_INT, &RegBlock);
if(cd_ResumeReq->status&0x8000)
{
cd_Error = CDERR_DEVREQBASE+(cd_ResumeReq->status)&0x00ff;
return -1;
}
return 0;
}
//==========================================================================
//
// I_CDMusSetVolume
//
// Sets the CD audio volume (0 - 255).
//
// Returns: 0 (ok) or -1 (error, in cd_Error).
//
//==========================================================================
int I_CDMusSetVolume(int volume)
{
if(!OkInit)
{
cd_Error = CDERR_NOTINSTALLED;
return -1;
}
// Read current channel info
InputIOCTL(AUDIOCHANINFO, cd_AudChanInfoSeg);
// Change the volumes
cd_AudChanInfo->volumeOut0 =
cd_AudChanInfo->volumeOut1 =
cd_AudChanInfo->volumeOut2 =
cd_AudChanInfo->volumeOut3 = volume;
// Write modified channel info
OutputIOCTL(AUDIOCHANCONTROL, cd_AudChanInfoSeg);
return 0;
}
//==========================================================================
//
// I_CDMusFirstTrack
//
// Returns: the number of the first track.
//
//==========================================================================
int I_CDMusFirstTrack(void)
{
return cd_FirstTrack;
}
//==========================================================================
//
// I_CDMusLastTrack
//
// Returns: the number of the last track.
//
//==========================================================================
int I_CDMusLastTrack(void)
{
return cd_LastTrack;
}
//==========================================================================
//
// I_CDMusTrackLength
//
// Returns: Length of the given track in seconds, or -1 (error, in
// cd_Error).
//
//==========================================================================
int I_CDMusTrackLength(int track)
{
if(track < cd_FirstTrack || track > cd_LastTrack)
{
cd_Error = CDERR_BADTRACK;
return -1;
}
return cd_AudioTracks[track].lengthMin*60
+cd_AudioTracks[track].lengthSec;
}
//==========================================================================
//
// AllocIOCTLBuffers
//
// Allocates conventional memory for the IOCTL input and output buffers.
// Sets cd_IOCTLBufferTotal to the total allocated.
//
// Returns: 0 (ok) or -1 (error, in cd_Error).
//
//==========================================================================
static int AllocIOCTLBuffers(void)
{
int i;
int size;
DOSChunk_t *ck;
cd_IOCTLBufferTotal = 0;
for(i = 0; DOSChunks[i].size != 0; i++)
{
ck = &DOSChunks[i];
size = ck->size;
cd_IOCTLBufferTotal += (size+15)&0xfffffff0;
*ck->address = DPMI_AllocRealMem(size, ck->segment, ck->selector);
if(*ck->address == NULL)
{
return -1;
}
memset(*ck->address, 0, size);
}
cd_IOCTLIn->headerSize = sizeof(struct IOCTLIn_s);
cd_IOCTLIn->command = DRC_IOCTLINPUT;
cd_IOCTLOut->headerSize = sizeof(struct IOCTLOut_s);
cd_IOCTLOut->command = DRC_IOCTLOUTPUT;
cd_PlayReq->headerSize = sizeof(struct PlayReq_s);
cd_PlayReq->command = DRC_PLAYAUDIO;
cd_StopReq->headerSize = sizeof(struct StopReq_s);
cd_StopReq->command = DRC_STOPAUDIO;
cd_ResumeReq->headerSize = sizeof(struct ResumeReq_s);
cd_ResumeReq->command = DRC_RESUMEAUDIO;
return 0;
}
//==========================================================================
//
// InputIOCTL
//
// Sends an IOCTL input device request command.
//
// Returns: the status of the request.
//
//==========================================================================
static U_WORD InputIOCTL(S_LONG request, U_WORD buffSeg)
{
U_BYTE *code;
code = (U_BYTE *)(buffSeg<<4);
*code = (U_BYTE)request;
cd_IOCTLIn->ctrlBlkAddr = buffSeg<<16;
cd_IOCTLIn->tranSize = InCtrlBlkSize[request];
memset(&RegBlock, 0, sizeof(RegBlock));
RegBlock.eax = CDROM_SENDDEVICEREQ;
RegBlock.ecx = cd_CurDrive;
RegBlock.ebx = 0;
RegBlock.es = cd_IOCTLInSeg;
DPMI_SimRealInt(MULTIPLEX_INT, &RegBlock);
return cd_IOCTLIn->status;
}
//==========================================================================
//
// OutputIOCTL
//
// Sends an IOCTL output device request command.
//
// Returns: the status of the request.
//
//==========================================================================
static U_WORD OutputIOCTL(S_LONG request, U_WORD buffSeg)
{
U_BYTE *code;
code = (U_BYTE *)(buffSeg<<4);
*code = (U_BYTE)request;
cd_IOCTLOut->ctrlBlkAddr = buffSeg<<16;
cd_IOCTLOut->tranSize = OutCtrlBlkSize[request];
RegBlock.eax = CDROM_SENDDEVICEREQ;
RegBlock.ecx = cd_CurDrive;
RegBlock.ebx = 0;
RegBlock.es = cd_IOCTLOutSeg;
DPMI_SimRealInt(MULTIPLEX_INT, &RegBlock);
return cd_IOCTLOut->status;
}
//==========================================================================
//
// RedToSectors
//
// Converts Red Book addresses to HSG sectors.
// Sectors = Minutes * 60 * 75 + Seconds * 75 + Frame - 150
//
// Returns: HSG sectors.
//
//==========================================================================
static U_LONG RedToSectors(U_LONG red)
{
U_LONG sector;
sector = ((red&0x00ff0000) >> 16) * 60 * 75;
sector += ((red&0x0000ff00) >> 8) * 75;
sector += (red&0x000000ff);
return sector-150;
}
//==========================================================================
//
// DPMI_SimRealInt
//
//==========================================================================
static void DPMI_SimRealInt(U_LONG intr, RegBlock_t *rBlock)
{
union REGS regs;
struct SREGS sRegs;
regs.x.eax = DPMI_SIMREALINT;
regs.x.ebx = intr;
regs.x.ecx = 0;
regs.x.edi = FP_OFF((void far *)rBlock);
sRegs.es = FP_SEG((void far *)rBlock);
sRegs.ds = FP_SEG((void far *)rBlock);
int386x(DPMI_INT, ®s, ®s, &sRegs);
}
//==========================================================================
//
// DPMI_AllocRealMem
//
//==========================================================================
static void *DPMI_AllocRealMem(U_LONG size, U_WORD *segment,
U_WORD *selector)
{
union REGS inRegs;
union REGS outRegs;
inRegs.x.eax = DPMI_ALLOCREALMEM;
inRegs.x.ebx = (size+15)/16;
int386(DPMI_INT, &inRegs, &outRegs);
if(outRegs.x.cflag)
{
return NULL;
}
*segment = outRegs.x.eax&0xffff;
*selector = outRegs.x.edx&0xffff;
return (void *)(outRegs.x.eax<<4);
}
//==========================================================================
//
// DPMI_FreeRealMem
//
//==========================================================================
static void DPMI_FreeRealMem(U_WORD selector)
{
union REGS regs;
regs.x.eax = DPMI_FREEREALMEM;
regs.x.edx = selector;
int386(DPMI_INT, ®s, ®s);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -