Lame
lastmod 2018-08-17created 2014-01-0512 edits
LAME is an open-source MP3 encoder. The name LAME is a recursive acronym for “LAME Ain't an MP3 Encoder”. Despite the name, it is in fact one of the most widely used MP3 encoders today. As of 2004, LAME was known to produce the highest-quality MP3 files at bitrates of 128 kbit/s and above. In a public listening test in early 2004, files encoded with LAME reportedly showed the least degradation in sound quality compared to the original audio.
Porting and using LAME MP3 on Android with JNI
Preparing libraries: The LAME library can be downloaded from the following website: http://lame.sourceforge.net/download.php When the download is finished, an initial version (without a functional wrapper) of the shared library being created can be built. In order to do so, it is needed to create a directory called jni in the project's root. Then copy the libmp3lame directory from the downloaded archive to the created one. It is needed to copy all *.c and *.h files, so all others can be skipped. The main library header file named lame.h is also necessary. It is placed in the include directory in the downloaded archive. Copy it as the rest of files to the libmp3lame directory. Some preparations are to be made yet. Since the standard compilation method with autoconf will not be used, some changes in header files need to be performed. First of all edit util.h and replace line:
with used architecture 32-bit float implementation, which is simply float:
In set_get.h replace
with
LAME MPEG1 or MPEG2 Audio Layer III Select logic
When using LAME, the choice between MPEG1 and MPEG2 changes depending on the 'Output Samplerate'.
For details, refer to SmpFrqIndex() in util.c.
/* convert samp freq in Hz to index */
int SmpFrqIndex(int sample_freq, int *const version)
{
// version = 0: MPEG2.
// version = 1: MPEG1.
switch (sample_freq) {
case 44100:
*version = 1;
return 0;
case 48000:
*version = 1;
return 1;
case 32000:
*version = 1;
return 2;
case 22050:
*version = 0;
return 0;
case 24000:
*version = 0;
return 1;
case 16000:
*version = 0;
return 2;
case 11025:
*version = 0;
return 0;
case 12000:
*version = 0;
return 1;
case 8000:
*version = 0;
return 2;
default:
*version = 0;
return -1;
}
}
The reason this logic is included can be found by reading Wikipedia.
MPEG-2에도 Audio Layer-3이 있어 MP3라고 부르지만, MPEG-2 AudioBC (Backward Compatible)이 정식 명칭이다.
MPEG-2 MP3는 압축 방식은 동일하지만, 비트율이 낮은 매체를 위한 낮은 고정 비트율, 다채널 대응이 포함되어 있다.
이 형식은 유럽형 DVD에 채용되어 있다.
또한 ISO 표준 규격이 아닌 MPEG2.5 Audio Layer 3 이라는 것도 있다.
Sample encoding for iOS
/// @brief 기본 설정 PCM/MP3의 Sample Rate.
#define DEFAULT_SAMPLE_RATE 44100.0f
// ...
- (void)readyRecorder
{
// Recorder setting...
NSMutableDictionary *recordSetting = [[NSMutableDictionary alloc] init];
[recordSetting setValue:[NSNumber numberWithInt:kAudioFormatLinearPCM] forKey:AVFormatIDKey];
[recordSetting setValue:[NSNumber numberWithFloat:DEFAULT_SAMPLE_RATE] forKey:AVSampleRateKey];
[recordSetting setValue:[NSNumber numberWithInt:2] forKey:AVNumberOfChannelsKey];
[recordSetting setValue:[NSNumber numberWithInt:AVAudioQualityMax] forKey:AVEncoderAudioQualityKey];
// ...
}
- (void)runConvertPcmToMp3
{
[NSThread detachNewThreadSelector:@selector(convertPcmToMp3) toTarget:self withObject:nil];
}
- (void)convertPcmToMp3
{
BOOL isConvertSuccess = NO;
FILE * pcm = NULL;
FILE * mp3 = NULL;
lame_t lame = NULL;
@try {
int read = 0, write = 0;
pcm = fopen([recordPcmPath cStringUsingEncoding:1], "rb"); // source
fseek(pcm, 4 * 1024, SEEK_CUR); // skip file header
mp3 = fopen([recordMp3Path cStringUsingEncoding:1], "wb"); // output
const int PCM_SIZE = 8192;
const int MP3_SIZE = 8192;
short int pcm_buffer[PCM_SIZE*2] = {0,};
unsigned char mp3_buffer[MP3_SIZE] = {0,};
lame = lame_init();
lame_set_in_samplerate(lame, DEFAULT_SAMPLE_RATE);
lame_set_VBR(lame, vbr_default);
lame_init_params(lame);
do {
read = fread(pcm_buffer, 2 * sizeof(short int), PCM_SIZE, pcm);
if (read == 0) {
write = lame_encode_flush(lame, mp3_buffer, MP3_SIZE);
} else {
write = lame_encode_buffer_interleaved(lame, pcm_buffer, read, mp3_buffer, MP3_SIZE);
}
fwrite(mp3_buffer, write, 1, mp3);
} while (read != 0);
// convert success.
isConvertSuccess = YES;
} @catch (NSException * e) {
isConvertSuccess = NO;
NSLog(@"PCM to MP3 Convert failure: %@", [e description]);
} @finally {
if (lame != NULL) {
lame_close(lame);
}
if (mp3 != NULL) {
fclose(mp3);
}
if (pcm != NULL) {
fclose(pcm);
}
[self performSelectorOnMainThread:@selector(convertMp3Finish:)
withObject:[NSNumber numberWithBool:isConvertSuccess]
waitUntilDone:YES];
}
}
- (void)convertMp3Finish:(NSNumber*)convertResult
{
// ...
}
See also
Favorite site
- LAME website.
- Wikipedia (en) description of LAME.
- LAME Libraries.
- Github: MP3 voice recorder sample for Android.
- Github: LAME for Android.
References
-
Porting_and_using_LAME_MP3_on_Android_with_JNI.pdf ↩