/// <summary> /// Attempts to determine the type of the disc. /// In the future, we might return a struct or a class with more detailed information /// </summary> public DiscType DetectDiscType() { //check track 1's data type. if it's an audio track, further data-track testing is useless //furthermore, it's probably senseless (no binary data there to read) //however a sector could mark itself as audio without actually being.. we'll just wait for that one. if (dsr.ReadLBA_Mode(disc.TOC.TOCItems[1].LBA) == 0) { return(DiscType.AudioDisc); } //sega doesnt put anything identifying in the cdfs volume info. but its consistent about putting its own header here in sector 0 if (DetectSegaSaturn()) { return(DiscType.SegaSaturn); } // not fully tested yet if (DetectMegaCD()) { return(DiscType.MegaCD); } // not fully tested yet if (DetectPSX()) { return(DiscType.SonyPSX); } //we dont know how to detect TurboCD. //an emulator frontend will likely just guess TurboCD if the disc is UnknownFormat //(we can also have a gameDB!) var discView = EDiscStreamView.DiscStreamView_Mode1_2048; if (disc.TOC.Session1Format == SessionFormat.Type20_CDXA) { discView = EDiscStreamView.DiscStreamView_Mode2_Form1_2048; } var iso = new ISOFile(); bool isIso = iso.Parse(new DiscStream(disc, discView, 0)); if (isIso) { var appId = System.Text.Encoding.ASCII.GetString(iso.VolumeDescriptors[0].ApplicationIdentifier).TrimEnd('\0', ' '); //for example: PSX magical drop F (JP SLPS_02337) doesn't have the correct iso PVD fields //but, some PSX games (junky rips) don't have the 'licensed by string' so we'll hope they get caught here if (appId == "PLAYSTATION") { return(DiscType.SonyPSX); } if (appId == "PSP GAME") { return(DiscType.SonyPSP); } return(DiscType.UnknownCDFS); } return(DiscType.UnknownFormat); }
/// <exception cref="InvalidOperationException">first track of <see cref="TOCRaw"/> is not <c>1</c></exception> public void Run() { var dsr = new DiscSectorReader(IN_Disc) { Policy = { DeterministicClearBuffer = false } }; Result = new DiscStructure(); var session = new DiscStructure.Session(); Result.Sessions.Add(null); //placeholder session for reindexing Result.Sessions.Add(session); session.Number = 1; if (TOCRaw.FirstRecordedTrackNumber != 1) { throw new InvalidOperationException($"Unsupported: {nameof(TOCRaw.FirstRecordedTrackNumber)} != 1"); } //add a lead-in track session.Tracks.Add(new DiscStructure.Track { Number = 0, Control = EControlQ.None, //we'll set this later LBA = -new Timestamp(99, 99, 99).Sector //obvious garbage }); int ntracks = TOCRaw.LastRecordedTrackNumber - TOCRaw.FirstRecordedTrackNumber + 1; for (int i = 0; i < ntracks; i++) { var item = TOCRaw.TOCItems[i + 1]; var track = new DiscStructure.Track { Number = i + 1, Control = item.Control, LBA = item.LBA }; session.Tracks.Add(track); if (!item.IsData) { track.Mode = 0; } else { //determine the mode by a hardcoded heuristic: check mode of first sector track.Mode = dsr.ReadLBA_Mode(track.LBA); } //determine track length according to... how? It isn't clear. //Let's not do this until it's needed. //if (i == ntracks - 1) // track.Length = TOCRaw.LeadoutLBA.Sector - track.LBA; //else track.Length = (TOCRaw.TOCItems[i + 2].LBATimestamp.Sector - track.LBA); } //add lead-out track session.Tracks.Add(new DiscStructure.Track { Number = 0xA0, //right? //kind of a guess, but not completely Control = session.Tracks[session.Tracks.Count - 1].Control, Mode = session.Tracks[session.Tracks.Count - 1].Mode, LBA = TOCRaw.LeadoutLBA }); //link track list for (int i = 0; i < session.Tracks.Count - 1; i++) { session.Tracks[i].NextTrack = session.Tracks[i + 1]; } //fix lead-in track type //guesses: session.Tracks[0].Control = session.Tracks[1].Control; session.Tracks[0].Mode = session.Tracks[1].Mode; }
public void Run() { var dsr = new DiscSectorReader(IN_Disc); dsr.Policy.DeterministicClearBuffer = false; Result = new DiscStructure(); var session = new DiscStructure.Session(); Result.Sessions.Add(null); //placeholder session for reindexing Result.Sessions.Add(session); session.Number = 1; if (TOCRaw.FirstRecordedTrackNumber != 1) throw new InvalidOperationException("Unsupported: FirstRecordedTrackNumber != 1"); //add a lead-in track session.Tracks.Add(new DiscStructure.Track() { Number = 0, Control = EControlQ.None, //we'll set this later LBA = -new Timestamp(99,99,99).Sector //obvious garbage }); int ntracks = TOCRaw.LastRecordedTrackNumber - TOCRaw.FirstRecordedTrackNumber + 1; for (int i = 0; i < ntracks; i++) { var item = TOCRaw.TOCItems[i + 1]; var track = new DiscStructure.Track() { Number = i + 1, Control = item.Control, LBA = item.LBA }; session.Tracks.Add(track); if (!item.IsData) track.Mode = 0; else { //determine the mode by a hardcoded heuristic: check mode of first sector track.Mode = dsr.ReadLBA_Mode(track.LBA); } //determine track length according to... how? It isn't clear. //Let's not do this until it's needed. //if (i == ntracks - 1) // track.Length = TOCRaw.LeadoutLBA.Sector - track.LBA; //else track.Length = (TOCRaw.TOCItems[i + 2].LBATimestamp.Sector - track.LBA); } //add lead-out track session.Tracks.Add(new DiscStructure.Track() { Number = 0xA0, //right? //kind of a guess, but not completely Control = session.Tracks[session.Tracks.Count -1 ].Control, Mode = session.Tracks[session.Tracks.Count - 1].Mode, LBA = TOCRaw.LeadoutLBA }); //link track list for (int i = 0; i < session.Tracks.Count - 1; i++) { session.Tracks[i].NextTrack = session.Tracks[i + 1]; } //fix lead-in track type //guesses: session.Tracks[0].Control = session.Tracks[1].Control; session.Tracks[0].Mode = session.Tracks[1].Mode; }