public void CRCTestSplit() { var ar0 = TestImageGenerator.CreateAccurateRipVerify("13 68 99 136", 723722, 0); var splits = new int[] { 1, 13 * 588 - 1, 13 * 588, 13 * 588 + 1, 30 * 588, 68 * 588 - 1, 68 * 588, 68 * 588 + 1 }; foreach (int split in splits) { var ar1 = TestImageGenerator.CreateAccurateRipVerify("13 68 99 136", 723722, 0, 0, split); var ar2 = TestImageGenerator.CreateAccurateRipVerify("13 68 99 136", 723722, 0, split, (int)ar0.FinalSampleCount); ar1.Combine(ar2, split, (int)ar0.FinalSampleCount); var offsets = new int[] { 0, -1, 1, -2, 2, -3, 3, -4, 4, -11, 11, -256, 256, -588, 588, 1 - 588 * 5, 588 * 5 - 1 }; foreach (int offs in offsets) { for (int track = 0; track < 3; track++) { string message = "split = " + CDImageLayout.TimeToString((uint)split / 588) + "." + (split % 588).ToString() + ", offset = " + offs.ToString() + ", track = " + (track + 1).ToString(); Assert.AreEqual <uint>(ar0.CRC(track, offs), ar1.CRC(track, offs), "CRC was not set correctly, " + message); Assert.AreEqual <uint>(ar0.CTDBCRC(track, offs, 5 * 588, 5 * 588), ar1.CTDBCRC(track, offs, 5 * 588, 5 * 588), "CTDBCRC was not set correctly, " + message); //CRC450 is zero here :( too small tracks //Assert.AreEqual<uint>(ar0.CRC450(track, offs), ar1.CRC450(track, offs), "CRC450 was not set correctly, " + message); if ((track != 2 || offs <= 0)) // && (track != 0 || offs >= 0)) { Assert.AreEqual <uint>(ar0.CRC32(track + 1, offs), ar1.CRC32(track + 1, offs), "CRC32 was not set correctly, " + message); Assert.AreEqual <uint>(ar0.CRCWONULL(track + 1, offs), ar1.CRCWONULL(track + 1, offs), "CRCWONULL was not set correctly, " + message); } if (offs == 0) { Assert.AreEqual <uint>(ar0.CRCV2(track), ar1.CRCV2(track), "CRCV2 was not set correctly, " + message); } } } } }
public void CDRepairSplitTest() { var seed = 723722; var ar0 = new TestImageGenerator("13 68 99 136", seed, 0, 0).CreateCDRepairEncode(stride); var splits = new int[] { 1, 13 * 588 - 1, 13 * 588, 13 * 588 + 1, 30 * 588 - 1, 30 * 588, 30 * 588 + 1, 68 * 588 - 1, 68 * 588, 68 * 588 + 1 }; foreach (int split in splits) { var ar1 = new TestImageGenerator("13 68 99 136", seed, 0, 0, 0, 0, split).CreateCDRepairEncode(stride); var ar2 = new TestImageGenerator("13 68 99 136", seed, 0, 0, 0, split, (int)ar0.FinalSampleCount).CreateCDRepairEncode(stride); ar1.AR.Combine(ar2.AR, split, (int)ar0.FinalSampleCount); string message = "split = " + CDImageLayout.TimeToString((uint)split / 588) + "." + (split % 588).ToString(); Assert.AreEqual(ar0.CRC, ar1.CRC, "CRC was not set correctly, " + message); CollectionAssert.AreEqual(ar0.AR.GetSyndrome(), ar1.AR.GetSyndrome(), "Parity was not set correctly, " + message); } }
public static string GetTOCContents(CUESheet sheet) { StringWriter sw = new StringWriter(); sw.WriteLine(" Track | Start | Length | Start sector | End sector "); sw.WriteLine(" ---------------------------------------------------------"); for (int track = 1; track <= sheet.TOC.TrackCount; track++) { sw.WriteLine("{0,9} | {1,8} | {2,8} | {3,8} | {4,8} ", track, // sheet.TOC[track].Number, CDImageLayout.TimeToString("{0,2}:{1:00}.{2:00}", sheet.TOC[track].Start), CDImageLayout.TimeToString("{0,2}:{1:00}.{2:00}", sheet.TOC[track].Length), sheet.TOC[track].Start, sheet.TOC[track].End); } return(sw.ToString()); }
public string GetAffectedSectors(int min, int max, int offs = 0) { min = Math.Max(2 * min, 2 * pregap + stride - 2 * ActualOffset); max = Math.Min(2 * max, 2 * finalSampleCount - laststride - 2 * ActualOffset); offs = offs * 2; StringBuilder sb = new StringBuilder(); for (int i = 0; i < correctableErrors; i++) { if (erroffsorted[i] >= min && erroffsorted[i] < max) { int j; for (j = i + 1; j < correctableErrors; j++) { if (erroffsorted[j] - erroffsorted[j - 1] > 2 * 588 * 5) { break; } } uint sec1 = (uint)(erroffsorted[i] - offs) / 2 / 588; uint sec2 = (uint)(erroffsorted[j - 1] - offs) / 2 / 588; if (sb.Length != 0) { sb.Append(","); } sb.Append(CDImageLayout.TimeToString(sec1)); if (sec1 != sec2) { sb.Append("-"); } if (sec1 != sec2) { sb.Append(CDImageLayout.TimeToString(sec2)); } i = j - 1; } } return(sb.ToString()); }
public void GenerateLog(TextWriter sw, bool old) { if (this.DBStatus != null || this.Total == 0) { return; } if (old) { sw.WriteLine(" [ CTDBID ] Status"); foreach (DBEntry entry in this.Entries) { string confFormat = (this.Total < 10) ? "{0:0}/{1:0}" : (this.Total < 100) ? "{0:00}/{1:00}" : "{0:000}/{1:000}"; string conf = string.Format(confFormat, entry.conf, this.Total); string dataTrackInfo = !entry.toc[entry.toc.TrackCount].IsAudio && this.toc[this.toc.TrackCount].IsAudio ? string.Format("CD-Extra data track length {0}", entry.toc[entry.toc.TrackCount].LengthMSF) : !entry.toc[1].IsAudio && this.toc[1].IsAudio ? string.Format("Playstation type data track length {0}", entry.toc[entry.toc.FirstAudio].StartMSF) : (entry.toc[1].IsAudio && !this.toc[1].IsAudio) || (entry.toc[entry.toc.TrackCount].IsAudio && !this.toc[this.toc.TrackCount].IsAudio) ? "Has no data track" : ""; if (entry.toc.Pregap != this.toc.Pregap) { dataTrackInfo = dataTrackInfo + (dataTrackInfo == "" ? "" : ", ") + string.Format("Has pregap length {0}", CDImageLayout.TimeToString(entry.toc.Pregap)); } string status = entry.toc.AudioLength - entry.toc.Pregap != this.TOC.AudioLength - this.TOC.Pregap ? string.Format("Has audio length {0}", CDImageLayout.TimeToString(entry.toc.AudioLength)) : ((entry.toc.TrackOffsets != this.TOC.TrackOffsets) ? dataTrackInfo + ", " : "") + ((!entry.hasErrors) ? "Accurately ripped" : //((!entry.hasErrors) ? string.Format("Accurately ripped, offset {0}", -entry.offset) : entry.canRecover ? string.Format("Differs in {0} samples @{1}", entry.repair.CorrectableErrors, entry.repair.AffectedSectors) : (entry.httpStatus == 0 || entry.httpStatus == HttpStatusCode.OK) ? "No match" : entry.httpStatus.ToString()); sw.WriteLine(" [{0:x8}] ({1}) {2}", entry.crc, conf, status); } } const int _arOffsetRange = 5 * 588 - 1; sw.WriteLine("Track | CTDB Status"); string ifmt = this.Total < 10 ? "1" : this.Total < 100 ? "2" : "3"; for (int iTrack = 0; iTrack < this.TOC.AudioTracks; iTrack++) { int conf = 0; List <int> resConfidence = new List <int>(); List <string> resStatus = new List <string>(); foreach (DBEntry entry in this.Entries) { if (!entry.hasErrors) { conf += entry.conf; continue; } if (entry.canRecover) { var tri = this.TOC[this.TOC.FirstAudio + iTrack]; var tr0 = this.TOC[this.TOC.FirstAudio]; var min = (int)(tri.Start - tr0.Start) * 588; var max = (int)(tri.End + 1 - tr0.Start) * 588; var diffCount = entry.repair.GetAffectedSectorsCount(min, max); if (diffCount == 0) { conf += entry.conf; continue; } resConfidence.Add(entry.conf); resStatus.Add(string.Format("differs in {0} samples @{1}", diffCount, entry.repair.GetAffectedSectors(min, max, min))); continue; } if (entry.trackcrcs != null) { if (this.verify.TrackCRC(iTrack + 1, -entry.offset) == entry.trackcrcs[iTrack]) { conf += entry.conf; continue; } for (int oi = -_arOffsetRange; oi <= _arOffsetRange; oi++) { if (this.verify.TrackCRC(iTrack + 1, oi) == entry.trackcrcs[iTrack]) { conf += entry.conf; break; } } } } if (conf > 0) { resConfidence.Insert(0, conf); resStatus.Insert(0, "accurately ripped"); } if (resStatus.Count == 0) { resConfidence.Add(0); resStatus.Add("no match"); } resStatus[0] = string.Format("({0," + ifmt + "}/{1}) {2}", resConfidence[0], this.Total, char.ToUpper(resStatus[0][0]) + resStatus[0].Substring(1)); for (int i = 1; i < resStatus.Count; i++) { resStatus[i] = string.Format("({0}/{1}) {2}", resConfidence[i], this.Total, resStatus[i]); } sw.WriteLine(string.Format(" {0,2} | {1}", iTrack + 1, string.Join(", or ", resStatus.ToArray()))); } }
static void Main(string[] args) { Console.SetOut(Console.Error); Console.WriteLine("CUERipper v2.1.7 Copyright (C) 2008-10 Grigory Chudov"); Console.WriteLine("This is free software under the GNU GPLv3+ license; There is NO WARRANTY, to"); Console.WriteLine("the extent permitted by law. <http://www.gnu.org/licenses/> for details."); int correctionQuality = 1; string driveLetter = null; int driveOffset = 0; bool test = false; bool forceD8 = false, forceBE = false, quiet = false; for (int arg = 0; arg < args.Length; arg++) { bool ok = true; if (args[arg] == "-P" || args[arg] == "--paranoid") { correctionQuality = 2; } else if (args[arg] == "-S" || args[arg] == "--secure") { correctionQuality = 1; } else if (args[arg] == "-B" || args[arg] == "--burst") { correctionQuality = 0; } else if (args[arg] == "-T" || args[arg] == "--test") { test = true; } else if (args[arg] == "--d8") { forceD8 = true; } else if (args[arg] == "--be") { forceBE = true; } else if (args[arg] == "-Q" || args[arg] == "--quiet") { quiet = true; } else if ((args[arg] == "-D" || args[arg] == "--drive") && ++arg < args.Length) { driveLetter = args[arg]; } else if ((args[arg] == "-O" || args[arg] == "--offset") && ++arg < args.Length) { ok = int.TryParse(args[arg], out driveOffset); } else { ok = false; } if (!ok) { Usage(); return; } } char[] drives; if (driveLetter == null || driveLetter.Length < 1) { drives = CDDrivesList.DrivesAvailable(); if (drives.Length < 1) { Console.WriteLine("No CD drives found."); return; } } else { drives = new char[1]; drives[0] = driveLetter[0]; } #if !DEBUG try #endif { CDDriveReader audioSource = new CDDriveReader(); audioSource.Open(drives[0]); if (audioSource.TOC.AudioTracks < 1) { Console.WriteLine("{0}: CD does not contain any audio tracks.", audioSource.Path); audioSource.Close(); return; } if (driveOffset == 0) { if (!AccurateRipVerify.FindDriveReadOffset(audioSource.ARName, out driveOffset)) { Console.WriteLine("Unknown read offset for drive {0}!!!", audioSource.Path); } } //throw new Exception("Failed to find drive read offset for drive" + audioSource.ARName); audioSource.DriveOffset = driveOffset; audioSource.CorrectionQuality = correctionQuality; audioSource.DebugMessages = !quiet; if (forceD8) { audioSource.ForceD8 = true; } if (forceBE) { audioSource.ForceBE = true; } string readCmd = audioSource.AutoDetectReadCommand; if (test) { Console.Write(readCmd); return; } AccurateRipVerify arVerify = new AccurateRipVerify(audioSource.TOC, WebRequest.GetSystemWebProxy()); AudioBuffer buff = new AudioBuffer(audioSource, 0x10000); string CDDBId = AccurateRipVerify.CalculateCDDBId(audioSource.TOC); string ArId = AccurateRipVerify.CalculateAccurateRipId(audioSource.TOC); var ctdb = new CUEToolsDB(audioSource.TOC, null); ctdb.Init(arVerify); ctdb.ContactDB(null, "CUETools.ConsoleRipper 2.1.7", audioSource.ARName, true, false, CTDBMetadataSearch.Fast); arVerify.ContactAccurateRip(ArId); CTDBResponseMeta meta = null; foreach (var imeta in ctdb.Metadata) { meta = imeta; break; } //string destFile = (release == null) ? "cdimage.flac" : release.GetArtist() + " - " + release.GetTitle() + ".flac"; string destFile = (meta == null) ? "cdimage.wav" : meta.artist + " - " + meta.album + ".wav"; Console.WriteLine("Drive : {0}", audioSource.Path); Console.WriteLine("Read offset : {0}", audioSource.DriveOffset); Console.WriteLine("Read cmd : {0}", audioSource.CurrentReadCommand); Console.WriteLine("Secure mode : {0}", audioSource.CorrectionQuality); Console.WriteLine("Filename : {0}", destFile); Console.WriteLine("Disk length : {0}", CDImageLayout.TimeToString(audioSource.TOC.AudioLength)); Console.WriteLine("AccurateRip : {0}", arVerify.ARStatus == null ? "ok" : arVerify.ARStatus); Console.WriteLine("MusicBrainz : {0}", meta == null ? "not found" : meta.artist + " - " + meta.album); ProgressMeter meter = new ProgressMeter(); audioSource.ReadProgress += new EventHandler <ReadProgressArgs>(meter.ReadProgress); audioSource.DetectGaps(); StringWriter cueWriter = new StringWriter(); cueWriter.WriteLine("REM DISCID {0}", CDDBId); cueWriter.WriteLine("REM ACCURATERIPID {0}", ArId); cueWriter.WriteLine("REM COMMENT \"{0}\"", audioSource.RipperVersion); if (meta != null && meta.year != "") { cueWriter.WriteLine("REM DATE {0}", meta.year); } if (audioSource.TOC.Barcode != null) { cueWriter.WriteLine("CATALOG {0}", audioSource.TOC.Barcode); } if (meta != null) { cueWriter.WriteLine("PERFORMER \"{0}\"", meta.artist); cueWriter.WriteLine("TITLE \"{0}\"", meta.album); } cueWriter.WriteLine("FILE \"{0}\" WAVE", destFile); for (int track = 1; track <= audioSource.TOC.TrackCount; track++) { if (audioSource.TOC[track].IsAudio) { cueWriter.WriteLine(" TRACK {0:00} AUDIO", audioSource.TOC[track].Number); if (meta != null && meta.track.Length >= audioSource.TOC[track].Number) { cueWriter.WriteLine(" TITLE \"{0}\"", meta.track[(int)audioSource.TOC[track].Number - 1].name); cueWriter.WriteLine(" PERFORMER \"{0}\"", meta.track[(int)audioSource.TOC[track].Number - 1].artist); } if (audioSource.TOC[track].ISRC != null) { cueWriter.WriteLine(" ISRC {0}", audioSource.TOC[track].ISRC); } if (audioSource.TOC[track].DCP || audioSource.TOC[track].PreEmphasis) { cueWriter.WriteLine(" FLAGS{0}{1}", audioSource.TOC[track].PreEmphasis ? " PRE" : "", audioSource.TOC[track].DCP ? " DCP" : ""); } for (int index = audioSource.TOC[track].Pregap > 0 ? 0 : 1; index <= audioSource.TOC[track].LastIndex; index++) { cueWriter.WriteLine(" INDEX {0:00} {1}", index, audioSource.TOC[track][index].MSF); } } } cueWriter.Close(); StreamWriter cueFile = new StreamWriter(Path.ChangeExtension(destFile, ".cue")); cueFile.Write(cueWriter.ToString()); cueFile.Close(); //IAudioDest audioDest = new FLACWriter(destFile, audioSource.BitsPerSample, audioSource.ChannelCount, audioSource.SampleRate); IAudioDest audioDest = new Codecs.WAV.AudioEncoder(new Codecs.WAV.EncoderSettings(audioSource.PCM), destFile); audioDest.FinalSampleCount = audioSource.Length; while (audioSource.Read(buff, -1) != 0) { arVerify.Write(buff); audioDest.Write(buff); } TimeSpan totalElapsed = DateTime.Now - meter.realStart; Console.Write("\r \r"); Console.WriteLine("Results : {0:0.00}x; {1:d5} errors; {2:d2}:{3:d2}:{4:d2}", audioSource.Length / totalElapsed.TotalSeconds / audioSource.PCM.SampleRate, audioSource.FailedSectors.PopulationCount(), totalElapsed.Hours, totalElapsed.Minutes, totalElapsed.Seconds ); audioDest.Close(); StringWriter logWriter = new StringWriter(); logWriter.WriteLine("{0}", audioSource.RipperVersion); logWriter.WriteLine("Extraction logfile from {0}", DateTime.Now); logWriter.WriteLine("Used drive : {0}", audioSource.Path); logWriter.WriteLine("Read offset correction : {0}", audioSource.DriveOffset); bool wereErrors = false; for (int iTrack = 1; iTrack <= audioSource.TOC.AudioTracks; iTrack++) { for (uint iSector = audioSource.TOC[iTrack].Start; iSector <= audioSource.TOC[iTrack].End; iSector++) { if (audioSource.FailedSectors[(int)iSector]) { if (!wereErrors) { logWriter.WriteLine(); logWriter.WriteLine("Errors detected"); logWriter.WriteLine(); } wereErrors = true; logWriter.WriteLine("Track {0} contains errors", iTrack); break; } } } logWriter.WriteLine(); logWriter.WriteLine("TOC of the extracted CD"); logWriter.WriteLine(); logWriter.WriteLine(" Track | Start | Length | Start sector | End sector"); logWriter.WriteLine(" ---------------------------------------------------------"); for (int track = 1; track <= audioSource.TOC.TrackCount; track++) { logWriter.WriteLine("{0,9} | {1,8} | {2,8} | {3,9} | {4,9}", audioSource.TOC[track].Number, audioSource.TOC[track].StartMSF, audioSource.TOC[track].LengthMSF, audioSource.TOC[track].Start, audioSource.TOC[track].End); } logWriter.WriteLine(); logWriter.WriteLine("AccurateRip summary"); logWriter.WriteLine(); arVerify.GenerateFullLog(logWriter, true, ArId); logWriter.WriteLine(); logWriter.WriteLine("End of status report"); logWriter.Close(); StreamWriter logFile = new StreamWriter(Path.ChangeExtension(destFile, ".log")); logFile.Write(logWriter.ToString()); logFile.Close(); audioSource.Close(); //FLACReader tagger = new FLACReader(destFile, null); //tagger.Tags.Add("CUESHEET", cueWriter.ToString()); //tagger.Tags.Add("LOG", logWriter.ToString()); //tagger.UpdateTags(false); } #if !DEBUG catch (Exception ex) { Console.WriteLine(); Console.WriteLine("Error: {0}", ex.Message); Console.WriteLine("{0}", ex.StackTrace); } #endif }
static int Main(string[] args) { bool ok = true; string sourceFile = null, destFile = null; int padding = 8192; int stream = 0; string encoderMode = null; string encoderName = null; string encoderFormat = null; AudioEncoderType audioEncoderType = AudioEncoderType.NoAudio; var decoderOptions = new Dictionary <string, string>(); bool queryMeta = false; for (int arg = 0; arg < args.Length; arg++) { if (args[arg].Length == 0) { ok = false; } else if (args[arg] == "--encoder" && ++arg < args.Length) { encoderName = args[arg]; } else if (args[arg] == "--encoder-format" && ++arg < args.Length) { encoderFormat = args[arg]; } else if ((args[arg] == "-p" || args[arg] == "--padding") && ++arg < args.Length) { ok = int.TryParse(args[arg], out padding); } else if ((args[arg] == "-m" || args[arg] == "--mode") && arg + 1 < args.Length) { encoderMode = args[++arg]; } else if (args[arg] == "--lossy") { audioEncoderType = AudioEncoderType.Lossy; } else if (args[arg] == "--lossless") { audioEncoderType = AudioEncoderType.Lossless; } else if (args[arg] == "--ctdb") { queryMeta = true; } else if (args[arg] == "--decoder-option" && arg + 2 < args.Length) { var optionName = args[++arg]; var optionValue = args[++arg]; decoderOptions.Add(optionName, optionValue); } else if ((args[arg][0] != '-' || args[arg] == "-") && sourceFile == null) { sourceFile = args[arg]; } else if ((args[arg][0] != '-' || args[arg] == "-") && sourceFile != null && destFile == null) { destFile = args[arg]; var x = destFile.Split(':'); if (x.Length > 1) { stream = int.Parse(x[0]); if (x[1] != "") { destFile = x[1]; } else { arg++; if (arg >= args.Length) { ok = false; break; } destFile = args[arg]; } } } else { ok = false; } if (!ok) { break; } } if (!ok || sourceFile == null) { Usage(); return(22); } if (destFile != null && destFile != "-" && destFile != "nul" && File.Exists(destFile)) { Console.Error.WriteLine("Error: file {0} already exists.", destFile); return(17); } DateTime start = DateTime.Now; TimeSpan lastPrint = TimeSpan.FromMilliseconds(0); var config = new CUEConfigAdvanced(); config.Init(); #if !DEBUG try #endif { IAudioSource audioSource = null; IAudioTitleSet audioContainer = null; IAudioDest audioDest = null; var videos = new List <Codecs.MPEG.MPLS.MPLSStream>(); List <IAudioTitle> audios = null; List <TimeSpan> chapters = null; TagLib.UserDefined.AdditionalFileTypes.Config = config; #if !DEBUG try #endif { if (true) { IAudioDecoderSettings decoderSettings = null; if (Path.GetExtension(sourceFile) == ".mpls") { decoderSettings = new Codecs.MPEG.MPLS.DecoderSettings(); } else { decoderSettings = new Codecs.MPEG.ATSI.DecoderSettings(); } foreach (var decOpt in decoderOptions) { var property = TypeDescriptor.GetProperties(decoderSettings).Find(decOpt.Key, true); if (property == null) { throw new Exception($"{decoderSettings.Name} {decoderSettings.Extension} decoder settings object (of type {decoderSettings.GetType().FullName}) doesn't have a property named {decOpt.Key}."); } property.SetValue(decoderSettings, TypeDescriptor.GetConverter(property.PropertyType).ConvertFromString(decOpt.Value)); } audioSource = decoderSettings.Open(sourceFile); audioContainer = audioSource as IAudioTitleSet; if (audioContainer == null) { audioContainer = new SingleAudioTitleSet(audioSource); } Console.ForegroundColor = ConsoleColor.White; int frameRate = 0; bool interlaced = false; audios = audioContainer.AudioTitles; audios.ForEach(t => chapters = t.Chapters); if (audioSource is Codecs.MPEG.MPLS.AudioDecoder) { var mpls = audioSource as Codecs.MPEG.MPLS.AudioDecoder; mpls.MPLSHeader.play_item.ForEach(i => i.video.ForEach(v => { if (!videos.Exists(v1 => v1.pid == v.pid)) { videos.Add(v); } })); } videos.ForEach(v => { frameRate = v.FrameRate; interlaced = v.Interlaced; }); Console.Error.Write($@"M2TS, { videos.Count} video track{(videos.Count != 1 ? "s" : "")}, { audios.Count} audio track{(audios.Count != 1 ? "s" : "")}, { CDImageLayout.TimeToString(audios[0].GetDuration(), "{0:0}:{1:00}:{2:00}")}, { (frameRate * (interlaced ? 2 : 1))}{ (interlaced ? "i" : "p")}"); Console.Error.WriteLine(); //foreach (var item in mpls.MPLSHeader.play_item) //Console.Error.WriteLine("{0}.m2ts", item.clip_id); { Console.ForegroundColor = ConsoleColor.Gray; int id = 1; if (chapters.Count > 1) { Console.ForegroundColor = ConsoleColor.White; Console.Error.Write(id++); Console.Error.Write(": "); Console.ForegroundColor = ConsoleColor.Gray; Console.Error.WriteLine("Chapters, {0} chapters", chapters.Count - 1); } foreach (var video in videos) { Console.ForegroundColor = ConsoleColor.White; Console.Error.Write(id++); Console.Error.Write(": "); Console.ForegroundColor = ConsoleColor.Gray; Console.Error.WriteLine("{0}, {1}{2}", video.CodecString, video.FormatString, video.FrameRate * (video.Interlaced ? 2 : 1)); } foreach (var audio in audios) { Console.ForegroundColor = ConsoleColor.White; Console.Error.Write(id++); Console.Error.Write(": "); Console.ForegroundColor = ConsoleColor.Gray; Console.Error.WriteLine("{0}, {1}, {2}, {3}", audio.Codec, audio.Language, audio.GetFormatString(), audio.GetRateString()); } } } if (destFile == null) { return(0); } string strtoc = ""; for (int i = 0; i < chapters.Count; i++) { strtoc += string.Format(" {0}", (int)Math.Round((chapters[i].TotalSeconds * 75))); } strtoc = strtoc.Substring(1); CDImageLayout toc = new CDImageLayout(strtoc); CTDBResponseMeta meta = null; if (queryMeta) { var ctdb = new CUEToolsDB(toc, null); Console.Error.WriteLine("Contacting CTDB..."); ctdb.ContactDB(null, "CUETools.eac3to 2.1.8", "", false, true, CTDBMetadataSearch.Extensive); foreach (var imeta in ctdb.Metadata) { meta = imeta; break; } } if (stream > 0) { int chapterStreams = chapters.Count > 1 ? 1 : 0; if (stream <= chapterStreams) { if (destFile == "-" || destFile == "nul") { encoderFormat = "txt"; } else { string extension = Path.GetExtension(destFile).ToLower(); if (!extension.StartsWith(".")) { encoderFormat = destFile; if (meta == null || meta.artist == null || meta.album == null) { destFile = string.Format("{0}.{1}", Path.GetFileNameWithoutExtension(sourceFile), destFile); } else { destFile = string.Format("{0} - {1} - {2}.{3}", meta.artist, meta.year, meta.album, destFile); } } else { encoderFormat = extension.Substring(1); } if (encoderFormat != "txt" && encoderFormat != "cue") { throw new Exception(string.Format("Unsupported chapters file format \"{0}\"", encoderFormat)); } } Console.Error.WriteLine("Creating file \"{0}\"...", destFile); if (encoderFormat == "txt") { using (TextWriter sw = destFile == "nul" ? (TextWriter) new StringWriter() : destFile == "-" ? Console.Out : (TextWriter) new StreamWriter(destFile)) { for (int i = 0; i < chapters.Count - 1; i++) { sw.WriteLine("CHAPTER{0:00}={1}", i + 1, CDImageLayout.TimeToString(chapters[i])); if (meta != null && meta.track.Length >= toc[i + 1].Number) { sw.WriteLine("CHAPTER{0:00}NAME={1}", i + 1, meta.track[(int)toc[i + 1].Number - 1].name); } else { sw.WriteLine("CHAPTER{0:00}NAME=", i + 1); } } } Console.BackgroundColor = ConsoleColor.DarkGreen; Console.Error.Write("Done."); Console.BackgroundColor = ConsoleColor.Black; Console.Error.WriteLine(); return(0); } if (encoderFormat == "cue") { using (StreamWriter cueWriter = new StreamWriter(destFile, false, Encoding.UTF8)) { cueWriter.WriteLine("REM COMMENT \"{0}\"", "Created by CUETools.eac3to"); if (meta != null && meta.year != null) { cueWriter.WriteLine("REM DATE {0}", meta.year); } else { cueWriter.WriteLine("REM DATE XXXX"); } if (meta != null) { cueWriter.WriteLine("PERFORMER \"{0}\"", meta.artist); cueWriter.WriteLine("TITLE \"{0}\"", meta.album); } else { cueWriter.WriteLine("PERFORMER \"\""); cueWriter.WriteLine("TITLE \"\""); } if (meta != null) { //cueWriter.WriteLine("FILE \"{0}\" WAVE", Path.GetFileNameWithoutExtension(destFile) + (extension ?? ".wav")); cueWriter.WriteLine("FILE \"{0}\" WAVE", Path.GetFileNameWithoutExtension(destFile) + (".wav")); } else { cueWriter.WriteLine("FILE \"{0}\" WAVE", ""); } for (int track = 1; track <= toc.TrackCount; track++) { if (toc[track].IsAudio) { cueWriter.WriteLine(" TRACK {0:00} AUDIO", toc[track].Number); if (meta != null && meta.track.Length >= toc[track].Number) { cueWriter.WriteLine(" TITLE \"{0}\"", meta.track[(int)toc[track].Number - 1].name); if (meta.track[(int)toc[track].Number - 1].artist != null) { cueWriter.WriteLine(" PERFORMER \"{0}\"", meta.track[(int)toc[track].Number - 1].artist); } } else { cueWriter.WriteLine(" TITLE \"\""); } if (toc[track].ISRC != null) { cueWriter.WriteLine(" ISRC {0}", toc[track].ISRC); } for (int index = toc[track].Pregap > 0 ? 0 : 1; index <= toc[track].LastIndex; index++) { cueWriter.WriteLine(" INDEX {0:00} {1}", index, toc[track][index].MSF); } } } } Console.BackgroundColor = ConsoleColor.DarkGreen; Console.Error.Write("Done."); Console.BackgroundColor = ConsoleColor.Black; Console.Error.WriteLine(); return(0); } throw new Exception("Unknown encoder format: " + destFile); } if (stream - chapterStreams <= videos.Count) { throw new Exception("Video extraction not supported."); } if (stream - chapterStreams - videos.Count > audios.Count) { throw new Exception(string.Format("The source file doesn't contain a track with the number {0}.", stream)); } int streamId = audios[stream - chapterStreams - videos.Count - 1].StreamId; if (audioSource is Codecs.MPEG.MPLS.AudioDecoder) { (audioSource.Settings as Codecs.MPEG.MPLS.DecoderSettings).StreamId = streamId; } } AudioBuffer buff = new AudioBuffer(audioSource, 0x10000); Console.Error.WriteLine("Filename : {0}", sourceFile); Console.Error.WriteLine("File Info : {0}kHz; {1} channel; {2} bit; {3}", audioSource.PCM.SampleRate, audioSource.PCM.ChannelCount, audioSource.PCM.BitsPerSample, audioSource.Duration); CUEToolsFormat fmt; if (encoderFormat == null) { if (destFile == "-" || destFile == "nul") { encoderFormat = "wav"; } else { string extension = Path.GetExtension(destFile).ToLower(); if (!extension.StartsWith(".")) { encoderFormat = destFile; if (meta == null || meta.artist == null || meta.album == null) { destFile = string.Format("{0} - {1}.{2}", Path.GetFileNameWithoutExtension(sourceFile), stream, destFile); } else { destFile = string.Format("{0} - {1} - {2}.{3}", meta.artist, meta.year, meta.album, destFile); } } else { encoderFormat = extension.Substring(1); } if (File.Exists(destFile)) { throw new Exception(string.Format("Error: file {0} already exists.", destFile)); } } } if (!config.formats.TryGetValue(encoderFormat, out fmt)) { throw new Exception("Unsupported encoder format: " + encoderFormat); } AudioEncoderSettingsViewModel encoder = audioEncoderType == AudioEncoderType.Lossless ? Program.GetEncoder(config, fmt, true, encoderName) : audioEncoderType == AudioEncoderType.Lossy ? Program.GetEncoder(config, fmt, false, encoderName) : Program.GetEncoder(config, fmt, true, encoderName) ?? Program.GetEncoder(config, fmt, false, encoderName); if (encoder == null) { var lst = new List <AudioEncoderSettingsViewModel>(config.encodersViewModel).FindAll( e => e.Extension == fmt.extension && (audioEncoderType == AudioEncoderType.NoAudio || audioEncoderType == (e.Lossless ? AudioEncoderType.Lossless : AudioEncoderType.Lossy))). ConvertAll(e => e.Name + (e.Lossless ? " (lossless)" : " (lossy)")); throw new Exception("Encoders available for format " + fmt.extension + ": " + (lst.Count == 0 ? "none" : string.Join(", ", lst.ToArray()))); } Console.Error.WriteLine("Output {0} : {1}", stream, destFile); var settings = encoder.Settings.Clone(); settings.PCM = audioSource.PCM; settings.Padding = padding; settings.EncoderMode = encoderMode ?? settings.EncoderMode; object o = null; try { o = destFile == "-" ? Activator.CreateInstance(settings.EncoderType, settings, "", Console.OpenStandardOutput()) : destFile == "nul" ? Activator.CreateInstance(settings.EncoderType, settings, "", new NullStream()) : Activator.CreateInstance(settings.EncoderType, settings, destFile, null); } catch (System.Reflection.TargetInvocationException ex) { throw ex.InnerException; } if (o == null || !(o is IAudioDest)) { throw new Exception("Unsupported audio type: " + destFile + ": " + settings.EncoderType.FullName); } audioDest = o as IAudioDest; audioDest.FinalSampleCount = audioSource.Length; bool keepRunning = true; Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e) { keepRunning = false; if (e.SpecialKey == ConsoleSpecialKey.ControlC) { e.Cancel = true; } else { audioDest.Delete(); } }; while (audioSource.Read(buff, -1) != 0) { audioDest.Write(buff); TimeSpan elapsed = DateTime.Now - start; if ((elapsed - lastPrint).TotalMilliseconds > 60) { var duration = audioSource.Duration; var position = TimeSpan.FromSeconds((double)audioSource.Position / audioSource.PCM.SampleRate); if (duration < position) { duration = position; } if (duration < TimeSpan.FromSeconds(1)) { duration = TimeSpan.FromSeconds(1); } Console.Error.Write("\rProgress : {0:00}%; {1:0.00}x; {2}/{3}", 100.0 * position.TotalSeconds / duration.TotalSeconds, position.TotalSeconds / elapsed.TotalSeconds, elapsed, TimeSpan.FromSeconds(elapsed.TotalSeconds / position.TotalSeconds * duration.TotalSeconds) ); lastPrint = elapsed; } if (!keepRunning) { throw new Exception("Aborted"); } } TimeSpan totalElapsed = DateTime.Now - start; Console.Error.Write("\r \r"); Console.Error.WriteLine("Results : {0:0.00}x; {1}", audioSource.Position / totalElapsed.TotalSeconds / audioSource.PCM.SampleRate, totalElapsed ); } #if !DEBUG catch (Exception ex) { if (audioSource != null) { audioSource.Close(); } if (audioDest != null) { audioDest.Delete(); } throw ex; } #endif audioSource.Close(); audioDest.Close(); if (sourceFile != "-" && destFile != "-" && destFile != "nul") { //TagLib.File destInfo = TagLib.File.Create(new TagLib.File.LocalFileAbstraction(destFile)); //NameValueCollection tags; //if (Tagging.UpdateTags(destInfo, tags, config, false)) //{ // destInfo.Save(); //} } } #if !DEBUG catch (Exception ex) { Console.Error.Write("\r \r"); Console.BackgroundColor = ConsoleColor.DarkRed; Console.Error.Write("Error : {0}", ex.Message); Console.BackgroundColor = ConsoleColor.Black; Console.Error.WriteLine(); return(1); //Console.WriteLine("{0}", ex.StackTrace); } #endif return(0); }
public static string GetRipperLog(CUESheet sheet) { StringWriter logWriter = new StringWriter(CultureInfo.InvariantCulture); logWriter.WriteLine("{0}", sheet.CDRipper.RipperVersion); logWriter.WriteLine("Extraction logfile from : {0}", DateTime.Now); logWriter.WriteLine("Used drive : {0}", sheet.CDRipper.ARName); logWriter.WriteLine("Read offset correction : {0}", sheet.CDRipper.DriveOffset); logWriter.WriteLine("Read command : {0}", sheet.CDRipper.CurrentReadCommand); logWriter.WriteLine("Secure mode : {0}", sheet.CDRipper.CorrectionQuality); logWriter.WriteLine("Disk length : {0}", CDImageLayout.TimeToString(sheet.TOC.AudioLength)); logWriter.WriteLine("AccurateRip : {0}", sheet.ArVerify.ARStatus == null ? "ok" : sheet.ArVerify.ARStatus); if (sheet.HDCDDecoder != null && string.Format("{0:s}", sheet.HDCDDecoder) != "") { logWriter.WriteLine("HDCD : {0:f}", sheet.HDCDDecoder); } logWriter.WriteLine(); logWriter.WriteLine("TOC of the extracted CD"); logWriter.WriteLine(); logWriter.Write(GetTOCContents(sheet)); logWriter.WriteLine(); logWriter.WriteLine(" Track | Pregap | Indexes"); logWriter.WriteLine(" ---------------------------------------------------------"); for (int track = 1; track <= sheet.TOC.TrackCount; track++) { logWriter.WriteLine("{0,9} | {1,8} | {2,2}", sheet.TOC[track].Number, CDImageLayout.TimeToString(sheet.TOC[track].Pregap + (track == 1 ? 150U : 0U)), sheet.TOC[track].LastIndex); } logWriter.WriteLine(); logWriter.WriteLine("Destination files"); foreach (string path in sheet.DestPaths) { logWriter.WriteLine(" {0}", path); } bool wereErrors = sheet.PrintErrors(logWriter, sheet.TOC[sheet.TOC.FirstAudio][0].Start, sheet.TOC.AudioLength); if (wereErrors) { logWriter.WriteLine(); if (wereErrors) { logWriter.WriteLine("There were errors"); } else { logWriter.WriteLine("No errors occurred"); } } if (sheet.IsUsingCUEToolsDB) { logWriter.WriteLine(); sheet.GenerateCTDBLog(logWriter); } if (sheet.IsUsingAccurateRip) { logWriter.WriteLine(); logWriter.WriteLine("AccurateRip summary"); logWriter.WriteLine(); sheet.ArVerify.GenerateFullLog(logWriter, true, AccurateRipVerify.CalculateAccurateRipId(sheet.TOC)); } logWriter.WriteLine(); logWriter.WriteLine("End of status report"); logWriter.Close(); return(logWriter.ToString()); }
public static string GetExactAudioCopyLog(CUESheet sheet) { StringWriter logWriter = new StringWriter(CultureInfo.InvariantCulture); string eacHeader = "{7}\r\n" + "\r\n" + "EAC extraction logfile from {0:d'.' MMMM yyyy', 'H':'mm}\r\n" + "\r\n" + "{1} / {2}\r\n" + "\r\n" + "Used drive : {3} Adapter: 1 ID: 0\r\n" + "\r\n" + "Read mode : {4}\r\n" + "Utilize accurate stream : Yes\r\n" + "Defeat audio cache : Yes\r\n" + "Make use of C2 pointers : No\r\n" + "\r\n" + "Read offset correction : {5}\r\n" + "Overread into Lead-In and Lead-Out : No\r\n" + "Fill up missing offset samples with silence : Yes\r\n" + "Delete leading and trailing silent blocks : No\r\n" + "Null samples used in CRC calculations : Yes\r\n" + "Used interface : Native Win32 interface for Win NT & 2000\r\n" + "{6}" + "\r\n" + "Used output format : Internal WAV Routines\r\n" + "Sample format : 44.100 Hz; 16 Bit; Stereo\r\n"; logWriter.WriteLine(eacHeader, DateTime.Now, sheet.Metadata.Artist, sheet.Metadata.Title, sheet.CDRipper.EACName, sheet.CDRipper.CorrectionQuality > 0 ? "Secure" : "Burst", sheet.CDRipper.DriveOffset, (sheet.OutputStyle == CUEStyle.SingleFile || sheet.OutputStyle == CUEStyle.SingleFileWithCUE) ? "" : "Gap handling : " + (sheet.CDRipper.GapsDetected ? "Appended to previous track\r\n" : "Not detected, thus appended to previous track\r\n"), sheet.CDRipper.RipperVersion); // "Exact Audio Copy V0.99 prebeta 4 from 23. January 2008" logWriter.WriteLine(); logWriter.WriteLine("TOC of the extracted CD"); logWriter.WriteLine(); logWriter.Write(GetTOCContents(sheet)); logWriter.WriteLine(); bool htoaToFile = ((sheet.OutputStyle == CUEStyle.GapsAppended) && sheet.Config.preserveHTOA && (sheet.TOC.Pregap != 0)); int accurateTracks = 0, knownTracks = 0; bool wereErrors = false; if (sheet.OutputStyle != CUEStyle.SingleFile && sheet.OutputStyle != CUEStyle.SingleFileWithCUE) { logWriter.WriteLine(); for (int track = 0; track < sheet.TOC.AudioTracks; track++) { logWriter.WriteLine("Track {0,2}", track + 1); logWriter.WriteLine(); logWriter.WriteLine(" Filename {0}", Path.ChangeExtension(Path.GetFullPath(sheet.DestPaths[track + (htoaToFile ? 1 : 0)]), ".wav")); if (sheet.TOC[track + sheet.TOC.FirstAudio].Pregap > 0 || track + sheet.TOC.FirstAudio == 1) { logWriter.WriteLine(); logWriter.WriteLine(" Pre-gap length 0:{0}.{1:00}", CDImageLayout.TimeToString("{0:00}:{1:00}", sheet.TOC[track + sheet.TOC.FirstAudio].Pregap + (track + sheet.TOC.FirstAudio == 1 ? 150U : 0U)), (sheet.TOC[track + sheet.TOC.FirstAudio].Pregap % 75) * 100 / 75); } wereErrors |= sheet.PrintErrors(logWriter, sheet.TOC[track + sheet.TOC.FirstAudio].Start, sheet.TOC[track + sheet.TOC.FirstAudio].Length); logWriter.WriteLine(); logWriter.WriteLine(" Peak level {0:F1} %", (sheet.ArVerify.PeakLevel(track + 1) * 1000 / 65534) * 0.1); logWriter.WriteLine(" Track quality {0:F1} %", GetRangeQuality(sheet, sheet.TOC[track + sheet.TOC.FirstAudio].Start, sheet.TOC[track + sheet.TOC.FirstAudio].Length)); if (sheet.ArTestVerify != null) { logWriter.WriteLine(" Test CRC {0:X8}", sheet.ArTestVerify.CRC32(track + 1)); } logWriter.WriteLine(" Copy CRC {0:X8}", sheet.ArVerify.CRC32(track + 1)); if (sheet.ArVerify.Total(track) == 0) { logWriter.WriteLine(" Track not present in AccurateRip database"); } else { knownTracks++; if (sheet.ArVerify.Confidence(track) == 0) { logWriter.WriteLine(" Cannot be verified as accurate (confidence {0}) [{1:X8}], AccurateRip returned [{2:X8}]", sheet.ArVerify.Total(track), sheet.ArVerify.CRC(track), sheet.ArVerify.DBCRC(track)); } else { logWriter.WriteLine(" Accurately ripped (confidence {0}) [{1:X8}]", sheet.ArVerify.Confidence(track), sheet.ArVerify.CRC(track)); accurateTracks++; } } logWriter.WriteLine(" Copy OK"); logWriter.WriteLine(); } } else { logWriter.WriteLine(); logWriter.WriteLine("Range status and errors"); logWriter.WriteLine(); logWriter.WriteLine("Selected range"); logWriter.WriteLine(); logWriter.WriteLine(" Filename {0}", Path.ChangeExtension(Path.GetFullPath(sheet.DestPaths[0]), ".wav")); wereErrors = sheet.PrintErrors(logWriter, sheet.TOC[sheet.TOC.FirstAudio][0].Start, sheet.TOC.AudioLength); logWriter.WriteLine(); logWriter.WriteLine(" Peak level {0:F1} %", (sheet.ArVerify.PeakLevel() * 1000 / 65535) * 0.1); logWriter.WriteLine(" Range quality {0:F1} %", GetRangeQuality(sheet, sheet.TOC[sheet.TOC.FirstAudio][0].Start, sheet.TOC.AudioLength)); if (sheet.ArTestVerify != null) { logWriter.WriteLine(" Test CRC {0:X8}", sheet.ArTestVerify.CRC32(0)); } logWriter.WriteLine(" Copy CRC {0:X8}", sheet.ArVerify.CRC32(0)); logWriter.WriteLine(" Copy OK"); logWriter.WriteLine(); if (wereErrors) { logWriter.WriteLine("There were errors"); } else { logWriter.WriteLine("No errors occurred"); } logWriter.WriteLine(); logWriter.WriteLine(); logWriter.WriteLine("AccurateRip summary"); logWriter.WriteLine(); for (int track = 0; track < sheet.TOC.AudioTracks; track++) { if (sheet.ArVerify.Total(track) == 0) { logWriter.WriteLine("Track {0,2} not present in database", track + 1); } else { knownTracks++; if (sheet.ArVerify.Confidence(track) == 0) { logWriter.WriteLine("Track {3,2} cannot be verified as accurate (confidence {0}) [{1:X8}], AccurateRip returned [{2:X8}]", sheet.ArVerify.Total(track), sheet.ArVerify.CRC(track), sheet.ArVerify.DBCRC(track), track + 1); } else { logWriter.WriteLine("Track {2,2} accurately ripped (confidence {0}) [{1:X8}]", sheet.ArVerify.Confidence(track), sheet.ArVerify.CRC(track), track + 1); accurateTracks++; } } } } logWriter.WriteLine(); if (knownTracks == 0) { logWriter.WriteLine("None of the tracks are present in the AccurateRip database"); } else if (accurateTracks == 0) { logWriter.WriteLine("No tracks could be verified as accurate"); logWriter.WriteLine("You may have a different pressing from the one(s) in the database"); } else if (accurateTracks == sheet.TrackCount) { logWriter.WriteLine("All tracks accurately ripped"); } else { logWriter.WriteLine("{0,2} track(s) accurately ripped", accurateTracks); if (sheet.TrackCount - knownTracks > 0) { logWriter.WriteLine("{0,2} track(s) not present in the AccurateRip database", sheet.TrackCount - knownTracks); } logWriter.WriteLine(); logWriter.WriteLine("Some tracks could not be verified as accurate"); } logWriter.WriteLine(); if (sheet.OutputStyle != CUEStyle.SingleFile && sheet.OutputStyle != CUEStyle.SingleFileWithCUE) { if (wereErrors) { logWriter.WriteLine("There were errors"); } else { logWriter.WriteLine("No errors occurred"); } logWriter.WriteLine(); } logWriter.WriteLine("End of status report"); logWriter.Close(); return(logWriter.ToString()); }
public static void WriteAccurateRipLog(CUESheet sheet, TextWriter writer) { writer.WriteLine("[CUETools log; Date: {0}; Version: {1}]", DateTime.Now, CUESheet.CUEToolsVersion); if (sheet.PreGapLength != 0) { writer.WriteLine("Pregap length {0}.", sheet.PreGapLengthMSF); } if (!sheet.TOC[1].IsAudio) { writer.WriteLine("Playstation type data track length {0}.", sheet.TOC[sheet.TOC.FirstAudio].StartMSF); } if (!sheet.TOC[sheet.TOC.TrackCount].IsAudio) { writer.WriteLine("CD-Extra data track length {0}.", sheet.TOC[sheet.TOC.TrackCount].Length == 0 && sheet.MinDataTrackLength.HasValue ? CDImageLayout.TimeToString(sheet.MinDataTrackLength.Value) + " - " + CDImageLayout.TimeToString(sheet.MinDataTrackLength.Value + 74) : sheet.TOC[sheet.TOC.TrackCount].LengthMSF); } if (sheet.CDDBDiscIdTag != null && AccurateRipVerify.CalculateCDDBId(sheet.TOC).ToUpper() != sheet.CDDBDiscIdTag.ToUpper() && !sheet.MinDataTrackLength.HasValue) { writer.WriteLine("CDDBId mismatch: {0} vs {1}", sheet.CDDBDiscIdTag.ToUpper(), AccurateRipVerify.CalculateCDDBId(sheet.TOC).ToUpper()); } if (sheet.AccurateRipId != null && AccurateRipVerify.CalculateAccurateRipId(sheet.TOC) != sheet.AccurateRipId) { writer.WriteLine("Using preserved id, actual id is {0}.", AccurateRipVerify.CalculateAccurateRipId(sheet.TOC)); } if (sheet.Truncated4608) { writer.WriteLine("Truncated 4608 extra samples in some input files."); } if (sheet.PaddedToFrame) { writer.WriteLine("Padded some input files to a frame boundary."); } if (!sheet.Processed) { if (sheet.IsUsingCUEToolsDB) { sheet.GenerateCTDBLog(writer); } if (sheet.IsUsingAccurateRip) { writer.WriteLine("[AccurateRip ID: {0}] {1}.", sheet.AccurateRipId ?? AccurateRipVerify.CalculateAccurateRipId(sheet.TOC), sheet.ArVerify.ARStatus ?? "found"); } return; } if (sheet.HDCDDecoder != null && string.Format("{0:s}", sheet.HDCDDecoder) != "") { writer.WriteLine("HDCD: {0:f}", sheet.HDCDDecoder); } if (0 != sheet.WriteOffset) { writer.WriteLine("Offset applied: {0}", sheet.WriteOffset); } if (sheet.IsUsingCUEToolsDBFix)// && _CUEToolsDB.SelectedEntry != null) { writer.WriteLine("CUETools DB: corrected {0} errors.", sheet.CTDB.SelectedEntry.repair.CorrectableErrors); } else if (sheet.IsUsingCUEToolsDB) { sheet.GenerateCTDBLog(writer); } sheet.ArVerify.GenerateFullLog(writer, sheet.Config.arLogVerbose, sheet.AccurateRipId ?? AccurateRipVerify.CalculateAccurateRipId(sheet.TOC)); }