Introduction
The way of storing and sharing audio files took a new turn in the early 1990’s following the popularization of the internet. The world use the PCM but this format requires a lot of bits and bandwidth which weren’t available then to store and stream these files (a 4 seconds stereo 44.1khz PCM file will require about 1MB or space).
The MP3 was invented which is a lossy compression of the PCM data (the removal or reduction of accuracy of certain parts of sound considered to be beyond the hearing ability of most people) which result in about 1/11 of the size of the PCM data when encoded at 128kbps.
The mp3 format gained rapid growth and popularity because of the drastic reduction in size and so does the codec/encoders which convert PCM to this file format.
LAME
Lame Aint an MP3 Encoder was created around mid-1998 by Mike Cheng with improvement still ongoing till date. It’s one of the encoders with really good quality (actually called the best by a large majority). The source can be obtained at http://lame.sourceforge.net or the compiled static library from this article attachment.
The Wrapper
This wrapper was written to ease working with LAME because of how complicated it can get (power brings complexity). The wrapper will
- Reduce encoding/decoding to just two lines of code in each case (if you are using the default value of the wrapper)
- Make settings of parameters very easy, even to the id3 tagging
Setting up your environment
If you already know how to setup your development environment to compile with LAME, please skip to the second part of this section.
I will be using Visual Studio, if you are using another IDE please find out how to link a static library to your project.
- Download and compile the LAME library from http://lame.sourceforge.net
Grab the LAME archive from this article and extract it. - Click on the Project button on the menu bar of Visual Studio, select Property Pages from the drop down menu (<Your Project Name> Property Pages), then go to Configuration Properties section. Go to the Linker subsection, then to the General item. Select Additional Library Directories from the list of now available options and add the extracted archive path to it.
- Go to the Input item and select Additional Dependencies. Add
libmp3lame-static.lib
and libmpghip-static.lib
to it (each on separate lines) - Now go back to the Configuration Properties section then to the C/C++ subsection, then to the General item. Select Additional Include Directories from the list of now available options and add the extracted archive path to it.
Environment ready for LAME.
Secondly, grab the lameHelper_dd_mm_yyyy archive and extract it
- Add the two files (lameHelper.cpp and lameHelper.h) to your project.
#include
the lameHelper.h to your project
#include "lameHelper.h"
Using the wrapper
To use the wrapper,
#include "lameHelper.h"
int main()
{
lameHelper lhHandle;
return 0;
}
Encoding (Conversion of PCM to mp3)
The class has three encode() overloaded member functions which handles conversion of PCM to 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);
void* encode(char* pcm_in, char* mp3_out, settings_t settings, WNDPROC callback_proc, bool async);
encode(char* pcm_in, char* mp3_out)
The encode(char*, char*)
can be used to encode PCM using the default settings of the wrapper as specified in settings_t::settings_t()
in lameHelper.cpp
The default settings been id3 tags are set to NULL
or empty strings, channels set to stereo, encode mode to CBR, in samplerate to 44100hz, resample frequency to 44100hz, bitrate to 128kbps and quality to 5.
Parameters
- pcm_in: the path to the PCM (*.wav) file
- mp3_out: the output path of the mp3 (including the file name)
Return Values
The member function returns 0
on success, -1
if one or both of the path is not available for read or write and -2
if LAME initialization fails.
#include "lameHelper.h"
int main()
{
lameHelper lhHandle;
lhHandle.encode("c:/.../song.wav", "c:/.../song.mp3");
return 0;
}
encode(char* pcm_in, char* mp3_out, settings_t settings)
This overloaded member function can be used to encode while specifying various settings and options.
Parameters
- pcm_in: the path to the PCM (*.wav) file
- mp3_out: the output path of the mp3 (including the file name)
- settings: object of struct settings_t which is used to specify settings and options.
Return Values
The member function returns 0
on success, -1
if one or both of the path is not available for read or write and -2
if LAME initialization fails.
settings_t
The settings_t
struct
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;
settings_t();
};
An example
#include "lameHelper.h"
int main()
{
settings_t settings;
settings.enc_mode = EM_ABR;
settings.abr_bitrate = BR_128kbps; settings.album = "The Album"; settings.albumart = "c:/.../art.jpg"; settings.track = "01";
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)
The first two method described above are both synchronous and with no notification of the progress on the task at hand. This method is also synchronous (i.e. will also block) but will send notifications of the progress of the task.
Parameters
- pcm_in: the path to the PCM (*.wav) file
- mp3_out: the output path of the mp3 (including the file name)
- settings: object of struct
settings_t
which is used to specify settings and options. - callback_proc: a callback (
WNDPROC
) function which will receive progress notifications
Return Values
The member function returns 0
on success, -1
if one or both of the path is not available for read or write and -2
if LAME initialization fails.
Notes
In WNDPROC callback_proc
, msg
receive the a LH_STARTED
message at the start of encoding/decoding, it receives an LH_COMPUTED
message with WPARAM
holding the percentage of progress (as an int
) during encoding/decoding, and LH_DONE
at the end of encoding/decoding.
A typical callback_proc
HRESULT CALLBACK proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case LH_STARTED:
break;
case LH_COMPUTED:
printf("%i ", wParam);
break;
case LH_DONE:
break;
}
return 0;
}
An example
#include "lameHelper.h"
HRESULT CALLBACK proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case LH_STARTED:
break;
case LH_COMPUTED:
printf("%i ", wParam);
break;
case LH_DONE:
break;
}
return 0;
}
int main()
{
settings_t settings;
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);
This member function is asynchronous(i.e. will not block like the other previous 3 functions).
Parameters
- pcm_in: the path to the PCM (*.wav) file
- mp3_out: the output path of the mp3 (including the file name)
- settings: object of struct
settings_t
which is used to specify settings and options. - callback_proc: a callback (
WNDPROC
) function which will receive progress notifications - async: if set to
TRUE
the function will be asynchronous and if FALSE
, the function will be synchronous and behave exactly like ncode(char* pcm_in, char* mp3_out, settings_t settings, WNDPROC callback_proc). Default is FALSE.
Return Values
If async
is set to TRUE
, the function returns an HANDLE
if successful or -3 if the maximum allowed process is reached. If any other error occurred, LH_ERROR
message is sent with WPARAM
holding the error code.
If async
is set to FALSE
, the member function returns 0
on success, -1
if one or both of the path is not available for read or write and -2
if LAME initialization fails.
An asynchronous example
#include "lameHelper.h"
HRESULT CALLBACK proc1(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case LH_STARTED:
break;
case LH_COMPUTED:
printf("%i ", wParam);
break;
case LH_ERROR:
printf("Failed with error code %i\n", wParam);
break;
case LH_DONE:
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;
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;
}
Decoding (Conversion of mp3 to PCM)
The wrapper also enable the decoding of mp3 and there are two overloaded member function for this.
int lameHelper::decode(char* mp3_in, char* pcm_out);
int lameHelper::decode(char* mp3_in, char* pcm_out, WNDPROC callback_proc);
void* decode(char* mp3_in, char* pcm_out, WNDPROC callback_proc, bool async);
Decoding it done according to LAME default settings.
PLEASE NOTE: that the mp3 data that is gotten from mp3_in is supposed to be pure mp3 data (i.e. with no id3 or APE tags). To find out how to remove id3 tags from mp3, read my "A wrapper for the id3lib library" article, the removeAllTags()
sub-section.
decode(char* mp3_in, char* pcm_out)
This decode an mp3 into PCM
Parameters
- mp3_in: the path to the mp3 input file
- pcm_out: the output path of the PCM (*.wav) (including the file name)
Return Values
The member function returns 0
on success, -1
if one or both of the path is not available for read or write and -2
if LAME initialization fails.
lameHelper lhHandle;
lhHandle.decode("c:/.../song.mp3", "c:/.../song.wav");
decode(char* mp3_in, char* pcm_out, WNDPROC callback_proc)
This decode an mp3 into PCM sending notification in the process
Parameters
- mp3_in: the path to the mp3 input file
- pcm_out: the output path of the PCM (*.wav) (including the file name)
- callback_proc: a callback (
WNDPROC
) function which will receive progress notifications
Return Values
The member function returns 0
on success, -1
if one or both of the path is not available for read or write and -2
if LAME initialization fails.
lameHelper lhHandle;
lhHandle.decode("c:/.../song.mp3", "c:/.../song.wav", proc);
decode(char* mp3_in, char* pcm_out, WNDPROC callback_proc, bool async);
This member function is asynchronous(i.e. will not block).
Parameters
- mp3_in: the path to the mp3 input file
- pcm_out: the output path of the PCM (*.wav) (including the file name)
- callback_proc: a callback (
WNDPROC
) function which will receive progress notifications - async: if set to
TRUE
the function will be asynchronous and if FALSE
, the function will be synchronous. Default is FALSE.
Return Values
If async
is set to TRUE
, the function returns an HANDLE
if successful or -3 if the maximum allowed process is reached. If any other error occurred, LH_ERROR
message is sent with WPARAM
holding the error code.
If async
is set to FALSE
, the member function returns 0
on success, -1
if one or both of the path is not available for read or write and -2
if LAME initialization fails.
History
- 25th of September, 2013 - Asynchronous member functions added
- 20th of September, 2013 - Initial Article