This commit is contained in:
chudov
2010-03-30 02:41:43 +00:00
parent 771df3be5a
commit 881951cb02
74 changed files with 6489 additions and 1709 deletions

View File

@@ -2245,7 +2245,7 @@ namespace Bwg.Scsi
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
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);

View File

@@ -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,6 +556,16 @@ namespace BBBNOVA
}
}
protected virtual Color GetOuterBorderColor()
{
return (Enabled) ? BackColor : BackColor;
}
protected virtual Color GetInnerBorderColor()
{
return (Enabled) ? BackColor : SystemColors.Control;
}
protected override void OnPaint(PaintEventArgs e)
{
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
@@ -597,19 +607,19 @@ namespace BBBNOVA
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;
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();
blend.Colors = new Color[] { Color.Transparent, foreColor, Color.Transparent };
blend.Positions = new float[] { 0.0f, 0.5f, 1.0f};
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);
@@ -620,10 +630,17 @@ namespace BBBNOVA
{
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
@@ -640,7 +657,7 @@ namespace BBBNOVA
path.CloseFigure();
e.Graphics.RotateTransform(0);
SolidBrush br = new SolidBrush(Enabled?Color.Gray:Color.Gainsboro);
SolidBrush br = new SolidBrush(Enabled ? Color.Gray : Color.Gainsboro);
e.Graphics.FillPath(br, path);
e.Graphics.ResetTransform();
br.Dispose();
@@ -689,7 +706,6 @@ namespace BBBNOVA
pathInnerBorder.Dispose();
pathBtnBorder.Dispose();
penOuterBorder.Dispose();
penInnerBorder.Dispose();
penLeftButton.Dispose();
@@ -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)
@@ -1132,4 +1148,38 @@ namespace BBBNOVA
}
}
public class BNComboBoxItem<T>
{
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;
}
}
}

View File

@@ -91,6 +91,9 @@
<SubType>Designer</SubType>
<DependentUpon>frmCUERipper.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="frmCUERipper.ru-RU.resx">
<DependentUpon>frmCUERipper.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="frmProperties.resx">
<DependentUpon>frmProperties.cs</DependentUpon>
<SubType>Designer</SubType>
@@ -100,6 +103,7 @@
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.ru-RU.resx" />
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>

View File

@@ -95,6 +95,60 @@ namespace CUERipper.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to Detecting drives.
/// </summary>
internal static string DetectingDrives {
get {
return ResourceManager.GetString("DetectingDrives", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Done ripping.
/// </summary>
internal static string DoneRipping {
get {
return ResourceManager.GetString("DoneRipping", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Rip probably contains errors.
/// </summary>
internal static string DoneRippingErrors {
get {
return ResourceManager.GetString("DoneRippingErrors", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to You can try to repair it using CUETools.
/// </summary>
internal static string DoneRippingRepair {
get {
return ResourceManager.GetString("DoneRippingRepair", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Exception.
/// </summary>
internal static string ExceptionMessage {
get {
return ResourceManager.GetString("ExceptionMessage", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Failed to load ripper module.
/// </summary>
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 {
}
}
/// <summary>
/// Looks up a localized string similar to Looking up album via.
/// </summary>
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 {
}
}
/// <summary>
/// Looks up a localized string similar to No CD drives found.
/// </summary>
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 {
}
}
/// <summary>
/// Looks up a localized string similar to Paused.
/// </summary>
internal static string PausedMessage {
get {
return ResourceManager.GetString("PausedMessage", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to retry.
/// </summary>
internal static string Retry {
get {
return ResourceManager.GetString("Retry", resourceCulture);
}
}
internal static System.Drawing.Icon tta {
get {
object obj = ResourceManager.GetObject("tta", resourceCulture);

View File

@@ -160,4 +160,34 @@
<data name="wv" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\wv.ico;System.Drawing.Icon, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="DoneRipping" xml:space="preserve">
<value>Done ripping</value>
</data>
<data name="DoneRippingErrors" xml:space="preserve">
<value>Rip probably contains errors</value>
</data>
<data name="DoneRippingRepair" xml:space="preserve">
<value>You can try to repair it using CUETools</value>
</data>
<data name="ExceptionMessage" xml:space="preserve">
<value>Exception</value>
</data>
<data name="FailedToLoadRipperModule" xml:space="preserve">
<value>Failed to load ripper module</value>
</data>
<data name="LookingUpVia" xml:space="preserve">
<value>Looking up album via</value>
</data>
<data name="NoDrives" xml:space="preserve">
<value>No CD drives found</value>
</data>
<data name="PausedMessage" xml:space="preserve">
<value>Paused</value>
</data>
<data name="Retry" xml:space="preserve">
<value>retry</value>
</data>
<data name="DetectingDrives" xml:space="preserve">
<value>Detecting drives</value>
</data>
</root>

View File

@@ -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;
}
}

View File

@@ -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<string> cueStyles = new BindingList<string> { "image", "tracks" };
private BindingList<string> losslessOrNot = new BindingList<string> { "lossless", "lossy" };
//private BindingList<string> losslessOrNot = new BindingList<string> { "lossless", "lossy" };
private BindingList<BNComboBoxItem<AudioEncoderType>> losslessOrNot = new BindingList<BNComboBoxItem<AudioEncoderType>> {
new BNComboBoxItem<AudioEncoderType>("lossless", "checked", AudioEncoderType.Lossless),
new BNComboBoxItem<AudioEncoderType>("lossy", "unchecked", AudioEncoderType.Lossy)
};
private BindingList<ReleaseInfo> releases = new BindingList<ReleaseInfo>();
private BindingList<DriveInfo> drives = new BindingList<DriveInfo>();
private BindingList<FormatInfo> formats = new BindingList<FormatInfo>();
@@ -69,7 +74,7 @@ namespace CUERipper
}
}
public BindingList<string> LosslessOrNot
public BindingList<BNComboBoxItem<AudioEncoderType>> 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();
//bnComboBoxDrives.SelectedIndex = 0;
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;
}
_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;
if ((cueSheet.CTDB.AccResult == HttpStatusCode.NotFound || cueSheet.CTDB.AccResult == HttpStatusCode.OK)
&& audioSource.CorrectionQuality > 0 && audioSource.ErrorsCount == 0)
{
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 (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<Krystalware.UploadHelper.UploadProgressEventArgs>(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<AudioEncoderType>).Value;
}
set
{
switch (value)
foreach (BNComboBoxItem<AudioEncoderType> item in losslessOrNot)
if (value == item.Value)
{
case AudioEncoderType.Hybrid:
bnComboBoxLosslessOrNot.SelectedItem = "hybrid";
break;
case AudioEncoderType.Lossy:
bnComboBoxLosslessOrNot.SelectedItem = "lossy";
break;
default:
bnComboBoxLosslessOrNot.SelectedItem = "lossless";
break;
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);
}
}

View File

@@ -197,7 +197,7 @@
<value>$this</value>
</data>
<data name="&gt;&gt;statusStrip1.ZOrder" xml:space="preserve">
<value>11</value>
<value>10</value>
</data>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="listTracks.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
@@ -243,7 +243,7 @@
<value>2</value>
</data>
<metadata name="toolTip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>376, 17</value>
<value>357, 17</value>
</metadata>
<data name="listTracks.ToolTip" xml:space="preserve">
<value>Double-click to edit track names</value>
@@ -258,7 +258,7 @@
<value>$this</value>
</data>
<data name="&gt;&gt;listTracks.ZOrder" xml:space="preserve">
<value>9</value>
<value>8</value>
</data>
<data name="buttonGo.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Left, Right</value>
@@ -288,7 +288,7 @@
<value>$this</value>
</data>
<data name="&gt;&gt;buttonGo.ZOrder" xml:space="preserve">
<value>10</value>
<value>9</value>
</data>
<data name="buttonAbort.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Left, Right</value>
@@ -321,7 +321,7 @@
<value>$this</value>
</data>
<data name="&gt;&gt;buttonAbort.ZOrder" xml:space="preserve">
<value>12</value>
<value>11</value>
</data>
<data name="buttonPause.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Left, Right</value>
@@ -354,7 +354,7 @@
<value>$this</value>
</data>
<data name="&gt;&gt;buttonPause.ZOrder" xml:space="preserve">
<value>13</value>
<value>12</value>
</data>
<metadata name="contextMenuStripRelease.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
@@ -459,7 +459,7 @@
<value>11</value>
</data>
<metadata name="losslessOrNotBindingSource.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>631, 456</value>
<value>369, 95</value>
</metadata>
<metadata name="bindingSourceCR.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>210, 56</value>
@@ -467,14 +467,6 @@
<data name="bnComboBoxLosslessOrNot.Location" type="System.Drawing.Point, System.Drawing">
<value>6, 19</value>
</data>
<data name="bnComboBoxLosslessOrNot.Radius" mimetype="application/x-microsoft.net.object.binary.base64">
<value>
AAEAAAD/////AQAAAAAAAAAMAgAAAEJDVUVDb250cm9scywgVmVyc2lvbj0yLjAuNy4wLCBDdWx0dXJl
PW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPW51bGwFAQAAABBCQkJOT1ZBLkJOUmFkaXVzBAAAAAhfdG9w
TGVmdAlfdG9wUmlnaHQLX2JvdHRvbUxlZnQMX2JvdHRvbVJpZ2h0AAAAAAgICAgCAAAAAgAAAAYAAAAC
AAAAAgAAAAs=
</value>
</data>
<data name="bnComboBoxLosslessOrNot.Size" type="System.Drawing.Size, System.Drawing">
<value>80, 21</value>
</data>
@@ -485,7 +477,7 @@
<value>bnComboBoxLosslessOrNot</value>
</data>
<data name="&gt;&gt;bnComboBoxLosslessOrNot.Type" xml:space="preserve">
<value>BBBNOVA.BNComboBox, CUEControls, Version=2.0.7.0, Culture=neutral, PublicKeyToken=null</value>
<value>CUEControls.BNComboBox, CUEControls, Version=2.0.7.0, Culture=neutral, PublicKeyToken=null</value>
</data>
<data name="&gt;&gt;bnComboBoxLosslessOrNot.Parent" xml:space="preserve">
<value>groupBoxSettings</value>
@@ -494,19 +486,11 @@
<value>0</value>
</data>
<metadata name="encodersBindingSource.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>451, 456</value>
<value>189, 95</value>
</metadata>
<data name="bnComboBoxEncoder.Location" type="System.Drawing.Point, System.Drawing">
<value>92, 46</value>
</data>
<data name="bnComboBoxEncoder.Radius" mimetype="application/x-microsoft.net.object.binary.base64">
<value>
AAEAAAD/////AQAAAAAAAAAMAgAAAEJDVUVDb250cm9scywgVmVyc2lvbj0yLjAuNy4wLCBDdWx0dXJl
PW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPW51bGwFAQAAABBCQkJOT1ZBLkJOUmFkaXVzBAAAAAhfdG9w
TGVmdAlfdG9wUmlnaHQLX2JvdHRvbUxlZnQMX2JvdHRvbVJpZ2h0AAAAAAgICAgCAAAAAgAAAAYAAAAC
AAAAAgAAAAs=
</value>
</data>
<data name="bnComboBoxEncoder.Size" type="System.Drawing.Size, System.Drawing">
<value>80, 21</value>
</data>
@@ -517,7 +501,7 @@
<value>bnComboBoxEncoder</value>
</data>
<data name="&gt;&gt;bnComboBoxEncoder.Type" xml:space="preserve">
<value>BBBNOVA.BNComboBox, CUEControls, Version=2.0.7.0, Culture=neutral, PublicKeyToken=null</value>
<value>CUEControls.BNComboBox, CUEControls, Version=2.0.7.0, Culture=neutral, PublicKeyToken=null</value>
</data>
<data name="&gt;&gt;bnComboBoxEncoder.Parent" xml:space="preserve">
<value>groupBoxSettings</value>
@@ -553,19 +537,11 @@
<value>2</value>
</data>
<metadata name="formatsBindingSource.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>279, 456</value>
<value>17, 95</value>
</metadata>
<data name="bnComboBoxFormat.Location" type="System.Drawing.Point, System.Drawing">
<value>92, 19</value>
</data>
<data name="bnComboBoxFormat.Radius" mimetype="application/x-microsoft.net.object.binary.base64">
<value>
AAEAAAD/////AQAAAAAAAAAMAgAAAEJDVUVDb250cm9scywgVmVyc2lvbj0yLjAuNy4wLCBDdWx0dXJl
PW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPW51bGwFAQAAABBCQkJOT1ZBLkJOUmFkaXVzBAAAAAhfdG9w
TGVmdAlfdG9wUmlnaHQLX2JvdHRvbUxlZnQMX2JvdHRvbVJpZ2h0AAAAAAgICAgCAAAAAgAAAAYAAAAC
AAAAAgAAAAs=
</value>
</data>
<data name="bnComboBoxFormat.Size" type="System.Drawing.Size, System.Drawing">
<value>80, 21</value>
</data>
@@ -576,7 +552,7 @@
<value>bnComboBoxFormat</value>
</data>
<data name="&gt;&gt;bnComboBoxFormat.Type" xml:space="preserve">
<value>BBBNOVA.BNComboBox, CUEControls, Version=2.0.7.0, Culture=neutral, PublicKeyToken=null</value>
<value>CUEControls.BNComboBox, CUEControls, Version=2.0.7.0, Culture=neutral, PublicKeyToken=null</value>
</data>
<data name="&gt;&gt;bnComboBoxFormat.Parent" xml:space="preserve">
<value>groupBoxSettings</value>
@@ -624,19 +600,11 @@
<value>4</value>
</data>
<metadata name="cUEStylesBindingSource.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>642, 56</value>
<value>526, 56</value>
</metadata>
<data name="bnComboBoxImage.Location" type="System.Drawing.Point, System.Drawing">
<value>6, 46</value>
</data>
<data name="bnComboBoxImage.Radius" mimetype="application/x-microsoft.net.object.binary.base64">
<value>
AAEAAAD/////AQAAAAAAAAAMAgAAAEJDVUVDb250cm9scywgVmVyc2lvbj0yLjAuNy4wLCBDdWx0dXJl
PW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPW51bGwFAQAAABBCQkJOT1ZBLkJOUmFkaXVzBAAAAAhfdG9w
TGVmdAlfdG9wUmlnaHQLX2JvdHRvbUxlZnQMX2JvdHRvbVJpZ2h0AAAAAAgICAgCAAAAAgAAAAYAAAAC
AAAAAgAAAAs=
</value>
</data>
<data name="bnComboBoxImage.Size" type="System.Drawing.Size, System.Drawing">
<value>80, 21</value>
</data>
@@ -647,7 +615,7 @@
<value>bnComboBoxImage</value>
</data>
<data name="&gt;&gt;bnComboBoxImage.Type" xml:space="preserve">
<value>BBBNOVA.BNComboBox, CUEControls, Version=2.0.7.0, Culture=neutral, PublicKeyToken=null</value>
<value>CUEControls.BNComboBox, CUEControls, Version=2.0.7.0, Culture=neutral, PublicKeyToken=null</value>
</data>
<data name="&gt;&gt;bnComboBoxImage.Parent" xml:space="preserve">
<value>groupBoxSettings</value>
@@ -800,7 +768,58 @@
<value>$this</value>
</data>
<data name="&gt;&gt;groupBoxSettings.ZOrder" xml:space="preserve">
<value>8</value>
<value>7</value>
</data>
<metadata name="imageListChecked.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>207, 17</value>
</metadata>
<data name="imageListChecked.ImageStream" mimetype="application/x-microsoft.net.object.binary.base64">
<value>
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=
</value>
</data>
<data name="toolStripMenuItem1.Size" type="System.Drawing.Size, System.Drawing">
<value>181, 22</value>
@@ -809,19 +828,19 @@
<value>toolStripMenuItem1</value>
</data>
<metadata name="plainBackgroundPainter1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>979, 17</value>
<value>960, 17</value>
</metadata>
<metadata name="styledBorderPainter1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>643, 17</value>
<value>624, 17</value>
</metadata>
<data name="progressBarErrors.Location" type="System.Drawing.Point, System.Drawing">
<value>382, 421</value>
</data>
<metadata name="plainProgressPainter1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>473, 17</value>
<value>454, 17</value>
</metadata>
<metadata name="gradientGlossPainter1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>808, 17</value>
<value>789, 17</value>
</metadata>
<data name="progressBarErrors.Size" type="System.Drawing.Size, System.Drawing">
<value>177, 23</value>
@@ -839,7 +858,7 @@
<value>$this</value>
</data>
<data name="&gt;&gt;progressBarErrors.ZOrder" xml:space="preserve">
<value>6</value>
<value>5</value>
</data>
<data name="progressBarCD.Location" type="System.Drawing.Point, System.Drawing">
<value>382, 392</value>
@@ -866,34 +885,7 @@
<value>$this</value>
</data>
<data name="&gt;&gt;progressBarCD.ZOrder" xml:space="preserve">
<value>7</value>
</data>
<data name="comboBoxOutputFormat.Location" type="System.Drawing.Point, System.Drawing">
<value>6, 170</value>
</data>
<data name="comboBoxOutputFormat.MaxDropDownItems" type="System.Int32, mscorlib">
<value>10</value>
</data>
<data name="comboBoxOutputFormat.Size" type="System.Drawing.Size, System.Drawing">
<value>553, 21</value>
</data>
<data name="comboBoxOutputFormat.TabIndex" type="System.Int32, mscorlib">
<value>32</value>
</data>
<data name="comboBoxOutputFormat.ToolTip" xml:space="preserve">
<value>Template for output files (foobar2000 format)</value>
</data>
<data name="&gt;&gt;comboBoxOutputFormat.Name" xml:space="preserve">
<value>comboBoxOutputFormat</value>
</data>
<data name="&gt;&gt;comboBoxOutputFormat.Type" xml:space="preserve">
<value>System.Windows.Forms.ComboBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;comboBoxOutputFormat.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;comboBoxOutputFormat.ZOrder" xml:space="preserve">
<value>5</value>
<value>6</value>
</data>
<data name="txtOutputPath.Location" type="System.Drawing.Point, System.Drawing">
<value>7, 61</value>
@@ -920,7 +912,7 @@
<value>1</value>
</data>
<metadata name="releasesBindingSource.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>824, 56</value>
<value>708, 56</value>
</metadata>
<metadata name="imageListMetadataSource.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 56</value>
@@ -974,14 +966,6 @@
<data name="bnComboBoxRelease.Location" type="System.Drawing.Point, System.Drawing">
<value>6, 33</value>
</data>
<data name="bnComboBoxRelease.Radius" mimetype="application/x-microsoft.net.object.binary.base64">
<value>
AAEAAAD/////AQAAAAAAAAAMAgAAAEJDVUVDb250cm9scywgVmVyc2lvbj0yLjAuNy4wLCBDdWx0dXJl
PW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPW51bGwFAQAAABBCQkJOT1ZBLkJOUmFkaXVzBAAAAAhfdG9w
TGVmdAlfdG9wUmlnaHQLX2JvdHRvbUxlZnQMX2JvdHRvbVJpZ2h0AAAAAAgICAgCAAAAAgAAAAYAAAAC
AAAAAgAAAAs=
</value>
</data>
<data name="bnComboBoxRelease.Size" type="System.Drawing.Size, System.Drawing">
<value>552, 21</value>
</data>
@@ -995,7 +979,7 @@
<value>bnComboBoxRelease</value>
</data>
<data name="&gt;&gt;bnComboBoxRelease.Type" xml:space="preserve">
<value>BBBNOVA.BNComboBox, CUEControls, Version=2.0.7.0, Culture=neutral, PublicKeyToken=null</value>
<value>CUEControls.BNComboBox, CUEControls, Version=2.0.7.0, Culture=neutral, PublicKeyToken=null</value>
</data>
<data name="&gt;&gt;bnComboBoxRelease.Parent" xml:space="preserve">
<value>$this</value>
@@ -1004,19 +988,11 @@
<value>2</value>
</data>
<metadata name="drivesBindingSource.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>116, 456</value>
<value>998, 56</value>
</metadata>
<data name="bnComboBoxDrives.Location" type="System.Drawing.Point, System.Drawing">
<value>6, 6</value>
</data>
<data name="bnComboBoxDrives.Radius" mimetype="application/x-microsoft.net.object.binary.base64">
<value>
AAEAAAD/////AQAAAAAAAAAMAgAAAEJDVUVDb250cm9scywgVmVyc2lvbj0yLjAuNy4wLCBDdWx0dXJl
PW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPW51bGwFAQAAABBCQkJOT1ZBLkJOUmFkaXVzBAAAAAhfdG9w
TGVmdAlfdG9wUmlnaHQLX2JvdHRvbUxlZnQMX2JvdHRvbVJpZ2h0AAAAAAgICAgCAAAAAgAAAAYAAAAC
AAAAAgAAAAs=
</value>
</data>
<data name="bnComboBoxDrives.Size" type="System.Drawing.Size, System.Drawing">
<value>552, 21</value>
</data>
@@ -1027,7 +1003,7 @@
<value>bnComboBoxDrives</value>
</data>
<data name="&gt;&gt;bnComboBoxDrives.Type" xml:space="preserve">
<value>BBBNOVA.BNComboBox, CUEControls, Version=2.0.7.0, Culture=neutral, PublicKeyToken=null</value>
<value>CUEControls.BNComboBox, CUEControls, Version=2.0.7.0, Culture=neutral, PublicKeyToken=null</value>
</data>
<data name="&gt;&gt;bnComboBoxDrives.Parent" xml:space="preserve">
<value>$this</value>
@@ -1038,14 +1014,6 @@
<data name="bnComboBoxOutputFormat.Location" type="System.Drawing.Point, System.Drawing">
<value>6, 60</value>
</data>
<data name="bnComboBoxOutputFormat.Radius" mimetype="application/x-microsoft.net.object.binary.base64">
<value>
AAEAAAD/////AQAAAAAAAAAMAgAAAEJDVUVDb250cm9scywgVmVyc2lvbj0yLjAuNy4wLCBDdWx0dXJl
PW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPW51bGwFAQAAABBCQkJOT1ZBLkJOUmFkaXVzBAAAAAhfdG9w
TGVmdAlfdG9wUmlnaHQLX2JvdHRvbUxlZnQMX2JvdHRvbVJpZ2h0AAAAAAgICAgCAAAAAgAAAAYAAAAC
AAAAAgAAAAs=
</value>
</data>
<data name="bnComboBoxOutputFormat.Size" type="System.Drawing.Size, System.Drawing">
<value>552, 21</value>
</data>
@@ -1056,7 +1024,7 @@
<value>bnComboBoxOutputFormat</value>
</data>
<data name="&gt;&gt;bnComboBoxOutputFormat.Type" xml:space="preserve">
<value>BBBNOVA.BNComboBox, CUEControls, Version=2.0.7.0, Culture=neutral, PublicKeyToken=null</value>
<value>CUEControls.BNComboBox, CUEControls, Version=2.0.7.0, Culture=neutral, PublicKeyToken=null</value>
</data>
<data name="&gt;&gt;bnComboBoxOutputFormat.Parent" xml:space="preserve">
<value>$this</value>
@@ -1575,6 +1543,12 @@
<data name="&gt;&gt;cUEStylesBindingSource.Type" xml:space="preserve">
<value>System.Windows.Forms.BindingSource, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;imageListChecked.Name" xml:space="preserve">
<value>imageListChecked</value>
</data>
<data name="&gt;&gt;imageListChecked.Type" xml:space="preserve">
<value>System.Windows.Forms.ImageList, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;toolStripMenuItem1.Name" xml:space="preserve">
<value>toolStripMenuItem1</value>
</data>

View File

@@ -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
{

View File

@@ -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();

View File

@@ -0,0 +1,110 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{FAD09EE2-D6B2-4A8E-9F1C-2A9FB293661A}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>CUETools.Codecs.CoreAudio</RootNamespace>
<AssemblyName>CUETools.Codecs.CoreAudio</AssemblyName>
<TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>..\bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="CoreAudioApi\AudioCaptureClient.cs" />
<Compile Include="CoreAudioApi\AudioClient.cs" />
<Compile Include="CoreAudioApi\AudioClientBufferFlags.cs" />
<Compile Include="CoreAudioApi\AudioClientShareMode.cs" />
<Compile Include="CoreAudioApi\AudioClientStreamFlags.cs" />
<Compile Include="CoreAudioApi\AudioEndpointVolume.cs" />
<Compile Include="CoreAudioApi\AudioEndpointVolumeCallback.cs" />
<Compile Include="CoreAudioApi\AudioEndpointVolumeChannel.cs" />
<Compile Include="CoreAudioApi\AudioEndpointVolumeChannels.cs" />
<Compile Include="CoreAudioApi\AudioEndpointVolumeNotificationDelegate.cs" />
<Compile Include="CoreAudioApi\AudioEndpointVolumeStepInformation.cs" />
<Compile Include="CoreAudioApi\AudioEndpointVolumeVolumeRange.cs" />
<Compile Include="CoreAudioApi\AudioMeterInformation.cs" />
<Compile Include="CoreAudioApi\AudioMeterInformationChannels.cs" />
<Compile Include="CoreAudioApi\AudioRenderClient.cs" />
<Compile Include="CoreAudioApi\AudioVolumeNotificationData.cs" />
<Compile Include="CoreAudioApi\DataFlow.cs" />
<Compile Include="CoreAudioApi\DeviceState.cs" />
<Compile Include="CoreAudioApi\EEndpointHardwareSupport.cs" />
<Compile Include="CoreAudioApi\Interfaces\AudioVolumeNotificationDataStruct.cs" />
<Compile Include="CoreAudioApi\Interfaces\Blob.cs" />
<Compile Include="CoreAudioApi\Interfaces\ClsCtx.cs" />
<Compile Include="CoreAudioApi\Interfaces\ErrorCodes.cs" />
<Compile Include="CoreAudioApi\Interfaces\IAudioCaptureClient.cs" />
<Compile Include="CoreAudioApi\Interfaces\IAudioClient.cs" />
<Compile Include="CoreAudioApi\Interfaces\IAudioEndpointVolume.cs" />
<Compile Include="CoreAudioApi\Interfaces\IAudioEndpointVolumeCallback.cs" />
<Compile Include="CoreAudioApi\Interfaces\IAudioMeterInformation.cs" />
<Compile Include="CoreAudioApi\Interfaces\IAudioRenderClient.cs" />
<Compile Include="CoreAudioApi\Interfaces\IMMDevice.cs" />
<Compile Include="CoreAudioApi\Interfaces\IMMDeviceCollection.cs" />
<Compile Include="CoreAudioApi\Interfaces\IMMDeviceEnumerator.cs" />
<Compile Include="CoreAudioApi\Interfaces\IMMEndpoint.cs" />
<Compile Include="CoreAudioApi\Interfaces\IMMNotificationClient.cs" />
<Compile Include="CoreAudioApi\Interfaces\IPropertyStore.cs" />
<Compile Include="CoreAudioApi\Interfaces\MMDeviceEnumeratorComObject.cs" />
<Compile Include="CoreAudioApi\Interfaces\StorageAccessMode.cs" />
<Compile Include="CoreAudioApi\MMDevice.cs" />
<Compile Include="CoreAudioApi\MMDeviceCollection.cs" />
<Compile Include="CoreAudioApi\MMDeviceEnumerator.cs" />
<Compile Include="CoreAudioApi\PropertyKey.cs" />
<Compile Include="CoreAudioApi\PropertyKeys.cs" />
<Compile Include="CoreAudioApi\PropertyStore.cs" />
<Compile Include="CoreAudioApi\PropertyStoreProperty.cs" />
<Compile Include="CoreAudioApi\PropVariant.cs" />
<Compile Include="CoreAudioApi\Role.cs" />
<Compile Include="IWavePlayer.cs" />
<Compile Include="PlaybackState.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="WasapiOut.cs" />
<Compile Include="WaveFormats\AdpcmWaveFormat.cs" />
<Compile Include="WaveFormats\AudioMediaSubtypes.cs" />
<Compile Include="WaveFormats\WaveFormat.cs" />
<Compile Include="WaveFormats\WaveFormatEncoding.cs" />
<Compile Include="WaveFormats\WaveFormatExtensible.cs" />
<Compile Include="WaveFormats\WaveFormatExtraData.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\CUETools.Codecs\CUETools.Codecs.csproj">
<Project>{6458A13A-30EF-45A9-9D58-E5031B17BEE2}</Project>
<Name>CUETools.Codecs</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@@ -0,0 +1,91 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using NAudio.CoreAudioApi.Interfaces;
namespace NAudio.CoreAudioApi
{
/// <summary>
/// Audio Capture Client
/// </summary>
public class AudioCaptureClient : IDisposable
{
IAudioCaptureClient audioCaptureClientInterface;
internal AudioCaptureClient(IAudioCaptureClient audioCaptureClientInterface)
{
this.audioCaptureClientInterface = audioCaptureClientInterface;
}
/// <summary>
/// Gets a pointer to the buffer
/// </summary>
/// <returns>Pointer to the buffer</returns>
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;
}
/// <summary>
/// Gets a pointer to the buffer
/// </summary>
/// <param name="numFramesToRead">Number of frames to read</param>
/// <param name="bufferFlags">Buffer flags</param>
/// <returns>Pointer to the buffer</returns>
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;
}
/// <summary>
/// Gets the size of the next packet
/// </summary>
public int GetNextPacketSize()
{
int numFramesInNextPacket;
Marshal.ThrowExceptionForHR(audioCaptureClientInterface.GetNextPacketSize(out numFramesInNextPacket));
return numFramesInNextPacket;
}
/// <summary>
/// Release buffer
/// </summary>
/// <param name="numFramesWritten">Number of frames written</param>
public void ReleaseBuffer(int numFramesWritten)
{
Marshal.ThrowExceptionForHR(audioCaptureClientInterface.ReleaseBuffer(numFramesWritten));
}
#region IDisposable Members
/// <summary>
/// Release the COM object
/// </summary>
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
}
}

View File

@@ -0,0 +1,296 @@
using System;
using System.Threading;
using NAudio.CoreAudioApi.Interfaces;
using System.Runtime.InteropServices;
using NAudio.Wave;
namespace NAudio.CoreAudioApi
{
/// <summary>
/// Windows Vista CoreAudio AudioClient
/// </summary>
public class AudioClient : IDisposable
{
IAudioClient audioClientInterface;
WaveFormat mixFormat;
AudioRenderClient audioRenderClient;
AudioCaptureClient audioCaptureClient;
internal AudioClient(IAudioClient audioClientInterface)
{
this.audioClientInterface = audioClientInterface;
}
/// <summary>
/// Mix Format,
/// Can be called before initialize
/// </summary>
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;
}
}
}
/// <summary>
/// Initialize the Audio Client
/// </summary>
/// <param name="shareMode">Share Mode</param>
/// <param name="streamFlags">Stream Flags</param>
/// <param name="bufferDuration">Buffer Duration</param>
/// <param name="periodicity">Periodicity</param>
/// <param name="waveFormat">Wave Format</param>
/// <param name="audioSessionGuid">Audio Session GUID (can be null)</param>
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;
}
/// <summary>
/// Gets the buffer size (must initialize first)
/// </summary>
public int BufferSize
{
get
{
uint bufferSize;
audioClientInterface.GetBufferSize(out bufferSize);
return (int) bufferSize;
}
}
/// <summary>
/// Gets the stream latency (must initialize first)
/// </summary>
public long StreamLatency
{
get
{
return audioClientInterface.GetStreamLatency();
}
}
/// <summary>
/// Gets the current padding (must initialize first)
/// </summary>
public int CurrentPadding
{
get
{
int currentPadding;
audioClientInterface.GetCurrentPadding(out currentPadding);
return currentPadding;
}
}
/// <summary>
/// Gets the default device period (can be called before initialize)
/// </summary>
public long DefaultDevicePeriod
{
get
{
long defaultDevicePeriod;
long minimumDevicePeriod;
audioClientInterface.GetDevicePeriod(out defaultDevicePeriod, out minimumDevicePeriod);
return defaultDevicePeriod;
}
}
/// <summary>
/// Gets the minimum device period (can be called before initialize)
/// </summary>
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
/// <summary>
/// Gets the AudioRenderClient service
/// </summary>
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;
}
}
/// <summary>
/// Gets the AudioCaptureClient service
/// </summary>
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;
}
}
/// <summary>
/// Determines whether if the specified output format is supported
/// </summary>
/// <param name="shareMode">The share mode.</param>
/// <param name="desiredFormat">The desired format.</param>
/// <returns>
/// <c>true</c> if [is format supported] [the specified share mode]; otherwise, <c>false</c>.
/// </returns>
public bool IsFormatSupported(AudioClientShareMode shareMode,
WaveFormat desiredFormat)
{
WaveFormatExtensible closestMatchFormat;
return IsFormatSupported(shareMode, desiredFormat, out closestMatchFormat);
}
/// <summary>
/// Determines if the specified output format is supported in shared mode
/// </summary>
/// <param name="shareMode">Share Mode</param>
/// <param name="desiredFormat">Desired Format</param>
/// <param name="closestMatchFormat">Output The closest match format.</param>
/// <returns>
/// <c>true</c> if [is format supported] [the specified share mode]; otherwise, <c>false</c>.
/// </returns>
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());
}
/// <summary>
/// Starts the audio stream
/// </summary>
public void Start()
{
audioClientInterface.Start();
}
/// <summary>
/// Stops the audio stream.
/// </summary>
public void Stop()
{
audioClientInterface.Stop();
}
/// <summary>
/// Set the Event Handle for buffer synchro.
/// </summary>
/// <param name="eventWaitHandle">The Wait Handle to setup</param>
public void SetEventHandle(EventWaitHandle eventWaitHandle)
{
audioClientInterface.SetEventHandle(eventWaitHandle.SafeWaitHandle.DangerousGetHandle());
}
/// <summary>
/// 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
/// </summary>
public void Reset()
{
audioClientInterface.Reset();
}
#region IDisposable Members
/// <summary>
/// Dispose
/// </summary>
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
}
}

View File

@@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace NAudio.CoreAudioApi
{
/// <summary>
/// Audio Client Buffer Flags
/// </summary>
[Flags]
public enum AudioClientBufferFlags
{
/// <summary>
/// None
/// </summary>
None,
/// <summary>
/// AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY
/// </summary>
DataDiscontinuity = 0x1,
/// <summary>
/// AUDCLNT_BUFFERFLAGS_SILENT
/// </summary>
Silent = 0x2,
/// <summary>
/// AUDCLNT_BUFFERFLAGS_TIMESTAMP_ERROR
/// </summary>
TimestampError = 0x4
}
}

View File

@@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace NAudio.CoreAudioApi
{
/// <summary>
/// AUDCLNT_SHAREMODE
/// </summary>
public enum AudioClientShareMode
{
/// <summary>
/// AUDCLNT_SHAREMODE_SHARED,
/// </summary>
Shared,
/// <summary>
/// AUDCLNT_SHAREMODE_EXCLUSIVE
/// </summary>
Exclusive,
}
}

View File

@@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace NAudio.CoreAudioApi
{
/// <summary>
/// AUDCLNT_STREAMFLAGS
/// </summary>
[Flags]
public enum AudioClientStreamFlags
{
/// <summary>
/// None
/// </summary>
None,
/// <summary>
/// AUDCLNT_STREAMFLAGS_CROSSPROCESS
/// </summary>
CrossProcess = 0x00010000,
/// <summary>
/// AUDCLNT_STREAMFLAGS_LOOPBACK
/// </summary>
Loopback = 0x00020000,
/// <summary>
/// AUDCLNT_STREAMFLAGS_EVENTCALLBACK
/// </summary>
EventCallback = 0x00040000,
/// <summary>
/// AUDCLNT_STREAMFLAGS_NOPERSIST
/// </summary>
NoPersist = 0x00080000,
}
}

View File

@@ -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
{
/// <summary>
/// Audio Endpoint Volume
/// </summary>
public class AudioEndpointVolume : IDisposable
{
private IAudioEndpointVolume _AudioEndPointVolume;
private AudioEndpointVolumeChannels _Channels;
private AudioEndpointVolumeStepInformation _StepInformation;
private AudioEndpointVolumeVolumeRange _VolumeRange;
private EEndpointHardwareSupport _HardwareSupport;
private AudioEndpointVolumeCallback _CallBack;
/// <summary>
/// On Volume Notification
/// </summary>
public event AudioEndpointVolumeNotificationDelegate OnVolumeNotification;
/// <summary>
/// Volume Range
/// </summary>
public AudioEndpointVolumeVolumeRange VolumeRange
{
get
{
return _VolumeRange;
}
}
/// <summary>
/// Hardware Support
/// </summary>
public EEndpointHardwareSupport HardwareSupport
{
get
{
return _HardwareSupport;
}
}
/// <summary>
/// Step Information
/// </summary>
public AudioEndpointVolumeStepInformation StepInformation
{
get
{
return _StepInformation;
}
}
/// <summary>
/// Channels
/// </summary>
public AudioEndpointVolumeChannels Channels
{
get
{
return _Channels;
}
}
/// <summary>
/// Master Volume Level
/// </summary>
public float MasterVolumeLevel
{
get
{
float result;
Marshal.ThrowExceptionForHR(_AudioEndPointVolume.GetMasterVolumeLevel(out result));
return result;
}
set
{
Marshal.ThrowExceptionForHR(_AudioEndPointVolume.SetMasterVolumeLevel(value, Guid.Empty));
}
}
/// <summary>
/// Master Volume Level Scalar
/// </summary>
public float MasterVolumeLevelScalar
{
get
{
float result;
Marshal.ThrowExceptionForHR(_AudioEndPointVolume.GetMasterVolumeLevelScalar(out result));
return result;
}
set
{
Marshal.ThrowExceptionForHR(_AudioEndPointVolume.SetMasterVolumeLevelScalar(value, Guid.Empty));
}
}
/// <summary>
/// Mute
/// </summary>
public bool Mute
{
get
{
bool result;
Marshal.ThrowExceptionForHR(_AudioEndPointVolume.GetMute(out result));
return result;
}
set
{
Marshal.ThrowExceptionForHR(_AudioEndPointVolume.SetMute(value, Guid.Empty));
}
}
/// <summary>
/// Volume Step Up
/// </summary>
public void VolumeStepUp()
{
Marshal.ThrowExceptionForHR(_AudioEndPointVolume.VolumeStepUp(Guid.Empty));
}
/// <summary>
/// Volume Step Down
/// </summary>
public void VolumeStepDown()
{
Marshal.ThrowExceptionForHR(_AudioEndPointVolume.VolumeStepDown(Guid.Empty));
}
/// <summary>
/// Creates a new Audio endpoint volume
/// </summary>
/// <param name="realEndpointVolume">IAudioEndpointVolume COM interface</param>
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
/// <summary>
/// Dispose
/// </summary>
public void Dispose()
{
if (_CallBack != null)
{
Marshal.ThrowExceptionForHR(_AudioEndPointVolume.UnregisterControlChangeNotify(_CallBack));
_CallBack = null;
}
GC.SuppressFinalize(this);
}
/// <summary>
/// Finalizer
/// </summary>
~AudioEndpointVolume()
{
Dispose();
}
#endregion
}
}

View File

@@ -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);
}
}
}

View File

@@ -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
{
/// <summary>
/// Audio Endpoint Volume Channel
/// </summary>
public class AudioEndpointVolumeChannel
{
private uint _Channel;
private IAudioEndpointVolume _AudioEndpointVolume;
internal AudioEndpointVolumeChannel(IAudioEndpointVolume parent, int channel)
{
_Channel = (uint)channel;
_AudioEndpointVolume = parent;
}
/// <summary>
/// Volume Level
/// </summary>
public float VolumeLevel
{
get
{
float result;
Marshal.ThrowExceptionForHR(_AudioEndpointVolume.GetChannelVolumeLevel(_Channel,out result));
return result;
}
set
{
Marshal.ThrowExceptionForHR(_AudioEndpointVolume.SetChannelVolumeLevel(_Channel, value,Guid.Empty));
}
}
/// <summary>
/// Volume Level Scalar
/// </summary>
public float VolumeLevelScalar
{
get
{
float result;
Marshal.ThrowExceptionForHR(_AudioEndpointVolume.GetChannelVolumeLevelScalar(_Channel, out result));
return result;
}
set
{
Marshal.ThrowExceptionForHR(_AudioEndpointVolume.SetChannelVolumeLevelScalar(_Channel, value, Guid.Empty));
}
}
}
}

View File

@@ -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
{
/// <summary>
/// Audio Endpoint Volume Channels
/// </summary>
public class AudioEndpointVolumeChannels
{
IAudioEndpointVolume _AudioEndPointVolume;
AudioEndpointVolumeChannel[] _Channels;
/// <summary>
/// Channel Count
/// </summary>
public int Count
{
get
{
int result;
Marshal.ThrowExceptionForHR(_AudioEndPointVolume.GetChannelCount(out result));
return result;
}
}
/// <summary>
/// Indexer - get a specific channel
/// </summary>
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);
}
}
}
}

View File

@@ -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
{
/// <summary>
/// Audio Endpoint Volume Notifiaction Delegate
/// </summary>
/// <param name="data">Audio Volume Notification Data</param>
public delegate void AudioEndpointVolumeNotificationDelegate( AudioVolumeNotificationData data);
}

View File

@@ -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
{
/// <summary>
/// Audio Endpoint Volume Step Information
/// </summary>
public class AudioEndpointVolumeStepInformation
{
private uint _Step;
private uint _StepCount;
internal AudioEndpointVolumeStepInformation(IAudioEndpointVolume parent)
{
Marshal.ThrowExceptionForHR(parent.GetVolumeStepInfo(out _Step, out _StepCount));
}
/// <summary>
/// Step
/// </summary>
public uint Step
{
get
{
return _Step;
}
}
/// <summary>
/// StepCount
/// </summary>
public uint StepCount
{
get
{
return _StepCount;
}
}
}
}

View File

@@ -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
{
/// <summary>
/// Audio Endpoint Volume Volume Range
/// </summary>
public class AudioEndpointVolumeVolumeRange
{
float _VolumeMindB;
float _VolumeMaxdB;
float _VolumeIncrementdB;
internal AudioEndpointVolumeVolumeRange(IAudioEndpointVolume parent)
{
Marshal.ThrowExceptionForHR(parent.GetVolumeRange(out _VolumeMindB,out _VolumeMaxdB,out _VolumeIncrementdB));
}
/// <summary>
/// Minimum Decibels
/// </summary>
public float MinDecibels
{
get
{
return _VolumeMindB;
}
}
/// <summary>
/// Maximum Decibels
/// </summary>
public float MaxDecibels
{
get
{
return _VolumeMaxdB;
}
}
/// <summary>
/// Increment Decibels
/// </summary>
public float IncrementDecibels
{
get
{
return _VolumeIncrementdB;
}
}
}
}

View File

@@ -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
{
/// <summary>
/// Audio Meter Information
/// </summary>
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);
}
/// <summary>
/// Peak Values
/// </summary>
public AudioMeterInformationChannels PeakValues
{
get
{
return _Channels;
}
}
/// <summary>
/// Hardware Support
/// </summary>
public EEndpointHardwareSupport HardwareSupport
{
get
{
return _HardwareSupport;
}
}
/// <summary>
/// Master Peak Value
/// </summary>
public float MasterPeakValue
{
get
{
float result;
Marshal.ThrowExceptionForHR(_AudioMeterInformation.GetPeakValue(out result));
return result;
}
}
}
}

View File

@@ -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
{
/// <summary>
/// Audio Meter Information Channels
/// </summary>
public class AudioMeterInformationChannels
{
IAudioMeterInformation _AudioMeterInformation;
/// <summary>
/// Metering Channel Count
/// </summary>
public int Count
{
get
{
int result;
Marshal.ThrowExceptionForHR(_AudioMeterInformation.GetMeteringChannelCount(out result));
return result;
}
}
/// <summary>
/// Get Peak value
/// </summary>
/// <param name="index">Channel index</param>
/// <returns>Peak value</returns>
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;
}
}
}

View File

@@ -0,0 +1,60 @@
using System;
using System.Collections.Generic;
using System.Text;
using NAudio.CoreAudioApi.Interfaces;
using System.Runtime.InteropServices;
namespace NAudio.CoreAudioApi
{
/// <summary>
/// Audio Render Client
/// </summary>
public class AudioRenderClient : IDisposable
{
IAudioRenderClient audioRenderClientInterface;
internal AudioRenderClient(IAudioRenderClient audioRenderClientInterface)
{
this.audioRenderClientInterface = audioRenderClientInterface;
}
/// <summary>
/// Gets a pointer to the buffer
/// </summary>
/// <param name="numFramesRequested">Number of frames requested</param>
/// <returns>Pointer to the buffer</returns>
public IntPtr GetBuffer(int numFramesRequested)
{
return audioRenderClientInterface.GetBuffer(numFramesRequested);
}
/// <summary>
/// Release buffer
/// </summary>
/// <param name="numFramesWritten">Number of frames written</param>
/// <param name="bufferFlags">Buffer flags</param>
public void ReleaseBuffer(int numFramesWritten,AudioClientBufferFlags bufferFlags)
{
audioRenderClientInterface.ReleaseBuffer(numFramesWritten, bufferFlags);
}
#region IDisposable Members
/// <summary>
/// Release the COM object
/// </summary>
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
}
}

View File

@@ -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
{
/// <summary>
/// Audio Volume Notification Data
/// </summary>
public class AudioVolumeNotificationData
{
private Guid _EventContext;
private bool _Muted;
private float _MasterVolume;
private int _Channels;
private float[] _ChannelVolume;
/// <summary>
/// Event Context
/// </summary>
public Guid EventContext
{
get
{
return _EventContext;
}
}
/// <summary>
/// Muted
/// </summary>
public bool Muted
{
get
{
return _Muted;
}
}
/// <summary>
/// Master Volume
/// </summary>
public float MasterVolume
{
get
{
return _MasterVolume;
}
}
/// <summary>
/// Channels
/// </summary>
public int Channels
{
get
{
return _Channels;
}
}
/// <summary>
/// Channel Volume
/// </summary>
public float[] ChannelVolume
{
get
{
return _ChannelVolume;
}
}
/// <summary>
/// Audio Volume Notification Data
/// </summary>
/// <param name="eventContext"></param>
/// <param name="muted"></param>
/// <param name="masterVolume"></param>
/// <param name="channelVolume"></param>
public AudioVolumeNotificationData(Guid eventContext, bool muted, float masterVolume, float[] channelVolume)
{
_EventContext = eventContext;
_Muted = muted;
_MasterVolume = masterVolume;
_Channels = channelVolume.Length;
_ChannelVolume = channelVolume;
}
/// <summary>
/// Audio Volume Notification Data
/// </summary>
/// <param name="eventContext"></param>
/// <param name="muted"></param>
/// <param name="masterVolume"></param>
/// <param name="channels"></param>
public AudioVolumeNotificationData(Guid eventContext, bool muted, float masterVolume)
{
_EventContext = eventContext;
_Muted = muted;
_MasterVolume = masterVolume;
}
}
}

View File

@@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace NAudio.CoreAudioApi
{
/// <summary>
/// The EDataFlow enumeration defines constants that indicate the direction
/// in which audio data flows between an audio endpoint device and an application
/// </summary>
public enum DataFlow
{
/// <summary>
/// Audio rendering stream.
/// Audio data flows from the application to the audio endpoint device, which renders the stream.
/// </summary>
Render,
/// <summary>
/// Audio capture stream. Audio data flows from the audio endpoint device that captures the stream,
/// to the application
/// </summary>
Capture,
/// <summary>
/// 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.
/// </summary>
All
};
}

View File

@@ -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
{
/// <summary>
/// Device State
/// </summary>
[Flags]
public enum DeviceState
{
/// <summary>
/// DEVICE_STATE_ACTIVE
/// </summary>
Active = 0x00000001,
/// <summary>
/// DEVICE_STATE_UNPLUGGED
/// </summary>
Unplugged = 0x00000002,
/// <summary>
/// DEVICE_STATE_NOTPRESENT
/// </summary>
NotPresent = 0x00000004,
/// <summary>
/// DEVICE_STATEMASK_ALL
/// </summary>
All = 0x00000007
}
}

View File

@@ -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
{
/// <summary>
/// Endpoint Hardware Support
/// </summary>
[Flags]
public enum EEndpointHardwareSupport
{
/// <summary>
/// Volume
/// </summary>
Volume = 0x00000001,
/// <summary>
/// Mute
/// </summary>
Mute = 0x00000002,
/// <summary>
/// Meter
/// </summary>
Meter = 0x00000004
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace NAudio.CoreAudioApi.Interfaces
{
/// <summary>
/// is defined in WTypes.h
/// </summary>
[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
}
}

View File

@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace NAudio.CoreAudioApi.Interfaces
{
enum AudioClientErrors
{
/// <summary>
/// AUDCLNT_E_NOT_INITIALIZED
/// </summary>
NotInitialized = unchecked((int)0x88890001),
/// <summary>
/// AUDCLNT_E_UNSUPPORTED_FORMAT
/// </summary>
UnsupportedFormat = unchecked((int)0x88890008),
/// <summary>
/// AUDCLNT_E_DEVICE_IN_USE
/// </summary>
DeviceInUse = unchecked((int)0x8889000A),
}
}

View File

@@ -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);
}
}

View File

@@ -0,0 +1,53 @@
using System;
using System.Runtime.InteropServices;
using NAudio.Wave;
namespace NAudio.CoreAudioApi.Interfaces
{
/// <summary>
/// n.b. WORK IN PROGRESS - this code will probably do nothing but crash at the moment
/// Defined in AudioClient.h
/// </summary>
[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);
/// <summary>
/// The GetBufferSize method retrieves the size (maximum capacity) of the endpoint buffer.
/// </summary>
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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
};
}

View File

@@ -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);
};
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace NAudio.CoreAudioApi.Interfaces
{
/// <summary>
/// defined in MMDeviceAPI.h
/// </summary>
[Guid("1BE09788-6894-4089-8586-9A2A6C265AC5"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IMMEndpoint
{
int GetDataFlow(out DataFlow dataFlow);
}
}

View File

@@ -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);
}
}

View File

@@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace NAudio.CoreAudioApi.Interfaces
{
/// <summary>
/// is defined in propsys.h
/// </summary>
[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();
}
}

View File

@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace NAudio.CoreAudioApi.Interfaces
{
/// <summary>
/// implements IMMDeviceEnumerator
/// </summary>
[ComImport, Guid("BCDE0395-E52F-467C-8E3D-C4579291692E")]
class MMDeviceEnumeratorComObject
{
}
}

View File

@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace NAudio.CoreAudioApi.Interfaces
{
/// <summary>
/// MMDevice STGM enumeration
/// </summary>
enum StorageAccessMode
{
Read,
Write,
ReadWrite
}
}

View File

@@ -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
{
/// <summary>
/// MM Device
/// </summary>
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
/// <summary>
/// Audio Client
/// </summary>
public AudioClient AudioClient
{
get
{
if (audioClient == null)
{
GetAudioClientInterface();
}
return audioClient;
}
}
/// <summary>
/// Audio Meter Information
/// </summary>
public AudioMeterInformation AudioMeterInformation
{
get
{
if (_AudioMeterInformation == null)
GetAudioMeterInformation();
return _AudioMeterInformation;
}
}
/// <summary>
/// Audio Endpoint Volume
/// </summary>
public AudioEndpointVolume AudioEndpointVolume
{
get
{
if (_AudioEndpointVolume == null)
GetAudioEndpointVolume();
return _AudioEndpointVolume;
}
}
/// <summary>
/// Properties
/// </summary>
public PropertyStore Properties
{
get
{
if (_PropertyStore == null)
GetPropertyInformation();
return _PropertyStore;
}
}
/// <summary>
/// Friendly name
/// </summary>
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";
}
}
/// <summary>
/// Device ID
/// </summary>
public string ID
{
get
{
string Result;
Marshal.ThrowExceptionForHR(deviceInterface.GetId(out Result));
return Result;
}
}
/// <summary>
/// Data Flow
/// </summary>
public DataFlow DataFlow
{
get
{
DataFlow Result;
IMMEndpoint ep = deviceInterface as IMMEndpoint;
ep.GetDataFlow(out Result);
return Result;
}
}
/// <summary>
/// Device State
/// </summary>
public DeviceState State
{
get
{
DeviceState Result;
Marshal.ThrowExceptionForHR(deviceInterface.GetState(out Result));
return Result;
}
}
#endregion
#region Constructor
internal MMDevice(IMMDevice realDevice)
{
deviceInterface = realDevice;
}
#endregion
/// <summary>
/// To string
/// </summary>
public override string ToString()
{
return FriendlyName;
}
}
}

View File

@@ -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
{
/// <summary>
/// Multimedia Device Collection
/// </summary>
public class MMDeviceCollection : IEnumerable<MMDevice>
{
private IMMDeviceCollection _MMDeviceCollection;
/// <summary>
/// Device count
/// </summary>
public int Count
{
get
{
int result;
Marshal.ThrowExceptionForHR(_MMDeviceCollection.GetCount(out result));
return result;
}
}
/// <summary>
/// Get device by index
/// </summary>
/// <param name="index">Device index</param>
/// <returns>Device at the specified index</returns>
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<MMDevice> Members
/// <summary>
/// Get Enumerator
/// </summary>
/// <returns>Device enumerator</returns>
public IEnumerator<MMDevice> 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
}
}

View File

@@ -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
{
/// <summary>
/// MM Device Enumerator
/// </summary>
public class MMDeviceEnumerator
{
private IMMDeviceEnumerator _realEnumerator;
/// <summary>
/// Enumerate Audio Endpoints
/// </summary>
/// <param name="dataFlow">Desired DataFlow</param>
/// <param name="dwStateMask">State Mask</param>
/// <returns>Device Collection</returns>
public MMDeviceCollection EnumerateAudioEndPoints(DataFlow dataFlow, DeviceState dwStateMask)
{
IMMDeviceCollection result;
Marshal.ThrowExceptionForHR(_realEnumerator.EnumAudioEndpoints(dataFlow, dwStateMask, out result));
return new MMDeviceCollection(result);
}
/// <summary>
/// Get Default Endpoint
/// </summary>
/// <param name="dataFlow">Data Flow</param>
/// <param name="role">Role</param>
/// <returns>Device</returns>
public MMDevice GetDefaultAudioEndpoint(DataFlow dataFlow, Role role)
{
IMMDevice _Device = null;
Marshal.ThrowExceptionForHR(((IMMDeviceEnumerator)_realEnumerator).GetDefaultAudioEndpoint(dataFlow, role, out _Device));
return new MMDevice(_Device);
}
/// <summary>
/// Get device by ID
/// </summary>
/// <param name="ID">Device ID</param>
/// <returns>Device</returns>
public MMDevice GetDevice(string ID)
{
IMMDevice _Device = null;
Marshal.ThrowExceptionForHR(((IMMDeviceEnumerator)_realEnumerator).GetDevice(ID, out _Device));
return new MMDevice(_Device);
}
/// <summary>
/// Creates a new MM Device Enumerator
/// </summary>
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;
}
}
}

View File

@@ -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
{
/// <summary>
/// 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
/// </summary>
[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;
*/
/// <summary>
/// Helper method to gets blob data
/// </summary>
byte[] GetBlob()
{
byte[] Result = new byte[blobVal.Length];
Marshal.Copy(blobVal.Data, Result, 0, Result.Length);
return Result;
}
/// <summary>
/// Property value
/// </summary>
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());
}
}
}
}

View File

@@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace NAudio.CoreAudioApi
{
/// <summary>
/// PROPERTYKEY is defined in wtypes.h
/// </summary>
public struct PropertyKey
{
/// <summary>
/// Format ID
/// </summary>
public Guid formatId;
/// <summary>
/// Property ID
/// </summary>
public int propertyId;
}
}

View File

@@ -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
{
/// <summary>
/// Property Keys
/// </summary>
public static class PropertyKeys
{
/// <summary>
/// PKEY_DeviceInterface_FriendlyName
/// </summary>
public static readonly Guid PKEY_DeviceInterface_FriendlyName = new Guid(0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0);
/// <summary>
/// PKEY_AudioEndpoint_FormFactor
/// </summary>
public static readonly Guid PKEY_AudioEndpoint_FormFactor = new Guid(0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x23, 0xe0, 0xc0, 0xff, 0xee, 0x7f, 0x0e);
/// <summary>
/// PKEY_AudioEndpoint_ControlPanelPageProvider
/// </summary>
public static readonly Guid PKEY_AudioEndpoint_ControlPanelPageProvider = new Guid(0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x23, 0xe0, 0xc0, 0xff, 0xee, 0x7f, 0x0e);
/// <summary>
/// PKEY_AudioEndpoint_Association
/// </summary>
public static readonly Guid PKEY_AudioEndpoint_Association = new Guid(0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x23, 0xe0, 0xc0, 0xff, 0xee, 0x7f, 0x0e);
/// <summary>
/// PKEY_AudioEndpoint_PhysicalSpeakers
/// </summary>
public static readonly Guid PKEY_AudioEndpoint_PhysicalSpeakers = new Guid(0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x23, 0xe0, 0xc0, 0xff, 0xee, 0x7f, 0x0e);
/// <summary>
/// PKEY_AudioEndpoint_GUID
/// </summary>
public static readonly Guid PKEY_AudioEndpoint_GUID = new Guid(0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x23, 0xe0, 0xc0, 0xff, 0xee, 0x7f, 0x0e);
/// <summary>
/// PKEY_AudioEndpoint_Disable_SysFx
/// </summary>
public static readonly Guid PKEY_AudioEndpoint_Disable_SysFx = new Guid(0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x23, 0xe0, 0xc0, 0xff, 0xee, 0x7f, 0x0e);
/// <summary>
/// PKEY_AudioEndpoint_FullRangeSpeakers
/// </summary>
public static readonly Guid PKEY_AudioEndpoint_FullRangeSpeakers = new Guid(0x1da5d803, 0xd492, 0x4edd, 0x8c, 0x23, 0xe0, 0xc0, 0xff, 0xee, 0x7f, 0x0e);
/// <summary>
/// PKEY_AudioEngine_DeviceFormat
/// </summary>
public static readonly Guid PKEY_AudioEngine_DeviceFormat = new Guid(0xf19f064d, 0x82c, 0x4e27, 0xbc, 0x73, 0x68, 0x82, 0xa1, 0xbb, 0x8e, 0x4c);
}
}

View File

@@ -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
{
/// <summary>
/// Property Store class, only supports reading properties at the moment.
/// </summary>
public class PropertyStore
{
private IPropertyStore storeInterface;
/// <summary>
/// Property Count
/// </summary>
public int Count
{
get
{
int result;
Marshal.ThrowExceptionForHR(storeInterface.GetCount(out result));
return result;
}
}
/// <summary>
/// Gets property by index
/// </summary>
/// <param name="index">Property index</param>
/// <returns>The property</returns>
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);
}
}
/// <summary>
/// Contains property guid
/// </summary>
/// <param name="guid">Looks for a specific Guid</param>
/// <returns>True if found</returns>
public bool Contains(Guid guid)
{
for (int i = 0; i < Count; i++)
{
PropertyKey key = Get(i);
if (key.formatId == guid)
{
return true;
}
}
return false;
}
/// <summary>
/// Indexer by guid
/// </summary>
/// <param name="guid">Property guid</param>
/// <returns>Property or null if not found</returns>
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;
}
}
/// <summary>
/// Gets property key at sepecified index
/// </summary>
/// <param name="index">Index</param>
/// <returns>Property key</returns>
public PropertyKey Get(int index)
{
PropertyKey key;
Marshal.ThrowExceptionForHR(storeInterface.GetAt(index, out key));
return key;
}
/// <summary>
/// Gets property value at specified index
/// </summary>
/// <param name="index">Index</param>
/// <returns>Property value</returns>
public PropVariant GetValue(int index)
{
PropVariant result;
PropertyKey key = Get(index);
Marshal.ThrowExceptionForHR(storeInterface.GetValue(ref key, out result));
return result;
}
/// <summary>
/// Creates a new property store
/// </summary>
/// <param name="store">IPropertyStore COM interface</param>
internal PropertyStore(IPropertyStore store)
{
this.storeInterface = store;
}
}
}

View File

@@ -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
{
/// <summary>
/// Property Store Property
/// </summary>
public class PropertyStoreProperty
{
private PropertyKey propertyKey;
private PropVariant propertyValue;
internal PropertyStoreProperty(PropertyKey key, PropVariant value)
{
propertyKey = key;
propertyValue = value;
}
/// <summary>
/// Property Key
/// </summary>
public PropertyKey Key
{
get
{
return propertyKey;
}
}
/// <summary>
/// Property Value
/// </summary>
public object Value
{
get
{
return propertyValue.Value;
}
}
}
}

View File

@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace NAudio.CoreAudioApi
{
/// <summary>
/// The ERole enumeration defines constants that indicate the role
/// that the system has assigned to an audio endpoint device
/// </summary>
public enum Role
{
/// <summary>
/// Games, system notification sounds, and voice commands.
/// </summary>
Console,
/// <summary>
/// Music, movies, narration, and live music recording
/// </summary>
Multimedia,
/// <summary>
/// Voice communications (talking to another person).
/// </summary>
Communications,
}
}

View File

@@ -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
{
/// <summary>
/// Audio Capture using Wasapi
/// See http://msdn.microsoft.com/en-us/library/dd370800%28VS.85%29.aspx
/// </summary>
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;
/// <summary>
/// Indicates recorded data is available
/// </summary>
public event EventHandler<WaveInEventArgs> DataAvailable;
/// <summary>
/// Indicates that all recorded data has now been received.
/// </summary>
public event EventHandler RecordingStopped;
/// <summary>
/// Initialises a new instance of the WASAPI capture class
/// </summary>
public WasapiCapture() :
this(GetDefaultCaptureDevice())
{
}
/// <summary>
/// Initialises a new instance of the WASAPI capture class
/// </summary>
/// <param name="captureDevice">Capture device to use</param>
public WasapiCapture(MMDevice captureDevice)
{
this.audioClient = captureDevice.AudioClient;
WaveFormat = audioClient.MixFormat;
}
/// <summary>
/// Recording wave format
/// </summary>
public WaveFormat WaveFormat { get; set; }
/// <summary>
/// Gets the default audio capture device
/// </summary>
/// <returns>The default audio capture device</returns>
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));
}
/// <summary>
/// Start Recording
/// </summary>
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();
}
/// <summary>
/// Stop Recording
/// </summary>
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));
}
}
/// <summary>
/// Dispose
/// </summary>
public void Dispose()
{
StopRecording();
}
}
}

View File

@@ -0,0 +1,42 @@
using System;
using CUETools.Codecs;
namespace CUETools.Codecs.CoreAudio
{
/// <summary>
/// Represents the interface to a device that can play a WaveFile
/// </summary>
public interface IWavePlayer : IDisposable, IAudioDest
{
/// <summary>
/// Begin playback
/// </summary>
void Play();
/// <summary>
/// Stop playback
/// </summary>
void Stop();
/// <summary>
/// Pause Playback
/// </summary>
void Pause();
/// <summary>
/// Current playback state
/// </summary>
PlaybackState PlaybackState { get; }
/// <summary>
/// The volume 1.0 is full scale
/// </summary>
float Volume { get; set; }
/// <summary>
/// Indicates that playback has gone into a stopped state due to
/// reaching the end of the input stream
/// </summary>
event EventHandler PlaybackStopped;
}
}

View File

@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace CUETools.Codecs.CoreAudio
{
/// <summary>
/// Playback State
/// </summary>
public enum PlaybackState
{
/// <summary>
/// Stopped
/// </summary>
Stopped,
/// <summary>
/// Playing
/// </summary>
Playing,
/// <summary>
/// Paused
/// </summary>
Paused
}
}

View File

@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("CUETools.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")]

View File

@@ -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
{
/// <summary>
/// Support for playback using Wasapi
/// </summary>
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;
/// <summary>
/// Playback Stopped
/// </summary>
public event EventHandler PlaybackStopped;
/// <summary>
/// WASAPI Out using default audio endpoint
/// </summary>
/// <param name="shareMode">ShareMode - shared or exclusive</param>
/// <param name="latency">Desired latency in milliseconds</param>
public WasapiOut(AudioClientShareMode shareMode, int latency) :
this(GetDefaultAudioEndpoint(), shareMode, true, latency, AudioPCMConfig.RedBook)
{
}
/// <summary>
/// WASAPI Out using default audio endpoint
/// </summary>
/// <param name="shareMode">ShareMode - shared or exclusive</param>
/// <param name="useEventSync">true if sync is done with event. false use sleep.</param>
/// <param name="latency">Desired latency in milliseconds</param>
public WasapiOut(AudioClientShareMode shareMode, bool useEventSync, int latency) :
this(GetDefaultAudioEndpoint(), shareMode, useEventSync, latency, AudioPCMConfig.RedBook)
{
}
/// <summary>
/// Creates a new WASAPI Output
/// </summary>
/// <param name="device">Device to use</param>
/// <param name="shareMode"></param>
/// <param name="useEventSync">true if sync is done with event. false use sleep.</param>
/// <param name="latency"></param>
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
/// <summary>
/// Begin Playback
/// </summary>
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;
}
}
/// <summary>
/// Stop playback and flush buffers
/// </summary>
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;
}
}
/// <summary>
/// Stop playback without flushing buffers
/// </summary>
public void Pause()
{
if (playbackState == PlaybackState.Playing)
{
//playbackState = PlaybackState.Paused;
}
if (frameEventWaitHandle != null)
frameEventWaitHandle.Set();
}
private bool inited = false;
/// <summary>
/// Initialize for playing the specified format
/// </summary>
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;
}
/// <summary>
/// Playback State
/// </summary>
public PlaybackState PlaybackState
{
get { return playbackState; }
}
/// <summary>
/// Volume
/// </summary>
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
/// <summary>
/// Dispose
/// </summary>
public void Dispose()
{
if (audioClient != null)
{
Stop();
audioClient.Dispose();
audioClient = null;
renderClient = null;
}
}
#endregion
}
}

View File

@@ -0,0 +1,117 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace NAudio.Wave
{
/// <summary>
/// Microsoft ADPCM
/// See http://icculus.org/SDL_sound/downloads/external_documentation/wavecomp.htm
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack=2)]
public class AdpcmWaveFormat : WaveFormat
{
short samplesPerBlock;
short numCoeff;
// 7 pairs of coefficients
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 14)]
short[] coefficients;
/// <summary>
/// Empty constructor needed for marshalling from a pointer
/// </summary>
AdpcmWaveFormat() : this(8000,1)
{
}
/// <summary>
/// Samples per block
/// </summary>
public int SamplesPerBlock
{
get { return samplesPerBlock; }
}
/// <summary>
/// Number of coefficients
/// </summary>
public int NumCoefficients
{
get { return numCoeff; }
}
/// <summary>
/// Coefficients
/// </summary>
public short[] Coefficients
{
get { return coefficients; }
}
/// <summary>
/// Microsoft ADPCM
/// </summary>
/// <param name="sampleRate">Sample Rate</param>
/// <param name="channels">Channels</param>
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
};
}
/// <summary>
/// Serializes this wave format
/// </summary>
/// <param name="writer">Binary writer</param>
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);
}
}
/// <summary>
/// String Description of this WaveFormat
/// </summary>
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);
}
}
}

View File

@@ -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();
}
}
}

View File

@@ -0,0 +1,373 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
namespace NAudio.Wave
{
/// <summary>
/// Represents a Wave file format
/// </summary>
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi, Pack=2)]
public class WaveFormat
{
/// <summary>format type</summary>
protected WaveFormatEncoding waveFormatTag;
/// <summary>number of channels</summary>
protected short channels;
/// <summary>sample rate</summary>
protected int sampleRate;
/// <summary>for buffer estimation</summary>
protected int averageBytesPerSecond;
/// <summary>block size of data</summary>
protected short blockAlign;
/// <summary>number of bits per sample of mono data</summary>
protected short bitsPerSample;
/// <summary>number of following bytes</summary>
protected short extraSize;
/// <summary>
/// Creates a new PCM 44.1Khz stereo 16 bit format
/// </summary>
public WaveFormat() : this(44100,16,2)
{
}
/// <summary>
/// Creates a new 16 bit wave format with the specified sample
/// rate and channel count
/// </summary>
/// <param name="sampleRate">Sample Rate</param>
/// <param name="channels">Number of channels</param>
public WaveFormat(int sampleRate, int channels)
: this(sampleRate, 16, channels)
{
}
/// <summary>
/// Gets the size of a wave buffer equivalent to the latency in milliseconds.
/// </summary>
/// <param name="milliseconds">The milliseconds.</param>
/// <returns></returns>
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;
}
/// <summary>
/// Creates a WaveFormat with custom members
/// </summary>
/// <param name="tag">The encoding</param>
/// <param name="sampleRate">Sample Rate</param>
/// <param name="channels">Number of channels</param>
/// <param name="averageBytesPerSecond">Average Bytes Per Second</param>
/// <param name="blockAlign">Block Align</param>
/// <param name="bitsPerSample">Bits Per Sample</param>
/// <returns></returns>
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;
}
/// <summary>
/// Creates an A-law wave format
/// </summary>
/// <param name="sampleRate">Sample Rate</param>
/// <param name="channels">Number of Channels</param>
/// <returns>Wave Format</returns>
public static WaveFormat CreateALawFormat(int sampleRate, int channels)
{
return CreateCustomFormat(WaveFormatEncoding.ALaw, sampleRate, channels, sampleRate * channels, 1, 8);
}
/// <summary>
/// Creates a Mu-law wave format
/// </summary>
/// <param name="sampleRate">Sample Rate</param>
/// <param name="channels">Number of Channels</param>
/// <returns>Wave Format</returns>
public static WaveFormat CreateMuLawFormat(int sampleRate, int channels)
{
return CreateCustomFormat(WaveFormatEncoding.MuLaw, sampleRate, channels, sampleRate * channels, 1, 8);
}
/// <summary>
/// Creates a new PCM format with the specified sample rate, bit depth and channels
/// </summary>
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;
}
/// <summary>
/// Creates a new 32 bit IEEE floating point wave format
/// </summary>
/// <param name="sampleRate">sample rate</param>
/// <param name="channels">number of channels</param>
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;
}
/// <summary>
/// Helper function to retrieve a WaveFormat structure from a pointer
/// </summary>
/// <param name="pointer">WaveFormat structure</param>
/// <returns></returns>
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;
}
/// <summary>
/// Helper function to marshal WaveFormat to an IntPtr
/// </summary>
/// <param name="format">WaveFormat</param>
/// <returns>IntPtr to WaveFormat structure (needs to be freed by callee)</returns>
public static IntPtr MarshalToPtr(WaveFormat format)
{
int formatSize = Marshal.SizeOf(format);
IntPtr formatPointer = Marshal.AllocHGlobal(formatSize);
Marshal.StructureToPtr(format, formatPointer, false);
return formatPointer;
}
/// <summary>
/// Reads a new WaveFormat object from a stream
/// </summary>
/// <param name="br">A binary reader that wraps the stream</param>
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);
}
}
/// <summary>
/// Reports this WaveFormat as a string
/// </summary>
/// <returns>String describing the wave format</returns>
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();
}
}
/// <summary>
/// Compares with another WaveFormat object
/// </summary>
/// <param name="obj">Object to compare to</param>
/// <returns>True if the objects are the same</returns>
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;
}
/// <summary>
/// Provides a Hashcode for this WaveFormat
/// </summary>
/// <returns>A hashcode</returns>
public override int GetHashCode()
{
return (int) waveFormatTag ^
(int) channels ^
sampleRate ^
averageBytesPerSecond ^
(int) blockAlign ^
(int) bitsPerSample;
}
/// <summary>
/// Returns the encoding type used
/// </summary>
public WaveFormatEncoding Encoding
{
get
{
return waveFormatTag;
}
}
/// <summary>
/// Writes this WaveFormat object to a stream
/// </summary>
/// <param name="writer">the output stream</param>
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);
}
/// <summary>
/// Returns the number of channels (1=mono,2=stereo etc)
/// </summary>
public int Channels
{
get
{
return channels;
}
}
/// <summary>
/// Returns the sample rate (samples per second)
/// </summary>
public int SampleRate
{
get
{
return sampleRate;
}
}
/// <summary>
/// Returns the average number of bytes used per second
/// </summary>
public int AverageBytesPerSecond
{
get
{
return averageBytesPerSecond;
}
}
/// <summary>
/// Returns the block alignment
/// </summary>
public virtual int BlockAlign
{
get
{
return blockAlign;
}
}
/// <summary>
/// Returns the number of bits per sample (usually 16 or 32, sometimes 24 or 8)
/// Can be 0 for some codecs
/// </summary>
public int BitsPerSample
{
get
{
return bitsPerSample;
}
}
/// <summary>
/// Returns the number of extra bytes used by this waveformat. Often 0,
/// except for compressed formats which store extra data after the WAVEFORMATEX header
/// </summary>
public int ExtraSize
{
get
{
return extraSize;
}
}
}
}

View File

@@ -0,0 +1,314 @@
using System;
namespace NAudio.Wave
{
/// <summary>
/// Summary description for WaveFormatEncoding.
/// </summary>
public enum WaveFormatEncoding : ushort
{
/// <summary>WAVE_FORMAT_UNKNOWN, Microsoft Corporation</summary>
Unknown = 0x0000,
/// <summary>WAVE_FORMAT_PCM Microsoft Corporation</summary>
Pcm = 0x0001,
/// <summary>WAVE_FORMAT_ADPCM Microsoft Corporation</summary>
Adpcm = 0x0002,
/// <summary>WAVE_FORMAT_IEEE_FLOAT Microsoft Corporation</summary>
IeeeFloat = 0x0003,
/// <summary>WAVE_FORMAT_VSELP Compaq Computer Corp.</summary>
Vselp = 0x0004,
/// <summary>WAVE_FORMAT_IBM_CVSD IBM Corporation</summary>
IbmCvsd = 0x0005,
/// <summary>WAVE_FORMAT_ALAW Microsoft Corporation</summary>
ALaw = 0x0006,
/// <summary>WAVE_FORMAT_MULAW Microsoft Corporation</summary>
MuLaw = 0x0007,
/// <summary>WAVE_FORMAT_DTS Microsoft Corporation</summary>
Dts = 0x0008,
/// <summary>WAVE_FORMAT_DRM Microsoft Corporation</summary>
Drm = 0x0009,
/// <summary>WAVE_FORMAT_OKI_ADPCM OKI</summary>
OkiAdpcm = 0x0010,
/// <summary>WAVE_FORMAT_DVI_ADPCM Intel Corporation</summary>
DviAdpcm = 0x0011,
/// <summary>WAVE_FORMAT_IMA_ADPCM Intel Corporation</summary>
ImaAdpcm = DviAdpcm,
/// <summary>WAVE_FORMAT_MEDIASPACE_ADPCM Videologic</summary>
MediaspaceAdpcm = 0x0012,
/// <summary>WAVE_FORMAT_SIERRA_ADPCM Sierra Semiconductor Corp </summary>
SierraAdpcm = 0x0013,
/// <summary>WAVE_FORMAT_G723_ADPCM Antex Electronics Corporation </summary>
G723Adpcm = 0x0014,
/// <summary>WAVE_FORMAT_DIGISTD DSP Solutions, Inc.</summary>
DigiStd = 0x0015,
/// <summary>WAVE_FORMAT_DIGIFIX DSP Solutions, Inc.</summary>
DigiFix = 0x0016,
/// <summary>WAVE_FORMAT_DIALOGIC_OKI_ADPCM Dialogic Corporation</summary>
DialogicOkiAdpcm = 0x0017,
/// <summary>WAVE_FORMAT_MEDIAVISION_ADPCM Media Vision, Inc.</summary>
MediaVisionAdpcm = 0x0018,
/// <summary>WAVE_FORMAT_CU_CODEC Hewlett-Packard Company </summary>
CUCodec = 0x0019,
/// <summary>WAVE_FORMAT_YAMAHA_ADPCM Yamaha Corporation of America</summary>
YamahaAdpcm = 0x0020,
/// <summary>WAVE_FORMAT_SONARC Speech Compression</summary>
SonarC = 0x0021,
/// <summary>WAVE_FORMAT_DSPGROUP_TRUESPEECH DSP Group, Inc </summary>
DspGroupTruespeech = 0x0022,
/// <summary>WAVE_FORMAT_ECHOSC1 Echo Speech Corporation</summary>
EchoSpeechCorporation1 = 0x0023,
/// <summary>WAVE_FORMAT_AUDIOFILE_AF36, Virtual Music, Inc.</summary>
AudioFileAf36 = 0x0024,
/// <summary>WAVE_FORMAT_APTX Audio Processing Technology</summary>
Aptx = 0x0025,
/// <summary>WAVE_FORMAT_AUDIOFILE_AF10, Virtual Music, Inc.</summary>
AudioFileAf10 = 0x0026,
/// <summary>WAVE_FORMAT_PROSODY_1612, Aculab plc</summary>
Prosody1612 = 0x0027,
/// <summary>WAVE_FORMAT_LRC, Merging Technologies S.A. </summary>
Lrc = 0x0028,
/// <summary>WAVE_FORMAT_DOLBY_AC2, Dolby Laboratories</summary>
DolbyAc2 = 0x0030,
/// <summary>WAVE_FORMAT_GSM610, Microsoft Corporation</summary>
Gsm610 = 0x0031,
/// <summary>WAVE_FORMAT_MSNAUDIO, Microsoft Corporation</summary>
MsnAudio = 0x0032,
/// <summary>WAVE_FORMAT_ANTEX_ADPCME, Antex Electronics Corporation</summary>
AntexAdpcme = 0x0033,
/// <summary>WAVE_FORMAT_CONTROL_RES_VQLPC, Control Resources Limited </summary>
ControlResVqlpc = 0x0034,
/// <summary>WAVE_FORMAT_DIGIREAL, DSP Solutions, Inc. </summary>
DigiReal = 0x0035,
/// <summary>WAVE_FORMAT_DIGIADPCM, DSP Solutions, Inc.</summary>
DigiAdpcm = 0x0036,
/// <summary>WAVE_FORMAT_CONTROL_RES_CR10, Control Resources Limited</summary>
ControlResCr10 = 0x0037,
/// <summary></summary>
WAVE_FORMAT_NMS_VBXADPCM = 0x0038, // Natural MicroSystems
/// <summary></summary>
WAVE_FORMAT_CS_IMAADPCM = 0x0039, // Crystal Semiconductor IMA ADPCM
/// <summary></summary>
WAVE_FORMAT_ECHOSC3 = 0x003A, // Echo Speech Corporation
/// <summary></summary>
WAVE_FORMAT_ROCKWELL_ADPCM = 0x003B, // Rockwell International
/// <summary></summary>
WAVE_FORMAT_ROCKWELL_DIGITALK = 0x003C, // Rockwell International
/// <summary></summary>
WAVE_FORMAT_XEBEC = 0x003D, // Xebec Multimedia Solutions Limited
/// <summary></summary>
WAVE_FORMAT_G721_ADPCM = 0x0040, // Antex Electronics Corporation
/// <summary></summary>
WAVE_FORMAT_G728_CELP = 0x0041, // Antex Electronics Corporation
/// <summary></summary>
WAVE_FORMAT_MSG723 = 0x0042, // Microsoft Corporation
/// <summary></summary>
Mpeg = 0x0050, // WAVE_FORMAT_MPEG, Microsoft Corporation
/// <summary></summary>
WAVE_FORMAT_RT24 = 0x0052, // InSoft, Inc.
/// <summary></summary>
WAVE_FORMAT_PAC = 0x0053, // InSoft, Inc.
/// <summary></summary>
MpegLayer3 = 0x0055, // WAVE_FORMAT_MPEGLAYER3, ISO/MPEG Layer3 Format Tag
/// <summary></summary>
WAVE_FORMAT_LUCENT_G723 = 0x0059, // Lucent Technologies
/// <summary></summary>
WAVE_FORMAT_CIRRUS = 0x0060, // Cirrus Logic
/// <summary></summary>
WAVE_FORMAT_ESPCM = 0x0061, // ESS Technology
/// <summary></summary>
WAVE_FORMAT_VOXWARE = 0x0062, // Voxware Inc
/// <summary></summary>
WAVE_FORMAT_CANOPUS_ATRAC = 0x0063, // Canopus, co., Ltd.
/// <summary></summary>
WAVE_FORMAT_G726_ADPCM = 0x0064, // APICOM
/// <summary></summary>
WAVE_FORMAT_G722_ADPCM = 0x0065, // APICOM
/// <summary></summary>
WAVE_FORMAT_DSAT_DISPLAY = 0x0067, // Microsoft Corporation
/// <summary></summary>
WAVE_FORMAT_VOXWARE_BYTE_ALIGNED = 0x0069, // Voxware Inc
/// <summary></summary>
WAVE_FORMAT_VOXWARE_AC8 = 0x0070, // Voxware Inc
/// <summary></summary>
WAVE_FORMAT_VOXWARE_AC10 = 0x0071, // Voxware Inc
/// <summary></summary>
WAVE_FORMAT_VOXWARE_AC16 = 0x0072, // Voxware Inc
/// <summary></summary>
WAVE_FORMAT_VOXWARE_AC20 = 0x0073, // Voxware Inc
/// <summary></summary>
WAVE_FORMAT_VOXWARE_RT24 = 0x0074, // Voxware Inc
/// <summary></summary>
WAVE_FORMAT_VOXWARE_RT29 = 0x0075, // Voxware Inc
/// <summary></summary>
WAVE_FORMAT_VOXWARE_RT29HW = 0x0076, // Voxware Inc
/// <summary></summary>
WAVE_FORMAT_VOXWARE_VR12 = 0x0077, // Voxware Inc
/// <summary></summary>
WAVE_FORMAT_VOXWARE_VR18 = 0x0078, // Voxware Inc
/// <summary></summary>
WAVE_FORMAT_VOXWARE_TQ40 = 0x0079, // Voxware Inc
/// <summary></summary>
WAVE_FORMAT_SOFTSOUND = 0x0080, // Softsound, Ltd.
/// <summary></summary>
WAVE_FORMAT_VOXWARE_TQ60 = 0x0081, // Voxware Inc
/// <summary></summary>
WAVE_FORMAT_MSRT24 = 0x0082, // Microsoft Corporation
/// <summary></summary>
WAVE_FORMAT_G729A = 0x0083, // AT&T Labs, Inc.
/// <summary></summary>
WAVE_FORMAT_MVI_MVI2 = 0x0084, // Motion Pixels
/// <summary></summary>
WAVE_FORMAT_DF_G726 = 0x0085, // DataFusion Systems (Pty) (Ltd)
/// <summary></summary>
WAVE_FORMAT_DF_GSM610 = 0x0086, // DataFusion Systems (Pty) (Ltd)
/// <summary></summary>
WAVE_FORMAT_ISIAUDIO = 0x0088, // Iterated Systems, Inc.
/// <summary></summary>
WAVE_FORMAT_ONLIVE = 0x0089, // OnLive! Technologies, Inc.
/// <summary></summary>
WAVE_FORMAT_SBC24 = 0x0091, // Siemens Business Communications Sys
/// <summary></summary>
WAVE_FORMAT_DOLBY_AC3_SPDIF = 0x0092, // Sonic Foundry
/// <summary></summary>
WAVE_FORMAT_MEDIASONIC_G723 = 0x0093, // MediaSonic
/// <summary></summary>
WAVE_FORMAT_PROSODY_8KBPS = 0x0094, // Aculab plc
/// <summary></summary>
WAVE_FORMAT_ZYXEL_ADPCM = 0x0097, // ZyXEL Communications, Inc.
/// <summary></summary>
WAVE_FORMAT_PHILIPS_LPCBB = 0x0098, // Philips Speech Processing
/// <summary></summary>
WAVE_FORMAT_PACKED = 0x0099, // Studer Professional Audio AG
/// <summary></summary>
WAVE_FORMAT_MALDEN_PHONYTALK = 0x00A0, // Malden Electronics Ltd.
/// <summary>WAVE_FORMAT_GSM</summary>
Gsm = 0x00A1,
/// <summary>WAVE_FORMAT_G729</summary>
G729 = 0x00A2,
/// <summary>WAVE_FORMAT_G723</summary>
G723 = 0x00A3,
/// <summary>WAVE_FORMAT_ACELP</summary>
Acelp = 0x00A4,
/// <summary></summary>
WAVE_FORMAT_RHETOREX_ADPCM = 0x0100, // Rhetorex Inc.
/// <summary></summary>
WAVE_FORMAT_IRAT = 0x0101, // BeCubed Software Inc.
/// <summary></summary>
WAVE_FORMAT_VIVO_G723 = 0x0111, // Vivo Software
/// <summary></summary>
WAVE_FORMAT_VIVO_SIREN = 0x0112, // Vivo Software
/// <summary></summary>
WAVE_FORMAT_DIGITAL_G723 = 0x0123, // Digital Equipment Corporation
/// <summary></summary>
WAVE_FORMAT_SANYO_LD_ADPCM = 0x0125, // Sanyo Electric Co., Ltd.
/// <summary></summary>
WAVE_FORMAT_SIPROLAB_ACEPLNET = 0x0130, // Sipro Lab Telecom Inc.
/// <summary></summary>
WAVE_FORMAT_SIPROLAB_ACELP4800 = 0x0131, // Sipro Lab Telecom Inc.
/// <summary></summary>
WAVE_FORMAT_SIPROLAB_ACELP8V3 = 0x0132, // Sipro Lab Telecom Inc.
/// <summary></summary>
WAVE_FORMAT_SIPROLAB_G729 = 0x0133, // Sipro Lab Telecom Inc.
/// <summary></summary>
WAVE_FORMAT_SIPROLAB_G729A = 0x0134, // Sipro Lab Telecom Inc.
/// <summary></summary>
WAVE_FORMAT_SIPROLAB_KELVIN = 0x0135, // Sipro Lab Telecom Inc.
/// <summary></summary>
WAVE_FORMAT_G726ADPCM = 0x0140, // Dictaphone Corporation
/// <summary></summary>
WAVE_FORMAT_QUALCOMM_PUREVOICE = 0x0150, // Qualcomm, Inc.
/// <summary></summary>
WAVE_FORMAT_QUALCOMM_HALFRATE = 0x0151, // Qualcomm, Inc.
/// <summary></summary>
WAVE_FORMAT_TUBGSM = 0x0155, // Ring Zero Systems, Inc.
/// <summary></summary>
WAVE_FORMAT_MSAUDIO1 = 0x0160, // Microsoft Corporation
/// <summary>
/// WAVE_FORMAT_WMAUDIO2, Microsoft Corporation
/// </summary>
WAVE_FORMAT_WMAUDIO2 = 0x0161,
/// <summary>
/// WAVE_FORMAT_WMAUDIO3, Microsoft Corporation
/// </summary>
WAVE_FORMAT_WMAUDIO3 = 0x0162,
/// <summary></summary>
WAVE_FORMAT_UNISYS_NAP_ADPCM = 0x0170, // Unisys Corp.
/// <summary></summary>
WAVE_FORMAT_UNISYS_NAP_ULAW = 0x0171, // Unisys Corp.
/// <summary></summary>
WAVE_FORMAT_UNISYS_NAP_ALAW = 0x0172, // Unisys Corp.
/// <summary></summary>
WAVE_FORMAT_UNISYS_NAP_16K = 0x0173, // Unisys Corp.
/// <summary></summary>
WAVE_FORMAT_CREATIVE_ADPCM = 0x0200, // Creative Labs, Inc
/// <summary></summary>
WAVE_FORMAT_CREATIVE_FASTSPEECH8 = 0x0202, // Creative Labs, Inc
/// <summary></summary>
WAVE_FORMAT_CREATIVE_FASTSPEECH10 = 0x0203, // Creative Labs, Inc
/// <summary></summary>
WAVE_FORMAT_UHER_ADPCM = 0x0210, // UHER informatic GmbH
/// <summary></summary>
WAVE_FORMAT_QUARTERDECK = 0x0220, // Quarterdeck Corporation
/// <summary></summary>
WAVE_FORMAT_ILINK_VC = 0x0230, // I-link Worldwide
/// <summary></summary>
WAVE_FORMAT_RAW_SPORT = 0x0240, // Aureal Semiconductor
/// <summary></summary>
WAVE_FORMAT_ESST_AC3 = 0x0241, // ESS Technology, Inc.
/// <summary></summary>
WAVE_FORMAT_IPI_HSX = 0x0250, // Interactive Products, Inc.
/// <summary></summary>
WAVE_FORMAT_IPI_RPELP = 0x0251, // Interactive Products, Inc.
/// <summary></summary>
WAVE_FORMAT_CS2 = 0x0260, // Consistent Software
/// <summary></summary>
WAVE_FORMAT_SONY_SCX = 0x0270, // Sony Corp.
/// <summary></summary>
WAVE_FORMAT_FM_TOWNS_SND = 0x0300, // Fujitsu Corp.
/// <summary></summary>
WAVE_FORMAT_BTV_DIGITAL = 0x0400, // Brooktree Corporation
/// <summary></summary>
WAVE_FORMAT_QDESIGN_MUSIC = 0x0450, // QDesign Corporation
/// <summary></summary>
WAVE_FORMAT_VME_VMPCM = 0x0680, // AT&T Labs, Inc.
/// <summary></summary>
WAVE_FORMAT_TPC = 0x0681, // AT&T Labs, Inc.
/// <summary></summary>
WAVE_FORMAT_OLIGSM = 0x1000, // Ing C. Olivetti & C., S.p.A.
/// <summary></summary>
WAVE_FORMAT_OLIADPCM = 0x1001, // Ing C. Olivetti & C., S.p.A.
/// <summary></summary>
WAVE_FORMAT_OLICELP = 0x1002, // Ing C. Olivetti & C., S.p.A.
/// <summary></summary>
WAVE_FORMAT_OLISBC = 0x1003, // Ing C. Olivetti & C., S.p.A.
/// <summary></summary>
WAVE_FORMAT_OLIOPR = 0x1004, // Ing C. Olivetti & C., S.p.A.
/// <summary></summary>
WAVE_FORMAT_LH_CODEC = 0x1100, // Lernout & Hauspie
/// <summary></summary>
WAVE_FORMAT_NORRIS = 0x1400, // Norris Communications, Inc.
/// <summary></summary>
WAVE_FORMAT_SOUNDSPACE_MUSICOMPRESS = 0x1500, // AT&T Labs, Inc.
/// <summary></summary>
WAVE_FORMAT_DVM = 0x2000, // FAST Multimedia AG
/// <summary>WAVE_FORMAT_EXTENSIBLE</summary>
Extensible = 0xFFFE, // Microsoft
/// <summary></summary>
WAVE_FORMAT_DEVELOPMENT = 0xFFFF,
// others - not from MS headers
/// <summary>WAVE_FORMAT_VORBIS1 "Og" Original stream compatible</summary>
Vorbis1 = 0x674f,
/// <summary>WAVE_FORMAT_VORBIS2 "Pg" Have independent header</summary>
Vorbis2 = 0x6750,
/// <summary>WAVE_FORMAT_VORBIS3 "Qg" Have no codebook header</summary>
Vorbis3 = 0x6751,
/// <summary>WAVE_FORMAT_VORBIS1P "og" Original stream compatible</summary>
Vorbis1P = 0x676f,
/// <summary>WAVE_FORMAT_VORBIS2P "pg" Have independent headere</summary>
Vorbis2P = 0x6770,
/// <summary>WAVE_FORMAT_VORBIS3P "qg" Have no codebook header</summary>
Vorbis3P = 0x6771,
}
}

View File

@@ -0,0 +1,79 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using NAudio.Dmo;
namespace NAudio.Wave
{
/// <summary>
/// WaveFormatExtensible
/// http://www.microsoft.com/whdc/device/audio/multichaud.mspx
/// </summary>
[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;
/// <summary>
/// Parameterless constructor for marshalling
/// </summary>
WaveFormatExtensible()
{
}
/// <summary>
/// Creates a new WaveFormatExtensible for PCM or IEEE
/// </summary>
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");
}
}
/// <summary>
/// Serialize
/// </summary>
/// <param name="writer"></param>
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);
}
/// <summary>
/// String representation
/// </summary>
public override string ToString()
{
return String.Format("{0} wBitsPerSample:{1} dwChannelMask:{2} subFormat:{3} extraSize:{4}",
base.ToString(),
wValidBitsPerSample,
dwChannelMask,
subFormat,
extraSize);
}
}
}

View File

@@ -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];
/// <summary>
/// parameterless constructor for marshalling
/// </summary>
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);
}
}
}
}

View File

@@ -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;
}

View File

@@ -1593,7 +1593,7 @@ string status = processor.Go();
private bool _stop, _pause;
private List<CUELine> _attributes;
private List<TrackInfo> _tracks;
private List<SourceInfo> _sources;
internal List<SourceInfo> _sources;
private List<string> _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);
}
}
}

View File

@@ -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++)

View File

@@ -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<ReadProgressArgs> ReadProgress;

View File

@@ -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

File diff suppressed because it is too large Load Diff