diff --git a/DICUI.Library/CueSheets/CueFile.cs b/DICUI.Library/CueSheets/CueFile.cs
index be543476..bd0bfda3 100644
--- a/DICUI.Library/CueSheets/CueFile.cs
+++ b/DICUI.Library/CueSheets/CueFile.cs
@@ -1,10 +1,10 @@
-using System;
-using System.Collections.Generic;
+using System.Collections.Generic;
+using System.IO;
///
/// Information sourced from http://web.archive.org/web/20070221154246/http://www.goldenhawk.com/download/cdrwin.pdf
///
-namespace DICUI.Library.CueSheets
+namespace DICUI.CueSheets
{
///
/// The audio or data file’s filetype
@@ -45,7 +45,7 @@ namespace DICUI.Library.CueSheets
///
/// filename
///
- public string Name { get; set; }
+ public string FileName { get; set; }
///
/// filetype
@@ -56,5 +56,94 @@ namespace DICUI.Library.CueSheets
/// List of TRACK in FILE
///
public List Tracks { get; set; }
+
+ ///
+ /// Create an empty FILE
+ ///
+ public CueFile()
+ {
+ }
+
+ ///
+ /// Fill a FILE from a stream reader
+ ///
+ /// File name to set
+ /// File type to set
+ /// StreamReader to pull from
+ public CueFile(string fileName, string fileType, StreamReader sr)
+ {
+ if (sr == null)
+ return;
+
+ // Set the current fields
+ this.FileName = fileName;
+ this.FileType = GetFileType(fileType);
+
+ while (!sr.EndOfStream)
+ {
+ string line = sr.ReadLine().Trim();
+ string[] splitLine = line.Split(' ');
+
+ // If we have an empty line, we skip
+ if (string.IsNullOrWhiteSpace(line))
+ continue;
+
+ switch (splitLine[0])
+ {
+ // Read comments
+ case "REM":
+ // We ignore all comments for now
+ break;
+
+ // Read track information
+ case "TRACK":
+ if (splitLine.Length < 3)
+ continue; // TODO: Make this throw an exception
+
+ if (this.Tracks == null)
+ this.Tracks = new List();
+
+ var track = new CueTrack(splitLine[1], splitLine[2], sr);
+ if (track == default)
+ continue; // TODO: Make this throw an exception
+
+ this.Tracks.Add(track);
+ break;
+
+ // Default means return
+ default:
+ return;
+ }
+ }
+ }
+
+ ///
+ /// Get the file type from a given string
+ ///
+ /// String to get value from
+ /// CueFileType, if possible (default BINARY)
+ private CueFileType GetFileType(string fileType)
+ {
+ switch (fileType.ToLowerInvariant())
+ {
+ case "binary":
+ return CueFileType.BINARY;
+
+ case "motorola":
+ return CueFileType.MOTOROLA;
+
+ case "aiff":
+ return CueFileType.AIFF;
+
+ case "wave":
+ return CueFileType.WAVE;
+
+ case "mp3":
+ return CueFileType.MP3;
+
+ default:
+ return CueFileType.BINARY;
+ }
+ }
}
}
diff --git a/DICUI.Library/CueSheets/CueIndex.cs b/DICUI.Library/CueSheets/CueIndex.cs
index 3a418da6..9fcbecb6 100644
--- a/DICUI.Library/CueSheets/CueIndex.cs
+++ b/DICUI.Library/CueSheets/CueIndex.cs
@@ -1,7 +1,9 @@
-///
+using System.Linq;
+
+///
/// Information sourced from http://web.archive.org/web/20070221154246/http://www.goldenhawk.com/download/cdrwin.pdf
///
-namespace DICUI.Library.CueSheets
+namespace DICUI.CueSheets
{
///
/// Represents a single INDEX in a TRACK
@@ -9,25 +11,86 @@ namespace DICUI.Library.CueSheets
public class CueIndex
{
///
- /// number, between 0 and 99
+ /// INDEX number, between 0 and 99
///
public int Index { get; set; }
///
- /// Starting time of index in minutes
+ /// Starting time of INDEX in minutes
///
public int Minutes { get; set; }
///
- /// Starting time of index in seconds
+ /// Starting time of INDEX in seconds
///
/// There are 60 seconds in a minute
public int Seconds { get; set; }
///
- /// Starting time of index in frames.
+ /// Starting time of INDEX in frames.
///
/// There are 75 frames per second
public int Frames { get; set; }
+
+ ///
+ /// Create an empty INDEX
+ ///
+ public CueIndex()
+ {
+ }
+
+ ///
+ /// Fill a INDEX from a stream reader
+ ///
+ /// Index to set
+ /// Start time to set
+ public CueIndex(string index, string startTime)
+ {
+ // Set the current fields
+ if (!int.TryParse(index, out int parsedIndex))
+ return; // TODO: Make this throw an exception
+ else if (parsedIndex < 1 || parsedIndex > 99)
+ return; // TODO: Make this throw an exception
+
+ // Ignore empty lines
+ if (string.IsNullOrWhiteSpace(startTime))
+ return; // TODO: Make this throw an exception
+
+ // Ignore lines that don't contain the correct information
+ if (startTime.Length != 8 || startTime.Count(c => c == ':') != 2)
+ return; // TODO: Make this throw an exception
+
+ // Split the line
+ string[] splitTime = startTime.Split(':');
+ if (splitTime.Length != 3)
+ return; // TODO: Make this throw an exception
+
+ // Parse the lengths
+ int[] lengthSegments = new int[3];
+
+ // Minutes
+ if (!int.TryParse(splitTime[0], out lengthSegments[0]))
+ return; // TODO: Make this throw an exception
+ else if (lengthSegments[0] < 0)
+ return; // TODO: Make this throw an exception
+
+ // Seconds
+ if (!int.TryParse(splitTime[1], out lengthSegments[1]))
+ return; // TODO: Make this throw an exception
+ else if (lengthSegments[1] < 0 || lengthSegments[1] > 60)
+ return; // TODO: Make this throw an exception
+
+ // Frames
+ if (!int.TryParse(splitTime[2], out lengthSegments[2]))
+ return; // TODO: Make this throw an exception
+ else if (lengthSegments[2] < 0 || lengthSegments[2] > 75)
+ return; // TODO: Make this throw an exception
+
+ // Set the values
+ this.Index = parsedIndex;
+ this.Minutes = lengthSegments[0];
+ this.Seconds = lengthSegments[1];
+ this.Frames = lengthSegments[2];
+ }
}
}
diff --git a/DICUI.Library/CueSheets/CueSheet.cs b/DICUI.Library/CueSheets/CueSheet.cs
index 09ba08fe..952d1ad7 100644
--- a/DICUI.Library/CueSheets/CueSheet.cs
+++ b/DICUI.Library/CueSheets/CueSheet.cs
@@ -1,13 +1,11 @@
using System;
using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
+using System.IO;
///
/// Information sourced from http://web.archive.org/web/20070221154246/http://www.goldenhawk.com/download/cdrwin.pdf
///
-namespace DICUI.Library.CueSheets
+namespace DICUI.CueSheets
{
///
/// Represents a single cuesheet
@@ -43,5 +41,108 @@ namespace DICUI.Library.CueSheets
/// List of FILE in cuesheet
///
public List Files { get; set; }
+
+ ///
+ /// Create an empty cuesheet
+ ///
+ public CueSheet()
+ {
+ }
+
+ ///
+ /// Create a cuesheet from a file, if possible
+ ///
+ ///
+ public CueSheet(string filename)
+ {
+ // Check that the file exists
+ if (!File.Exists(filename))
+ return;
+
+ // Check the extension
+ string ext = Path.GetExtension(filename).TrimStart('.');
+ if (!string.Equals(ext, "cue", StringComparison.OrdinalIgnoreCase)
+ && !string.Equals(ext, "txt", StringComparison.OrdinalIgnoreCase))
+ {
+ return;
+ }
+
+ // Open the file and begin reading
+ using (var sr = new StreamReader(filename))
+ {
+ while (!sr.EndOfStream)
+ {
+ string line = sr.ReadLine().Trim();
+ string[] splitLine = line.Split(' ');
+
+ // If we have an empty line, we skip
+ if (string.IsNullOrWhiteSpace(line))
+ continue;
+
+ switch (splitLine[0])
+ {
+ // Read comments
+ case "REM":
+ // We ignore all comments for now
+ break;
+
+ // Read MCN
+ case "CATALOG":
+ if (splitLine.Length < 2)
+ continue; // TODO: Make this throw an exception
+
+ this.Catalog = splitLine[1];
+ break;
+
+ // Read external CD-Text file path
+ case "CDTEXTFILE":
+ if (splitLine.Length < 2)
+ continue; // TODO: Make this throw an exception
+
+ this.CdTextFile = splitLine[1];
+ break;
+
+ // Read CD-Text enhanced performer
+ case "PERFORMER":
+ if (splitLine.Length < 2)
+ continue; // TODO: Make this throw an exception
+
+ this.Performer = splitLine[1];
+ break;
+
+ // Read CD-Text enhanced songwriter
+ case "SONGWRITER":
+ if (splitLine.Length < 2)
+ continue; // TODO: Make this throw an exception
+
+ this.Songwriter = splitLine[1];
+ break;
+
+ // Read CD-Text enhanced title
+ case "TITLE":
+ if (splitLine.Length < 2)
+ continue; // TODO: Make this throw an exception
+
+ this.Title = splitLine[1];
+ break;
+
+ // Read file information
+ case "FILE":
+ if (splitLine.Length < 3)
+ continue; // TODO: Make this throw an exception
+
+ if (this.Files == null)
+ this.Files = new List();
+
+ var file = new CueFile(splitLine[1], splitLine[2], sr);
+ if (file == default)
+ continue; // TODO: Make this throw an exception
+
+ this.Files.Add(file);
+ break;
+ }
+ }
+ }
+ }
}
}
diff --git a/DICUI.Library/CueSheets/CueTrack.cs b/DICUI.Library/CueSheets/CueTrack.cs
index 2cc8d949..72b46cb3 100644
--- a/DICUI.Library/CueSheets/CueTrack.cs
+++ b/DICUI.Library/CueSheets/CueTrack.cs
@@ -1,10 +1,11 @@
using System;
using System.Collections.Generic;
+using System.IO;
///
/// Information sourced from http://web.archive.org/web/20070221154246/http://www.goldenhawk.com/download/cdrwin.pdf
///
-namespace DICUI.Library.CueSheets
+namespace DICUI.CueSheets
{
///
/// Track datatype
@@ -140,5 +141,215 @@ namespace DICUI.Library.CueSheets
/// POSTGAP
///
public PostGap PostGap { get; set; }
+
+ ///
+ /// Create an empty TRACK
+ ///
+ public CueTrack()
+ {
+ }
+
+ ///
+ /// Fill a TRACK from a stream reader
+ ///
+ /// Number to set
+ /// Data type to set
+ /// StreamReader to pull from
+ public CueTrack(string number, string dataType, StreamReader sr)
+ {
+ if (sr == null)
+ return;
+
+ // Set the current fields
+ if (!int.TryParse(number, out int parsedNumber))
+ return; // TODO: Make this throw an exception
+ else if (parsedNumber < 1 || parsedNumber > 99)
+ return; // TODO: Make this throw an exception
+
+ this.Number = parsedNumber;
+ this.DataType = GetDataType(dataType);
+
+ while (!sr.EndOfStream)
+ {
+ string line = sr.ReadLine().Trim();
+ string[] splitLine = line.Split(' ');
+
+ // If we have an empty line, we skip
+ if (string.IsNullOrWhiteSpace(line))
+ continue;
+
+ switch (splitLine[0])
+ {
+ // Read comments
+ case "REM":
+ // We ignore all comments for now
+ break;
+
+ // Read flag information
+ case "FLAGS":
+ if (splitLine.Length < 2)
+ continue; // TODO: Make this throw an exception
+
+ this.Flags = GetFlags(splitLine);
+ break;
+
+ // Read International Standard Recording Code
+ case "ISRC":
+ if (splitLine.Length < 2)
+ continue; // TODO: Make this throw an exception
+
+ this.ISRC = splitLine[1];
+ break;
+
+ // Read CD-Text enhanced performer
+ case "PERFORMER":
+ if (splitLine.Length < 2)
+ continue; // TODO: Make this throw an exception
+
+ this.Performer = splitLine[1];
+ break;
+
+ // Read CD-Text enhanced songwriter
+ case "SONGWRITER":
+ if (splitLine.Length < 2)
+ continue; // TODO: Make this throw an exception
+
+ this.Songwriter = splitLine[1];
+ break;
+
+ // Read CD-Text enhanced title
+ case "TITLE":
+ if (splitLine.Length < 2)
+ continue; // TODO: Make this throw an exception
+
+ this.Title = splitLine[1];
+ break;
+
+ // Read pregap information
+ case "PREGAP":
+ if (splitLine.Length < 2)
+ continue; // TODO: Make this throw an exception
+
+ var pregap = new PreGap(splitLine[1]);
+ if (pregap == default)
+ continue; // TODO: Make this throw an exception
+
+ this.PreGap = pregap;
+ break;
+
+ // Read index information
+ case "INDEX":
+ if (splitLine.Length < 3)
+ continue; // TODO: Make this throw an exception
+
+ if (this.Indices == null)
+ this.Indices = new List();
+
+ var index = new CueIndex(splitLine[1], splitLine[2]);
+ if (index == default)
+ continue; // TODO: Make this throw an exception
+
+ this.Indices.Add(index);
+ break;
+
+ // Read postgap information
+ case "POSTGAP":
+ if (splitLine.Length < 2)
+ continue; // TODO: Make this throw an exception
+
+ var postgap = new PostGap(splitLine[1]);
+ if (postgap == default)
+ continue; // TODO: Make this throw an exception
+
+ this.PostGap = postgap;
+ break;
+
+ // Default means return
+ default:
+ return;
+ }
+ }
+ }
+
+ ///
+ /// Get the data type from a given string
+ ///
+ /// String to get value from
+ /// CueTrackDataType, if possible (default AUDIO)
+ private CueTrackDataType GetDataType(string dataType)
+ {
+ switch (dataType.ToLowerInvariant())
+ {
+ case "audio":
+ return CueTrackDataType.AUDIO;
+
+ case "cdg":
+ return CueTrackDataType.CDG;
+
+ case "mode1/2048":
+ return CueTrackDataType.MODE1_2048;
+
+ case "mode1/2352":
+ return CueTrackDataType.MODE1_2352;
+
+ case "mode2/2336":
+ return CueTrackDataType.MODE2_2336;
+
+ case "mode2/2352":
+ return CueTrackDataType.MODE2_2352;
+
+ case "cdi/2336":
+ return CueTrackDataType.CDI_2336;
+
+ case "cdi/2352":
+ return CueTrackDataType.CDI_2352;
+
+ default:
+ return CueTrackDataType.AUDIO;
+ }
+ }
+
+ ///
+ /// Get the flag value for an array of strings
+ ///
+ /// Possible flags as strings
+ /// CueTrackFlag value representing the strings, if possible
+ private CueTrackFlag GetFlags(string[] flagStrings)
+ {
+ CueTrackFlag flag = 0;
+
+ foreach (string flagString in flagStrings)
+ {
+ // TODO: Make default throw an exception
+ switch (flagString.ToLowerInvariant())
+ {
+ case "flags":
+ // No-op since this is the start of the line
+ break;
+
+ case "dcp":
+ flag |= CueTrackFlag.DCP;
+ break;
+
+ case "4ch":
+ flag |= CueTrackFlag.FourCH;
+ break;
+
+ case "pre":
+ flag |= CueTrackFlag.PRE;
+ break;
+
+ case "scms":
+ flag |= CueTrackFlag.SCMS;
+ break;
+
+ case "data":
+ flag |= CueTrackFlag.DATA;
+ break;
+ }
+ }
+
+ return flag;
+ }
}
}
diff --git a/DICUI.Library/CueSheets/PostGap.cs b/DICUI.Library/CueSheets/PostGap.cs
index 07663cfa..e5c572b6 100644
--- a/DICUI.Library/CueSheets/PostGap.cs
+++ b/DICUI.Library/CueSheets/PostGap.cs
@@ -1,28 +1,82 @@
-///
+using System.Linq;
+
+///
/// Information sourced from http://web.archive.org/web/20070221154246/http://www.goldenhawk.com/download/cdrwin.pdf
///
-namespace DICUI.Library.CueSheets
+namespace DICUI.CueSheets
{
///
- /// Represents postgap information of a track
+ /// Represents POSTGAP information of a track
///
public class PostGap
{
///
- /// Length of postgap in minutes
+ /// Length of POSTGAP in minutes
///
public int Minutes { get; set; }
///
- /// Length of postgap in seconds
+ /// Length of POSTGAP in seconds
///
/// There are 60 seconds in a minute
public int Seconds { get; set; }
///
- /// Length of postgap in frames.
+ /// Length of POSTGAP in frames.
///
/// There are 75 frames per second
public int Frames { get; set; }
+
+ /// Create an empty POSTGAP
+ ///
+ public PostGap()
+ {
+ }
+
+ ///
+ /// Create a POSTGAP from a mm:ss:ff length
+ ///
+ /// String to get length information from
+ public PostGap(string length)
+ {
+ // Ignore empty lines
+ if (string.IsNullOrWhiteSpace(length))
+ return; // TODO: Make this throw an exception
+
+ // Ignore lines that don't contain the correct information
+ if (length.Length != 8 || length.Count(c => c == ':') != 2)
+ return; // TODO: Make this throw an exception
+
+ // Split the line
+ string[] splitLength = length.Split(':');
+ if (splitLength.Length != 3)
+ return; // TODO: Make this throw an exception
+
+ // Parse the lengths
+ int[] lengthSegments = new int[3];
+
+ // Minutes
+ if (!int.TryParse(splitLength[0], out lengthSegments[0]))
+ return; // TODO: Make this throw an exception
+ else if (lengthSegments[0] < 0)
+ return; // TODO: Make this throw an exception
+
+ // Seconds
+ if (!int.TryParse(splitLength[1], out lengthSegments[1]))
+ return; // TODO: Make this throw an exception
+ else if (lengthSegments[1] < 0 || lengthSegments[1] > 60)
+ return; // TODO: Make this throw an exception
+
+ // Frames
+ if (!int.TryParse(splitLength[2], out lengthSegments[2]))
+ return; // TODO: Make this throw an exception
+ else if (lengthSegments[2] < 0 || lengthSegments[2] > 75)
+ return; // TODO: Make this throw an exception
+
+ // Set the values
+ this.Minutes = lengthSegments[0];
+ this.Seconds = lengthSegments[1];
+ this.Frames = lengthSegments[2];
+ }
}
}
diff --git a/DICUI.Library/CueSheets/PreGap.cs b/DICUI.Library/CueSheets/PreGap.cs
index 219fee53..0cd65e42 100644
--- a/DICUI.Library/CueSheets/PreGap.cs
+++ b/DICUI.Library/CueSheets/PreGap.cs
@@ -1,28 +1,83 @@
-///
+using System.Linq;
+
+///
/// Information sourced from http://web.archive.org/web/20070221154246/http://www.goldenhawk.com/download/cdrwin.pdf
///
-namespace DICUI.Library.CueSheets
+namespace DICUI.CueSheets
{
///
- /// Represents pregap information of a track
+ /// Represents PREGAP information of a track
///
public class PreGap
{
///
- /// Length of postgap in minutes
+ /// Length of PREGAP in minutes
///
public int Minutes { get; set; }
///
- /// Length of postgap in seconds
+ /// Length of PREGAP in seconds
///
/// There are 60 seconds in a minute
public int Seconds { get; set; }
///
- /// Length of postgap in frames.
+ /// Length of PREGAP in frames.
///
/// There are 75 frames per second
public int Frames { get; set; }
+
+ ///
+ /// Create an empty PREGAP
+ ///
+ public PreGap()
+ {
+ }
+
+ ///
+ /// Create a PREGAP from a mm:ss:ff length
+ ///
+ /// String to get length information from
+ public PreGap(string length)
+ {
+ // Ignore empty lines
+ if (string.IsNullOrWhiteSpace(length))
+ return; // TODO: Make this throw an exception
+
+ // Ignore lines that don't contain the correct information
+ if (length.Length != 8 || length.Count(c => c == ':') != 2)
+ return; // TODO: Make this throw an exception
+
+ // Split the line
+ string[] splitLength = length.Split(':');
+ if (splitLength.Length != 3)
+ return; // TODO: Make this throw an exception
+
+ // Parse the lengths
+ int[] lengthSegments = new int[3];
+
+ // Minutes
+ if (!int.TryParse(splitLength[0], out lengthSegments[0]))
+ return; // TODO: Make this throw an exception
+ else if (lengthSegments[0] < 0)
+ return; // TODO: Make this throw an exception
+
+ // Seconds
+ if (!int.TryParse(splitLength[1], out lengthSegments[1]))
+ return; // TODO: Make this throw an exception
+ else if (lengthSegments[1] < 0 || lengthSegments[1] > 60)
+ return; // TODO: Make this throw an exception
+
+ // Frames
+ if (!int.TryParse(splitLength[2], out lengthSegments[2]))
+ return; // TODO: Make this throw an exception
+ else if (lengthSegments[2] < 0 || lengthSegments[2] > 75)
+ return; // TODO: Make this throw an exception
+
+ // Set the values
+ this.Minutes = lengthSegments[0];
+ this.Seconds = lengthSegments[1];
+ this.Frames = lengthSegments[2];
+ }
}
}