From 881951cb02868b9b8b653abfc9091b3f4709394e Mon Sep 17 00:00:00 2001 From: chudov Date: Tue, 30 Mar 2010 02:41:43 +0000 Subject: [PATCH] 2.0.7 --- Bwg.Scsi/Device.cs | 6 +- CUEControls/BNComboBox.cs | 280 ++- CUERipper/CUERipper.csproj | 4 + CUERipper/Properties/Resources.Designer.cs | 90 + CUERipper/Properties/Resources.resx | 30 + CUERipper/frmCUERipper.Designer.cs | 79 +- CUERipper/frmCUERipper.cs | 260 ++- CUERipper/frmCUERipper.resx | 192 +- CUETools.AccurateRip/AccurateRip.cs | 4 +- CUETools.CTDB/CUEToolsDB.cs | 2 +- .../CUETools.Codecs.CoreAudio.csproj | 110 + .../CoreAudioApi/AudioCaptureClient.cs | 91 + .../CoreAudioApi/AudioClient.cs | 296 +++ .../CoreAudioApi/AudioClientBufferFlags.cs | 31 + .../CoreAudioApi/AudioClientShareMode.cs | 21 + .../CoreAudioApi/AudioClientStreamFlags.cs | 34 + .../CoreAudioApi/AudioEndpointVolume.cs | 211 ++ .../AudioEndpointVolumeCallback.cs | 73 + .../AudioEndpointVolumeChannel.cs | 80 + .../AudioEndpointVolumeChannels.cs | 78 + ...AudioEndpointVolumeNotificationDelegate.cs | 34 + .../AudioEndpointVolumeStepInformation.cs | 65 + .../AudioEndpointVolumeVolumeRange.cs | 78 + .../CoreAudioApi/AudioMeterInformation.cs | 85 + .../AudioMeterInformationChannels.cs | 72 + .../CoreAudioApi/AudioRenderClient.cs | 60 + .../AudioVolumeNotificationData.cs | 124 + .../CoreAudioApi/DataFlow.cs | 31 + .../CoreAudioApi/DeviceState.cs | 52 + .../CoreAudioApi/EEndpointHardwareSupport.cs | 47 + .../AudioVolumeNotificationDataStruct.cs | 54 + .../CoreAudioApi/Interfaces/Blob.cs | 49 + .../CoreAudioApi/Interfaces/ClsCtx.cs | 39 + .../CoreAudioApi/Interfaces/ErrorCodes.cs | 23 + .../Interfaces/IAudioCaptureClient.cs | 34 + .../CoreAudioApi/Interfaces/IAudioClient.cs | 53 + .../Interfaces/IAudioEndpointVolume.cs | 52 + .../IAudioEndpointVolumeCallback.cs | 37 + .../Interfaces/IAudioMeterInformation.cs | 38 + .../Interfaces/IAudioRenderClient.cs | 17 + .../CoreAudioApi/Interfaces/IMMDevice.cs | 23 + .../Interfaces/IMMDeviceCollection.cs | 15 + .../Interfaces/IMMDeviceEnumerator.cs | 23 + .../CoreAudioApi/Interfaces/IMMEndpoint.cs | 17 + .../Interfaces/IMMNotificationClient.cs | 23 + .../CoreAudioApi/Interfaces/IPropertyStore.cs | 21 + .../Interfaces/MMDeviceEnumeratorComObject.cs | 15 + .../Interfaces/StorageAccessMode.cs | 16 + .../CoreAudioApi/MMDevice.cs | 219 ++ .../CoreAudioApi/MMDeviceCollection.cs | 96 + .../CoreAudioApi/MMDeviceEnumerator.cs | 89 + .../CoreAudioApi/PropVariant.cs | 157 ++ .../CoreAudioApi/PropertyKey.cs | 21 + .../CoreAudioApi/PropertyKeys.cs | 71 + .../CoreAudioApi/PropertyStore.cs | 143 ++ .../CoreAudioApi/PropertyStoreProperty.cs | 69 + .../CoreAudioApi/Role.cs | 26 + .../CoreAudioApi/WasapiCapture.cs | 216 ++ CUETools.Codecs.CoreAudio/IWavePlayer.cs | 42 + CUETools.Codecs.CoreAudio/PlaybackState.cs | 25 + .../Properties/AssemblyInfo.cs | 36 + CUETools.Codecs.CoreAudio/WasapiOut.cs | 492 ++++ .../WaveFormats/AdpcmWaveFormat.cs | 117 + .../WaveFormats/AudioMediaSubtypes.cs | 70 + .../WaveFormats/WaveFormat.cs | 373 +++ .../WaveFormats/WaveFormatEncoding.cs | 314 +++ .../WaveFormats/WaveFormatExtensible.cs | 79 + .../WaveFormats/WaveFormatExtraData.cs | 41 + CUETools.Codecs/Codecs.cs | 47 +- CUETools.Processor/Processor.cs | 154 +- CUETools.Ripper.SCSI/SCSIDrive.cs | 83 +- CUETools.Ripper/Ripper.cs | 1 + CUETools/CUETools.sln | 20 + CUETools/frmCUETools.resx | 2028 +++++++---------- 74 files changed, 6489 insertions(+), 1709 deletions(-) create mode 100644 CUETools.Codecs.CoreAudio/CUETools.Codecs.CoreAudio.csproj create mode 100644 CUETools.Codecs.CoreAudio/CoreAudioApi/AudioCaptureClient.cs create mode 100644 CUETools.Codecs.CoreAudio/CoreAudioApi/AudioClient.cs create mode 100644 CUETools.Codecs.CoreAudio/CoreAudioApi/AudioClientBufferFlags.cs create mode 100644 CUETools.Codecs.CoreAudio/CoreAudioApi/AudioClientShareMode.cs create mode 100644 CUETools.Codecs.CoreAudio/CoreAudioApi/AudioClientStreamFlags.cs create mode 100644 CUETools.Codecs.CoreAudio/CoreAudioApi/AudioEndpointVolume.cs create mode 100644 CUETools.Codecs.CoreAudio/CoreAudioApi/AudioEndpointVolumeCallback.cs create mode 100644 CUETools.Codecs.CoreAudio/CoreAudioApi/AudioEndpointVolumeChannel.cs create mode 100644 CUETools.Codecs.CoreAudio/CoreAudioApi/AudioEndpointVolumeChannels.cs create mode 100644 CUETools.Codecs.CoreAudio/CoreAudioApi/AudioEndpointVolumeNotificationDelegate.cs create mode 100644 CUETools.Codecs.CoreAudio/CoreAudioApi/AudioEndpointVolumeStepInformation.cs create mode 100644 CUETools.Codecs.CoreAudio/CoreAudioApi/AudioEndpointVolumeVolumeRange.cs create mode 100644 CUETools.Codecs.CoreAudio/CoreAudioApi/AudioMeterInformation.cs create mode 100644 CUETools.Codecs.CoreAudio/CoreAudioApi/AudioMeterInformationChannels.cs create mode 100644 CUETools.Codecs.CoreAudio/CoreAudioApi/AudioRenderClient.cs create mode 100644 CUETools.Codecs.CoreAudio/CoreAudioApi/AudioVolumeNotificationData.cs create mode 100644 CUETools.Codecs.CoreAudio/CoreAudioApi/DataFlow.cs create mode 100644 CUETools.Codecs.CoreAudio/CoreAudioApi/DeviceState.cs create mode 100644 CUETools.Codecs.CoreAudio/CoreAudioApi/EEndpointHardwareSupport.cs create mode 100644 CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/AudioVolumeNotificationDataStruct.cs create mode 100644 CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/Blob.cs create mode 100644 CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/ClsCtx.cs create mode 100644 CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/ErrorCodes.cs create mode 100644 CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/IAudioCaptureClient.cs create mode 100644 CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/IAudioClient.cs create mode 100644 CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/IAudioEndpointVolume.cs create mode 100644 CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/IAudioEndpointVolumeCallback.cs create mode 100644 CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/IAudioMeterInformation.cs create mode 100644 CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/IAudioRenderClient.cs create mode 100644 CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/IMMDevice.cs create mode 100644 CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/IMMDeviceCollection.cs create mode 100644 CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/IMMDeviceEnumerator.cs create mode 100644 CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/IMMEndpoint.cs create mode 100644 CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/IMMNotificationClient.cs create mode 100644 CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/IPropertyStore.cs create mode 100644 CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/MMDeviceEnumeratorComObject.cs create mode 100644 CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/StorageAccessMode.cs create mode 100644 CUETools.Codecs.CoreAudio/CoreAudioApi/MMDevice.cs create mode 100644 CUETools.Codecs.CoreAudio/CoreAudioApi/MMDeviceCollection.cs create mode 100644 CUETools.Codecs.CoreAudio/CoreAudioApi/MMDeviceEnumerator.cs create mode 100644 CUETools.Codecs.CoreAudio/CoreAudioApi/PropVariant.cs create mode 100644 CUETools.Codecs.CoreAudio/CoreAudioApi/PropertyKey.cs create mode 100644 CUETools.Codecs.CoreAudio/CoreAudioApi/PropertyKeys.cs create mode 100644 CUETools.Codecs.CoreAudio/CoreAudioApi/PropertyStore.cs create mode 100644 CUETools.Codecs.CoreAudio/CoreAudioApi/PropertyStoreProperty.cs create mode 100644 CUETools.Codecs.CoreAudio/CoreAudioApi/Role.cs create mode 100644 CUETools.Codecs.CoreAudio/CoreAudioApi/WasapiCapture.cs create mode 100644 CUETools.Codecs.CoreAudio/IWavePlayer.cs create mode 100644 CUETools.Codecs.CoreAudio/PlaybackState.cs create mode 100644 CUETools.Codecs.CoreAudio/Properties/AssemblyInfo.cs create mode 100644 CUETools.Codecs.CoreAudio/WasapiOut.cs create mode 100644 CUETools.Codecs.CoreAudio/WaveFormats/AdpcmWaveFormat.cs create mode 100644 CUETools.Codecs.CoreAudio/WaveFormats/AudioMediaSubtypes.cs create mode 100644 CUETools.Codecs.CoreAudio/WaveFormats/WaveFormat.cs create mode 100644 CUETools.Codecs.CoreAudio/WaveFormats/WaveFormatEncoding.cs create mode 100644 CUETools.Codecs.CoreAudio/WaveFormats/WaveFormatExtensible.cs create mode 100644 CUETools.Codecs.CoreAudio/WaveFormats/WaveFormatExtraData.cs diff --git a/Bwg.Scsi/Device.cs b/Bwg.Scsi/Device.cs index 795f294..2d0c7a3 100644 --- a/Bwg.Scsi/Device.cs +++ b/Bwg.Scsi/Device.cs @@ -2245,7 +2245,7 @@ namespace Bwg.Scsi /// /// /// - public CommandStatus ReadCDText(out byte [] data) + public CommandStatus ReadCDText(out byte [] data, int _timeout) { ushort len; @@ -2256,7 +2256,7 @@ namespace Bwg.Scsi } data = null; - using (Command cmd = new Command(ScsiCommandCode.ReadTocPmaAtip, 10, 4, Command.CmdDirection.In, 5 * 60)) + using (Command cmd = new Command(ScsiCommandCode.ReadTocPmaAtip, 10, 4, Command.CmdDirection.In, _timeout)) { cmd.SetCDB8(2, 5); // CDText info in leadin cmd.SetCDB16(7, 4); @@ -2276,7 +2276,7 @@ namespace Bwg.Scsi } } - using (Command cmd = new Command(ScsiCommandCode.ReadTocPmaAtip, 10, len, Command.CmdDirection.In, 5 * 60)) + using (Command cmd = new Command(ScsiCommandCode.ReadTocPmaAtip, 10, len, Command.CmdDirection.In, _timeout)) { cmd.SetCDB8(2, 5); // CDText info in leadin cmd.SetCDB16(7, len); diff --git a/CUEControls/BNComboBox.cs b/CUEControls/BNComboBox.cs index d9f4eb8..5eb4ee3 100644 --- a/CUEControls/BNComboBox.cs +++ b/CUEControls/BNComboBox.cs @@ -5,7 +5,7 @@ using System.Windows.Forms.Design; using System.ComponentModel; using System; -namespace BBBNOVA +namespace CUEControls { public class BNComboBox : ListControl { @@ -178,7 +178,7 @@ namespace BBBNOVA public BNRadius Radius { get { return _radius; } - set { _radius = value; } + set { if (value != null) _radius = value; } } [Category("Appearance"), Description("Selects the type of border around drop down list."), DefaultValue(BorderStyle.None)] @@ -556,95 +556,112 @@ namespace BBBNOVA } } - protected override void OnPaint(PaintEventArgs e) - { - e.Graphics.SmoothingMode = SmoothingMode.AntiAlias; + protected virtual Color GetOuterBorderColor() + { + return (Enabled) ? BackColor : BackColor; + } - //content border - Rectangle rectCont = rectContent; - rectCont.X += 1; - rectCont.Y += 1; - rectCont.Width -= 3; - rectCont.Height -= 3; - GraphicsPath pathContentBorder = CreateRoundRectangle(rectCont, Radius.TopLeft, Radius.TopRight, Radius.BottomRight, - Radius.BottomLeft); + protected virtual Color GetInnerBorderColor() + { + return (Enabled) ? BackColor : SystemColors.Control; + } - //button border - Rectangle rectButton = rectBtn; - rectButton.X += 1; - rectButton.Y += 1; - rectButton.Width -= 3; - rectButton.Height -= 3; - GraphicsPath pathBtnBorder = CreateRoundRectangle(rectButton, 0, Radius.TopRight, Radius.BottomRight, 0); + protected override void OnPaint(PaintEventArgs e) + { + e.Graphics.SmoothingMode = SmoothingMode.AntiAlias; - //outer border - Rectangle rectOuter = rectContent; - rectOuter.Width -= 1; - rectOuter.Height -= 1; - GraphicsPath pathOuterBorder = CreateRoundRectangle(rectOuter, Radius.TopLeft, Radius.TopRight, Radius.BottomRight, - Radius.BottomLeft); + //content border + Rectangle rectCont = rectContent; + rectCont.X += 1; + rectCont.Y += 1; + rectCont.Width -= 3; + rectCont.Height -= 3; + GraphicsPath pathContentBorder = CreateRoundRectangle(rectCont, Radius.TopLeft, Radius.TopRight, Radius.BottomRight, + Radius.BottomLeft); - //inner border - Rectangle rectInner = rectContent; - rectInner.X += 1; - rectInner.Y += 1; - rectInner.Width -= 3; - rectInner.Height -= 3; - GraphicsPath pathInnerBorder = CreateRoundRectangle(rectInner, Radius.TopLeft, Radius.TopRight, Radius.BottomRight, - Radius.BottomLeft); + //button border + Rectangle rectButton = rectBtn; + rectButton.X += 1; + rectButton.Y += 1; + rectButton.Width -= 3; + rectButton.Height -= 3; + GraphicsPath pathBtnBorder = CreateRoundRectangle(rectButton, 0, Radius.TopRight, Radius.BottomRight, 0); - //brushes and pens - Color foreColor = Color.FromArgb(IsDroppedDown ? 100 : 50, ForeColor); + //outer border + Rectangle rectOuter = rectContent; + rectOuter.Width -= 1; + rectOuter.Height -= 1; + GraphicsPath pathOuterBorder = CreateRoundRectangle(rectOuter, Radius.TopLeft, Radius.TopRight, Radius.BottomRight, + Radius.BottomLeft); + + //inner border + Rectangle rectInner = rectContent; + rectInner.X += 1; + rectInner.Y += 1; + rectInner.Width -= 3; + rectInner.Height -= 3; + GraphicsPath pathInnerBorder = CreateRoundRectangle(rectInner, Radius.TopLeft, Radius.TopRight, Radius.BottomRight, + Radius.BottomLeft); + + //brushes and pens + Color foreColor = Color.FromArgb(IsDroppedDown ? 100 : 50, ForeColor); Brush brInnerBrush = new LinearGradientBrush( new Rectangle(rectInner.X, rectInner.Y, rectInner.Width, rectInner.Height + 1), - Color.FromArgb((hovered || IsDroppedDown || Focused) ? 200 : 100, ForeColor), Color.Transparent, + Color.FromArgb((hovered || IsDroppedDown || Focused) ? 200 : 100, ForeColor), + Color.Transparent, LinearGradientMode.Vertical); - Brush brBackground; + Brush brBackground; if (this.DropDownStyle == ComboBoxStyle.DropDownList) - brBackground = new LinearGradientBrush(pathInnerBorder.GetBounds(), BackColor, foreColor, LinearGradientMode.Vertical); + brBackground = new LinearGradientBrush(pathInnerBorder.GetBounds(), BackColor, hovered ? Color.FromArgb(100, SystemColors.HotTrack) : foreColor, LinearGradientMode.Vertical); else brBackground = new SolidBrush(BackColor); - Pen penOuterBorder = new Pen(BackColor, 0); - Pen penInnerBorder = new Pen(brInnerBrush, 0); - LinearGradientBrush brButtonLeft = new LinearGradientBrush(rectBtn, BackColor, ForeColor, LinearGradientMode.Vertical); - ColorBlend blend = new ColorBlend(); + Pen penInnerBorder = new Pen(brInnerBrush, 0); + LinearGradientBrush brButtonLeft = new LinearGradientBrush(rectBtn, BackColor, ForeColor, LinearGradientMode.Vertical); + ColorBlend blend = new ColorBlend(); blend.Colors = new Color[] { Color.Transparent, foreColor, Color.Transparent }; - blend.Positions = new float[] { 0.0f, 0.5f, 1.0f}; - brButtonLeft.InterpolationColors = blend; - Pen penLeftButton = new Pen(brButtonLeft, 0); - Brush brButton = new LinearGradientBrush(pathBtnBorder.GetBounds(), BackColor, foreColor, LinearGradientMode.Vertical); + blend.Positions = new float[] { 0.0f, 0.5f, 1.0f }; + brButtonLeft.InterpolationColors = blend; + Pen penLeftButton = new Pen(brButtonLeft, 0); + Brush brButton = new LinearGradientBrush(pathBtnBorder.GetBounds(), BackColor, foreColor, LinearGradientMode.Vertical); - //draw - e.Graphics.FillPath(brBackground, pathContentBorder); - if (DropDownStyle != ComboBoxStyle.DropDownList) - { - e.Graphics.FillPath(brButton, pathBtnBorder); - } - e.Graphics.DrawPath(penOuterBorder, pathOuterBorder); - e.Graphics.DrawPath(penInnerBorder, pathInnerBorder); + //draw + e.Graphics.FillPath(brBackground, pathContentBorder); + if (DropDownStyle != ComboBoxStyle.DropDownList) + { + e.Graphics.FillPath(brButton, pathBtnBorder); + } + Color outerBorderColor = GetOuterBorderColor(); + if (outerBorderColor.IsSystemColor) + { + Pen penOuterBorder = SystemPens.FromSystemColor(outerBorderColor); + e.Graphics.DrawPath(penOuterBorder, pathOuterBorder); + } + else using (Pen penOuterBorder = new Pen(outerBorderColor)) + e.Graphics.DrawPath(penOuterBorder, pathOuterBorder); + e.Graphics.DrawPath(penInnerBorder, pathInnerBorder); - e.Graphics.DrawLine(penLeftButton, rectBtn.Left + 1, rectInner.Top+1, rectBtn.Left + 1, rectInner.Bottom-1); - + e.Graphics.DrawLine(penLeftButton, rectBtn.Left + 1, rectInner.Top + 1, rectBtn.Left + 1, rectInner.Bottom - 1); - //Glimph - Rectangle rectGlimph = rectButton; - rectButton.Width -= 4; - e.Graphics.TranslateTransform(rectGlimph.Left + rectGlimph.Width / 2.0f, rectGlimph.Top + rectGlimph.Height / 2.0f); - GraphicsPath path = new GraphicsPath(); - PointF[] points = new PointF[3]; - points[0] = new PointF(-6 / 2.0f, -3 / 2.0f); - points[1] = new PointF(6 / 2.0f, -3 / 2.0f); - points[2] = new PointF(0, 6 / 2.0f); - path.AddLine(points[0], points[1]); - path.AddLine(points[1], points[2]); - path.CloseFigure(); - e.Graphics.RotateTransform(0); - SolidBrush br = new SolidBrush(Enabled?Color.Gray:Color.Gainsboro); - e.Graphics.FillPath(br, path); - e.Graphics.ResetTransform(); - br.Dispose(); - path.Dispose(); + //Glimph + Rectangle rectGlimph = rectButton; + rectButton.Width -= 4; + e.Graphics.TranslateTransform(rectGlimph.Left + rectGlimph.Width / 2.0f, rectGlimph.Top + rectGlimph.Height / 2.0f); + GraphicsPath path = new GraphicsPath(); + PointF[] points = new PointF[3]; + points[0] = new PointF(-6 / 2.0f, -3 / 2.0f); + points[1] = new PointF(6 / 2.0f, -3 / 2.0f); + points[2] = new PointF(0, 6 / 2.0f); + path.AddLine(points[0], points[1]); + path.AddLine(points[1], points[2]); + path.CloseFigure(); + e.Graphics.RotateTransform(0); + + SolidBrush br = new SolidBrush(Enabled ? Color.Gray : Color.Gainsboro); + e.Graphics.FillPath(br, path); + e.Graphics.ResetTransform(); + br.Dispose(); + path.Dispose(); // image if (ImageList != null) @@ -654,50 +671,49 @@ namespace BBBNOVA this.ImageList.Draw(e.Graphics, _textBox.Bounds.Left - this.ImageList.ImageSize.Width - 5, rectContent.Y + 2, idx); } - //text - if (DropDownStyle == ComboBoxStyle.DropDownList) - { - StringFormat sf = new StringFormat(StringFormatFlags.NoWrap); - sf.Alignment = StringAlignment.Near; + //text + if (DropDownStyle == ComboBoxStyle.DropDownList) + { + StringFormat sf = new StringFormat(StringFormatFlags.NoWrap); + sf.Alignment = StringAlignment.Near; - Rectangle rectText = _textBox.Bounds; - rectText.Offset(-3, 0); + Rectangle rectText = _textBox.Bounds; + rectText.Offset(-3, 0); - SolidBrush foreBrush = new SolidBrush(ForeColor); - if (Enabled) - { - e.Graphics.DrawString(_textBox.Text, this.Font, foreBrush, rectText); - } - else - { + SolidBrush foreBrush = new SolidBrush(ForeColor); + if (Enabled) + { + e.Graphics.DrawString(_textBox.Text, this.Font, foreBrush, rectText); + } + else + { ControlPaint.DrawStringDisabled(e.Graphics, _textBox.Text, Font, BackColor, rectText, sf); - } - } - /* - Dim foreBrush As SolidBrush = New SolidBrush(color) - If (enabled) Then - g.DrawString(text, font, foreBrush, rect, sf) - Else - ControlPaint.DrawStringDisabled(g, text, font, backColor, _ - rect, sf) - End If - foreBrush.Dispose()*/ + } + } + /* + Dim foreBrush As SolidBrush = New SolidBrush(color) + If (enabled) Then + g.DrawString(text, font, foreBrush, rect, sf) + Else + ControlPaint.DrawStringDisabled(g, text, font, backColor, _ + rect, sf) + End If + foreBrush.Dispose()*/ - pathContentBorder.Dispose(); - pathOuterBorder.Dispose(); - pathInnerBorder.Dispose(); - pathBtnBorder.Dispose(); + pathContentBorder.Dispose(); + pathOuterBorder.Dispose(); + pathInnerBorder.Dispose(); + pathBtnBorder.Dispose(); - penOuterBorder.Dispose(); - penInnerBorder.Dispose(); - penLeftButton.Dispose(); + penInnerBorder.Dispose(); + penLeftButton.Dispose(); - brBackground.Dispose(); - brInnerBrush.Dispose(); - brButtonLeft.Dispose(); - brButton.Dispose(); - } + brBackground.Dispose(); + brInnerBrush.Dispose(); + brButtonLeft.Dispose(); + brButton.Dispose(); + } #endregion @@ -857,8 +873,8 @@ namespace BBBNOVA { if (DrawMode == DrawMode.Normal) { - Color fg = _hoverItem != -1 && _hoverItem == e.Index ? BackColor : ForeColor; - Color bg = _hoverItem != -1 && _hoverItem == e.Index ? ForeColor : BackColor; + Color fg = _hoverItem != -1 && _hoverItem == e.Index ? SystemColors.HighlightText : ForeColor; + Color bg = _hoverItem != -1 && _hoverItem == e.Index ? SystemColors.Highlight : BackColor; e.Graphics.FillRectangle(new SolidBrush(bg), e.Bounds); if (e.Index >= 0) @@ -1131,5 +1147,39 @@ namespace BBBNOVA set { _bottomRight = value; } } } - + + public class BNComboBoxItem + { + string text; + string imageKey; + T value; + + public string ImageKey + { + get + { + return imageKey; + } + } + + public override string ToString() + { + return text ?? value.ToString(); + } + + public T Value + { + get + { + return value; + } + } + + public BNComboBoxItem(string text, string imageKey, T value) + { + this.text = text; + this.imageKey = imageKey; + this.value = value; + } + } } diff --git a/CUERipper/CUERipper.csproj b/CUERipper/CUERipper.csproj index 1baa5df..1fb40ee 100644 --- a/CUERipper/CUERipper.csproj +++ b/CUERipper/CUERipper.csproj @@ -91,6 +91,9 @@ Designer frmCUERipper.cs + + frmCUERipper.cs + frmProperties.cs Designer @@ -100,6 +103,7 @@ Resources.Designer.cs Designer + True Resources.resx diff --git a/CUERipper/Properties/Resources.Designer.cs b/CUERipper/Properties/Resources.Designer.cs index 93444be..fd94d45 100644 --- a/CUERipper/Properties/Resources.Designer.cs +++ b/CUERipper/Properties/Resources.Designer.cs @@ -95,6 +95,60 @@ namespace CUERipper.Properties { } } + /// + /// Looks up a localized string similar to Detecting drives. + /// + internal static string DetectingDrives { + get { + return ResourceManager.GetString("DetectingDrives", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Done ripping. + /// + internal static string DoneRipping { + get { + return ResourceManager.GetString("DoneRipping", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Rip probably contains errors. + /// + internal static string DoneRippingErrors { + get { + return ResourceManager.GetString("DoneRippingErrors", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You can try to repair it using CUETools. + /// + internal static string DoneRippingRepair { + get { + return ResourceManager.GetString("DoneRippingRepair", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Exception. + /// + internal static string ExceptionMessage { + get { + return ResourceManager.GetString("ExceptionMessage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Failed to load ripper module. + /// + internal static string FailedToLoadRipperModule { + get { + return ResourceManager.GetString("FailedToLoadRipperModule", resourceCulture); + } + } + internal static System.Drawing.Icon flac { get { object obj = ResourceManager.GetObject("flac", resourceCulture); @@ -116,6 +170,15 @@ namespace CUERipper.Properties { } } + /// + /// Looks up a localized string similar to Looking up album via. + /// + internal static string LookingUpVia { + get { + return ResourceManager.GetString("LookingUpVia", resourceCulture); + } + } + internal static System.Drawing.Icon mp3 { get { object obj = ResourceManager.GetObject("mp3", resourceCulture); @@ -130,6 +193,15 @@ namespace CUERipper.Properties { } } + /// + /// Looks up a localized string similar to No CD drives found. + /// + internal static string NoDrives { + get { + return ResourceManager.GetString("NoDrives", resourceCulture); + } + } + internal static System.Drawing.Icon ogg { get { object obj = ResourceManager.GetObject("ogg", resourceCulture); @@ -137,6 +209,24 @@ namespace CUERipper.Properties { } } + /// + /// Looks up a localized string similar to Paused. + /// + internal static string PausedMessage { + get { + return ResourceManager.GetString("PausedMessage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to retry. + /// + internal static string Retry { + get { + return ResourceManager.GetString("Retry", resourceCulture); + } + } + internal static System.Drawing.Icon tta { get { object obj = ResourceManager.GetObject("tta", resourceCulture); diff --git a/CUERipper/Properties/Resources.resx b/CUERipper/Properties/Resources.resx index 7c63f5b..21d6bff 100644 --- a/CUERipper/Properties/Resources.resx +++ b/CUERipper/Properties/Resources.resx @@ -160,4 +160,34 @@ ..\Resources\wv.ico;System.Drawing.Icon, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + Done ripping + + + Rip probably contains errors + + + You can try to repair it using CUETools + + + Exception + + + Failed to load ripper module + + + Looking up album via + + + No CD drives found + + + Paused + + + retry + + + Detecting drives + \ No newline at end of file diff --git a/CUERipper/frmCUERipper.Designer.cs b/CUERipper/frmCUERipper.Designer.cs index 7b5abc0..5d50782 100644 --- a/CUERipper/frmCUERipper.Designer.cs +++ b/CUERipper/frmCUERipper.Designer.cs @@ -51,21 +51,22 @@ namespace CUERipper this.lblWriteOffset = new System.Windows.Forms.Label(); this.checkBoxEACMode = new System.Windows.Forms.CheckBox(); this.groupBoxSettings = new System.Windows.Forms.GroupBox(); - this.bnComboBoxLosslessOrNot = new BBBNOVA.BNComboBox(); + this.bnComboBoxLosslessOrNot = new CUEControls.BNComboBox(); this.losslessOrNotBindingSource = new System.Windows.Forms.BindingSource(this.components); this.bindingSourceCR = new System.Windows.Forms.BindingSource(this.components); - this.bnComboBoxEncoder = new BBBNOVA.BNComboBox(); + this.bnComboBoxEncoder = new CUEControls.BNComboBox(); this.encodersBindingSource = new System.Windows.Forms.BindingSource(this.components); this.labelSecureMode = new System.Windows.Forms.Label(); - this.bnComboBoxFormat = new BBBNOVA.BNComboBox(); + this.bnComboBoxFormat = new CUEControls.BNComboBox(); this.formatsBindingSource = new System.Windows.Forms.BindingSource(this.components); this.labelEncoderMinMode = new System.Windows.Forms.Label(); - this.bnComboBoxImage = new BBBNOVA.BNComboBox(); + this.bnComboBoxImage = new CUEControls.BNComboBox(); this.cUEStylesBindingSource = new System.Windows.Forms.BindingSource(this.components); this.labelEncoderMaxMode = new System.Windows.Forms.Label(); this.labelEncoderMode = new System.Windows.Forms.Label(); this.trackBarEncoderMode = new System.Windows.Forms.TrackBar(); this.trackBarSecureMode = new System.Windows.Forms.TrackBar(); + this.imageListChecked = new System.Windows.Forms.ImageList(this.components); this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); this.progressBarErrors = new ProgressODoom.ProgressBarEx(); this.plainBackgroundPainter1 = new ProgressODoom.PlainBackgroundPainter(); @@ -74,15 +75,14 @@ namespace CUERipper this.gradientGlossPainter1 = new ProgressODoom.GradientGlossPainter(); this.progressBarCD = new ProgressODoom.ProgressBarEx(); this.plainProgressPainter2 = new ProgressODoom.PlainProgressPainter(); - this.comboBoxOutputFormat = new System.Windows.Forms.ComboBox(); this.txtOutputPath = new System.Windows.Forms.TextBox(); this.toolTip1 = new System.Windows.Forms.ToolTip(this.components); - this.bnComboBoxRelease = new BBBNOVA.BNComboBox(); + this.bnComboBoxRelease = new CUEControls.BNComboBox(); this.releasesBindingSource = new System.Windows.Forms.BindingSource(this.components); this.imageListMetadataSource = new System.Windows.Forms.ImageList(this.components); - this.bnComboBoxDrives = new BBBNOVA.BNComboBox(); + this.bnComboBoxDrives = new CUEControls.BNComboBox(); this.drivesBindingSource = new System.Windows.Forms.BindingSource(this.components); - this.bnComboBoxOutputFormat = new BBBNOVA.BNComboBox(); + this.bnComboBoxOutputFormat = new CUEControls.BNComboBox(); this.statusStrip1.SuspendLayout(); this.contextMenuStripRelease.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.numericWriteOffset)).BeginInit(); @@ -202,8 +202,9 @@ namespace CUERipper // buttonGo // resources.ApplyResources(this.buttonGo, "buttonGo"); + this.buttonGo.BackColor = System.Drawing.Color.Transparent; this.buttonGo.Name = "buttonGo"; - this.buttonGo.UseVisualStyleBackColor = true; + this.buttonGo.UseVisualStyleBackColor = false; this.buttonGo.Click += new System.EventHandler(this.buttonGo_Click); // // buttonAbort @@ -287,13 +288,14 @@ namespace CUERipper this.bnComboBoxLosslessOrNot.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; this.bnComboBoxLosslessOrNot.DropDownWidth = 80; this.bnComboBoxLosslessOrNot.ForeColor = System.Drawing.SystemColors.ControlText; + this.bnComboBoxLosslessOrNot.ImageKeyMember = "ImageKey"; this.bnComboBoxLosslessOrNot.ImageList = null; this.bnComboBoxLosslessOrNot.IsDroppedDown = false; resources.ApplyResources(this.bnComboBoxLosslessOrNot, "bnComboBoxLosslessOrNot"); this.bnComboBoxLosslessOrNot.MaxDropDownItems = 8; this.bnComboBoxLosslessOrNot.MinimumSize = new System.Drawing.Size(40, 21); this.bnComboBoxLosslessOrNot.Name = "bnComboBoxLosslessOrNot"; - this.bnComboBoxLosslessOrNot.Radius = ((BBBNOVA.BNRadius)(resources.GetObject("bnComboBoxLosslessOrNot.Radius"))); + this.bnComboBoxLosslessOrNot.Radius = ((CUEControls.BNRadius)(resources.GetObject("bnComboBoxLosslessOrNot.Radius"))); this.bnComboBoxLosslessOrNot.SelectedIndex = -1; this.bnComboBoxLosslessOrNot.SelectedItem = null; this.bnComboBoxLosslessOrNot.Sorted = false; @@ -322,7 +324,7 @@ namespace CUERipper this.bnComboBoxEncoder.MaxDropDownItems = 8; this.bnComboBoxEncoder.MinimumSize = new System.Drawing.Size(40, 21); this.bnComboBoxEncoder.Name = "bnComboBoxEncoder"; - this.bnComboBoxEncoder.Radius = ((BBBNOVA.BNRadius)(resources.GetObject("bnComboBoxEncoder.Radius"))); + this.bnComboBoxEncoder.Radius = ((CUEControls.BNRadius)(resources.GetObject("bnComboBoxEncoder.Radius"))); this.bnComboBoxEncoder.SelectedIndex = -1; this.bnComboBoxEncoder.SelectedItem = null; this.bnComboBoxEncoder.Sorted = false; @@ -353,7 +355,7 @@ namespace CUERipper this.bnComboBoxFormat.MaxDropDownItems = 8; this.bnComboBoxFormat.MinimumSize = new System.Drawing.Size(40, 21); this.bnComboBoxFormat.Name = "bnComboBoxFormat"; - this.bnComboBoxFormat.Radius = ((BBBNOVA.BNRadius)(resources.GetObject("bnComboBoxFormat.Radius"))); + this.bnComboBoxFormat.Radius = ((CUEControls.BNRadius)(resources.GetObject("bnComboBoxFormat.Radius"))); this.bnComboBoxFormat.SelectedIndex = -1; this.bnComboBoxFormat.SelectedItem = null; this.bnComboBoxFormat.Sorted = false; @@ -383,7 +385,7 @@ namespace CUERipper this.bnComboBoxImage.MaxDropDownItems = 8; this.bnComboBoxImage.MinimumSize = new System.Drawing.Size(40, 21); this.bnComboBoxImage.Name = "bnComboBoxImage"; - this.bnComboBoxImage.Radius = ((BBBNOVA.BNRadius)(resources.GetObject("bnComboBoxImage.Radius"))); + this.bnComboBoxImage.Radius = ((CUEControls.BNRadius)(resources.GetObject("bnComboBoxImage.Radius"))); this.bnComboBoxImage.SelectedIndex = -1; this.bnComboBoxImage.SelectedItem = null; this.bnComboBoxImage.Sorted = false; @@ -418,6 +420,15 @@ namespace CUERipper this.trackBarSecureMode.Name = "trackBarSecureMode"; this.trackBarSecureMode.Scroll += new System.EventHandler(this.trackBarSecureMode_Scroll); // + // imageListChecked + // + this.imageListChecked.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("imageListChecked.ImageStream"))); + this.imageListChecked.TransparentColor = System.Drawing.Color.Transparent; + this.imageListChecked.Images.SetKeyName(0, "checked"); + this.imageListChecked.Images.SetKeyName(1, "unchecked"); + this.imageListChecked.Images.SetKeyName(2, "disabled"); + this.imageListChecked.Images.SetKeyName(3, "mix"); + // // toolStripMenuItem1 // this.toolStripMenuItem1.Image = global::CUERipper.Properties.Resources.cddb; @@ -491,22 +502,8 @@ namespace CUERipper this.plainProgressPainter2.LeadingEdge = System.Drawing.Color.Transparent; this.plainProgressPainter2.ProgressBorderPainter = null; // - // comboBoxOutputFormat - // - this.comboBoxOutputFormat.AutoCompleteMode = System.Windows.Forms.AutoCompleteMode.SuggestAppend; - this.comboBoxOutputFormat.AutoCompleteSource = System.Windows.Forms.AutoCompleteSource.ListItems; - this.comboBoxOutputFormat.FormattingEnabled = true; - resources.ApplyResources(this.comboBoxOutputFormat, "comboBoxOutputFormat"); - this.comboBoxOutputFormat.Name = "comboBoxOutputFormat"; - this.toolTip1.SetToolTip(this.comboBoxOutputFormat, resources.GetString("comboBoxOutputFormat.ToolTip")); - this.comboBoxOutputFormat.SelectedIndexChanged += new System.EventHandler(this.comboBoxOutputFormat_SelectedIndexChanged); - this.comboBoxOutputFormat.MouseLeave += new System.EventHandler(this.comboBoxOutputFormat_MouseLeave); - this.comboBoxOutputFormat.TextUpdate += new System.EventHandler(this.comboBoxOutputFormat_TextUpdate); - // // txtOutputPath // - this.txtOutputPath.AutoCompleteMode = System.Windows.Forms.AutoCompleteMode.SuggestAppend; - this.txtOutputPath.AutoCompleteSource = System.Windows.Forms.AutoCompleteSource.FileSystem; resources.ApplyResources(this.txtOutputPath, "txtOutputPath"); this.txtOutputPath.Name = "txtOutputPath"; this.txtOutputPath.ReadOnly = true; @@ -529,7 +526,7 @@ namespace CUERipper this.bnComboBoxRelease.MaxDropDownItems = 8; this.bnComboBoxRelease.MinimumSize = new System.Drawing.Size(61, 21); this.bnComboBoxRelease.Name = "bnComboBoxRelease"; - this.bnComboBoxRelease.Radius = ((BBBNOVA.BNRadius)(resources.GetObject("bnComboBoxRelease.Radius"))); + this.bnComboBoxRelease.Radius = ((CUEControls.BNRadius)(resources.GetObject("bnComboBoxRelease.Radius"))); this.bnComboBoxRelease.SelectedIndex = -1; this.bnComboBoxRelease.SelectedItem = null; this.bnComboBoxRelease.Sorted = false; @@ -545,8 +542,8 @@ namespace CUERipper // this.imageListMetadataSource.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("imageListMetadataSource.ImageStream"))); this.imageListMetadataSource.TransparentColor = System.Drawing.Color.Transparent; - this.imageListMetadataSource.Images.SetKeyName(0, "musicbrainz.ico"); - this.imageListMetadataSource.Images.SetKeyName(1, "freedb16.png"); + this.imageListMetadataSource.Images.SetKeyName(0, "musicbrainz"); + this.imageListMetadataSource.Images.SetKeyName(1, "freedb"); // // bnComboBoxDrives // @@ -563,7 +560,7 @@ namespace CUERipper this.bnComboBoxDrives.MaxDropDownItems = 8; this.bnComboBoxDrives.MinimumSize = new System.Drawing.Size(61, 21); this.bnComboBoxDrives.Name = "bnComboBoxDrives"; - this.bnComboBoxDrives.Radius = ((BBBNOVA.BNRadius)(resources.GetObject("bnComboBoxDrives.Radius"))); + this.bnComboBoxDrives.Radius = ((CUEControls.BNRadius)(resources.GetObject("bnComboBoxDrives.Radius"))); this.bnComboBoxDrives.SelectedIndex = -1; this.bnComboBoxDrives.SelectedItem = null; this.bnComboBoxDrives.Sorted = false; @@ -587,11 +584,12 @@ namespace CUERipper this.bnComboBoxOutputFormat.MaxDropDownItems = 8; this.bnComboBoxOutputFormat.MinimumSize = new System.Drawing.Size(40, 21); this.bnComboBoxOutputFormat.Name = "bnComboBoxOutputFormat"; - this.bnComboBoxOutputFormat.Radius = ((BBBNOVA.BNRadius)(resources.GetObject("bnComboBoxOutputFormat.Radius"))); + this.bnComboBoxOutputFormat.Radius = ((CUEControls.BNRadius)(resources.GetObject("bnComboBoxOutputFormat.Radius"))); this.bnComboBoxOutputFormat.SelectedIndex = -1; this.bnComboBoxOutputFormat.SelectedItem = null; this.bnComboBoxOutputFormat.Sorted = false; this.bnComboBoxOutputFormat.DroppedDown += new System.EventHandler(this.bnComboBoxOutputFormat_DroppedDown); + this.bnComboBoxOutputFormat.Leave += new System.EventHandler(this.bnComboBoxOutputFormat_Leave); this.bnComboBoxOutputFormat.MouseLeave += new System.EventHandler(this.bnComboBoxOutputFormat_MouseLeave); this.bnComboBoxOutputFormat.TextChanged += new System.EventHandler(this.bnComboBoxOutputFormat_TextChanged); // @@ -603,7 +601,6 @@ namespace CUERipper this.Controls.Add(this.bnComboBoxRelease); this.Controls.Add(this.bnComboBoxDrives); this.Controls.Add(this.bnComboBoxOutputFormat); - this.Controls.Add(this.comboBoxOutputFormat); this.Controls.Add(this.progressBarErrors); this.Controls.Add(this.progressBarCD); this.Controls.Add(this.groupBoxSettings); @@ -677,24 +674,24 @@ namespace CUERipper private ProgressODoom.ProgressBarEx progressBarCD; private ProgressODoom.PlainProgressPainter plainProgressPainter2; private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabelMusicBrainz; - private System.Windows.Forms.ComboBox comboBoxOutputFormat; private System.Windows.Forms.TextBox txtOutputPath; private System.Windows.Forms.ToolTip toolTip1; - private BBBNOVA.BNComboBox bnComboBoxImage; + private CUEControls.BNComboBox bnComboBoxImage; private System.Windows.Forms.BindingSource bindingSourceCR; private System.Windows.Forms.ImageList imageListMetadataSource; private System.Windows.Forms.BindingSource cUEStylesBindingSource; - private BBBNOVA.BNComboBox bnComboBoxRelease; + private CUEControls.BNComboBox bnComboBoxRelease; private System.Windows.Forms.BindingSource releasesBindingSource; - private BBBNOVA.BNComboBox bnComboBoxDrives; + private CUEControls.BNComboBox bnComboBoxDrives; private System.Windows.Forms.BindingSource drivesBindingSource; - private BBBNOVA.BNComboBox bnComboBoxFormat; + private CUEControls.BNComboBox bnComboBoxFormat; private System.Windows.Forms.BindingSource formatsBindingSource; - private BBBNOVA.BNComboBox bnComboBoxEncoder; + private CUEControls.BNComboBox bnComboBoxEncoder; private System.Windows.Forms.BindingSource encodersBindingSource; - private BBBNOVA.BNComboBox bnComboBoxLosslessOrNot; + private CUEControls.BNComboBox bnComboBoxLosslessOrNot; private System.Windows.Forms.BindingSource losslessOrNotBindingSource; - private BBBNOVA.BNComboBox bnComboBoxOutputFormat; + private CUEControls.BNComboBox bnComboBoxOutputFormat; + private System.Windows.Forms.ImageList imageListChecked; } } diff --git a/CUERipper/frmCUERipper.cs b/CUERipper/frmCUERipper.cs index 5064d43..f8c0138 100644 --- a/CUERipper/frmCUERipper.cs +++ b/CUERipper/frmCUERipper.cs @@ -16,6 +16,7 @@ using CUETools.CDImage; using CUETools.Codecs; using CUETools.Processor; using CUETools.Ripper; +using CUEControls; using MusicBrainz; using Freedb; @@ -55,7 +56,11 @@ namespace CUERipper }; private BindingList cueStyles = new BindingList { "image", "tracks" }; - private BindingList losslessOrNot = new BindingList { "lossless", "lossy" }; + //private BindingList losslessOrNot = new BindingList { "lossless", "lossy" }; + private BindingList> losslessOrNot = new BindingList> { + new BNComboBoxItem("lossless", "checked", AudioEncoderType.Lossless), + new BNComboBoxItem("lossy", "unchecked", AudioEncoderType.Lossy) + }; private BindingList releases = new BindingList(); private BindingList drives = new BindingList(); private BindingList formats = new BindingList(); @@ -69,7 +74,7 @@ namespace CUERipper } } - public BindingList LosslessOrNot + public BindingList> LosslessOrNot { get { @@ -126,16 +131,11 @@ namespace CUERipper SetupControls(); int iFormat, nFormats = sr.LoadInt32("OutputPathUseTemplates", 0, 10) ?? 0; - for (iFormat = 0; iFormat < OutputPathUseTemplates.Length; iFormat++) - comboBoxOutputFormat.Items.Add(OutputPathUseTemplates[iFormat]); - for (iFormat = nFormats - 1; iFormat >= 0; iFormat--) - comboBoxOutputFormat.Items.Add(sr.Load(string.Format("OutputPathUseTemplate{0}", iFormat)) ?? ""); for (iFormat = 0; iFormat < OutputPathUseTemplates.Length; iFormat++) bnComboBoxOutputFormat.Items.Add(OutputPathUseTemplates[iFormat]); for (iFormat = nFormats - 1; iFormat >= 0; iFormat--) bnComboBoxOutputFormat.Items.Add(sr.Load(string.Format("OutputPathUseTemplate{0}", iFormat)) ?? ""); - comboBoxOutputFormat.Text = sr.Load("PathFormat") ?? "%music%\\%artist%\\[%year% - ]%album%\\%artist% - %album%.cue"; bnComboBoxOutputFormat.Text = sr.Load("PathFormat") ?? "%music%\\%artist%\\[%year% - ]%album%\\%artist% - %album%.cue"; checkBoxEACMode.Checked = _config.createEACLOG; SelectedOutputAudioType = (AudioEncoderType?)sr.LoadInt32("OutputAudioType", null, null) ?? AudioEncoderType.Lossless; @@ -176,26 +176,22 @@ namespace CUERipper base.WndProc(ref m); } - private void UpdateDrives() + private void DrivesLookup(object o) { - buttonGo.Enabled = false; - foreach (DriveInfo driveInfo in drives) - if (driveInfo.drive != null) - driveInfo.drive.Close(); - drives.Clear(); + // Lookup drives.RaiseListChangedEvents = false; - listTracks.Items.Clear(); - releases.Clear(); - selectedRelease = null; - selectedDriveInfo = null; - bnComboBoxRelease.Text = ""; foreach (char drive in CDDrivesList.DrivesAvailable()) { - ICDRipper reader = Activator.CreateInstance(CUEProcessorPlugins.ripper) as ICDRipper; + ICDRipper reader = null; string arName = null; int driveOffset; try { + this.BeginInvoke((MethodInvoker)delegate() + { + toolStripStatusLabel1.Text = Properties.Resources.DetectingDrives + ": " + drive + ":\\..."; + }); + reader = Activator.CreateInstance(CUEProcessorPlugins.ripper) as ICDRipper; reader.Open(drive); arName = reader.ARName; reader.Close(); @@ -217,13 +213,41 @@ namespace CUERipper reader.DriveOffset = driveOffset; drives.Add(new DriveInfo(m_icon_mgr, drive + ":\\", reader)); } - if (drives.Count == 0) + _workThread = null; + this.BeginInvoke((MethodInvoker)delegate() { - bnComboBoxDrives.Text = "No CD drives found"; + SetupControls(); + drives.RaiseListChangedEvents = true; + drives.ResetBindings(); + if (drives.Count == 0) + bnComboBoxDrives.Text = Properties.Resources.NoDrives; + }); + } + + private void UpdateDrives() + { + buttonGo.Enabled = false; + foreach (DriveInfo driveInfo in drives) + if (driveInfo.drive != null) + driveInfo.drive.Close(); + drives.Clear(); + listTracks.Items.Clear(); + releases.Clear(); + selectedRelease = null; + selectedDriveInfo = null; + bnComboBoxRelease.Text = ""; + + if (CUEProcessorPlugins.ripper == null) + { + bnComboBoxDrives.Text = Properties.Resources.FailedToLoadRipperModule; + return; } - drives.RaiseListChangedEvents = true; - drives.ResetBindings(); - //bnComboBoxDrives.SelectedIndex = 0; + + _workThread = new Thread(DrivesLookup); + _workThread.Priority = ThreadPriority.BelowNormal; + _workThread.IsBackground = true; + SetupControls(); + _workThread.Start(this); } bool outputFormatVisible = false; @@ -232,14 +256,13 @@ namespace CUERipper { bool running = _workThread != null; - bnComboBoxOutputFormat.Visible = comboBoxOutputFormat.Visible = outputFormatVisible; + bnComboBoxOutputFormat.Visible = outputFormatVisible; txtOutputPath.Visible = !outputFormatVisible; txtOutputPath.Enabled = !running && !outputFormatVisible; bnComboBoxRelease.Enabled = !running && releases.Count > 0; + bnComboBoxDrives.Enabled = !running && drives.Count > 0; bnComboBoxOutputFormat.Enabled = - comboBoxOutputFormat.Enabled = listTracks.Enabled = - bnComboBoxDrives.Enabled = groupBoxSettings.Enabled = !running; buttonPause.Visible = buttonPause.Enabled = buttonAbort.Visible = buttonAbort.Enabled = running; buttonGo.Visible = buttonGo.Enabled = !running; @@ -263,7 +286,7 @@ namespace CUERipper { this.BeginInvoke((MethodInvoker)delegate() { - toolStripStatusLabel1.Text = "Paused..."; + toolStripStatusLabel1.Text = Properties.Resources.PausedMessage + "..."; }); Monitor.Wait(_startStop); } @@ -290,9 +313,10 @@ namespace CUERipper double speed = elapsed.TotalSeconds > 0 ? processed / elapsed.TotalSeconds / 75 : 1.0; double percentTrck = (double)(e.Position - e.PassStart) / (e.PassEnd - e.PassStart); + string retry = e.Pass > 0 ? " (" + Properties.Resources.Retry + " " + e.Pass.ToString() + ")" : ""; string status = (elapsed.TotalSeconds > 0 && e.Pass >= 0) ? - string.Format("{0} @{1:00.00}x{2}...", e.Action, speed, e.Pass > 0 ? " (Retry " + e.Pass.ToString() + ")" : "") : - string.Format("{0}{1}...", e.Action, e.Pass > 0 ? " (Retry " + e.Pass.ToString() + ")" : ""); + string.Format("{0} @{1:00.00}x{2}...", e.Action, speed, retry) : + string.Format("{0}{1}...", e.Action, retry); this.BeginInvoke((MethodInvoker)delegate() { toolStripStatusLabel1.Text = status; @@ -317,23 +341,14 @@ namespace CUERipper { cueSheet.Go(); - bool submit = cueSheet.CTDB.AccResult == HttpStatusCode.NotFound || - cueSheet.CTDB.AccResult == HttpStatusCode.OK; - //_cueSheet.CTDB.AccResult == HttpStatusCode.NoContent; - DBEntry confirm = null; - - submit &= audioSource.CorrectionQuality > 0; - - foreach (DBEntry entry in cueSheet.CTDB.Entries) - if (entry.toc.TrackOffsets == selectedDriveInfo.drive.TOC.TrackOffsets && !entry.hasErrors) - confirm = entry; - - for (int iSector = 0; iSector < (int)cueSheet.TOC.AudioLength; iSector++) - if (audioSource.Errors[iSector]) - submit = false; - - if (submit) + if ((cueSheet.CTDB.AccResult == HttpStatusCode.NotFound || cueSheet.CTDB.AccResult == HttpStatusCode.OK) + && audioSource.CorrectionQuality > 0 && audioSource.ErrorsCount == 0) { + DBEntry confirm = null; + foreach (DBEntry entry in cueSheet.CTDB.Entries) + if (entry.toc.TrackOffsets == selectedDriveInfo.drive.TOC.TrackOffsets && !entry.hasErrors) + confirm = entry; + if (confirm != null) cueSheet.CTDB.Confirm(confirm); else @@ -343,8 +358,20 @@ namespace CUERipper cueSheet.Artist, cueSheet.Title); } - //CUESheet.WriteText(_pathOut, _cueSheet.CUESheetContents(_style)); - //CUESheet.WriteText(Path.ChangeExtension(_pathOut, ".log"), _cueSheet.LOGContents()); + + bool canFix = false; + if (cueSheet.CTDB.AccResult == HttpStatusCode.OK && audioSource.ErrorsCount != 0) + { + foreach (DBEntry entry in cueSheet.CTDB.Entries) + if (entry.hasErrors && entry.canRecover) + canFix = true; + } + this.Invoke((MethodInvoker)delegate() + { + DialogResult dlgRes = audioSource.ErrorsCount != 0 ? + MessageBox.Show(this, cueSheet.GenerateAccurateRipStatus() + (canFix ? "\n" + Properties.Resources.DoneRippingRepair : "") + ".", Properties.Resources.DoneRippingErrors, MessageBoxButtons.OK, MessageBoxIcon.Error) : + MessageBox.Show(this, cueSheet.GenerateAccurateRipStatus() + ".", Properties.Resources.DoneRipping, MessageBoxButtons.OK, MessageBoxIcon.Information); + }); } catch (StopException) { @@ -354,10 +381,10 @@ namespace CUERipper { this.Invoke((MethodInvoker)delegate() { - string message = "Exception"; + string message = Properties.Resources.ExceptionMessage; for (Exception e = ex; e != null; e = e.InnerException) message += ": " + e.Message; - DialogResult dlgRes = MessageBox.Show(this, message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + DialogResult dlgRes = MessageBox.Show(this, message, Properties.Resources.ExceptionMessage, MessageBoxButtons.OK, MessageBoxIcon.Error); }); } #endif @@ -390,13 +417,6 @@ namespace CUERipper if (selectedDriveInfo == null) return; - if (!comboBoxOutputFormat.Items.Contains(comboBoxOutputFormat.Text) && comboBoxOutputFormat.Text.Contains("%")) - { - comboBoxOutputFormat.Items.Insert(OutputPathUseTemplates.Length, comboBoxOutputFormat.Text); - if (comboBoxOutputFormat.Items.Count > OutputPathUseTemplates.Length + 10) - comboBoxOutputFormat.Items.RemoveAt(OutputPathUseTemplates.Length + 10); - } - if (!bnComboBoxOutputFormat.Items.Contains(bnComboBoxOutputFormat.Text) && bnComboBoxOutputFormat.Text.Contains("%")) { bnComboBoxOutputFormat.Items.Insert(OutputPathUseTemplates.Length, bnComboBoxOutputFormat.Text); @@ -460,7 +480,7 @@ namespace CUERipper //_progress.input = e.Uri.ToString(); this.BeginInvoke((MethodInvoker)delegate() { - toolStripStatusLabel1.Text = "Looking up album via " + (e == null ? "FreeDB" : "MusicBrainz"); + toolStripStatusLabel1.Text = Properties.Resources.LookingUpVia + " " + (e == null ? "FreeDB" : "MusicBrainz") + "..."; toolStripProgressBar1.Value = (100 + 2 * toolStripProgressBar1.Value) / 3; }); } @@ -492,12 +512,12 @@ namespace CUERipper if (release != null) { r.metadata.FillFromMusicBrainz(release); - r.ImageKey = "musicbrainz.ico"; + r.ImageKey = "musicbrainz"; } else if (cdEntry != null) { r.metadata.FillFromFreedb(cdEntry); - r.ImageKey = "freedb16.png"; + r.ImageKey = "freedb"; } else { @@ -521,12 +541,12 @@ namespace CUERipper cueSheet.OpenCD(audioSource); cueSheet.Action = CUEAction.Encode; - this.BeginInvoke((MethodInvoker)delegate() { toolStripStatusLabel1.Text = "Contacting CTDB database..."; }); + this.BeginInvoke((MethodInvoker)delegate() { toolStripStatusLabel1.Text = Properties.Resources.LookingUpVia + " CTDB..."; }); cueSheet.UseCUEToolsDB(true, "CUERipper 2.0.7: " + selectedDriveInfo.drive.ARName); cueSheet.CTDB.UploadHelper.onProgress += new EventHandler(UploadProgress); - this.BeginInvoke((MethodInvoker)delegate() { toolStripStatusLabel1.Text = "Contacting AccurateRip database..."; }); + this.BeginInvoke((MethodInvoker)delegate() { toolStripStatusLabel1.Text = Properties.Resources.LookingUpVia + " AccurateRip..."; }); cueSheet.UseAccurateRip(); - this.BeginInvoke((MethodInvoker)delegate() { toolStripStatusLabel1.Text = "Looking album info..."; }); + this.BeginInvoke((MethodInvoker)delegate() { toolStripStatusLabel1.Text = Properties.Resources.LookingUpVia + " MusicBrainz..."; }); General.SetCUELine(cueSheet.Attributes, "REM", "DISCID", AccurateRipVerify.CalculateCDDBId(audioSource.TOC), false); General.SetCUELine(cueSheet.Attributes, "REM", "COMMENT", _config.createEACLOG ? "ExactAudioCopy v0.99pb4" : audioSource.RipperVersion, true); @@ -555,7 +575,7 @@ namespace CUERipper m_freedb.UserName = "gchudov"; m_freedb.Hostname = "gmail.com"; m_freedb.ClientName = "CUERipper"; - m_freedb.Version = "1.0"; + m_freedb.Version = "2.0.7"; m_freedb.SetDefaultSiteAddress(Properties.Settings.Default.MAIN_FREEDB_SITEADDRESS); QueryResult queryResult; @@ -612,16 +632,16 @@ namespace CUERipper releases.RaiseListChangedEvents = true; releases.ResetBindings(); //bnComboBoxRelease.SelectedIndex = 0; - toolStripStatusAr.Visible = cueSheet.ArVerify.ARStatus == null; - toolStripStatusAr.Text = cueSheet.ArVerify.ARStatus == null ? cueSheet.ArVerify.WorstTotal().ToString() : "?"; + toolStripStatusAr.Enabled = cueSheet.ArVerify.ARStatus == null; + toolStripStatusAr.Text = cueSheet.ArVerify.ARStatus == null ? cueSheet.ArVerify.WorstTotal().ToString() : ""; toolStripStatusAr.ToolTipText = "AccurateRip: " + (cueSheet.ArVerify.ARStatus ?? "found") + "."; - toolStripStatusCTDB.Visible = cueSheet.CTDB.DBStatus == null; + toolStripStatusCTDB.Enabled = cueSheet.CTDB.DBStatus == null; toolStripStatusCTDB.Text = cueSheet.CTDB.DBStatus == null ? cueSheet.CTDB.Total.ToString() : ""; toolStripStatusCTDB.ToolTipText = "CUETools DB: " + (cueSheet.CTDB.DBStatus ?? "found") + "."; + toolStripStatusLabelMusicBrainz.Enabled = true; toolStripStatusLabelMusicBrainz.BorderStyle = results.Count > 0 ? Border3DStyle.SunkenInner : Border3DStyle.RaisedInner; - toolStripStatusLabelMusicBrainz.Visible = true; - toolStripStatusLabelMusicBrainz.Text = results.Count > 0 ? results.Count.ToString() : "-"; - toolStripStatusLabelMusicBrainz.ToolTipText = "Musicbrainz: " + results.Count.ToString() + " entries found."; + toolStripStatusLabelMusicBrainz.Text = results.Count > 0 ? results.Count.ToString() : ""; + toolStripStatusLabelMusicBrainz.ToolTipText = "Musicbrainz: " + (results.Count > 0 ? results.Count.ToString() + " entries found." : "click to submit."); }); } @@ -631,9 +651,15 @@ namespace CUERipper if (selectedDriveInfo == null) return; - toolStripStatusAr.Visible = false; - toolStripStatusCTDB.Visible = false; - toolStripStatusLabelMusicBrainz.Visible = false; + toolStripStatusAr.Enabled = false; + toolStripStatusAr.Text = ""; + toolStripStatusAr.ToolTipText = ""; + toolStripStatusCTDB.Enabled = false; + toolStripStatusCTDB.Text = ""; + toolStripStatusCTDB.ToolTipText = ""; + toolStripStatusLabelMusicBrainz.Enabled = false; + toolStripStatusLabelMusicBrainz.Text = ""; + toolStripStatusLabelMusicBrainz.ToolTipText = ""; buttonGo.Enabled = false; listTracks.Items.Clear(); releases.Clear(); @@ -734,11 +760,11 @@ namespace CUERipper //sw.Save("CreateM3U", _config.createM3U); sw.Save("OutputAudioType", (int)SelectedOutputAudioType); sw.Save("ComboImage", bnComboBoxImage.SelectedIndex); - sw.Save("PathFormat", comboBoxOutputFormat.Text); + sw.Save("PathFormat", bnComboBoxOutputFormat.Text); sw.Save("SecureMode", trackBarSecureMode.Value); - sw.Save("OutputPathUseTemplates", comboBoxOutputFormat.Items.Count - OutputPathUseTemplates.Length); - for (int iFormat = comboBoxOutputFormat.Items.Count - 1; iFormat >= OutputPathUseTemplates.Length; iFormat--) - sw.Save(string.Format("OutputPathUseTemplate{0}", iFormat - OutputPathUseTemplates.Length), comboBoxOutputFormat.Items[iFormat].ToString()); + sw.Save("OutputPathUseTemplates", bnComboBoxOutputFormat.Items.Count - OutputPathUseTemplates.Length); + for (int iFormat = bnComboBoxOutputFormat.Items.Count - 1; iFormat >= OutputPathUseTemplates.Length; iFormat--) + sw.Save(string.Format("OutputPathUseTemplate{0}", iFormat - OutputPathUseTemplates.Length), bnComboBoxOutputFormat.Items[iFormat].ToString()); sw.Close(); } @@ -777,24 +803,17 @@ namespace CUERipper { get { - return bnComboBoxLosslessOrNot.Text == "lossy" ? AudioEncoderType.Lossy - : bnComboBoxLosslessOrNot.Text == "hybrid" ? AudioEncoderType.Hybrid - : AudioEncoderType.Lossless; + return (bnComboBoxLosslessOrNot.SelectedItem as BNComboBoxItem).Value; } set { - switch (value) - { - case AudioEncoderType.Hybrid: - bnComboBoxLosslessOrNot.SelectedItem = "hybrid"; - break; - case AudioEncoderType.Lossy: - bnComboBoxLosslessOrNot.SelectedItem = "lossy"; - break; - default: - bnComboBoxLosslessOrNot.SelectedItem = "lossless"; - break; - } + foreach (BNComboBoxItem item in losslessOrNot) + if (value == item.Value) + { + bnComboBoxLosslessOrNot.SelectedItem = item; + return; + } + throw new Exception("invalid value"); } } @@ -863,7 +882,7 @@ namespace CUERipper private void frmCUERipper_KeyDown(object sender, KeyEventArgs e) { if (_workThread == null && e.KeyCode == Keys.F5) - UpdateDrive(); + UpdateDrives(); } private void comboBoxOutputFormat_SelectedIndexChanged(object sender, EventArgs e) @@ -879,29 +898,6 @@ namespace CUERipper style == CUEStyle.SingleFileWithCUE ? "." + selectedFormat.ToString() : ".cue", CUEAction.Encode, null); } - private void comboBoxOutputFormat_MouseLeave(object sender, EventArgs e) - { - if (!outputFormatVisible) - return; - outputFormatVisible = false; - bnComboBoxOutputFormat.Visible = false; - txtOutputPath.Enabled = true; - txtOutputPath.Visible = true; - } - - private void txtOutputPath_Enter(object sender, EventArgs e) - { - if (outputFormatVisible) - return; - outputFormatVisible = true; - //comboBoxOutputFormat.Visible = true; - bnComboBoxOutputFormat.Visible = true; - bnComboBoxOutputFormat.Focus(); - //bnComboBoxOutputFormat.Select(); - txtOutputPath.Enabled = false; - txtOutputPath.Visible = false; - } - private void bnComboBoxRelease_SelectedIndexChanged(object sender, EventArgs e) { UpdateRelease(); @@ -1006,9 +1002,30 @@ namespace CUERipper comboBoxOutputFormat_TextUpdate(sender, e); } + private void txtOutputPath_Enter(object sender, EventArgs e) + { + if (outputFormatVisible) + return; + outputFormatVisible = true; + bnComboBoxOutputFormat.Visible = true; + bnComboBoxOutputFormat.Focus(); + txtOutputPath.Enabled = false; + txtOutputPath.Visible = false; + } + private void bnComboBoxOutputFormat_MouseLeave(object sender, EventArgs e) { - if (!outputFormatVisible) + //if (!outputFormatVisible) + // return; + //outputFormatVisible = false; + //bnComboBoxOutputFormat.Visible = false; + //txtOutputPath.Enabled = true; + //txtOutputPath.Visible = true; + } + + private void bnComboBoxOutputFormat_DroppedDown(object sender, EventArgs e) + { + if (!outputFormatVisible || bnComboBoxOutputFormat.IsDroppedDown || bnComboBoxOutputFormat.Focused) return; outputFormatVisible = false; bnComboBoxOutputFormat.Visible = false; @@ -1016,14 +1033,9 @@ namespace CUERipper txtOutputPath.Visible = true; } - private void bnComboBoxOutputFormat_DroppedDown(object sender, EventArgs e) + private void bnComboBoxOutputFormat_Leave(object sender, EventArgs e) { - if (!outputFormatVisible || bnComboBoxOutputFormat.IsDroppedDown) - return; - outputFormatVisible = false; - bnComboBoxOutputFormat.Visible = false; - txtOutputPath.Enabled = true; - txtOutputPath.Visible = true; + bnComboBoxOutputFormat_DroppedDown(sender, e); } } diff --git a/CUERipper/frmCUERipper.resx b/CUERipper/frmCUERipper.resx index 93d83a0..b28f8cf 100644 --- a/CUERipper/frmCUERipper.resx +++ b/CUERipper/frmCUERipper.resx @@ -197,7 +197,7 @@ $this - 11 + 10 @@ -243,7 +243,7 @@ 2 - 376, 17 + 357, 17 Double-click to edit track names @@ -258,7 +258,7 @@ $this - 9 + 8 Top, Left, Right @@ -288,7 +288,7 @@ $this - 10 + 9 Top, Left, Right @@ -321,7 +321,7 @@ $this - 12 + 11 Top, Left, Right @@ -354,7 +354,7 @@ $this - 13 + 12 17, 17 @@ -459,7 +459,7 @@ 11 - 631, 456 + 369, 95 210, 56 @@ -467,14 +467,6 @@ 6, 19 - - - AAEAAAD/////AQAAAAAAAAAMAgAAAEJDVUVDb250cm9scywgVmVyc2lvbj0yLjAuNy4wLCBDdWx0dXJl - PW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPW51bGwFAQAAABBCQkJOT1ZBLkJOUmFkaXVzBAAAAAhfdG9w - TGVmdAlfdG9wUmlnaHQLX2JvdHRvbUxlZnQMX2JvdHRvbVJpZ2h0AAAAAAgICAgCAAAAAgAAAAYAAAAC - AAAAAgAAAAs= - - 80, 21 @@ -485,7 +477,7 @@ bnComboBoxLosslessOrNot - BBBNOVA.BNComboBox, CUEControls, Version=2.0.7.0, Culture=neutral, PublicKeyToken=null + CUEControls.BNComboBox, CUEControls, Version=2.0.7.0, Culture=neutral, PublicKeyToken=null groupBoxSettings @@ -494,19 +486,11 @@ 0 - 451, 456 + 189, 95 92, 46 - - - AAEAAAD/////AQAAAAAAAAAMAgAAAEJDVUVDb250cm9scywgVmVyc2lvbj0yLjAuNy4wLCBDdWx0dXJl - PW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPW51bGwFAQAAABBCQkJOT1ZBLkJOUmFkaXVzBAAAAAhfdG9w - TGVmdAlfdG9wUmlnaHQLX2JvdHRvbUxlZnQMX2JvdHRvbVJpZ2h0AAAAAAgICAgCAAAAAgAAAAYAAAAC - AAAAAgAAAAs= - - 80, 21 @@ -517,7 +501,7 @@ bnComboBoxEncoder - BBBNOVA.BNComboBox, CUEControls, Version=2.0.7.0, Culture=neutral, PublicKeyToken=null + CUEControls.BNComboBox, CUEControls, Version=2.0.7.0, Culture=neutral, PublicKeyToken=null groupBoxSettings @@ -553,19 +537,11 @@ 2 - 279, 456 + 17, 95 92, 19 - - - AAEAAAD/////AQAAAAAAAAAMAgAAAEJDVUVDb250cm9scywgVmVyc2lvbj0yLjAuNy4wLCBDdWx0dXJl - PW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPW51bGwFAQAAABBCQkJOT1ZBLkJOUmFkaXVzBAAAAAhfdG9w - TGVmdAlfdG9wUmlnaHQLX2JvdHRvbUxlZnQMX2JvdHRvbVJpZ2h0AAAAAAgICAgCAAAAAgAAAAYAAAAC - AAAAAgAAAAs= - - 80, 21 @@ -576,7 +552,7 @@ bnComboBoxFormat - BBBNOVA.BNComboBox, CUEControls, Version=2.0.7.0, Culture=neutral, PublicKeyToken=null + CUEControls.BNComboBox, CUEControls, Version=2.0.7.0, Culture=neutral, PublicKeyToken=null groupBoxSettings @@ -624,19 +600,11 @@ 4 - 642, 56 + 526, 56 6, 46 - - - AAEAAAD/////AQAAAAAAAAAMAgAAAEJDVUVDb250cm9scywgVmVyc2lvbj0yLjAuNy4wLCBDdWx0dXJl - PW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPW51bGwFAQAAABBCQkJOT1ZBLkJOUmFkaXVzBAAAAAhfdG9w - TGVmdAlfdG9wUmlnaHQLX2JvdHRvbUxlZnQMX2JvdHRvbVJpZ2h0AAAAAAgICAgCAAAAAgAAAAYAAAAC - AAAAAgAAAAs= - - 80, 21 @@ -647,7 +615,7 @@ bnComboBoxImage - BBBNOVA.BNComboBox, CUEControls, Version=2.0.7.0, Culture=neutral, PublicKeyToken=null + CUEControls.BNComboBox, CUEControls, Version=2.0.7.0, Culture=neutral, PublicKeyToken=null groupBoxSettings @@ -800,7 +768,58 @@ $this - 8 + 7 + + + 207, 17 + + + + AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj0yLjAuMC4w + LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 + ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAACK + CQAAAk1TRnQBSQFMAgEBBAEAAQwBAAEEAQABEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo + AwABQAMAASADAAEBAQABCAYAAQgYAAGAAgABgAMAAoABAAGAAwABgAEAAYABAAKAAgADwAEAAcAB3AHA + AQAB8AHKAaYBAAEzBQABMwEAATMBAAEzAQACMwIAAxYBAAMcAQADIgEAAykBAANVAQADTQEAA0IBAAM5 + AQABgAF8Af8BAAJQAf8BAAGTAQAB1gEAAf8B7AHMAQABxgHWAe8BAAHWAucBAAGQAakBrQIAAf8BMwMA + AWYDAAGZAwABzAIAATMDAAIzAgABMwFmAgABMwGZAgABMwHMAgABMwH/AgABZgMAAWYBMwIAAmYCAAFm + AZkCAAFmAcwCAAFmAf8CAAGZAwABmQEzAgABmQFmAgACmQIAAZkBzAIAAZkB/wIAAcwDAAHMATMCAAHM + AWYCAAHMAZkCAALMAgABzAH/AgAB/wFmAgAB/wGZAgAB/wHMAQABMwH/AgAB/wEAATMBAAEzAQABZgEA + ATMBAAGZAQABMwEAAcwBAAEzAQAB/wEAAf8BMwIAAzMBAAIzAWYBAAIzAZkBAAIzAcwBAAIzAf8BAAEz + AWYCAAEzAWYBMwEAATMCZgEAATMBZgGZAQABMwFmAcwBAAEzAWYB/wEAATMBmQIAATMBmQEzAQABMwGZ + AWYBAAEzApkBAAEzAZkBzAEAATMBmQH/AQABMwHMAgABMwHMATMBAAEzAcwBZgEAATMBzAGZAQABMwLM + AQABMwHMAf8BAAEzAf8BMwEAATMB/wFmAQABMwH/AZkBAAEzAf8BzAEAATMC/wEAAWYDAAFmAQABMwEA + AWYBAAFmAQABZgEAAZkBAAFmAQABzAEAAWYBAAH/AQABZgEzAgABZgIzAQABZgEzAWYBAAFmATMBmQEA + AWYBMwHMAQABZgEzAf8BAAJmAgACZgEzAQADZgEAAmYBmQEAAmYBzAEAAWYBmQIAAWYBmQEzAQABZgGZ + AWYBAAFmApkBAAFmAZkBzAEAAWYBmQH/AQABZgHMAgABZgHMATMBAAFmAcwBmQEAAWYCzAEAAWYBzAH/ + AQABZgH/AgABZgH/ATMBAAFmAf8BmQEAAWYB/wHMAQABzAEAAf8BAAH/AQABzAEAApkCAAGZATMBmQEA + AZkBAAGZAQABmQEAAcwBAAGZAwABmQIzAQABmQEAAWYBAAGZATMBzAEAAZkBAAH/AQABmQFmAgABmQFm + ATMBAAGZATMBZgEAAZkBZgGZAQABmQFmAcwBAAGZATMB/wEAApkBMwEAApkBZgEAA5kBAAKZAcwBAAKZ + Af8BAAGZAcwCAAGZAcwBMwEAAWYBzAFmAQABmQHMAZkBAAGZAswBAAGZAcwB/wEAAZkB/wIAAZkB/wEz + AQABmQHMAWYBAAGZAf8BmQEAAZkB/wHMAQABmQL/AQABzAMAAZkBAAEzAQABzAEAAWYBAAHMAQABmQEA + AcwBAAHMAQABmQEzAgABzAIzAQABzAEzAWYBAAHMATMBmQEAAcwBMwHMAQABzAEzAf8BAAHMAWYCAAHM + AWYBMwEAAZkCZgEAAcwBZgGZAQABzAFmAcwBAAGZAWYB/wEAAcwBmQIAAcwBmQEzAQABzAGZAWYBAAHM + ApkBAAHMAZkBzAEAAcwBmQH/AQACzAIAAswBMwEAAswBZgEAAswBmQEAA8wBAALMAf8BAAHMAf8CAAHM + Af8BMwEAAZkB/wFmAQABzAH/AZkBAAHMAf8BzAEAAcwC/wEAAcwBAAEzAQAB/wEAAWYBAAH/AQABmQEA + AcwBMwIAAf8CMwEAAf8BMwFmAQAB/wEzAZkBAAH/ATMBzAEAAf8BMwH/AQAB/wFmAgAB/wFmATMBAAHM + AmYBAAH/AWYBmQEAAf8BZgHMAQABzAFmAf8BAAH/AZkCAAH/AZkBMwEAAf8BmQFmAQAB/wKZAQAB/wGZ + AcwBAAH/AZkB/wEAAf8BzAIAAf8BzAEzAQAB/wHMAWYBAAH/AcwBmQEAAf8CzAEAAf8BzAH/AQAC/wEz + AQABzAH/AWYBAAL/AZkBAAL/AcwBAAJmAf8BAAFmAf8BZgEAAWYC/wEAAf8CZgEAAf8BZgH/AQAC/wFm + AQABIQEAAaUBAANfAQADdwEAA4YBAAOWAQADywEAA7IBAAPXAQAD3QEAA+MBAAPqAQAD8QEAA/gBAAHw + AfsB/wEAAaQCoAEAA4ADAAH/AgAB/wMAAv8BAAH/AwAB/wEAAf8BAAL/AgAD//8A/wD/AP8AyAAB9AHx + BvAB8QH0BgAB9AHxBvAB8QH0BgAB9AHyBvEB8gH0BgAB9AHxBvAB8QH0BgAC8QbzAvEGAALxBvMC8QYA + AfIB9AL/AfQD/wH0AfIGAALxBvMC8QYAAfEB8wHyAfAB6gHwAvIB8wHxBgAB8QHzBvIB8wHxBgAB8QL/ + AfQB8QH0A/8B8QYAAfEB8wbyAfMB8QYAAfEB8wHxA20B8QLzAfEGAAHxCPMB8QYAAfEB/wH0A/EB9AL/ + AfEGAAHxAvMB7ALqAewC8wHxBgAB8QH0AuwB8ALsAfEB9AHxBgAB8QH0BvMB9AHxBgAB8gH0AvIB9ALy + AvQB8gYAAfEB9AHzBOsB8wH0AfEGAAHyAfQB7AHyAfQB8gLsAfQB8gYAAfII9AHyBgAB8gH0AfID9ALy + AfQB8gYAAfIC9ATsAvQB8gYAAfIB/wT0AfMB7QH/AfIGAAHyAf8G9AH/AfIGAAHyAvQD/wH0AfIB9AHy + BgAB8gH/AfQB7wLtAe8B9AH/AfIGAAHyBv8B8gH/AfIGAAHyCP8B8gYAAfIB9AT/A/QB8gYAAfII/wHy + BgAC8wb/AvMGAALzBv8C8wYAAfMI9AHzBgAC8wb/AvMGAAH/AfMG8gHzAf8GAAH/AfMG8gHzAf8GAAH/ + AfMG8gHzAf8GAAH/AfMG8gHzAf/DAAFCAU0BPgcAAT4DAAEoAwABQAMAASADAAEBAQABAQYAAQEWAAP/ + gQAY/wHgAQcB4AEHAeABBwHgAQcB4AEHAeABBwHgAQcB4AEHAeABBwHgAQcB4AEHAeABBwHgAQcB4AEH + AeABBwHgAQcB4AEHAeABBwHgAQcB4AEHAeABBwHgAQcB4AEHAeABBwHgAQcB4AEHAeABBwHgAQcB4AEH + AeABBwHgAQcB4AEHAeABBwHgAQcB4AEHAeABBwHgAQcB4AEHAeABBwHgAQcY/ws= + 181, 22 @@ -809,19 +828,19 @@ toolStripMenuItem1 - 979, 17 + 960, 17 - 643, 17 + 624, 17 382, 421 - 473, 17 + 454, 17 - 808, 17 + 789, 17 177, 23 @@ -839,7 +858,7 @@ $this - 6 + 5 382, 392 @@ -866,34 +885,7 @@ $this - 7 - - - 6, 170 - - - 10 - - - 553, 21 - - - 32 - - - Template for output files (foobar2000 format) - - - comboBoxOutputFormat - - - System.Windows.Forms.ComboBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - $this - - - 5 + 6 7, 61 @@ -920,7 +912,7 @@ 1 - 824, 56 + 708, 56 17, 56 @@ -974,14 +966,6 @@ 6, 33 - - - AAEAAAD/////AQAAAAAAAAAMAgAAAEJDVUVDb250cm9scywgVmVyc2lvbj0yLjAuNy4wLCBDdWx0dXJl - PW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPW51bGwFAQAAABBCQkJOT1ZBLkJOUmFkaXVzBAAAAAhfdG9w - TGVmdAlfdG9wUmlnaHQLX2JvdHRvbUxlZnQMX2JvdHRvbVJpZ2h0AAAAAAgICAgCAAAAAgAAAAYAAAAC - AAAAAgAAAAs= - - 552, 21 @@ -995,7 +979,7 @@ bnComboBoxRelease - BBBNOVA.BNComboBox, CUEControls, Version=2.0.7.0, Culture=neutral, PublicKeyToken=null + CUEControls.BNComboBox, CUEControls, Version=2.0.7.0, Culture=neutral, PublicKeyToken=null $this @@ -1004,19 +988,11 @@ 2 - 116, 456 + 998, 56 6, 6 - - - AAEAAAD/////AQAAAAAAAAAMAgAAAEJDVUVDb250cm9scywgVmVyc2lvbj0yLjAuNy4wLCBDdWx0dXJl - PW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPW51bGwFAQAAABBCQkJOT1ZBLkJOUmFkaXVzBAAAAAhfdG9w - TGVmdAlfdG9wUmlnaHQLX2JvdHRvbUxlZnQMX2JvdHRvbVJpZ2h0AAAAAAgICAgCAAAAAgAAAAYAAAAC - AAAAAgAAAAs= - - 552, 21 @@ -1027,7 +1003,7 @@ bnComboBoxDrives - BBBNOVA.BNComboBox, CUEControls, Version=2.0.7.0, Culture=neutral, PublicKeyToken=null + CUEControls.BNComboBox, CUEControls, Version=2.0.7.0, Culture=neutral, PublicKeyToken=null $this @@ -1038,14 +1014,6 @@ 6, 60 - - - AAEAAAD/////AQAAAAAAAAAMAgAAAEJDVUVDb250cm9scywgVmVyc2lvbj0yLjAuNy4wLCBDdWx0dXJl - PW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPW51bGwFAQAAABBCQkJOT1ZBLkJOUmFkaXVzBAAAAAhfdG9w - TGVmdAlfdG9wUmlnaHQLX2JvdHRvbUxlZnQMX2JvdHRvbVJpZ2h0AAAAAAgICAgCAAAAAgAAAAYAAAAC - AAAAAgAAAAs= - - 552, 21 @@ -1056,7 +1024,7 @@ bnComboBoxOutputFormat - BBBNOVA.BNComboBox, CUEControls, Version=2.0.7.0, Culture=neutral, PublicKeyToken=null + CUEControls.BNComboBox, CUEControls, Version=2.0.7.0, Culture=neutral, PublicKeyToken=null $this @@ -1575,6 +1543,12 @@ System.Windows.Forms.BindingSource, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + imageListChecked + + + System.Windows.Forms.ImageList, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + toolStripMenuItem1 diff --git a/CUETools.AccurateRip/AccurateRip.cs b/CUETools.AccurateRip/AccurateRip.cs index 83dabea..37da48d 100644 --- a/CUETools.AccurateRip/AccurateRip.cs +++ b/CUETools.AccurateRip/AccurateRip.cs @@ -822,7 +822,7 @@ namespace CUETools.AccurateRip public static bool FindDriveReadOffset(string driveName, out int driveReadOffset) { string fileName = System.IO.Path.Combine(CachePath, "DriveOffsets.bin"); - if (!File.Exists(fileName)) + if (!File.Exists(fileName) || (DateTime.Now - File.GetLastWriteTime(fileName) > TimeSpan.FromDays(1)) ) { HttpWebRequest req = (HttpWebRequest)WebRequest.Create("http://www.accuraterip.com/accuraterip/DriveOffsets.bin"); req.Method = "GET"; @@ -835,7 +835,7 @@ namespace CUETools.AccurateRip return false; } Stream respStream = resp.GetResponseStream(); - FileStream myOffsetsSaved = new FileStream(fileName, FileMode.CreateNew, FileAccess.Write); + FileStream myOffsetsSaved = new FileStream(fileName, FileMode.Create, FileAccess.Write); byte[] buff = new byte[0x8000]; do { diff --git a/CUETools.CTDB/CUEToolsDB.cs b/CUETools.CTDB/CUEToolsDB.cs index c1fb2f7..dcd110c 100644 --- a/CUETools.CTDB/CUEToolsDB.cs +++ b/CUETools.CTDB/CUEToolsDB.cs @@ -507,7 +507,7 @@ namespace CUETools.CTDB if (!hasErrors) return string.Format("verified OK, confidence {0}", conf); if (canRecover) - return string.Format("contains {1} correctable errors, confidence {0}", conf, repair.CorrectableErrors); + return string.Format("differs in {1} samples, confidence {0}", conf, repair.CorrectableErrors); if (httpStatus == HttpStatusCode.OK) return "could not be verified"; return "could not be verified: " + httpStatus.ToString(); diff --git a/CUETools.Codecs.CoreAudio/CUETools.Codecs.CoreAudio.csproj b/CUETools.Codecs.CoreAudio/CUETools.Codecs.CoreAudio.csproj new file mode 100644 index 0000000..3cc336f --- /dev/null +++ b/CUETools.Codecs.CoreAudio/CUETools.Codecs.CoreAudio.csproj @@ -0,0 +1,110 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {FAD09EE2-D6B2-4A8E-9F1C-2A9FB293661A} + Library + Properties + CUETools.Codecs.CoreAudio + CUETools.Codecs.CoreAudio + v2.0 + 512 + + + true + full + false + ..\bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + ..\bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {6458A13A-30EF-45A9-9D58-E5031B17BEE2} + CUETools.Codecs + + + + + \ No newline at end of file diff --git a/CUETools.Codecs.CoreAudio/CoreAudioApi/AudioCaptureClient.cs b/CUETools.Codecs.CoreAudio/CoreAudioApi/AudioCaptureClient.cs new file mode 100644 index 0000000..27f8478 --- /dev/null +++ b/CUETools.Codecs.CoreAudio/CoreAudioApi/AudioCaptureClient.cs @@ -0,0 +1,91 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Runtime.InteropServices; +using NAudio.CoreAudioApi.Interfaces; + +namespace NAudio.CoreAudioApi +{ + /// + /// Audio Capture Client + /// + public class AudioCaptureClient : IDisposable + { + IAudioCaptureClient audioCaptureClientInterface; + + internal AudioCaptureClient(IAudioCaptureClient audioCaptureClientInterface) + { + this.audioCaptureClientInterface = audioCaptureClientInterface; + } + + /// + /// Gets a pointer to the buffer + /// + /// Pointer to the buffer + public IntPtr GetBuffer( + out int numFramesToRead, + out AudioClientBufferFlags bufferFlags, + out long devicePosition, + out long qpcPosition) + { + IntPtr bufferPointer; + Marshal.ThrowExceptionForHR(audioCaptureClientInterface.GetBuffer(out bufferPointer, out numFramesToRead, out bufferFlags, out devicePosition, out qpcPosition)); + return bufferPointer; + } + + /// + /// Gets a pointer to the buffer + /// + /// Number of frames to read + /// Buffer flags + /// Pointer to the buffer + public IntPtr GetBuffer( + out int numFramesToRead, + out AudioClientBufferFlags bufferFlags) + { + IntPtr bufferPointer; + long devicePosition; + long qpcPosition; + Marshal.ThrowExceptionForHR(audioCaptureClientInterface.GetBuffer(out bufferPointer, out numFramesToRead, out bufferFlags, out devicePosition, out qpcPosition)); + return bufferPointer; + } + + /// + /// Gets the size of the next packet + /// + public int GetNextPacketSize() + { + int numFramesInNextPacket; + Marshal.ThrowExceptionForHR(audioCaptureClientInterface.GetNextPacketSize(out numFramesInNextPacket)); + return numFramesInNextPacket; + } + + /// + /// Release buffer + /// + /// Number of frames written + public void ReleaseBuffer(int numFramesWritten) + { + Marshal.ThrowExceptionForHR(audioCaptureClientInterface.ReleaseBuffer(numFramesWritten)); + } + + #region IDisposable Members + + /// + /// Release the COM object + /// + public void Dispose() + { + if (audioCaptureClientInterface != null) + { + // althugh GC would do this for us, we want it done now + // to let us reopen WASAPI + Marshal.ReleaseComObject(audioCaptureClientInterface); + audioCaptureClientInterface = null; + GC.SuppressFinalize(this); + } + } + + #endregion + } +} \ No newline at end of file diff --git a/CUETools.Codecs.CoreAudio/CoreAudioApi/AudioClient.cs b/CUETools.Codecs.CoreAudio/CoreAudioApi/AudioClient.cs new file mode 100644 index 0000000..a53d796 --- /dev/null +++ b/CUETools.Codecs.CoreAudio/CoreAudioApi/AudioClient.cs @@ -0,0 +1,296 @@ +using System; +using System.Threading; +using NAudio.CoreAudioApi.Interfaces; +using System.Runtime.InteropServices; +using NAudio.Wave; + +namespace NAudio.CoreAudioApi +{ + /// + /// Windows Vista CoreAudio AudioClient + /// + public class AudioClient : IDisposable + { + IAudioClient audioClientInterface; + WaveFormat mixFormat; + AudioRenderClient audioRenderClient; + AudioCaptureClient audioCaptureClient; + + internal AudioClient(IAudioClient audioClientInterface) + { + this.audioClientInterface = audioClientInterface; + } + + /// + /// Mix Format, + /// Can be called before initialize + /// + public WaveFormat MixFormat + { + get + { + if(mixFormat == null) + { + IntPtr waveFormatPointer; + audioClientInterface.GetMixFormat(out waveFormatPointer); + //WaveFormatExtensible waveFormat = new WaveFormatExtensible(44100,32,2); + //Marshal.PtrToStructure(waveFormatPointer, waveFormat); + WaveFormat waveFormat = WaveFormat.MarshalFromPtr(waveFormatPointer); + Marshal.FreeCoTaskMem(waveFormatPointer); + mixFormat = waveFormat; + return waveFormat; + } + else + { + return mixFormat; + } + } + } + + /// + /// Initialize the Audio Client + /// + /// Share Mode + /// Stream Flags + /// Buffer Duration + /// Periodicity + /// Wave Format + /// Audio Session GUID (can be null) + public void Initialize(AudioClientShareMode shareMode, + AudioClientStreamFlags streamFlags, + long bufferDuration, + long periodicity, + WaveFormat waveFormat, + Guid audioSessionGuid) + { + audioClientInterface.Initialize(shareMode, streamFlags, bufferDuration, periodicity, waveFormat, ref audioSessionGuid); + // may have changed the mix format so reset it + mixFormat = null; + } + + /// + /// Gets the buffer size (must initialize first) + /// + public int BufferSize + { + get + { + uint bufferSize; + audioClientInterface.GetBufferSize(out bufferSize); + return (int) bufferSize; + } + } + + /// + /// Gets the stream latency (must initialize first) + /// + public long StreamLatency + { + get + { + return audioClientInterface.GetStreamLatency(); + } + } + + /// + /// Gets the current padding (must initialize first) + /// + public int CurrentPadding + { + get + { + int currentPadding; + audioClientInterface.GetCurrentPadding(out currentPadding); + return currentPadding; + } + } + + /// + /// Gets the default device period (can be called before initialize) + /// + public long DefaultDevicePeriod + { + get + { + long defaultDevicePeriod; + long minimumDevicePeriod; + audioClientInterface.GetDevicePeriod(out defaultDevicePeriod, out minimumDevicePeriod); + return defaultDevicePeriod; + } + } + + /// + /// Gets the minimum device period (can be called before initialize) + /// + public long MinimumDevicePeriod + { + get + { + long defaultDevicePeriod; + long minimumDevicePeriod; + audioClientInterface.GetDevicePeriod(out defaultDevicePeriod, out minimumDevicePeriod); + return minimumDevicePeriod; + } + } + + // TODO: GetService: + // IID_IAudioCaptureClient + // IID_IAudioClock + // IID_IAudioSessionControl + // IID_IAudioStreamVolume + // IID_IChannelAudioVolume + // IID_ISimpleAudioVolume + + + /// + /// Gets the AudioRenderClient service + /// + public AudioRenderClient AudioRenderClient + { + get + { + if (audioRenderClient == null) + { + object audioRenderClientInterface; + Guid audioRenderClientGuid = new Guid("F294ACFC-3146-4483-A7BF-ADDCA7C260E2"); + audioClientInterface.GetService(ref audioRenderClientGuid, out audioRenderClientInterface); + audioRenderClient = new AudioRenderClient((IAudioRenderClient)audioRenderClientInterface); + } + return audioRenderClient; + } + } + + /// + /// Gets the AudioCaptureClient service + /// + public AudioCaptureClient AudioCaptureClient + { + get + { + if (audioCaptureClient == null) + { + object audioCaptureClientInterface; + Guid audioCaptureClientGuid = new Guid("c8adbd64-e71e-48a0-a4de-185c395cd317"); + audioClientInterface.GetService(ref audioCaptureClientGuid, out audioCaptureClientInterface); + audioCaptureClient = new AudioCaptureClient((IAudioCaptureClient)audioCaptureClientInterface); + } + return audioCaptureClient; + } + } + + /// + /// Determines whether if the specified output format is supported + /// + /// The share mode. + /// The desired format. + /// + /// true if [is format supported] [the specified share mode]; otherwise, false. + /// + public bool IsFormatSupported(AudioClientShareMode shareMode, + WaveFormat desiredFormat) + { + WaveFormatExtensible closestMatchFormat; + return IsFormatSupported(shareMode, desiredFormat, out closestMatchFormat); + } + + + + /// + /// Determines if the specified output format is supported in shared mode + /// + /// Share Mode + /// Desired Format + /// Output The closest match format. + /// + /// true if [is format supported] [the specified share mode]; otherwise, false. + /// + public bool IsFormatSupported(AudioClientShareMode shareMode, WaveFormat desiredFormat, out WaveFormatExtensible closestMatchFormat) + { + int hresult = audioClientInterface.IsFormatSupported(shareMode, desiredFormat, out closestMatchFormat); + // S_OK is 0, S_FALSE = 1 + if (hresult == 0) + { + // directly supported + return true; + } + if (hresult == 1) + { + return false; + } + else if (hresult == (int)AudioClientErrors.UnsupportedFormat) + { + return false; + } + else + { + Marshal.ThrowExceptionForHR(hresult); + } + // shouldn't get here + throw new NotSupportedException("Unknown hresult " + hresult.ToString()); + } + + + /// + /// Starts the audio stream + /// + public void Start() + { + audioClientInterface.Start(); + } + + /// + /// Stops the audio stream. + /// + public void Stop() + { + audioClientInterface.Stop(); + } + + /// + /// Set the Event Handle for buffer synchro. + /// + /// The Wait Handle to setup + public void SetEventHandle(EventWaitHandle eventWaitHandle) + { + audioClientInterface.SetEventHandle(eventWaitHandle.SafeWaitHandle.DangerousGetHandle()); + } + + /// + /// Resets the audio stream + /// Reset is a control method that the client calls to reset a stopped audio stream. + /// Resetting the stream flushes all pending data and resets the audio clock stream + /// position to 0. This method fails if it is called on a stream that is not stopped + /// + public void Reset() + { + audioClientInterface.Reset(); + } + + #region IDisposable Members + + /// + /// Dispose + /// + public void Dispose() + { + if (audioClientInterface != null) + { + if (audioRenderClient != null) + { + audioRenderClient.Dispose(); + audioRenderClient = null; + } + if (audioCaptureClient != null) + { + audioCaptureClient.Dispose(); + audioCaptureClient = null; + } + Marshal.ReleaseComObject(audioClientInterface); + audioClientInterface = null; + GC.SuppressFinalize(this); + } + } + + #endregion + } +} diff --git a/CUETools.Codecs.CoreAudio/CoreAudioApi/AudioClientBufferFlags.cs b/CUETools.Codecs.CoreAudio/CoreAudioApi/AudioClientBufferFlags.cs new file mode 100644 index 0000000..0b03d7d --- /dev/null +++ b/CUETools.Codecs.CoreAudio/CoreAudioApi/AudioClientBufferFlags.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace NAudio.CoreAudioApi +{ + /// + /// Audio Client Buffer Flags + /// + [Flags] + public enum AudioClientBufferFlags + { + /// + /// None + /// + None, + /// + /// AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY + /// + DataDiscontinuity = 0x1, + /// + /// AUDCLNT_BUFFERFLAGS_SILENT + /// + Silent = 0x2, + /// + /// AUDCLNT_BUFFERFLAGS_TIMESTAMP_ERROR + /// + TimestampError = 0x4 + + } +} diff --git a/CUETools.Codecs.CoreAudio/CoreAudioApi/AudioClientShareMode.cs b/CUETools.Codecs.CoreAudio/CoreAudioApi/AudioClientShareMode.cs new file mode 100644 index 0000000..bbe89df --- /dev/null +++ b/CUETools.Codecs.CoreAudio/CoreAudioApi/AudioClientShareMode.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace NAudio.CoreAudioApi +{ + /// + /// AUDCLNT_SHAREMODE + /// + public enum AudioClientShareMode + { + /// + /// AUDCLNT_SHAREMODE_SHARED, + /// + Shared, + /// + /// AUDCLNT_SHAREMODE_EXCLUSIVE + /// + Exclusive, + } +} diff --git a/CUETools.Codecs.CoreAudio/CoreAudioApi/AudioClientStreamFlags.cs b/CUETools.Codecs.CoreAudio/CoreAudioApi/AudioClientStreamFlags.cs new file mode 100644 index 0000000..009b4ed --- /dev/null +++ b/CUETools.Codecs.CoreAudio/CoreAudioApi/AudioClientStreamFlags.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace NAudio.CoreAudioApi +{ + /// + /// AUDCLNT_STREAMFLAGS + /// + [Flags] + public enum AudioClientStreamFlags + { + /// + /// None + /// + None, + /// + /// AUDCLNT_STREAMFLAGS_CROSSPROCESS + /// + CrossProcess = 0x00010000, + /// + /// AUDCLNT_STREAMFLAGS_LOOPBACK + /// + Loopback = 0x00020000, + /// + /// AUDCLNT_STREAMFLAGS_EVENTCALLBACK + /// + EventCallback = 0x00040000, + /// + /// AUDCLNT_STREAMFLAGS_NOPERSIST + /// + NoPersist = 0x00080000, + } +} diff --git a/CUETools.Codecs.CoreAudio/CoreAudioApi/AudioEndpointVolume.cs b/CUETools.Codecs.CoreAudio/CoreAudioApi/AudioEndpointVolume.cs new file mode 100644 index 0000000..d2d9f96 --- /dev/null +++ b/CUETools.Codecs.CoreAudio/CoreAudioApi/AudioEndpointVolume.cs @@ -0,0 +1,211 @@ +/* + LICENSE + ------- + Copyright (C) 2007 Ray Molenkamp + + This source code is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this source code or the software it produces. + + Permission is granted to anyone to use this source code for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this source code must not be misrepresented; you must not + claim that you wrote the original source code. If you use this source code + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original source code. + 3. This notice may not be removed or altered from any source distribution. +*/ + +using System; +using System.Collections.Generic; +using System.Text; +using NAudio.CoreAudioApi.Interfaces; +using System.Runtime.InteropServices; + +namespace NAudio.CoreAudioApi +{ + /// + /// Audio Endpoint Volume + /// + public class AudioEndpointVolume : IDisposable + { + private IAudioEndpointVolume _AudioEndPointVolume; + private AudioEndpointVolumeChannels _Channels; + private AudioEndpointVolumeStepInformation _StepInformation; + private AudioEndpointVolumeVolumeRange _VolumeRange; + private EEndpointHardwareSupport _HardwareSupport; + private AudioEndpointVolumeCallback _CallBack; + + /// + /// On Volume Notification + /// + public event AudioEndpointVolumeNotificationDelegate OnVolumeNotification; + + /// + /// Volume Range + /// + public AudioEndpointVolumeVolumeRange VolumeRange + { + get + { + return _VolumeRange; + } + } + + /// + /// Hardware Support + /// + public EEndpointHardwareSupport HardwareSupport + { + get + { + return _HardwareSupport; + } + } + + /// + /// Step Information + /// + public AudioEndpointVolumeStepInformation StepInformation + { + get + { + return _StepInformation; + } + } + + /// + /// Channels + /// + public AudioEndpointVolumeChannels Channels + { + get + { + return _Channels; + } + } + + /// + /// Master Volume Level + /// + public float MasterVolumeLevel + { + get + { + float result; + Marshal.ThrowExceptionForHR(_AudioEndPointVolume.GetMasterVolumeLevel(out result)); + return result; + } + set + { + Marshal.ThrowExceptionForHR(_AudioEndPointVolume.SetMasterVolumeLevel(value, Guid.Empty)); + } + } + + /// + /// Master Volume Level Scalar + /// + public float MasterVolumeLevelScalar + { + get + { + float result; + Marshal.ThrowExceptionForHR(_AudioEndPointVolume.GetMasterVolumeLevelScalar(out result)); + return result; + } + set + { + Marshal.ThrowExceptionForHR(_AudioEndPointVolume.SetMasterVolumeLevelScalar(value, Guid.Empty)); + } + } + + /// + /// Mute + /// + public bool Mute + { + get + { + bool result; + Marshal.ThrowExceptionForHR(_AudioEndPointVolume.GetMute(out result)); + return result; + } + set + { + Marshal.ThrowExceptionForHR(_AudioEndPointVolume.SetMute(value, Guid.Empty)); + } + } + + /// + /// Volume Step Up + /// + public void VolumeStepUp() + { + Marshal.ThrowExceptionForHR(_AudioEndPointVolume.VolumeStepUp(Guid.Empty)); + } + + /// + /// Volume Step Down + /// + public void VolumeStepDown() + { + Marshal.ThrowExceptionForHR(_AudioEndPointVolume.VolumeStepDown(Guid.Empty)); + } + + /// + /// Creates a new Audio endpoint volume + /// + /// IAudioEndpointVolume COM interface + internal AudioEndpointVolume(IAudioEndpointVolume realEndpointVolume) + { + uint HardwareSupp; + + _AudioEndPointVolume = realEndpointVolume; + _Channels = new AudioEndpointVolumeChannels(_AudioEndPointVolume); + _StepInformation = new AudioEndpointVolumeStepInformation(_AudioEndPointVolume); + Marshal.ThrowExceptionForHR(_AudioEndPointVolume.QueryHardwareSupport(out HardwareSupp)); + _HardwareSupport = (EEndpointHardwareSupport)HardwareSupp; + _VolumeRange = new AudioEndpointVolumeVolumeRange(_AudioEndPointVolume); + _CallBack = new AudioEndpointVolumeCallback(this); + Marshal.ThrowExceptionForHR(_AudioEndPointVolume.RegisterControlChangeNotify(_CallBack)); + } + internal void FireNotification(AudioVolumeNotificationData NotificationData) + { + AudioEndpointVolumeNotificationDelegate del = OnVolumeNotification; + if (del != null) + { + del(NotificationData); + } + } + #region IDisposable Members + + /// + /// Dispose + /// + public void Dispose() + { + if (_CallBack != null) + { + Marshal.ThrowExceptionForHR(_AudioEndPointVolume.UnregisterControlChangeNotify(_CallBack)); + _CallBack = null; + } + GC.SuppressFinalize(this); + + } + + /// + /// Finalizer + /// + ~AudioEndpointVolume() + { + Dispose(); + } + + #endregion + + } +} diff --git a/CUETools.Codecs.CoreAudio/CoreAudioApi/AudioEndpointVolumeCallback.cs b/CUETools.Codecs.CoreAudio/CoreAudioApi/AudioEndpointVolumeCallback.cs new file mode 100644 index 0000000..efe6b1c --- /dev/null +++ b/CUETools.Codecs.CoreAudio/CoreAudioApi/AudioEndpointVolumeCallback.cs @@ -0,0 +1,73 @@ +/* + LICENSE + ------- + Copyright (C) 2007 Ray Molenkamp + + This source code is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this source code or the software it produces. + + Permission is granted to anyone to use this source code for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this source code must not be misrepresented; you must not + claim that you wrote the original source code. If you use this source code + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original source code. + 3. This notice may not be removed or altered from any source distribution. +*/ + +using System; +using System.Collections.Generic; +using System.Text; +using NAudio.CoreAudioApi.Interfaces; +using System.Runtime.InteropServices; + +namespace NAudio.CoreAudioApi +{ + // This class implements the IAudioEndpointVolumeCallback interface, + // it is implemented in this class because implementing it on AudioEndpointVolume + // (where the functionality is really wanted, would cause the OnNotify function + // to show up in the public API. + internal class AudioEndpointVolumeCallback : IAudioEndpointVolumeCallback + { + private AudioEndpointVolume _Parent; + + internal AudioEndpointVolumeCallback(AudioEndpointVolume parent) + { + _Parent = parent; + } + + public void OnNotify(ref AudioVolumeNotificationDataStruct data) + //public int OnNotify(IntPtr NotifyData) + { + //Since AUDIO_VOLUME_NOTIFICATION_DATA is dynamic in length based on the + //number of audio channels available we cannot just call PtrToStructure + //to get all data, thats why it is split up into two steps, first the static + //data is marshalled into the data structure, then with some IntPtr math the + //remaining floats are read from memory. + // + //AudioVolumeNotificationDataStruct data = (AudioVolumeNotificationDataStruct)Marshal.PtrToStructure(NotifyData, typeof(AudioVolumeNotificationDataStruct)); + + //Determine offset in structure of the first float + //IntPtr Offset = Marshal.OffsetOf(typeof(AudioVolumeNotificationDataStruct), "ChannelVolume"); + //Determine offset in memory of the first float + //IntPtr FirstFloatPtr = (IntPtr)((long)NotifyData + (long)Offset); + + //float[] voldata = new float[data.nChannels]; + + //Read all floats from memory. + //for (int i = 0; i < data.nChannels; i++) + //{ + // voldata[i] = data.fMasterVolume; + //} + + //Create combined structure and Fire Event in parent class. + AudioVolumeNotificationData NotificationData = new AudioVolumeNotificationData(data.guidEventContext, data.bMuted, data.fMasterVolume); + _Parent.FireNotification(NotificationData); + } + } +} diff --git a/CUETools.Codecs.CoreAudio/CoreAudioApi/AudioEndpointVolumeChannel.cs b/CUETools.Codecs.CoreAudio/CoreAudioApi/AudioEndpointVolumeChannel.cs new file mode 100644 index 0000000..af0afe5 --- /dev/null +++ b/CUETools.Codecs.CoreAudio/CoreAudioApi/AudioEndpointVolumeChannel.cs @@ -0,0 +1,80 @@ +/* + LICENSE + ------- + Copyright (C) 2007 Ray Molenkamp + + This source code is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this source code or the software it produces. + + Permission is granted to anyone to use this source code for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this source code must not be misrepresented; you must not + claim that you wrote the original source code. If you use this source code + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original source code. + 3. This notice may not be removed or altered from any source distribution. +*/ + +using System; +using System.Collections.Generic; +using System.Text; +using NAudio.CoreAudioApi.Interfaces; +using System.Runtime.InteropServices; + +namespace NAudio.CoreAudioApi +{ + /// + /// Audio Endpoint Volume Channel + /// + public class AudioEndpointVolumeChannel + { + private uint _Channel; + private IAudioEndpointVolume _AudioEndpointVolume; + + internal AudioEndpointVolumeChannel(IAudioEndpointVolume parent, int channel) + { + _Channel = (uint)channel; + _AudioEndpointVolume = parent; + } + + /// + /// Volume Level + /// + public float VolumeLevel + { + get + { + float result; + Marshal.ThrowExceptionForHR(_AudioEndpointVolume.GetChannelVolumeLevel(_Channel,out result)); + return result; + } + set + { + Marshal.ThrowExceptionForHR(_AudioEndpointVolume.SetChannelVolumeLevel(_Channel, value,Guid.Empty)); + } + } + + /// + /// Volume Level Scalar + /// + public float VolumeLevelScalar + { + get + { + float result; + Marshal.ThrowExceptionForHR(_AudioEndpointVolume.GetChannelVolumeLevelScalar(_Channel, out result)); + return result; + } + set + { + Marshal.ThrowExceptionForHR(_AudioEndpointVolume.SetChannelVolumeLevelScalar(_Channel, value, Guid.Empty)); + } + } + + } +} diff --git a/CUETools.Codecs.CoreAudio/CoreAudioApi/AudioEndpointVolumeChannels.cs b/CUETools.Codecs.CoreAudio/CoreAudioApi/AudioEndpointVolumeChannels.cs new file mode 100644 index 0000000..8ccad55 --- /dev/null +++ b/CUETools.Codecs.CoreAudio/CoreAudioApi/AudioEndpointVolumeChannels.cs @@ -0,0 +1,78 @@ +/* + LICENSE + ------- + Copyright (C) 2007 Ray Molenkamp + + This source code is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this source code or the software it produces. + + Permission is granted to anyone to use this source code for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this source code must not be misrepresented; you must not + claim that you wrote the original source code. If you use this source code + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original source code. + 3. This notice may not be removed or altered from any source distribution. +*/ + +using System; +using System.Collections.Generic; +using System.Text; +using NAudio.CoreAudioApi.Interfaces; +using System.Runtime.InteropServices; + +namespace NAudio.CoreAudioApi +{ + /// + /// Audio Endpoint Volume Channels + /// + public class AudioEndpointVolumeChannels + { + IAudioEndpointVolume _AudioEndPointVolume; + AudioEndpointVolumeChannel[] _Channels; + + /// + /// Channel Count + /// + public int Count + { + get + { + int result; + Marshal.ThrowExceptionForHR(_AudioEndPointVolume.GetChannelCount(out result)); + return result; + } + } + + /// + /// Indexer - get a specific channel + /// + public AudioEndpointVolumeChannel this[int index] + { + get + { + return _Channels[index]; + } + } + + internal AudioEndpointVolumeChannels(IAudioEndpointVolume parent) + { + int ChannelCount; + _AudioEndPointVolume = parent; + + ChannelCount = Count; + _Channels = new AudioEndpointVolumeChannel[ChannelCount]; + for (int i = 0; i < ChannelCount; i++) + { + _Channels[i] = new AudioEndpointVolumeChannel(_AudioEndPointVolume, i); + } + } + + + } +} diff --git a/CUETools.Codecs.CoreAudio/CoreAudioApi/AudioEndpointVolumeNotificationDelegate.cs b/CUETools.Codecs.CoreAudio/CoreAudioApi/AudioEndpointVolumeNotificationDelegate.cs new file mode 100644 index 0000000..e43233f --- /dev/null +++ b/CUETools.Codecs.CoreAudio/CoreAudioApi/AudioEndpointVolumeNotificationDelegate.cs @@ -0,0 +1,34 @@ +/* + LICENSE + ------- + Copyright (C) 2007 Ray Molenkamp + + This source code is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this source code or the software it produces. + + Permission is granted to anyone to use this source code for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this source code must not be misrepresented; you must not + claim that you wrote the original source code. If you use this source code + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original source code. + 3. This notice may not be removed or altered from any source distribution. +*/ + +using System; +using System.Collections.Generic; +using System.Text; + +namespace NAudio.CoreAudioApi +{ + /// + /// Audio Endpoint Volume Notifiaction Delegate + /// + /// Audio Volume Notification Data + public delegate void AudioEndpointVolumeNotificationDelegate( AudioVolumeNotificationData data); +} diff --git a/CUETools.Codecs.CoreAudio/CoreAudioApi/AudioEndpointVolumeStepInformation.cs b/CUETools.Codecs.CoreAudio/CoreAudioApi/AudioEndpointVolumeStepInformation.cs new file mode 100644 index 0000000..9763ea3 --- /dev/null +++ b/CUETools.Codecs.CoreAudio/CoreAudioApi/AudioEndpointVolumeStepInformation.cs @@ -0,0 +1,65 @@ +/* + LICENSE + ------- + Copyright (C) 2007 Ray Molenkamp + + This source code is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this source code or the software it produces. + + Permission is granted to anyone to use this source code for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this source code must not be misrepresented; you must not + claim that you wrote the original source code. If you use this source code + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original source code. + 3. This notice may not be removed or altered from any source distribution. +*/ +using System; +using System.Collections.Generic; +using System.Text; +using NAudio.CoreAudioApi.Interfaces; +using System.Runtime.InteropServices; + +namespace NAudio.CoreAudioApi +{ + /// + /// Audio Endpoint Volume Step Information + /// + public class AudioEndpointVolumeStepInformation + { + private uint _Step; + private uint _StepCount; + internal AudioEndpointVolumeStepInformation(IAudioEndpointVolume parent) + { + Marshal.ThrowExceptionForHR(parent.GetVolumeStepInfo(out _Step, out _StepCount)); + } + + /// + /// Step + /// + public uint Step + { + get + { + return _Step; + } + } + + /// + /// StepCount + /// + public uint StepCount + { + get + { + return _StepCount; + } + } + + } +} diff --git a/CUETools.Codecs.CoreAudio/CoreAudioApi/AudioEndpointVolumeVolumeRange.cs b/CUETools.Codecs.CoreAudio/CoreAudioApi/AudioEndpointVolumeVolumeRange.cs new file mode 100644 index 0000000..ae7732c --- /dev/null +++ b/CUETools.Codecs.CoreAudio/CoreAudioApi/AudioEndpointVolumeVolumeRange.cs @@ -0,0 +1,78 @@ +/* + LICENSE + ------- + Copyright (C) 2007 Ray Molenkamp + + This source code is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this source code or the software it produces. + + Permission is granted to anyone to use this source code for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this source code must not be misrepresented; you must not + claim that you wrote the original source code. If you use this source code + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original source code. + 3. This notice may not be removed or altered from any source distribution. +*/ +// modified for NAudio +using System; +using System.Collections.Generic; +using System.Text; +using NAudio.CoreAudioApi.Interfaces; +using System.Runtime.InteropServices; + +namespace NAudio.CoreAudioApi +{ + /// + /// Audio Endpoint Volume Volume Range + /// + public class AudioEndpointVolumeVolumeRange + { + float _VolumeMindB; + float _VolumeMaxdB; + float _VolumeIncrementdB; + + internal AudioEndpointVolumeVolumeRange(IAudioEndpointVolume parent) + { + Marshal.ThrowExceptionForHR(parent.GetVolumeRange(out _VolumeMindB,out _VolumeMaxdB,out _VolumeIncrementdB)); + } + + /// + /// Minimum Decibels + /// + public float MinDecibels + { + get + { + return _VolumeMindB; + } + } + + /// + /// Maximum Decibels + /// + public float MaxDecibels + { + get + { + return _VolumeMaxdB; + } + } + + /// + /// Increment Decibels + /// + public float IncrementDecibels + { + get + { + return _VolumeIncrementdB; + } + } + } +} diff --git a/CUETools.Codecs.CoreAudio/CoreAudioApi/AudioMeterInformation.cs b/CUETools.Codecs.CoreAudio/CoreAudioApi/AudioMeterInformation.cs new file mode 100644 index 0000000..2978470 --- /dev/null +++ b/CUETools.Codecs.CoreAudio/CoreAudioApi/AudioMeterInformation.cs @@ -0,0 +1,85 @@ +/* + LICENSE + ------- + Copyright (C) 2007 Ray Molenkamp + + This source code is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this source code or the software it produces. + + Permission is granted to anyone to use this source code for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this source code must not be misrepresented; you must not + claim that you wrote the original source code. If you use this source code + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original source code. + 3. This notice may not be removed or altered from any source distribution. +*/ +using System; +using System.Collections.Generic; +using System.Text; +using System.Runtime.InteropServices; +using NAudio.CoreAudioApi.Interfaces; + +namespace NAudio.CoreAudioApi +{ + /// + /// Audio Meter Information + /// + public class AudioMeterInformation + { + private IAudioMeterInformation _AudioMeterInformation; + private EEndpointHardwareSupport _HardwareSupport; + private AudioMeterInformationChannels _Channels; + + internal AudioMeterInformation(IAudioMeterInformation realInterface) + { + int HardwareSupp; + + _AudioMeterInformation = realInterface; + Marshal.ThrowExceptionForHR(_AudioMeterInformation.QueryHardwareSupport(out HardwareSupp)); + _HardwareSupport = (EEndpointHardwareSupport)HardwareSupp; + _Channels = new AudioMeterInformationChannels(_AudioMeterInformation); + + } + + /// + /// Peak Values + /// + public AudioMeterInformationChannels PeakValues + { + get + { + return _Channels; + } + } + + /// + /// Hardware Support + /// + public EEndpointHardwareSupport HardwareSupport + { + get + { + return _HardwareSupport; + } + } + + /// + /// Master Peak Value + /// + public float MasterPeakValue + { + get + { + float result; + Marshal.ThrowExceptionForHR(_AudioMeterInformation.GetPeakValue(out result)); + return result; + } + } + } +} diff --git a/CUETools.Codecs.CoreAudio/CoreAudioApi/AudioMeterInformationChannels.cs b/CUETools.Codecs.CoreAudio/CoreAudioApi/AudioMeterInformationChannels.cs new file mode 100644 index 0000000..d409b42 --- /dev/null +++ b/CUETools.Codecs.CoreAudio/CoreAudioApi/AudioMeterInformationChannels.cs @@ -0,0 +1,72 @@ +/* + LICENSE + ------- + Copyright (C) 2007 Ray Molenkamp + + This source code is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this source code or the software it produces. + + Permission is granted to anyone to use this source code for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this source code must not be misrepresented; you must not + claim that you wrote the original source code. If you use this source code + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original source code. + 3. This notice may not be removed or altered from any source distribution. +*/ +using System; +using System.Collections.Generic; +using System.Text; +using NAudio.CoreAudioApi.Interfaces; +using System.Runtime.InteropServices; + +namespace NAudio.CoreAudioApi +{ + /// + /// Audio Meter Information Channels + /// + public class AudioMeterInformationChannels + { + IAudioMeterInformation _AudioMeterInformation; + + /// + /// Metering Channel Count + /// + public int Count + { + get + { + int result; + Marshal.ThrowExceptionForHR(_AudioMeterInformation.GetMeteringChannelCount(out result)); + return result; + } + } + + /// + /// Get Peak value + /// + /// Channel index + /// Peak value + public float this[int index] + { + get + { + float[] peakValues = new float[Count]; + GCHandle Params = GCHandle.Alloc(peakValues, GCHandleType.Pinned); + Marshal.ThrowExceptionForHR(_AudioMeterInformation.GetChannelsPeakValues(peakValues.Length, Params.AddrOfPinnedObject())); + Params.Free(); + return peakValues[index]; + } + } + + internal AudioMeterInformationChannels(IAudioMeterInformation parent) + { + _AudioMeterInformation = parent; + } + } +} diff --git a/CUETools.Codecs.CoreAudio/CoreAudioApi/AudioRenderClient.cs b/CUETools.Codecs.CoreAudio/CoreAudioApi/AudioRenderClient.cs new file mode 100644 index 0000000..1b3cec2 --- /dev/null +++ b/CUETools.Codecs.CoreAudio/CoreAudioApi/AudioRenderClient.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using System.Text; +using NAudio.CoreAudioApi.Interfaces; +using System.Runtime.InteropServices; + +namespace NAudio.CoreAudioApi +{ + /// + /// Audio Render Client + /// + public class AudioRenderClient : IDisposable + { + IAudioRenderClient audioRenderClientInterface; + + internal AudioRenderClient(IAudioRenderClient audioRenderClientInterface) + { + this.audioRenderClientInterface = audioRenderClientInterface; + } + + /// + /// Gets a pointer to the buffer + /// + /// Number of frames requested + /// Pointer to the buffer + public IntPtr GetBuffer(int numFramesRequested) + { + return audioRenderClientInterface.GetBuffer(numFramesRequested); + } + + /// + /// Release buffer + /// + /// Number of frames written + /// Buffer flags + public void ReleaseBuffer(int numFramesWritten,AudioClientBufferFlags bufferFlags) + { + audioRenderClientInterface.ReleaseBuffer(numFramesWritten, bufferFlags); + } + + #region IDisposable Members + + /// + /// Release the COM object + /// + public void Dispose() + { + if (audioRenderClientInterface != null) + { + // althugh GC would do this for us, we want it done now + // to let us reopen WASAPI + Marshal.ReleaseComObject(audioRenderClientInterface); + audioRenderClientInterface = null; + GC.SuppressFinalize(this); + } + } + + #endregion + } +} diff --git a/CUETools.Codecs.CoreAudio/CoreAudioApi/AudioVolumeNotificationData.cs b/CUETools.Codecs.CoreAudio/CoreAudioApi/AudioVolumeNotificationData.cs new file mode 100644 index 0000000..ebb5448 --- /dev/null +++ b/CUETools.Codecs.CoreAudio/CoreAudioApi/AudioVolumeNotificationData.cs @@ -0,0 +1,124 @@ +/* + LICENSE + ------- + Copyright (C) 2007 Ray Molenkamp + + This source code is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this source code or the software it produces. + + Permission is granted to anyone to use this source code for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this source code must not be misrepresented; you must not + claim that you wrote the original source code. If you use this source code + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original source code. + 3. This notice may not be removed or altered from any source distribution. +*/ +using System; +using System.Collections.Generic; +using System.Text; + +namespace NAudio.CoreAudioApi +{ + /// + /// Audio Volume Notification Data + /// + public class AudioVolumeNotificationData + { + private Guid _EventContext; + private bool _Muted; + private float _MasterVolume; + private int _Channels; + private float[] _ChannelVolume; + + /// + /// Event Context + /// + public Guid EventContext + { + get + { + return _EventContext; + } + } + + /// + /// Muted + /// + public bool Muted + { + get + { + return _Muted; + } + } + + /// + /// Master Volume + /// + public float MasterVolume + { + get + { + return _MasterVolume; + } + } + + /// + /// Channels + /// + public int Channels + { + get + { + return _Channels; + } + } + + /// + /// Channel Volume + /// + public float[] ChannelVolume + { + get + { + return _ChannelVolume; + } + } + + /// + /// Audio Volume Notification Data + /// + /// + /// + /// + /// + public AudioVolumeNotificationData(Guid eventContext, bool muted, float masterVolume, float[] channelVolume) + { + _EventContext = eventContext; + _Muted = muted; + _MasterVolume = masterVolume; + _Channels = channelVolume.Length; + _ChannelVolume = channelVolume; + } + + /// + /// Audio Volume Notification Data + /// + /// + /// + /// + /// + public AudioVolumeNotificationData(Guid eventContext, bool muted, float masterVolume) + { + _EventContext = eventContext; + _Muted = muted; + _MasterVolume = masterVolume; + } + } +} diff --git a/CUETools.Codecs.CoreAudio/CoreAudioApi/DataFlow.cs b/CUETools.Codecs.CoreAudio/CoreAudioApi/DataFlow.cs new file mode 100644 index 0000000..c0810fd --- /dev/null +++ b/CUETools.Codecs.CoreAudio/CoreAudioApi/DataFlow.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace NAudio.CoreAudioApi +{ + /// + /// The EDataFlow enumeration defines constants that indicate the direction + /// in which audio data flows between an audio endpoint device and an application + /// + public enum DataFlow + { + /// + /// Audio rendering stream. + /// Audio data flows from the application to the audio endpoint device, which renders the stream. + /// + Render, + /// + /// Audio capture stream. Audio data flows from the audio endpoint device that captures the stream, + /// to the application + /// + Capture, + /// + /// Audio rendering or capture stream. Audio data can flow either from the application to the audio + /// endpoint device, or from the audio endpoint device to the application. + /// + All + }; + + +} diff --git a/CUETools.Codecs.CoreAudio/CoreAudioApi/DeviceState.cs b/CUETools.Codecs.CoreAudio/CoreAudioApi/DeviceState.cs new file mode 100644 index 0000000..2c4bc96 --- /dev/null +++ b/CUETools.Codecs.CoreAudio/CoreAudioApi/DeviceState.cs @@ -0,0 +1,52 @@ +/* + LICENSE + ------- + Copyright (C) 2007 Ray Molenkamp + + This source code is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this source code or the software it produces. + + Permission is granted to anyone to use this source code for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this source code must not be misrepresented; you must not + claim that you wrote the original source code. If you use this source code + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original source code. + 3. This notice may not be removed or altered from any source distribution. +*/ +// adapted for NAudio +using System; +using System.Collections.Generic; +using System.Text; + +namespace NAudio.CoreAudioApi +{ + /// + /// Device State + /// + [Flags] + public enum DeviceState + { + /// + /// DEVICE_STATE_ACTIVE + /// + Active = 0x00000001, + /// + /// DEVICE_STATE_UNPLUGGED + /// + Unplugged = 0x00000002, + /// + /// DEVICE_STATE_NOTPRESENT + /// + NotPresent = 0x00000004, + /// + /// DEVICE_STATEMASK_ALL + /// + All = 0x00000007 + } +} diff --git a/CUETools.Codecs.CoreAudio/CoreAudioApi/EEndpointHardwareSupport.cs b/CUETools.Codecs.CoreAudio/CoreAudioApi/EEndpointHardwareSupport.cs new file mode 100644 index 0000000..883e4ce --- /dev/null +++ b/CUETools.Codecs.CoreAudio/CoreAudioApi/EEndpointHardwareSupport.cs @@ -0,0 +1,47 @@ +/* + LICENSE + ------- + Copyright (C) 2007 Ray Molenkamp + + This source code is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this source code or the software it produces. + + Permission is granted to anyone to use this source code for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this source code must not be misrepresented; you must not + claim that you wrote the original source code. If you use this source code + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original source code. + 3. This notice may not be removed or altered from any source distribution. +*/ +using System; +using System.Collections.Generic; +using System.Text; + +namespace NAudio.CoreAudioApi +{ + /// + /// Endpoint Hardware Support + /// + [Flags] + public enum EEndpointHardwareSupport + { + /// + /// Volume + /// + Volume = 0x00000001, + /// + /// Mute + /// + Mute = 0x00000002, + /// + /// Meter + /// + Meter = 0x00000004 + } +} diff --git a/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/AudioVolumeNotificationDataStruct.cs b/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/AudioVolumeNotificationDataStruct.cs new file mode 100644 index 0000000..8eba18b --- /dev/null +++ b/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/AudioVolumeNotificationDataStruct.cs @@ -0,0 +1,54 @@ +/* + LICENSE + ------- + Copyright (C) 2007 Ray Molenkamp + + This source code is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this source code or the software it produces. + + Permission is granted to anyone to use this source code for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this source code must not be misrepresented; you must not + claim that you wrote the original source code. If you use this source code + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original source code. + 3. This notice may not be removed or altered from any source distribution. +*/ + +using System; +using System.Collections.Generic; +using System.Text; + +namespace NAudio.CoreAudioApi.Interfaces +{ + internal struct AudioVolumeNotificationDataStruct + { + public Guid guidEventContext; + public bool bMuted; + public float fMasterVolume; + public uint nChannels; + public float ChannelVolume; + + //Code Should Compile at warning level4 without any warnings, + //However this struct will give us Warning CS0649: Field [Fieldname] + //is never assigned to, and will always have its default value + //You can disable CS0649 in the project options but that will disable + //the warning for the whole project, it's a nice warning and we do want + //it in other places so we make a nice dummy function to keep the compiler + //happy. + private void FixCS0649() + { + guidEventContext = Guid.Empty; + bMuted = false; + fMasterVolume = 0; + nChannels = 0; + ChannelVolume = 0; + } + + } +} diff --git a/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/Blob.cs b/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/Blob.cs new file mode 100644 index 0000000..3937228 --- /dev/null +++ b/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/Blob.cs @@ -0,0 +1,49 @@ +/* + LICENSE + ------- + Copyright (C) 2007 Ray Molenkamp + + This source code is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this source code or the software it produces. + + Permission is granted to anyone to use this source code for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this source code must not be misrepresented; you must not + claim that you wrote the original source code. If you use this source code + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original source code. + 3. This notice may not be removed or altered from any source distribution. +*/ +// Adapted for NAudio +using System; +using System.Collections.Generic; +using System.Text; +using System.Runtime.InteropServices; + +namespace NAudio.CoreAudioApi.Interfaces +{ + internal struct Blob + { + public int Length; + public IntPtr Data; + + //Code Should Compile at warning level4 without any warnings, + //However this struct will give us Warning CS0649: Field [Fieldname] + //is never assigned to, and will always have its default value + //You can disable CS0649 in the project options but that will disable + //the warning for the whole project, it's a nice warning and we do want + //it in other places so we make a nice dummy function to keep the compiler + //happy. + private void FixCS0649() + { + Length = 0; + Data = IntPtr.Zero; + } + } +} + diff --git a/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/ClsCtx.cs b/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/ClsCtx.cs new file mode 100644 index 0000000..13ab7ae --- /dev/null +++ b/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/ClsCtx.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace NAudio.CoreAudioApi.Interfaces +{ + /// + /// is defined in WTypes.h + /// + [Flags] + enum ClsCtx + { + INPROC_SERVER = 0x1, + INPROC_HANDLER = 0x2, + LOCAL_SERVER = 0x4, + INPROC_SERVER16 = 0x8, + REMOTE_SERVER = 0x10, + INPROC_HANDLER16 = 0x20, + //RESERVED1 = 0x40, + //RESERVED2 = 0x80, + //RESERVED3 = 0x100, + //RESERVED4 = 0x200, + NO_CODE_DOWNLOAD = 0x400, + //RESERVED5 = 0x800, + NO_CUSTOM_MARSHAL = 0x1000, + ENABLE_CODE_DOWNLOAD = 0x2000, + NO_FAILURE_LOG = 0x4000, + DISABLE_AAA = 0x8000, + ENABLE_AAA = 0x10000, + FROM_DEFAULT_CONTEXT = 0x20000, + ACTIVATE_32_BIT_SERVER = 0x40000, + ACTIVATE_64_BIT_SERVER = 0x80000, + ENABLE_CLOAKING = 0x100000, + PS_DLL = unchecked ( (int) 0x80000000 ), + INPROC = INPROC_SERVER | INPROC_HANDLER, + SERVER = INPROC_SERVER | LOCAL_SERVER | REMOTE_SERVER, + ALL = SERVER | INPROC_HANDLER + } +} diff --git a/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/ErrorCodes.cs b/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/ErrorCodes.cs new file mode 100644 index 0000000..c435b88 --- /dev/null +++ b/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/ErrorCodes.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace NAudio.CoreAudioApi.Interfaces +{ + enum AudioClientErrors + { + /// + /// AUDCLNT_E_NOT_INITIALIZED + /// + NotInitialized = unchecked((int)0x88890001), + /// + /// AUDCLNT_E_UNSUPPORTED_FORMAT + /// + UnsupportedFormat = unchecked((int)0x88890008), + /// + /// AUDCLNT_E_DEVICE_IN_USE + /// + DeviceInUse = unchecked((int)0x8889000A), + + } +} diff --git a/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/IAudioCaptureClient.cs b/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/IAudioCaptureClient.cs new file mode 100644 index 0000000..d8c04e6 --- /dev/null +++ b/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/IAudioCaptureClient.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Runtime.InteropServices; + +namespace NAudio.CoreAudioApi.Interfaces +{ + + + [Guid("C8ADBD64-E71E-48a0-A4DE-185C395CD317"), + InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + interface IAudioCaptureClient + { + /*HRESULT GetBuffer( + BYTE** ppData, + UINT32* pNumFramesToRead, + DWORD* pdwFlags, + UINT64* pu64DevicePosition, + UINT64* pu64QPCPosition + );*/ + + int GetBuffer( + out IntPtr dataBuffer, + out int numFramesToRead, + out AudioClientBufferFlags bufferFlags, + out long devicePosition, + out long qpcPosition); + + int ReleaseBuffer(int numFramesRead); + + int GetNextPacketSize(out int numFramesInNextPacket); + + } +} diff --git a/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/IAudioClient.cs b/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/IAudioClient.cs new file mode 100644 index 0000000..37024a5 --- /dev/null +++ b/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/IAudioClient.cs @@ -0,0 +1,53 @@ +using System; +using System.Runtime.InteropServices; +using NAudio.Wave; + +namespace NAudio.CoreAudioApi.Interfaces +{ + /// + /// n.b. WORK IN PROGRESS - this code will probably do nothing but crash at the moment + /// Defined in AudioClient.h + /// + [Guid("1CB9AD4C-DBFA-4c32-B178-C2F568A703B2"), + InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + internal interface IAudioClient + { + void Initialize(AudioClientShareMode shareMode, + AudioClientStreamFlags StreamFlags, + long hnsBufferDuration, // REFERENCE_TIME + long hnsPeriodicity, // REFERENCE_TIME + [In] WaveFormat pFormat, + [In] ref Guid AudioSessionGuid); + + /// + /// The GetBufferSize method retrieves the size (maximum capacity) of the endpoint buffer. + /// + void GetBufferSize(out uint bufferSize); + + [return: MarshalAs(UnmanagedType.I8)] + long GetStreamLatency(); + + void GetCurrentPadding(out int currentPadding); + + [PreserveSig] + int IsFormatSupported( + AudioClientShareMode shareMode, + [In] WaveFormat pFormat, + [Out, MarshalAs(UnmanagedType.LPStruct)] out WaveFormatExtensible closestMatchFormat); + + void GetMixFormat(out IntPtr deviceFormatPointer); + + // REFERENCE_TIME is 64 bit int + void GetDevicePeriod(out long defaultDevicePeriod, out long minimumDevicePeriod); + + void Start(); + + void Stop(); + + void Reset(); + + void SetEventHandle(IntPtr eventHandle); + + void GetService(ref Guid interfaceId, [MarshalAs(UnmanagedType.IUnknown)] out object interfacePointer); + } +} diff --git a/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/IAudioEndpointVolume.cs b/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/IAudioEndpointVolume.cs new file mode 100644 index 0000000..8f0104f --- /dev/null +++ b/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/IAudioEndpointVolume.cs @@ -0,0 +1,52 @@ +/* + LICENSE + ------- + Copyright (C) 2007 Ray Molenkamp + + This source code is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this source code or the software it produces. + + Permission is granted to anyone to use this source code for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this source code must not be misrepresented; you must not + claim that you wrote the original source code. If you use this source code + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original source code. + 3. This notice may not be removed or altered from any source distribution. +*/ +using System; +using System.Collections.Generic; +using System.Text; +using System.Runtime.InteropServices; + +namespace NAudio.CoreAudioApi.Interfaces +{ + [Guid("5CDF2C82-841E-4546-9722-0CF74078229A"), + InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + internal interface IAudioEndpointVolume + { + int RegisterControlChangeNotify(IAudioEndpointVolumeCallback pNotify); + int UnregisterControlChangeNotify(IAudioEndpointVolumeCallback pNotify); + int GetChannelCount(out int pnChannelCount); + int SetMasterVolumeLevel(float fLevelDB, Guid pguidEventContext); + int SetMasterVolumeLevelScalar(float fLevel, Guid pguidEventContext); + int GetMasterVolumeLevel(out float pfLevelDB); + int GetMasterVolumeLevelScalar(out float pfLevel); + int SetChannelVolumeLevel(uint nChannel, float fLevelDB, Guid pguidEventContext); + int SetChannelVolumeLevelScalar(uint nChannel, float fLevel, Guid pguidEventContext); + int GetChannelVolumeLevel(uint nChannel, out float pfLevelDB); + int GetChannelVolumeLevelScalar(uint nChannel, out float pfLevel); + int SetMute([MarshalAs(UnmanagedType.Bool)] Boolean bMute, Guid pguidEventContext); + int GetMute(out bool pbMute); + int GetVolumeStepInfo(out uint pnStep, out uint pnStepCount); + int VolumeStepUp(Guid pguidEventContext); + int VolumeStepDown(Guid pguidEventContext); + int QueryHardwareSupport(out uint pdwHardwareSupportMask); + int GetVolumeRange(out float pflVolumeMindB, out float pflVolumeMaxdB, out float pflVolumeIncrementdB); + } +} diff --git a/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/IAudioEndpointVolumeCallback.cs b/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/IAudioEndpointVolumeCallback.cs new file mode 100644 index 0000000..4170ead --- /dev/null +++ b/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/IAudioEndpointVolumeCallback.cs @@ -0,0 +1,37 @@ +/* + LICENSE + ------- + Copyright (C) 2007 Ray Molenkamp + + This source code is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this source code or the software it produces. + + Permission is granted to anyone to use this source code for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this source code must not be misrepresented; you must not + claim that you wrote the original source code. If you use this source code + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original source code. + 3. This notice may not be removed or altered from any source distribution. +*/ +using System; +using System.Collections.Generic; +using System.Text; +using System.Runtime.InteropServices; + +namespace NAudio.CoreAudioApi.Interfaces +{ + [Guid("657804FA-D6AD-4496-8A60-352752AF4F89"), + InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + internal interface IAudioEndpointVolumeCallback + { + //int OnNotify(IntPtr NotifyData); + void OnNotify(ref AudioVolumeNotificationDataStruct pNotifyData); + }; + +} diff --git a/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/IAudioMeterInformation.cs b/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/IAudioMeterInformation.cs new file mode 100644 index 0000000..8a91e64 --- /dev/null +++ b/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/IAudioMeterInformation.cs @@ -0,0 +1,38 @@ +/* + LICENSE + ------- + Copyright (C) 2007 Ray Molenkamp + + This source code is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this source code or the software it produces. + + Permission is granted to anyone to use this source code for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this source code must not be misrepresented; you must not + claim that you wrote the original source code. If you use this source code + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original source code. + 3. This notice may not be removed or altered from any source distribution. +*/ +using System; +using System.Collections.Generic; +using System.Text; +using System.Runtime.InteropServices; + +namespace NAudio.CoreAudioApi.Interfaces +{ + [Guid("C02216F6-8C67-4B5B-9D00-D008E73E0064"), + InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + internal interface IAudioMeterInformation + { + int GetPeakValue(out float pfPeak); + int GetMeteringChannelCount(out int pnChannelCount); + int GetChannelsPeakValues(int u32ChannelCount, [In] IntPtr afPeakValues); + int QueryHardwareSupport(out int pdwHardwareSupportMask); + }; +} diff --git a/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/IAudioRenderClient.cs b/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/IAudioRenderClient.cs new file mode 100644 index 0000000..c9ab71a --- /dev/null +++ b/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/IAudioRenderClient.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Runtime.InteropServices; + +namespace NAudio.CoreAudioApi.Interfaces +{ + [Guid("F294ACFC-3146-4483-A7BF-ADDCA7C260E2"), + InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + interface IAudioRenderClient + { + IntPtr GetBuffer(int numFramesRequested); + void ReleaseBuffer(int numFramesWritten, AudioClientBufferFlags bufferFlags); + } + + +} diff --git a/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/IMMDevice.cs b/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/IMMDevice.cs new file mode 100644 index 0000000..bbc1e55 --- /dev/null +++ b/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/IMMDevice.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Runtime.InteropServices; + +namespace NAudio.CoreAudioApi.Interfaces +{ + [Guid("D666063F-1587-4E43-81F1-B948E807363F"), + InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + interface IMMDevice + { + // activationParams is a propvariant + int Activate(ref Guid id, ClsCtx clsCtx, IntPtr activationParams, + [MarshalAs(UnmanagedType.IUnknown)] out object interfacePointer); + + int OpenPropertyStore(StorageAccessMode stgmAccess, out IPropertyStore properties); + + int GetId(out string id); + + int GetState(out DeviceState state); + } + +} diff --git a/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/IMMDeviceCollection.cs b/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/IMMDeviceCollection.cs new file mode 100644 index 0000000..6a9402a --- /dev/null +++ b/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/IMMDeviceCollection.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Runtime.InteropServices; + +namespace NAudio.CoreAudioApi.Interfaces +{ + [Guid("0BD7A1BE-7A1A-44DB-8397-CC5392387B5E"), + InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + interface IMMDeviceCollection + { + int GetCount(out int numDevices); + int Item(int deviceNumber, out IMMDevice device); + } +} diff --git a/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/IMMDeviceEnumerator.cs b/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/IMMDeviceEnumerator.cs new file mode 100644 index 0000000..e0b4c9d --- /dev/null +++ b/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/IMMDeviceEnumerator.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Runtime.InteropServices; + +namespace NAudio.CoreAudioApi.Interfaces +{ + [Guid("A95664D2-9614-4F35-A746-DE8DB63617E6"), + InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + interface IMMDeviceEnumerator + { + int EnumAudioEndpoints(DataFlow dataFlow, DeviceState stateMask, + out IMMDeviceCollection devices); + + int GetDefaultAudioEndpoint(DataFlow dataFlow, Role role, out IMMDevice endpoint); + + int GetDevice(string id, out IMMDevice deviceName); + + int RegisterEndpointNotificationCallback(IMMNotificationClient client); + + int UnregisterEndpointNotificationCallback(IMMNotificationClient client); + } +} diff --git a/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/IMMEndpoint.cs b/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/IMMEndpoint.cs new file mode 100644 index 0000000..4d7c8b6 --- /dev/null +++ b/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/IMMEndpoint.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Runtime.InteropServices; + +namespace NAudio.CoreAudioApi.Interfaces +{ + /// + /// defined in MMDeviceAPI.h + /// + [Guid("1BE09788-6894-4089-8586-9A2A6C265AC5"), + InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + interface IMMEndpoint + { + int GetDataFlow(out DataFlow dataFlow); + } +} diff --git a/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/IMMNotificationClient.cs b/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/IMMNotificationClient.cs new file mode 100644 index 0000000..7da8778 --- /dev/null +++ b/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/IMMNotificationClient.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Runtime.InteropServices; + +namespace NAudio.CoreAudioApi.Interfaces +{ + [Guid("7991EEC9-7E89-4D85-8390-6C703CEC60C0"), + InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + interface IMMNotificationClient + { + int OnDeviceStateChanged(string deviceId, int newState); + + int OnDeviceAdded(string pwstrDeviceId); + + int OnDeviceRemoved(string deviceId); + + int OnDefaultDeviceChanged(DataFlow flow, Role role, string defaultDeviceId); + + int OnPropertyValueChanged(string pwstrDeviceId, PropertyKey key); + + } +} diff --git a/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/IPropertyStore.cs b/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/IPropertyStore.cs new file mode 100644 index 0000000..4d6e8f3 --- /dev/null +++ b/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/IPropertyStore.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Runtime.InteropServices; + +namespace NAudio.CoreAudioApi.Interfaces +{ + /// + /// is defined in propsys.h + /// + [Guid("886d8eeb-8cf2-4446-8d02-cdba1dbdcf99"), + InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + interface IPropertyStore + { + int GetCount(out int propCount); + int GetAt(int property, out PropertyKey key); + int GetValue(ref PropertyKey key, out PropVariant value); + int SetValue(ref PropertyKey key, ref PropVariant value); + int Commit(); + } +} diff --git a/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/MMDeviceEnumeratorComObject.cs b/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/MMDeviceEnumeratorComObject.cs new file mode 100644 index 0000000..a144fe7 --- /dev/null +++ b/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/MMDeviceEnumeratorComObject.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Runtime.InteropServices; + +namespace NAudio.CoreAudioApi.Interfaces +{ + /// + /// implements IMMDeviceEnumerator + /// + [ComImport, Guid("BCDE0395-E52F-467C-8E3D-C4579291692E")] + class MMDeviceEnumeratorComObject + { + } +} diff --git a/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/StorageAccessMode.cs b/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/StorageAccessMode.cs new file mode 100644 index 0000000..1d01f02 --- /dev/null +++ b/CUETools.Codecs.CoreAudio/CoreAudioApi/Interfaces/StorageAccessMode.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace NAudio.CoreAudioApi.Interfaces +{ + /// + /// MMDevice STGM enumeration + /// + enum StorageAccessMode + { + Read, + Write, + ReadWrite + } +} diff --git a/CUETools.Codecs.CoreAudio/CoreAudioApi/MMDevice.cs b/CUETools.Codecs.CoreAudio/CoreAudioApi/MMDevice.cs new file mode 100644 index 0000000..e1d9ee2 --- /dev/null +++ b/CUETools.Codecs.CoreAudio/CoreAudioApi/MMDevice.cs @@ -0,0 +1,219 @@ +/* + LICENSE + ------- + Copyright (C) 2007 Ray Molenkamp + + This source code is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this source code or the software it produces. + + Permission is granted to anyone to use this source code for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this source code must not be misrepresented; you must not + claim that you wrote the original source code. If you use this source code + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original source code. + 3. This notice may not be removed or altered from any source distribution. +*/ +// modified for NAudio +using System; +using System.Collections.Generic; +using System.Text; +using NAudio.CoreAudioApi.Interfaces; +using System.Runtime.InteropServices; + +namespace NAudio.CoreAudioApi +{ + /// + /// MM Device + /// + public class MMDevice + { + #region Variables + private IMMDevice deviceInterface; + private PropertyStore _PropertyStore; + private AudioMeterInformation _AudioMeterInformation; + private AudioEndpointVolume _AudioEndpointVolume; + private AudioClient audioClient; + + #endregion + + #region Guids + private static Guid IID_IAudioMeterInformation = new Guid("C02216F6-8C67-4B5B-9D00-D008E73E0064"); + private static Guid IID_IAudioEndpointVolume = new Guid("5CDF2C82-841E-4546-9722-0CF74078229A"); + private static Guid IID_IAudioClient = new Guid("1CB9AD4C-DBFA-4c32-B178-C2F568A703B2"); + #endregion + + #region Init + private void GetPropertyInformation() + { + IPropertyStore propstore; + Marshal.ThrowExceptionForHR(deviceInterface.OpenPropertyStore(StorageAccessMode.Read, out propstore)); + _PropertyStore = new PropertyStore(propstore); + } + + private void GetAudioClientInterface() + { + object result; + Marshal.ThrowExceptionForHR(deviceInterface.Activate(ref IID_IAudioClient, ClsCtx.ALL, IntPtr.Zero, out result)); + audioClient = new AudioClient(result as IAudioClient); + } + + private void GetAudioMeterInformation() + { + object result; + Marshal.ThrowExceptionForHR(deviceInterface.Activate(ref IID_IAudioMeterInformation, ClsCtx.ALL, IntPtr.Zero, out result)); + _AudioMeterInformation = new AudioMeterInformation(result as IAudioMeterInformation); + } + + private void GetAudioEndpointVolume() + { + object result; + Marshal.ThrowExceptionForHR(deviceInterface.Activate(ref IID_IAudioEndpointVolume, ClsCtx.ALL, IntPtr.Zero, out result)); + _AudioEndpointVolume = new AudioEndpointVolume(result as IAudioEndpointVolume); + } + + #endregion + + #region Properties + + /// + /// Audio Client + /// + public AudioClient AudioClient + { + get + { + if (audioClient == null) + { + GetAudioClientInterface(); + } + return audioClient; + } + } + + /// + /// Audio Meter Information + /// + public AudioMeterInformation AudioMeterInformation + { + get + { + if (_AudioMeterInformation == null) + GetAudioMeterInformation(); + + return _AudioMeterInformation; + } + } + + /// + /// Audio Endpoint Volume + /// + public AudioEndpointVolume AudioEndpointVolume + { + get + { + if (_AudioEndpointVolume == null) + GetAudioEndpointVolume(); + + return _AudioEndpointVolume; + } + } + + /// + /// Properties + /// + public PropertyStore Properties + { + get + { + if (_PropertyStore == null) + GetPropertyInformation(); + return _PropertyStore; + } + } + + /// + /// Friendly name + /// + public string FriendlyName + { + get + { + if (_PropertyStore == null) + { + GetPropertyInformation(); + } + if (_PropertyStore.Contains(PropertyKeys.PKEY_DeviceInterface_FriendlyName)) + { + return (string)_PropertyStore[PropertyKeys.PKEY_DeviceInterface_FriendlyName].Value; + } + else + return "Unknown"; + } + } + + + /// + /// Device ID + /// + public string ID + { + get + { + string Result; + Marshal.ThrowExceptionForHR(deviceInterface.GetId(out Result)); + return Result; + } + } + + /// + /// Data Flow + /// + public DataFlow DataFlow + { + get + { + DataFlow Result; + IMMEndpoint ep = deviceInterface as IMMEndpoint; + ep.GetDataFlow(out Result); + return Result; + } + } + + /// + /// Device State + /// + public DeviceState State + { + get + { + DeviceState Result; + Marshal.ThrowExceptionForHR(deviceInterface.GetState(out Result)); + return Result; + + } + } + #endregion + + #region Constructor + internal MMDevice(IMMDevice realDevice) + { + deviceInterface = realDevice; + } + #endregion + + /// + /// To string + /// + public override string ToString() + { + return FriendlyName; + } + + } +} diff --git a/CUETools.Codecs.CoreAudio/CoreAudioApi/MMDeviceCollection.cs b/CUETools.Codecs.CoreAudio/CoreAudioApi/MMDeviceCollection.cs new file mode 100644 index 0000000..9d4b811 --- /dev/null +++ b/CUETools.Codecs.CoreAudio/CoreAudioApi/MMDeviceCollection.cs @@ -0,0 +1,96 @@ +/* + LICENSE + ------- + Copyright (C) 2007 Ray Molenkamp + + This source code is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this source code or the software it produces. + + Permission is granted to anyone to use this source code for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this source code must not be misrepresented; you must not + claim that you wrote the original source code. If you use this source code + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original source code. + 3. This notice may not be removed or altered from any source distribution. +*/ +// updated for NAudio +using System; +using System.Collections.Generic; +using System.Text; +using System.Runtime.InteropServices; +using NAudio.CoreAudioApi.Interfaces; + +namespace NAudio.CoreAudioApi +{ + /// + /// Multimedia Device Collection + /// + public class MMDeviceCollection : IEnumerable + { + private IMMDeviceCollection _MMDeviceCollection; + + /// + /// Device count + /// + public int Count + { + get + { + int result; + Marshal.ThrowExceptionForHR(_MMDeviceCollection.GetCount(out result)); + return result; + } + } + + /// + /// Get device by index + /// + /// Device index + /// Device at the specified index + public MMDevice this[int index] + { + get + { + IMMDevice result; + _MMDeviceCollection.Item(index, out result); + return new MMDevice(result); + } + } + + internal MMDeviceCollection(IMMDeviceCollection parent) + { + _MMDeviceCollection = parent; + } + + #region IEnumerable Members + + /// + /// Get Enumerator + /// + /// Device enumerator + public IEnumerator GetEnumerator() + { + for (int index = 0; index < Count; index++) + { + yield return this[index]; + } + } + + #endregion + + #region IEnumerable Members + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + #endregion + } +} diff --git a/CUETools.Codecs.CoreAudio/CoreAudioApi/MMDeviceEnumerator.cs b/CUETools.Codecs.CoreAudio/CoreAudioApi/MMDeviceEnumerator.cs new file mode 100644 index 0000000..119360c --- /dev/null +++ b/CUETools.Codecs.CoreAudio/CoreAudioApi/MMDeviceEnumerator.cs @@ -0,0 +1,89 @@ +/* + LICENSE + ------- + Copyright (C) 2007 Ray Molenkamp + + This source code is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this source code or the software it produces. + + Permission is granted to anyone to use this source code for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this source code must not be misrepresented; you must not + claim that you wrote the original source code. If you use this source code + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original source code. + 3. This notice may not be removed or altered from any source distribution. +*/ +// updated for use in NAudio +using System; +using System.Collections.Generic; +using System.Text; +using System.Runtime.InteropServices; +using NAudio.CoreAudioApi.Interfaces; + +namespace NAudio.CoreAudioApi +{ + + /// + /// MM Device Enumerator + /// + public class MMDeviceEnumerator + { + private IMMDeviceEnumerator _realEnumerator; + + /// + /// Enumerate Audio Endpoints + /// + /// Desired DataFlow + /// State Mask + /// Device Collection + public MMDeviceCollection EnumerateAudioEndPoints(DataFlow dataFlow, DeviceState dwStateMask) + { + IMMDeviceCollection result; + Marshal.ThrowExceptionForHR(_realEnumerator.EnumAudioEndpoints(dataFlow, dwStateMask, out result)); + return new MMDeviceCollection(result); + } + + /// + /// Get Default Endpoint + /// + /// Data Flow + /// Role + /// Device + public MMDevice GetDefaultAudioEndpoint(DataFlow dataFlow, Role role) + { + IMMDevice _Device = null; + Marshal.ThrowExceptionForHR(((IMMDeviceEnumerator)_realEnumerator).GetDefaultAudioEndpoint(dataFlow, role, out _Device)); + return new MMDevice(_Device); + } + + /// + /// Get device by ID + /// + /// Device ID + /// Device + public MMDevice GetDevice(string ID) + { + IMMDevice _Device = null; + Marshal.ThrowExceptionForHR(((IMMDeviceEnumerator)_realEnumerator).GetDevice(ID, out _Device)); + return new MMDevice(_Device); + } + + /// + /// Creates a new MM Device Enumerator + /// + public MMDeviceEnumerator() + { + if (System.Environment.OSVersion.Version.Major < 6) + { + throw new NotSupportedException("This functionality is only supported on Windows Vista or newer."); + } + _realEnumerator = new MMDeviceEnumeratorComObject() as IMMDeviceEnumerator; + } + } +} diff --git a/CUETools.Codecs.CoreAudio/CoreAudioApi/PropVariant.cs b/CUETools.Codecs.CoreAudio/CoreAudioApi/PropVariant.cs new file mode 100644 index 0000000..7d540bb --- /dev/null +++ b/CUETools.Codecs.CoreAudio/CoreAudioApi/PropVariant.cs @@ -0,0 +1,157 @@ +/* + LICENSE + ------- + Copyright (C) 2007 Ray Molenkamp + + This source code is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this source code or the software it produces. + + Permission is granted to anyone to use this source code for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this source code must not be misrepresented; you must not + claim that you wrote the original source code. If you use this source code + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original source code. + 3. This notice may not be removed or altered from any source distribution. +*/ +// adapted for use in NAudio +using System; +using System.Collections.Generic; +using System.Text; +using System.Runtime.InteropServices; + +namespace NAudio.CoreAudioApi.Interfaces +{ + /// + /// from Propidl.h. + /// http://msdn.microsoft.com/en-us/library/aa380072(VS.85).aspx + /// contains a union so we have to do an explicit layout + /// + [StructLayout(LayoutKind.Explicit)] + public struct PropVariant + { + [FieldOffset(0)] short vt; + [FieldOffset(2)] short wReserved1; + [FieldOffset(4)] short wReserved2; + [FieldOffset(6)] short wReserved3; + [FieldOffset(8)] sbyte cVal; + [FieldOffset(8)] byte bVal; + [FieldOffset(8)] short iVal; + [FieldOffset(8)] ushort uiVal; + [FieldOffset(8)] int lVal; + [FieldOffset(8)] uint ulVal; + [FieldOffset(8)] int intVal; + [FieldOffset(8)] uint uintVal; + [FieldOffset(8)] long hVal; + [FieldOffset(8)] long uhVal; + [FieldOffset(8)] float fltVal; + [FieldOffset(8)] double dblVal; + [FieldOffset(8)] bool boolVal; + [FieldOffset(8)] int scode; + //CY cyVal; + [FieldOffset(8)] DateTime date; + [FieldOffset(8)] System.Runtime.InteropServices.ComTypes.FILETIME filetime; + //CLSID* puuid; + //CLIPDATA* pclipdata; + //BSTR bstrVal; + //BSTRBLOB bstrblobVal; + [FieldOffset(8)] Blob blobVal; + //LPSTR pszVal; + [FieldOffset(8)] IntPtr pwszVal; //LPWSTR + //IUnknown* punkVal; + /*IDispatch* pdispVal; + IStream* pStream; + IStorage* pStorage; + LPVERSIONEDSTREAM pVersionedStream; + LPSAFEARRAY parray; + CAC cac; + CAUB caub; + CAI cai; + CAUI caui; + CAL cal; + CAUL caul; + CAH cah; + CAUH cauh; + CAFLT caflt; + CADBL cadbl; + CABOOL cabool; + CASCODE cascode; + CACY cacy; + CADATE cadate; + CAFILETIME cafiletime; + CACLSID cauuid; + CACLIPDATA caclipdata; + CABSTR cabstr; + CABSTRBLOB cabstrblob; + CALPSTR calpstr; + CALPWSTR calpwstr; + CAPROPVARIANT capropvar; + CHAR* pcVal; + UCHAR* pbVal; + SHORT* piVal; + USHORT* puiVal; + LONG* plVal; + ULONG* pulVal; + INT* pintVal; + UINT* puintVal; + FLOAT* pfltVal; + DOUBLE* pdblVal; + VARIANT_BOOL* pboolVal; + DECIMAL* pdecVal; + SCODE* pscode; + CY* pcyVal; + DATE* pdate; + BSTR* pbstrVal; + IUnknown** ppunkVal; + IDispatch** ppdispVal; + LPSAFEARRAY* pparray; + PROPVARIANT* pvarVal; + */ + + /// + /// Helper method to gets blob data + /// + byte[] GetBlob() + { + byte[] Result = new byte[blobVal.Length]; + Marshal.Copy(blobVal.Data, Result, 0, Result.Length); + return Result; + } + + /// + /// Property value + /// + public object Value + { + get + { + VarEnum ve = (VarEnum)vt; + switch (ve) + { + case VarEnum.VT_I1: + return bVal; + case VarEnum.VT_I2: + return iVal; + case VarEnum.VT_I4: + return lVal; + case VarEnum.VT_I8: + return hVal; + case VarEnum.VT_INT: + return iVal; + case VarEnum.VT_UI4: + return ulVal; + case VarEnum.VT_LPWSTR: + return Marshal.PtrToStringUni(pwszVal); + case VarEnum.VT_BLOB: + return GetBlob(); + } + throw new NotImplementedException("PropVariant " + ve.ToString()); + } + } + } +} diff --git a/CUETools.Codecs.CoreAudio/CoreAudioApi/PropertyKey.cs b/CUETools.Codecs.CoreAudio/CoreAudioApi/PropertyKey.cs new file mode 100644 index 0000000..4ac344c --- /dev/null +++ b/CUETools.Codecs.CoreAudio/CoreAudioApi/PropertyKey.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace NAudio.CoreAudioApi +{ + /// + /// PROPERTYKEY is defined in wtypes.h + /// + public struct PropertyKey + { + /// + /// Format ID + /// + public Guid formatId; + /// + /// Property ID + /// + public int propertyId; + } +} diff --git a/CUETools.Codecs.CoreAudio/CoreAudioApi/PropertyKeys.cs b/CUETools.Codecs.CoreAudio/CoreAudioApi/PropertyKeys.cs new file mode 100644 index 0000000..1d369e4 --- /dev/null +++ b/CUETools.Codecs.CoreAudio/CoreAudioApi/PropertyKeys.cs @@ -0,0 +1,71 @@ +/* + LICENSE + ------- + Copyright (C) 2007 Ray Molenkamp + + This source code is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this source code or the software it produces. + + Permission is granted to anyone to use this source code for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this source code must not be misrepresented; you must not + claim that you wrote the original source code. If you use this source code + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original source code. + 3. This notice may not be removed or altered from any source distribution. +*/ +using System; +using System.Collections.Generic; +using System.Text; + +namespace NAudio.CoreAudioApi +{ + /// + /// Property Keys + /// + public static class PropertyKeys + { + /// + /// PKEY_DeviceInterface_FriendlyName + /// + public static readonly Guid PKEY_DeviceInterface_FriendlyName = new Guid(0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0); + /// + /// PKEY_AudioEndpoint_FormFactor + /// + public static readonly Guid PKEY_AudioEndpoint_FormFactor = new Guid(0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x23, 0xe0, 0xc0, 0xff, 0xee, 0x7f, 0x0e); + /// + /// PKEY_AudioEndpoint_ControlPanelPageProvider + /// + public static readonly Guid PKEY_AudioEndpoint_ControlPanelPageProvider = new Guid(0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x23, 0xe0, 0xc0, 0xff, 0xee, 0x7f, 0x0e); + /// + /// PKEY_AudioEndpoint_Association + /// + public static readonly Guid PKEY_AudioEndpoint_Association = new Guid(0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x23, 0xe0, 0xc0, 0xff, 0xee, 0x7f, 0x0e); + /// + /// PKEY_AudioEndpoint_PhysicalSpeakers + /// + public static readonly Guid PKEY_AudioEndpoint_PhysicalSpeakers = new Guid(0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x23, 0xe0, 0xc0, 0xff, 0xee, 0x7f, 0x0e); + /// + /// PKEY_AudioEndpoint_GUID + /// + public static readonly Guid PKEY_AudioEndpoint_GUID = new Guid(0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x23, 0xe0, 0xc0, 0xff, 0xee, 0x7f, 0x0e); + /// + /// PKEY_AudioEndpoint_Disable_SysFx + /// + public static readonly Guid PKEY_AudioEndpoint_Disable_SysFx = new Guid(0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x23, 0xe0, 0xc0, 0xff, 0xee, 0x7f, 0x0e); + /// + /// PKEY_AudioEndpoint_FullRangeSpeakers + /// + public static readonly Guid PKEY_AudioEndpoint_FullRangeSpeakers = new Guid(0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x23, 0xe0, 0xc0, 0xff, 0xee, 0x7f, 0x0e); + /// + /// PKEY_AudioEngine_DeviceFormat + /// + public static readonly Guid PKEY_AudioEngine_DeviceFormat = new Guid(0xf19f064d, 0x82c, 0x4e27, 0xbc, 0x73, 0x68, 0x82, 0xa1, 0xbb, 0x8e, 0x4c); + + } +} diff --git a/CUETools.Codecs.CoreAudio/CoreAudioApi/PropertyStore.cs b/CUETools.Codecs.CoreAudio/CoreAudioApi/PropertyStore.cs new file mode 100644 index 0000000..83560c7 --- /dev/null +++ b/CUETools.Codecs.CoreAudio/CoreAudioApi/PropertyStore.cs @@ -0,0 +1,143 @@ +/* + LICENSE + ------- + Copyright (C) 2007 Ray Molenkamp + + This source code is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this source code or the software it produces. + + Permission is granted to anyone to use this source code for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this source code must not be misrepresented; you must not + claim that you wrote the original source code. If you use this source code + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original source code. + 3. This notice may not be removed or altered from any source distribution. +*/ +// this version modified for NAudio from Ray Molenkamp's original +using System; +using System.Collections.Generic; +using System.Text; +using System.Runtime.InteropServices; +using NAudio.CoreAudioApi.Interfaces; + +namespace NAudio.CoreAudioApi +{ + /// + /// Property Store class, only supports reading properties at the moment. + /// + public class PropertyStore + { + private IPropertyStore storeInterface; + + /// + /// Property Count + /// + public int Count + { + get + { + int result; + Marshal.ThrowExceptionForHR(storeInterface.GetCount(out result)); + return result; + } + } + + /// + /// Gets property by index + /// + /// Property index + /// The property + public PropertyStoreProperty this[int index] + { + get + { + PropVariant result; + PropertyKey key = Get(index); + Marshal.ThrowExceptionForHR(storeInterface.GetValue(ref key, out result)); + return new PropertyStoreProperty(key, result); + } + } + + /// + /// Contains property guid + /// + /// Looks for a specific Guid + /// True if found + public bool Contains(Guid guid) + { + for (int i = 0; i < Count; i++) + { + PropertyKey key = Get(i); + if (key.formatId == guid) + { + return true; + } + } + return false; + } + + /// + /// Indexer by guid + /// + /// Property guid + /// Property or null if not found + public PropertyStoreProperty this[Guid guid] + { + get + { + PropVariant result; + for (int i = 0; i < Count; i++) + { + PropertyKey key = Get(i); + if (key.formatId == guid) + { + Marshal.ThrowExceptionForHR(storeInterface.GetValue(ref key, out result)); + return new PropertyStoreProperty(key, result); + } + } + return null; + } + } + + /// + /// Gets property key at sepecified index + /// + /// Index + /// Property key + public PropertyKey Get(int index) + { + PropertyKey key; + Marshal.ThrowExceptionForHR(storeInterface.GetAt(index, out key)); + return key; + } + + /// + /// Gets property value at specified index + /// + /// Index + /// Property value + public PropVariant GetValue(int index) + { + PropVariant result; + PropertyKey key = Get(index); + Marshal.ThrowExceptionForHR(storeInterface.GetValue(ref key, out result)); + return result; + } + + /// + /// Creates a new property store + /// + /// IPropertyStore COM interface + internal PropertyStore(IPropertyStore store) + { + this.storeInterface = store; + } + } +} + diff --git a/CUETools.Codecs.CoreAudio/CoreAudioApi/PropertyStoreProperty.cs b/CUETools.Codecs.CoreAudio/CoreAudioApi/PropertyStoreProperty.cs new file mode 100644 index 0000000..cc78ece --- /dev/null +++ b/CUETools.Codecs.CoreAudio/CoreAudioApi/PropertyStoreProperty.cs @@ -0,0 +1,69 @@ +/* + LICENSE + ------- + Copyright (C) 2007 Ray Molenkamp + + This source code is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this source code or the software it produces. + + Permission is granted to anyone to use this source code for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this source code must not be misrepresented; you must not + claim that you wrote the original source code. If you use this source code + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original source code. + 3. This notice may not be removed or altered from any source distribution. +*/ +// modified from Ray Molenkamp's original + + +using System; +using System.Collections.Generic; +using System.Text; +using NAudio.CoreAudioApi.Interfaces; + +namespace NAudio.CoreAudioApi +{ + /// + /// Property Store Property + /// + public class PropertyStoreProperty + { + private PropertyKey propertyKey; + private PropVariant propertyValue; + + internal PropertyStoreProperty(PropertyKey key, PropVariant value) + { + propertyKey = key; + propertyValue = value; + } + + /// + /// Property Key + /// + public PropertyKey Key + { + get + { + return propertyKey; + } + } + + /// + /// Property Value + /// + public object Value + { + get + { + return propertyValue.Value; + } + } + } +} + diff --git a/CUETools.Codecs.CoreAudio/CoreAudioApi/Role.cs b/CUETools.Codecs.CoreAudio/CoreAudioApi/Role.cs new file mode 100644 index 0000000..078ecfd --- /dev/null +++ b/CUETools.Codecs.CoreAudio/CoreAudioApi/Role.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace NAudio.CoreAudioApi +{ + /// + /// The ERole enumeration defines constants that indicate the role + /// that the system has assigned to an audio endpoint device + /// + public enum Role + { + /// + /// Games, system notification sounds, and voice commands. + /// + Console, + /// + /// Music, movies, narration, and live music recording + /// + Multimedia, + /// + /// Voice communications (talking to another person). + /// + Communications, + } +} diff --git a/CUETools.Codecs.CoreAudio/CoreAudioApi/WasapiCapture.cs b/CUETools.Codecs.CoreAudio/CoreAudioApi/WasapiCapture.cs new file mode 100644 index 0000000..75a0ad6 --- /dev/null +++ b/CUETools.Codecs.CoreAudio/CoreAudioApi/WasapiCapture.cs @@ -0,0 +1,216 @@ +using System; +using System.Collections.Generic; +using System.Text; +using NAudio.Wave; +using System.Threading; +using System.Diagnostics; +using System.Runtime.InteropServices; + +namespace NAudio.CoreAudioApi +{ + /// + /// Audio Capture using Wasapi + /// See http://msdn.microsoft.com/en-us/library/dd370800%28VS.85%29.aspx + /// + public class WasapiCapture : IWaveIn + { + private const long REFTIMES_PER_SEC = 10000000; + private const long REFTIMES_PER_MILLISEC = 10000; + private volatile bool stop; + private byte[] recordBuffer; + private Thread captureThread; + private AudioClient audioClient; + private int bytesPerFrame; + + /// + /// Indicates recorded data is available + /// + public event EventHandler DataAvailable; + + /// + /// Indicates that all recorded data has now been received. + /// + public event EventHandler RecordingStopped; + + /// + /// Initialises a new instance of the WASAPI capture class + /// + public WasapiCapture() : + this(GetDefaultCaptureDevice()) + { + } + + /// + /// Initialises a new instance of the WASAPI capture class + /// + /// Capture device to use + public WasapiCapture(MMDevice captureDevice) + { + this.audioClient = captureDevice.AudioClient; + WaveFormat = audioClient.MixFormat; + } + + /// + /// Recording wave format + /// + public WaveFormat WaveFormat { get; set; } + + /// + /// Gets the default audio capture device + /// + /// The default audio capture device + public static MMDevice GetDefaultCaptureDevice() + { + MMDeviceEnumerator devices = new MMDeviceEnumerator(); + return devices.GetDefaultAudioEndpoint(DataFlow.Capture, Role.Console); + } + + private void InitializeCaptureDevice() + { + long requestedDuration = REFTIMES_PER_MILLISEC * 100; + + if (!audioClient.IsFormatSupported(AudioClientShareMode.Shared, WaveFormat)) + { + throw new ArgumentException("Unsupported Wave Format"); + } + + audioClient.Initialize(AudioClientShareMode.Shared, + AudioClientStreamFlags.None, + requestedDuration, + 0, + WaveFormat, + Guid.Empty); + + int bufferFrameCount = audioClient.BufferSize; + bytesPerFrame = WaveFormat.Channels * WaveFormat.BitsPerSample / 8; + recordBuffer = new byte[bufferFrameCount * bytesPerFrame]; + Debug.WriteLine(string.Format("record buffer size = {0}", recordBuffer.Length)); + } + + /// + /// Start Recording + /// + public void StartRecording() + { + InitializeCaptureDevice(); + ThreadStart start = delegate { this.CaptureThread(this.audioClient); }; + this.captureThread = new Thread(start); + + Debug.WriteLine("Thread starting..."); + this.stop = false; + this.captureThread.Start(); + } + + /// + /// Stop Recording + /// + public void StopRecording() + { + if (this.captureThread != null) + { + this.stop = true; + + Debug.WriteLine("Thread ending..."); + + // wait for thread to end + this.captureThread.Join(); + this.captureThread = null; + + Debug.WriteLine("Done."); + + this.stop = false; + } + } + + private void CaptureThread(AudioClient client) + { + Debug.WriteLine(client.BufferSize); + int bufferFrameCount = audioClient.BufferSize; + + // Calculate the actual duration of the allocated buffer. + long actualDuration = (long)((double)REFTIMES_PER_SEC * + bufferFrameCount / WaveFormat.SampleRate); + int sleepMilliseconds = (int)(actualDuration / REFTIMES_PER_MILLISEC / 2); + + AudioCaptureClient capture = client.AudioCaptureClient; + client.Start(); + + try + { + Debug.WriteLine(string.Format("sleep: {0} ms", sleepMilliseconds)); + while (!this.stop) + { + Thread.Sleep(sleepMilliseconds); + ReadNextPacket(capture); + } + + client.Stop(); + + if (RecordingStopped != null) + { + RecordingStopped(this, EventArgs.Empty); + } + } + finally + { + if (capture != null) + { + capture.Dispose(); + } + if (client != null) + { + client.Dispose(); + } + + client = null; + capture = null; + } + + System.Diagnostics.Debug.WriteLine("stop wasapi"); + } + + private void ReadNextPacket(AudioCaptureClient capture) + { + IntPtr buffer; + int framesAvailable; + AudioClientBufferFlags flags; + int packetSize = capture.GetNextPacketSize(); + int recordBufferOffset = 0; + //Debug.WriteLine(string.Format("packet size: {0} samples", packetSize / 4)); + + while (packetSize != 0) + { + buffer = capture.GetBuffer(out framesAvailable, out flags); + + int bytesAvailable = framesAvailable * bytesPerFrame; + + //Debug.WriteLine(string.Format("got buffer: {0} frames", framesAvailable)); + + // if not silence... + if ((flags & AudioClientBufferFlags.Silent) != AudioClientBufferFlags.Silent) + { + Marshal.Copy(buffer, recordBuffer, recordBufferOffset, bytesAvailable); + } + else + { + Array.Clear(recordBuffer, recordBufferOffset, bytesAvailable); + } + recordBufferOffset += bytesAvailable; + capture.ReleaseBuffer(framesAvailable); + packetSize = capture.GetNextPacketSize(); + } + if (DataAvailable != null) + { + DataAvailable(this, new WaveInEventArgs(recordBuffer, recordBufferOffset)); + } + } + + /// + /// Dispose + /// + public void Dispose() + { + StopRecording(); + } + } +} diff --git a/CUETools.Codecs.CoreAudio/IWavePlayer.cs b/CUETools.Codecs.CoreAudio/IWavePlayer.cs new file mode 100644 index 0000000..c676483 --- /dev/null +++ b/CUETools.Codecs.CoreAudio/IWavePlayer.cs @@ -0,0 +1,42 @@ +using System; +using CUETools.Codecs; + +namespace CUETools.Codecs.CoreAudio +{ + /// + /// Represents the interface to a device that can play a WaveFile + /// + public interface IWavePlayer : IDisposable, IAudioDest + { + /// + /// Begin playback + /// + void Play(); + + /// + /// Stop playback + /// + void Stop(); + + /// + /// Pause Playback + /// + void Pause(); + + /// + /// Current playback state + /// + PlaybackState PlaybackState { get; } + + /// + /// The volume 1.0 is full scale + /// + float Volume { get; set; } + + /// + /// Indicates that playback has gone into a stopped state due to + /// reaching the end of the input stream + /// + event EventHandler PlaybackStopped; + } +} diff --git a/CUETools.Codecs.CoreAudio/PlaybackState.cs b/CUETools.Codecs.CoreAudio/PlaybackState.cs new file mode 100644 index 0000000..277cbd9 --- /dev/null +++ b/CUETools.Codecs.CoreAudio/PlaybackState.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace CUETools.Codecs.CoreAudio +{ + /// + /// Playback State + /// + public enum PlaybackState + { + /// + /// Stopped + /// + Stopped, + /// + /// Playing + /// + Playing, + /// + /// Paused + /// + Paused + } +} diff --git a/CUETools.Codecs.CoreAudio/Properties/AssemblyInfo.cs b/CUETools.Codecs.CoreAudio/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..d60860f --- /dev/null +++ b/CUETools.Codecs.CoreAudio/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("CUETools.Codecs.CoreAudio")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("CUETools.Codecs.CoreAudio")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2010")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("f597837f-dd1c-4e0f-b915-0e929bf0dd35")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/CUETools.Codecs.CoreAudio/WasapiOut.cs b/CUETools.Codecs.CoreAudio/WasapiOut.cs new file mode 100644 index 0000000..6ec1b51 --- /dev/null +++ b/CUETools.Codecs.CoreAudio/WasapiOut.cs @@ -0,0 +1,492 @@ +using System; +using System.Collections.Generic; +using System.Text; +using CUETools.Codecs; +using NAudio.CoreAudioApi; +using System.Threading; +using System.Runtime.InteropServices; +using System.Diagnostics; + +namespace CUETools.Codecs.CoreAudio +{ + /// + /// Support for playback using Wasapi + /// + public class WasapiOut : IWavePlayer + { + AudioClient audioClient; + AudioClientShareMode shareMode; + AudioRenderClient renderClient; + int latencyMilliseconds; + int bufferFrameCount; + bool isUsingEventSync; + EventWaitHandle frameEventWaitHandle; + AudioBuffer[] readBuffers; + volatile PlaybackState playbackState; + Thread playThread; + private long _sampleOffset; + private AudioPCMConfig pcm; + private NAudio.Wave.WaveFormat outputFormat; + + /// + /// Playback Stopped + /// + public event EventHandler PlaybackStopped; + + /// + /// WASAPI Out using default audio endpoint + /// + /// ShareMode - shared or exclusive + /// Desired latency in milliseconds + public WasapiOut(AudioClientShareMode shareMode, int latency) : + this(GetDefaultAudioEndpoint(), shareMode, true, latency, AudioPCMConfig.RedBook) + { + + } + + /// + /// WASAPI Out using default audio endpoint + /// + /// ShareMode - shared or exclusive + /// true if sync is done with event. false use sleep. + /// Desired latency in milliseconds + public WasapiOut(AudioClientShareMode shareMode, bool useEventSync, int latency) : + this(GetDefaultAudioEndpoint(), shareMode, useEventSync, latency, AudioPCMConfig.RedBook) + { + + } + + /// + /// Creates a new WASAPI Output + /// + /// Device to use + /// + /// true if sync is done with event. false use sleep. + /// + public WasapiOut(MMDevice device, AudioClientShareMode shareMode, bool useEventSync, int latency, AudioPCMConfig pcm) + { + this.audioClient = device.AudioClient; + this.shareMode = shareMode; + this.isUsingEventSync = useEventSync; + this.latencyMilliseconds = latency; + this.pcm = pcm; + this.outputFormat = new NAudio.Wave.WaveFormat(pcm.SampleRate, pcm.BitsPerSample, pcm.ChannelCount); + NAudio.Wave.WaveFormatExtensible closestSampleRateFormat; + if (!audioClient.IsFormatSupported(shareMode, outputFormat, out closestSampleRateFormat)) + throw new NotSupportedException("PCM format mismatch"); + Init(); + bufferFrameCount = audioClient.BufferSize; + readBuffers = new AudioBuffer[2]; + readBuffers[0] = new AudioBuffer(pcm, bufferFrameCount); + readBuffers[1] = new AudioBuffer(pcm, bufferFrameCount); + //if (this.shareMode == AudioClientShareMode.Exclusive) + // this.latencyMilliseconds = (int)(this.audioClient.DefaultDevicePeriod / 10000); + } + + + public static MMDevice GetDefaultAudioEndpoint() + { + if (Environment.OSVersion.Version.Major < 6) + { + throw new NotSupportedException("WASAPI supported only on Windows Vista and above"); + } + MMDeviceEnumerator enumerator = new MMDeviceEnumerator(); + return enumerator.GetDefaultAudioEndpoint(DataFlow.Render, Role.Console); + } + + private bool BufferReady(int iBuf, bool write) + { + return write ? readBuffers[iBuf].Length == 0 : readBuffers[iBuf].Length == readBuffers[iBuf].Size; + } + + public AudioBuffer GetBuffer(bool write) + { + lock (this) + { + while (!BufferReady(0, write) && !BufferReady(1, write) && playbackState != PlaybackState.Stopped) + Monitor.Wait(this); + if (playbackState == PlaybackState.Stopped) + return null; + if (BufferReady(0, write)) + return readBuffers[0]; + return readBuffers[1]; + } + } + + public void ReleaseBuffer(AudioBuffer buff, bool write, int length) + { + lock (this) + { + buff.Length = length; + Monitor.Pulse(this); + } + } + + private void PlayThread() + { + try + { + AudioBuffer buff = GetBuffer(false); + if (buff == null) + { + RaisePlaybackStopped(); + return; + } + + audioClient.Reset(); + + // fill a whole buffer + IntPtr buffer = renderClient.GetBuffer(buff.Length); + Marshal.Copy(buff.Bytes, 0, buffer, buff.ByteLength); + renderClient.ReleaseBuffer(buff.Length, AudioClientBufferFlags.None); + ReleaseBuffer(buff, false, 0); + + // Create WaitHandle for sync + WaitHandle[] waitHandles = new WaitHandle[] { frameEventWaitHandle }; + if (frameEventWaitHandle != null) + frameEventWaitHandle.Reset(); + audioClient.Start(); + + if (isUsingEventSync && shareMode == AudioClientShareMode.Exclusive) + { + while (playbackState != PlaybackState.Stopped) + { + int indexHandle = WaitHandle.WaitAny(waitHandles, 10 * latencyMilliseconds, false); + if (playbackState == PlaybackState.Playing && indexHandle != WaitHandle.WaitTimeout) + { + // In exclusive mode, always ask the max = bufferFrameCount = audioClient.BufferSize + buff = GetBuffer(false); + if (buff == null) + break; + buffer = renderClient.GetBuffer(buff.Length); + Marshal.Copy(buff.Bytes, 0, buffer, buff.ByteLength); + renderClient.ReleaseBuffer(buff.Length, AudioClientBufferFlags.None); + ReleaseBuffer(buff, false, 0); + } + } + } + else + { + buff = null; + int offs = 0; + while (playbackState != PlaybackState.Stopped) + { + // If using Event Sync, Wait for notification from AudioClient or Sleep half latency + int indexHandle = 0; + if (isUsingEventSync) + { + indexHandle = WaitHandle.WaitAny(waitHandles, 3 * latencyMilliseconds, false); + } + else + { + Thread.Sleep(latencyMilliseconds / 2); + } + + // If still playing and notification is ok + if (playbackState == PlaybackState.Playing && indexHandle != WaitHandle.WaitTimeout) + { + // See how much buffer space is available. + int numFramesAvailable = bufferFrameCount - audioClient.CurrentPadding; + if (numFramesAvailable > 0) + { + if (buff == null) + { + buff = GetBuffer(false); + offs = 0; + } + if (buff == null) + break; + numFramesAvailable = Math.Min(numFramesAvailable, buff.Length - offs); + buffer = renderClient.GetBuffer(numFramesAvailable); + Marshal.Copy(buff.Bytes, offs * pcm.BlockAlign, buffer, numFramesAvailable * pcm.BlockAlign); + renderClient.ReleaseBuffer(numFramesAvailable, AudioClientBufferFlags.None); + offs += numFramesAvailable; + if (offs == buff.Length) + { + ReleaseBuffer(buff, false, 0); + buff = null; + } + } + } + } + } + //Thread.Sleep(isUsingEventSync ? latencyMilliseconds : latencyMilliseconds / 2); + audioClient.Stop(); + if (playbackState == PlaybackState.Stopped) + audioClient.Reset(); + } + catch (Exception ex) + { + playbackState = PlaybackState.Stopped; + ReleaseBuffer(readBuffers[0], false, 0); + ReleaseBuffer(readBuffers[1], false, 0); + playThread = null; + try + { + audioClient.Stop(); + } + catch { } + RaisePlaybackException(ex); + return; + } + ReleaseBuffer(readBuffers[0], false, 0); + ReleaseBuffer(readBuffers[1], false, 0); + RaisePlaybackStopped(); + } + + private void RaisePlaybackException(Exception ex) + { + RaisePlaybackStopped(); + } + + private void RaisePlaybackStopped() + { + if (PlaybackStopped != null) + { + PlaybackStopped(this, EventArgs.Empty); + } + } + + #region IWavePlayer Members + + /// + /// Begin Playback + /// + public void Play() + { + switch (playbackState) + { + case PlaybackState.Playing: + return; + case PlaybackState.Paused: + playbackState = PlaybackState.Playing; + return; + case PlaybackState.Stopped: + playbackState = PlaybackState.Playing; + playThread = new Thread(new ThreadStart(PlayThread)); + playThread.Priority = ThreadPriority.Highest; + playThread.IsBackground = true; + playThread.Name = "Pro Audio"; + playThread.Start(); + return; + } + } + + /// + /// Stop playback and flush buffers + /// + public void Stop() + { + if (playbackState != PlaybackState.Stopped) + { + playbackState = PlaybackState.Stopped; + if (frameEventWaitHandle != null) + frameEventWaitHandle.Set(); + playThread.Join(); + playThread = null; + ReleaseBuffer(readBuffers[0], false, 0); + ReleaseBuffer(readBuffers[1], false, 0); + active = null; + active_offset = 0; + } + } + + /// + /// Stop playback without flushing buffers + /// + public void Pause() + { + if (playbackState == PlaybackState.Playing) + { + //playbackState = PlaybackState.Paused; + } + if (frameEventWaitHandle != null) + frameEventWaitHandle.Set(); + } + + private bool inited = false; + + + /// + /// Initialize for playing the specified format + /// + private void Init() + { + if (inited) + return; + + long latencyRefTimes = latencyMilliseconds * 10000; + // first attempt uses the WaveFormat from the WaveStream + + // If using EventSync, setup is specific with shareMode + if (isUsingEventSync) + { + // Init Shared or Exclusive + if (shareMode == AudioClientShareMode.Shared) + { + // With EventCallBack and Shared, both latencies must be set to 0 + audioClient.Initialize(shareMode, AudioClientStreamFlags.EventCallback, 0, 0, + outputFormat, Guid.Empty); + + // Get back the effective latency from AudioClient + latencyMilliseconds = (int)(audioClient.StreamLatency / 10000); + } + else + { + // With EventCallBack and Exclusive, both latencies must equals + audioClient.Initialize(shareMode, AudioClientStreamFlags.EventCallback, latencyRefTimes, latencyRefTimes, + outputFormat, Guid.Empty); + } + + // Create the Wait Event Handle + frameEventWaitHandle = new EventWaitHandle(false, EventResetMode.AutoReset); + audioClient.SetEventHandle(frameEventWaitHandle); + } + else + { + // Normal setup for both sharedMode + audioClient.Initialize(shareMode, AudioClientStreamFlags.None, latencyRefTimes, 0, + outputFormat, Guid.Empty); + } + + // Get the RenderClient + renderClient = audioClient.AudioRenderClient; + inited = true; + } + + /// + /// Playback State + /// + public PlaybackState PlaybackState + { + get { return playbackState; } + } + + /// + /// Volume + /// + public float Volume + { + get + { + return 1.0f; + } + set + { + if (value != 1.0f) + { + throw new NotImplementedException(); + } + } + } + + public void Close() + { + if (audioClient != null) + Stop(); + } + + public void Delete() + { + Close(); + } + + + private AudioBuffer active = null; + private int active_offset = 0; + + public void Write(AudioBuffer src) + { + if (src.Length == 0) + { + Stop(); + return; + } + int src_offs = 0; + do + { + if (active == null) + active = GetBuffer(true); + if (active == null) + throw new Exception("done"); + int toCopy = Math.Min(active.Size - active_offset, src.Length - src_offs); + Array.Copy(src.Bytes, src_offs * pcm.BlockAlign, active.Bytes, active_offset * pcm.BlockAlign, toCopy * pcm.BlockAlign); + src_offs += toCopy; + active_offset += toCopy; + if (active_offset == active.Size) + { + ReleaseBuffer(active, true, active.Size); + active = null; + active_offset = 0; + } + } + while (src_offs < src.Length); + } + + #endregion + + #region IAudioDest Members + + public long Position + { + get + { + return _sampleOffset; + } + } + + public long BlockSize + { + set { } + } + + public long FinalSampleCount + { + set { ; } + } + + public int CompressionLevel + { + get { return 0; } + set { } + } + + public string Options + { + set + { + if (value == null || value == "") return; + throw new Exception("Unsupported options " + value); + } + } + + public AudioPCMConfig PCM + { + get { return pcm; } + } + + public string Path { get { return null; } } + + #endregion + + #region IDisposable Members + + /// + /// Dispose + /// + public void Dispose() + { + if (audioClient != null) + { + Stop(); + + audioClient.Dispose(); + audioClient = null; + renderClient = null; + } + + } + + #endregion + } +} diff --git a/CUETools.Codecs.CoreAudio/WaveFormats/AdpcmWaveFormat.cs b/CUETools.Codecs.CoreAudio/WaveFormats/AdpcmWaveFormat.cs new file mode 100644 index 0000000..020ecce --- /dev/null +++ b/CUETools.Codecs.CoreAudio/WaveFormats/AdpcmWaveFormat.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Runtime.InteropServices; + +namespace NAudio.Wave +{ + /// + /// Microsoft ADPCM + /// See http://icculus.org/SDL_sound/downloads/external_documentation/wavecomp.htm + /// + [StructLayout(LayoutKind.Sequential, Pack=2)] + public class AdpcmWaveFormat : WaveFormat + { + short samplesPerBlock; + short numCoeff; + // 7 pairs of coefficients + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 14)] + short[] coefficients; + + /// + /// Empty constructor needed for marshalling from a pointer + /// + AdpcmWaveFormat() : this(8000,1) + { + } + + /// + /// Samples per block + /// + public int SamplesPerBlock + { + get { return samplesPerBlock; } + } + + /// + /// Number of coefficients + /// + public int NumCoefficients + { + get { return numCoeff; } + } + + /// + /// Coefficients + /// + public short[] Coefficients + { + get { return coefficients; } + } + + /// + /// Microsoft ADPCM + /// + /// Sample Rate + /// Channels + public AdpcmWaveFormat(int sampleRate, int channels) : + base(sampleRate,0,channels) + { + this.waveFormatTag = WaveFormatEncoding.Adpcm; + + // TODO: validate sampleRate, bitsPerSample + this.extraSize = 32; + switch(this.sampleRate) + { + case 8000: + case 11025: + blockAlign = 256; + break; + case 22050: + blockAlign = 512; + break; + case 44100: + default: + blockAlign = 1024; + break; + } + + this.bitsPerSample = 4; + this.samplesPerBlock = (short) ((((blockAlign - (7 * channels)) * 8) / (bitsPerSample * channels)) + 2); + this.averageBytesPerSecond = + ((this.SampleRate * blockAlign) / samplesPerBlock); + + // samplesPerBlock = blockAlign - (7 * channels)) * (2 / channels) + 2; + + + numCoeff = 7; + coefficients = new short[14] { + 256,0,512,-256,0,0,192,64,240,0,460,-208,392,-232 + }; + } + + /// + /// Serializes this wave format + /// + /// Binary writer + public override void Serialize(System.IO.BinaryWriter writer) + { + base.Serialize(writer); + writer.Write(samplesPerBlock); + writer.Write(numCoeff); + foreach (short coefficient in coefficients) + { + writer.Write(coefficient); + } + } + + /// + /// String Description of this WaveFormat + /// + public override string ToString() + { + return String.Format("Microsoft ADPCM {0} Hz {1} channels {2} bits per sample {3} samples per block", + this.SampleRate, this.channels, this.bitsPerSample, this.samplesPerBlock); + } + } +} diff --git a/CUETools.Codecs.CoreAudio/WaveFormats/AudioMediaSubtypes.cs b/CUETools.Codecs.CoreAudio/WaveFormats/AudioMediaSubtypes.cs new file mode 100644 index 0000000..cfeaca5 --- /dev/null +++ b/CUETools.Codecs.CoreAudio/WaveFormats/AudioMediaSubtypes.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace NAudio.Dmo +{ + class AudioMediaSubtypes + { + public static readonly Guid MEDIASUBTYPE_PCM = new Guid("00000001-0000-0010-8000-00AA00389B71"); // PCM audio. + public static readonly Guid MEDIASUBTYPE_PCMAudioObsolete = new Guid("e436eb8a-524f-11ce-9f53-0020af0ba770"); // Obsolete. Do not use. + public static readonly Guid MEDIASUBTYPE_MPEG1Packet = new Guid("e436eb80-524f-11ce-9f53-0020af0ba770"); // MPEG1 Audio packet. + public static readonly Guid MEDIASUBTYPE_MPEG1Payload = new Guid("e436eb81-524f-11ce-9f53-0020af0ba770"); // MPEG1 Audio Payload. + public static readonly Guid MEDIASUBTYPE_MPEG2_AUDIO = new Guid("e06d802b-db46-11cf-b4d1-00805f6cbbea"); // MPEG-2 audio data + public static readonly Guid MEDIASUBTYPE_DVD_LPCM_AUDIO = new Guid("e06d8032-db46-11cf-b4d1-00805f6cbbea"); // DVD audio data + public static readonly Guid MEDIASUBTYPE_DRM_Audio = new Guid("00000009-0000-0010-8000-00aa00389b71"); // Corresponds to WAVE_FORMAT_DRM. + public static readonly Guid MEDIASUBTYPE_IEEE_FLOAT = new Guid("00000003-0000-0010-8000-00aa00389b71"); // Corresponds to WAVE_FORMAT_IEEE_FLOAT + public static readonly Guid MEDIASUBTYPE_DOLBY_AC3 = new Guid("e06d802c-db46-11cf-b4d1-00805f6cbbea"); // Dolby data + public static readonly Guid MEDIASUBTYPE_DOLBY_AC3_SPDIF = new Guid("00000092-0000-0010-8000-00aa00389b71"); // Dolby AC3 over SPDIF. + public static readonly Guid MEDIASUBTYPE_RAW_SPORT = new Guid("00000240-0000-0010-8000-00aa00389b71"); // Equivalent to MEDIASUBTYPE_DOLBY_AC3_SPDIF. + public static readonly Guid MEDIASUBTYPE_SPDIF_TAG_241h = new Guid("00000241-0000-0010-8000-00aa00389b71"); // Equivalent to MEDIASUBTYPE_DOLBY_AC3_SPDIF. + + // others? + public static readonly Guid MEDIASUBTYPE_WAVE = new Guid("e436eb8b-524f-11ce-9f53-0020af0ba770"); + public static readonly Guid MEDIASUBTYPE_AU = new Guid("e436eb8c-524f-11ce-9f53-0020af0ba770"); + public static readonly Guid MEDIASUBTYPE_AIFF = new Guid("e436eb8d-524f-11ce-9f53-0020af0ba770"); + + public static readonly Guid[] AudioSubTypes = new Guid[] + { + MEDIASUBTYPE_PCM, + MEDIASUBTYPE_PCMAudioObsolete, + MEDIASUBTYPE_MPEG1Packet, + MEDIASUBTYPE_MPEG1Payload, + MEDIASUBTYPE_MPEG2_AUDIO, + MEDIASUBTYPE_DVD_LPCM_AUDIO, + MEDIASUBTYPE_DRM_Audio, + MEDIASUBTYPE_IEEE_FLOAT, + MEDIASUBTYPE_DOLBY_AC3, + MEDIASUBTYPE_DOLBY_AC3_SPDIF, + MEDIASUBTYPE_RAW_SPORT, + MEDIASUBTYPE_SPDIF_TAG_241h, + }; + + public static readonly string[] AudioSubTypeNames = new string[] + { + "PCM", + "PCM Obsolete", + "MPEG1Packet", + "MPEG1Payload", + "MPEG2_AUDIO", + "DVD_LPCM_AUDIO", + "DRM_Audio", + "IEEE_FLOAT", + "DOLBY_AC3", + "DOLBY_AC3_SPDIF", + "RAW_SPORT", + "SPDIF_TAG_241h", + }; + public static string GetAudioSubtypeName(Guid subType) + { + for (int index = 0; index < AudioSubTypes.Length; index++) + { + if (subType == AudioSubTypes[index]) + { + return AudioSubTypeNames[index]; + } + } + return subType.ToString(); + } + } +} diff --git a/CUETools.Codecs.CoreAudio/WaveFormats/WaveFormat.cs b/CUETools.Codecs.CoreAudio/WaveFormats/WaveFormat.cs new file mode 100644 index 0000000..30f6301 --- /dev/null +++ b/CUETools.Codecs.CoreAudio/WaveFormats/WaveFormat.cs @@ -0,0 +1,373 @@ +using System; +using System.IO; +using System.Runtime.InteropServices; + +namespace NAudio.Wave +{ + /// + /// Represents a Wave file format + /// + [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=2)] + public class WaveFormat + { + /// format type + protected WaveFormatEncoding waveFormatTag; + /// number of channels + protected short channels; + /// sample rate + protected int sampleRate; + /// for buffer estimation + protected int averageBytesPerSecond; + /// block size of data + protected short blockAlign; + /// number of bits per sample of mono data + protected short bitsPerSample; + /// number of following bytes + protected short extraSize; + + /// + /// Creates a new PCM 44.1Khz stereo 16 bit format + /// + public WaveFormat() : this(44100,16,2) + { + + } + + /// + /// Creates a new 16 bit wave format with the specified sample + /// rate and channel count + /// + /// Sample Rate + /// Number of channels + public WaveFormat(int sampleRate, int channels) + : this(sampleRate, 16, channels) + { + } + + /// + /// Gets the size of a wave buffer equivalent to the latency in milliseconds. + /// + /// The milliseconds. + /// + public int ConvertLatencyToByteSize(int milliseconds) + { + int bytes = (int) ((AverageBytesPerSecond/1000.0)*milliseconds); + if ((bytes%BlockAlign) != 0) + { + // Return the upper BlockAligned + bytes = bytes + BlockAlign - (bytes % BlockAlign); + } + return bytes; + } + + /// + /// Creates a WaveFormat with custom members + /// + /// The encoding + /// Sample Rate + /// Number of channels + /// Average Bytes Per Second + /// Block Align + /// Bits Per Sample + /// + public static WaveFormat CreateCustomFormat(WaveFormatEncoding tag, int sampleRate, int channels, int averageBytesPerSecond, int blockAlign, int bitsPerSample) + { + WaveFormat waveFormat = new WaveFormat(); + waveFormat.waveFormatTag = tag; + waveFormat.channels = (short)channels; + waveFormat.sampleRate = sampleRate; + waveFormat.averageBytesPerSecond = averageBytesPerSecond; + waveFormat.blockAlign = (short)blockAlign; + waveFormat.bitsPerSample = (short)bitsPerSample; + waveFormat.extraSize = 0; + return waveFormat; + } + + /// + /// Creates an A-law wave format + /// + /// Sample Rate + /// Number of Channels + /// Wave Format + public static WaveFormat CreateALawFormat(int sampleRate, int channels) + { + return CreateCustomFormat(WaveFormatEncoding.ALaw, sampleRate, channels, sampleRate * channels, 1, 8); + } + + /// + /// Creates a Mu-law wave format + /// + /// Sample Rate + /// Number of Channels + /// Wave Format + public static WaveFormat CreateMuLawFormat(int sampleRate, int channels) + { + return CreateCustomFormat(WaveFormatEncoding.MuLaw, sampleRate, channels, sampleRate * channels, 1, 8); + } + + /// + /// Creates a new PCM format with the specified sample rate, bit depth and channels + /// + public WaveFormat(int rate, int bits, int channels) + { + if (channels < 1) + { + throw new ArgumentOutOfRangeException("Channels must be 1 or greater", "channels"); + } + // minimum 16 bytes, sometimes 18 for PCM + this.waveFormatTag = WaveFormatEncoding.Pcm; + this.channels = (short)channels; + this.sampleRate = rate; + this.bitsPerSample = (short)bits; + this.extraSize = 0; + + this.blockAlign = (short)(channels * (bits / 8)); + this.averageBytesPerSecond = this.sampleRate * this.blockAlign; + } + + /// + /// Creates a new 32 bit IEEE floating point wave format + /// + /// sample rate + /// number of channels + public static WaveFormat CreateIeeeFloatWaveFormat(int sampleRate, int channels) + { + WaveFormat wf = new WaveFormat(); + wf.waveFormatTag = WaveFormatEncoding.IeeeFloat; + wf.channels = (short)channels; + wf.bitsPerSample = 32; + wf.sampleRate = sampleRate; + wf.blockAlign = (short) (4*channels); + wf.averageBytesPerSecond = sampleRate * wf.blockAlign; + wf.extraSize = 0; + return wf; + } + + /// + /// Helper function to retrieve a WaveFormat structure from a pointer + /// + /// WaveFormat structure + /// + public static WaveFormat MarshalFromPtr(IntPtr pointer) + { + WaveFormat waveFormat = (WaveFormat)Marshal.PtrToStructure(pointer, typeof(WaveFormat)); + switch (waveFormat.Encoding) + { + case WaveFormatEncoding.Pcm: + // can't rely on extra size even being there for PCM so blank it to avoid reading + // corrupt data + waveFormat.extraSize = 0; + break; + case WaveFormatEncoding.Extensible: + waveFormat = (WaveFormatExtensible)Marshal.PtrToStructure(pointer, typeof(WaveFormatExtensible)); + break; + case WaveFormatEncoding.Adpcm: + waveFormat = (AdpcmWaveFormat)Marshal.PtrToStructure(pointer, typeof(AdpcmWaveFormat)); + break; + default: + if (waveFormat.ExtraSize > 0) + { + waveFormat = (WaveFormatExtraData)Marshal.PtrToStructure(pointer, typeof(WaveFormatExtraData)); + } + break; + } + return waveFormat; + } + + /// + /// Helper function to marshal WaveFormat to an IntPtr + /// + /// WaveFormat + /// IntPtr to WaveFormat structure (needs to be freed by callee) + public static IntPtr MarshalToPtr(WaveFormat format) + { + int formatSize = Marshal.SizeOf(format); + IntPtr formatPointer = Marshal.AllocHGlobal(formatSize); + Marshal.StructureToPtr(format, formatPointer, false); + return formatPointer; + } + + /// + /// Reads a new WaveFormat object from a stream + /// + /// A binary reader that wraps the stream + public WaveFormat(BinaryReader br) + { + int formatChunkLength = br.ReadInt32(); + if(formatChunkLength < 16) + throw new ApplicationException("Invalid WaveFormat Structure"); + this.waveFormatTag = (WaveFormatEncoding) br.ReadUInt16(); + this.channels = br.ReadInt16(); + this.sampleRate = br.ReadInt32(); + this.averageBytesPerSecond = br.ReadInt32(); + this.blockAlign = br.ReadInt16(); + this.bitsPerSample = br.ReadInt16(); + if (formatChunkLength > 16) + { + + this.extraSize = br.ReadInt16(); + if (this.extraSize > formatChunkLength - 18) + { + Console.WriteLine("Format chunk mismatch"); + //RRL GSM exhibits this bug. Don't throw an exception + //throw new ApplicationException("Format chunk length mismatch"); + + this.extraSize = (short) (formatChunkLength - 18); + } + + // read any extra data + // br.ReadBytes(extraSize); + + } + } + + /// + /// Reports this WaveFormat as a string + /// + /// String describing the wave format + public override string ToString() + { + switch (this.waveFormatTag) + { + case WaveFormatEncoding.Pcm: + case WaveFormatEncoding.Extensible: + // extensible just has some extra bits after the PCM header + return String.Format("{0} bit PCM: {1}kHz {2} channels", + bitsPerSample, sampleRate / 1000, channels); + default: + return this.waveFormatTag.ToString(); + } + } + + /// + /// Compares with another WaveFormat object + /// + /// Object to compare to + /// True if the objects are the same + public override bool Equals(object obj) + { + WaveFormat other = obj as WaveFormat; + if(other != null) + { + return waveFormatTag == other.waveFormatTag && + channels == other.channels && + sampleRate == other.sampleRate && + averageBytesPerSecond == other.averageBytesPerSecond && + blockAlign == other.blockAlign && + bitsPerSample == other.bitsPerSample; + } + return false; + } + + /// + /// Provides a Hashcode for this WaveFormat + /// + /// A hashcode + public override int GetHashCode() + { + return (int) waveFormatTag ^ + (int) channels ^ + sampleRate ^ + averageBytesPerSecond ^ + (int) blockAlign ^ + (int) bitsPerSample; + } + + /// + /// Returns the encoding type used + /// + public WaveFormatEncoding Encoding + { + get + { + return waveFormatTag; + } + } + + /// + /// Writes this WaveFormat object to a stream + /// + /// the output stream + public virtual void Serialize(BinaryWriter writer) + { + writer.Write((int)(18 + extraSize)); // wave format length + writer.Write((short)Encoding); + writer.Write((short)Channels); + writer.Write((int)SampleRate); + writer.Write((int)AverageBytesPerSecond); + writer.Write((short)BlockAlign); + writer.Write((short)BitsPerSample); + writer.Write((short)extraSize); + } + + /// + /// Returns the number of channels (1=mono,2=stereo etc) + /// + public int Channels + { + get + { + return channels; + } + } + + /// + /// Returns the sample rate (samples per second) + /// + public int SampleRate + { + get + { + return sampleRate; + } + } + + /// + /// Returns the average number of bytes used per second + /// + public int AverageBytesPerSecond + { + get + { + return averageBytesPerSecond; + } + } + + /// + /// Returns the block alignment + /// + public virtual int BlockAlign + { + get + { + return blockAlign; + } + } + + /// + /// Returns the number of bits per sample (usually 16 or 32, sometimes 24 or 8) + /// Can be 0 for some codecs + /// + public int BitsPerSample + { + get + { + return bitsPerSample; + } + } + + /// + /// Returns the number of extra bytes used by this waveformat. Often 0, + /// except for compressed formats which store extra data after the WAVEFORMATEX header + /// + public int ExtraSize + { + get + { + return extraSize; + } + } + + + } +} diff --git a/CUETools.Codecs.CoreAudio/WaveFormats/WaveFormatEncoding.cs b/CUETools.Codecs.CoreAudio/WaveFormats/WaveFormatEncoding.cs new file mode 100644 index 0000000..9c82e2a --- /dev/null +++ b/CUETools.Codecs.CoreAudio/WaveFormats/WaveFormatEncoding.cs @@ -0,0 +1,314 @@ +using System; + +namespace NAudio.Wave +{ + /// + /// Summary description for WaveFormatEncoding. + /// + public enum WaveFormatEncoding : ushort + { + /// WAVE_FORMAT_UNKNOWN, Microsoft Corporation + Unknown = 0x0000, + /// WAVE_FORMAT_PCM Microsoft Corporation + Pcm = 0x0001, + /// WAVE_FORMAT_ADPCM Microsoft Corporation + Adpcm = 0x0002, + /// WAVE_FORMAT_IEEE_FLOAT Microsoft Corporation + IeeeFloat = 0x0003, + /// WAVE_FORMAT_VSELP Compaq Computer Corp. + Vselp = 0x0004, + /// WAVE_FORMAT_IBM_CVSD IBM Corporation + IbmCvsd = 0x0005, + /// WAVE_FORMAT_ALAW Microsoft Corporation + ALaw = 0x0006, + /// WAVE_FORMAT_MULAW Microsoft Corporation + MuLaw = 0x0007, + /// WAVE_FORMAT_DTS Microsoft Corporation + Dts = 0x0008, + /// WAVE_FORMAT_DRM Microsoft Corporation + Drm = 0x0009, + /// WAVE_FORMAT_OKI_ADPCM OKI + OkiAdpcm = 0x0010, + /// WAVE_FORMAT_DVI_ADPCM Intel Corporation + DviAdpcm = 0x0011, + /// WAVE_FORMAT_IMA_ADPCM Intel Corporation + ImaAdpcm = DviAdpcm, + /// WAVE_FORMAT_MEDIASPACE_ADPCM Videologic + MediaspaceAdpcm = 0x0012, + /// WAVE_FORMAT_SIERRA_ADPCM Sierra Semiconductor Corp + SierraAdpcm = 0x0013, + /// WAVE_FORMAT_G723_ADPCM Antex Electronics Corporation + G723Adpcm = 0x0014, + /// WAVE_FORMAT_DIGISTD DSP Solutions, Inc. + DigiStd = 0x0015, + /// WAVE_FORMAT_DIGIFIX DSP Solutions, Inc. + DigiFix = 0x0016, + /// WAVE_FORMAT_DIALOGIC_OKI_ADPCM Dialogic Corporation + DialogicOkiAdpcm = 0x0017, + /// WAVE_FORMAT_MEDIAVISION_ADPCM Media Vision, Inc. + MediaVisionAdpcm = 0x0018, + /// WAVE_FORMAT_CU_CODEC Hewlett-Packard Company + CUCodec = 0x0019, + /// WAVE_FORMAT_YAMAHA_ADPCM Yamaha Corporation of America + YamahaAdpcm = 0x0020, + /// WAVE_FORMAT_SONARC Speech Compression + SonarC = 0x0021, + /// WAVE_FORMAT_DSPGROUP_TRUESPEECH DSP Group, Inc + DspGroupTruespeech = 0x0022, + /// WAVE_FORMAT_ECHOSC1 Echo Speech Corporation + EchoSpeechCorporation1 = 0x0023, + /// WAVE_FORMAT_AUDIOFILE_AF36, Virtual Music, Inc. + AudioFileAf36 = 0x0024, + /// WAVE_FORMAT_APTX Audio Processing Technology + Aptx = 0x0025, + /// WAVE_FORMAT_AUDIOFILE_AF10, Virtual Music, Inc. + AudioFileAf10 = 0x0026, + /// WAVE_FORMAT_PROSODY_1612, Aculab plc + Prosody1612 = 0x0027, + /// WAVE_FORMAT_LRC, Merging Technologies S.A. + Lrc = 0x0028, + /// WAVE_FORMAT_DOLBY_AC2, Dolby Laboratories + DolbyAc2 = 0x0030, + /// WAVE_FORMAT_GSM610, Microsoft Corporation + Gsm610 = 0x0031, + /// WAVE_FORMAT_MSNAUDIO, Microsoft Corporation + MsnAudio = 0x0032, + /// WAVE_FORMAT_ANTEX_ADPCME, Antex Electronics Corporation + AntexAdpcme = 0x0033, + /// WAVE_FORMAT_CONTROL_RES_VQLPC, Control Resources Limited + ControlResVqlpc = 0x0034, + /// WAVE_FORMAT_DIGIREAL, DSP Solutions, Inc. + DigiReal = 0x0035, + /// WAVE_FORMAT_DIGIADPCM, DSP Solutions, Inc. + DigiAdpcm = 0x0036, + /// WAVE_FORMAT_CONTROL_RES_CR10, Control Resources Limited + ControlResCr10 = 0x0037, + /// + WAVE_FORMAT_NMS_VBXADPCM = 0x0038, // Natural MicroSystems + /// + WAVE_FORMAT_CS_IMAADPCM = 0x0039, // Crystal Semiconductor IMA ADPCM + /// + WAVE_FORMAT_ECHOSC3 = 0x003A, // Echo Speech Corporation + /// + WAVE_FORMAT_ROCKWELL_ADPCM = 0x003B, // Rockwell International + /// + WAVE_FORMAT_ROCKWELL_DIGITALK = 0x003C, // Rockwell International + /// + WAVE_FORMAT_XEBEC = 0x003D, // Xebec Multimedia Solutions Limited + /// + WAVE_FORMAT_G721_ADPCM = 0x0040, // Antex Electronics Corporation + /// + WAVE_FORMAT_G728_CELP = 0x0041, // Antex Electronics Corporation + /// + WAVE_FORMAT_MSG723 = 0x0042, // Microsoft Corporation + /// + Mpeg = 0x0050, // WAVE_FORMAT_MPEG, Microsoft Corporation + /// + WAVE_FORMAT_RT24 = 0x0052, // InSoft, Inc. + /// + WAVE_FORMAT_PAC = 0x0053, // InSoft, Inc. + /// + MpegLayer3 = 0x0055, // WAVE_FORMAT_MPEGLAYER3, ISO/MPEG Layer3 Format Tag + /// + WAVE_FORMAT_LUCENT_G723 = 0x0059, // Lucent Technologies + /// + WAVE_FORMAT_CIRRUS = 0x0060, // Cirrus Logic + /// + WAVE_FORMAT_ESPCM = 0x0061, // ESS Technology + /// + WAVE_FORMAT_VOXWARE = 0x0062, // Voxware Inc + /// + WAVE_FORMAT_CANOPUS_ATRAC = 0x0063, // Canopus, co., Ltd. + /// + WAVE_FORMAT_G726_ADPCM = 0x0064, // APICOM + /// + WAVE_FORMAT_G722_ADPCM = 0x0065, // APICOM + /// + WAVE_FORMAT_DSAT_DISPLAY = 0x0067, // Microsoft Corporation + /// + WAVE_FORMAT_VOXWARE_BYTE_ALIGNED = 0x0069, // Voxware Inc + /// + WAVE_FORMAT_VOXWARE_AC8 = 0x0070, // Voxware Inc + /// + WAVE_FORMAT_VOXWARE_AC10 = 0x0071, // Voxware Inc + /// + WAVE_FORMAT_VOXWARE_AC16 = 0x0072, // Voxware Inc + /// + WAVE_FORMAT_VOXWARE_AC20 = 0x0073, // Voxware Inc + /// + WAVE_FORMAT_VOXWARE_RT24 = 0x0074, // Voxware Inc + /// + WAVE_FORMAT_VOXWARE_RT29 = 0x0075, // Voxware Inc + /// + WAVE_FORMAT_VOXWARE_RT29HW = 0x0076, // Voxware Inc + /// + WAVE_FORMAT_VOXWARE_VR12 = 0x0077, // Voxware Inc + /// + WAVE_FORMAT_VOXWARE_VR18 = 0x0078, // Voxware Inc + /// + WAVE_FORMAT_VOXWARE_TQ40 = 0x0079, // Voxware Inc + /// + WAVE_FORMAT_SOFTSOUND = 0x0080, // Softsound, Ltd. + /// + WAVE_FORMAT_VOXWARE_TQ60 = 0x0081, // Voxware Inc + /// + WAVE_FORMAT_MSRT24 = 0x0082, // Microsoft Corporation + /// + WAVE_FORMAT_G729A = 0x0083, // AT&T Labs, Inc. + /// + WAVE_FORMAT_MVI_MVI2 = 0x0084, // Motion Pixels + /// + WAVE_FORMAT_DF_G726 = 0x0085, // DataFusion Systems (Pty) (Ltd) + /// + WAVE_FORMAT_DF_GSM610 = 0x0086, // DataFusion Systems (Pty) (Ltd) + /// + WAVE_FORMAT_ISIAUDIO = 0x0088, // Iterated Systems, Inc. + /// + WAVE_FORMAT_ONLIVE = 0x0089, // OnLive! Technologies, Inc. + /// + WAVE_FORMAT_SBC24 = 0x0091, // Siemens Business Communications Sys + /// + WAVE_FORMAT_DOLBY_AC3_SPDIF = 0x0092, // Sonic Foundry + /// + WAVE_FORMAT_MEDIASONIC_G723 = 0x0093, // MediaSonic + /// + WAVE_FORMAT_PROSODY_8KBPS = 0x0094, // Aculab plc + /// + WAVE_FORMAT_ZYXEL_ADPCM = 0x0097, // ZyXEL Communications, Inc. + /// + WAVE_FORMAT_PHILIPS_LPCBB = 0x0098, // Philips Speech Processing + /// + WAVE_FORMAT_PACKED = 0x0099, // Studer Professional Audio AG + /// + WAVE_FORMAT_MALDEN_PHONYTALK = 0x00A0, // Malden Electronics Ltd. + /// WAVE_FORMAT_GSM + Gsm = 0x00A1, + /// WAVE_FORMAT_G729 + G729 = 0x00A2, + /// WAVE_FORMAT_G723 + G723 = 0x00A3, + /// WAVE_FORMAT_ACELP + Acelp = 0x00A4, + /// + WAVE_FORMAT_RHETOREX_ADPCM = 0x0100, // Rhetorex Inc. + /// + WAVE_FORMAT_IRAT = 0x0101, // BeCubed Software Inc. + /// + WAVE_FORMAT_VIVO_G723 = 0x0111, // Vivo Software + /// + WAVE_FORMAT_VIVO_SIREN = 0x0112, // Vivo Software + /// + WAVE_FORMAT_DIGITAL_G723 = 0x0123, // Digital Equipment Corporation + /// + WAVE_FORMAT_SANYO_LD_ADPCM = 0x0125, // Sanyo Electric Co., Ltd. + /// + WAVE_FORMAT_SIPROLAB_ACEPLNET = 0x0130, // Sipro Lab Telecom Inc. + /// + WAVE_FORMAT_SIPROLAB_ACELP4800 = 0x0131, // Sipro Lab Telecom Inc. + /// + WAVE_FORMAT_SIPROLAB_ACELP8V3 = 0x0132, // Sipro Lab Telecom Inc. + /// + WAVE_FORMAT_SIPROLAB_G729 = 0x0133, // Sipro Lab Telecom Inc. + /// + WAVE_FORMAT_SIPROLAB_G729A = 0x0134, // Sipro Lab Telecom Inc. + /// + WAVE_FORMAT_SIPROLAB_KELVIN = 0x0135, // Sipro Lab Telecom Inc. + /// + WAVE_FORMAT_G726ADPCM = 0x0140, // Dictaphone Corporation + /// + WAVE_FORMAT_QUALCOMM_PUREVOICE = 0x0150, // Qualcomm, Inc. + /// + WAVE_FORMAT_QUALCOMM_HALFRATE = 0x0151, // Qualcomm, Inc. + /// + WAVE_FORMAT_TUBGSM = 0x0155, // Ring Zero Systems, Inc. + /// + WAVE_FORMAT_MSAUDIO1 = 0x0160, // Microsoft Corporation + /// + /// WAVE_FORMAT_WMAUDIO2, Microsoft Corporation + /// + WAVE_FORMAT_WMAUDIO2 = 0x0161, + /// + /// WAVE_FORMAT_WMAUDIO3, Microsoft Corporation + /// + WAVE_FORMAT_WMAUDIO3 = 0x0162, + /// + WAVE_FORMAT_UNISYS_NAP_ADPCM = 0x0170, // Unisys Corp. + /// + WAVE_FORMAT_UNISYS_NAP_ULAW = 0x0171, // Unisys Corp. + /// + WAVE_FORMAT_UNISYS_NAP_ALAW = 0x0172, // Unisys Corp. + /// + WAVE_FORMAT_UNISYS_NAP_16K = 0x0173, // Unisys Corp. + /// + WAVE_FORMAT_CREATIVE_ADPCM = 0x0200, // Creative Labs, Inc + /// + WAVE_FORMAT_CREATIVE_FASTSPEECH8 = 0x0202, // Creative Labs, Inc + /// + WAVE_FORMAT_CREATIVE_FASTSPEECH10 = 0x0203, // Creative Labs, Inc + /// + WAVE_FORMAT_UHER_ADPCM = 0x0210, // UHER informatic GmbH + /// + WAVE_FORMAT_QUARTERDECK = 0x0220, // Quarterdeck Corporation + /// + WAVE_FORMAT_ILINK_VC = 0x0230, // I-link Worldwide + /// + WAVE_FORMAT_RAW_SPORT = 0x0240, // Aureal Semiconductor + /// + WAVE_FORMAT_ESST_AC3 = 0x0241, // ESS Technology, Inc. + /// + WAVE_FORMAT_IPI_HSX = 0x0250, // Interactive Products, Inc. + /// + WAVE_FORMAT_IPI_RPELP = 0x0251, // Interactive Products, Inc. + /// + WAVE_FORMAT_CS2 = 0x0260, // Consistent Software + /// + WAVE_FORMAT_SONY_SCX = 0x0270, // Sony Corp. + /// + WAVE_FORMAT_FM_TOWNS_SND = 0x0300, // Fujitsu Corp. + /// + WAVE_FORMAT_BTV_DIGITAL = 0x0400, // Brooktree Corporation + /// + WAVE_FORMAT_QDESIGN_MUSIC = 0x0450, // QDesign Corporation + /// + WAVE_FORMAT_VME_VMPCM = 0x0680, // AT&T Labs, Inc. + /// + WAVE_FORMAT_TPC = 0x0681, // AT&T Labs, Inc. + /// + WAVE_FORMAT_OLIGSM = 0x1000, // Ing C. Olivetti & C., S.p.A. + /// + WAVE_FORMAT_OLIADPCM = 0x1001, // Ing C. Olivetti & C., S.p.A. + /// + WAVE_FORMAT_OLICELP = 0x1002, // Ing C. Olivetti & C., S.p.A. + /// + WAVE_FORMAT_OLISBC = 0x1003, // Ing C. Olivetti & C., S.p.A. + /// + WAVE_FORMAT_OLIOPR = 0x1004, // Ing C. Olivetti & C., S.p.A. + /// + WAVE_FORMAT_LH_CODEC = 0x1100, // Lernout & Hauspie + /// + WAVE_FORMAT_NORRIS = 0x1400, // Norris Communications, Inc. + /// + WAVE_FORMAT_SOUNDSPACE_MUSICOMPRESS = 0x1500, // AT&T Labs, Inc. + /// + WAVE_FORMAT_DVM = 0x2000, // FAST Multimedia AG + /// WAVE_FORMAT_EXTENSIBLE + Extensible = 0xFFFE, // Microsoft + /// + WAVE_FORMAT_DEVELOPMENT = 0xFFFF, + + // others - not from MS headers + /// WAVE_FORMAT_VORBIS1 "Og" Original stream compatible + Vorbis1 = 0x674f, + /// WAVE_FORMAT_VORBIS2 "Pg" Have independent header + Vorbis2 = 0x6750, + /// WAVE_FORMAT_VORBIS3 "Qg" Have no codebook header + Vorbis3 = 0x6751, + /// WAVE_FORMAT_VORBIS1P "og" Original stream compatible + Vorbis1P = 0x676f, + /// WAVE_FORMAT_VORBIS2P "pg" Have independent headere + Vorbis2P = 0x6770, + /// WAVE_FORMAT_VORBIS3P "qg" Have no codebook header + Vorbis3P = 0x6771, + + } +} diff --git a/CUETools.Codecs.CoreAudio/WaveFormats/WaveFormatExtensible.cs b/CUETools.Codecs.CoreAudio/WaveFormats/WaveFormatExtensible.cs new file mode 100644 index 0000000..f41ec5e --- /dev/null +++ b/CUETools.Codecs.CoreAudio/WaveFormats/WaveFormatExtensible.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Runtime.InteropServices; +using NAudio.Dmo; + +namespace NAudio.Wave +{ + /// + /// WaveFormatExtensible + /// http://www.microsoft.com/whdc/device/audio/multichaud.mspx + /// + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 2)] + public class WaveFormatExtensible : WaveFormat + { + short wValidBitsPerSample; // bits of precision, or is wSamplesPerBlock if wBitsPerSample==0 + int dwChannelMask; // which channels are present in stream + Guid subFormat; + + /// + /// Parameterless constructor for marshalling + /// + WaveFormatExtensible() + { + } + + /// + /// Creates a new WaveFormatExtensible for PCM or IEEE + /// + public WaveFormatExtensible(int rate, int bits, int channels) + : base(rate, bits, channels) + { + waveFormatTag = WaveFormatEncoding.Extensible; + extraSize = 22; + wValidBitsPerSample = (short) bits; + for (int n = 0; n < channels; n++) + { + dwChannelMask |= (1 << n); + } + if (bits == 32) + { + // KSDATAFORMAT_SUBTYPE_IEEE_FLOAT + subFormat = AudioMediaSubtypes.MEDIASUBTYPE_IEEE_FLOAT; // new Guid("00000003-0000-0010-8000-00aa00389b71"); + } + else + { + // KSDATAFORMAT_SUBTYPE_PCM + subFormat = AudioMediaSubtypes.MEDIASUBTYPE_PCM; // new Guid("00000001-0000-0010-8000-00aa00389b71"); + } + + } + + /// + /// Serialize + /// + /// + public override void Serialize(System.IO.BinaryWriter writer) + { + base.Serialize(writer); + writer.Write(wValidBitsPerSample); + writer.Write(dwChannelMask); + byte[] guid = subFormat.ToByteArray(); + writer.Write(guid, 0, guid.Length); + } + + /// + /// String representation + /// + public override string ToString() + { + return String.Format("{0} wBitsPerSample:{1} dwChannelMask:{2} subFormat:{3} extraSize:{4}", + base.ToString(), + wValidBitsPerSample, + dwChannelMask, + subFormat, + extraSize); + } + } +} diff --git a/CUETools.Codecs.CoreAudio/WaveFormats/WaveFormatExtraData.cs b/CUETools.Codecs.CoreAudio/WaveFormats/WaveFormatExtraData.cs new file mode 100644 index 0000000..de016e9 --- /dev/null +++ b/CUETools.Codecs.CoreAudio/WaveFormats/WaveFormatExtraData.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Runtime.InteropServices; +using System.IO; + +namespace NAudio.Wave +{ + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 2)] + class WaveFormatExtraData : WaveFormat + { + // try with 100 bytes for now, increase if necessary + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)] + byte[] extraData = new byte[100]; + + /// + /// parameterless constructor for marshalling + /// + WaveFormatExtraData() + { + } + + public WaveFormatExtraData(BinaryReader reader) + : base(reader) + { + if (this.extraSize > 0) + { + reader.Read(extraData,0, extraSize); + } + } + + public override void Serialize(BinaryWriter writer) + { + base.Serialize(writer); + if (extraSize > 0) + { + writer.Write(extraData, 0, extraSize); + } + } + } +} diff --git a/CUETools.Codecs/Codecs.cs b/CUETools.Codecs/Codecs.cs index d849829..623610b 100644 --- a/CUETools.Codecs/Codecs.cs +++ b/CUETools.Codecs/Codecs.cs @@ -253,6 +253,7 @@ namespace CUETools.Codecs { pcm = _pcm; size = _size; + length = 0; } public AudioBuffer(AudioPCMConfig _pcm, int[,] _samples, int _length) @@ -581,7 +582,7 @@ namespace CUETools.Codecs unsafe public static void MemCpy(byte* res, byte* smp, int n) { - if ((((IntPtr)smp).ToInt64() & 4) == 0 && (((IntPtr)res).ToInt64() & 4) == 0 && n > 4) + if ((((IntPtr)smp).ToInt64() & 3) == 0 && (((IntPtr)res).ToInt64() & 3) == 0 && n > 4) { MemCpy((int*)res, (int*)smp, n >> 2); int n4 = (n >> 2) << 2; @@ -599,6 +600,50 @@ namespace CUETools.Codecs *(res++) = smp; } + unsafe public static void MemSet(long* res, long smp, int n) + { + for (int i = n; i > 0; i--) + *(res++) = smp; + } + + unsafe public static void MemSet(byte* res, byte smp, int n) + { + if (IntPtr.Size == 8 && (((IntPtr)res).ToInt64() & 7) == 0 && smp == 0 && n > 8) + { + MemSet((long*)res, 0, n >> 3); + int n8 = (n >> 3) << 3; + n -= n8; + res += n8; + } + if ((((IntPtr)res).ToInt64() & 3) == 0 && smp == 0 && n > 4) + { + MemSet((int*)res, 0, n >> 2); + int n4 = (n >> 2) << 2; + n -= n4; + res += n4; + } + for (int i = n; i > 0; i--) + *(res++) = smp; + } + + unsafe public static void MemSet(byte[] res, byte smp, int offs, int n) + { + fixed (byte* pres = &res[offs]) + MemSet(pres, smp, n); + } + + unsafe public static void MemSet(int[] res, int smp, int offs, int n) + { + fixed (int* pres = &res[offs]) + MemSet(pres, smp, n); + } + + unsafe public static void MemSet(long[] res, long smp, int offs, int n) + { + fixed (long* pres = &res[offs]) + MemSet(pres, smp, n); + } + public const uint UINT32_MAX = 0xffffffff; } diff --git a/CUETools.Processor/Processor.cs b/CUETools.Processor/Processor.cs index 1cd33eb..75727ff 100644 --- a/CUETools.Processor/Processor.cs +++ b/CUETools.Processor/Processor.cs @@ -1593,7 +1593,7 @@ string status = processor.Go(); private bool _stop, _pause; private List _attributes; private List _tracks; - private List _sources; + internal List _sources; private List _sourcePaths, _trackFilenames; private string _htoaFilename, _singleFilename; private bool _hasHTOAFilename = false, _hasTrackFilenames = false, _hasSingleFilename = false, _appliedWriteOffset; @@ -1704,6 +1704,14 @@ string status = processor.Go(); _ripper = null; } + public string InputPath + { + get + { + return _inputPath; + } + } + public AccurateRipVerify ArVerify { get @@ -3624,9 +3632,11 @@ string status = processor.Go(); { string prefix = ""; if (hdcdDecoder != null && string.Format("{0:s}", hdcdDecoder) != "") - prefix += string.Format("{0:s}, ", hdcdDecoder); + prefix += string.Format("{0:s}", hdcdDecoder); if (_useAccurateRip) { + if (prefix != "") prefix += ", "; + prefix += "AR: "; if (_arVerify.ARStatus != null) prefix += _arVerify.ARStatus; else @@ -3641,7 +3651,18 @@ string status = processor.Go(); else prefix += "rip not accurate"; } - } else + } + if (!_useCUEToolsDBFix && _useCUEToolsDB) + { + if (prefix != "") prefix += ", "; + prefix += "CTDB: " + CTDB.Status; + } + if (_isCD && _ripper.ErrorsCount > 0) + { + if (prefix != "") prefix += ", "; + prefix += "ripper found " + _ripper.ErrorsCount + " suspicious sectors"; + } + if (prefix == "") prefix += "done"; return prefix; } @@ -4225,6 +4246,22 @@ string status = processor.Go(); return destTags; } + //public IAudioSource OpenSource(long position) + //{ + // int pos = 0; + // for (int iSource = 0; iSource < _sources.Count; iSource++) + // { + // if (position >= pos && position < pos + (int)_sources[iSource].Length) + // { + // IAudioSource audioSource = GetAudioSource(iSource); + // audioSource.Position = position - pos; + // return audioSource; + // } + // pos += (int)_sources[iSource].Length; + // } + // return null; + //} + public void WriteAudioFilesPass(string dir, CUEStyle style, int[] destLengths, bool htoaToFile, bool noOutput) { int iTrack, iIndex; @@ -4776,7 +4813,7 @@ string status = processor.Go(); return AudioReadWrite.GetAudioDest(_audioEncoderType, path, finalSampleCount, bps, 44100, padding, _config); } - private IAudioSource GetAudioSource(int sourceIndex) { + internal IAudioSource GetAudioSource(int sourceIndex) { SourceInfo sourceInfo = _sources[sourceIndex]; IAudioSource audioSource; @@ -5635,4 +5672,113 @@ string status = processor.Go(); public StopException() : base() { } } + + public class CUESheetAudio : IAudioSource + { + CUESheet cueSheet; + IAudioSource currentAudio; + int currentSource; + long _samplePos, _sampleLen; + + public CUESheetAudio(CUESheet cueSheet) + { + this.cueSheet = cueSheet; + this.currentAudio = null; + this._samplePos = 0; + this._sampleLen = 0; + this.currentSource = 0; + for (int iSource = 0; iSource < cueSheet._sources.Count; iSource++) + this._sampleLen += cueSheet._sources[iSource].Length; + this.currentAudio = cueSheet.GetAudioSource(0); + } + + public void Close() + { + if (currentAudio != null) + { + currentAudio.Close(); + currentAudio = null; + } + } + + public long Position + { + get + { + return _samplePos; + } + set + { + long sourceStart = 0; + for (int iSource = 0; iSource < cueSheet._sources.Count; iSource++) + { + if (value >= sourceStart && value < sourceStart + cueSheet._sources[iSource].Length) + { + if (iSource != currentSource) + { + currentAudio.Close(); + currentSource = iSource; + currentAudio = cueSheet.GetAudioSource(currentSource); + } + currentAudio.Position = value - sourceStart; + _samplePos = value; + return; + } + sourceStart += cueSheet._sources[iSource].Length; + } + throw new Exception("Invalid position"); + } + } + + public long Length + { + get + { + return _sampleLen; + } + } + + public long Remaining + { + get + { + return _sampleLen - _samplePos; + } + } + + public AudioPCMConfig PCM + { + get + { + return AudioPCMConfig.RedBook; + } + } + + public string Path + { + get + { + return cueSheet.InputPath; + } + } + + public int Read(AudioBuffer buff, int maxLength) + { + buff.Prepare(this, maxLength); + + if (currentAudio.Remaining == 0) + { + currentSource++; + if (currentSource >= cueSheet._sources.Count) + { + buff.Length = 0; + return 0; + } + currentAudio.Close(); + currentAudio = cueSheet.GetAudioSource(currentSource); + } + + return currentAudio.Read(buff, maxLength); + } + } } diff --git a/CUETools.Ripper.SCSI/SCSIDrive.cs b/CUETools.Ripper.SCSI/SCSIDrive.cs index ced2a54..acafb0a 100644 --- a/CUETools.Ripper.SCSI/SCSIDrive.cs +++ b/CUETools.Ripper.SCSI/SCSIDrive.cs @@ -259,7 +259,7 @@ namespace CUETools.Ripper.SCSI //if (st != Device.CommandStatus.Success) // throw new SCSIException("ReadPMA", m_device, st); - st = m_device.ReadCDText(out cdtext); + //st = m_device.ReadCDText(out cdtext, _timeout); // new CDTextEncoderDecoder _toc2 = null; @@ -718,8 +718,6 @@ namespace CUETools.Ripper.SCSI int sector = 3; int pass = 0; - _timeout = 10; - for (int c = 0; c <= 2 && !found; c++) for (int r = 0; r <= 1 && !found; r++) for (int m = 0; m <= 1 && !found; m++) @@ -750,8 +748,6 @@ namespace CUETools.Ripper.SCSI _autodetectResult += string.Format("{0}: {1} ({2}ms)\n", CurrentReadCommand, (st == Device.CommandStatus.DeviceFailed ? Device.LookupSenseError(m_device.GetSenseAsc(), m_device.GetSenseAscq()) : st.ToString()), delay.TotalMilliseconds); found = st == Device.CommandStatus.Success; - _timeout = 1; - //sector += m_max_sectors; } //if (found) @@ -772,7 +768,6 @@ namespace CUETools.Ripper.SCSI else _readCDCommand = ReadCDCommand.Unknown; - _timeout = 10; _currentStart = -1; _currentEnd = -1; readCommandFound = found; @@ -861,8 +856,8 @@ namespace CUETools.Ripper.SCSI fixed (long* userData = &UserData[sector - _currentStart, 0, 0]) fixed (byte* c2Count = &C2Count[sector - _currentStart, 0]) { - ZeroMemory((byte*)userData, 8 * 2 * 4 * 588 * Sectors2Read); - ZeroMemory(c2Count, 294 * Sectors2Read); + AudioSamples.MemSet((byte*)userData, 0, 8 * 2 * 4 * 588 * Sectors2Read); + AudioSamples.MemSet(c2Count, 0, 294 * Sectors2Read); } } @@ -875,7 +870,7 @@ namespace CUETools.Ripper.SCSI { int size = (4 * 588 + (_c2ErrorMode == Device.C2ErrorMode.Mode294 ? 294 : _c2ErrorMode == Device.C2ErrorMode.Mode296 ? 296 : 0)) * (int)Sectors2Read; - MemSet(data, size, 0xff); + AudioSamples.MemSet(data, 0xff, size); } if (_readCDCommand == ReadCDCommand.ReadCdBEh) st = m_device.ReadCDAndSubChannel(_mainChannelMode, Device.SubChannelMode.None, _c2ErrorMode, 1, false, (uint)sector + _toc[_toc.FirstAudio][0].Start, (uint)Sectors2Read, (IntPtr)((void*)data), _timeout); @@ -914,76 +909,6 @@ namespace CUETools.Ripper.SCSI throw ex; } - private unsafe void ZeroMemory(short *buf, int count) - { - if (IntPtr.Size == 4) - { - Int32* start = (Int32*)buf; - Int32* end = (Int32*)(buf + count); - while (start < end) - *(start++) = 0; - } - else if (IntPtr.Size == 8) - { - Int64* start = (Int64*)buf; - Int64* end = (Int64*)(buf + count); - while (start < end) - *(start++) = 0; - } - else - throw new Exception("wierd IntPtr.Size"); - } - - private unsafe void ZeroMemory(byte* buf, int count) - { - if (IntPtr.Size == 4) - { - Int32* start = (Int32*)buf; - Int32* end = (Int32*)(buf + count); - while (start < end) - *(start++) = 0; - for (int i = 0; i < (count & 3); i++) - buf[count - i - 1] = 0; - } - else if (IntPtr.Size == 8) - { - Int64* start = (Int64*)buf; - Int64* end = (Int64*)(buf + count); - while (start < end) - *(start++) = 0; - for (int i = 0; i < (count & 7); i++) - buf[count - i - 1] = 0; - } - else - throw new Exception("wierd IntPtr.Size"); - } - - private unsafe void MemSet(byte* buf, int count, byte val) - { - Int32 intVal = (((((val << 8) + val) << 8) + val) << 8) + val; - if (IntPtr.Size == 4) - { - Int32* start = (Int32*)buf; - Int32* end = (Int32*)(buf + count); - while (start < end) - *(start++) = intVal; - for (int i = 0; i < (count & 3); i++) - buf[count - i - 1] = val; - } - else if (IntPtr.Size == 8) - { - Int64 int64Val = ((Int64)intVal << 32) + intVal; - Int64* start = (Int64*)buf; - Int64* end = (Int64*)(buf + count); - while (start < end) - *(start++) = int64Val; - for (int i = 0; i < (count & 7); i++) - buf[count - i - 1] = val; - } - else - throw new Exception("wierd IntPtr.Size"); - } - private unsafe void CorrectSectors(int pass, int sector, int Sectors2Read, bool markErrors) { for (int iSector = 0; iSector < Sectors2Read; iSector++) diff --git a/CUETools.Ripper/Ripper.cs b/CUETools.Ripper/Ripper.cs index 4e60e57..75202a5 100644 --- a/CUETools.Ripper/Ripper.cs +++ b/CUETools.Ripper/Ripper.cs @@ -20,6 +20,7 @@ namespace CUETools.Ripper string RipperVersion { get; } string CurrentReadCommand { get; } int CorrectionQuality { get; set; } + int ErrorsCount { get; } BitArray Errors { get; } event EventHandler ReadProgress; diff --git a/CUETools/CUETools.sln b/CUETools/CUETools.sln index 69035cc..aaa5170 100644 --- a/CUETools/CUETools.sln +++ b/CUETools/CUETools.sln @@ -155,6 +155,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CUETools.CTDB", "..\CUETool EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProgressODoom", "..\ProgressODoom\ProgressODoom.csproj", "{8DD1E84B-0B03-4C0B-9B42-1E49F75E7CB1}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CUEPlayer", "..\CUEPlayer\CUEPlayer.csproj", "{04E59836-0C5A-4B9B-8899-848D56911758}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CUETools.Codecs.CoreAudio", "..\CUETools.Codecs.CoreAudio\CUETools.Codecs.CoreAudio.csproj", "{FAD09EE2-D6B2-4A8E-9F1C-2A9FB293661A}" +EndProject Global GlobalSection(TestCaseManagementSettings) = postSolution CategoryFile = CUETools1.vsmdi @@ -570,6 +574,22 @@ Global {8DD1E84B-0B03-4C0B-9B42-1E49F75E7CB1}.Release|Any CPU.Build.0 = Release|Any CPU {8DD1E84B-0B03-4C0B-9B42-1E49F75E7CB1}.Release|Win32.ActiveCfg = Release|Any CPU {8DD1E84B-0B03-4C0B-9B42-1E49F75E7CB1}.Release|x64.ActiveCfg = Release|Any CPU + {04E59836-0C5A-4B9B-8899-848D56911758}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {04E59836-0C5A-4B9B-8899-848D56911758}.Debug|Any CPU.Build.0 = Debug|Any CPU + {04E59836-0C5A-4B9B-8899-848D56911758}.Debug|Win32.ActiveCfg = Debug|Any CPU + {04E59836-0C5A-4B9B-8899-848D56911758}.Debug|x64.ActiveCfg = Debug|Any CPU + {04E59836-0C5A-4B9B-8899-848D56911758}.Release|Any CPU.ActiveCfg = Release|Any CPU + {04E59836-0C5A-4B9B-8899-848D56911758}.Release|Any CPU.Build.0 = Release|Any CPU + {04E59836-0C5A-4B9B-8899-848D56911758}.Release|Win32.ActiveCfg = Release|Any CPU + {04E59836-0C5A-4B9B-8899-848D56911758}.Release|x64.ActiveCfg = Release|Any CPU + {FAD09EE2-D6B2-4A8E-9F1C-2A9FB293661A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FAD09EE2-D6B2-4A8E-9F1C-2A9FB293661A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FAD09EE2-D6B2-4A8E-9F1C-2A9FB293661A}.Debug|Win32.ActiveCfg = Debug|Any CPU + {FAD09EE2-D6B2-4A8E-9F1C-2A9FB293661A}.Debug|x64.ActiveCfg = Debug|Any CPU + {FAD09EE2-D6B2-4A8E-9F1C-2A9FB293661A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FAD09EE2-D6B2-4A8E-9F1C-2A9FB293661A}.Release|Any CPU.Build.0 = Release|Any CPU + {FAD09EE2-D6B2-4A8E-9F1C-2A9FB293661A}.Release|Win32.ActiveCfg = Release|Any CPU + {FAD09EE2-D6B2-4A8E-9F1C-2A9FB293661A}.Release|x64.ActiveCfg = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/CUETools/frmCUETools.resx b/CUETools/frmCUETools.resx index 2ce1053..e9f23f3 100644 --- a/CUETools/frmCUETools.resx +++ b/CUETools/frmCUETools.resx @@ -258,6 +258,21 @@ 0 + + Top, Bottom, Left, Right + + + 19 + + + 3, 17 + + + 192, 304 + + + 1 + fileSystemTreeView1 @@ -303,9 +318,255 @@ 3 - - 3, 17 + + 3 + + + True + + + Fill + + + NoControl + + + 95, 84 + + + 0, 0, 0, 0 + + + 49, 26 + + + 5 + + + 153, 8 + + Use AccurateRip + + + checkBoxUseAccurateRip + + + System.Windows.Forms.CheckBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableLayoutPanelCUEStyle + + + 0 + + + True + + + Fill + + + NoControl + + + 47, 84 + + + 0, 0, 0, 0 + + + 48, 26 + + + 4 + + + Use FreeDb + + + checkBoxUseFreeDb + + + System.Windows.Forms.CheckBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableLayoutPanelCUEStyle + + + 1 + + + True + + + Fill + + + NoControl + + + 3, 40 + + + 3, 0, 3, 0 + + + 138, 20 + + + 2 + + + &Tracks + + + File per track. Gap handling can be selected in advanced settings. + + + rbTracks + + + System.Windows.Forms.RadioButton, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableLayoutPanelCUEStyle + + + 2 + + + True + + + Fill + + + NoControl + + + 3, 0 + + + 3, 0, 3, 0 + + + 138, 20 + + + 0 + + + &Embedded + + + Create single file with embedded CUE sheet. + + + rbEmbedCUE + + + System.Windows.Forms.RadioButton, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableLayoutPanelCUEStyle + + + 3 + + + True + + + Fill + + + NoControl + + + 3, 20 + + + 3, 0, 3, 0 + + + 138, 20 + + + 1 + + + Image + CUE + + + Create single file + CUE sheet + + + rbSingleFile + + + System.Windows.Forms.RadioButton, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableLayoutPanelCUEStyle + + + 4 + + + True + + + Fill + + + NoControl + + + 0, 84 + + + 0, 0, 0, 0 + + + 47, 26 + + + 3 + + + Use MusicBrainz + + + checkBoxUseMusicBrainz + + + System.Windows.Forms.CheckBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableLayoutPanelCUEStyle + + + 5 + + + Fill + + + 3, 17 + + + 0, 0, 0, 0 + + + 5 + + + 144, 110 + + + 11 + tableLayoutPanelCUEStyle @@ -321,6 +582,72 @@ <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="checkBoxUseAccurateRip" Row="4" RowSpan="1" Column="2" ColumnSpan="1" /><Control Name="checkBoxUseFreeDb" Row="4" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="rbTracks" Row="2" RowSpan="1" Column="0" ColumnSpan="3" /><Control Name="rbEmbedCUE" Row="0" RowSpan="1" Column="0" ColumnSpan="3" /><Control Name="rbSingleFile" Row="1" RowSpan="1" Column="0" ColumnSpan="3" /><Control Name="checkBoxUseMusicBrainz" Row="4" RowSpan="1" Column="0" ColumnSpan="1" /></Controls><Columns Styles="Percent,33,33332,Percent,33,33334,Percent,33,33334" /><Rows Styles="Percent,18,18229,Percent,18,18229,Percent,18,18229,Percent,22,72658,Percent,22,72658" /></TableLayoutSettings> + + 3, 17 + + + False + + + Fill + + + Magenta + + + 78, 20 + + + Overwrite + + + 168, 22 + + + Locate files + + + Try to locate missing files automatically + + + 168, 22 + + + Change extension + + + Replace extension for audio files with this: + + + Magenta + + + 79, 19 + + + Locate files + + + Magenta + + + 39, 19 + + + flac + + + 3, 17 + + + 3, 0, 1, 0 + + + 144, 110 + + + 20 + toolStripCorrectorFormat @@ -333,6 +660,57 @@ 1 + + 2 + + + True + + + Fill + + + NoControl + + + 3, 3 + + + 45, 29 + + + 0 + + + checkBoxVerifyUseCDRepair + + + System.Windows.Forms.CheckBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableLayoutPanelVerifyMode + + + 0 + + + Fill + + + 3, 17 + + + 2 + + + 144, 110 + + + 2 + + + Use CUETools database + tableLayoutPanelVerifyMode @@ -720,9 +1098,6 @@ 9 - - 153, 8 - Audio file format @@ -795,1059 +1170,9 @@ 2 - - tableLayoutPanelPaths - - - System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - grpOutputPathGeneration - - - 0 - - - <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="labelOutputTemplate" Row="2" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="comboBoxOutputFormat" Row="2" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="txtInputPath" Row="0" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="txtOutputPath" Row="1" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="toolStripInput" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="toolStripOutput" Row="1" RowSpan="1" Column="0" ColumnSpan="1" /></Controls><Columns Styles="Percent,20,94017,Percent,79,05983" /><Rows Styles="Percent,33,33333,Percent,33,33333,Percent,33,33333" /></TableLayoutSettings> - - - Fill - - - 3, 3 - - - 474, 92 - - - 1 - - - CUE Paths - - - grpOutputPathGeneration - - - System.Windows.Forms.GroupBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - tableLayoutPanel2 - - - 3 - - - comboBoxScript - - - System.Windows.Forms.ComboBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - grpAction - - - 0 - - - rbActionCorrectFilenames - - - System.Windows.Forms.RadioButton, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - grpAction - - - 1 - - - rbActionCreateCUESheet - - - System.Windows.Forms.RadioButton, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - grpAction - - - 2 - - - rbActionVerify - - - System.Windows.Forms.RadioButton, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - grpAction - - - 3 - - - rbActionEncode - - - System.Windows.Forms.RadioButton, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - grpAction - - - 4 - - - Fill - - - 3, 101 - - - 164, 130 - - - 4 - - - Action - - - grpAction - - - System.Windows.Forms.GroupBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - tableLayoutPanel2 - - - 4 - - - tableLayoutPanel4 - - - System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - grpExtra - - - 0 - - - <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="labelPregap" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="lblWriteOffset" Row="2" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="numericWriteOffset" Row="2" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="txtPreGapLength" Row="0" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="labelDataTrack" Row="1" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="txtDataTrackLength" Row="1" RowSpan="1" Column="1" ColumnSpan="1" /></Controls><Columns Styles="Percent,56,75676,Percent,43,24324" /><Rows Styles="Percent,33,33333,Percent,33,33333,Percent,33,33333" /></TableLayoutSettings> - - - Fill - - - 173, 237 - - - 150, 90 - - - 6 - - - Extra - - - grpExtra - - - System.Windows.Forms.GroupBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - tableLayoutPanel2 - - - 5 - - - btnConvert - - - System.Windows.Forms.Button, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - panelGo - - - 0 - - - btnStop - - - System.Windows.Forms.Button, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - panelGo - - - 1 - - - btnResume - - - System.Windows.Forms.Button, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - panelGo - - - 2 - - - btnPause - - - System.Windows.Forms.Button, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - panelGo - - - 3 - - - Fill - - - 338, 301 - - - 12, 3, 12, 3 - - - 130, 26 - - - 14 - - - panelGo - - - System.Windows.Forms.Panel, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - tableLayoutPanel2 - - - 6 - - - Fill - - - 204, 0 - - - 0, 0, 0, 0 - - - 4 - - - 480, 330 - - - 1 - - - tableLayoutPanel2 - - - System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - tableLayoutPanel1 - - - 2 - - - <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="groupBoxMode" Row="1" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="grpAudioOutput" Row="1" RowSpan="2" Column="2" ColumnSpan="1" /><Control Name="pictureBoxMotd" Row="2" RowSpan="2" Column="0" ColumnSpan="1" /><Control Name="grpOutputPathGeneration" Row="0" RowSpan="1" Column="0" ColumnSpan="3" /><Control Name="grpAction" Row="1" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="grpExtra" Row="2" RowSpan="2" Column="1" ColumnSpan="1" /><Control Name="panelGo" Row="3" RowSpan="1" Column="2" ColumnSpan="1" /></Controls><Columns Styles="Percent,35,41667,Percent,32,70833,Percent,31,875" /><Rows Styles="Percent,29,69697,Percent,41,51515,Percent,19,39394,Percent,9,393939" /></TableLayoutSettings> - - - Fill - - - 0, 0 - - - 0, 0, 0, 0 - - - 2 - - - 684, 451 - - - 17 - - - tableLayoutPanel1 - - - System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - toolStripContainer1.ContentPanel - - - 0 - - - <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="textBatchReport" Row="1" RowSpan="1" Column="0" ColumnSpan="2" /><Control Name="grpInput" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="tableLayoutPanel2" Row="0" RowSpan="1" Column="1" ColumnSpan="1" /></Controls><Columns Styles="Percent,100,Absolute,480" /><Rows Styles="Absolute,330,Percent,100" /></TableLayoutSettings> - - - 0, 0, 0, 0 - - - 684, 451 - - - toolStripContainer1.ContentPanel - - - System.Windows.Forms.ToolStripContentPanel, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - toolStripContainer1 - - - 0 - - - Fill - - - toolStripContainer1.LeftToolStripPanel - - - System.Windows.Forms.ToolStripPanel, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - toolStripContainer1 - - - 1 - - - 0, 0 - - - toolStripContainer1.RightToolStripPanel - - - System.Windows.Forms.ToolStripPanel, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - toolStripContainer1 - - - 2 - - - 684, 502 - - - 17 - - - toolStripContainer1 - - - 0, 0 - - - None - - - 0, 0 - - - 684, 25 - - - 0 - - - toolStripMenu - - - System.Windows.Forms.ToolStrip, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - toolStripContainer1.TopToolStripPanel - - - 0 - - - toolStripContainer1.TopToolStripPanel - - - System.Windows.Forms.ToolStripPanel, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - toolStripContainer1 - - - 3 - - - toolStripContainer1 - - - System.Windows.Forms.ToolStripContainer, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - $this - - - 1 - - - Top, Bottom, Left, Right - - - 19 - - - 3, 17 - - - 192, 304 - - - 1 - - - fileSystemTreeView1 - - - CUEControls.FileSystemTreeView, CUEControls, Version=2.0.7.0, Culture=neutral, PublicKeyToken=null - - - grpInput - - - 0 - - - 3 - - - checkBoxUseAccurateRip - - - System.Windows.Forms.CheckBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - tableLayoutPanelCUEStyle - - - 0 - - - checkBoxUseFreeDb - - - System.Windows.Forms.CheckBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - tableLayoutPanelCUEStyle - - - 1 - - - rbTracks - - - System.Windows.Forms.RadioButton, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - tableLayoutPanelCUEStyle - - - 2 - - - rbEmbedCUE - - - System.Windows.Forms.RadioButton, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - tableLayoutPanelCUEStyle - - - 3 - - - rbSingleFile - - - System.Windows.Forms.RadioButton, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - tableLayoutPanelCUEStyle - - - 4 - - - checkBoxUseMusicBrainz - - - System.Windows.Forms.CheckBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - tableLayoutPanelCUEStyle - - - 5 - - - Fill - - - 3, 17 - - - 0, 0, 0, 0 - - - 5 - - - 144, 110 - - - 11 - - - tableLayoutPanelCUEStyle - - - System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - groupBoxMode - - - 0 - - - <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="checkBoxUseAccurateRip" Row="4" RowSpan="1" Column="2" ColumnSpan="1" /><Control Name="checkBoxUseFreeDb" Row="4" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="rbTracks" Row="2" RowSpan="1" Column="0" ColumnSpan="3" /><Control Name="rbEmbedCUE" Row="0" RowSpan="1" Column="0" ColumnSpan="3" /><Control Name="rbSingleFile" Row="1" RowSpan="1" Column="0" ColumnSpan="3" /><Control Name="checkBoxUseMusicBrainz" Row="4" RowSpan="1" Column="0" ColumnSpan="1" /></Controls><Columns Styles="Percent,33,33332,Percent,33,33334,Percent,33,33334" /><Rows Styles="Percent,18,18229,Percent,18,18229,Percent,18,18229,Percent,22,72658,Percent,22,72658" /></TableLayoutSettings> - - - 153, 8 - - - True - - - Fill - - - NoControl - - - 95, 84 - - - 0, 0, 0, 0 - - - 49, 26 - - - 5 - - - Use AccurateRip - - - checkBoxUseAccurateRip - - - System.Windows.Forms.CheckBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - tableLayoutPanelCUEStyle - - - 0 - - - True - - - Fill - - - NoControl - - - 47, 84 - - - 0, 0, 0, 0 - - - 48, 26 - - - 4 - - - Use FreeDb - - - checkBoxUseFreeDb - - - System.Windows.Forms.CheckBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - tableLayoutPanelCUEStyle - - - 1 - - - True - - - Fill - - - NoControl - - - 3, 40 - - - 3, 0, 3, 0 - - - 138, 20 - - - 2 - - - &Tracks - - - File per track. Gap handling can be selected in advanced settings. - - - rbTracks - - - System.Windows.Forms.RadioButton, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - tableLayoutPanelCUEStyle - - - 2 - - - True - - - Fill - - - NoControl - - - 3, 0 - - - 3, 0, 3, 0 - - - 138, 20 - - - 0 - - - &Embedded - - - Create single file with embedded CUE sheet. - - - rbEmbedCUE - - - System.Windows.Forms.RadioButton, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - tableLayoutPanelCUEStyle - - - 3 - - - True - - - Fill - - - NoControl - - - 3, 20 - - - 3, 0, 3, 0 - - - 138, 20 - - - 1 - - - Image + CUE - - - Create single file + CUE sheet - - - rbSingleFile - - - System.Windows.Forms.RadioButton, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - tableLayoutPanelCUEStyle - - - 4 - - - True - - - Fill - - - NoControl - - - 0, 84 - - - 0, 0, 0, 0 - - - 47, 26 - - - 3 - - - Use MusicBrainz - - - checkBoxUseMusicBrainz - - - System.Windows.Forms.CheckBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - tableLayoutPanelCUEStyle - - - 5 - - - 3, 17 - - - False - - - Fill - - - 3, 17 - - - 3, 0, 1, 0 - - - 144, 110 - - - 20 - - - toolStripCorrectorFormat - - - System.Windows.Forms.ToolStrip, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - groupBoxMode - - - 1 - - - Magenta - - - 78, 20 - - - Overwrite - - - Magenta - - - 79, 19 - - - Locate files - - - 168, 22 - - - Locate files - - - Try to locate missing files automatically - - - 168, 22 - - - Change extension - - - Replace extension for audio files with this: - - - Magenta - - - 39, 19 - - - flac - - - 2 - - - checkBoxVerifyUseCDRepair - - - System.Windows.Forms.CheckBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - tableLayoutPanelVerifyMode - - - 0 - - - Fill - - - 3, 17 - - - 2 - - - 144, 110 - - - 2 - - - Use CUETools database - - - tableLayoutPanelVerifyMode - - - System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - groupBoxMode - - - 2 - - - <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="checkBoxVerifyUseCDRepair" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /></Controls><Columns Styles="Percent,36,11111,Percent,63,88889" /><Rows Styles="Percent,32,72727,Percent,67,27273" /></TableLayoutSettings> - - - True - - - Fill - - - NoControl - - - 3, 3 - - - 45, 29 - - - 0 - - - checkBoxVerifyUseCDRepair - - - System.Windows.Forms.CheckBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - tableLayoutPanelVerifyMode - - - 0 - - - 0, 0 - - - 0, 24 - 2 - - labelOutputTemplate - - - System.Windows.Forms.Label, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - tableLayoutPanelPaths - - - 0 - - - comboBoxOutputFormat - - - System.Windows.Forms.ComboBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - tableLayoutPanelPaths - - - 1 - - - txtInputPath - - - System.Windows.Forms.TextBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - tableLayoutPanelPaths - - - 2 - - - txtOutputPath - - - System.Windows.Forms.TextBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - tableLayoutPanelPaths - - - 3 - - - toolStripInput - - - System.Windows.Forms.ToolStrip, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - tableLayoutPanelPaths - - - 4 - - - toolStripOutput - - - System.Windows.Forms.ToolStrip, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - tableLayoutPanelPaths - - - 5 - - - Fill - - - 3, 17 - - - 0, 0, 0, 0 - - - 3 - - - 468, 72 - - - 14 - - - tableLayoutPanelPaths - - - System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - grpOutputPathGeneration - - - 0 - - - <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="labelOutputTemplate" Row="2" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="comboBoxOutputFormat" Row="2" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="txtInputPath" Row="0" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="txtOutputPath" Row="1" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="toolStripInput" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="toolStripOutput" Row="1" RowSpan="1" Column="0" ColumnSpan="1" /></Controls><Columns Styles="Percent,20,94017,Percent,79,05983" /><Rows Styles="Percent,33,33333,Percent,33,33333,Percent,33,33333" /></TableLayoutSettings> - Fill @@ -1971,6 +1296,45 @@ Fill + + 38, 21 + + + Input: + + + 177, 22 + + + Folder browser + + + 177, 22 + + + Multiselect Browser + + + 177, 22 + + + Drag'n'drop mode + + + 177, 22 + + + Hide browser + + + Magenta + + + 32, 21 + + + Open/close input browser + 0, 0 @@ -1998,51 +1362,45 @@ 4 - - 38, 21 - - - Input: - - - Magenta - - - 32, 21 - - - Open/close input browser - - - 177, 22 - - - Folder browser - - - 177, 22 - - - Multiselect Browser - - - 177, 22 - - - Drag'n'drop mode - - - 177, 22 - - - Hide browser - 0, 24 Fill + + 48, 24 + + + Output: + + + 143, 22 + + + Browse + + + 143, 22 + + + Manual + + + 143, 22 + + + Use template + + + Magenta + + + 32, 21 + + + toolStripSplitButtonOutputBrowser + 0, 24 @@ -2070,38 +1428,65 @@ 5 - - 48, 24 + + Fill - - Output: + + 3, 17 - - Magenta + + 0, 0, 0, 0 - - 32, 21 + + 3 - - toolStripSplitButtonOutputBrowser + + 468, 72 - - 143, 22 + + 14 - - Browse + + tableLayoutPanelPaths - - 143, 22 + + System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - Manual + + grpOutputPathGeneration - - 143, 22 + + 0 - - Use template + + <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="labelOutputTemplate" Row="2" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="comboBoxOutputFormat" Row="2" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="txtInputPath" Row="0" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="txtOutputPath" Row="1" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="toolStripInput" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="toolStripOutput" Row="1" RowSpan="1" Column="0" ColumnSpan="1" /></Controls><Columns Styles="Percent,20,94017,Percent,79,05983" /><Rows Styles="Percent,33,33333,Percent,33,33333,Percent,33,33333" /></TableLayoutSettings> + + + Fill + + + 3, 3 + + + 474, 92 + + + 1 + + + CUE Paths + + + grpOutputPathGeneration + + + System.Windows.Forms.GroupBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableLayoutPanel2 + + + 3 Top, Left, Right @@ -2262,113 +1647,35 @@ 4 - - 2 - - - labelPregap - - - System.Windows.Forms.Label, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - tableLayoutPanel4 - - - 0 - - - lblWriteOffset - - - System.Windows.Forms.Label, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - tableLayoutPanel4 - - - 1 - - - numericWriteOffset - - - System.Windows.Forms.NumericUpDown, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - tableLayoutPanel4 - - - 2 - - - txtPreGapLength - - - System.Windows.Forms.MaskedTextBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - tableLayoutPanel4 - - - 3 - - - labelDataTrack - - - System.Windows.Forms.Label, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - tableLayoutPanel4 - - - 4 - - - txtDataTrackLength - - - System.Windows.Forms.MaskedTextBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - tableLayoutPanel4 - - - 5 - - + Fill - - 3, 17 + + 3, 101 - - 0, 0, 0, 0 + + 164, 130 - - 3 + + 4 - - 144, 70 + + Action - - 6 + + grpAction - - tableLayoutPanel4 + + System.Windows.Forms.GroupBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + tableLayoutPanel2 - - grpExtra + + 4 - - 0 - - - <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="labelPregap" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="lblWriteOffset" Row="2" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="numericWriteOffset" Row="2" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="txtPreGapLength" Row="0" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="labelDataTrack" Row="1" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="txtDataTrackLength" Row="1" RowSpan="1" Column="1" ColumnSpan="1" /></Controls><Columns Styles="Percent,56,75676,Percent,43,24324" /><Rows Styles="Percent,33,33333,Percent,33,33333,Percent,33,33333" /></TableLayoutSettings> + + 2 True @@ -2574,6 +1881,66 @@ 5 + + Fill + + + 3, 17 + + + 0, 0, 0, 0 + + + 3 + + + 144, 70 + + + 6 + + + tableLayoutPanel4 + + + System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + grpExtra + + + 0 + + + <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="labelPregap" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="lblWriteOffset" Row="2" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="numericWriteOffset" Row="2" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="txtPreGapLength" Row="0" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="labelDataTrack" Row="1" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="txtDataTrackLength" Row="1" RowSpan="1" Column="1" ColumnSpan="1" /></Controls><Columns Styles="Percent,56,75676,Percent,43,24324" /><Rows Styles="Percent,33,33333,Percent,33,33333,Percent,33,33333" /></TableLayoutSettings> + + + Fill + + + 173, 237 + + + 150, 90 + + + 6 + + + Extra + + + grpExtra + + + System.Windows.Forms.GroupBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableLayoutPanel2 + + + 5 + Fill @@ -2712,17 +2079,161 @@ 3 - - Magenta + + Fill - - 73, 22 + + 338, 301 - - default + + 12, 3, 12, 3 - - Profile + + 130, 26 + + + 14 + + + panelGo + + + System.Windows.Forms.Panel, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableLayoutPanel2 + + + 6 + + + Fill + + + 204, 0 + + + 0, 0, 0, 0 + + + 4 + + + 480, 330 + + + 1 + + + tableLayoutPanel2 + + + System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tableLayoutPanel1 + + + 2 + + + <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="groupBoxMode" Row="1" RowSpan="1" Column="1" ColumnSpan="1" /><Control Name="grpAudioOutput" Row="1" RowSpan="2" Column="2" ColumnSpan="1" /><Control Name="pictureBoxMotd" Row="2" RowSpan="2" Column="0" ColumnSpan="1" /><Control Name="grpOutputPathGeneration" Row="0" RowSpan="1" Column="0" ColumnSpan="3" /><Control Name="grpAction" Row="1" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="grpExtra" Row="2" RowSpan="2" Column="1" ColumnSpan="1" /><Control Name="panelGo" Row="3" RowSpan="1" Column="2" ColumnSpan="1" /></Controls><Columns Styles="Percent,35,41667,Percent,32,70833,Percent,31,875" /><Rows Styles="Percent,29,69697,Percent,41,51515,Percent,19,39394,Percent,9,393939" /></TableLayoutSettings> + + + Fill + + + 0, 0 + + + 0, 0, 0, 0 + + + 2 + + + 684, 451 + + + 17 + + + tableLayoutPanel1 + + + System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + toolStripContainer1.ContentPanel + + + 0 + + + <?xml version="1.0" encoding="utf-16"?><TableLayoutSettings><Controls><Control Name="textBatchReport" Row="1" RowSpan="1" Column="0" ColumnSpan="2" /><Control Name="grpInput" Row="0" RowSpan="1" Column="0" ColumnSpan="1" /><Control Name="tableLayoutPanel2" Row="0" RowSpan="1" Column="1" ColumnSpan="1" /></Controls><Columns Styles="Percent,100,Absolute,480" /><Rows Styles="Absolute,330,Percent,100" /></TableLayoutSettings> + + + 0, 0, 0, 0 + + + 684, 451 + + + toolStripContainer1.ContentPanel + + + System.Windows.Forms.ToolStripContentPanel, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + toolStripContainer1 + + + 0 + + + Fill + + + toolStripContainer1.LeftToolStripPanel + + + System.Windows.Forms.ToolStripPanel, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + toolStripContainer1 + + + 1 + + + 0, 0 + + + toolStripContainer1.RightToolStripPanel + + + System.Windows.Forms.ToolStripPanel, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + toolStripContainer1 + + + 2 + + + 684, 502 + + + 17 + + + toolStripContainer1 + + + 0, 0 + + + None 100, 23 @@ -2748,6 +2259,18 @@ default + + Magenta + + + 73, 22 + + + default + + + Profile + 6, 25 @@ -2790,18 +2313,54 @@ Batch log + + 0, 0 + + + 684, 25 + + + 0 + + + toolStripMenu + + + System.Windows.Forms.ToolStrip, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + toolStripContainer1.TopToolStripPanel + + + 0 + + + toolStripContainer1.TopToolStripPanel + + + System.Windows.Forms.ToolStripPanel, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + toolStripContainer1 + + + 3 + + + toolStripContainer1 + + + System.Windows.Forms.ToolStripContainer, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 1 + 424, 8 - - 206, 76 - - - contextMenuStripFileTree - - - System.Windows.Forms.ContextMenuStrip, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - False @@ -2826,6 +2385,15 @@ Reset to original location + + 206, 76 + + + contextMenuStripFileTree + + + System.Windows.Forms.ContextMenuStrip, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + True