⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cd.c

📁 game duke3d source
💻 C
📖 第 1 页 / 共 2 页
字号:
//-------------------------------------------------------------------------
/*
Copyright (C) 1996, 2003 - 3D Realms Entertainment

This file is NOT part of Duke Nukem 3D version 1.5 - Atomic EditionHowever, it is either an older version of a file that is, or issome test code written during the development of Duke Nukem 3D.This file is provided purely for educational interest.Duke Nukem 3D 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.

Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms
*/
//-------------------------------------------------------------------------

#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			32

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);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -