diff --git a/BizHawk.Emulation.DiscSystem/BizHawk.Emulation.DiscSystem.csproj b/BizHawk.Emulation.DiscSystem/BizHawk.Emulation.DiscSystem.csproj
index ebccdb8ab6..1da8e0a609 100644
--- a/BizHawk.Emulation.DiscSystem/BizHawk.Emulation.DiscSystem.csproj
+++ b/BizHawk.Emulation.DiscSystem/BizHawk.Emulation.DiscSystem.csproj
@@ -71,9 +71,11 @@
+
+
diff --git a/BizHawk.Emulation.DiscSystem/DiscFormats/CUE/CUE_Compile.cs b/BizHawk.Emulation.DiscSystem/DiscFormats/CUE/CUE_Compile.cs
index 0ca2c873b4..2034f0ce03 100644
--- a/BizHawk.Emulation.DiscSystem/DiscFormats/CUE/CUE_Compile.cs
+++ b/BizHawk.Emulation.DiscSystem/DiscFormats/CUE/CUE_Compile.cs
@@ -7,483 +7,479 @@ using System.Collections.Generic;
//this would be a good place for structural validation
//after this step, we won't want to have to do stuff like that (it will gunk up already sticky code)
-namespace BizHawk.Emulation.DiscSystem
+namespace BizHawk.Emulation.DiscSystem.CUE
{
- partial class CUE_Context
+ internal class CompiledCDText
{
- internal class CompiledCDText
- {
- public string Songwriter;
- public string Performer;
- public string Title;
- public string ISRC;
- }
+ public string Songwriter;
+ public string Performer;
+ public string Title;
+ public string ISRC;
+ }
- internal class CompiledCueIndex
- {
- public int Number;
-
- ///
- /// this is annoying, it should just be an integer
- ///
- public Timestamp FileMSF;
-
- public override string ToString()
- {
- return string.Format("I#{0:D2} {1}", Number, FileMSF);
- }
- }
+ internal class CompiledCueIndex
+ {
+ public int Number;
///
- /// What type of file we're looking at.. each one would require a different ingestion handler
+ /// this is annoying, it should just be an integer
///
- public enum CompiledCueFileType
+ public Timestamp FileMSF;
+
+ public override string ToString()
{
- Unknown,
-
- ///
- /// a raw BIN that can be mounted directly
- ///
- BIN,
-
- ///
- /// a raw WAV that can be mounted directly
- ///
- WAVE,
-
- ///
- /// an ECM file that can be mounted directly (once the index is generated)
- ///
- ECM,
-
- ///
- /// An encoded audio file which can be seeked on the fly, therefore roughly mounted on the fly
- /// THIS ISN'T SUPPORTED YET
- ///
- SeekAudio,
-
- ///
- /// An encoded audio file which can't be seeked on the fly. It must be decoded to a temp buffer, or pre-discohawked
- ///
- DecodeAudio,
+ return string.Format("I#{0:D2} {1}", Number, FileMSF);
}
+ }
- internal class CompiledCueFile
+ ///
+ /// What type of file we're looking at.. each one would require a different ingestion handler
+ ///
+ public enum CompiledCueFileType
+ {
+ Unknown,
+
+ ///
+ /// a raw BIN that can be mounted directly
+ ///
+ BIN,
+
+ ///
+ /// a raw WAV that can be mounted directly
+ ///
+ WAVE,
+
+ ///
+ /// an ECM file that can be mounted directly (once the index is generated)
+ ///
+ ECM,
+
+ ///
+ /// An encoded audio file which can be seeked on the fly, therefore roughly mounted on the fly
+ /// THIS ISN'T SUPPORTED YET
+ ///
+ SeekAudio,
+
+ ///
+ /// An encoded audio file which can't be seeked on the fly. It must be decoded to a temp buffer, or pre-discohawked
+ ///
+ DecodeAudio,
+ }
+
+ internal class CompiledCueFile
+ {
+ public string FullPath;
+ public CompiledCueFileType Type;
+ public override string ToString()
{
- public string FullPath;
- public CompiledCueFileType Type;
- public override string ToString()
- {
- return string.Format("{0}: {1}", Type, Path.GetFileName(FullPath));
- }
+ return string.Format("{0}: {1}", Type, Path.GetFileName(FullPath));
}
+ }
- internal class CompiledDiscInfo
- {
- public int FirstRecordedTrackNumber, LastRecordedTrackNumber;
- public SessionFormat SessionFormat;
- }
+ internal class CompiledDiscInfo
+ {
+ public int FirstRecordedTrackNumber, LastRecordedTrackNumber;
+ public SessionFormat SessionFormat;
+ }
- internal class CompiledCueTrack
- {
- public int BlobIndex;
- public int Number;
+ internal class CompiledCueTrack
+ {
+ public int BlobIndex;
+ public int Number;
- ///
- /// A track that's final in a file gets its length from the length of the file; other tracks lengths are determined from the succeeding track
- ///
- public bool IsFinalInFile;
+ ///
+ /// A track that's final in a file gets its length from the length of the file; other tracks lengths are determined from the succeeding track
+ ///
+ public bool IsFinalInFile;
- ///
- /// A track that's first in a file has an implicit index 0 at 00:00:00
- /// Otherwise it has an implicit index 0 at the placement of the index 1
- ///
- public bool IsFirstInFile;
+ ///
+ /// A track that's first in a file has an implicit index 0 at 00:00:00
+ /// Otherwise it has an implicit index 0 at the placement of the index 1
+ ///
+ public bool IsFirstInFile;
- public CompiledCDText CDTextData = new CompiledCDText();
- public Timestamp PregapLength, PostgapLength;
- public CueFile.TrackFlags Flags = CueFile.TrackFlags.None;
- public CueFile.TrackType TrackType = CueFile.TrackType.Unknown;
+ public CompiledCDText CDTextData = new CompiledCDText();
+ public Timestamp PregapLength, PostgapLength;
+ public CueTrackFlags Flags = CueTrackFlags.None;
+ public CueTrackType TrackType = CueTrackType.Unknown;
- public List Indexes = new List();
+ public List Indexes = new List();
- public override string ToString()
+ public override string ToString()
+ {
+ var idx = Indexes.Find((i) => i.Number == 1);
+ if (idx == null)
+ return string.Format("T#{0:D2} NO INDEX 1", Number);
+ else
{
- var idx = Indexes.Find((i) => i.Number == 1);
- if (idx == null)
- return string.Format("T#{0:D2} NO INDEX 1", Number);
- else
+ var indexlist = string.Join("|", Indexes);
+ return string.Format("T#{0:D2} {1}:{2} ({3})", Number, BlobIndex, idx.FileMSF, indexlist);
+ }
+ }
+ }
+
+ internal class CompileCueJob : DiscJob
+ {
+ ///
+ /// input: the CueFile to analyze
+ ///
+ public CUE_File IN_CueFile;
+
+ ///
+ /// The context used for this compiling job
+ /// TODO - rename something like context
+ ///
+ public CUE_Context IN_CueFormat;
+
+ ///
+ /// output: high level disc info
+ ///
+ public CompiledDiscInfo OUT_CompiledDiscInfo;
+
+ ///
+ /// output: CD-Text set at the global level (before any track commands)
+ ///
+ public CompiledCDText OUT_GlobalCDText;
+
+ ///
+ /// output: The compiled file info
+ ///
+ public List OUT_CompiledCueFiles;
+
+ ///
+ /// output: The compiled track info
+ ///
+ public List OUT_CompiledCueTracks;
+
+ ///
+ /// output: An integer between 0 and 10 indicating how costly it will be to load this disc completely.
+ /// Activites like decoding non-seekable media will increase the load time.
+ /// 0 - Requires no noticeable time
+ /// 1 - Requires minimal processing (indexing ECM)
+ /// 10 - Requires ages, decoding audio data, etc.
+ ///
+ public int OUT_LoadTime;
+
+ //-----------------------------------------------------------------
+
+ CompiledCDText curr_cdtext;
+ int curr_blobIndex = -1;
+ CompiledCueTrack curr_track = null;
+ CompiledCueFile curr_file = null;
+ bool discinfo_session1Format_determined = false;
+ bool curr_fileHasTrack = false;
+
+ void UpdateDiscInfo(CUE_File.Command.TRACK trackCommand)
+ {
+ if (OUT_CompiledDiscInfo.FirstRecordedTrackNumber == 0)
+ OUT_CompiledDiscInfo.FirstRecordedTrackNumber = trackCommand.Number;
+ OUT_CompiledDiscInfo.LastRecordedTrackNumber = trackCommand.Number;
+ if (!discinfo_session1Format_determined)
+ {
+ switch (trackCommand.Type)
{
- var indexlist = string.Join("|", Indexes);
- return string.Format("T#{0:D2} {1}:{2} ({3})", Number, BlobIndex, idx.FileMSF, indexlist);
+ case CueTrackType.Mode2_2336:
+ case CueTrackType.Mode2_2352:
+ OUT_CompiledDiscInfo.SessionFormat = SessionFormat.Type20_CDXA;
+ discinfo_session1Format_determined = true;
+ break;
+
+ case CueTrackType.CDI_2336:
+ case CueTrackType.CDI_2352:
+ OUT_CompiledDiscInfo.SessionFormat = SessionFormat.Type10_CDI;
+ discinfo_session1Format_determined = true;
+ break;
+
+ default:
+ break;
}
}
}
- internal class CompileCueJob : DiscJob
+ void CloseFile()
{
- ///
- /// input: the CueFile to analyze
- ///
- public CueFile IN_CueFile;
-
- ///
- /// The context used for this compiling job
- /// TODO - rename something like context
- ///
- public CUE_Context IN_CueFormat;
-
- ///
- /// output: high level disc info
- ///
- public CompiledDiscInfo OUT_CompiledDiscInfo;
-
- ///
- /// output: CD-Text set at the global level (before any track commands)
- ///
- public CompiledCDText OUT_GlobalCDText;
-
- ///
- /// output: The compiled file info
- ///
- public List OUT_CompiledCueFiles;
-
- ///
- /// output: The compiled track info
- ///
- public List OUT_CompiledCueTracks;
-
- ///
- /// output: An integer between 0 and 10 indicating how costly it will be to load this disc completely.
- /// Activites like decoding non-seekable media will increase the load time.
- /// 0 - Requires no noticeable time
- /// 1 - Requires minimal processing (indexing ECM)
- /// 10 - Requires ages, decoding audio data, etc.
- ///
- public int OUT_LoadTime;
-
- //-----------------------------------------------------------------
-
- CompiledCDText curr_cdtext;
- int curr_blobIndex = -1;
- CompiledCueTrack curr_track = null;
- CompiledCueFile curr_file = null;
- bool discinfo_session1Format_determined = false;
- bool curr_fileHasTrack = false;
-
- void UpdateDiscInfo(CueFile.Command.TRACK trackCommand)
+ if (curr_track != null)
{
- if (OUT_CompiledDiscInfo.FirstRecordedTrackNumber == 0)
- OUT_CompiledDiscInfo.FirstRecordedTrackNumber = trackCommand.Number;
- OUT_CompiledDiscInfo.LastRecordedTrackNumber = trackCommand.Number;
- if (!discinfo_session1Format_determined)
+ //flag this track as the final one in the file
+ curr_track.IsFinalInFile = true;
+ }
+
+ curr_file = null;
+ }
+
+ void OpenFile(CUE_File.Command.FILE f)
+ {
+ if (curr_file != null)
+ CloseFile();
+
+ curr_blobIndex++;
+ curr_fileHasTrack = false;
+
+ var Resolver = IN_CueFormat.Resolver;
+
+ //TODO - smart audio file resolving only for AUDIO types. not BINARY or MOTOROLA or AIFF or ECM or what have you
+
+ var options = Resolver.Resolve(f.Path);
+ string choice = null;
+ if (options.Count == 0)
+ {
+ Error("Couldn't resolve referenced cue file: " + f.Path);
+ return;
+ }
+ else
+ {
+ choice = options[0];
+ if (options.Count > 1)
+ Warn("Multiple options resolving referenced cue file; choosing: " + Path.GetFileName(choice));
+ }
+
+ var cfi = new CompiledCueFile();
+ OUT_CompiledCueFiles.Add(cfi);
+
+ cfi.FullPath = choice;
+
+ //determine the CueFileInfo's type, based on extension and extra checking
+ //TODO - once we reorganize the file ID stuff, do legit checks here (this is completely redundant with the fileID system
+ //TODO - decode vs stream vs unpossible policies in input policies object (including ffmpeg availability-checking callback (results can be cached))
+ string blobPathExt = Path.GetExtension(choice).ToUpperInvariant();
+ if (blobPathExt == ".BIN" || blobPathExt == ".IMG") cfi.Type = CompiledCueFileType.BIN;
+ else if (blobPathExt == ".ISO") cfi.Type = CompiledCueFileType.BIN;
+ else if (blobPathExt == ".WAV")
+ {
+ //quickly, check the format. turn it to DecodeAudio if it can't be supported
+ //TODO - fix exception-throwing inside
+ //TODO - verify stream-disposing semantics
+ var fs = File.OpenRead(choice);
+ using (var blob = new Disc.Blob_WaveFile())
{
- switch (trackCommand.Type)
+ try
{
- case CueFile.TrackType.Mode2_2336:
- case CueFile.TrackType.Mode2_2352:
- OUT_CompiledDiscInfo.SessionFormat = SessionFormat.Type20_CDXA;
- discinfo_session1Format_determined = true;
- break;
-
- case CueFile.TrackType.CDI_2336:
- case CueFile.TrackType.CDI_2352:
- OUT_CompiledDiscInfo.SessionFormat = SessionFormat.Type10_CDI;
- discinfo_session1Format_determined = true;
- break;
-
- default:
- break;
+ blob.Load(fs);
+ cfi.Type = CompiledCueFileType.WAVE;
+ }
+ catch
+ {
+ cfi.Type = CompiledCueFileType.DecodeAudio;
}
}
}
-
- void CloseFile()
+ else if (blobPathExt == ".APE") cfi.Type = CompiledCueFileType.DecodeAudio;
+ else if (blobPathExt == ".MP3") cfi.Type = CompiledCueFileType.DecodeAudio;
+ else if (blobPathExt == ".MPC") cfi.Type = CompiledCueFileType.DecodeAudio;
+ else if (blobPathExt == ".FLAC") cfi.Type = CompiledCueFileType.DecodeAudio;
+ else if (blobPathExt == ".ECM")
{
- if (curr_track != null)
+ cfi.Type = CompiledCueFileType.ECM;
+ if (!Disc.Blob_ECM.IsECM(choice))
{
- //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++;
- curr_fileHasTrack = false;
-
- var Resolver = IN_CueFormat.Resolver;
-
- //TODO - smart audio file resolving only for AUDIO types. not BINARY or MOTOROLA or AIFF or ECM or what have you
-
- var options = Resolver.Resolve(f.Path);
- string choice = null;
- if (options.Count == 0)
- {
- Error("Couldn't resolve referenced cue file: " + f.Path);
- return;
- }
- else
- {
- choice = options[0];
- if (options.Count > 1)
- Warn("Multiple options resolving referenced cue file; choosing: " + Path.GetFileName(choice));
- }
-
- var cfi = new CompiledCueFile();
- OUT_CompiledCueFiles.Add(cfi);
-
- cfi.FullPath = choice;
-
- //determine the CueFileInfo's type, based on extension and extra checking
- //TODO - once we reorganize the file ID stuff, do legit checks here (this is completely redundant with the fileID system
- //TODO - decode vs stream vs unpossible policies in input policies object (including ffmpeg availability-checking callback (results can be cached))
- string blobPathExt = Path.GetExtension(choice).ToUpperInvariant();
- if (blobPathExt == ".BIN" || blobPathExt == ".IMG") cfi.Type = CompiledCueFileType.BIN;
- else if (blobPathExt == ".ISO") cfi.Type = CompiledCueFileType.BIN;
- else if (blobPathExt == ".WAV")
- {
- //quickly, check the format. turn it to DecodeAudio if it can't be supported
- //TODO - fix exception-throwing inside
- //TODO - verify stream-disposing semantics
- var fs = File.OpenRead(choice);
- using (var blob = new Disc.Blob_WaveFile())
- {
- try
- {
- blob.Load(fs);
- cfi.Type = CompiledCueFileType.WAVE;
- }
- catch
- {
- cfi.Type = CompiledCueFileType.DecodeAudio;
- }
- }
- }
- else if (blobPathExt == ".APE") cfi.Type = CompiledCueFileType.DecodeAudio;
- else if (blobPathExt == ".MP3") cfi.Type = CompiledCueFileType.DecodeAudio;
- else if (blobPathExt == ".MPC") cfi.Type = CompiledCueFileType.DecodeAudio;
- else if (blobPathExt == ".FLAC") cfi.Type = CompiledCueFileType.DecodeAudio;
- else if (blobPathExt == ".ECM")
- {
- cfi.Type = CompiledCueFileType.ECM;
- if (!Disc.Blob_ECM.IsECM(choice))
- {
- Error("an ECM file was specified or detected, but it isn't a valid ECM file: " + Path.GetFileName(choice));
- cfi.Type = CompiledCueFileType.Unknown;
- }
- }
- else
- {
- Error("Unknown cue file type. Since it's likely an unsupported compression, this is an error: ", Path.GetFileName(choice));
+ Error("an ECM file was specified or detected, but it isn't a valid ECM file: " + Path.GetFileName(choice));
cfi.Type = CompiledCueFileType.Unknown;
}
-
- //TODO - check for mismatches between track types and file types, or is that best done when interpreting the commands?
+ }
+ else
+ {
+ Error("Unknown cue file type. Since it's likely an unsupported compression, this is an error: ", Path.GetFileName(choice));
+ cfi.Type = CompiledCueFileType.Unknown;
}
- void CreateTrack1Pregap()
+ //TODO - check for mismatches between track types and file types, or is that best done when interpreting the commands?
+ }
+
+ void CreateTrack1Pregap()
+ {
+ if (OUT_CompiledCueTracks[1].PregapLength.Sector == 0) { }
+ else if (OUT_CompiledCueTracks[1].PregapLength.Sector == 150) { }
+ else
{
- if (OUT_CompiledCueTracks[1].PregapLength.Sector == 0) { }
- else if (OUT_CompiledCueTracks[1].PregapLength.Sector == 150) { }
- else
+ Error("Track 1 specified an illegal pregap. It's being ignored and replaced with a 00:02:00 pregap");
+ }
+ OUT_CompiledCueTracks[1].PregapLength = new Timestamp(150);
+ }
+
+ void FinalAnalysis()
+ {
+ //some quick checks:
+ if (OUT_CompiledCueFiles.Count == 0)
+ Error("Cue file doesn't specify any input files!");
+
+ //we can't reliably analyze the length of files here, because we might have to be decoding to get lengths (VBR mp3s)
+ //So, it's not really worth the trouble. We'll cope with lengths later
+ //we could check the format of the wav file here, though
+
+ //score the cost of loading the file
+ bool needsCodec = false;
+ OUT_LoadTime = 0;
+ foreach (var cfi in OUT_CompiledCueFiles)
+ {
+ if (cfi.Type == CompiledCueFileType.DecodeAudio)
{
- Error("Track 1 specified an illegal pregap. It's being ignored and replaced with a 00:02:00 pregap");
+ needsCodec = true;
+ OUT_LoadTime = Math.Max(OUT_LoadTime, 10);
}
- OUT_CompiledCueTracks[1].PregapLength = new Timestamp(150);
+ if (cfi.Type == CompiledCueFileType.SeekAudio)
+ needsCodec = true;
+ if (cfi.Type == CompiledCueFileType.ECM)
+ OUT_LoadTime = Math.Max(OUT_LoadTime, 1);
}
- void FinalAnalysis()
+ //check whether processing was available
+ if (needsCodec)
{
- //some quick checks:
- if (OUT_CompiledCueFiles.Count == 0)
- Error("Cue file doesn't specify any input files!");
-
- //we can't reliably analyze the length of files here, because we might have to be decoding to get lengths (VBR mp3s)
- //So, it's not really worth the trouble. We'll cope with lengths later
- //we could check the format of the wav file here, though
-
- //score the cost of loading the file
- bool needsCodec = false;
- OUT_LoadTime = 0;
- foreach (var cfi in OUT_CompiledCueFiles)
- {
- if (cfi.Type == CompiledCueFileType.DecodeAudio)
- {
- needsCodec = true;
- OUT_LoadTime = Math.Max(OUT_LoadTime, 10);
- }
- if (cfi.Type == CompiledCueFileType.SeekAudio)
- needsCodec = true;
- if (cfi.Type == CompiledCueFileType.ECM)
- OUT_LoadTime = Math.Max(OUT_LoadTime, 1);
- }
-
- //check whether processing was available
- if (needsCodec)
- {
- FFMpeg ffmpeg = new FFMpeg();
- if (!ffmpeg.QueryServiceAvailable())
- Warn("Decoding service will be required for further processing, but is not available");
- }
+ FFMpeg ffmpeg = new FFMpeg();
+ if (!ffmpeg.QueryServiceAvailable())
+ Warn("Decoding service will be required for further processing, but is not available");
}
+ }
- void CloseTrack()
- {
- if (curr_track == null)
- return;
+ void CloseTrack()
+ {
+ if (curr_track == null)
+ return;
- //normalize: if an index 0 is missing, add it here
- if (curr_track.Indexes[0].Number != 0)
- {
- var index0 = new CompiledCueIndex();
- var index1 = curr_track.Indexes[0];
- index0.Number = 0;
- index0.FileMSF = index1.FileMSF; //same MSF as index 1 will make it effectively nonexistent
+ //normalize: if an index 0 is missing, add it here
+ if (curr_track.Indexes[0].Number != 0)
+ {
+ var index0 = new CompiledCueIndex();
+ var index1 = curr_track.Indexes[0];
+ index0.Number = 0;
+ index0.FileMSF = index1.FileMSF; //same MSF as index 1 will make it effectively nonexistent
- //well now, if it's the first in the file, an implicit index will take its value from 00:00:00 in the file
- //this is the kind of thing I sought to solve originally by 'interpreting' the file, but it seems easy enough to handle this way
- //my carlin.cue tests this but test cases shouldnt be hard to find
- if (curr_track.IsFirstInFile)
- index0.FileMSF = new Timestamp(0);
+ //well now, if it's the first in the file, an implicit index will take its value from 00:00:00 in the file
+ //this is the kind of thing I sought to solve originally by 'interpreting' the file, but it seems easy enough to handle this way
+ //my carlin.cue tests this but test cases shouldnt be hard to find
+ if (curr_track.IsFirstInFile)
+ index0.FileMSF = new Timestamp(0);
- curr_track.Indexes.Insert(0, index0);
- }
-
- OUT_CompiledCueTracks.Add(curr_track);
- curr_track = null;
+ curr_track.Indexes.Insert(0, index0);
}
- void OpenTrack(CueFile.Command.TRACK trackCommand)
- {
- curr_track = new CompiledCueTrack();
+ OUT_CompiledCueTracks.Add(curr_track);
+ curr_track = null;
+ }
- //spill cdtext data into this track
- curr_cdtext = curr_track.CDTextData;
+ void OpenTrack(CUE_File.Command.TRACK trackCommand)
+ {
+ curr_track = new CompiledCueTrack();
+
+ //spill cdtext data into this track
+ curr_cdtext = curr_track.CDTextData;
- curr_track.BlobIndex = curr_blobIndex;
- curr_track.Number = trackCommand.Number;
- curr_track.TrackType = trackCommand.Type;
+ curr_track.BlobIndex = curr_blobIndex;
+ curr_track.Number = trackCommand.Number;
+ curr_track.TrackType = trackCommand.Type;
- //default flags
- if (curr_track.TrackType != CueFile.TrackType.Audio)
- curr_track.Flags = CueFile.TrackFlags.DATA;
+ //default flags
+ if (curr_track.TrackType != CueTrackType.Audio)
+ curr_track.Flags = CueTrackFlags.DATA;
- if (!curr_fileHasTrack)
- {
- curr_fileHasTrack = curr_track.IsFirstInFile = true;
- }
-
- UpdateDiscInfo(trackCommand);
+ if (!curr_fileHasTrack)
+ {
+ curr_fileHasTrack = curr_track.IsFirstInFile = true;
}
- void AddIndex(CueFile.Command.INDEX indexCommand)
+ UpdateDiscInfo(trackCommand);
+ }
+
+ void AddIndex(CUE_File.Command.INDEX indexCommand)
+ {
+ var newindex = new CompiledCueIndex();
+ newindex.FileMSF = indexCommand.Timestamp;
+ newindex.Number = indexCommand.Number;
+ curr_track.Indexes.Add(newindex);
+ }
+
+ public void Run()
+ {
+ //in params
+ var cue = IN_CueFile;
+
+ //output state
+ OUT_GlobalCDText = new CompiledCDText();
+ OUT_CompiledDiscInfo = new CompiledDiscInfo();
+ OUT_CompiledCueFiles = new List();
+ OUT_CompiledCueTracks = new List();
+
+ //add a track 0, for addressing convenience.
+ //note: for future work, track 0 may need emulation (accessible by very negative LBA--the TOC is stored there)
+ var track0 = new CompiledCueTrack() {
+ Number = 0,
+ };
+ OUT_CompiledCueTracks.Add(track0);
+
+ //global cd text will acquire the cdtext commands set before track commands
+ curr_cdtext = OUT_GlobalCDText;
+
+ for (int i = 0; i < cue.Commands.Count; i++)
{
- var newindex = new CompiledCueIndex();
- newindex.FileMSF = indexCommand.Timestamp;
- newindex.Number = indexCommand.Number;
- curr_track.Indexes.Add(newindex);
- }
+ var cmd = cue.Commands[i];
- public void Run()
- {
- //in params
- var cue = IN_CueFile;
+ //these commands get dealt with globally. nothing to be done here
+ //(but in the future we need to accumulate them into the compile pass output)
+ if (cmd is CUE_File.Command.CATALOG || cmd is CUE_File.Command.CDTEXTFILE) continue;
- //output state
- OUT_GlobalCDText = new CompiledCDText();
- OUT_CompiledDiscInfo = new CompiledDiscInfo();
- OUT_CompiledCueFiles = new List();
- OUT_CompiledCueTracks = new List();
+ //nothing to be done for comments
+ if (cmd is CUE_File.Command.REM) continue;
+ if (cmd is CUE_File.Command.COMMENT) continue;
- //add a track 0, for addressing convenience.
- //note: for future work, track 0 may need emulation (accessible by very negative LBA--the TOC is stored there)
- var track0 = new CompiledCueTrack() {
- Number = 0,
- };
- OUT_CompiledCueTracks.Add(track0);
+ //CD-text and related
+ if (cmd is CUE_File.Command.PERFORMER) curr_cdtext.Performer = (cmd as CUE_File.Command.PERFORMER).Value;
+ if (cmd is CUE_File.Command.SONGWRITER) curr_cdtext.Songwriter = (cmd as CUE_File.Command.SONGWRITER).Value;
+ if (cmd is CUE_File.Command.TITLE) curr_cdtext.Title = (cmd as CUE_File.Command.TITLE).Value;
+ if (cmd is CUE_File.Command.ISRC) curr_cdtext.ISRC = (cmd as CUE_File.Command.ISRC).Value;
- //global cd text will acquire the cdtext commands set before track commands
- curr_cdtext = OUT_GlobalCDText;
-
- for (int i = 0; i < cue.Commands.Count; i++)
+ //flags can only be set when a track command is running
+ if (cmd is CUE_File.Command.FLAGS)
{
- var cmd = cue.Commands[i];
-
- //these commands get dealt with globally. nothing to be done here
- //(but in the future we need to accumulate them into the compile pass output)
- 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;
-
- //CD-text and related
- if (cmd is CueFile.Command.PERFORMER) curr_cdtext.Performer = (cmd as CueFile.Command.PERFORMER).Value;
- if (cmd is CueFile.Command.SONGWRITER) curr_cdtext.Songwriter = (cmd as CueFile.Command.SONGWRITER).Value;
- if (cmd is CueFile.Command.TITLE) curr_cdtext.Title = (cmd as CueFile.Command.TITLE).Value;
- if (cmd is CueFile.Command.ISRC) curr_cdtext.ISRC = (cmd as CueFile.Command.ISRC).Value;
-
- //flags can only be set when a track command is running
- if (cmd is CueFile.Command.FLAGS)
- {
- if (curr_track == null)
- Warn("Ignoring invalid flag commands outside of a track command");
- else
- //take care to |= it here, so the data flag doesn't get cleared
- curr_track.Flags |= (cmd as CueFile.Command.FLAGS).Flags;
- }
-
- if (cmd is CueFile.Command.TRACK)
- {
- CloseTrack();
- OpenTrack(cmd as CueFile.Command.TRACK);
- }
-
- if (cmd is CueFile.Command.FILE)
- {
- CloseFile();
- OpenFile(cmd as CueFile.Command.FILE);
- }
-
- if (cmd is CueFile.Command.INDEX)
- {
- //todo - validate no postgap specified
- AddIndex(cmd as CueFile.Command.INDEX);
- }
-
- if (cmd is CueFile.Command.PREGAP)
- {
- //validate track open
- //validate no indexes
- curr_track.PregapLength = (cmd as CueFile.Command.PREGAP).Length;
- }
-
- if (cmd is CueFile.Command.POSTGAP)
- {
- curr_track.PostgapLength = (cmd as CueFile.Command.POSTGAP).Length;
- }
-
+ if (curr_track == null)
+ Warn("Ignoring invalid flag commands outside of a track command");
+ else
+ //take care to |= it here, so the data flag doesn't get cleared
+ curr_track.Flags |= (cmd as CUE_File.Command.FLAGS).Flags;
}
- //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();
+ if (cmd is CUE_File.Command.TRACK)
+ {
+ CloseTrack();
+ OpenTrack(cmd as CUE_File.Command.TRACK);
+ }
- CreateTrack1Pregap();
- FinalAnalysis();
+ if (cmd is CUE_File.Command.FILE)
+ {
+ CloseFile();
+ OpenFile(cmd as CUE_File.Command.FILE);
+ }
+
+ if (cmd is CUE_File.Command.INDEX)
+ {
+ //todo - validate no postgap specified
+ AddIndex(cmd as CUE_File.Command.INDEX);
+ }
+
+ if (cmd is CUE_File.Command.PREGAP)
+ {
+ //validate track open
+ //validate no indexes
+ curr_track.PregapLength = (cmd as CUE_File.Command.PREGAP).Length;
+ }
+
+ if (cmd is CUE_File.Command.POSTGAP)
+ {
+ curr_track.PostgapLength = (cmd as CUE_File.Command.POSTGAP).Length;
+ }
+
+ }
+
+ //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();
+ FinalAnalysis();
- } //Run()
+ } //Run()
- } //class CompileCueJob
-
- } //partial class CUE_Format2
+ } //class CompileCueJob
} //namespace BizHawk.Emulation.DiscSystem
\ No newline at end of file
diff --git a/BizHawk.Emulation.DiscSystem/DiscFormats/CUE/CUE_Context.cs b/BizHawk.Emulation.DiscSystem/DiscFormats/CUE/CUE_Context.cs
index f98da48aee..4a6529c5be 100644
--- a/BizHawk.Emulation.DiscSystem/DiscFormats/CUE/CUE_Context.cs
+++ b/BizHawk.Emulation.DiscSystem/DiscFormats/CUE/CUE_Context.cs
@@ -6,9 +6,9 @@ using System.Collections.Generic;
//http://digitalx.org/cue-sheet/index.html "all cue sheet information is a straight 1:1 copy from the cdrwin helpfile"
-namespace BizHawk.Emulation.DiscSystem
+namespace BizHawk.Emulation.DiscSystem.CUE
{
- public partial class CUE_Context
+ public class CUE_Context
{
///
/// The CueFileResolver to be used by this instance
diff --git a/BizHawk.Emulation.DiscSystem/DiscFormats/CUE/CUE_File.cs b/BizHawk.Emulation.DiscSystem/DiscFormats/CUE/CUE_File.cs
new file mode 100644
index 0000000000..7a55fead7b
--- /dev/null
+++ b/BizHawk.Emulation.DiscSystem/DiscFormats/CUE/CUE_File.cs
@@ -0,0 +1,52 @@
+using System;
+using System.Collections.Generic;
+
+namespace BizHawk.Emulation.DiscSystem.CUE
+{
+ ///
+ /// Represents the contents of a cue file
+ ///
+ class CUE_File
+ {
+ // (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 CueFileType Type; public override string ToString() { return string.Format("FILE ({0}): {1}", Type, Path); } }
+ public class FLAGS { public CueTrackFlags Flags; public override string ToString() { return string.Format("FLAGS {0}", Flags); } }
+ public class INDEX { public int Number; public Timestamp Timestamp; public override string ToString() { return string.Format("INDEX {0,2} {1}", Number, Timestamp); } }
+ public class ISRC { public string Value; public override string ToString() { return string.Format("ISRC: {0}", Value); } }
+ public class PERFORMER { public string Value; public override string ToString() { return string.Format("PERFORMER: {0}", Value); } }
+ public class POSTGAP { public Timestamp Length; public override string ToString() { return string.Format("POSTGAP: {0}", Length); } }
+ public class PREGAP { public Timestamp Length; public override string ToString() { return string.Format("PREGAP: {0}", Length); } }
+ public class REM { public string Value; public override string ToString() { return string.Format("REM: {0}", Value); } }
+ public class COMMENT { public string Value; public override string ToString() { return string.Format("COMMENT: {0}", Value); } }
+ public class SONGWRITER { public string Value; public override string ToString() { return string.Format("SONGWRITER: {0}", Value); } }
+ public class TITLE { public string Value; public override string ToString() { return string.Format("TITLE: {0}", Value); } }
+ public class TRACK { public int Number; public CueTrackType Type; public override string ToString() { return string.Format("TRACK {0,2} ({1})", Number, Type); } }
+ }
+
+
+ ///
+ /// Stuff other than the commands, global for the whole disc
+ ///
+ public class DiscInfo
+ {
+ public Command.CATALOG Catalog;
+ public Command.ISRC ISRC;
+ public Command.CDTEXTFILE CDTextFile;
+ }
+
+ ///
+ /// The sequential list of commands parsed out of the cue file
+ ///
+ public List