refactor discstructure mightily

This commit is contained in:
zeromus 2015-07-07 22:29:11 -05:00
parent 5e71224eda
commit cc31331bc0
16 changed files with 174 additions and 153 deletions

View File

@ -19,15 +19,16 @@ namespace BizHawk.Client.DiscoHawk
var dsr = new DiscSectorReader(disc); var dsr = new DiscSectorReader(disc);
bool confirmed = false; bool confirmed = false;
var tracks = disc.Structure.Sessions[0].Tracks; var tracks = disc.Session1.Tracks;
foreach (var track in tracks) foreach (var track in tracks)
{ {
if (!track.IsAudio) if (!track.IsAudio)
continue; continue;
var waveData = new byte[track.Length * 2352]; int trackLength = track.NextTrack.LBA - track.LBA;
var waveData = new byte[trackLength * 2352];
int startLba = track.LBA; int startLba = track.LBA;
for (int sector = 0; sector < track.Length; sector++) for (int sector = 0; sector < trackLength; sector++)
dsr.ReadLBA_2352(startLba + sector, waveData, sector * 2352); dsr.ReadLBA_2352(startLba + sector, waveData, sector * 2352);
string mp3Path = string.Format("{0} - Track {1:D2}.mp3", Path.Combine(path, filebase), track.Number); string mp3Path = string.Format("{0} - Track {1:D2}.mp3", Path.Combine(path, filebase), track.Number);

View File

@ -379,9 +379,9 @@ namespace BizHawk.Client.DiscoHawk
}; };
//verify sector count //verify sector count
if (src_disc.LBACount != dst_disc.LBACount) if (src_disc.Session1.LeadoutLBA != dst_disc.Session1.LeadoutLBA)
{ {
sw.Write("LBACount count {0} vs {1}\n", src_disc.LBACount, dst_disc.LBACount); sw.Write("LeadoutTrack.LBA {0} vs {1}\n", src_disc.Session1.LeadoutTrack.LBA, dst_disc.Session1.LeadoutTrack.LBA);
goto SKIPPO; goto SKIPPO;
} }
@ -442,12 +442,12 @@ namespace BizHawk.Client.DiscoHawk
}; };
//verify each sector contents //verify each sector contents
int nSectors = src_disc.LBACount; int nSectors = src_disc.Session1.LeadoutLBA;
for (int lba = -150; lba < nSectors; lba++) for (int lba = -150; lba < nSectors; lba++)
{ {
if (verbose) if (verbose)
if (lba % 1000 == 0) if (lba % 1000 == 0)
Console.WriteLine("LBA {0} of {1}", lba, src_disc.LBACount); Console.WriteLine("LBA {0} of {1}", lba, nSectors);
if (cancelToken != null) if (cancelToken != null)
if (cancelToken.Token.IsCancellationRequested) if (cancelToken.Token.IsCancellationRequested)

View File

@ -422,7 +422,7 @@ namespace BizHawk.Emulation.Cores.PCEngine
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.Structure.Sessions[0].Tracks[trackNo - 1].LBA; audioStartLBA = disc.Session1.Tracks[trackNo].LBA;
break; break;
} }
@ -457,10 +457,10 @@ namespace BizHawk.Emulation.Cores.PCEngine
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();
if (trackNo - 1 >= disc.Structure.Sessions[0].Tracks.Count) if (trackNo - 1 >= disc.Session1.Tracks.Count)
audioEndLBA = disc.LBACount; audioEndLBA = disc.Session1.LeadoutLBA;
else else
audioEndLBA = disc.Structure.Sessions[0].Tracks[trackNo - 1].LBA; audioEndLBA = disc.Session1.Tracks[trackNo].LBA;
break; break;
} }
@ -530,13 +530,14 @@ namespace BizHawk.Emulation.Cores.PCEngine
{ {
DataIn.Clear(); DataIn.Clear();
DataIn.Enqueue(0x01); DataIn.Enqueue(0x01);
DataIn.Enqueue(((byte)disc.Structure.Sessions[0].Tracks.Count).BinToBCD()); DataIn.Enqueue(((byte)disc.Session1.Tracks.Count).BinToBCD());
SetPhase(BusPhase_DataIn); SetPhase(BusPhase_DataIn);
break; break;
} }
case 1: // return total disc length in minutes/seconds/frames case 1: // return total disc length in minutes/seconds/frames
{ {
int totalLbaLength = disc.LBACount; //zero 07-jul-2015 - I may have broken this
int totalLbaLength = disc.Session1.LeadoutLBA;
byte m, s, f; byte m, s, f;
Disc.ConvertLBAtoMSF(totalLbaLength, out m, out s, out f); Disc.ConvertLBAtoMSF(totalLbaLength, out m, out s, out f);
@ -548,20 +549,18 @@ namespace BizHawk.Emulation.Cores.PCEngine
SetPhase(BusPhase_DataIn); SetPhase(BusPhase_DataIn);
break; break;
} }
case 2: // Return starting position of specified track in MSF format case 2: // Return starting position of specified track in MSF format. TODO - did zero adapt this right? track indexing might be off
{ {
int track = CommandBuffer[2].BCDtoBin(); int track = CommandBuffer[2].BCDtoBin();
var tracks = disc.Structure.Sessions[0].Tracks; var tracks = disc.Session1.Tracks;
if (CommandBuffer[2] > 0x99) if (CommandBuffer[2] > 0x99)
throw new Exception("invalid track number BCD request... is something I need to handle?"); throw new Exception("invalid track number BCD request... is something I need to handle?");
if (track == 0) track = 1; if (track == 0) track = 1;
track--;
int lbaPos; int lbaPos;
if (track > tracks.Count) if (track > disc.Session1.InformationTrackCount)
lbaPos = disc.TOCRaw.LeadoutLBA.Sector; //zero 03-jul-2015 - did I adapt this right? lbaPos = disc.Session1.LeadoutLBA; //zero 03-jul-2015 - did I adapt this right?
else else
lbaPos = tracks[track].LBA; lbaPos = tracks[track].LBA;
@ -573,7 +572,7 @@ namespace BizHawk.Emulation.Cores.PCEngine
DataIn.Enqueue(s.BinToBCD()); DataIn.Enqueue(s.BinToBCD());
DataIn.Enqueue(f.BinToBCD()); DataIn.Enqueue(f.BinToBCD());
if (track > tracks.Count || disc.Structure.Sessions[0].Tracks[track].IsAudio) if (track > tracks.Count || disc.Session1.Tracks[track].IsAudio)
DataIn.Enqueue(0); DataIn.Enqueue(0);
else else
DataIn.Enqueue(4); DataIn.Enqueue(4);

View File

@ -392,13 +392,13 @@ namespace BizHawk.Emulation.Cores.Sega.Saturn
int CD_ReadTOC(IntPtr dest) int CD_ReadTOC(IntPtr dest)
{ {
// this stuff from yabause's cdbase.c. don't ask me to explain it // this stuff from yabause's cdbase.c. don't ask me to explain it
//TODO - we could just get this out of the actual TOC, it's the same thing
var TOC = CD.Structure;
int[] rTOC = new int[102]; int[] rTOC = new int[102];
var ses = TOC.Sessions[0]; var ses = CD.Session1;
int ntrk = ses.Tracks.Count; int ntrk = ses.Tracks.Count;
for (int i = 0; i < 99; i++) for (int i = 1; i <= 99; i++)
{ {
if (i < ntrk) if (i < ntrk)
{ {

View File

@ -292,7 +292,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
if (audio) if (audio)
{ {
byte[] data = new byte[2352]; byte[] data = new byte[2352];
if (lba < CD.LBACount) if (lba < CD.Session1.LeadoutLBA)
{ {
DiscSectorReader.ReadLBA_2352(lba, data, 0); DiscSectorReader.ReadLBA_2352(lba, data, 0);
} }
@ -322,16 +322,17 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
ret.readcallback = cd_callback_handle = new LibGPGX.cd_read_cb(CDRead); ret.readcallback = cd_callback_handle = new LibGPGX.cd_read_cb(CDRead);
var ses = CD.Structure.Sessions[0]; var ses = CD.Session1;
int ntrack = ses.Tracks.Count; int ntrack = ses.Tracks.Count;
// bet you a dollar this is all wrong // bet you a dollar this is all wrong
//zero 07-jul-2015 - throws a dollar in the pile, since he probably messed it up worse
for (int i = 0; i < LibGPGX.CD_MAX_TRACKS; i++) for (int i = 0; i < LibGPGX.CD_MAX_TRACKS; i++)
{ {
if (i < ntrack) if (i < ntrack)
{ {
ret.tracks[i].start = ses.Tracks[i].LBA; ret.tracks[i].start = ses.Tracks[i].LBA;
ret.tracks[i].end = ses.Tracks[i].Length + ret.tracks[i].start; ret.tracks[i].end = ses.Tracks[i + 1].LBA;
if (i == ntrack - 1) if (i == ntrack - 1)
{ {
ret.end = ret.tracks[i].end; ret.end = ret.tracks[i].end;

View File

@ -291,7 +291,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
if (audio) if (audio)
{ {
byte[] data = new byte[2352]; byte[] data = new byte[2352];
if (lba < CD.LBACount) if (lba < CD.Session1.LeadoutLBA)
{ {
CDReader.ReadLBA_2352(lba, data, 0); CDReader.ReadLBA_2352(lba, data, 0);
} }
@ -321,16 +321,17 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
ret.readcallback = cd_callback_handle = new LibGPGXDynamic.cd_read_cb(CDRead); ret.readcallback = cd_callback_handle = new LibGPGXDynamic.cd_read_cb(CDRead);
var ses = CD.Structure.Sessions[0]; var ses = CD.Session1;
int ntrack = ses.Tracks.Count; int ntrack = ses.Tracks.Count;
// bet you a dollar this is all wrong // bet you a dollar this is all wrong
//zero 07-jul-2015 - throws a dollar in the pile, since he probably messed it up worse
for (int i = 0; i < LibGPGXDynamic.CD_MAX_TRACKS; i++) for (int i = 0; i < LibGPGXDynamic.CD_MAX_TRACKS; i++)
{ {
if (i < ntrack) if (i < ntrack)
{ {
ret.tracks[i].start = ses.Tracks[i].LBA; ret.tracks[i].start = ses.Tracks[i].LBA;
ret.tracks[i].end = ses.Tracks[i].Length + ret.tracks[i].start; ret.tracks[i].end = ses.Tracks[i + 1].LBA;
if (i == ntrack - 1) if (i == ntrack - 1)
{ {
ret.end = ret.tracks[i].end; ret.end = ret.tracks[i].end;

View File

@ -142,7 +142,7 @@ namespace BizHawk.Emulation.Cores.Sony.PSX
cbReadTOC = ShockDisc_ReadTOC; cbReadTOC = ShockDisc_ReadTOC;
cbReadLBA = ShockDisc_ReadLBA2448; cbReadLBA = ShockDisc_ReadLBA2448;
this.cbActivity = cbActivity; this.cbActivity = cbActivity;
OctoshockDll.shock_CreateDisc(out OctoshockHandle, IntPtr.Zero, disc.LBACount, cbReadTOC, cbReadLBA, true); OctoshockDll.shock_CreateDisc(out OctoshockHandle, IntPtr.Zero, disc.Session1.LeadoutLBA, cbReadTOC, cbReadLBA, true);
} }
OctoshockDll.ShockDisc_ReadTOC cbReadTOC; OctoshockDll.ShockDisc_ReadTOC cbReadTOC;

View File

@ -7,37 +7,10 @@ using BizHawk.Common.BufferExtensions;
namespace BizHawk.Emulation.DiscSystem namespace BizHawk.Emulation.DiscSystem
{ {
[Serializable]
public class DiscReferenceException : Exception
{
public DiscReferenceException(string fname, Exception inner)
: base(string.Format("A disc attempted to reference a file which could not be accessed or loaded: {0}", fname), inner)
{
}
public DiscReferenceException(string fname, string extrainfo)
: base(string.Format("A disc attempted to reference a file which could not be accessed or loaded:\n\n{0}\n\n{1}", fname, extrainfo))
{
}
}
sealed public partial class Disc sealed public partial class Disc
{ {
/// <summary>
/// Main API to determine how many LBAs are available on the disc.
/// This counts from LBA 0 to the final sector available.
/// THIS IS DUMB. Like everything else here.
/// Fetch it from a toc or disc structure
/// </summary>
public int LBACount { get { return ABACount - 150; } }
/// <summary>
/// Main API to determine how many ABAs (sectors) are available on the disc.
/// This counts from ABA 0 to the final sector available.
/// </summary>
public int ABACount { get { return Sectors.Count; } }
// 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

View File

@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using BizHawk.Common.BufferExtensions;
//some old junk
namespace BizHawk.Emulation.DiscSystem
{
[Serializable]
public class DiscReferenceException : Exception
{
public DiscReferenceException(string fname, Exception inner)
: base(string.Format("A disc attempted to reference a file which could not be accessed or loaded: {0}", fname), inner)
{
}
public DiscReferenceException(string fname, string extrainfo)
: base(string.Format("A disc attempted to reference a file which could not be accessed or loaded:\n\n{0}\n\n{1}", fname, extrainfo))
{
}
}
}

View File

@ -20,13 +20,13 @@ namespace BizHawk.Emulation.DiscSystem
{ {
byte[] buffer = new byte[512 * 2352]; byte[] buffer = new byte[512 * 2352];
DiscSectorReader dsr = new DiscSectorReader(disc); DiscSectorReader dsr = new DiscSectorReader(disc);
foreach (var track in disc.Structure.Sessions[0].Tracks) foreach (var track in disc.Session1.Tracks)
{ {
if (track.IsAudio) if (track.IsAudio)
continue; continue;
int lba_len = Math.Min(track.Length, 512); int lba_len = Math.Min(track.NextTrack.LBA, 512);
for (int s = 0; s < 512 && s < track.Length; s++) for (int s = 0; s < 512 && s < lba_len; s++)
dsr.ReadLBA_2352(track.LBA + s, buffer, s * 2352); dsr.ReadLBA_2352(track.LBA + s, buffer, s * 2352);
return buffer.HashMD5(0, lba_len * 2352); return buffer.HashMD5(0, lba_len * 2352);

View File

@ -70,7 +70,7 @@ namespace BizHawk.Emulation.DiscSystem
SectorSize = 2048; SectorSize = 2048;
Disc = disc; Disc = disc;
NumSectors = disc.LBACount; NumSectors = disc.Session1.LeadoutLBA;
dsr = new DiscSectorReader(disc); dsr = new DiscSectorReader(disc);
//following the provided view //following the provided view

View File

@ -52,6 +52,7 @@
</Compile> </Compile>
<Compile Include="API\Disc.API.cs" /> <Compile Include="API\Disc.API.cs" />
<Compile Include="API\Disc.ID.cs" /> <Compile Include="API\Disc.ID.cs" />
<Compile Include="API\DiscExceptions.cs" />
<Compile Include="API\DiscHasher.cs" /> <Compile Include="API\DiscHasher.cs" />
<Compile Include="API\DiscSectorReader.cs" /> <Compile Include="API\DiscSectorReader.cs" />
<Compile Include="API\DiscStream.cs" /> <Compile Include="API\DiscStream.cs" />

View File

@ -50,11 +50,14 @@ namespace BizHawk.Emulation.DiscSystem
public void PlayTrack(int track) public void PlayTrack(int track)
{ {
if (track < 1 || track > Disc.Structure.Sessions[0].Tracks.Count) if (track < 1 || track > Disc.Session1.InformationTrackCount)
return; return;
StartLBA = Disc.Structure.Sessions[0].Tracks[track - 1].LBA; StartLBA = Disc.Session1.Tracks[track].LBA;
EndLBA = StartLBA + Disc.Structure.Sessions[0].Tracks[track - 1].Length;
//play until the beginning of the next track (?)
EndLBA = Disc.Session1.Tracks[track + 1].LBA;
PlayingTrack = track; PlayingTrack = track;
CurrentSector = StartLBA; CurrentSector = StartLBA;
SectorOffset = 0; SectorOffset = 0;
@ -71,7 +74,9 @@ namespace BizHawk.Emulation.DiscSystem
PlayingTrack = track.Number; PlayingTrack = track.Number;
StartLBA = lba; StartLBA = lba;
EndLBA = track.LBA + track.Length;
//play until the beginning of the next track (?)
EndLBA = Disc.Session1.Tracks[track.Number + 1].LBA;
CurrentSector = StartLBA; CurrentSector = StartLBA;
SectorOffset = 0; SectorOffset = 0;
@ -123,7 +128,7 @@ namespace BizHawk.Emulation.DiscSystem
{ {
if (CachedSector != CurrentSector) if (CachedSector != CurrentSector)
{ {
if (CurrentSector >= Disc.LBACount) if (CurrentSector >= Disc.Session1.LeadoutLBA)
Array.Clear(SectorCache, 0, 2352); // request reading past end of available disc Array.Clear(SectorCache, 0, 2352); // request reading past end of available disc
else else
DiscSectorReader.ReadLBA_2352(CurrentSector, SectorCache, 0); DiscSectorReader.ReadLBA_2352(CurrentSector, SectorCache, 0);

View File

@ -82,12 +82,6 @@ namespace BizHawk.Emulation.DiscSystem
public partial class Disc : IDisposable public partial class Disc : IDisposable
{ {
/// <summary>
/// The DiscMountPolicy used to mount the disc. Consider this read-only.
/// NOT SURE WE NEED THIS
/// </summary>
//public DiscMountPolicy DiscMountPolicy;
/// <summary> /// <summary>
/// Free-form optional memos about the disc /// Free-form optional memos about the disc
/// </summary> /// </summary>
@ -102,6 +96,7 @@ namespace BizHawk.Emulation.DiscSystem
/// <summary> /// <summary>
/// The DiscTOCRaw corresponding to the RawTOCEntries. /// The DiscTOCRaw corresponding to the RawTOCEntries.
/// TODO - rename to TOC /// TODO - rename to TOC
/// TODO - there's one of these for every session, so... having one here doesnt make sense
/// </summary> /// </summary>
public DiscTOCRaw TOCRaw; public DiscTOCRaw TOCRaw;
@ -110,6 +105,11 @@ namespace BizHawk.Emulation.DiscSystem
/// </summary> /// </summary>
public DiscStructure Structure; public DiscStructure Structure;
/// <summary>
/// DiscStructure.Session 1 of the disc, since that's all thats needed most of the time.
/// </summary>
public DiscStructure.Session Session1 { get { return Structure.Sessions[1]; } }
/// <summary> /// <summary>
/// Disposable resources (blobs, mostly) referenced by this disc /// Disposable resources (blobs, mostly) referenced by this disc
/// </summary> /// </summary>
@ -120,8 +120,17 @@ namespace BizHawk.Emulation.DiscSystem
/// </summary> /// </summary>
internal List<ISectorSynthJob2448> Sectors = new List<ISectorSynthJob2448>(); internal List<ISectorSynthJob2448> Sectors = new List<ISectorSynthJob2448>();
/// <summary>
/// Parameters set during disc loading which can be referenced by the sector synthesizers
/// </summary>
internal SectorSynthParams SynthParams = new SectorSynthParams(); internal SectorSynthParams SynthParams = new SectorSynthParams();
/// <summary>
/// The DiscMountPolicy used to mount the disc. Consider this read-only.
/// NOT SURE WE NEED THIS
/// </summary>
//public DiscMountPolicy DiscMountPolicy;
public Disc() public Disc()
{ {
} }
@ -134,7 +143,6 @@ namespace BizHawk.Emulation.DiscSystem
} }
} }
/// <summary> /// <summary>
/// generates lead-out sectors according to very crude approximations /// generates lead-out sectors according to very crude approximations
/// TODO - this isnt being used right now /// TODO - this isnt being used right now

View File

@ -88,6 +88,20 @@ namespace BizHawk.Emulation.DiscSystem
RunMednaDisc(); RunMednaDisc();
break; break;
} }
if (OUT_Disc != null)
{
//generate toc and structure:
//1. TOCRaw from RawTOCEntries
var tocSynth = new DiscTOCRaw.SynthesizeFromRawTOCEntriesJob() { Entries = OUT_Disc.RawTOCEntries };
tocSynth.Run();
OUT_Disc.TOCRaw = tocSynth.Result;
//2. Structure frmo TOCRaw
var structureSynth = new DiscStructure.SynthesizeFromTOCRawJob() { IN_Disc = OUT_Disc, TOCRaw = OUT_Disc.TOCRaw };
structureSynth.Run();
OUT_Disc.Structure = structureSynth.Result;
}
FinishLog(); FinishLog();
} }
@ -178,20 +192,7 @@ namespace BizHawk.Emulation.DiscSystem
OUT_Disc = ccdLoader.LoadCCDToDisc(IN_FromPath); OUT_Disc = ccdLoader.LoadCCDToDisc(IN_FromPath);
} }
DONE: DONE: ;
if (OUT_Disc != null)
{
//generate toc and structure:
//1. TOCRaw from RawTOCEntries
var tocSynth = new DiscTOCRaw.SynthesizeFromRawTOCEntriesJob() { Entries = OUT_Disc.RawTOCEntries };
tocSynth.Run();
OUT_Disc.TOCRaw = tocSynth.Result;
//2. Structure frmo TOCRaw
var structureSynth = new DiscStructure.SynthesizeFromTOCRawJob() { IN_Disc = OUT_Disc, TOCRaw = OUT_Disc.TOCRaw };
structureSynth.Run();
OUT_Disc.Structure = structureSynth.Result;
}
} }
} }

View File

@ -7,50 +7,34 @@ namespace BizHawk.Emulation.DiscSystem
/// <summary> /// <summary>
/// Contains structural information for the disc broken down into c# data structures for easy interrogation. /// Contains structural information for the disc broken down into c# data structures for easy interrogation.
/// This represents a best-effort interpretation of the raw disc image. /// This represents a best-effort interpretation of the raw disc image.
/// NOTE: Since this ended up really just having the list of sessions.. maybe it isn't needed and can just float on up into Disc
/// </summary> /// </summary>
public class DiscStructure public class DiscStructure
{ {
/// <summary> /// <summary>
/// This is a 0-indexed list of sessions (session 1 is at [0]) /// This is a 0-indexed list of sessions (session 1 is at [0])
/// Support for multiple sessions is thoroughly not working yet /// Support for multiple sessions is thoroughly not working yet
/// TODO - make re-index me with a null session 0
/// </summary> /// </summary>
public List<Session> Sessions = new List<Session>(); public List<Session> Sessions = new List<Session>();
/// <summary>
/// How many sectors in the disc, including the 150 lead-in sectors, up to the end of the last track (before the lead-out track)
/// TODO - does anyone ever need this as the ABA Count? Rename it LBACount or ABACount
/// </summary>
public int LengthInSectors;
/// <summary> /// <summary>
/// Length (including lead-in) of the disc as a timestamp /// Determines which track of session 1 is at the specified LBA.
/// TODO - does anyone ever need this as the ABA Count? Rename it LBACount or ABACount
/// </summary>
public Timestamp FriendlyLength { get { return new Timestamp(LengthInSectors); } }
/// <summary>
/// How many bytes of data in the disc (including lead-in). Disc sectors are really 2352 bytes each, so this is LengthInSectors * 2352
/// TODO - this is garbage
/// </summary>
public long BinarySize
{
get { return LengthInSectors * 2352; }
}
/// <summary>
/// Determines which track of session 0 is at the specified LBA.
/// Returns null if it's before track 1 /// Returns null if it's before track 1
/// </summary> /// </summary>
public Track SeekTrack(int lba) public Track SeekTrack(int lba)
{ {
var ses = Sessions[0]; var ses = Sessions[0];
for (int i = 0; i < ses.Tracks.Count; i++)
//take care with this loop bounds:
for (int i = 1; i <= ses.InformationTrackCount; i++)
{ {
var track = ses.Tracks[i]; var track = ses.Tracks[i];
if (track.LBA > lba) if (track.LBA > lba)
return (i==0)?null:ses.Tracks[i - 1]; return (i==1)?null:ses.Tracks[i];
} }
return ses.Tracks[ses.Tracks.Count - 1]; return ses.Tracks[ses.Tracks.Count];
} }
///// <summary> ///// <summary>
@ -94,6 +78,7 @@ namespace BizHawk.Emulation.DiscSystem
Result = new DiscStructure(); Result = new DiscStructure();
var session = new Session(); var session = new Session();
Result.Sessions.Add(null); //placeholder session for reindexing
Result.Sessions.Add(session); Result.Sessions.Add(session);
session.Number = 1; session.Number = 1;
@ -101,6 +86,13 @@ namespace BizHawk.Emulation.DiscSystem
if(TOCRaw.FirstRecordedTrackNumber != 1) if(TOCRaw.FirstRecordedTrackNumber != 1)
throw new InvalidOperationException("Unsupported: FirstRecordedTrackNumber != 1"); throw new InvalidOperationException("Unsupported: FirstRecordedTrackNumber != 1");
//add a lead-in track
session.Tracks.Add(new DiscStructure.Track() {
Number = 0,
Control = EControlQ.None, //TODO - not accurate (take from track 1?)
LBA = -150 //TODO - not accurate
});
int ntracks = TOCRaw.LastRecordedTrackNumber - TOCRaw.FirstRecordedTrackNumber + 1; int ntracks = TOCRaw.LastRecordedTrackNumber - TOCRaw.FirstRecordedTrackNumber + 1;
for(int i=0;i<ntracks;i++) for(int i=0;i<ntracks;i++)
{ {
@ -120,35 +112,72 @@ namespace BizHawk.Emulation.DiscSystem
track.Mode = dsr.ReadLBA_Mode(track.LBA); track.Mode = dsr.ReadLBA_Mode(track.LBA);
} }
//determine track length according to law specified in comments for track length //determine track length according to... how? It isn't clear.
if (i == ntracks - 1) //Let's not do this until it's needed.
track.Length = TOCRaw.LeadoutLBA.Sector - track.LBA; //if (i == ntracks - 1)
else track.Length = (TOCRaw.TOCItems[i + 2].LBATimestamp.Sector - track.LBA); // track.Length = TOCRaw.LeadoutLBA.Sector - track.LBA;
//else track.Length = (TOCRaw.TOCItems[i + 2].LBATimestamp.Sector - track.LBA);
} }
//add lead-out track
session.Tracks.Add(new DiscStructure.Track()
{
Number = 0xA0, //right?
Control = EControlQ.None, //TODO - not accurate (take from track 1?)
LBA = TOCRaw.LeadoutLBA.Sector
});
//link track list
for (int i = 0; i < session.Tracks.Count - 1; i++)
{
session.Tracks[i].NextTrack = session.Tracks[i + 1];
}
//other misc fields
session.InformationTrackCount = session.Tracks.Count - 2;
} }
} }
public class Session public class Session
{ {
//Notable omission:
//Length of the session
//How should this be defined? It's even harder than determining a track length
/// <summary>
/// The LBA of the session's leadout. In other words, for all intents and purposes, the end of the session
/// </summary>
public int LeadoutLBA { get { return LeadoutTrack.LBA; } }
/// <summary> /// <summary>
/// The session number /// The session number
/// </summary> /// </summary>
public int Number; public int Number;
/// <summary> /// <summary>
/// All the tracks in the session.. but... Tracks[0] should be "Track 1". So beware of this. /// The number of user information tracks in the session.
/// Tracks.Count will be good for counting the useful user information tracks on the disc. /// This excludes track 0 and the lead-out track.
/// Use this instead of Tracks.Count
/// </summary>
public int InformationTrackCount;
/// <summary>
/// All the tracks in the session.. but... Tracks[0] is the lead-in track placeholder. Tracks[1] should be "Track 1". So beware of this.
/// For a disc with "3 tracks", Tracks.Count will be 5: it includes that lead-in track as well as the leadout track.
/// Perhaps we should turn this into a special collection type with no Count or Length, or a method to GetTrack()
/// </summary> /// </summary>
public List<Track> Tracks = new List<Track>(); public List<Track> Tracks = new List<Track>();
//I've thought about how to solve this, but it's not easy.
//At some point we may need to add a true track 0, too.
//Ideas: Dictionary, or a separate PhysicalTracks and UserTracks list, or add a null and make all loops just cope with that
//But, the DiscStructure is kind of weak. It might be better to just optimize it for end-users
//It seems that the current end-users are happy with tracks being implemented the way it is
//removed: /// <summary>
////the length of the session (should be the sum of all track lengths) /// A reference to the first information track (Track 1)
//public int length_aba; /// </summary>
public Track FirstInformationTrack { get { return Tracks[1]; } }
/// <summary>
/// A reference to the lead-out track.
/// Effectively, the end of the user area of the disc.
/// </summary>
public Track LeadoutTrack { get { return Tracks[Tracks.Count - 1]; } }
} }
/// <summary> /// <summary>
@ -184,11 +213,10 @@ namespace BizHawk.Emulation.DiscSystem
//Indices may need scanning sector by sector. //Indices may need scanning sector by sector.
//It's unlikely that any software would be needing indices anyway. //It's unlikely that any software would be needing indices anyway.
//We should add another index scanning service if that's ever needed. //We should add another index scanning service if that's ever needed.
//(note: a CCD should contain indices, but it's not clear whether it's required. logically it wshouldnt be) //(note: a CCD should contain indices, but it's not clear whether it's required. logically it shouldnt be)
//Notable omission: //Notable omission:
//Mode (0,1,2) //Length of the track.
//Modes 1 and 2 can't be generally distinguished. //How should this be defined? Between which indices? It's really hard.
//It's a relatively easy heuristic, though: just read the first sector of each track.
//These omissions could be handled by ReadStructure() policies which permit the scanning of the entire disc. //These omissions could be handled by ReadStructure() policies which permit the scanning of the entire disc.
//After that, they could be cached in here. //After that, they could be cached in here.
@ -228,17 +256,9 @@ namespace BizHawk.Emulation.DiscSystem
public int LBA; public int LBA;
/// <summary> /// <summary>
/// The length of the track, counted from its index 1 to the next track. /// The next track in the session. null for the leadout track of a session.
/// TODO - Shouldn't it exclude the post-gap?
/// NO - in at least one place (CDAudio) this is used.. and.. it should probably play through the post-gap
/// That just goes to show how ill-defined this concept is
/// </summary> /// </summary>
public int Length; public Track NextTrack;
///// <summary>
///// The length as a timestamp (for accessing as a MM:SS:FF)
///// </summary>
//public Timestamp FriendlyLength { get { return new Timestamp(Length); } }
} }
public class Index public class Index
@ -247,19 +267,6 @@ namespace BizHawk.Emulation.DiscSystem
public int LBA; public int LBA;
} }
//public void AnalyzeLengthsFromIndexLengths()
//{
// //this is a little more complex than it looks, because the length of a thing is not determined by summing it
// //but rather by the difference in lbas between start and end
// LengthInSectors = 0;
// foreach (var session in Sessions)
// {
// var firstTrack = session.Tracks[0];
// var lastTrack = session.Tracks[session.Tracks.Count - 1];
// session.length_aba = lastTrack.Indexes[0].aba + lastTrack.Length - firstTrack.Indexes[0].aba;
// LengthInSectors += session.length_aba;
// }
//}
} }
} }