public static BufferedSubcodeSector CloneFromBytesDeinterleaved(byte[] buffer) { var ret = new BufferedSubcodeSector(); Buffer.BlockCopy(buffer, 0, ret.SubcodeDeinterleaved, 0, 96); return(ret); }
/// <summary> /// applies an SBI file to the disc /// </summary> public void ApplySBI(SBI_Format.SBIFile sbi) { //save this, it's small, and we'll want it for disc processing a/b checks Memos["sbi"] = sbi; int n = sbi.ABAs.Count; byte[] subcode = new byte[96]; int b = 0; for (int i = 0; i < n; i++) { int aba = sbi.ABAs[i]; var oldSubcode = this.Sectors[aba].SubcodeSector; oldSubcode.ReadSubcodeDeinterleaved(subcode, 0); for (int j = 0; j < 12; j++) { short patch = sbi.subq[b++]; if (patch == -1) { continue; } else { subcode[12 + j] = (byte)patch; } } var bss = new BufferedSubcodeSector(); Sectors[aba].SubcodeSector = BufferedSubcodeSector.CloneFromBytesDeinterleaved(subcode); } }
/// <summary> /// Creates the subcode (really, just subchannel Q) for this disc from its current TOC. /// Depends on the TOCPoints existing in the structure /// TODO - do we need a fully 0xFF P-subchannel for PSX? /// </summary> void Synthesize_SubcodeFromStructure() { int aba = 0; int dpIndex = 0; //TODO - from mednafen (on PC-FX chip chan kick) //If we're more than 2 seconds(150 sectors) from the real "start" of the track/INDEX 01, and the track is a data track, //and the preceding track is an audio track, encode it as audio(by taking the SubQ control field from the preceding //NOTE: discs may have subcode which is nonsense or possibly not recoverable from a sensible disc structure. //but this function does what it says. //SO: heres the main idea of how this works. //we have the Structure.Points (whose name we dont like) which is a list of sectors where the tno/index changes. //So for each sector, we see if we've advanced to the next point. //TODO - check if this is synthesized correctly when producing a structure from a TOCRaw while (aba < Sectors.Count) { if (dpIndex < Structure.Points.Count - 1) { while (aba >= Structure.Points[dpIndex + 1].ABA) { dpIndex++; } } var dp = Structure.Points[dpIndex]; var se = Sectors[aba]; EControlQ control = dp.Control; bool pause = true; if (dp.Num != 0) //TODO - shouldnt this be IndexNum? pause = false; if ((dp.Control & EControlQ.DataUninterrupted)!=0) pause = false; int adr = dp.ADR; SubchannelQ sq = new SubchannelQ(); sq.q_status = SubchannelQ.ComputeStatus(adr, control); sq.q_tno = BCD2.FromDecimal(dp.TrackNum).BCDValue; sq.q_index = BCD2.FromDecimal(dp.IndexNum).BCDValue; int track_relative_aba = aba - dp.Track.Indexes[1].aba; track_relative_aba = Math.Abs(track_relative_aba); Timestamp track_relative_timestamp = new Timestamp(track_relative_aba); sq.min = BCD2.FromDecimal(track_relative_timestamp.MIN); sq.sec = BCD2.FromDecimal(track_relative_timestamp.SEC); sq.frame = BCD2.FromDecimal(track_relative_timestamp.FRAC); sq.zero = 0; Timestamp absolute_timestamp = new Timestamp(aba); sq.ap_min = BCD2.FromDecimal(absolute_timestamp.MIN); sq.ap_sec = BCD2.FromDecimal(absolute_timestamp.SEC); sq.ap_frame = BCD2.FromDecimal(absolute_timestamp.FRAC); var bss = new BufferedSubcodeSector(); bss.Synthesize_SubchannelQ(ref sq, true); //TEST: need this for psx? if(pause) bss.Synthesize_SubchannelP(true); se.SubcodeSector = bss; aba++; } }
/// <summary> /// applies an SBI file to the disc /// </summary> public void ApplySBI(SBI_Format.SBIFile sbi) { //save this, it's small, and we'll want it for disc processing a/b checks Memos["sbi"] = sbi; int n = sbi.ABAs.Count; byte[] subcode = new byte[96]; int b=0; for (int i = 0; i < n; i++) { int aba = sbi.ABAs[i]; var oldSubcode = this.Sectors[aba].SubcodeSector; oldSubcode.ReadSubcodeDeinterleaved(subcode, 0); for (int j = 0; j < 12; j++) { short patch = sbi.subq[b++]; if (patch == -1) continue; else subcode[12 + j] = (byte)patch; } var bss = new BufferedSubcodeSector(); Sectors[aba].SubcodeSector = BufferedSubcodeSector.CloneFromBytesDeinterleaved(subcode); } }
public static BufferedSubcodeSector CloneFromBytesDeinterleaved(byte[] buffer) { var ret = new BufferedSubcodeSector(); Buffer.BlockCopy(buffer, 0, ret.SubcodeDeinterleaved, 0, 96); return ret; }
/// <summary> /// Creates the subcode (really, just subchannel Q) for this disc from its current TOC. /// Depends on the TOCPoints existing in the structure /// TODO - do we need a fully 0xFF P-subchannel for PSX? /// </summary> void Synthesize_SubcodeFromStructure() { int aba = 0; int dpIndex = 0; //TODO - from mednafen (on PC-FX chip chan kick) //If we're more than 2 seconds(150 sectors) from the real "start" of the track/INDEX 01, and the track is a data track, //and the preceding track is an audio track, encode it as audio(by taking the SubQ control field from the preceding //NOTE: discs may have subcode which is nonsense or possibly not recoverable from a sensible disc structure. //but this function does what it says. //SO: heres the main idea of how this works. //we have the Structure.Points (whose name we dont like) which is a list of sectors where the tno/index changes. //So for each sector, we see if we've advanced to the next point. //TODO - check if this is synthesized correctly when producing a structure from a TOCRaw while (aba < Sectors.Count) { if (dpIndex < Structure.Points.Count - 1) { while (aba >= Structure.Points[dpIndex + 1].ABA) { dpIndex++; } } var dp = Structure.Points[dpIndex]; var se = Sectors[aba]; EControlQ control = dp.Control; bool pause = true; if (dp.Num != 0) //TODO - shouldnt this be IndexNum? { pause = false; } if ((dp.Control & EControlQ.DataUninterrupted) != 0) { pause = false; } int adr = dp.ADR; SubchannelQ sq = new SubchannelQ(); sq.q_status = SubchannelQ.ComputeStatus(adr, control); sq.q_tno = BCD2.FromDecimal(dp.TrackNum).BCDValue; sq.q_index = BCD2.FromDecimal(dp.IndexNum).BCDValue; int track_relative_aba = aba - dp.Track.Indexes[1].aba; track_relative_aba = Math.Abs(track_relative_aba); Timestamp track_relative_timestamp = new Timestamp(track_relative_aba); sq.min = BCD2.FromDecimal(track_relative_timestamp.MIN); sq.sec = BCD2.FromDecimal(track_relative_timestamp.SEC); sq.frame = BCD2.FromDecimal(track_relative_timestamp.FRAC); sq.zero = 0; Timestamp absolute_timestamp = new Timestamp(aba); sq.ap_min = BCD2.FromDecimal(absolute_timestamp.MIN); sq.ap_sec = BCD2.FromDecimal(absolute_timestamp.SEC); sq.ap_frame = BCD2.FromDecimal(absolute_timestamp.FRAC); var bss = new BufferedSubcodeSector(); bss.Synthesize_SubchannelQ(ref sq, true); //TEST: need this for psx? if (pause) { bss.Synthesize_SubchannelP(true); } se.SubcodeSector = bss; aba++; } }
/// <summary> /// Loads a CCD at the specified path to a Disc object /// </summary> public Disc LoadCCDToDisc(string ccdPath) { var loadResults = LoadCCDPath(ccdPath); if (!loadResults.Valid) { throw loadResults.FailureException; } Disc disc = new Disc(); var ccdf = loadResults.ParsedCCDFile; var imgBlob = new Disc.Blob_RawFile() { PhysicalPath = loadResults.ImgPath }; var subBlob = new Disc.Blob_RawFile() { PhysicalPath = loadResults.SubPath }; disc.Blobs.Add(imgBlob); disc.Blobs.Add(subBlob); //generate DiscTOCRaw items from the ones specified in the CCD file //TODO - range validate these (too many truncations to byte) disc.RawTOCEntries = new List <RawTOCEntry>(); BufferedSubcodeSector bss = new BufferedSubcodeSector(); foreach (var entry in ccdf.TOCEntries) { var q = new SubchannelQ { q_status = SubchannelQ.ComputeStatus(entry.ADR, (EControlQ)(entry.Control & 0xF)), q_tno = (byte)entry.TrackNo, q_index = (byte)entry.Point, min = BCD2.FromDecimal(entry.AMin), sec = BCD2.FromDecimal(entry.ASec), frame = BCD2.FromDecimal(entry.AFrame), zero = (byte)entry.Zero, ap_min = BCD2.FromDecimal(entry.PMin), ap_sec = BCD2.FromDecimal(entry.PSec), ap_frame = BCD2.FromDecimal(entry.PFrame), }; //CRC cant be calculated til we've got all the fields setup q.q_crc = bss.Synthesize_SubchannelQ(ref q, true); disc.RawTOCEntries.Add(new RawTOCEntry { QData = q }); } //generate the toc from the entries var tocSynth = new DiscTOCRaw.SynthesizeFromRawTOCEntriesJob() { Entries = disc.RawTOCEntries }; tocSynth.Run(); disc.TOCRaw = tocSynth.Result; //synthesize DiscStructure var structureSynth = new DiscStructure.SynthesizeFromDiscTOCRawJob() { TOCRaw = disc.TOCRaw }; structureSynth.Run(); disc.Structure = structureSynth.Result; //I *think* implicitly there is an index 0.. at.. i dunno, 0 maybe, for track 1 { var dsi0 = new DiscStructure.Index(); dsi0.LBA = 0; dsi0.Number = 0; disc.Structure.Sessions[0].Tracks[0].Indexes.Add(dsi0); } //now, how to get the track types for the DiscStructure? //1. the CCD tells us (somehow the reader has judged) //2. scan it out of the Q subchannel //lets choose1. //TODO - better consider how to handle the situation where we have havent received all the [TRACK] items we need foreach (var st in disc.Structure.Sessions[0].Tracks) { var ccdt = ccdf.TracksByNumber[st.Number]; switch (ccdt.Mode) { case 0: st.TrackType = ETrackType.Audio; //for CCD, this means audio, apparently. break; case 1: st.TrackType = ETrackType.Mode1_2352; break; case 2: st.TrackType = ETrackType.Mode2_2352; break; default: throw new InvalidOperationException("Unsupported CCD mode"); } //add indexes for this track foreach (var ccdi in ccdt.Indexes) { var dsi = new DiscStructure.Index(); //if (ccdi.Key == 0) continue; dsi.LBA = ccdi.Value; dsi.Number = ccdi.Key; st.Indexes.Add(dsi); } } //add sectors for the lead-in, which isn't stored in the CCD file, I think //TODO - synthesize lead-in sectors from TOC, if the lead-in isn't available. //need a test case for that though. var leadin_sector_zero = new Sector_Zero(); var leadin_subcode_zero = new ZeroSubcodeSector(); for (int i = 0; i < 150; i++) { var se = new SectorEntry(leadin_sector_zero); disc.Sectors.Add(se); se.SubcodeSector = leadin_subcode_zero; } //build the sectors: //set up as many sectors as we have img/sub for, even if the TOC doesnt reference them (TOC is unreliable, although the tracks should have covered it all) for (int i = 0; i < loadResults.NumImgSectors; i++) { var isec = new Sector_RawBlob(); isec.Offset = ((long)i) * 2352; isec.Blob = imgBlob; var se = new SectorEntry(isec); disc.Sectors.Add(se); var scsec = new BlobSubcodeSectorPreDeinterleaved(); scsec.Offset = ((long)i) * 96; scsec.Blob = subBlob; se.SubcodeSector = scsec; } return(disc); }