cleanup CUE toc handling a bit

This commit is contained in:
zeromus 2015-06-27 04:57:22 -05:00
parent fda3ec03ed
commit 4b8d3cfa79
9 changed files with 126 additions and 125 deletions

View File

@ -137,7 +137,9 @@
<Compile Include="Computers\AppleII\AppleII.IMemoryDomains.cs">
<DependentUpon>AppleII.cs</DependentUpon>
</Compile>
<Compile Include="Computers\AppleII\AppleII.ISettable.cs" />
<Compile Include="Computers\AppleII\AppleII.ISettable.cs">
<DependentUpon>AppleII.cs</DependentUpon>
</Compile>
<Compile Include="Computers\AppleII\AppleII.IStatable.cs">
<DependentUpon>AppleII.cs</DependentUpon>
</Compile>

View File

@ -85,6 +85,7 @@
<Compile Include="Jobs\DiscMountJob.MednaDisc.cs" />
<Compile Include="Jobs\LoadSBIJob.cs" />
<Compile Include="Jobs\LoggedJob.cs" />
<Compile Include="Jobs\Synthesize_A0A1A2_Job.cs" />
<Compile Include="M3U_file.cs" />
<Compile Include="MednaDiscAPI.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />

View File

@ -560,7 +560,7 @@ namespace BizHawk.Emulation.DiscSystem
//if we keep this, it should just be as a memo that later heuristics can use. For example: 'use guidance from original disc image'
track.ModeHeuristic = ccdt.Mode;
//TODO - this should be deleted anyway (
//TODO - this should be deleted anyway (
switch (ccdt.Mode)
{
case 0:

View File

@ -162,8 +162,11 @@ namespace BizHawk.Emulation.DiscSystem
{
var ext = Path.GetExtension(fi.FullName).ToLowerInvariant();
//SBI and CUE are always bad choices
if (ext == ".cue" || ext == ".sbi")
//some choices are always bad: (we're looking for things like .bin and .wav)
//it's a little unclear whether we should go for a whitelist or a blacklist here.
//there's similar numbers of cases either way.
//perhaps we could code both (and prefer choices from the whitelist)
if (ext == ".cue" || ext == ".sbi" || ext == ".ccd" || ext == ".sub")
continue;
@ -230,7 +233,7 @@ namespace BizHawk.Emulation.DiscSystem
//TODO - once we reorganize the file ID stuff, do legit checks here (this is completely redundant with the fileID system
//TODO - decode vs stream vs unpossible policies in input policies object (including ffmpeg availability-checking callback (results can be cached))
string blobPathExt = Path.GetExtension(choice).ToUpperInvariant();
if (blobPathExt == ".BIN") cfi.Type = AnalyzeCueJob.CueFileType.BIN;
if (blobPathExt == ".BIN" || blobPathExt == ".IMG") cfi.Type = AnalyzeCueJob.CueFileType.BIN;
else if (blobPathExt == ".ISO") cfi.Type = AnalyzeCueJob.CueFileType.BIN;
else if (blobPathExt == ".WAV")
{

View File

@ -345,9 +345,10 @@ namespace BizHawk.Emulation.DiscSystem
SubchannelQ priorSubchannelQ = new SubchannelQ();
int LBA = 0;
List<IDisposable> resources = disc.DisposableResources;
var TOCInfo = new Synthesize_A0A1A2_Job { FirstRecordedTrackNumber = -1, LastRecordedTrackNumber = -1, LeadoutLBA = -1};
//lets start with this. we'll change it if we ever find a track of a different format (this is based on mednafen's behaviour)
TOCInfo.Session1Format = DiscTOCRaw.SessionFormat.Type00_CDROM_CDDA;
//lets start with session type CDDA. we'll change it if we ever find a track of a different format (this is based on mednafen's behaviour)
var TOCMiscInfo = new Synthesize_A0A1A2_Job { IN_FirstRecordedTrackNumber = -1, IN_LastRecordedTrackNumber = -1, IN_LeadoutTimestamp = new Timestamp(0) };
TOCMiscInfo.IN_Session1Format = DiscTOCRaw.SessionFormat.Type00_CDROM_CDDA;
//a little subroutine to wrap a sector if the blob is out of space
Func<int,Sector_RawBlob> eatBlobAndWrap = (required) =>
@ -384,7 +385,7 @@ namespace BizHawk.Emulation.DiscSystem
sq.sec = BCD2.FromDecimal(0);
sq.frame = BCD2.FromDecimal(0);
sq.AP_Timestamp = new Timestamp(LBA); //off by 150?
sq.AP_Timestamp = new Timestamp(LBA + 150); //its supposed to be an absolute timestamp
disc.RawTOCEntries.Add(new RawTOCEntry { QData = sq });
};
@ -768,21 +769,21 @@ namespace BizHawk.Emulation.DiscSystem
disc.Structure.Sessions[0].Tracks.Add(st);
//maintain some memos
if (TOCInfo.FirstRecordedTrackNumber == -1)
TOCInfo.FirstRecordedTrackNumber = track_num;
TOCInfo.LastRecordedTrackNumber = track_num;
if (TOCMiscInfo.IN_FirstRecordedTrackNumber == -1)
TOCMiscInfo.IN_FirstRecordedTrackNumber = track_num;
TOCMiscInfo.IN_LastRecordedTrackNumber = track_num;
//update the disc type... do we need to do any double checks here to check for regressions? doubt it.
if (TOCInfo.Session1Format == DiscTOCRaw.SessionFormat.Type00_CDROM_CDDA)
if (TOCMiscInfo.IN_Session1Format == DiscTOCRaw.SessionFormat.Type00_CDROM_CDDA)
{
switch (track_currentCommand.Type)
{
case CueFile.TrackType.Mode2_2336:
case CueFile.TrackType.Mode2_2352:
TOCInfo.Session1Format = DiscTOCRaw.SessionFormat.Type20_CDXA;
TOCMiscInfo.IN_Session1Format = DiscTOCRaw.SessionFormat.Type20_CDXA;
break;
case CueFile.TrackType.CDI_2336:
case CueFile.TrackType.CDI_2352:
TOCInfo.Session1Format = DiscTOCRaw.SessionFormat.Type10_CDI;
TOCMiscInfo.IN_Session1Format = DiscTOCRaw.SessionFormat.Type10_CDI;
break;
default:
//no changes here
@ -863,8 +864,8 @@ namespace BizHawk.Emulation.DiscSystem
disc.Structure.LengthInSectors = disc.Sectors.Count;
//add RawTOCEntries A0 A1 A2 to round out the TOC
TOCInfo.LeadoutLBA = LBA;
TOCInfo.Run(disc.RawTOCEntries);
TOCMiscInfo.IN_LeadoutTimestamp = new Timestamp(LBA + 150);
TOCMiscInfo.Run(disc.RawTOCEntries);
//generate the TOCRaw from the RawTocEntries
var tocSynth = new DiscTOCRaw.SynthesizeFromRawTOCEntriesJob() { Entries = disc.RawTOCEntries };

View File

@ -5,11 +5,14 @@ using System.IO;
using System.Collections.Generic;
//ARCHITECTURE NOTE:
//no provisions are made for caching synthesized data for later accelerated use.
//in the worst case that might result in synthesizing an entire disc in memory.
//instead, users should be advised to `hawk` the disc first for most rapid access
//this will result in a completely flattened CCD where everything comes right off the hard drive
//This might be an unwise decision for disc ID and miscellaneous purposes but it's best for gaming and stream-converting (hawking and hashing)
//No provisions are made for caching synthesized data for later accelerated use.
//This is because, in the worst case that might result in synthesizing an entire disc in memory.
//Instead, users should be advised to `hawk` the disc first for most rapid access so that synthesis won't be necessary and speed will be maximized.
//This will result in a completely flattened CCD where everything comes right off the hard drive
//Our choice here might be an unwise decision for disc ID and miscellaneous purposes but it's best for gaming and stream-converting (hawking and hashing)
//https://books.google.com/books?id=caF_AAAAQBAJ&lpg=PA124&ots=OA9Ttj9CHZ&dq=disc%20TOC%20point%20A2&pg=PA124
//http://www.staff.uni-mainz.de/tacke/scsi/SCSI2-14.html

View File

@ -20,60 +20,7 @@ namespace BizHawk.Emulation.DiscSystem
BizHawk, MednaDisc, LibMirage
}
/// <summary>
/// Synthesizes RawTCOEntry A0 A1 A2 from the provided information
/// TODO - dont these need to have timestamps too?
/// </summary>
public class Synthesize_A0A1A2_Job
{
//heres a thing
//https://books.google.com/books?id=caF_AAAAQBAJ&lpg=PA124&ots=OA9Ttj9CHZ&dq=disc%20TOC%20point%20A2&pg=PA124
public int FirstRecordedTrackNumber;
public int LastRecordedTrackNumber;
public int LeadoutLBA;
/// <summary>
/// TODO - this hasnt been set for CCD, has it?
/// </summary>
public DiscTOCRaw.SessionFormat Session1Format;
/// <summary>
/// Appends the new entries to the provided list
/// </summary>
public void Run(List<RawTOCEntry> entries)
{
SubchannelQ sq = new SubchannelQ();
//first recorded track number:
sq.q_index.DecimalValue = 0xA0;
sq.ap_min.DecimalValue = FirstRecordedTrackNumber;
switch(Session1Format)
{
case DiscTOCRaw.SessionFormat.Type00_CDROM_CDDA: sq.ap_sec.DecimalValue = 0x00; break;
case DiscTOCRaw.SessionFormat.Type10_CDI: sq.ap_sec.DecimalValue = 0x10; break;
case DiscTOCRaw.SessionFormat.Type20_CDXA: sq.ap_sec.DecimalValue = 0x20; break;
default: throw new InvalidOperationException("Invalid Session1Format");
}
sq.ap_frame.DecimalValue = 0;
entries.Add(new RawTOCEntry { QData = sq });
//last recorded track number:
sq.q_index.DecimalValue = 0xA1;
sq.ap_min.DecimalValue = LastRecordedTrackNumber;
sq.ap_sec.DecimalValue = 0;
sq.ap_frame.DecimalValue = 0;
entries.Add(new RawTOCEntry { QData = sq });
//leadout:
sq.q_index.DecimalValue = 0xA2;
sq.AP_Timestamp = new Timestamp(LeadoutLBA);
entries.Add(new RawTOCEntry { QData = sq });
}
}
/// <summary>
/// Main unit of organization for reading data from the disc. Represents one physical disc sector.

View File

@ -0,0 +1,83 @@
using System;
using System.Linq;
using System.Text;
using System.IO;
using System.Collections.Generic;
//TODO - generate correct Q subchannel CRC
namespace BizHawk.Emulation.DiscSystem
{
/// <summary>
/// Synthesizes RawTCOEntry A0 A1 A2 from the provided information.
/// This might be reused by formats other than CUE later, so it isn't directly associated with that
/// </summary>
public class Synthesize_A0A1A2_Job
{
/// <summary>
/// "First Recorded Track Number" value for TOC (usually 1)
/// </summary>
public int IN_FirstRecordedTrackNumber;
/// <summary>
/// "Last Recorded Track Number" value for TOC
/// </summary>
public int IN_LastRecordedTrackNumber;
/// <summary>
/// The absolute timestamp of the lead-out track
/// </summary>
public Timestamp IN_LeadoutTimestamp;
/// <summary>
/// The session format for this TOC
/// </summary>
public DiscTOCRaw.SessionFormat IN_Session1Format;
/// <summary>
/// Appends the new entries to the provided list
/// </summary>
public void Run(List<RawTOCEntry> entries)
{
SubchannelQ sq = new SubchannelQ();
BufferedSubcodeSector bss = new BufferedSubcodeSector(); //TODO - its hacky that we need this.. (NOT USED YET)
//ADR (q-Mode) is necessarily 0x01 for a RawTOCEntry
const int kADR = 1;
const int kUnknownControl = 0;
sq.SetStatus(kADR, (EControlQ)kUnknownControl);
//first recorded track number:
sq.q_index.BCDValue = 0xA0;
sq.ap_min.DecimalValue = IN_FirstRecordedTrackNumber;
switch(IN_Session1Format)
{
//TODO these probably shouldn't be decimal values
case DiscTOCRaw.SessionFormat.Type00_CDROM_CDDA: sq.ap_sec.DecimalValue = 0x00; break;
case DiscTOCRaw.SessionFormat.Type10_CDI: sq.ap_sec.DecimalValue = 0x10; break;
case DiscTOCRaw.SessionFormat.Type20_CDXA: sq.ap_sec.DecimalValue = 0x20; break;
default: throw new InvalidOperationException("Invalid Session1Format");
}
sq.ap_frame.DecimalValue = 0;
entries.Add(new RawTOCEntry { QData = sq });
//last recorded track number:
sq.q_index.BCDValue = 0xA1;
sq.ap_min.DecimalValue = IN_LastRecordedTrackNumber;
sq.ap_sec.DecimalValue = 0;
sq.ap_frame.DecimalValue = 0;
entries.Add(new RawTOCEntry { QData = sq });
//leadout:
sq.q_index.BCDValue = 0xA2;
sq.AP_Timestamp = IN_LeadoutTimestamp;
entries.Add(new RawTOCEntry { QData = sq });
}
}
}

View File

@ -249,44 +249,6 @@ namespace BizHawk.Emulation.DiscSystem
_4CH = 8, //Four channel audio
}
/// <summary>
/// the q-mode 1 Q subchannel data. These contain TOC entries.
/// design of this struct is from [IEC10149].
/// Nothing in here is BCD
/// </summary>
public class Q_Mode_1
{
/// <summary>
/// Supposed to be zero, because it was in the lead-in track, but you never know
/// </summary>
public byte TNO;
/// <summary>
/// The track number (or a special A0 A1 A2 value) of the track being described
/// </summary>
public byte POINTER;
/// <summary>
/// Supposedly the timestamp within the lead-in track. but it's useless
/// </summary>
public byte MIN, SEC, FRAC;
/// <summary>
/// Supposed to be zero
/// </summary>
public byte ZERO;
/// <summary>
/// A track number of the first (for A0) or final (A1) information track; or the _absolute_ time position of an information track
/// </summary>
public byte P_MIN;
/// <summary>
/// ZERO for an A0 or A1 entry (where P_MIN was the track number); or the _absolute_ time position of an information track
/// </summary>
public byte P_SEC, P_FRAC;
}
/// <summary>
/// Why did I make this a struct? I thought there might be a shitton of these and I was trying to cut down on object creation churn during disc-loading.
/// But I ended up mostly just having a shitton of byte[] for each buffer (I could improve that later to possibly reference a blob on top of a memorystream)
@ -296,18 +258,18 @@ namespace BizHawk.Emulation.DiscSystem
{
/// <summary>
/// ADR and CONTROL
/// TODO - make BCD2?
/// TODO - make BCD2? PROBABLY NOT. I DONT KNOW.
/// </summary>
public byte q_status;
/// <summary>
/// normal track: BCD indications of the current track number
/// normal track: BCD indication of the current track number
/// leadin track: should be 0
/// </summary>
public BCD2 q_tno;
/// <summary>
/// normal track: BCD indications of the current index
/// normal track: BCD indication of the current index
/// leadin track: 'POINT' field used to ID the TOC entry #
/// </summary>
public BCD2 q_index;
@ -318,7 +280,7 @@ namespace BizHawk.Emulation.DiscSystem
/// normal track: relative timestamp
/// leadin track: unknown
/// leadout: relative timestamp
/// TODO - why are these BCD2? having things in BCD2 is freaking annoying, I should only make them BCD2 when serializing
/// TODO - why are these BCD2? having things in BCD2 is freaking annoying, I should only make them BCD2 when serializing into a subchannel Q buffer
/// EDIT - elsewhere I rambled "why not BCD2?". geh. need to make a final organized approach
/// </summary>
public BCD2 min, sec, frame;
@ -345,7 +307,6 @@ namespace BizHawk.Emulation.DiscSystem
/// </summary>
public ushort q_crc;
/// <summary>
/// Retrieves the initial set of timestamps (min,sec,frac) as a convenient Timestamp
/// </summary>
@ -360,19 +321,19 @@ namespace BizHawk.Emulation.DiscSystem
}
/// <summary>
/// sets the status byte from the provided adr and control values
/// sets the status byte from the provided adr/qmode and control values
/// </summary>
public void SetStatus(byte adr, EControlQ control)
public void SetStatus(byte adr_or_qmode, EControlQ control)
{
q_status = ComputeStatus(adr, control);
q_status = ComputeStatus(adr_or_qmode, control);
}
/// <summary>
/// computes a status byte from the provided adr and control values
/// computes a status byte from the provided adr/qmode and control values
/// </summary>
public static byte ComputeStatus(int adr, EControlQ control)
public static byte ComputeStatus(int adr_or_qmode, EControlQ control)
{
return (byte)(adr | (((int)control) << 4));
return (byte)(adr_or_qmode | (((int)control) << 4));
}
/// <summary>