NeoGeo CD: add support for bin/cue and ccd/img/sub (trurip). remove support for mode1-2048 (.iso + .wav). new cdimage support is better, faster, no pauses when cd audio starts, works with savestates(git diff .)

This commit is contained in:
dinkc64 2019-02-05 19:53:08 -05:00
parent 6d3031d56d
commit 3fb85cb996
9 changed files with 1073 additions and 129 deletions

View File

@ -22,7 +22,7 @@ depobj += about.o bzip.o choose_monitor.o cona.o debugger.o drv.o d3dkmt_sync.o
\
2xpm.o 2xsai.o ddt3x.o epx.o hq2xs.o hq2xs_16.o xbr.o \
\
aud_dsound3.o aud_xaudio2.o cd_isowav.o cdsound.o ddraw_core.o dinput_core.o directx9_core.o dsound_core.o \
aud_dsound3.o aud_xaudio2.o cd_img.o ddraw_core.o dinput_core.o directx9_core.o dsound_core.o \
inp_dinput.o prf_performance_counter.o vid_d3d.o vid_ddraw.o vid_ddrawfx.o vid_directx9.o vid_directx_support.o
ifdef INCLUDE_7Z_SUPPORT

View File

@ -1,16 +1,10 @@
// NeoGeo CD-WIP - Jan 25, 2019
// NeoGeo CD-WIP - Jan 25, 2019 - present
// mit .bin/.cue & .ccd/.img (trurip) unterstutzung (feb.4.2019)
// todo:
// burner/win32/neocdsel.cpp needs updated to support mode1/2352
// ssrpg bugs in sfx-audio in cutscene after starting game
// neogeocd: states WIP "the 3rd attempt."
// working restrictions AKA at least it no longer crashes :)
// game must be fully loaded in order to use them.
//
// TODO: (in order to remove restrictions)
// state-able iso-library
// state-able wav-player
// Advanced-TODO:
// stream wav instead of telling directX/SDL to play WAVfile.
// this will fix neo-cdplayer in bios, get rid of platform-specific stuff, etc..
// Note: this text will self-destruct upon completion / end of WIP. -dink
/*
* FB Alpha Neo Geo module
@ -79,6 +73,8 @@
#include "bitswap.h"
#include "neocdlist.h"
static INT32 isowav_mode = 0;
// #undef USE_SPEEDHACKS
// #define LOG_IRQ
@ -280,7 +276,7 @@ static INT32 nNeoControlConfig;
static INT32 nNeoSystemType;
static bool bZ80BIOS;
static INT32 /*nNeoCDCyclesIRQ = 0,*/ nNeoCDCyclesIRQPeriod = 0;
static INT32 nNeoCDCyclesIRQ = 0, nNeoCDCyclesIRQPeriod = 0;
#ifdef BUILD_A68K
static bool bUseAsm68KCoreOldValue = false;
@ -1555,6 +1551,7 @@ INT32 NeoScan(INT32 nAction, INT32* pnMin)
SCAN_VAR(nNeoCDMode);
SCAN_VAR(nff0002);
CDEmuScan(nAction, pnMin);
}
if (nAction & ACB_WRITE) {
@ -2512,11 +2509,17 @@ static void LC8951UpdateHeader()
} else {
// HEAD registers have header
LC8951RegistersR[4] = ((NeoCDSectorMin / 10) << 4) | (NeoCDSectorMin % 10); // HEAD0
LC8951RegistersR[5] = ((NeoCDSectorSec / 10) << 4) | (NeoCDSectorSec % 10); // HEAD1
LC8951RegistersR[6] = ((NeoCDSectorFrm / 10) << 4) | (NeoCDSectorFrm % 10); // HEAD2
LC8951RegistersR[7] = 1; // HEAD3
if (isowav_mode) {
LC8951RegistersR[4] = ((NeoCDSectorMin / 10) << 4) | (NeoCDSectorMin % 10); // HEAD0
LC8951RegistersR[5] = ((NeoCDSectorSec / 10) << 4) | (NeoCDSectorSec % 10); // HEAD1
LC8951RegistersR[6] = ((NeoCDSectorFrm / 10) << 4) | (NeoCDSectorFrm % 10); // HEAD2
LC8951RegistersR[7] = 1; // HEAD3
} else {
LC8951RegistersR[4] = NeoCDSectorData[12]; // HEAD0
LC8951RegistersR[5] = NeoCDSectorData[13]; // HEAD1
LC8951RegistersR[6] = NeoCDSectorData[14]; // HEAD2
LC8951RegistersR[7] = NeoCDSectorData[15]; // HEAD3
}
}
}
@ -2535,8 +2538,12 @@ static char* LC8951InitTransfer()
return NULL;
}
return NeoCDSectorData + ((LC8951RegistersW[5] << 8) | LC8951RegistersW[4]);
}
if (isowav_mode) {
return NeoCDSectorData + ((LC8951RegistersW[5] << 8) | LC8951RegistersW[4]);
} else {
return NeoCDSectorData + 12 + ((LC8951RegistersW[5] << 8) | LC8951RegistersW[4]);
}
}
static void LC8951EndTransfer()
{
@ -2556,21 +2563,21 @@ static void LC8951EndTransfer()
static void LC8951Reset()
{
memset(NeoCDSectorData, 0, sizeof(NeoCDSectorData));
memset(LC8951RegistersR, 0, sizeof(LC8951RegistersR));
memset(LC8951RegistersW, 0, sizeof(LC8951RegistersW));
LC8951RegistersR[0x04] = 0x01; // head0
bNeoCDLoadSector = false;
LC8951RegistersR[0x01] = 0xFF;
LC8951RegistersR[0x0F] = 0x80;
memset(NeoCDSectorData, 0, sizeof(NeoCDSectorData));
LC8951UpdateHeader();
}
// for NeoGeo CD (WAV playback)
void wav_exit();
void wav_pause(bool bResume);
//void wav_exit();
//void wav_pause(bool bResume);
static void NeoCDProcessCommand()
{
@ -2598,16 +2605,29 @@ static void NeoCDProcessCommand()
case 0: {
UINT8* ChannelData = CDEmuReadQChannel();
NeoCDCommsStatusFIFO[2] = ChannelData[1] / 10;
NeoCDCommsStatusFIFO[3] = ChannelData[1] % 10;
if (isowav_mode) {
NeoCDCommsStatusFIFO[2] = ChannelData[1] / 10;
NeoCDCommsStatusFIFO[3] = ChannelData[1] % 10;
NeoCDCommsStatusFIFO[4] = ChannelData[2] / 10;
NeoCDCommsStatusFIFO[5] = ChannelData[2] % 10;
NeoCDCommsStatusFIFO[4] = ChannelData[2] / 10;
NeoCDCommsStatusFIFO[5] = ChannelData[2] % 10;
NeoCDCommsStatusFIFO[6] = ChannelData[3] / 10;
NeoCDCommsStatusFIFO[7] = ChannelData[3] % 10;
NeoCDCommsStatusFIFO[8] = ChannelData[7];
NeoCDCommsStatusFIFO[6] = ChannelData[3] / 10;
NeoCDCommsStatusFIFO[7] = ChannelData[3] % 10;
NeoCDCommsStatusFIFO[8] = ChannelData[7];
} else {
NeoCDCommsStatusFIFO[2] = ChannelData[1] >> 4;
NeoCDCommsStatusFIFO[3] = ChannelData[1] & 0x0F;
NeoCDCommsStatusFIFO[4] = ChannelData[2] >> 4;
NeoCDCommsStatusFIFO[5] = ChannelData[2] & 0x0F;
NeoCDCommsStatusFIFO[6] = ChannelData[3] >> 4;
NeoCDCommsStatusFIFO[7] = ChannelData[3] & 0x0F;
NeoCDCommsStatusFIFO[8] = ChannelData[7];
}
// bprintf(PRINT_ERROR, _T(" %02i %02i:%02i:%02i %02i:%02i:%02i %02i\n"), ChannelData[0], ChannelData[1], ChannelData[2], ChannelData[3], ChannelData[4], ChannelData[5], ChannelData[6], ChannelData[7]);
@ -2616,16 +2636,29 @@ static void NeoCDProcessCommand()
case 1: {
UINT8* ChannelData = CDEmuReadQChannel();
NeoCDCommsStatusFIFO[2] = ChannelData[4] / 10;
NeoCDCommsStatusFIFO[3] = ChannelData[4] % 10;
if (isowav_mode) {
NeoCDCommsStatusFIFO[2] = ChannelData[4] / 10;
NeoCDCommsStatusFIFO[3] = ChannelData[4] % 10;
NeoCDCommsStatusFIFO[4] = ChannelData[5] / 10;
NeoCDCommsStatusFIFO[5] = ChannelData[5] % 10;
NeoCDCommsStatusFIFO[4] = ChannelData[5] / 10;
NeoCDCommsStatusFIFO[5] = ChannelData[5] % 10;
NeoCDCommsStatusFIFO[6] = ChannelData[6] / 10;
NeoCDCommsStatusFIFO[7] = ChannelData[6] % 10;
NeoCDCommsStatusFIFO[6] = ChannelData[6] / 10;
NeoCDCommsStatusFIFO[7] = ChannelData[6] % 10;
NeoCDCommsStatusFIFO[8] = ChannelData[7];
NeoCDCommsStatusFIFO[8] = ChannelData[7];
} else {
NeoCDCommsStatusFIFO[2] = ChannelData[4] >> 4;
NeoCDCommsStatusFIFO[3] = ChannelData[4] & 0x0F;
NeoCDCommsStatusFIFO[4] = ChannelData[5] >> 4;
NeoCDCommsStatusFIFO[5] = ChannelData[5] & 0x0F;
NeoCDCommsStatusFIFO[6] = ChannelData[6] >> 4;
NeoCDCommsStatusFIFO[7] = ChannelData[6] & 0x0F;
NeoCDCommsStatusFIFO[8] = ChannelData[7];
}
break;
}
@ -2633,59 +2666,99 @@ static void NeoCDProcessCommand()
UINT8* ChannelData = CDEmuReadQChannel();
NeoCDCommsStatusFIFO[2] = ChannelData[0] / 10;
NeoCDCommsStatusFIFO[3] = ChannelData[0] % 10;
if (isowav_mode) {
NeoCDCommsStatusFIFO[2] = ChannelData[0] / 10;
NeoCDCommsStatusFIFO[3] = ChannelData[0] % 10;
NeoCDCommsStatusFIFO[8] = ChannelData[7];
} else {
NeoCDCommsStatusFIFO[2] = ChannelData[0] >> 4;
NeoCDCommsStatusFIFO[3] = ChannelData[0] & 0x0F;
NeoCDCommsStatusFIFO[8] = ChannelData[7];
NeoCDCommsStatusFIFO[8] = ChannelData[7];
}
break;
}
case 3: {
UINT8* TOCEntry = CDEmuReadTOC(-2);
NeoCDCommsStatusFIFO[2] = TOCEntry[0] / 10;
NeoCDCommsStatusFIFO[3] = TOCEntry[0] % 10;
if (isowav_mode) {
NeoCDCommsStatusFIFO[2] = TOCEntry[0] / 10;
NeoCDCommsStatusFIFO[3] = TOCEntry[0] % 10;
NeoCDCommsStatusFIFO[4] = TOCEntry[1] / 10;
NeoCDCommsStatusFIFO[5] = TOCEntry[1] % 10;
NeoCDCommsStatusFIFO[4] = TOCEntry[1] / 10;
NeoCDCommsStatusFIFO[5] = TOCEntry[1] % 10;
NeoCDCommsStatusFIFO[6] = TOCEntry[2] / 10;
NeoCDCommsStatusFIFO[7] = TOCEntry[2] % 10;
NeoCDCommsStatusFIFO[6] = TOCEntry[2] / 10;
NeoCDCommsStatusFIFO[7] = TOCEntry[2] % 10;
} else {
NeoCDCommsStatusFIFO[2] = TOCEntry[0] >> 4;
NeoCDCommsStatusFIFO[3] = TOCEntry[0] & 0x0F;
NeoCDCommsStatusFIFO[4] = TOCEntry[1] >> 4;
NeoCDCommsStatusFIFO[5] = TOCEntry[1] & 0x0F;
NeoCDCommsStatusFIFO[6] = TOCEntry[2] >> 4;
NeoCDCommsStatusFIFO[7] = TOCEntry[2] & 0x0F;
}
break;
}
case 4: {
UINT8* TOCEntry = CDEmuReadTOC(-1);
NeoCDCommsStatusFIFO[2] = TOCEntry[0] / 10;
NeoCDCommsStatusFIFO[3] = TOCEntry[0] % 10;
if (isowav_mode) {
NeoCDCommsStatusFIFO[2] = TOCEntry[0] / 10;
NeoCDCommsStatusFIFO[3] = TOCEntry[0] % 10;
NeoCDCommsStatusFIFO[4] = TOCEntry[1] / 10;
NeoCDCommsStatusFIFO[5] = TOCEntry[1] % 10;
NeoCDCommsStatusFIFO[4] = TOCEntry[1] / 10;
NeoCDCommsStatusFIFO[5] = TOCEntry[1] % 10;
} else {
NeoCDCommsStatusFIFO[2] = TOCEntry[0] > 4;
NeoCDCommsStatusFIFO[3] = TOCEntry[0] & 0x0F;
NeoCDCommsStatusFIFO[4] = TOCEntry[1] >> 4;
NeoCDCommsStatusFIFO[5] = TOCEntry[1] & 0x0F;
}
break;
}
case 5: {
NeoCDTrack = NeoCDCommsCommandFIFO[4] * 10 + NeoCDCommsCommandFIFO[5];
NeoCDTrack = (NeoCDCommsCommandFIFO[4] << 4) | NeoCDCommsCommandFIFO[5];
UINT8* TOCEntry = CDEmuReadTOC(NeoCDTrack);
NeoCDCommsStatusFIFO[2] = TOCEntry[0] / 10;
NeoCDCommsStatusFIFO[3] = TOCEntry[0] % 10;
if (isowav_mode) {
NeoCDCommsStatusFIFO[2] = TOCEntry[0] / 10;
NeoCDCommsStatusFIFO[3] = TOCEntry[0] % 10;
NeoCDCommsStatusFIFO[4] = TOCEntry[1] / 10;
NeoCDCommsStatusFIFO[5] = TOCEntry[1] % 10;
NeoCDCommsStatusFIFO[4] = TOCEntry[1] / 10;
NeoCDCommsStatusFIFO[5] = TOCEntry[1] % 10;
NeoCDCommsStatusFIFO[6] = TOCEntry[2] / 10;
NeoCDCommsStatusFIFO[7] = TOCEntry[2] % 10;
NeoCDCommsStatusFIFO[6] = TOCEntry[2] / 10;
NeoCDCommsStatusFIFO[7] = TOCEntry[2] % 10;
} else {
NeoCDCommsStatusFIFO[2] = TOCEntry[0] >> 4;
NeoCDCommsStatusFIFO[3] = TOCEntry[0] & 0x0F;
NeoCDCommsStatusFIFO[4] = TOCEntry[1] >> 4;
NeoCDCommsStatusFIFO[5] = TOCEntry[1] & 0x0F;
NeoCDCommsStatusFIFO[6] = TOCEntry[2] >> 4;
NeoCDCommsStatusFIFO[7] = TOCEntry[2] & 0x0F;
}
// bit 3 of the 1st minutes digit indicates a data track
if (TOCEntry[3] & 4) {
NeoCDCommsStatusFIFO[6] |= 8;
}
NeoCDCommsStatusFIFO[8] = NeoCDTrack % 10;
if (isowav_mode) {
NeoCDCommsStatusFIFO[8] = NeoCDTrack % 10;
} else {
NeoCDCommsStatusFIFO[8] = NeoCDTrack & 0x0F;
}
break;
}
@ -2703,7 +2776,7 @@ static void NeoCDProcessCommand()
// must be 02, 0E, 0F, or 05
NeoCDCommsStatusFIFO[2] = 0;
NeoCDCommsStatusFIFO[3] = 5;
NeoCDCommsStatusFIFO[3] = (isowav_mode) ? 5 : NeoCDAssyStatus;
NeoCDCommsStatusFIFO[4] = 0;
NeoCDCommsStatusFIFO[5] = 0;
@ -2730,7 +2803,8 @@ static void NeoCDProcessCommand()
NeoCDSectorLBA += NeoCDCommsCommandFIFO[6] * (10 );
NeoCDSectorLBA += NeoCDCommsCommandFIFO[7] * ( 1 );
NeoCDSectorLBA -= CD_FRAMES_PREGAP;
if (isowav_mode)
NeoCDSectorLBA -= CD_FRAMES_PREGAP;
CDEmuStartRead();
// LC8951RegistersR[1] |= 0x20;
@ -2740,7 +2814,11 @@ static void NeoCDProcessCommand()
bprintf(PRINT_ERROR, _T("*** Switching CD mode to audio while in CD-ROM mode!(PC: 0x%06X)\n"), SekGetPC(-1));
}
CDEmuPlay((NeoCDCommsCommandFIFO[2] * 10) + NeoCDCommsCommandFIFO[3], (NeoCDCommsCommandFIFO[4] * 10) + NeoCDCommsCommandFIFO[5], (NeoCDCommsCommandFIFO[6] * 10) + NeoCDCommsCommandFIFO[7]);
if (isowav_mode) {
CDEmuPlay((NeoCDCommsCommandFIFO[2] * 10) + NeoCDCommsCommandFIFO[3], (NeoCDCommsCommandFIFO[4] * 10) + NeoCDCommsCommandFIFO[5], (NeoCDCommsCommandFIFO[6] * 10) + NeoCDCommsCommandFIFO[7]);
} else {
CDEmuPlay((NeoCDCommsCommandFIFO[2] * 16) + NeoCDCommsCommandFIFO[3], (NeoCDCommsCommandFIFO[4] * 16) + NeoCDCommsCommandFIFO[5], (NeoCDCommsCommandFIFO[6] * 16) + NeoCDCommsCommandFIFO[7]);
}
}
NeoCDAssyStatus = 1;
@ -2763,14 +2841,14 @@ static void NeoCDProcessCommand()
NeoCDAssyStatus = 4;
bNeoCDLoadSector = false;
CDEmuPause();
wav_pause(0);
//if (isowav_mode) wav_pause(0);
break;
case 7:
// bprintf(PRINT_ERROR, _T(" CD comms received command %i\n"), NeoCDCommsCommandFIFO[0]);
NeoCDAssyStatus = 1;
bNeoCDLoadSector = true;
CDEmuResume();
wav_pause(1);
//if (isowav_mode) wav_pause(1);
break;
case 8:
@ -3137,7 +3215,11 @@ void NeoCDReadSector()
// if (LC8951RegistersW[10] & 0x80) {
NeoCDSectorLBA++;
NeoCDSectorLBA = CDEmuLoadSector(NeoCDSectorLBA, NeoCDSectorData + 4) - 1;
if (isowav_mode) {
NeoCDSectorLBA = CDEmuLoadSector(NeoCDSectorLBA, NeoCDSectorData + 4) - 1;
} else {
NeoCDSectorLBA = CDEmuLoadSector(NeoCDSectorLBA, NeoCDSectorData) - 1;
}
// }
if (LC8951RegistersW[10] & 0x80) {
@ -3148,18 +3230,18 @@ void NeoCDReadSector()
LC8951RegistersR[14] = 0x10; // STAT2
LC8951RegistersR[15] = 0; // STAT3
// bprintf(PRINT_IMPORTANT, _T(" Sector %08i (%02i:%02i:%02i) read\n"), NeoCDSectorLBA, NeoCDSectorMin, NeoCDSectorSec, NeoCDSectorFrm);
//bprintf(PRINT_IMPORTANT, _T(" Sector %08i (%02i:%02i:%02i) read\n"), NeoCDSectorLBA, NeoCDSectorMin, NeoCDSectorSec, NeoCDSectorFrm);
INT32 sectoffs = (isowav_mode) ? 0 : 12;
if (NeoCDSectorData[sectoffs + 4 + 64] == 'g' && !strncmp(NeoCDSectorData + sectoffs + 4, "Copyright by SNK", 16)) {
//bprintf(0, _T("\n simulated CDZ protection error\n"));
//bprintf(PRINT_ERROR, _T(" %.70hs\n"), NeoCDSectorData + sectoffs + 4);
#if 1
if (NeoCDSectorData[4 + 64] == 'g' && !strncmp(NeoCDSectorData + 4, "Copyright by SNK", 16)) {
// printf(PRINT_ERROR, _T(" simulated CDZ protection error\n"));
// bprintf(PRINT_ERROR, _T(" %.70hs\n"), NeoCDSectorData + 4);
NeoCDSectorData[4 + 64] = 'f';
NeoCDSectorData[sectoffs + 4 + 64] = 'f';
// LC8951RegistersR[12] = 0x00; // STAT0
}
#endif
nIRQAcknowledge &= ~0x20;
NeoCDIRQUpdate(0);
@ -3241,7 +3323,7 @@ void __fastcall neogeoWriteByteCDROM(UINT32 sekAddress, UINT8 byteValue)
// bprintf(PRINT_NORMAL, _T(" - Neo Geo CD: 0x%06X -> 0x%02X (PC: 0x%06X)\n"), sekAddress, byteValue, SekGetPC(-1));
switch (sekAddress & 0xFFFF) {
case 0x000E:
//case 0x000E:
case 0x000F:
NeoCDIRQUpdate(byteValue);
break;
@ -3397,15 +3479,18 @@ void __fastcall neogeoWriteWordCDROM(UINT32 sekAddress, UINT16 wordValue)
switch (sekAddress & 0xFFFE) {
case 0x0002:
// bprintf(PRINT_IMPORTANT, _T(" - NGCD Interrupt mask -> 0x%04X (PC: 0x%06X)\n"), wordValue, SekGetPC(-1));
nff0002 = wordValue;
if ((wordValue & 0x0500) && !(nff0002 & 0x0500))
nNeoCDCyclesIRQ = nNeoCDCyclesIRQPeriod;
nff0002 = wordValue;
// LC8951RegistersR[1] |= 0x20;
if (nff0002 & 0x0500)
/* if (nff0002 & 0x0500)
nNeoCDCyclesIRQPeriod = (INT32)(12000000.0 * nBurnCPUSpeedAdjust / (256.0 * 75.0));
else
nNeoCDCyclesIRQPeriod = (INT32)(12000000.0 * nBurnCPUSpeedAdjust / (256.0 * 75.0));
*/
break;
case 0x000E:
@ -3413,6 +3498,11 @@ void __fastcall neogeoWriteWordCDROM(UINT32 sekAddress, UINT16 wordValue)
break;
// DMA controller
case 0x0060:
if (wordValue & 0x40) {
NeoCDDoDMA();
}
break;
case 0x0064:
NeoCDDMAAddress1 &= 0x0000FFFF;
@ -3542,12 +3632,8 @@ void __fastcall neogeoWriteByteTransfer(UINT32 sekAddress, UINT8 byteValue)
YM2610ADPCMAROM[nNeoActiveSlot][nADPCMTransferBank + ((sekAddress & 0x0FFFFF) >> 1)] = byteValue;
break;
case 4: // Z80
if (ZetGetBUSREQLine() == 0) {
YM2610ADPCMAROM[nNeoActiveSlot][nADPCMTransferBank + ((sekAddress & 0x0FFFFF) >> 1)] = byteValue;
} else {
if ((sekAddress & 0xfffff) >= 0x20000) break;
NeoZ80ROMActive[(sekAddress & 0x1FFFF) >> 1] = byteValue;
}
if ((sekAddress & 0xfffff) >= 0x20000) break;
NeoZ80ROMActive[(sekAddress & 0x1FFFF) >> 1] = byteValue;
break;
case 5: // Text
NeoTextRAM[(sekAddress & 0x3FFFF) >> 1] = byteValue;
@ -3610,9 +3696,6 @@ UINT8 __fastcall neogeoCDReadByte68KProgram(UINT32 sekAddress)
// ----------------------------------------------------------------------------
// for NeoGeo CD (WAV playback)
void wav_exit();
static INT32 neogeoReset()
{
if (nNeoSystemType & NEO_SYS_CART) {
@ -3681,7 +3764,7 @@ static INT32 neogeoReset()
bprintf(PRINT_IMPORTANT, _T(" - Emulating Neo CD system.\n"));
// exit WAV object if needed
wav_exit();
//if (isowav_mode) wav_exit();
}
#endif
@ -4448,18 +4531,16 @@ static void NeoStandardInputs(INT32 nBank)
}
}
#if 1
#if 0
#define NeoSekRun SekRun
#else
static INT32 NeoSekRun(const INT32 nCycles)
{
INT32 nCyclesExecutedTotal = 0, nOldCyclesSegment = nCyclesSegment;
if (!(nNeoSystemType & NEO_SYS_CD) || !(nff0002 & 0x0050))
if (!(nNeoSystemType & NEO_SYS_CD) /*|| !(nff0002 & 0x0050)*/ )
return SekRun(nCycles);
//bprintf(PRINT_NORMAL, _T("***\n"));
while (nCyclesExecutedTotal < nCycles) {
INT32 nCyclesExecuted;
@ -4467,24 +4548,20 @@ static INT32 NeoSekRun(const INT32 nCycles)
if (nNeoCDCyclesIRQ <= 0) {
nNeoCDCyclesIRQ += nNeoCDCyclesIRQPeriod;
// Trigger CD mechanism communication interrupt
//bprintf(PRINT_NORMAL, _T(" DECI status %i\n"), (LC8951RegistersR[1] & 0x20) >> 5);
if ((nff0002 & 0x0500) /*&& (LC8951RegistersR[1] & 0x20)*/ )
NeoCDReadSector();
// Trigger CD mechanism communication interrupt
//bprintf(PRINT_NORMAL, _T(" DECI status %i\n"), (LC8951RegistersR[1] & 0x20) >> 5);
nIRQAcknowledge &= ~0x10;
NeoCDIRQUpdate(0);
if ((nff0002 & 0x0500) && (LC8951RegistersR[1] & 0x20))
NeoCDReadSector();
}
nCyclesSegment = (nNeoCDCyclesIRQ < (nCycles - nCyclesExecutedTotal)) ? nNeoCDCyclesIRQ : (nCycles - nCyclesExecutedTotal);
nCyclesExecuted = SekRun(nCyclesSegment);
//bprintf(PRINT_NORMAL, _T("%010i %010i %010i %010i\n"), nCycles, nCyclesExecutedTotal, nCyclesExecuted, nNeoCDCyclesIRQ);
nCyclesExecutedTotal += nCyclesExecuted;
nNeoCDCyclesIRQ -= nCyclesExecuted;
}
nCyclesSegment = nOldCyclesSegment;
@ -4663,6 +4740,8 @@ INT32 NeoFrame()
// uPD499A ticks per second (same as 68K clock)
uPD499ASetTicks((INT64)12000000 * nBurnCPUSpeedAdjust / 256);
nNeoCDCyclesIRQPeriod = (int)(12000000.0 * nBurnCPUSpeedAdjust / (256.0 * 150.0));
nPrevBurnCPUSpeedAdjust = nBurnCPUSpeedAdjust;
}
@ -4706,12 +4785,14 @@ INT32 NeoFrame()
// Run 68000
if ((nNeoSystemType & NEO_SYS_CD) && (nff0002 & 0x0050)) {
nIRQAcknowledge &= ~0x10;
NeoCDIRQUpdate(0);
if (isowav_mode) {
if ((nNeoSystemType & NEO_SYS_CD) && (nff0002 & 0x0050)) {
nIRQAcknowledge &= ~0x10;
NeoCDIRQUpdate(0);
if (nff0002 & 0x0500) {
NeoCDReadSector();
if (nff0002 & 0x0500) {
NeoCDReadSector();
}
}
}
@ -4981,7 +5062,8 @@ INT32 NeoFrame()
}
if (pBurnSoundOut) {
CDEmuGetSoundBuffer(pBurnSoundOut, nBurnSoundLen);
if (!(LC8951RegistersW[10] & 4))
CDEmuGetSoundBuffer(pBurnSoundOut, nBurnSoundLen);
}
return 0;

View File

@ -1,9 +1,6 @@
// Run module
#include "burner.h"
// for NeoGeo CD (WAV playback)
void wav_pause(bool bResume);
int bRunPause = 0;
int bAltPause = 0;
@ -674,9 +671,6 @@ int RunMessageLoop()
}
}
} else {
bRunPause ? wav_pause(false) : wav_pause(true);
// No messages are waiting
SplashDestroy(0);
RunIdle();

View File

@ -1023,7 +1023,7 @@ static void OnCommand(HWND /*hDlg*/, int id, HWND /*hwndCtl*/, UINT codeNotify)
nCDEmuSelect = 0;
TCHAR szFilter[100];
_stprintf(szFilter, _T("%s"), FBALoadStringEx(hAppInst, IDS_CD_SELECT_FILTER, true));
memcpy(szFilter + _tcslen(szFilter), _T(" (*.iso,*.cue)\0*.iso;*.cue\0\0"), 28 * sizeof(TCHAR));
memcpy(szFilter + _tcslen(szFilter), _T(" (*.ccd,*.cue)\0*.ccd;*.cue\0\0"), 28 * sizeof(TCHAR));
TCHAR szTitle[100];
_stprintf(szTitle, _T("%s"), FBALoadStringEx(hAppInst, IDS_CD_SELECT_IMAGE_TITLE, true));
if (UseDialogs() && !bDrvOkay) {

View File

@ -51,13 +51,8 @@ static struct AudOut *pAudOut[]=
static InterfaceInfo AudInfo = { NULL, NULL, NULL };
// for NeoGeo CD (WAV playback)
void wav_pause(bool bResume);
INT32 AudBlankSound()
{
wav_pause(false); // pause / stop if needed
if (!bAudOkay || nAudActive >= AUD_LEN) {
return 1;
}
@ -67,8 +62,6 @@ INT32 AudBlankSound()
// This function checks the Sound loop, and if necessary gets some more sound
INT32 AudSoundCheck()
{
if(!bRunPause) wav_pause(true); // resume, if needed
if (!bAudOkay || nAudActive >= AUD_LEN) {
return 1;
}
@ -109,7 +102,6 @@ INT32 AudSoundPlay()
INT32 nRet = pAudOut[nAudActive]->SoundPlay();
if (!nRet) {
bAudPlaying = true;
if (bCDEmuOkay) wav_pause(true);
}
return nRet;
@ -122,8 +114,7 @@ INT32 AudSoundStop()
}
bAudPlaying = false;
if (bCDEmuOkay) wav_pause(false);
return pAudOut[nAudActive]->SoundStop();
}

View File

@ -9,7 +9,7 @@ CDEmuStatusValue CDEmuStatus;
static InterfaceInfo CDEmuInfo = { NULL, NULL, NULL };
#if defined BUILD_WIN32
extern struct CDEmuDo isowavDo;
extern struct CDEmuDo cdimgDo;
#elif defined BUILD_SDL
// CD emulation module
#elif defined (_XBOX)
@ -19,7 +19,7 @@ static InterfaceInfo CDEmuInfo = { NULL, NULL, NULL };
static struct CDEmuDo* pCDEmuDo[] =
{
#if defined BUILD_WIN32
&isowavDo,
&cdimgDo,
#elif defined BUILD_SDL
// CD emulation module
#elif defined (_XBOX)
@ -117,6 +117,15 @@ INT32 CDEmuGetSoundBuffer(INT16* buffer, INT32 samples)
return pCDEmuDo[nCDEmuSelect]->CDEmuGetSoundBuffer(buffer, samples);
}
INT32 CDEmuScan(INT32 nAction, INT32 *pnMin)
{
if (!bCDEmuOkay || nCDEmuSelect >= CDEMU_LEN) {
return 1;
}
return pCDEmuDo[nCDEmuSelect]->CDEmuScan(nAction, pnMin);
}
InterfaceInfo* CDEmuGetInfo()
{
if (IntInfoInit(&CDEmuInfo)) {

View File

@ -16,6 +16,7 @@ INT32 CDEmuLoadSector(INT32 LBA, char* pBuffer);
UINT8* CDEmuReadTOC(INT32 track);
UINT8* CDEmuReadQChannel();
INT32 CDEmuGetSoundBuffer(INT16* buffer, INT32 samples);
INT32 CDEmuScan(INT32 nAction, INT32 *pnMin);
static inline CDEmuStatusValue CDEmuGetStatus()
{

View File

@ -0,0 +1,866 @@
// FBAlpha cd-img, TruRip .ccd/.sub/.img support by Jan Klaassen
// .bin/.cue re-work by dink
#include "burner.h"
#include "io.h"
const int MAXIMUM_NUMBER_TRACKS = 100;
const int CD_FRAMES_MINUTE = 60 * 75;
const int CD_FRAMES_SECOND = 75;
const int CD_TYPE_NONE = 1 << 0;
const int CD_TYPE_BINCUE = 1 << 1;
const int CD_TYPE_CCD = 1 << 2;
static int cd_pregap;
struct MSF { UINT8 M; UINT8 S; UINT8 F; };
struct MSFAddress { UINT8 Control; MSF MSF; };
struct cdimgTRACK_DATA { UINT8 Control; UINT8 TrackNumber; UINT8 Address[4]; UINT8 EndAddress[4]; };
struct cdimgCDROM_TOC { UINT8 FirstTrack; UINT8 LastTrack; UINT8 ImageType; TCHAR Image[MAX_PATH]; cdimgTRACK_DATA TrackData[MAXIMUM_NUMBER_TRACKS]; };
static cdimgCDROM_TOC* cdimgTOC;
static FILE* cdimgFile = NULL;
static int cdimgFileSize = 0;
static int cdimgTrack = 0;
static int cdimgLBA = 0;
static int cdimgSamples = 0;
// identical to the format used in clonecd .sub files, can use memcpy
struct QData { UINT8 Control; char track; char index; MSF MSFrel; char unused; MSF MSFabs; unsigned short CRC; };
static QData* QChannel = NULL;
// -----------------------------------------------------------------------------
const int cdimgOUT_SIZE = 2352;
static int cdimgOutputbufferSize = 0;
static short* cdimgOutputbuffer = NULL;
static int cdimgOutputPosition;
// -----------------------------------------------------------------------------
TCHAR* GetIsoPath()
{
if (cdimgTOC) {
return cdimgTOC->Image;
}
return NULL;
}
static UINT8 bcd(const UINT8 v)
{
return ((v >> 4) * 10) + (v & 0x0F);
}
static UINT8 tobcd(const UINT8 v)
{
return ((v / 10) << 4) | (v % 10);
}
static const UINT8* cdimgLBAToMSF(int LBA)
{
static UINT8 address[4];
address[0] = 0;
address[1] = tobcd(LBA / CD_FRAMES_MINUTE);
address[2] = tobcd(LBA % CD_FRAMES_MINUTE / CD_FRAMES_SECOND);
address[3] = tobcd(LBA % CD_FRAMES_SECOND);
return address;
}
static int cdimgMSFToLBA(const UINT8* address)
{
int LBA;
LBA = bcd(address[3]);
LBA += bcd(address[2]) * CD_FRAMES_SECOND;
LBA += bcd(address[1]) * CD_FRAMES_MINUTE;
return LBA;
}
static const UINT8* dinkLBAToMSF(const int LBA) // not BCD version
{
static UINT8 address[4];
address[0] = 0;
address[1] = LBA / CD_FRAMES_MINUTE;
address[2] = LBA % CD_FRAMES_MINUTE / CD_FRAMES_SECOND;
address[3] = LBA % CD_FRAMES_SECOND;
return address;
}
static int dinkMSFToLBA(const UINT8* address)
{
int LBA;
LBA = address[3];
LBA += address[2] * CD_FRAMES_SECOND;
LBA += address[1] * CD_FRAMES_MINUTE;
return LBA;
}
// -----------------------------------------------------------------------------
static void cdimgExitStream()
{
free(cdimgOutputbuffer);
cdimgOutputbuffer = NULL;
}
static int cdimgInitStream()
{
cdimgExitStream();
cdimgOutputbuffer = (short*)malloc(cdimgOUT_SIZE * 2 * sizeof(short));
if (cdimgOutputbuffer == NULL)
return 1;
return 0;
}
static int cdimgSkip(FILE* h, int samples)
{
fseek(h, samples * 4, SEEK_CUR);
return samples * 4;
}
// -----------------------------------------------------------------------------
static void cdimgPrintImageInfo()
{
bprintf(0, _T("Image file: %s\n"), cdimgTOC->Image);
bprintf(0, _T(" CD image TOC - "));
if (cdimgTOC->ImageType == CD_TYPE_CCD)
bprintf(0, _T("TruRip (.CCD/.SUB/.IMG) format\n"));
if (cdimgTOC->ImageType == CD_TYPE_BINCUE)
bprintf(0, _T("Disk At Once (.BIN/.CUE) format\n"));
for (INT32 trk = cdimgTOC->FirstTrack - 1; trk <= cdimgTOC->LastTrack; trk++) {
const UINT8* addressUNBCD = dinkLBAToMSF(cdimgMSFToLBA(cdimgTOC->TrackData[trk].Address));
if (trk != cdimgTOC->LastTrack) {
bprintf(0, _T("Track %02d: %02d:%02d:%02d\n"), trk + 1, addressUNBCD[1], addressUNBCD[2], addressUNBCD[3]);
} else {
bprintf(0, _T(" total running time %02i:%02i:%02i\n"), addressUNBCD[1], addressUNBCD[2], addressUNBCD[3]);
}
}
}
// parse .sub file and build a TOC based in Q sub channel data
static int cdimgParseSubFile()
{
TCHAR filename_sub[MAX_PATH];
int length = 0;
QData* Q = 0;
int Qsize = 0;
FILE* h;
int track = 1;
cdimgTOC->ImageType = CD_TYPE_CCD;
cdimgTOC->FirstTrack = 1;
_tcscpy(filename_sub, CDEmuImage);
length = _tcslen(filename_sub);
if (length <= 4 ||
(_tcscmp(_T(".ccd"), filename_sub + length - 4) &&
_tcscmp(_T(".img"), filename_sub + length - 4) &&
_tcscmp(_T(".sub"), filename_sub + length - 4)))
{
dprintf(_T("*** Bad image: %s\n"), filename_sub);
return 1;
}
_tcscpy(cdimgTOC->Image, CDEmuImage);
_tcscpy(cdimgTOC->Image + length - 4, _T(".img"));
//bprintf(0, _T("Image file: %s\n"),cdimgTOC->Image);
if (_waccess(cdimgTOC->Image, 4) == -1)
{
dprintf(_T("*** Bad image: %s\n"), cdimgTOC->Image);
return 1;
}
_tcscpy(filename_sub + length - 4, _T(".sub"));
//bprintf(0, _T("filename_sub: %s\n"),filename_sub);
h = _wfopen(filename_sub, _T("rb"));
if (h == 0)
{
dprintf(_T("*** Bad image: %s\n"), filename_sub);
return 1;
}
fseek(h, 0, SEEK_END);
INT32 subQidx = 0;
INT32 subQsize = ftell(h);
UINT8 *subQdata = (UINT8*)malloc(subQsize);
memset(subQdata, 0, subQsize);
//bprintf(0, _T("raw .sub data size: %d\n"), subQsize);
fseek(h, 0, SEEK_SET);
fread(subQdata, subQsize, 1, h);
fclose(h);
Qsize = (subQsize + 95) / 96 * sizeof(QData);
Q = QChannel = (QData*)malloc(Qsize);
memset(Q, 0, Qsize);
INT32 track_linear = 1;
while (1)
{
subQidx += 12;
if (subQidx >= subQsize) break;
memcpy(Q, &subQdata[subQidx], 12);
subQidx += 12;
subQidx += 6*12;
if (Q->index && (Q->Control & 1) && (cdimgTOC->TrackData[bcd(Q->track) - 1].TrackNumber == 0))
{
// new track
track = bcd(Q->track);
if (track == track_linear) {
//dprintf(_T(" - Track %i found starting at %02X:%02X:%02X\n"), track, Q->MSFabs.M, Q->MSFabs.S, Q->MSFabs.F);
//bprintf(0, _T(" contrl: %X track %X(%d) indx %X\n"),Q->Control,Q->track,track,Q->index);
cdimgTOC->TrackData[track - 1].Control = Q->Control; // >> 4;
cdimgTOC->TrackData[track - 1].TrackNumber = Q->track;
cdimgTOC->TrackData[track - 1].Address[1] = Q->MSFabs.M;
cdimgTOC->TrackData[track - 1].Address[2] = Q->MSFabs.S;
cdimgTOC->TrackData[track - 1].Address[3] = Q->MSFabs.F;
track_linear++;
} else {
//bprintf(0, _T("skipped weird track: %X (%X)\n"), track, Q->track);
}
}
Q++;
}
cdimgTOC->LastTrack = track;
free(subQdata);
cd_pregap = QChannel[0].MSFabs.F + QChannel[0].MSFabs.S * CD_FRAMES_SECOND + QChannel[0].MSFabs.M * CD_FRAMES_MINUTE;
//bprintf(0, _T("pregap lba: %d MSF: %d:%d:%d\n"), cd_pregap, QChannel[0].MSFabs.M, QChannel[0].MSFabs.S, QChannel[0].MSFabs.F);
{ // Make a fake last-track w/total image size (for bounds checking)
h = _wfopen(cdimgTOC->Image, _T("rb"));
if (h)
{
fseek(h, 0, SEEK_END);
const UINT8* address = cdimgLBAToMSF((ftell(h) + 2351) / 2352);
fclose(h);
cdimgTOC->TrackData[cdimgTOC->LastTrack].Address[1] = address[1];
cdimgTOC->TrackData[cdimgTOC->LastTrack].Address[2] = address[2];
cdimgTOC->TrackData[cdimgTOC->LastTrack].Address[3] = address[3];
}
}
return 0;
}
static int cdimgParseCueFile()
{
TCHAR szLine[1024];
TCHAR szFile[1024];
TCHAR* s;
TCHAR* t;
FILE* h;
int track = 1;
int length;
cdimgTOC->ImageType = CD_TYPE_BINCUE;
cdimgTOC->FirstTrack = 1;
cdimgTOC->LastTrack = 1;
cdimgTOC->TrackData[0].Address[1] = 0;
cdimgTOC->TrackData[0].Address[2] = 2;
cdimgTOC->TrackData[0].Address[3] = 0;
cd_pregap = 150; // default for bin/cue?
// derive .bin name from .cue filename (it gets the actual name from the .cue, below)
length = _tcslen(CDEmuImage);
_tcscpy(cdimgTOC->Image, CDEmuImage);
_tcscpy(cdimgTOC->Image + length - 4, _T(".bin"));
//bprintf(0, _T("Image file: %s\n"),cdimgTOC->Image);
h = _tfopen(CDEmuImage, _T("rt"));
if (h == NULL) {
return 1;
}
while (1) {
if (_fgetts(szLine, sizeof(szLine), h) == NULL) {
break;
}
length = _tcslen(szLine);
// get rid of the linefeed at the end
while (length && (szLine[length - 1] == _T('\r') || szLine[length - 1] == _T('\n'))) {
szLine[length - 1] = 0;
length--;
}
s = szLine;
// file info
if ((t = LabelCheck(s, _T("FILE"))) != 0) {
s = t;
TCHAR* szQuote;
// read filename
QuoteRead(&szQuote, NULL, s);
_sntprintf(szFile, ExtractFilename(CDEmuImage) - CDEmuImage, _T("%s"), CDEmuImage);
_sntprintf(szFile + (ExtractFilename(CDEmuImage) - CDEmuImage), 1024 - (ExtractFilename(CDEmuImage) - CDEmuImage), _T("/%s"), szQuote);
if (track == 1) {
//bprintf(0, _T("Image file (from .CUE): %s\n"), szFile);
_tcscpy(cdimgTOC->Image, szFile);
}
continue;
}
// track info
if ((t = LabelCheck(s, _T("TRACK"))) != 0) {
s = t;
// track number
track = _tcstol(s, &t, 10);
if (track < 1 || track > MAXIMUM_NUMBER_TRACKS) {
fclose(h);
return 1;
}
if (track < cdimgTOC->FirstTrack) {
cdimgTOC->FirstTrack = track;
}
if (track > cdimgTOC->LastTrack) {
cdimgTOC->LastTrack = track;
}
cdimgTOC->TrackData[track - 1].TrackNumber = tobcd(track);
s = t;
// type of track
if ((t = LabelCheck(s, _T("MODE1/2352"))) != 0) {
cdimgTOC->TrackData[track - 1].Control = 0x41;
//bprintf(0, _T(".cue: Track #%d, data.\n"), track);
continue;
}
if ((t = LabelCheck(s, _T("AUDIO"))) != 0) {
cdimgTOC->TrackData[track - 1].Control = 0x01;
//bprintf(0, _T(".cue: Track #%d, AUDIO.\n"), track);
continue;
}
fclose(h);
return 1;
}
// PREGAP (not handled)
if ((t = LabelCheck(s, _T("PREGAP"))) != 0) {
continue;
}
// TRACK Index
if ((t = LabelCheck(s, _T("INDEX 01"))) != 0) {
s = t;
int M, S, F;
// index M
M = _tcstol(s, &t, 10);
s = t + 1;
// index S
S = _tcstol(s, &t, 10);
s = t + 1;
// index F
F = _tcstol(s, &t, 10);
if (M < 0 || M > 100 || S < 0 || S > 59 || F < 0 || F > 74) {
bprintf(0, _T("Bad M:S:F!\n"));
fclose(h);
return 1;
}
const UINT8 address[] = { 0, (UINT8)M, (UINT8)S, (UINT8)F };
const UINT8* newaddress = cdimgLBAToMSF(dinkMSFToLBA(address) + cd_pregap);
//const UINT8* newaddressUNBCD = dinkLBAToMSF(dinkMSFToLBA(address) + cd_pregap);
//bprintf(0, _T("Track MSF: %02d:%02d:%02d "), newaddressUNBCD[1], newaddressUNBCD[2], newaddressUNBCD[3]);
cdimgTOC->TrackData[track - 1].Address[1] = newaddress[1];
cdimgTOC->TrackData[track - 1].Address[2] = newaddress[2];
cdimgTOC->TrackData[track - 1].Address[3] = newaddress[3];
continue;
}
}
fclose(h);
{
h = _wfopen(cdimgTOC->Image, _T("rb"));
if (h)
{
fseek(h, 0, SEEK_END);
const UINT8* address = cdimgLBAToMSF((ftell(h) + 2351) / 2352);
fclose(h);
cdimgTOC->TrackData[cdimgTOC->LastTrack].Address[1] = address[1];
cdimgTOC->TrackData[cdimgTOC->LastTrack].Address[2] = address[2];
cdimgTOC->TrackData[cdimgTOC->LastTrack].Address[3] = address[3];
}
}
return 0;
}
// -----------------------------------------------------------------------------
static int cdimgExit()
{
cdimgExitStream();
if (cdimgFile)
fclose(cdimgFile);
cdimgFile = NULL;
cdimgFileSize = 0;
cdimgTrack = 0;
cdimgLBA = 0;
if (cdimgTOC)
free(cdimgTOC);
cdimgTOC = NULL;
free(QChannel);
QChannel = NULL;
return 0;
}
static int cdimgInit()
{
cdimgTOC = (cdimgCDROM_TOC*)malloc(sizeof(cdimgCDROM_TOC));
if (cdimgTOC == NULL)
return 1;
memset(cdimgTOC, 0, sizeof(cdimgCDROM_TOC));
cdimgTOC->ImageType = CD_TYPE_NONE;
TCHAR* filename = ExtractFilename(CDEmuImage);
if (_tcslen(filename) < 4)
return 1;
if (_tcscmp(_T(".cue"), filename + _tcslen(filename) - 4) == 0)
{
if (cdimgParseCueFile())
{
dprintf(_T("*** Couldn't parse .cue file\n"));
cdimgExit();
return 1;
}
} else
if (_tcscmp(_T(".ccd"), filename + _tcslen(filename) - 4) == 0)
{
if (cdimgParseSubFile())
{
dprintf(_T("*** Couldn't parse .sub file\n"));
cdimgExit();
return 1;
}
}
else
{
dprintf(_T("*** Couldn't find .img / .bin file\n"));
cdimgExit();
return 1;
}
cdimgPrintImageInfo();
CDEmuStatus = idle;
cdimgInitStream();
{
char buf[2048];
FILE* h = _wfopen(cdimgTOC->Image, _T("rb")); cdimgLBA++;
if (h)
{
if (fseek(h, 16 * 2352 + 16, SEEK_SET) == 0)
{
if (fread(buf, 1, 2048, h) == 2048)
{
if (strncmp("CD001", buf + 1, 5) == 0)
{
buf[48] = 0;
/* BurnDrvFindMedium(buf + 40); */
}
else
dprintf(_T("*** Bad CD!\n"));
}
}
fclose(h);
}
//CDEmuPrintCDName();
}
return 0;
}
static void cdimgCloseFile()
{
if (cdimgFile)
{
fclose(cdimgFile);
cdimgFile = NULL;
}
}
static int cdimgStop()
{
cdimgCloseFile();
CDEmuStatus = idle;
return 0;
}
static int cdimgFindTrack(int LBA)
{
int trk = 0;
for (trk = cdimgTOC->FirstTrack - 1; trk < cdimgTOC->LastTrack; trk++)
if (LBA < cdimgMSFToLBA(cdimgTOC->TrackData[trk + 1].Address))
break;
return trk;
}
static int cdimgPlayLBA(int LBA)
{
cdimgStop();
if (QChannel != NULL) { // .CCD dump w/.SUB
if (QChannel[LBA].Control & 0x40)
return 1;
} else { // .BIN/.CUE dump
if (cdimgTOC->TrackData[cdimgFindTrack(LBA)].Control & 0x40)
return 1;
}
cdimgLBA = LBA;
cdimgTrack = cdimgFindTrack(cdimgLBA);
if (cdimgTrack >= cdimgTOC->LastTrack)
return 1;
bprintf(PRINT_IMPORTANT, _T(" playing track %2i\n"), cdimgTrack + 1);
cdimgFile = _wfopen(cdimgTOC->Image, _T("rb"));
if (cdimgFile == NULL)
return 1;
// advance if we're not starting at the beginning of a CD
if (cdimgLBA > cd_pregap)
cdimgSkip(cdimgFile, (cdimgLBA - cd_pregap) * (44100 / CD_FRAMES_SECOND));
// fill the input buffer
if ((cdimgOutputbufferSize = fread(cdimgOutputbuffer, 4, cdimgOUT_SIZE, cdimgFile)) <= 0)
return 1;
cdimgOutputPosition = 0;
cdimgSamples = 0;
cdimgLBA = cdimgMSFToLBA(cdimgTOC->TrackData[cdimgTrack].Address);
CDEmuStatus = playing;
return 0;
}
static int cdimgPlay(UINT8 M, UINT8 S, UINT8 F)
{
const UINT8 address[] = { 0, M, S, F };
dprintf(_T(" play %02i:%02i:%02i\n"), M, S, F);
return cdimgPlayLBA(cdimgMSFToLBA(address));
}
static int cdimgLoadSector(int LBA, char* pBuffer)
{
//dprintf(_T(" read LBA %i\n"), LBA);
if (CDEmuStatus == playing) return 0; // this might cause problems? - dink
if (LBA != cdimgLBA)
{
if (cdimgFile == NULL)
{
cdimgStop();
cdimgFile = _wfopen(cdimgTOC->Image, _T("rb"));
if (cdimgFile == NULL)
return 0;
}
//bprintf(PRINT_IMPORTANT, _T(" loading data at LBA %08u 0x%08X\n"), (LBA - cdimgMSFToLBA(cdimgTOC->TrackData[cdimgTrack].Address)) * 2352, LBA * 2352);
if (fseek(cdimgFile, (LBA - cd_pregap) * 2352, SEEK_SET))
{
dprintf(_T("*** couldn't seek (LBA %08u)\n"), LBA);
//cdimgStop(); // stopping here will break ssrpg
return 0;
}
CDEmuStatus = reading;
}
//dprintf(_T(" reading LBA %08i 0x%08X"), LBA, ftell(cdimgFile));
cdimgLBA = cdimgMSFToLBA(cdimgTOC->TrackData[0].Address) + (ftell(cdimgFile) + 2351) / 2352 - cd_pregap;
bool status = (fread(pBuffer, 1, 2352, cdimgFile) <= 0);
if (status)
{
dprintf(_T("*** couldn't read from file\n"));
cdimgStop();
return 0;
}
// dprintf(_T(" [ %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X ]\n"), pBuffer[0], pBuffer[1], pBuffer[2], pBuffer[3], pBuffer[4], pBuffer[5], pBuffer[6], pBuffer[7], pBuffer[8], pBuffer[9], pBuffer[10], pBuffer[11], pBuffer[12], pBuffer[13], pBuffer[14], pBuffer[15]);
cdimgLBA++;
return cdimgLBA;
}
static UINT8* cdimgReadTOC(int track)
{
static UINT8 TOCEntry[4];
if (track == -1)
{
TOCEntry[0] = tobcd(cdimgTOC->FirstTrack - 1);
TOCEntry[1] = tobcd(cdimgTOC->LastTrack);
TOCEntry[2] = 0;
TOCEntry[3] = 0;
return TOCEntry;
}
if (track == -2)
{
TOCEntry[0] = cdimgTOC->TrackData[cdimgTOC->LastTrack].Address[1];
TOCEntry[1] = cdimgTOC->TrackData[cdimgTOC->LastTrack].Address[2];
TOCEntry[2] = cdimgTOC->TrackData[cdimgTOC->LastTrack].Address[3];
TOCEntry[3] = 0;
return TOCEntry;
}
track = bcd(track);
if (track >= cdimgTOC->FirstTrack - 1 && track <= cdimgTOC->LastTrack)
{
TOCEntry[0] = cdimgTOC->TrackData[track - 1].Address[1];
TOCEntry[1] = cdimgTOC->TrackData[track - 1].Address[2];
TOCEntry[2] = cdimgTOC->TrackData[track - 1].Address[3];
TOCEntry[3] = cdimgTOC->TrackData[track - 1].Control >> 4;
}
// dprintf(_T(" track %02i - %02x:%02x:%02x\n"), track, TOCEntry[0], TOCEntry[1], TOCEntry[2]);
return TOCEntry;
}
static UINT8* cdimgReadQChannel()
{
// Q channel format
// byte 0: 41 = data, 1 = cdda ( flags described at https://en.wikipedia.org/wiki/Compact_Disc_subcode )
// track, index, M rel, S rel, F rel, M to start, S to start, F to start, 0, CRC, CRC
// if index is 0, MSF rel counts down to next track
static UINT8 QChannelData[8];
switch (CDEmuStatus)
{
case reading:
case playing:
{
if (QChannel != NULL) { // .CCD/.SUB
QChannelData[0] = QChannel[cdimgLBA].track;
QChannelData[1] = QChannel[cdimgLBA].MSFrel.M;
QChannelData[2] = QChannel[cdimgLBA].MSFrel.S;
QChannelData[3] = QChannel[cdimgLBA].MSFrel.F;
QChannelData[4] = QChannel[cdimgLBA].MSFrel.M;
QChannelData[5] = QChannel[cdimgLBA].MSFrel.S;
QChannelData[6] = QChannel[cdimgLBA].MSFrel.F;
QChannelData[7] = QChannel[cdimgLBA].Control;
} else { // .BIN/.ISO
const UINT8* AddressAbs = cdimgLBAToMSF(cdimgLBA);
const UINT8* AddressRel = cdimgLBAToMSF(cdimgLBA - cdimgMSFToLBA(cdimgTOC->TrackData[cdimgTrack].Address));
QChannelData[0] = cdimgTOC->TrackData[cdimgTrack].TrackNumber;
QChannelData[1] = AddressAbs[1];
QChannelData[2] = AddressAbs[2];
QChannelData[3] = AddressAbs[3];
QChannelData[4] = AddressRel[1];
QChannelData[5] = AddressRel[2];
QChannelData[6] = AddressRel[3];
QChannelData[7] = cdimgTOC->TrackData[cdimgTrack].Control;
}
// dprintf(_T(" Q %02x %02x %02x:%02x:%02x %02x:%02x:%02x\n"), QChannel[cdimgLBA].track, QChannel[cdimgLBA].index, QChannel[cdimgLBA].MSFrel.M, QChannel[cdimgLBA].MSFrel.S, QChannel[cdimgLBA].MSFrel.F, QChannel[cdimgLBA].MSFabs.M, QChannel[cdimgLBA].MSFabs.S, QChannel[cdimgLBA].MSFabs.F);
break;
}
case paused:
break;
default:
memset(QChannelData, 0, sizeof(QChannelData));
}
return QChannelData;
}
static int cdimgGetSoundBuffer(short* buffer, int samples)
{
#define CLIP(A) ((A) < -0x8000 ? -0x8000 : (A) > 0x7fff ? 0x7fff : (A))
if (CDEmuStatus != playing) {
memset(cdimgOutputbuffer, 0x00, cdimgOUT_SIZE * 2 * sizeof(short));
return 0;
}
cdimgSamples += samples;
while (cdimgSamples > (44100 / CD_FRAMES_SECOND))
{
cdimgSamples -= (44100 / CD_FRAMES_SECOND);
cdimgLBA++;
/* if (cdimgFile == NULL) // play next track? bad idea. -dink
if (cdimgLBA >= cdimgMSFToLBA(cdimgTOC->TrackData[cdimgTrack + 1].Address))
cdimgPlayLBA(cdimgLBA); */
}
if (cdimgFile == NULL) { // restart play if fileptr lost
bprintf(0, _T("CDDA file pointer lost, re-starting!\n"));
if (cdimgLBA < cdimgMSFToLBA(cdimgTOC->TrackData[cdimgTrack + 1].Address))
cdimgPlayLBA(cdimgLBA);
}
if (cdimgFile == NULL) { // restart failed (really?) - time to give up.
cdimgStop();
return 0;
}
if ((cdimgOutputPosition + samples) >= cdimgOutputbufferSize)
{
short* src = cdimgOutputbuffer + cdimgOutputPosition * 2;
short* dst = buffer;
for (int i = (cdimgOutputbufferSize - cdimgOutputPosition) * 2 - 1; i > 0; )
{
dst[i] = CLIP((src[i]) + dst[i]); i--;
dst[i] = CLIP((src[i]) + dst[i]); i--;
}
buffer += (cdimgOutputbufferSize - cdimgOutputPosition) * 2;
samples -= (cdimgOutputbufferSize - cdimgOutputPosition);
cdimgOutputPosition = 0;
cdimgLBA++;
if ((cdimgOutputbufferSize = fread(cdimgOutputbuffer, 4, cdimgOUT_SIZE, cdimgFile)) <= 0)
cdimgStop();
if (cdimgLBA >= cdimgMSFToLBA(cdimgTOC->TrackData[cdimgTrack + 1 /* next track */].Address)) {
bprintf(0, _T("End of audio track %d reached!! stopping.\n"), cdimgTrack + 1);
cdimgStop();
}
}
if ((cdimgOutputPosition + samples) < cdimgOutputbufferSize)
{
short* src = cdimgOutputbuffer + cdimgOutputPosition * 2;
short* dst = buffer;
for (int i = samples * 2 - 1; i > 0; )
{
dst[i] = CLIP((src[i]) + dst[i]); i--;
dst[i] = CLIP((src[i]) + dst[i]); i--;
}
cdimgOutputPosition += samples;
}
return 0;
#undef CLIP
}
static INT32 cdimgScan(INT32 nAction, INT32 *pnMin)
{
if (nAction & ACB_VOLATILE) {
SCAN_VAR(CDEmuStatus);
SCAN_VAR(cdimgTrack);
SCAN_VAR(cdimgLBA);
}
if (nAction & ACB_WRITE) {
cdimgCloseFile();
}
return 0;
}
static int cdimgGetSettings(InterfaceInfo* pInfo)
{
return 0;
}
struct CDEmuDo cdimgDo = { cdimgExit, cdimgInit, cdimgStop, cdimgPlay, cdimgLoadSector, cdimgReadTOC, cdimgReadQChannel, cdimgGetSoundBuffer, cdimgScan, cdimgGetSettings, _T("raw image CD emulation") };

View File

@ -62,9 +62,10 @@ struct CDEmuDo {
INT32 (*CDEmuStop)();
INT32 (*CDEmuPlay)(UINT8 M, UINT8 S, UINT8 F);
INT32 (*CDEmuLoadSector)(INT32 LBA, char* pBuffer);
UINT8* (*CDEmuReadTOC)(INT32 track);
UINT8* (*CDEmuReadQChannel)();
UINT8* (*CDEmuReadTOC)(INT32 track);
UINT8* (*CDEmuReadQChannel)();
INT32 (*CDEmuGetSoundBuffer)(INT16* buffer, INT32 samples);
INT32 (*CDEmuScan)(INT32 nAction, INT32 *pnMin);
// Get plugin info
INT32 (*GetPluginSettings)(InterfaceInfo* pInfo);
const TCHAR* szModuleName;