disc-clarify difference between LBA and ABA
This commit is contained in:
parent
cd65961b53
commit
3bab049363
|
@ -414,7 +414,7 @@ throw new Exception("requesting 0 sectors read.............................");
|
||||||
|
|
||||||
case 0x80: // Set start offset in track units
|
case 0x80: // Set start offset in track units
|
||||||
byte trackNo = CommandBuffer[2].BCDtoBin();
|
byte trackNo = CommandBuffer[2].BCDtoBin();
|
||||||
audioStartLBA = disc.TOC.Sessions[0].Tracks[trackNo - 1].Indexes[1].lba;
|
audioStartLBA = disc.TOC.Sessions[0].Tracks[trackNo - 1].Indexes[1].LBA;
|
||||||
Console.WriteLine("Set Start track: {0} lba={1}", trackNo, audioStartLBA);
|
Console.WriteLine("Set Start track: {0} lba={1}", trackNo, audioStartLBA);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -454,7 +454,7 @@ throw new Exception("requesting 0 sectors read.............................");
|
||||||
|
|
||||||
case 0x80: // Set end offset in track units
|
case 0x80: // Set end offset in track units
|
||||||
byte trackNo = CommandBuffer[2].BCDtoBin();
|
byte trackNo = CommandBuffer[2].BCDtoBin();
|
||||||
audioEndLBA = disc.TOC.Sessions[0].Tracks[trackNo - 1].Indexes[1].lba;
|
audioEndLBA = disc.TOC.Sessions[0].Tracks[trackNo - 1].Indexes[1].LBA;
|
||||||
Console.WriteLine("Set End track: {0} lba={1}", trackNo, audioEndLBA);
|
Console.WriteLine("Set End track: {0} lba={1}", trackNo, audioEndLBA);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -496,8 +496,7 @@ throw new Exception("requesting 0 sectors read.............................");
|
||||||
|
|
||||||
private void CommandReadSubcodeQ()
|
private void CommandReadSubcodeQ()
|
||||||
{
|
{
|
||||||
//TODO VECNA - i changed this for you but maybe i did it wrong
|
var sectorEntry = disc.ReadLBA_SectorEntry(pce.CDAudio.CurrentSector);
|
||||||
var sectorEntry = disc.ReadSectorEntry(pce.CDAudio.CurrentSector);
|
|
||||||
|
|
||||||
DataIn.Clear();
|
DataIn.Clear();
|
||||||
|
|
||||||
|
@ -561,7 +560,7 @@ throw new Exception("requesting 0 sectors read.............................");
|
||||||
throw new Exception("Request more tracks than exist.... need to do error handling");
|
throw new Exception("Request more tracks than exist.... need to do error handling");
|
||||||
// I error handled your mom last night
|
// I error handled your mom last night
|
||||||
|
|
||||||
int lbaPos = disc.TOC.Sessions[0].Tracks[track].Indexes[1].lba;
|
int lbaPos = disc.TOC.Sessions[0].Tracks[track].Indexes[1].LBA;
|
||||||
byte m, s, f;
|
byte m, s, f;
|
||||||
Disc.ConvertLBAtoMSF(lbaPos, out m, out s, out f);
|
Disc.ConvertLBAtoMSF(lbaPos, out m, out s, out f);
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ namespace BizHawk.DiscSystem
|
||||||
string blobPath = Path.Combine(cueDir, cue_file.Path);
|
string blobPath = Path.Combine(cueDir, cue_file.Path);
|
||||||
|
|
||||||
int blob_sectorsize = Cue.BINSectorSizeForTrackType(cue_file.Tracks[0].TrackType);
|
int blob_sectorsize = Cue.BINSectorSizeForTrackType(cue_file.Tracks[0].TrackType);
|
||||||
int blob_length_lba, blob_leftover;
|
int blob_length_aba, blob_leftover;
|
||||||
IBlob cue_blob = null;
|
IBlob cue_blob = null;
|
||||||
|
|
||||||
if (cue_file.FileType == Cue.CueFileType.Binary)
|
if (cue_file.FileType == Cue.CueFileType.Binary)
|
||||||
|
@ -41,8 +41,8 @@ namespace BizHawk.DiscSystem
|
||||||
blob.PhysicalPath = blobPath;
|
blob.PhysicalPath = blobPath;
|
||||||
Blobs.Add(blob);
|
Blobs.Add(blob);
|
||||||
|
|
||||||
blob_length_lba = (int)(blob.Length / blob_sectorsize);
|
blob_length_aba = (int)(blob.Length / blob_sectorsize);
|
||||||
blob_leftover = (int)(blob.Length - blob_length_lba * blob_sectorsize);
|
blob_leftover = (int)(blob.Length - blob_length_aba * blob_sectorsize);
|
||||||
cue_blob = blob;
|
cue_blob = blob;
|
||||||
}
|
}
|
||||||
else if (cue_file.FileType == Cue.CueFileType.Wave)
|
else if (cue_file.FileType == Cue.CueFileType.Wave)
|
||||||
|
@ -84,8 +84,8 @@ namespace BizHawk.DiscSystem
|
||||||
throw new DiscReferenceException(blobPath, ex);
|
throw new DiscReferenceException(blobPath, ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
blob_length_lba = (int)(blob.Length / blob_sectorsize);
|
blob_length_aba = (int)(blob.Length / blob_sectorsize);
|
||||||
blob_leftover = (int)(blob.Length - blob_length_lba * blob_sectorsize);
|
blob_leftover = (int)(blob.Length - blob_length_aba * blob_sectorsize);
|
||||||
cue_blob = blob;
|
cue_blob = blob;
|
||||||
}
|
}
|
||||||
else throw new DiscReferenceException(blobPath, new InvalidOperationException("unknown cue file type: " + cue_file.StrFileType));
|
else throw new DiscReferenceException(blobPath, new InvalidOperationException("unknown cue file type: " + cue_file.StrFileType));
|
||||||
|
@ -96,8 +96,8 @@ namespace BizHawk.DiscSystem
|
||||||
//start timekeeping for the blob. every time we hit an index, this will advance
|
//start timekeeping for the blob. every time we hit an index, this will advance
|
||||||
int blob_timestamp = 0;
|
int blob_timestamp = 0;
|
||||||
|
|
||||||
//the lba that this cue blob starts on
|
//the aba that this cue blob starts on
|
||||||
int blob_disc_lba_start = Sectors.Count;
|
int blob_disc_aba_start = Sectors.Count;
|
||||||
|
|
||||||
//for each track within the file, create an index 0 if it is missing.
|
//for each track within the file, create an index 0 if it is missing.
|
||||||
//also check to make sure there is an index 1
|
//also check to make sure there is an index 1
|
||||||
|
@ -118,7 +118,7 @@ namespace BizHawk.DiscSystem
|
||||||
}
|
}
|
||||||
|
|
||||||
//validate that the first index in the file is 00:00:00
|
//validate that the first index in the file is 00:00:00
|
||||||
if (cue_file.Tracks[0].Indexes[0].Timestamp.LBA != 0) throw new Cue.CueBrokenException("`The first index of a blob must start at 00:00:00.`");
|
if (cue_file.Tracks[0].Indexes[0].Timestamp.ABA != 0) throw new Cue.CueBrokenException("`The first index of a blob must start at 00:00:00.`");
|
||||||
|
|
||||||
|
|
||||||
//for each track within the file:
|
//for each track within the file:
|
||||||
|
@ -126,11 +126,11 @@ namespace BizHawk.DiscSystem
|
||||||
{
|
{
|
||||||
var cue_track = cue_file.Tracks[t];
|
var cue_track = cue_file.Tracks[t];
|
||||||
|
|
||||||
//record the disc LBA that this track started on
|
//record the disc ABA that this track started on
|
||||||
int track_disc_lba_start = Sectors.Count;
|
int track_disc_aba_start = Sectors.Count;
|
||||||
|
|
||||||
//record the pregap location. it will default to the start of the track unless we supplied a pregap command
|
//record the pregap location. it will default to the start of the track unless we supplied a pregap command
|
||||||
int track_disc_pregap_lba = track_disc_lba_start;
|
int track_disc_pregap_aba = track_disc_aba_start;
|
||||||
|
|
||||||
int blob_track_start = blob_timestamp;
|
int blob_track_start = blob_timestamp;
|
||||||
|
|
||||||
|
@ -148,7 +148,7 @@ namespace BizHawk.DiscSystem
|
||||||
|
|
||||||
if (curr_track == 1)
|
if (curr_track == 1)
|
||||||
{
|
{
|
||||||
if (cue_track.PreGap.LBA != 0)
|
if (cue_track.PreGap.ABA != 0)
|
||||||
throw new InvalidOperationException("not supported (yet): cue files with track 1 pregaps");
|
throw new InvalidOperationException("not supported (yet): cue files with track 1 pregaps");
|
||||||
//but now we add one anyway, because every existing cue+bin seems to implicitly specify this
|
//but now we add one anyway, because every existing cue+bin seems to implicitly specify this
|
||||||
cue_track.PreGap = new Timestamp(150);
|
cue_track.PreGap = new Timestamp(150);
|
||||||
|
@ -156,9 +156,9 @@ namespace BizHawk.DiscSystem
|
||||||
|
|
||||||
//check whether a pregap is requested.
|
//check whether a pregap is requested.
|
||||||
//this causes empty sectors to get generated without consuming data from the blob
|
//this causes empty sectors to get generated without consuming data from the blob
|
||||||
if (cue_track.PreGap.LBA > 0)
|
if (cue_track.PreGap.ABA > 0)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < cue_track.PreGap.LBA; i++)
|
for (int i = 0; i < cue_track.PreGap.ABA; i++)
|
||||||
{
|
{
|
||||||
Sectors.Add(new SectorEntry(pregap_sector));
|
Sectors.Add(new SectorEntry(pregap_sector));
|
||||||
}
|
}
|
||||||
|
@ -166,11 +166,11 @@ namespace BizHawk.DiscSystem
|
||||||
|
|
||||||
//look ahead to the next track's index 1 so we can see how long this track's last index is
|
//look ahead to the next track's index 1 so we can see how long this track's last index is
|
||||||
//or, for the last track, use the length of the file
|
//or, for the last track, use the length of the file
|
||||||
int track_length_lba;
|
int track_length_aba;
|
||||||
if (t == cue_file.Tracks.Count - 1)
|
if (t == cue_file.Tracks.Count - 1)
|
||||||
track_length_lba = blob_length_lba - blob_timestamp;
|
track_length_aba = blob_length_aba - blob_timestamp;
|
||||||
else track_length_lba = cue_file.Tracks[t + 1].Indexes[1].Timestamp.LBA - blob_timestamp;
|
else track_length_aba = cue_file.Tracks[t + 1].Indexes[1].Timestamp.ABA - blob_timestamp;
|
||||||
//toc_track.length_lba = track_length_lba; //xxx
|
//toc_track.length_aba = track_length_aba; //xxx
|
||||||
|
|
||||||
//find out how many indexes we have
|
//find out how many indexes we have
|
||||||
int num_indexes = 0;
|
int num_indexes = 0;
|
||||||
|
@ -188,22 +188,22 @@ namespace BizHawk.DiscSystem
|
||||||
toc_track.Indexes.Add(toc_index);
|
toc_track.Indexes.Add(toc_index);
|
||||||
if (index == 0)
|
if (index == 0)
|
||||||
{
|
{
|
||||||
toc_index.lba = track_disc_pregap_lba - (cue_track.Indexes[1].Timestamp.LBA - cue_track.Indexes[0].Timestamp.LBA);
|
toc_index.aba = track_disc_pregap_aba - (cue_track.Indexes[1].Timestamp.ABA - cue_track.Indexes[0].Timestamp.ABA);
|
||||||
}
|
}
|
||||||
else toc_index.lba = Sectors.Count;
|
else toc_index.aba = Sectors.Count;
|
||||||
|
|
||||||
//calculate length of the index
|
//calculate length of the index
|
||||||
//if it is the last index then we use our calculation from before, otherwise we check the next index
|
//if it is the last index then we use our calculation from before, otherwise we check the next index
|
||||||
int index_length_lba;
|
int index_length_aba;
|
||||||
if (is_last_index)
|
if (is_last_index)
|
||||||
index_length_lba = track_length_lba - (blob_timestamp - blob_track_start);
|
index_length_aba = track_length_aba - (blob_timestamp - blob_track_start);
|
||||||
else index_length_lba = cue_track.Indexes[index + 1].Timestamp.LBA - blob_timestamp;
|
else index_length_aba = cue_track.Indexes[index + 1].Timestamp.ABA - blob_timestamp;
|
||||||
|
|
||||||
//emit sectors
|
//emit sectors
|
||||||
for (int lba = 0; lba < index_length_lba; lba++)
|
for (int aba = 0; aba < index_length_aba; aba++)
|
||||||
{
|
{
|
||||||
bool is_last_lba_in_index = (lba == index_length_lba - 1);
|
bool is_last_aba_in_index = (aba == index_length_aba - 1);
|
||||||
bool is_last_lba_in_track = is_last_lba_in_index && is_last_index;
|
bool is_last_aba_in_track = is_last_aba_in_index && is_last_index;
|
||||||
|
|
||||||
switch (cue_track.TrackType)
|
switch (cue_track.TrackType)
|
||||||
{
|
{
|
||||||
|
@ -220,7 +220,7 @@ namespace BizHawk.DiscSystem
|
||||||
Sector_Raw sector_raw = new Sector_Raw();
|
Sector_Raw sector_raw = new Sector_Raw();
|
||||||
sector_raw.BaseSector = sector_rawblob;
|
sector_raw.BaseSector = sector_rawblob;
|
||||||
//take care to handle final sectors that are too short.
|
//take care to handle final sectors that are too short.
|
||||||
if (is_last_lba_in_track && blob_leftover > 0)
|
if (is_last_aba_in_track && blob_leftover > 0)
|
||||||
{
|
{
|
||||||
Sector_ZeroPad sector_zeropad = new Sector_ZeroPad();
|
Sector_ZeroPad sector_zeropad = new Sector_ZeroPad();
|
||||||
sector_zeropad.BaseSector = sector_rawblob;
|
sector_zeropad.BaseSector = sector_rawblob;
|
||||||
|
@ -235,8 +235,8 @@ namespace BizHawk.DiscSystem
|
||||||
//2048 bytes are present. ECM needs to be generated to create a full sector
|
//2048 bytes are present. ECM needs to be generated to create a full sector
|
||||||
{
|
{
|
||||||
//ECM needs to know the sector number so we have to record that here
|
//ECM needs to know the sector number so we have to record that here
|
||||||
int curr_disc_lba = Sectors.Count;
|
int curr_disc_aba = Sectors.Count;
|
||||||
var sector_2048 = new Sector_Mode1_2048(curr_disc_lba + 150);
|
var sector_2048 = new Sector_Mode1_2048(curr_disc_aba + 150);
|
||||||
sector_2048.Blob = new ECMCacheBlob(cue_blob);
|
sector_2048.Blob = new ECMCacheBlob(cue_blob);
|
||||||
sector_2048.Offset = (long)blob_timestamp * 2048;
|
sector_2048.Offset = (long)blob_timestamp * 2048;
|
||||||
if (blob_leftover > 0) throw new Cue.CueBrokenException("TODO - Incomplete 2048 byte/sector bin files (iso files) not yet supported.");
|
if (blob_leftover > 0) throw new Cue.CueBrokenException("TODO - Incomplete 2048 byte/sector bin files (iso files) not yet supported.");
|
||||||
|
@ -245,22 +245,22 @@ namespace BizHawk.DiscSystem
|
||||||
}
|
}
|
||||||
} //switch(TrackType)
|
} //switch(TrackType)
|
||||||
|
|
||||||
//we've emitted an LBA, so consume it from the blob
|
//we've emitted an ABA, so consume it from the blob
|
||||||
blob_timestamp++;
|
blob_timestamp++;
|
||||||
|
|
||||||
} //lba emit loop
|
} //aba emit loop
|
||||||
|
|
||||||
} //index loop
|
} //index loop
|
||||||
|
|
||||||
//check whether a postgap is requested. if it is, we need to generate silent sectors
|
//check whether a postgap is requested. if it is, we need to generate silent sectors
|
||||||
for (int i = 0; i < cue_track.PostGap.LBA; i++)
|
for (int i = 0; i < cue_track.PostGap.ABA; i++)
|
||||||
{
|
{
|
||||||
Sectors.Add(new SectorEntry(pregap_sector));
|
Sectors.Add(new SectorEntry(pregap_sector));
|
||||||
}
|
}
|
||||||
|
|
||||||
//we're done with the track now.
|
//we're done with the track now.
|
||||||
//record its length:
|
//record its length:
|
||||||
toc_track.length_lba = Sectors.Count - toc_track.Indexes[1].lba;
|
toc_track.length_aba = Sectors.Count - toc_track.Indexes[1].aba;
|
||||||
curr_track++;
|
curr_track++;
|
||||||
|
|
||||||
} //track loop
|
} //track loop
|
||||||
|
@ -268,18 +268,18 @@ namespace BizHawk.DiscSystem
|
||||||
|
|
||||||
//finally, analyze the length of the sessions and the entire disc by summing the lengths of the tracks
|
//finally, analyze the length of the sessions and the entire disc by summing the lengths of the tracks
|
||||||
//this is a little more complex than it looks, because the length of a thing is not determined by summing it
|
//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
|
//but rather by the difference in abas between start and end
|
||||||
TOC.length_lba = 0;
|
TOC.length_aba = 0;
|
||||||
foreach (var toc_session in TOC.Sessions)
|
foreach (var toc_session in TOC.Sessions)
|
||||||
{
|
{
|
||||||
var firstTrack = toc_session.Tracks[0];
|
var firstTrack = toc_session.Tracks[0];
|
||||||
|
|
||||||
//track 0, index 0 is actually -150. but cue sheets will never say that
|
//track 0, index 0 is actually -150. but cue sheets will never say that
|
||||||
//firstTrack.Indexes[0].lba -= 150;
|
//firstTrack.Indexes[0].aba -= 150;
|
||||||
|
|
||||||
var lastTrack = toc_session.Tracks[toc_session.Tracks.Count - 1];
|
var lastTrack = toc_session.Tracks[toc_session.Tracks.Count - 1];
|
||||||
session.length_lba = lastTrack.Indexes[1].lba + lastTrack.length_lba - firstTrack.Indexes[0].lba;
|
session.length_aba = lastTrack.Indexes[1].aba + lastTrack.length_aba - firstTrack.Indexes[0].aba;
|
||||||
TOC.length_lba += toc_session.length_lba;
|
TOC.length_aba += toc_session.length_aba;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -381,7 +381,6 @@ namespace BizHawk.DiscSystem
|
||||||
public CueTrackIndex(int num) { IndexNum = num; }
|
public CueTrackIndex(int num) { IndexNum = num; }
|
||||||
public int IndexNum;
|
public int IndexNum;
|
||||||
public Timestamp Timestamp;
|
public Timestamp Timestamp;
|
||||||
public int ZeroLBA;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class CueBrokenException : Exception
|
public class CueBrokenException : Exception
|
||||||
|
|
|
@ -56,60 +56,66 @@ namespace BizHawk.DiscSystem
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO - rename these APIs to ReadSector
|
|
||||||
public partial class Disc
|
public partial class Disc
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Main API to read a 2352-byte sector from a disc.
|
/// Main API to read a 2352-byte sector from a disc.
|
||||||
/// This starts at the beginning of the "userdata" area of the disc (track 1, index 0)
|
/// This starts after the mandatory pregap of 2 seconds (but what happens if there is more more?).
|
||||||
/// However, located here is a mandatory pregap of 2 seconds (or more?).
|
|
||||||
/// so you may need to add 150 depending on how your system addresses things to get to the "start" of the first track. (track 1, index 1)
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void ReadLBA_2352(int lba, byte[] buffer, int offset)
|
public void ReadLBA_2352(int lba, byte[] buffer, int offset)
|
||||||
{
|
{
|
||||||
Sectors[lba].Sector.Read(buffer, offset);
|
ReadABA_2352(lba + 150, buffer, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Main API to read a 2048-byte sector from a disc.
|
||||||
|
/// This starts after the mandatory pregap of 2 seconds (but what happens if there is more more?).
|
||||||
|
/// </summary>
|
||||||
|
public void ReadLBA_2048(int lba, byte[] buffer, int offset)
|
||||||
|
{
|
||||||
|
ReadABA_2048(lba + 150, buffer, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void ReadABA_2352(int aba, byte[] buffer, int offset)
|
||||||
|
{
|
||||||
|
Sectors[aba].Sector.Read(buffer, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void ReadABA_2048(int aba, byte[] buffer, int offset)
|
||||||
|
{
|
||||||
|
byte[] temp = new byte[2352];
|
||||||
|
Sectors[aba].Sector.Read(temp, offset);
|
||||||
|
Array.Copy(temp, 16, buffer, offset, 2048);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns a SectorEntry from which you can retrieve various interesting pieces of information about the sector.
|
/// 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.
|
/// The SectorEntry's interface is not likely to be stable, though, but it may be more convenient.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public SectorEntry ReadSectorEntry(int lba)
|
public SectorEntry ReadLBA_SectorEntry(int lba)
|
||||||
{
|
{
|
||||||
return Sectors[lba];
|
return Sectors[lba + 150];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reads the specified sector's subcode (96 bytes) deinterleaved into the provided buffer.
|
/// Reads the specified LBA's subcode (96 bytes) deinterleaved into the provided buffer.
|
||||||
/// P is first 12 bytes, followed by 12 Q bytes, etc.
|
/// P is first 12 bytes, followed by 12 Q bytes, etc.
|
||||||
/// I'm not sure what format scsi commands generally return it in.
|
/// I'm not sure what format scsi commands generally return it in.
|
||||||
/// It could be this, or RAW (interleaved) which I could also supply when we need it
|
/// It could be this, or RAW (interleaved) which I could also supply when we need it
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void ReadSector_Subcode_Deinterleaved(int lba, byte[] buffer, int offset)
|
public void ReadLBA_Subcode_Deinterleaved(int lba, byte[] buffer, int offset)
|
||||||
{
|
{
|
||||||
Array.Clear(buffer, offset, 96);
|
Array.Clear(buffer, offset, 96);
|
||||||
Sectors[lba].Read_SubchannelQ(buffer, offset + 12);
|
Sectors[lba + 150].Read_SubchannelQ(buffer, offset + 12);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reads the specified sector's subchannel Q (12 bytes) into the provided buffer
|
/// Reads the specified LBA's subchannel Q (12 bytes) into the provided buffer
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void ReadSector_Subchannel_Q(int lba, byte[] buffer, int offset)
|
public void ReadLBA_Subchannel_Q(int lba, byte[] buffer, int offset)
|
||||||
{
|
{
|
||||||
Sectors[lba].Read_SubchannelQ(buffer, offset);
|
Sectors[lba + 150].Read_SubchannelQ(buffer, offset);
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Main API to read a 2048-byte sector from a disc.
|
|
||||||
/// This starts at the beginning of the "userdata" area of the disc (track 1, index 0)
|
|
||||||
/// However, located here is a mandatory pregap of 2 seconds (or more?).
|
|
||||||
/// so you may need to add 150 depending on how your system addresses things to get to the "start" of the first track. (track 1, index 1)
|
|
||||||
/// </summary>
|
|
||||||
public void ReadLBA_2048(int lba, byte[] buffer, int offset)
|
|
||||||
{
|
|
||||||
byte[] temp = new byte[2352];
|
|
||||||
Sectors[lba].Sector.Read(temp, offset);
|
|
||||||
Array.Copy(temp, 16, buffer, offset, 2048);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -132,7 +138,7 @@ namespace BizHawk.DiscSystem
|
||||||
return TOC;
|
return TOC;
|
||||||
}
|
}
|
||||||
|
|
||||||
// converts LBA to minute:second:frame format.
|
// converts LBA to minute:second:frame format.
|
||||||
//TODO - somewhat redundant with Timestamp, which is due for refactoring into something not cue-related
|
//TODO - somewhat redundant with Timestamp, which is due for refactoring into something not cue-related
|
||||||
public static void ConvertLBAtoMSF(int lba, out byte m, out byte s, out byte f)
|
public static void ConvertLBAtoMSF(int lba, out byte m, out byte s, out byte f)
|
||||||
{
|
{
|
||||||
|
@ -157,9 +163,9 @@ namespace BizHawk.DiscSystem
|
||||||
if (track.TrackType == ETrackType.Audio)
|
if (track.TrackType == ETrackType.Audio)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
int lba_len = Math.Min(track.length_lba, 512);
|
int lba_len = Math.Min(track.length_aba, 512);
|
||||||
for (int s=0; s<512 && s<track.length_lba; s++)
|
for (int s=0; s<512 && s<track.length_aba; s++)
|
||||||
ReadLBA_2352(track.Indexes[1].lba + s, buffer, s*2352);
|
ReadLBA_2352(track.Indexes[1].aba + s, buffer, s*2352);
|
||||||
|
|
||||||
return Util.Hash_MD5(buffer, 0, lba_len*2352);
|
return Util.Hash_MD5(buffer, 0, lba_len*2352);
|
||||||
}
|
}
|
||||||
|
|
|
@ -198,16 +198,16 @@ namespace BizHawk.DiscSystem
|
||||||
|
|
||||||
class Sector_Mode1_2048 : ISector
|
class Sector_Mode1_2048 : ISector
|
||||||
{
|
{
|
||||||
public Sector_Mode1_2048(int LBA)
|
public Sector_Mode1_2048(int ABA)
|
||||||
{
|
{
|
||||||
byte lba_min = (byte)(LBA / 60 / 75);
|
byte aba_min = (byte)(ABA / 60 / 75);
|
||||||
byte lba_sec = (byte)((LBA / 75) % 60);
|
byte aba_sec = (byte)((ABA / 75) % 60);
|
||||||
byte lba_frac = (byte)(LBA % 75);
|
byte aba_frac = (byte)(ABA % 75);
|
||||||
bcd_lba_min = BCD_Byte(lba_min);
|
bcd_aba_min = BCD_Byte(aba_min);
|
||||||
bcd_lba_sec = BCD_Byte(lba_sec);
|
bcd_aba_sec = BCD_Byte(aba_sec);
|
||||||
bcd_lba_frac = BCD_Byte(lba_frac);
|
bcd_aba_frac = BCD_Byte(aba_frac);
|
||||||
}
|
}
|
||||||
byte bcd_lba_min, bcd_lba_sec, bcd_lba_frac;
|
byte bcd_aba_min, bcd_aba_sec, bcd_aba_frac;
|
||||||
|
|
||||||
public ECMCacheBlob Blob;
|
public ECMCacheBlob Blob;
|
||||||
public long Offset;
|
public long Offset;
|
||||||
|
@ -231,9 +231,9 @@ namespace BizHawk.DiscSystem
|
||||||
buffer[offset + 4] = 0xFF; buffer[offset + 5] = 0xFF; buffer[offset + 6] = 0xFF; buffer[offset + 7] = 0xFF;
|
buffer[offset + 4] = 0xFF; buffer[offset + 5] = 0xFF; buffer[offset + 6] = 0xFF; buffer[offset + 7] = 0xFF;
|
||||||
buffer[offset + 8] = 0xFF; buffer[offset + 9] = 0xFF; buffer[offset + 10] = 0xFF; buffer[offset + 11] = 0x00;
|
buffer[offset + 8] = 0xFF; buffer[offset + 9] = 0xFF; buffer[offset + 10] = 0xFF; buffer[offset + 11] = 0x00;
|
||||||
//sector address
|
//sector address
|
||||||
buffer[offset + 12] = bcd_lba_min;
|
buffer[offset + 12] = bcd_aba_min;
|
||||||
buffer[offset + 13] = bcd_lba_sec;
|
buffer[offset + 13] = bcd_aba_sec;
|
||||||
buffer[offset + 14] = bcd_lba_frac;
|
buffer[offset + 14] = bcd_aba_frac;
|
||||||
//mode 1
|
//mode 1
|
||||||
buffer[offset + 15] = 1;
|
buffer[offset + 15] = 1;
|
||||||
//EDC
|
//EDC
|
||||||
|
@ -330,14 +330,14 @@ namespace BizHawk.DiscSystem
|
||||||
Blob_RawFile blob = new Blob_RawFile();
|
Blob_RawFile blob = new Blob_RawFile();
|
||||||
blob.PhysicalPath = fiIso.FullName;
|
blob.PhysicalPath = fiIso.FullName;
|
||||||
Blobs.Add(blob);
|
Blobs.Add(blob);
|
||||||
int num_lba = (int)(fiIso.Length / 2048);
|
int num_aba = (int)(fiIso.Length / 2048);
|
||||||
track.length_lba = num_lba;
|
track.length_aba = num_aba;
|
||||||
if (fiIso.Length % 2048 != 0)
|
if (fiIso.Length % 2048 != 0)
|
||||||
throw new InvalidOperationException("invalid iso file (size not multiple of 2048)");
|
throw new InvalidOperationException("invalid iso file (size not multiple of 2048)");
|
||||||
//TODO - handle this with Final Fantasy 9 cd1.iso
|
//TODO - handle this with Final Fantasy 9 cd1.iso
|
||||||
|
|
||||||
var ecmCacheBlob = new ECMCacheBlob(blob);
|
var ecmCacheBlob = new ECMCacheBlob(blob);
|
||||||
for (int i = 0; i < num_lba; i++)
|
for (int i = 0; i < num_aba; i++)
|
||||||
{
|
{
|
||||||
Sector_Mode1_2048 sector = new Sector_Mode1_2048(i+150);
|
Sector_Mode1_2048 sector = new Sector_Mode1_2048(i+150);
|
||||||
sector.Blob = ecmCacheBlob;
|
sector.Blob = ecmCacheBlob;
|
||||||
|
@ -369,10 +369,10 @@ namespace BizHawk.DiscSystem
|
||||||
bfd.SectorSize = 2352;
|
bfd.SectorSize = 2352;
|
||||||
|
|
||||||
//skip the mandatory track 1 pregap! cue+bin files do not contain it
|
//skip the mandatory track 1 pregap! cue+bin files do not contain it
|
||||||
for (int i = 150; i < TOC.length_lba; i++)
|
for (int i = 150; i < TOC.length_aba; i++)
|
||||||
{
|
{
|
||||||
bfd.lbas.Add(i);
|
bfd.abas.Add(i);
|
||||||
bfd.lba_zeros.Add(false);
|
bfd.aba_zeros.Add(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -387,24 +387,24 @@ namespace BizHawk.DiscSystem
|
||||||
bfd.name = baseName + string.Format(" (Track {0:D2}).bin", track.num);
|
bfd.name = baseName + string.Format(" (Track {0:D2}).bin", track.num);
|
||||||
bfd.SectorSize = Cue.BINSectorSizeForTrackType(track.TrackType);
|
bfd.SectorSize = Cue.BINSectorSizeForTrackType(track.TrackType);
|
||||||
ret.bins.Add(bfd);
|
ret.bins.Add(bfd);
|
||||||
int lba=0;
|
int aba = 0;
|
||||||
|
|
||||||
//skip the mandatory track 1 pregap! cue+bin files do not contain it
|
//skip the mandatory track 1 pregap! cue+bin files do not contain it
|
||||||
if (i == 0) lba = 150;
|
if (i == 0) aba = 150;
|
||||||
|
|
||||||
for (; lba < track.length_lba; lba++)
|
for (; aba < track.length_aba; aba++)
|
||||||
{
|
{
|
||||||
int thislba = track.Indexes[0].lba + lba;
|
int thisaba = track.Indexes[0].aba + aba;
|
||||||
bfd.lbas.Add(thislba);
|
bfd.abas.Add(thisaba);
|
||||||
bfd.lba_zeros.Add(false);
|
bfd.aba_zeros.Add(false);
|
||||||
}
|
}
|
||||||
sbCue.AppendFormat("FILE \"{0}\" BINARY\n", bfd.name);
|
sbCue.AppendFormat("FILE \"{0}\" BINARY\n", bfd.name);
|
||||||
|
|
||||||
sbCue.AppendFormat(" TRACK {0:D2} {1}\n", track.num, Cue.TrackTypeStringForTrackType(track.TrackType));
|
sbCue.AppendFormat(" TRACK {0:D2} {1}\n", track.num, Cue.TrackTypeStringForTrackType(track.TrackType));
|
||||||
foreach (var index in track.Indexes)
|
foreach (var index in track.Indexes)
|
||||||
{
|
{
|
||||||
int x = index.lba - track.Indexes[0].lba;
|
int x = index.aba - track.Indexes[0].aba;
|
||||||
//if (prefs.OmitRedundantIndex0 && index.num == 0 && index.lba == track.Indexes[1].lba)
|
//if (prefs.OmitRedundantIndex0 && 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
|
// //dont emit index 0 when it is the same as index 1, it confuses some cue parsers
|
||||||
//}
|
//}
|
||||||
|
@ -427,13 +427,19 @@ namespace BizHawk.DiscSystem
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DumpBin_2352(string binPath)
|
/// <summary>
|
||||||
|
/// NOT USED RIGHT NOW. AMBIGUOUS, ANYWAY.
|
||||||
|
/// "bin" is an ill-defined concept.
|
||||||
|
/// </summary>
|
||||||
|
[Obsolete]
|
||||||
|
void DumpBin_2352(string binPath)
|
||||||
{
|
{
|
||||||
byte[] temp = new byte[2352];
|
byte[] temp = new byte[2352];
|
||||||
using(FileStream fs = new FileStream(binPath,FileMode.Create,FileAccess.Write,FileShare.None))
|
//a cue's bin probably doesn't contain the first 150 sectors, so skip it
|
||||||
for (int i = 0; i < Sectors.Count; i++)
|
using (FileStream fs = new FileStream(binPath, FileMode.Create, FileAccess.Write, FileShare.None))
|
||||||
|
for (int i = 150; i < Sectors.Count; i++)
|
||||||
{
|
{
|
||||||
ReadLBA_2352(150+i, temp, 0);
|
ReadLBA_2352(i, temp, 0);
|
||||||
fs.Write(temp, 0, 2352);
|
fs.Write(temp, 0, 2352);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -461,21 +467,21 @@ namespace BizHawk.DiscSystem
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void PopulateQSubchannel()
|
void PopulateQSubchannel()
|
||||||
{
|
{
|
||||||
int lba = 0;
|
int aba = 0;
|
||||||
int dpIndex = 0;
|
int dpIndex = 0;
|
||||||
|
|
||||||
while (lba < Sectors.Count)
|
while (aba < Sectors.Count)
|
||||||
{
|
{
|
||||||
if (dpIndex < TOC.Points.Count - 1)
|
if (dpIndex < TOC.Points.Count - 1)
|
||||||
{
|
{
|
||||||
if (lba >= TOC.Points[dpIndex + 1].LBA)
|
if (aba >= TOC.Points[dpIndex + 1].ABA)
|
||||||
{
|
{
|
||||||
dpIndex++;
|
dpIndex++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var dp = TOC.Points[dpIndex];
|
var dp = TOC.Points[dpIndex];
|
||||||
|
|
||||||
var se = Sectors[lba];
|
var se = Sectors[aba];
|
||||||
|
|
||||||
int control = 0;
|
int control = 0;
|
||||||
//choose a control byte depending on whether this is an audio or data track
|
//choose a control byte depending on whether this is an audio or data track
|
||||||
|
@ -490,18 +496,18 @@ namespace BizHawk.DiscSystem
|
||||||
se.q_tno = BCD2.FromDecimal(dp.TrackNum);
|
se.q_tno = BCD2.FromDecimal(dp.TrackNum);
|
||||||
se.q_index = BCD2.FromDecimal(dp.IndexNum);
|
se.q_index = BCD2.FromDecimal(dp.IndexNum);
|
||||||
|
|
||||||
int track_relative_lba = lba - dp.Track.Indexes[1].lba;
|
int track_relative_aba = aba - dp.Track.Indexes[1].aba;
|
||||||
track_relative_lba = Math.Abs(track_relative_lba);
|
track_relative_aba = Math.Abs(track_relative_aba);
|
||||||
Timestamp track_relative_timestamp = new Timestamp(track_relative_lba);
|
Timestamp track_relative_timestamp = new Timestamp(track_relative_aba);
|
||||||
se.q_min = BCD2.FromDecimal(track_relative_timestamp.MIN);
|
se.q_min = BCD2.FromDecimal(track_relative_timestamp.MIN);
|
||||||
se.q_sec = BCD2.FromDecimal(track_relative_timestamp.SEC);
|
se.q_sec = BCD2.FromDecimal(track_relative_timestamp.SEC);
|
||||||
se.q_frame = BCD2.FromDecimal(track_relative_timestamp.FRAC);
|
se.q_frame = BCD2.FromDecimal(track_relative_timestamp.FRAC);
|
||||||
Timestamp absolute_timestamp = new Timestamp(lba);
|
Timestamp absolute_timestamp = new Timestamp(aba);
|
||||||
se.q_amin = BCD2.FromDecimal(absolute_timestamp.MIN);
|
se.q_amin = BCD2.FromDecimal(absolute_timestamp.MIN);
|
||||||
se.q_asec = BCD2.FromDecimal(absolute_timestamp.SEC);
|
se.q_asec = BCD2.FromDecimal(absolute_timestamp.SEC);
|
||||||
se.q_aframe = BCD2.FromDecimal(absolute_timestamp.FRAC);
|
se.q_aframe = BCD2.FromDecimal(absolute_timestamp.FRAC);
|
||||||
|
|
||||||
lba++;
|
aba++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -584,20 +590,20 @@ namespace BizHawk.DiscSystem
|
||||||
MIN = int.Parse(value.Substring(0, 2));
|
MIN = int.Parse(value.Substring(0, 2));
|
||||||
SEC = int.Parse(value.Substring(3, 2));
|
SEC = int.Parse(value.Substring(3, 2));
|
||||||
FRAC = int.Parse(value.Substring(6, 2));
|
FRAC = int.Parse(value.Substring(6, 2));
|
||||||
LBA = MIN * 60 * 75 + SEC * 75 + FRAC;
|
ABA = MIN * 60 * 75 + SEC * 75 + FRAC;
|
||||||
}
|
}
|
||||||
public readonly string Value;
|
public readonly string Value;
|
||||||
public readonly int MIN, SEC, FRAC, LBA;
|
public readonly int MIN, SEC, FRAC, ABA;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// creates timestamp from supplied LBA
|
/// creates timestamp from supplied ABA
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Timestamp(int LBA)
|
public Timestamp(int ABA)
|
||||||
{
|
{
|
||||||
this.LBA = LBA;
|
this.ABA = ABA;
|
||||||
MIN = LBA / (60 * 75);
|
MIN = ABA / (60 * 75);
|
||||||
SEC = (LBA / 75) % 60;
|
SEC = (ABA / 75) % 60;
|
||||||
FRAC = LBA % 75;
|
FRAC = ABA % 75;
|
||||||
Value = string.Format("{0:D2}:{1:D2}:{2:D2}", MIN, SEC, FRAC);
|
Value = string.Format("{0:D2}:{1:D2}:{2:D2}", MIN, SEC, FRAC);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -681,50 +687,52 @@ namespace BizHawk.DiscSystem
|
||||||
public class BinFileDescriptor
|
public class BinFileDescriptor
|
||||||
{
|
{
|
||||||
public string name;
|
public string name;
|
||||||
public List<int> lbas = new List<int>();
|
public List<int> abas = new List<int>();
|
||||||
|
|
||||||
//todo - do we really need this? i dont think so...
|
//todo - do we really need this? i dont think so...
|
||||||
public List<bool> lba_zeros = new List<bool>();
|
public List<bool> aba_zeros = new List<bool>();
|
||||||
public int SectorSize;
|
public int SectorSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<BinFileDescriptor> bins = new List<BinFileDescriptor>();
|
public List<BinFileDescriptor> bins = new List<BinFileDescriptor>();
|
||||||
|
|
||||||
public string CreateRedumpReport()
|
//NOT SUPPORTED RIGHT NOW
|
||||||
{
|
//public string CreateRedumpReport()
|
||||||
if (disc.TOC.Sessions[0].Tracks.Count != bins.Count)
|
//{
|
||||||
throw new InvalidOperationException("Cannot generate redump report on CueBin lacking OneBinPerTrack property");
|
// if (disc.TOC.Sessions[0].Tracks.Count != bins.Count)
|
||||||
StringBuilder sb = new StringBuilder();
|
// throw new InvalidOperationException("Cannot generate redump report on CueBin lacking OneBinPerTrack property");
|
||||||
for (int i = 0; i < disc.TOC.Sessions[0].Tracks.Count; i++)
|
// StringBuilder sb = new StringBuilder();
|
||||||
{
|
// for (int i = 0; i < disc.TOC.Sessions[0].Tracks.Count; i++)
|
||||||
var track = disc.TOC.Sessions[0].Tracks[i];
|
// {
|
||||||
var bfd = bins[i];
|
// var track = disc.TOC.Sessions[0].Tracks[i];
|
||||||
|
// var bfd = bins[i];
|
||||||
|
|
||||||
//dump the track
|
// //dump the track
|
||||||
byte[] dump = new byte[track.length_lba * 2352];
|
// byte[] dump = new byte[track.length_aba * 2352];
|
||||||
for (int lba = 0; lba < track.length_lba; lba++)
|
// //TODO ????????? post-ABA unknown
|
||||||
disc.ReadLBA_2352(bfd.lbas[lba],dump,lba*2352);
|
// //for (int aba = 0; aba < track.length_aba; aba++)
|
||||||
string crc32 = string.Format("{0:X8}", CRC32.Calculate(dump));
|
// // disc.ReadLBA_2352(bfd.lbas[lba],dump,lba*2352);
|
||||||
string md5 = Util.Hash_MD5(dump, 0, dump.Length);
|
// string crc32 = string.Format("{0:X8}", CRC32.Calculate(dump));
|
||||||
string sha1 = Util.Hash_SHA1(dump, 0, dump.Length);
|
// string md5 = Util.Hash_MD5(dump, 0, dump.Length);
|
||||||
|
// string sha1 = Util.Hash_SHA1(dump, 0, dump.Length);
|
||||||
|
|
||||||
int pregap = track.Indexes[1].lba - track.Indexes[0].lba;
|
// int pregap = track.Indexes[1].lba - track.Indexes[0].lba;
|
||||||
Timestamp pregap_ts = new Timestamp(pregap);
|
// Timestamp pregap_ts = new Timestamp(pregap);
|
||||||
Timestamp len_ts = new Timestamp(track.length_lba);
|
// Timestamp len_ts = new Timestamp(track.length_lba);
|
||||||
sb.AppendFormat("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}\t{7}\t{8}\n",
|
// sb.AppendFormat("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}\t{7}\t{8}\n",
|
||||||
i,
|
// i,
|
||||||
Cue.RedumpTypeStringForTrackType(track.TrackType),
|
// Cue.RedumpTypeStringForTrackType(track.TrackType),
|
||||||
pregap_ts.Value,
|
// pregap_ts.Value,
|
||||||
len_ts.Value,
|
// len_ts.Value,
|
||||||
track.length_lba,
|
// track.length_lba,
|
||||||
track.length_lba*Cue.BINSectorSizeForTrackType(track.TrackType),
|
// track.length_lba*Cue.BINSectorSizeForTrackType(track.TrackType),
|
||||||
crc32,
|
// crc32,
|
||||||
md5,
|
// md5,
|
||||||
sha1
|
// sha1
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
return sb.ToString();
|
// return sb.ToString();
|
||||||
}
|
//}
|
||||||
|
|
||||||
public void Dump(string directory, CueBinPrefs prefs)
|
public void Dump(string directory, CueBinPrefs prefs)
|
||||||
{
|
{
|
||||||
|
@ -746,7 +754,7 @@ namespace BizHawk.DiscSystem
|
||||||
|
|
||||||
progress.Message = "Writing bin(s)";
|
progress.Message = "Writing bin(s)";
|
||||||
progress.TaskCurrent = 1;
|
progress.TaskCurrent = 1;
|
||||||
progress.ProgressEstimate = bins.Sum((bfd) => bfd.lbas.Count);
|
progress.ProgressEstimate = bins.Sum((bfd) => bfd.abas.Count);
|
||||||
progress.ProgressCurrent = 0;
|
progress.ProgressCurrent = 0;
|
||||||
if(!prefs.ReallyDumpBin) return;
|
if(!prefs.ReallyDumpBin) return;
|
||||||
|
|
||||||
|
@ -765,28 +773,28 @@ namespace BizHawk.DiscSystem
|
||||||
if (prefs.DumpSubchannelQ)
|
if (prefs.DumpSubchannelQ)
|
||||||
fsSubQ = new FileStream(subQPath, FileMode.Create, FileAccess.Write, FileShare.None);
|
fsSubQ = new FileStream(subQPath, FileMode.Create, FileAccess.Write, FileShare.None);
|
||||||
|
|
||||||
for (int i = 0; i < bfd.lbas.Count; i++)
|
for (int i = 0; i < bfd.abas.Count; i++)
|
||||||
{
|
{
|
||||||
if (progress.CancelSignal) return;
|
if (progress.CancelSignal) return;
|
||||||
|
|
||||||
progress.ProgressCurrent++;
|
progress.ProgressCurrent++;
|
||||||
int lba = bfd.lbas[i];
|
int aba = bfd.abas[i];
|
||||||
if (bfd.lba_zeros[i])
|
if (bfd.aba_zeros[i])
|
||||||
{
|
{
|
||||||
fs.Write(empty, 0, sectorSize);
|
fs.Write(empty, 0, sectorSize);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (sectorSize == 2352)
|
if (sectorSize == 2352)
|
||||||
disc.ReadLBA_2352(lba, temp, 0);
|
disc.ReadABA_2352(aba, temp, 0);
|
||||||
else if (sectorSize == 2048) disc.ReadLBA_2048(lba, temp, 0);
|
else if (sectorSize == 2048) disc.ReadABA_2048(aba, temp, 0);
|
||||||
else throw new InvalidOperationException();
|
else throw new InvalidOperationException();
|
||||||
fs.Write(temp, 0, sectorSize);
|
fs.Write(temp, 0, sectorSize);
|
||||||
|
|
||||||
//write subQ if necessary
|
//write subQ if necessary
|
||||||
if (fsSubQ != null)
|
if (fsSubQ != null)
|
||||||
{
|
{
|
||||||
disc.Sectors[lba].Read_SubchannelQ(subQ_temp, 0);
|
disc.Sectors[aba].Read_SubchannelQ(subQ_temp, 0);
|
||||||
fsSubQ.Write(subQ_temp, 0, 12);
|
fsSubQ.Write(subQ_temp, 0, 12);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,32 +21,38 @@ namespace BizHawk.DiscSystem
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Todo - comment about what this actually means
|
/// Todo - comment about what this actually means
|
||||||
|
/// TODO - this is redundant with Sectors.Count
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int length_lba;
|
public int length_aba;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// todo - comment about what this actually means
|
/// todo - comment about what this actually means
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Timestamp FriendlyLength { get { return new Timestamp(length_lba); } }
|
public Timestamp FriendlyLength { get { return new Timestamp(length_aba); } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// todo - comment about what this actually means
|
||||||
|
/// </summary>
|
||||||
|
public long BinarySize
|
||||||
|
{
|
||||||
|
get { return length_aba * 2352; }
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// seeks the point immediately before (or equal to) this LBA
|
/// seeks the point immediately before (or equal to) this LBA
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public TOCPoint SeekPoint(int lba)
|
public TOCPoint SeekPoint(int lba)
|
||||||
{
|
{
|
||||||
|
int aba = lba + 150;
|
||||||
for(int i=0;i<Points.Count;i++)
|
for(int i=0;i<Points.Count;i++)
|
||||||
{
|
{
|
||||||
TOCPoint tp = Points[i];
|
TOCPoint tp = Points[i];
|
||||||
if (tp.LBA > lba)
|
if (tp.ABA > aba)
|
||||||
return Points[i - 1];
|
return Points[i - 1];
|
||||||
}
|
}
|
||||||
return Points[Points.Count - 1];
|
return Points[Points.Count - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
public long BinarySize
|
|
||||||
{
|
|
||||||
get { return length_lba * 2352; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
|
@ -54,7 +60,7 @@ namespace BizHawk.DiscSystem
|
||||||
public class TOCPoint
|
public class TOCPoint
|
||||||
{
|
{
|
||||||
public int Num;
|
public int Num;
|
||||||
public int LBA, TrackNum, IndexNum;
|
public int ABA, TrackNum, IndexNum;
|
||||||
public Track Track;
|
public Track Track;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,7 +79,7 @@ namespace BizHawk.DiscSystem
|
||||||
{
|
{
|
||||||
var tp = new TOCPoint();
|
var tp = new TOCPoint();
|
||||||
tp.Num = num++;
|
tp.Num = num++;
|
||||||
tp.LBA = index.lba;
|
tp.ABA = index.aba;
|
||||||
tp.TrackNum = track.num;
|
tp.TrackNum = track.num;
|
||||||
tp.IndexNum = index.num;
|
tp.IndexNum = index.num;
|
||||||
tp.Track = track;
|
tp.Track = track;
|
||||||
|
@ -83,7 +89,7 @@ namespace BizHawk.DiscSystem
|
||||||
var tpLeadout = new TOCPoint();
|
var tpLeadout = new TOCPoint();
|
||||||
var lastTrack = ses.Tracks[ses.Tracks.Count - 1];
|
var lastTrack = ses.Tracks[ses.Tracks.Count - 1];
|
||||||
tpLeadout.Num = num++;
|
tpLeadout.Num = num++;
|
||||||
tpLeadout.LBA = lastTrack.Indexes[1].lba + lastTrack.length_lba;
|
tpLeadout.ABA = lastTrack.Indexes[1].aba + lastTrack.length_aba;
|
||||||
tpLeadout.IndexNum = 0;
|
tpLeadout.IndexNum = 0;
|
||||||
tpLeadout.TrackNum = 100;
|
tpLeadout.TrackNum = 100;
|
||||||
tpLeadout.Track = null; //no leadout track.. now... or ever?
|
tpLeadout.Track = null; //no leadout track.. now... or ever?
|
||||||
|
@ -97,8 +103,8 @@ namespace BizHawk.DiscSystem
|
||||||
public List<Track> Tracks = new List<Track>();
|
public List<Track> Tracks = new List<Track>();
|
||||||
|
|
||||||
//the length of the session (should be the sum of all track lengths)
|
//the length of the session (should be the sum of all track lengths)
|
||||||
public int length_lba;
|
public int length_aba;
|
||||||
public Timestamp FriendlyLength { get { return new Timestamp(length_lba); } }
|
public Timestamp FriendlyLength { get { return new Timestamp(length_aba); } }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Track
|
public class Track
|
||||||
|
@ -112,14 +118,19 @@ namespace BizHawk.DiscSystem
|
||||||
/// so this is the length from this index 1 to the next index 1 (or the end of the disc)
|
/// 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...
|
/// the time before track 1 index 1 is the lead-in and isn't accounted for in any track...
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int length_lba;
|
public int length_aba;
|
||||||
public Timestamp FriendlyLength { get { return new Timestamp(length_lba); } }
|
public Timestamp FriendlyLength { get { return new Timestamp(length_aba); } }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Index
|
public class Index
|
||||||
{
|
{
|
||||||
public int num;
|
public int num;
|
||||||
public int lba;
|
public int aba;
|
||||||
|
|
||||||
|
public int LBA
|
||||||
|
{
|
||||||
|
get { return aba - 150; }
|
||||||
|
}
|
||||||
|
|
||||||
//the length of the section
|
//the length of the section
|
||||||
//HEY! This is commented out because it is a bad idea.
|
//HEY! This is commented out because it is a bad idea.
|
||||||
|
@ -140,7 +151,7 @@ namespace BizHawk.DiscSystem
|
||||||
if (!prefs.SingleSession)
|
if (!prefs.SingleSession)
|
||||||
{
|
{
|
||||||
//dont want to screw around with sessions for now
|
//dont want to screw around with sessions for now
|
||||||
if (prefs.AnnotateCue) sb.AppendFormat("SESSION {0:D2} (length={1})\n", session.num, session.length_lba);
|
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);
|
else sb.AppendFormat("SESSION {0:D2}\n", session.num);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,14 +163,14 @@ namespace BizHawk.DiscSystem
|
||||||
if (trackType == ETrackType.Mode1_2048 && prefs.DumpECM)
|
if (trackType == ETrackType.Mode1_2048 && prefs.DumpECM)
|
||||||
trackType = ETrackType.Mode1_2352;
|
trackType = ETrackType.Mode1_2352;
|
||||||
|
|
||||||
if (prefs.AnnotateCue) sb.AppendFormat(" TRACK {0:D2} {1} (length={2})\n", track.num, Cue.TrackTypeStringForTrackType(trackType), track.length_lba);
|
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));
|
else sb.AppendFormat(" TRACK {0:D2} {1}\n", track.num, Cue.TrackTypeStringForTrackType(trackType));
|
||||||
foreach (var index in track.Indexes)
|
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
|
//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.
|
//except for the baked-in sector addressing.
|
||||||
//but, if there is an extra-long pregap, we want to reflect it this way
|
//but, if there is an extra-long pregap, we want to reflect it this way
|
||||||
int lba = index.lba - 150;
|
int lba = index.aba - 150;
|
||||||
if (lba <= 0 && index.num == 0 && track.num == 1)
|
if (lba <= 0 && index.num == 0 && track.num == 1)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -179,13 +190,13 @@ namespace BizHawk.DiscSystem
|
||||||
{
|
{
|
||||||
//this is a little more complex than it looks, because the length of a thing is not determined by summing it
|
//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
|
//but rather by the difference in lbas between start and end
|
||||||
length_lba = 0;
|
length_aba = 0;
|
||||||
foreach (var session in Sessions)
|
foreach (var session in Sessions)
|
||||||
{
|
{
|
||||||
var firstTrack = session.Tracks[0];
|
var firstTrack = session.Tracks[0];
|
||||||
var lastTrack = session.Tracks[session.Tracks.Count - 1];
|
var lastTrack = session.Tracks[session.Tracks.Count - 1];
|
||||||
session.length_lba = lastTrack.Indexes[0].lba + lastTrack.length_lba - firstTrack.Indexes[0].lba;
|
session.length_aba = lastTrack.Indexes[0].aba + lastTrack.length_aba - firstTrack.Indexes[0].aba;
|
||||||
length_lba += session.length_lba;
|
length_aba += session.length_aba;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,7 +70,7 @@ namespace BizHawk
|
||||||
var ti = new TrackInfo();
|
var ti = new TrackInfo();
|
||||||
var toc_track = DiscHopper.CurrentDisc.ReadTOC().Sessions[session].Tracks[track];
|
var toc_track = DiscHopper.CurrentDisc.ReadTOC().Sessions[session].Tracks[track];
|
||||||
ti.TrackType = toc_track.TrackType;
|
ti.TrackType = toc_track.TrackType;
|
||||||
ti.length_lba = toc_track.length_lba;
|
ti.length_lba = toc_track.length_aba;
|
||||||
return ti;
|
return ti;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,8 +52,8 @@ namespace BizHawk.Emulation.Sound
|
||||||
return;
|
return;
|
||||||
|
|
||||||
//note for vecna: you may find that the new "Point" and "SeekPoint" concept in the TOC is more useful than this kind of logic. just something to think about
|
//note for vecna: you may find that the new "Point" and "SeekPoint" concept in the TOC is more useful than this kind of logic. just something to think about
|
||||||
StartLBA = Disc.TOC.Sessions[0].Tracks[track - 1].Indexes[1].lba;
|
StartLBA = Disc.TOC.Sessions[0].Tracks[track - 1].Indexes[1].LBA;
|
||||||
EndLBA = StartLBA + Disc.TOC.Sessions[0].Tracks[track - 1].length_lba;
|
EndLBA = StartLBA + Disc.TOC.Sessions[0].Tracks[track - 1].length_aba;
|
||||||
PlayingTrack = track;
|
PlayingTrack = track;
|
||||||
CurrentSector = StartLBA;
|
CurrentSector = StartLBA;
|
||||||
SectorOffset = 0;
|
SectorOffset = 0;
|
||||||
|
@ -69,8 +69,8 @@ namespace BizHawk.Emulation.Sound
|
||||||
//note for vecna: you may find that the new "Point" and "SeekPoint" concept in the TOC is more useful than this kind of logic. just something to think about
|
//note for vecna: you may find that the new "Point" and "SeekPoint" concept in the TOC is more useful than this kind of logic. just something to think about
|
||||||
for (track = 0; track < tracks.Count; track++)
|
for (track = 0; track < tracks.Count; track++)
|
||||||
{
|
{
|
||||||
int trackStart = tracks[track].Indexes[0].lba;
|
int trackStart = tracks[track].Indexes[0].LBA;
|
||||||
int trackEnd = trackStart + tracks[track].length_lba;
|
int trackEnd = trackStart + tracks[track].length_aba;
|
||||||
if (lba >= trackStart && lba < trackEnd)
|
if (lba >= trackStart && lba < trackEnd)
|
||||||
{
|
{
|
||||||
foundTrack = true;
|
foundTrack = true;
|
||||||
|
|
|
@ -124,7 +124,7 @@ namespace BizHawk
|
||||||
//var cueBin = disc.DumpCueBin("Bomberman '94 Taikenban (SCD)(JPN)_hawked", prefs);
|
//var cueBin = disc.DumpCueBin("Bomberman '94 Taikenban (SCD)(JPN)_hawked", prefs);
|
||||||
//cueBin.Dump(@"D:\discs\Bomberman_'94_Taikenban_(SCD)(JPN)_-_wav'd", prefs);
|
//cueBin.Dump(@"D:\discs\Bomberman_'94_Taikenban_(SCD)(JPN)_-_wav'd", prefs);
|
||||||
|
|
||||||
DiscSystem.Disc disc = DiscSystem.Disc.FromCuePath(@"D:\programs\cdrdao\eac-ripped\Awakening.cue");
|
DiscSystem.Disc disc = DiscSystem.Disc.FromCuePath(@"D:\discs\R-Type Complete CD (J)");
|
||||||
var prefs = new DiscSystem.CueBinPrefs();
|
var prefs = new DiscSystem.CueBinPrefs();
|
||||||
prefs.AnnotateCue = false;
|
prefs.AnnotateCue = false;
|
||||||
prefs.OneBlobPerTrack = false;
|
prefs.OneBlobPerTrack = false;
|
||||||
|
@ -133,7 +133,7 @@ namespace BizHawk
|
||||||
//prefs.OmitRedundantIndex0 = true;
|
//prefs.OmitRedundantIndex0 = true;
|
||||||
prefs.SingleSession = true;
|
prefs.SingleSession = true;
|
||||||
//var cueBin = disc.DumpCueBin("Bomberman '94 Taikenban (SCD)(JPN)_hawked_hawked", prefs);
|
//var cueBin = disc.DumpCueBin("Bomberman '94 Taikenban (SCD)(JPN)_hawked_hawked", prefs);
|
||||||
var cueBin = disc.DumpCueBin("test", prefs);
|
var cueBin = disc.DumpCueBin("entire", prefs);
|
||||||
cueBin.Dump(@"D:\programs\cdrdao\eac-ripped", prefs);
|
cueBin.Dump(@"D:\programs\cdrdao\eac-ripped", prefs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,8 +51,6 @@
|
||||||
this.label7 = new System.Windows.Forms.Label();
|
this.label7 = new System.Windows.Forms.Label();
|
||||||
this.checkCueProp_Annotations = new System.Windows.Forms.CheckBox();
|
this.checkCueProp_Annotations = new System.Windows.Forms.CheckBox();
|
||||||
this.panel3 = new System.Windows.Forms.Panel();
|
this.panel3 = new System.Windows.Forms.Panel();
|
||||||
this.label8 = new System.Windows.Forms.Label();
|
|
||||||
this.checkCueProp_OmitRedundantIndex0 = new System.Windows.Forms.CheckBox();
|
|
||||||
this.btnPresetCanonical = new System.Windows.Forms.Button();
|
this.btnPresetCanonical = new System.Windows.Forms.Button();
|
||||||
this.btnPresetDaemonTools = new System.Windows.Forms.Button();
|
this.btnPresetDaemonTools = new System.Windows.Forms.Button();
|
||||||
this.groupBox2 = new System.Windows.Forms.GroupBox();
|
this.groupBox2 = new System.Windows.Forms.GroupBox();
|
||||||
|
@ -68,7 +66,6 @@
|
||||||
this.tableLayoutPanel1.SuspendLayout();
|
this.tableLayoutPanel1.SuspendLayout();
|
||||||
this.panel1.SuspendLayout();
|
this.panel1.SuspendLayout();
|
||||||
this.panel2.SuspendLayout();
|
this.panel2.SuspendLayout();
|
||||||
this.panel3.SuspendLayout();
|
|
||||||
this.groupBox2.SuspendLayout();
|
this.groupBox2.SuspendLayout();
|
||||||
this.SuspendLayout();
|
this.SuspendLayout();
|
||||||
//
|
//
|
||||||
|
@ -296,33 +293,11 @@
|
||||||
//
|
//
|
||||||
this.panel3.AutoSize = true;
|
this.panel3.AutoSize = true;
|
||||||
this.panel3.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
|
this.panel3.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
|
||||||
this.panel3.Controls.Add(this.label8);
|
|
||||||
this.panel3.Controls.Add(this.checkCueProp_OmitRedundantIndex0);
|
|
||||||
this.panel3.Location = new System.Drawing.Point(15, 94);
|
this.panel3.Location = new System.Drawing.Point(15, 94);
|
||||||
this.panel3.Name = "panel3";
|
this.panel3.Name = "panel3";
|
||||||
this.panel3.Size = new System.Drawing.Size(203, 68);
|
this.panel3.Size = new System.Drawing.Size(0, 0);
|
||||||
this.panel3.TabIndex = 10;
|
this.panel3.TabIndex = 10;
|
||||||
//
|
//
|
||||||
// label8
|
|
||||||
//
|
|
||||||
this.label8.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
|
||||||
this.label8.Location = new System.Drawing.Point(4, 26);
|
|
||||||
this.label8.Name = "label8";
|
|
||||||
this.label8.Size = new System.Drawing.Size(196, 42);
|
|
||||||
this.label8.TabIndex = 6;
|
|
||||||
this.label8.Text = "Should the output be split into several blobs, or just use one?";
|
|
||||||
//
|
|
||||||
// checkCueProp_OmitRedundantIndex0
|
|
||||||
//
|
|
||||||
this.checkCueProp_OmitRedundantIndex0.AutoSize = true;
|
|
||||||
this.checkCueProp_OmitRedundantIndex0.Location = new System.Drawing.Point(7, 6);
|
|
||||||
this.checkCueProp_OmitRedundantIndex0.Name = "checkCueProp_OmitRedundantIndex0";
|
|
||||||
this.checkCueProp_OmitRedundantIndex0.Size = new System.Drawing.Size(132, 17);
|
|
||||||
this.checkCueProp_OmitRedundantIndex0.TabIndex = 5;
|
|
||||||
this.checkCueProp_OmitRedundantIndex0.Text = "OmitRedundantIndex0";
|
|
||||||
this.checkCueProp_OmitRedundantIndex0.UseVisualStyleBackColor = true;
|
|
||||||
this.checkCueProp_OmitRedundantIndex0.CheckedChanged += new System.EventHandler(this.checkCueProp_CheckedChanged);
|
|
||||||
//
|
|
||||||
// btnPresetCanonical
|
// btnPresetCanonical
|
||||||
//
|
//
|
||||||
this.btnPresetCanonical.Location = new System.Drawing.Point(720, 210);
|
this.btnPresetCanonical.Location = new System.Drawing.Point(720, 210);
|
||||||
|
@ -459,8 +434,6 @@
|
||||||
this.panel1.PerformLayout();
|
this.panel1.PerformLayout();
|
||||||
this.panel2.ResumeLayout(false);
|
this.panel2.ResumeLayout(false);
|
||||||
this.panel2.PerformLayout();
|
this.panel2.PerformLayout();
|
||||||
this.panel3.ResumeLayout(false);
|
|
||||||
this.panel3.PerformLayout();
|
|
||||||
this.groupBox2.ResumeLayout(false);
|
this.groupBox2.ResumeLayout(false);
|
||||||
this.groupBox2.PerformLayout();
|
this.groupBox2.PerformLayout();
|
||||||
this.ResumeLayout(false);
|
this.ResumeLayout(false);
|
||||||
|
@ -492,8 +465,6 @@
|
||||||
private System.Windows.Forms.Label label7;
|
private System.Windows.Forms.Label label7;
|
||||||
private System.Windows.Forms.CheckBox checkCueProp_Annotations;
|
private System.Windows.Forms.CheckBox checkCueProp_Annotations;
|
||||||
private System.Windows.Forms.Panel panel3;
|
private System.Windows.Forms.Panel panel3;
|
||||||
private System.Windows.Forms.Label label8;
|
|
||||||
private System.Windows.Forms.CheckBox checkCueProp_OmitRedundantIndex0;
|
|
||||||
private System.Windows.Forms.Button btnPresetCanonical;
|
private System.Windows.Forms.Button btnPresetCanonical;
|
||||||
private System.Windows.Forms.Button btnPresetDaemonTools;
|
private System.Windows.Forms.Button btnPresetDaemonTools;
|
||||||
private System.Windows.Forms.GroupBox groupBox2;
|
private System.Windows.Forms.GroupBox groupBox2;
|
||||||
|
|
|
@ -79,7 +79,7 @@ namespace BizHawk
|
||||||
boundDisc = disc;
|
boundDisc = disc;
|
||||||
lblSessions.Text = toc.Sessions.Count.ToString();
|
lblSessions.Text = toc.Sessions.Count.ToString();
|
||||||
lblTracks.Text = toc.Sessions.Sum((ses) => ses.Tracks.Count).ToString();
|
lblTracks.Text = toc.Sessions.Sum((ses) => ses.Tracks.Count).ToString();
|
||||||
lblSectors.Text = string.Format("{0} ({1})", toc.length_lba, toc.FriendlyLength.Value);
|
lblSectors.Text = string.Format("{0} ({1})", toc.length_aba, toc.FriendlyLength.Value);
|
||||||
lblSize.Text = string.Format("{0:0.00} MB", toc.BinarySize / 1024.0 / 1024.0);
|
lblSize.Text = string.Format("{0:0.00} MB", toc.BinarySize / 1024.0 / 1024.0);
|
||||||
btnExportCue.Enabled = true;
|
btnExportCue.Enabled = true;
|
||||||
UpdateCue();
|
UpdateCue();
|
||||||
|
@ -115,7 +115,7 @@ namespace BizHawk
|
||||||
void PresetCanonical()
|
void PresetCanonical()
|
||||||
{
|
{
|
||||||
checkCueProp_Annotations.Checked = false;
|
checkCueProp_Annotations.Checked = false;
|
||||||
checkCueProp_OmitRedundantIndex0.Checked = false;
|
//checkCueProp_OmitRedundantIndex0.Checked = false;
|
||||||
checkCueProp_OneBlobPerTrack.Checked = false;
|
checkCueProp_OneBlobPerTrack.Checked = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,7 +126,7 @@ namespace BizHawk
|
||||||
void PresetDaemonTools()
|
void PresetDaemonTools()
|
||||||
{
|
{
|
||||||
checkCueProp_Annotations.Checked = false;
|
checkCueProp_Annotations.Checked = false;
|
||||||
checkCueProp_OmitRedundantIndex0.Checked = true;
|
//checkCueProp_OmitRedundantIndex0.Checked = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkCueProp_CheckedChanged(object sender, EventArgs e)
|
private void checkCueProp_CheckedChanged(object sender, EventArgs e)
|
||||||
|
|
Loading…
Reference in New Issue