0,0 → 1,886 |
/* |
Copyright (C) 1996-1997 Id Software, Inc. |
|
This program is free software; you can redistribute it and/or |
modify it under the terms of the GNU General Public License |
as published by the Free Software Foundation; either version 2 |
of the License, or (at your option) any later version. |
|
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
|
See the GNU General Public License for more details. |
|
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
|
*/ |
// Quake is a trademark of Id Software, Inc., (c) 1996 Id Software, Inc. All |
// rights reserved. |
|
#include <dpmi.h> |
#include "quakedef.h" |
#include "dosisms.h" |
|
extern cvar_t bgmvolume; |
|
#define ADDRESS_MODE_HSG 0 |
#define ADDRESS_MODE_RED_BOOK 1 |
|
#define STATUS_ERROR_BIT 0x8000 |
#define STATUS_BUSY_BIT 0x0200 |
#define STATUS_DONE_BIT 0x0100 |
#define STATUS_ERROR_MASK 0x00ff |
|
#define ERROR_WRITE_PROTECT 0 |
#define ERROR_UNKNOWN_UNIT 1 |
#define ERROR_DRIVE_NOT_READY 2 |
#define ERROR_UNKNOWN_COMMAND 3 |
#define ERROR_CRC_ERROR 4 |
#define ERROR_BAD_REQUEST_LEN 5 |
#define ERROR_SEEK_ERROR 6 |
#define ERROR_UNKNOWN_MEDIA 7 |
#define ERROR_SECTOR_NOT_FOUND 8 |
#define ERROR_OUT_OF_PAPER 9 |
#define ERROR_WRITE_FAULT 10 |
#define ERROR_READ_FAULT 11 |
#define ERROR_GENERAL_FAILURE 12 |
#define ERROR_RESERVED_13 13 |
#define ERROR_RESERVED_14 14 |
#define ERROR_BAD_DISK_CHANGE 15 |
|
#define COMMAND_READ 3 |
#define COMMAND_WRITE 12 |
#define COMMAND_PLAY_AUDIO 132 |
#define COMMAND_STOP_AUDIO 133 |
#define COMMAND_RESUME_AUDIO 136 |
|
#define READ_REQUEST_AUDIO_CHANNEL_INFO 4 |
#define READ_REQUEST_DEVICE_STATUS 6 |
#define READ_REQUEST_MEDIA_CHANGE 9 |
#define READ_REQUEST_AUDIO_DISK_INFO 10 |
#define READ_REQUEST_AUDIO_TRACK_INFO 11 |
#define READ_REQUEST_AUDIO_STATUS 15 |
|
#define WRITE_REQUEST_EJECT 0 |
#define WRITE_REQUEST_RESET 2 |
#define WRITE_REQUEST_AUDIO_CHANNEL_INFO 3 |
|
#define STATUS_DOOR_OPEN 0x00000001 |
#define STATUS_DOOR_UNLOCKED 0x00000002 |
#define STATUS_RAW_SUPPORT 0x00000004 |
#define STATUS_READ_WRITE 0x00000008 |
#define STATUS_AUDIO_SUPPORT 0x00000010 |
#define STATUS_INTERLEAVE_SUPPORT 0x00000020 |
#define STATUS_BIT_6_RESERVED 0x00000040 |
#define STATUS_PREFETCH_SUPPORT 0x00000080 |
#define STATUS_AUDIO_MANIPLUATION_SUPPORT 0x00000100 |
#define STATUS_RED_BOOK_ADDRESS_SUPPORT 0x00000200 |
|
#define MEDIA_NOT_CHANGED 1 |
#define MEDIA_STATUS_UNKNOWN 0 |
#define MEDIA_CHANGED -1 |
|
#define AUDIO_CONTROL_MASK 0xd0 |
#define AUDIO_CONTROL_DATA_TRACK 0x40 |
#define AUDIO_CONTROL_AUDIO_2_TRACK 0x00 |
#define AUDIO_CONTROL_AUDIO_2P_TRACK 0x10 |
#define AUDIO_CONTROL_AUDIO_4_TRACK 0x80 |
#define AUDIO_CONTROL_AUDIO_4P_TRACK 0x90 |
|
#define AUDIO_STATUS_PAUSED 0x0001 |
|
#pragma pack(1) |
|
struct playAudioRequest |
{ |
char addressingMode; |
int startLocation; |
int sectors; |
}; |
|
struct readRequest |
{ |
char mediaDescriptor; |
short bufferOffset; |
short bufferSegment; |
short length; |
short startSector; |
int volumeID; |
}; |
|
struct writeRequest |
{ |
char mediaDescriptor; |
short bufferOffset; |
short bufferSegment; |
short length; |
short startSector; |
int volumeID; |
}; |
|
struct cd_request |
{ |
char headerLength; |
char unit; |
char command; |
short status; |
char reserved[8]; |
union |
{ |
struct playAudioRequest playAudio; |
struct readRequest read; |
struct writeRequest write; |
} x; |
}; |
|
|
struct audioChannelInfo_s |
{ |
char code; |
char channel0input; |
char channel0volume; |
char channel1input; |
char channel1volume; |
char channel2input; |
char channel2volume; |
char channel3input; |
char channel3volume; |
}; |
|
struct deviceStatus_s |
{ |
char code; |
int status; |
}; |
|
struct mediaChange_s |
{ |
char code; |
char status; |
}; |
|
struct audioDiskInfo_s |
{ |
char code; |
char lowTrack; |
char highTrack; |
int leadOutStart; |
}; |
|
struct audioTrackInfo_s |
{ |
char code; |
char track; |
int start; |
char control; |
}; |
|
struct audioStatus_s |
{ |
char code; |
short status; |
int PRstartLocation; |
int PRendLocation; |
}; |
|
struct reset_s |
{ |
char code; |
}; |
|
union readInfo_u |
{ |
struct audioChannelInfo_s audioChannelInfo; |
struct deviceStatus_s deviceStatus; |
struct mediaChange_s mediaChange; |
struct audioDiskInfo_s audioDiskInfo; |
struct audioTrackInfo_s audioTrackInfo; |
struct audioStatus_s audioStatus; |
struct reset_s reset; |
}; |
|
#pragma pack() |
|
#define MAXIMUM_TRACKS 100 |
|
typedef struct |
{ |
int start; |
int length; |
qboolean isData; |
} track_info; |
|
typedef struct |
{ |
qboolean valid; |
int leadOutAddress; |
track_info track[MAXIMUM_TRACKS]; |
byte lowTrack; |
byte highTrack; |
} cd_info; |
|
static struct cd_request *cdRequest; |
static union readInfo_u *readInfo; |
static cd_info cd; |
|
static qboolean playing = false; |
static qboolean wasPlaying = false; |
static qboolean mediaCheck = false; |
static qboolean initialized = false; |
static qboolean enabled = true; |
static qboolean playLooping = false; |
static short cdRequestSegment; |
static short cdRequestOffset; |
static short readInfoSegment; |
static short readInfoOffset; |
static byte remap[256]; |
static byte cdrom; |
static byte playTrack; |
static byte cdvolume; |
|
|
static int RedBookToSector(int rb) |
{ |
byte minute; |
byte second; |
byte frame; |
|
minute = (rb >> 16) & 0xff; |
second = (rb >> 8) & 0xff; |
frame = rb & 0xff; |
return minute * 60 * 75 + second * 75 + frame; |
} |
|
|
static void CDAudio_Reset(void) |
{ |
cdRequest->headerLength = 13; |
cdRequest->unit = 0; |
cdRequest->command = COMMAND_WRITE; |
cdRequest->status = 0; |
|
cdRequest->x.write.mediaDescriptor = 0; |
cdRequest->x.write.bufferOffset = readInfoOffset; |
cdRequest->x.write.bufferSegment = readInfoSegment; |
cdRequest->x.write.length = sizeof(struct reset_s); |
cdRequest->x.write.startSector = 0; |
cdRequest->x.write.volumeID = 0; |
|
readInfo->reset.code = WRITE_REQUEST_RESET; |
|
regs.x.ax = 0x1510; |
regs.x.cx = cdrom; |
regs.x.es = cdRequestSegment; |
regs.x.bx = cdRequestOffset; |
dos_int86 (0x2f); |
} |
|
|
static void CDAudio_Eject(void) |
{ |
cdRequest->headerLength = 13; |
cdRequest->unit = 0; |
cdRequest->command = COMMAND_WRITE; |
cdRequest->status = 0; |
|
cdRequest->x.write.mediaDescriptor = 0; |
cdRequest->x.write.bufferOffset = readInfoOffset; |
cdRequest->x.write.bufferSegment = readInfoSegment; |
cdRequest->x.write.length = sizeof(struct reset_s); |
cdRequest->x.write.startSector = 0; |
cdRequest->x.write.volumeID = 0; |
|
readInfo->reset.code = WRITE_REQUEST_EJECT; |
|
regs.x.ax = 0x1510; |
regs.x.cx = cdrom; |
regs.x.es = cdRequestSegment; |
regs.x.bx = cdRequestOffset; |
dos_int86 (0x2f); |
} |
|
|
static int CDAudio_GetAudioTrackInfo(byte track, int *start) |
{ |
byte control; |
|
cdRequest->headerLength = 13; |
cdRequest->unit = 0; |
cdRequest->command = COMMAND_READ; |
cdRequest->status = 0; |
|
cdRequest->x.read.mediaDescriptor = 0; |
cdRequest->x.read.bufferOffset = readInfoOffset; |
cdRequest->x.read.bufferSegment = readInfoSegment; |
cdRequest->x.read.length = sizeof(struct audioTrackInfo_s); |
cdRequest->x.read.startSector = 0; |
cdRequest->x.read.volumeID = 0; |
|
readInfo->audioTrackInfo.code = READ_REQUEST_AUDIO_TRACK_INFO; |
readInfo->audioTrackInfo.track = track; |
|
regs.x.ax = 0x1510; |
regs.x.cx = cdrom; |
regs.x.es = cdRequestSegment; |
regs.x.bx = cdRequestOffset; |
dos_int86 (0x2f); |
|
if (cdRequest->status & STATUS_ERROR_BIT) |
{ |
Con_DPrintf("CDAudio_GetAudioTrackInfo %04x\n", cdRequest->status & 0xffff); |
return -1; |
} |
|
*start = readInfo->audioTrackInfo.start; |
control = readInfo->audioTrackInfo.control & AUDIO_CONTROL_MASK; |
return (control & AUDIO_CONTROL_DATA_TRACK); |
} |
|
|
static int CDAudio_GetAudioDiskInfo(void) |
{ |
int n; |
|
cdRequest->headerLength = 13; |
cdRequest->unit = 0; |
cdRequest->command = COMMAND_READ; |
cdRequest->status = 0; |
|
cdRequest->x.read.mediaDescriptor = 0; |
cdRequest->x.read.bufferOffset = readInfoOffset; |
cdRequest->x.read.bufferSegment = readInfoSegment; |
cdRequest->x.read.length = sizeof(struct audioDiskInfo_s); |
cdRequest->x.read.startSector = 0; |
cdRequest->x.read.volumeID = 0; |
|
readInfo->audioDiskInfo.code = READ_REQUEST_AUDIO_DISK_INFO; |
|
regs.x.ax = 0x1510; |
regs.x.cx = cdrom; |
regs.x.es = cdRequestSegment; |
regs.x.bx = cdRequestOffset; |
dos_int86 (0x2f); |
|
if (cdRequest->status & STATUS_ERROR_BIT) |
{ |
Con_DPrintf("CDAudio_GetAudioDiskInfo %04x\n", cdRequest->status & 0xffff); |
return -1; |
} |
|
cd.valid = true; |
cd.lowTrack = readInfo->audioDiskInfo.lowTrack; |
cd.highTrack = readInfo->audioDiskInfo.highTrack; |
cd.leadOutAddress = readInfo->audioDiskInfo.leadOutStart; |
|
for (n = cd.lowTrack; n <= cd.highTrack; n++) |
{ |
cd.track[n].isData = CDAudio_GetAudioTrackInfo (n, &cd.track[n].start); |
if (n > cd.lowTrack) |
{ |
cd.track[n-1].length = RedBookToSector(cd.track[n].start) - RedBookToSector(cd.track[n-1].start); |
if (n == cd.highTrack) |
cd.track[n].length = RedBookToSector(cd.leadOutAddress) - RedBookToSector(cd.track[n].start); |
} |
} |
|
return 0; |
} |
|
|
static int CDAudio_GetAudioStatus(void) |
{ |
cdRequest->headerLength = 13; |
cdRequest->unit = 0; |
cdRequest->command = COMMAND_READ; |
cdRequest->status = 0; |
|
cdRequest->x.read.mediaDescriptor = 0; |
cdRequest->x.read.bufferOffset = readInfoOffset; |
cdRequest->x.read.bufferSegment = readInfoSegment; |
cdRequest->x.read.length = sizeof(struct audioStatus_s); |
cdRequest->x.read.startSector = 0; |
cdRequest->x.read.volumeID = 0; |
|
readInfo->audioDiskInfo.code = READ_REQUEST_AUDIO_STATUS; |
|
regs.x.ax = 0x1510; |
regs.x.cx = cdrom; |
regs.x.es = cdRequestSegment; |
regs.x.bx = cdRequestOffset; |
dos_int86 (0x2f); |
|
if (cdRequest->status & STATUS_ERROR_BIT) |
return -1; |
return 0; |
} |
|
|
static int CDAudio_MediaChange(void) |
{ |
cdRequest->headerLength = 13; |
cdRequest->unit = 0; |
cdRequest->command = COMMAND_READ; |
cdRequest->status = 0; |
|
cdRequest->x.read.mediaDescriptor = 0; |
cdRequest->x.read.bufferOffset = readInfoOffset; |
cdRequest->x.read.bufferSegment = readInfoSegment; |
cdRequest->x.read.length = sizeof(struct mediaChange_s); |
cdRequest->x.read.startSector = 0; |
cdRequest->x.read.volumeID = 0; |
|
readInfo->mediaChange.code = READ_REQUEST_MEDIA_CHANGE; |
|
regs.x.ax = 0x1510; |
regs.x.cx = cdrom; |
regs.x.es = cdRequestSegment; |
regs.x.bx = cdRequestOffset; |
dos_int86 (0x2f); |
|
return readInfo->mediaChange.status; |
} |
|
|
// we set the volume to 0 first and then to the desired volume |
// some cd-rom drivers seem to need it done this way |
void CDAudio_SetVolume (byte volume) |
{ |
if (!initialized || !enabled) |
return; |
|
cdRequest->headerLength = 13; |
cdRequest->unit = 0; |
cdRequest->command = COMMAND_WRITE; |
cdRequest->status = 0; |
|
cdRequest->x.read.mediaDescriptor = 0; |
cdRequest->x.read.bufferOffset = readInfoOffset; |
cdRequest->x.read.bufferSegment = readInfoSegment; |
cdRequest->x.read.length = sizeof(struct audioChannelInfo_s); |
cdRequest->x.read.startSector = 0; |
cdRequest->x.read.volumeID = 0; |
|
readInfo->audioChannelInfo.code = WRITE_REQUEST_AUDIO_CHANNEL_INFO; |
readInfo->audioChannelInfo.channel0input = 0; |
readInfo->audioChannelInfo.channel0volume = 0; |
readInfo->audioChannelInfo.channel1input = 1; |
readInfo->audioChannelInfo.channel1volume = 0; |
readInfo->audioChannelInfo.channel2input = 2; |
readInfo->audioChannelInfo.channel2volume = 0; |
readInfo->audioChannelInfo.channel3input = 3; |
readInfo->audioChannelInfo.channel3volume = 0; |
|
regs.x.ax = 0x1510; |
regs.x.cx = cdrom; |
regs.x.es = cdRequestSegment; |
regs.x.bx = cdRequestOffset; |
dos_int86 (0x2f); |
|
readInfo->audioChannelInfo.channel0volume = volume; |
readInfo->audioChannelInfo.channel1volume = volume; |
|
regs.x.ax = 0x1510; |
regs.x.cx = cdrom; |
regs.x.es = cdRequestSegment; |
regs.x.bx = cdRequestOffset; |
dos_int86 (0x2f); |
|
cdvolume = volume; |
} |
|
|
void CDAudio_Play(byte track, qboolean looping) |
{ |
int volume; |
|
if (!initialized || !enabled) |
return; |
|
if (!cd.valid) |
return; |
|
track = remap[track]; |
|
if (playing) |
{ |
if (playTrack == track) |
return; |
CDAudio_Stop(); |
} |
|
playLooping = looping; |
|
if (track < cd.lowTrack || track > cd.highTrack) |
{ |
Con_DPrintf("CDAudio_Play: Bad track number %u.\n", track); |
return; |
} |
|
playTrack = track; |
|
if (cd.track[track].isData) |
{ |
Con_DPrintf("CDAudio_Play: Can not play data.\n"); |
return; |
} |
|
volume = (int)(bgmvolume.value * 255.0); |
if (volume < 0) |
{ |
Cvar_SetValue ("bgmvolume", 0.0); |
volume = 0; |
} |
else if (volume > 255) |
{ |
Cvar_SetValue ("bgmvolume", 1.0); |
volume = 255; |
} |
CDAudio_SetVolume (volume); |
|
cdRequest->headerLength = 13; |
cdRequest->unit = 0; |
cdRequest->command = COMMAND_PLAY_AUDIO; |
cdRequest->status = 0; |
|
cdRequest->x.playAudio.addressingMode = ADDRESS_MODE_RED_BOOK; |
cdRequest->x.playAudio.startLocation = cd.track[track].start; |
cdRequest->x.playAudio.sectors = cd.track[track].length; |
|
regs.x.ax = 0x1510; |
regs.x.cx = cdrom; |
regs.x.es = cdRequestSegment; |
regs.x.bx = cdRequestOffset; |
dos_int86 (0x2f); |
|
if (cdRequest->status & STATUS_ERROR_BIT) |
{ |
Con_DPrintf("CDAudio_Play: track %u failed\n", track); |
cd.valid = false; |
playing = false; |
return; |
} |
|
playing = true; |
} |
|
|
void CDAudio_Stop(void) |
{ |
if (!initialized || !enabled) |
return; |
|
cdRequest->headerLength = 13; |
cdRequest->unit = 0; |
cdRequest->command = COMMAND_STOP_AUDIO; |
cdRequest->status = 0; |
|
regs.x.ax = 0x1510; |
regs.x.cx = cdrom; |
regs.x.es = cdRequestSegment; |
regs.x.bx = cdRequestOffset; |
dos_int86 (0x2f); |
|
wasPlaying = playing; |
playing = false; |
} |
|
|
void CDAudio_Pause(void) |
{ |
CDAudio_Stop(); |
} |
|
|
void CDAudio_Resume(void) |
{ |
if (!initialized || !enabled) |
return; |
|
if (!cd.valid) |
return; |
|
if (!wasPlaying) |
return; |
|
cdRequest->headerLength = 13; |
cdRequest->unit = 0; |
cdRequest->command = COMMAND_RESUME_AUDIO; |
cdRequest->status = 0; |
|
regs.x.ax = 0x1510; |
regs.x.cx = cdrom; |
regs.x.es = cdRequestSegment; |
regs.x.bx = cdRequestOffset; |
dos_int86 (0x2f); |
|
playing = true; |
} |
|
|
static void CD_f (void) |
{ |
char *command; |
int ret; |
int n; |
int startAddress; |
|
if (Cmd_Argc() < 2) |
return; |
|
command = Cmd_Argv (1); |
|
if (Q_strcasecmp(command, "on") == 0) |
{ |
enabled = true; |
return; |
} |
|
if (Q_strcasecmp(command, "off") == 0) |
{ |
if (playing) |
CDAudio_Stop(); |
enabled = false; |
return; |
} |
|
if (Q_strcasecmp(command, "reset") == 0) |
{ |
enabled = true; |
if (playing) |
CDAudio_Stop(); |
for (n = 0; n < 256; n++) |
remap[n] = n; |
CDAudio_Reset(); |
CDAudio_GetAudioDiskInfo(); |
return; |
} |
|
if (Q_strcasecmp(command, "remap") == 0) |
{ |
ret = Cmd_Argc() - 2; |
if (ret <= 0) |
{ |
for (n = 1; n < 256; n++) |
if (remap[n] != n) |
Con_Printf(" %u -> %u\n", n, remap[n]); |
return; |
} |
for (n = 1; n <= ret; n++) |
remap[n] = Q_atoi(Cmd_Argv (n+1)); |
return; |
} |
|
if (!cd.valid) |
{ |
Con_Printf("No CD in player.\n"); |
return; |
} |
|
if (Q_strcasecmp(command, "play") == 0) |
{ |
CDAudio_Play(Q_atoi(Cmd_Argv (2)), false); |
return; |
} |
|
if (Q_strcasecmp(command, "loop") == 0) |
{ |
CDAudio_Play(Q_atoi(Cmd_Argv (2)), true); |
return; |
} |
|
if (Q_strcasecmp(command, "stop") == 0) |
{ |
CDAudio_Stop(); |
return; |
} |
|
if (Q_strcasecmp(command, "pause") == 0) |
{ |
CDAudio_Pause(); |
return; |
} |
|
if (Q_strcasecmp(command, "resume") == 0) |
{ |
CDAudio_Resume(); |
return; |
} |
|
if (Q_strcasecmp(command, "eject") == 0) |
{ |
if (playing) |
CDAudio_Stop(); |
CDAudio_Eject(); |
cd.valid = false; |
return; |
} |
|
if (Q_strcasecmp(command, "info") == 0) |
{ |
Con_Printf("%u tracks\n", cd.highTrack - cd.lowTrack + 1); |
for (n = cd.lowTrack; n <= cd.highTrack; n++) |
{ |
ret = CDAudio_GetAudioTrackInfo (n, &startAddress); |
Con_Printf("Track %2u: %s at %2u:%02u\n", n, ret ? "data " : "music", (startAddress >> 16) & 0xff, (startAddress >> 8) & 0xff); |
} |
if (playing) |
Con_Printf("Currently %s track %u\n", playLooping ? "looping" : "playing", playTrack); |
Con_Printf("Volume is %u\n", cdvolume); |
CDAudio_MediaChange(); |
Con_Printf("Status %04x\n", cdRequest->status & 0xffff); |
return; |
} |
} |
|
|
void CDAudio_Update(void) |
{ |
int ret; |
int newVolume; |
static double lastUpdate; |
|
if (!initialized || !enabled) |
return; |
|
if ((realtime - lastUpdate) < 0.25) |
return; |
lastUpdate = realtime; |
|
if (mediaCheck) |
{ |
static double lastCheck; |
|
if ((realtime - lastCheck) < 5.0) |
return; |
lastCheck = realtime; |
|
ret = CDAudio_MediaChange(); |
if (ret == MEDIA_CHANGED) |
{ |
Con_DPrintf("CDAudio: media changed\n"); |
playing = false; |
wasPlaying = false; |
cd.valid = false; |
CDAudio_GetAudioDiskInfo(); |
return; |
} |
} |
|
newVolume = (int)(bgmvolume.value * 255.0); |
if (newVolume != cdvolume) |
{ |
if (newVolume < 0) |
{ |
Cvar_SetValue ("bgmvolume", 0.0); |
newVolume = 0; |
} |
else if (newVolume > 255) |
{ |
Cvar_SetValue ("bgmvolume", 1.0); |
newVolume = 255; |
} |
CDAudio_SetVolume (newVolume); |
} |
|
if (playing) |
{ |
CDAudio_GetAudioStatus(); |
if ((cdRequest->status & STATUS_BUSY_BIT) == 0) |
{ |
playing = false; |
if (playLooping) |
CDAudio_Play(playTrack, true); |
} |
} |
} |
|
|
int CDAudio_Init(void) |
{ |
char *memory; |
int n; |
|
if (cls.state == ca_dedicated) |
return -1; |
|
if (COM_CheckParm("-nocdaudio")) |
return -1; |
|
if (COM_CheckParm("-cdmediacheck")) |
mediaCheck = true; |
|
regs.x.ax = 0x1500; |
regs.x.bx = 0; |
dos_int86 (0x2f); |
if (regs.x.bx == 0) |
{ |
Con_NotifyBox ( |
"MSCDEX not loaded, music is\n" |
"disabled. Use \"-nocdaudio\" if you\n" |
"wish to avoid this message in the\n" |
"future. See README.TXT for help.\n" |
); |
return -1; |
} |
if (regs.x.bx > 1) |
Con_DPrintf("CDAudio_Init: First CD-ROM drive will be used\n"); |
cdrom = regs.x.cx; |
|
regs.x.ax = 0x150c; |
regs.x.bx = 0; |
dos_int86 (0x2f); |
if (regs.x.bx == 0) |
{ |
Con_NotifyBox ( |
"MSCDEX version 2.00 or later\n" |
"required for music. See README.TXT\n" |
"for help.\n" |
); |
Con_DPrintf("CDAudio_Init: MSCDEX version 2.00 or later required.\n"); |
return -1; |
} |
|
memory = dos_getmemory(sizeof(struct cd_request |
) + sizeof(union readInfo_u)); |
if (memory == NULL) |
{ |
Con_DPrintf("CDAudio_Init: Unable to allocate low memory.\n"); |
return -1; |
} |
|
cdRequest = (struct cd_request *)memory; |
cdRequestSegment = ptr2real(cdRequest) >> 4; |
cdRequestOffset = ptr2real(cdRequest) & 0xf; |
|
readInfo = (union readInfo_u *)(memory + sizeof(struct cd_request)); |
readInfoSegment = ptr2real(readInfo) >> 4; |
readInfoOffset = ptr2real(readInfo) & 0xf; |
|
for (n = 0; n < 256; n++) |
remap[n] = n; |
initialized = true; |
|
CDAudio_SetVolume (255); |
if (CDAudio_GetAudioDiskInfo()) |
{ |
Con_Printf("CDAudio_Init: No CD in player.\n"); |
enabled = false; |
} |
|
Cmd_AddCommand ("cd", CD_f); |
|
Con_Printf("CD Audio Initialized\n"); |
|
return 0; |
} |
|
|
void CDAudio_Shutdown(void) |
{ |
if (!initialized) |
return; |
CDAudio_Stop(); |
} |