3 Copyright (C) 2005 and later Cockos Incorporated
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
38 #include "wdlcstring.h"
39 #include "lameencdec.h"
43 #include <Carbon/Carbon.h>
49 typedef enum MPEG_mode_e
{
52 DUAL_CHANNEL
, /* LAME doesn't supports this! */
55 MAX_INDICATOR
/* Don't use this! It's used for sanity checks. */
63 int (*set_in_samplerate
)(lame_t
, int);
64 int (*set_num_channels
)(lame_t
,int);
65 int (*set_out_samplerate
)(lame_t
,int);
66 int (*set_quality
)(lame_t
,int);
67 int (*set_mode
)(lame_t
,MPEG_mode
);
68 int (*set_brate
)(lame_t
, int);
69 int (*init_params
)(lame_t
);
70 int (*get_framesize
)(lame_t
);
72 int (*encode_buffer_float
)(lame_t
,
73 const float buffer_l
[], /* PCM data for left channel */
74 const float buffer_r
[], /* PCM data for right channel */
75 const int nsamples
, /* number of samples per channel */
76 unsigned char* mp3buf
, /* pointer to encoded MP3 stream */
77 const int mp3buf_size
);
78 int (*encode_flush
)(lame_t
,unsigned char* mp3buf
, int size
);
81 int (*set_VBR
)(lame_t
, int);
82 int (*set_VBR_q
)(lame_t
, int);
83 int (*set_VBR_mean_bitrate_kbps
)(lame_t
, int);
84 int (*set_VBR_min_bitrate_kbps
)(lame_t
, int);
85 int (*set_VBR_max_bitrate_kbps
)(lame_t
, int);
86 size_t (*get_lametag_frame
)(lame_t
, unsigned char *, size_t);
87 const char *(*get_lame_version
)();
91 #define LAME_DEBUG_LOADING(x)
93 #define LAME_DEBUG_LOADING(x) OutputDebugString(x)
96 static char s_last_dll_file
[128];
98 static bool tryLoadDLL2(const char *name
)
101 HINSTANCE dll
= LoadLibrary(name
);
103 void *dll
=dlopen(name
,RTLD_NOW
|RTLD_LOCAL
);
106 if (!dll
) return false;
108 LAME_DEBUG_LOADING("trying to load");
109 LAME_DEBUG_LOADING(name
);
112 #define GETITEM(x) if (NULL == (*(void **)&lame.x = GetProcAddress((HINSTANCE)dll,"lame_" #x))) errcnt++;
113 #define GETITEM_NP(x) if (NULL == (*(void **)&lame.x = GetProcAddress((HINSTANCE)dll, #x))) errcnt++;
115 #define GETITEM(x) if (NULL == (*(void **)&lame.x = dlsym(dll,"lame_" #x))) errcnt++;
116 #define GETITEM_NP(x) if (NULL == (*(void **)&lame.x = dlsym(dll,#x))) errcnt++;
120 GETITEM(set_in_samplerate
)
121 GETITEM(set_num_channels
)
122 GETITEM(set_out_samplerate
)
127 GETITEM(get_framesize
)
128 GETITEM(encode_buffer_float
)
129 GETITEM(encode_flush
)
131 int errcnt2
= errcnt
;
134 GETITEM(set_VBR_mean_bitrate_kbps
)
135 GETITEM(set_VBR_min_bitrate_kbps
)
136 GETITEM(set_VBR_max_bitrate_kbps
)
137 GETITEM(get_lametag_frame
)
138 GETITEM_NP(get_lame_version
)
143 memset(&lame
, 0, sizeof(lame
));
153 LAME_DEBUG_LOADING("loaded normal mode");
155 lstrcpyn_safe(s_last_dll_file
, name
, sizeof(s_last_dll_file
));
157 // if (!strstr(name,"\\"))
158 GetModuleFileName(dll
,s_last_dll_file
, (DWORD
)sizeof(s_last_dll_file
));
160 // if (!strstr(name,"/"))
163 dladdr((void*)lame
.init
,&inf
);
165 lstrcpyn_safe(s_last_dll_file
,inf
.dli_fname
,sizeof(s_last_dll_file
));
174 void LameEncoder::InitDLL(const char *extrapath
, bool forceRetry
)
180 else if (a
> 30) return; // give up
186 const char *dll
= "libmp3lame.dll";
187 #elif defined(__APPLE__)
188 const char *dll
= "libmp3lame.dylib";
190 const char *dll
= "libmp3lame.so.0";
195 snprintf(me
,sizeof(me
),"%s%c%s",extrapath
,WDL_DIRCHAR
,dll
);
196 if (tryLoadDLL2(me
)) { a
= -1; return; }
199 if (tryLoadDLL2(dll
)) a
=-1;
203 const char *LameEncoder::GetLibName() { return s_last_dll_file
; }
205 const char *LameEncoder::GetInfo()
207 static char buf
[128];
208 if (!CheckDLL()) return NULL
;
209 const char *p
= lame
.get_lame_version
? lame
.get_lame_version() : NULL
;
212 snprintf(buf
, sizeof(buf
), "LAME %s", p
);
218 int LameEncoder::CheckDLL() // returns 1 for lame API, 2 for Blade, 0 for none
223 !lame
.set_in_samplerate
||
224 !lame
.set_num_channels
||
225 !lame
.set_out_samplerate
||
230 !lame
.get_framesize
||
231 !lame
.encode_buffer_float
||
241 LameEncoder::LameEncoder(int srate
, int nch
, int bitrate
, int stereomode
, int quality
, int vbrmethod
, int vbrquality
, int vbrmax
, int abr
)
252 m_encoder_nch
= stereomode
== 3 ? 1 : m_nch
;
255 m_lamestate
=lame
.init();
262 lame
.set_in_samplerate(m_lamestate
, srate
);
263 lame
.set_num_channels(m_lamestate
,m_encoder_nch
);
266 int maxbr
= (vbrmethod
!= -1 ? vbrmax
: bitrate
);
267 if (outrate
>=32000 && maxbr
<= 32*m_encoder_nch
) outrate
/=2;
269 lame
.set_out_samplerate(m_lamestate
,outrate
);
270 lame
.set_quality(m_lamestate
,(quality
>9 ||quality
<0) ? 0 : quality
);
271 lame
.set_mode(m_lamestate
,(MPEG_mode
) (m_encoder_nch
==1?3 :stereomode
));
272 lame
.set_brate(m_lamestate
,bitrate
);
274 //int vbrmethod (-1 no vbr), int vbrquality (nVBRQuality), int vbrmax, int abr
275 if (vbrmethod
!= -1 && lame
.set_VBR
)
278 if (vbrmethod
== 4) vm
= 3; //ABR
279 lame
.set_VBR(m_lamestate
,vm
);
281 if (lame
.set_VBR_q
) lame
.set_VBR_q(m_lamestate
,vbrquality
);
283 if (vbrmethod
== 4&&lame
.set_VBR_mean_bitrate_kbps
)
285 lame
.set_VBR_mean_bitrate_kbps(m_lamestate
,abr
);
287 if (lame
.set_VBR_max_bitrate_kbps
)
289 lame
.set_VBR_max_bitrate_kbps(m_lamestate
,vbrmax
);
291 if (lame
.set_VBR_min_bitrate_kbps
)
293 lame
.set_VBR_min_bitrate_kbps(m_lamestate
,bitrate
);
296 lame
.init_params(m_lamestate
);
297 in_size_samples
=lame
.get_framesize(m_lamestate
);
299 outtmp
.Resize(65536);
302 void LameEncoder::Encode(float *in
, int in_spls
, int spacing
)
304 if (errorstat
) return;
308 if (m_nch
> 1 && m_encoder_nch
==1)
314 for (x
= 0; x
< in_spls
; x
++)
316 float f
=in
[pos
]+in
[pos
+1];
318 spltmp
[0].Add(&f
,sizeof(float));
322 else if (m_encoder_nch
> 1) // deinterleave
327 for (x
= 0; x
< in_spls
; x
++)
331 spltmp
[0].Add(&f
,sizeof(float));
335 spltmp
[1].Add(&f
,sizeof(float));
344 for (x
= 0; x
< in_spls
; x
++)
348 spltmp
[0].Add(&f
,sizeof(float));
356 int a
= spltmp
[0].Available()/sizeof(float);
357 if (a
>= in_size_samples
) a
= in_size_samples
;
358 else if (a
<1 || in_spls
>0) break; // not enough samples available, and not flushing
360 int dwo
=lame
.encode_buffer_float(m_lamestate
,(float *)spltmp
[0].Get(),(float*)spltmp
[m_encoder_nch
>1].Get(), a
,(unsigned char *)outtmp
.Get(),outtmp
.GetSize());
361 outqueue
.Add(outtmp
.Get(),dwo
);
362 spltmp
[0].Advance(a
*sizeof(float));
363 if (m_encoder_nch
> 1) spltmp
[1].Advance(a
*sizeof(float));
368 int a
=lame
.encode_flush(m_lamestate
,(unsigned char *)outtmp
.Get(),outtmp
.GetSize());
369 if (a
>0) outqueue
.Add(outtmp
.Get(),a
);
381 static BOOL
HasUTF8(const char *_str
)
383 const unsigned char *str
= (const unsigned char *)_str
;
384 if (!str
) return FALSE
;
387 unsigned char c
= *str
;
388 if (c
>= 0xC2) // discard overlongs
390 if (c
<= 0xDF && str
[1] >=0x80 && str
[1] <= 0xBF) return TRUE
;
391 else if (c
<= 0xEF && str
[1] >=0x80 && str
[1] <= 0xBF && str
[2] >=0x80 && str
[2] <= 0xBF) return TRUE
;
392 else if (c
<= 0xF4 && str
[1] >=0x80 && str
[1] <= 0xBF && str
[2] >=0x80 && str
[2] <= 0xBF) return TRUE
;
400 LameEncoder::~LameEncoder()
404 if (m_vbrfile
.Get()[0] && lame
.get_lametag_frame
)
406 unsigned char buf
[16384];
407 size_t a
=lame
.get_lametag_frame(m_lamestate
,buf
,sizeof(buf
));
408 if (a
>0 && a
<=sizeof(buf
))
412 if (HasUTF8(m_vbrfile
.Get()) && GetVersion()<0x80000000)
415 if (MultiByteToWideChar(CP_UTF8
,MB_ERR_INVALID_CHARS
,m_vbrfile
.Get(),-1,wf
,2048))
417 fp
= _wfopen(wf
,L
"r+b");
421 if (!fp
) fp
= fopen(m_vbrfile
.Get(),"r+b");
424 fseek(fp
,0,SEEK_SET
);
430 lame
.close(m_lamestate
);