/*
Title: CueSharp
Version: 0.5
Released: March 24, 2007
Author: Wyatt O'Day
Website: wyday.com/cuesharp
*/
// MK: fixes to substring processing
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace CueSharp_N
{
///
/// A CueSheet class used to create, open, edit, and save cuesheets.
///
public class CueSheet
{
#region Private Variables
private string[] cueLines;
private string m_Catalog = "";
private string m_CDTextFile = "";
private string[] m_Comments = new string[0];
// strings that don't belong or were mistyped in the global part of the cue
private string[] m_Garbage = new string[0];
private string m_Performer = "";
private string m_Songwriter = "";
private string m_Title = "";
private Track[] m_Tracks = new Track[0];
#endregion Private Variables
#region Properties
///
/// Returns/Sets track in this cuefile.
///
/// The track in this cuefile.
/// Track at the tracknumber.
public Track this[int tracknumber]
{
get { return m_Tracks[tracknumber]; }
set { m_Tracks[tracknumber] = value; }
}
///
/// The catalog number must be 13 digits long and is encoded according to UPC/EAN rules.
/// Example: CATALOG 1234567890123
///
public string Catalog
{
get { return m_Catalog; }
set { m_Catalog = value; }
}
///
/// This command is used to specify the name of the file that contains the encoded CD-TEXT information for the disc. This command is only used with files that were either created with the graphical CD-TEXT editor or generated automatically by the software when copying a CD-TEXT enhanced disc.
///
public string CDTextFile
{
get { return m_CDTextFile; }
set { m_CDTextFile = value; }
}
///
/// This command is used to put comments in your CUE SHEET file.
///
public string[] Comments
{
get { return m_Comments; }
set { m_Comments = value; }
}
///
/// Lines in the cue file that don't belong or have other general syntax errors.
///
public string[] Garbage
{
get { return m_Garbage; }
}
///
/// This command is used to specify the name of a perfomer for a CD-TEXT enhanced disc.
///
public string Performer
{
get { return m_Performer; }
set { m_Performer = value; }
}
///
/// This command is used to specify the name of a songwriter for a CD-TEXT enhanced disc.
///
public string Songwriter
{
get { return m_Songwriter; }
set { m_Songwriter = value; }
}
///
/// The title of the entire disc as a whole.
///
public string Title
{
get { return m_Title; }
set { m_Title = value; }
}
///
/// The array of tracks on the cuesheet.
///
public Track[] Tracks
{
get { return m_Tracks; }
set { m_Tracks = value; }
}
#endregion Properties
#region Constructors
///
/// Create a cue sheet from scratch.
///
public CueSheet()
{ }
///
/// Parse a cue sheet string.
///
/// A string containing the cue sheet data.
/// Line delimeters; set to "(char[])null" for default delimeters.
public CueSheet(string cueString, char[] lineDelims)
{
if (lineDelims == null)
{
lineDelims = new char[] { '\n' };
}
cueLines = RemoveEmptyLines(cueString.Split(lineDelims));
ParseCue(cueLines);
}
///
/// Parses a cue sheet file.
///
/// The filename for the cue sheet to open.
public CueSheet(string cuefilename)
{
ReadCueSheet(cuefilename, Encoding.Default);
}
///
/// Parses a cue sheet file.
///
/// The filename for the cue sheet to open.
/// The encoding used to open the file.
public CueSheet(string cuefilename, Encoding encoding)
{
ReadCueSheet(cuefilename, encoding);
}
///
/// Parses a cue sheet file.
///
/// The text stream for the cue sheet to read.
public CueSheet(StreamReader file)
{
ReadCueSheet(file);
}
private void ReadCueSheet(StreamReader file)
{
// array of delimiters to split the sentence with
char[] delimiters = new char[] { '\n' };
//read in file
cueLines = RemoveEmptyLines(file.ReadToEnd().Split(delimiters));
ParseCue(cueLines);
}
private void ReadCueSheet(string filename, Encoding encoding)
{
// array of delimiters to split the sentence with
char[] delimiters = new char[] { '\n' };
// read in the full cue file
using (TextReader tr = new StreamReader(filename, encoding))
{
//read in file
cueLines = RemoveEmptyLines(tr.ReadToEnd().Split(delimiters));
}
ParseCue(cueLines);
}
#endregion Constructors
#region Methods
///
/// Trims leading and trailing spaces, removes any empty lines, elimating possible trouble.
///
///
private string[] RemoveEmptyLines(string[] file)
{
return file.Select(line => line.Trim()).Where(line => line != string.Empty).ToArray();
}
private void ParseCue(string[] file)
{
//-1 means still global,
//all others are track specific
int trackOn = -1;
AudioFile currentFile = new AudioFile();
foreach (var line in file)
{
var kv = SplitLine(line);
switch (kv.Key)
{
case "CATALOG":
ParseString(kv.Key, kv.Value, trackOn);
break;
case "CDTEXTFILE":
ParseString(kv.Key, kv.Value, trackOn);
break;
case "FILE":
currentFile = ParseFile(kv.Value, trackOn);
break;
case "FLAGS":
ParseFlags(line, trackOn);
break;
case "INDEX":
ParseIndex(kv.Key, kv.Value, trackOn);
break;
case "ISRC":
ParseString(kv.Key, kv.Value, trackOn);
break;
case "PERFORMER":
ParseString(kv.Key, kv.Value, trackOn);
break;
case "POSTGAP":
ParseIndex(kv.Key, kv.Value, trackOn);
break;
case "PREGAP":
ParseIndex(kv.Key, kv.Value, trackOn);
break;
case "REM":
ParseComment(kv.Value, trackOn);
break;
case "SONGWRITER":
ParseString(kv.Key, kv.Value, trackOn);
break;
case "TITLE":
ParseString(kv.Key, kv.Value, trackOn);
break;
case "TRACK":
trackOn++;
ParseTrack(kv.Value, trackOn);
if (currentFile.Filename != "") //if there's a file
{
m_Tracks[trackOn].DataFile = currentFile;
currentFile = new AudioFile();
}
break;
default:
ParseGarbage(line, trackOn);
//save discarded junk and place string[] with track it was found in
break;
}
}
}
private void ParseComment(string line, int trackOn)
{
// "REM" already removed
if (trackOn == -1)
{
if (line.Trim() != "")
{
m_Comments = (string[])ResizeArray(m_Comments, m_Comments.Length + 1);
m_Comments[m_Comments.Length - 1] = line;
}
}
else
{
m_Tracks[trackOn].AddComment(line);
}
}
private AudioFile ParseFile(string line, int trackOn)
{
string fileType = line.Substring(line.LastIndexOf(' '), line.Length - line.LastIndexOf(' ')).Trim();
line = line.Substring(0, line.LastIndexOf(' ')).Trim();
//if quotes around it, remove them.
if (line[0] == '"')
{
line = line.Substring(1, line.LastIndexOf('"') - 1);
}
return new AudioFile(line, fileType);
}
private void ParseFlags(string line, int trackOn)
{
string temp;
if (trackOn != -1)
{
line = line.Trim();
if (line != "")
{
var pos = line.IndexOf(' ');
temp = (pos >= 0 ? line.Substring(0, pos) : line).ToUpper();
switch (temp)
{
case "FLAGS":
m_Tracks[trackOn].AddFlag(temp);
break;
case "DATA":
m_Tracks[trackOn].AddFlag(temp);
break;
case "DCP":
m_Tracks[trackOn].AddFlag(temp);
break;
case "4CH":
m_Tracks[trackOn].AddFlag(temp);
break;
case "PRE":
m_Tracks[trackOn].AddFlag(temp);
break;
case "SCMS":
m_Tracks[trackOn].AddFlag(temp);
break;
default:
break;
}
temp = pos >= 0 ? line.Substring(pos, line.Length - pos) : line;
//if the flag hasn't already been processed
if (temp.ToUpper().Trim() != line.ToUpper().Trim())
{
ParseFlags(temp, trackOn);
}
}
}
}
private void ParseGarbage(string line, int trackOn)
{
if (trackOn == -1)
{
if (line.Trim() != "")
{
m_Garbage = (string[])ResizeArray(m_Garbage, m_Garbage.Length + 1);
m_Garbage[m_Garbage.Length - 1] = line;
}
}
else
{
m_Tracks[trackOn].AddGarbage(line);
}
}
private void ParseIndex(string indexType, string value, int trackOn)
{
string tempString;
int number = 0;
int minutes;
int seconds;
int frames;
tempString = value;
if (indexType == "INDEX")
{
//read the index number
number = Convert.ToInt32(tempString.Substring(0, tempString.IndexOf(' ')));
tempString = tempString.Substring(tempString.IndexOf(' '), tempString.Length - tempString.IndexOf(' ')).Trim();
}
//extract the minutes, seconds, and frames
minutes = Convert.ToInt32(tempString.Substring(0, tempString.IndexOf(':')));
seconds = Convert.ToInt32(tempString.Substring(tempString.IndexOf(':') + 1, tempString.LastIndexOf(':') - tempString.IndexOf(':') - 1));
frames = Convert.ToInt32(tempString.Substring(tempString.LastIndexOf(':') + 1, tempString.Length - tempString.LastIndexOf(':') - 1));
if (indexType == "INDEX")
{
m_Tracks[trackOn].AddIndex(number, minutes, seconds, frames);
}
else if (indexType == "PREGAP")
{
m_Tracks[trackOn].PreGap = new Index(0, minutes, seconds, frames);
}
else if (indexType == "POSTGAP")
{
m_Tracks[trackOn].PostGap = new Index(0, minutes, seconds, frames);
}
}
private void ParseString(string category, string line, int trackOn)
{
//get rid of the quotes
if (line[0] == '"')
{
line = line.Substring(1, line.LastIndexOf('"') - 1);
}
switch (category)
{
case "CATALOG":
if (trackOn == -1)
{
this.m_Catalog = line;
}
break;
case "CDTEXTFILE":
if (trackOn == -1)
{
this.m_CDTextFile = line;
}
break;
case "ISRC":
if (trackOn != -1)
{
m_Tracks[trackOn].ISRC = line;
}
break;
case "PERFORMER":
if (trackOn == -1)
{
this.m_Performer = line;
}
else
{
m_Tracks[trackOn].Performer = line;
}
break;
case "SONGWRITER":
if (trackOn == -1)
{
this.m_Songwriter = line;
}
else
{
m_Tracks[trackOn].Songwriter = line;
}
break;
case "TITLE":
if (trackOn == -1)
{
this.m_Title = line;
}
else
{
m_Tracks[trackOn].Title = line;
}
break;
default:
break;
}
}
///
/// Parses the TRACK command.
///
/// The line in the cue file that contains the TRACK command with TRACK part removed.
/// The track currently processing.
private void ParseTrack(string value, int trackOn)
{
string tempString;
int trackNumber;
tempString = value;
try
{
trackNumber = Convert.ToInt32(tempString.Substring(0, tempString.IndexOf(' ')));
}
catch (Exception)
{ throw; }
//find the data type.
tempString = tempString.Substring(tempString.IndexOf(' '), tempString.Length - tempString.IndexOf(' ')).Trim();
AddTrack(trackNumber, tempString);
}
///
/// Reallocates an array with a new size, and copies the contents
/// of the old array to the new array.
///
/// The old array, to be reallocated.
/// The new array size.
/// A new array with the same contents.
/// Useage: int[] a = {1,2,3}; a = (int[])ResizeArray(a,5);
public static System.Array ResizeArray(System.Array oldArray, int newSize)
{
int oldSize = oldArray.Length;
System.Type elementType = oldArray.GetType().GetElementType();
System.Array newArray = System.Array.CreateInstance(elementType, newSize);
int preserveLength = System.Math.Min(oldSize, newSize);
if (preserveLength > 0)
System.Array.Copy(oldArray, newArray, preserveLength);
return newArray;
}
///
/// Add a track to the current cuesheet.
///
/// The number of the said track.
/// The datatype of the track.
private void AddTrack(int tracknumber, string datatype)
{
m_Tracks = (Track[])ResizeArray(m_Tracks, m_Tracks.Length + 1);
m_Tracks[m_Tracks.Length - 1] = new Track(tracknumber, datatype);
}
///
/// Add a track to the current cuesheet
///
/// The title of the track.
/// The performer of this track.
public void AddTrack(string title, string performer)
{
m_Tracks = (Track[])ResizeArray(m_Tracks, m_Tracks.Length + 1);
m_Tracks[m_Tracks.Length - 1] = new Track(m_Tracks.Length, "");
m_Tracks[m_Tracks.Length - 1].Performer = performer;
m_Tracks[m_Tracks.Length - 1].Title = title;
}
public void AddTrack(string title, string performer, string filename, FileType fType)
{
m_Tracks = (Track[])ResizeArray(m_Tracks, m_Tracks.Length + 1);
m_Tracks[m_Tracks.Length - 1] = new Track(m_Tracks.Length, "");
m_Tracks[m_Tracks.Length - 1].Performer = performer;
m_Tracks[m_Tracks.Length - 1].Title = title;
m_Tracks[m_Tracks.Length - 1].DataFile = new AudioFile(filename, fType);
}
///
/// Add a track to the current cuesheet
///
/// The title of the track.
/// The performer of this track.
/// The datatype for the track (typically DataType.Audio)
public void AddTrack(string title, string performer, DataType datatype)
{
m_Tracks = (Track[])ResizeArray(m_Tracks, m_Tracks.Length + 1);
m_Tracks[m_Tracks.Length - 1] = new Track(m_Tracks.Length, datatype);
m_Tracks[m_Tracks.Length - 1].Performer = performer;
m_Tracks[m_Tracks.Length - 1].Title = title;
}
///
/// Add a track to the current cuesheet
///
/// Track object to add to the cuesheet.
public void AddTrack(Track track)
{
m_Tracks = (Track[])ResizeArray(m_Tracks, m_Tracks.Length + 1);
m_Tracks[m_Tracks.Length - 1] = track;
}
///
/// Remove a track from the cuesheet.
///
/// The index of the track you wish to remove.
public void RemoveTrack(int trackIndex)
{
for (int i = trackIndex; i < m_Tracks.Length - 1; i++)
{
m_Tracks[i] = m_Tracks[i + 1];
}
m_Tracks = (Track[])ResizeArray(m_Tracks, m_Tracks.Length - 1);
}
///
/// Add index information to an existing track.
///
/// The array index number of track to be modified
/// The index number of the new index
/// The minute value of the new index
/// The seconds value of the new index
/// The frames value of the new index
public void AddIndex(int trackIndex, int indexNum, int minutes, int seconds, int frames)
{
m_Tracks[trackIndex].AddIndex(indexNum, minutes, seconds, frames);
}
///
/// Remove an index from a track.
///
/// The array-index of the track.
/// The index of the Index you wish to remove.
public void RemoveIndex(int trackIndex, int indexIndex)
{
//Note it is the index of the Index you want to delete,
//which may or may not correspond to the number of the index.
m_Tracks[trackIndex].RemoveIndex(indexIndex);
}
///
/// Save the cue sheet file to specified location.
///
/// Filename of destination cue sheet file.
public void SaveCue(string filename)
{
SaveCue(filename, Encoding.Default);
}
///
/// Save the cue sheet file to specified location.
///
/// Filename of destination cue sheet file.
/// The encoding used to save the file.
public void SaveCue(string filename, Encoding encoding)
{
using (TextWriter tw = new StreamWriter(filename, false, encoding))
tw.WriteLine(this.ToString());
}
///
/// Method to output the cuesheet into a single formatted string.
///
/// The entire cuesheet formatted to specification.
public override string ToString()
{
StringBuilder output = new StringBuilder();
foreach (string comment in m_Comments)
{
output.Append("REM " + comment + Environment.NewLine);
}
if (m_Catalog.Trim() != "")
{
output.Append("CATALOG " + m_Catalog + Environment.NewLine);
}
if (m_Performer.Trim() != "")
{
output.Append("PERFORMER \"" + m_Performer + "\"" + Environment.NewLine);
}
if (m_Songwriter.Trim() != "")
{
output.Append("SONGWRITER \"" + m_Songwriter + "\"" + Environment.NewLine);
}
if (m_Title.Trim() != "")
{
output.Append("TITLE \"" + m_Title + "\"" + Environment.NewLine);
}
if (m_CDTextFile.Trim() != "")
{
output.Append("CDTEXTFILE \"" + m_CDTextFile.Trim() + "\"" + Environment.NewLine);
}
for (int i = 0; i < m_Tracks.Length; i++)
{
output.Append(m_Tracks[i].ToString());
if (i != m_Tracks.Length - 1)
{
//add line break for each track except last
output.Append(Environment.NewLine);
}
}
return output.ToString();
}
#endregion Methods
// split input line at the first space into two parts: UPPERCASE keyword and content,
// when there are no spaces entire line is a keyword
private static KeyValuePair SplitLine(string line)
{
var pos = line.IndexOf(' ');
// lines have been trimmed, so no leading/trailing spaces are expected here
if (pos > 0)
return new KeyValuePair(line.Substring(0, pos).ToUpper(), line.Substring(pos + 1));
else
return new KeyValuePair(line.ToUpper(), string.Empty);
}
}
///
/// DCP - Digital copy permitted
/// 4CH - Four channel audio
/// PRE - Pre-emphasis enabled (audio tracks only)
/// SCMS - Serial copy management system (not supported by all recorders)
/// There is a fourth subcode flag called "DATA" which is set for all non-audio tracks. This flag is set automatically based on the datatype of the track.
///
public enum Flags
{
DCP, CH4, PRE, SCMS, DATA, NONE
}
///
/// BINARY - Intel binary file (least significant byte first)
/// MOTOROLA - Motorola binary file (most significant byte first)
/// AIFF - Audio AIFF file
/// WAVE - Audio WAVE file
/// MP3 - Audio MP3 file
///
public enum FileType
{
BINARY, MOTOROLA, AIFF, WAVE, MP3
}
///
///
/// - AUDIO - Audio/Music (2352)
/// - CDG - Karaoke CD+G (2448)
/// - MODE1/2048 - CDROM Mode1 Data (cooked)
/// - MODE1/2352 - CDROM Mode1 Data (raw)
/// - MODE2/2336 - CDROM-XA Mode2 Data
/// - MODE2/2352 - CDROM-XA Mode2 Data
/// - CDI/2336 - CDI Mode2 Data
/// - CDI/2352 - CDI Mode2 Data
///
///
public enum DataType
{
AUDIO, CDG, MODE1_2048, MODE1_2352, MODE2_2336, MODE2_2352, CDI_2336, CDI_2352
}
///
/// This command is used to specify indexes (or subindexes) within a track.
/// Syntax:
/// INDEX [number] [mm:ss:ff]
///
public struct Index
{
//0-99
private int m_number;
private int m_minutes;
private int m_seconds;
private int m_frames;
///
/// Index number (0-99)
///
public int Number
{
get { return m_number; }
set
{
if (value > 99)
{
m_number = 99;
}
else if (value < 0)
{
m_number = 0;
}
else
{
m_number = value;
}
}
}
///
/// Possible values: 0-99
///
public int Minutes
{
get { return m_minutes; }
set
{
if (value > 99)
{
m_minutes = 99;
}
else if (value < 0)
{
m_minutes = 0;
}
else
{
m_minutes = value;
}
}
}
///
/// Possible values: 0-59
/// There are 60 seconds/minute
///
public int Seconds
{
get { return m_seconds; }
set
{
if (value >= 60)
{
m_seconds = 59;
}
else if (value < 0)
{
m_seconds = 0;
}
else
{
m_seconds = value;
}
}
}
///
/// Possible values: 0-74
/// There are 75 frames/second
///
public int Frames
{
get { return m_frames; }
set
{
if (value >= 75)
{
m_frames = 74;
}
else if (value < 0)
{
m_frames = 0;
}
else
{
m_frames = value;
}
}
}
///
/// The Index of a track.
///
/// Index number 0-99
/// Minutes (0-99)
/// Seconds (0-59)
/// Frames (0-74)
public Index(int number, int minutes, int seconds, int frames)
{
m_number = number;
m_minutes = minutes;
m_seconds = seconds;
m_frames = frames;
}
}
///
/// This command is used to specify a data/audio file that will be written to the recorder.
///
public struct AudioFile
{
private string m_Filename;
private FileType m_Filetype;
public string Filename
{
get { return m_Filename; }
set { m_Filename = value; }
}
///
/// BINARY - Intel binary file (least significant byte first)
/// MOTOROLA - Motorola binary file (most significant byte first)
/// AIFF - Audio AIFF file
/// WAVE - Audio WAVE file
/// MP3 - Audio MP3 file
///
public FileType Filetype
{
get { return m_Filetype; }
set { m_Filetype = value; }
}
public AudioFile(string filename, string filetype)
{
m_Filename = filename;
switch (filetype.Trim().ToUpper())
{
case "BINARY":
m_Filetype = FileType.BINARY;
break;
case "MOTOROLA":
m_Filetype = FileType.MOTOROLA;
break;
case "AIFF":
m_Filetype = FileType.AIFF;
break;
case "WAVE":
m_Filetype = FileType.WAVE;
break;
case "MP3":
m_Filetype = FileType.MP3;
break;
default:
m_Filetype = FileType.BINARY;
break;
}
}
public AudioFile(string filename, FileType filetype)
{
m_Filename = filename;
m_Filetype = filetype;
}
}
///
/// Track that contains either data or audio. It can contain Indices and comment information.
///
public class Track
{
#region Private Variables
private string[] m_Comments;
// strings that don't belong or were mistyped in the global part of the cue
private AudioFile m_DataFile;
private string[] m_Garbage;
private Index[] m_Indices;
private string m_ISRC;
private string m_Performer;
private Index m_PostGap;
private Index m_PreGap;
private string m_Songwriter;
private string m_Title;
private Flags[] m_TrackFlags;
private DataType m_TrackDataType;
private int m_TrackNumber;
#endregion Private Variables
#region Properties
///
/// Returns/Sets Index in this track.
///
/// Index in the track.
/// Index at indexnumber.
public Index this[int indexnumber]
{
get
{
return m_Indices[indexnumber];
}
set
{
m_Indices[indexnumber] = value;
}
}
public string[] Comments
{
get { return m_Comments; }
set { m_Comments = value; }
}
public AudioFile DataFile
{
get { return m_DataFile; }
set { m_DataFile = value; }
}
///
/// Lines in the cue file that don't belong or have other general syntax errors.
///
public string[] Garbage
{
get { return m_Garbage; }
set { m_Garbage = value; }
}
public Index[] Indices
{
get { return m_Indices; }
set { m_Indices = value; }
}
public string ISRC
{
get { return m_ISRC; }
set { m_ISRC = value; }
}
public string Performer
{
get { return m_Performer; }
set { m_Performer = value; }
}
public Index PostGap
{
get { return m_PostGap; }
set { m_PostGap = value; }
}
public Index PreGap
{
get { return m_PreGap; }
set { m_PreGap = value; }
}
public string Songwriter
{
get { return m_Songwriter; }
set { m_Songwriter = value; }
}
///
/// If the TITLE command appears before any TRACK commands, then the string will be encoded as the title of the entire disc.
///
public string Title
{
get { return m_Title; }
set { m_Title = value; }
}
public DataType TrackDataType
{
get { return m_TrackDataType; }
set { m_TrackDataType = value; }
}
public Flags[] TrackFlags
{
get { return m_TrackFlags; }
set { m_TrackFlags = value; }
}
public int TrackNumber
{
get { return m_TrackNumber; }
set { m_TrackNumber = value; }
}
#endregion Properties
#region Contructors
public Track(int tracknumber, string datatype)
{
m_TrackNumber = tracknumber;
switch (datatype.Trim().ToUpper())
{
case "AUDIO":
m_TrackDataType = DataType.AUDIO;
break;
case "CDG":
m_TrackDataType = DataType.CDG;
break;
case "MODE1/2048":
m_TrackDataType = DataType.MODE1_2048;
break;
case "MODE1/2352":
m_TrackDataType = DataType.MODE1_2352;
break;
case "MODE2/2336":
m_TrackDataType = DataType.MODE2_2336;
break;
case "MODE2/2352":
m_TrackDataType = DataType.MODE2_2352;
break;
case "CDI/2336":
m_TrackDataType = DataType.CDI_2336;
break;
case "CDI/2352":
m_TrackDataType = DataType.CDI_2352;
break;
default:
m_TrackDataType = DataType.AUDIO;
break;
}
m_TrackFlags = new Flags[0];
m_Songwriter = "";
m_Title = "";
m_ISRC = "";
m_Performer = "";
m_Indices = new Index[0];
m_Garbage = new string[0];
m_Comments = new string[0];
m_PreGap = new Index(-1, 0, 0, 0);
m_PostGap = new Index(-1, 0, 0, 0);
m_DataFile = new AudioFile();
}
public Track(int tracknumber, DataType datatype)
{
m_TrackNumber = tracknumber;
m_TrackDataType = datatype;
m_TrackFlags = new Flags[0];
m_Songwriter = "";
m_Title = "";
m_ISRC = "";
m_Performer = "";
m_Indices = new Index[0];
m_Garbage = new string[0];
m_Comments = new string[0];
m_PreGap = new Index(-1, 0, 0, 0);
m_PostGap = new Index(-1, 0, 0, 0);
m_DataFile = new AudioFile();
}
#endregion Contructors
#region Methods
public void AddFlag(Flags flag)
{
//if it's not a none tag
//and if the tags hasn't already been added
if (flag != Flags.NONE && NewFlag(flag) == true)
{
m_TrackFlags = (Flags[])CueSheet.ResizeArray(m_TrackFlags, m_TrackFlags.Length + 1);
m_TrackFlags[m_TrackFlags.Length - 1] = flag;
}
}
public void AddFlag(string flag)
{
switch (flag.Trim().ToUpper())
{
case "DATA":
AddFlag(Flags.DATA);
break;
case "DCP":
AddFlag(Flags.DCP);
break;
case "4CH":
AddFlag(Flags.CH4);
break;
case "PRE":
AddFlag(Flags.PRE);
break;
case "SCMS":
AddFlag(Flags.SCMS);
break;
default:
return;
}
}
public void AddGarbage(string garbage)
{
if (garbage.Trim() != "")
{
m_Garbage = (string[])CueSheet.ResizeArray(m_Garbage, m_Garbage.Length + 1);
m_Garbage[m_Garbage.Length - 1] = garbage;
}
}
public void AddComment(string comment)
{
if (comment.Trim() != "")
{
m_Comments = (string[])CueSheet.ResizeArray(m_Comments, m_Comments.Length + 1);
m_Comments[m_Comments.Length - 1] = comment;
}
}
public void AddIndex(int number, int minutes, int seconds, int frames)
{
m_Indices = (Index[])CueSheet.ResizeArray(m_Indices, m_Indices.Length + 1);
m_Indices[m_Indices.Length - 1] = new Index(number, minutes, seconds, frames);
}
public void RemoveIndex(int indexIndex)
{
for (int i = indexIndex; i < m_Indices.Length - 1; i++)
{
m_Indices[i] = m_Indices[i + 1];
}
m_Indices = (Index[])CueSheet.ResizeArray(m_Indices, m_Indices.Length - 1);
}
public TimeSpan Offset
{
get
{
if (m_Indices.Length == 0)
return TimeSpan.Zero;
var index = Indices.Length > 1 ? Indices[1] : Indices[0];
return new TimeSpan(0, 0, index.Minutes, index.Seconds, index.Frames * 1000 / 75);
}
}
///
/// Checks if the flag is indeed new in this track.
///
/// The new flag to be added to the track.
/// True if this flag doesn't already exist.
private bool NewFlag(Flags new_flag)
{
foreach (Flags flag in m_TrackFlags)
{
if (flag == new_flag)
{
return false;
}
}
return true;
}
///
/// CueSheet string representation for debugging purposes
///
///
public override string ToString()
{
StringBuilder output = new StringBuilder();
//write file
if (m_DataFile.Filename != null && m_DataFile.Filename.Trim() != "")
{
output.Append("FILE \"" + m_DataFile.Filename.Trim() + "\" " + m_DataFile.Filetype.ToString() + Environment.NewLine);
}
output.Append(" TRACK " + m_TrackNumber.ToString().PadLeft(2, '0') + " " + m_TrackDataType.ToString().Replace('_', '/'));
//write comments
foreach (string comment in m_Comments)
{
output.Append(Environment.NewLine + " REM " + comment);
}
if (m_Performer.Trim() != "")
{
output.Append(Environment.NewLine + " PERFORMER \"" + m_Performer + "\"");
}
if (m_Songwriter.Trim() != "")
{
output.Append(Environment.NewLine + " SONGWRITER \"" + m_Songwriter + "\"");
}
if (m_Title.Trim() != "")
{
output.Append(Environment.NewLine + " TITLE \"" + m_Title + "\"");
}
//write flags
if (m_TrackFlags.Length > 0)
{
output.Append(Environment.NewLine + " FLAGS");
}
foreach (Flags flag in m_TrackFlags)
{
output.Append(" " + flag.ToString().Replace("CH4", "4CH"));
}
//write isrc
if (m_ISRC.Trim() != "")
{
output.Append(Environment.NewLine + " ISRC " + m_ISRC.Trim());
}
//write pregap
if (m_PreGap.Number != -1)
{
output.Append(Environment.NewLine + " PREGAP " + m_PreGap.Minutes.ToString().PadLeft(2, '0') + ":" + m_PreGap.Seconds.ToString().PadLeft(2, '0') + ":" + m_PreGap.Frames.ToString().PadLeft(2, '0'));
}
//write Indices
for (int j = 0; j < m_Indices.Length; j++)
{
output.Append(Environment.NewLine + " INDEX " + this[j].Number.ToString().PadLeft(2, '0') + " " + this[j].Minutes.ToString().PadLeft(2, '0') + ":" + this[j].Seconds.ToString().PadLeft(2, '0') + ":" + this[j].Frames.ToString().PadLeft(2, '0'));
}
//write postgap
if (m_PostGap.Number != -1)
{
output.Append(Environment.NewLine + " POSTGAP " + m_PostGap.Minutes.ToString().PadLeft(2, '0') + ":" + m_PostGap.Seconds.ToString().PadLeft(2, '0') + ":" + m_PostGap.Frames.ToString().PadLeft(2, '0'));
}
return output.ToString();
}
#endregion Methods
}
}