diff --git a/src/BizHawk.Emulation.DiscSystem/DiscFormats/CDI_format.cs b/src/BizHawk.Emulation.DiscSystem/DiscFormats/CDI_format.cs index bbc0f48240..c228caaedf 100644 --- a/src/BizHawk.Emulation.DiscSystem/DiscFormats/CDI_format.cs +++ b/src/BizHawk.Emulation.DiscSystem/DiscFormats/CDI_format.cs @@ -443,52 +443,6 @@ namespace BizHawk.Emulation.DiscSystem return ret; } - private class SS_CDI_RawQ : SS_Base - { - public override void Synth(SectorSynthJob job) - { - Blob.Read(BlobOffset, job.DestBuffer2448, job.DestOffset, 2352); - - if ((job.Parts & ESectorSynthPart.SubchannelP) != 0) - { - SynthUtils.SubP(job.DestBuffer2448, job.DestOffset + 2352, Pause); - } - - // Q is present in the blob and non-interleaved - if ((job.Parts & ESectorSynthPart.SubchannelQ) != 0) - { - Blob.Read(BlobOffset, job.DestBuffer2448, job.DestOffset + 2352 + 12, 12); - } - - //clear R-W if needed - if ((job.Parts & ESectorSynthPart.Subchannel_RSTUVW) != 0) - { - Array.Clear(job.DestBuffer2448, job.DestOffset + 2352 + 12 + 12, 12 * 6); - } - - //subcode has been generated deinterleaved; we may still need to interleave it - if ((job.Parts & ESectorSynthPart.SubcodeAny) != 0 && (job.Parts & ESectorSynthPart.SubcodeDeinterleave) == 0) - { - SynthUtils.InterleaveSubcodeInplace(job.DestBuffer2448, job.DestOffset + 2352); - } - } - } - - private class SS_CDI_RawPQRSTUVW : SS_Base - { - public override void Synth(SectorSynthJob job) - { - // all subcode is present and interleaved, just read it all - Blob.Read(BlobOffset, job.DestBuffer2448, job.DestOffset, 2448); - - // deinterleave it if needed - if ((job.Parts & ESectorSynthPart.SubcodeDeinterleave) != 0) - { - SynthUtils.DeinterleaveSubcodeInplace(job.DestBuffer2448, job.DestOffset + 2352); - } - } - } - /// file not found public static Disc LoadCDIToDisc(string cdiPath, DiscMountPolicy IN_DiscMountPolicy) { @@ -559,8 +513,8 @@ namespace BizHawk.Emulation.DiscSystem 0 => new SS_Mode1_2048(), 1 => new SS_Mode2_2336(), 2 => new SS_2352(), - 3 => new SS_CDI_RawQ(), - 4 => new SS_CDI_RawPQRSTUVW(), + 3 => new SS_2364_DeinterleavedQ(), + 4 => new SS_2448_Interleaved(), _ => throw new InvalidOperationException() }; synth.Blob = cdiBlob; diff --git a/src/BizHawk.Emulation.DiscSystem/DiscFormats/CUE/CUE_SynthExtras.cs b/src/BizHawk.Emulation.DiscSystem/DiscFormats/CUE/CUE_SynthExtras.cs new file mode 100644 index 0000000000..b42e494af0 --- /dev/null +++ b/src/BizHawk.Emulation.DiscSystem/DiscFormats/CUE/CUE_SynthExtras.cs @@ -0,0 +1,127 @@ +using System; + +namespace BizHawk.Emulation.DiscSystem.CUE +{ + // extra synths using SS_Base, not used by CUEs but used for other formats + + /// + /// Represents a Mode2 Form1 2048-byte sector + /// Only used by MDS + /// + internal class SS_Mode2_Form1_2048 : SS_Base + { + public override void Synth(SectorSynthJob job) + { + var ecm = (job.Parts & ESectorSynthPart.ECMAny) != 0; + if (ecm) + { + // ecm needs these parts for synth + job.Parts |= ESectorSynthPart.User2048; + job.Parts |= ESectorSynthPart.Header16; + } + + //read the sector user data + if ((job.Parts & ESectorSynthPart.User2048) != 0) + Blob.Read(BlobOffset, job.DestBuffer2448, job.DestOffset + 24, 2048); + + if ((job.Parts & ESectorSynthPart.Header16) != 0) + SynthUtils.SectorHeader(job.DestBuffer2448, job.DestOffset + 0, job.LBA, 2); + + if (ecm) + SynthUtils.ECM_Mode2_Form1(job.DestBuffer2448, job.DestOffset); + + SynthSubchannelAsNeed(job); + } + } + + /// + /// Represents a Mode2 Form1 2324-byte sector + /// Only used by MDS + /// + internal class SS_Mode2_Form2_2324 : SS_Base + { + public override void Synth(SectorSynthJob job) + { + //read the sector userdata (note: ECC data is now userdata in this regard) + if ((job.Parts & ESectorSynthPart.User2336) != 0) + { + Blob.Read(BlobOffset, job.DestBuffer2448, job.DestOffset + 24, 2324); + // only needs userdata for synth + SynthUtils.ECM_Mode2_Form2(job.DestBuffer2448, job.DestOffset); + } + + if ((job.Parts & ESectorSynthPart.Header16) != 0) + SynthUtils.SectorHeader(job.DestBuffer2448, job.DestOffset + 0, job.LBA, 2); + + SynthSubchannelAsNeed(job); + } + } + + /// + /// Represents a Mode2 Form1 2328-byte sector + /// Only used by MDS + /// + internal class SS_Mode2_Form2_2328 : SS_Base + { + public override void Synth(SectorSynthJob job) + { + //read the sector userdata (note: ECC data is now userdata in this regard) + if ((job.Parts & ESectorSynthPart.User2336) != 0) + { + Blob.Read(BlobOffset, job.DestBuffer2448, job.DestOffset + 24, 2328); + // only subheader needs to be synthed + SynthUtils.SectorSubHeader(job.DestBuffer2448, job.DestOffset + 16, 2); + } + + if ((job.Parts & ESectorSynthPart.Header16) != 0) + SynthUtils.SectorHeader(job.DestBuffer2448, job.DestOffset + 0, job.LBA, 2); + + SynthSubchannelAsNeed(job); + } + } + + /// + /// Represents a full 2448-byte sector with interleaved subcode + /// Only used by MDS and CDI + /// + internal class SS_2448_Interleaved : SS_Base + { + public override void Synth(SectorSynthJob job) + { + // all subcode is present and interleaved, just read it all + Blob.Read(BlobOffset, job.DestBuffer2448, job.DestOffset, 2448); + + // deinterleave it if needed + if ((job.Parts & ESectorSynthPart.SubcodeDeinterleave) != 0) + SynthUtils.DeinterleaveSubcodeInplace(job.DestBuffer2448, job.DestOffset + 2352); + } + } + + /// + /// Represents a 2364-byte (2352 + 12) sector with deinterleaved Q subcode + /// Only used by CDI + /// + internal class SS_2364_DeinterleavedQ : SS_Base + { + public override void Synth(SectorSynthJob job) + { + if ((job.Parts & ESectorSynthPart.User2352) != 0) + Blob.Read(BlobOffset, job.DestBuffer2448, job.DestOffset, 2352); + + if ((job.Parts & ESectorSynthPart.SubchannelP) != 0) + SynthUtils.SubP(job.DestBuffer2448, job.DestOffset + 2352, Pause); + + // Q is present in the blob and non-interleaved + if ((job.Parts & ESectorSynthPart.SubchannelQ) != 0) + Blob.Read(BlobOffset + 2352, job.DestBuffer2448, job.DestOffset + 2352 + 12, 12); + + // clear R-W if needed + if ((job.Parts & ESectorSynthPart.Subchannel_RSTUVW) != 0) + Array.Clear(job.DestBuffer2448, job.DestOffset + 2352 + 12 + 12, 12 * 6); + + // subcode has been generated deinterleaved; we may still need to interleave it + if ((job.Parts & ESectorSynthPart.SubcodeAny) != 0 && (job.Parts & ESectorSynthPart.SubcodeDeinterleave) == 0) + SynthUtils.InterleaveSubcodeInplace(job.DestBuffer2448, job.DestOffset + 2352); + } + } +} \ No newline at end of file diff --git a/src/BizHawk.Emulation.DiscSystem/DiscFormats/CUE/CUE_Synths.cs b/src/BizHawk.Emulation.DiscSystem/DiscFormats/CUE/CUE_Synths.cs index a5b278587a..299ddd5e8d 100644 --- a/src/BizHawk.Emulation.DiscSystem/DiscFormats/CUE/CUE_Synths.cs +++ b/src/BizHawk.Emulation.DiscSystem/DiscFormats/CUE/CUE_Synths.cs @@ -39,11 +39,10 @@ namespace BizHawk.Emulation.DiscSystem.CUE } //subcode has been generated deinterleaved; we may still need to interleave it - if((job.Parts & ESectorSynthPart.SubcodeAny) != 0) - if ((job.Parts & (ESectorSynthPart.SubcodeDeinterleave)) == 0) - { - SynthUtils.InterleaveSubcodeInplace(job.DestBuffer2448, job.DestOffset + 2352); - } + if ((job.Parts & ESectorSynthPart.SubcodeAny) != 0 && (job.Parts & ESectorSynthPart.SubcodeDeinterleave) == 0) + { + SynthUtils.InterleaveSubcodeInplace(job.DestBuffer2448, job.DestOffset + 2352); + } } } @@ -54,15 +53,23 @@ namespace BizHawk.Emulation.DiscSystem.CUE { public override void Synth(SectorSynthJob job) { + var ecm = (job.Parts & ESectorSynthPart.ECMAny) != 0; + if (ecm) + { + // ecm needs these parts for synth + job.Parts |= ESectorSynthPart.User2048; + job.Parts |= ESectorSynthPart.Header16; + } + //read the sector user data - if((job.Parts & ESectorSynthPart.User2048) != 0) + if ((job.Parts & ESectorSynthPart.User2048) != 0) Blob.Read(BlobOffset, job.DestBuffer2448, job.DestOffset + 16, 2048); if ((job.Parts & ESectorSynthPart.Header16) != 0) SynthUtils.SectorHeader(job.DestBuffer2448, job.DestOffset + 0, job.LBA, 1); - if ((job.Parts & ESectorSynthPart.ECMAny) != 0) - SynthUtils.ECM_Mode1(job.DestBuffer2448, job.DestOffset + 0, job.LBA); + if (ecm) + SynthUtils.ECM_Mode1(job.DestBuffer2448, job.DestOffset + 0); SynthSubchannelAsNeed(job); } @@ -75,8 +82,9 @@ namespace BizHawk.Emulation.DiscSystem.CUE { public override void Synth(SectorSynthJob job) { - //read the sector user data - Blob.Read(BlobOffset, job.DestBuffer2448, job.DestOffset + 16, 2336); + //read the sector sector user data + ECM data + if ((job.Parts & ESectorSynthPart.User2336) != 0) + Blob.Read(BlobOffset, job.DestBuffer2448, job.DestOffset + 16, 2336); if ((job.Parts & ESectorSynthPart.Header16) != 0) SynthUtils.SectorHeader(job.DestBuffer2448, job.DestOffset + 0, job.LBA, 2); @@ -94,7 +102,8 @@ namespace BizHawk.Emulation.DiscSystem.CUE public override void Synth(SectorSynthJob job) { //read the sector user data - Blob.Read(BlobOffset, job.DestBuffer2448, job.DestOffset, 2352); + if ((job.Parts & ESectorSynthPart.User2352) != 0) + Blob.Read(BlobOffset, job.DestBuffer2448, job.DestOffset, 2352); //if subcode is needed, synthesize it SynthSubchannelAsNeed(job); @@ -159,7 +168,7 @@ namespace BizHawk.Emulation.DiscSystem.CUE case 1: { if ((job.Parts & ESectorSynthPart.ECMAny) != 0) - SynthUtils.ECM_Mode1(job.DestBuffer2448, job.DestOffset + 0, job.LBA); + SynthUtils.ECM_Mode1(job.DestBuffer2448, job.DestOffset + 0); break; } case 2 when form == 2: @@ -170,6 +179,4 @@ namespace BizHawk.Emulation.DiscSystem.CUE SynthSubchannelAsNeed(job); } } - - } \ No newline at end of file diff --git a/src/BizHawk.Emulation.DiscSystem/DiscFormats/MDS_Format.cs b/src/BizHawk.Emulation.DiscSystem/DiscFormats/MDS_Format.cs index 9924c718f0..025858a569 100644 --- a/src/BizHawk.Emulation.DiscSystem/DiscFormats/MDS_Format.cs +++ b/src/BizHawk.Emulation.DiscSystem/DiscFormats/MDS_Format.cs @@ -154,9 +154,9 @@ namespace BizHawk.Emulation.DiscSystem public class ATrack { /// - /// The specified data mode + /// The specified data mode (only lower 3 bits are actually meaningful) /// 0x00 - None (no data) - /// 0x02 - DVD + /// 0x02 - DVD (when header specifies DVD, Mode1 otherwise) /// 0xA9 - Audio /// 0xAA - Mode1 /// 0xAB - Mode2 @@ -271,6 +271,19 @@ namespace BizHawk.Emulation.DiscSystem public int PSec; public int PFrame; + /// + /// Lower 3 bits of ATrack Mode + /// Upper 5 bits are meaningless (see mirage_parser_mds_convert_track_mode) + /// 0x0 - None or Mode2 (Depends on sector size) + /// 0x1 - Audio + /// 0x2 - DVD or Mode1 (Depends on medium) + /// 0x3 - Mode2 + /// 0x4 - Mode2 Form1 + /// 0x5 - Mode2 Form2 + /// 0x6 - UNKNOWN + /// 0x7 - Mode2 + /// + public int TrackMode; public int SectorSize; public long TrackOffset; @@ -313,6 +326,12 @@ namespace BizHawk.Emulation.DiscSystem throw new MDSParseException($"MDS Parse Error: Only MDS version 1.x is supported!\nDetected version: {aFile.Header.Version[0]}.{aFile.Header.Version[1]}"); } + isDvd = aFile.Header.Medium is 0x10 or 0x12; + if (isDvd) + { + throw new MDSParseException("DVD Detected. Not currently supported!"); + } + // parse sessions var aSessions = new Dictionary(); @@ -377,12 +396,6 @@ namespace BizHawk.Emulation.DiscSystem track.Files = bc.ToInt32(trackHeader.Skip(48).Take(4).ToArray()); track.FooterOffset = bc.ToInt32(trackHeader.Skip(52).Take(4).ToArray()); - if (track.Mode == 0x02) - { - isDvd = true; - throw new MDSParseException("DVD Detected. Not currently supported!"); - } - // check for track extra block - this can probably be handled in a separate loop, // but I'll just store the current stream position then seek forward to the extra block for this track var currPos = stream.Position; @@ -484,8 +497,15 @@ namespace BizHawk.Emulation.DiscSystem stream.Position = currPos; + var point = track.Point; + // each session has its own 0xA0/0xA1/0xA3 track + // so this can't be used directly as a key + if (point is 0xA0 or 0xA1 or 0xA2) + { + point |= session.SessionNumber << 8; + } - aTracks.Add(track.Point, track); + aTracks.Add(point, track); aFile.Tracks.Add(track); if (footerOffset == 0) @@ -521,32 +541,57 @@ namespace BizHawk.Emulation.DiscSystem // now build the TOC object foreach (var se in aFile.ParsedSession) - foreach (var t in aTracks.Values - .Where(a => se.StartTrack <= a.TrackNo && a.TrackNo <= se.EndTrack) - .OrderBy(a => a.TrackNo)) + { + ATOCEntry CreateTOCEntryFromTrack(ATrack track) { - aFile.TOCEntries.Add(new(t.Point) + return new(track.Point) { - ADR_Control = t.ADR_Control, - AFrame = t.AFrame, - AMin = t.AMin, - ASec = t.ASec, - BlobIndex = t.BlobIndex, - EntryNum = t.TrackNo, - ExtraBlock = t.ExtraBlock, - ImageFileNamePaths = t.ImageFileNamePaths, - PFrame = t.PFrame, - PLBA = Convert.ToInt32(t.PLBA), - PMin = t.PMin, - Point = t.Point, - PSec = t.PSec, - SectorSize = t.SectorSize, + ADR_Control = track.ADR_Control, + AFrame = track.AFrame, + AMin = track.AMin, + ASec = track.ASec, + BlobIndex = track.BlobIndex, + EntryNum = track.TrackNo, + ExtraBlock = track.ExtraBlock, + ImageFileNamePaths = track.ImageFileNamePaths, + PFrame = track.PFrame, + PLBA = Convert.ToInt32(track.PLBA), + PMin = track.PMin, + Point = track.Point, + PSec = track.PSec, + TrackMode = track.Mode & 0x7, + SectorSize = track.SectorSize, Session = se.SessionSequence, - TrackOffset = Convert.ToInt64(t.StartOffset), - Zero = t.Zero - }); + TrackOffset = Convert.ToInt64(track.StartOffset), + Zero = track.Zero + }; } + void AddAXTrack(int x) + { + if (aTracks.TryGetValue(se.SessionSequence << 8 | 0xA0 | x, out var axTrack)) + { + aFile.TOCEntries.Add(CreateTOCEntryFromTrack(axTrack)); + } + } + + // add in the 0xA0/0xA1/0xA2 tracks + AddAXTrack(0); + AddAXTrack(1); + AddAXTrack(2); + + // add in the rest of the tracks + foreach (var t in aTracks + .Where(a => se.StartTrack <= a.Key && a.Key <= se.EndTrack) + .OrderBy(a => a.Key) + .Select(a => a.Value)) + { + aFile.TOCEntries.Add(CreateTOCEntryFromTrack(t)); + } + + // TODO: first session might have 0xB0/0xC0 tracks... not sure how to handle these + } + return aFile; } @@ -714,6 +759,32 @@ namespace BizHawk.Emulation.DiscSystem var currBlobIndex = 0; foreach (var session in mdsf.ParsedSession) { + // leadin track + // we create this only for session 2+, not session 1 + var leadinSize = session.SessionSequence == 1 ? 0 : 4500; + for (var i = 0; i < leadinSize; i++) + { + // this is most certainly wrong + // nothing relies on the exact contents for now (only multisession core is VirtualJaguar which doesn't touch leadin) + // just needs sectors to be present due to track info LBAs of session 2+ accounting for this being present + var pregapTrackType = CUE.CueTrackType.Audio; + if (tocSynth.Result.TOCItems[1].IsData) + { + pregapTrackType = tocSynth.Result.SessionFormat switch + { + SessionFormat.Type20_CDXA => CUE.CueTrackType.Mode2_2352, + SessionFormat.Type10_CDI => CUE.CueTrackType.CDI_2352, + SessionFormat.Type00_CDROM_CDDA => CUE.CueTrackType.Mode1_2352, + _ => pregapTrackType + }; + } + disc._Sectors.Add(new CUE.SS_Gap() + { + Policy = IN_DiscMountPolicy, + TrackType = pregapTrackType + }); + } + for (var i = session.StartTrack; i <= session.EndTrack; i++) { var relMSF = -1; @@ -800,8 +871,6 @@ namespace BizHawk.Emulation.DiscSystem var currBlobOffset = track.TrackOffset; for (var sector = session.StartSector; sector <= session.EndSector; sector++) { - CUE.SS_Base sBase; - // get the current blob from the BlobIndex var currBlob = (Blob_RawFile) BlobIndex[currBlobIndex]; var currBlobLength = currBlob.Length; @@ -809,33 +878,29 @@ namespace BizHawk.Emulation.DiscSystem currBlobIndex++; var mdfBlob = (IBlob) disc.DisposableResources[currBlobIndex]; - //int userSector = 2048; - switch (track.SectorSize) + CUE.SS_Base sBase = track.SectorSize switch { - case 2448: - sBase = new CUE.SS_2352() - { - Policy = IN_DiscMountPolicy - }; - //userSector = 2352; - break; - case 2048: - default: - sBase = new CUE.SS_Mode1_2048() - { - Policy = IN_DiscMountPolicy - }; - //userSector = 2048; - break; - - //throw new Exception($"Not supported: Sector Size {track.SectorSize}"); - } + 2352 when track.TrackMode is 1 => new CUE.SS_2352(), + 2048 when track.TrackMode is 2 => new CUE.SS_Mode1_2048(), + 2336 when track.TrackMode is 0 or 3 or 7 => new CUE.SS_Mode2_2336(), + 2048 when track.TrackMode is 4 => new CUE.SS_Mode2_Form1_2048(), + 2324 when track.TrackMode is 5 => new CUE.SS_Mode2_Form2_2324(), + 2328 when track.TrackMode is 5 => new CUE.SS_Mode2_Form2_2328(), + // best guesses + 2048 => new CUE.SS_Mode1_2048(), + 2336 => new CUE.SS_Mode2_2336(), + 2352 => new CUE.SS_2352(), + 2448 => new CUE.SS_2448_Interleaved(), + _ => throw new InvalidOperationException($"Not supported: Sector Size {track.SectorSize}, Track Mode {track.TrackMode}") + }; + + sBase.Policy = IN_DiscMountPolicy; // configure blob sBase.Blob = mdfBlob; sBase.BlobOffset = currBlobOffset; - currBlobOffset += track.SectorSize; // userSector; + currBlobOffset += track.SectorSize; // add subchannel data relMSF++; @@ -873,6 +938,18 @@ namespace BizHawk.Emulation.DiscSystem disc._Sectors.Add(sBase); } } + + // leadout track + // first leadout is 6750 sectors, later ones are 2250 sectors + var leadoutSize = session.SessionSequence == 1 ? 6750 : 2250; + for (var i = 0; i < leadoutSize; i++) + { + disc._Sectors.Add(new SS_Leadout + { + SessionNumber = session.SessionSequence, + Policy = IN_DiscMountPolicy + }); + } } return disc; diff --git a/src/BizHawk.Emulation.DiscSystem/Internal/Jobs/Synthesize_DiscTOC_From_RawTOCEntries_Job.cs b/src/BizHawk.Emulation.DiscSystem/Internal/Jobs/Synthesize_DiscTOC_From_RawTOCEntries_Job.cs index a9af429704..3afe135445 100644 --- a/src/BizHawk.Emulation.DiscSystem/Internal/Jobs/Synthesize_DiscTOC_From_RawTOCEntries_Job.cs +++ b/src/BizHawk.Emulation.DiscSystem/Internal/Jobs/Synthesize_DiscTOC_From_RawTOCEntries_Job.cs @@ -29,11 +29,8 @@ namespace BizHawk.Emulation.DiscSystem Result.TOCItems[0].Control = 0; Result.TOCItems[0].Exists = false; - //just in case this doesn't get set... - Result.FirstRecordedTrackNumber = 0; - Result.LastRecordedTrackNumber = 0; - - var maxFoundTrack = 0; + var minFoundTrack = 1; + var maxFoundTrack = 1; foreach (var te in Entries) { @@ -50,6 +47,7 @@ namespace BizHawk.Emulation.DiscSystem case 255: throw new InvalidOperationException("point == 255"); case <= 99: + minFoundTrack = Math.Min(minFoundTrack, point); maxFoundTrack = Math.Max(maxFoundTrack, point); Result.TOCItems[point].LBA = q.AP_Timestamp - 150; //RawTOCEntries contained an absolute time Result.TOCItems[point].Control = q.CONTROL; @@ -96,8 +94,7 @@ namespace BizHawk.Emulation.DiscSystem } //this is speculative: - //well, nothing to be done here.. -// if (ret.FirstRecordedTrackNumber == -1) { } + if (Result.FirstRecordedTrackNumber == -1) { Result.FirstRecordedTrackNumber = minFoundTrack; } if (Result.LastRecordedTrackNumber == -1) { Result.LastRecordedTrackNumber = maxFoundTrack; } if (Result.SessionFormat == SessionFormat.None) Result.SessionFormat = SessionFormat.Type00_CDROM_CDDA; diff --git a/src/BizHawk.Emulation.DiscSystem/Internal/SectorSynth.cs b/src/BizHawk.Emulation.DiscSystem/Internal/SectorSynth.cs index 17c5235f30..723c6e01bd 100644 --- a/src/BizHawk.Emulation.DiscSystem/Internal/SectorSynth.cs +++ b/src/BizHawk.Emulation.DiscSystem/Internal/SectorSynth.cs @@ -50,7 +50,7 @@ namespace BizHawk.Emulation.DiscSystem /// /// The complete sector userdata (2352 bytes) is required /// - UserComplete = 15, + UserComplete = (Header16 | User2048 | ECM288Complete), /// /// An alias for UserComplete diff --git a/src/BizHawk.Emulation.DiscSystem/Internal/SynthUtils.cs b/src/BizHawk.Emulation.DiscSystem/Internal/SynthUtils.cs index 90394208cd..a873e24faa 100644 --- a/src/BizHawk.Emulation.DiscSystem/Internal/SynthUtils.cs +++ b/src/BizHawk.Emulation.DiscSystem/Internal/SynthUtils.cs @@ -71,6 +71,30 @@ namespace BizHawk.Emulation.DiscSystem buffer16[offset + 15] = mode; } + /// + /// Synthesizes a Mode2 sector subheader + /// + public static void SectorSubHeader(byte[] buffer8, int offset, byte form) + { + // see mirage_sector_generate_subheader + for (var i = 0; i < 8; i++) buffer8[offset + i] = 0; + if (form == 2) + { + // these are just 0 in form 1 + buffer8[offset + 2] = 0x20; + buffer8[offset + 5] = 0x20; + } + } + + /// + /// Synthesizes the EDC checksum for a Mode 1 data sector (and puts it in place) + /// + public static void EDC_Mode1(byte[] buf2352, int offset) + { + var edc = ECM.EDC_Calc(buf2352, offset, 2064); + ECM.PokeUint(buf2352, offset + 2064, edc); + } + /// /// Synthesizes the EDC checksum for a Mode 2 Form 1 data sector (and puts it in place) /// @@ -92,13 +116,12 @@ namespace BizHawk.Emulation.DiscSystem /// /// Synthesizes the complete ECM data (EDC + ECC) for a Mode 1 data sector (and puts it in place) - /// Make sure everything else in the sector userdata is done before calling this + /// Make sure everything else in the sector header and userdata is done before calling this /// - public static void ECM_Mode1(byte[] buf2352, int offset, int LBA) + public static void ECM_Mode1(byte[] buf2352, int offset) { //EDC - var edc = ECM.EDC_Calc(buf2352, offset, 2064); - ECM.PokeUint(buf2352, offset + 2064, edc); + EDC_Mode1(buf2352, offset); //reserved, zero for (var i = 0; i < 8; i++) buf2352[offset + 2068 + i] = 0; @@ -107,6 +130,37 @@ namespace BizHawk.Emulation.DiscSystem ECM.ECC_Populate(buf2352, offset, buf2352, offset, false); } + /// + /// Synthesizes the complete ECM data (Subheader + EDC + ECC) for a Mode 2 Form 1 data sector (and puts it in place) + /// Make sure everything else in the sector header and userdata is done before calling this + /// + public static void ECM_Mode2_Form1(byte[] buf2352, int offset) + { + //Subheader + SectorSubHeader(buf2352, offset + 16, 1); + + //EDC + EDC_Mode2_Form1(buf2352, offset); + + //ECC + ECM.ECC_Populate(buf2352, offset, buf2352, offset, false); + } + + /// + /// Synthesizes the complete ECM data (Subheader + EDC) for a Mode 2 Form 2 data sector (and puts it in place) + /// Make sure everything else in the userdata is done before calling this + /// + public static void ECM_Mode2_Form2(byte[] buf2352, int offset) + { + //Subheader + SectorSubHeader(buf2352, offset + 16, 2); + + //EDC + EDC_Mode2_Form2(buf2352, offset); + + //note that Mode 2 Form 2 does not have ECC + } + /// /// Converts the useful (but unrealistic) deinterleaved subchannel data into the useless (but realistic) interleaved format. /// in_buf and out_buf should not overlap