Aumplib: 用于音频转换的 C# 命名空间和类






3.04/5 (24投票s)
2004年10月12日
7分钟阅读

276770

7964
一个命名空间,包含各种提供音频转换功能的类,可以转换包括 MP3 在内的多种音频格式。
引言
Aumplib (完全限定名:Arbingersys.Audio.Aumplib
) 是一个命名空间,包含各种提供音频转换功能的类,可以转换包括 MP3 在内的多种音频格式。Aumplib 通过 P/Invoke 为多个著名的开源项目提供面向对象的接口。这些项目包括 LAME (MP3 编码)、libsndfile (非 MP3 音频格式) 和 madlldlib/libmad (MP3 解码)。它支持大量音频格式之间的转换,并且未来还将支持更多格式。
背景
Aumplib 的设计宗旨是为 C# 程序员提供一个简洁、易用且强大的音频转换接口,以方便使用著名的开源音频转换库 (这些库是用 C/C++ 编写的)。这些库在互联网上存在已久,但由于数据结构映射不清或不是 DLL 形式,C# 程序员不易使用。Aumplib 使用 P/Invoke “封装”了这些库,并提供了各种对象来简化它们的使用。
使用代码
Aumplib 由各种与第三方 DLL 通信的“包装器”类组成,以及主要的接口类 Aumpel
,它“包装了包装器”类,以尽可能简化转换任务。源代码中包含了一个名为 TestForm.cs 的示例,演示了如何使用 Aumpel
类。我们将对其进行简要研究,因为它是主要的接口。每个包装器类都可以单独使用,但对于大多数情况,Aumpel
应该足够了。
TestForm.cs 定义了一个名为 TestForm
的类,该类派生自“Systems.Windows.Forms
”类;基本上,它是一个窗口而不是控制台应用程序。当您向下浏览源代码时,会看到它首先声明变量,其中大多数是窗口控件(例如 ComboBox
、ProgressBar
)。构造函数 TestForm()
实例化控件,定义它们的属性,设置事件处理程序,并将它们添加到窗体。要理解这部分内容,最好参考一些关于在 C# 中创建 Windows 应用程序的文档。
声明了三个私有变量,它们在后续代码中很重要。它们是 audioConverter
(一个 Aumpel
对象)以及两个 Aumpel.soundFormat
类型,用于确定输入和输出声音文件的格式。
private Aumpel audioConverter = new Aumpel();
private Aumpel.soundFormat inputFileFormat;
private Aumpel.soundFormat outputFileFormat;
继续浏览,我们到达了委托函数的定义。这些对于 Aumplib 的运行至关重要。委托执行两项操作:
- 它们接收来自 Aumplib 的更新 (例如,当前转换已处理的字节数),您将使用这些更新来更新应用程序的状态,以及
- 引用结构体或
Aumpel
本身,使您能够获取更多信息、更改设置或取消转换。
如果您想在类中使用 MP3 解码功能,则必须定义至少两个委托 (MP3 解码委托接受的参数略有不同)。
// Conversion callback (lame,libsndfile)
private static void
ReportStatus(int totalBytes,
int processedBytes, Aumpel aumpelObj)
{
progressBar1.Value = (int)(((float)processedBytes/(float)totalBytes)*100);
}
第一个委托 ReportStatus
处理 MP3 *编码*和非 MP3 转换 (例如 WAV、AIFF、AU 等) 的状态更新。正如您所见,它非常简单。它所做的就是接收参数 totalBytes
(要处理的总字节数) 和 processedBytes
(已转换的总字节数),并根据它们之间的计算来更新进度条。aumpelObj
参数是对 Aumpel
对象的引用。它可以用于取消转换。
// Decoding callback (madlldlib)
private static bool
ReportStatusMad(uint frameCount,
uint byteCount, ref MadlldlibWrapper.mad_header mh)
{
progressBar1.Value = (int)(((float)byteCount/(float)soundFileSize)*100);
return true;
}
我们声明的第二个委托 ReportStatusMad
处理 MP3 解码的状态更新。它的参数是 frameCount
(已处理的 MP3 帧数)、byteCount
(已处理的总字节数) 以及对 MadlldlibWrapper.mad_header
结构体的引用。此结构体是 DLL 中结构的映射,并提供 MP3 文件特有的信息 (例如,层、频率)。由于每次调用此委托时仅返回已处理的字节数,因此我们必须使用另一个“类”变量 soundFileSize
来获取文件总大小 (以字节为单位,在选择输入文件时计算)。然后,我们使用它来进行计算以更新进度条。如果此方法返回 false
,则转换将中止。
接下来,我们来看窗体的事件处理程序。首先,我们定义 sourceFileButton
和 destFileButton
的处理程序,它们使用对话框来选择输入文件 (要转换的文件) 和输出文件。之后是调用 Aumpel
的方法,即 convertButton
的处理程序,convertButton_Click()
。我们将在下面分块研究它,因为它包含大部分转换代码。
protected void
convertButton_Click (object sender, System.EventArgs e)
{
// Set conversion type
switch((string)comboBox1.SelectedItem)
{
case "WAV":
outputFileFormat = Aumpel.soundFormat.WAV;
break;
case "MP3":
outputFileFormat = Aumpel.soundFormat.MP3;
break;
case "AU":
outputFileFormat = Aumpel.soundFormat.AU;
break;
case "AIFF":
outputFileFormat = Aumpel.soundFormat.AIFF;
break;
default:
MessageBox.Show("You must select a type to convert to.",
"Error", MessageBoxButtons.OK);
return;
}
...
首先,convertButton_Click()
检查控件 comboBox1
以查看用户指定的输出声音格式。如果没有指定,则通知用户,并且该方法返回。如果指定了,则为 outputFileFormat
分配 Aumpel
可理解的值。然后我们检查 outputFileFormat
来确定需要哪种类型的转换。
...
// Convert to MP3
if ( (int)outputFileFormat == (int)Aumpel.soundFormat.MP3 )
{
try
{
Aumpel.Reporter defaultCallback = new Aumpel.Reporter(ReportStatus);
audioConverter.Convert(inputFile,
(int)inputFileFormat, outputFile,
(int)outputFileFormat, defaultCallback);
progressBar1.Value = 0;
destFileLabel.Text = outputFile = "";
sourceFileLabel.Text = inputFile = "";
MessageBox.Show("Conversion finished.", "Done.", MessageBoxButtons.OK);
}
catch (Exception ex)
{
ShowExceptionMsg(ex);
return;
}
}
...
使用 outputFileFormat
,我们检查需要执行的转换类型:转换为 MP3、从 MP3 转换,还是非 MP3 (WAV、AIFF...)。如果指定的输出格式是 MP3,则执行上面的代码块。首先,它从委托定义 ReportStatus
定义 defaultCallback
,然后调用处理 MP3 编码的 Aumplib.Convert()
方法的重载。此方法的参数之一是我们定义的委托,如您所见。整个过程都包含在 try
/catch
子句中,任何异常都会被捕获并显示给用户。
...
// From MP3:
else if ( (int)inputFileFormat == (int)Aumpel.soundFormat.MP3 )
{
try
{
MadlldlibWrapper.Callback defaultCallback =
new MadlldlibWrapper.Callback(ReportStatusMad);
// Determine file size
FileInfo fi = new FileInfo(inputFile);
soundFileSize = (int)fi.Length;
audioConverter.Convert(inputFile,
outputFile, outputFileFormat, defaultCallback);
progressBar1.Value = 0;
destFileLabel.Text = outputFile = "";
sourceFileLabel.Text = inputFile = "";
MessageBox.Show("Conversion finished.", "Done.", MessageBoxButtons.OK);
}
catch (Exception ex)
{
ShowExceptionMsg(ex);
return;
}
}
...
如果您是从 MP3 解码为 WAV,则执行上面的代码。请注意,在 MP3 编码块将 defaultCallback
定义为 Aumpel.Reporter
委托的地方,此块使用 MadlldlibWrapper.Callback
使用 ReportStatusMad
委托定义 defaultCallback
,我们将上面定义的委托传递给它。这就是为什么两个委托的定义不同的原因。除了这个差异之外,此代码块的行为与第一个代码块基本相同;它调用 Aumpel.Convert()
方法的重载并等待转换完成。请注意,在此 Aumpel.Convert()
的重载中,缺少 inputFileFormat
参数。这是因为源文件格式是隐含的 (MP3)。
...
// Non-MP3 soundfile conversion:
else
{
try
{
Aumpel.Reporter defaultCallback = new Aumpel.Reporter(ReportStatus);
audioConverter.Convert(inputFile,
(int)inputFileFormat,
outputFile,
(int)(outputFileFormat | Aumpel.soundFormat.PCM_16),
defaultCallback);
progressBar1.Value = 0;
destFileLabel.Text = outputFile = "";
sourceFileLabel.Text = inputFile = "";
MessageBox.Show("Conversion finished.", "Done.", MessageBoxButtons.OK);
}
catch (Exception ex)
{
ShowExceptionMsg(ex);
return;
}
}
}
如果未指定转换为 MP3 或从 MP3 转换,则尝试进行非 MP3 转换。再次使用 Aumpel.Convert()
方法的重载。此转换也使用 ReportStatus
委托。此块与上面的“转换为 MP3”块之间唯一显著的差异是,在 outputFileFormat
参数中使用了一个子类型,该子类型通过 |
运算符组合。(Aumpel.soundFormat
类型本质上就是 int
,并且可以像这样对待。) 在上面的代码中,我们指定输出为 16 位 PCM 以及我们选择的任何文件格式 (outputFileFormat
):WAV、AIFF 或 AU。
基本就是这样。当按下“Convert”按钮时,上述代码开始执行,如果一切设置正确,转换就会发生,并通过进度条显示其进度。
注释
- TestForm.cs 没有使用计时器对象,而计时器对象在许多 Windows 应用程序中是常见的做法。您会注意到,当执行转换时,应用程序会停止响应直到转换完成。通过使用计时器对象,可以很容易地解决这个问题,它允许在转换等长时间操作期间处理其他按键或单击。
- 提供的源代码依赖于前面提到的开源项目。它们不包含在内。您需要下载并可能编译它们。有关详细信息,请参阅发行版中的“readme.txt”文件。
- 在撰写本文时,源代码处于 Beta 版本。我会尽量在代码更改时更新本文,但您应始终查看 我的网站 以获取最新更新。它们将首先在那里发布。您可以在此处或在我的开发者论坛 aumplib-dev 中提问。我将乐意回答我能回答的问题并有时间回答的问题,也乐于接受关于代码优化或方法的任何建议。
- Aumplib 接口的开源项目包括:LAME (MP3 编码)、libsndfile (非 MP3 转换) 和 madlldlib/libmad (MP3 解码)。
历史
- 2004-10-12:发布 1.0b3 版本。