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

📄 i_cdmus.c

📁 制作游戏 魔法师传奇 源代码设计 MOFASHICHUANQI 经典老游戏
💻 C
📖 第 1 页 / 共 2 页
字号:
		&cd_UPCCode, &cd_UPCCodeSeg, &cd_UPCCodeSel
	},
	{
		sizeof(struct AudStat_s),
		&cd_AudStat, &cd_AudStatSeg, &cd_AudStatSel
	},
	{
		0, NULL, NULL, NULL
	}
};

// CODE --------------------------------------------------------------------

//==========================================================================
//
// I_CDMusInit
//
// Initializes the CD audio system.  Must be called before using any
// other I_CDMus functions.
//
// Returns: 0 (ok) or -1 (error, in cd_Error).
//
//==========================================================================

int I_CDMusInit(void)
{
	int i;
	int sect;
	int maxTrack;
	S_BYTE startMin1 = 0;
	S_BYTE startSec1 = 0;
	S_BYTE startMin2 = 0;
	S_BYTE startSec2 = 0;
	S_BYTE lengthMin = 0;
	S_BYTE lengthSec = 0;

	if(OkInit != 1)
	{ // Only execute if uninitialized

		// Get number of CD-ROM drives and first drive
		memset(&RegBlock, 0, sizeof(RegBlock));
		RegBlock.eax = CDROM_GETDRIVECOUNT;
		RegBlock.ebx = 0;
		DPMI_SimRealInt(MULTIPLEX_INT, &RegBlock);
		cd_DriveCount = RegBlock.ebx;

		// MSCDEX not installed if number of drives = 0
		if(cd_DriveCount == 0)
		{
			cd_Error = CDERR_NOTINSTALLED;
			return -1;
		}
		cd_FirstDrive = RegBlock.ecx;
		cd_CurDrive = cd_FirstDrive;

		// Allocate the IOCTL buffers
		if(AllocIOCTLBuffers() == -1)
		{
			cd_Error = CDERR_IOCTLBUFFMEM;
			return -1;
		}

		// Get MSCDEX version
		// Major version in upper byte, minor version in lower byte
		memset(&RegBlock, 0, sizeof(RegBlock));
		RegBlock.eax = CDROM_GETVERSION;
		DPMI_SimRealInt(MULTIPLEX_INT, &RegBlock);
		cd_Version = RegBlock.ebx;

		// Check device status to make sure we can read Audio CD's
		InputIOCTL(DEVICESTATUS, cd_DevStatSeg);
		if((cd_DevStat->devParams & 0x0010) == 0)
		{
			cd_Error = CDERR_NOAUDIOSUPPORT;
			return -1;
		}
	}

	// Force audio to stop playing
	I_CDMusStop();

	// Make sure we have the current TOC
	InputIOCTL(MEDIACHANGED, cd_MedChngSeg);

	// Set track variables
	InputIOCTL(AUDIODISKINFO, cd_DiskInfoSeg);
	cd_FirstTrack = cd_DiskInfo->lowTrack;
	cd_LastTrack = cd_DiskInfo->highTrack;
	if(cd_FirstTrack == 0 && cd_FirstTrack == cd_LastTrack)
	{
		cd_Error = CDERR_NOAUDIOTRACKS;
		return -1;
	}
	cd_TrackCount = cd_LastTrack-cd_FirstTrack+1;
	cd_LeadOutMin = cd_DiskInfo->startLeadOut>>16 & 0xFF;
	cd_LeadOutSec = cd_DiskInfo->startLeadOut>>8 & 0xFF;
	cd_LeadOutRed = cd_DiskInfo->startLeadOut;
	cd_LeadOutSector = RedToSectors(cd_DiskInfo->startLeadOut);

	// Create Red Book start, sector start, and sector length
	// for all tracks
	sect = cd_LeadOutSector;
	for(i = cd_LastTrack; i >= cd_FirstTrack; i--)
	{
		cd_TrackInfo->track = i;
		InputIOCTL(AUDIOTRACKINFO, cd_TrackInfoSeg);
		if(i < MAX_AUDIO_TRACKS)
		{
			cd_AudioTracks[i].redStart = cd_TrackInfo->start;
			cd_AudioTracks[i].sectorStart =
				RedToSectors(cd_TrackInfo->start);
			cd_AudioTracks[i].sectorLength =
				sect-RedToSectors(cd_TrackInfo->start);
		}
		sect = RedToSectors(cd_TrackInfo->start);
	}

	// Create track lengths in minutes and seconds
	if(cd_LastTrack >= MAX_AUDIO_TRACKS)
	{
		maxTrack = MAX_AUDIO_TRACKS-1;
	}
	else
	{
		maxTrack = cd_LastTrack;
	}
	cd_TrackInfo->track = cd_FirstTrack;
	InputIOCTL(AUDIOTRACKINFO, cd_TrackInfoSeg);
	startMin1 = (cd_TrackInfo->start >> 16);
	startSec1 = (cd_TrackInfo->start >> 8);
	for(i = cd_FirstTrack; i <= maxTrack; i++)
	{
		cd_TrackInfo->track = i+1;
		if(i < cd_LastTrack)
		{
			InputIOCTL(AUDIOTRACKINFO, cd_TrackInfoSeg);
			startMin2 = (cd_TrackInfo->start >> 16);
			startSec2 = (cd_TrackInfo->start >> 8);
		}
		else
		{
			startMin2 = cd_LeadOutRed>>16;
			startSec2 = cd_LeadOutRed>>8;
		}
		lengthSec = startSec2 - startSec1;
		lengthMin = startMin2 - startMin1;
		if(lengthSec < 0)
		{
			lengthSec += 60;
			lengthMin--;
		}
		cd_AudioTracks[i].lengthMin = lengthMin;
		cd_AudioTracks[i].lengthSec = lengthSec;
		startMin1 = startMin2;
		startSec1 = startSec2;
	}

	// Clip high tracks
	cd_LastTrack = maxTrack;

	OkInit = 1;
	return 0;
}

//==========================================================================
//
// I_CDMusPlay
//
// Play an audio CD track.
//
// Returns: 0 (ok) or -1 (error, in cd_Error).
//
//==========================================================================

int I_CDMusPlay(int track)
{
	int start;
	int len;

	if(track < cd_FirstTrack || track > cd_LastTrack)
	{
		cd_Error = CDERR_BADTRACK;
		return(-1);
	}
	I_CDMusStop();
	start = cd_AudioTracks[track].redStart;
	len = cd_AudioTracks[track].sectorLength;
	cd_PlayReq->addressMode = RED_MODE;
	cd_PlayReq->startSector = start;
	cd_PlayReq->numberToRead = len;
	memset(&RegBlock, 0, sizeof(RegBlock));
	RegBlock.eax = CDROM_SENDDEVICEREQ;
	RegBlock.ecx = cd_CurDrive;
	RegBlock.ebx = 0;
	RegBlock.es = cd_PlayReqSeg;
	DPMI_SimRealInt(MULTIPLEX_INT, &RegBlock);
	if(cd_PlayReq->status&0x8000)
	{
		cd_Error = CDERR_DEVREQBASE+(cd_PlayReq->status)&0x00ff;
		return(-1);
	}
	return(0);
}

//==========================================================================
//
// I_CDMusStop
//
// Stops the playing of an audio CD.
//
// Returns: 0 (ok) or -1 (error, in cd_Error).
//
//==========================================================================

int I_CDMusStop(void)
{
	memset(&RegBlock, 0, sizeof(RegBlock));
	RegBlock.eax = CDROM_SENDDEVICEREQ;
	RegBlock.ecx = cd_CurDrive;
	RegBlock.ebx = 0;
	RegBlock.es = cd_StopReqSeg;
	DPMI_SimRealInt(MULTIPLEX_INT, &RegBlock);
	if(cd_StopReq->status&0x8000)
	{
		cd_Error = CDERR_DEVREQBASE+(cd_StopReq->status)&0x00ff;
		return -1;
	}
	return 0;
}

//==========================================================================
//
// I_CDMusResume
//
// Resumes the playing of an audio CD.
//
// Returns: 0 (ok) or -1 (error, in cd_Error).
//
//==========================================================================

int I_CDMusResume(void)
{
	memset(&RegBlock, 0, sizeof(RegBlock));
	RegBlock.eax = CDROM_SENDDEVICEREQ;
	RegBlock.ecx = cd_CurDrive;
	RegBlock.ebx = 0;
	RegBlock.es = cd_ResumeReqSeg;
	DPMI_SimRealInt(MULTIPLEX_INT, &RegBlock);
	if(cd_ResumeReq->status&0x8000)
	{
		cd_Error = CDERR_DEVREQBASE+(cd_ResumeReq->status)&0x00ff;
		return -1;
	}
	return 0;
}

//==========================================================================
//
// I_CDMusSetVolume
//
// Sets the CD audio volume (0 - 255).
//
// Returns: 0 (ok) or -1 (error, in cd_Error).
//
//==========================================================================

int I_CDMusSetVolume(int volume)
{

	if(!OkInit)
	{
		cd_Error = CDERR_NOTINSTALLED;
	   	return -1;
	}

	// Read current channel info
	InputIOCTL(AUDIOCHANINFO, cd_AudChanInfoSeg);

	// Change the volumes
	cd_AudChanInfo->volumeOut0 =
		cd_AudChanInfo->volumeOut1 =
		cd_AudChanInfo->volumeOut2 =
		cd_AudChanInfo->volumeOut3 = volume;

	// Write modified channel info
	OutputIOCTL(AUDIOCHANCONTROL, cd_AudChanInfoSeg);

	return 0;
}

//==========================================================================
//
// I_CDMusFirstTrack
//
// Returns: the number of the first track.
//
//==========================================================================

int I_CDMusFirstTrack(void)
{
	return cd_FirstTrack;
}

//==========================================================================
//
// I_CDMusLastTrack
//
// Returns: the number of the last track.
//
//==========================================================================

int I_CDMusLastTrack(void)
{
	return cd_LastTrack;
}

//==========================================================================
//
// I_CDMusTrackLength
//
// Returns: Length of the given track in seconds, or -1 (error, in
// cd_Error).
//
//==========================================================================

int I_CDMusTrackLength(int track)
{
	if(track < cd_FirstTrack || track > cd_LastTrack)
	{
		cd_Error = CDERR_BADTRACK;
		return -1;
	}
	return cd_AudioTracks[track].lengthMin*60
		+cd_AudioTracks[track].lengthSec;
}

//==========================================================================
//
// AllocIOCTLBuffers
//
// Allocates conventional memory for the IOCTL input and output buffers.
// Sets cd_IOCTLBufferTotal to the total allocated.
//
// Returns: 0 (ok) or -1 (error, in cd_Error).
//
//==========================================================================

static int AllocIOCTLBuffers(void)
{
	int i;
	int size;
	DOSChunk_t *ck;

	cd_IOCTLBufferTotal = 0;
	for(i = 0; DOSChunks[i].size != 0; i++)
	{
		ck = &DOSChunks[i];
		size = ck->size;
		cd_IOCTLBufferTotal += (size+15)&0xfffffff0;
		*ck->address = DPMI_AllocRealMem(size, ck->segment, ck->selector);
		if(*ck->address == NULL)
		{
			return -1;
		}
		memset(*ck->address, 0, size);
	}
	cd_IOCTLIn->headerSize = sizeof(struct IOCTLIn_s);
	cd_IOCTLIn->command = DRC_IOCTLINPUT;
	cd_IOCTLOut->headerSize = sizeof(struct IOCTLOut_s);
	cd_IOCTLOut->command = DRC_IOCTLOUTPUT;
	cd_PlayReq->headerSize = sizeof(struct PlayReq_s);
	cd_PlayReq->command = DRC_PLAYAUDIO;
	cd_StopReq->headerSize = sizeof(struct StopReq_s);
	cd_StopReq->command = DRC_STOPAUDIO;
	cd_ResumeReq->headerSize = sizeof(struct ResumeReq_s);
	cd_ResumeReq->command = DRC_RESUMEAUDIO;
	return 0;
}

//==========================================================================
//
// InputIOCTL
//
// Sends an IOCTL input device request command.
//
// Returns: the status of the request.
//
//==========================================================================

static U_WORD InputIOCTL(S_LONG request, U_WORD buffSeg)
{
	U_BYTE *code;

	code = (U_BYTE *)(buffSeg<<4);
	*code = (U_BYTE)request;
	cd_IOCTLIn->ctrlBlkAddr = buffSeg<<16;
	cd_IOCTLIn->tranSize = InCtrlBlkSize[request];
	memset(&RegBlock, 0, sizeof(RegBlock));
	RegBlock.eax = CDROM_SENDDEVICEREQ;
	RegBlock.ecx = cd_CurDrive;
	RegBlock.ebx = 0;
	RegBlock.es = cd_IOCTLInSeg;
	DPMI_SimRealInt(MULTIPLEX_INT, &RegBlock);
	return cd_IOCTLIn->status;
}

//==========================================================================
//
// OutputIOCTL
//
// Sends an IOCTL output device request command.
//
// Returns: the status of the request.
//
//==========================================================================

static U_WORD OutputIOCTL(S_LONG request, U_WORD buffSeg)
{
	U_BYTE *code;

	code = (U_BYTE *)(buffSeg<<4);
	*code = (U_BYTE)request;
	cd_IOCTLOut->ctrlBlkAddr = buffSeg<<16;
	cd_IOCTLOut->tranSize = OutCtrlBlkSize[request];
	RegBlock.eax = CDROM_SENDDEVICEREQ;
	RegBlock.ecx = cd_CurDrive;
	RegBlock.ebx = 0;
	RegBlock.es = cd_IOCTLOutSeg;
	DPMI_SimRealInt(MULTIPLEX_INT, &RegBlock);
	return cd_IOCTLOut->status;
}

//==========================================================================
//
// RedToSectors
//
// Converts Red Book addresses to HSG sectors.
// Sectors = Minutes * 60 * 75 + Seconds * 75 + Frame - 150
//
// Returns: HSG sectors.
//
//==========================================================================

static U_LONG RedToSectors(U_LONG red)
{
	U_LONG sector;

	sector = ((red&0x00ff0000) >> 16) * 60 * 75;
	sector += ((red&0x0000ff00) >> 8) * 75;
	sector += (red&0x000000ff);
	return sector-150;
}

//==========================================================================
//
// DPMI_SimRealInt
//
//==========================================================================

static void DPMI_SimRealInt(U_LONG intr, RegBlock_t *rBlock)
{
	union REGS regs;
	struct SREGS sRegs;

	regs.x.eax = DPMI_SIMREALINT;
	regs.x.ebx = intr;
	regs.x.ecx = 0;
	regs.x.edi = FP_OFF((void far *)rBlock);
	sRegs.es = FP_SEG((void far *)rBlock);
	sRegs.ds = FP_SEG((void far *)rBlock);
	int386x(DPMI_INT, &regs, &regs, &sRegs);
}

//==========================================================================
//
// DPMI_AllocRealMem
//
//==========================================================================

static void *DPMI_AllocRealMem(U_LONG size, U_WORD *segment,
	U_WORD *selector)
{
	union REGS inRegs;
	union REGS outRegs;

	inRegs.x.eax = DPMI_ALLOCREALMEM;
	inRegs.x.ebx = (size+15)/16;
	int386(DPMI_INT, &inRegs, &outRegs);
	if(outRegs.x.cflag)
	{
		return NULL;
	}
	*segment = outRegs.x.eax&0xffff;
	*selector = outRegs.x.edx&0xffff;
	return (void *)(outRegs.x.eax<<4);
}

//==========================================================================
//
// DPMI_FreeRealMem
//
//==========================================================================

static void DPMI_FreeRealMem(U_WORD selector)
{
	union REGS regs;

	regs.x.eax = DPMI_FREEREALMEM;
	regs.x.edx = selector;
	int386(DPMI_INT, &regs, &regs);
}

⌨️ 快捷键说明

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