EAC plugin for CTDB

This commit is contained in:
chudov
2011-04-01 21:34:11 +00:00
parent 1b20d9fa99
commit e08e86fea5
8 changed files with 647 additions and 0 deletions

View File

@@ -0,0 +1,90 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{816D964C-9772-46C5-AF1D-49E8C78A1E7C}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>CUETools.CTDB.EACPlugin</RootNamespace>
<AssemblyName>CUETools.CTDB.EACPlugin</AssemblyName>
<TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkSubset>
</TargetFrameworkSubset>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\bin\Debug\interop\EAC\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>..\bin\Release\interop\EAC\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Interop.HelperFunctionsLib, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>.\Interop.HelperFunctionsLib.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Plugin.cs" />
<Compile Include="Options.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Options.Designer.cs">
<DependentUpon>Options.cs</DependentUpon>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Options.resx">
<DependentUpon>Options.cs</DependentUpon>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\CUETools.AccurateRip\CUETools.AccurateRip.csproj">
<Project>{5802C7E9-157E-4124-946D-70B5AE48A5A1}</Project>
<Name>CUETools.AccurateRip</Name>
</ProjectReference>
<ProjectReference Include="..\CUETools.CDImage\CUETools.CDImage.csproj">
<Project>{1DD41038-D885-46C5-8DDE-E0B82F066584}</Project>
<Name>CUETools.CDImage</Name>
</ProjectReference>
<ProjectReference Include="..\CUETools.Codecs\CUETools.Codecs.csproj">
<Project>{6458A13A-30EF-45A9-9D58-E5031B17BEE2}</Project>
<Name>CUETools.Codecs</Name>
</ProjectReference>
<ProjectReference Include="..\CUETools.CTDB\CUETools.CTDB.csproj">
<Project>{AA2A9A7E-45FB-4632-AD85-85B0E556F818}</Project>
<Name>CUETools.CTDB</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

Binary file not shown.

View File

@@ -0,0 +1,88 @@

namespace AudioDataPlugIn
{
partial class Options
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.label1 = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.linkLabel1 = new System.Windows.Forms.LinkLabel();
this.SuspendLayout();
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(12, 9);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(139, 13);
this.label1.TabIndex = 0;
this.label1.Text = "CUETools DB Plugin V2.1.1";
//
// label2
//
this.label2.Location = new System.Drawing.Point(12, 71);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(260, 52);
this.label2.TabIndex = 1;
this.label2.Text = "Copyright (c) 2011 Gregory S. Chudov";
//
// linkLabel1
//
this.linkLabel1.AutoSize = true;
this.linkLabel1.Location = new System.Drawing.Point(12, 39);
this.linkLabel1.Name = "linkLabel1";
this.linkLabel1.Size = new System.Drawing.Size(111, 13);
this.linkLabel1.TabIndex = 3;
this.linkLabel1.TabStop = true;
this.linkLabel1.Text = "http://db.cuetools.net";
//
// Options
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(284, 124);
this.Controls.Add(this.linkLabel1);
this.Controls.Add(this.label2);
this.Controls.Add(this.label1);
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "Options";
this.ShowIcon = false;
this.Text = "Options";
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.LinkLabel linkLabel1;
}
}

View File

@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace AudioDataPlugIn
{
public partial class Options : Form
{
public Options()
{
InitializeComponent();
}
}
}

View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@@ -0,0 +1,291 @@
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;
namespace AudioDataPlugIn
{
[Guid("C02A1BF2-5C46-4990-80C2-78E8C395CB80"),
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;
bool m_test_mode = false;
IMetadataLookup m_data = null;
CDImageLayout TOC;
string ArId;
AccurateRipVerify ar;
CUEToolsDB ctdb;
bool sequence_ok = true;
bool is_accurate;
string m_drivename;
// This functions just returns an unique identifier.
// For that, the string representation of the unique
// guid is used
public string GetAudioTransferPluginGuid()
{
// Determine the guid attribute of the given class
Attribute attrib = Attribute.GetCustomAttribute(typeof(AudioDataTransfer), typeof(GuidAttribute));
// Is the returned attribute a GuidAttribute as
// we asked for?
if (attrib is GuidAttribute)
{
// Yes, so return the guid of this class
return ((GuidAttribute)attrib).Value;
}
else
{
// No, something went wrong. Just return
// the name of the plugin and hope that it
// is unique
return GetAudioTransferPluginName();
}
}
// 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()
{
// Return the name which should be
// displayed in EAC and in the log file
// including a version number
return "CUETools DB Plugin V2.1.1";
}
// 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()
{
// Create a new option dialog object
Options opt = new Options();
// And show that dialog (return when
// the dialog is closed)
opt.ShowDialog();
}
// 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)
public void StartNewSession(IMetadataLookup data, string drivename, int offset, bool aroffset)
{
// Copy the CD metadata to the object
m_data = data;
m_drivename = drivename;
TOC = new CDImageLayout();
for (int i = 0; i < m_data.NumberOfTracks; i++)
{
uint start = m_data.GetTrackStartPosition(i);
uint next;
if (i < m_data.NumberOfTracks - 1)
{
next = m_data.GetTrackStartPosition(i + 1);
if (!m_data.GetTrackDataTrack(i) && m_data.GetTrackDataTrack(i + 1))
next -= 152 * 75;
} else
next = m_data.LeadoutPosition;
TOC.AddTrack(new CDTrack(
(uint)i + 1,
start,
next - start,
!m_data.GetTrackDataTrack(i),
m_data.GetTrackPreemphasis(i)));
}
TOC[1][0].Start = 0U;
ArId = AccurateRipVerify.CalculateAccurateRipId(TOC);
ar = new AccurateRipVerify(TOC, null);
ctdb = new CUEToolsDB(TOC, null);
ar.ContactAccurateRip(ArId);
ctdb.ContactDB("EAC 1.0 CTDB 2.1.1: " + m_drivename);
ctdb.Init(true, ar);
this.sequence_ok = true;
this.m_start_pos = 0;
this.m_length = 0;
this.m_test_mode = false;
this.is_accurate = aroffset; // TODO: && not a virtual drive && not a burst mode!!!!
}
// 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
m_start_pos = startpos - (int)TOC[TOC.FirstAudio][0].Start;
m_length = length;
m_test_mode = testmode;
if (this.sequence_ok)
{
if (this.m_start_pos * 588 != ar.Position)
this.sequence_ok = false;
}
}
// 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)
{
if (!this.m_test_mode && this.sequence_ok)
{
byte[] ad = (byte[])audiodata;
AudioBuffer buff = new AudioBuffer(AudioPCMConfig.RedBook, ad, ad.Length / 4);
ar.Write(buff);
}
}
// 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()
{
if (this.sequence_ok)
{
if ((m_start_pos + m_length) * 588 != ar.Position)
this.sequence_ok = false;
}
}
// 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()
{
StringWriter sw = new StringWriter();
if (this.sequence_ok)
{
if (TOC.AudioLength * 588 != ar.Position)
this.sequence_ok = false;
}
if (!this.sequence_ok)
return "";
if (this.sequence_ok)
{
int rippingErrorsCount = 0; // TODO: !!!
DBEntry confirm = null;
if ((ctdb.AccResult == HttpStatusCode.NotFound || ctdb.AccResult == HttpStatusCode.OK)
&& this.is_accurate && rippingErrorsCount == 0)
{
foreach (DBEntry entry in ctdb.Entries)
if (entry.toc.TrackOffsets == TOC.TrackOffsets && !entry.hasErrors)
confirm = entry;
if (confirm != null)
ctdb.Confirm(confirm);
else
ctdb.Submit(
(int)ar.WorstConfidence() + 1,
(int)ar.WorstTotal() + 1,
m_data.AlbumArtist,
m_data.AlbumTitle);
}
sw.WriteLine("[CTDB TOCID: {0}] {1}.", TOC.TOCID, ctdb.DBStatus ?? "found");
if (ctdb.SubStatus != null && confirm == null)
sw.WriteLine("Submit result: {0}.", ctdb.SubStatus);
foreach (DBEntry entry in ctdb.Entries)
{
string confFormat = (ctdb.Total < 10) ? "{0:0}/{1:0}" :
(ctdb.Total < 100) ? "{0:00}/{1:00}" : "{0:000}/{1:000}";
string conf = string.Format(confFormat, entry.conf, ctdb.Total);
string dataTrackInfo = !entry.toc[entry.toc.TrackCount].IsAudio ? string.Format("CD-Extra 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) : "Has no data track";
string status =
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.hasErrors) ? string.Format("Accurately ripped, offset {0}", -entry.offset) :
entry.canRecover ? string.Format("Differs in {0} samples @{1}", entry.repair.CorrectableErrors, entry.repair.AffectedSectors) :
(entry.httpStatus == 0 || entry.httpStatus == HttpStatusCode.OK) ? "No match" :
entry.httpStatus.ToString());
sw.WriteLine("[{0:x8}] ({1}) {2}{3}", entry.crc, conf, status, entry != confirm || ctdb.SubStatus == null ? "" : (", Submit result: " + ctdb.SubStatus));
}
bool canFix = false;
if (ctdb.AccResult == HttpStatusCode.OK && rippingErrorsCount != 0)
{
foreach (DBEntry entry in ctdb.Entries)
if (entry.hasErrors && entry.canRecover)
canFix = true;
}
if (canFix)
sw.WriteLine("You can use CUETools to repair this rip.");
//ar.GenerateFullLog(sw, true, ArId);
}
else
sw.WriteLine("Some tracks have been skipped");
return sw.ToString();
}
}
}

View File

@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("CUETools.CTDB.EACPlugin")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("CUETools.CTDB.EACPlugin")]
[assembly: AssemblyCopyright("Copyright © Gregory S. Chudov 2011")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("a8b718f7-3c33-4d04-9606-264ce30fe056")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -0,0 +1,3 @@
<?xml version="1.0"?>
<configuration>
<startup><supportedRuntime version="v2.0.50727"/></startup></configuration>