diff --git a/CUERipper/CUERipper.csproj b/CUERipper/CUERipper.csproj
index cd4e8fc..e140908 100644
--- a/CUERipper/CUERipper.csproj
+++ b/CUERipper/CUERipper.csproj
@@ -87,22 +87,12 @@
frmCUERipper.cs
-
- Form
-
-
- frmRelease.cs
-
Designer
frmCUERipper.cs
-
- Designer
- frmRelease.cs
-
ResXFileCodeGenerator
Resources.Designer.cs
@@ -111,6 +101,7 @@
True
Resources.resx
+ True
@@ -154,6 +145,15 @@
MusicBrainz
+
+
+
+
+
+
+
+
+
+
@@ -68,9 +69,10 @@
-
+
+
@@ -85,9 +87,10 @@
-
+
+
@@ -114,4 +117,14 @@
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ ..\musicbrainz.ico;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\cddb.ico;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\freedb.gif;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
\ No newline at end of file
diff --git a/CUERipper/frmCUERipper.Designer.cs b/CUERipper/frmCUERipper.Designer.cs
index d6fec31..e54d307 100644
--- a/CUERipper/frmCUERipper.Designer.cs
+++ b/CUERipper/frmCUERipper.Designer.cs
@@ -47,12 +47,13 @@ namespace CUERipper
this.buttonAbort = new System.Windows.Forms.Button();
this.buttonPause = new System.Windows.Forms.Button();
this.comboRelease = new System.Windows.Forms.ComboBox();
- this.releaseBindingSource = new System.Windows.Forms.BindingSource(this.components);
this.contextMenuStripRelease = new System.Windows.Forms.ContextMenuStrip(this.components);
this.editToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem();
+ this.releaseBindingSource = new System.Windows.Forms.BindingSource(this.components);
this.statusStrip1.SuspendLayout();
- ((System.ComponentModel.ISupportInitialize)(this.releaseBindingSource)).BeginInit();
this.contextMenuStripRelease.SuspendLayout();
+ ((System.ComponentModel.ISupportInitialize)(this.releaseBindingSource)).BeginInit();
this.SuspendLayout();
//
// comboDrives
@@ -84,6 +85,7 @@ namespace CUERipper
// toolStripProgressBar1
//
this.toolStripProgressBar1.AutoToolTip = true;
+ this.toolStripProgressBar1.MarqueeAnimationSpeed = 500;
this.toolStripProgressBar1.Name = "toolStripProgressBar1";
resources.ApplyResources(this.toolStripProgressBar1, "toolStripProgressBar1");
this.toolStripProgressBar1.Style = System.Windows.Forms.ProgressBarStyle.Continuous;
@@ -187,17 +189,16 @@ namespace CUERipper
// comboRelease
//
resources.ApplyResources(this.comboRelease, "comboRelease");
+ this.comboRelease.BackColor = System.Drawing.SystemColors.Control;
this.comboRelease.ContextMenuStrip = this.contextMenuStripRelease;
+ this.comboRelease.DrawMode = System.Windows.Forms.DrawMode.OwnerDrawFixed;
this.comboRelease.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.comboRelease.FormattingEnabled = true;
this.comboRelease.Name = "comboRelease";
+ this.comboRelease.DrawItem += new System.Windows.Forms.DrawItemEventHandler(this.comboRelease_DrawItem);
this.comboRelease.SelectedIndexChanged += new System.EventHandler(this.comboRelease_SelectedIndexChanged);
this.comboRelease.Format += new System.Windows.Forms.ListControlConvertEventHandler(this.comboRelease_Format);
//
- // releaseBindingSource
- //
- this.releaseBindingSource.DataSource = typeof(MusicBrainz.Release);
- //
// contextMenuStripRelease
//
this.contextMenuStripRelease.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
@@ -211,6 +212,16 @@ namespace CUERipper
resources.ApplyResources(this.editToolStripMenuItem, "editToolStripMenuItem");
this.editToolStripMenuItem.Click += new System.EventHandler(this.editToolStripMenuItem_Click);
//
+ // toolStripMenuItem1
+ //
+ this.toolStripMenuItem1.Image = global::CUERipper.Properties.Resources.cddb;
+ this.toolStripMenuItem1.Name = "toolStripMenuItem1";
+ resources.ApplyResources(this.toolStripMenuItem1, "toolStripMenuItem1");
+ //
+ // releaseBindingSource
+ //
+ this.releaseBindingSource.DataSource = typeof(MusicBrainz.Release);
+ //
// frmCUERipper
//
resources.ApplyResources(this, "$this");
@@ -232,8 +243,8 @@ namespace CUERipper
this.Load += new System.EventHandler(this.frmCUERipper_Load);
this.statusStrip1.ResumeLayout(false);
this.statusStrip1.PerformLayout();
- ((System.ComponentModel.ISupportInitialize)(this.releaseBindingSource)).EndInit();
this.contextMenuStripRelease.ResumeLayout(false);
+ ((System.ComponentModel.ISupportInitialize)(this.releaseBindingSource)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
@@ -261,6 +272,7 @@ namespace CUERipper
private System.Windows.Forms.BindingSource releaseBindingSource;
private System.Windows.Forms.ContextMenuStrip contextMenuStripRelease;
private System.Windows.Forms.ToolStripMenuItem editToolStripMenuItem;
+ private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem1;
}
}
diff --git a/CUERipper/frmCUERipper.cs b/CUERipper/frmCUERipper.cs
index 2d4471f..7591f27 100644
--- a/CUERipper/frmCUERipper.cs
+++ b/CUERipper/frmCUERipper.cs
@@ -37,11 +37,24 @@ namespace CUERipper
_startStop = new StartStop();
}
+ //private byte toBCD(int val)
+ //{
+ // return (byte)(((val / 10) << 4) + (val % 10));
+ //}
+
private void frmCUERipper_Load(object sender, EventArgs e)
{
- //byte[] _subchannelBuffer0 = { 0x1, 0x01, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x02, 0x10, 0x75, 0x4E };
+ //byte[] _subchannelBuffer0 = { 0x01, 0x01, 0x01, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x02, 0x0A, 0x4C, 0x43 };
//byte[] _subchannelBuffer1 = { 0x21, 0x01, 0x01, 0x00, 0x00, 0x11, 0x00, 0x00, 0x02, 0x11, 0xCF, 0x3E };
//byte[] _subchannelBuffer2 = { 0x21, 0x01, 0x01, 0x00, 0x00, 0x12, 0x00, 0x00, 0x02, 0x12, 0x11, 0x8F };
+
+ //_subchannelBuffer0[3] = toBCD(_subchannelBuffer0[3]);
+ //_subchannelBuffer0[4] = toBCD(_subchannelBuffer0[4]);
+ //_subchannelBuffer0[5] = toBCD(_subchannelBuffer0[5]);
+ //_subchannelBuffer0[7] = toBCD(_subchannelBuffer0[7]);
+ //_subchannelBuffer0[8] = toBCD(_subchannelBuffer0[8]);
+ //_subchannelBuffer0[9] = toBCD(_subchannelBuffer0[9]);
+
//Crc16Ccitt _crc = new Crc16Ccitt(InitialCrcValue.Zeros);
//ushort crc0a = (ushort)(_crc.ComputeChecksum(_subchannelBuffer0, 0, 10) ^ 0xffff);
//ushort crc0b = (ushort)(_subchannelBuffer0[11] + (_subchannelBuffer0[10] << 8));
@@ -49,21 +62,25 @@ namespace CUERipper
//ushort crc1b = (ushort)(_subchannelBuffer1[11] + (_subchannelBuffer1[10] << 8));
//ushort crc2a = (ushort)(_crc.ComputeChecksum(_subchannelBuffer2, 0, 10) ^ 0xffff);
//ushort crc2b = (ushort)(_subchannelBuffer2[11] + (_subchannelBuffer2[10] << 8));
- //if (crc0a != crc0b || crc1a != crc1b || crc2a != crc2b)
+ //if (crc0a != crc0b) // || crc1a != crc1b || crc2a != crc2b)
//{
//}
foreach(char drive in CDDriveReader.DrivesAvailable())
{
CDDriveReader reader = new CDDriveReader();
- if (reader.Open(drive))
+ int driveOffset;
+ try
{
- int driveOffset;
- if (!AccurateRipVerify.FindDriveReadOffset(reader.ARName, out driveOffset))
- ; //throw new Exception("Failed to find drive read offset for drive" + _ripper.ARName);
- reader.DriveOffset = driveOffset;
- comboDrives.Items.Add(reader);
+ reader.Open(drive);
}
+ catch
+ {
+ }
+ if (!AccurateRipVerify.FindDriveReadOffset(reader.ARName, out driveOffset))
+ ; //throw new Exception("Failed to find drive read offset for drive" + _ripper.ARName);
+ reader.DriveOffset = driveOffset;
+ comboDrives.Items.Add(reader);
}
if (comboDrives.Items.Count == 0)
comboDrives.Items.Add("No CD drives found");
@@ -119,9 +136,15 @@ namespace CUERipper
this.BeginInvoke((MethodInvoker)delegate()
{
+ //Color color = ColorTranslator.FromWin32(e.ErrorsCount == 0 || e.Position == 0 ? (byte)0 : (byte)(Math.Log(1 + e.ErrorsCount / e.Position, 2) * 255));
toolStripStatusLabel1.Text = status;
toolStripProgressBar1.Value = Math.Max(0, Math.Min(100, (int)(percentTrck * 100)));
+ //toolStripProgressBar1.ProgressBar.Style = ProgressBarStyle.Blocks;
toolStripProgressBar2.Value = Math.Max(0, Math.Min(100, (int)(percentDisk * 100)));
+ //if (e.ErrorsCount == 0 || e.Position == 0)
+ //toolStripProgressBar3.Value = 0;
+ //else
+ //toolStripProgressBar3.Value = Math.Min(100, (int)(100 + Math.Log10(e.ErrorsCount / e.Position / 4 / 588) * 100));
});
}
@@ -130,11 +153,11 @@ namespace CUERipper
CDDriveReader audioSource = (CDDriveReader)o;
audioSource.ReadProgress += new EventHandler(CDReadProgress);
- CUESheet.WriteText(_pathOut, _cueSheet.CUESheetContents(_style));
- CUESheet.WriteText(Path.ChangeExtension(_pathOut, ".log"), _cueSheet.LOGContents());
try
{
_cueSheet.WriteAudioFiles(".", _style);
+ //CUESheet.WriteText(_pathOut, _cueSheet.CUESheetContents(_style));
+ //CUESheet.WriteText(Path.ChangeExtension(_pathOut, ".log"), _cueSheet.LOGContents());
}
catch (StopException)
{
@@ -197,8 +220,8 @@ namespace CUERipper
{
if (e.ListItem is string)
return;
- CUELine date = General.FindCUELine(((CUESheet)e.ListItem).Attributes, "REM", "DATE");
- e.Value = string.Format("{0}{1} - {2}", date != null ? date.Params[2] + ": " : "", ((CUESheet)e.ListItem).Artist, ((CUESheet)e.ListItem).Title);
+ ReleaseInfo r = (ReleaseInfo)(e.ListItem);
+ e.Value = string.Format("{0}{1} - {2}", r.cueSheet.Year != "" ? r.cueSheet.Year + ": " : "", r.cueSheet.Artist, r.cueSheet.Title);
}
private void comboRelease_SelectedIndexChanged(object sender, EventArgs e)
@@ -206,7 +229,7 @@ namespace CUERipper
listTracks.Items.Clear();
if (comboRelease.SelectedItem == null || comboRelease.SelectedItem is string)
return;
- _cueSheet = (CUESheet)comboRelease.SelectedItem;
+ _cueSheet = ((ReleaseInfo)comboRelease.SelectedItem).cueSheet;
for (int i = 1; i <= _reader.TOC.AudioTracks; i++)
listTracks.Items.Add(new ListViewItem(new string[] {
_cueSheet.Tracks[i-1].Title,
@@ -238,39 +261,39 @@ namespace CUERipper
}
this.BeginInvoke((MethodInvoker)delegate()
{
- toolStripStatusLabel1.Text = "Looking up album via MusicBrainz";
+ toolStripStatusLabel1.Text = "Looking up album via " + (e == null ? "FreeDB" : "MusicBrainz");
toolStripProgressBar1.Value = 0;
- toolStripProgressBar2.Value = (100 + toolStripProgressBar2.Value) / 2;
+ toolStripProgressBar2.Value = (100 + 2 * toolStripProgressBar2.Value) / 3;
});
}
- private CUESheet CreateCUESheet(CDDriveReader audioSource, Release release, CDEntry cdEntry)
+ private ReleaseInfo CreateCUESheet(CDDriveReader audioSource, Release release, CDEntry cdEntry)
{
- CUESheet cueSheet = new CUESheet(_config);
- cueSheet.OpenCD(audioSource);
- General.SetCUELine(cueSheet.Attributes, "REM", "DISCID", AccurateRipVerify.CalculateCDDBId(audioSource.TOC), false);
- General.SetCUELine(cueSheet.Attributes, "REM", "COMMENT", CDDriveReader.RipperVersion(), true);
+ ReleaseInfo r = new ReleaseInfo();
+ r.cueSheet = new CUESheet(_config);
+ r.cueSheet.OpenCD(audioSource);
+ General.SetCUELine(r.cueSheet.Attributes, "REM", "DISCID", AccurateRipVerify.CalculateCDDBId(audioSource.TOC), false);
+ General.SetCUELine(r.cueSheet.Attributes, "REM", "COMMENT", CDDriveReader.RipperVersion(), true);
if (release != null)
- cueSheet.FillFromMusicBrainz(release);
+ {
+ r.cueSheet.FillFromMusicBrainz(release);
+ r.bitmap = Properties.Resources.musicbrainz;
+ }
else if (cdEntry != null)
{
- cueSheet.Artist = cdEntry.Artist;
- cueSheet.Title = cdEntry.Title;
- General.SetCUELine(cueSheet.Attributes, "REM", "DATE", cdEntry.Year, false);
- General.SetCUELine(cueSheet.Attributes, "REM", "GENRE", cdEntry.Genre, true);
- for (int i = 0; i < audioSource.TOC.AudioTracks; i++)
- cueSheet.Tracks[i].Title = cdEntry.Tracks[i].Title;
+ r.cueSheet.FillFromFreedb(cdEntry);
+ r.bitmap = Properties.Resources.freedb;
}
else
{
- cueSheet.Artist = "Unknown Artist";
- cueSheet.Title = "Unknown Title";
+ r.cueSheet.Artist = "Unknown Artist";
+ r.cueSheet.Title = "Unknown Title";
for (int i = 0; i < audioSource.TOC.AudioTracks; i++)
- cueSheet.Tracks[i].Title = string.Format("Track {0:00}", i + 1);
+ r.cueSheet.Tracks[i].Title = string.Format("Track {0:00}", i + 1);
}
- cueSheet.AccurateRip = AccurateRipMode.VerifyAndConvert;
- cueSheet.ArVerify.ContactAccurateRip(AccurateRipVerify.CalculateAccurateRipId(audioSource.TOC));
- return cueSheet;
+ r.cueSheet.AccurateRip = AccurateRipMode.VerifyAndConvert;
+ r.cueSheet.ArVerify.ContactAccurateRip(AccurateRipVerify.CalculateAccurateRipId(audioSource.TOC));
+ return r;
}
private void Lookup(object o)
@@ -287,10 +310,10 @@ namespace CUERipper
{
release.GetEvents();
release.GetTracks();
- CUESheet cueSheet = CreateCUESheet(audioSource, release, null);
+ ReleaseInfo r = CreateCUESheet(audioSource, release, null);
this.BeginInvoke((MethodInvoker)delegate()
{
- comboRelease.Items.Add(cueSheet);
+ comboRelease.Items.Add(r);
});
}
}
@@ -313,17 +336,19 @@ namespace CUERipper
string code = string.Empty;
try
{
+ MusicBrainz_LookupProgress(this, null);
code = m_freedb.Query(AccurateRipVerify.CalculateCDDBQuery(audioSource.TOC), out queryResult, out coll);
if (code == FreedbHelper.ResponseCodes.CODE_200)
{
CDEntry cdEntry;
+ MusicBrainz_LookupProgress(this, null);
code = m_freedb.Read(queryResult, out cdEntry);
if (code == FreedbHelper.ResponseCodes.CODE_210)
{
- CUESheet cueSheet = CreateCUESheet(audioSource, null, cdEntry);
+ ReleaseInfo r = CreateCUESheet(audioSource, null, cdEntry);
this.BeginInvoke((MethodInvoker)delegate()
{
- comboRelease.Items.Add(cueSheet);
+ comboRelease.Items.Add(r);
});
}
}
@@ -334,13 +359,14 @@ namespace CUERipper
foreach (QueryResult qr in coll)
{
CDEntry cdEntry;
+ MusicBrainz_LookupProgress(this, null);
code = m_freedb.Read(qr, out cdEntry);
if (code == FreedbHelper.ResponseCodes.CODE_210)
{
- CUESheet cueSheet = CreateCUESheet(audioSource, null, cdEntry);
+ ReleaseInfo r = CreateCUESheet(audioSource, null, cdEntry);
this.BeginInvoke((MethodInvoker)delegate()
{
- comboRelease.Items.Add(cueSheet);
+ comboRelease.Items.Add(r);
});
}
}
@@ -354,8 +380,8 @@ namespace CUERipper
{
if (comboRelease.Items.Count == 0)
{
- CUESheet cueSheet = CreateCUESheet(audioSource, null, null);
- comboRelease.Items.Add(cueSheet);
+ ReleaseInfo r = CreateCUESheet(audioSource, null, null);
+ comboRelease.Items.Add(r);
}
});
_workThread = null;
@@ -373,9 +399,21 @@ namespace CUERipper
if (comboDrives.SelectedItem is string)
return;
_reader = (CDDriveReader)comboDrives.SelectedItem;
+ try
+ {
+ _reader.Open(_reader.Path[0]);
+ }
+ catch (Exception ex)
+ {
+ _reader.Close();
+ comboRelease.Items.Add(ex.Message);
+ comboRelease.SelectedIndex = 0;
+ return;
+ }
if (_reader.TOC.AudioTracks == 0)
{
comboRelease.Items.Add("No audio tracks");
+ comboRelease.SelectedIndex = 0;
return;
}
comboRelease_SelectedIndexChanged(sender, e);
@@ -415,18 +453,37 @@ namespace CUERipper
private void listTracks_AfterLabelEdit(object sender, LabelEditEventArgs e)
{
- CUESheet cueSheet = (CUESheet)comboRelease.SelectedItem;
+ CUESheet cueSheet = ((ReleaseInfo)comboRelease.SelectedItem).cueSheet;
if (e.Label != null)
cueSheet.Tracks[e.Item].Title = e.Label;
}
private void editToolStripMenuItem_Click(object sender, EventArgs e)
{
- CUESheet cueSheet = (CUESheet)comboRelease.SelectedItem;
- frmRelease frm = new frmRelease();
+ CUESheet cueSheet = ((ReleaseInfo)comboRelease.SelectedItem).cueSheet;
+ frmProperties frm = new frmProperties();
frm.CUE = cueSheet;
frm.ShowDialog();
- comboRelease.Items[comboRelease.SelectedIndex] = cueSheet;
+ }
+
+ private void comboRelease_DrawItem(object sender, DrawItemEventArgs e)
+ {
+ e.DrawBackground();
+ StringFormat format = new StringFormat();
+ format.FormatFlags = StringFormatFlags.NoClip;
+ format.Alignment = StringAlignment.Near;
+ if (e.Index >= 0 && e.Index < comboRelease.Items.Count)
+ {
+ string text = comboRelease.GetItemText(comboRelease.Items[e.Index]);
+ if (comboRelease.Items[e.Index] is ReleaseInfo)
+ {
+ Bitmap ImageToDraw = ((ReleaseInfo)comboRelease.Items[e.Index]).bitmap;
+ e.Graphics.DrawImage(ImageToDraw, new Rectangle(e.Bounds.X, e.Bounds.Y, e.Bounds.Height, e.Bounds.Height));
+ //e.Graphics.DrawImage(ImageToDraw, new Rectangle(e.Bounds.X + e.Bounds.Width - ImageToDraw.Width, e.Bounds.Y, ImageToDraw.Width, e.Bounds.Height));
+ }
+ e.Graphics.DrawString(text, e.Font, new SolidBrush(e.ForeColor), new RectangleF((float)e.Bounds.X + e.Bounds.Height, (float)e.Bounds.Y, (float)(e.Bounds.Width - e.Bounds.Height), (float)e.Bounds.Height), format);
+ }
+ e.DrawFocusRectangle();
}
}
@@ -468,4 +525,10 @@ namespace CUERipper
}
}
}
+
+ class ReleaseInfo
+ {
+ public CUESheet cueSheet;
+ public Bitmap bitmap;
+ }
}
diff --git a/CUERipper/frmCUERipper.resx b/CUERipper/frmCUERipper.resx
index 5dfde32..e1d3e1c 100644
--- a/CUERipper/frmCUERipper.resx
+++ b/CUERipper/frmCUERipper.resx
@@ -147,6 +147,24 @@
0, 371
+
+ 169, 17
+
+
+ MiddleLeft
+
+
+ 140, 16
+
+
+ Track progress
+
+
+ 140, 16
+
+
+ Disk progress
+
0, 371
@@ -171,48 +189,9 @@
9
-
- 200, 17
-
-
- MiddleLeft
-
-
- 140, 16
-
-
- Track progress
-
-
- 140, 16
-
-
- Disk progress
-
Top, Left, Right
-
- 6, 60
-
-
- 481, 269
-
-
- 0
-
-
- listTracks
-
-
- System.Windows.Forms.ListView, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
-
- $this
-
-
- 8
-
1
@@ -243,9 +222,33 @@
70
+
+ 6, 60
+
+
+ 481, 269
+
+
+ 0
+
+
+ listTracks
+
+
+ System.Windows.Forms.ListView, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ $this
+
+
+ 8
+
Top, Left, Right
+
+ NoControl
+
396, 335
@@ -433,7 +436,7 @@
285, 58
- 152, 22
+ 94, 22
Edit
@@ -468,6 +471,12 @@
1
+
+ 181, 22
+
+
+ toolStripMenuItem1
+
116, 371
@@ -528,18 +537,24 @@
System.Windows.Forms.ColumnHeader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
- releaseBindingSource
-
-
- System.Windows.Forms.BindingSource, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
editToolStripMenuItem
System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+ toolStripMenuItem1
+
+
+ System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ releaseBindingSource
+
+
+ System.Windows.Forms.BindingSource, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
frmCUERipper
diff --git a/CUETools.AccurateRip/AccurateRip.cs b/CUETools.AccurateRip/AccurateRip.cs
index 7014e7f..1246678 100644
--- a/CUETools.AccurateRip/AccurateRip.cs
+++ b/CUETools.AccurateRip/AccurateRip.cs
@@ -16,6 +16,7 @@ namespace CUETools.AccurateRip
{
_toc = toc;
_accDisks = new List();
+ _crc32 = new Crc32();
Init();
}
@@ -23,7 +24,11 @@ namespace CUETools.AccurateRip
{
fixed (uint* CRCsA = &_offsetedCRC[Math.Max(0, iTrack - 1), 0],
CRCsB = &_offsetedCRC[iTrack, 0],
- CRCsC = &_offsetedCRC[Math.Min(_toc.AudioTracks - 1, iTrack + 1), 0])
+ CRCsC = &_offsetedCRC[Math.Min(_toc.AudioTracks - 1, iTrack + 1), 0]
+ //CRC32A = &_offsetedCRC32[Math.Max(0, iTrack - 1), 0],
+ //CRC32B = &_offsetedCRC32[iTrack, 0],
+ //CRC32C = &_offsetedCRC32[Math.Min(_toc.AudioTracks - 1, iTrack + 1), 0]
+ )
{
for (uint si = 0; si < count; si++)
{
@@ -31,24 +36,27 @@ namespace CUETools.AccurateRip
int i;
int iB = Math.Max(0, _arOffsetRange - (int)(currentOffset + si));
int iC = Math.Min(2 * _arOffsetRange + 1, _arOffsetRange + (int)trackLength - (int)(currentOffset + si));
-
+
uint baseSumA = sampleValue * (uint)(previousOffset + 1 - iB);
for (i = 0; i < iB; i++)
{
CRCsA[i] += baseSumA;
baseSumA += sampleValue;
+ //CRC32A[i] = _crc32.ComputeChecksum(CRC32A[i], sampleValue);
}
uint baseSumB = sampleValue * (uint)Math.Max(1, (int)(currentOffset + si) - _arOffsetRange + 1);
for (i = iB; i < iC; i++)
{
CRCsB[i] += baseSumB;
baseSumB += sampleValue;
+ //CRC32B[i] = _crc32.ComputeChecksum(CRC32B[i], sampleValue);
}
uint baseSumC = sampleValue;
for (i = iC; i <= 2 * _arOffsetRange; i++)
{
CRCsC[i] += baseSumC;
baseSumC += sampleValue;
+ //CRC32C[i] = _crc32.ComputeChecksum(CRC32C[i], sampleValue);
}
}
return;
@@ -60,6 +68,7 @@ namespace CUETools.AccurateRip
for (int si = 0; si < count; si++)
{
uint sampleValue = (uint)((samples[2 * si] & 0xffff) + (samples[2 * si + 1] << 16));
+
for (int oi = -_arOffsetRange; oi <= _arOffsetRange; oi++)
{
int iTrack2 = iTrack;
@@ -88,6 +97,7 @@ namespace CUETools.AccurateRip
currentOffset2 -= (int)trackLength;
}
_offsetedCRC[iTrack2, _arOffsetRange - oi] += sampleValue * (uint)(currentOffset2 + 1);
+ //_offsetedCRC32[iTrack2, _arOffsetRange - oi] = _crc32.ComputeChecksum(_offsetedCRC32[iTrack2, _arOffsetRange - oi], sampleValue);
}
}
}
@@ -121,6 +131,7 @@ namespace CUETools.AccurateRip
{
CRCs[i] += baseSum;
baseSum -= stepSum;
+ //CRC32[i] = _crc32.ComputeChecksum (CRC32[i], samples, count);
}
}
}
@@ -140,6 +151,11 @@ namespace CUETools.AccurateRip
return _offsetedCRC[iTrack, _arOffsetRange - oi];
}
+ public uint CRC32(int iTrack)
+ {
+ return _offsetedCRC32[iTrack] ^ 0xffffffff;
+ }
+
public uint CRC450(int iTrack, int oi)
{
return _offsetedFrame450CRC[iTrack, _arOffsetRange - oi];
@@ -150,11 +166,11 @@ namespace CUETools.AccurateRip
for (uint pos = 0; pos < sampleCount; )
{
uint copyCount = Math.Min(sampleCount - pos, (uint)_samplesRemTrack);
- if (_currentTrack != 0)
+ unsafe
{
- unsafe
+ fixed (int* pSampleBuff = &sampleBuffer[pos, 0])
{
- fixed (int* pSampleBuff = &sampleBuffer[pos, 0])
+ if (_currentTrack != 0)
{
uint trackLength = _toc[_currentTrack].Length * 588;
uint currentOffset = (uint)_sampleCount - _toc[_currentTrack].Start * 588;
@@ -171,7 +187,10 @@ namespace CUETools.AccurateRip
CalculateAccurateRipCRCs(pSampleBuff + si2 * 2, copyCount - si2, _currentTrack - 1, currentOffset + si2, previousOffset, trackLength);
else
CalculateAccurateRipCRCsSemifast(pSampleBuff + si2 * 2, copyCount - si2, _currentTrack - 1, currentOffset + si2, previousOffset, trackLength);
+
+ _offsetedCRC32[_currentTrack] = _crc32.ComputeChecksum(_offsetedCRC32[_currentTrack], pSampleBuff, copyCount);
}
+ _offsetedCRC32[0] = _crc32.ComputeChecksum(_offsetedCRC32[0], pSampleBuff, copyCount);
}
}
pos += copyCount;
@@ -185,6 +204,9 @@ namespace CUETools.AccurateRip
{
_offsetedCRC = new uint[_toc.AudioTracks, 10 * 588];
_offsetedFrame450CRC = new uint[_toc.AudioTracks, 10 * 588];
+ _offsetedCRC32 = new uint[_toc.AudioTracks + 1];
+ for (int i = 0; i <= _toc.AudioTracks; i++)
+ _offsetedCRC32[i] = 0xffffffff;
_currentTrack = 0;
_sampleCount = 0;
_samplesRemTrack = _toc.Pregap * 588;
@@ -413,6 +435,14 @@ namespace CUETools.AccurateRip
}
}
}
+ if (CRC32(0) != 0)
+ {
+ sw.WriteLine("");
+ sw.WriteLine("Track\t[ CRC32 ]");
+ sw.WriteLine(String.Format(" --\t[{0:X8}]", CRC32(0)));
+ for (int iTrack = 1; iTrack <= _toc.AudioTracks; iTrack++)
+ sw.WriteLine(String.Format(" {0:00}\t[{1:X8}]", iTrack, CRC32(iTrack)));
+ }
}
private static uint sumDigits(uint n)
@@ -505,8 +535,8 @@ namespace CUETools.AccurateRip
{
uint cddbDiscId = 0;
for (int iTrack = 1; iTrack <= toc.TrackCount; iTrack++)
- cddbDiscId += sumDigits(toc[iTrack].Start / 75 + 2);
- return string.Format("{0:X8}", ((cddbDiscId << 24) + ((toc.Length / 75 - toc[1].Start / 75) << 8) + (uint)toc.TrackCount) & 0xFFFFFFFF);
+ cddbDiscId += sumDigits(toc[iTrack].Start / 75 + 2); // !!!!!!!!!!!!!!!!! %255 !!
+ return string.Format("{0:X8}", (((cddbDiscId % 255) << 24) + ((toc.Length / 75 - toc[1].Start / 75) << 8) + (uint)toc.TrackCount) & 0xFFFFFFFF);
}
public static string CalculateAccurateRipId(CDImageLayout toc)
@@ -560,8 +590,11 @@ namespace CUETools.AccurateRip
private HttpStatusCode _accResult;
private uint[,] _offsetedCRC;
private uint[,] _offsetedFrame450CRC;
+ private uint[] _offsetedCRC32;
private uint[] _backupCRC;
+ Crc32 _crc32;
+
private const int _arOffsetRange = 5 * 588 - 1;
}
diff --git a/CUETools.Codecs.ALAC/ALACDotNet.cs b/CUETools.Codecs.ALAC/ALACDotNet.cs
index 04da71c..32cef67 100644
--- a/CUETools.Codecs.ALAC/ALACDotNet.cs
+++ b/CUETools.Codecs.ALAC/ALACDotNet.cs
@@ -41,6 +41,11 @@ namespace CUETools.Codecs.ALAC
_saved_mdat_pos = _IO.Position;
}
+ public int[,] Read(int[,] buff)
+ {
+ return AudioSamples.Read(this, buff);
+ }
+
public uint Read(int[,] buff, uint sampleCount)
{
if (_predicterror_buffer_a == null)
diff --git a/CUETools.Codecs.APE/CUETools.Codecs.APE.cpp b/CUETools.Codecs.APE/CUETools.Codecs.APE.cpp
index 6542b91..bf3a6c2 100644
--- a/CUETools.Codecs.APE/CUETools.Codecs.APE.cpp
+++ b/CUETools.Codecs.APE/CUETools.Codecs.APE.cpp
@@ -239,6 +239,11 @@ namespace CUETools { namespace Codecs { namespace APE {
return true;
}
+ virtual array^ Read(array^ buff)
+ {
+ return AudioSamples::Read(this, buff);
+ }
+
virtual UInt32 Read([Out] array^ buff, UInt32 sampleCount)
{
UInt32 buffOffset = 0;
diff --git a/CUETools.Codecs.FLAC/CUETools.Codecs.FLAC.cpp b/CUETools.Codecs.FLAC/CUETools.Codecs.FLAC.cpp
index eb88772..02ba34d 100644
--- a/CUETools.Codecs.FLAC/CUETools.Codecs.FLAC.cpp
+++ b/CUETools.Codecs.FLAC/CUETools.Codecs.FLAC.cpp
@@ -265,6 +265,11 @@ namespace CUETools { namespace Codecs { namespace FLAC {
}
}
+ virtual array^ Read(array^ buff)
+ {
+ return AudioSamples::Read(this, buff);
+ }
+
virtual UInt32 Read([Out] array^ buff, UInt32 sampleCount)
{
UInt32 buffOffset = 0;
diff --git a/CUETools.Codecs.LossyWAV/LossyWAV.cs b/CUETools.Codecs.LossyWAV/LossyWAV.cs
index 0784e74..0e42589 100644
--- a/CUETools.Codecs.LossyWAV/LossyWAV.cs
+++ b/CUETools.Codecs.LossyWAV/LossyWAV.cs
@@ -901,6 +901,11 @@ namespace CUETools.Codecs.LossyWAV
scaling_factor = 1.0; // !!!! Need to read 'fact' chunks or tags here
}
+ public int[,] Read(int[,] buff)
+ {
+ return AudioSamples.Read(this, buff);
+ }
+
public uint Read(int[,] buff, uint sampleCount)
{
if (sampleBuffer == null || sampleBuffer.Length < sampleCount)
diff --git a/CUETools.Codecs.TTA/CUETools.Codecs.TTA.cpp b/CUETools.Codecs.TTA/CUETools.Codecs.TTA.cpp
index 8d8e10e..7878f61 100644
--- a/CUETools.Codecs.TTA/CUETools.Codecs.TTA.cpp
+++ b/CUETools.Codecs.TTA/CUETools.Codecs.TTA.cpp
@@ -4,9 +4,12 @@
#include "CUETools.Codecs.TTA.h"
+using namespace APETagsDotNet;
+
typedef void * HANDLE;
#include "../TTALib-1.1/TTAReader.h"
+#include "../TTALib-1.1/TTAWriter.h"
#include "../TTALib-1.1/TTAError.h"
namespace CUETools {
@@ -31,7 +34,7 @@ namespace TTA {
public:
TTAReader(String^ path, Stream^ IO)
{
- _tags = gcnew NameValueCollection();
+ _tags = nullptr;
_sampleOffset = 0;
_sampleBuffer = nullptr;
_path = path;
@@ -127,6 +130,12 @@ namespace TTA {
virtual property NameValueCollection^ Tags {
NameValueCollection^ get () {
+ if (!_tags)
+ {
+ APETagDotNet^ apeTag = gcnew APETagDotNet (_IO, true);
+ _tags = apeTag->GetStringTags (true);
+ apeTag->Close ();
+ }
return _tags;
}
void set (NameValueCollection ^tags) {
@@ -136,7 +145,12 @@ namespace TTA {
virtual bool UpdateTags (bool preserveTime)
{
- return false;
+ Close ();
+ APETagDotNet^ apeTag = gcnew APETagDotNet (_path, true, false);
+ apeTag->SetStringTags (_tags, true);
+ apeTag->Save();
+ apeTag->Close();
+ return true;
}
virtual property UInt64 Remaining {
@@ -193,7 +207,14 @@ namespace TTA {
do
{
long * buf;
- int samplesInBuf = _ttaReader->GetBlock(&buf);
+ int samplesInBuf;
+ try
+ {
+ samplesInBuf = _ttaReader->GetBlock(&buf);
+ } catch (TTALib::TTAException ex)
+ {
+ throw gcnew Exception(String::Format("TTA decoder: {0}", gcnew String(TTAErrorsStr[ex.GetErrNo()])));
+ }
if (samplesInBuf == 0)
throw gcnew Exception("An error occurred while decoding.");
processBlock (buf, samplesInBuf);
@@ -227,6 +248,247 @@ namespace TTA {
}
}
};
+
+ public ref class TTAWriter : IAudioDest
+ {
+ public:
+ TTAWriter(String^ path, Int32 bitsPerSample, Int32 channelCount, Int32 sampleRate)
+ {
+ if (bitsPerSample < 16 || bitsPerSample > 24)
+ throw gcnew Exception("Bits per sample must be 16..24.");
+
+ _initialized = false;
+ _sampleBuffer = nullptr;
+ _path = path;
+ _finalSampleCount = 0;
+ _samplesWritten = 0;
+ _bitsPerSample = bitsPerSample;
+ _channelCount = channelCount;
+ _sampleRate = sampleRate;
+ _compressionLevel = 5;
+ _blockSize = 0;
+ _tags = gcnew NameValueCollection();
+ }
+
+ virtual void Close() {
+ //FLAC__stream_encoder_finish(_encoder);
+ //for (int i = 0; i < _metadataCount; i++) {
+ // FLAC__metadata_object_delete(_metadataList[i]);
+ //}
+
+ if (_ttaWriter)
+ {
+ try
+ {
+ delete _ttaWriter;
+ } catch (TTALib::TTAException ex)
+ {
+ _ttaWriter = nullptr;
+ throw gcnew Exception(String::Format("TTA encoder: {0}", gcnew String(TTAErrorsStr[ex.GetErrNo()])));
+ }
+ _ttaWriter = nullptr;
+ }
+
+ if (_IO)
+ _IO->Close();
+
+ if (_tags->Count > 0)
+ {
+ APETagDotNet^ apeTag = gcnew APETagDotNet (_path, true, false);
+ apeTag->SetStringTags (_tags, true);
+ apeTag->Save();
+ apeTag->Close();
+ _tags->Clear ();
+ }
+
+ if ((_finalSampleCount != 0) && (_samplesWritten != _finalSampleCount)) {
+ throw gcnew Exception("Samples written differs from the expected sample count.");
+ }
+ _tags->Clear ();
+ }
+
+ virtual void Delete()
+ {
+ try { Close (); } catch (Exception^) {}
+ File::Delete(_path);
+ }
+
+ virtual property Int64 FinalSampleCount {
+ Int64 get() {
+ 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.");
+ }
+ _finalSampleCount = value;
+ }
+ }
+
+ virtual property Int64 BlockSize
+ {
+ void set(Int64 value)
+ {
+ _blockSize = value;
+ }
+ }
+
+ virtual property int BitsPerSample
+ {
+ int get() { return _bitsPerSample; }
+ }
+
+ virtual bool SetTags (NameValueCollection^ tags)
+ {
+ _tags = tags;
+ return true;
+ }
+
+ virtual property String^ Path {
+ String^ get() {
+ return _path;
+ }
+ }
+
+ virtual void Write(array^ sampleBuffer, UInt32 sampleCount) {
+ if (!_initialized) Initialize();
+
+ if ((_sampleBuffer == nullptr) || (_sampleBuffer->Length < sampleCount * _channelCount))
+ _sampleBuffer = gcnew array (sampleCount * _channelCount);
+
+ interior_ptr pSampleBuffer = &sampleBuffer[0, 0];
+ interior_ptr pTTABuffer = &_sampleBuffer[0];
+ for (int i = 0; i < sampleCount * _channelCount; i++)
+ pTTABuffer[i] = pSampleBuffer[i];
+
+ pin_ptr buffer = &_sampleBuffer[0];
+ try
+ {
+ _ttaWriter->CompressBlock(buffer, sampleCount);
+ } catch (TTALib::TTAException ex)
+ {
+ throw gcnew Exception(String::Format("TTA encoder: {0}", gcnew String(TTAErrorsStr[ex.GetErrNo()])));
+ }
+
+ _samplesWritten += sampleCount;
+ }
+
+ property Int32 CompressionLevel {
+ Int32 get() {
+ return _compressionLevel;
+ }
+ void set(Int32 value) {
+ if ((value < 0) || (value > 8)) {
+ throw gcnew Exception("Invalid compression level.");
+ }
+ _compressionLevel = value;
+ }
+ }
+
+ private:
+ TTALib::TTAWriter* _ttaWriter;
+ FileStream^ _IO;
+ array^ _sampleBuffer;
+ bool _initialized;
+ String^ _path;
+ Int64 _finalSampleCount, _samplesWritten, _blockSize;
+ Int32 _bitsPerSample, _channelCount, _sampleRate;
+ Int32 _compressionLevel;
+ NameValueCollection^ _tags;
+
+ void Initialize()
+ {
+ if (!_finalSampleCount)
+ throw gcnew Exception("FinalSampleCount not set.");
+
+ //FLAC__StreamMetadata *padding, *seektable, *vorbiscomment;
+
+ //_metadataList = new FLAC__StreamMetadata*[8];
+ //_metadataCount = 0;
+
+ //if (_finalSampleCount != 0) {
+ // seektable = FLAC__metadata_object_new(FLAC__METADATA_TYPE_SEEKTABLE);
+ // FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(
+ // seektable, _sampleRate * 10, _finalSampleCount);
+ // FLAC__metadata_object_seektable_template_sort(seektable, true);
+ // _metadataList[_metadataCount++] = seektable;
+ //}
+
+ //vorbiscomment = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+ //for (int tagno = 0; tagno < _tags->Count; tagno++)
+ //{
+ // String ^ tag_name = _tags->GetKey(tagno);
+ // int tag_len = tag_name->Length;
+ // char * tag = new char [tag_len + 1];
+ // IntPtr nameChars = Marshal::StringToHGlobalAnsi(tag_name);
+ // memcpy (tag, (const char*)nameChars.ToPointer(), tag_len);
+ // Marshal::FreeHGlobal(nameChars);
+ // tag[tag_len] = 0;
+
+ // array^ tag_values = _tags->GetValues(tagno);
+ // for (int valno = 0; valno < tag_values->Length; valno++)
+ // {
+ // UTF8Encoding^ enc = gcnew UTF8Encoding();
+ // array^ value_array = enc->GetBytes (tag_values[valno]);
+ // int value_len = value_array->Length;
+ // char * value = new char [value_len + 1];
+ // Marshal::Copy (value_array, 0, (IntPtr) value, value_len);
+ // value[value_len] = 0;
+
+ // FLAC__StreamMetadata_VorbisComment_Entry entry;
+ // /* create and entry and append it */
+ // if(!FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, tag, value)) {
+ // throw gcnew Exception("Unable to add tags, must be valid utf8.");
+ // }
+ // if(!FLAC__metadata_object_vorbiscomment_append_comment(vorbiscomment, entry, /*copy=*/false)) {
+ // throw gcnew Exception("Unable to add tags.");
+ // }
+ // delete [] value;
+ // }
+ // delete [] tag;
+ //}
+ //_metadataList[_metadataCount++] = vorbiscomment;
+
+ //if (_paddingLength != 0) {
+ // padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING);
+ // padding->length = _paddingLength;
+ // _metadataList[_metadataCount++] = padding;
+ //}
+
+ //FLAC__stream_encoder_set_metadata(_encoder, _metadataList, _metadataCount);
+
+ //FLAC__stream_encoder_set_verify(_encoder, _verify);
+
+ //if (_finalSampleCount != 0) {
+ // FLAC__stream_encoder_set_total_samples_estimate(_encoder, _finalSampleCount);
+ //}
+
+ //FLAC__stream_encoder_set_compression_level(_encoder, _compressionLevel);
+
+ //if (_blockSize > 0)
+ // FLAC__stream_encoder_set_blocksize(_encoder, (unsigned)_blockSize);
+
+ //if (FLAC__stream_encoder_init_FILE(_encoder, hFile, NULL, NULL) !=
+ // FLAC__STREAM_ENCODER_INIT_STATUS_OK)
+ //{
+ // throw gcnew Exception("Unable to initialize the encoder.");
+ //}
+
+ _IO = gcnew FileStream (_path, FileMode::Create, FileAccess::Write, FileShare::Read);
+ try
+ {
+ _ttaWriter = new TTALib::TTAWriter((HANDLE)_IO->Handle, 0, WAVE_FORMAT_PCM, _channelCount, _bitsPerSample, _sampleRate, _finalSampleCount);
+ } catch (TTALib::TTAException ex)
+ {
+ throw gcnew Exception(String::Format("TTA encoder: {0}", gcnew String(TTAErrorsStr[ex.GetErrNo()])));
+ }
+ _initialized = true;
+ }
+ };
}
}
}
diff --git a/CUETools.Codecs.TTA/CUETools.Codecs.TTA.vcproj b/CUETools.Codecs.TTA/CUETools.Codecs.TTA.vcproj
index 1494f32..69f339b 100644
--- a/CUETools.Codecs.TTA/CUETools.Codecs.TTA.vcproj
+++ b/CUETools.Codecs.TTA/CUETools.Codecs.TTA.vcproj
@@ -92,79 +92,6 @@
Name="VCPostBuildEventTool"
/>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
^ Read(array^ buff)
+ {
+ return AudioSamples::Read(this, buff);
+ }
+
virtual UInt32 Read(array^ sampleBuffer, UInt32 sampleCount)
{
pin_ptr pSampleBuffer = &sampleBuffer[0, 0];
diff --git a/CUETools.Codecs/Codecs.cs b/CUETools.Codecs/Codecs.cs
index a8180e3..9118c82 100644
--- a/CUETools.Codecs/Codecs.cs
+++ b/CUETools.Codecs/Codecs.cs
@@ -3,12 +3,14 @@ using System.IO;
using System.Text;
using System.Collections.Generic;
using System.Collections.Specialized;
+using System.Threading;
namespace CUETools.Codecs
{
public interface IAudioSource
{
uint Read(int[,] buff, uint sampleCount);
+ int[,] Read(int[,] buff);
ulong Length { get; }
ulong Position { get; set; }
NameValueCollection Tags { get; set; }
@@ -128,6 +130,19 @@ namespace CUETools.Codecs
}
}
}
+
+ public static int[,] Read(IAudioSource source, int[,] buff)
+ {
+ if (source.Remaining == 0) return null;
+ uint toRead = Math.Min(65536U, (uint)source.Remaining);
+ if (buff == null || (ulong)buff.GetLength(0) > source.Remaining)
+ buff = new int[toRead, source.ChannelCount];
+ else
+ toRead = (uint)buff.GetLength(0);
+ uint samplesRead = source.Read(buff, toRead);
+ if (samplesRead != toRead) throw new Exception("samples read != requested");
+ return buff;
+ }
}
public class DummyWriter : IAudioDest
@@ -266,6 +281,19 @@ namespace CUETools.Codecs
return sampleCount;
}
+ public int[,] Read(int[,] buff)
+ {
+ if (buff != null && buff.GetLength(0) <= (int)Remaining)
+ {
+ _sampleOffset += (ulong) buff.GetLength(0);
+ Array.Clear(buff, 0, buff.Length);
+ return buff;
+ }
+ ulong samples = Math.Min(Remaining, (ulong)4096);
+ _sampleCount += samples;
+ return new int[samples, ChannelCount];
+ }
+
public void Close()
{
}
@@ -487,12 +515,6 @@ namespace CUETools.Codecs
return false;
}
- public void GetTags(out List names, out List values)
- {
- names = new List();
- values = new List();
- }
-
public uint Read(int[,] buff, uint sampleCount)
{
if (sampleCount > Remaining)
@@ -511,6 +533,11 @@ namespace CUETools.Codecs
return sampleCount;
}
+ public int[,] Read(int[,] buff)
+ {
+ return AudioSamples.Read(this, buff);
+ }
+
public string Path { get { return _path; } }
}
@@ -701,4 +728,283 @@ namespace CUETools.Codecs
public string Path { get { return _path; } }
}
+
+ public class AudioPipe : IAudioSource//, IDisposable
+ {
+ private readonly Queue _buffer = new Queue();
+ int _bitsPerSample, _channelCount, _sampleRate, _bufferPos;
+ ulong _sampleLen, _samplePos;
+ private int _maxLength;
+ private Thread _workThread;
+ IAudioSource _source;
+ bool _close = false;
+ Exception _ex = null;
+
+ public AudioPipe(IAudioSource source, int maxLength)
+ {
+ _source = source;
+ _maxLength = maxLength;
+ _bitsPerSample = _source.BitsPerSample;
+ _channelCount = _source.ChannelCount;
+ _sampleRate = _source.SampleRate;
+ _sampleLen = _source.Length;
+ _samplePos = 0;
+ _bufferPos = 0;
+ }
+
+ private void Decompress(object o)
+ {
+ // catch
+ try
+ {
+ do
+ {
+ //int[,] buff = new int[65536, 2];
+ //uint toRead = Math.Min((uint)buff.GetLength(0), (uint)_source.Remaining);
+ //uint samplesRead = _source.Read(buff, toRead);
+ int[,] buff = _source.Read(null);
+ if (buff == null) break;
+ //uint samplesRead = buff.GetLength(0);
+ //if (samplesRead == 0) break;
+ //if (samplesRead != toRead)
+ // throw new Exception("samples read != samples requested");
+ Write(buff);
+ } while (true);
+ }
+ catch (Exception ex)
+ {
+ lock (_buffer)
+ {
+ _ex = ex;
+ Monitor.Pulse(_buffer);
+ }
+ }
+ }
+
+ private void Go()
+ {
+ if (_workThread != null || _ex != null) return;
+ _workThread = new Thread(Decompress);
+ _workThread.Priority = ThreadPriority.BelowNormal;
+ _workThread.IsBackground = true;
+ _workThread.Start(null);
+ }
+
+ //public new void Dispose()
+ //{
+ // _buffer.Clear();
+ //}
+
+ public void Close()
+ {
+ lock (_buffer)
+ {
+ _close = true;
+ Monitor.Pulse(_buffer);
+ }
+ if (_workThread != null)
+ {
+ _workThread.Join();
+ _workThread = null;
+ }
+ _buffer.Clear();
+ }
+
+ public ulong Position
+ {
+ get
+ {
+ return _samplePos;
+ }
+ set
+ {
+ throw new Exception("not supported");
+ }
+ }
+
+ public ulong Length
+ {
+ get
+ {
+ return _sampleLen;
+ }
+ }
+
+ public ulong Remaining
+ {
+ get
+ {
+ return _sampleLen - _samplePos;
+ }
+ }
+
+ public int ChannelCount
+ {
+ get
+ {
+ return _channelCount;
+ }
+ }
+
+ public int SampleRate
+ {
+ get
+ {
+ return _sampleRate;
+ }
+ }
+
+ public int BitsPerSample
+ {
+ get
+ {
+ return _bitsPerSample;
+ }
+ }
+
+ public NameValueCollection Tags
+ {
+ get
+ {
+ return _source.Tags;
+ //return new NameValueCollection();
+ }
+ set
+ {
+ }
+ }
+
+ public bool UpdateTags(bool preserveTime)
+ {
+ return false;
+ }
+
+ public int[,] Read(int[,] buff)
+ {
+ Go();
+ if (Remaining == 0)
+ return null;
+ if (_bufferPos != 0)
+ throw new Exception("Mixed Read usage not yet suppoted");
+ lock (_buffer)
+ {
+ while (_buffer.Count == 0 && _ex == null)
+ Monitor.Wait(_buffer);
+ if (_ex != null)
+ throw _ex;
+ buff = _buffer.Dequeue();
+ Monitor.Pulse(_buffer);
+ }
+ return buff;
+ }
+
+ public uint Read(int[,] buff, uint sampleCount)
+ {
+ Go();
+ if (sampleCount > Remaining)
+ sampleCount = (uint)Remaining;
+ int pos = 0;
+ while (sampleCount > 0)
+ {
+ lock (_buffer)
+ {
+ while (_buffer.Count == 0 && _ex == null)
+ Monitor.Wait(_buffer);
+ if (_ex != null)
+ throw _ex;
+ int[,] chunk = _buffer.Peek();
+ int copyCount = Math.Min((int)sampleCount, chunk.GetLength(0) - _bufferPos);
+ Array.Copy(chunk, _bufferPos * _channelCount, buff, pos * _channelCount, copyCount * _channelCount);
+ pos += copyCount;
+ sampleCount -= (uint) copyCount;
+ _samplePos += (ulong) copyCount;
+ _bufferPos += copyCount;
+ if (_bufferPos == chunk.GetLength(0))
+ {
+ _buffer.Dequeue(); // .Finalize?
+ _bufferPos = 0;
+ Monitor.Pulse(_buffer);
+ }
+ }
+ }
+ return (uint) pos;
+ }
+
+ public void Write(int[,] buff)
+ {
+ lock (_buffer)
+ {
+ while (_buffer.Count >= _maxLength && !_close)
+ Monitor.Wait(_buffer);
+ if (_close)
+ throw new Exception("Decompression aborted");
+ //_flushed = false;
+ _buffer.Enqueue(buff);
+ Monitor.Pulse(_buffer);
+ }
+ }
+
+ public string Path { get { return _source.Path; } }
+ }
+
+ public class Crc32
+ {
+ uint[] table = new uint[256];
+
+ public uint ComputeChecksum(uint crc, byte val)
+ {
+ return (crc >> 8) ^ table[(crc & 0xff) ^ val];
+ }
+
+ public uint ComputeChecksum(uint crc, byte[] bytes, int pos, int count)
+ {
+ for (int i = pos; i < pos + count; i++)
+ crc = ComputeChecksum(crc, bytes[i]);
+ return crc;
+ }
+
+ public uint ComputeChecksum(uint crc, uint s)
+ {
+ return ComputeChecksum(ComputeChecksum(ComputeChecksum(ComputeChecksum(
+ crc, (byte)s), (byte)(s >> 8)), (byte)(s >> 16)), (byte)(s >> 24));
+ }
+
+ public unsafe uint ComputeChecksum(uint crc, int * samples, uint count)
+ {
+ for (uint i = 0; i < count; i++)
+ {
+ int s1 = samples[2 * i], s2 = samples[2 * i + 1];
+ crc = ComputeChecksum(ComputeChecksum(ComputeChecksum(ComputeChecksum(
+ crc, (byte)s1), (byte)(s1 >> 8)), (byte)(s2)), (byte)(s2 >> 8));
+ }
+ return crc;
+ }
+
+ uint Reflect(uint val, int ch)
+ {
+ uint value = 0;
+ // Swap bit 0 for bit 7
+ // bit 1 for bit 6, etc.
+ for (int i = 1; i < (ch + 1); i++)
+ {
+ if (0 != (val & 1))
+ value |= 1U << (ch - i);
+ val >>= 1;
+ }
+ return value;
+ }
+
+ const uint ulPolynomial = 0x04c11db7;
+
+ public Crc32()
+ {
+ for (uint i = 0; i < table.Length; i++)
+ {
+ table[i] = Reflect(i, 8) << 24;
+ for (int j = 0; j < 8; j++)
+ table[i] = (table[i] << 1) ^ ((table[i] & (1U << 31)) == 0 ? 0 : ulPolynomial);
+ table[i] = Reflect(table[i], 32);
+ }
+ }
+ }
}
diff --git a/CUETools.Processor/AudioReadWrite.cs b/CUETools.Processor/AudioReadWrite.cs
index 45e6a7d..02e0575 100644
--- a/CUETools.Processor/AudioReadWrite.cs
+++ b/CUETools.Processor/AudioReadWrite.cs
@@ -2,9 +2,12 @@ using System;
using System.IO;
using CUETools.Codecs;
using CUETools.Codecs.ALAC;
+#if !MONO
using CUETools.Codecs.FLAC;
using CUETools.Codecs.WavPack;
using CUETools.Codecs.APE;
+using CUETools.Codecs.TTA;
+#endif
using CUETools.Codecs.LossyWAV;
using System.Collections.Generic;
using System.Collections.Specialized;
@@ -27,9 +30,11 @@ namespace CUETools.Processor
return new WavPackReader(path, IO, null);
case ".ape":
return new APEReader(path, IO);
+ case ".tta":
+ return new TTAReader(path, IO);
#endif
default:
- throw new Exception("Unsupported audio type.");
+ throw new Exception("Unsupported audio type: " + path);
}
}
@@ -44,7 +49,15 @@ namespace CUETools.Processor
string lossyPath = Path.Combine(Path.GetDirectoryName(path), Path.GetFileNameWithoutExtension(filename) + ".lossy" + extension);
string lwcdfPath = Path.Combine(Path.GetDirectoryName(path), Path.GetFileNameWithoutExtension(filename) + ".lwcdf" + extension);
IAudioSource lossySource = GetAudioSource(lossyPath, null, extension);
- IAudioSource lwcdfSource = GetAudioSource(lwcdfPath, null, extension);
+ IAudioSource lwcdfSource = null;
+ try
+ {
+ lwcdfSource = GetAudioSource(lwcdfPath, null, extension);
+ }
+ catch
+ {
+ return lossySource;
+ }
return new LossyWAVReader(lossySource, lwcdfSource);
}
@@ -70,12 +83,15 @@ namespace CUETools.Processor
dest = new APEWriter(path, bitsPerSample, channelCount, sampleRate);
((APEWriter)dest).CompressionLevel = (int)config.apeCompressionLevel;
break;
+ case ".tta":
+ dest = new TTAWriter(path, bitsPerSample, channelCount, sampleRate);
+ break;
case ".dummy":
dest = new DummyWriter(path, bitsPerSample, channelCount, sampleRate);
break;
#endif
default:
- throw new Exception("Unsupported audio type.");
+ throw new Exception("Unsupported audio type: " + path);
}
dest.FinalSampleCount = finalSampleCount;
return dest;
diff --git a/CUETools.Processor/CUETools.Processor.csproj b/CUETools.Processor/CUETools.Processor.csproj
index 58586db..6b1ef21 100644
--- a/CUETools.Processor/CUETools.Processor.csproj
+++ b/CUETools.Processor/CUETools.Processor.csproj
@@ -80,10 +80,18 @@
+
+
+
+ Form
+
+
+ frmProperties.cs
+
@@ -97,6 +105,10 @@
{9AE965C4-301E-4C01-B90F-297AF341ACC6}
CUETools.Codecs.APE
+
+ {1D1E99BC-6D22-41C0-BD94-FF4DD5EC725B}
+ CUETools.Codecs.TTA
+
{6458A13A-30EF-45A9-9D58-E5031B17BEE2}
CUETools.Codecs
@@ -117,6 +129,10 @@
{E70FA90A-7012-4A52-86B5-362B699D1540}
CUETools.Codecs.FLAC
+
+ {5ADCFD6D-BFEA-4B10-BB45-9083BBB56AF4}
+ Freedb
+
{32338A04-5B6B-4C63-8EE7-C6400F73B5D7}
HDCDDotNet
@@ -138,6 +154,12 @@
CUETools.Codecs.WavPack
+
+
+ Designer
+ frmProperties.cs
+
+