From 377f8e8b1c53fcac6713821df63c74725d8e3de7 Mon Sep 17 00:00:00 2001 From: zeromus Date: Thu, 2 Jul 2015 01:06:03 -0500 Subject: [PATCH] reimplement cue SBI loading --- .../API/DiscSectorReader.cs | 23 +++- .../CUE/CUE_Synths.cs | 51 -------- BizHawk.Emulation.DiscSystem/Disc.cs | 119 ++++++++++++++++-- .../Jobs/DiscMountJob.cs | 9 +- 4 files changed, 135 insertions(+), 67 deletions(-) diff --git a/BizHawk.Emulation.DiscSystem/API/DiscSectorReader.cs b/BizHawk.Emulation.DiscSystem/API/DiscSectorReader.cs index 0173b0843a..7e6b407e01 100644 --- a/BizHawk.Emulation.DiscSystem/API/DiscSectorReader.cs +++ b/BizHawk.Emulation.DiscSystem/API/DiscSectorReader.cs @@ -42,8 +42,7 @@ namespace BizHawk.Emulation.DiscSystem public bool ThrowExceptions2048 = true; /// - /// Indicates whether subcode should be delivered deinterleaved. It isn't stored that way on actual discs. - /// How about .sub files? Can't remember right now. + /// Indicates whether subcode should be delivered deinterleaved. It isn't stored that way on actual discs. But it is in .sub files /// public bool DeinterleavedSubcode = true; @@ -161,6 +160,26 @@ namespace BizHawk.Emulation.DiscSystem return 2048; } + /// + /// Reads 12 bytes of subQ data from a sector. + /// This is necessarily deinterleaved. + /// + public int ReadLBA_SubQ(int lba, byte[] buffer, int offset) + { + var sector = disc.Sectors[lba + 150]; + + PrepareBuffer(buffer, offset, 12); + PrepareJob(lba); + job.DestBuffer2448 = buf2442; + job.DestOffset = 0; + job.Parts = ESectorSynthPart.SubchannelQ | ESectorSynthPart.SubcodeDeinterleave; + + sector.SectorSynth.Synth(job); + Buffer.BlockCopy(buf2442, 2352 + 12, buffer, offset, 12); + + return 12; + } + /// /// reads 2048 bytes of user data from a sector. /// diff --git a/BizHawk.Emulation.DiscSystem/CUE/CUE_Synths.cs b/BizHawk.Emulation.DiscSystem/CUE/CUE_Synths.cs index f0d6194901..1c1b18e792 100644 --- a/BizHawk.Emulation.DiscSystem/CUE/CUE_Synths.cs +++ b/BizHawk.Emulation.DiscSystem/CUE/CUE_Synths.cs @@ -52,57 +52,6 @@ namespace BizHawk.Emulation.DiscSystem } } - static class SynthUtils - { - public static void SubP(byte[] buffer, int offset, bool pause) - { - byte val = (byte)(pause?0xFF:0x00); - for (int i = 0; i < 12; i++) - buffer[offset + i] = val; - } - - public static void SectorHeader(byte[] buffer, int offset, int LBA, byte mode) - { - buffer[offset + 0] = 0x00; - for (int i = 1; i < 11; i++) buffer[offset + i] = 0xFF; - buffer[offset + 11] = 0x00; - Timestamp ts = new Timestamp(LBA + 150); - buffer[offset + 12] = BCD2.IntToBCD(ts.MIN); - buffer[offset + 13] = BCD2.IntToBCD(ts.SEC); - buffer[offset + 14] = BCD2.IntToBCD(ts.FRAC); - buffer[offset + 15] = mode; - } - - public static void EDC_Mode2_Form1(byte[] buffer, int offset) - { - uint edc = ECM.EDC_Calc(buffer, offset + 16, 2048 + 8); - ECM.PokeUint(buffer, offset + 2072, edc); - } - - public static void EDC_Mode2_Form2(byte[] buffer, int offset) - { - uint edc = ECM.EDC_Calc(buffer, offset + 16, 2324+8); - ECM.PokeUint(buffer, offset + 2348, edc); - } - - - /// - /// Make sure everything else in the sector userdata is done before calling this - /// - public static void ECM_Mode1(byte[] buffer, int offset, int LBA) - { - //EDC - uint edc = ECM.EDC_Calc(buffer, offset, 2064); - ECM.PokeUint(buffer, offset + 2064, edc); - - //reserved, zero - for (int i = 0; i < 8; i++) buffer[offset + 2068 + i] = 0; - - //ECC - ECM.ECC_Populate(buffer, offset, buffer, offset, false); - } - } - /// /// Represents a Mode1 2048-byte sector /// diff --git a/BizHawk.Emulation.DiscSystem/Disc.cs b/BizHawk.Emulation.DiscSystem/Disc.cs index 50032b65dd..e7509372e6 100644 --- a/BizHawk.Emulation.DiscSystem/Disc.cs +++ b/BizHawk.Emulation.DiscSystem/Disc.cs @@ -224,37 +224,67 @@ namespace BizHawk.Emulation.DiscSystem } } + class SS_PatchQ : ISectorSynthJob2448 + { + public ISectorSynthJob2448 Original; + public byte[] Buffer_SubQ = new byte[12]; + public void Synth(SectorSynthJob job) + { + Original.Synth(job); + + if ((job.Parts & ESectorSynthPart.SubchannelQ) == 0) + return; + + //apply patched subQ + for (int i = 0; i < 12; i++) + job.DestBuffer2448[2352 + 12 + i] = Buffer_SubQ[i]; + } + } + /// /// applies an SBI file to the disc /// public void ApplySBI(SBI.SubQPatchData sbi, bool asMednafen) { + //TODO - could implement as a blob, to avoid allocating so many byte buffers + //save this, it's small, and we'll want it for disc processing a/b checks Memos["sbi"] = sbi; + DiscSectorReader dsr = new DiscSectorReader(this); + int n = sbi.ABAs.Count; - byte[] subcode = new byte[96]; int b=0; for (int i = 0; i < n; i++) { - int aba = sbi.ABAs[i]; - var oldSubcode = this.Sectors[aba].SubcodeSector; - oldSubcode.ReadSubcodeDeinterleaved(subcode, 0); + int lba = sbi.ABAs[i] - 150; + + //create a synthesizer which can return the patched data + var ss_patchq = new SS_PatchQ() { Original = this.Sectors[lba+150].SectorSynth }; + byte[] subQbuf = ss_patchq.Buffer_SubQ; + + //read the old subcode + dsr.ReadLBA_SubQ(lba, subQbuf, 0); + + //insert patch + Sectors[lba + 150].SectorSynth = ss_patchq; + + //apply SBI patch for (int j = 0; j < 12; j++) { short patch = sbi.subq[b++]; if (patch == -1) continue; - else subcode[12 + j] = (byte)patch; + else subQbuf[j] = (byte)patch; } - var bss = BufferedSubcodeSector.CloneFromBytesDeinterleaved(subcode); - Sectors[aba].SubcodeSector = bss; - //not fully sure what the basis is for this, but here we go + //Apply mednafen hacks + //The reasoning here is that we know we expect these sectors to have a wrong checksum. therefore, generate a checksum, and make it wrong + //However, this seems senseless to me. The whole point of the SBI data is that it stores the patches needed to generate an acceptable subQ, right? if (asMednafen) { - bss.Synthesize_SunchannelQ_Checksum(); - bss.SubcodeDeinterleaved[12 + 10] ^= 0xFF; - bss.SubcodeDeinterleaved[12 + 11] ^= 0xFF; + SynthUtils.SubQ_Checksum(subQbuf, 0); + subQbuf[10] ^= 0xFF; + subQbuf[11] ^= 0xFF; } } } @@ -489,7 +519,72 @@ namespace BizHawk.Emulation.DiscSystem } } - + + static class SynthUtils + { + + /// + /// Calculates the checksum of the provided Q subchannel + /// + /// 12 byte Q subchannel: input and output buffer for operation + /// location within buffer of Q subchannel + public static void SubQ_Checksum(byte[] buffer, int offset) + { + ushort crc16 = CRC16_CCITT.Calculate(buffer, offset, 10); + + //CRC is stored inverted and big endian + buffer[offset + 10] = (byte)(~(crc16 >> 8)); + buffer[offset + 11] = (byte)(~(crc16)); + } + + public static void SubP(byte[] buffer, int offset, bool pause) + { + byte val = (byte)(pause ? 0xFF : 0x00); + for (int i = 0; i < 12; i++) + buffer[offset + i] = val; + } + + public static void SectorHeader(byte[] buffer, int offset, int LBA, byte mode) + { + buffer[offset + 0] = 0x00; + for (int i = 1; i < 11; i++) buffer[offset + i] = 0xFF; + buffer[offset + 11] = 0x00; + Timestamp ts = new Timestamp(LBA + 150); + buffer[offset + 12] = BCD2.IntToBCD(ts.MIN); + buffer[offset + 13] = BCD2.IntToBCD(ts.SEC); + buffer[offset + 14] = BCD2.IntToBCD(ts.FRAC); + buffer[offset + 15] = mode; + } + + public static void EDC_Mode2_Form1(byte[] buffer, int offset) + { + uint edc = ECM.EDC_Calc(buffer, offset + 16, 2048 + 8); + ECM.PokeUint(buffer, offset + 2072, edc); + } + + public static void EDC_Mode2_Form2(byte[] buffer, int offset) + { + uint edc = ECM.EDC_Calc(buffer, offset + 16, 2324 + 8); + ECM.PokeUint(buffer, offset + 2348, edc); + } + + + /// + /// Make sure everything else in the sector userdata is done before calling this + /// + public static void ECM_Mode1(byte[] buffer, int offset, int LBA) + { + //EDC + uint edc = ECM.EDC_Calc(buffer, offset, 2064); + ECM.PokeUint(buffer, offset + 2064, edc); + + //reserved, zero + for (int i = 0; i < 8; i++) buffer[offset + 2068 + i] = 0; + + //ECC + ECM.ECC_Populate(buffer, offset, buffer, offset, false); + } + } //not being used yet class DiscPreferences diff --git a/BizHawk.Emulation.DiscSystem/Jobs/DiscMountJob.cs b/BizHawk.Emulation.DiscSystem/Jobs/DiscMountJob.cs index b04127ade9..30e8432e89 100644 --- a/BizHawk.Emulation.DiscSystem/Jobs/DiscMountJob.cs +++ b/BizHawk.Emulation.DiscSystem/Jobs/DiscMountJob.cs @@ -33,7 +33,12 @@ namespace BizHawk.Emulation.DiscSystem /// public bool CUE_PregapMode2_As_XA_Form2 = true; - public void SetForPlaystation() + /// + /// Mednafen loads SBI files oddly + /// + public bool SBO_As_Mednafen = true; + + public void SetForPSX() { //probably set CUE_PauseContradictionModeA to follow mednafen, but not proven yet //almost surely set CUE_PregapMode2_As_XA_Form2 to follow mednafen @@ -163,7 +168,7 @@ namespace BizHawk.Emulation.DiscSystem var sbiJob = new SBI.LoadSBIJob(); sbiJob.IN_Path = sbiPath; sbiJob.Run(); - OUT_Disc.ApplySBI(sbiJob.OUT_Data, true); + OUT_Disc.ApplySBI(sbiJob.OUT_Data, IN_DiscMountPolicy.SBO_As_Mednafen); } } else if (ext == ".ccd")