From aecd23d001849618a45c50604af9192b3f21d7b5 Mon Sep 17 00:00:00 2001 From: Grigory Chudov Date: Sun, 21 Apr 2013 19:52:36 -0400 Subject: [PATCH] Preliminary support for CDTOC tag --- CUETools.CDImage/CDImage.cs | 54 ++++++++++++++++++ CUETools.Processor/CUEConfigAdvanced.cs | 3 + CUETools.Processor/CUESheet.cs | 76 +++++++++++++++++-------- 3 files changed, 108 insertions(+), 25 deletions(-) diff --git a/CUETools.CDImage/CDImage.cs b/CUETools.CDImage/CDImage.cs index b66924e..17955c3 100644 --- a/CUETools.CDImage/CDImage.cs +++ b/CUETools.CDImage/CDImage.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Security.Cryptography; using System.Text; +using System.Globalization; namespace CUETools.CDImage { @@ -437,6 +438,21 @@ namespace CUETools.CDImage } } + public string TAG + { + get + { + StringBuilder mbSB = new StringBuilder(); + mbSB.AppendFormat(CultureInfo.InvariantCulture, "{0:X}", AudioTracks); + for (int iTrack = _firstAudio; iTrack < TrackCount; iTrack++) + mbSB.AppendFormat("+{0:X}", _tracks[iTrack].Start + 150); + mbSB.AppendFormat("+{0:X}", Length + 150); + for (int iTrack = 0; iTrack < _firstAudio; iTrack++) + mbSB.AppendFormat("+X{0:X}", _tracks[iTrack].Start + 150); + return mbSB.ToString(); + } + } + public static CDImageLayout FromString(string str) { var ids = str.Split(':'); @@ -453,6 +469,44 @@ namespace CUETools.CDImage return new CDImageLayout(trackcount, audiotracks, firstaudio, string.Join(" ", ids)); } + public static CDImageLayout FromTag(string str) + { + var ids = str.Split('+'); + int audiotracks; + int firstaudio = 1; + int trackcount = ids.Length - 2; + int offs; + var ids2 = new List(); + if (!int.TryParse(ids[0], NumberStyles.HexNumber, CultureInfo.InvariantCulture, out audiotracks)) + return null; + if (trackcount > audiotracks && ids[ids.Length - 1][0] == 'X') + { + firstaudio = 1 + trackcount - audiotracks; + for (int i = 0; i < trackcount - audiotracks; i++) + { + if (!int.TryParse(ids[i + 2 + audiotracks].Substring(1), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out offs)) + return null; + ids2.Add((offs - 150).ToString()); + } + for (int i = 0; i <= audiotracks; i++) + { + if (!int.TryParse(ids[i + 1], NumberStyles.HexNumber, CultureInfo.InvariantCulture, out offs)) + return null; + ids2.Add((offs - 150).ToString()); + } + } + else + { + for (int i = 0; i <= trackcount; i++) + { + if (!int.TryParse(ids[i + 1], NumberStyles.HexNumber, CultureInfo.InvariantCulture, out offs)) + return null; + ids2.Add((offs - 150).ToString()); + } + } + return new CDImageLayout(trackcount, audiotracks, firstaudio, string.Join(" ", ids2.ToArray())); + } + public override string ToString() { StringBuilder mbSB = new StringBuilder(); diff --git a/CUETools.Processor/CUEConfigAdvanced.cs b/CUETools.Processor/CUEConfigAdvanced.cs index 6aca308..6348837 100644 --- a/CUETools.Processor/CUEConfigAdvanced.cs +++ b/CUETools.Processor/CUEConfigAdvanced.cs @@ -87,5 +87,8 @@ namespace CUETools.Processor [DefaultValue(false), Category("Tagging"), DisplayName("Use id3v2.4 instead of id3v2.3")] public bool UseId3v24 { get; set; } + + [DefaultValue(true), Category("Tagging"), DisplayName("Write CDTOC tag")] + public bool WriteCDTOCTag { get; set; } } } diff --git a/CUETools.Processor/CUESheet.cs b/CUETools.Processor/CUESheet.cs index 4c360f6..72d25b2 100644 --- a/CUETools.Processor/CUESheet.cs +++ b/CUETools.Processor/CUESheet.cs @@ -1549,20 +1549,30 @@ namespace CUETools.Processor } } + if (tocFromLog == null) + { + var tocTag = GetCommonMiscTag("CDTOC"); + if (tocTag != null) + { + tocFromLog = CDImageLayout.FromTag(tocTag); + if (tocFromLog != null && tocFromLog.TOCID != _toc.TOCID) + tocFromLog = null; + } + } + // use pregaps from log if (tocFromLog != null) { - //int srcNo = (int) _toc[_toc.FirstAudio].LastIndex - (PreGapLength == 0 ? 1 : 0); - if (PreGapLength < tocFromLog.Pregap) - { - PreGapLength = tocFromLog.Pregap; - //srcNo ++; - } int trNo; - for (trNo = 1; trNo < tocFromLog.AudioTracks && trNo < _toc.AudioTracks; trNo++) + for (trNo = 0; trNo < tocFromLog.AudioTracks && trNo < _toc.AudioTracks; trNo++) { if (_toc[_toc.FirstAudio + trNo].Pregap < tocFromLog[tocFromLog.FirstAudio + trNo].Pregap) - _toc[_toc.FirstAudio + trNo].Pregap = tocFromLog[tocFromLog.FirstAudio + trNo].Pregap; + { + if (_toc.FirstAudio + trNo == 1) + PreGapLength = tocFromLog[tocFromLog.FirstAudio + trNo].Pregap; + else + _toc[_toc.FirstAudio + trNo].Pregap = tocFromLog[tocFromLog.FirstAudio + trNo].Pregap; + } } //if (_toc[_toc.FirstAudio].Length > tocFromLog[tocFromLog.FirstAudio].Length) //{ @@ -1613,26 +1623,31 @@ namespace CUETools.Processor _toc[_toc.TrackCount][0].Start = tocFromLog[_toc.TrackCount].Start; _toc[_toc.TrackCount][1].Start = tocFromLog[_toc.TrackCount].Start; } + if (_toc.TrackCount == _toc.AudioTracks && tocFromLog.TrackCount == tocFromLog.AudioTracks && tocFromLog.TrackCount > _toc.TrackCount) { int dtracks = tocFromLog.TrackCount - _toc.TrackCount; - bool matches = true; - for (int iTrack = 1; iTrack <= _toc.TrackCount; iTrack++) - if (tocFromLog[iTrack + dtracks].Length != _toc[iTrack].Length) - matches = false; - if (matches) - { - for (int iTrack = 1; iTrack <= dtracks; iTrack++) - { - _toc.InsertTrack(new CDTrack((uint)iTrack, 0, 0, false, false)); - tocFromLog[iTrack].IsAudio = false; - } - tocFromLog.FirstAudio += dtracks; - tocFromLog.AudioTracks -= (uint)dtracks; - } + var toc2 = new CDImageLayout(tocFromLog); + for (int iTrack = 1; iTrack <= dtracks; iTrack++) + toc2[iTrack].IsAudio = false; + toc2.FirstAudio += dtracks; + toc2.AudioTracks -= (uint)dtracks; + if (toc2.TOCID == _toc.TOCID) + tocFromLog = toc2; } + + if (tocFromLog.AudioTracks == _toc.AudioTracks +// && tocFromLog.TOCID == _toc.TOCID + && _toc.TrackCount == _toc.AudioTracks + && tocFromLog.FirstAudio > 1 + && tocFromLog.TrackCount == tocFromLog.FirstAudio + tocFromLog.AudioTracks - 1) + { + for (int iTrack = 1; iTrack < tocFromLog.FirstAudio; iTrack++) + _toc.InsertTrack(new CDTrack((uint)iTrack, 0, 0, false, false)); + } + if (tocFromLog.AudioTracks == _toc.AudioTracks && tocFromLog.TrackCount == _toc.TrackCount && tocFromLog.FirstAudio == _toc.FirstAudio @@ -3100,6 +3115,9 @@ namespace CUETools.Processor isUsingAccurateRip && _arVerify.ExceptionStatus == WebExceptionStatus.Success) GenerateAccurateRipTags(destTags, bestOffset, iTrack); + + if (_config.advanced.WriteCDTOCTag) + destTags.Add("CDTOC", _toc.TAG); return destTags; } @@ -4096,6 +4114,7 @@ namespace CUETools.Processor uint number = 0; string album = null; string cueFound = null; + CDImageLayout tocFound = null; TimeSpan dur = TimeSpan.Zero; TagLib.UserDefined.AdditionalFileTypes.Config = _config; TagLib.File.IFileAbstraction fileAbsraction = new TagLib.File.LocalFileAbstraction(file.FullName); @@ -4106,7 +4125,10 @@ namespace CUETools.Processor album = fileInfo.Tag.Album; number = fileInfo.Tag.Track; dur = fileInfo.Properties.Duration; - cueFound = fmt.allowEmbed ? Tagging.Analyze(fileInfo).Get("CUESHEET") : null; + var tags = Tagging.Analyze(fileInfo); + cueFound = fmt.allowEmbed ? tags.Get("CUESHEET") : null; + var toc = tags.Get("CDTOC"); + if (toc != null) tocFound = CDImageLayout.FromTag(toc); } catch { } if (cueFound != null) @@ -4117,13 +4139,14 @@ namespace CUETools.Processor fileGroups.Add(group); continue; } - disc = Math.Min(5, Math.Max(1, disc)); + disc = Math.Min(50, Math.Max(1, disc)); FileGroupInfo groupFound = null; foreach (FileGroupInfo fileGroup in fileGroups) { if (fileGroup.type == FileGroupInfoType.TrackFiles && fileGroup.discNo == disc && fileGroup.album == album + && (fileGroup.TOC == null ? "" : fileGroup.TOC.ToString()) == (tocFound == null ? "" : tocFound.ToString()) && fileGroup.main.Extension.ToLower() == ext) { groupFound = fileGroup; @@ -4135,6 +4158,7 @@ namespace CUETools.Processor groupFound = new FileGroupInfo(file, FileGroupInfoType.TrackFiles); groupFound.discNo = disc; groupFound.album = album; + groupFound.TOC = tocFound; groupFound.durations = new Dictionary(); fileGroups.Add(groupFound); } @@ -4143,7 +4167,9 @@ namespace CUETools.Processor if (dur != TimeSpan.Zero) groupFound.durations.Add(file, dur); } } - fileGroups.RemoveAll(group => group.type == FileGroupInfoType.TrackFiles && group.files.Count < 2); + fileGroups.RemoveAll(group => group.type == FileGroupInfoType.TrackFiles && ( + (group.TOC == null && group.files.Count < 2) || + (group.TOC != null && group.TOC.AudioTracks != group.files.Count))); // tracks must be sorted according to tracknumer (or filename if missing) foreach (FileGroupInfo group in fileGroups) if (group.type == FileGroupInfoType.TrackFiles)