From 10de1aac066e657d0a5035b05d945e4b7ccd1abd Mon Sep 17 00:00:00 2001 From: Daniel <790119+DanTheMan827@users.noreply.github.com> Date: Tue, 13 Nov 2018 09:27:28 -0600 Subject: [PATCH] Import v0.5 from https://wyday.com/cuesharp/ --- .gitignore | 334 ++++++ CueSharp.sln | 26 + CueSharp/CueSharp.cs | 1376 +++++++++++++++++++++++ CueSharp/CueSharp.csproj | 51 + CueSharp/Properties/AssemblyInfo.cs | 33 + LICENSE.txt | 10 + TestCueSharp/Program.cs | 128 +++ TestCueSharp/Properties/AssemblyInfo.cs | 32 + TestCueSharp/TestCueSharp.csproj | 51 + readme.md | 19 + 10 files changed, 2060 insertions(+) create mode 100644 .gitignore create mode 100644 CueSharp.sln create mode 100644 CueSharp/CueSharp.cs create mode 100644 CueSharp/CueSharp.csproj create mode 100644 CueSharp/Properties/AssemblyInfo.cs create mode 100644 LICENSE.txt create mode 100644 TestCueSharp/Program.cs create mode 100644 TestCueSharp/Properties/AssemblyInfo.cs create mode 100644 TestCueSharp/TestCueSharp.csproj create mode 100644 readme.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f00a0eb --- /dev/null +++ b/.gitignore @@ -0,0 +1,334 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ \ No newline at end of file diff --git a/CueSharp.sln b/CueSharp.sln new file mode 100644 index 0000000..63ea1c8 --- /dev/null +++ b/CueSharp.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CueSharp", "CueSharp\CueSharp.csproj", "{AEC446C6-FA7D-4224-83C4-87C270759403}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestCueSharp", "TestCueSharp\TestCueSharp.csproj", "{FB4D1AF3-5D88-4442-A15C-95A5112B285C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {AEC446C6-FA7D-4224-83C4-87C270759403}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AEC446C6-FA7D-4224-83C4-87C270759403}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AEC446C6-FA7D-4224-83C4-87C270759403}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AEC446C6-FA7D-4224-83C4-87C270759403}.Release|Any CPU.Build.0 = Release|Any CPU + {FB4D1AF3-5D88-4442-A15C-95A5112B285C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FB4D1AF3-5D88-4442-A15C-95A5112B285C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FB4D1AF3-5D88-4442-A15C-95A5112B285C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FB4D1AF3-5D88-4442-A15C-95A5112B285C}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/CueSharp/CueSharp.cs b/CueSharp/CueSharp.cs new file mode 100644 index 0000000..3fbbb08 --- /dev/null +++ b/CueSharp/CueSharp.cs @@ -0,0 +1,1376 @@ +/* +Title: CueSharp +Version: 0.5 +Released: March 24, 2007 + +Author: Wyatt O'Day +Website: wyday.com/cuesharp +*/ +using System; +using System.Text; +using System.IO; + +namespace CueSharp +{ + /// + /// A CueSheet class used to create, open, edit, and save cuesheets. + /// + public class CueSheet + { + #region Private Variables + 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 + + #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 + + #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 = cueString.Split(lineDelims); + RemoveEmptyLines(ref cueLines); + 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); + } + + 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 + TextReader tr = new StreamReader(filename, encoding); + //read in file + cueLines = tr.ReadToEnd().Split(delimiters); + + // close the stream + tr.Close(); + + RemoveEmptyLines(ref cueLines); + + ParseCue(cueLines); + } + + #endregion + + #region Methods + + /// + /// Removes any empty lines, elimating possible trouble. + /// + /// + private void RemoveEmptyLines(ref string[] file) + { + int itemsRemoved = 0; + + for (int i = 0; i < file.Length; i++) + { + if (file[i].Trim() != "") + { + file[i - itemsRemoved] = file[i]; + } + else if (file[i].Trim() == "") + { + itemsRemoved++; + } + } + + if (itemsRemoved > 0) + { + file = (string[])ResizeArray(file, file.Length - itemsRemoved); + } + } + + private void ParseCue(string[] file) + { + //-1 means still global, + //all others are track specific + int trackOn = -1; + AudioFile currentFile = new AudioFile(); + + for (int i = 0; i < file.Length; i++) + { + file[i] = file[i].Trim(); + + switch (file[i].Substring(0, file[i].IndexOf(' ')).ToUpper()) + { + case "CATALOG": + ParseString(file[i], trackOn); + break; + case "CDTEXTFILE": + ParseString(file[i], trackOn); + break; + case "FILE": + currentFile = ParseFile(file[i], trackOn); + break; + case "FLAGS": + ParseFlags(file[i], trackOn); + break; + case "INDEX": + ParseIndex(file[i], trackOn); + break; + case "ISRC": + ParseString(file[i], trackOn); + break; + case "PERFORMER": + ParseString(file[i], trackOn); + break; + case "POSTGAP": + ParseIndex(file[i], trackOn); + break; + case "PREGAP": + ParseIndex(file[i], trackOn); + break; + case "REM": + ParseComment(file[i], trackOn); + break; + case "SONGWRITER": + ParseString(file[i], trackOn); + break; + case "TITLE": + ParseString(file[i], trackOn); + break; + case "TRACK": + trackOn++; + ParseTrack(file[i], trackOn); + if (currentFile.Filename != "") //if there's a file + { + m_Tracks[trackOn].DataFile = currentFile; + currentFile = new AudioFile(); + } + break; + default: + ParseGarbage(file[i], trackOn); + //save discarded junk and place string[] with track it was found in + break; + } + } + + } + + private void ParseComment(string line, int trackOn) + { + //remove "REM" (we know the line has already been .Trim()'ed) + line = line.Substring(line.IndexOf(' '), line.Length - line.IndexOf(' ')).Trim(); + + 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 = line.Substring(line.IndexOf(' '), line.Length - line.IndexOf(' ')).Trim(); + + 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 != "") + { + try + { + temp = line.Substring(0, line.IndexOf(' ')).ToUpper(); + } + catch (Exception) + { + temp = 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; + } + + //processing for a case when there isn't any more spaces + //i.e. avoiding the "index cannot be less than zero" error + //when calling line.IndexOf(' ') + try + { + temp = line.Substring(line.IndexOf(' '), line.Length - line.IndexOf(' ')); + } + catch (Exception) + { + temp = line.Substring(0, line.Length); + } + + //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 line, int trackOn) + { + string indexType; + string tempString; + + int number = 0; + int minutes; + int seconds; + int frames; + + indexType = line.Substring(0, line.IndexOf(' ')).ToUpper(); + + tempString = line.Substring(line.IndexOf(' '), line.Length - line.IndexOf(' ')).Trim(); + + 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 line, int trackOn) + { + string category = line.Substring(0, line.IndexOf(' ')).ToUpper(); + + line = line.Substring(line.IndexOf(' '), line.Length - line.IndexOf(' ')).Trim(); + + //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. + /// The track currently processing. + private void ParseTrack(string line, int trackOn) + { + string tempString; + int trackNumber; + + tempString = line.Substring(line.IndexOf(' '), line.Length - line.IndexOf(' ')).Trim(); + + 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) + { + TextWriter tw = new StreamWriter(filename, false, encoding); + + tw.WriteLine(this.ToString()); + + //close the writer stream + tw.Close(); + } + + /// + /// 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 + + //TODO: Fix calculation bugs; currently generates erroneous IDs. + #region CalculateDiscIDs + //For complete CDDB/freedb discID calculation, see: + //http://www.freedb.org/modules.php?name=Sections&sop=viewarticle&artid=6 + + public string CalculateCDDBdiscID() + { + int i, t = 0, n = 0; + + /* For backward compatibility this algorithm must not change */ + + i = 0; + + while (i < m_Tracks.Length) + { + n = n + cddb_sum((lastTrackIndex(m_Tracks[i]).Minutes * 60) + lastTrackIndex(m_Tracks[i]).Seconds); + i++; + } + + Console.WriteLine(n.ToString()); + + t = ((lastTrackIndex(m_Tracks[m_Tracks.Length - 1]).Minutes * 60) + lastTrackIndex(m_Tracks[m_Tracks.Length - 1]).Seconds) - + ((lastTrackIndex(m_Tracks[0]).Minutes * 60) + lastTrackIndex(m_Tracks[0]).Seconds); + + ulong lDiscId = (((uint)n % 0xff) << 24 | (uint)t << 8 | (uint)m_Tracks.Length); + return String.Format("{0:x8}", lDiscId); + } + + private Index lastTrackIndex(Track track) + { + return track.Indices[track.Indices.Length - 1]; + } + + private int cddb_sum(int n) + { + int ret; + + /* For backward compatibility this algorithm must not change */ + + ret = 0; + + while (n > 0) + { + ret = ret + (n % 10); + n = n / 10; + } + + return (ret); + } + + #endregion CalculateDiscIDS + + + } + + /// + ///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 + int m_number; + + int m_minutes; + int m_seconds; + 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 struct 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 + + #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 + + #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 + + #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); + } + + /// + /// 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; + } + + 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 + } +} diff --git a/CueSharp/CueSharp.csproj b/CueSharp/CueSharp.csproj new file mode 100644 index 0000000..70fd395 --- /dev/null +++ b/CueSharp/CueSharp.csproj @@ -0,0 +1,51 @@ + + + Debug + AnyCPU + 8.0.50727 + 2.0 + {AEC446C6-FA7D-4224-83C4-87C270759403} + Library + Properties + CueSharp + CueSharp + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + bin\Debug\CueSharp.XML + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + bin\Release\CueSharp.XML + + + + + + + + + + + + + \ No newline at end of file diff --git a/CueSharp/Properties/AssemblyInfo.cs b/CueSharp/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..d620890 --- /dev/null +++ b/CueSharp/Properties/AssemblyInfo.cs @@ -0,0 +1,33 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("CueSharp")] +[assembly: AssemblyDescription("Cue sheet parser library")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("wyDay")] +[assembly: AssemblyProduct("CueSharp")] +[assembly: AssemblyCopyright("Copyright © 2005-2007 wyDay")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("0cbbf417-3aa4-4f3a-aa90-e9f7aef735b5")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +[assembly: AssemblyVersion("0.5.0")] +[assembly: AssemblyFileVersion("0.5.0")] diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..edcc063 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,10 @@ +Copyright (c) 2018, wyDay +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/TestCueSharp/Program.cs b/TestCueSharp/Program.cs new file mode 100644 index 0000000..613c24c --- /dev/null +++ b/TestCueSharp/Program.cs @@ -0,0 +1,128 @@ +using System; +using System.Text; +using CueSharp; +using System.IO; + +namespace ConsoleApplication1 +{ + class Program + { + static void Main(string[] args) + { + OpenExistingFile(); + + Console.WriteLine("\n\n"); + + NewCueSheet(); + + //keep the console open 'till enter is pressed + Console.Read(); + } + + /// + /// Create a new cuesheet from scratch + /// + static void NewCueSheet() + { + CueSheet cue = new CueSheet(); + + //Album performer + cue.Performer = "Rotterdam Philharmonic Orchestra"; + //Album title + cue.Title = "Edo de Waart / Rachmaninoff: The 3 Symphonies, The Rock - Disc 1"; + + //Create 1st track, with a filename that future tracks will inherit + cue.AddTrack("Symphony No. 2 in E minor, Op. 27: I. Largo - Allegro moderato", "", "CDImage.ape", FileType.WAVE); + cue.AddIndex(0, 0, 0, 0, 0); + cue.AddIndex(0, 1, 0, 0, 33); + + //Create 2nd track, with optional 'Performance' field used + cue.AddTrack("II. Allegro molto", "Fake G. Uy: Timpani"); + cue.AddIndex(1, 0, 18, 39, 33); + cue.AddIndex(1, 2, 22, 14, 10); //add another index we'll delete later + cue.AddIndex(1, 1, 18, 44, 25); + + //Create 3rd track + cue.AddTrack("III. Adagio", ""); + cue.AddIndex(2, 0, 27, 56, 33); + cue.AddIndex(2, 1, 27, 59, 40); + + //Create 4th track using a method that gives us more control over the data + Track tempTrack = new Track(4, DataType.AUDIO); + tempTrack.Title = "IV. Allegro vivace"; + tempTrack.ISRC = "0000078652395"; + tempTrack.AddFlag(Flags.CH4); + tempTrack.AddIndex(0, 41, 57, 33); + tempTrack.AddIndex(1, 42, 00, 60); + cue.AddTrack(tempTrack); + + //Create 5th track we'll delete later + cue.AddTrack("Symphony No. Infinity", "Rachmaninoff's Dog"); + + + //Remove the bad index from the 2nd track + cue.RemoveIndex(1, 1);//(trackIndex, indexIndex) + //Notice the index (array-wise) of the Index (cuesheet min/sec/frame) is '1' + //but the Index Number is 2. This is to show that index and the Index Number are + //not the same thing and may or may not be equal. + + //Remove the 5th track + cue.RemoveTrack(4); + + Console.WriteLine(cue.ToString()); + cue.SaveCue("newCDImage.cue"); + } + + /// + /// Open an manipulate an existing cuesheet. + /// + static void OpenExistingFile() + { + //Incomplete FreeDB feature + //Console.WriteLine(cue.CalculateCDDBdiscID()); + //Console.Read(); + + //open a cuesheet from file with the default encoding. + CueSheet cue = new CueSheet("CDImage.cue"); + + //print out the title from the global section of the cue file + Console.WriteLine(cue.Title); + + //print out the performer from the global section of the cue file + Console.WriteLine(cue.Performer); + + //Show how many track there are + Console.WriteLine("There are " + cue.Tracks.Length.ToString() + "tracks in this cue file."); + + //Write out the first track + Console.WriteLine(cue[0].ToString()); + + Console.WriteLine("------ Start CueSheet -------"); + Console.WriteLine(cue.ToString()); + Console.WriteLine("------ End CueSheet -------"); + + //print out the title of the second track + Console.WriteLine(cue[1].Title); + + //print out the Minutes, seconds, and frames of the first index of the second track. + Console.WriteLine(cue[1][0].Minutes); + Console.WriteLine(cue[1][0].Seconds); + Console.WriteLine(cue[1][0].Frames); + + //Print out the image filename + Console.WriteLine("Data file location: " + cue[0].DataFile.Filename); + + //change the title of the cuesheet + cue.Title = "Great Music"; + + //Manipulate the first track + Track tempTrack = cue[0];//create a tempTrack to change info + tempTrack.AddFlag(Flags.CH4);//add a new flag + tempTrack.Title = "Wonderful track #1";//change the title + cue[0] = tempTrack;//Set the 1st track with the newly manipulated track. + + cue.SaveCue("newcue.cue"); + + } + } +} diff --git a/TestCueSharp/Properties/AssemblyInfo.cs b/TestCueSharp/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..7849084 --- /dev/null +++ b/TestCueSharp/Properties/AssemblyInfo.cs @@ -0,0 +1,32 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("ConsoleApplication1")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("ConsoleApplication1")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("da8fc6db-d569-412c-a2a2-beee2ddbbacf")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +[assembly: AssemblyVersion("1.5.0.0")] +[assembly: AssemblyFileVersion("1.5.0.0")] diff --git a/TestCueSharp/TestCueSharp.csproj b/TestCueSharp/TestCueSharp.csproj new file mode 100644 index 0000000..0395cb4 --- /dev/null +++ b/TestCueSharp/TestCueSharp.csproj @@ -0,0 +1,51 @@ + + + Debug + AnyCPU + 8.0.50727 + 2.0 + {FB4D1AF3-5D88-4442-A15C-95A5112B285C} + Exe + Properties + TestCueSharp + TestCueSharp + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + False + ..\CueSharp\bin\Debug\CueSharp.dll + + + + + + + + + + + + \ No newline at end of file diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..0b9cf70 --- /dev/null +++ b/readme.md @@ -0,0 +1,19 @@ +# CueSharp + +CueSharp is an open source cue sheet parser library written in C#. + +The cue sheet, simply put, is a text file that stores metadata for extracted audio CDs and data CDs. Cue sheets are typically generated using [Exact Audio Copy (EAC)](http://www.exactaudiocopy.de/ "EAC") in order to rip your audio CDs perfectly. + +## Features at a glance + +- Accurately follows the [cue sheet specification](https://wyday.com/cuesharp/specification.php "Cue sheet specifcation"). +- Can open cue sheets for wave files and binary data files alike. +- Easy to use interface to create, open, edit, and save cue sheets. +- Compiles with .NET 1.1 – 3.5, and Mono. + +## What CueSharp Isn't + +CueSharp is not a standalone program - if you aren't a developer, then CueSharp isn't for you. Here are a couple of standalone programs that can open and manipulate CueSheets: + +- [foobar2000](http://www.foobar2000.org/ "foobar2000"): A freeware audio player for Windows 2000, XP and Vista. +- [DaemonTools](http://www.daemon-tools.cc/ "DaemonTools"): A freeware program for mounting .bin/.cue files to a virtual disc drive. \ No newline at end of file