mirror of
https://github.com/claunia/cuetools.net.git
synced 2025-12-16 18:14:25 +00:00
More work on CUERipper
This commit is contained in:
@@ -29,7 +29,7 @@ using System.Diagnostics;
|
||||
|
||||
namespace Bwg.Scsi
|
||||
{
|
||||
class Command : IDisposable
|
||||
public class Command : IDisposable
|
||||
{
|
||||
[DllImport("ntdll.dll")]
|
||||
internal static extern void RtlZeroMemory(IntPtr dest, int size);
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
namespace Bwg.Scsi
|
||||
{
|
||||
enum ScsiCommandCode
|
||||
public enum ScsiCommandCode
|
||||
{
|
||||
TestUnitReady = 0x00,
|
||||
RequestSense = 0x03,
|
||||
|
||||
@@ -939,7 +939,7 @@ namespace Bwg.Scsi
|
||||
}
|
||||
#endregion
|
||||
|
||||
private CommandStatus SendCommand(Command cmd)
|
||||
public CommandStatus SendCommand(Command cmd)
|
||||
{
|
||||
return (m_ossize == 32) ? SendCommand32(cmd) : SendCommand64(cmd);
|
||||
}
|
||||
@@ -1971,7 +1971,7 @@ namespace Bwg.Scsi
|
||||
/// <param name="data">The buffer to receive the data</param>
|
||||
/// <param name="size">The size of the buffer given by the data parameter</param>
|
||||
/// <returns></returns>
|
||||
public CommandStatus Read(bool force, bool streaming, uint lba, uint length, IntPtr data, ushort size)
|
||||
public CommandStatus Read(bool force, bool streaming, uint lba, uint length, IntPtr data, int size)
|
||||
{
|
||||
if (m_logger != null)
|
||||
{
|
||||
@@ -2134,15 +2134,16 @@ namespace Bwg.Scsi
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="mode">subchannel mode</param>
|
||||
/// <param name="exp"></param>
|
||||
/// <param name="mode">subchannel mode (+16 bytes if equals 2)</param>
|
||||
/// <param name="c2">report C2 errors (+296 bytes if true)</param>
|
||||
/// <param name="exp">expected sector type</param>
|
||||
/// <param name="dap"></param>
|
||||
/// <param name="start"></param>
|
||||
/// <param name="length"></param>
|
||||
/// <param name="data">the memory area </param>
|
||||
/// <param name="size">the size of the memory area given by the data parameter</param>
|
||||
/// <returns></returns>
|
||||
public CommandStatus ReadCDAndSubChannel(byte mode, byte exp, bool dap, uint start, uint length, IntPtr data, int size)
|
||||
public CommandStatus ReadCDAndSubChannel(byte mode, bool c2, byte exp, bool dap, uint start, uint length, IntPtr data, int size)
|
||||
{
|
||||
if (m_logger != null)
|
||||
{
|
||||
@@ -2161,10 +2162,13 @@ namespace Bwg.Scsi
|
||||
byte b = (byte)((exp & 0x07) << 2);
|
||||
if (dap)
|
||||
b |= 0x02;
|
||||
byte byte9 = 0x10;
|
||||
if (c2)
|
||||
byte9 |= 0x02;
|
||||
cmd.SetCDB8(1, b);
|
||||
cmd.SetCDB32(2, start);
|
||||
cmd.SetCDB24(6, length);
|
||||
cmd.SetCDB8(9, 0x10); // User data only
|
||||
cmd.SetCDB8(9, byte9); // User data + possibly c2 errors
|
||||
cmd.SetCDB8(10, mode); // Subchannel
|
||||
|
||||
CommandStatus st = SendCommand(cmd);
|
||||
|
||||
@@ -52,12 +52,13 @@ namespace CUETools.CDImage
|
||||
|
||||
public class CDTrack : ICloneable
|
||||
{
|
||||
public CDTrack(uint number, uint start, uint length, bool isAudio)
|
||||
public CDTrack(uint number, uint start, uint length, bool isAudio, bool preEmpasis)
|
||||
{
|
||||
_number = number;
|
||||
_start = start;
|
||||
_length = length;
|
||||
_isAudio = isAudio;
|
||||
_preEmphasis = preEmpasis;
|
||||
_indexes = new List<CDTrackIndex>();
|
||||
_indexes.Add(new CDTrackIndex(0, start));
|
||||
_indexes.Add(new CDTrackIndex(1, start));
|
||||
@@ -69,6 +70,7 @@ namespace CUETools.CDImage
|
||||
_start = src._start;
|
||||
_length = src._length;
|
||||
_isAudio = src._isAudio;
|
||||
_preEmphasis = src._preEmphasis;
|
||||
_indexes = new List<CDTrackIndex>();
|
||||
for (int i = 0; i < src._indexes.Count; i++)
|
||||
_indexes.Add(new CDTrackIndex(src._indexes[i]));
|
||||
@@ -187,6 +189,18 @@ namespace CUETools.CDImage
|
||||
}
|
||||
}
|
||||
|
||||
public bool PreEmphasis
|
||||
{
|
||||
get
|
||||
{
|
||||
return _preEmphasis;
|
||||
}
|
||||
set
|
||||
{
|
||||
_preEmphasis = value;
|
||||
}
|
||||
}
|
||||
|
||||
public void AddIndex(CDTrackIndex index)
|
||||
{
|
||||
if (index.Index < 2)
|
||||
@@ -198,6 +212,7 @@ namespace CUETools.CDImage
|
||||
IList<CDTrackIndex> _indexes;
|
||||
string _isrc;
|
||||
bool _isAudio;
|
||||
bool _preEmphasis;
|
||||
uint _start;
|
||||
uint _length;
|
||||
uint _number;
|
||||
|
||||
@@ -27,13 +27,60 @@ using CUETools.Ripper.SCSI;
|
||||
using CUETools.Codecs;
|
||||
using CUETools.CDImage;
|
||||
using CUETools.AccurateRip;
|
||||
using FLACDotNet;
|
||||
//using FLACDotNet;
|
||||
using MusicBrainz;
|
||||
|
||||
namespace CUERipper
|
||||
{
|
||||
class ProgressMeter
|
||||
{
|
||||
public DateTime realStart;
|
||||
|
||||
public ProgressMeter()
|
||||
{
|
||||
realStart = DateTime.Now;
|
||||
//TimeSpan lastPrint = TimeSpan.FromMilliseconds(0);
|
||||
}
|
||||
|
||||
public void ReadProgress(object sender, ReadProgressArgs e)
|
||||
{
|
||||
CDDriveReader audioSource = (CDDriveReader)sender;
|
||||
int processed = e.Position - e.PassStart;
|
||||
TimeSpan elapsed = DateTime.Now - e.PassTime;
|
||||
double speed = elapsed.TotalSeconds > 0 ? processed / elapsed.TotalSeconds / 75 : 1.0;
|
||||
TimeSpan totalElapsed = DateTime.Now - realStart;
|
||||
TimeSpan totalEstimated = TimeSpan.FromMilliseconds(totalElapsed.TotalMilliseconds / Math.Max(1, (e.PassStart + (processed + e.Pass * (e.PassEnd - e.PassStart)) / 16)) * audioSource.TOC.AudioLength);
|
||||
|
||||
// if ((elapsed - lastPrint).TotalMilliseconds > 60) ;
|
||||
Console.Write("\r{9} : {0:00}%; {1:00.00}x; {2} ({10:0.00}%) errors; {3:d2}:{4:d2}:{5:d2}/{6:d2}:{7:d2}:{8:d2} ",
|
||||
100.0 * e.Position / audioSource.TOC.AudioLength,
|
||||
speed,
|
||||
e.ErrorsCount,
|
||||
totalElapsed.Hours, totalElapsed.Minutes, totalElapsed.Seconds,
|
||||
totalEstimated.Hours, totalEstimated.Minutes, totalEstimated.Seconds,
|
||||
e.Pass < 1 ? "Progress " : string.Format("Retry {0:00} ", e.Pass),
|
||||
processed > 0 ? 100.0 * e.ErrorsCount / processed / (4 * 588) : 0
|
||||
);
|
||||
//lastPrint = elapsed;
|
||||
}
|
||||
}
|
||||
|
||||
class Program
|
||||
{
|
||||
static void Usage()
|
||||
{
|
||||
string drives = "";
|
||||
char[] drivesAvailable = CDDriveReader.DrivesAvailable();
|
||||
for (int i = 0; i < drivesAvailable.Length; i++)
|
||||
drives += string.Format("{0}: ", drivesAvailable[i]);
|
||||
Console.WriteLine("Usage : CUERipper.exe <options>");
|
||||
Console.WriteLine();
|
||||
//Console.WriteLine("-S, --secure secure mode, read each block twice;");
|
||||
Console.WriteLine("-P, --paranoid maximum level of error correction;");
|
||||
Console.WriteLine("-D, --drive <letter> use a specific CD drive, e.g. {0};", drives);
|
||||
Console.WriteLine("-O, --offset <samples> use specific drive read offset;");
|
||||
}
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
string programVersion = "CUERipper v1.9.3 Copyright (C) 2008 Gregory S. Chudov";
|
||||
@@ -42,25 +89,65 @@ namespace CUERipper
|
||||
Console.WriteLine("This is free software under the GNU GPLv3+ license; There is NO WARRANTY, to");
|
||||
Console.WriteLine("the extent permitted by law. <http://www.gnu.org/licenses/> for details.");
|
||||
|
||||
char[] drives = CDDriveReader.DrivesAvailable();
|
||||
if (drives.Length < 1)
|
||||
int correctionQuality = 1;
|
||||
string driveLetter = null;
|
||||
int driveOffset = 0;
|
||||
for (int arg = 0; arg < args.Length; arg++)
|
||||
{
|
||||
Console.WriteLine("No CD drives found.");
|
||||
return;
|
||||
bool ok = true;
|
||||
if (args[arg] == "-P" || args[arg] == "--paranoid")
|
||||
correctionQuality = 4;
|
||||
//else if (args[arg] == "-B" || args[arg] == "--burst")
|
||||
// correctionQuality = 1;
|
||||
else if ((args[arg] == "-D" || args[arg] == "--drive") && ++arg < args.Length)
|
||||
driveLetter = args[arg];
|
||||
else if ((args[arg] == "-O" || args[arg] == "--offset") && ++arg < args.Length)
|
||||
ok = int.TryParse(args[arg], out driveOffset);
|
||||
else
|
||||
ok = false;
|
||||
if (!ok)
|
||||
{
|
||||
Usage();
|
||||
return;
|
||||
}
|
||||
}
|
||||
char driveLetter = drives[0];
|
||||
|
||||
char[] drives;
|
||||
if (driveLetter == null || driveLetter.Length < 1)
|
||||
{
|
||||
drives = CDDriveReader.DrivesAvailable();
|
||||
if (drives.Length < 1)
|
||||
{
|
||||
Console.WriteLine("No CD drives found.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
drives = new char[1];
|
||||
drives[0] = driveLetter[0];
|
||||
}
|
||||
|
||||
#if !DEBUG
|
||||
try
|
||||
#endif
|
||||
{
|
||||
CDDriveReader audioSource = new CDDriveReader();
|
||||
audioSource.Open(driveLetter);
|
||||
int driveOffset;
|
||||
if (!AccurateRipVerify.FindDriveReadOffset(audioSource.ARName, out driveOffset))
|
||||
throw new Exception("Failed to find drive read offset for drive" + audioSource.ARName);
|
||||
audioSource.Open(drives[0]);
|
||||
|
||||
if (audioSource.TOC.AudioTracks < 1)
|
||||
{
|
||||
Console.WriteLine("{0}: CD does not contain any audio tracks.", audioSource.Path);
|
||||
audioSource.Close();
|
||||
return;
|
||||
}
|
||||
if (driveOffset == 0)
|
||||
if (!AccurateRipVerify.FindDriveReadOffset(audioSource.ARName, out driveOffset))
|
||||
Console.WriteLine("Unknown read offset for drive {0}!!!", audioSource.Path);
|
||||
//throw new Exception("Failed to find drive read offset for drive" + audioSource.ARName);
|
||||
audioSource.DriveOffset = driveOffset;
|
||||
audioSource.CorrectionQuality = correctionQuality;
|
||||
|
||||
//bool toStdout = false;
|
||||
AccurateRipVerify arVerify = new AccurateRipVerify(audioSource.TOC);
|
||||
int[,] buff = new int[audioSource.BestBlockSize, audioSource.ChannelCount];
|
||||
string CDDBId = AccurateRipVerify.CalculateCDDBId(audioSource.TOC);
|
||||
@@ -81,7 +168,8 @@ namespace CUERipper
|
||||
release = null;
|
||||
}
|
||||
|
||||
string destFile = (release == null) ? "cdimage.flac" : release.GetArtist() + " - " + release.GetTitle() + ".flac";
|
||||
//string destFile = (release == null) ? "cdimage.flac" : release.GetArtist() + " - " + release.GetTitle() + ".flac";
|
||||
string destFile = (release == null) ? "cdimage.wav" : release.GetArtist() + " - " + release.GetTitle() + ".wav";
|
||||
|
||||
Console.WriteLine("Drive : {0}", audioSource.Path);
|
||||
Console.WriteLine("Read offset : {0}", audioSource.DriveOffset);
|
||||
@@ -90,48 +178,53 @@ namespace CUERipper
|
||||
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 FLACWriter(destFile, audioSource.BitsPerSample, audioSource.ChannelCount, audioSource.SampleRate);
|
||||
IAudioDest audioDest = new WAVWriter(destFile, audioSource.BitsPerSample, audioSource.ChannelCount, audioSource.SampleRate, null);
|
||||
audioDest.FinalSampleCount = (long)audioSource.Length;
|
||||
|
||||
|
||||
DateTime start = DateTime.Now;
|
||||
TimeSpan lastPrint = TimeSpan.FromMilliseconds(0);
|
||||
ProgressMeter meter = new ProgressMeter();
|
||||
audioSource.ReadProgress += new EventHandler<ReadProgressArgs>(meter.ReadProgress);
|
||||
|
||||
do
|
||||
{
|
||||
uint samplesRead = audioSource.Read(buff, Math.Min((uint)buff.GetLength(0), (uint)audioSource.Remaining));
|
||||
uint toRead = Math.Min((uint)buff.GetLength(0), (uint)audioSource.Remaining);
|
||||
uint samplesRead = audioSource.Read(buff, toRead);
|
||||
if (samplesRead == 0) break;
|
||||
if (samplesRead != toRead)
|
||||
throw new Exception("samples read != samples requested");
|
||||
arVerify.Write(buff, samplesRead);
|
||||
audioDest.Write(buff, samplesRead);
|
||||
TimeSpan elapsed = DateTime.Now - start;
|
||||
if ((elapsed - lastPrint).TotalMilliseconds > 60)
|
||||
{
|
||||
Console.Write("\rProgress : {0:00}%; {1:0.00}x; {2}/{3}",
|
||||
100.0 * audioSource.Position / audioSource.Length,
|
||||
audioSource.Position / elapsed.TotalSeconds / audioSource.SampleRate,
|
||||
elapsed,
|
||||
TimeSpan.FromMilliseconds(elapsed.TotalMilliseconds / audioSource.Position * audioSource.Length)
|
||||
);
|
||||
lastPrint = elapsed;
|
||||
}
|
||||
} while (true);
|
||||
|
||||
TimeSpan totalElapsed = DateTime.Now - start;
|
||||
Console.Write("\r \r");
|
||||
Console.WriteLine("Results : {0:0.00}x; {1}",
|
||||
TimeSpan totalElapsed = DateTime.Now - meter.realStart;
|
||||
Console.Write("\r \r");
|
||||
Console.WriteLine("Results : {0:0.00}x; {1:d5} errors; {2:d2}:{3:d2}:{4:d2}",
|
||||
audioSource.Length / totalElapsed.TotalSeconds / audioSource.SampleRate,
|
||||
totalElapsed
|
||||
audioSource.ErrorsCount,
|
||||
totalElapsed.Hours, totalElapsed.Minutes, totalElapsed.Seconds
|
||||
);
|
||||
audioDest.Close();
|
||||
|
||||
StringWriter logWriter = new StringWriter();
|
||||
logWriter.WriteLine("{0}", programVersion);
|
||||
logWriter.WriteLine();
|
||||
logWriter.WriteLine("Extraction logfile from {0}", DateTime.Now);
|
||||
logWriter.WriteLine();
|
||||
logWriter.WriteLine("Used drive : {0}", audioSource.Path);
|
||||
logWriter.WriteLine();
|
||||
logWriter.WriteLine("Read offset correction : {0}", audioSource.DriveOffset);
|
||||
bool wereErrors = false;
|
||||
for (int iTrack = 1; iTrack <= audioSource.TOC.AudioTracks; iTrack++)
|
||||
for (uint iSector = audioSource.TOC[iTrack].Start; iSector <= audioSource.TOC[iTrack].End; iSector ++)
|
||||
if (audioSource.Errors[(int)iSector])
|
||||
{
|
||||
if (!wereErrors)
|
||||
{
|
||||
logWriter.WriteLine();
|
||||
logWriter.WriteLine("Errors detected");
|
||||
logWriter.WriteLine();
|
||||
}
|
||||
wereErrors = true;
|
||||
logWriter.WriteLine("Track {0} contains errors", iTrack);
|
||||
break;
|
||||
}
|
||||
logWriter.WriteLine();
|
||||
logWriter.WriteLine("TOC of the extracted CD");
|
||||
logWriter.WriteLine();
|
||||
@@ -180,6 +273,8 @@ namespace CUERipper
|
||||
}
|
||||
if (audioSource.TOC[track].ISRC != null)
|
||||
cueWriter.WriteLine(" ISRC {0}", audioSource.TOC[track].ISRC);
|
||||
if (audioSource.TOC[track].PreEmphasis)
|
||||
cueWriter.WriteLine(" FLAGS PRE");
|
||||
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);
|
||||
}
|
||||
@@ -190,10 +285,10 @@ namespace CUERipper
|
||||
|
||||
audioSource.Close();
|
||||
|
||||
FLACReader tagger = new FLACReader(destFile, null);
|
||||
tagger.Tags.Add("CUESHEET", cueWriter.ToString());
|
||||
tagger.Tags.Add("LOG", logWriter.ToString());
|
||||
tagger.UpdateTags(false);
|
||||
//FLACReader tagger = new FLACReader(destFile, null);
|
||||
//tagger.Tags.Add("CUESHEET", cueWriter.ToString());
|
||||
//tagger.Tags.Add("LOG", logWriter.ToString());
|
||||
//tagger.UpdateTags(false);
|
||||
}
|
||||
#if !DEBUG
|
||||
catch (Exception ex)
|
||||
@@ -204,5 +299,17 @@ namespace CUERipper
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//private void MusicBrainz_LookupProgress(object sender, XmlRequestEventArgs e)
|
||||
//{
|
||||
// if (this.CUEToolsProgress == null)
|
||||
// return;
|
||||
// _progress.percentDisk = (1.0 + _progress.percentDisk) / 2;
|
||||
// _progress.percentTrack = 0;
|
||||
// _progress.input = e.Uri.ToString();
|
||||
// _progress.output = null;
|
||||
// _progress.status = "Looking up album via MusicBrainz";
|
||||
// this.CUEToolsProgress(this, _progress);
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,6 +81,10 @@
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="CRC16CCITT.cs" />
|
||||
<Compile Include="Galois.cs" />
|
||||
<Compile Include="RsDecode.cs" />
|
||||
<Compile Include="RsEncode.cs" />
|
||||
<Compile Include="SCSIDrive.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Text;
|
||||
@@ -40,16 +41,29 @@ namespace CUETools.Ripper.SCSI
|
||||
byte[] cdtext = null;
|
||||
private Device m_device;
|
||||
int _sampleOffset = 0;
|
||||
uint _samplesInBuffer = 0;
|
||||
uint _samplesBufferOffset = 0;
|
||||
uint _samplesBufferSector = 0;
|
||||
int _driveOffset = 0;
|
||||
const int CB_AUDIO = 588 * 4 + 16;
|
||||
const int NSECTORS = 32;
|
||||
int _correctionQuality = 1;
|
||||
int _currentStart = -1, _currentEnd = -1, _currentErrorsCount = 0;
|
||||
const bool DoC2 = true;
|
||||
const int CB_AUDIO = 588 * 4 + 16 + (DoC2 ? 294 : 0);
|
||||
//const int REDUNDANCY = 8;
|
||||
const int NSECTORS = 64; //255 - REDUNDANCY;
|
||||
const int MSECTORS = 10000000 / CB_AUDIO;
|
||||
int _currentTrack = -1, _currentIndex = -1, _currentTrackActualStart = -1;
|
||||
Logger m_logger;
|
||||
CDImageLayout _toc;
|
||||
DeviceInfo m_info;
|
||||
Crc16Ccitt _crc;
|
||||
//RsEncode _rsEncoder;
|
||||
//RsDecode _rsDecoder;
|
||||
List<ScanResults> _scanResults;
|
||||
ScanResults _currentScan;
|
||||
BitArray _errors;
|
||||
int _errorsCount;
|
||||
byte[] _currentData = new byte[MSECTORS * 4 * 588];
|
||||
int[] valueScore = new int[256];
|
||||
|
||||
public event EventHandler<ReadProgressArgs> ReadProgress;
|
||||
|
||||
public CDImageLayout TOC
|
||||
{
|
||||
@@ -59,9 +73,28 @@ namespace CUETools.Ripper.SCSI
|
||||
}
|
||||
}
|
||||
|
||||
public BitArray Errors
|
||||
{
|
||||
get
|
||||
{
|
||||
return _errors;
|
||||
}
|
||||
}
|
||||
|
||||
public int ErrorsCount
|
||||
{
|
||||
get
|
||||
{
|
||||
return _errorsCount;
|
||||
}
|
||||
}
|
||||
|
||||
public CDDriveReader()
|
||||
{
|
||||
m_logger = new Logger();
|
||||
_crc = new Crc16Ccitt(InitialCrcValue.Zeros);
|
||||
//_rsEncoder = new RsEncode(REDUNDANCY);
|
||||
//_rsDecoder = new RsDecode(REDUNDANCY);
|
||||
}
|
||||
|
||||
public bool Open(char Drive)
|
||||
@@ -97,19 +130,28 @@ namespace CUETools.Ripper.SCSI
|
||||
//ParseProfileList(f.Data);
|
||||
// }
|
||||
|
||||
SpeedDescriptorList speed_list;
|
||||
st = m_device.GetSpeed(out speed_list);
|
||||
if (st != Device.CommandStatus.Success)
|
||||
throw new Exception("GetSpeed failed: SCSI error");
|
||||
//SpeedDescriptorList speed_list;
|
||||
//st = m_device.GetSpeed(out speed_list);
|
||||
//if (st != Device.CommandStatus.Success)
|
||||
// throw new Exception("GetSpeed failed: SCSI error");
|
||||
|
||||
st = m_device.SetCdSpeed(Device.RotationalControl.CLVandNonPureCav, 32767/*Device.OptimumSpeed*/, Device.OptimumSpeed);
|
||||
if (st != Device.CommandStatus.Success)
|
||||
throw new Exception("SetCdSpeed failed: SCSI error");
|
||||
//int bytesPerSec = 4 * 588 * 75 * (pass > 8 ? 4 : pass > 4 ? 8 : pass > 0 ? 16 : 32);
|
||||
//Device.CommandStatus st = m_device.SetStreaming(Device.RotationalControl.CLVandNonPureCav, start, end, bytesPerSec, 1, bytesPerSec, 1);
|
||||
//if (st != Device.CommandStatus.Success)
|
||||
// System.Console.WriteLine("SetStreaming: ", (st == Device.CommandStatus.DeviceFailed ? Device.LookupSenseError(m_device.GetSenseAsc(), m_device.GetSenseAscq()) : st.ToString()));
|
||||
//st = m_device.SetCdSpeed(Device.RotationalControl.CLVandNonPureCav, (ushort)(bytesPerSec / 1024), (ushort)(bytesPerSec / 1024));
|
||||
//if (st != Device.CommandStatus.Success)
|
||||
// System.Console.WriteLine("SetCdSpeed: ", (st == Device.CommandStatus.DeviceFailed ? Device.LookupSenseError(m_device.GetSenseAsc(), m_device.GetSenseAscq()) : st.ToString()));
|
||||
|
||||
|
||||
//st = m_device.SetCdSpeed(Device.RotationalControl.CLVandNonPureCav, 32767/*Device.OptimumSpeed*/, Device.OptimumSpeed);
|
||||
//if (st != Device.CommandStatus.Success)
|
||||
// throw new Exception("SetCdSpeed failed: SCSI error");
|
||||
|
||||
IList<TocEntry> toc;
|
||||
st = m_device.ReadToc((byte)0, false, out toc);
|
||||
if (st != Device.CommandStatus.Success)
|
||||
throw new Exception("ReadToc failed: SCSI error");
|
||||
throw new Exception("ReadTOC: " + (st == Device.CommandStatus.DeviceFailed ? Device.LookupSenseError(m_device.GetSenseAsc(), m_device.GetSenseAscq()) : st.ToString()));
|
||||
|
||||
st = m_device.ReadCDText(out cdtext);
|
||||
// new CDTextEncoderDecoder
|
||||
@@ -119,10 +161,13 @@ namespace CUETools.Ripper.SCSI
|
||||
_toc.AddTrack(new CDTrack((uint)iTrack + 1,
|
||||
toc[iTrack].StartSector,
|
||||
toc[iTrack + 1].StartSector - toc[iTrack].StartSector -
|
||||
((toc[iTrack + 1].Control == 0 || iTrack + 1 == toc.Count - 1) ? 0U : 152U * 75U),
|
||||
toc[iTrack].Control == 0));
|
||||
((toc[iTrack + 1].Control < 4 || iTrack + 1 == toc.Count - 1) ? 0U : 152U * 75U),
|
||||
toc[iTrack].Control < 4,
|
||||
(toc[iTrack].Control & 1) == 1));
|
||||
if (_toc[1].IsAudio)
|
||||
_toc[1][0].Start = 0;
|
||||
if (_toc.AudioLength > 0)
|
||||
_errors = new BitArray((int)_toc.AudioLength); // !!!
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -137,32 +182,54 @@ namespace CUETools.Ripper.SCSI
|
||||
{
|
||||
get
|
||||
{
|
||||
return Math.Min(m_device.MaximumTransferLength / CB_AUDIO, NSECTORS) * 588;
|
||||
return Math.Min(m_device.MaximumTransferLength / CB_AUDIO - 1, NSECTORS) * 588;
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessSubchannel(int sector, int Sectors2Read)
|
||||
private void ProcessSubchannel(int sector, int Sectors2Read, bool updateMap)
|
||||
{
|
||||
for (int iSector = 0; iSector < Sectors2Read; iSector++)
|
||||
{
|
||||
int q_pos = (iSector + 1) * (588 * 4 + 16) - 16;
|
||||
int ctl = _sectorBuffer[q_pos + 0] >> 4;
|
||||
int adr = _sectorBuffer[q_pos + 0] & 7;
|
||||
bool preemph = (ctl == 1);
|
||||
int q_pos = (sector - _currentStart + iSector + 1) * CB_AUDIO - 16;
|
||||
int ctl = _currentScan.Data[q_pos + 0] >> 4;
|
||||
int adr = _currentScan.Data[q_pos + 0] & 7;
|
||||
bool preemph = (ctl & 1) == 1;
|
||||
switch (adr)
|
||||
{
|
||||
case 1: // current position
|
||||
{
|
||||
int iTrack = fromBCD(_sectorBuffer[q_pos + 1]);
|
||||
int iIndex = fromBCD(_sectorBuffer[q_pos + 2]);
|
||||
int iTrack = fromBCD(_currentScan.Data[q_pos + 1]);
|
||||
int iIndex = fromBCD(_currentScan.Data[q_pos + 2]);
|
||||
int mm = fromBCD(_currentScan.Data[q_pos + 7]);
|
||||
int ss = fromBCD(_currentScan.Data[q_pos + 8]);
|
||||
int ff = fromBCD(_currentScan.Data[q_pos + 9]);
|
||||
int sec = ff + 75 * (ss + 60 * mm) - 150; // sector + iSector;
|
||||
//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);
|
||||
//ushort crc = _crc.ComputeChecksum(_currentScan.Data, q_pos, 10);
|
||||
//crc ^= 0xffff;
|
||||
//if (_currentScan.Data[q_pos + 10] != 0 && _currentScan.Data[q_pos + 11] != 0 &&
|
||||
// ((crc & 0xff) != _currentScan.Data[q_pos + 11] ||
|
||||
// (crc >> 8) != _currentScan.Data[q_pos + 10])
|
||||
// )
|
||||
//{
|
||||
// System.Console.WriteLine("CRC error at {0}", CDImageLayout.TimeToString((uint)(sector + iSector)));
|
||||
//}
|
||||
if (iTrack == 110)
|
||||
throw new Exception("lead out area encountred");
|
||||
{
|
||||
if (sector + iSector + 75 < _toc.AudioLength)
|
||||
throw new Exception("lead out area encountred");
|
||||
// make sure that data is zero?
|
||||
return;
|
||||
}
|
||||
if (iTrack == 0)
|
||||
throw new Exception("lead in area encountred");
|
||||
if (!updateMap)
|
||||
break;
|
||||
if (iTrack != _currentTrack)
|
||||
{
|
||||
_currentTrack = iTrack;
|
||||
_currentTrackActualStart = sector + iSector;
|
||||
_currentTrackActualStart = sec;
|
||||
_currentIndex = iIndex;
|
||||
if (_currentIndex != 1 && _currentIndex != 0)
|
||||
throw new Exception("invalid index");
|
||||
@@ -174,13 +241,15 @@ namespace CUETools.Ripper.SCSI
|
||||
_currentIndex = iIndex;
|
||||
if (_currentIndex == 1)
|
||||
{
|
||||
uint pregap = (uint) (sector + iSector - _currentTrackActualStart);
|
||||
uint pregap = (uint)(sec - _currentTrackActualStart);
|
||||
_toc[iTrack][0].Start = _toc[iTrack].Start - pregap;
|
||||
_currentTrackActualStart = sector + iSector;
|
||||
_currentTrackActualStart = sec;
|
||||
} else
|
||||
_toc[iTrack].AddIndex(new CDTrackIndex((uint)iIndex, (uint)(_toc[iTrack].Start + sector + iSector - _currentTrackActualStart)));
|
||||
_toc[iTrack].AddIndex(new CDTrackIndex((uint)iIndex, (uint)(_toc[iTrack].Start + sec - _currentTrackActualStart)));
|
||||
_currentIndex = iIndex;
|
||||
}
|
||||
if (preemph)
|
||||
_toc[iTrack].PreEmphasis = true;
|
||||
break;
|
||||
}
|
||||
case 2: // catalog
|
||||
@@ -188,7 +257,7 @@ namespace CUETools.Ripper.SCSI
|
||||
{
|
||||
StringBuilder catalog = new StringBuilder();
|
||||
for (int i = 1; i < 8; i++)
|
||||
catalog.AppendFormat("{0:x2}", _sectorBuffer[q_pos + i]);
|
||||
catalog.AppendFormat("{0:x2}", _currentScan.Data[q_pos + i]);
|
||||
_toc.Catalog = catalog.ToString(0, 13);
|
||||
}
|
||||
break;
|
||||
@@ -197,16 +266,16 @@ namespace CUETools.Ripper.SCSI
|
||||
{
|
||||
StringBuilder isrc = new StringBuilder();
|
||||
char[] ISRC6 = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '#', '#', '#', '#', '#', '#', '#', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' };
|
||||
isrc.Append(ISRC6[_sectorBuffer[q_pos + 1] >> 2]);
|
||||
isrc.Append(ISRC6[((_sectorBuffer[q_pos + 1] & 0x3) << 4) + (_sectorBuffer[q_pos + 2] >> 4)]);
|
||||
isrc.Append(ISRC6[((_sectorBuffer[q_pos + 2] & 0xf) << 2) + (_sectorBuffer[q_pos + 3] >> 6)]);
|
||||
isrc.Append(ISRC6[(_sectorBuffer[q_pos + 3] & 0x3f)]);
|
||||
isrc.Append(ISRC6[_sectorBuffer[q_pos + 4] >> 2]);
|
||||
isrc.Append(ISRC6[((_sectorBuffer[q_pos + 4] & 0x3) << 4) + (_sectorBuffer[q_pos + 5] >> 4)]);
|
||||
isrc.AppendFormat("{0:x}", _sectorBuffer[q_pos + 5] & 0xf);
|
||||
isrc.AppendFormat("{0:x2}", _sectorBuffer[q_pos + 6]);
|
||||
isrc.AppendFormat("{0:x2}", _sectorBuffer[q_pos + 7]);
|
||||
isrc.AppendFormat("{0:x}", _sectorBuffer[q_pos + 8] >> 4);
|
||||
isrc.Append(ISRC6[_currentScan.Data[q_pos + 1] >> 2]);
|
||||
isrc.Append(ISRC6[((_currentScan.Data[q_pos + 1] & 0x3) << 4) + (_currentScan.Data[q_pos + 2] >> 4)]);
|
||||
isrc.Append(ISRC6[((_currentScan.Data[q_pos + 2] & 0xf) << 2) + (_currentScan.Data[q_pos + 3] >> 6)]);
|
||||
isrc.Append(ISRC6[(_currentScan.Data[q_pos + 3] & 0x3f)]);
|
||||
isrc.Append(ISRC6[_currentScan.Data[q_pos + 4] >> 2]);
|
||||
isrc.Append(ISRC6[((_currentScan.Data[q_pos + 4] & 0x3) << 4) + (_currentScan.Data[q_pos + 5] >> 4)]);
|
||||
isrc.AppendFormat("{0:x}", _currentScan.Data[q_pos + 5] & 0xf);
|
||||
isrc.AppendFormat("{0:x2}", _currentScan.Data[q_pos + 6]);
|
||||
isrc.AppendFormat("{0:x2}", _currentScan.Data[q_pos + 7]);
|
||||
isrc.AppendFormat("{0:x}", _currentScan.Data[q_pos + 8] >> 4);
|
||||
_toc[_currentTrack].ISRC = isrc.ToString();
|
||||
}
|
||||
break;
|
||||
@@ -216,117 +285,294 @@ namespace CUETools.Ripper.SCSI
|
||||
|
||||
private unsafe void FetchSectors(int sector, int Sectors2Read)
|
||||
{
|
||||
fixed (byte* data = _sectorBuffer)
|
||||
fixed (byte* data = _currentScan.Data)
|
||||
{
|
||||
Device.CommandStatus st = m_device.ReadCDAndSubChannel(2, 1, true, (uint)sector, (uint)Sectors2Read, (IntPtr)((void*)data), Sectors2Read * (2352 + 16));
|
||||
//Device.CommandStatus st;
|
||||
//using (Command cmd = new Command(ScsiCommandCode.Read12, 12, (IntPtr)((void*)data), Sectors2Read * 588 * 4, Command.CmdDirection.In, 5 * 60))
|
||||
//{
|
||||
// //cmd.SetCDB8(1, 4); // force from media
|
||||
// cmd.SetCDB32(2, sector);
|
||||
// cmd.SetCDB32(6, Sectors2Read);
|
||||
// //cmd.SetCDB8(10, 0x80); // streaming
|
||||
// st= m_device.SendCommand(cmd);
|
||||
//}
|
||||
Device.CommandStatus st = m_device.ReadCDAndSubChannel(2, DoC2, 1, false, (uint)sector, (uint)Sectors2Read, (IntPtr)((void*)(data + (sector - _currentStart) * CB_AUDIO)), Sectors2Read * CB_AUDIO);
|
||||
if (st != Device.CommandStatus.Success)
|
||||
throw new Exception("ReadCDAndSubChannel failed: SCSI error");
|
||||
{
|
||||
if (st == Device.CommandStatus.DeviceFailed && m_device.GetSenseAsc() == 0x64 && m_device.GetSenseAscq() == 0x00)
|
||||
{
|
||||
int iErrors = 0;
|
||||
for (int iSector = 0; iSector < Sectors2Read; iSector++)
|
||||
{
|
||||
st = m_device.ReadCDAndSubChannel(2, DoC2, 1, false, (uint)(sector + iSector), 1U, (IntPtr)((void*)(data + (sector + iSector - _currentStart) * CB_AUDIO)), CB_AUDIO);
|
||||
if (st != Device.CommandStatus.Success)
|
||||
{
|
||||
iErrors ++;
|
||||
for (int iPos = 0; iPos < CB_AUDIO; iPos++)
|
||||
data[(sector + iSector - _currentStart) * CB_AUDIO + iPos] = (DoC2 && iPos >= 4 * 588 && iPos < 4 * 588 + 294) ? (byte)255 : (byte)0;
|
||||
}
|
||||
}
|
||||
if (iErrors < Sectors2Read)
|
||||
return;
|
||||
}
|
||||
string status = (st == Device.CommandStatus.DeviceFailed ? Device.LookupSenseError(m_device.GetSenseAsc(), m_device.GetSenseAscq()) : st.ToString());
|
||||
st = m_device.ReadCDAndSubChannel(0, false, 1, false, (uint)sector, (uint)Sectors2Read, (IntPtr)((void*)(data + (sector - _currentStart) * 4 * 588)), Sectors2Read * 4 * 588);
|
||||
if (st != Device.CommandStatus.Success)
|
||||
status += "; ReadWithoutSubchannel: " + (st == Device.CommandStatus.DeviceFailed ? Device.LookupSenseError(m_device.GetSenseAsc(), m_device.GetSenseAscq()) : st.ToString());
|
||||
else
|
||||
status += "; ReadWithoutSubchannel: might work";
|
||||
throw new Exception("ReadCD: " + status);
|
||||
}
|
||||
|
||||
//int localC2 = 0;
|
||||
//if (DoC2)
|
||||
// for (int iSector = 0; iSector < Sectors2Read; iSector++)
|
||||
// {
|
||||
// _currentScan.C2Errors[sector + iSector] = data[(iSector + 1) * CB_AUDIO - 18] != 0;
|
||||
// localC2 += (data[(iSector + 1) * CB_AUDIO - 18] != 0) ? 1 : 0;
|
||||
// }
|
||||
//_currentScan.C2Count += localC2;
|
||||
}
|
||||
ProcessSubchannel(sector, Sectors2Read);
|
||||
}
|
||||
|
||||
public unsafe uint Read(int[,] buff, uint sampleCount)
|
||||
private unsafe void CorrectSectors(int sector, int Sectors2Read, bool findWorst, bool markErrors)
|
||||
{
|
||||
int c2Score = 10;
|
||||
for (int iSector = 0; iSector < Sectors2Read; iSector++)
|
||||
{
|
||||
for (int iPar = 0; iPar < 4 * 588; iPar++)
|
||||
{
|
||||
int dataPos = (sector - _currentStart + iSector) * CB_AUDIO + iPar;
|
||||
int c2Pos = (sector - _currentStart + iSector) * CB_AUDIO + 4 * 588 + iPar / 8;
|
||||
int c2Bit = 0x80 >> (iPar % 8);
|
||||
|
||||
Array.Clear(valueScore, 0, 256);
|
||||
|
||||
byte bestValue = _currentScan.Data[dataPos];
|
||||
valueScore[bestValue] += 1 + (((_currentScan.Data[c2Pos] & c2Bit) == 0) ? c2Score : 0);
|
||||
int totalScore = valueScore[bestValue];
|
||||
for (int result = 0; result < _scanResults.Count; result++)
|
||||
{
|
||||
byte value = _scanResults[result].Data[dataPos];
|
||||
valueScore[value] += 1 + (((_scanResults[result].Data[c2Pos] & c2Bit) == 0) ? c2Score : 0);
|
||||
totalScore += 1 + (((_scanResults[result].Data[c2Pos] & c2Bit) == 0) ? c2Score : 0);
|
||||
if (valueScore[value] > valueScore[bestValue])
|
||||
bestValue = value;
|
||||
}
|
||||
bool fError = valueScore[bestValue] * 2 <= c2Score + totalScore;
|
||||
if (fError)
|
||||
_currentErrorsCount++;
|
||||
_currentData[(sector - _currentStart + iSector) * 4 * 588 + iPar] = bestValue;
|
||||
if (findWorst)
|
||||
{
|
||||
for (int result = 0; result < _scanResults.Count; result++)
|
||||
_scanResults[result].Quality += Math.Min(0, valueScore[_scanResults[result].Data[dataPos]] - c2Score - 1);
|
||||
_currentScan.Quality += Math.Min(0, valueScore[_currentScan.Data[dataPos]] - c2Score - 1);
|
||||
}
|
||||
if (markErrors)
|
||||
{
|
||||
_errors[sector + iSector] = fError;
|
||||
_errorsCount += fError ? 1 : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//private unsafe int CorrectSectorsTest(int start, int end, int c2Score, byte[] realData, int worstScan)
|
||||
//{
|
||||
// int[] valueScore = new int[256];
|
||||
// int[] scoreErrors = new int[256];
|
||||
// int realErrors = 0;
|
||||
// int bestScore = 0;
|
||||
// int _errorsCaught = 0;
|
||||
// int _falsePositives = 0;
|
||||
// for (int iSector = 0; iSector < end - start; iSector++)
|
||||
// {
|
||||
// for (int iPar = 0; iPar < 4 * 588; iPar++)
|
||||
// {
|
||||
// int dataPos = iSector * CB_AUDIO + iPar;
|
||||
// int c2Pos = iSector * CB_AUDIO + 4 * 588 + iPar / 8;
|
||||
// int c2Bit = 0x80 >> (iPar % 8);
|
||||
|
||||
// Array.Clear(valueScore, 0, 256);
|
||||
|
||||
// byte bestValue = _currentScan.Data[dataPos];
|
||||
// valueScore[bestValue] += 1 + (((_currentScan.Data[c2Pos] & c2Bit) == 0) ? c2Score : 0);
|
||||
// int totalScore = valueScore[bestValue];
|
||||
// for (int result = 0; result < _scanResults.Count; result++)
|
||||
// {
|
||||
// if (result == worstScan)
|
||||
// continue;
|
||||
// byte value = _scanResults[result].Data[dataPos];
|
||||
// valueScore[value] += 1 + (((_scanResults[result].Data[c2Pos] & c2Bit) == 0) ? c2Score : 0);
|
||||
// totalScore += 1 + (((_scanResults[result].Data[c2Pos] & c2Bit) == 0) ? c2Score : 0);
|
||||
// if (valueScore[value] > valueScore[bestValue])
|
||||
// bestValue = value;
|
||||
// }
|
||||
// if (valueScore[bestValue] < (1 + c2Score + totalScore) / 2)
|
||||
// _currentErrorsCount++;
|
||||
// //_currentData[iSector * 4 * 588 + iPar] = bestValue;
|
||||
// if (realData[iSector * 4 * 588 + iPar] != bestValue)
|
||||
// {
|
||||
// if (valueScore[bestValue] > bestScore)
|
||||
// scoreErrors[valueScore[bestValue]]++;
|
||||
// realErrors++;
|
||||
// if (valueScore[bestValue] * 2 <= c2Score + totalScore)
|
||||
// _errorsCaught++;
|
||||
// } else
|
||||
// if (valueScore[bestValue] * 2 <= c2Score + totalScore)
|
||||
// _falsePositives++;
|
||||
// }
|
||||
// }
|
||||
// //string s = "";
|
||||
// //for (int i = 0; i < 256; i++)
|
||||
// // if (scoreErrors[i] > 0)
|
||||
// // s += string.Format("[{0}]={1};", i, scoreErrors[i]);
|
||||
// //System.Console.WriteLine("RE{0:000} EC{1} FP{2}", realErrors, _errorsCaught, _falsePositives);
|
||||
// return realErrors;
|
||||
//}
|
||||
|
||||
public void PrefetchSector(int iSector)
|
||||
{
|
||||
int nPasses = 16 + _correctionQuality * 2;
|
||||
int nExtraPasses = 8 + _correctionQuality;
|
||||
|
||||
if (_currentStart == MSECTORS * (iSector / MSECTORS))
|
||||
return;
|
||||
|
||||
_currentStart = MSECTORS * (iSector / MSECTORS);
|
||||
_currentEnd = Math.Min(_currentStart + MSECTORS, (int)_toc.AudioLength);
|
||||
_scanResults = new List<ScanResults>();
|
||||
|
||||
//FileStream correctFile = new FileStream("correct.wav", FileMode.Open);
|
||||
//byte[] realData = new byte[MSECTORS * 4 * 588];
|
||||
//correctFile.Seek(0x2C + start * 588 * 4, SeekOrigin.Begin);
|
||||
//if (correctFile.Read(realData, 0, MSECTORS * 4 * 588) != MSECTORS * 4 * 588)
|
||||
// throw new Exception("read");
|
||||
//correctFile.Close();
|
||||
|
||||
for (int pass = 0; pass <= nPasses + nExtraPasses; pass++)
|
||||
{
|
||||
DateTime PassTime = DateTime.Now;
|
||||
_currentScan = new ScanResults(MSECTORS, CB_AUDIO);
|
||||
_currentErrorsCount = 0;
|
||||
int nSectors = Math.Min(NSECTORS, m_device.MaximumTransferLength / CB_AUDIO - 1);
|
||||
for (int sector = _currentStart; sector < _currentEnd; sector += nSectors)
|
||||
{
|
||||
int Sectors2Read = Math.Min(nSectors, _currentEnd - sector);
|
||||
FetchSectors(sector, Sectors2Read);
|
||||
CorrectSectors(sector, Sectors2Read, pass > nPasses, pass == nPasses + nExtraPasses);
|
||||
ProcessSubchannel(sector, Sectors2Read, pass == 0);
|
||||
if (ReadProgress != null)
|
||||
ReadProgress(this, new ReadProgressArgs(sector + Sectors2Read, pass, _currentStart, _currentEnd, _currentErrorsCount, PassTime));
|
||||
}
|
||||
//System.Console.WriteLine();
|
||||
//if (CorrectSectorsTest(start, _currentEnd, 10, realData) == 0)
|
||||
// break;
|
||||
if (pass == nPasses + nExtraPasses)
|
||||
break;
|
||||
if (pass > nPasses)
|
||||
{
|
||||
int worstPass = -1;
|
||||
for (int result = 0; result < _scanResults.Count; result++)
|
||||
if (_scanResults[result].Quality < (worstPass < 0 ? _currentScan.Quality : _scanResults[worstPass].Quality))
|
||||
worstPass = result;
|
||||
//if (worstPass < 0)
|
||||
// System.Console.WriteLine("bad scan");
|
||||
//else
|
||||
// System.Console.WriteLine("{0}->{1}, {2}->{3}", _scanResults[worstPass].Quality, _currentScan.Quality, CorrectSectorsTest(_currentStart, _currentEnd, 10, realData, -1), CorrectSectorsTest(_currentStart, _currentEnd, 10, realData, worstPass));
|
||||
if (worstPass < 0)
|
||||
_currentScan = null;
|
||||
else
|
||||
_scanResults[worstPass] = _currentScan;
|
||||
for (int result = 0; result < _scanResults.Count; result++)
|
||||
_scanResults[result].Quality = 0;
|
||||
continue;
|
||||
}
|
||||
if (_currentErrorsCount == 0 && pass >= _correctionQuality)
|
||||
{
|
||||
bool syncOk = true;
|
||||
//if (pass == 0)
|
||||
//{
|
||||
// ScanResults saved = _currentScan;
|
||||
// _currentScan = new ScanResults(_currentEnd - _currentStart, CB_AUDIO);
|
||||
// for (int sector = _currentStart; sector < _currentEnd && syncOk; sector += 7)
|
||||
// {
|
||||
// FetchSectors(sector, 2);
|
||||
// for (int i = 0; i < 2 * CB_AUDIO; i++)
|
||||
// if (_currentScan.Data[(sector - _currentStart) * CB_AUDIO + i] != saved.Data[(sector - _currentStart) * CB_AUDIO + i])
|
||||
// {
|
||||
// System.Console.WriteLine("Lost Sync");
|
||||
// syncOk = false;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// _currentScan = saved;
|
||||
//}
|
||||
if (syncOk)
|
||||
break;
|
||||
}
|
||||
_scanResults.Add(_currentScan);
|
||||
}
|
||||
_currentScan = null;
|
||||
_scanResults = null;
|
||||
}
|
||||
|
||||
public uint Read(int[,] buff, uint sampleCount)
|
||||
{
|
||||
if (_toc == null)
|
||||
throw new Exception("Read: invalid TOC");
|
||||
if (_sampleOffset - _driveOffset >= (uint)Length)
|
||||
return 0;
|
||||
return 0;
|
||||
if (_sampleOffset > (uint)Length)
|
||||
{
|
||||
int samplesRead = _sampleOffset - (int)Length;
|
||||
for (int i = 0; i < samplesRead; i++)
|
||||
for (int c = 0; c < ChannelCount; c++)
|
||||
buff[i, c] = 0;
|
||||
_sampleOffset += samplesRead;
|
||||
return 0;
|
||||
int samplesRead = _sampleOffset - (int)Length;
|
||||
for (int i = 0; i < samplesRead; i++)
|
||||
for (int c = 0; c < ChannelCount; c++)
|
||||
buff[i, c] = 0;
|
||||
_sampleOffset += samplesRead;
|
||||
return 0;
|
||||
}
|
||||
if ((uint)(_sampleOffset - _driveOffset + sampleCount) > Length)
|
||||
sampleCount = (uint)((int)Length + _driveOffset - _sampleOffset);
|
||||
sampleCount = (uint)((int)Length + _driveOffset - _sampleOffset);
|
||||
int silenceCount = 0;
|
||||
if ((uint)(_sampleOffset + sampleCount) > Length)
|
||||
{
|
||||
silenceCount = _sampleOffset + (int)sampleCount - (int)Length;
|
||||
sampleCount -= (uint) silenceCount;
|
||||
silenceCount = _sampleOffset + (int)sampleCount - (int)Length;
|
||||
sampleCount -= (uint) silenceCount;
|
||||
}
|
||||
uint pos = 0;
|
||||
if (_sampleOffset < 0)
|
||||
{
|
||||
uint nullSamplesRead = Math.Min((uint)-_sampleOffset, sampleCount);
|
||||
for (int i = 0; i < nullSamplesRead; i++)
|
||||
for (int c = 0; c < ChannelCount; c++)
|
||||
buff[i, c] = 0;
|
||||
pos += nullSamplesRead;
|
||||
sampleCount -= nullSamplesRead;
|
||||
_sampleOffset += (int)nullSamplesRead;
|
||||
if (sampleCount == 0)
|
||||
return pos;
|
||||
uint nullSamplesRead = Math.Min((uint)-_sampleOffset, sampleCount);
|
||||
for (int i = 0; i < nullSamplesRead; i++)
|
||||
for (int c = 0; c < ChannelCount; c++)
|
||||
buff[i, c] = 0;
|
||||
pos += nullSamplesRead;
|
||||
sampleCount -= nullSamplesRead;
|
||||
_sampleOffset += (int)nullSamplesRead;
|
||||
if (sampleCount == 0)
|
||||
return pos;
|
||||
}
|
||||
if (_samplesInBuffer > 0)
|
||||
{
|
||||
uint samplesRead = Math.Min(_samplesInBuffer, sampleCount);
|
||||
AudioSamples.BytesToFLACSamples_16(_sectorBuffer, (int)(_samplesBufferSector * (588 * 4 + 16) + _samplesBufferOffset * 4), buff, (int)pos, samplesRead, 2);
|
||||
pos += samplesRead;
|
||||
sampleCount -= samplesRead;
|
||||
_sampleOffset += (int) samplesRead;
|
||||
if (sampleCount == 0)
|
||||
{
|
||||
_samplesInBuffer -= samplesRead;
|
||||
_samplesBufferOffset += samplesRead;
|
||||
if (silenceCount > 0)
|
||||
{
|
||||
uint nullSamplesRead = (uint) silenceCount;
|
||||
for (int i = 0; i < nullSamplesRead; i++)
|
||||
for (int c = 0; c < ChannelCount; c++)
|
||||
buff[pos + i, c] = 0;
|
||||
pos += nullSamplesRead;
|
||||
_sampleOffset += (int)nullSamplesRead;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
_samplesInBuffer = 0;
|
||||
_samplesBufferOffset = 0;
|
||||
_samplesBufferSector = 0;
|
||||
}
|
||||
// if (_sampleOffset < PreGapLength && !_overreadIntoPreGap ... ?
|
||||
int firstSector = (int)_sampleOffset / 588;
|
||||
int lastSector = (int)(_sampleOffset + sampleCount + 587) / 588;
|
||||
for (int sector = firstSector; sector < lastSector; sector += NSECTORS)
|
||||
int lastSector = Math.Min((int)(_sampleOffset + sampleCount + 587)/588, (int)_toc.AudioLength);
|
||||
for (int sector = firstSector; sector < lastSector; sector ++)
|
||||
{
|
||||
int Sectors2Read = ((sector + NSECTORS) < lastSector) ? NSECTORS : (lastSector - sector);
|
||||
FetchSectors(sector, Sectors2Read);
|
||||
for (int iSector = 0; iSector < Sectors2Read; iSector++)
|
||||
{
|
||||
uint samplesRead = (uint) (Math.Min((int)sampleCount, 588) - (_sampleOffset % 588));
|
||||
AudioSamples.BytesToFLACSamples_16(_sectorBuffer, iSector * (588 * 4 + 16) + ((int)_sampleOffset % 588) * 4, buff, (int)pos, samplesRead, 2);
|
||||
pos += samplesRead;
|
||||
sampleCount -= samplesRead;
|
||||
_sampleOffset += (int) samplesRead;
|
||||
if (sampleCount == 0)
|
||||
{
|
||||
_samplesBufferSector = (uint)iSector;
|
||||
_samplesBufferOffset = samplesRead;
|
||||
_samplesInBuffer = 588U - samplesRead;
|
||||
if (silenceCount > 0)
|
||||
{
|
||||
uint nullSamplesRead = (uint)silenceCount;
|
||||
for (int i = 0; i < nullSamplesRead; i++)
|
||||
for (int c = 0; c < ChannelCount; c++)
|
||||
buff[pos + i, c] = 0;
|
||||
pos += nullSamplesRead;
|
||||
_sampleOffset += (int)nullSamplesRead;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
PrefetchSector(sector);
|
||||
uint samplesRead = (uint) (Math.Min((int)sampleCount, 588 - (_sampleOffset % 588)));
|
||||
AudioSamples.BytesToFLACSamples_16(_currentData, (sector - _currentStart) * 4 * 588 + ((int)_sampleOffset % 588) * 4, buff, (int)pos, samplesRead, 2);
|
||||
pos += samplesRead;
|
||||
sampleCount -= samplesRead;
|
||||
_sampleOffset += (int) samplesRead;
|
||||
}
|
||||
if (silenceCount > 0)
|
||||
{
|
||||
uint nullSamplesRead = (uint)silenceCount;
|
||||
for (int i = 0; i < nullSamplesRead; i++)
|
||||
for (int c = 0; c < ChannelCount; c++)
|
||||
buff[pos + i, c] = 0;
|
||||
pos += nullSamplesRead;
|
||||
_sampleOffset += (int)nullSamplesRead;
|
||||
uint nullSamplesRead = (uint)silenceCount;
|
||||
for (int i = 0; i < nullSamplesRead; i++)
|
||||
for (int c = 0; c < ChannelCount; c++)
|
||||
buff[pos + i, c] = 0;
|
||||
pos += nullSamplesRead;
|
||||
_sampleOffset += (int)nullSamplesRead;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
@@ -430,14 +676,24 @@ namespace CUETools.Ripper.SCSI
|
||||
}
|
||||
}
|
||||
|
||||
public int CorrectionQuality
|
||||
{
|
||||
get
|
||||
{
|
||||
return _correctionQuality;
|
||||
}
|
||||
set
|
||||
{
|
||||
_correctionQuality = value;
|
||||
}
|
||||
}
|
||||
|
||||
public static string RipperVersion()
|
||||
{
|
||||
return "CUERipper v1.9.3 Copyright (C) 2008 Gregory S. Chudov";
|
||||
// ripper.GetName().Name + " " + ripper.GetName().Version;
|
||||
}
|
||||
|
||||
byte[] _sectorBuffer = new byte[CB_AUDIO * NSECTORS];
|
||||
|
||||
private int fromBCD(byte hex)
|
||||
{
|
||||
return (hex >> 4) * 10 + (hex & 15);
|
||||
@@ -452,4 +708,35 @@ namespace CUETools.Ripper.SCSI
|
||||
return result.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
internal class ScanResults
|
||||
{
|
||||
public byte[] Data;
|
||||
public long Quality;
|
||||
|
||||
public ScanResults(int msector, int cbaudio)
|
||||
{
|
||||
Data = new byte[msector * cbaudio];
|
||||
Quality = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ReadProgressArgs: EventArgs
|
||||
{
|
||||
public int Position;
|
||||
public int Pass;
|
||||
public int PassStart, PassEnd;
|
||||
public int ErrorsCount;
|
||||
public DateTime PassTime;
|
||||
|
||||
public ReadProgressArgs(int position, int pass, int passStart, int passEnd, int errorsCount, DateTime passTime)
|
||||
{
|
||||
Position = position;
|
||||
Pass = pass;
|
||||
PassStart = passStart;
|
||||
PassEnd = passEnd;
|
||||
ErrorsCount = errorsCount;
|
||||
PassTime = passTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
// ****************************************************************************
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Text;
|
||||
@@ -436,6 +437,7 @@ namespace CUETools.Processor
|
||||
private bool _isCD;
|
||||
private string _driveName;
|
||||
private int _driveOffset;
|
||||
private BitArray _cdErrors;
|
||||
private bool _isArchive;
|
||||
private List<string> _archiveContents;
|
||||
private string _archiveCUEpath;
|
||||
@@ -696,7 +698,7 @@ namespace CUETools.Processor
|
||||
}
|
||||
trackInfo = new TrackInfo();
|
||||
_tracks.Add(trackInfo);
|
||||
_toc.AddTrack(new CDTrack((uint)trackNumber, 0, 0, true));
|
||||
_toc.AddTrack(new CDTrack((uint)trackNumber, 0, 0, true, false));
|
||||
}
|
||||
}
|
||||
else if (seenDataTrack) {
|
||||
@@ -892,7 +894,7 @@ namespace CUETools.Processor
|
||||
uint trNo, trStart, trEnd;
|
||||
if (n.Length == 5 && uint.TryParse(n[0], out trNo) && uint.TryParse(n[3], out trStart) && uint.TryParse(n[4], out trEnd))
|
||||
tocFromLog.AddTrack(new CDTrack(trNo, trStart, trEnd + 1 - trStart,
|
||||
tocFromLog.TrackCount < _toc.TrackCount || trStart != tocFromLog[tocFromLog.TrackCount].End + 1U + 152U * 75U));
|
||||
tocFromLog.TrackCount < _toc.TrackCount || trStart != tocFromLog[tocFromLog.TrackCount].End + 1U + 152U * 75U, false));
|
||||
} else
|
||||
if (lineStr.StartsWith("TOC of the extracted CD")
|
||||
|| lineStr.StartsWith("Exact Audio Copy")
|
||||
@@ -906,7 +908,7 @@ namespace CUETools.Processor
|
||||
if (_accurateRipId == null && _dataTrackLength != null)
|
||||
{
|
||||
CDImageLayout toc2 = new CDImageLayout(_toc);
|
||||
toc2.AddTrack(new CDTrack((uint)_toc.TrackCount, _toc.Length + 152U * 75U, _dataTrackLength.Value, false));
|
||||
toc2.AddTrack(new CDTrack((uint)_toc.TrackCount, _toc.Length + 152U * 75U, _dataTrackLength.Value, false, false));
|
||||
_accurateRipId = AccurateRipVerify.CalculateAccurateRipId(toc2);
|
||||
}
|
||||
|
||||
@@ -1216,18 +1218,39 @@ namespace CUETools.Processor
|
||||
_toc[track].LengthMSF,
|
||||
_toc[track].Start,
|
||||
_toc[track].End);
|
||||
logWriter.WriteLine();
|
||||
if (_accurateRipMode == AccurateRipMode.VerifyThenConvert)
|
||||
for (int iTrack = 0; iTrack < _toc.AudioTracks; iTrack++)
|
||||
if (_arVerify.BackupCRC(iTrack) != _arVerify.CRC(iTrack))
|
||||
logWriter.WriteLine("Track {0} CRC mismatch: test {1:X8} vs copy {2:X8}", iTrack + 1, _arVerify.BackupCRC(iTrack), _arVerify.CRC(iTrack));
|
||||
bool wereErrors = false;
|
||||
for (int iTrack = 0; iTrack < _toc.AudioTracks; iTrack++)
|
||||
{
|
||||
int cdErrors = 0;
|
||||
bool crcMismatch = _accurateRipMode == AccurateRipMode.VerifyThenConvert &&
|
||||
_arVerify.BackupCRC(iTrack) != _arVerify.CRC(iTrack);
|
||||
for (uint iSector = _toc[iTrack + 1].Start; iSector <= _toc[iTrack + 1].End; iSector++)
|
||||
if (_cdErrors[(int)iSector])
|
||||
cdErrors++;
|
||||
if (crcMismatch || cdErrors != 0)
|
||||
{
|
||||
if (!wereErrors)
|
||||
{
|
||||
logWriter.WriteLine();
|
||||
logWriter.WriteLine("Errors detected");
|
||||
logWriter.WriteLine();
|
||||
}
|
||||
wereErrors = true;
|
||||
if (crcMismatch)
|
||||
logWriter.WriteLine("Track {0} contains {1} errors, CRC mismatch: test {2:X8} vs copy {3:X8}", iTrack + 1, cdErrors, _arVerify.BackupCRC(iTrack), _arVerify.CRC(iTrack));
|
||||
else
|
||||
logWriter.WriteLine("Track {0} contains {1} errors", iTrack + 1, cdErrors);
|
||||
}
|
||||
}
|
||||
if (_accurateRipMode != AccurateRipMode.None)
|
||||
{
|
||||
logWriter.WriteLine();
|
||||
logWriter.WriteLine("AccurateRip summary");
|
||||
logWriter.WriteLine();
|
||||
_arVerify.GenerateFullLog(logWriter, 0);
|
||||
logWriter.WriteLine();
|
||||
}
|
||||
logWriter.WriteLine();
|
||||
logWriter.WriteLine("End of status report");
|
||||
logWriter.Close();
|
||||
return logWriter.ToString();
|
||||
@@ -1494,7 +1517,7 @@ namespace CUETools.Processor
|
||||
{
|
||||
uint minDTL = _minDataTrackLength.Value;
|
||||
CDImageLayout toc2 = new CDImageLayout(_toc);
|
||||
toc2.AddTrack(new CDTrack((uint)_toc.TrackCount, _toc.Length + 152 * 75, minDTL, false));
|
||||
toc2.AddTrack(new CDTrack((uint)_toc.TrackCount, _toc.Length + 152 * 75, minDTL, false, false));
|
||||
for (uint dtl = minDTL; dtl < minDTL + 75; dtl++)
|
||||
{
|
||||
toc2[toc2.TrackCount].Length = dtl;
|
||||
@@ -1608,7 +1631,7 @@ namespace CUETools.Processor
|
||||
{
|
||||
WriteText(_cuePath, cueContents);
|
||||
#if !MONO
|
||||
if (needNewCRCs)
|
||||
if (needNewCRCs && style != CUEStyle.SingleFile)
|
||||
{
|
||||
for (int iTrack = 0; iTrack < TrackCount; iTrack++)
|
||||
{
|
||||
@@ -1972,7 +1995,10 @@ namespace CUETools.Processor
|
||||
{
|
||||
#if !MONO
|
||||
if (_isCD && audioSource != null && audioSource is CDDriveReader)
|
||||
{
|
||||
updatedTOC = ((CDDriveReader)audioSource).TOC;
|
||||
_cdErrors = ((CDDriveReader)audioSource).Errors;
|
||||
}
|
||||
#endif
|
||||
if (audioSource != null) audioSource.Close();
|
||||
audioSource = GetAudioSource(++iSource);
|
||||
@@ -2057,15 +2083,22 @@ namespace CUETools.Processor
|
||||
|
||||
#if !MONO
|
||||
if (_isCD && audioSource != null && audioSource is CDDriveReader)
|
||||
{
|
||||
updatedTOC = ((CDDriveReader)audioSource).TOC;
|
||||
_cdErrors = ((CDDriveReader)audioSource).Errors;
|
||||
}
|
||||
if (updatedTOC != null)
|
||||
{
|
||||
_toc = updatedTOC;
|
||||
if (_toc.Catalog != null)
|
||||
General.SetCUELine(_attributes, "CATALOG", _toc.Catalog, false);
|
||||
for (iTrack = 1; iTrack <= _toc.TrackCount; iTrack++)
|
||||
{
|
||||
if (_toc[iTrack].IsAudio && _toc[iTrack].ISRC != null)
|
||||
General.SetCUELine(_tracks[iTrack - 1].Attributes, "ISRC", _toc[iTrack].ISRC, false);
|
||||
if (_toc[iTrack].IsAudio && _toc[iTrack].PreEmphasis)
|
||||
General.SetCUELine(_tracks[iTrack - 1].Attributes, "FLAGS", "PRE", false);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -2401,7 +2434,7 @@ namespace CUETools.Processor
|
||||
{
|
||||
_dataTrackLength = dtl;
|
||||
CDImageLayout toc2 = new CDImageLayout(_toc);
|
||||
toc2.AddTrack(new CDTrack((uint)_toc.TrackCount, _toc.Length + 152 * 75, dtl, false));
|
||||
toc2.AddTrack(new CDTrack((uint)_toc.TrackCount, _toc.Length + 152 * 75, dtl, false, false));
|
||||
_accurateRipIdActual = _accurateRipId = AccurateRipVerify.CalculateAccurateRipId(toc2);
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user