From 4b8d3cfa793bbc4e0b97f820086a232586075084 Mon Sep 17 00:00:00 2001 From: zeromus Date: Sat, 27 Jun 2015 04:57:22 -0500 Subject: [PATCH] cleanup CUE toc handling a bit --- .../BizHawk.Emulation.Cores.csproj | 4 +- .../BizHawk.Emulation.DiscSystem.csproj | 1 + BizHawk.Emulation.DiscSystem/CCD_format.cs | 2 +- .../CUE/CUE_Analyze.cs | 9 +- BizHawk.Emulation.DiscSystem/CUE/CUE_Load.cs | 25 +++--- BizHawk.Emulation.DiscSystem/Disc.cs | 13 +-- BizHawk.Emulation.DiscSystem/DiscTypes.cs | 55 +----------- .../Jobs/Synthesize_A0A1A2_Job.cs | 83 +++++++++++++++++++ BizHawk.Emulation.DiscSystem/Subcode.cs | 59 +++---------- 9 files changed, 126 insertions(+), 125 deletions(-) create mode 100644 BizHawk.Emulation.DiscSystem/Jobs/Synthesize_A0A1A2_Job.cs diff --git a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj index 850f3c6798..f4eb67bf9a 100644 --- a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj +++ b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj @@ -137,7 +137,9 @@ AppleII.cs - + + AppleII.cs + AppleII.cs diff --git a/BizHawk.Emulation.DiscSystem/BizHawk.Emulation.DiscSystem.csproj b/BizHawk.Emulation.DiscSystem/BizHawk.Emulation.DiscSystem.csproj index 50f18716cc..5de64f69f4 100644 --- a/BizHawk.Emulation.DiscSystem/BizHawk.Emulation.DiscSystem.csproj +++ b/BizHawk.Emulation.DiscSystem/BizHawk.Emulation.DiscSystem.csproj @@ -85,6 +85,7 @@ + diff --git a/BizHawk.Emulation.DiscSystem/CCD_format.cs b/BizHawk.Emulation.DiscSystem/CCD_format.cs index 963bc94b30..51da7f1d50 100644 --- a/BizHawk.Emulation.DiscSystem/CCD_format.cs +++ b/BizHawk.Emulation.DiscSystem/CCD_format.cs @@ -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: diff --git a/BizHawk.Emulation.DiscSystem/CUE/CUE_Analyze.cs b/BizHawk.Emulation.DiscSystem/CUE/CUE_Analyze.cs index e05cbf25d3..31fb4c5263 100644 --- a/BizHawk.Emulation.DiscSystem/CUE/CUE_Analyze.cs +++ b/BizHawk.Emulation.DiscSystem/CUE/CUE_Analyze.cs @@ -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") { diff --git a/BizHawk.Emulation.DiscSystem/CUE/CUE_Load.cs b/BizHawk.Emulation.DiscSystem/CUE/CUE_Load.cs index 8a0519e1a6..80d04e4987 100644 --- a/BizHawk.Emulation.DiscSystem/CUE/CUE_Load.cs +++ b/BizHawk.Emulation.DiscSystem/CUE/CUE_Load.cs @@ -345,9 +345,10 @@ namespace BizHawk.Emulation.DiscSystem SubchannelQ priorSubchannelQ = new SubchannelQ(); int LBA = 0; List 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 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 }; diff --git a/BizHawk.Emulation.DiscSystem/Disc.cs b/BizHawk.Emulation.DiscSystem/Disc.cs index e5673efc4c..839498e847 100644 --- a/BizHawk.Emulation.DiscSystem/Disc.cs +++ b/BizHawk.Emulation.DiscSystem/Disc.cs @@ -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 diff --git a/BizHawk.Emulation.DiscSystem/DiscTypes.cs b/BizHawk.Emulation.DiscSystem/DiscTypes.cs index c4a6d2b52b..49ae05f19d 100644 --- a/BizHawk.Emulation.DiscSystem/DiscTypes.cs +++ b/BizHawk.Emulation.DiscSystem/DiscTypes.cs @@ -20,60 +20,7 @@ namespace BizHawk.Emulation.DiscSystem BizHawk, MednaDisc, LibMirage } - /// - /// Synthesizes RawTCOEntry A0 A1 A2 from the provided information - /// TODO - dont these need to have timestamps too? - /// - 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; - - /// - /// TODO - this hasnt been set for CCD, has it? - /// - public DiscTOCRaw.SessionFormat Session1Format; - - /// - /// Appends the new entries to the provided list - /// - public void Run(List 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 }); - } - } + /// /// Main unit of organization for reading data from the disc. Represents one physical disc sector. diff --git a/BizHawk.Emulation.DiscSystem/Jobs/Synthesize_A0A1A2_Job.cs b/BizHawk.Emulation.DiscSystem/Jobs/Synthesize_A0A1A2_Job.cs new file mode 100644 index 0000000000..0a038cfb53 --- /dev/null +++ b/BizHawk.Emulation.DiscSystem/Jobs/Synthesize_A0A1A2_Job.cs @@ -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 +{ + /// + /// 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 + /// + public class Synthesize_A0A1A2_Job + { + /// + /// "First Recorded Track Number" value for TOC (usually 1) + /// + public int IN_FirstRecordedTrackNumber; + + /// + /// "Last Recorded Track Number" value for TOC + /// + public int IN_LastRecordedTrackNumber; + + /// + /// The absolute timestamp of the lead-out track + /// + public Timestamp IN_LeadoutTimestamp; + + /// + /// The session format for this TOC + /// + public DiscTOCRaw.SessionFormat IN_Session1Format; + + /// + /// Appends the new entries to the provided list + /// + public void Run(List 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 }); + } + } +} \ No newline at end of file diff --git a/BizHawk.Emulation.DiscSystem/Subcode.cs b/BizHawk.Emulation.DiscSystem/Subcode.cs index f8e9047aff..1b60755aa1 100644 --- a/BizHawk.Emulation.DiscSystem/Subcode.cs +++ b/BizHawk.Emulation.DiscSystem/Subcode.cs @@ -249,44 +249,6 @@ namespace BizHawk.Emulation.DiscSystem _4CH = 8, //Four channel audio } - /// - /// the q-mode 1 Q subchannel data. These contain TOC entries. - /// design of this struct is from [IEC10149]. - /// Nothing in here is BCD - /// - public class Q_Mode_1 - { - /// - /// Supposed to be zero, because it was in the lead-in track, but you never know - /// - public byte TNO; - - /// - /// The track number (or a special A0 A1 A2 value) of the track being described - /// - public byte POINTER; - - /// - /// Supposedly the timestamp within the lead-in track. but it's useless - /// - public byte MIN, SEC, FRAC; - - /// - /// Supposed to be zero - /// - public byte ZERO; - - /// - /// A track number of the first (for A0) or final (A1) information track; or the _absolute_ time position of an information track - /// - public byte P_MIN; - - /// - /// ZERO for an A0 or A1 entry (where P_MIN was the track number); or the _absolute_ time position of an information track - /// - public byte P_SEC, P_FRAC; - } - /// /// 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 { /// /// ADR and CONTROL - /// TODO - make BCD2? + /// TODO - make BCD2? PROBABLY NOT. I DONT KNOW. /// public byte q_status; /// - /// normal track: BCD indications of the current track number + /// normal track: BCD indication of the current track number /// leadin track: should be 0 /// public BCD2 q_tno; /// - /// 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 # /// 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 /// public BCD2 min, sec, frame; @@ -345,7 +307,6 @@ namespace BizHawk.Emulation.DiscSystem /// public ushort q_crc; - /// /// Retrieves the initial set of timestamps (min,sec,frac) as a convenient Timestamp /// @@ -360,19 +321,19 @@ namespace BizHawk.Emulation.DiscSystem } /// - /// sets the status byte from the provided adr and control values + /// sets the status byte from the provided adr/qmode and control values /// - 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); } /// - /// computes a status byte from the provided adr and control values + /// computes a status byte from the provided adr/qmode and control values /// - 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)); } ///