using System; using System.Text; using System.Collections.Generic; namespace BizHawk.Emulation.DiscSystem { public class DiscTOC { /// /// Sessions contained in the disc. Right now support for anything other than 1 session is totally not working /// public List Sessions = new List(); /// /// this is an unfinished concept of "TOC Points" which is sometimes more convenient way for organizing the disc contents /// public List Points = new List(); /// /// Todo - comment about what this actually means /// TODO - this is redundant with Sectors.Count /// public int length_aba; /// /// todo - comment about what this actually means /// public Timestamp FriendlyLength { get { return new Timestamp(length_aba); } } /// /// todo - comment about what this actually means /// public long BinarySize { get { return length_aba * 2352; } } /// /// seeks the point immediately before (or equal to) this LBA /// public TOCPoint SeekPoint(int lba) { int aba = lba + 150; for(int i=0;i aba) return Points[i - 1]; } return Points[Points.Count - 1]; } /// /// /// public class TOCPoint { public int Num; public int ABA, TrackNum, IndexNum; public Track Track; public int LBA { get { return ABA - 150; } } } /// /// Generates the Points list from the current TOC /// public void GeneratePoints() { int num = 0; Points.Clear(); foreach (var ses in Sessions) { foreach (var track in ses.Tracks) foreach (var index in track.Indexes) { var tp = new TOCPoint { Num = num++, ABA = index.aba, TrackNum = track.num, IndexNum = index.num, Track = track }; Points.Add(tp); } var tpLeadout = new TOCPoint(); var lastTrack = ses.Tracks[ses.Tracks.Count - 1]; tpLeadout.Num = num++; tpLeadout.ABA = lastTrack.Indexes[1].aba + lastTrack.length_aba; tpLeadout.IndexNum = 0; tpLeadout.TrackNum = 100; tpLeadout.Track = null; //no leadout track.. now... or ever? Points.Add(tpLeadout); } } public class Session { public int num; public List Tracks = new List(); //the length of the session (should be the sum of all track lengths) public int length_aba; public Timestamp FriendlyLength { get { return new Timestamp(length_aba); } } } public class Track { public ETrackType TrackType; public int num; public List Indexes = new List(); /// /// a track logically starts at index 1. /// so this is the length from this index 1 to the next index 1 (or the end of the disc) /// the time before track 1 index 1 is the lead-in and isn't accounted for in any track... /// public int length_aba; public Timestamp FriendlyLength { get { return new Timestamp(length_aba); } } } public class Index { public int num; public int aba; public int LBA { get { return aba - 150; } } //the length of the section //HEY! This is commented out because it is a bad idea. //The length of a section is almost useless, and if you want it, you are probably making an error. //public int length_lba; //public Cue.Timestamp FriendlyLength { get { return new Cue.Timestamp(length_lba); } } } public string GenerateCUE_OneBin(CueBinPrefs prefs) { if (prefs.OneBlobPerTrack) throw new InvalidOperationException("OneBinPerTrack passed to GenerateCUE_OneBin"); //this generates a single-file cue!!!!!!! dont expect it to generate bin-per-track! StringBuilder sb = new StringBuilder(); foreach (var session in Sessions) { if (!prefs.SingleSession) { //dont want to screw around with sessions for now if (prefs.AnnotateCue) sb.AppendFormat("SESSION {0:D2} (length={1})\n", session.num, session.length_aba); else sb.AppendFormat("SESSION {0:D2}\n", session.num); } foreach (var track in session.Tracks) { ETrackType trackType = track.TrackType; //mutate track type according to our principle of canonicalization if (trackType == ETrackType.Mode1_2048 && prefs.DumpECM) trackType = ETrackType.Mode1_2352; if (prefs.AnnotateCue) sb.AppendFormat(" TRACK {0:D2} {1} (length={2})\n", track.num, Cue.TrackTypeStringForTrackType(trackType), track.length_aba); else sb.AppendFormat(" TRACK {0:D2} {1}\n", track.num, Cue.TrackTypeStringForTrackType(trackType)); foreach (var index in track.Indexes) { //cue+bin has an implicit 150 sector pregap which neither the cue nor the bin has any awareness of //except for the baked-in sector addressing. //but, if there is an extra-long pregap, we want to reflect it this way int lba = index.aba - 150; if (lba <= 0 && index.num == 0 && track.num == 1) { } //dont emit index 0 when it is the same as index 1, it is illegal for some reason else if (index.num == 0 && index.aba == track.Indexes[1].aba) { //dont emit index 0 when it is the same as index 1, it confuses some cue parsers } else { sb.AppendFormat(" INDEX {0:D2} {1}\n", index.num, new Timestamp(lba).Value); } } } } return sb.ToString(); } public void AnalyzeLengthsFromIndexLengths() { //this is a little more complex than it looks, because the length of a thing is not determined by summing it //but rather by the difference in lbas between start and end length_aba = 0; foreach (var session in Sessions) { var firstTrack = session.Tracks[0]; var lastTrack = session.Tracks[session.Tracks.Count - 1]; session.length_aba = lastTrack.Indexes[0].aba + lastTrack.length_aba - firstTrack.Indexes[0].aba; length_aba += session.length_aba; } } } }