summaryrefslogtreecommitdiff
path: root/src/hexen/i_cdmus.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/hexen/i_cdmus.c')
-rw-r--r--src/hexen/i_cdmus.c1023
1 files changed, 1023 insertions, 0 deletions
diff --git a/src/hexen/i_cdmus.c b/src/hexen/i_cdmus.c
new file mode 100644
index 00000000..dc2e91bc
--- /dev/null
+++ b/src/hexen/i_cdmus.c
@@ -0,0 +1,1023 @@
+
+//**************************************************************************
+//**
+//** i_cdmus.c
+//**
+//**************************************************************************
+
+// HEADER FILES ------------------------------------------------------------
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <dos.h>
+#include <stddef.h>
+#include <string.h>
+#include "h2def.h"
+#include "i_sound.h"
+
+// MACROS ------------------------------------------------------------------
+
+#define MAX_AUDIO_TRACKS 25
+#define MULTIPLEX_INT 0x2f
+#define CDROM_GETDRIVECOUNT 0x1500
+#define CDROM_SENDDEVICEREQ 0x1510
+#define CDROM_GETVERSION 0x150c
+#define HSG_MODE 0
+#define RED_MODE 1
+#define DRC_IOCTLINPUT 0x03
+#define DRC_IOCTLOUTPUT 0x0c
+#define DRC_PLAYAUDIO 0x84
+#define DRC_STOPAUDIO 0x85
+#define DRC_RESUMEAUDIO 0x88
+
+#define DPMI_INT 0x31
+#define DPMI_ALLOCREALMEM 0x0100
+#define DPMI_FREEREALMEM 0x0101
+#define DPMI_SIMREALINT 0x0300
+
+// IOCTL input commands
+
+#define ADRDEVHEAD 0 // Return Address of Device Header
+#define HEADLOCATION 1 // Location of Head
+#define RESERVED 2 // Reserved
+#define ERRSTATISTICS 3 // Error Statistics
+#define AUDIOCHANINFO 4 // Audio Channel Info
+#define READDRVBYTES 5 // Read Drive Bytes
+#define DEVICESTATUS 6 // Device Status
+#define GETSECTORSIZE 7 // Return Sector Size
+#define GETVOLSIZE 8 // Return Volume Size
+#define MEDIACHANGED 9 // Media Changed
+#define AUDIODISKINFO 10 // Audio Disk Info
+#define AUDIOTRACKINFO 11 // Audio Track Info
+#define AUDIOQCHANINFO 12 // Audio Q-Channel Info
+#define AUDIOSUBINFO 13 // Audio Sub-Channel Info
+#define UPCCODE 14 // UPC Code
+#define AUDIOSTATUSINFO 15 // Audio Status Info
+
+// IOCTL output commands
+
+#define EJECTDISK 0 // Eject Disk
+#define DOORLOCK 1 // Lock/Unlock Door
+#define RESETDRIVE 2 // Reset Drive
+#define AUDIOCHANCONTROL 3 // Audio Channel Control
+#define WRITEDEVCONTROL 4 // Write Device Control String
+#define CLOSETRAY 5 // Close Tray
+
+// TYPES -------------------------------------------------------------------
+
+typedef signed char S_BYTE;
+typedef unsigned char U_BYTE;
+typedef signed short S_WORD;
+typedef unsigned short U_WORD;
+typedef signed int S_LONG;
+typedef unsigned int U_LONG;
+
+typedef struct {
+ U_LONG size;
+ void **address;
+ U_WORD *segment;
+ U_WORD *selector;
+} DOSChunk_t;
+
+typedef struct {
+ U_LONG edi;
+ U_LONG esi;
+ U_LONG ebp;
+ U_LONG reserved;
+ U_LONG ebx;
+ U_LONG edx;
+ U_LONG ecx;
+ U_LONG eax;
+ U_WORD flags;
+ U_WORD es;
+ U_WORD ds;
+ U_WORD fs;
+ U_WORD gs;
+ U_WORD ip;
+ U_WORD cs;
+ U_WORD sp;
+ U_WORD ss;
+} RegBlock_t;
+
+typedef struct {
+ short lengthMin;
+ short lengthSec;
+ int redStart;
+ int sectorStart;
+ int sectorLength;
+} AudioTrack_t;
+
+// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
+
+// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
+
+// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
+
+static U_WORD InputIOCTL(S_WORD request, U_LONG pctrlblk);
+static U_WORD OutputIOCTL(S_WORD request, U_LONG pctrlblk);
+static U_LONG RedToSectors(U_LONG red);
+static int AllocIOCTLBuffers(void);
+static void DPMI_SimRealInt(U_LONG intr, RegBlock_t *rBlock);
+static void *DPMI_AllocRealMem(U_LONG size, U_WORD *segment,
+ U_WORD *selector);
+static void DPMI_FreeRealMem(U_WORD selector);
+
+// EXTERNAL DATA DECLARATIONS ----------------------------------------------
+
+// PUBLIC DATA DEFINITIONS -------------------------------------------------
+
+int cd_Error;
+
+// PRIVATE DATA DEFINITIONS ------------------------------------------------
+
+static int cd_DriveCount;
+static int cd_FirstDrive;
+static int cd_CurDrive;
+static U_WORD cd_Version;
+static int cd_FirstTrack;
+static int cd_LastTrack;
+static int cd_TrackCount;
+static U_WORD cd_LeadOutMin;
+static U_WORD cd_LeadOutSec;
+static U_LONG cd_LeadOutRed;
+static U_LONG cd_LeadOutSector;
+static U_LONG cd_IOCTLBufferTotal;
+static AudioTrack_t cd_AudioTracks[MAX_AUDIO_TRACKS];
+
+static int OkInit = 0;
+
+static RegBlock_t RegBlock;
+
+static struct PlayReq_s { // CD-ROM Play Audio Device Request Struct
+ U_BYTE headerSize;
+ U_BYTE subUnitCode;
+ U_BYTE command; // = DRC_PLAYAUDIO
+ U_WORD status;
+ U_BYTE reserved[8];
+ U_BYTE addressMode;
+ U_LONG startSector;
+ U_LONG numberToRead;
+} *cd_PlayReq;
+static U_WORD cd_PlayReqSeg;
+static U_WORD cd_PlayReqSel;
+
+static struct StopReq_s { // CD-ROM Stop Audio Device Request Struct
+ U_BYTE headerSize;
+ U_BYTE subUnitCode;
+ U_BYTE command; // = DRC_STOPAUDIO
+ U_WORD status;
+ U_BYTE reserved[8];
+} *cd_StopReq;
+static U_WORD cd_StopReqSeg;
+static U_WORD cd_StopReqSel;
+
+static struct ResumeReq_s { // CD-ROM Resume Audio Device Request Struct
+ U_BYTE headerSize;
+ U_BYTE subUnitCode;
+ U_BYTE command; // = DRC_RESUMEAUDIO
+ U_WORD status;
+ U_BYTE reserved[8];
+} *cd_ResumeReq;
+static U_WORD cd_ResumeReqSeg;
+static U_WORD cd_ResumeReqSel;
+
+// IOCTL Input command data buffer structures
+
+static struct IOCTLIn_s { // IOCTL Input Struct
+ U_BYTE headerSize;
+ U_BYTE subUnitCode;
+ U_BYTE command; // = DRC_IOCTLINPUT
+ U_WORD status;
+ U_BYTE reserved[8];
+ U_BYTE mediaDescriptor;
+ U_LONG ctrlBlkAddr;
+ U_WORD tranSize;
+ U_WORD startSector;
+ U_LONG volPtr;
+} *cd_IOCTLIn;
+static U_WORD cd_IOCTLInSeg;
+static U_WORD cd_IOCTLInSel;
+
+static struct RAddrDevHead_s {
+ U_BYTE code; // ADRDEVHEAD
+ U_LONG devHdrAddr; // Address of device header
+} *cd_RAddrDevHead;
+static U_WORD cd_RAddrDevHeadSeg;
+static U_WORD cd_RAddrDevHeadSel;
+
+static struct LocHead_s {
+ U_BYTE code; // HEADLOCATION
+ U_BYTE addrMode; // Addressing mode
+ U_LONG headLocation; // Location of drive head
+} *cd_LocHead;
+static U_WORD cd_LocHeadSeg;
+static U_WORD cd_LocHeadSel;
+
+static struct ErrStat_s {
+ U_BYTE code; // ERRSTATISTICS
+ U_BYTE errVal; // Error statistics
+} *cd_ErrStat;
+static U_WORD cd_ErrStatSeg;
+static U_WORD cd_ErrStatSel;
+
+static struct AudChanInfo_s {
+ U_BYTE code; // AUDIOCHANINFO
+ U_BYTE inChanOut0; // Input chan(0,1,2,or 3) for output chan 0
+ U_BYTE volumeOut0; // Volume control (0-0xff) for output chan 0
+ U_BYTE inChanOut1; // Input chan(0,1,2,or 3) for output chan 1
+ U_BYTE volumeOut1; // Volume control (0-0xff) for output chan 1
+ U_BYTE inChanOut2; // Input chan(0,1,2,or 3) for output chan 2
+ U_BYTE volumeOut2; // Volume control (0-0xff) for output chan 2
+ U_BYTE inChanOut3; // Input chan(0,1,2,or 3) for output chan 3
+ U_BYTE volumeOut3; // Volume control (0-0xff) for output chan 3
+} *cd_AudChanInfo;
+static U_WORD cd_AudChanInfoSeg;
+static U_WORD cd_AudChanInfoSel;
+
+static struct RDrvBytes_s {
+ U_BYTE code; // READDRVBYTES
+ U_BYTE numBytes; // Number of bytes to read
+ U_BYTE rBuffer[128]; // Read buffer
+} *cd_RDrvBytes;
+static U_WORD cd_RDrvBytesSeg;
+static U_WORD cd_RDrvBytesSel;
+
+static struct DevStat_s {
+ U_BYTE code; // DEVICESTATUS
+ U_LONG devParams; // Device parameters
+} *cd_DevStat;
+static U_WORD cd_DevStatSeg;
+static U_WORD cd_DevStatSel;
+
+static struct SectSize_s {
+ U_BYTE code; // GETSECTORSIZE
+ U_BYTE readMode; // Read mode
+ U_WORD sectorSize; // Sector size
+} *cd_SectSize;
+static U_WORD cd_SectSizeSeg;
+static U_WORD cd_SectSizeSel;
+
+static struct VolSize_s {
+ U_BYTE code; // GETVOLSIZE
+ U_LONG volumeSize; // Volume size
+} *cd_VolSize;
+static U_WORD cd_VolSizeSeg;
+static U_WORD cd_VolSizeSel;
+
+static struct MedChng_s {
+ U_BYTE code; // MEDIACHANGED
+ U_BYTE changed; // Media byte
+} *cd_MedChng;
+static U_WORD cd_MedChngSeg;
+static U_WORD cd_MedChngSel;
+
+static struct DiskInfo_s {
+ U_BYTE code; // AUDIODISKINFO
+ U_BYTE lowTrack; // Lowest track number
+ U_BYTE highTrack; // Highest track number
+ U_LONG startLeadOut; // Starting point of the lead-out track
+} *cd_DiskInfo;
+static U_WORD cd_DiskInfoSeg;
+static U_WORD cd_DiskInfoSel;
+
+static struct TrackInfo_s {
+ U_BYTE code; // AUDIOTRACKINFO
+ U_BYTE track; // Track number
+ U_LONG start; // Starting point of the track
+ U_BYTE ctrlInfo; // Track control information
+} *cd_TrackInfo;
+static U_WORD cd_TrackInfoSeg;
+static U_WORD cd_TrackInfoSel;
+
+static struct QInfo_s {
+ U_BYTE code; // AUDIOQCHANINFO
+ U_BYTE control; // CONTROL and ADR byte
+ U_BYTE tno; // Track number (TNO)
+ U_BYTE index; // (POINT) or Index(X)
+ U_BYTE min; // (MIN) Running time within a track
+ U_BYTE sec; // (SEC) " " " " "
+ U_BYTE frame; // (FRAME) " " " " "
+ U_BYTE zero; // (ZERO) " " " " "
+ U_BYTE aMin; // (AMIN) or (PMIN) Running time on disk
+ U_BYTE aSec; // (ASEC) or (PSEC) " " " "
+ U_BYTE aFrame; // (AFRAME) or (PFRAME)" " " "
+} *cd_QInfo;
+static U_WORD cd_QInfoSeg;
+static U_WORD cd_QInfoSel;
+
+static struct SubChanInfo_s {
+ U_BYTE code; // AUDIOSUBINFO
+ U_LONG startSectAddr; // Starting sector address
+ U_LONG transAddr; // Transfer address
+ U_LONG numSects; // Number of sectors to read
+} *cd_SubChanInfo;
+static U_WORD cd_SubChanInfoSeg;
+static U_WORD cd_SubChanInfoSel;
+
+static struct UPCCode_s {
+ U_BYTE code; // UPCCODE
+ U_BYTE control; // CONTROL and ADR byte
+ U_BYTE upc[7]; // UPC/EAN code
+ U_BYTE zero; // Zero
+ U_BYTE aFrame; // Aframe
+} *cd_UPCCode;
+static U_WORD cd_UPCCodeSeg;
+static U_WORD cd_UPCCodeSel;
+
+static struct AudStat_s {
+ U_BYTE code; // AUDIOSTATUSINFO
+ U_WORD status; // Audio status bits
+ U_LONG startPlay; // Starting location of last Play/Resume
+ U_LONG endPlay; // Ending location for last Play/Resume
+} *cd_AudStat;
+static U_WORD cd_AudStatSeg;
+static U_WORD cd_AudStatSel;
+
+// IOCTL Output command data buffer structures
+
+static struct IOCTLOut_s { // IOCTL Output struct
+ U_BYTE headerSize;
+ U_BYTE subUnitCode;
+ U_BYTE command; // = DRC_IOCTLOUTPUT
+ U_WORD status;
+ U_BYTE reserved[8];
+ U_BYTE mediaDescriptor;
+ U_LONG ctrlBlkAddr;
+ U_WORD tranSize;
+ U_WORD startSector;
+ U_LONG volPtr;
+} *cd_IOCTLOut;
+static U_WORD cd_IOCTLOutSeg;
+static U_WORD cd_IOCTLOutSel;
+
+static struct Eject_s {
+ U_BYTE code; // EJECTDISK
+} *cd_Eject;
+static U_WORD cd_EjectSeg;
+static U_WORD cd_EjectSel;
+
+static struct LockDoor_s {
+ U_BYTE code; // DOORLOCK
+ U_BYTE lock; // Lock function : 0 = unlock, 1 = lock
+} *cd_LockDoor;
+static U_WORD cd_LockDoorSeg;
+static U_WORD cd_LockDoorSel;
+
+static struct ResetDrv_s {
+ U_BYTE code; // RESETDRIVE
+} *cd_ResetDrv;
+static U_WORD cd_ResetDrvSeg;
+static U_WORD cd_ResetDrvSel;
+
+static struct AudInfo_s {
+ U_BYTE code; // AUDIOCHANCONTROL
+ U_BYTE inChanOut0; // Input chan(0,1,2,or 3) for output chan 0
+ U_BYTE volumeOut0; // Volume control (0-0xff) for output chan 0
+ U_BYTE inChanOut1; // Input chan(0,1,2,or 3) for output chan 1
+ U_BYTE volumeOut1; // Volume control (0-0xff) for output chan 1
+ U_BYTE inChanOut2; // Input chan(0,1,2,or 3) for output chan 2
+ U_BYTE volumeOut2; // Volume control (0-0xff) for output chan 2
+ U_BYTE inChanOut3; // Input chan(0,1,2,or 3) for output chan 3
+ U_BYTE volumeOut3; // Volume control (0-0xff) for output chan 3
+} *cd_AudInfo;
+static U_WORD cd_AudInfoSeg;
+static U_WORD cd_AudInfoSel;
+
+static struct WDrvBytes_s {
+ U_BYTE code; // WRITEDEVCONTROL
+ U_BYTE buf[5]; // Write buffer - size ??
+} *cd_WDrvBytes;
+static U_WORD cd_WDrvBytesSeg;
+static U_WORD cd_WDrvBytesSel;
+
+static struct CloseTray_s {
+ U_BYTE code; // CLOSETRAY
+} *cd_CloseTray;
+static U_WORD cd_CloseTraySeg;
+static U_WORD cd_CloseTraySel;
+
+static U_WORD InCtrlBlkSize[16] = {
+ 0x05, 0x06, 0x00, 0x00,
+ 0x09, 0x82, 0x05, 0x04,
+ 0x05, 0x02, 0x07, 0x07,
+ 0x0b, 0x0d, 0x0b, 0x0b
+};
+
+static U_WORD OutCtrlBlkSize[6] = {
+ 0x01, 0x02,
+ 0x01, 0x09,
+ 0x06, 0x01
+};
+
+// Structures for allocating conventional memory
+
+static DOSChunk_t DOSChunks[] = {
+ {
+ sizeof(struct PlayReq_s),
+ &cd_PlayReq, &cd_PlayReqSeg, &cd_PlayReqSel
+ },
+ {
+ sizeof(struct StopReq_s),
+ &cd_StopReq, &cd_StopReqSeg, &cd_StopReqSel
+ },
+ {
+ sizeof(struct ResumeReq_s),
+ &cd_ResumeReq, &cd_ResumeReqSeg, &cd_ResumeReqSel
+ },
+ {
+ sizeof(struct IOCTLOut_s),
+ &cd_IOCTLOut, &cd_IOCTLOutSeg, &cd_IOCTLOutSel
+ },
+ {
+ sizeof(struct Eject_s),
+ &cd_Eject, &cd_EjectSeg, &cd_EjectSel
+ },
+ {
+ sizeof(struct LockDoor_s),
+ &cd_LockDoor, &cd_LockDoorSeg, &cd_LockDoorSel
+ },
+ {
+ sizeof(struct ResetDrv_s),
+ &cd_ResetDrv, &cd_ResetDrvSeg, &cd_ResetDrvSel
+ },
+ {
+ sizeof(struct AudInfo_s),
+ &cd_AudInfo, &cd_AudInfoSeg, &cd_AudInfoSel
+ },
+ {
+ sizeof(struct WDrvBytes_s),
+ &cd_WDrvBytes, &cd_WDrvBytesSeg, &cd_WDrvBytesSel
+ },
+ {
+ sizeof(struct CloseTray_s),
+ &cd_CloseTray, &cd_CloseTraySeg, &cd_CloseTraySel
+ },
+ {
+ sizeof(struct IOCTLIn_s),
+ &cd_IOCTLIn, &cd_IOCTLInSeg, &cd_IOCTLInSel
+ },
+ {
+ sizeof(struct RAddrDevHead_s),
+ &cd_RAddrDevHead, &cd_RAddrDevHeadSeg, &cd_RAddrDevHeadSel
+ },
+ {
+ sizeof(struct LocHead_s),
+ &cd_LocHead, &cd_LocHeadSeg, &cd_LocHeadSel
+ },
+ {
+ sizeof(struct ErrStat_s),
+ &cd_ErrStat, &cd_ErrStatSeg, &cd_ErrStatSel
+ },
+ {
+ sizeof(struct AudChanInfo_s),
+ &cd_AudChanInfo, &cd_AudChanInfoSeg, &cd_AudChanInfoSel
+ },
+ {
+ sizeof(struct RDrvBytes_s),
+ &cd_RDrvBytes, &cd_RDrvBytesSeg, &cd_RDrvBytesSel
+ },
+ {
+ sizeof(struct DevStat_s),
+ &cd_DevStat, &cd_DevStatSeg, &cd_DevStatSel
+ },
+ {
+ sizeof(struct SectSize_s),
+ &cd_SectSize, &cd_SectSizeSeg, &cd_SectSizeSel
+ },
+ {
+ sizeof(struct VolSize_s),
+ &cd_VolSize, &cd_VolSizeSeg, &cd_VolSizeSel
+ },
+ {
+ sizeof(struct MedChng_s),
+ &cd_MedChng, &cd_MedChngSeg, &cd_MedChngSel
+ },
+ {
+ sizeof(struct DiskInfo_s),
+ &cd_DiskInfo, &cd_DiskInfoSeg, &cd_DiskInfoSel
+ },
+ {
+ sizeof(struct TrackInfo_s),
+ &cd_TrackInfo, &cd_TrackInfoSeg, &cd_TrackInfoSel
+ },
+ {
+ sizeof(struct QInfo_s),
+ &cd_QInfo, &cd_QInfoSeg, &cd_QInfoSel
+ },
+ {
+ sizeof(struct SubChanInfo_s),
+ &cd_SubChanInfo, &cd_SubChanInfoSeg, &cd_SubChanInfoSel
+ },
+ {
+ sizeof(struct UPCCode_s),
+ &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, &regs, &regs, &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, &regs, &regs);
+}