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 MPF.CueSheets { /// /// The audio or data file’s filetype /// public enum CueFileType { /// /// Intel binary file (least significant byte first). Use for data files. /// BINARY, /// /// Motorola binary file (most significant byte first). Use for data files. /// MOTOROLA, /// /// Audio AIFF file (44.1KHz 16-bit stereo) /// AIFF, /// /// Audio WAVE file (44.1KHz 16-bit stereo) /// WAVE, /// /// Audio MP3 file (44.1KHz 16-bit stereo) /// MP3, } /// /// Represents a single FILE in a cuesheet /// public class CueFile { /// /// filename /// public string FileName { get; set; } /// /// filetype /// public CueFileType FileType { get; set; } /// /// List of TRACK in FILE /// public List Tracks { get; set; } /// /// Create an empty FILE /// public CueFile() { } /// /// Fill a FILE from an array of lines /// /// File name to set /// File type to set /// Lines array to pull from /// Reference to index in array /// True if errors throw an exception, false otherwise public CueFile(string fileName, string fileType, string[] cueLines, ref int i, bool throwOnError = false) { if (cueLines == null) { if (throwOnError) throw new ArgumentNullException(nameof(cueLines)); return; } else if (i < 0 || i > cueLines.Length) { if (throwOnError) throw new IndexOutOfRangeException(); return; } // Set the current fields this.FileName = fileName.Trim('"'); this.FileType = GetFileType(fileType); // Increment to start i++; for (; i < cueLines.Length; i++) { string line = cueLines[i].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) { if (throwOnError) throw new FormatException($"TRACK line malformed: {line}"); continue; } if (this.Tracks == null) this.Tracks = new List(); var track = new CueTrack(splitLine[1], splitLine[2], cueLines, ref i); if (track == default) { if (throwOnError) throw new FormatException($"TRACK line malformed: {line}"); continue; } this.Tracks.Add(track); break; // Default means return default: i--; return; } } } /// /// Write the FILE out to a stream /// /// StreamWriter to write to /// True if errors throw an exception, false otherwise public void Write(StreamWriter sw, bool throwOnError = false) { // If we don't have any tracks, it's invalid if (this.Tracks == null) { if (throwOnError) throw new ArgumentNullException(nameof(this.Tracks)); return; } else if (this.Tracks.Count == 0) { if (throwOnError) throw new ArgumentException("No tracks provided to write"); return; } sw.WriteLine($"FILE \"{this.FileName}\" {FromFileType(this.FileType)}"); foreach (var track in Tracks) { track.Write(sw); } } /// /// Get the file type from a given string /// /// String to get value from /// CueFileType, if possible 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; } } /// /// Get the string from a given file type /// /// CueFileType to get value from /// String, if possible (default BINARY) private string FromFileType(CueFileType fileType) { switch (fileType) { case CueFileType.BINARY: return "BINARY"; case CueFileType.MOTOROLA: return "MOTOROLA"; case CueFileType.AIFF: return "AIFF"; case CueFileType.WAVE: return "WAVE"; case CueFileType.MP3: return "MP3"; default: return string.Empty; } } } }