diff --git a/Bwg.Hardware/app.config b/Bwg.Hardware/app.config new file mode 100644 index 0000000..b7db281 --- /dev/null +++ b/Bwg.Hardware/app.config @@ -0,0 +1,3 @@ + + + diff --git a/Bwg.Logging/app.config b/Bwg.Logging/app.config new file mode 100644 index 0000000..b7db281 --- /dev/null +++ b/Bwg.Logging/app.config @@ -0,0 +1,3 @@ + + + diff --git a/Bwg.Scsi/Device.cs b/Bwg.Scsi/Device.cs index 2ee0b38..9b79def 100644 --- a/Bwg.Scsi/Device.cs +++ b/Bwg.Scsi/Device.cs @@ -2369,6 +2369,47 @@ namespace Bwg.Scsi return CommandStatus.Success ; } + /// + /// Read the subchannel data from a series of sectors + /// + /// subchannel mode + /// track number + /// output buffer + /// output buffer offset + /// timeout (in seconds) + /// + public CommandStatus ReadSubChannel42(byte mode, int track, ref byte[] data, int offs, int timeout) + { + if (m_logger != null) + { + m_logger.LogMessage(new UserMessage(UserMessage.Category.Debug, 8, "Bwg.Scsi.Device.ReadSubChannel42()")); + } + + if (mode != 1 && mode != 2 && mode != 3) + throw new Exception("invalid read mode for ReadSubchannel42() call"); + + int size = mode == 1 ? 16 : 24; + if (offs + data.GetLength(0) < size) + throw new Exception("data buffer is not large enough to hold the data requested"); + + using (Command cmd = new Command(ScsiCommandCode.ReadSubChannel, 10, size, Command.CmdDirection.In, timeout)) + { + // 42 00 40 01 00 00 00 00 10 00 + //cmd.SetCDB8(1, 2); // MSF + cmd.SetCDB8(2, 64); // SUBQ + cmd.SetCDB8(3, mode); + cmd.SetCDB8(6, (byte)track); + cmd.SetCDB16(7, (ushort)size); + + CommandStatus st = SendCommand(cmd); + if (st != CommandStatus.Success) + return st; + + Marshal.Copy(cmd.GetBuffer(), data, offs, size); + } + return CommandStatus.Success; + } + /// /// Read the CD text information from the leadin using the ReadTocPmaAtip command form /// @@ -3069,10 +3110,11 @@ namespace Bwg.Scsi string args = "info"; m_logger.LogMessage(new UserMessage(UserMessage.Category.Debug, 8, "Bwg.Scsi.Device.ReadFullToc(" + args + ")")); } - using (Command cmd = new Command(ScsiCommandCode.ReadTocPmaAtip, 10, 32, Command.CmdDirection.In, 5 * 60)) + using (Command cmd = new Command(ScsiCommandCode.ReadTocPmaAtip, 10, 320, Command.CmdDirection.In, 5 * 60)) { + cmd.SetCDB8(1, 2); cmd.SetCDB8(2, 3); - cmd.SetCDB16(7, 32); + cmd.SetCDB16(7, 320); CommandStatus st = SendCommand(cmd); if (st != CommandStatus.Success) @@ -3081,7 +3123,7 @@ namespace Bwg.Scsi len = cmd.GetBuffer16(0); len += 2; - if (len <= 32) + if (len <= 320) { data = new byte[len]; Marshal.Copy(cmd.GetBuffer(), data, 0, len); @@ -3380,7 +3422,7 @@ namespace Bwg.Scsi string args = ctrl.ToString() + ", " + read.ToString() + ", " + write.ToString(); m_logger.LogMessage(new UserMessage(UserMessage.Category.Debug, 8, "Bwg.Scsi.Device.SetCdSpeed(" + args + ")")); } - using (Command cmd = new Command(ScsiCommandCode.SetCdSpeed, 12, 0, Command.CmdDirection.None, 2)) + using (Command cmd = new Command(ScsiCommandCode.SetCdSpeed, 12, 0, Command.CmdDirection.Out, 30)) { cmd.SetCDB8(1, (byte)ctrl); cmd.SetCDB16(2, read); @@ -3393,6 +3435,30 @@ namespace Bwg.Scsi return CommandStatus.Success; } + /// + /// + /// + /// + public CommandStatus SetCdSpeedDA(RotationalControl ctrl, ushort read, ushort write) + { + if (m_logger != null) + { + string args = ctrl.ToString() + ", " + read.ToString() + ", " + write.ToString(); + m_logger.LogMessage(new UserMessage(UserMessage.Category.Debug, 8, "Bwg.Scsi.Device.SetCdSpeed(" + args + ")")); + } + using (Command cmd = new Command((ScsiCommandCode)0xDA, 12, 0, Command.CmdDirection.None, 2)) + { + cmd.SetCDB8(1, (byte)ctrl); + cmd.SetCDB16(2, read); + cmd.SetCDB16(4, write); + + CommandStatus st = SendCommand(cmd); + if (st != CommandStatus.Success) + return st; + } + return CommandStatus.Success; + } + /// /// /// diff --git a/Bwg.Scsi/app.config b/Bwg.Scsi/app.config new file mode 100644 index 0000000..b7db281 --- /dev/null +++ b/Bwg.Scsi/app.config @@ -0,0 +1,3 @@ + + + diff --git a/CUEControls/Properties/AssemblyInfo.cs b/CUEControls/Properties/AssemblyInfo.cs index 03ec260..02ba2cf 100644 --- a/CUEControls/Properties/AssemblyInfo.cs +++ b/CUEControls/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ using System.Runtime.InteropServices; // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("2.0.5.0")] -[assembly: AssemblyFileVersion("2.0.5.0")] +[assembly: AssemblyVersion("2.0.6.0")] +[assembly: AssemblyFileVersion("2.0.6.0")] diff --git a/CUERipper/CUERipper.csproj b/CUERipper/CUERipper.csproj index 3a3880f..5ec61d2 100644 --- a/CUERipper/CUERipper.csproj +++ b/CUERipper/CUERipper.csproj @@ -15,6 +15,35 @@ cue2.ico + F89503BB83CA42A647C506D67956D6F32C1C6E7E + CUERipper_TemporaryKey.pfx + true + true + true + publish\ + true + Web + true + Background + 7 + Days + false + false + true + http://www.cuetools.net/install/cueripper/ + http://www.cuetools.net/ + CUERipper + Gregory S. Chudov + true + index.html + 2 + 2.0.7.2 + false + true + true + false + + true @@ -131,21 +160,185 @@ - + - - - - - - - - + + + False + .NET Framework Client Profile + false + + + False + .NET Framework 2.0 %28x86%29 + true + + + False + .NET Framework 3.0 %28x86%29 + false + + + False + .NET Framework 3.5 + false + + + False + .NET Framework 3.5 SP1 + false + + + False + Visual C++ Runtime Libraries %28x64%29 + true + + + False + Visual C++ Runtime Libraries %28x86%29 + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + False + Plugins %28win32%29 + + + Auto + True + File + + + False + Plugins %28win32%29 + + + Auto + True + File + + + False + Plugins %28win32%29 + + + Auto + True + File + + + False + Plugins %28win32%29 + + + Auto + True + File + + + False + Plugins %28win32%29 + + + Auto + True + File + + + False + Plugins %28win32%29 + + + Auto + True + File + + + False + Plugins %28x64%29 + + + Auto + True + File + + + False + Plugins %28x64%29 + + + Auto + True + File + + + False + Plugins %28x64%29 + + + Auto + True + File + + + False + Plugins %28x64%29 + + + Auto + True + File + + + False + Plugins %28x64%29 + + + Auto + True + File + + + False + Plugins %28x64%29 + + + Auto + True + File + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + Top, Left, Right + + + + 48, 12 + + + 375, 20 + + + + 0 + + + textArtist + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 15 + + + True + + + 12, 15 + + + 30, 13 + + + 1 + + + Artist + + + label1 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 14 + + + True + + + NoControl + + + 12, 41 + + + 27, 13 + + + 3 + + + Title + + + label2 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 12 + + + Top, Left, Right + + + 48, 38 + + + 375, 20 + + + 2 + + + textTitle + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 13 + + + 347, 90 + + + 75, 23 + + + 14 + + + Ok + + + button1 + + + System.Windows.Forms.Button, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 11 + + + 266, 90 + + + 75, 23 + + + 15 + + + Cancel + + + button2 + + + System.Windows.Forms.Button, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 10 + + + True + + + 12, 67 + + + 29, 13 + + + 6 + + + Year + + + label3 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 9 + + + 48, 64 + + + 67, 20 + + + 7 + + + textYear + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 8 + + + 163, 64 + + + 100, 20 + + + 8 + + + textGenre + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 7 + + + 318, 64 + + + 104, 20 + + + 9 + + + textCatalog + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 6 + + + True + + + 121, 67 + + + 36, 13 + + + 10 + + + Genre + + + label4 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 5 + + + True + + + 269, 67 + + + 43, 13 + + + 11 + + + Catalog + + + label5 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 4 + + + True + + + 12, 95 + + + 22, 13 + + + 16 + + + CD + + + labelCD + + + System.Windows.Forms.Label, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 3 + + + 48, 92 + + + 50, 20 + + + 17 + + + textBoxDiscNumber + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 2 + + + 125, 92 + + + 50, 20 + + + 18 + + + textBoxTotalDiscs + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 1 + + + True + + + 107, 95 + + + 12, 13 + + + 19 + + + / + + + labelSlash + + + System.Windows.Forms.Label, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 0 + + + True + + + 6, 13 + + + 435, 127 + + + CenterParent + + + Release information + + + frmProperties + + + System.Windows.Forms.Form, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/CUETools.ALACEnc/Program.cs b/CUETools.ALACEnc/Program.cs index 59d5da1..d30913d 100644 --- a/CUETools.ALACEnc/Program.cs +++ b/CUETools.ALACEnc/Program.cs @@ -162,7 +162,7 @@ namespace CUETools.ALACEnc return 2; } if (buffered) - audioSource = new AudioPipe(audioSource, 0x10000, true); + audioSource = new AudioPipe(audioSource, 0x10000); if (output_file == null) output_file = Path.ChangeExtension(input_file, "m4a"); ALACWriter alac = new ALACWriter((output_file == "-" || output_file == "nul") ? "" : output_file, diff --git a/CUETools.ARCUE/Properties/AssemblyInfo.cs b/CUETools.ARCUE/Properties/AssemblyInfo.cs index 8e30727..7685f60 100644 --- a/CUETools.ARCUE/Properties/AssemblyInfo.cs +++ b/CUETools.ARCUE/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("2.0.5.0")] -[assembly: AssemblyFileVersion("2.0.5.0")] +[assembly: AssemblyVersion("2.0.6.0")] +[assembly: AssemblyFileVersion("2.0.6.0")] diff --git a/CUETools.AccurateRip/AccurateRip.cs b/CUETools.AccurateRip/AccurateRip.cs index 75b9b58..83dabea 100644 --- a/CUETools.AccurateRip/AccurateRip.cs +++ b/CUETools.AccurateRip/AccurateRip.cs @@ -30,8 +30,9 @@ namespace CUETools.AccurateRip return 0U; uint conf = 0; for (int di = 0; di < (int)AccDisks.Count; di++) - if (CRC(iTrack) == AccDisks[di].tracks[iTrack].CRC) - conf += AccDisks[di].tracks[iTrack].count; + if (iTrack + _toc.FirstAudio - 1 < AccDisks[di].tracks.Count + && CRC(iTrack) == AccDisks[di].tracks[iTrack + _toc.FirstAudio - 1].CRC) + conf += AccDisks[di].tracks[iTrack + _toc.FirstAudio - 1].count; return conf; } @@ -66,8 +67,9 @@ namespace CUETools.AccurateRip uint conf = 0; for (int iDisk = 0; iDisk < AccDisks.Count; iDisk++) for (int oi = -_arOffsetRange; oi <= _arOffsetRange; oi++) - if (CRC(iTrack, oi) == AccDisks[iDisk].tracks[iTrack].CRC) - conf += AccDisks[iDisk].tracks[iTrack].count; + if (iTrack + _toc.FirstAudio - 1 < AccDisks[iDisk].tracks.Count + && CRC(iTrack, oi) == AccDisks[iDisk].tracks[iTrack + _toc.FirstAudio - 1].CRC) + conf += AccDisks[iDisk].tracks[iTrack + _toc.FirstAudio - 1].count; return conf; } @@ -77,8 +79,9 @@ namespace CUETools.AccurateRip return 0U; uint conf = 0; for (int di = 0; di < (int)AccDisks.Count; di++) - if (CRC(iTrack, oi) == AccDisks[di].tracks[iTrack].CRC) - conf += AccDisks[di].tracks[iTrack].count; + if (iTrack +_toc.FirstAudio - 1 < AccDisks[di].tracks.Count + && CRC(iTrack, oi) == AccDisks[di].tracks[iTrack + _toc.FirstAudio - 1].CRC) + conf += AccDisks[di].tracks[iTrack + _toc.FirstAudio - 1].count; return conf; } @@ -88,13 +91,15 @@ namespace CUETools.AccurateRip return 0U; uint total = 0; for (int di = 0; di < (int)AccDisks.Count; di++) - total += AccDisks[di].tracks[iTrack].count; + if (iTrack + _toc.FirstAudio - 1 < AccDisks[di].tracks.Count) + total += AccDisks[di].tracks[iTrack + _toc.FirstAudio - 1].count; return total; } public uint DBCRC(int iTrack) { - return ARStatus == null ? AccDisks[0].tracks[iTrack].CRC : 0U; + return ARStatus == null && iTrack +_toc.FirstAudio - 1 < AccDisks[0].tracks.Count + ? AccDisks[0].tracks[iTrack + _toc.FirstAudio - 1].CRC : 0U; } public uint CRC(int iTrack) @@ -136,6 +141,20 @@ namespace CUETools.AccurateRip return crcb - crca - offs * (sumb - suma); } + public int PeakLevel() + { + int peak = 0; + for (int track = 0; track <= _toc.AudioTracks; track++) + if (peak < _Peak[track]) + peak = _Peak[track]; + return peak; + } + + public int PeakLevel(int iTrack) + { + return _Peak[iTrack]; + } + public uint CRC32(int iTrack) { return CRC32(iTrack, 0); @@ -310,6 +329,7 @@ namespace CUETools.AccurateRip uint crc32 = _CRC32[_currentTrack, 0]; uint crcwn = _CRCWN[_currentTrack, 0]; int crcnl = _CRCNL[_currentTrack, 0]; + int peak = _Peak[_currentTrack]; fixed (uint* t = _crc32.table) { for (int i = 0; i < count; i++) @@ -337,6 +357,9 @@ namespace CUETools.AccurateRip } else crcnl++; + int pk = ((int)(lo << 16)) >> 16; + peak = Math.Max(peak, (pk << 1) ^ (pk >> 31)); + uint hi = sample >> 16; crc32 = (crc32 >> 8) ^ t[(byte)(crc32 ^ hi)]; crc32 = (crc32 >> 8) ^ t[(byte)(crc32 ^ (hi >> 8))]; @@ -346,6 +369,9 @@ namespace CUETools.AccurateRip crcwn = (crcwn >> 8) ^ t[(byte)(crcwn ^ (hi >> 8))]; } else crcnl++; + + pk = ((int)(hi << 16)) >> 16; + peak = Math.Max(peak, (pk << 1) ^ (pk >> 31)); } } @@ -354,6 +380,7 @@ namespace CUETools.AccurateRip _CRC32[_currentTrack, 0] = crc32; _CRCWN[_currentTrack, 0] = crcwn; _CRCNL[_currentTrack, 0] = crcnl; + _Peak[_currentTrack] = peak; } public void Write(AudioBuffer sampleBuffer) @@ -401,6 +428,7 @@ namespace CUETools.AccurateRip _CRCWN = new uint[_toc.AudioTracks + 1, 31 * 588]; _CacheCRCWN = new uint[_toc.AudioTracks + 1, 31 * 588]; _CRCNL = new int[_toc.AudioTracks + 1, 31 * 588]; + _Peak = new int[_toc.AudioTracks + 1]; _currentTrack = 0; _sampleCount = _toc[_toc.FirstAudio][0].Start * 588; _samplesRemTrack = _toc[_toc.FirstAudio].Pregap * 588; @@ -572,11 +600,16 @@ namespace CUETools.AccurateRip uint conf = 0; for (int di = 0; di < (int)AccDisks.Count; di++) { - count += AccDisks[di].tracks[iTrack].count; - if (CRC(iTrack, oi) == AccDisks[di].tracks[iTrack].CRC) - conf += AccDisks[di].tracks[iTrack].count; - if (CRC450(iTrack, oi) == AccDisks[di].tracks[iTrack].Frame450CRC) - partials += AccDisks[di].tracks[iTrack].count; + int trno = iTrack + _toc.FirstAudio - 1; + if (trno >= AccDisks[di].tracks.Count) + continue; + count += AccDisks[di].tracks[trno].count; + if (CRC(iTrack, oi) == AccDisks[di].tracks[trno].CRC + && 0 != AccDisks[di].tracks[trno].CRC) + conf += AccDisks[di].tracks[trno].count; + if (CRC450(iTrack, oi) == AccDisks[di].tracks[trno].Frame450CRC + && 0 != AccDisks[di].tracks[trno].Frame450CRC) + partials += AccDisks[di].tracks[trno].count; } if (conf > 0) sw.WriteLine(String.Format(" {0:00}\t[{1:x8}] ({3:00}/{2:00}) Accurately ripped", iTrack + 1, CRC(iTrack, oi), count, conf)); @@ -612,12 +645,17 @@ namespace CUETools.AccurateRip { uint matches = 0; for (int iTrack = 0; iTrack < _toc.AudioTracks; iTrack++) + { + int trno = iTrack + _toc.FirstAudio - 1; for (int di = 0; di < (int)AccDisks.Count; di++) - if ((CRC(iTrack, oi) == AccDisks[di].tracks[iTrack].CRC && AccDisks[di].tracks[iTrack].CRC != 0)) + if (trno < AccDisks[di].tracks.Count + && (CRC(iTrack, oi) == AccDisks[di].tracks[trno].CRC + && AccDisks[di].tracks[trno].CRC != 0)) { matches++; break; } + } if (matches == _toc.AudioTracks && oi != 0) { if (offsets_match++ > 16) @@ -636,12 +674,17 @@ namespace CUETools.AccurateRip for (int iTrack = 0; iTrack < _toc.AudioTracks; iTrack++) for (int di = 0; di < (int)AccDisks.Count; di++) { - if ((CRC(iTrack, oi) == AccDisks[di].tracks[iTrack].CRC && AccDisks[di].tracks[iTrack].CRC != 0)) + int trno = iTrack + _toc.FirstAudio - 1; + if (trno < AccDisks[di].tracks.Count + && (CRC(iTrack, oi) == AccDisks[di].tracks[trno].CRC + && AccDisks[di].tracks[trno].CRC != 0)) { matches++; break; } - if ((CRC450(iTrack, oi) == AccDisks[di].tracks[iTrack].Frame450CRC && AccDisks[di].tracks[iTrack].Frame450CRC != 0)) + if (trno < AccDisks[di].tracks.Count + && (CRC450(iTrack, oi) == AccDisks[di].tracks[trno].Frame450CRC + && AccDisks[di].tracks[trno].Frame450CRC != 0)) partials++; } if (matches != _toc.AudioTracks && oi != 0 && matches + partials != 0) @@ -668,12 +711,15 @@ namespace CUETools.AccurateRip for (int oi = -_arOffsetRange; oi <= _arOffsetRange; oi++) for (int iDisk = 0; iDisk < AccDisks.Count; iDisk++) { - if (CRC(iTrack, oi) == AccDisks[iDisk].tracks[iTrack].CRC && (AccDisks[iDisk].tracks[iTrack].CRC != 0 || oi == 0)) + int trno = iTrack + _toc.FirstAudio - 1; + if (trno < AccDisks[iDisk].tracks.Count + && CRC(iTrack, oi) == AccDisks[iDisk].tracks[trno].CRC + && (AccDisks[iDisk].tracks[trno].CRC != 0 || oi == 0)) { - conf += AccDisks[iDisk].tracks[iTrack].count; + conf += AccDisks[iDisk].tracks[trno].count; if (oi == 0) zeroOffset = true; - pressings.AppendFormat("{0}{1}({2})", pressings.Length > 0 ? "," : "", oi, AccDisks[iDisk].tracks[iTrack].count); + pressings.AppendFormat("{0}{1}({2})", pressings.Length > 0 ? "," : "", oi, AccDisks[iDisk].tracks[trno].count); } } if (conf > 0 && zeroOffset && pressings.Length == 0) @@ -692,7 +738,7 @@ namespace CUETools.AccurateRip if (CRC32(0) != 0 && (_hasLogCRC || verbose)) { sw.WriteLine(""); - sw.WriteLine("Track\t[ CRC32 ]\t[W/O NULL]\t{0:10}", _hasLogCRC ? "[ LOG ]" : ""); + sw.WriteLine("Track Peak [ CRC32 ] [W/O NULL] {0:10}", _hasLogCRC ? "[ LOG ]" : ""); for (int iTrack = 0; iTrack <= _toc.AudioTracks; iTrack++) { string inLog, extra = ""; @@ -740,7 +786,13 @@ namespace CUETools.AccurateRip } } } - sw.WriteLine(String.Format(" {0}\t[{1:X8}]\t[{2:X8}]\t{3:10}{4}", iTrack == 0 ? "--" : string.Format("{0:00}", iTrack), CRC32(iTrack), CRCWONULL(iTrack), inLog, extra)); + sw.WriteLine(" {0} {5,5:F1} [{1:X8}] [{2:X8}] {3,10}{4}", + iTrack == 0 ? "--" : string.Format("{0:00}", iTrack), + CRC32(iTrack), + CRCWONULL(iTrack), + inLog, + extra, + ((iTrack == 0 ? PeakLevel() : PeakLevel(iTrack)) * 1000 / 65535) * 0.1); } } } @@ -897,6 +949,7 @@ namespace CUETools.AccurateRip private int[,] _CRCNL; private uint[,] _CacheCRCWN; private uint[,] _CacheCRC32; + private int[] _Peak; private uint[] _CRCLOG; private IWebProxy proxy; diff --git a/CUETools.AccurateRip/CUETools.AccurateRip.csproj b/CUETools.AccurateRip/CUETools.AccurateRip.csproj index 2dac3ef..3e7f423 100644 --- a/CUETools.AccurateRip/CUETools.AccurateRip.csproj +++ b/CUETools.AccurateRip/CUETools.AccurateRip.csproj @@ -14,6 +14,9 @@ 2.0 + false + + true diff --git a/CUETools.AccurateRip/Properties/AssemblyInfo.cs b/CUETools.AccurateRip/Properties/AssemblyInfo.cs index 4274380..9ba5ffe 100644 --- a/CUETools.AccurateRip/Properties/AssemblyInfo.cs +++ b/CUETools.AccurateRip/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ using System.Runtime.InteropServices; // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("2.0.5.0")] -[assembly: AssemblyFileVersion("2.0.5.0")] +[assembly: AssemblyVersion("2.0.6.0")] +[assembly: AssemblyFileVersion("2.0.6.0")] diff --git a/CUETools.CDImage/CDImage.cs b/CUETools.CDImage/CDImage.cs index 141e31d..f0fda06 100644 --- a/CUETools.CDImage/CDImage.cs +++ b/CUETools.CDImage/CDImage.cs @@ -253,6 +253,26 @@ namespace CUETools.CDImage _tracks.Add(new CDTrack(src._tracks[i])); } + public CDImageLayout(int trackcount, int audiotracks, int firstaudio, string trackoffsets) + { + _audioTracks = audiotracks; + _firstAudio = firstaudio - 1; + _tracks = new List(); + string[] n = trackoffsets.Split(' '); + if (n.Length != trackcount + 1) + throw new Exception("Invalid trackoffsets."); + for (int i = 0; i < trackcount; i++) + { + uint len = uint.Parse(n[i + 1]) - uint.Parse(n[i]) - + ((i + 1 < _firstAudio + _audioTracks || i + 1 == trackcount) ? 0U : 152U * 75U); + bool isaudio = i >= _firstAudio && i < _firstAudio + _audioTracks; + _tracks.Add(new CDTrack((uint)i + 1, uint.Parse(n[i]), len, isaudio, false)); + } + _tracks[0][0].Start = 0; + if (TrackOffsets != trackoffsets) + throw new Exception("TrackOffsets != trackoffsets"); + } + public object Clone() { return new CDImageLayout(this); @@ -306,6 +326,14 @@ namespace CUETools.CDImage } } + public uint Leadout + { + get + { + return _tracks[_firstAudio][0].Start + AudioLength; + } + } + public uint AudioLength { get @@ -326,20 +354,69 @@ namespace CUETools.CDImage } } + public string MusicBrainzTOC + { + get + { + StringBuilder mbSB = new StringBuilder(); + mbSB.AppendFormat("{0} {1}", 1 + _firstAudio, AudioTracks + _firstAudio); + mbSB.AppendFormat(" {0}", _tracks[_firstAudio + (int)AudioTracks - 1].End + 1 + 150); + for (int iTrack = 0; iTrack < AudioTracks; iTrack++) + mbSB.AppendFormat(" {0}", _tracks[_firstAudio + iTrack].Start + 150); + return mbSB.ToString(); + } + } + public string MusicBrainzId { get { StringBuilder mbSB = new StringBuilder(); - mbSB.AppendFormat("{0:X2}{1:X2}{2:X8}", 1, AudioTracks, _tracks[(int)AudioTracks-1].End + 1 + 150); + mbSB.AppendFormat("{0:X2}{1:X2}", 1 + _firstAudio, AudioTracks + _firstAudio); + mbSB.AppendFormat("{0:X8}", _tracks[_firstAudio + (int)AudioTracks - 1].End + 1 + 150); for (int iTrack = 0; iTrack < AudioTracks; iTrack++) - mbSB.AppendFormat("{0:X8}", _tracks[iTrack].Start + 150); + mbSB.AppendFormat("{0:X8}", _tracks[_firstAudio + iTrack].Start + 150); mbSB.Append(new string('0', (99 - (int)AudioTracks) * 8)); byte[] hashBytes = (new SHA1CryptoServiceProvider()).ComputeHash(Encoding.ASCII.GetBytes(mbSB.ToString())); return Convert.ToBase64String(hashBytes).Replace('+', '.').Replace('/', '_').Replace('=', '-'); } } + public string TrackOffsets + { + get + { + StringBuilder mbSB = new StringBuilder(); + for (int iTrack = 0; iTrack < TrackCount; iTrack++) + mbSB.AppendFormat("{0} ", _tracks[iTrack].Start); + mbSB.AppendFormat("{0}", Length); + return mbSB.ToString(); + } + } + + public string TOCID + { + get + { + StringBuilder mbSB = new StringBuilder(); + for (int iTrack = 1; iTrack < AudioTracks; iTrack++) + mbSB.AppendFormat("{0:X8}", _tracks[_firstAudio + iTrack].Start - _tracks[_firstAudio].Start); + mbSB.AppendFormat("{0:X8}", _tracks[_firstAudio + (int)AudioTracks - 1].End + 1 - _tracks[_firstAudio].Start); + mbSB.Append(new string('0', (100 - (int)AudioTracks) * 8)); + byte[] hashBytes = (new SHA1CryptoServiceProvider()).ComputeHash(Encoding.ASCII.GetBytes(mbSB.ToString())); + return Convert.ToBase64String(hashBytes).Replace('+', '.').Replace('/', '_').Replace('=', '-'); + } + } + + public void InsertTrack(CDTrack track) + { + _tracks.Insert((int)track.Number - 1, track); + if (track.IsAudio) + _audioTracks++; + if (!track.IsAudio && track.Number <= FirstAudio) + _firstAudio++; + } + public void AddTrack(CDTrack track) { _tracks.Add(track); diff --git a/CUETools.CDImage/CUETools.CDImage.csproj b/CUETools.CDImage/CUETools.CDImage.csproj index 684d025..68bb0f3 100644 --- a/CUETools.CDImage/CUETools.CDImage.csproj +++ b/CUETools.CDImage/CUETools.CDImage.csproj @@ -14,6 +14,9 @@ 2.0 + false + + true diff --git a/CUETools.CDImage/Properties/AssemblyInfo.cs b/CUETools.CDImage/Properties/AssemblyInfo.cs index 07c6c27..b6d33e0 100644 --- a/CUETools.CDImage/Properties/AssemblyInfo.cs +++ b/CUETools.CDImage/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ using System.Runtime.InteropServices; // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("2.0.5.0")] -[assembly: AssemblyFileVersion("2.0.5.0")] +[assembly: AssemblyVersion("2.0.6.0")] +[assembly: AssemblyFileVersion("2.0.6.0")] diff --git a/CUETools.CDRepair/CDRepair.cs b/CUETools.CDRepair/CDRepair.cs index 3759897..ed9300a 100644 --- a/CUETools.CDRepair/CDRepair.cs +++ b/CUETools.CDRepair/CDRepair.cs @@ -325,10 +325,13 @@ namespace CUETools.CDRepair new public unsafe void Write(AudioBuffer sampleBuffer) { + if (!verify && !encode) + return; + sampleBuffer.Prepare(this); - if ((sampleBuffer.ByteLength & 1) != 0) - throw new Exception("never happens"); + if ((sampleBuffer.ByteLength & 1) != 0 || sampleCount + sampleBuffer.Length > finalSampleCount) + throw new Exception("sampleCount > finalSampleCount"); fixed (byte* bytes = sampleBuffer.Bytes) { diff --git a/CUETools.CTDB/CUEToolsDB.cs b/CUETools.CTDB/CUEToolsDB.cs index ccbb0fb..c1fb2f7 100644 --- a/CUETools.CTDB/CUEToolsDB.cs +++ b/CUETools.CTDB/CUEToolsDB.cs @@ -5,6 +5,7 @@ using System.Globalization; using System.IO; using System.Management; using System.Net; +using System.Xml; using System.Text; using CUETools.CDImage; using CUETools.CDRepair; @@ -20,11 +21,7 @@ namespace CUETools.CTDB private CDRepairEncode verify; private CDImageLayout toc; private HttpStatusCode accResult; - private string id; - private string urlfolder; - private string fullid; private string subResult; - private byte[] contents; private int length; private int total; List entries = new List(); @@ -40,27 +37,86 @@ namespace CUETools.CTDB this.uploadHelper = new HttpUploadHelper(); } - public void ContactDB(string id, string userAgent) + public void ContactDB(string userAgent) { this.userAgent = userAgent; - this.id = id; + this.total = 0; - // Calculate the three disc ids used by AR - uint discId1 = 0; - uint discId2 = 0; - uint cddbDiscId = 0; + HttpWebRequest req = (HttpWebRequest)WebRequest.Create(urlbase + "/lookup.php?tocid=" + toc.TOCID); + req.Method = "GET"; + req.Proxy = proxy; + req.UserAgent = userAgent; - string[] n = id.Split('-'); - if (n.Length != 3) - throw new Exception("Invalid accurateRipId."); - discId1 = UInt32.Parse(n[0], NumberStyles.HexNumber); - discId2 = UInt32.Parse(n[1], NumberStyles.HexNumber); - cddbDiscId = UInt32.Parse(n[2], NumberStyles.HexNumber); + if (uploadHelper.onProgress != null) + uploadHelper.onProgress(this, new UploadProgressEventArgs(req.RequestUri.AbsoluteUri, 0)); - fullid = string.Format("{0:d3}-{1:x8}-{2:x8}-{3:x8}", toc.AudioTracks, discId1, discId2, cddbDiscId); - urlfolder = string.Format("{0}/parity/{1:x}/{2:x}/{3:x}/{4}", urlbase, discId1 & 0xF, discId1 >> 4 & 0xF, discId1 >> 8 & 0xF, fullid); - - FetchDB(string.Format("{0}/ctdb.bin", urlfolder), out accResult, out contents, out total, entries); + try + { + HttpWebResponse resp = (HttpWebResponse)req.GetResponse(); + accResult = resp.StatusCode; + + if (accResult == HttpStatusCode.OK) + { + total = 0; + using (Stream responseStream = resp.GetResponseStream()) + { + using (XmlTextReader reader = new XmlTextReader(responseStream)) + { + reader.ReadToFollowing("ctdb"); + if (reader.ReadToDescendant("entry")) + do + { + XmlReader entry = reader.ReadSubtree(); + string crc32 = reader["crc32"]; + string confidence = reader["confidence"]; + string npar = reader["npar"]; + string stride = reader["stride"]; + string id = reader["id"]; + byte[] parity = null; + CDImageLayout entry_toc = null; + + entry.Read(); + while (entry.Read() && entry.NodeType != XmlNodeType.EndElement) + { + if (entry.Name == "parity") + { + entry.Read(); // entry.NodeType == XmlNodeType.Text + parity = Convert.FromBase64String(entry.Value); + entry.Read(); + } + else if (entry.Name == "toc") + { + string trackcount = entry["trackcount"]; + string audiotracks = entry["audiotracks"]; + string firstaudio = entry["firstaudio"]; + entry.Read(); + string trackoffsets = entry.Value; + entry.Read(); + entry_toc = new CDImageLayout(int.Parse(trackcount), int.Parse(audiotracks), int.Parse(firstaudio), trackoffsets); + } + else + { + reader.Skip(); + } + } + entry.Close(); + total += int.Parse(confidence); + entries.Add(new DBEntry(parity, 0, parity.Length, int.Parse(confidence), int.Parse(npar), uint.Parse(crc32, NumberStyles.HexNumber), id, entry_toc)); + } while (reader.ReadToNextSibling("entry")); + reader.Close(); + } + } + if (entries.Count == 0) + accResult = HttpStatusCode.NotFound; + } + } + catch (WebException ex) + { + if (ex.Status == WebExceptionStatus.ProtocolError) + accResult = ((HttpWebResponse)ex.Response).StatusCode; + else + accResult = HttpStatusCode.BadRequest; + } } public void FetchDB(string url, out HttpStatusCode accResult, out byte[] contents, out int total, List entries) @@ -110,45 +166,52 @@ namespace CUETools.CTDB } } - static string cpuInfo = null; + static string uuidInfo = null; - public static string GetCPUID() + public static string GetUUID() { - if (cpuInfo == null) + if (uuidInfo == null) { - ManagementClass mc = new ManagementClass("win32_processor"); + ManagementClass mc = new ManagementClass("Win32_ComputerSystemProduct"); foreach (ManagementObject mo in mc.GetInstances()) { - //Get only the first CPU's ID - cpuInfo = mo.Properties["processorID"].Value.ToString(); + uuidInfo = mo.Properties["UUID"].Value.ToString(); break; } } - return cpuInfo ?? "unknown"; + return uuidInfo ?? "unknown"; } public string Confirm(DBEntry entry) { - if (fullid == null) - throw new Exception("no id"); - HttpWebRequest req = (HttpWebRequest)WebRequest.Create(urlbase + "/confirm.php"); + HttpWebRequest req = (HttpWebRequest)WebRequest.Create(urlbase + "/confirm.php?tocid=" + toc.TOCID + "&id=" + entry.id); + req.Method = "GET"; req.Proxy = proxy; req.UserAgent = userAgent; - NameValueCollection form = new NameValueCollection(); - form.Add("id", fullid); - form.Add("ctdbid", string.Format("{0:x8}", entry.crc)); - HttpWebResponse resp = uploadHelper.Upload(req, new UploadFile[0], form); - using (Stream s = resp.GetResponseStream()) - using (StreamReader sr = new StreamReader(s)) - subResult = sr.ReadToEnd(); + try + { + HttpWebResponse resp = (HttpWebResponse)req.GetResponse(); + if (resp.StatusCode != HttpStatusCode.OK) + subResult = resp.StatusCode.ToString(); + else + { + using (Stream s = resp.GetResponseStream()) + using (StreamReader sr = new StreamReader(s)) + subResult = sr.ReadToEnd(); + } + } + catch (WebException ex) + { + if (ex.Status == WebExceptionStatus.ProtocolError) + subResult = ((HttpWebResponse)ex.Response).StatusCode.ToString(); + else + subResult = "unknown error"; + } return subResult; } public string Submit(int confidence, int total, string artist, string title) { - if (fullid == null) - throw new Exception("no id"); - UploadFile[] files = new UploadFile[1]; MemoryStream newcontents = new MemoryStream(); using (DBHDR FTYP = new DBHDR(newcontents, "ftyp")) @@ -179,7 +242,7 @@ namespace CUETools.CTDB } if (artist != null && artist != "") using (DBHDR TAG = DISC.HDR("ART ")) TAG.Write(artist); if (title != null && title != "") using (DBHDR TAG = DISC.HDR("nam ")) TAG.Write(title); - using (DBHDR USER = DISC.HDR("USER")) USER.Write(GetCPUID()); + using (DBHDR USER = DISC.HDR("USER")) USER.Write(GetUUID()); using (DBHDR TOOL = DISC.HDR("TOOL")) TOOL.Write(userAgent); using (DBHDR TOOL = DISC.HDR("MBID")) TOOL.Write(toc.MusicBrainzId); using (DBHDR DATE = DISC.HDR("DATE")) DATE.Write(DateTime.Now); @@ -195,7 +258,18 @@ namespace CUETools.CTDB req.Proxy = proxy; req.UserAgent = userAgent; NameValueCollection form = new NameValueCollection(); - form.Add("id", fullid); + form.Add("tocid", toc.TOCID); + form.Add("crc32", string.Format("%08X", verify.CRC)); + form.Add("parity", Convert.ToBase64String(verify.Parity, 0, 16)); + form.Add("confidence", confidence.ToString()); + form.Add("trackcount", toc.TrackCount.ToString()); + form.Add("firstaudio", toc.FirstAudio.ToString()); + form.Add("audiotracks", toc.AudioTracks.ToString()); + form.Add("trackoffsets", toc.TrackOffsets); + form.Add("userid", GetUUID()); + form.Add("agent", userAgent); + if (artist != null && artist != "") form.Add("artist", artist); + if (title != null && title != "") form.Add("title", title); HttpWebResponse resp = uploadHelper.Upload(req, files, form); using (Stream s = resp.GetResponseStream()) using (StreamReader sr = new StreamReader(s)) @@ -257,7 +331,7 @@ namespace CUETools.CTDB } if (parPos != 0 && npar >= 2 && npar <= 16 && conf >= 0) //if (parPos != 0 && npar >= 2 && npar <= 16 && conf != 0) - entries.Add(new DBEntry(parPos, parLen, conf, npar, crc)); + entries.Add(new DBEntry(contents, parPos, parLen, conf, npar, crc, null, null)); } } @@ -265,14 +339,20 @@ namespace CUETools.CTDB { foreach (DBEntry entry in entries) { - if (!verify.FindOffset(entry.npar, contents, entry.pos, entry.crc, out entry.offset, out entry.hasErrors)) + if (entry.toc.Pregap != toc.Pregap || entry.toc.AudioLength != toc.AudioLength) + { + entry.hasErrors = false; + entry.canRecover = false; + continue; + } + if (!verify.FindOffset(entry.npar, entry.parity, entry.pos, entry.crc, out entry.offset, out entry.hasErrors)) entry.canRecover = false; else if (entry.hasErrors) { byte[] contents2; int total2; List entries2 = new List(); - FetchDB(string.Format("{0}/{1:x8}.bin", urlfolder, entry.crc), out entry.httpStatus, out contents2, out total2, entries2); + FetchDB(string.Format("{0}/repair.php?tocid={1}&id={2}", urlbase, toc.TOCID, entry.id), out entry.httpStatus, out contents2, out total2, entries2); if (entry.httpStatus != HttpStatusCode.OK) entry.canRecover = false; else @@ -358,13 +438,13 @@ namespace CUETools.CTDB { DBEntry popular = null; foreach (DBEntry entry in entries) - if (!entry.hasErrors || entry.canRecover) + if (entry.toc.Pregap == toc.Pregap && (!entry.hasErrors || entry.canRecover)) if (popular == null || entry.conf > popular.conf) popular = entry; if (popular != null) res = popular.Status; foreach (DBEntry entry in entries) - if (entry != popular && (!entry.hasErrors || entry.canRecover)) + if (entry != popular && entry.toc.Pregap == toc.Pregap && (!entry.hasErrors || entry.canRecover)) res += ", or " + entry.Status; if (res == null) res = "could not be verified"; @@ -394,6 +474,7 @@ namespace CUETools.CTDB public class DBEntry { + public byte[] parity; public int pos; public int len; public int conf; @@ -404,14 +485,19 @@ namespace CUETools.CTDB public bool canRecover; public CDRepairFix repair; public HttpStatusCode httpStatus; + public string id; + public CDImageLayout toc; - public DBEntry(int pos, int len, int conf, int npar, uint crc) + public DBEntry(byte[] parity, int pos, int len, int conf, int npar, uint crc, string id, CDImageLayout toc) { + this.parity = parity; + this.id = id; this.pos = pos; this.len = len; this.conf = conf; this.crc = crc; this.npar = npar; + this.toc = toc; } public string Status diff --git a/CUETools.Codecs.ALAC/Properties/AssemblyInfo.cs b/CUETools.Codecs.ALAC/Properties/AssemblyInfo.cs index 2a267ef..8bddce4 100644 --- a/CUETools.Codecs.ALAC/Properties/AssemblyInfo.cs +++ b/CUETools.Codecs.ALAC/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ using System.Runtime.InteropServices; // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("2.0.5.0")] -[assembly: AssemblyFileVersion("2.0.5.0")] +[assembly: AssemblyVersion("2.0.6.0")] +[assembly: AssemblyFileVersion("2.0.6.0")] diff --git a/CUETools.Codecs.FLAC/CUETools.Codecs.FLAC.cpp b/CUETools.Codecs.FLAC/CUETools.Codecs.FLAC.cpp index 729fe67..98bca0b 100644 --- a/CUETools.Codecs.FLAC/CUETools.Codecs.FLAC.cpp +++ b/CUETools.Codecs.FLAC/CUETools.Codecs.FLAC.cpp @@ -95,12 +95,12 @@ namespace CUETools { namespace Codecs { namespace FLAC { _decoder = FLAC__stream_decoder_new(); if (!FLAC__stream_decoder_set_metadata_respond (_decoder, FLAC__METADATA_TYPE_VORBIS_COMMENT)) - throw gcnew Exception("Unable to setup the decoder."); + throw gcnew Exception("unable to setup the decoder"); //if (!FLAC__stream_decoder_set_disable_asm(_decoder, disableAsm)) - // throw gcnew Exception("Unable to setup the decoder."); + // throw gcnew Exception("unable to setup the decoder"); - if (FLAC__stream_decoder_init_stream(_decoder, + FLAC__StreamDecoderInitStatus st = FLAC__stream_decoder_init_stream(_decoder, (FLAC__StreamDecoderReadCallback)Marshal::GetFunctionPointerForDelegate(_readDel).ToPointer(), _IO->CanSeek?(FLAC__StreamDecoderSeekCallback)Marshal::GetFunctionPointerForDelegate(_seekDel).ToPointer():NULL, _IO->CanSeek?(FLAC__StreamDecoderTellCallback)Marshal::GetFunctionPointerForDelegate(_tellDel).ToPointer():NULL, @@ -109,17 +109,15 @@ namespace CUETools { namespace Codecs { namespace FLAC { (FLAC__StreamDecoderWriteCallback)Marshal::GetFunctionPointerForDelegate(_writeDel).ToPointer(), (FLAC__StreamDecoderMetadataCallback)Marshal::GetFunctionPointerForDelegate(_metadataDel).ToPointer(), (FLAC__StreamDecoderErrorCallback)Marshal::GetFunctionPointerForDelegate(_errorDel).ToPointer(), - NULL) != FLAC__STREAM_DECODER_INIT_STATUS_OK) - { - throw gcnew Exception("Unable to initialize the decoder."); - } + NULL); + + if (st != FLAC__STREAM_DECODER_INIT_STATUS_OK) + throw gcnew Exception(String::Format("unable to initialize the decoder: {0}", gcnew String(FLAC__StreamDecoderInitStatusString[st]))); _decoderActive = true; - if (!FLAC__stream_decoder_process_until_end_of_metadata(_decoder)) { - throw gcnew Exception("Unable to retrieve metadata."); - } - + if (!FLAC__stream_decoder_process_until_end_of_metadata(_decoder)) + throw gcnew Exception("unable to retrieve metadata"); } ~FLACReader () @@ -149,9 +147,8 @@ namespace CUETools { namespace Codecs { namespace FLAC { _sampleOffset = offset; _bufferOffset = 0; _bufferLength = 0; - if (!FLAC__stream_decoder_seek_absolute(_decoder, offset)) { - throw gcnew Exception("Unable to seek."); - } + if (!FLAC__stream_decoder_seek_absolute(_decoder, offset)) + throw gcnew Exception("unable to seek"); } } @@ -263,7 +260,10 @@ namespace CUETools { namespace Codecs { namespace FLAC { if (FLAC__stream_decoder_get_state(_decoder) == FLAC__STREAM_DECODER_END_OF_STREAM) return buff->Length - samplesNeeded; if (!FLAC__stream_decoder_process_single(_decoder)) - throw gcnew Exception("An error occurred while decoding."); + { + String^ state = gcnew String(FLAC__StreamDecoderStateString[FLAC__stream_decoder_get_state(_decoder)]); + throw gcnew Exception(String::Format("an error occurred while decoding: {0}", state)); + } } while (_bufferLength == 0); _sampleOffset += _bufferLength; } @@ -307,19 +307,16 @@ namespace CUETools { namespace Codecs { namespace FLAC { { Int32 sampleCount = frame->header.blocksize; - if (_bufferLength > 0) { - throw gcnew Exception("Received unrequested samples."); - } + if (_bufferLength > 0) + throw gcnew Exception("received unrequested samples"); if ((frame->header.bits_per_sample != pcm->BitsPerSample) || (frame->header.channels != pcm->ChannelCount) || (frame->header.sample_rate != pcm->SampleRate)) - { - throw gcnew Exception("Format changes within a file are not allowed."); - } + throw gcnew Exception("format changes within a file are not allowed"); if (_bufferOffset != 0) - throw gcnew Exception("Internal buffer error."); + throw gcnew Exception("internal buffer error"); if (_sampleBuffer == nullptr || _sampleBuffer->Size < sampleCount) _sampleBuffer = gcnew AudioBuffer(pcm, sampleCount); @@ -382,13 +379,13 @@ namespace CUETools { namespace Codecs { namespace FLAC { { switch (status) { case FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC: - throw gcnew Exception("Synchronization was lost."); + throw gcnew Exception("synchronization was lost"); case FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER: - throw gcnew Exception("Encountered a corrupted frame header."); + throw gcnew Exception("encountered a corrupted frame header"); case FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH: - throw gcnew Exception("Frame CRC mismatch."); + throw gcnew Exception("frame CRC mismatch"); default: - throw gcnew Exception("An unknown error has occurred."); + throw gcnew Exception("an unknown error has occurred"); } } @@ -452,7 +449,7 @@ namespace CUETools { namespace Codecs { namespace FLAC { _pcm = pcm; if (_pcm->BitsPerSample < 16 || _pcm->BitsPerSample > 24) - throw gcnew Exception("Bits per sample must be 16..24."); + throw gcnew Exception("bits per sample must be 16..24"); _initialized = false; _disableAsm = false; @@ -484,7 +481,7 @@ namespace CUETools { namespace Codecs { namespace FLAC { FLAC__stream_encoder_delete(_encoder); if ((_finalSampleCount != 0) && (_samplesWritten != _finalSampleCount)) - throw gcnew Exception("Samples written differs from the expected sample count."); + throw gcnew Exception("samples written differs from the expected sample count"); } virtual void Delete() @@ -498,12 +495,10 @@ namespace CUETools { namespace Codecs { namespace FLAC { return _finalSampleCount; } void set(Int64 value) { - if (value < 0) { - throw gcnew Exception("Invalid final sample count."); - } - if (_initialized) { - throw gcnew Exception("Final sample count cannot be changed after encoding begins."); - } + if (value < 0) + throw gcnew Exception("invalid final sample count"); + if (_initialized) + throw gcnew Exception("final sample count cannot be changed after encoding begins"); _finalSampleCount = value; } } @@ -549,7 +544,7 @@ namespace CUETools { namespace Codecs { namespace FLAC { FLAC__stream_encoder_get_verify_decoder_error_stats(_encoder, &absolute_sample, &frame_number, &channel, &sample, &expected, &got); state = state + String::Format("({0:x} instead of {1:x} @{2:x})", got, expected, absolute_sample); } - throw gcnew Exception("An error occurred while encoding: " + state); + throw gcnew Exception("an error occurred while encoding: " + state); } _samplesWritten += sampleBuffer->Length; @@ -560,9 +555,8 @@ namespace CUETools { namespace Codecs { namespace FLAC { return _compressionLevel; } void set(Int32 value) { - if ((value < 0) || (value > 8)) { - throw gcnew Exception("Invalid compression level."); - } + if ((value < 0) || (value > 8)) + throw gcnew Exception("invalid compression level"); _compressionLevel = value; } } @@ -590,7 +584,7 @@ namespace CUETools { namespace Codecs { namespace FLAC { Verify = true; continue; } - throw gcnew Exception(String::Format("Unsupported options: {0}", value)); + throw gcnew Exception(String::Format("unsupported options: {0}", value)); } } } @@ -618,9 +612,8 @@ namespace CUETools { namespace Codecs { namespace FLAC { return _paddingLength; } void set(Int32 value) { - if (value < 0) { - throw gcnew Exception("Invalid padding length."); - } + if (value < 0) + throw gcnew Exception("invalid padding length"); _paddingLength = value; } } @@ -711,15 +704,19 @@ namespace CUETools { namespace Codecs { namespace FLAC { FLAC__stream_encoder_set_blocksize(_encoder, (unsigned)_blockSize); pathChars = Marshal::StringToHGlobalUni(_path); - hFile = _wfopen((const wchar_t*)pathChars.ToPointer(), L"w+b"); + errno_t err = _wfopen_s(&hFile, (const wchar_t*)pathChars.ToPointer(), L"w+b"); Marshal::FreeHGlobal(pathChars); - - if (FLAC__stream_encoder_init_FILE(_encoder, hFile, NULL, NULL) != - FLAC__STREAM_ENCODER_INIT_STATUS_OK) + if (err) { - throw gcnew Exception("Unable to initialize the encoder."); + wchar_t buffer[256]; + _wcserror_s(buffer, err); + throw gcnew Exception(String::Format("unable to open output file {0}: {1}", _path, gcnew String(buffer))); } + FLAC__StreamEncoderInitStatus st = FLAC__stream_encoder_init_FILE(_encoder, hFile, NULL, NULL); + if (st != FLAC__STREAM_ENCODER_INIT_STATUS_OK) + throw gcnew Exception(String::Format("unable to initialize the encoder: {0}", gcnew String(FLAC__StreamEncoderInitStatusString[st]))); + _initialized = true; } }; diff --git a/CUETools.Codecs.FLAKE/Properties/AssemblyInfo.cs b/CUETools.Codecs.FLAKE/Properties/AssemblyInfo.cs index d884831..2fb0069 100644 --- a/CUETools.Codecs.FLAKE/Properties/AssemblyInfo.cs +++ b/CUETools.Codecs.FLAKE/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ using System.Runtime.InteropServices; // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("2.0.5.0")] -[assembly: AssemblyFileVersion("2.0.5.0")] +[assembly: AssemblyVersion("2.0.6.0")] +[assembly: AssemblyFileVersion("2.0.6.0")] diff --git a/CUETools.Codecs.FlaCuda/Properties/AssemblyInfo.cs b/CUETools.Codecs.FlaCuda/Properties/AssemblyInfo.cs index 1fde694..98f5901 100644 --- a/CUETools.Codecs.FlaCuda/Properties/AssemblyInfo.cs +++ b/CUETools.Codecs.FlaCuda/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ using System.Runtime.InteropServices; // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("2.0.5.0")] -[assembly: AssemblyFileVersion("2.0.5.0")] +[assembly: AssemblyVersion("2.0.6.0")] +[assembly: AssemblyFileVersion("2.0.6.0")] diff --git a/CUETools.Codecs.LossyWAV/CUETools.Codecs.LossyWAV.csproj b/CUETools.Codecs.LossyWAV/CUETools.Codecs.LossyWAV.csproj index 30c660c..37b7546 100644 --- a/CUETools.Codecs.LossyWAV/CUETools.Codecs.LossyWAV.csproj +++ b/CUETools.Codecs.LossyWAV/CUETools.Codecs.LossyWAV.csproj @@ -2,7 +2,7 @@ Debug AnyCPU - 8.0.50727 + 9.0.30729 2.0 {8A0426FA-0BC2-4C49-A6E5-1F9A68156F19} Library @@ -14,6 +14,9 @@ 2.0 + false + + true diff --git a/CUETools.Codecs/CUETools.Codecs.csproj b/CUETools.Codecs/CUETools.Codecs.csproj index 8fa1e6f..5d4b6ee 100644 --- a/CUETools.Codecs/CUETools.Codecs.csproj +++ b/CUETools.Codecs/CUETools.Codecs.csproj @@ -14,6 +14,9 @@ 2.0 + false + + true diff --git a/CUETools.Codecs/Codecs.cs b/CUETools.Codecs/Codecs.cs index 00d5ee8..d849829 100644 --- a/CUETools.Codecs/Codecs.cs +++ b/CUETools.Codecs/Codecs.cs @@ -320,10 +320,20 @@ namespace CUETools.Codecs length = Math.Min(size, _src.Length - _offset); if (_length >= 0) length = Math.Min(length, _length); - dataInBytes = false; - dataInSamples = true; - fixed (int* dest = Samples, src = &_src.Samples[_offset, 0]) - AudioSamples.MemCpy(dest, src, Length * pcm.ChannelCount); + if (_src.dataInSamples) + { + dataInBytes = false; + dataInSamples = true; + fixed (int* dest = Samples, src = &_src.Samples[_offset, 0]) + AudioSamples.MemCpy(dest, src, Length * pcm.ChannelCount); + } + else + { + dataInSamples = false; + dataInBytes = true; + fixed (byte* dest = Bytes, src = &_src.Bytes[_offset * pcm.BlockAlign]) + AudioSamples.MemCpy(dest, src, length * pcm.BlockAlign); + } } public void Swap(AudioBuffer buffer) @@ -1643,10 +1653,12 @@ namespace CUETools.Codecs int _bufferPos = 0; Exception _ex = null; bool own; + ThreadPriority priority; - public AudioPipe(IAudioSource source, int size, bool own) + public AudioPipe(IAudioSource source, int size, bool own, ThreadPriority priority) { this.own = own; + this.priority = priority; _source = source; _readBuffer = new AudioBuffer(source, size); _writeBuffer = new AudioBuffer(source, size); @@ -1655,6 +1667,11 @@ namespace CUETools.Codecs _samplePos = _source.Position; } + public AudioPipe(IAudioSource source, int size) + : this(source, size, true, ThreadPriority.BelowNormal) + { + } + private void Decompress(object o) { #if !DEBUG @@ -1695,7 +1712,7 @@ namespace CUETools.Codecs { if (_workThread != null || _ex != null) return; _workThread = new Thread(Decompress); - _workThread.Priority = ThreadPriority.BelowNormal; + _workThread.Priority = priority; _workThread.IsBackground = true; _workThread.Start(null); } diff --git a/CUETools.Codecs/Properties/AssemblyInfo.cs b/CUETools.Codecs/Properties/AssemblyInfo.cs index b30d89e..5f5f062 100644 --- a/CUETools.Codecs/Properties/AssemblyInfo.cs +++ b/CUETools.Codecs/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ using System.Runtime.InteropServices; // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("2.0.5.0")] -[assembly: AssemblyFileVersion("2.0.5.0")] +[assembly: AssemblyVersion("2.0.6.0")] +[assembly: AssemblyFileVersion("2.0.6.0")] diff --git a/CUETools.Compression.Rar/CUETools.Compression.Rar.csproj b/CUETools.Compression.Rar/CUETools.Compression.Rar.csproj index c3a0cb2..322a552 100644 --- a/CUETools.Compression.Rar/CUETools.Compression.Rar.csproj +++ b/CUETools.Compression.Rar/CUETools.Compression.Rar.csproj @@ -2,7 +2,7 @@ Debug AnyCPU - 8.0.50727 + 9.0.30729 2.0 {8427CAA5-80B8-4952-9A68-5F3DFCFBDF40} Library @@ -27,7 +27,7 @@ pdbonly true - ..\bin\Release\plugins\ + ..\bin\Release\Plugins %28Win32%29\ TRACE prompt 4 diff --git a/CUETools.Compression.Rar/Properties/AssemblyInfo.cs b/CUETools.Compression.Rar/Properties/AssemblyInfo.cs index a36d93a..f25653e 100644 --- a/CUETools.Compression.Rar/Properties/AssemblyInfo.cs +++ b/CUETools.Compression.Rar/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ using System.Runtime.InteropServices; // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("2.0.5.0")] -[assembly: AssemblyFileVersion("2.0.5.0")] +[assembly: AssemblyVersion("2.0.6.0")] +[assembly: AssemblyFileVersion("2.0.6.0")] diff --git a/CUETools.Compression.Zip/Properties/AssemblyInfo.cs b/CUETools.Compression.Zip/Properties/AssemblyInfo.cs index 5727ecb..d608293 100644 --- a/CUETools.Compression.Zip/Properties/AssemblyInfo.cs +++ b/CUETools.Compression.Zip/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ using System.Runtime.InteropServices; // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("2.0.5.0")] -[assembly: AssemblyFileVersion("2.0.5.0")] +[assembly: AssemblyVersion("2.0.6.0")] +[assembly: AssemblyFileVersion("2.0.6.0")] diff --git a/CUETools.Compression/Properties/AssemblyInfo.cs b/CUETools.Compression/Properties/AssemblyInfo.cs index d878c03..0daf3b3 100644 --- a/CUETools.Compression/Properties/AssemblyInfo.cs +++ b/CUETools.Compression/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ using System.Runtime.InteropServices; // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("2.0.5.0")] -[assembly: AssemblyFileVersion("2.0.5.0")] +[assembly: AssemblyVersion("2.0.6.0")] +[assembly: AssemblyFileVersion("2.0.6.0")] diff --git a/CUETools.FlaCudaExe/Program.cs b/CUETools.FlaCudaExe/Program.cs index 9295d46..c147f27 100644 --- a/CUETools.FlaCudaExe/Program.cs +++ b/CUETools.FlaCudaExe/Program.cs @@ -191,7 +191,7 @@ namespace CUETools.FlaCudaExe return 2; } if (buffered) - audioSource = new AudioPipe(audioSource, FlaCudaWriter.MAX_BLOCKSIZE, true); + audioSource = new AudioPipe(audioSource, FlaCudaWriter.MAX_BLOCKSIZE); if (output_file == null) output_file = Path.ChangeExtension(input_file, "flac"); FlaCudaWriter encoder = new FlaCudaWriter((output_file == "-" || output_file == "nul") ? "" : output_file, diff --git a/CUETools.FlaCudaExe/Properties/AssemblyInfo.cs b/CUETools.FlaCudaExe/Properties/AssemblyInfo.cs index f8fe4e8..153ecaa 100644 --- a/CUETools.FlaCudaExe/Properties/AssemblyInfo.cs +++ b/CUETools.FlaCudaExe/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("2.0.5.0")] -[assembly: AssemblyFileVersion("2.0.5.0")] +[assembly: AssemblyVersion("2.0.6.0")] +[assembly: AssemblyFileVersion("2.0.6.0")] diff --git a/CUETools.Flake/Program.cs b/CUETools.Flake/Program.cs index 2403ada..fba04f2 100644 --- a/CUETools.Flake/Program.cs +++ b/CUETools.Flake/Program.cs @@ -173,7 +173,7 @@ namespace CUETools.FlakeExe return; } if (buffered) - audioSource = new AudioPipe(audioSource, 0x10000, true); + audioSource = new AudioPipe(audioSource, 0x10000); if (output_file == null) output_file = Path.ChangeExtension(input_file, "flac"); FlakeWriter flake = new FlakeWriter((output_file == "-" || output_file == "nul") ? "" : output_file, diff --git a/CUETools.Processor/AudioReadWrite.cs b/CUETools.Processor/AudioReadWrite.cs index c70cf99..c7744bc 100644 --- a/CUETools.Processor/AudioReadWrite.cs +++ b/CUETools.Processor/AudioReadWrite.cs @@ -31,11 +31,20 @@ namespace CUETools.Processor return new UserDefinedReader(path, IO, decoder.path, decoder.parameters); if (decoder.type == null) throw new Exception("Unsupported audio type: " + path); - - object src = Activator.CreateInstance(decoder.type, path, IO); - if (src == null || !(src is IAudioSource)) - throw new Exception("Unsupported audio type: " + path + ": " + decoder.type.FullName); - return src as IAudioSource; + + try + { + object src = Activator.CreateInstance(decoder.type, path, IO); + if (src == null || !(src is IAudioSource)) + throw new Exception("Unsupported audio type: " + path + ": " + decoder.type.FullName); + return src as IAudioSource; + } + catch (System.Reflection.TargetInvocationException ex) + { + if (ex.InnerException == null) + throw ex; + throw ex.InnerException; + } } public static IAudioSource GetAudioSource(string path, Stream IO, CUEConfig config) diff --git a/CUETools.Processor/CUETools.Processor.csproj b/CUETools.Processor/CUETools.Processor.csproj index 2982abc..5ca1040 100644 --- a/CUETools.Processor/CUETools.Processor.csproj +++ b/CUETools.Processor/CUETools.Processor.csproj @@ -29,6 +29,9 @@ false false true + false + + true diff --git a/CUETools.Processor/Processor.cs b/CUETools.Processor/Processor.cs index 7e2fffa..09ee443 100644 --- a/CUETools.Processor/Processor.cs +++ b/CUETools.Processor/Processor.cs @@ -814,10 +814,10 @@ namespace CUETools.Processor //ActivationContext is null most of the time :( string arch = Marshal.SizeOf(typeof(IntPtr)) == 8 ? "x64" : "Win32"; - string plugins_path = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "plugins (" + arch + ")"); + string plugins_path = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Plugins (" + arch + ")"); if (Directory.Exists(plugins_path)) AddPluginDirectory(plugins_path); - plugins_path = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "plugins"); + plugins_path = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Plugins"); if (Directory.Exists(plugins_path)) AddPluginDirectory(plugins_path); } @@ -1671,15 +1671,14 @@ string status = processor.Go(); _tracks.Add(new TrackInfo()); } _arVerify = new AccurateRipVerify(_toc, proxy); - _CUEToolsDB = new CUEToolsDB(_toc, proxy); - _CUEToolsDB.UploadHelper.onProgress += new EventHandler(UploadProgress); _isCD = true; SourceInfo cdInfo; cdInfo.Path = _ripper.ARName; cdInfo.Offset = 0; cdInfo.Length = _toc.AudioLength * 588; _sources.Add(cdInfo); - _ripper.ReadProgress += new EventHandler(CDReadProgress); + // Causes memory leak, so had to disable! + //_ripper.ReadProgress += new EventHandler(CDReadProgress); _padding += TrackCount * 200; _padding += _config.embedLog ? 500 + TrackCount * 200 : 0; } @@ -1690,7 +1689,10 @@ string status = processor.Go(); _archive.Close(); _archive = null; if (_ripper != null) + { + //_ripper.ReadProgress -= new EventHandler(CDReadProgress); _ripper.Close(); + } _ripper = null; } @@ -1739,7 +1741,8 @@ string status = processor.Go(); public void FillFromMusicBrainz(MusicBrainz.Release release) { - Year = release.GetEvents().Count > 0 ? release.GetEvents()[0].Date.Substring(0, 4) : ""; + string date = release.GetEvents().Count > 0 ? release.GetEvents()[0].Date : null; + Year = date == null ? "" : date.Substring(0, 4); Artist = release.GetArtist(); Title = release.GetTitle(); // How to get Genre: http://mm.musicbrainz.org/ws/1/release/6fe1e218-2aee-49ac-94f0-7910ba2151df.html?type=xml&inc=tags @@ -1760,7 +1763,7 @@ string status = processor.Go(); Title = cdEntry.Title; for (int i = 0; i < _toc.AudioTracks; i++) { - Tracks[i].Title = cdEntry.Tracks[i].Title; + Tracks[i].Title = cdEntry.Tracks[i + _toc.FirstAudio - 1].Title; Tracks[i].Artist = cdEntry.Artist; } } @@ -1778,7 +1781,7 @@ string status = processor.Go(); m_freedb.UserName = "gchudov"; m_freedb.Hostname = "gmail.com"; m_freedb.ClientName = "CUETools"; - m_freedb.Version = "1.9.5"; + m_freedb.Version = "2.0.6"; m_freedb.SetDefaultSiteAddress("freedb.org"); QueryResult queryResult; @@ -1790,6 +1793,7 @@ string status = processor.Go(); code = m_freedb.Query(AccurateRipVerify.CalculateCDDBQuery(_toc), out queryResult, out coll); if (code == FreedbHelper.ResponseCodes.CODE_200) { + ShowProgress("Looking up album via Freedb... " + queryResult.Discid, 0.5, 0.0, null, null); code = m_freedb.Read(queryResult, out cdEntry); if (code == FreedbHelper.ResponseCodes.CODE_210) Releases.Add(cdEntry); @@ -1801,7 +1805,7 @@ string status = processor.Go(); int i = 0; foreach (QueryResult qr in coll) { - ShowProgress("Looking up album via freedb...", 0.0, (++i + 0.0) / coll.Count, null, null); + ShowProgress("Looking up album via freedb... " + qr.Discid, 0.0, (++i + 0.0) / coll.Count, null, null); CheckStop(); code = m_freedb.Read(qr, out cdEntry); if (code == FreedbHelper.ResponseCodes.CODE_210) @@ -2575,6 +2579,23 @@ string status = processor.Go(); DataTrackLength = tocFromLog[1].Length; } + // use data track length from log + if (tocFromLog != null + && _toc.TrackCount == _toc.AudioTracks + && tocFromLog.TrackCount == tocFromLog.AudioTracks + && tocFromLog.TrackCount == _toc.TrackCount + 1) + { + bool matches = true; + for (int iTrack = 1; iTrack <= _toc.TrackCount; iTrack++) + if (tocFromLog[iTrack + 1].Length != _toc[iTrack].Length) + matches = false; + if (matches) + { + _toc.InsertTrack(new CDTrack(1, 0, 0, false, false)); + DataTrackLength = tocFromLog[1].Length; + } + } + // use data track length range from cddbId if (DataTrackLength == 0 && _cddbDiscIdTag != null) { @@ -2589,8 +2610,6 @@ string status = processor.Go(); } _arVerify = new AccurateRipVerify(_toc, proxy); - _CUEToolsDB = new CUEToolsDB(_toc, proxy); - _CUEToolsDB.UploadHelper.onProgress += new EventHandler(UploadProgress); if (_eacLog != null) { @@ -2639,7 +2658,9 @@ string status = processor.Go(); { ShowProgress((string)"Contacting CUETools database...", 0, 0, null, null); - _CUEToolsDB.ContactDB(_accurateRipId ?? AccurateRipVerify.CalculateAccurateRipId(_toc), userAgent); + _CUEToolsDB = new CUEToolsDB(_toc, proxy); + _CUEToolsDB.UploadHelper.onProgress += new EventHandler(UploadProgress); + _CUEToolsDB.ContactDB(userAgent); ShowProgress("", 0.0, 0.0, null, null); _useCUEToolsDB = true; @@ -3152,21 +3173,24 @@ string status = processor.Go(); uint sec_end = Math.Min(sec_start + 74, tr_start + len - 1); bool fError = false; for (uint iSector = sec_start; iSector <= sec_end; iSector++) - if (_ripper.Errors[(int)iSector]) + if (_ripper.Errors[(int)iSector - (int)_toc[_toc.FirstAudio][0].Start]) fError = true; if (fError) { - uint end = iSecond; + uint end = tr_end - 1; for (uint jSecond = iSecond + 1; jSecond < tr_end; jSecond++) { uint jsec_start = tr_start + jSecond * 75; uint jsec_end = Math.Min(jsec_start + 74, tr_start + len - 1); bool jfError = false; for (uint jSector = jsec_start; jSector <= jsec_end; jSector++) - if (_ripper.Errors[(int)jSector]) + if (_ripper.Errors[(int)jSector - (int)_toc[_toc.FirstAudio][0].Start]) jfError = true; - if (jfError) - end = jSecond; + if (!jfError) + { + end = jSecond - 1; + break; + } } if (errCount == 0) logWriter.WriteLine(); @@ -3180,7 +3204,7 @@ string status = processor.Go(); logWriter.WriteLine(" Suspicious position {0}", s1); else logWriter.WriteLine(" Suspicious position {0} - {1}", s1, s2); - iSecond = end; + iSecond = end + 1; } } return errCount > 0; @@ -3219,7 +3243,9 @@ string status = processor.Go(); _ripper.EACName, _ripper.CorrectionQuality > 0 ? "Secure" : "Burst", _ripper.DriveOffset, - (OutputStyle != CUEStyle.SingleFile && OutputStyle != CUEStyle.SingleFileWithCUE) ? "Gap handling : Appended to previous track\r\n" : "" ); + (OutputStyle == CUEStyle.SingleFile || OutputStyle == CUEStyle.SingleFileWithCUE) ? "" : + "Gap handling : " + + (_ripper.GapsDetected ? "Appended to previous track\r\n" : "Not detected, thus appended to previous track\r\n")); logWriter.WriteLine(); logWriter.WriteLine("TOC of the extracted CD"); @@ -3256,7 +3282,7 @@ string status = processor.Go(); wereErrors |= PrintErrors(logWriter, _toc[track + _toc.FirstAudio].Start, _toc[track + _toc.FirstAudio].Length); logWriter.WriteLine(); - logWriter.WriteLine(" Peak level {0:F1} %", (Tracks[track].PeakLevel * 1000 / 32768) * 0.1); + logWriter.WriteLine(" Peak level {0:F1} %", (_arVerify.PeakLevel(track + 1) * 1000 / 65535) * 0.1); logWriter.WriteLine(" Track quality 100.0 %"); logWriter.WriteLine(" Test CRC {0:X8}", _arVerify.CRC32(track + 1)); logWriter.WriteLine(" Copy CRC {0:X8}", _arVerify.CRC32(track + 1)); @@ -3287,11 +3313,7 @@ string status = processor.Go(); logWriter.WriteLine(" Filename {0}", Path.ChangeExtension(Path.GetFullPath(_destPaths[0]), ".wav")); wereErrors = PrintErrors(logWriter, _toc[_toc.FirstAudio][0].Start, _toc.AudioLength); logWriter.WriteLine(); - int PeakLevel = 0; - for (int track = 0; track < TrackCount; track++) - if (PeakLevel < Tracks[track].PeakLevel) - PeakLevel = Tracks[track].PeakLevel; - logWriter.WriteLine(" Peak level {0:F1} %", (PeakLevel * 1000 / 32768) * 0.1); + logWriter.WriteLine(" Peak level {0:F1} %", (_arVerify.PeakLevel() * 1000 / 65535) * 0.1); logWriter.WriteLine(" Range quality 100.0 %"); logWriter.WriteLine(" Test CRC {0:X8}", _arVerify.CRC32(0)); logWriter.WriteLine(" Copy CRC {0:X8}", _arVerify.CRC32(0)); @@ -3363,7 +3385,7 @@ string status = processor.Go(); CreateExactAudioCopyLOG(); return; } - StringWriter logWriter = new StringWriter(); + StringWriter logWriter = new StringWriter(CultureInfo.InvariantCulture); logWriter.WriteLine("{0}", _ripper.RipperVersion); logWriter.WriteLine("Extraction logfile from : {0}", DateTime.Now); logWriter.WriteLine("Used drive : {0}", _ripper.ARName); @@ -3525,8 +3547,9 @@ string status = processor.Go(); public void GenerateCTDBLog(TextWriter sw) { - if (_CUEToolsDB.DBStatus != null) - sw.WriteLine("CUETools DB: {0}.", _CUEToolsDB.DBStatus); + sw.WriteLine("[CTDB TOCID: {0}] {1}.", _toc.TOCID, _CUEToolsDB.DBStatus ?? "found"); + if (!_processed) + return; if (_CUEToolsDB.SubStatus != null) sw.WriteLine("CUETools DB: {0}.", _CUEToolsDB.SubStatus); if (_CUEToolsDB.DBStatus == null) @@ -3536,21 +3559,24 @@ string status = processor.Go(); string confFormat = (_CUEToolsDB.Total < 10) ? "{0:0}/{1:0}" : (_CUEToolsDB.Total < 100) ? "{0:00}/{1:00}" : "{0:000}/{1:000}"; string conf = string.Format(confFormat, entry.conf, _CUEToolsDB.Total); + string dataTrackInfo = !entry.toc[entry.toc.TrackCount].IsAudio ? string.Format("Is an Enhanced CD, data track length {0}", entry.toc[entry.toc.TrackCount].LengthMSF) : + !entry.toc[1].IsAudio ? string.Format("Playstation type data track length {0}", entry.toc[1].LengthMSF) : ""; string status = - (!entry.hasErrors) ? "Accurately ripped" : - entry.canRecover ? string.Format("Contains {0} correctable errors", entry.repair.CorrectableErrors) : - (entry.httpStatus == 0 || entry.httpStatus == HttpStatusCode.OK) ? "No match" : - entry.httpStatus.ToString(); + entry.toc.Pregap != _toc.Pregap ? string.Format("Has pregap length {0}", CDImageLayout.TimeToString(entry.toc.Pregap)) : + entry.toc.AudioLength != _toc.AudioLength ? string.Format("Has audio length {0}", CDImageLayout.TimeToString(entry.toc.AudioLength)) : + ((entry.toc.TrackOffsets != _toc.TrackOffsets) ? dataTrackInfo + ", " : "") + + ((!entry.hasErrors) ? "Accurately ripped" : + entry.canRecover ? string.Format("Differs in {0} samples", entry.repair.CorrectableErrors) : + (entry.httpStatus == 0 || entry.httpStatus == HttpStatusCode.OK) ? "No match" : + entry.httpStatus.ToString()); sw.WriteLine(" [{0:x8}] ({1}) {2}", entry.crc, conf, status); } } public void GenerateAccurateRipLog(TextWriter sw) { - if (!_processed) - throw new Exception("not processed"); sw.WriteLine("[Verification date: {0}]", DateTime.Now); - sw.WriteLine("[Disc ID: {0}]", _accurateRipId ?? AccurateRipVerify.CalculateAccurateRipId(_toc)); + sw.WriteLine("[AccurateRip ID: {0}] {1}.", _accurateRipId ?? AccurateRipVerify.CalculateAccurateRipId(_toc), _arVerify.ARStatus ?? "found"); if (PreGapLength != 0) sw.WriteLine("Pregap length {0}.", PreGapLengthMSF); if (!_toc[1].IsAudio) @@ -3568,6 +3594,13 @@ string status = processor.Go(); sw.WriteLine("Truncated 4608 extra samples in some input files."); if (_paddedToFrame) sw.WriteLine("Padded some input files to a frame boundary."); + + if (!_processed) + { + if (_useCUEToolsDB) GenerateCTDBLog(sw); + return; + } + if (hdcdDecoder != null && string.Format("{0:s}", hdcdDecoder) != "") sw.WriteLine("HDCD: {0:f}", hdcdDecoder); if (0 != _writeOffset) @@ -3685,9 +3718,9 @@ string status = processor.Go(); bool htoaToFile = ((OutputStyle == CUEStyle.GapsAppended) && _config.preserveHTOA && (_toc.Pregap != 0)); - if (_isCD && (OutputStyle == CUEStyle.GapsLeftOut || OutputStyle == CUEStyle.GapsPrepended)) - throw new Exception("Gaps Left Out/Gaps prepended modes cannot be used when ripping a CD"); - + if (_isCD) + DetectGaps(); + if (_usePregapForFirstTrackInSingleFile) throw new Exception("UsePregapForFirstTrackInSingleFile is not supported for writing audio files."); @@ -3699,8 +3732,6 @@ string status = processor.Go(); destLengths = CalculateAudioFileLengths(OutputStyle); - // TODO: if (_isCD) might need to recalc, might have changed after scanning the CD - // Lookup(); if (_action != CUEAction.Verify) @@ -3708,7 +3739,18 @@ string status = processor.Go(); if (!Directory.Exists(OutputDir)) Directory.CreateDirectory(OutputDir); } - + + if (_action == CUEAction.Encode) + { + string cueContents = CUESheetContents(OutputStyle); + if (_config.createEACLOG) + cueContents = CUESheet.Encoding.GetString(CUESheet.Encoding.GetBytes(cueContents)); + if (OutputStyle == CUEStyle.SingleFileWithCUE && _config.createCUEFileWhenEmbedded) + WriteText(Path.ChangeExtension(_outputPath, ".cue"), cueContents); + else + WriteText(_outputPath, cueContents); + } + if (_audioEncoderType != AudioEncoderType.NoAudio || _action == CUEAction.Verify) WriteAudioFilesPass(OutputDir, OutputStyle, destLengths, htoaToFile, _action == CUEAction.Verify); @@ -3724,7 +3766,6 @@ string status = processor.Go(); if (_action == CUEAction.Encode) { - string cueContents = CUESheetContents(OutputStyle); uint tracksMatch = 0; int bestOffset = 0; @@ -3733,12 +3774,8 @@ string status = processor.Go(); _arVerify.AccResult == HttpStatusCode.OK) FindBestOffset(1, true, out tracksMatch, out bestOffset); - if (_config.createEACLOG) - { - if (_ripperLog != null) - _ripperLog = CUESheet.Encoding.GetString(CUESheet.Encoding.GetBytes(_ripperLog)); - cueContents = CUESheet.Encoding.GetString(CUESheet.Encoding.GetBytes(cueContents)); - } + if (_config.createEACLOG && _ripperLog != null) + _ripperLog = CUESheet.Encoding.GetString(CUESheet.Encoding.GetBytes(_ripperLog)); if (_ripperLog != null) WriteText(Path.ChangeExtension(_outputPath, ".log"), _ripperLog); @@ -3751,10 +3788,6 @@ string status = processor.Go(); if (OutputStyle == CUEStyle.SingleFileWithCUE || OutputStyle == CUEStyle.SingleFile) { - if (OutputStyle == CUEStyle.SingleFileWithCUE && _config.createCUEFileWhenEmbedded) - WriteText(Path.ChangeExtension(_outputPath, ".cue"), cueContents); - if (OutputStyle == CUEStyle.SingleFile) - WriteText(_outputPath, cueContents); if (_audioEncoderType != AudioEncoderType.NoAudio) { NameValueCollection tags = GenerateAlbumTags(bestOffset, OutputStyle == CUEStyle.SingleFileWithCUE, _ripperLog ?? _eacLog); @@ -3813,7 +3846,6 @@ string status = processor.Go(); } else { - WriteText(_outputPath, cueContents); if (_config.createM3U) WriteText(Path.ChangeExtension(_outputPath, ".m3u"), M3UContents(OutputStyle)); bool fNeedAlbumArtist = false; @@ -4337,7 +4369,7 @@ string status = processor.Go(); { // if (_isCD && audioSource != null && audioSource is CDDriveReader) // updatedTOC = ((CDDriveReader)audioSource).TOC; - if (audioSource != null && !_isCD) audioSource.Close(); + if (audioSource != null) audioSource.Close(); audioSource = GetAudioSource(++iSource); samplesRemSource = (int)_sources[iSource].Length; } @@ -4360,6 +4392,9 @@ string status = processor.Go(); else _CUEToolsDB.Verify.Write(sampleBuffer); } + // we use AR after CTDB, so that we can verify what we fixed + if (_useAccurateRip) + _arVerify.Write(sampleBuffer); if (!discardOutput) { if (!_config.detectHDCD || !_config.decodeHDCD) @@ -4372,7 +4407,7 @@ string status = processor.Go(); hdcdDecoder = null; if (_config.decodeHDCD) { - if (!_isCD) audioSource.Close(); + audioSource.Close(); audioDest.Delete(); throw new Exception("HDCD not detected."); } @@ -4385,12 +4420,6 @@ string status = processor.Go(); } } } - if (_useAccurateRip) - { - _arVerify.Write(sampleBuffer); - if (iTrack > 0 || iIndex > 0) - Tracks[iTrack + (iIndex == 0 ? -1 : 0)].MeasurePeakLevel(sampleBuffer, copyCount); - } currentOffset += copyCount; diskOffset += copyCount; @@ -4408,40 +4437,51 @@ string status = processor.Go(); if (hdcdDecoder != null) (hdcdDecoder as IAudioFilter).AudioDest = null; hdcdDecoder = null; - try { if (audioSource != null && !_isCD) audioSource.Close(); } - catch { } + if (audioSource != null) + try { audioSource.Close(); } catch { } audioSource = null; - try { if (audioDest != null) audioDest.Delete(); } - catch { } + if (audioDest != null) + try { audioDest.Delete(); } catch { } audioDest = null; throw ex; } #endif - //if (_isCD && audioSource != null && audioSource is CDDriveReader) - // updatedTOC = ((CDDriveReader)audioSource).TOC; - if (_isCD) - { - _toc = (CDImageLayout)_ripper.TOC.Clone(); - if (_toc.Catalog != null) - Catalog = _toc.Catalog; - for (iTrack = 0; iTrack < _toc.AudioTracks; iTrack++) - { - if (_toc[_toc.FirstAudio + iTrack].ISRC != null) - General.SetCUELine(_tracks[iTrack].Attributes, "ISRC", _toc[_toc.FirstAudio + iTrack].ISRC, false); - if (_toc[_toc.FirstAudio + iTrack].DCP || _toc[_toc.FirstAudio + iTrack].PreEmphasis) - _tracks[iTrack].Attributes.Add(new CUELine("FLAGS" + (_toc[_toc.FirstAudio + iTrack].PreEmphasis ? " PRE" : "") + (_toc[_toc.FirstAudio + iTrack].DCP ? " DCP" : ""))); - } - } - if (hdcdDecoder != null) (hdcdDecoder as IAudioFilter).AudioDest = null; - if (audioSource != null && !_isCD) + if (audioSource != null) audioSource.Close(); if (audioDest != null) audioDest.Close(); } + private void DetectGaps() + { + if (!_isCD) + throw new Exception("not a CD"); + + try { _ripper.DetectGaps(); } + catch (Exception ex) + { + if (ex is StopException) + throw ex; + } + + if (!_ripper.GapsDetected) + return; + + _toc = (CDImageLayout)_ripper.TOC.Clone(); + if (_toc.Catalog != null) + Catalog = _toc.Catalog; + for (int iTrack = 0; iTrack < _toc.AudioTracks; iTrack++) + { + if (_toc[_toc.FirstAudio + iTrack].ISRC != null) + General.SetCUELine(_tracks[iTrack].Attributes, "ISRC", _toc[_toc.FirstAudio + iTrack].ISRC, false); + if (_toc[_toc.FirstAudio + iTrack].DCP || _toc[_toc.FirstAudio + iTrack].PreEmphasis) + _tracks[iTrack].Attributes.Add(new CUELine("FLAGS" + (_toc[_toc.FirstAudio + iTrack].PreEmphasis ? " PRE" : "") + (_toc[_toc.FirstAudio + iTrack].DCP ? " DCP" : ""))); + } + } + public static string CreateDummyCUESheet(CUEConfig _config, string pathIn) { pathIn = Path.GetFullPath(pathIn); @@ -4740,7 +4780,7 @@ string status = processor.Go(); { _ripper.Position = 0; //audioSource = _ripper; - audioSource = new AudioPipe(_ripper, 0x100000, false); + audioSource = new AudioPipe(_ripper, 0x100000, false, ThreadPriority.Highest); } else if (_isArchive) audioSource = AudioReadWrite.GetAudioSource(sourceInfo.Path, OpenArchive(sourceInfo.Path, false), _config); @@ -4753,7 +4793,7 @@ string status = processor.Go(); //if (!(audioSource is AudioPipe) && !(audioSource is UserDefinedReader) && _config.separateDecodingThread) if (!(audioSource is AudioPipe) && _config.separateDecodingThread) - audioSource = new AudioPipe(audioSource, 0x10000, true); + audioSource = new AudioPipe(audioSource, 0x10000); return audioSource; } @@ -5272,7 +5312,7 @@ string status = processor.Go(); string status = Go(); if (CTDB.AccResult == HttpStatusCode.OK) foreach (DBEntry entry in CTDB.Entries) - if (!entry.hasErrors) + if (entry.toc.TrackOffsets == _toc.TrackOffsets && !entry.hasErrors) return "CUEToolsDB: " + CTDB.Status; if (ArVerify.WorstConfidence() < 3) return status + ": confidence too low"; @@ -5280,7 +5320,7 @@ string status = processor.Go(); } case "repair": { - UseCUEToolsDB(false, "CUETools 205"); + UseCUEToolsDB(false, "CUETools 2.0.6"); Action = CUEAction.Verify; if (CTDB.DBStatus != null) return CTDB.DBStatus; @@ -5535,37 +5575,11 @@ string status = processor.Go(); public class TrackInfo { private List _attributes; - private int _peakLevel; public TagLib.File _fileInfo; public TrackInfo() { _attributes = new List(); _fileInfo = null; - _peakLevel = 0; - } - - public unsafe void MeasurePeakLevel(AudioBuffer buff, int sampleCount) - { - if (!buff.PCM.IsRedBook) - throw new Exception(); - fixed (byte* bb = buff.Bytes) - { - short* ss = (short*)bb; - for (int i = 0; i < sampleCount * 2; i++) - _peakLevel = Math.Max(_peakLevel, Math.Abs((int)ss[i])); - } - //for (uint i = 0; i < sampleCount; i++) - // for (uint j = 0; j < 2; j++) - // if (_peakLevel < Math.Abs(samplesBuffer[i, j])) - // _peakLevel = Math.Abs(samplesBuffer[i, j]); - } - - public int PeakLevel - { - get - { - return _peakLevel; - } } public List Attributes { diff --git a/CUETools.Processor/Properties/AssemblyInfo.cs b/CUETools.Processor/Properties/AssemblyInfo.cs index abebb90..5d43b7b 100644 --- a/CUETools.Processor/Properties/AssemblyInfo.cs +++ b/CUETools.Processor/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ using System.Runtime.InteropServices; // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("2.0.5.0")] -[assembly: AssemblyFileVersion("2.0.5.0")] +[assembly: AssemblyVersion("2.0.6.0")] +[assembly: AssemblyFileVersion("2.0.6.0")] diff --git a/CUETools.Ripper.Console/Program.cs b/CUETools.Ripper.Console/Program.cs index 0194300..6a49de7 100644 --- a/CUETools.Ripper.Console/Program.cs +++ b/CUETools.Ripper.Console/Program.cs @@ -71,7 +71,7 @@ namespace CUETools.ConsoleRipper static void Usage() { string drives = ""; - char[] drivesAvailable = CDDriveReader.DrivesAvailable(); + char[] drivesAvailable = CDDrivesList.DrivesAvailable(); for (int i = 0; i < drivesAvailable.Length; i++) drives += string.Format("{0}: ", drivesAvailable[i]); Console.WriteLine("Usage : CUERipper.exe "); @@ -89,7 +89,7 @@ namespace CUETools.ConsoleRipper static void Main(string[] args) { Console.SetOut(Console.Error); - Console.WriteLine("CUERipper v2.0.5 Copyright (C) 2008-10 Gregory S. Chudov"); + Console.WriteLine("CUERipper v2.0.6 Copyright (C) 2008-10 Gregory S. Chudov"); Console.WriteLine("This is free software under the GNU GPLv3+ license; There is NO WARRANTY, to"); Console.WriteLine("the extent permitted by law. for details."); @@ -102,7 +102,7 @@ namespace CUETools.ConsoleRipper { bool ok = true; if (args[arg] == "-P" || args[arg] == "--paranoid") - correctionQuality = 4; + correctionQuality = 2; else if (args[arg] == "-S" || args[arg] == "--secure") correctionQuality = 1; else if (args[arg] == "-B" || args[arg] == "--burst") @@ -131,7 +131,7 @@ namespace CUETools.ConsoleRipper char[] drives; if (driveLetter == null || driveLetter.Length < 1) { - drives = CDDriveReader.DrivesAvailable(); + drives = CDDrivesList.DrivesAvailable(); if (drives.Length < 1) { Console.WriteLine("No CD drives found."); @@ -206,13 +206,49 @@ namespace CUETools.ConsoleRipper Console.WriteLine("AccurateRip : {0}", arVerify.ARStatus == null ? "ok" : arVerify.ARStatus); Console.WriteLine("MusicBrainz : {0}", release == null ? "not found" : release.GetArtist() + " - " + release.GetTitle()); - //IAudioDest audioDest = new FLACWriter(destFile, audioSource.BitsPerSample, audioSource.ChannelCount, audioSource.SampleRate); - IAudioDest audioDest = new WAVWriter(destFile, null, audioSource.PCM); - audioDest.FinalSampleCount = audioSource.Length; - ProgressMeter meter = new ProgressMeter(); audioSource.ReadProgress += new EventHandler(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 (release != null && release.GetEvents().Count > 0) + cueWriter.WriteLine("REM DATE {0}", release.GetEvents()[0].Date.Substring(0, 4)); + if (audioSource.TOC.Catalog != null) + cueWriter.WriteLine("CATALOG {0}", audioSource.TOC.Catalog); + if (release != null) + { + cueWriter.WriteLine("PERFORMER \"{0}\"", release.GetArtist()); + cueWriter.WriteLine("TITLE \"{0}\"", release.GetTitle()); + } + 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 (release != null && release.GetTracks().Count >= audioSource.TOC[track].Number) + { + cueWriter.WriteLine(" TITLE \"{0}\"", release.GetTracks()[(int)audioSource.TOC[track].Number - 1].GetTitle()); + cueWriter.WriteLine(" PERFORMER \"{0}\"", release.GetTracks()[(int)audioSource.TOC[track].Number - 1].GetArtist()); + } + 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 WAVWriter(destFile, null, audioSource.PCM); + audioDest.FinalSampleCount = audioSource.Length; while (audioSource.Read(buff, -1) != 0) { arVerify.Write(buff); @@ -271,41 +307,6 @@ namespace CUETools.ConsoleRipper logFile.Write(logWriter.ToString()); logFile.Close(); - StringWriter cueWriter = new StringWriter(); - cueWriter.WriteLine("REM DISCID {0}", CDDBId); - cueWriter.WriteLine("REM ACCURATERIPID {0}", ArId); - cueWriter.WriteLine("REM COMMENT \"{0}\"", audioSource.RipperVersion); - if (release != null && release.GetEvents().Count > 0) - cueWriter.WriteLine("REM DATE {0}", release.GetEvents()[0].Date.Substring(0,4)); - if (audioSource.TOC.Catalog != null) - cueWriter.WriteLine("CATALOG {0}", audioSource.TOC.Catalog); - if (release != null) - { - cueWriter.WriteLine("PERFORMER \"{0}\"", release.GetArtist()); - cueWriter.WriteLine("TITLE \"{0}\"", release.GetTitle()); - } - 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 (release != null && release.GetTracks().Count >= audioSource.TOC[track].Number) - { - cueWriter.WriteLine(" TITLE \"{0}\"", release.GetTracks()[(int)audioSource.TOC[track].Number - 1].GetTitle()); - cueWriter.WriteLine(" PERFORMER \"{0}\"", release.GetTracks()[(int)audioSource.TOC[track].Number - 1].GetArtist()); - } - 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(); - audioSource.Close(); //FLACReader tagger = new FLACReader(destFile, null); diff --git a/CUETools.Ripper.SCSI/Properties/AssemblyInfo.cs b/CUETools.Ripper.SCSI/Properties/AssemblyInfo.cs index 479fd26..73a3926 100644 --- a/CUETools.Ripper.SCSI/Properties/AssemblyInfo.cs +++ b/CUETools.Ripper.SCSI/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ using System.Runtime.InteropServices; // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("2.0.5.0")] -[assembly: AssemblyFileVersion("2.0.5.0")] +[assembly: AssemblyVersion("2.0.6.0")] +[assembly: AssemblyFileVersion("2.0.6.0")] diff --git a/CUETools.Ripper.SCSI/SCSIDrive.cs b/CUETools.Ripper.SCSI/SCSIDrive.cs index dc872dd..a429aaf 100644 --- a/CUETools.Ripper.SCSI/SCSIDrive.cs +++ b/CUETools.Ripper.SCSI/SCSIDrive.cs @@ -52,6 +52,7 @@ namespace CUETools.Ripper.SCSI int _currentTrack = -1, _currentIndex = -1, _currentTrackActualStart = -1; Logger m_logger; CDImageLayout _toc; + CDImageLayout _toc2; char m_device_letter; InquiryResult m_inqury_result; int m_max_sectors; @@ -59,7 +60,6 @@ namespace CUETools.Ripper.SCSI Crc16Ccitt _crc; public long[,,] UserData; public byte[,] C2Count; - public byte[,] QData; public long[] byte2long; BitArray _errors; int _errorsCount; @@ -70,20 +70,20 @@ namespace CUETools.Ripper.SCSI ReadCDCommand _readCDCommand = ReadCDCommand.Unknown; ReadCDCommand _forceReadCommand = ReadCDCommand.Unknown; Device.MainChannelSelection _mainChannelMode = Device.MainChannelSelection.UserData; - Device.SubChannelMode _subChannelMode = Device.SubChannelMode.QOnly; Device.C2ErrorMode _c2ErrorMode = Device.C2ErrorMode.Mode296; string _autodetectResult; byte[] _readBuffer = new byte[NSECTORS * CB_AUDIO]; - byte[] _subchannelBuffer = new byte[NSECTORS * 16]; + byte[] _subchannelBuffer = new byte[CB_AUDIO]; bool _qChannelInBCD = true; + private ReadProgressArgs progressArgs = new ReadProgressArgs(); public event EventHandler ReadProgress; public CDImageLayout TOC { get { - return _toc; + return gapsDetected && _toc2 != null ? _toc2 : _toc; } } @@ -131,11 +131,8 @@ namespace CUETools.Ripper.SCSI { get { - if (_autodetectResult != null || TestReadCommand()) - return _autodetectResult; - string ret = _autodetectResult; - _autodetectResult = null; - return ret; + TestReadCommand(); + return _autodetectResult; } } @@ -173,7 +170,7 @@ namespace CUETools.Ripper.SCSI (_readCDCommand == ReadCDCommand.ReadCdBEh ? "BEh" : "D8h"), (_mainChannelMode == Device.MainChannelSelection.UserData ? 0x10 : 0xF8) + (_c2ErrorMode == Device.C2ErrorMode.None ? 0 : _c2ErrorMode == Device.C2ErrorMode.Mode294 ? 2 : 4), - (_subChannelMode == Device.SubChannelMode.None ? "00h" : _subChannelMode == Device.SubChannelMode.QOnly ? "02h" : "04h"), + (_gapDetection == GapDetectionMethod.ReadCD ? "BEh" : _gapDetection == GapDetectionMethod.ReadSubchannel ? "42h" : ""), _qChannelInBCD ? "" : "nonBCD", m_max_sectors); } @@ -183,9 +180,6 @@ namespace CUETools.Ripper.SCSI { m_logger = new Logger(); _crc = new Crc16Ccitt(InitialCrcValue.Zeros); - UserData = new long[MSECTORS, 2, 4 * 588]; - C2Count = new byte[MSECTORS, 294]; - QData = new byte[MSECTORS, 16]; byte2long = new long[256]; for (long i = 0; i < 256; i++) { @@ -261,9 +255,15 @@ namespace CUETools.Ripper.SCSI throw new SCSIException("ReadTOC", m_device, st); //throw new Exception("ReadTOC: " + (st == Device.CommandStatus.DeviceFailed ? Device.LookupSenseError(m_device.GetSenseAsc(), m_device.GetSenseAscq()) : st.ToString())); + //byte[] qdata = null; + //st = m_device.ReadPMA(out qdata); + //if (st != Device.CommandStatus.Success) + // throw new SCSIException("ReadPMA", m_device, st); + st = m_device.ReadCDText(out cdtext); // new CDTextEncoderDecoder + _toc2 = null; _toc = new CDImageLayout(); for (int iTrack = 0; iTrack < toc.Count - 1; iTrack++) _toc.AddTrack(new CDTrack((uint)iTrack + 1, @@ -278,15 +278,24 @@ namespace CUETools.Ripper.SCSI _toc[1][0].Start = 0; Position = 0; } + + UserData = new long[MSECTORS, 2, 4 * 588]; + C2Count = new byte[MSECTORS, 294]; + return true; } public void Close() { + UserData = null; + C2Count = null; if (m_device != null) m_device.Close(); m_device = null; _toc = null; + _toc2 = null; + gapsDetected = false; + readCommandFound = false; _currentStart = -1; _currentEnd = -1; } @@ -304,199 +313,444 @@ namespace CUETools.Ripper.SCSI } } - private int ProcessSubchannel(int sector, int Sectors2Read, bool updateMap) + private enum GapDetectionMethod { - int posCount = 0; - for (int iSector = 0; iSector < Sectors2Read; iSector++) - { - int q_pos = (sector - _currentStart + iSector); - int ctl = QData[q_pos, 0] >> 4; - int adr = QData[q_pos, 0] & 7; - bool preemph = (ctl & 1) == 1; - bool dcp = (ctl & 2) == 2; + ReadCD, + ReadSubchannel, + None + } - for (int i = 0; i < 10; i++) - _subchannelBuffer[i] = QData[ q_pos, i]; - if (!_qChannelInBCD && adr == 1) + private GapDetectionMethod _gapDetection = GapDetectionMethod.None; + + private unsafe void LocateLastSector(int sec0, int sec1, int iTrack, int iIndex, ref int maxIndex, out int pos) + { + if (sec1 <= sec0) + { + pos = Math.Min(sec0, sec1); + return; + } + int msector = (sec0 + sec1) / 2; + int fsector = Math.Max(sec0, msector - 1); + int lsector = Math.Min(sec1, msector + 3); + + if (lsector >= fsector && _gapDetection == GapDetectionMethod.ReadCD) + { + Device.CommandStatus st = m_device.ReadSubChannel(2, (uint)fsector, (uint)(lsector - fsector + 1), ref _subchannelBuffer, _timeout); + if (st != Device.CommandStatus.Success) + lsector = fsector - 1; + } + + fixed (byte * data = _subchannelBuffer) + for (int sector = fsector; sector <= lsector; sector++) { - _subchannelBuffer[3] = toBCD(_subchannelBuffer[3]); - _subchannelBuffer[4] = toBCD(_subchannelBuffer[4]); - _subchannelBuffer[5] = toBCD(_subchannelBuffer[5]); - _subchannelBuffer[7] = toBCD(_subchannelBuffer[7]); - _subchannelBuffer[8] = toBCD(_subchannelBuffer[8]); - _subchannelBuffer[9] = toBCD(_subchannelBuffer[9]); - } - ushort crc = _crc.ComputeChecksum(_subchannelBuffer, 0, 10); - crc ^= 0xffff; - if ((QData[q_pos, 10] != 0 || QData[q_pos, 11] != 0) && - ((byte)(crc & 0xff) != QData[q_pos, 11] || (byte)(crc >> 8) != QData[q_pos, 10]) - ) - { - if (!updateMap) - continue; - _crcErrorsCount++; - if (_debugMessages && _crcErrorsCount < 4) + Device.CommandStatus st = Device.CommandStatus.Success; + int sTrack, sIndex, sPos, ctl; + switch (_gapDetection) { - StringBuilder st = new StringBuilder(); - for (int i = 0; i < 12; i++) - st.AppendFormat(",0x{0:X2}", QData[q_pos, i]); - System.Console.WriteLine("\rCRC error@{0}{1};", CDImageLayout.TimeToString((uint)(sector + iSector)), st.ToString()); - } - continue; - } - switch (adr) - { - case 1: // current position - { - int iTrack = fromBCD(QData[q_pos, 1]); - int iIndex = fromBCD(QData[q_pos, 2]); - int mm = _qChannelInBCD ? fromBCD(QData[q_pos, 7]) : QData[q_pos, 7]; - int ss = _qChannelInBCD ? fromBCD(QData[q_pos, 8]) : QData[q_pos, 8]; - int ff = _qChannelInBCD ? fromBCD(QData[q_pos, 9]) : QData[q_pos, 9]; - //if (sec != sector + iSector) - // System.Console.WriteLine("\rLost sync: {0} vs {1} ({2:X} vs {3:X})", CDImageLayout.TimeToString((uint)(sector + iSector)), CDImageLayout.TimeToString((uint)sec), sector + iSector, sec); - if (iTrack == 110) + case GapDetectionMethod.ReadSubchannel: { - if (sector + iSector + 75 < _toc.AudioLength) - throw new Exception("lead out area encountred"); - // make sure that data is zero? - return posCount; - } - if (iTrack == 0) - throw new Exception("lead in area encountred"); - posCount++; - if (!updateMap) + // seek to given sector + if (_readCDCommand == ReadCDCommand.ReadCdBEh) + st = m_device.ReadCDAndSubChannel(_mainChannelMode, Device.SubChannelMode.None, _c2ErrorMode, 1, false, (uint)sector, 1, (IntPtr)((void*)data), _timeout); + else + st = m_device.ReadCDDA(Device.SubChannelMode.None, (uint)sector, 1, (IntPtr)((void*)data), _timeout); + if (st != Device.CommandStatus.Success) + continue; + st = m_device.ReadSubChannel42(1, 0, ref _subchannelBuffer, 0, _timeout); + // x x x x 01 adrctl tr ind abs abs abs rel rel rel + if (st != Device.CommandStatus.Success) + continue; + if (_subchannelBuffer[0] != 0 || _subchannelBuffer[2] != 0 || _subchannelBuffer[3] != 12 || _subchannelBuffer[4] != 1) + continue; + + ctl = _subchannelBuffer[5] & 0xf; + int adr = (_subchannelBuffer[5] >> 4) & 0xf; + sTrack = _subchannelBuffer[6]; + sIndex = _subchannelBuffer[7]; + sPos = (_subchannelBuffer[8] << 24) | (_subchannelBuffer[9] << 16) | (_subchannelBuffer[10] << 8) | (_subchannelBuffer[11]); + //int sRel = (_subchannelBuffer[12] << 24) | (_subchannelBuffer[13] << 16) | (_subchannelBuffer[14] << 8) | (_subchannelBuffer[15]); + if (adr != 1) + continue; + + if (sTrack < _toc2.FirstAudio || sTrack >= _toc2.FirstAudio + _toc2.AudioTracks) + continue; + break; - int sec = ff + 75 * (ss + 60 * mm) - 150; // sector + iSector; - if (iTrack >= _toc.FirstAudio + _toc.AudioTracks) - throw new Exception("strange track number encountred"); - if (iTrack != _currentTrack) - { - if (_currentTrack != -1 && iTrack != _currentTrack + 1) - { - if (_debugMessages) - System.Console.WriteLine("\nNon-consequent track at {0}: {1} after {2}", CDImageLayout.TimeToString((uint)(sector + iSector)), iTrack, _currentTrack); - //throw new Exception("invalid track"); - continue; - } - if (iIndex != 1 && iIndex != 0) - { - if (_debugMessages) - System.Console.WriteLine("\nInvalid track start index at {0}: {1}.{2}", CDImageLayout.TimeToString((uint)(sector + iSector)), iTrack, iIndex); - //throw new Exception("invalid index"); - continue; - } - _currentTrack = iTrack; - _currentTrackActualStart = sec; - _currentIndex = iIndex; } - else if (iIndex != _currentIndex) + case GapDetectionMethod.ReadCD: { - if (iIndex != _currentIndex + 1) + int offs = 16 * (sector - fsector); + ctl = _subchannelBuffer[offs + 0] >> 4; + int adr = _subchannelBuffer[offs + 0] & 7; + if (!_qChannelInBCD && adr == 1) { - if (_debugMessages) - System.Console.WriteLine("\nNon-consequent index at {0}: {1} after {2}", CDImageLayout.TimeToString((uint)(sector + iSector)), iIndex, _currentIndex); - //throw new Exception("invalid index"); - continue; + _subchannelBuffer[offs + 3] = toBCD(_subchannelBuffer[offs + 3]); + _subchannelBuffer[offs + 4] = toBCD(_subchannelBuffer[offs + 4]); + _subchannelBuffer[offs + 5] = toBCD(_subchannelBuffer[offs + 5]); + _subchannelBuffer[offs + 7] = toBCD(_subchannelBuffer[offs + 7]); + _subchannelBuffer[offs + 8] = toBCD(_subchannelBuffer[offs + 8]); + _subchannelBuffer[offs + 9] = toBCD(_subchannelBuffer[offs + 9]); } - _currentIndex = iIndex; - if (_currentIndex == 1) - { - if (iTrack != 1) - { - uint pregap = (uint)(sec - _currentTrackActualStart); - _toc[iTrack][0].Start = _toc[iTrack].Start - pregap; - } - _currentTrackActualStart = sec; - } else - _toc[iTrack].AddIndex(new CDTrackIndex((uint)iIndex, (uint)(_toc[iTrack].Start + sec - _currentTrackActualStart))); - _currentIndex = iIndex; + + ushort crc = _crc.ComputeChecksum(_subchannelBuffer, offs, 10); + crc ^= 0xffff; + ushort scrc = (ushort)((_subchannelBuffer[offs + 10] << 8) | _subchannelBuffer[offs + 11]); + if (scrc != 0 && scrc != crc) + continue; + if (adr != 1) + continue; + + sTrack = fromBCD(_subchannelBuffer[offs + 1]); + sIndex = fromBCD(_subchannelBuffer[offs + 2]); + + if (sTrack < _toc2.FirstAudio || sTrack >= _toc2.FirstAudio + _toc2.AudioTracks) + continue; + + int mm = fromBCD(_subchannelBuffer[offs + 7]); + int ss = fromBCD(_subchannelBuffer[offs + 8]); + int ff = fromBCD(_subchannelBuffer[offs + 9]); + sPos = ff + 75 * (ss + 60 * mm) - 150; + break; } - if (preemph) - _toc[iTrack].PreEmphasis = true; - if (dcp) - _toc[iTrack].DCP = true; - break; - } - case 2: // catalog - if (updateMap && _toc.Catalog == null) + default: + continue; + } + + bool preemph = (ctl & 1) == 1; + bool dcp = (ctl & 2) == 2; + if (preemph) + _toc2[sTrack].PreEmphasis = true; + if (dcp) + _toc2[sTrack].DCP = true; + + if (sPos <= sec0 || sPos > sec1) + continue; + if (sTrack > iTrack || (sTrack == iTrack && iIndex >= 0 && sIndex > iIndex)) + { + LocateLastSector(sec0, sPos - 1, iTrack, iIndex, ref maxIndex, out pos); + return; + } + if (sTrack < iTrack || (sTrack == iTrack && (iIndex < 0 || sIndex <= iIndex))) + { + if (sTrack == iTrack && iIndex < 0) + maxIndex = sIndex; + LocateLastSector(sPos, sec1, iTrack, iIndex, ref maxIndex, out pos); + return; + } + } + if (sec1 <= sec0 + 16) + { + pos = Math.Min(sec0, sec1); + return; + } + + // TODO: catch? + throw new Exception("gap detection failed"); + } + + private unsafe void TestGaps() + { + _gapDetection = GapDetectionMethod.None; + + //st = m_device.Seek((uint)(sector + i * 33) + _toc[_toc.FirstAudio][0].Start); + //if (st != Device.CommandStatus.Success) + // break; + //bool ready; + //st = m_device.TestUnitReady(out ready); + //if (st != Device.CommandStatus.Success) + // break; + //if (!ready) + //{ + // st = Device.CommandStatus.NotSupported; + // break; + //} + + // try ReadCD: + Device.CommandStatus st; + int sector = 3; + + if (_readCDCommand == ReadCDCommand.ReadCdBEh) + { + st = m_device.ReadSubChannel(2, (uint)sector + _toc[_toc.FirstAudio][0].Start, (uint)m_max_sectors, ref _subchannelBuffer, _timeout); + if (st == Device.CommandStatus.Success) + { + int[] goodsecs = new int[2]; + for (int bcd = 1; bcd >= 0; bcd--) + { + for (int i = 0; i < m_max_sectors; i++) { - StringBuilder catalog = new StringBuilder(); - for (int i = 1; i < 8; i++) - catalog.AppendFormat("{0:x2}", QData[q_pos, i]); - _toc.Catalog = catalog.ToString(0, 13); + int adr = _subchannelBuffer[i * 16 + 0] & 7; + if (bcd == 0 && adr == 1) + { + _subchannelBuffer[i * 16 + 3] = toBCD(_subchannelBuffer[i * 16 + 3]); + _subchannelBuffer[i * 16 + 4] = toBCD(_subchannelBuffer[i * 16 + 4]); + _subchannelBuffer[i * 16 + 5] = toBCD(_subchannelBuffer[i * 16 + 5]); + _subchannelBuffer[i * 16 + 7] = toBCD(_subchannelBuffer[i * 16 + 7]); + _subchannelBuffer[i * 16 + 8] = toBCD(_subchannelBuffer[i * 16 + 8]); + _subchannelBuffer[i * 16 + 9] = toBCD(_subchannelBuffer[i * 16 + 9]); + } + + ushort crc = _crc.ComputeChecksum(_subchannelBuffer, i * 16, 10); + crc ^= 0xffff; + ushort scrc = (ushort)((_subchannelBuffer[i * 16 + 10] << 8) | _subchannelBuffer[i * 16 + 11]); + if (scrc != 0 && scrc != crc) + continue; + if (adr != 1) + continue; + + int sTrack = fromBCD(_subchannelBuffer[i * 16 + 1]); + int sIndex = fromBCD(_subchannelBuffer[i * 16 + 2]); + + if (sTrack == 0 || sTrack == 110) + continue; + + int mm = fromBCD(_subchannelBuffer[i * 16 + 7]); + int ss = fromBCD(_subchannelBuffer[i * 16 + 8]); + int ff = fromBCD(_subchannelBuffer[i * 16 + 9]); + int sPos = ff + 75 * (ss + 60 * mm) - 150; + + if (sPos < sector + i - 8 || sPos > sector + i + 8) + continue; + + goodsecs[bcd]++; } - break; - case 3: //isrc - if (updateMap && _toc[_currentTrack].ISRC == null) - { - StringBuilder isrc = new StringBuilder(); - isrc.Append(from6bit(QData[q_pos, 1] >> 2)); - isrc.Append(from6bit(((QData[q_pos, 1] & 0x3) << 4) + (0x0f & (QData[q_pos, 2] >> 4)))); - isrc.Append(from6bit(((QData[q_pos, 2] & 0xf) << 2) + (0x03 & (QData[q_pos, 3] >> 6)))); - isrc.Append(from6bit((QData[q_pos, 3] & 0x3f))); - isrc.Append(from6bit(QData[q_pos, 4] >> 2)); - isrc.Append(from6bit(((QData[q_pos, 4] & 0x3) << 4) + (0x0f & (QData[q_pos, 5] >> 4)))); - isrc.AppendFormat("{0:x}", QData[q_pos, 5] & 0xf); - isrc.AppendFormat("{0:x2}", QData[q_pos, 6]); - isrc.AppendFormat("{0:x2}", QData[q_pos, 7]); - isrc.AppendFormat("{0:x}", QData[q_pos, 8] >> 4); - if (!isrc.ToString().Contains("#") && isrc.ToString() != "0000000000") - _toc[_currentTrack].ISRC = isrc.ToString(); - } - break; + } + + if (goodsecs[0] > 0 || goodsecs[1] > 0) + { + _qChannelInBCD = goodsecs[1] >= goodsecs[0]; + _gapDetection = GapDetectionMethod.ReadCD; + } + } + } + + if (_gapDetection == GapDetectionMethod.None) + { + fixed (byte* data = _subchannelBuffer) + { + // seek to given sector + if (_readCDCommand == ReadCDCommand.ReadCdBEh) + st = m_device.ReadCDAndSubChannel(_mainChannelMode, Device.SubChannelMode.None, _c2ErrorMode, 1, false, (uint)sector + _toc[_toc.FirstAudio][0].Start, 1, (IntPtr)((void*)data), _timeout); + else + st = m_device.ReadCDDA(Device.SubChannelMode.None, (uint)sector + _toc[_toc.FirstAudio][0].Start, 1, (IntPtr)((void*)data), _timeout); + } + if (st == Device.CommandStatus.Success) + { + st = m_device.ReadSubChannel42(1, 0, ref _subchannelBuffer, 0, _timeout); + if (st == Device.CommandStatus.Success) + { + if (_subchannelBuffer[0] == 0 && _subchannelBuffer[2] == 0 && _subchannelBuffer[3] == 12 && _subchannelBuffer[4] == 1) + { + int ctl = _subchannelBuffer[5] & 0xf; + int adr = (_subchannelBuffer[5] >> 4) & 0xf; + if (adr == 1) + { + _gapDetection = GapDetectionMethod.ReadSubchannel; + } + } + } } } - return posCount; } + public bool GapsDetected + { + get + { + return gapsDetected; + } + } + + bool gapsDetected = false; + + public unsafe bool DetectGaps() + { + if (!TestReadCommand()) + throw new Exception("failed to autodetect read command:\n" + _autodetectResult); + + if (_gapDetection == GapDetectionMethod.None) + { + gapsDetected = false; + return false; + } + + if (gapsDetected) + return true; + + _toc2 = (CDImageLayout)_toc.Clone(); + + if (_gapDetection == GapDetectionMethod.ReadSubchannel) + { + Device.CommandStatus st = m_device.ReadSubChannel42(2, 0, ref _subchannelBuffer, 0, _timeout); + if (st == Device.CommandStatus.Success) + if (_subchannelBuffer[0] == 0 && _subchannelBuffer[2] == 0 && _subchannelBuffer[3] == 20 + && _subchannelBuffer[4] == 2 && _subchannelBuffer[8] == 0x80) + { + string catalog = Encoding.ASCII.GetString(_subchannelBuffer, 9, 13); + if (catalog.ToString() != "0000000000000") + _toc2.Catalog = catalog.ToString(); + } + } + + int sec0 = (int)_toc2[_toc2.FirstAudio][0].Start, disc1 = (int)(_toc2[_toc2.FirstAudio][0].Start + _toc2.AudioLength) - 1; + for (int iTrack = _toc2.FirstAudio; iTrack < _toc2.FirstAudio + _toc2.AudioTracks; iTrack++) + { + if (ReadProgress != null) + { + progressArgs.Action = "Detecting gaps"; + progressArgs.Pass = -1; + progressArgs.Position = (iTrack - _toc2.FirstAudio) * 3; + progressArgs.PassStart = 0; + progressArgs.PassEnd = _toc2.TrackCount * 3 - 1; + progressArgs.ErrorsCount = 0; + progressArgs.PassTime = DateTime.Now; + ReadProgress(this, progressArgs); + } + int sec1, idx1 = 1; + LocateLastSector(sec0, Math.Min(disc1, (int)_toc[iTrack].End + 16), iTrack, -1, ref idx1, out sec1); + int isec0 = sec0; + for (int idx = 0; idx <= idx1; idx++) + { + int isec1 = sec1, iidx1 = 1; + if (idx < idx1) + { + if (ReadProgress != null) + { + progressArgs.Position = (iTrack - _toc2.FirstAudio) * 3 + 1; + progressArgs.PassTime = DateTime.Now; + ReadProgress(this, progressArgs); + } + LocateLastSector(isec0, sec1, iTrack, idx, ref iidx1, out isec1); + } + if (isec1 > isec0) + { + if (idx == 0 && iTrack > 1) + _toc2[iTrack][0].Start = _toc2[iTrack].Start - (uint)(isec1 - isec0 + 1); + if (idx > 1) + _toc2[iTrack].AddIndex(new CDTrackIndex((uint)idx, (uint)(_toc2[iTrack][0].Start + isec0 - sec0))); + } + isec0 = isec1 + 1; + } + + if (ReadProgress != null) + { + progressArgs.Position = (iTrack - _toc2.FirstAudio) * 3 + 2; + progressArgs.PassTime = DateTime.Now; + ReadProgress(this, progressArgs); + } + + if (_gapDetection == GapDetectionMethod.ReadSubchannel) + { + Device.CommandStatus st = m_device.ReadSubChannel42(3, iTrack, ref _subchannelBuffer, 0, _timeout); + if (st == Device.CommandStatus.Success) + if (_subchannelBuffer[0] == 0 && _subchannelBuffer[2] == 0 && _subchannelBuffer[3] == 20 + && _subchannelBuffer[4] == 3 && _subchannelBuffer[8] == 0x80) //&& _subchannelBuffer[6] == iTrack) + { + string isrc = Encoding.ASCII.GetString(_subchannelBuffer, 9, 12); + if (!isrc.ToString().Contains("#") && isrc.ToString() != "000000000000") + _toc2[iTrack].ISRC = isrc.ToString(); + } + } + if (_gapDetection == GapDetectionMethod.ReadCD) + { + Device.CommandStatus st = m_device.ReadSubChannel(2, _toc2[iTrack].Start + 16, 100, ref _subchannelBuffer, _timeout); + if (st == Device.CommandStatus.Success) + { + for (int offs = 0; offs < 100 * 16; offs += 16) + { + int ctl = _subchannelBuffer[offs + 0] >> 4; + int adr = _subchannelBuffer[offs + 0] & 7; + if (adr != 2 && adr != 3) + continue; + ushort crc = _crc.ComputeChecksum(_subchannelBuffer, offs, 10); + crc ^= 0xffff; + ushort scrc = (ushort)((_subchannelBuffer[offs + 10] << 8) | _subchannelBuffer[offs + 11]); + if (scrc != 0 && scrc != crc) + continue; + if (adr == 3 && _toc2[iTrack].ISRC == null) + { + StringBuilder isrc = new StringBuilder(); + isrc.Append(from6bit(_subchannelBuffer[offs + 1] >> 2)); + isrc.Append(from6bit(((_subchannelBuffer[offs + 1] & 0x3) << 4) + (0x0f & (_subchannelBuffer[offs + 2] >> 4)))); + isrc.Append(from6bit(((_subchannelBuffer[offs + 2] & 0xf) << 2) + (0x03 & (_subchannelBuffer[offs + 3] >> 6)))); + isrc.Append(from6bit((_subchannelBuffer[offs + 3] & 0x3f))); + isrc.Append(from6bit(_subchannelBuffer[offs + 4] >> 2)); + isrc.Append(from6bit(((_subchannelBuffer[offs + 4] & 0x3) << 4) + (0x0f & (_subchannelBuffer[offs + 5] >> 4)))); + isrc.AppendFormat("{0:x}", _subchannelBuffer[offs + 5] & 0xf); + isrc.AppendFormat("{0:x2}", _subchannelBuffer[offs + 6]); + isrc.AppendFormat("{0:x2}", _subchannelBuffer[offs + 7]); + isrc.AppendFormat("{0:x}", _subchannelBuffer[offs + 8] >> 4); + if (!isrc.ToString().Contains("#") && isrc.ToString() != "000000000000") + _toc2[iTrack].ISRC = isrc.ToString(); + } + if (adr == 2 && _toc2.Catalog == null) + { + StringBuilder catalog = new StringBuilder(); + for (int i = 1; i < 8; i++) + catalog.AppendFormat("{0:x2}", _subchannelBuffer[offs + i]); + if (catalog.ToString() != "0000000000000") + _toc2.Catalog = catalog.ToString(0, 13); + } + } + } + } + sec0 = sec1 + 1; + } + + gapsDetected = true; + return true; + } + + bool readCommandFound = false; + public unsafe bool TestReadCommand() { + if (readCommandFound) + return true; + //ReadCDCommand[] readmode = { ReadCDCommand.ReadCdBEh, ReadCDCommand.ReadCdD8h }; ReadCDCommand[] readmode = { ReadCDCommand.ReadCdD8h, ReadCDCommand.ReadCdBEh }; - Device.SubChannelMode[] submode = { Device.SubChannelMode.QOnly, Device.SubChannelMode.None, Device.SubChannelMode.RWMode }; - Device.C2ErrorMode[] c2mode = { Device.C2ErrorMode.Mode296, Device.C2ErrorMode.Mode294, Device.C2ErrorMode.None }; + Device.C2ErrorMode[] c2mode = { Device.C2ErrorMode.Mode294, Device.C2ErrorMode.Mode296, Device.C2ErrorMode.None }; Device.MainChannelSelection[] mainmode = { Device.MainChannelSelection.UserData, Device.MainChannelSelection.F8h }; bool found = false; + _autodetectResult = ""; _currentStart = 0; _currentTrack = -1; _currentIndex = -1; m_max_sectors = Math.Min(NSECTORS, m_device.MaximumTransferLength / CB_AUDIO - 1); int sector = 3; - for (int q = 0; q <= 1 && !found; q++) - for (int c = 0; c <= 2 && !found; c++) - for (int r = 0; r <= 1 && !found; r++) - for (int m = 0; m <= 1 && !found; m++) + int pass = 0; + for (int c = 0; c <= 2 && !found; c++) + for (int r = 0; r <= 1 && !found; r++) + for (int m = 0; m <= 1 && !found; m++) + { + _readCDCommand = readmode[r]; + _c2ErrorMode = c2mode[c]; + _mainChannelMode = mainmode[m]; + if (_forceReadCommand != ReadCDCommand.Unknown && _readCDCommand != _forceReadCommand) + continue; + if (_readCDCommand == ReadCDCommand.ReadCdD8h) // && (_c2ErrorMode != Device.C2ErrorMode.None || _mainChannelMode != Device.MainChannelSelection.UserData)) + continue; + Array.Clear(_readBuffer, 0, _readBuffer.Length); // fill with something nasty instead? + DateTime tm = DateTime.Now; + if (ReadProgress != null) { - _readCDCommand = readmode[r]; - _subChannelMode = submode[q]; - _c2ErrorMode = c2mode[c]; - _mainChannelMode = mainmode[m]; - if (_forceReadCommand != ReadCDCommand.Unknown && _readCDCommand != _forceReadCommand) - continue; - if (_readCDCommand == ReadCDCommand.ReadCdD8h) // && (_c2ErrorMode != Device.C2ErrorMode.None || _mainChannelMode != Device.MainChannelSelection.UserData)) - continue; - Array.Clear(_readBuffer, 0, _readBuffer.Length); // fill with something nasty instead? - DateTime tm = DateTime.Now; - Device.CommandStatus st = FetchSectors(sector, m_max_sectors, false, false); - TimeSpan delay = DateTime.Now - tm; - if (st == Device.CommandStatus.Success && _subChannelMode == Device.SubChannelMode.QOnly) - { - _qChannelInBCD = false; - int sub1 = ProcessSubchannel(sector, m_max_sectors, false); - _qChannelInBCD = true; - int sub2 = ProcessSubchannel(sector, m_max_sectors, false); - _qChannelInBCD = sub2 >= sub1; - if (sub1 == 0 && sub2 == 0) - { - _autodetectResult += string.Format("{0}: {1}\n", CurrentReadCommand, "Got no subchannel information"); - continue; - } - } - _autodetectResult += string.Format("{0}: {1} ({2}ms)\n", CurrentReadCommand, (st == Device.CommandStatus.DeviceFailed ? Device.LookupSenseError(m_device.GetSenseAsc(), m_device.GetSenseAscq()) : st.ToString()), delay.TotalMilliseconds); - found = st == Device.CommandStatus.Success && _subChannelMode != Device.SubChannelMode.RWMode;// && _subChannelMode != Device.SubChannelMode.QOnly; - //sector += m_max_sectors; + progressArgs.Action = "Detecting drive features"; + progressArgs.Pass = -1; + progressArgs.Position = pass++; + progressArgs.PassStart = 0; + progressArgs.PassEnd = 2 * 3 * 2 - 1; + progressArgs.ErrorsCount = 0; + progressArgs.PassTime = tm; + ReadProgress(this, progressArgs); } + Device.CommandStatus st = FetchSectors(sector, m_max_sectors, false); + TimeSpan delay = DateTime.Now - tm; + _autodetectResult += string.Format("{0}: {1} ({2}ms)\n", CurrentReadCommand, (st == Device.CommandStatus.DeviceFailed ? Device.LookupSenseError(m_device.GetSenseAsc(), m_device.GetSenseAscq()) : st.ToString()), delay.TotalMilliseconds); + found = st == Device.CommandStatus.Success; + + //sector += m_max_sectors; + } //if (found) // for (int n = 1; n <= m_max_sectors; n++) // { @@ -508,11 +762,16 @@ namespace CUETools.Ripper.SCSI // break; // } // } + TestGaps(); + if (found) _autodetectResult += "Chosen " + CurrentReadCommand + "\n"; else _readCDCommand = ReadCDCommand.Unknown; + _currentStart = -1; + _currentEnd = -1; + readCommandFound = found; return found; } @@ -522,8 +781,8 @@ namespace CUETools.Ripper.SCSI private unsafe void ReorganiseSectors(int sector, int Sectors2Read) { int c2Size = _c2ErrorMode == Device.C2ErrorMode.None ? 0 : _c2ErrorMode == Device.C2ErrorMode.Mode294 ? 294 : 296; - int oldSize = 4 * 588 + c2Size + (_subChannelMode == Device.SubChannelMode.None ? 0 : 16); - fixed (byte* readBuf = _readBuffer, qBuf = _subchannelBuffer, qData = QData, c2Count = C2Count) + int oldSize = 4 * 588 + c2Size; + fixed (byte* readBuf = _readBuffer, c2Count = C2Count) fixed (long* userData = UserData) { for (int iSector = 0; iSector < Sectors2Read; iSector++) @@ -531,7 +790,6 @@ namespace CUETools.Ripper.SCSI byte* sectorPtr = readBuf + iSector * oldSize; long* userDataPtr = userData + (sector - _currentStart + iSector) * 8 * 588; byte* c2CountPtr = c2Count + (sector - _currentStart + iSector) * 294; - byte* qDataPtr = qData + (sector - _currentStart + iSector) * 16; //if (_currentStart > 0) //{ @@ -552,7 +810,7 @@ namespace CUETools.Ripper.SCSI int offs = 0; if (c2Size == 296) { - // sometimes sector C2 byte is placed after C2 info, not before!! + // TODO: sometimes sector C2 byte is placed after C2 info, not before!! int c2 = 0; for (int pos = 2; pos < 294; pos++) c2 |= sectorPtr[4 * 588 + pos]; @@ -582,14 +840,8 @@ namespace CUETools.Ripper.SCSI else { for (int sample = 0; sample < 4 * 588; sample++) - userDataPtr[sample] += byte2long[sectorPtr[sample]] * 3; + userDataPtr[sample] += byte2long[sectorPtr[sample]]; } - if (_subChannelMode != Device.SubChannelMode.None) - for (int qi = 0; qi < 16; qi++) - qDataPtr[qi] = sectorPtr[4 * 588 + c2Size + qi]; - else - for (int qi = 0; qi < 16; qi++) - qDataPtr[qi] = qBuf[iSector * 16 + qi]; } } } @@ -604,26 +856,22 @@ namespace CUETools.Ripper.SCSI } } - private unsafe Device.CommandStatus FetchSectors(int sector, int Sectors2Read, bool abort, bool subchannel) + private unsafe Device.CommandStatus FetchSectors(int sector, int Sectors2Read, bool abort) { Device.CommandStatus st; fixed (byte* data = _readBuffer) { if (_debugMessages) { - int size = (4 * 588 + - (_subChannelMode == Device.SubChannelMode.QOnly ? 16 : _subChannelMode == Device.SubChannelMode.RWMode ? 96 : 0) + - (_c2ErrorMode == Device.C2ErrorMode.Mode294 ? 294 : _c2ErrorMode == Device.C2ErrorMode.Mode296 ? 296 : 0)) * (int)Sectors2Read; + int size = (4 * 588 + (_c2ErrorMode == Device.C2ErrorMode.Mode294 ? 294 : _c2ErrorMode == Device.C2ErrorMode.Mode296 ? 296 : 0)) + * (int)Sectors2Read; MemSet(data, size, 0xff); } if (_readCDCommand == ReadCDCommand.ReadCdBEh) - st = m_device.ReadCDAndSubChannel(_mainChannelMode, _subChannelMode, _c2ErrorMode, 1, false, (uint)sector + _toc[_toc.FirstAudio][0].Start, (uint)Sectors2Read, (IntPtr)((void*)data), _timeout); + st = m_device.ReadCDAndSubChannel(_mainChannelMode, Device.SubChannelMode.None, _c2ErrorMode, 1, false, (uint)sector + _toc[_toc.FirstAudio][0].Start, (uint)Sectors2Read, (IntPtr)((void*)data), _timeout); else - st = m_device.ReadCDDA(_subChannelMode, (uint)sector + _toc[_toc.FirstAudio][0].Start, (uint)Sectors2Read, (IntPtr)((void*)data), _timeout); + st = m_device.ReadCDDA(Device.SubChannelMode.None, (uint)sector + _toc[_toc.FirstAudio][0].Start, (uint)Sectors2Read, (IntPtr)((void*)data), _timeout); } - - if (st == Device.CommandStatus.Success && _subChannelMode == Device.SubChannelMode.None && subchannel) - st = m_device.ReadSubChannel(2, (uint)sector + _toc[_toc.FirstAudio][0].Start, (uint)Sectors2Read, ref _subchannelBuffer, _timeout); if (st == Device.CommandStatus.Success) { @@ -641,13 +889,11 @@ namespace CUETools.Ripper.SCSI int iErrors = 0; for (int iSector = 0; iSector < Sectors2Read; iSector++) { - if (FetchSectors(sector + iSector, 1, false, subchannel) != Device.CommandStatus.Success) + if (FetchSectors(sector + iSector, 1, false) != Device.CommandStatus.Success) { iErrors ++; for (int i = 0; i < 294; i++) C2Count[sector + iSector - _currentStart, i] ++; - for (int i = 0; i < 16; i++) - QData[ sector + iSector - _currentStart, i] = 0; if (_debugMessages) System.Console.WriteLine("\nSector lost"); } @@ -814,6 +1060,7 @@ namespace CUETools.Ripper.SCSI fError |= (sum ^ sig) < er_limit; bestValue += sig & (1 << i); val >>= 8; + val1 >>= 8; } currentData.Bytes[pos * 4 * 588 + iPar] = (byte)bestValue; } @@ -891,10 +1138,10 @@ namespace CUETools.Ripper.SCSI if (iSector >= _currentStart && iSector < _currentEnd) return; - if (_readCDCommand == ReadCDCommand.Unknown && !TestReadCommand()) - throw new Exception("failed to autodetect read command: " + _autodetectResult); + if (!TestReadCommand()) + throw new Exception("failed to autodetect read command:\n" + _autodetectResult); - _currentStart = MSECTORS * (iSector / MSECTORS); + _currentStart = iSector; _currentEnd = _currentStart + MSECTORS; if (_currentEnd > (int)_toc.AudioLength) { @@ -918,6 +1165,12 @@ namespace CUETools.Ripper.SCSI for (int i = 0; i < MSECTORS; i++) errtmp[i] = 0; + //Device.CommandStatus st = m_device.SetCdSpeed(Device.RotationalControl.CLVandNonPureCav, (ushort)(176 * 4), 65535); + //if (st != Device.CommandStatus.Success) + // System.Console.WriteLine("SetCdSpeed: {0}", (st == Device.CommandStatus.DeviceFailed ? Device.LookupSenseError(m_device.GetSenseAsc(), m_device.GetSenseAscq()) : st.ToString())); + + // TODO: + //int max_scans = 1 << _correctionQuality; int max_scans = 16 << _correctionQuality; for (int pass = 0; pass < max_scans; pass++) { @@ -935,10 +1188,8 @@ namespace CUETools.Ripper.SCSI LastFetch = DateTime.Now; if (pass == 0) ClearSectors(sector, Sectors2Read); - FetchSectors(sector, Sectors2Read, true, pass == 0); + FetchSectors(sector, Sectors2Read, true); //TimeSpan delay1 = DateTime.Now - LastFetch; - if (pass == 0) - ProcessSubchannel(sector, Sectors2Read, true); //DateTime LastFetched = DateTime.Now; if (pass >= _correctionQuality) { @@ -949,7 +1200,16 @@ namespace CUETools.Ripper.SCSI //if (sector == _currentStart) //System.Console.WriteLine("\n{0},{1}", delay1.TotalMilliseconds, delay2.TotalMilliseconds); if (ReadProgress != null) - ReadProgress(this, new ReadProgressArgs(sector + Sectors2Read, pass, _currentStart, _currentEnd, _currentErrorsCount, PassTime)); + { + progressArgs.Action = "Ripping"; + progressArgs.Position = sector + Sectors2Read; + progressArgs.Pass = pass; + progressArgs.PassStart = _currentStart; + progressArgs.PassEnd = _currentEnd; + progressArgs.ErrorsCount = _currentErrorsCount; + progressArgs.PassTime = PassTime; + ReadProgress(this, progressArgs); + } } //System.Console.WriteLine(); //if (CorrectSectorsTest(start, _currentEnd, 10, realData) == 0) @@ -970,6 +1230,7 @@ namespace CUETools.Ripper.SCSI { for (int i = 0; i < buff.ByteLength; i++) buff.Bytes[i] = 0; + _sampleOffset += buff.Length; return buff.Length; // == Remaining } if (_sampleOffset < 0) @@ -977,9 +1238,10 @@ namespace CUETools.Ripper.SCSI buff.Length = Math.Min(buff.Length, -_sampleOffset); for (int i = 0; i < buff.ByteLength; i++) buff.Bytes[i] = 0; + _sampleOffset += buff.Length; return buff.Length; } - PrefetchSector(_sampleOffset / 588); + PrefetchSector(/*(int)_toc[_toc.FirstAudio][0].Start +*/ (_sampleOffset / 588)); buff.Length = Math.Min(buff.Length, (int)Length - _sampleOffset); buff.Length = Math.Min(buff.Length, _currentEnd * 588 - _sampleOffset); if ((_sampleOffset - _currentStart * 588) == 0 && (maxLength < 0 || (_currentEnd - _currentStart) * 588 <= buff.Length)) @@ -1101,7 +1363,7 @@ namespace CUETools.Ripper.SCSI { get { - return "CUERipper v2.0.5 Copyright (C) 2008-10 Gregory S. Chudov"; + return "CUERipper v2.0.6 Copyright (C) 2008-10 Gregory S. Chudov"; // ripper.GetName().Name + " " + ripper.GetName().Version; } } diff --git a/CUETools.Ripper/Properties/AssemblyInfo.cs b/CUETools.Ripper/Properties/AssemblyInfo.cs index 113510b..4099b0a 100644 --- a/CUETools.Ripper/Properties/AssemblyInfo.cs +++ b/CUETools.Ripper/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ using System.Runtime.InteropServices; // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("2.0.5.0")] -[assembly: AssemblyFileVersion("2.0.5.0")] +[assembly: AssemblyVersion("2.0.6.0")] +[assembly: AssemblyFileVersion("2.0.6.0")] diff --git a/CUETools.Ripper/Ripper.cs b/CUETools.Ripper/Ripper.cs index 7356e13..4e60e57 100644 --- a/CUETools.Ripper/Ripper.cs +++ b/CUETools.Ripper/Ripper.cs @@ -11,6 +11,8 @@ namespace CUETools.Ripper public interface ICDRipper : IAudioSource, IDisposable { bool Open(char Drive); + bool DetectGaps(); + bool GapsDetected { get; } CDImageLayout TOC { get; } string ARName { get; } string EACName { get; } @@ -37,12 +39,17 @@ namespace CUETools.Ripper public sealed class ReadProgressArgs : EventArgs { + public string Action; public int Position; public int Pass; public int PassStart, PassEnd; public int ErrorsCount; public DateTime PassTime; + public ReadProgressArgs() + { + } + public ReadProgressArgs(int position, int pass, int passStart, int passEnd, int errorsCount, DateTime passTime) { Position = position; diff --git a/CUETools/CUETools.TestProcessor/ProcessorTest.cs b/CUETools/CUETools.TestProcessor/ProcessorTest.cs index 37e2f35..637fb7d 100644 --- a/CUETools/CUETools.TestProcessor/ProcessorTest.cs +++ b/CUETools/CUETools.TestProcessor/ProcessorTest.cs @@ -71,36 +71,49 @@ namespace CUETools.TestProcessor /// - ///A test for Open (string) + ///A test for CD-Extra /// [TestMethod()] - public void OpenTest() + public void OpenCDExtra() { - CUEConfig config = new CUEConfig(); - CUESheet target = null; - // test playstation-type CD-Extra - target = new CUESheet(config); + CUESheet target = new CUESheet(new CUEConfig()); target.Open("Circuitry\\1.cue"); Assert.AreEqual("00078c13-001b4ab9-40086205", AccurateRipVerify.CalculateAccurateRipId(target.TOC), "Wrong TOC"); // test playstation-type CD-Extra with nonstandard pregap - target = new CUESheet(config); + target = new CUESheet(new CUEConfig()); target.Open("Headcandy\\Headcandy.cue"); Assert.AreEqual("0014fc22-0052b286-62104a06", AccurateRipVerify.CalculateAccurateRipId(target.TOC), "Wrong TOC"); - // test Enhanced-CD - target = new CUESheet(config); - target.Open("No Man's Land\\1.cue"); - Assert.AreEqual("0015c42c-00d1e13f-ba0fe50d", AccurateRipVerify.CalculateAccurateRipId(target.TOC), "Wrong TOC"); - - // test one-track CD - target = new CUESheet(config); - target.Open("Amarok\\Amarok.cue"); - Assert.AreEqual("00041f6d-00083ece-020e1201", AccurateRipVerify.CalculateAccurateRipId(target.TOC), "Wrong TOC"); + // test playstation-type CD-Extra with no info in cuesheet + target = new CUESheet(new CUEConfig()); + target.Open("Anatomy\\Anatomy.cue"); + Assert.AreEqual("002a09da-01e82f64-f00f4811", AccurateRipVerify.CalculateAccurateRipId(target.TOC), "Wrong TOC"); } + /// + ///A test for Enhanced-CD + /// + [TestMethod()] + public void OpenEnhancedCD() + { + // test Enhanced-CD + CUESheet target = new CUESheet(new CUEConfig()); + target.Open("No Man's Land\\1.cue"); + Assert.AreEqual("0015c42c-00d1e13f-ba0fe50d", AccurateRipVerify.CalculateAccurateRipId(target.TOC), "Wrong TOC"); + } + + /// + ///A test for one-track CD + /// + [TestMethod()] + public void OpenOneTrackCD() + { + // test one-track CD + CUESheet target = new CUESheet(new CUEConfig()); + target.Open("Amarok\\Amarok.cue"); + Assert.AreEqual("00041f6d-00083ece-020e1201", AccurateRipVerify.CalculateAccurateRipId(target.TOC), "Wrong TOC"); + } } - - } diff --git a/CUETools/CUETools.TestProcessor/Test Images/Anatomy/Anatomy.cue b/CUETools/CUETools.TestProcessor/Test Images/Anatomy/Anatomy.cue new file mode 100644 index 0000000..a43b68b --- /dev/null +++ b/CUETools/CUETools.TestProcessor/Test Images/Anatomy/Anatomy.cue @@ -0,0 +1,33 @@ +FILE "Anatomy.dummy" WAVE + TRACK 01 AUDIO + INDEX 01 00:00:00 + TRACK 02 AUDIO + INDEX 01 02:59:32 + TRACK 03 AUDIO + INDEX 01 06:53:18 + TRACK 04 AUDIO + INDEX 01 11:09:10 + TRACK 05 AUDIO + INDEX 01 15:35:10 + TRACK 06 AUDIO + INDEX 01 19:38:47 + TRACK 07 AUDIO + INDEX 01 24:58:61 + TRACK 08 AUDIO + INDEX 01 29:05:63 + TRACK 09 AUDIO + INDEX 01 32:34:34 + TRACK 10 AUDIO + INDEX 01 38:55:70 + TRACK 11 AUDIO + INDEX 01 40:06:35 + TRACK 12 AUDIO + INDEX 01 43:35:72 + TRACK 13 AUDIO + INDEX 01 48:04:59 + TRACK 14 AUDIO + INDEX 01 49:35:03 + TRACK 15 AUDIO + INDEX 01 55:31:06 + TRACK 16 AUDIO + INDEX 01 58:17:56 diff --git a/CUETools/CUETools.TestProcessor/Test Images/Anatomy/Anatomy.dummy b/CUETools/CUETools.TestProcessor/Test Images/Anatomy/Anatomy.dummy new file mode 100644 index 0000000..728d5ad --- /dev/null +++ b/CUETools/CUETools.TestProcessor/Test Images/Anatomy/Anatomy.dummy @@ -0,0 +1 @@ +160952652 \ No newline at end of file diff --git a/CUETools/CUETools.TestProcessor/Test Images/Anatomy/Anatomy.log b/CUETools/CUETools.TestProcessor/Test Images/Anatomy/Anatomy.log new file mode 100644 index 0000000..2a4773e --- /dev/null +++ b/CUETools/CUETools.TestProcessor/Test Images/Anatomy/Anatomy.log @@ -0,0 +1,85 @@ +Exact Audio Copy V0.99 prebeta 4 from 23. January 2008 + +EAC extraction logfile from 4. March 2010, 23:08 + +Îëüãà Àðåôüåâà / Àíàòîìèÿ (CD1) + +Used drive : PIONEER DVD-RW DVR-215D Adapter: 1 ID: 0 + +Read mode : Secure +Utilize accurate stream : Yes +Defeat audio cache : Yes +Make use of C2 pointers : No + +Read offset correction : 48 +Overread into Lead-In and Lead-Out : No +Fill up missing offset samples with silence : Yes +Delete leading and trailing silent blocks : No +Null samples used in CRC calculations : Yes +Used interface : Native Win32 interface for Win NT & 2000 + +Used output format : Internal WAV Routines +Sample format : 44.100 Hz; 16 Bit; Stereo + + +TOC of the extracted CD + + Track | Start | Length | Start sector | End sector + --------------------------------------------------------- + 1 | 0:00.00 | 4:22.37 | 0 | 19686 + 2 | 4:22.37 | 2:59.32 | 19687 | 33143 + 3 | 7:21.69 | 3:53.61 | 33144 | 50679 + 4 | 11:15.55 | 4:15.67 | 50680 | 69871 + 5 | 15:31.47 | 4:26.00 | 69872 | 89821 + 6 | 19:57.47 | 4:03.37 | 89822 | 108083 + 7 | 24:01.09 | 5:20.14 | 108084 | 132097 + 8 | 29:21.23 | 4:07.02 | 132098 | 150624 + 9 | 33:28.25 | 3:28.46 | 150625 | 166270 + 10 | 36:56.71 | 6:21.36 | 166271 | 194881 + 11 | 43:18.32 | 1:10.40 | 194882 | 200171 + 12 | 44:28.72 | 3:29.37 | 200172 | 215883 + 13 | 47:58.34 | 4:28.62 | 215884 | 236045 + 14 | 52:27.21 | 1:30.19 | 236046 | 242814 + 15 | 53:57.40 | 5:56.03 | 242815 | 269517 + 16 | 59:53.43 | 2:46.50 | 269518 | 282017 + 17 | 62:40.18 | 2:31.73 | 282018 | 293415 + + +Range status and errors + +Selected range + + Filename Z:\Music\New\Îëüãà Àðåôüåâà - 2001 - Àíàòîìèÿ (CD1) (2)\Îëüãà Àðåôüåâà - Àíàòîìèÿ (CD1).wav + + Peak level 96.8 % + Range quality 100.0 % + Test_CRC 900B46C9 + Copy_CRC 900B46C9 + Copy OK + +No errors occurred + + +AccurateRip summary + +Track 1 not present in database +Track 2 not present in database +Track 3 cannot be verified as accurate (confidence 2) [ABFDCBE5], AccurateRip returned [CE139C13] +Track 4 cannot be verified as accurate (confidence 2) [FD73C536], AccurateRip returned [ABFDCBE5] +Track 5 cannot be verified as accurate (confidence 2) [041E67B6], AccurateRip returned [FD73C536] +Track 6 cannot be verified as accurate (confidence 2) [7F3ACA35], AccurateRip returned [041E67B6] +Track 7 cannot be verified as accurate (confidence 2) [40F2BE73], AccurateRip returned [7F3ACA35] +Track 8 cannot be verified as accurate (confidence 2) [19AAED4C], AccurateRip returned [40F2BE73] +Track 9 cannot be verified as accurate (confidence 2) [7C0E0656], AccurateRip returned [19AAED4C] +Track 10 cannot be verified as accurate (confidence 2) [ADD905EF], AccurateRip returned [7C0E0656] +Track 11 cannot be verified as accurate (confidence 2) [A18D8581], AccurateRip returned [ADD905EF] +Track 12 cannot be verified as accurate (confidence 2) [B4E21ED5], AccurateRip returned [A18D8581] +Track 13 cannot be verified as accurate (confidence 2) [7D5BC78C], AccurateRip returned [B4E21ED5] +Track 14 cannot be verified as accurate (confidence 2) [40D2728E], AccurateRip returned [7D5BC78C] +Track 15 cannot be verified as accurate (confidence 2) [990F316E], AccurateRip returned [40D2728E] +Track 16 cannot be verified as accurate (confidence 2) [FC5F3E48], AccurateRip returned [990F316E] + +No tracks could be verified as accurate +You may have a different pressing from the one(s) in the database + +End of status report diff --git a/CUETools/CUETools1.vsmdi b/CUETools/CUETools1.vsmdi new file mode 100644 index 0000000..72f5653 --- /dev/null +++ b/CUETools/CUETools1.vsmdi @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/CUETools/Properties/AssemblyInfo.cs b/CUETools/Properties/AssemblyInfo.cs index 2ba63af..f069d41 100644 --- a/CUETools/Properties/AssemblyInfo.cs +++ b/CUETools/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("2.0.5.0")] -[assembly: AssemblyFileVersion("2.0.5.0")] +[assembly: AssemblyVersion("2.0.6.0")] +[assembly: AssemblyFileVersion("2.0.6.0")] diff --git a/CUETools/Resources/more/icons/folder.png b/CUETools/Resources/more/icons/folder.png new file mode 100644 index 0000000..784e8fa Binary files /dev/null and b/CUETools/Resources/more/icons/folder.png differ diff --git a/CUETools/Resources/more/icons/folder_add.png b/CUETools/Resources/more/icons/folder_add.png new file mode 100644 index 0000000..529fe8f Binary files /dev/null and b/CUETools/Resources/more/icons/folder_add.png differ diff --git a/CUETools/Resources/more/icons/folder_delete.png b/CUETools/Resources/more/icons/folder_delete.png new file mode 100644 index 0000000..112b016 Binary files /dev/null and b/CUETools/Resources/more/icons/folder_delete.png differ diff --git a/CUETools/Resources/more/icons/folder_feed.png b/CUETools/Resources/more/icons/folder_feed.png new file mode 100644 index 0000000..d06ee51 Binary files /dev/null and b/CUETools/Resources/more/icons/folder_feed.png differ diff --git a/CUETools/Resources/more/icons/folder_page.png b/CUETools/Resources/more/icons/folder_page.png new file mode 100644 index 0000000..1ef6e11 Binary files /dev/null and b/CUETools/Resources/more/icons/folder_page.png differ diff --git a/CUETools/frmCUETools.Designer.cs b/CUETools/frmCUETools.Designer.cs index aca7f0d..04cc7d9 100644 --- a/CUETools/frmCUETools.Designer.cs +++ b/CUETools/frmCUETools.Designer.cs @@ -286,9 +286,9 @@ namespace JDP { this.fileSystemTreeView1.DragDrop += new System.Windows.Forms.DragEventHandler(this.fileSystemTreeView1_DragDrop); this.fileSystemTreeView1.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.fileSystemTreeView1_AfterSelect); this.fileSystemTreeView1.MouseDown += new System.Windows.Forms.MouseEventHandler(this.fileSystemTreeView1_MouseDown); - this.fileSystemTreeView1.DragEnter += new System.Windows.Forms.DragEventHandler(this.fileSystemTreeView1_DragEnter); this.fileSystemTreeView1.KeyDown += new System.Windows.Forms.KeyEventHandler(this.fileSystemTreeView1_KeyDown); this.fileSystemTreeView1.AfterExpand += new System.Windows.Forms.TreeViewEventHandler(this.fileSystemTreeView1_AfterExpand); + this.fileSystemTreeView1.DragOver += new System.Windows.Forms.DragEventHandler(this.fileSystemTreeView1_DragOver); // // tableLayoutPanel2 // diff --git a/CUETools/frmCUETools.cs b/CUETools/frmCUETools.cs index fcbabe6..7c78ce2 100644 --- a/CUETools/frmCUETools.cs +++ b/CUETools/frmCUETools.cs @@ -738,15 +738,12 @@ namespace JDP { cueSheet.OutputStyle = cueStyle; cueSheet.Open(pathIn); cueSheet.PreGapLengthMSF = txtPreGapLength.Text; - if (useAR) - { + if (useAR || useCUEToolsDB) cueSheet.DataTrackLengthMSF = txtDataTrackLength.Text; - cueSheet.UseAccurateRip(); - } if (useCUEToolsDB) - { - cueSheet.UseCUEToolsDB(false, "CUETools 205"); - } + cueSheet.UseCUEToolsDB(false, "CUETools 2.0.6"); + if (useAR) + cueSheet.UseAccurateRip(); if (_batchPaths.Count == 0 && action == CUEAction.Encode) { @@ -761,10 +758,15 @@ namespace JDP { toolStripStatusLabelAR.Text = cueSheet.ArVerify.ARStatus == null ? cueSheet.ArVerify.WorstTotal().ToString() : ""; toolStripStatusLabelAR.ToolTipText = "AccurateRip: " + (cueSheet.ArVerify.ARStatus ?? "found") + "."; - toolStripStatusLabelCTDB.Enabled = cueSheet.CTDB.DBStatus == null; - toolStripStatusLabelCTDB.Visible = useCUEToolsDB; - toolStripStatusLabelCTDB.Text = cueSheet.CTDB.DBStatus == null ? cueSheet.CTDB.Total.ToString() : ""; - toolStripStatusLabelCTDB.ToolTipText = "CUETools DB: " + (cueSheet.CTDB.DBStatus ?? "found") + "."; + if (!useCUEToolsDB) + toolStripStatusLabelCTDB.Visible = false; + else + { + toolStripStatusLabelCTDB.Visible = true; + toolStripStatusLabelCTDB.Enabled = cueSheet.CTDB.DBStatus == null; + toolStripStatusLabelCTDB.Text = cueSheet.CTDB.DBStatus == null ? cueSheet.CTDB.Total.ToString() : ""; + toolStripStatusLabelCTDB.ToolTipText = "CUETools DB: " + (cueSheet.CTDB.DBStatus ?? "found") + "."; + } if (releases != null) { @@ -917,7 +919,11 @@ namespace JDP { else { _batchProcessed++; - BatchLog("{0}.", pathIn, ex.Message); + String msg = ""; + for (Exception e = ex; e != null; e = e.InnerException) + msg += ": " + e.Message; + BatchLog("{0}.", pathIn, msg.Substring(2)); + } } #endif @@ -1592,13 +1598,20 @@ namespace JDP { private void fileSystemTreeView1_KeyDown(object sender, KeyEventArgs e) { - if (e.KeyCode != Keys.F5) return; - if (fileSystemTreeView1.Nodes.Count == 0) return; - string was = fileSystemTreeView1.SelectedPath; - fileSystemTreeView1.Nodes[0].Collapse(); - fileSystemTreeView1.Nodes[0].Expand(); - if (was != null) - fileSystemTreeView1.SelectedPath = was; + switch (e.KeyCode) + { + case Keys.F5: + string was = fileSystemTreeView1.SelectedPath; + foreach (TreeNode node in fileSystemTreeView1.Nodes) + node.Collapse(); + if (was != null) + fileSystemTreeView1.SelectedPath = was; + break; + case Keys.Delete: + if (FileBrowserState == FileBrowserStateEnum.DragDrop && fileSystemTreeView1.SelectedNode != null) + fileSystemTreeView1.Nodes.Remove(fileSystemTreeView1.SelectedNode); + break; + } } private void fileSystemTreeView1_NodeExpand(object sender, CUEControls.FileSystemTreeViewNodeExpandEventArgs e) @@ -1680,11 +1693,14 @@ namespace JDP { node.Checked = e.Node.Checked; } - private void fileSystemTreeView1_DragEnter(object sender, DragEventArgs e) + private void fileSystemTreeView1_DragOver(object sender, DragEventArgs e) { if (e.Data.GetDataPresent(DataFormats.FileDrop)) { - e.Effect = DragDropEffects.Copy; + if (((e.KeyState & 8) != 0 && FileBrowserState == FileBrowserStateEnum.DragDrop) || FileBrowserState == FileBrowserStateEnum.Checkboxes) + e.Effect = DragDropEffects.Copy; + else + e.Effect = DragDropEffects.Move; } } @@ -1716,7 +1732,8 @@ namespace JDP { } break; case FileBrowserStateEnum.DragDrop: - fileSystemTreeView1.Nodes.Clear(); + if (e.Effect == DragDropEffects.Move) + fileSystemTreeView1.Nodes.Clear(); foreach (string folder in folders) { TreeNode node = Directory.Exists(folder) diff --git a/CUETools/frmCUETools.resx b/CUETools/frmCUETools.resx index 4a4a385..00defbc 100644 --- a/CUETools/frmCUETools.resx +++ b/CUETools/frmCUETools.resx @@ -258,26 +258,11 @@ 0 - - Top, Bottom, Left, Right - - - 19 - - - 3, 17 - - - 192, 304 - - - 1 - fileSystemTreeView1 - CUEControls.FileSystemTreeView, CUEControls, Version=2.0.5.0, Culture=neutral, PublicKeyToken=null + CUEControls.FileSystemTreeView, CUEControls, Version=2.0.6.0, Culture=neutral, PublicKeyToken=null grpInput @@ -318,9 +303,1032 @@ 3 + + 3, 17 + + + tableLayoutPanelCUEStyle + + + System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + groupBoxMode + + + 0 + + + <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="checkBoxUseAccurateRip" Row="4" RowSpan="1" Column="2" ColumnSpan="1" /><Control Name="checkBoxUseFreeDb" Row="4" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="rbTracks" Row="2" RowSpan="1" Column="0" ColumnSpan="3" /><Control Name="rbEmbedCUE" Row="0" RowSpan="1" Column="0" ColumnSpan="3" /><Control Name="rbSingleFile" Row="1" RowSpan="1" Column="0" ColumnSpan="3" /><Control Name="checkBoxUseMusicBrainz" Row="4" RowSpan="1" Column="0" ColumnSpan="1" /></Controls><Columns Styles="Percent,33,33332,Percent,33,33334,Percent,33,33334" /><Rows Styles="Percent,18,18229,Percent,18,18229,Percent,18,18229,Percent,22,72658,Percent,22,72658" /></TableLayoutSettings> + + + toolStripCorrectorFormat + + + System.Windows.Forms.ToolStrip, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + groupBoxMode + + + 1 + + + tableLayoutPanelVerifyMode + + + System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + groupBoxMode + + + 2 + + + <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="checkBoxVerifyUseCDRepair" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /></Controls><Columns Styles="Percent,36,11111,Percent,63,88889" /><Rows Styles="Percent,32,72727,Percent,67,27273" /></TableLayoutSettings> + + + Fill + + + 173, 101 + + + 150, 130 + + + 12 + + + Mode + + + groupBoxMode + + + System.Windows.Forms.GroupBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableLayoutPanel2 + + + 0 + + + labelEncoderMaxMode + + + System.Windows.Forms.Label, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + grpAudioOutput + + + 0 + + + labelEncoderMinMode + + + System.Windows.Forms.Label, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + grpAudioOutput + + + 1 + + + labelEncoderMode + + + System.Windows.Forms.Label, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + grpAudioOutput + + + 2 + + + trackBarEncoderMode + + + System.Windows.Forms.TrackBar, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + grpAudioOutput + + + 3 + + + comboBoxEncoder + + + System.Windows.Forms.ComboBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + grpAudioOutput + + + 4 + + + radioButtonAudioNone + + + System.Windows.Forms.RadioButton, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + grpAudioOutput + + + 5 + + + radioButtonAudioLossy + + + System.Windows.Forms.RadioButton, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + grpAudioOutput + + + 6 + + + radioButtonAudioHybrid + + + System.Windows.Forms.RadioButton, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + grpAudioOutput + + + 7 + + + radioButtonAudioLossless + + + System.Windows.Forms.RadioButton, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + grpAudioOutput + + + 8 + + + labelFormat + + + System.Windows.Forms.Label, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + grpAudioOutput + + + 9 + + + comboBoxAudioFormat + + + System.Windows.Forms.ComboBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + grpAudioOutput + + + 10 + + + Fill + + + 329, 101 + + + 148, 194 + + + 2 + + + Audio Output + + + grpAudioOutput + + + System.Windows.Forms.GroupBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableLayoutPanel2 + + + 1 + + + Fill + + + NoControl + + + 3, 237 + + + 164, 90 + + + Zoom + + + 15 + + + pictureBoxMotd + + + System.Windows.Forms.PictureBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableLayoutPanel2 + + + 2 + + + 2 + + + Fill + + + NoControl + + + 0, 48 + + + 0, 0, 0, 0 + + + 97, 24 + + + 13 + + + Template: + + + MiddleLeft + + + labelOutputTemplate + + + System.Windows.Forms.Label, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableLayoutPanelPaths + + + 0 + + + Fill + + + 100, 51 + + + 365, 21 + + + 9 + + + 153, 8 + + + Template for output files (foobar2000 format) + + + comboBoxOutputFormat + + + System.Windows.Forms.ComboBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableLayoutPanelPaths + + + 1 + + + Fill + + + 100, 3 + + + 365, 21 + + + 0 + + + Input file + + + txtInputPath + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableLayoutPanelPaths + + + 2 + + + Fill + + + 100, 27 + + + 365, 21 + + + 0 + + + Output file + + + txtOutputPath + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableLayoutPanelPaths + + + 3 + + + 0, 0 + + + Fill + + + 0, 0 + + + 0, 0, 0, 0 + + + 97, 24 + + + 14 + + + toolStripInput + + + toolStripInput + + + System.Windows.Forms.ToolStrip, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableLayoutPanelPaths + + + 4 + + + 0, 24 + + + Fill + + + 0, 24 + + + 0, 0, 0, 0 + + + 97, 24 + + + 15 + + + toolStripOutput + + + toolStripOutput + + + System.Windows.Forms.ToolStrip, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableLayoutPanelPaths + + + 5 + + + Fill + + + 3, 17 + + + 0, 0, 0, 0 + + + 3 + + + 468, 72 + + + 14 + + + tableLayoutPanelPaths + + + System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + grpOutputPathGeneration + + + 0 + + + <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="labelOutputTemplate" Row="2" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="comboBoxOutputFormat" Row="2" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="txtInputPath" Row="0" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="txtOutputPath" Row="1" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="toolStripInput" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="toolStripOutput" Row="1" RowSpan="1" Column="0" ColumnSpan="1" /></Controls><Columns Styles="Percent,20,94017,Percent,79,05983" /><Rows Styles="Percent,33,33333,Percent,33,33333,Percent,33,33333" /></TableLayoutSettings> + + + Fill + + + 3, 3 + + + 474, 92 + + + 1 + + + CUE Paths + + + grpOutputPathGeneration + + + System.Windows.Forms.GroupBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableLayoutPanel2 + + + 3 + + + comboBoxScript + + + System.Windows.Forms.ComboBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + grpAction + + + 0 + + + rbActionCorrectFilenames + + + System.Windows.Forms.RadioButton, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + grpAction + + + 1 + + + rbActionCreateCUESheet + + + System.Windows.Forms.RadioButton, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + grpAction + + + 2 + + + rbActionVerify + + + System.Windows.Forms.RadioButton, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + grpAction + + + 3 + + + rbActionEncode + + + System.Windows.Forms.RadioButton, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + grpAction + + + 4 + + + Fill + + + 3, 101 + + + 164, 130 + + + 4 + + + Action + + + grpAction + + + System.Windows.Forms.GroupBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableLayoutPanel2 + + + 4 + + + tableLayoutPanel4 + + + System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + grpExtra + + + 0 + + + <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="labelPregap" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="lblWriteOffset" Row="2" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="numericWriteOffset" Row="2" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="txtPreGapLength" Row="0" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="labelDataTrack" Row="1" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="txtDataTrackLength" Row="1" RowSpan="1" Column="1" ColumnSpan="1" /></Controls><Columns Styles="Percent,56,75676,Percent,43,24324" /><Rows Styles="Percent,33,33333,Percent,33,33333,Percent,33,33333" /></TableLayoutSettings> + + + Fill + + + 173, 237 + + + 150, 90 + + + 6 + + + Extra + + + grpExtra + + + System.Windows.Forms.GroupBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableLayoutPanel2 + + + 5 + + + btnConvert + + + System.Windows.Forms.Button, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + panelGo + + + 0 + + + btnStop + + + System.Windows.Forms.Button, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + panelGo + + + 1 + + + btnResume + + + System.Windows.Forms.Button, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + panelGo + + + 2 + + + btnPause + + + System.Windows.Forms.Button, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + panelGo + + + 3 + + + Fill + + + 338, 301 + + + 12, 3, 12, 3 + + + 130, 26 + + + 14 + + + panelGo + + + System.Windows.Forms.Panel, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableLayoutPanel2 + + + 6 + + + Fill + + + 204, 0 + + + 0, 0, 0, 0 + + + 4 + + + 480, 330 + + + 1 + + + tableLayoutPanel2 + + + System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableLayoutPanel1 + + + 2 + + + <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="groupBoxMode" Row="1" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="grpAudioOutput" Row="1" RowSpan="2" Column="2" ColumnSpan="1" /><Control Name="pictureBoxMotd" Row="2" RowSpan="2" Column="0" ColumnSpan="1" /><Control Name="grpOutputPathGeneration" Row="0" RowSpan="1" Column="0" ColumnSpan="3" /><Control Name="grpAction" Row="1" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="grpExtra" Row="2" RowSpan="2" Column="1" ColumnSpan="1" /><Control Name="panelGo" Row="3" RowSpan="1" Column="2" ColumnSpan="1" /></Controls><Columns Styles="Percent,35,41667,Percent,32,70833,Percent,31,875" /><Rows Styles="Percent,29,69697,Percent,41,51515,Percent,19,39394,Percent,9,393939" /></TableLayoutSettings> + + + Fill + + + 0, 0 + + + 0, 0, 0, 0 + + + 2 + + + 684, 451 + + + 17 + + + tableLayoutPanel1 + + + System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + toolStripContainer1.ContentPanel + + + 0 + + + <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="textBatchReport" Row="1" RowSpan="1" Column="0" ColumnSpan="2" /><Control Name="grpInput" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="tableLayoutPanel2" Row="0" RowSpan="1" Column="1" ColumnSpan="1" /></Controls><Columns Styles="Percent,100,Absolute,480" /><Rows Styles="Absolute,330,Percent,100" /></TableLayoutSettings> + + + 0, 0, 0, 0 + + + 684, 451 + + + toolStripContainer1.ContentPanel + + + System.Windows.Forms.ToolStripContentPanel, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + toolStripContainer1 + + + 0 + + + Fill + + + toolStripContainer1.LeftToolStripPanel + + + System.Windows.Forms.ToolStripPanel, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + toolStripContainer1 + + + 1 + + + 0, 0 + + + toolStripContainer1.RightToolStripPanel + + + System.Windows.Forms.ToolStripPanel, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + toolStripContainer1 + + + 2 + + + 684, 502 + + + 17 + + + toolStripContainer1 + + + 0, 0 + + + None + + + 0, 0 + + + 684, 25 + + + 0 + + + toolStripMenu + + + System.Windows.Forms.ToolStrip, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + toolStripContainer1.TopToolStripPanel + + + 0 + + + toolStripContainer1.TopToolStripPanel + + + System.Windows.Forms.ToolStripPanel, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + toolStripContainer1 + + + 3 + + + toolStripContainer1 + + + System.Windows.Forms.ToolStripContainer, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 1 + + + Top, Bottom, Left, Right + + + 19 + + + 3, 17 + + + 192, 304 + + + 1 + + + fileSystemTreeView1 + + + CUEControls.FileSystemTreeView, CUEControls, Version=2.0.6.0, Culture=neutral, PublicKeyToken=null + + + grpInput + + + 0 + 3 + + checkBoxUseAccurateRip + + + System.Windows.Forms.CheckBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableLayoutPanelCUEStyle + + + 0 + + + checkBoxUseFreeDb + + + System.Windows.Forms.CheckBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableLayoutPanelCUEStyle + + + 1 + + + rbTracks + + + System.Windows.Forms.RadioButton, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableLayoutPanelCUEStyle + + + 2 + + + rbEmbedCUE + + + System.Windows.Forms.RadioButton, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableLayoutPanelCUEStyle + + + 3 + + + rbSingleFile + + + System.Windows.Forms.RadioButton, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableLayoutPanelCUEStyle + + + 4 + + + checkBoxUseMusicBrainz + + + System.Windows.Forms.CheckBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableLayoutPanelCUEStyle + + + 5 + + + Fill + + + 3, 17 + + + 0, 0, 0, 0 + + + 5 + + + 144, 110 + + + 11 + + + tableLayoutPanelCUEStyle + + + System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + groupBoxMode + + + 0 + + + <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="checkBoxUseAccurateRip" Row="4" RowSpan="1" Column="2" ColumnSpan="1" /><Control Name="checkBoxUseFreeDb" Row="4" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="rbTracks" Row="2" RowSpan="1" Column="0" ColumnSpan="3" /><Control Name="rbEmbedCUE" Row="0" RowSpan="1" Column="0" ColumnSpan="3" /><Control Name="rbSingleFile" Row="1" RowSpan="1" Column="0" ColumnSpan="3" /><Control Name="checkBoxUseMusicBrainz" Row="4" RowSpan="1" Column="0" ColumnSpan="1" /></Controls><Columns Styles="Percent,33,33332,Percent,33,33334,Percent,33,33334" /><Rows Styles="Percent,18,18229,Percent,18,18229,Percent,18,18229,Percent,22,72658,Percent,22,72658" /></TableLayoutSettings> + + + 153, 8 + True @@ -342,9 +1350,6 @@ 5 - - 153, 8 - Use AccurateRip @@ -549,39 +1554,6 @@ 5 - - Fill - - - 3, 17 - - - 0, 0, 0, 0 - - - 5 - - - 144, 110 - - - 11 - - - tableLayoutPanelCUEStyle - - - System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - groupBoxMode - - - 0 - - - <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="checkBoxUseAccurateRip" Row="4" RowSpan="1" Column="2" ColumnSpan="1" /><Control Name="checkBoxUseFreeDb" Row="4" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="rbTracks" Row="2" RowSpan="1" Column="0" ColumnSpan="3" /><Control Name="rbEmbedCUE" Row="0" RowSpan="1" Column="0" ColumnSpan="3" /><Control Name="rbSingleFile" Row="1" RowSpan="1" Column="0" ColumnSpan="3" /><Control Name="checkBoxUseMusicBrainz" Row="4" RowSpan="1" Column="0" ColumnSpan="1" /></Controls><Columns Styles="Percent,33,33332,Percent,33,33334,Percent,33,33334" /><Rows Styles="Percent,18,18229,Percent,18,18229,Percent,18,18229,Percent,22,72658,Percent,22,72658" /></TableLayoutSettings> - 3, 17 @@ -591,51 +1563,6 @@ Fill - - Magenta - - - 78, 20 - - - Overwrite - - - 168, 22 - - - Locate files - - - Try to locate missing files automatically - - - 168, 22 - - - Change extension - - - Replace extension for audio files with this: - - - Magenta - - - 79, 19 - - - Locate files - - - Magenta - - - 39, 19 - - - flac - 3, 17 @@ -660,27 +1587,54 @@ 1 + + Magenta + + + 78, 20 + + + Overwrite + + + Magenta + + + 79, 19 + + + Locate files + + + 168, 22 + + + Locate files + + + Try to locate missing files automatically + + + 168, 22 + + + Change extension + + + Replace extension for audio files with this: + + + Magenta + + + 39, 19 + + + flac + 2 - - True - - - Fill - - - NoControl - - - 3, 3 - - - 45, 29 - - - 0 - checkBoxVerifyUseCDRepair @@ -726,31 +1680,34 @@ <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="checkBoxVerifyUseCDRepair" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /></Controls><Columns Styles="Percent,36,11111,Percent,63,88889" /><Rows Styles="Percent,32,72727,Percent,67,27273" /></TableLayoutSettings> - + + True + + Fill - - 173, 101 + + NoControl - - 150, 130 + + 3, 3 - - 12 + + 45, 29 - - Mode + + 0 - - groupBoxMode + + checkBoxVerifyUseCDRepair - - System.Windows.Forms.GroupBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + System.Windows.Forms.CheckBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - tableLayoutPanel2 + + tableLayoutPanelVerifyMode - + 0 @@ -1113,195 +2070,21 @@ 10 - - Fill - - - 329, 101 - - - 148, 194 - - - 2 - - - Audio Output - - - grpAudioOutput - - - System.Windows.Forms.GroupBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - tableLayoutPanel2 - - - 1 - - - Fill - - - NoControl - - - 3, 237 - - - 164, 90 - - - Zoom - - - 15 - - - pictureBoxMotd - - - System.Windows.Forms.PictureBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - tableLayoutPanel2 - - - 2 - - - 2 - - - Fill - - - NoControl - - - 0, 48 - - - 0, 0, 0, 0 - - - 97, 24 - - - 13 - - - Template: - - - MiddleLeft - - - labelOutputTemplate - - - System.Windows.Forms.Label, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - tableLayoutPanelPaths - - - 0 - - - Fill - - - 100, 51 - - - 365, 21 - - - 9 - - - Template for output files (foobar2000 format) - - - comboBoxOutputFormat - - - System.Windows.Forms.ComboBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - tableLayoutPanelPaths - - - 1 - - - Fill - - - 100, 3 - - - 365, 21 - - - 0 - - - Input file - - - txtInputPath - - - System.Windows.Forms.TextBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - tableLayoutPanelPaths - - - 2 - - - Fill - - - 100, 27 - - - 365, 21 - - - 0 - - - Output file - - - txtOutputPath - - - System.Windows.Forms.TextBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - tableLayoutPanelPaths - - - 3 - - - 0, 0 - - - Fill - 38, 21 Input: + + Magenta + + + 32, 21 + + + Open/close input browser + 177, 22 @@ -1326,54 +2109,21 @@ Hide browser - - Magenta - - - 32, 21 - - - Open/close input browser - - - 0, 0 - - - 0, 0, 0, 0 - - - 97, 24 - - - 14 - - - toolStripInput - - - toolStripInput - - - System.Windows.Forms.ToolStrip, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - tableLayoutPanelPaths - - - 4 - - - 0, 24 - - - Fill - 48, 24 Output: + + Magenta + + + 32, 21 + + + toolStripSplitButtonOutputBrowser + 143, 22 @@ -1392,102 +2142,6 @@ Use template - - Magenta - - - 32, 21 - - - toolStripSplitButtonOutputBrowser - - - 0, 24 - - - 0, 0, 0, 0 - - - 97, 24 - - - 15 - - - toolStripOutput - - - toolStripOutput - - - System.Windows.Forms.ToolStrip, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - tableLayoutPanelPaths - - - 5 - - - Fill - - - 3, 17 - - - 0, 0, 0, 0 - - - 3 - - - 468, 72 - - - 14 - - - tableLayoutPanelPaths - - - System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - grpOutputPathGeneration - - - 0 - - - <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="labelOutputTemplate" Row="2" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="comboBoxOutputFormat" Row="2" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="txtInputPath" Row="0" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="txtOutputPath" Row="1" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="toolStripInput" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="toolStripOutput" Row="1" RowSpan="1" Column="0" ColumnSpan="1" /></Controls><Columns Styles="Percent,20,94017,Percent,79,05983" /><Rows Styles="Percent,33,33333,Percent,33,33333,Percent,33,33333" /></TableLayoutSettings> - - - Fill - - - 3, 3 - - - 474, 92 - - - 1 - - - CUE Paths - - - grpOutputPathGeneration - - - System.Windows.Forms.GroupBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - tableLayoutPanel2 - - - 3 - Top, Left, Right @@ -1647,36 +2301,114 @@ 4 - - Fill - - - 3, 101 - - - 164, 130 - - - 4 - - - Action - - - grpAction - - - System.Windows.Forms.GroupBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - tableLayoutPanel2 - - - 4 - 2 + + labelPregap + + + System.Windows.Forms.Label, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableLayoutPanel4 + + + 0 + + + lblWriteOffset + + + System.Windows.Forms.Label, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableLayoutPanel4 + + + 1 + + + numericWriteOffset + + + System.Windows.Forms.NumericUpDown, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableLayoutPanel4 + + + 2 + + + txtPreGapLength + + + System.Windows.Forms.MaskedTextBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableLayoutPanel4 + + + 3 + + + labelDataTrack + + + System.Windows.Forms.Label, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableLayoutPanel4 + + + 4 + + + txtDataTrackLength + + + System.Windows.Forms.MaskedTextBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableLayoutPanel4 + + + 5 + + + Fill + + + 3, 17 + + + 0, 0, 0, 0 + + + 3 + + + 144, 70 + + + 6 + + + tableLayoutPanel4 + + + System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + grpExtra + + + 0 + + + <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="labelPregap" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="lblWriteOffset" Row="2" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="numericWriteOffset" Row="2" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="txtPreGapLength" Row="0" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="labelDataTrack" Row="1" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="txtDataTrackLength" Row="1" RowSpan="1" Column="1" ColumnSpan="1" /></Controls><Columns Styles="Percent,56,75676,Percent,43,24324" /><Rows Styles="Percent,33,33333,Percent,33,33333,Percent,33,33333" /></TableLayoutSettings> + True @@ -1881,66 +2613,6 @@ 5 - - Fill - - - 3, 17 - - - 0, 0, 0, 0 - - - 3 - - - 144, 70 - - - 6 - - - tableLayoutPanel4 - - - System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - grpExtra - - - 0 - - - <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="labelPregap" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="lblWriteOffset" Row="2" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="numericWriteOffset" Row="2" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="txtPreGapLength" Row="0" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="labelDataTrack" Row="1" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="txtDataTrackLength" Row="1" RowSpan="1" Column="1" ColumnSpan="1" /></Controls><Columns Styles="Percent,56,75676,Percent,43,24324" /><Rows Styles="Percent,33,33333,Percent,33,33333,Percent,33,33333" /></TableLayoutSettings> - - - Fill - - - 173, 237 - - - 150, 90 - - - 6 - - - Extra - - - grpExtra - - - System.Windows.Forms.GroupBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - tableLayoutPanel2 - - - 5 - Fill @@ -2079,161 +2751,17 @@ 3 - - Fill + + Magenta - - 338, 301 + + 73, 22 - - 12, 3, 12, 3 + + default - - 130, 26 - - - 14 - - - panelGo - - - System.Windows.Forms.Panel, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - tableLayoutPanel2 - - - 6 - - - Fill - - - 204, 0 - - - 0, 0, 0, 0 - - - 4 - - - 480, 330 - - - 1 - - - tableLayoutPanel2 - - - System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - tableLayoutPanel1 - - - 2 - - - <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="groupBoxMode" Row="1" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="grpAudioOutput" Row="1" RowSpan="2" Column="2" ColumnSpan="1" /><Control Name="pictureBoxMotd" Row="2" RowSpan="2" Column="0" ColumnSpan="1" /><Control Name="grpOutputPathGeneration" Row="0" RowSpan="1" Column="0" ColumnSpan="3" /><Control Name="grpAction" Row="1" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="grpExtra" Row="2" RowSpan="2" Column="1" ColumnSpan="1" /><Control Name="panelGo" Row="3" RowSpan="1" Column="2" ColumnSpan="1" /></Controls><Columns Styles="Percent,35,41667,Percent,32,70833,Percent,31,875" /><Rows Styles="Percent,29,69697,Percent,41,51515,Percent,19,39394,Percent,9,393939" /></TableLayoutSettings> - - - Fill - - - 0, 0 - - - 0, 0, 0, 0 - - - 2 - - - 684, 451 - - - 17 - - - tableLayoutPanel1 - - - System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - toolStripContainer1.ContentPanel - - - 0 - - - <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="textBatchReport" Row="1" RowSpan="1" Column="0" ColumnSpan="2" /><Control Name="grpInput" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="tableLayoutPanel2" Row="0" RowSpan="1" Column="1" ColumnSpan="1" /></Controls><Columns Styles="Percent,100,Absolute,480" /><Rows Styles="Absolute,330,Percent,100" /></TableLayoutSettings> - - - 0, 0, 0, 0 - - - 684, 451 - - - toolStripContainer1.ContentPanel - - - System.Windows.Forms.ToolStripContentPanel, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - toolStripContainer1 - - - 0 - - - Fill - - - toolStripContainer1.LeftToolStripPanel - - - System.Windows.Forms.ToolStripPanel, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - toolStripContainer1 - - - 1 - - - 0, 0 - - - toolStripContainer1.RightToolStripPanel - - - System.Windows.Forms.ToolStripPanel, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - toolStripContainer1 - - - 2 - - - 684, 502 - - - 17 - - - toolStripContainer1 - - - 0, 0 - - - None + + Profile 100, 23 @@ -2259,18 +2787,6 @@ default - - Magenta - - - 73, 22 - - - default - - - Profile - 6, 25 @@ -2313,54 +2829,18 @@ Batch log - - 0, 0 - - - 684, 25 - - - 0 - - - toolStripMenu - - - System.Windows.Forms.ToolStrip, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - toolStripContainer1.TopToolStripPanel - - - 0 - - - toolStripContainer1.TopToolStripPanel - - - System.Windows.Forms.ToolStripPanel, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - toolStripContainer1 - - - 3 - - - toolStripContainer1 - - - System.Windows.Forms.ToolStripContainer, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - $this - - - 1 - 424, 8 + + 206, 76 + + + contextMenuStripFileTree + + + System.Windows.Forms.ContextMenuStrip, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + False @@ -2385,15 +2865,6 @@ Reset to original location - - 206, 76 - - - contextMenuStripFileTree - - - System.Windows.Forms.ContextMenuStrip, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - True @@ -2810,7 +3281,7 @@ 700, 538 - CUETools 2.0.5 + CUETools 2.0.6 toolStripStatusLabel1 diff --git a/MAC_SDK/Source/MACLib/Assembly/Assembly.obj b/MAC_SDK/Source/MACLib/Assembly/Assembly.obj index fa72420..8e054d8 100644 Binary files a/MAC_SDK/Source/MACLib/Assembly/Assembly.obj and b/MAC_SDK/Source/MACLib/Assembly/Assembly.obj differ diff --git a/MAC_SDK/Source/MACLib/Assembly/Assembly64.obj b/MAC_SDK/Source/MACLib/Assembly/Assembly64.obj index 1594d7c..1cb3d66 100644 Binary files a/MAC_SDK/Source/MACLib/Assembly/Assembly64.obj and b/MAC_SDK/Source/MACLib/Assembly/Assembly64.obj differ diff --git a/flac/src/libFLAC/ia32/bitreader_asm.obj b/flac/src/libFLAC/ia32/bitreader_asm.obj index ab2f273..8a56e40 100644 Binary files a/flac/src/libFLAC/ia32/bitreader_asm.obj and b/flac/src/libFLAC/ia32/bitreader_asm.obj differ diff --git a/flac/src/libFLAC/ia32/cpu_asm.obj b/flac/src/libFLAC/ia32/cpu_asm.obj index 99d892f..27aa3ad 100644 Binary files a/flac/src/libFLAC/ia32/cpu_asm.obj and b/flac/src/libFLAC/ia32/cpu_asm.obj differ diff --git a/flac/src/libFLAC/ia32/fixed_asm.obj b/flac/src/libFLAC/ia32/fixed_asm.obj index d8c397c..3486f7e 100644 Binary files a/flac/src/libFLAC/ia32/fixed_asm.obj and b/flac/src/libFLAC/ia32/fixed_asm.obj differ diff --git a/flac/src/libFLAC/ia32/lpc_asm.obj b/flac/src/libFLAC/ia32/lpc_asm.obj index 3eee1bf..f599400 100644 Binary files a/flac/src/libFLAC/ia32/lpc_asm.obj and b/flac/src/libFLAC/ia32/lpc_asm.obj differ diff --git a/flac/src/libFLAC/ia32/stream_encoder_asm.obj b/flac/src/libFLAC/ia32/stream_encoder_asm.obj index 4797683..3baf650 100644 Binary files a/flac/src/libFLAC/ia32/stream_encoder_asm.obj and b/flac/src/libFLAC/ia32/stream_encoder_asm.obj differ diff --git a/flac/src/libFLAC/ia64/lpc_asm.nasm b/flac/src/libFLAC/ia64/lpc_asm.nasm new file mode 100644 index 0000000..250be21 --- /dev/null +++ b/flac/src/libFLAC/ia64/lpc_asm.nasm @@ -0,0 +1,271 @@ +; vim:filetype=nasm ts=8 + +; libFLAC - Free Lossless Audio Codec library +; Copyright (C) 2001,2002,2003,2004,2005,2006,2007,2008 Josh Coalson +; +; 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. +; +; - Neither the name of the Xiph.org Foundation nor the names of its +; contributors may be used to endorse or promote products derived from +; this software without specific prior written permission. +; +; 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 FOUNDATION 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. + +;/* +; * MMX optimized FLAC DSP utils +; * Copyright (c) 2007 Loren Merritt +; * +; * This file is part of FFmpeg. +; * +; * FFmpeg is free software; you can redistribute it and/or +; * modify it under the terms of the GNU Lesser General Public +; * License as published by the Free Software Foundation; either +; * version 2.1 of the License, or (at your option) any later version. +; * +; * FFmpeg is distributed in the hope that it will be useful, +; * but WITHOUT ANY WARRANTY; without even the implied warranty of +; * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; * Lesser General Public License for more details. +; * +; * You should have received a copy of the GNU Lesser General Public +; * License along with FFmpeg; if not, write to the Free Software +; * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +; */ + +%include "nasm.h" + + data_section + +;cglobal FLAC__lpc_compute_autocorrelation_asm_ia64 +cglobal FLAC__lpc_compute_autocorrelation_asm_ia64_sse_lag_4 +cglobal FLAC__lpc_compute_autocorrelation_asm_ia64_sse_lag_8 +cglobal FLAC__lpc_compute_autocorrelation_asm_ia64_sse_lag_12 + + code_section + +; ********************************************************************** +; +; void FLAC__lpc_compute_autocorrelation_asm(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]) +; { +; FLAC__real d; +; unsigned sample, coeff; +; const unsigned limit = data_len - lag; +; +; FLAC__ASSERT(lag > 0); +; FLAC__ASSERT(lag <= data_len); +; +; for(coeff = 0; coeff < lag; coeff++) +; autoc[coeff] = 0.0; +; for(sample = 0; sample <= limit; sample++) { +; d = data[sample]; +; for(coeff = 0; coeff < lag; coeff++) +; autoc[coeff] += d * data[sample+coeff]; +; } +; for(; sample < data_len; sample++) { +; d = data[sample]; +; for(coeff = 0; coeff < data_len - sample; coeff++) +; autoc[coeff] += d * data[sample+coeff]; +; } +; } +; + + ALIGN 16 +cident FLAC__lpc_compute_autocorrelation_asm_ia64_sse_lag_4 + ; r9d == autoc[] + ; r8d == lag + ; rdx == data_len + ; rcx == data[] + + ;ASSERT(lag > 0) + ;ASSERT(lag <= 4) + ;ASSERT(lag <= data_len) + + ; for(coeff = 0; coeff < lag; coeff++) + ; autoc[coeff] = 0.0; + xorps xmm5, xmm5 + + movss xmm0, [rcx] ; xmm0 = 0,0,0,data[0] + add rcx, 4 + movaps xmm2, xmm0 ; xmm2 = 0,0,0,data[0] + shufps xmm0, xmm0, 0 ; xmm0 == data[sample],data[sample],data[sample],data[sample] = data[0],data[0],data[0],data[0] +.warmup: ; xmm2 == data[sample-3],data[sample-2],data[sample-1],data[sample] + mulps xmm0, xmm2 ; xmm0 = xmm0 * xmm2 + addps xmm5, xmm0 ; xmm5 += xmm0 * xmm2 + dec rdx + jz .loop_end + ALIGN 16 +.loop_start: + ; start by reading the next sample + movss xmm0, [rcx] ; xmm0 = 0,0,0,data[sample] + add rcx, 4 + shufps xmm0, xmm0, 0 ; xmm0 = data[sample],data[sample],data[sample],data[sample] + shufps xmm2, xmm2, 93h ; 93h=2-1-0-3 => xmm2 gets rotated left by one float + movss xmm2, xmm0 + mulps xmm0, xmm2 ; xmm0 = xmm0 * xmm2 + addps xmm5, xmm0 ; xmm5 += xmm0 * xmm2 + dec rdx + jnz .loop_start +.loop_end: + ; store autoc + movups [r9d], xmm5 + +.end: + emms + ret + + ALIGN 16 +cident FLAC__lpc_compute_autocorrelation_asm_ia64_sse_lag_8 + ; r9d == autoc[] + ; r8d == lag + ; rdx == data_len + ; rcx == data[] + + ;ASSERT(lag > 0) + ;ASSERT(lag <= 8) + ;ASSERT(lag <= data_len) + + ; for(coeff = 0; coeff < lag; coeff++) + ; autoc[coeff] = 0.0; + xorps xmm4, xmm4 + xorps xmm5, xmm5 + + movss xmm0, [rcx] ; xmm0 = 0,0,0,data[0] + add rcx, 4 + movaps xmm2, xmm0 ; xmm2 = 0,0,0,data[0] + shufps xmm0, xmm0, 0 ; xmm0 == data[sample],data[sample],data[sample],data[sample] = data[0],data[0],data[0],data[0] + movaps xmm1, xmm0 ; xmm1 == data[sample],data[sample],data[sample],data[sample] = data[0],data[0],data[0],data[0] + xorps xmm3, xmm3 ; xmm3 = 0,0,0,0 +.warmup: ; xmm3:xmm2 == data[sample-7],data[sample-6],...,data[sample] + mulps xmm0, xmm2 + mulps xmm1, xmm3 ; xmm1:xmm0 = xmm1:xmm0 * xmm3:xmm2 + addps xmm4, xmm0 + addps xmm5, xmm1 ; xmm5:xmm4 += xmm1:xmm0 * xmm3:xmm2 + dec rdx + jz .loop_end + ALIGN 16 +.loop_start: + ; start by reading the next sample + movss xmm0, [rcx] ; xmm0 = 0,0,0,data[sample] + ; here we reorder the instructions; see the (#) indexes for a logical order + shufps xmm2, xmm2, 93h ; (3) 93h=2-1-0-3 => xmm2 gets rotated left by one float + add rcx, 4 ; (0) + shufps xmm3, xmm3, 93h ; (4) 93h=2-1-0-3 => xmm3 gets rotated left by one float + shufps xmm0, xmm0, 0 ; (1) xmm0 = data[sample],data[sample],data[sample],data[sample] + movss xmm3, xmm2 ; (5) + movaps xmm1, xmm0 ; (2) xmm1 = data[sample],data[sample],data[sample],data[sample] + movss xmm2, xmm0 ; (6) + mulps xmm1, xmm3 ; (8) + mulps xmm0, xmm2 ; (7) xmm1:xmm0 = xmm1:xmm0 * xmm3:xmm2 + addps xmm5, xmm1 ; (10) + addps xmm4, xmm0 ; (9) xmm5:xmm4 += xmm1:xmm0 * xmm3:xmm2 + dec rdx + jnz .loop_start +.loop_end: + ; store autoc + movups [r9d], xmm4 + movups [r9d + 16], xmm5 + +.end: + emms + ret + + + ALIGN 16 +cident FLAC__lpc_compute_autocorrelation_asm_ia64_sse_lag_12 + ; r9d == autoc[] + ; r8d == lag + ; rdx == data_len + ; rcx == data[] + + ;ASSERT(lag > 0) + ;ASSERT(lag <= 12) + ;ASSERT(lag <= data_len) + + movups [r9d], xmm6 ; save xmm6, which might be used by the caller + movups [r9d + 16], xmm7 ; save xmm7, which might be used by the caller + + ; for(coeff = 0; coeff < lag; coeff++) + ; autoc[coeff] = 0.0; + xorps xmm5, xmm5 + xorps xmm6, xmm6 + xorps xmm7, xmm7 + + movss xmm0, [rcx] ; xmm0 = 0,0,0,data[0] + add rcx, 4 + movaps xmm2, xmm0 ; xmm2 = 0,0,0,data[0] + shufps xmm0, xmm0, 0 ; xmm0 == data[sample],data[sample],data[sample],data[sample] = data[0],data[0],data[0],data[0] + xorps xmm3, xmm3 ; xmm3 = 0,0,0,0 + xorps xmm4, xmm4 ; xmm4 = 0,0,0,0 +.warmup: ; xmm3:xmm2 == data[sample-7],data[sample-6],...,data[sample] + movaps xmm1, xmm0 + mulps xmm1, xmm2 + addps xmm5, xmm1 + movaps xmm1, xmm0 + mulps xmm1, xmm3 + addps xmm6, xmm1 + mulps xmm0, xmm4 + addps xmm7, xmm0 ; xmm7:xmm6:xmm5 += xmm0:xmm0:xmm0 * xmm4:xmm3:xmm2 + dec rdx + jz .loop_end + ALIGN 16 +.loop_start: + ; start by reading the next sample + movss xmm0, [rcx] ; xmm0 = 0,0,0,data[sample] + add rcx, 4 + shufps xmm0, xmm0, 0 ; xmm0 = data[sample],data[sample],data[sample],data[sample] + + ; shift xmm4:xmm3:xmm2 left by one float + shufps xmm2, xmm2, 93h ; 93h=2-1-0-3 => xmm2 gets rotated left by one float + shufps xmm3, xmm3, 93h ; 93h=2-1-0-3 => xmm3 gets rotated left by one float + shufps xmm4, xmm4, 93h ; 93h=2-1-0-3 => xmm4 gets rotated left by one float + movss xmm4, xmm3 + movss xmm3, xmm2 + movss xmm2, xmm0 + + ; xmm7:xmm6:xmm5 += xmm0:xmm0:xmm0 * xmm3:xmm3:xmm2 + movaps xmm1, xmm0 + mulps xmm1, xmm2 + addps xmm5, xmm1 + movaps xmm1, xmm0 + mulps xmm1, xmm3 + addps xmm6, xmm1 + mulps xmm0, xmm4 + addps xmm7, xmm0 + + dec rdx + jnz .loop_start +.loop_end: + ; store autoc + movups [r9d + 32], xmm7 + movups xmm7, [r9d + 16] ; restore xmm7 + movups [r9d + 16], xmm6 + movups xmm6, [r9d] ; restore xmm6 + movups [r9d], xmm5 + +.end: + emms + ret + + +%ifdef OBJ_FORMAT_elf + section .note.GNU-stack noalloc +%endif diff --git a/flac/src/libFLAC/ia64/lpc_asm.obj b/flac/src/libFLAC/ia64/lpc_asm.obj new file mode 100644 index 0000000..02f43eb Binary files /dev/null and b/flac/src/libFLAC/ia64/lpc_asm.obj differ diff --git a/flac/src/libFLAC/ia64/nasm.h b/flac/src/libFLAC/ia64/nasm.h new file mode 100644 index 0000000..339ee68 --- /dev/null +++ b/flac/src/libFLAC/ia64/nasm.h @@ -0,0 +1,81 @@ +; libFLAC - Free Lossless Audio Codec library +; Copyright (C) 2001,2002,2003,2004,2005,2006,2007,2008 Josh Coalson +; +; 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. +; +; - Neither the name of the Xiph.org Foundation nor the names of its +; contributors may be used to endorse or promote products derived from +; this software without specific prior written permission. +; +; 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 FOUNDATION 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. + + bits 64 + CPU X64 + +%ifdef OBJ_FORMAT_win32 + %define FLAC__PUBLIC_NEEDS_UNDERSCORE + %idefine code_section section .text align=16 class=CODE use32 + %idefine data_section section .data align=32 class=DATA use32 + %idefine bss_section section .bss align=32 class=DATA use32 +%elifdef OBJ_FORMAT_win64 +; %define FLAC__PUBLIC_NEEDS_UNDERSCORE + %idefine code_section section .text align=16 class=CODE use32 + %idefine data_section section .data align=32 class=DATA use32 + %idefine bss_section section .bss align=32 class=DATA use32 +%elifdef OBJ_FORMAT_aout + %define FLAC__PUBLIC_NEEDS_UNDERSCORE + %idefine code_section section .text + %idefine data_section section .data + %idefine bss_section section .bss +%elifdef OBJ_FORMAT_aoutb + %define FLAC__PUBLIC_NEEDS_UNDERSCORE + %idefine code_section section .text + %idefine data_section section .data + %idefine bss_section section .bss +%elifdef OBJ_FORMAT_elf + %idefine code_section section .text align=16 + %idefine data_section section .data align=32 + %idefine bss_section section .bss align=32 +%else + %error unsupported object format! +%endif + +%imacro cglobal 1 + %ifdef FLAC__PUBLIC_NEEDS_UNDERSCORE + global _%1 + %else + global %1 + %endif +%endmacro + +%imacro cextern 1 + %ifdef FLAC__PUBLIC_NEEDS_UNDERSCORE + extern _%1 + %else + extern %1 + %endif +%endmacro + +%imacro cident 1 +_%1: +%1: +%endmacro