/* | |
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(); | |
} |