reorg and cleanup of old interfaces, stop populating q_crc for RawTOCEntry instances

This commit is contained in:
zeromus 2015-07-06 06:06:37 -05:00
parent 962b567f6d
commit 5e71224eda
10 changed files with 200 additions and 458 deletions

View File

@ -25,16 +25,6 @@ namespace BizHawk.Emulation.DiscSystem
sealed public partial class Disc
{
/// <summary>
/// Returns a SectorEntry from which you can retrieve various interesting pieces of information about the sector.
/// The SectorEntry's interface is not likely to be stable, though, but it may be more convenient.
/// </summary>
public SectorEntry ReadLBA_SectorEntry(int lba)
{
return Sectors[lba + 150];
}
/// <summary>
/// Main API to determine how many LBAs are available on the disc.
/// This counts from LBA 0 to the final sector available.

View File

@ -94,7 +94,7 @@ namespace BizHawk.Emulation.DiscSystem
job.Parts = ESectorSynthPart.User2352;
job.Disc = disc;
sector.SectorSynth.Synth(job);
sector.Synth(job);
Buffer.BlockCopy(buf2442, 0, buffer, offset, 2352);
@ -116,7 +116,7 @@ namespace BizHawk.Emulation.DiscSystem
if (Policy.DeinterleavedSubcode)
job.Parts |= ESectorSynthPart.SubcodeDeinterleave;
sector.SectorSynth.Synth(job);
sector.Synth(job);
//we went straight to the caller's buffer, so no need to copy
return 2442;
@ -133,7 +133,7 @@ namespace BizHawk.Emulation.DiscSystem
job.DestOffset = 0;
job.Parts = ESectorSynthPart.User2048;
sector.SectorSynth.Synth(job);
sector.Synth(job);
Buffer.BlockCopy(buf2442, 16, buffer, offset, 2048);
return 2048;
@ -150,7 +150,7 @@ namespace BizHawk.Emulation.DiscSystem
job.DestOffset = 0;
job.Parts = ESectorSynthPart.User2336;
sector.SectorSynth.Synth(job);
sector.Synth(job);
Buffer.BlockCopy(buf2442, 24, buffer, offset, 2048);
return 2048;
@ -170,7 +170,7 @@ namespace BizHawk.Emulation.DiscSystem
job.DestOffset = 0;
job.Parts = ESectorSynthPart.SubchannelQ | ESectorSynthPart.SubcodeDeinterleave;
sector.SectorSynth.Synth(job);
sector.Synth(job);
Buffer.BlockCopy(buf2442, 2352 + 12, buffer, offset, 12);
return 12;
@ -201,7 +201,7 @@ namespace BizHawk.Emulation.DiscSystem
job.DestOffset = 0;
job.Parts = ESectorSynthPart.Header16 | ESectorSynthPart.User2048 | ESectorSynthPart.EDC12;
sector.SectorSynth.Synth(job);
sector.Synth(job);
//now the inspection, based on the mode
byte mode = buf2442[15];
@ -276,7 +276,7 @@ namespace BizHawk.Emulation.DiscSystem
job.Parts = ESectorSynthPart.Header16;
job.Disc = disc;
sector.SectorSynth.Synth(job);
sector.Synth(job);
return buf2442[15];
}

View File

@ -470,7 +470,7 @@ namespace BizHawk.Emulation.DiscSystem
//subcode comes to us deinterleved; we may still need to interleave it
if ((job.Parts & (ESectorSynthPart.SubcodeDeinterleave)) == 0)
{
SubcodeUtils.InterleaveInplace(job.DestBuffer2448, job.DestOffset + 2352);
SynthUtils.InterleaveSubcodeInplace(job.DestBuffer2448, job.DestOffset + 2352);
}
}
}
@ -501,7 +501,6 @@ namespace BizHawk.Emulation.DiscSystem
//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(); //TODO - its hacky that we need this..
foreach (var entry in ccdf.TOCEntries)
{
BCD2 tno, ino;
@ -530,82 +529,27 @@ namespace BizHawk.Emulation.DiscSystem
ap_min = BCD2.FromDecimal(entry.PMin),
ap_sec = BCD2.FromDecimal(entry.PSec),
ap_frame = BCD2.FromDecimal(entry.PFrame),
q_crc = 0, //meainingless
};
//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 });
}
//disc.Structure = new DiscStructure();
//var ses = new DiscStructure.Session();
//disc.Structure.Sessions.Add(ses);
//for(int i=1;i<=99;i++)
//{
// if(!ccdf.TracksByNumber.ContainsKey(i))
// continue;
// var ccdt = ccdf.TracksByNumber[i];
// DiscStructure.Track track = new DiscStructure.Track() { Number = i };
// ses.Tracks.Add(track);
// //if index 0 is missing, add it
// if (!ccdt.Indexes.ContainsKey(0))
// track.Indexes.Add(new DiscStructure.Index { Number = 0, LBA = ccdt.Indexes[1] });
// for(int j=1;j<=99;j++)
// if (ccdt.Indexes.ContainsKey(j))
// track.Indexes.Add(new DiscStructure.Index { Number = j, LBA = ccdt.Indexes[j] });
// //TODO - this should only be used in case the .sub needs reconstructing
// //determination should be done from heuristics.
// //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 (
// switch (ccdt.Mode)
// {
// case 0:
// track.TrackType = DiscStructure.ETrackType.Audio; //for CCD, this means audio, apparently.
// break;
// case 1:
// case 2:
// track.TrackType = DiscStructure.ETrackType.Data;
// break;
// default:
// throw new InvalidOperationException("Unsupported CCD mode");
// }
//}
//add sectors for the "mandatory track 1 pregap", which isn't stored in the CCD file
//THIS IS JUNK. MORE CORRECTLY SYNTHESIZE IT
//add sectors for the mandatory track 1 pregap, which isn't stored in the CCD file
//TODO - THIS IS JUNK. MORE CORRECTLY SYNTHESIZE IT
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;
//TODO - YIKES!
disc.Sectors.Add(null);
}
//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)
//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;
se.SectorSynth = synth;
disc.Sectors.Add(synth);
}
return disc;

View File

@ -331,10 +331,7 @@ namespace BizHawk.Emulation.DiscSystem
if (curr_index == 0)
ss.Pause = true;
//make the SectorEntry (some temporary bullshit here)
var se = new SectorEntry(null);
se.SectorSynth = ss;
OUT_Disc.Sectors.Add(se);
OUT_Disc.Sectors.Add(ss);
relMSF++;
if (cct.IsFinalInFile)
@ -360,7 +357,6 @@ namespace BizHawk.Emulation.DiscSystem
int specifiedPostgapLength = cct.PostgapLength.Sector;
for (int s = 0; s < specifiedPostgapLength; s++)
{
var se= new SectorEntry(null);
var ss = new SS_Gap();
ss.TrackType = cct.TrackType; //TODO - old track type in some < -150 cases?
@ -376,8 +372,7 @@ namespace BizHawk.Emulation.DiscSystem
//always paused--is this good enough?
ss.Pause = true;
se.SectorSynth = ss;
OUT_Disc.Sectors.Add(se);
OUT_Disc.Sectors.Add(ss);
relMSF++;
}

View File

@ -31,11 +31,10 @@ namespace BizHawk.Emulation.DiscSystem
}
//synth Q if needed
//TODO - why not already have it serialized? Into a disc resource, even.
if ((job.Parts & ESectorSynthPart.SubchannelQ) != 0)
{
var subcode = new BufferedSubcodeSector();
subcode.Synthesize_SubchannelQ(ref sq, true);
Buffer.BlockCopy(subcode.SubcodeDeinterleaved, 12, job.DestBuffer2448, job.DestOffset + 2352 + 12, 12);
SynthUtils.SubQ_Serialize(job.DestBuffer2448, job.DestOffset + 2352 + 12, ref sq);
}
//clear R-W if needed
@ -47,7 +46,7 @@ namespace BizHawk.Emulation.DiscSystem
//subcode has been generated deinterleaved; we may still need to interleave it
if ((job.Parts & (ESectorSynthPart.SubcodeDeinterleave)) == 0)
{
SubcodeUtils.InterleaveInplace(job.DestBuffer2448, job.DestOffset + 2352);
SynthUtils.InterleaveSubcodeInplace(job.DestBuffer2448, job.DestOffset + 2352);
}
}
}

View File

@ -118,7 +118,7 @@ namespace BizHawk.Emulation.DiscSystem
/// <summary>
/// The sectors on the disc
/// </summary>
public List<SectorEntry> Sectors = new List<SectorEntry>();
internal List<ISectorSynthJob2448> Sectors = new List<ISectorSynthJob2448>();
internal SectorSynthParams SynthParams = new SectorSynthParams();
@ -137,6 +137,7 @@ namespace BizHawk.Emulation.DiscSystem
/// <summary>
/// generates lead-out sectors according to very crude approximations
/// TODO - this isnt being used right now
/// </summary>
public class SynthesizeLeadoutJob
{
@ -159,8 +160,8 @@ namespace BizHawk.Emulation.DiscSystem
for (int i = 0; i < Length; i++)
{
var se = new SectorEntry(sz);
Disc.Sectors.Add(se);
//var se = new SectorEntry(sz);
//Disc.Sectors.Add(se);
SubchannelQ sq = new SubchannelQ();
int track_relative_msf = i;
@ -179,9 +180,7 @@ namespace BizHawk.Emulation.DiscSystem
byte ADR = 1;
sq.SetStatus(ADR, leadoutFlags);
var subcode = new BufferedSubcodeSector();
subcode.Synthesize_SubchannelQ(ref sq, true);
se.SubcodeSector = subcode;
//TODO - actually stash the subQ
}
}
}
@ -233,14 +232,14 @@ namespace BizHawk.Emulation.DiscSystem
int lba = sbi.ABAs[i] - 150;
//create a synthesizer which can return the patched data
var ss_patchq = new SS_PatchQ() { Original = this.Sectors[lba+150].SectorSynth };
var ss_patchq = new SS_PatchQ() { Original = this.Sectors[lba+150] };
byte[] subQbuf = ss_patchq.Buffer_SubQ;
//read the old subcode
dsr.ReadLBA_SubQ(lba, subQbuf, 0);
//insert patch
Sectors[lba + 150].SectorSynth = ss_patchq;
Sectors[lba + 150] = ss_patchq;
//apply SBI patch
for (int j = 0; j < 12; j++)
@ -255,7 +254,7 @@ namespace BizHawk.Emulation.DiscSystem
//However, this seems senseless to me. The whole point of the SBI data is that it stores the patches needed to generate an acceptable subQ, right?
if (asMednafen)
{
SynthUtils.SubQ_Checksum(subQbuf, 0);
SynthUtils.SubQ_SynthChecksum(subQbuf, 0);
subQbuf[10] ^= 0xFF;
subQbuf[11] ^= 0xFF;
}
@ -422,73 +421,199 @@ namespace BizHawk.Emulation.DiscSystem
static class SynthUtils
{
/// <summary>
/// Calculates the checksum of the provided Q subchannel
/// Calculates the checksum of the provided Q subchannel buffer and emplaces it
/// </summary>
/// <param name="buffer">12 byte Q subchannel: input and output buffer for operation</param>
/// <param name="buffer">12 byte Q subchannel buffer: input and output buffer for operation</param>
/// <param name="offset">location within buffer of Q subchannel</param>
public static void SubQ_Checksum(byte[] buffer, int offset)
public static ushort SubQ_SynthChecksum(byte[] buf12, int offset)
{
ushort crc16 = CRC16_CCITT.Calculate(buffer, offset, 10);
ushort crc16 = CRC16_CCITT.Calculate(buf12, offset, 10);
//CRC is stored inverted and big endian
buffer[offset + 10] = (byte)(~(crc16 >> 8));
buffer[offset + 11] = (byte)(~(crc16));
buf12[offset + 10] = (byte)(~(crc16 >> 8));
buf12[offset + 11] = (byte)(~(crc16));
return crc16;
}
public static void SubP(byte[] buffer, int offset, bool pause)
/// <summary>
/// Caclulates the checksum of the provided Q subchannel buffer
/// </summary>
public static ushort SubQ_CalcChecksum(byte[] buf12, int offset)
{
return CRC16_CCITT.Calculate(buf12, offset, 10);
}
/// <summary>
/// Serializes the provided SubchannelQ structure into a buffer
/// Returns the crc, calculated or otherwise.
/// </summary>
public static ushort SubQ_Serialize(byte[] buf12, int offset, ref SubchannelQ sq)
{
buf12[offset + 0] = sq.q_status;
buf12[offset + 1] = sq.q_tno.BCDValue;
buf12[offset + 2] = sq.q_index.BCDValue;
buf12[offset + 3] = sq.min.BCDValue;
buf12[offset + 4] = sq.sec.BCDValue;
buf12[offset + 5] = sq.frame.BCDValue;
buf12[offset + 6] = sq.zero;
buf12[offset + 7] = sq.ap_min.BCDValue;
buf12[offset + 8] = sq.ap_sec.BCDValue;
buf12[offset + 9] = sq.ap_frame.BCDValue;
return SubQ_SynthChecksum(buf12, offset);
}
/// <summary>
/// Synthesizes the typical subP data into the provided buffer depending on the indicated pause flag
/// </summary>
public static void SubP(byte[] buffer12, int offset, bool pause)
{
byte val = (byte)(pause ? 0xFF : 0x00);
for (int i = 0; i < 12; i++)
buffer[offset + i] = val;
buffer12[offset + i] = val;
}
public static void SectorHeader(byte[] buffer, int offset, int LBA, byte mode)
/// <summary>
/// Synthesizes a data sector header
/// </summary>
public static void SectorHeader(byte[] buffer16, int offset, int LBA, byte mode)
{
buffer[offset + 0] = 0x00;
for (int i = 1; i < 11; i++) buffer[offset + i] = 0xFF;
buffer[offset + 11] = 0x00;
buffer16[offset + 0] = 0x00;
for (int i = 1; i < 11; i++) buffer16[offset + i] = 0xFF;
buffer16[offset + 11] = 0x00;
Timestamp ts = new Timestamp(LBA + 150);
buffer[offset + 12] = BCD2.IntToBCD(ts.MIN);
buffer[offset + 13] = BCD2.IntToBCD(ts.SEC);
buffer[offset + 14] = BCD2.IntToBCD(ts.FRAC);
buffer[offset + 15] = mode;
buffer16[offset + 12] = BCD2.IntToBCD(ts.MIN);
buffer16[offset + 13] = BCD2.IntToBCD(ts.SEC);
buffer16[offset + 14] = BCD2.IntToBCD(ts.FRAC);
buffer16[offset + 15] = mode;
}
public static void EDC_Mode2_Form1(byte[] buffer, int offset)
/// <summary>
/// Synthesizes the EDC checksum for a Mode 2 Form 1 data sector (and puts it in place)
/// </summary>
public static void EDC_Mode2_Form1(byte[] buf2352, int offset)
{
uint edc = ECM.EDC_Calc(buffer, offset + 16, 2048 + 8);
ECM.PokeUint(buffer, offset + 2072, edc);
uint edc = ECM.EDC_Calc(buf2352, offset + 16, 2048 + 8);
ECM.PokeUint(buf2352, offset + 2072, edc);
}
public static void EDC_Mode2_Form2(byte[] buffer, int offset)
/// <summary>
/// Synthesizes the EDC checksum for a Mode 2 Form 2 data sector (and puts it in place)
/// </summary>
public static void EDC_Mode2_Form2(byte[] buf2352, int offset)
{
uint edc = ECM.EDC_Calc(buffer, offset + 16, 2324 + 8);
ECM.PokeUint(buffer, offset + 2348, edc);
uint edc = ECM.EDC_Calc(buf2352, offset + 16, 2324 + 8);
ECM.PokeUint(buf2352, offset + 2348, edc);
}
/// <summary>
/// Synthesizes the complete ECM data (EDC + ECC) for a Mode 1 data sector (and puts it in place)
/// Make sure everything else in the sector userdata is done before calling this
/// </summary>
public static void ECM_Mode1(byte[] buffer, int offset, int LBA)
public static void ECM_Mode1(byte[] buf2352, int offset, int LBA)
{
//EDC
uint edc = ECM.EDC_Calc(buffer, offset, 2064);
ECM.PokeUint(buffer, offset + 2064, edc);
uint edc = ECM.EDC_Calc(buf2352, offset, 2064);
ECM.PokeUint(buf2352, offset + 2064, edc);
//reserved, zero
for (int i = 0; i < 8; i++) buffer[offset + 2068 + i] = 0;
for (int i = 0; i < 8; i++) buf2352[offset + 2068 + i] = 0;
//ECC
ECM.ECC_Populate(buffer, offset, buffer, offset, false);
ECM.ECC_Populate(buf2352, offset, buf2352, offset, false);
}
/// <summary>
/// Converts the useful (but unrealistic) deinterleaved subchannel data into the useless (but realistic) interleaved format.
/// in_buf and out_buf should not overlap
/// </summary>
public static void InterleaveSubcode(byte[] in_buf, int in_buf_index, byte[] out_buf, int out_buf_index)
{
for (int d = 0; d < 12; d++)
{
for (int bitpoodle = 0; bitpoodle < 8; bitpoodle++)
{
int rawb = 0;
for (int ch = 0; ch < 8; ch++)
{
rawb |= ((in_buf[ch * 12 + d + in_buf_index] >> (7 - bitpoodle)) & 1) << (7 - ch);
}
out_buf[(d << 3) + bitpoodle + out_buf_index] = (byte)rawb;
}
}
}
/// <summary>
/// Converts the useless (but realistic) interleaved subchannel data into a useful (but unrealistic) deinterleaved format.
/// in_buf and out_buf should not overlap
/// </summary>
public static void DeinterleaveSubcode(byte[] in_buf, int in_buf_index, byte[] out_buf, int out_buf_index)
{
for (int i = 0; i < 96; i++)
out_buf[i] = 0;
for (int ch = 0; ch < 8; ch++)
{
for (int i = 0; i < 96; i++)
{
out_buf[(ch * 12) + (i >> 3) + out_buf_index] |= (byte)(((in_buf[i + in_buf_index] >> (7 - ch)) & 0x1) << (7 - (i & 0x7)));
}
}
}
/// <summary>
/// Converts the useful (but unrealistic) deinterleaved data into the useless (but realistic) interleaved subchannel format.
/// </summary>
public unsafe static void InterleaveSubcodeInplace(byte[] buf, int buf_index)
{
byte* out_buf = stackalloc byte[96];
for (int i = 0; i < 96; i++)
out_buf[i] = 0;
for (int d = 0; d < 12; d++)
{
for (int bitpoodle = 0; bitpoodle < 8; bitpoodle++)
{
int rawb = 0;
for (int ch = 0; ch < 8; ch++)
{
rawb |= ((buf[ch * 12 + d + buf_index] >> (7 - bitpoodle)) & 1) << (7 - ch);
}
out_buf[(d << 3) + bitpoodle] = (byte)rawb;
}
}
for (int i = 0; i < 96; i++)
buf[i + buf_index] = out_buf[i];
}
/// <summary>
/// Converts the useless (but realistic) interleaved subchannel data into a useful (but unrealistic) deinterleaved format.
/// </summary>
public unsafe static void DeinterleaveSubcodeInplace(byte[] buf, int buf_index)
{
byte* out_buf = stackalloc byte[96];
for (int i = 0; i < 96; i++)
out_buf[i] = 0;
for (int ch = 0; ch < 8; ch++)
{
for (int i = 0; i < 96; i++)
{
out_buf[(ch * 12) + (i >> 3)] |= (byte)(((buf[i + buf_index] >> (7 - ch)) & 0x1) << (7 - (i & 0x7)));
}
}
for (int i = 0; i < 96; i++)
buf[i + buf_index] = out_buf[i];
}
}
//not being used yet
class DiscPreferences
{
}
}

View File

@ -19,29 +19,4 @@ namespace BizHawk.Emulation.DiscSystem
{
BizHawk, MednaDisc, LibMirage
}
/// <summary>
/// Main unit of organization for reading data from the disc. Represents one physical disc sector.
/// </summary>
public class SectorEntry
{
public SectorEntry(ISector sec) { Sector = sec; }
internal ISectorSynthJob2448 SectorSynth;
/// <summary>
/// Access the --whatsitcalled-- normal data for the sector with this
/// </summary>
public ISector Sector;
/// <summary>
/// Access the subcode data for the sector
/// </summary>
public ISubcodeSector SubcodeSector;
//todo - add a PARAMETER fields to this (a long, maybe) so that the ISector can use them (so that each ISector doesnt have to be constructed also)
//also then, maybe this could be a struct
}
}

View File

@ -18,7 +18,7 @@ namespace BizHawk.Emulation.DiscSystem
//we may still need to deinterleave it if subcode was requested and it needs deinterleaving
if ((job.Parts & (ESectorSynthPart.SubcodeDeinterleave | ESectorSynthPart.SubcodeAny)) != 0)
{
SubcodeUtils.DeinterleaveInplace(job.DestBuffer2448, 2352);
SynthUtils.DeinterleaveSubcodeInplace(job.DestBuffer2448, 2352);
}
}
}
@ -26,6 +26,7 @@ namespace BizHawk.Emulation.DiscSystem
void RunMednaDisc()
{
var disc = new Disc();
OUT_Disc = disc;
//create a MednaDisc and give it to the disc for ownership
var md = new MednaDisc(IN_FromPath);
@ -43,27 +44,17 @@ namespace BizHawk.Emulation.DiscSystem
//make sector interfaces:
var pregap_sector_zero = new Sector_Zero();
var pregap_subcode_zero = new ZeroSubcodeSector();
for (int i = 0; i < 150; i++)
{
var se = new SectorEntry(pregap_sector_zero);
se.SectorSynth = synth;
disc.Sectors.Add(se);
se.SubcodeSector = pregap_subcode_zero;
disc.Sectors.Add(synth);
}
//2. actual sectors
for (int i = 0; i < nSectors; i++)
{
//var sectorInterface = new MednaDiscSectorInterface() { LBA = i, md = md };
var se = new SectorEntry(null);
//se.SubcodeSector = new MednaDiscSubcodeSectorInterface() { LBA = i, md = md };
se.SectorSynth = synth;
disc.Sectors.Add(se);
disc.Sectors.Add(synth);
}
BufferedSubcodeSector bss = new BufferedSubcodeSector(); //TODO - its hacky that we need this..
//ADR (q-Mode) is necessarily 0x01 for a RawTOCEntry
const int kADR = 1;
const int kUnknownControl = 0;
@ -96,15 +87,13 @@ namespace BizHawk.Emulation.DiscSystem
ap_min = BCD2.FromDecimal(m_ts.MIN),
ap_sec = BCD2.FromDecimal(m_ts.SEC),
ap_frame = BCD2.FromDecimal(m_ts.FRAC),
q_crc = 0 //meaningless
};
//a special fixup: mednafen's entry 100 is the lead-out track
if (i == 100)
q.q_index.BCDValue = 0xA2;
//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 });
}
@ -121,8 +110,8 @@ namespace BizHawk.Emulation.DiscSystem
ap_min = BCD2.FromDecimal(md.TOC.first_track),
ap_sec = BCD2.FromDecimal(0),
ap_frame = BCD2.FromDecimal(0),
q_crc = 0, //meaningless
};
qA1.q_crc = bss.Synthesize_SubchannelQ(ref qA1, true);
disc.RawTOCEntries.Add(new RawTOCEntry { QData = qA1 });
var qA2 = new SubchannelQ
{
@ -136,44 +125,10 @@ namespace BizHawk.Emulation.DiscSystem
ap_min = BCD2.FromDecimal(md.TOC.last_track),
ap_sec = BCD2.FromDecimal(0),
ap_frame = BCD2.FromDecimal(0),
q_crc = 0, //meaningless
};
qA2.q_crc = bss.Synthesize_SubchannelQ(ref qA2, true);
disc.RawTOCEntries.Add(new RawTOCEntry { QData = qA2 });
//generate the toc from the entries. still not sure we're liking this idea
var tocSynth = new DiscTOCRaw.SynthesizeFromRawTOCEntriesJob() { Entries = disc.RawTOCEntries };
tocSynth.Run();
disc.TOCRaw = tocSynth.Result;
//DO THIS IN A MORE UNIFORM WAY PLEASE
//setup the DiscStructure
//disc.Structure = new DiscStructure();
//var ses = new DiscStructure.Session();
//disc.Structure.Sessions.Add(ses);
//for (int i = 1; i < 100; i++)
//{
// var m_te = md.TOCTracks[i];
// if (!m_te.Valid) continue;
// DiscStructure.Track track = new DiscStructure.Track() { Number = i };
// ses.Tracks.Add(track);
// if ((m_te.control & (int)EControlQ.DATA) == 0)
// track.IsData = false;
// else
// track.IsData = true;
// track.Start_LBA = (int)m_te.lba;
// track.
// //from mednafen, we couldnt build the index 0, and that's OK, since that's not really a sensible thing in CD terms anyway.
// //I need to refactor this thing to oblivion
// //track.Indexes.Add(new DiscStructure.Index { Number = 0, LBA = (int)m_te.lba }); //<-- not accurate, but due for deletion
// //track.Indexes.Add(new DiscStructure.Index { Number = 1, LBA = (int)m_te.lba });
//}
//NOT FULLY COMPLETE
OUT_Disc = disc;
}
}
}

View File

@ -41,8 +41,6 @@ namespace BizHawk.Emulation.DiscSystem
{
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;

View File

@ -17,224 +17,6 @@
namespace BizHawk.Emulation.DiscSystem
{
//YET ANOTHER BAD IDEA
public interface ISubcodeSector
{
/// <summary>
/// reads 96 bytes of subcode data (deinterleaved) for this sector into the supplied buffer
/// </summary>
void ReadSubcodeDeinterleaved(byte[] buffer, int offset);
/// <summary>
/// Reads just one of the channels. p=0, q=1, etc.
/// </summary>
void ReadSubcodeChannel(int number, byte[] buffer, int offset);
}
public static class SubcodeUtils
{
/// <summary>
/// Converts the useful (but unrealistic) deinterleaved data into the useless (but realistic) interleaved subchannel format.
/// in_buf and out_buf should not overlap
/// </summary>
public static void Interleave(byte[] in_buf, int in_buf_index, byte[] out_buf, int out_buf_index)
{
for (int d = 0; d < 12; d++)
{
for (int bitpoodle = 0; bitpoodle < 8; bitpoodle++)
{
int rawb = 0;
for (int ch = 0; ch < 8; ch++)
{
rawb |= ((in_buf[ch * 12 + d + in_buf_index] >> (7 - bitpoodle)) & 1) << (7 - ch);
}
out_buf[(d << 3) + bitpoodle + out_buf_index] = (byte)rawb;
}
}
}
/// <summary>
/// Converts the useless (but realistic) interleaved subchannel data into a useful (but unrealistic) deinterleaved format.
/// in_buf and out_buf should not overlap
/// </summary>
public static void Deinterleave(byte[] in_buf, int in_buf_index, byte[] out_buf, int out_buf_index)
{
for (int i = 0; i < 96; i++)
out_buf[i] = 0;
for (int ch = 0; ch < 8; ch++)
{
for (int i = 0; i < 96; i++)
{
out_buf[(ch * 12) + (i >> 3) + out_buf_index] |= (byte)(((in_buf[i + in_buf_index] >> (7 - ch)) & 0x1) << (7 - (i & 0x7)));
}
}
}
/// <summary>
/// Converts the useful (but unrealistic) deinterleaved data into the useless (but realistic) interleaved subchannel format.
/// </summary>
public unsafe static void InterleaveInplace(byte[] buf, int buf_index)
{
byte* out_buf = stackalloc byte[96];
for (int i = 0; i < 96; i++)
out_buf[i] = 0;
for (int d = 0; d < 12; d++)
{
for (int bitpoodle = 0; bitpoodle < 8; bitpoodle++)
{
int rawb = 0;
for (int ch = 0; ch < 8; ch++)
{
rawb |= ((buf[ch * 12 + d + buf_index] >> (7 - bitpoodle)) & 1) << (7 - ch);
}
out_buf[(d << 3) + bitpoodle] = (byte)rawb;
}
}
for (int i = 0; i < 96; i++)
buf[i + buf_index] = out_buf[i];
}
/// <summary>
/// Converts the useless (but realistic) interleaved subchannel data into a useful (but unrealistic) deinterleaved format.
/// </summary>
public unsafe static void DeinterleaveInplace(byte[] buf, int buf_index)
{
byte* out_buf = stackalloc byte[96];
for (int i = 0; i < 96; i++)
out_buf[i] = 0;
for (int ch = 0; ch < 8; ch++)
{
for (int i = 0; i < 96; i++)
{
out_buf[(ch * 12) + (i >> 3)] |= (byte)(((buf[i + buf_index] >> (7 - ch)) & 0x1) << (7 - (i & 0x7)));
}
}
for (int i = 0; i < 96; i++)
buf[i + buf_index] = out_buf[i];
}
}
/// <summary>
/// Reads subcode from an internally-managed buffer
/// </summary>
class BufferedSubcodeSector : ISubcodeSector
{
public void Synthesize_SubchannelP(bool pause)
{
byte val = pause ? (byte)0xFF : (byte)0x00;
for (int i = 0; i < 12; i++)
SubcodeDeinterleaved[i] = val;
}
/// <summary>
/// Fills this subcode buffer with subchannel Q data. calculates the required CRC, as well.
/// Returns the crc, calculated or otherwise.
/// </summary>
public ushort Synthesize_SubchannelQ(ref SubchannelQ sq, bool calculateCRC)
{
int offset = 12; //Q subchannel begins after P, 12 bytes in
SubcodeDeinterleaved[offset + 0] = sq.q_status;
SubcodeDeinterleaved[offset + 1] = sq.q_tno.BCDValue;
SubcodeDeinterleaved[offset + 2] = sq.q_index.BCDValue;
SubcodeDeinterleaved[offset + 3] = sq.min.BCDValue;
SubcodeDeinterleaved[offset + 4] = sq.sec.BCDValue;
SubcodeDeinterleaved[offset + 5] = sq.frame.BCDValue;
SubcodeDeinterleaved[offset + 6] = sq.zero;
SubcodeDeinterleaved[offset + 7] = sq.ap_min.BCDValue;
SubcodeDeinterleaved[offset + 8] = sq.ap_sec.BCDValue;
SubcodeDeinterleaved[offset + 9] = sq.ap_frame.BCDValue;
ushort crc16;
if (calculateCRC)
crc16 = CRC16_CCITT.Calculate(SubcodeDeinterleaved, offset, 10);
else crc16 = sq.q_crc;
//CRC is stored inverted and big endian
SubcodeDeinterleaved[offset + 10] = (byte)(~(crc16 >> 8));
SubcodeDeinterleaved[offset + 11] = (byte)(~(crc16));
return crc16;
}
public void Synthesize_SunchannelQ_Checksum()
{
int offset = 12; //Q subchannel begins after P, 12 bytes in
ushort crc16 = CRC16_CCITT.Calculate(SubcodeDeinterleaved, offset, 10);
//CRC is stored inverted and big endian
SubcodeDeinterleaved[offset + 10] = (byte)(~(crc16 >> 8));
SubcodeDeinterleaved[offset + 11] = (byte)(~(crc16));
}
public void ReadSubcodeDeinterleaved(byte[] buffer, int offset)
{
Buffer.BlockCopy(SubcodeDeinterleaved, 0, buffer, offset, 96);
}
public void ReadSubcodeChannel(int number, byte[] buffer, int offset)
{
Buffer.BlockCopy(SubcodeDeinterleaved, number * 12, buffer, offset, 12);
}
public BufferedSubcodeSector()
{
SubcodeDeinterleaved = new byte[96];
}
public static BufferedSubcodeSector CloneFromBytesDeinterleaved(byte[] buffer)
{
var ret = new BufferedSubcodeSector();
Buffer.BlockCopy(buffer, 0, ret.SubcodeDeinterleaved, 0, 96);
return ret;
}
public byte[] SubcodeDeinterleaved;
}
public class ZeroSubcodeSector : ISubcodeSector
{
public void ReadSubcodeDeinterleaved(byte[] buffer, int offset)
{
for (int i = 0; i < 96; i++) buffer[i + offset] = 0;
}
public void ReadSubcodeChannel(int number, byte[] buffer, int offset)
{
for (int i = 0; i < 12; i++)
buffer[i + offset] = 0;
}
}
/// <summary>
/// Reads subcode data from a blob, assuming it was already stored in deinterleaved format
/// </summary>
public class BlobSubcodeSectorPreDeinterleaved : ISubcodeSector
{
public void ReadSubcodeDeinterleaved(byte[] buffer, int offset)
{
Blob.Read(Offset, buffer, offset, 96);
}
public void ReadSubcodeChannel(int number, byte[] buffer, int offset)
{
Blob.Read(Offset + number * 12, buffer, offset, 12);
}
public IBlob Blob;
public long Offset;
}
/// <summary>
/// Control bit flags for the Q Subchannel.
/// </summary>
@ -277,8 +59,8 @@ namespace BizHawk.Emulation.DiscSystem
/// <summary>
/// These are the initial set of timestamps. Meaning varies:
/// check yellowbook 22.3.3 and 22.3.4
/// normal track: relative timestamp
/// leadin track: unknown
/// user information track: relative timestamp
/// leadout: relative timestamp
/// 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
@ -293,17 +75,16 @@ namespace BizHawk.Emulation.DiscSystem
/// <summary>
/// These are the second set of timestamps. Meaning varies:
/// check yellowbook 22.3.3 and 22.3.4
/// normal track: absolute timestamp
/// leadin track q-mode 1: TOC entry, absolute MSF of track
/// user information track: absolute timestamp
/// leadout: absolute timestamp
/// </summary>
public BCD2 ap_min, ap_sec, ap_frame;
/// <summary>
/// The CRC. This is the actual CRC value as would be calculated from our library (it is inverted and written big endian to the disc)
/// Don't assume this CRC is correct-- If this SubchannelQ was read from a dumped disc, the CRC might be wrong.
/// CCD doesnt specify this for TOC entries, so it will be wrong. It may or may not be right for data track sectors from a CCD file.
/// Or we may have computed this SubchannelQ data and generated the correct CRC at that time.
/// Don't assume this CRC is correct, in the case of some copy protections it is intended to be wrong.
/// Furthermore, it is meaningless (and in BizHawk, unpopulated) for a TOC Entry
/// (since an invalid CRC on a [theyre redundantly/duplicately stored] toc entry would cause it to get discarded in favor of another one with a correct CRC)
/// </summary>
public ushort q_crc;
@ -390,24 +171,4 @@ namespace BizHawk.Emulation.DiscSystem
}
}
public class SubcodeDataDecoder
{
/// <summary>
/// This seems to deinterleave Q from a subcode buffer? Not sure.. it isn't getting used anywhere right now, as you can see.
/// </summary>
public static void Unpack_Q(byte[] output, int out_ofs, byte[] input, int in_ofs)
{
for (int i = 0; i < 12; i++)
output[out_ofs + i] = 0;
for (int i = 0; i < 96; i++)
{
int bytenum = i >> 3;
int bitnum = i & 7;
bitnum = 7 - bitnum;
int bitval = (byte)((input[in_ofs + i] >> 6) & 1);
bitval <<= bitnum;
output[out_ofs + bytenum] |= (byte)bitval;
}
}
}
}