From 399573c1bec075e12e70ddd457602a6497106cd2 Mon Sep 17 00:00:00 2001 From: chudov Date: Sat, 17 Jan 2009 04:09:38 +0000 Subject: [PATCH] 1.9.4... too many small changes to comment --- CUERipper/CUERipper.csproj | 20 +- CUERipper/Properties/AssemblyInfo.cs | 8 +- CUERipper/Properties/Resources.Designer.cs | 133 +- CUERipper/Properties/Resources.resx | 19 +- CUERipper/frmCUERipper.Designer.cs | 26 +- CUERipper/frmCUERipper.cs | 153 +- CUERipper/frmCUERipper.resx | 107 +- CUETools.AccurateRip/AccurateRip.cs | 47 +- CUETools.Codecs.ALAC/ALACDotNet.cs | 5 + CUETools.Codecs.APE/CUETools.Codecs.APE.cpp | 5 + CUETools.Codecs.FLAC/CUETools.Codecs.FLAC.cpp | 5 + CUETools.Codecs.LossyWAV/LossyWAV.cs | 5 + CUETools.Codecs.TTA/CUETools.Codecs.TTA.cpp | 268 +- .../CUETools.Codecs.TTA.vcproj | 154 +- .../CUETools.Codecs.WavPack.cpp | 5 + CUETools.Codecs/Codecs.cs | 318 +- CUETools.Processor/AudioReadWrite.cs | 22 +- CUETools.Processor/CUETools.Processor.csproj | 22 + CUETools.Processor/Processor.cs | 428 +- CUETools.Processor/Properties/AssemblyInfo.cs | 2 +- CUETools.Ripper.Console/Program.cs | 6 +- .../Properties/AssemblyInfo.cs | 8 +- CUETools.Ripper.SCSI/SCSIDrive.cs | 148 +- CUETools/CUETools.csproj | 32 + CUETools/CUETools.sln | 38 +- CUETools/Properties/AssemblyInfo.cs | 2 +- CUETools/Properties/Resources.Designer.cs | 14 + CUETools/Properties/Resources.resx | 7 + CUETools/Resources/freedb.gif | Bin 0 -> 1055 bytes CUETools/Resources/musicbrainz.ico | Bin 0 -> 1406 bytes CUETools/frmAbout.Designer.cs | 13 + CUETools/frmAbout.resx | 72 +- CUETools/frmAbout.ru-RU.resx | 15 +- CUETools/frmCUETools.Designer.cs | 71 +- CUETools/frmCUETools.cs | 100 +- CUETools/frmCUETools.de-DE.resx | 120 +- CUETools/frmCUETools.resx | 272 +- CUETools/frmCUETools.ru-RU.resx | 122 +- CUETools/frmChoice.Designer.cs | 5 +- CUETools/frmChoice.cs | 69 + CUETools/frmSettings.Designer.cs | 391 +- CUETools/frmSettings.cs | 11 + CUETools/frmSettings.resx | 3696 ++++++++--------- MAC_SDK/Source/MACLib/Assembly/Assembly.obj | Bin 836 -> 836 bytes MusicBrainz/MusicBrainz/MusicBrainzObject.cs | 869 ++-- .../encode/file/example_c_encode_file.vcproj | 165 +- flac/examples/c/encode/file/main.c | 2 +- flac/src/libFLAC/cpu.c | 11 +- flac/src/libFLAC/include/private/cpu.h | 1 + flac/src/libFLAC/include/private/lpc.h | 7 + flac/src/libFLAC/libFLAC_static.vcproj | 56 +- flac/src/libFLAC/stream_encoder.c | 11 + .../monkeys_audio_utilities/flac_mac/main.c | 624 ++- .../monkeys_audio_utilities/flac_ren/main.c | 117 +- ttalib-1.1/TTAWriter.cpp | 2 + ttalib-1.1/TTAWriter.h | 4 +- 56 files changed, 5188 insertions(+), 3645 deletions(-) create mode 100644 CUETools/Resources/freedb.gif create mode 100644 CUETools/Resources/musicbrainz.ico 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 + +