diff --git a/BizHawk.Emulation.DiscSystem/API/Disc.API.cs b/BizHawk.Emulation.DiscSystem/API/Disc.API.cs
index a7895df665..64f912d977 100644
--- a/BizHawk.Emulation.DiscSystem/API/Disc.API.cs
+++ b/BizHawk.Emulation.DiscSystem/API/Disc.API.cs
@@ -89,6 +89,8 @@ namespace BizHawk.Emulation.DiscSystem
///
/// 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
///
public int LBACount { get { return ABACount - 150; } }
diff --git a/BizHawk.Emulation.DiscSystem/Blobs/Blob_ZeroPadAdapter.cs b/BizHawk.Emulation.DiscSystem/Blobs/Blob_ZeroPadAdapter.cs
index ca2cd1c362..ca3cd043c5 100644
--- a/BizHawk.Emulation.DiscSystem/Blobs/Blob_ZeroPadAdapter.cs
+++ b/BizHawk.Emulation.DiscSystem/Blobs/Blob_ZeroPadAdapter.cs
@@ -7,6 +7,43 @@ namespace BizHawk.Emulation.DiscSystem
{
public partial class Disc : IDisposable
{
+
+ internal sealed class Blob_ZeroPadAdapter : IBlob
+ {
+ IBlob srcBlob;
+ long srcBlobLength;
+ public Blob_ZeroPadAdapter(IBlob srcBlob, long srcBlobLength)
+ {
+ this.srcBlob = srcBlob;
+ this.srcBlobLength = srcBlobLength;
+ }
+
+ public int Read(long byte_pos, byte[] buffer, int offset, int count)
+ {
+ int todo = count;
+ long end = byte_pos + todo;
+ if (end > srcBlobLength)
+ {
+ long temp = (int)(srcBlobLength - end);
+ if (temp > int.MaxValue)
+ throw new InvalidOperationException();
+ todo = (int)temp;
+
+ //zero-fill the unused part (just for safety's sake)
+ Array.Clear(buffer, offset + todo, count - todo);
+ }
+
+ srcBlob.Read(byte_pos, buffer, offset, todo);
+
+ //since it's zero padded, this never fails and always reads the requested amount
+ return count;
+ }
+
+ public void Dispose()
+ {
+ }
+ }
+
///
/// For use with blobs which are prematurely ended: buffers what there is, and zero-pads the rest
///
diff --git a/BizHawk.Emulation.DiscSystem/CUE/CUE_Compile.cs b/BizHawk.Emulation.DiscSystem/CUE/CUE_Compile.cs
index 72676bc31f..d34a513cf8 100644
--- a/BizHawk.Emulation.DiscSystem/CUE/CUE_Compile.cs
+++ b/BizHawk.Emulation.DiscSystem/CUE/CUE_Compile.cs
@@ -22,6 +22,10 @@ namespace BizHawk.Emulation.DiscSystem
internal class CompiledCueIndex
{
public int Number;
+
+ ///
+ /// this is annoying, it should just be an integer
+ ///
public Timestamp FileMSF;
public override string ToString()
@@ -84,6 +88,12 @@ namespace BizHawk.Emulation.DiscSystem
{
public int BlobIndex;
public int Number;
+
+ ///
+ /// A track that's final in the file gets its length from the length of the file; other tracks lengths are determined from the succeeding track
+ ///
+ public bool IsFinalInFile;
+
public CompiledCDText CDTextData = new CompiledCDText();
public Timestamp PregapLength, PostgapLength;
public CueFile.TrackFlags Flags = CueFile.TrackFlags.None;
@@ -150,6 +160,7 @@ namespace BizHawk.Emulation.DiscSystem
CompiledCDText curr_cdtext;
int curr_blobIndex = -1;
CompiledCueTrack curr_track = null;
+ CompiledCueFile curr_file = null;
bool discinfo_session1Format_determined = false;
void UpdateDiscInfo(CueFile.Command.TRACK trackCommand)
@@ -179,8 +190,22 @@ namespace BizHawk.Emulation.DiscSystem
}
}
- void AddFile(CueFile.Command.FILE f)
+ void CloseFile()
{
+ if (curr_track != null)
+ {
+ //flag this track as the final one in the file
+ curr_track.IsFinalInFile = true;
+ }
+
+ curr_file = null;
+ }
+
+ void OpenFile(CueFile.Command.FILE f)
+ {
+ if (curr_file != null)
+ CloseFile();
+
curr_blobIndex++;
var Resolver = IN_CueFormat.Resolver;
@@ -311,7 +336,7 @@ namespace BizHawk.Emulation.DiscSystem
var index0 = new CompiledCueIndex();
var index1 = curr_track.Indexes[0];
index0.Number = 0;
- index0.FileMSF = index1.FileMSF;
+ index0.FileMSF = index1.FileMSF; //same MSF as index 1 will make it effectively nonexistent
curr_track.Indexes.Insert(0, index0);
}
@@ -401,7 +426,8 @@ namespace BizHawk.Emulation.DiscSystem
if (cmd is CueFile.Command.FILE)
{
- AddFile(cmd as CueFile.Command.FILE);
+ CloseFile();
+ OpenFile(cmd as CueFile.Command.FILE);
}
if (cmd is CueFile.Command.INDEX)
@@ -424,6 +450,9 @@ namespace BizHawk.Emulation.DiscSystem
}
+ //it's a bit odd to close the file before closing the track, but...
+ //we need to be sure to CloseFile first to make sure the track is marked as the final one in the file
+ CloseFile();
CloseTrack();
CreateTrack1Pregap();
diff --git a/BizHawk.Emulation.DiscSystem/CUE/CUE_Load.cs b/BizHawk.Emulation.DiscSystem/CUE/CUE_Load.cs
index 8575354178..3f17469f5c 100644
--- a/BizHawk.Emulation.DiscSystem/CUE/CUE_Load.cs
+++ b/BizHawk.Emulation.DiscSystem/CUE/CUE_Load.cs
@@ -49,177 +49,35 @@ namespace BizHawk.Emulation.DiscSystem
Normal, Pregap, Postgap
}
- //current blob file state
- int file_cfi_index = -1;
- IBlob file_blob = null;
- CueFile.Command.FILE file_currentCommand = null;
- long file_ofs = 0, file_len = 0;
- int file_msf = -1;
-
- //current track, flags, and index state
- CueFile.Command.TRACK track_pendingCommand = null;
- CueFile.Command.TRACK track_currentCommand = null;
- CueFile.TrackFlags track_pendingFlags = CueFile.TrackFlags.None;
- CueFile.TrackFlags track_currentFlags = CueFile.TrackFlags.None;
-
- //burn state.
- //TODO - separate burner into another class?
- BurnType burntype_current;
- Timestamp burn_pregap_timestamp;
-
-
- void BeginBurnPregap()
+ class BlobInfo
{
- //TODO?
+ public IBlob Blob;
+ public long Length;
}
- void BurnPregap(Timestamp length)
+ //not sure if we need this...
+ class TrackInfo
{
- burntype_current = BurnType.Pregap;
- burn_pregap_timestamp = length;
- int length_lba = length.Sector;
+ public int Length;
- //TODO: read [IEC10149] 20, 20.1, & 20.2 to assign pre-gap and post-gap types correctly depending on track number and previous track
- //ALSO, if the last track is data, we need to make a post-gap
- //we can grab the previously generated sector in order to figure out how to encode new pregap sectors
- for(int i=0;i BlobInfos;
+ List TrackInfos = new List();
- ////open the new blob
- //file_currentCommand = file;
- //file_msf = 0;
- //var cfi = IN_CompileJob.OUT_FileInfos[++file_cfi_index];
-
- ////mount the file
- //if (cfi.Type == AnalyzeCueJob.CueFileType.BIN || cfi.Type == AnalyzeCueJob.CueFileType.Unknown)
- //{
- // //raw files:
- // var blob = new Disc.Blob_RawFile { PhysicalPath = cfi.FullPath };
- // OUT_Disc.DisposableResources.Add(file_blob = blob);
- // file_len = blob.Length;
- //}
- //else if (cfi.Type == AnalyzeCueJob.CueFileType.ECM)
- //{
- // var blob = new Disc.Blob_ECM();
- // OUT_Disc.DisposableResources.Add(file_blob = blob);
- // blob.Load(cfi.FullPath);
- // file_len = blob.Length;
- //}
- //else if (cfi.Type == AnalyzeCueJob.CueFileType.WAVE)
- //{
- // var blob = new Disc.Blob_WaveFile();
- // OUT_Disc.DisposableResources.Add(file_blob = blob);
- // blob.Load(cfi.FullPath);
- // file_len = blob.Length;
- //}
- //else if (cfi.Type == AnalyzeCueJob.CueFileType.DecodeAudio)
- //{
- // FFMpeg ffmpeg = new FFMpeg();
- // if (!ffmpeg.QueryServiceAvailable())
- // {
- // throw new DiscReferenceException(cfi.FullPath, "No decoding service was available (make sure ffmpeg.exe is available. even though this may be a wav, ffmpeg is used to load oddly formatted wave files. If you object to this, please send us a note and we'll see what we can do. It shouldn't be too hard.)");
- // }
- // AudioDecoder dec = new AudioDecoder();
- // byte[] buf = dec.AcquireWaveData(cfi.FullPath);
- // var blob = new Disc.Blob_WaveFile();
- // OUT_Disc.DisposableResources.Add(file_blob = blob);
- // blob.Load(new MemoryStream(buf));
- //}
- }
-
- void BurnToEOF()
- {
- while (file_ofs < file_len)
- BurnSector();
-
- //TODO - if a postgap was requested, do it now
- }
-
- void ProcessIndex(CueFile.Command.INDEX index)
- {
- //burn sectors with the previous registers until we reach the current index MSF
- int index_file_msf = index.Timestamp.Sector;
- while (file_msf < index_file_msf)
- BurnSector();
-
- //latch current track settings
- track_currentCommand = track_pendingCommand;
- track_currentFlags = track_pendingFlags;
-
- //index 0 is annoying. we have to code its subchannels while knowing the index that comes next
- //this is the main reason for transforming the cue file into a CueGrid (any index 0 can easily reference the index 1 that comes after it)
- if (index.Number == 0)
- {
- }
- }
-
- void EatBlobFileSector(int required, out IBlob blob, out long blobOffset)
- {
- blob = file_blob;
- blobOffset = file_ofs;
- if (file_ofs + required > file_len)
- {
- Warn("Zero-padding mis-sized cue blob file: " + Path.GetFileName(file_currentCommand.Path));
- blob = Disc.Blob_ZeroPadBuffer.MakeBufferFrom(file_blob,file_ofs,required);
- OUT_Disc.DisposableResources.Add(blob);
- blobOffset = 0;
- }
- file_ofs += required;
- }
-
- void BurnSector_Normal()
- {
- SS_Base ss = null;
- switch (track_currentCommand.Type)
- {
- case CueFile.TrackType.Mode2_2352:
- ss = new SS_2352();
- EatBlobFileSector(2352, out ss.Blob, out ss.BlobOffset);
- break;
- case CueFile.TrackType.Audio:
- ss = new SS_2352();
- EatBlobFileSector(2352, out ss.Blob, out ss.BlobOffset);
- break;
- }
-
- var se = new SectorEntry(null);
- se.SectorSynth = ss;
- OUT_Disc.Sectors.Add(se);
- }
-
- void BurnSector_Pregap()
- {
- var se = new SectorEntry(null);
- se.SectorSynth = new SS_Mode1_2048(); //TODO - actually burn the right thing
- OUT_Disc.Sectors.Add(se);
-
- burn_pregap_timestamp = new Timestamp(burn_pregap_timestamp.Sector - 1);
- }
-
- void BurnSector()
- {
- switch (burntype_current)
- {
- case BurnType.Normal:
- BurnSector_Normal();
- break;
- case BurnType.Pregap:
- BurnSector_Pregap();
- break;
- }
- }
void MountBlobs()
{
+ IBlob file_blob = null;
+ long file_len = 0;
+
+ BlobInfos = new List();
foreach (var ccf in IN_CompileJob.OUT_CompiledCueFiles)
{
+ var bi = new BlobInfo();
+ BlobInfos.Add(bi);
+
switch (ccf.Type)
{
case CompiledCueFileType.BIN:
@@ -228,7 +86,7 @@ namespace BizHawk.Emulation.DiscSystem
//raw files:
var blob = new Disc.Blob_RawFile { PhysicalPath = ccf.FullPath };
OUT_Disc.DisposableResources.Add(file_blob = blob);
- file_len = blob.Length;
+ bi.Length = blob.Length;
break;
}
case CompiledCueFileType.ECM:
@@ -236,7 +94,7 @@ namespace BizHawk.Emulation.DiscSystem
var blob = new Disc.Blob_ECM();
OUT_Disc.DisposableResources.Add(file_blob = blob);
blob.Load(ccf.FullPath);
- file_len = blob.Length;
+ bi.Length = blob.Length;
break;
}
case CompiledCueFileType.WAVE:
@@ -244,7 +102,7 @@ namespace BizHawk.Emulation.DiscSystem
var blob = new Disc.Blob_WaveFile();
OUT_Disc.DisposableResources.Add(file_blob = blob);
blob.Load(ccf.FullPath);
- file_len = blob.Length;
+ bi.Length = blob.Length;
break;
}
case CompiledCueFileType.DecodeAudio:
@@ -259,35 +117,69 @@ namespace BizHawk.Emulation.DiscSystem
var blob = new Disc.Blob_WaveFile();
OUT_Disc.DisposableResources.Add(file_blob = blob);
blob.Load(new MemoryStream(buf));
+ bi.Length = buf.Length;
break;
}
default:
throw new InvalidOperationException();
- }
+ } //switch(file type)
+
+ //wrap all the blobs with zero padding
+ bi.Blob = new Disc.Blob_ZeroPadAdapter(file_blob, bi.Length);
}
}
+
+ void AnalyzeTracks()
+ {
+ var compiledTracks = IN_CompileJob.OUT_CompiledCueTracks;
+
+ for(int t=0;t trackLookup = new Dictionary();
- foreach (var cct in compiled.OUT_CompiledCueTracks)
- trackLookup[cct.Number] = cct;
+ //unhappily, we cannot determine the length of all the tracks without knowing the length of the files
+ //now that the files are mounted, we can figure the track lengths
+ AnalyzeTracks();
//loop from track 1 to 99
//(track 0 isnt handled yet, that's way distant work)
- for (int t = 1; t <= 99; t++)
+ for (int t = 1; t < TrackInfos.Count; t++)
{
- CompiledCueTrack cct;
- if (!trackLookup.TryGetValue(t, out cct))
- continue;
+ TrackInfo ti = TrackInfos[t];
+ CompiledCueTrack cct = ti.CompiledCueTrack;
//---------------------------------
//generate track pregap
@@ -310,92 +202,129 @@ namespace BizHawk.Emulation.DiscSystem
//after this, pregap sectors are generated like a normal sector, but the subQ is specified as a pregap instead of a normal track
//---------------------------------
- //---------------------------------
- //WE ARE NOW AT INDEX 1
- //---------------------------------
//---------------------------------
- //generate the RawTOCEntry for this track
- SubchannelQ sq = new SubchannelQ();
- //absent some kind of policy for how to set it, this is a safe assumption:
- byte ADR = 1;
- sq.SetStatus(ADR, (EControlQ)(int)cct.Flags);
- sq.q_tno.BCDValue = 0; //kind of a little weird here.. the track number becomes the 'point' and put in the index instead. 0 is the track number here.
- sq.q_index = BCD2.FromDecimal(cct.Number);
- //not too sure about these yet
- sq.min = BCD2.FromDecimal(0);
- sq.sec = BCD2.FromDecimal(0);
- sq.frame = BCD2.FromDecimal(0);
- sq.AP_Timestamp = new Timestamp(OUT_Disc.Sectors.Count + 150); //its supposed to be an absolute timestamp
- OUT_Disc.RawTOCEntries.Add(new RawTOCEntry { QData = sq });
- }
+ //generate sectors for this track.
+
+ //advance to the next file if needed
+ if (curr_blobIndex != cct.BlobIndex)
+ {
+ curr_blobIndex = cct.BlobIndex;
+ curr_blobOffset = 0;
+ curr_blobMSF = 0;
+ curr_blobInfo = BlobInfos[curr_blobIndex];
+ }
+
+ //work until the next track is reached, or the end of the current file is reached, depending on the track type
+ curr_index = 0;
+ for (; ; )
+ {
+ bool trackDone = false;
+
+ //select the appropriate index by inspecting the next index and seeing if we've reached it
+ for (; ; )
+ {
+ if (curr_index == cct.Indexes.Count - 1)
+ break;
+ if (curr_blobMSF >= cct.Indexes[curr_index + 1].FileMSF.Sector)
+ {
+ curr_index++;
+ if (curr_index == 1)
+ {
+ //---- WE ARE NOW AT INDEX 1 -----
+ //generate the RawTOCEntry for this track (make another method for this please)
+ SubchannelQ toc_sq = new SubchannelQ();
+ //absent some kind of policy for how to set it, this is a safe assumption:
+ byte toc_ADR = 1;
+ toc_sq.SetStatus(toc_ADR, (EControlQ)(int)cct.Flags);
+ toc_sq.q_tno.BCDValue = 0; //kind of a little weird here.. the track number becomes the 'point' and put in the index instead. 0 is the track number here.
+ toc_sq.q_index = BCD2.FromDecimal(cct.Number);
+ //not too sure about these yet
+ toc_sq.min = BCD2.FromDecimal(0);
+ toc_sq.sec = BCD2.FromDecimal(0);
+ toc_sq.frame = BCD2.FromDecimal(0);
+ toc_sq.AP_Timestamp = new Timestamp(OUT_Disc.Sectors.Count); //its supposed to be an absolute timestamp
+ OUT_Disc.RawTOCEntries.Add(new RawTOCEntry { QData = toc_sq });
+ }
+ }
+ else break;
+ }
+
+ //generate a sector:
+ ISector siface = null;
+ SS_Base ss = null;
+ switch (cct.TrackType)
+ {
+ case CueFile.TrackType.Mode2_2352:
+ case CueFile.TrackType.Audio:
+ ss = new SS_2352() { Blob = curr_blobInfo.Blob, BlobOffset = curr_blobOffset };
+ curr_blobOffset += 2352;
+ break;
+ }
+
+ //make the subcode
+ //TODO - according to policies, or better yet, defer this til it's needed (user delivers a policies object to disc reader apis)
+ //at any rate, we'd paste this logic into there so let's go ahead and write it here
+ var subcode = new BufferedSubcodeSector(); //(its lame that we have to use this; make a static method when we delete this class)
+ SubchannelQ sq = new SubchannelQ();
+ byte ADR = 1; //absent some kind of policy for how to set it, this is a safe assumption:
+ sq.SetStatus(ADR, (EControlQ)(int)cct.Flags);
+ sq.q_tno = BCD2.FromDecimal(cct.Number);
+ sq.q_index = BCD2.FromDecimal(curr_index);
+ int LBA = OUT_Disc.Sectors.Count;
+ sq.ap_min = BCD2.FromDecimal(new Timestamp(LBA).MIN);
+ sq.ap_sec = BCD2.FromDecimal(new Timestamp(LBA).SEC);
+ sq.ap_frame = BCD2.FromDecimal(new Timestamp(LBA).FRAC);
+ int track_relative_msf = curr_blobMSF - cct.Indexes[1].FileMSF.Sector;
+ sq.min = BCD2.FromDecimal(new Timestamp(track_relative_msf).MIN);
+ sq.sec = BCD2.FromDecimal(new Timestamp(track_relative_msf).SEC);
+ sq.frame = BCD2.FromDecimal(new Timestamp(track_relative_msf).FRAC);
+ //finally we're done: synthesize subchannel
+ subcode.Synthesize_SubchannelQ(ref sq, true);
+
+ //make the SectorEntry (some temporary bullshit here)
+ var se = new SectorEntry(null);
+ se.SectorSynth = ss;
+ ss.sq = sq;
+ OUT_Disc.Sectors.Add(se);
+ curr_blobMSF++;
+
+ if (cct.IsFinalInFile)
+ {
+ //sometimes, break when the file is exhausted
+ if (curr_blobOffset >= curr_blobInfo.Length)
+ trackDone = true;
+ }
+ else
+ {
+ //other times, break when the track is done
+ //(this check is safe because it's not the final track overall if it's not the final track in a file)
+ if (curr_blobMSF >= TrackInfos[t + 1].CompiledCueTrack.Indexes[0].FileMSF.Sector)
+ trackDone = true;
+ }
+
+ if (trackDone)
+ break;
+ }
+
+ //TODO - POSTGAP
+
+ } //end track loop
-
- ////now for the magic. Process commands in order
- //for (int i = 0; i < cue.Commands.Count; i++)
- //{
- // var cmd = cue.Commands[i];
+ //add RawTOCEntries A0 A1 A2 to round out the TOC
+ var TOCMiscInfo = new Synthesize_A0A1A2_Job {
+ IN_FirstRecordedTrackNumber = IN_CompileJob.OUT_CompiledDiscInfo.FirstRecordedTrackNumber,
+ IN_LastRecordedTrackNumber = IN_CompileJob.OUT_CompiledDiscInfo.LastRecordedTrackNumber,
+ IN_Session1Format = IN_CompileJob.OUT_CompiledDiscInfo.SessionFormat,
+ IN_LeadoutTimestamp = new Timestamp(OUT_Disc.Sectors.Count) //do we need a +150?
+ };
+ TOCMiscInfo.Run(OUT_Disc.RawTOCEntries);
- // //these commands get dealt with globally. nothing to be done here
- // if (cmd is CueFile.Command.CATALOG || cmd is CueFile.Command.CDTEXTFILE) continue;
-
- // //nothing to be done for comments
- // if (cmd is CueFile.Command.REM) continue;
- // if (cmd is CueFile.Command.COMMENT) continue;
-
- // //handle cdtext and ISRC state updates, theyre kind of like little registers
- // if (cmd is CueFile.Command.PERFORMER)
- // cdtext_performer = (cmd as CueFile.Command.PERFORMER).Value;
- // if (cmd is CueFile.Command.SONGWRITER)
- // cdtext_songwriter = (cmd as CueFile.Command.SONGWRITER).Value;
- // if (cmd is CueFile.Command.TITLE)
- // cdtext_title = (cmd as CueFile.Command.TITLE).Value;
- // if (cmd is CueFile.Command.ISRC)
- // isrc = (cmd as CueFile.Command.ISRC).Value;
-
- // //flags are also a kind of a register. but the flags value is reset by the track command
- // if (cmd is CueFile.Command.FLAGS)
- // {
- // track_pendingFlags = (cmd as CueFile.Command.FLAGS).Flags;
- // }
-
- // if (cmd is CueFile.Command.TRACK)
- // {
- // var track = cmd as CueFile.Command.TRACK;
-
- // //register the track for further processing when an GENERATION command appears
- // track_pendingCommand = track;
- // track_pendingFlags = CueFile.TrackFlags.None;
-
- // }
-
- // if (cmd is CueFile.Command.FILE)
- // {
- // ProcessFile(cmd as CueFile.Command.FILE);
- // }
-
- // if (cmd is CueFile.Command.INDEX)
- // {
- // ProcessIndex(cmd as CueFile.Command.INDEX);
- // }
- //}
-
- //BurnToEOF();
-
- ////add RawTOCEntries A0 A1 A2 to round out the TOC
- //var TOCMiscInfo = new Synthesize_A0A1A2_Job {
- // IN_FirstRecordedTrackNumber = sloshy_firstRecordedTrackNumber,
- // IN_LastRecordedTrackNumber = sloshy_lastRecordedTrackNumber,
- // IN_Session1Format = sloshy_session1Format,
- // IN_LeadoutTimestamp = new Timestamp(OUT_Disc.Sectors.Count)
- //};
- //TOCMiscInfo.Run(OUT_Disc.RawTOCEntries);
-
- ////generate the TOCRaw from the RawTocEntries
- //var tocSynth = new DiscTOCRaw.SynthesizeFromRawTOCEntriesJob() { Entries = OUT_Disc.RawTOCEntries };
- //tocSynth.Run();
- //OUT_Disc.TOCRaw = tocSynth.Result;
+ //generate the TOCRaw from the RawTocEntries
+ var tocSynth = new DiscTOCRaw.SynthesizeFromRawTOCEntriesJob() { Entries = OUT_Disc.RawTOCEntries };
+ tocSynth.Run();
+ OUT_Disc.TOCRaw = tocSynth.Result;
////generate lead-out track with some canned number of sectors
////TODO - move this somewhere else and make it controllable depending on which console is loading up the disc
@@ -411,4 +340,30 @@ namespace BizHawk.Emulation.DiscSystem
} //Run()
} //class LoadCueJob
} //partial class CUE_Format2
-} //namespace BizHawk.Emulation.DiscSystem
\ No newline at end of file
+} //namespace BizHawk.Emulation.DiscSystem
+
+
+
+
+//TODO:
+ //if (index_num == 0 || type == SectorWriteType.Pregap)
+ //{
+ // //PREGAP:
+ // //things are negative here.
+ // if (track_relative_msf > 0) throw new InvalidOperationException("Perplexing internal error with non-negative pregap MSF");
+ // track_relative_msf = -track_relative_msf;
+
+ // //now for something special.
+ // //yellow-book says:
+ // //pre-gap for "first part of a digital data track not containing user data and encoded as a pause"
+ // //first interval: at least 75 sectors coded as preceding track
+ // //second interval: at least 150 sectors coded as user data track.
+ // //so... we ASSUME the 150 sector pregap is more important. so if thats all there is, theres no 75 sector pregap like the old track
+ // //if theres a longer pregap, then we generate weird old track pregap to contain the rest.
+ // if (track_relative_msf > 150)
+ // {
+ // //only if we're burning a data track now
+ // if((track_flags & CueFile.TrackFlags.DATA)!=0)
+ // sq.q_status = priorSubchannelQ.q_status;
+ // }
+ //}
\ No newline at end of file
diff --git a/BizHawk.Emulation.DiscSystem/CUE/CUE_Parse.cs b/BizHawk.Emulation.DiscSystem/CUE/CUE_Parse.cs
index 33ced561c9..1228f737ef 100644
--- a/BizHawk.Emulation.DiscSystem/CUE/CUE_Parse.cs
+++ b/BizHawk.Emulation.DiscSystem/CUE/CUE_Parse.cs
@@ -29,15 +29,14 @@ namespace BizHawk.Emulation.DiscSystem
///
/// Represents the contents of a cue file
- /// This is relatively unstructured because in a lot (maybe every) way a cue file is meant to be processed one command at a time
///
public class CueFile
{
- // (here are all the commands we can encounter)
- //TODO - record line number origin of command?
+ // (here are all the commands we can encounter)
public static class Command
{
+ //TODO - record line number origin of command? Kind of nice but inessential
public class CATALOG { public string Value; public override string ToString() { return string.Format("CATALOG: {0}", Value); } }
public class CDTEXTFILE { public string Path; public override string ToString() { return string.Format("CDTEXTFILE: {0}", Path); } }
public class FILE { public string Path; public FileType Type; public override string ToString() { return string.Format("FILE ({0}): {1}", Type, Path); } }
@@ -88,9 +87,11 @@ namespace BizHawk.Emulation.DiscSystem
//All audio files (WAVE, AIFF, and MP3) must be in 44.1KHz 16-bit stereo format.
//BUT NOTE: MP3 can be VBR and the length can't be known without decoding the whole thing.
//But, some ideas:
- //1. we could operate ffmpeg differently to retrieve the length, which maybe it can do without having to
+ //1. we could operate ffmpeg differently to retrieve the length, which maybe it can do without having to decode the entire thing
//2. we could retrieve it from an ID3 if present.
- //3. as a last resort, since MP3 is the annoying case usually, we could include my c# mp3 parser and sum the length
+ //3. as a last resort, since MP3 is the annoying case usually, we could include my c# mp3 parser and sum the length (test the performance, this might be reasonably fast on par with ECM parsing)
+ //NOTE: once deciding the length, we would have to stick with it! samples would have to be discarded or inserted to make the track work out
+ //but we COULD effectively achieve stream-loading mp3 discs, with enough work.
public enum FileType
{
Unspecified,
diff --git a/BizHawk.Emulation.DiscSystem/Disc.cs b/BizHawk.Emulation.DiscSystem/Disc.cs
index 839498e847..dd9a2a2100 100644
--- a/BizHawk.Emulation.DiscSystem/Disc.cs
+++ b/BizHawk.Emulation.DiscSystem/Disc.cs
@@ -11,14 +11,17 @@ using System.Collections.Generic;
//This will result in a completely flattened CCD where everything comes right off the hard drive
//Our choice here might be an unwise decision for disc ID and miscellaneous purposes but it's best for gaming and stream-converting (hawking and hashing)
+//TODO: in principle, we could mount audio to decode only on an as-needed basis
+//this might result in hiccups during emulation, though, so it should be an option.
+//This would imply either decode-length processing (scan file without decoding) or decoding and discarding the data.
+//We should probably have some richer policy specifications for this kind of thing, but it's not a high priority. Main workflow is still discohawking.
+//Alternate policies would probably be associated with copious warnings (examples: ? ? ?)
+
+
//https://books.google.com/books?id=caF_AAAAQBAJ&lpg=PA124&ots=OA9Ttj9CHZ&dq=disc%20TOC%20point%20A2&pg=PA124
-
-
//http://www.staff.uni-mainz.de/tacke/scsi/SCSI2-14.html
-
//http://www.pctechguide.com/iso-9660-data-format-for-cds-cd-roms-cd-rs-and-cd-rws
//http://linux.die.net/man/1/cue2toc
-
//http://cdemu.sourceforge.net/project.php#sf
//apparently cdrdao is the ultimate linux tool for doing this stuff but it doesnt support DAO96 (or other DAO modes) that would be necessary to extract P-Q subchannels
@@ -27,13 +30,11 @@ using System.Collections.Generic;
//here is a featureset list of windows cd burning programs (useful for cuesheet compatibility info)
//http://www.dcsoft.com/cue_mastering_progs.htm
-//good
+//good links
//http://linux-sxs.org/bedtime/cdapi.html
//http://en.wikipedia.org/wiki/Track_%28CD%29
//http://docs.google.com/viewer?a=v&q=cache:imNKye05zIEJ:www.13thmonkey.org/documentation/SCSI/mmc-r10a.pdf+q+subchannel+TOC+format&hl=en&gl=us&pid=bl&srcid=ADGEEShtYqlluBX2lgxTL3pVsXwk6lKMIqSmyuUCX4RJ3DntaNq5vI2pCvtkyze-fumj7vvrmap6g1kOg5uAVC0IxwU_MRhC5FB0c_PQ2BlZQXDD7P3GeNaAjDeomelKaIODrhwOoFNb&sig=AHIEtbRXljAcFjeBn3rMb6tauHWjSNMYrw
-//r:\consoles\~docs\yellowbook
//http://digitalx.org/cue-sheet/examples/
-//
//"qemu cdrom emulator"
//http://www.koders.com/c/fid7171440DEC7C18B932715D671DEE03743111A95A.aspx
@@ -48,7 +49,6 @@ using System.Collections.Generic;
//ideas:
/*
* do some stuff asynchronously. for example, decoding mp3 sectors.
- * keep a list of 'blobs' (giant bins or decoded wavs likely) which can reference the disk
* keep a list of sectors and the blob/offset from which they pull -- also whether the sector is available
* if it is not available and something requests it then it will have to block while that sector gets generated
* perhaps the blobs know how to resolve themselves and the requested sector can be immediately resolved (priority boost)