Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / multimedia / audio

The LAME wrapper (An audio converter)

4.56/5 (13 votes)
25 Sep 2013CPOL7 min read 56.6K   3.4K  
A c++ wrapper for the LAME library that reduces conversion of PCM (*.wav) to mp3 and vice versa to just two lines of codes

 

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 

  1. Reduce encoding/decoding to just two lines of code in each case (if you are using the default value of the wrapper) 
  2. 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.

  1. Download and compile the LAME library from http://lame.sourceforge.net Grab the LAME archive from this article and extract it.
  2. 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. 
  3. Go to the Input item and select Additional Dependencies. Add libmp3lame-static.lib and libmpghip-static.lib to it (each on separate lines)  
  4. 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

  1. Add the two files (lameHelper.cpp and lameHelper.h) to your project.
  2. #include the lameHelper.h to your project  
C++
#include "lameHelper.h"

Using the wrapper 

To use the wrapper, 

C++
#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

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

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. 

C++
#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)

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 

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

An example

C++
#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)

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

C++
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;
}

An example  

C++
#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);

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:
		//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;
}

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

//asynchronous member function
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. 

C++
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);

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

  1. 25th of September, 2013 - Asynchronous member functions added
  2. 20th of September, 2013 - Initial Article

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)