Files
cuetools.net/CUETools.CTDB.EACPlugin/Plugin.cs

346 lines
12 KiB
C#
Raw Normal View History

2011-04-01 21:34:11 +00:00
using System;
using System.Collections.Generic;
using System.Text;
using HelperFunctionsLib;
using System.Runtime.InteropServices;
using System.Reflection;
using System.Net;
using System.IO;
using CUETools.CDImage;
using CUETools.AccurateRip;
using CUETools.Codecs;
using CUETools.CTDB;
using CUETools.CTDB.EACPlugin;
2011-04-01 21:34:11 +00:00
namespace AudioDataPlugIn
{
2012-01-12 03:32:00 +00:00
[Guid("C02A1BF2-5C46-4990-80C2-78E8C395CB80"),
2011-04-01 21:34:11 +00:00
ClassInterface(ClassInterfaceType.None),
ComSourceInterfaces(typeof(IAudioDataTransfer)),
]
// Our class needs to inherit the IAudioDataTransfer in
// order to be found by EAC, further the class needs
// to be named AudioDataTransfer and must be in the
// namespace AudioDataPlugIn
public class AudioDataTransfer : IAudioDataTransfer
{
int m_start_pos = 0, m_length = 0;
int m_suspicious = 0;
int m_suspiciousTest = 0;
2011-04-01 21:34:11 +00:00
bool m_test_mode = false;
IMetadataLookup m_data = null;
2012-01-12 03:32:00 +00:00
CDImageLayout TOC;
#if USEAR
2011-04-01 21:34:11 +00:00
string ArId;
#endif
2012-01-12 03:32:00 +00:00
AccurateRipVerify ar;
AccurateRipVerify arTest;
CUEToolsDB ctdb;
bool sequence_ok = true;
bool is_secure_mode;
bool is_offset_set;
string m_drivename;
2012-01-12 03:18:29 +00:00
#if DEBUG
StringWriter m_trace;
#endif
2011-04-01 21:34:11 +00:00
// This functions just returns an unique identifier.
// For that, the string representation of the unique
// guid is used
public string GetAudioTransferPluginGuid()
{
2012-01-12 03:32:00 +00:00
return ((GuidAttribute)Attribute.GetCustomAttribute(GetType(), typeof(GuidAttribute))).Value;
2011-04-01 21:34:11 +00:00
}
// Each plugin has also an (unique) display name
// which will be used for selecting/deselecting
// the plugin and for display in the log file
public string GetAudioTransferPluginName()
{
2014-12-08 23:35:43 -05:00
return "CUETools DB Plugin V2.1.6";
2011-04-01 21:34:11 +00:00
}
// Each plugin should have its own options page.
// Even though if there are no options, a help or
// information dialog should be displayed
public void ShowOptions()
{
Options opt = new Options();
opt.ShowDialog();
}
public void SuspiciousPosition()
{
if (this.m_test_mode)
this.m_suspiciousTest++;
else
this.m_suspicious++;
#if DEBUG
var thisAr = m_test_mode ? arTest : ar;
m_trace.WriteLine("Suspicious position: {0} ({1}*588)", thisAr.Position, thisAr.Position/588);
#endif
}
2011-04-01 21:34:11 +00:00
// Now to the audio transfer functions, the sequence how
// the functions are called is:
// StartNewSession
// StartNewTransfer
// TransferAudio
// ...
// TransferAudio
// TransferFinshed
// Then perhaps repeating StartNewTransfer to TransferFinished
// (e.g. when extracting several tracks), and finally
// EndOfSession
// This is called just before the log window will be
// shown. You can return a log output in that stage (or
// even display a window of your own - even though it should
// not annoy the user)
// StartNewSession is called once at the very beginning of an
// extraction session. It receives the CD metadata, the
// name of the used drive, the used read offset and whether
// the offset was setted by AccurateRip (so having a comparable
// offset value)
2012-01-12 03:32:00 +00:00
public void StartNewSession(IMetadataLookup data, string drivename, int offset, bool aroffset, int mode)
2011-04-01 21:34:11 +00:00
{
// Copy the CD metadata to the object
m_data = data;
2012-01-12 03:18:29 +00:00
#if DEBUG
m_trace = new StringWriter();
#endif
2011-04-07 22:28:06 +00:00
2012-01-12 03:32:00 +00:00
var parts = drivename.Split(' ');
m_drivename = parts[0].PadRight(8, ' ') + " -";
for (int i = 1; i < parts.Length; i++)
m_drivename += " " + parts[i];
TOC = new CDImageLayout();
for (int i = 0; i < m_data.NumberOfTracks; i++)
{
uint start = m_data.GetTrackStartPosition(i);
uint next = m_data.GetTrackEndPosition(i);
TOC.AddTrack(new CDTrack(
(uint)i + 1,
start,
next - start,
!m_data.GetTrackDataTrack(i),
m_data.GetTrackPreemphasis(i)));
}
TOC[1][0].Start = 0U;
ar = new AccurateRipVerify(TOC, null);
arTest = new AccurateRipVerify(TOC, null);
ctdb = new CUEToolsDB(TOC, null);
2011-04-07 22:28:06 +00:00
#if USEAR
ArId = AccurateRipVerify.CalculateAccurateRipId(TOC);
2011-04-01 21:34:11 +00:00
ar.ContactAccurateRip(ArId);
2011-04-07 22:28:06 +00:00
#endif
2012-01-12 03:32:00 +00:00
ctdb.Init(ar);
this.sequence_ok = true;
this.m_start_pos = 0;
this.m_length = 0;
this.m_suspicious = 0;
this.m_suspiciousTest = 0;
2012-01-12 03:32:00 +00:00
this.m_test_mode = false;
this.is_offset_set = aroffset;
this.is_secure_mode = mode >= 2;
2011-04-01 21:34:11 +00:00
}
// This function will be called once per session. A session
// is e.g. a file on a real extraction (or the equivalent
// for test extractions). It receives the sector startpos
// the length in sectors and whether the extraction is performed
// in test mode
public void StartNewTransfer(int startpos, int length, bool testmode)
{
// Copy the current parameters to the objects variables
2012-01-12 03:32:00 +00:00
m_start_pos = startpos - (int)TOC[TOC.FirstAudio][0].Start;
m_length = length;
m_test_mode = testmode;
if (this.sequence_ok)
{
var thisAr = m_test_mode ? arTest : ar;
2012-01-12 03:18:29 +00:00
if (this.m_start_pos * 588 != thisAr.Position)
{
if (thisAr.Position == 0 && this.m_start_pos == (int)TOC[TOC.FirstAudio].Pregap)
{
#if DEBUG
m_trace.WriteLine("Adding pregap");
#endif
var ad = new byte[588 * 4];
AudioBuffer buff = new AudioBuffer(AudioPCMConfig.RedBook, ad, ad.Length / 4);
for (int i = 0; i < (int)TOC[TOC.FirstAudio].Pregap; i++)
thisAr.Write(buff);
}
else
{
#if DEBUG
m_trace.WriteLine("Sequence broken on new trasfer");
#endif
this.sequence_ok = false;
}
}
2012-01-12 03:32:00 +00:00
}
2011-04-01 21:34:11 +00:00
}
// This function received the extracted (and
// uncompressed/unmodified audio data), but no WAV
// header. If you want to write out the WAV file
// you need to generate one yourself. It will be always
// 44.1 kHz, stereo 16 bit samples (so 4 bytes per
// stereo sample)
public void TransferAudioData(Array audiodata)
{
2012-01-12 03:32:00 +00:00
if (this.sequence_ok)
{
byte[] ad = (byte[])audiodata;
AudioBuffer buff = new AudioBuffer(AudioPCMConfig.RedBook, ad, ad.Length / 4);
var thisAr = m_test_mode ? arTest : ar;
thisAr.Write(buff);
}
2011-04-01 21:34:11 +00:00
}
// This function is called after a transfer has finished.
// We don't do here anything, because a track can be delivered
// in several transfers (index extraction) and as AccurateRip
// is only (full) track based, we don't do anything...
public void TransferFinished()
{
2012-01-12 03:32:00 +00:00
if (this.sequence_ok)
{
var thisAr = m_test_mode ? arTest : ar;
2012-01-12 03:18:29 +00:00
if ((m_start_pos + m_length) * 588 != thisAr.Position)
{
#if DEBUG
m_trace.WriteLine("Sequence broken on end of trasfer");
#endif
this.sequence_ok = false;
}
2012-01-12 03:32:00 +00:00
}
}
2011-04-01 21:34:11 +00:00
// The extraction has finished, the log dialog will
// be shown soon, so we can return a string which will
// be displayed in the log window and be written to
// the log file. Anyway, you could also return just
// an empty string, in that case no log output will be done!
public string EndOfSession()
{
2012-01-12 03:32:00 +00:00
StringWriter sw = new StringWriter();
if (this.sequence_ok)
{
2012-01-12 03:18:29 +00:00
if (TOC.AudioLength * 588 != ar.Position)
{
#if DEBUG
m_trace.WriteLine("Sequence broken on end of session");
#endif
this.sequence_ok = false;
}
if (ar.Position != arTest.Position && arTest.Position > 0)
{
#if DEBUG
m_trace.WriteLine("Sequence broken on end of session");
#endif
this.sequence_ok = false;
}
2012-01-12 03:32:00 +00:00
}
2012-01-12 03:18:29 +00:00
if (!this.sequence_ok)
{
#if DEBUG
return m_trace.ToString();
#else
return "";
#endif
}
#if DEBUG
sw.Write(m_trace.ToString());
#endif
2012-01-12 03:32:00 +00:00
if (this.sequence_ok)
{
2011-04-07 22:28:06 +00:00
#if USEAR
2012-01-12 03:32:00 +00:00
int conf = (int)ar.WorstConfidence() + 1;
2011-04-07 22:28:06 +00:00
#else
2012-01-12 03:32:00 +00:00
int conf = 1;
2011-04-07 22:28:06 +00:00
#endif
2012-01-12 03:32:00 +00:00
var form = new FormSubmitParity(
ctdb,
2014-12-08 23:35:43 -05:00
"EAC" + m_data.HostVersion + " CTDB 2.1.6",
2012-01-12 03:32:00 +00:00
m_drivename,
conf,
(arTest.Position != 0 && arTest.CRC32(0) == ar.CRC32(0)) ? 100 :
(arTest.Position == 0 && this.is_secure_mode) ?
(int)(100 * (1.0 - Math.Log(m_suspicious + 1) / Math.Log(TOC.AudioLength + 1))) :
(int)( 49 * (1.0 - Math.Log(m_suspicious + 1) / Math.Log(TOC.AudioLength + 1))),
2012-01-12 03:32:00 +00:00
m_data.AlbumArtist,
m_data.AlbumTitle);
form.ShowDialog();
sw.WriteLine("[CTDB TOCID: {0}] {1}",
TOC.TOCID,
ctdb.DBStatus ?? "found");
2011-11-15 10:56:49 +00:00
if (ctdb.SubStatus != null)
sw.WriteLine("Submit result: " + ctdb.SubStatus);
2012-01-12 03:18:29 +00:00
#if DEBUG
ctdb.GenerateLog(sw, true);
#else
2011-11-15 10:56:49 +00:00
ctdb.GenerateLog(sw, false);
2012-01-12 03:18:29 +00:00
#endif
int fixConf = -1;
int myConf = 0;
2012-01-12 03:32:00 +00:00
if (ctdb.QueryExceptionStatus == WebExceptionStatus.Success)
{
foreach (DBEntry entry in ctdb.Entries)
2012-01-12 03:18:29 +00:00
if (!entry.hasErrors)
myConf += entry.conf;
else if (entry.canRecover)
fixConf = Math.Max(fixConf, entry.conf);
2012-01-12 03:32:00 +00:00
}
2012-01-12 03:18:29 +00:00
if (fixConf > myConf)
2012-01-12 03:32:00 +00:00
sw.WriteLine("If you are sure that your rip contains errors, you can use CUETools to repair it.");
2011-04-07 22:28:06 +00:00
#if USEAR
2012-01-12 03:32:00 +00:00
ar.GenerateFullLog(sw, false, ArId);
2011-04-07 22:28:06 +00:00
#endif
2012-01-12 03:32:00 +00:00
}
else
sw.WriteLine("Some tracks have been skipped");
return sw.ToString();
2011-04-01 21:34:11 +00:00
}
}
2012-01-17 08:04:16 +00:00
//private NativeWindow GetWindowFromHost(int hwnd)
//{
// IntPtr handle = new IntPtr(hwnd);
// NativeWindow nativeWindow = new NativeWindow();
// nativeWindow.AssignHandle(handle);
// return window;
//}
//NativeWindow parentWindow = GetWindowFromHwnd(hwnd);
//try
//{
// launchTarget.ShowDialog(parentWindow);
//}
//finally
//{
// parentWindow.ReleaseHandle();
//}
//internal class WindowWrapper : System.Windows.Forms.IWin32Window
//{
// public IntPtr Handle { get; private set; }
// public WindowWrapper(IntPtr hwnd) { Handle = hwnd; }
//}
2011-04-01 21:34:11 +00:00
}