From a8f828a066773a59fdf646299359d35ae0e845af Mon Sep 17 00:00:00 2001 From: wyatt8740 Date: Mon, 6 Jan 2014 12:02:16 -0500 Subject: Removed accidental upload of copyrighted map files --- WinQuake/cd_audio.c | 1772 +++++++++++++++++++++++++-------------------------- 1 file changed, 886 insertions(+), 886 deletions(-) (limited to 'WinQuake/cd_audio.c') diff --git a/WinQuake/cd_audio.c b/WinQuake/cd_audio.c index 0393422..8b15de7 100644 --- a/WinQuake/cd_audio.c +++ b/WinQuake/cd_audio.c @@ -1,886 +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 -#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(); -} +/* +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 +#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(); +} -- cgit v1.2.3