LAME 封装器 (音频转换器)






4.56/5 (13投票s)
LAME 库的 C++ 封装,可将 PCM (*.wav) 转换为 mp3,反之亦然,只需两行代码。
介绍
20 世纪 90 年代初,随着互联网的普及,音频文件的存储和共享方式发生了新的转变。世界普遍使用 PCM 格式,但该格式需要大量的比特和带宽,而当时这些资源并不充足,无法有效地存储和流式传输这些文件(一个 4 秒的立体声 44.1khz PCM 文件大约需要 1MB 的空间)。
MP3 被发明出来,它是一种有损压缩 PCM 数据的方法(通过移除或降低某些声音细节的精度,这些细节被认为超出大多数人的听觉能力),在 128kbps 编码时,其大小约为 PCM 数据的 1/11。
MP3 格式因其显著减小的文件大小而迅速普及,能够将 PCM 转换为此文件格式的编解码器/编码器也随之发展起来。
LAME
Lame Aint an MP3 Encoder(LAME 不是一个 MP3 编码器)由 Mike Cheng 于 1998 年中期创建,改进工作至今仍在进行。它是编码质量非常好的编码器之一(实际上被绝大多数人认为是最好的)。源代码可在 http://lame.sourceforge.net 获取,或者从本文附件中获取已编译的静态库。
包装器
编写此封装库是为了简化 LAME 的使用,因为 LAME 本身可能非常复杂(强大的功能也带来复杂性)。此封装库将:
- 在每次调用时将编码/解码操作简化为两行代码(如果您使用封装库的默认值)。
- 使参数设置变得非常简单,甚至包括 id3 标签的设置。
设置您的开发环境
如果您已经知道如何设置开发环境以编译 LAME,请跳至本节的第二部分。
我将使用 Visual Studio,如果您使用其他 IDE,请自行查找如何将静态库链接到您的项目。
- 从 http://lame.sourceforge.net 下载并编译 LAME 库,
从本文附件中抓取 LAME 存档并解压。 - 在 Visual Studio 的菜单栏中点击“项目”按钮,从下拉菜单中选择“属性页”(<您的项目名称> 属性页),然后转到“配置属性”部分。转到“链接器”子部分,然后是“常规”项。从现在可用的选项列表中选择“附加库目录”,然后添加解压后的存档路径。
- 转到“输入”项并选择“附加依赖项”。添加
libmp3lame-static.lib
和libmpghip-static.lib
(每行一个)。 - 现在返回到“配置属性”部分,然后是“C/C++”子部分,接着是“常规”项。从现在可用的选项列表中选择“附加包含目录”,然后添加解压后的存档路径。
LAME 环境已准备就绪。
其次,抓取 lameHelper_dd_mm_yyyy 存档并解压。
- 将两个文件(lameHelper.cpp 和 lameHelper.h)添加到您的项目中。
- 在您的项目中包含
#include
lameHelper.h。
#include "lameHelper.h"
使用封装库
要使用此封装库,请执行以下操作:
#include "lameHelper.h"
int main()
{
lameHelper lhHandle;
return 0;
}
编码 (PCM 转换为 mp3)
该类有三个重载的 encode() 成员函数,用于处理 PCM 到 mp3 的转换。
int lameHelper::encode(char* pcm_in, char* mp3_out);
int lameHelper::encode(char* pcm_in, char* mp3_out, settings_t settings);
int lameHelper::encode(char* pcm_in, char* mp3_out, settings_t settings, WNDPROC callback_proc);
//asynchronous member function
void* encode(char* pcm_in, char* mp3_out, settings_t settings, WNDPROC callback_proc, bool async);
encode(char* pcm_in, char* mp3_out)
encode(char*, char*)
可用于使用封装库默认设置对 PCM 进行编码,这些默认设置在 lameHelper.cpp 的 settings_t::settings_t()
中指定。
默认设置包括:id3 标签设置为 NULL
或空字符串,声道设置为立体声,编码模式为 CBR,采样率为 44100hz,重采样频率为 44100hz,比特率为 128kbps,质量为 5。
参数
- pcm_in: PCM (*.wav) 文件的路径。
- mp3_out: mp3 的输出路径(包括文件名)。
返回值
该成员函数在成功时返回 0
,如果一个或两个路径不可读或不可写则返回 -1
,如果 LAME 初始化失败则返回 -2
。
#include "lameHelper.h"
int main()
{
lameHelper lhHandle;
lhHandle.encode("c:/.../song.wav", "c:/.../song.mp3");//Just two lines as promised
return 0;
}
encode(char* pcm_in, char* mp3_out, settings_t settings)
此重载成员函数可用于在指定各种设置和选项的情况下进行编码。
参数
- pcm_in: PCM (*.wav) 文件的路径。
- mp3_out: mp3 的输出路径(包括文件名)。
- settings:
settings_t
结构体的对象,用于指定设置和选项。
返回值
该成员函数在成功时返回 0
,如果一个或两个路径不可读或不可写则返回 -1
,如果 LAME 初始化失败则返回 -2
。
settings_t
settings_t
结构体。
struct settings_t
{
char* title;
char* artist;
char* album;
char* comment;
char* year;
char* track;
char* genre;
char* albumart;
encode_channel_e channels;
bitrate_e abr_bitrate;
bitrate_e cbr_bitrate;
int quality;
encode_mode_e enc_mode;
samplerate_e resample_frequency;
samplerate_e in_samplerate;
//The constructor: used to set default values
settings_t();
};
示例
#include "lameHelper.h"
int main()
{
settings_t settings;
settings.enc_mode = EM_ABR;
settings.abr_bitrate = BR_128kbps;//If you are going to use ABR encode mode @ 128kbps
settings.album = "The Album";//Setting the album (id3 tag)
settings.albumart = "c:/.../art.jpg";//Setting the albumart
settings.track = "01";//Setting the track
//..and various other settings
lameHelper lhHandle;
lhHandle.encode("c:/.../song.wav", "c:/.../song.mp3", settings);
return 0;
}
encode(char* pcm_in, char* mp3_out, settings_t settings, WNDPROC callback_proc)
前面描述的前两种方法都是同步的,并且没有关于当前任务进度的通知。此方法也是同步的(即,它也会阻塞),但会发送任务进度的通知。
参数
- pcm_in: PCM (*.wav) 文件的路径。
- mp3_out: mp3 的输出路径(包括文件名)。
- settings:
settings_t
结构体的对象,用于指定设置和选项。 - callback_proc: 一个回调函数 (
WNDPROC
),它将接收进度通知。
返回值
该成员函数在成功时返回 0
,如果一个或两个路径不可读或不可写则返回 -1
,如果 LAME 初始化失败则返回 -2
。
注释
在 WNDPROC callback_proc
中,msg
在编码/解码开始时接收 LH_STARTED
消息,在编码/解码过程中接收 LH_COMPUTED
消息(WPARAM
包含进度的百分比(作为 int
)),并在编码/解码结束时接收 LH_DONE
消息。
一个典型的 callback_proc。
HRESULT CALLBACK proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case LH_STARTED:
//Start of encoding / decoding
break;
case LH_COMPUTED:
//Update of percentage done
//wParam contains the percentage as int
//the best way to use this is to pass wParam's value into a progress bar
printf("%i ", wParam);
break;
case LH_DONE:
//Notifying end of encoding / decoding
break;
}
return 0;
}
一个示例。
#include “lameHelper.h”
HRESULT CALLBACK proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case LH_STARTED:
//Start of encoding / decodeing
break;
case LH_COMPUTED:
//Update of percentage done
//wParam contains the percentage as int
//the best way to use this is to pass wParam's value into a progress bar
printf("%i ", wParam);
break;
case LH_DONE:
//Notifying end of encoding / decoding
break;
}
return 0;
}
int main()
{
settings_t settings;
//some settings here
lameHelper lhHandle;
lhHandle.encode("c:/.../song.wav", "c:/.../song.mp3", settings, proc);
return 0;
}
encode(char* pcm_in, char* mp3_out, settings_t settings, WNDPROC callback_proc, bool async);
此成员函数是异步的(即,不会阻塞)。
参数
- pcm_in: PCM (*.wav) 文件的路径。
- mp3_out: mp3 的输出路径(包括文件名)。
- settings:
settings_t
结构体的对象,用于指定设置和选项。 - callback_proc: 一个回调函数 (
WNDPROC
),它将接收进度通知。 - async: 如果设置为
TRUE
,函数将是异步的;如果设置为FALSE
,函数将是同步的,并且表现与 ncode(char* pcm_in, char* mp3_out, settings_t settings, WNDPROC callback_proc) 完全相同。默认为 FALSE。
返回值
如果 async
设置为 TRUE
,函数在成功时返回一个 HANDLE
,如果达到最大允许进程数则返回 -3。如果发生任何其他错误,将发送 LH_ERROR
消息,其中 WPARAM
包含错误代码。
如果 async
设置为 FALSE
,成员函数在成功时返回 0
,如果一个或两个路径不可读或不可写则返回 -1
,如果 LAME 初始化失败则返回 -2
。
一个异步示例。
#include "lameHelper.h" HRESULT CALLBACK proc1(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { case LH_STARTED: //Start of encoding / decodeing break; case LH_COMPUTED: //Update of percentage done //wParam contains the percentage as int //the best way to use this is to pass wParam's value into a progress bar printf("%i ", wParam); break; case LH_ERROR: printf("Failed with error code %i\n", wParam); break; case LH_DONE: //Notifying end of encoding / decoding break; } return 0; } HRESULT CALLBACK proc2(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); HRESULT CALLBACK proc3(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); int main() { HANDLE hLameHelpers[3]; settings_t se; //Other settings lameHelper lhHandle; hLameHelpers[0] = lhHandle.encode("song1.wav", "song1.mp3", se, proc1, true); hLameHelpers[1] = lhHandle.encode("song2.wav", "song2.mp3", se, proc2, true); hLameHelpers[2] = lhHandle.decode("song3.mp3", "song3.wav", proc3, true); WaitForMultipleObjects(3, hLameHelpers, TRUE, INFINITE); return 0; }
解码 (mp3 转换为 PCM)
此封装库也支持 mp3 的解码,并且有两个重载的成员函数可用于此目的。
int lameHelper::decode(char* mp3_in, char* pcm_out); int lameHelper::decode(char* mp3_in, char* pcm_out, WNDPROC callback_proc); //asynchronous member function void* decode(char* mp3_in, char* pcm_out, WNDPROC callback_proc, bool async);
解码根据 LAME 的默认设置进行。
请注意:从 mp3_in 获取的 mp3 数据应该是纯粹的 mp3 数据(即没有 id3 或 APE 标签)。要了解如何从 mp3 中移除 id3 标签,请阅读我的文章“id3lib 库的封装库”,其中 removeAllTags()
子部分。
decode(char* mp3_in, char* pcm_out)
此函数将 mp3 解码为 PCM。
参数
- mp3_in: 输入 mp3 文件的路径。
- pcm_out: 输出 PCM (*.wav) 的路径(包括文件名)。
返回值
该成员函数在成功时返回 0
,如果一个或两个路径不可读或不可写则返回 -1
,如果 LAME 初始化失败则返回 -2
。
lameHelper lhHandle; lhHandle.decode("c:/.../song.mp3", "c:/.../song.wav");
decode(char* mp3_in, char* pcm_out, WNDPROC callback_proc)
此函数将 mp3 解码为 PCM,并在过程中发送通知。
参数
- mp3_in: 输入 mp3 文件的路径。
- pcm_out: 输出 PCM (*.wav) 的路径(包括文件名)。
- callback_proc: 一个回调函数 (
WNDPROC
),它将接收进度通知。
返回值
该成员函数在成功时返回 0
,如果一个或两个路径不可读或不可写则返回 -1
,如果 LAME 初始化失败则返回 -2
。
lameHelper lhHandle;
lhHandle.decode("c:/.../song.mp3", "c:/.../song.wav", proc);//proc of above example applies
decode(char* mp3_in, char* pcm_out, WNDPROC callback_proc, bool async);
此成员函数是异步的(即,不会阻塞)。
参数
- mp3_in: 输入 mp3 文件的路径。
- pcm_out: 输出 PCM (*.wav) 的路径(包括文件名)。
- callback_proc: 一个回调函数 (
WNDPROC
),它将接收进度通知。 - async: 如果设置为
TRUE
,函数将是异步的;如果设置为FALSE
,函数将是同步的。默认为 FALSE。
返回值
如果 async
设置为 TRUE
,函数在成功时返回一个 HANDLE
,如果达到最大允许进程数则返回 -3。如果发生任何其他错误,将发送 LH_ERROR
消息,其中 WPARAM
包含错误代码。
如果 async
设置为 FALSE
,成员函数在成功时返回 0
,如果一个或两个路径不可读或不可写则返回 -1
,如果 LAME 初始化失败则返回 -2
。
历史
- 2013 年 9 月 25 日 - 添加了异步成员函数。
- 2013 年 9 月 20 日 - 初始文章。