mirror of
https://git.code.sf.net/p/quake/quakeforge-old
synced 2024-11-22 11:51:17 +00:00
886 lines
18 KiB
C
886 lines
18 KiB
C
/*
|
|
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();
|
|
}
|