Compare commits

...

7 Commits

Author SHA1 Message Date
Ty 2dadea4168
Merge 37555e3048 into fbe0c8b9cc 2025-01-17 15:22:49 -05:00
shockdude fbe0c8b9cc USB: Fix DJ Hero Turntable automatic mapping & turntable multiplier 2025-01-17 10:44:52 -05:00
Ziemas 2e3501366f iR3000A/iR5900: Partial revert of 8c98f5d928 ("Remove mid block jumping") 2025-01-17 10:42:48 -05:00
Ziemas ef7169dbbf host: fix gcc build 2025-01-17 10:42:13 -05:00
Ty Lamontagne 37555e3048
CDVD | CHD: Account for pre/post gap offsets when filling TOC
This will fix discs with tracks with both an INDEX 00 and INDEX 01
2024-11-27 15:55:11 -05:00
Ty Lamontagne d8f18a3318
CDVD: Byte swap hack. CHD CD audio with OSDSYS is working 2024-11-27 15:54:56 -05:00
Ty Lamontagne 47a732d0fe
CDVD: CHD cue support for audio CDs
experimental and will blow out your ears
2024-11-27 15:25:59 -05:00
13 changed files with 231 additions and 58 deletions

View File

@ -66,6 +66,14 @@ struct cdvdTN
u8 etrack; //number of the last track
};
struct toc_entry
{
u32 lba;
u8 track;
u8 adr : 4;
u8 control : 4;
};
// SpindleCtrl Masks
#define CDVD_SPINDLE_SPEED 0x7 // Speed ranges from 0-3 (1, 2, 3, 4x for DVD) and 0-5 (1, 2, 4, 12, 24x for CD)
#define CDVD_SPINDLE_NOMINAL 0x40 // Changes the speed to be constant (CLV) based on current speed

View File

@ -21,14 +21,6 @@ class Error;
extern int curDiskType;
extern int curTrayStatus;
struct toc_entry
{
u32 lba;
u8 track;
u8 adr : 4;
u8 control : 4;
};
class IOCtlSrc
{
IOCtlSrc(const IOCtlSrc&) = delete;

View File

@ -18,6 +18,44 @@ static int pmode, cdtype;
static s32 layer1start = -1;
static bool layer1searched = false;
static void ISOParseTOC()
{
tracks.fill(cdvdTrack{});
if (iso.GetType() != ISOTYPE_AUDIO)
{
strack = 1;
etrack = 1;
return;
}
strack = 0xFF;
etrack = 0;
// Audio CD
for (const auto& entry : iso.ReadTOC())
{
const u8 track = entry.track;
if (track < 1 || track >= tracks.size())
{
Console.Warning("CDVD: Invalid track index %u, ignoring\n", track);
continue;
}
strack = std::min(strack, track);
etrack = std::max(etrack, track);
tracks[track].start_lba = entry.lba;
if ((entry.control & 0x0C) == 0x04)
{
Console.Warning("CDVD: Unsupported data track reading. Assuming MODE1?\n");
tracks[track].type = CDVD_MODE1_TRACK;
}
else
{
tracks[track].type = CDVD_AUDIO_TRACK;
}
}
}
static void ISOclose()
{
iso.Close();
@ -49,6 +87,8 @@ static bool ISOopen(std::string filename, Error* error)
break;
}
ISOParseTOC();
layer1start = -1;
layer1searched = false;
@ -60,34 +100,56 @@ static bool ISOprecache(ProgressCallback* progress, Error* error)
return iso.Precache(progress, error);
}
static void lsn_to_msf(u8* minute, u8* second, u8* frame, u32 lsn)
{
*frame = itob(lsn % 75);
lsn /= 75;
*second = itob(lsn % 60);
lsn /= 60;
*minute = itob(lsn % 100);
}
static s32 ISOreadSubQ(u32 lsn, cdvdSubQ* subq)
{
// fake it
u8 min, sec, frm;
subq->ctrl = 4;
subq->adr = 1;
subq->trackNum = itob(1);
subq->trackIndex = itob(1);
lba_to_msf(lsn, &min, &sec, &frm);
subq->trackM = itob(min);
subq->trackS = itob(sec);
subq->trackF = itob(frm);
subq->pad = 0;
memset(subq, 0, sizeof(cdvdSubQ));
lba_to_msf(lsn + (2 * 75), &min, &sec, &frm);
subq->discM = itob(min);
subq->discS = itob(sec);
subq->discF = itob(frm);
lsn_to_msf(&subq->discM, &subq->discS, &subq->discF, lsn + 150);
// FIXME: Verify this is correct for ISOTYPE_CD :S
if (iso.GetType() != ISOTYPE_AUDIO && iso.GetType() != ISOTYPE_CD)
{
subq->ctrl = 4;
subq->adr = 1;
subq->trackNum = itob(1);
subq->trackIndex = itob(1);
}
else
{
u8 i = strack;
while (i < etrack && lsn >= tracks[i + 1].start_lba)
++i;
lsn -= tracks[i].start_lba;
subq->ctrl = 1;
subq->adr = 1;
subq->trackNum = i;
subq->trackIndex = 1; // FIXME ???
}
lsn_to_msf(&subq->trackM, &subq->trackS, &subq->trackF, lsn);
Console.Warning("CDVD: SubQ M %02x S %02x F %02x\n", subq->trackM, subq->trackS, subq->trackF);
return 0;
}
static s32 ISOgetTN(cdvdTN* Buffer)
{
Buffer->strack = 1;
Buffer->etrack = 1;
Buffer->strack = strack;
Buffer->etrack = etrack;
return 0;
}
@ -97,13 +159,15 @@ static s32 ISOgetTD(u8 Track, cdvdTD* Buffer)
if (Track == 0)
{
Buffer->lsn = iso.GetBlockCount();
}
else
{
Buffer->type = CDVD_MODE1_TRACK;
Buffer->lsn = 0;
Buffer->type = 0;
return 0;
}
if (Track < strack || Track > etrack)
return -1;
Buffer->lsn = tracks[Track].start_lba;
Buffer->type = tracks[Track].type;
return 0;
}
@ -299,11 +363,12 @@ static s32 ISOgetTOC(void* toc)
{
err = ISOgetTD(i, &trackInfo);
lba_to_msf(trackInfo.lsn, &min, &sec, &frm);
tocBuff[i * 10 + 30] = trackInfo.type;
tocBuff[i * 10 + 32] = err == -1 ? 0 : itob(i); //number
tocBuff[i * 10 + 37] = itob(min);
tocBuff[i * 10 + 38] = itob(sec);
tocBuff[i * 10 + 39] = itob(frm);
const u8 tocIndex = i - diskInfo.strack;
tocBuff[tocIndex * 10 + 30] = trackInfo.type;
tocBuff[tocIndex * 10 + 32] = err == -1 ? 0 : itob(i); //number
tocBuff[tocIndex * 10 + 37] = itob(min);
tocBuff[tocIndex * 10 + 38] = itob(sec);
tocBuff[tocIndex * 10 + 39] = itob(frm);
}
}
else

View File

@ -386,8 +386,9 @@ bool ChdFileReader::Open2(std::string filename, Error* error)
// The file size in the header is incorrect, each track gets padded to a multiple of 4 frames.
// (see chdman.cpp from MAME). Instead, we pull the real frame count from the TOC.
std::vector<toc_entry> entries;
u64 total_frames;
if (ParseTOC(&total_frames))
if (ParseTOC(&total_frames, entries))
{
file_size = total_frames * static_cast<u64>(chd_header->unitbytes);
}
@ -409,6 +410,21 @@ bool ChdFileReader::Precache2(ProgressCallback* progress, Error* error)
return fileWrapper->Precache(progress, error);
}
std::vector<toc_entry> ChdFileReader::ReadTOC()
{
u64 total_frames;
std::vector<toc_entry> entries;
if (ParseTOC(&total_frames, entries))
{
return entries;
}
else
{
Console.Warning("Failed to parse CHD TOC, file size may be incorrect.");
return {};
}
}
ThreadedFileReader::Chunk ChdFileReader::ChunkForOffset(u64 offset)
{
Chunk chunk = {0};
@ -454,11 +470,11 @@ u32 ChdFileReader::GetBlockCount() const
return (file_size - m_dataoffset) / m_internalBlockSize;
}
bool ChdFileReader::ParseTOC(u64* out_frame_count)
bool ChdFileReader::ParseTOC(u64* out_frame_count, std::vector<toc_entry>& entries)
{
u64 total_frames = 0;
int max_found_track = -1;
u64 total_gap_frames = 0;
for (int search_index = 0;; search_index++)
{
char metadata_str[256];
@ -498,17 +514,28 @@ bool ChdFileReader::ParseTOC(u64* out_frame_count)
}
}
DevCon.WriteLn(fmt::format("CHD Track {}: frames:{} pregap:{} postgap:{} type:{} sub:{} pgtype:{} pgsub:{}",
Console.WriteLn(fmt::format("CHD Track {}: frames:{} pregap:{} postgap:{} type:{} sub:{} pgtype:{} pgsub:{}",
track_num, frames, pregap_frames, postgap_frames, type_str, subtype_str, pgtype_str, pgsub_str));
// PCSX2 doesn't currently support multiple tracks for CDs.
if (track_num != 1)
if (track_num != 0)
{
Console.Warning(fmt::format(" Ignoring track {} in CHD.", track_num, frames));
continue;
toc_entry entry{};
entry.lba = static_cast<u32>(total_frames) - total_gap_frames;
entry.track = static_cast<u8>(track_num);
entry.adr = 1;
entry.control = 0;
//FIXME: DATA track?
if (strncmp(type_str, "AUDIO", 5) != 0)
entry.control |= 0x04;
entries.push_back(entry);
}
total_frames += static_cast<u64>(pregap_frames) + static_cast<u64>(frames) + static_cast<u64>(postgap_frames);
// I have not found a CHD with an audio track with a postgap, consider that untested
total_gap_frames += static_cast<u64>(pregap_frames) + static_cast<u64>(postgap_frames);
total_frames += total_gap_frames + static_cast<u64>(frames);
max_found_track = std::max(max_found_track, track_num);
}

View File

@ -19,6 +19,8 @@ public:
bool Precache2(ProgressCallback* progress, Error* error) override;
std::vector<toc_entry> ReadTOC() override;
Chunk ChunkForOffset(u64 offset) override;
int ReadChunk(void* dst, s64 blockID) override;
@ -26,7 +28,7 @@ public:
uint GetBlockCount(void) const override;
private:
bool ParseTOC(u64* out_frame_count);
bool ParseTOC(u64* out_frame_count, std::vector<toc_entry>& entries);
chd_file* ChdFile = nullptr;
u64 file_size = 0;

View File

@ -160,9 +160,31 @@ int InputIsoFile::FinishRead3(u8* dst, uint mode)
dst[diff - 9] = 2;
}
// Seems like CHD data ends up being the wrong endianess for audio
// Confidence is about 50% on this one, but it seems to work
// (CHD is the only file with a TOC anyways, so who cares about the other formats)
if (m_type == ISOTYPE_AUDIO && mode == CDVD_MODE_2352)
{
for (int i = 0; i < 2352; i += 2)
{
std::swap(dst[diff + i], dst[diff + i + 1]);
}
}
return 0;
}
std::vector<toc_entry> InputIsoFile::ReadTOC() const
{
std::vector<toc_entry> toc;
if (m_type == ISOTYPE_ILLEGAL)
return toc;
toc = m_reader->ReadTOC();
return toc;
}
InputIsoFile::InputIsoFile()
{
_init();
@ -271,7 +293,7 @@ bool InputIsoFile::tryIsoType(u32 size, u32 offset, u32 blockofs)
// Returns true if the image is valid/known/supported, or false if not (type == ISOTYPE_ILLEGAL).
bool InputIsoFile::Detect(bool readType)
{
m_type = ISOTYPE_ILLEGAL;
m_type = ISOTYPE_ILLEGAL;
// First sanity check: no sane CD image has less than 16 sectors, since that's what
// we need simply to contain a TOC. So if the file size is not large enough to

View File

@ -3,6 +3,7 @@
#pragma once
#include "CDVDcommon.h"
#include "CDVD/CDVD.h"
#include "CDVD/ThreadedFileReader.h"
#include <memory>
@ -75,6 +76,8 @@ public:
void BeginRead2(uint lsn);
int FinishRead3(u8* dest, uint mode);
std::vector<toc_entry> ReadTOC() const;
protected:
void _init();

View File

@ -264,6 +264,12 @@ bool ThreadedFileReader::Precache2(ProgressCallback* progress, Error* error)
return false;
}
std::vector<toc_entry> ThreadedFileReader::ReadTOC()
{
return {};
}
bool ThreadedFileReader::CheckAvailableMemoryForPrecaching(u64 required_size, Error* error)
{
// Don't allow precaching to use more than 50% of system memory.

View File

@ -4,6 +4,7 @@
#pragma once
#include "common/Pcsx2Defs.h"
#include "CDVDcommon.h"
#include <thread>
#include <mutex>
@ -117,6 +118,7 @@ public:
bool Open(std::string filename, Error* error);
bool Precache(ProgressCallback* progress, Error* error);
virtual std::vector<toc_entry> ReadTOC();
int ReadSync(void* pBuffer, u32 sector, u32 count);
void BeginRead(void* pBuffer, u32 sector, u32 count);
int FinishRead();

View File

@ -10,6 +10,7 @@
#include <ctime>
#include <functional>
#include <memory>
#include <mutex>
#include <optional>
#include <string>

View File

@ -93,19 +93,19 @@ namespace usb_pad
u8 right_turntable = 0x80;
if (data.left_turntable_ccw > 0)
{
left_turntable -= static_cast<u8>(std::min<int>(data.left_turntable_ccw * turntable_multiplier, 0x7F));
left_turntable -= static_cast<u8>(std::min<int>(data.left_turntable_ccw, 0x7F));
}
else
{
left_turntable += static_cast<u8>(std::min<int>(data.left_turntable_cw * turntable_multiplier, 0x7F));
left_turntable += static_cast<u8>(std::min<int>(data.left_turntable_cw, 0x7F));
}
if (data.right_turntable_ccw > 0)
{
right_turntable -= static_cast<u8>(std::min<int>(data.right_turntable_ccw * turntable_multiplier, 0x7F));
right_turntable -= static_cast<u8>(std::min<int>(data.right_turntable_ccw, 0x7F));
}
else
{
right_turntable += static_cast<u8>(std::min<int>(data.right_turntable_cw * turntable_multiplier, 0x7F));
right_turntable += static_cast<u8>(std::min<int>(data.right_turntable_cw, 0x7F));
}
buf[3] = 0x80;
buf[4] = 0x80;
@ -369,19 +369,19 @@ namespace usb_pad
break;
case CID_DJ_LEFT_TURNTABLE_CW:
s->data.left_turntable_cw = static_cast<u32>(std::clamp<long>(std::lroundf(value * 128.0f), 0, 128));
s->data.left_turntable_cw = static_cast<u32>(std::clamp<long>(std::lroundf(value * s->turntable_multiplier * 128.0f), 0, 128));
break;
case CID_DJ_LEFT_TURNTABLE_CCW:
s->data.left_turntable_ccw = static_cast<u32>(std::clamp<long>(std::lroundf(value * 128.0f), 0, 128));
s->data.left_turntable_ccw = static_cast<u32>(std::clamp<long>(std::lroundf(value * s->turntable_multiplier * 128.0f), 0, 128));
break;
case CID_DJ_RIGHT_TURNTABLE_CW:
s->data.right_turntable_cw = static_cast<u32>(std::clamp<long>(std::lroundf(value * 128.0f), 0, 128));
s->data.right_turntable_cw = static_cast<u32>(std::clamp<long>(std::lroundf(value * s->turntable_multiplier * 128.0f), 0, 128));
break;
case CID_DJ_RIGHT_TURNTABLE_CCW:
s->data.right_turntable_ccw = static_cast<u32>(std::clamp<long>(std::lroundf(value * 128.0f), 0, 128));
s->data.right_turntable_ccw = static_cast<u32>(std::clamp<long>(std::lroundf(value * s->turntable_multiplier * 128.0f), 0, 128));
break;
case CID_DJ_DPAD_UP:
@ -446,8 +446,8 @@ namespace usb_pad
{"EffectsKnobRight", TRANSLATE_NOOP("USB", "Effects Knob Right"), nullptr, InputBindingInfo::Type::HalfAxis, CID_DJ_EFFECTSKNOB_RIGHT, GenericInputBinding::RightStickRight},
{"LeftTurntableCW", TRANSLATE_NOOP("USB", "Left Turntable Clockwise"), nullptr, InputBindingInfo::Type::HalfAxis, CID_DJ_LEFT_TURNTABLE_CW, GenericInputBinding::LeftStickRight},
{"LeftTurntableCCW", TRANSLATE_NOOP("USB", "Left Turntable Counterclockwise"), nullptr, InputBindingInfo::Type::HalfAxis, CID_DJ_LEFT_TURNTABLE_CCW, GenericInputBinding::LeftStickLeft},
{"RightTurntableCW", TRANSLATE_NOOP("USB", "Right Turntable Clockwise"), nullptr, InputBindingInfo::Type::HalfAxis, CID_DJ_RIGHT_TURNTABLE_CW, GenericInputBinding::LeftStickDown},
{"RightTurntableCCW", TRANSLATE_NOOP("USB", "Right Turntable Counterclockwise"), nullptr, InputBindingInfo::Type::HalfAxis, CID_DJ_RIGHT_TURNTABLE_CCW, GenericInputBinding::LeftStickUp},
{"RightTurntableCW", TRANSLATE_NOOP("USB", "Right Turntable Clockwise"), nullptr, InputBindingInfo::Type::HalfAxis, CID_DJ_RIGHT_TURNTABLE_CW, GenericInputBinding::LeftStickUp},
{"RightTurntableCCW", TRANSLATE_NOOP("USB", "Right Turntable Counterclockwise"), nullptr, InputBindingInfo::Type::HalfAxis, CID_DJ_RIGHT_TURNTABLE_CCW, GenericInputBinding::LeftStickDown},
{"LeftTurntableGreen", TRANSLATE_NOOP("USB", "Left Turntable Green"), nullptr, InputBindingInfo::Type::Button, CID_DJ_LEFT_GREEN, GenericInputBinding::Unknown},
{"LeftTurntableRed", TRANSLATE_NOOP("USB", "Left Turntable Red"), nullptr, InputBindingInfo::Type::Button, CID_DJ_LEFT_RED, GenericInputBinding::Unknown},
{"LeftTurntableBlue", TRANSLATE_NOOP("USB", "Left Turntable Blue"), nullptr, InputBindingInfo::Type::Button, CID_DJ_LEFT_BLUE, GenericInputBinding::Unknown},
@ -464,8 +464,8 @@ namespace usb_pad
{
static constexpr const SettingInfo info[] = {
{SettingInfo::Type::Float, "TurntableMultiplier", TRANSLATE_NOOP("USB", "Turntable Multiplier"),
TRANSLATE_NOOP("USB", "Apply a multiplier to the turntable"),
"1.00", "0.00", "100.0", "1.0", "%.0fx", nullptr, nullptr, 1.0f}};
TRANSLATE_NOOP("USB", "Apply a sensitivity multiplier to turntable rotation.\nXbox 360 turntables require a 256x multiplier, most other turntables can use the default 1x multiplier."),
"1.00", "0.00", "512.0", "1.0", "%.0fx", nullptr, nullptr, 1.0f}};
return info;
}

View File

@ -1595,6 +1595,14 @@ static void iopRecRecompile(const u32 startpc)
while (1)
{
BASEBLOCK* pblock = PSX_GETBLOCK(i);
if (i != startpc && pblock->GetFnptr() != (uptr)iopJITCompile)
{
// branch = 3
willbranch3 = 1;
s_nEndBlock = i;
break;
}
psxRegs.code = iopMemRead32(i);

View File

@ -2294,6 +2294,8 @@ static void recRecompile(const u32 startpc)
while (1)
{
BASEBLOCK* pblock = PC_GETBLOCK(i);
// stop before breakpoints
if (isBreakpointNeeded(i) != 0 || isMemcheckNeeded(i) != 0)
{
@ -2311,6 +2313,13 @@ static void recRecompile(const u32 startpc)
eeRecPerfLog.Write("Pagesplit @ %08X : size=%d insts", startpc, (i - startpc) / 4);
break;
}
if (pblock->GetFnptr() != (uptr)JITCompile)
{
willbranch3 = 1;
s_nEndBlock = i;
break;
}
}
//HUH ? PSM ? whut ? THIS IS VIRTUAL ACCESS GOD DAMMIT
@ -2614,6 +2623,34 @@ StartRecomp:
pxAssert((pc - startpc) >> 2 <= 0xffff);
s_pCurBlockEx->size = (pc - startpc) >> 2;
if (HWADDR(pc) <= Ps2MemSize::ExposedRam)
{
BASEBLOCKEX* oldBlock;
int i;
i = recBlocks.LastIndex(HWADDR(pc) - 4);
while ((oldBlock = recBlocks[i--]))
{
if (oldBlock == s_pCurBlockEx)
continue;
if (oldBlock->startpc >= HWADDR(pc))
continue;
if ((oldBlock->startpc + oldBlock->size * 4) <= HWADDR(startpc))
break;
if (memcmp(&recRAMCopy[oldBlock->startpc / 4], PSM(oldBlock->startpc),
oldBlock->size * 4))
{
recClear(startpc, (pc - startpc) / 4);
s_pCurBlockEx = recBlocks.Get(HWADDR(startpc));
pxAssert(s_pCurBlockEx->startpc == HWADDR(startpc));
break;
}
}
memcpy(&recRAMCopy[HWADDR(startpc) / 4], PSM(startpc), pc - startpc);
}
s_pCurBlock->SetFnptr((uptr)recPtr);
if (!(pc & 0x10000000))