Fixup multisession handling with MDS and improve its track/sector size handling, also maybe fix it entirely? (not sure if this ever worked)
Move the various synths using the CUE SS_Base to a file, mostly just a nicer organizational change as MDS and CDI use one of these but not CUE Misc improvements elsewhere
This commit is contained in:
parent
1f3068fe77
commit
2012b083f6
|
@ -443,52 +443,6 @@ namespace BizHawk.Emulation.DiscSystem
|
||||||
return ret;
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <exception cref="CDIParseException">file <paramref name="cdiPath"/> not found</exception>
|
/// <exception cref="CDIParseException">file <paramref name="cdiPath"/> not found</exception>
|
||||||
public static Disc LoadCDIToDisc(string cdiPath, DiscMountPolicy IN_DiscMountPolicy)
|
public static Disc LoadCDIToDisc(string cdiPath, DiscMountPolicy IN_DiscMountPolicy)
|
||||||
{
|
{
|
||||||
|
@ -559,8 +513,8 @@ namespace BizHawk.Emulation.DiscSystem
|
||||||
0 => new SS_Mode1_2048(),
|
0 => new SS_Mode1_2048(),
|
||||||
1 => new SS_Mode2_2336(),
|
1 => new SS_Mode2_2336(),
|
||||||
2 => new SS_2352(),
|
2 => new SS_2352(),
|
||||||
3 => new SS_CDI_RawQ(),
|
3 => new SS_2364_DeinterleavedQ(),
|
||||||
4 => new SS_CDI_RawPQRSTUVW(),
|
4 => new SS_2448_Interleaved(),
|
||||||
_ => throw new InvalidOperationException()
|
_ => throw new InvalidOperationException()
|
||||||
};
|
};
|
||||||
synth.Blob = cdiBlob;
|
synth.Blob = cdiBlob;
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a Mode2 Form1 2048-byte sector
|
||||||
|
/// Only used by MDS
|
||||||
|
/// </summary>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a Mode2 Form1 2324-byte sector
|
||||||
|
/// Only used by MDS
|
||||||
|
/// </summary>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a Mode2 Form1 2328-byte sector
|
||||||
|
/// Only used by MDS
|
||||||
|
/// </summary>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a full 2448-byte sector with interleaved subcode
|
||||||
|
/// Only used by MDS and CDI
|
||||||
|
/// </summary>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a 2364-byte (2352 + 12) sector with deinterleaved Q subcode
|
||||||
|
/// Only used by CDI
|
||||||
|
/// </summary>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -39,11 +39,10 @@ namespace BizHawk.Emulation.DiscSystem.CUE
|
||||||
}
|
}
|
||||||
|
|
||||||
//subcode has been generated deinterleaved; we may still need to interleave it
|
//subcode has been generated deinterleaved; we may still need to interleave it
|
||||||
if((job.Parts & ESectorSynthPart.SubcodeAny) != 0)
|
if ((job.Parts & ESectorSynthPart.SubcodeAny) != 0 && (job.Parts & ESectorSynthPart.SubcodeDeinterleave) == 0)
|
||||||
if ((job.Parts & (ESectorSynthPart.SubcodeDeinterleave)) == 0)
|
{
|
||||||
{
|
SynthUtils.InterleaveSubcodeInplace(job.DestBuffer2448, job.DestOffset + 2352);
|
||||||
SynthUtils.InterleaveSubcodeInplace(job.DestBuffer2448, job.DestOffset + 2352);
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,15 +53,23 @@ namespace BizHawk.Emulation.DiscSystem.CUE
|
||||||
{
|
{
|
||||||
public override void Synth(SectorSynthJob job)
|
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
|
//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);
|
Blob.Read(BlobOffset, job.DestBuffer2448, job.DestOffset + 16, 2048);
|
||||||
|
|
||||||
if ((job.Parts & ESectorSynthPart.Header16) != 0)
|
if ((job.Parts & ESectorSynthPart.Header16) != 0)
|
||||||
SynthUtils.SectorHeader(job.DestBuffer2448, job.DestOffset + 0, job.LBA, 1);
|
SynthUtils.SectorHeader(job.DestBuffer2448, job.DestOffset + 0, job.LBA, 1);
|
||||||
|
|
||||||
if ((job.Parts & ESectorSynthPart.ECMAny) != 0)
|
if (ecm)
|
||||||
SynthUtils.ECM_Mode1(job.DestBuffer2448, job.DestOffset + 0, job.LBA);
|
SynthUtils.ECM_Mode1(job.DestBuffer2448, job.DestOffset + 0);
|
||||||
|
|
||||||
SynthSubchannelAsNeed(job);
|
SynthSubchannelAsNeed(job);
|
||||||
}
|
}
|
||||||
|
@ -75,8 +82,9 @@ namespace BizHawk.Emulation.DiscSystem.CUE
|
||||||
{
|
{
|
||||||
public override void Synth(SectorSynthJob job)
|
public override void Synth(SectorSynthJob job)
|
||||||
{
|
{
|
||||||
//read the sector user data
|
//read the sector sector user data + ECM data
|
||||||
Blob.Read(BlobOffset, job.DestBuffer2448, job.DestOffset + 16, 2336);
|
if ((job.Parts & ESectorSynthPart.User2336) != 0)
|
||||||
|
Blob.Read(BlobOffset, job.DestBuffer2448, job.DestOffset + 16, 2336);
|
||||||
|
|
||||||
if ((job.Parts & ESectorSynthPart.Header16) != 0)
|
if ((job.Parts & ESectorSynthPart.Header16) != 0)
|
||||||
SynthUtils.SectorHeader(job.DestBuffer2448, job.DestOffset + 0, job.LBA, 2);
|
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)
|
public override void Synth(SectorSynthJob job)
|
||||||
{
|
{
|
||||||
//read the sector user data
|
//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
|
//if subcode is needed, synthesize it
|
||||||
SynthSubchannelAsNeed(job);
|
SynthSubchannelAsNeed(job);
|
||||||
|
@ -159,7 +168,7 @@ namespace BizHawk.Emulation.DiscSystem.CUE
|
||||||
case 1:
|
case 1:
|
||||||
{
|
{
|
||||||
if ((job.Parts & ESectorSynthPart.ECMAny) != 0)
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case 2 when form == 2:
|
case 2 when form == 2:
|
||||||
|
@ -170,6 +179,4 @@ namespace BizHawk.Emulation.DiscSystem.CUE
|
||||||
SynthSubchannelAsNeed(job);
|
SynthSubchannelAsNeed(job);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -154,9 +154,9 @@ namespace BizHawk.Emulation.DiscSystem
|
||||||
public class ATrack
|
public class ATrack
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The specified data mode
|
/// The specified data mode (only lower 3 bits are actually meaningful)
|
||||||
/// 0x00 - None (no data)
|
/// 0x00 - None (no data)
|
||||||
/// 0x02 - DVD
|
/// 0x02 - DVD (when header specifies DVD, Mode1 otherwise)
|
||||||
/// 0xA9 - Audio
|
/// 0xA9 - Audio
|
||||||
/// 0xAA - Mode1
|
/// 0xAA - Mode1
|
||||||
/// 0xAB - Mode2
|
/// 0xAB - Mode2
|
||||||
|
@ -271,6 +271,19 @@ namespace BizHawk.Emulation.DiscSystem
|
||||||
public int PSec;
|
public int PSec;
|
||||||
public int PFrame;
|
public int PFrame;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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
|
||||||
|
/// </summary>
|
||||||
|
public int TrackMode;
|
||||||
|
|
||||||
public int SectorSize;
|
public int SectorSize;
|
||||||
public long TrackOffset;
|
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]}");
|
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
|
// parse sessions
|
||||||
var aSessions = new Dictionary<int, ASession>();
|
var aSessions = new Dictionary<int, ASession>();
|
||||||
|
|
||||||
|
@ -377,12 +396,6 @@ namespace BizHawk.Emulation.DiscSystem
|
||||||
track.Files = bc.ToInt32(trackHeader.Skip(48).Take(4).ToArray());
|
track.Files = bc.ToInt32(trackHeader.Skip(48).Take(4).ToArray());
|
||||||
track.FooterOffset = bc.ToInt32(trackHeader.Skip(52).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,
|
// 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
|
// but I'll just store the current stream position then seek forward to the extra block for this track
|
||||||
var currPos = stream.Position;
|
var currPos = stream.Position;
|
||||||
|
@ -484,8 +497,15 @@ namespace BizHawk.Emulation.DiscSystem
|
||||||
|
|
||||||
stream.Position = currPos;
|
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);
|
aFile.Tracks.Add(track);
|
||||||
|
|
||||||
if (footerOffset == 0)
|
if (footerOffset == 0)
|
||||||
|
@ -521,32 +541,57 @@ namespace BizHawk.Emulation.DiscSystem
|
||||||
|
|
||||||
// now build the TOC object
|
// now build the TOC object
|
||||||
foreach (var se in aFile.ParsedSession)
|
foreach (var se in aFile.ParsedSession)
|
||||||
foreach (var t in aTracks.Values
|
{
|
||||||
.Where(a => se.StartTrack <= a.TrackNo && a.TrackNo <= se.EndTrack)
|
ATOCEntry CreateTOCEntryFromTrack(ATrack track)
|
||||||
.OrderBy(a => a.TrackNo))
|
|
||||||
{
|
{
|
||||||
aFile.TOCEntries.Add(new(t.Point)
|
return new(track.Point)
|
||||||
{
|
{
|
||||||
ADR_Control = t.ADR_Control,
|
ADR_Control = track.ADR_Control,
|
||||||
AFrame = t.AFrame,
|
AFrame = track.AFrame,
|
||||||
AMin = t.AMin,
|
AMin = track.AMin,
|
||||||
ASec = t.ASec,
|
ASec = track.ASec,
|
||||||
BlobIndex = t.BlobIndex,
|
BlobIndex = track.BlobIndex,
|
||||||
EntryNum = t.TrackNo,
|
EntryNum = track.TrackNo,
|
||||||
ExtraBlock = t.ExtraBlock,
|
ExtraBlock = track.ExtraBlock,
|
||||||
ImageFileNamePaths = t.ImageFileNamePaths,
|
ImageFileNamePaths = track.ImageFileNamePaths,
|
||||||
PFrame = t.PFrame,
|
PFrame = track.PFrame,
|
||||||
PLBA = Convert.ToInt32(t.PLBA),
|
PLBA = Convert.ToInt32(track.PLBA),
|
||||||
PMin = t.PMin,
|
PMin = track.PMin,
|
||||||
Point = t.Point,
|
Point = track.Point,
|
||||||
PSec = t.PSec,
|
PSec = track.PSec,
|
||||||
SectorSize = t.SectorSize,
|
TrackMode = track.Mode & 0x7,
|
||||||
|
SectorSize = track.SectorSize,
|
||||||
Session = se.SessionSequence,
|
Session = se.SessionSequence,
|
||||||
TrackOffset = Convert.ToInt64(t.StartOffset),
|
TrackOffset = Convert.ToInt64(track.StartOffset),
|
||||||
Zero = t.Zero
|
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;
|
return aFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -714,6 +759,32 @@ namespace BizHawk.Emulation.DiscSystem
|
||||||
var currBlobIndex = 0;
|
var currBlobIndex = 0;
|
||||||
foreach (var session in mdsf.ParsedSession)
|
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++)
|
for (var i = session.StartTrack; i <= session.EndTrack; i++)
|
||||||
{
|
{
|
||||||
var relMSF = -1;
|
var relMSF = -1;
|
||||||
|
@ -800,8 +871,6 @@ namespace BizHawk.Emulation.DiscSystem
|
||||||
var currBlobOffset = track.TrackOffset;
|
var currBlobOffset = track.TrackOffset;
|
||||||
for (var sector = session.StartSector; sector <= session.EndSector; sector++)
|
for (var sector = session.StartSector; sector <= session.EndSector; sector++)
|
||||||
{
|
{
|
||||||
CUE.SS_Base sBase;
|
|
||||||
|
|
||||||
// get the current blob from the BlobIndex
|
// get the current blob from the BlobIndex
|
||||||
var currBlob = (Blob_RawFile) BlobIndex[currBlobIndex];
|
var currBlob = (Blob_RawFile) BlobIndex[currBlobIndex];
|
||||||
var currBlobLength = currBlob.Length;
|
var currBlobLength = currBlob.Length;
|
||||||
|
@ -809,33 +878,29 @@ namespace BizHawk.Emulation.DiscSystem
|
||||||
currBlobIndex++;
|
currBlobIndex++;
|
||||||
var mdfBlob = (IBlob) disc.DisposableResources[currBlobIndex];
|
var mdfBlob = (IBlob) disc.DisposableResources[currBlobIndex];
|
||||||
|
|
||||||
//int userSector = 2048;
|
CUE.SS_Base sBase = track.SectorSize switch
|
||||||
switch (track.SectorSize)
|
|
||||||
{
|
{
|
||||||
case 2448:
|
2352 when track.TrackMode is 1 => new CUE.SS_2352(),
|
||||||
sBase = 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(),
|
||||||
Policy = IN_DiscMountPolicy
|
2048 when track.TrackMode is 4 => new CUE.SS_Mode2_Form1_2048(),
|
||||||
};
|
2324 when track.TrackMode is 5 => new CUE.SS_Mode2_Form2_2324(),
|
||||||
//userSector = 2352;
|
2328 when track.TrackMode is 5 => new CUE.SS_Mode2_Form2_2328(),
|
||||||
break;
|
// best guesses
|
||||||
case 2048:
|
2048 => new CUE.SS_Mode1_2048(),
|
||||||
default:
|
2336 => new CUE.SS_Mode2_2336(),
|
||||||
sBase = new CUE.SS_Mode1_2048()
|
2352 => new CUE.SS_2352(),
|
||||||
{
|
2448 => new CUE.SS_2448_Interleaved(),
|
||||||
Policy = IN_DiscMountPolicy
|
_ => throw new InvalidOperationException($"Not supported: Sector Size {track.SectorSize}, Track Mode {track.TrackMode}")
|
||||||
};
|
};
|
||||||
//userSector = 2048;
|
|
||||||
break;
|
sBase.Policy = IN_DiscMountPolicy;
|
||||||
|
|
||||||
//throw new Exception($"Not supported: Sector Size {track.SectorSize}");
|
|
||||||
}
|
|
||||||
|
|
||||||
// configure blob
|
// configure blob
|
||||||
sBase.Blob = mdfBlob;
|
sBase.Blob = mdfBlob;
|
||||||
sBase.BlobOffset = currBlobOffset;
|
sBase.BlobOffset = currBlobOffset;
|
||||||
|
|
||||||
currBlobOffset += track.SectorSize; // userSector;
|
currBlobOffset += track.SectorSize;
|
||||||
|
|
||||||
// add subchannel data
|
// add subchannel data
|
||||||
relMSF++;
|
relMSF++;
|
||||||
|
@ -873,6 +938,18 @@ namespace BizHawk.Emulation.DiscSystem
|
||||||
disc._Sectors.Add(sBase);
|
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;
|
return disc;
|
||||||
|
|
|
@ -29,11 +29,8 @@ namespace BizHawk.Emulation.DiscSystem
|
||||||
Result.TOCItems[0].Control = 0;
|
Result.TOCItems[0].Control = 0;
|
||||||
Result.TOCItems[0].Exists = false;
|
Result.TOCItems[0].Exists = false;
|
||||||
|
|
||||||
//just in case this doesn't get set...
|
var minFoundTrack = 1;
|
||||||
Result.FirstRecordedTrackNumber = 0;
|
var maxFoundTrack = 1;
|
||||||
Result.LastRecordedTrackNumber = 0;
|
|
||||||
|
|
||||||
var maxFoundTrack = 0;
|
|
||||||
|
|
||||||
foreach (var te in Entries)
|
foreach (var te in Entries)
|
||||||
{
|
{
|
||||||
|
@ -50,6 +47,7 @@ namespace BizHawk.Emulation.DiscSystem
|
||||||
case 255:
|
case 255:
|
||||||
throw new InvalidOperationException("point == 255");
|
throw new InvalidOperationException("point == 255");
|
||||||
case <= 99:
|
case <= 99:
|
||||||
|
minFoundTrack = Math.Min(minFoundTrack, point);
|
||||||
maxFoundTrack = Math.Max(maxFoundTrack, point);
|
maxFoundTrack = Math.Max(maxFoundTrack, point);
|
||||||
Result.TOCItems[point].LBA = q.AP_Timestamp - 150; //RawTOCEntries contained an absolute time
|
Result.TOCItems[point].LBA = q.AP_Timestamp - 150; //RawTOCEntries contained an absolute time
|
||||||
Result.TOCItems[point].Control = q.CONTROL;
|
Result.TOCItems[point].Control = q.CONTROL;
|
||||||
|
@ -96,8 +94,7 @@ namespace BizHawk.Emulation.DiscSystem
|
||||||
}
|
}
|
||||||
|
|
||||||
//this is speculative:
|
//this is speculative:
|
||||||
//well, nothing to be done here..
|
if (Result.FirstRecordedTrackNumber == -1) { Result.FirstRecordedTrackNumber = minFoundTrack; }
|
||||||
// if (ret.FirstRecordedTrackNumber == -1) { }
|
|
||||||
if (Result.LastRecordedTrackNumber == -1) { Result.LastRecordedTrackNumber = maxFoundTrack; }
|
if (Result.LastRecordedTrackNumber == -1) { Result.LastRecordedTrackNumber = maxFoundTrack; }
|
||||||
if (Result.SessionFormat == SessionFormat.None) Result.SessionFormat = SessionFormat.Type00_CDROM_CDDA;
|
if (Result.SessionFormat == SessionFormat.None) Result.SessionFormat = SessionFormat.Type00_CDROM_CDDA;
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@ namespace BizHawk.Emulation.DiscSystem
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The complete sector userdata (2352 bytes) is required
|
/// The complete sector userdata (2352 bytes) is required
|
||||||
/// </summary>
|
/// </summary>
|
||||||
UserComplete = 15,
|
UserComplete = (Header16 | User2048 | ECM288Complete),
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An alias for UserComplete
|
/// An alias for UserComplete
|
||||||
|
|
|
@ -71,6 +71,30 @@ namespace BizHawk.Emulation.DiscSystem
|
||||||
buffer16[offset + 15] = mode;
|
buffer16[offset + 15] = mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Synthesizes a Mode2 sector subheader
|
||||||
|
/// </summary>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Synthesizes the EDC checksum for a Mode 1 data sector (and puts it in place)
|
||||||
|
/// </summary>
|
||||||
|
public static void EDC_Mode1(byte[] buf2352, int offset)
|
||||||
|
{
|
||||||
|
var edc = ECM.EDC_Calc(buf2352, offset, 2064);
|
||||||
|
ECM.PokeUint(buf2352, offset + 2064, edc);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Synthesizes the EDC checksum for a Mode 2 Form 1 data sector (and puts it in place)
|
/// Synthesizes the EDC checksum for a Mode 2 Form 1 data sector (and puts it in place)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -92,13 +116,12 @@ namespace BizHawk.Emulation.DiscSystem
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Synthesizes the complete ECM data (EDC + ECC) for a Mode 1 data sector (and puts it in place)
|
/// 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
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static void ECM_Mode1(byte[] buf2352, int offset, int LBA)
|
public static void ECM_Mode1(byte[] buf2352, int offset)
|
||||||
{
|
{
|
||||||
//EDC
|
//EDC
|
||||||
var edc = ECM.EDC_Calc(buf2352, offset, 2064);
|
EDC_Mode1(buf2352, offset);
|
||||||
ECM.PokeUint(buf2352, offset + 2064, edc);
|
|
||||||
|
|
||||||
//reserved, zero
|
//reserved, zero
|
||||||
for (var i = 0; i < 8; i++) buf2352[offset + 2068 + i] = 0;
|
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);
|
ECM.ECC_Populate(buf2352, offset, buf2352, offset, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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
|
||||||
|
/// </summary>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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
|
||||||
|
/// </summary>
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Converts the useful (but unrealistic) deinterleaved subchannel data into the useless (but realistic) interleaved format.
|
/// Converts the useful (but unrealistic) deinterleaved subchannel data into the useless (but realistic) interleaved format.
|
||||||
/// in_buf and out_buf should not overlap
|
/// in_buf and out_buf should not overlap
|
||||||
|
|
Loading…
Reference in New Issue