[IPLUG/AAX] remove IPlugAAX::SetParameterFromGUI()
[wdl/wdl-ol.git] / WDL / lameencdec.cpp
blobd1d7460d835add8deeb557b1ca74e8c1282bb806
1 /*
2 WDL - lameencdec.cpp
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.
27 #ifdef _WIN32
28 #include <windows.h>
29 #else
30 #include <unistd.h>
31 #endif
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
37 #include "wdlcstring.h"
38 #include "lameencdec.h"
41 #if defined(_WIN32) && !defined(_WIN64)
43 #define SUPPORT_BLADE_MODE
45 /// the blade mode is only use on 32-bit windows and is completely obsolete (libmp3lame.dll API is preferable and better)
46 #pragma pack(push)
47 #pragma pack(1)
49 #ifdef __cplusplus
50 extern "C" {
51 #endif
53 /* encoding formats */
55 #define BE_CONFIG_MP3 0
56 #define BE_CONFIG_LAME 256
58 /* type definitions */
60 typedef void *HBE_STREAM;
61 typedef HBE_STREAM *PHBE_STREAM;
62 typedef unsigned long BE_ERR;
64 /* error codes */
66 #define BE_ERR_SUCCESSFUL 0x00000000
67 #define BE_ERR_INVALID_FORMAT 0x00000001
68 #define BE_ERR_INVALID_FORMAT_PARAMETERS 0x00000002
69 #define BE_ERR_NO_MORE_HANDLES 0x00000003
70 #define BE_ERR_INVALID_HANDLE 0x00000004
71 #define BE_ERR_BUFFER_TOO_SMALL 0x00000005
73 /* other constants */
75 #define BE_MAX_HOMEPAGE 128
77 /* format specific variables */
79 #define BE_MP3_MODE_STEREO 0
80 #define BE_MP3_MODE_JSTEREO 1
81 #define BE_MP3_MODE_DUALCHANNEL 2
82 #define BE_MP3_MODE_MONO 3
84 #define MPEG1 1
85 #define MPEG2 0
87 #define CURRENT_STRUCT_VERSION 1
88 #define CURRENT_STRUCT_SIZE sizeof(BE_CONFIG) // is currently 331 bytes
90 /* OBSOLETE, VALUES STILL WORK
91 typedef enum
93 NORMAL_QUALITY=0,
94 LOW_QUALITY,
95 HIGH_QUALITY,
96 VOICE_QUALITY
97 } LAME_QUALTIY_PRESET;
102 typedef enum
104 VBR_METHOD_NONE = -1,
105 VBR_METHOD_DEFAULT = 0,
106 VBR_METHOD_OLD = 1,
107 VBR_METHOD_NEW = 2,
108 VBR_METHOD_MTRH = 3,
109 VBR_METHOD_ABR = 4
110 } VBRMETHOD;
112 typedef enum
114 LQP_NOPRESET=-1,
116 // QUALITY PRESETS
117 LQP_NORMAL_QUALITY=0,
118 LQP_LOW_QUALITY,
119 LQP_HIGH_QUALITY,
120 LQP_VOICE_QUALITY,
121 LQP_R3MIX_QUALITY,
122 LQP_VERYHIGH_QUALITY,
124 // NEW PRESET VALUES
125 LQP_PHONE =1000,
126 LQP_SW =2000,
127 LQP_AM =3000,
128 LQP_FM =4000,
129 LQP_VOICE =5000,
130 LQP_RADIO =6000,
131 LQP_TAPE =7000,
132 LQP_HIFI =8000,
133 LQP_CD =9000,
134 LQP_STUDIO =10000
136 } LAME_QUALTIY_PRESET;
140 typedef struct {
141 DWORD dwConfig; // BE_CONFIG_XXXXX
142 // Currently only BE_CONFIG_MP3 is supported
143 union {
145 struct {
147 DWORD dwSampleRate; // 48000, 44100 and 32000 allowed. RG note: also seems to support 16000, 22050, 24000.
148 BYTE byMode; // BE_MP3_MODE_STEREO, BE_MP3_MODE_DUALCHANNEL, BE_MP3_MODE_MONO
149 WORD wBitrate; // 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256 and 320 allowed. RG note: also seems to support 8,16,24.
150 BOOL bPrivate;
151 BOOL bCRC;
152 BOOL bCopyright;
153 BOOL bOriginal;
155 } mp3; // BE_CONFIG_MP3
157 struct
159 // STRUCTURE INFORMATION
160 DWORD dwStructVersion;
161 DWORD dwStructSize;
163 // BASIC ENCODER SETTINGS
164 DWORD dwSampleRate; // SAMPLERATE OF INPUT FILE
165 DWORD dwReSampleRate; // DOWNSAMPLERATE, 0=ENCODER DECIDES
166 LONG nMode; // BE_MP3_MODE_STEREO, BE_MP3_MODE_DUALCHANNEL, BE_MP3_MODE_MONO
167 DWORD dwBitrate; // CBR bitrate, VBR min bitrate
168 DWORD dwMaxBitrate; // CBR ignored, VBR Max bitrate
169 LONG nPreset; // Quality preset, use one of the settings of the LAME_QUALITY_PRESET enum
170 DWORD dwMpegVersion; // FUTURE USE, MPEG-1 OR MPEG-2
171 DWORD dwPsyModel; // FUTURE USE, SET TO 0
172 DWORD dwEmphasis; // FUTURE USE, SET TO 0
174 // BIT STREAM SETTINGS
175 BOOL bPrivate; // Set Private Bit (TRUE/FALSE)
176 BOOL bCRC; // Insert CRC (TRUE/FALSE)
177 BOOL bCopyright; // Set Copyright Bit (TRUE/FALSE)
178 BOOL bOriginal; // Set Original Bit (TRUE/FALSE)
180 // VBR STUFF
181 BOOL bWriteVBRHeader; // WRITE XING VBR HEADER (TRUE/FALSE)
182 BOOL bEnableVBR; // USE VBR ENCODING (TRUE/FALSE)
183 INT nVBRQuality; // VBR QUALITY 0..9
184 DWORD dwVbrAbr_bps; // Use ABR in stead of nVBRQuality
185 VBRMETHOD nVbrMethod;
186 BOOL bNoRes; // Disable Bit resorvoir
188 BYTE btReserved[255-3*sizeof(DWORD)]; // FUTURE USE, SET TO 0
190 } LHV1; // LAME header version 1
192 struct {
194 DWORD dwSampleRate;
195 BYTE byMode;
196 WORD wBitrate;
197 BYTE byEncodingMethod;
199 } aac;
201 } format;
203 } BE_CONFIG, *PBE_CONFIG;
206 typedef struct {
208 // BladeEnc DLL Version number
210 BYTE byDLLMajorVersion;
211 BYTE byDLLMinorVersion;
213 // BladeEnc Engine Version Number
215 BYTE byMajorVersion;
216 BYTE byMinorVersion;
218 // DLL Release date
220 BYTE byDay;
221 BYTE byMonth;
222 WORD wYear;
224 // BladeEnc Homepage URL
226 CHAR zHomepage[BE_MAX_HOMEPAGE + 1];
228 BYTE byAlphaLevel;
229 BYTE byBetaLevel;
230 BYTE byMMXEnabled;
232 BYTE btReserved[125];
235 } BE_VERSION, *PBE_VERSION;
238 #pragma pack(pop)
240 #ifdef __cplusplus
242 #endif
244 static struct
246 BE_ERR (*beInitStream)(PBE_CONFIG, PDWORD, PDWORD, void **str);
247 BE_ERR (*beCloseStream)(void *str);
248 BE_ERR (*beEncodeChunkFloatS16NI)(void *str, DWORD, PFLOAT, PFLOAT, PBYTE, PDWORD);
249 BE_ERR (*beDeinitStream)(void *str, PBYTE, PDWORD);
250 BE_ERR (*beWriteInfoTag)(HBE_STREAM, const char *);
251 VOID (*beVersion)(PBE_VERSION);
252 } bladeAPI;
254 #endif // SUPPORT_BLADE_MODE
258 #ifdef __APPLE__
259 #include <Carbon/Carbon.h>
260 #endif
261 #ifndef _WIN32
262 #include <dlfcn.h>
263 #endif
265 typedef enum MPEG_mode_e {
266 STEREO = 0,
267 JOINT_STEREO,
268 DUAL_CHANNEL, /* LAME doesn't supports this! */
269 MONO,
270 NOT_SET,
271 MAX_INDICATOR /* Don't use this! It's used for sanity checks. */
272 } MPEG_mode;
274 typedef void *lame_t;
276 static struct {
277 int (*close)(lame_t);
278 lame_t (*init)();
279 int (*set_in_samplerate)(lame_t, int);
280 int (*set_num_channels)(lame_t,int);
281 int (*set_out_samplerate)(lame_t,int);
282 int (*set_quality)(lame_t,int);
283 int (*set_mode)(lame_t,MPEG_mode);
284 int (*set_brate)(lame_t, int);
285 int (*init_params)(lame_t);
286 int (*get_framesize)(lame_t);
288 int (*encode_buffer_float)(lame_t,
289 const float buffer_l [], /* PCM data for left channel */
290 const float buffer_r [], /* PCM data for right channel */
291 const int nsamples, /* number of samples per channel */
292 unsigned char* mp3buf, /* pointer to encoded MP3 stream */
293 const int mp3buf_size );
294 int (*encode_flush)(lame_t,unsigned char* mp3buf, int size);
296 // these are optional
297 int (*set_VBR)(lame_t, int);
298 int (*set_VBR_q)(lame_t, int);
299 int (*set_VBR_mean_bitrate_kbps)(lame_t, int);
300 int (*set_VBR_min_bitrate_kbps)(lame_t, int);
301 int (*set_VBR_max_bitrate_kbps)(lame_t, int);
302 size_t (*get_lametag_frame)(lame_t, unsigned char *, size_t);
303 const char *(*get_lame_version)();
304 } lame;
306 #if 1
307 #define LAME_DEBUG_LOADING(x)
308 #else
309 #define LAME_DEBUG_LOADING(x) OutputDebugString(x)
310 #endif
312 static char s_last_dll_file[128];
314 static bool tryLoadDLL2(const char *name)
316 #ifdef _WIN32
317 HINSTANCE dll = LoadLibrary(name);
318 #else
319 void *dll=dlopen(name,RTLD_NOW|RTLD_LOCAL);
320 #endif
322 if (!dll) return false;
324 LAME_DEBUG_LOADING("trying to load");
325 LAME_DEBUG_LOADING(name);
326 int errcnt = 0;
327 #ifdef _WIN32
328 #define GETITEM(x) if (NULL == (*(void **)&lame.x = GetProcAddress((HINSTANCE)dll,"lame_" #x))) errcnt++;
329 #define GETITEM_NP(x) if (NULL == (*(void **)&lame.x = GetProcAddress((HINSTANCE)dll, #x))) errcnt++;
330 #else
331 #define GETITEM(x) if (NULL == (*(void **)&lame.x = dlsym(dll,"lame_" #x))) errcnt++;
332 #define GETITEM_NP(x) if (NULL == (*(void **)&lame.x = dlsym(dll,#x))) errcnt++;
333 #endif
334 GETITEM(close)
335 GETITEM(init)
336 GETITEM(set_in_samplerate)
337 GETITEM(set_num_channels)
338 GETITEM(set_out_samplerate)
339 GETITEM(set_quality)
340 GETITEM(set_mode)
341 GETITEM(set_brate)
342 GETITEM(init_params)
343 GETITEM(get_framesize)
344 GETITEM(encode_buffer_float)
345 GETITEM(encode_flush)
347 int errcnt2 = errcnt;
348 GETITEM(set_VBR)
349 GETITEM(set_VBR_q)
350 GETITEM(set_VBR_mean_bitrate_kbps)
351 GETITEM(set_VBR_min_bitrate_kbps)
352 GETITEM(set_VBR_max_bitrate_kbps)
353 GETITEM(get_lametag_frame)
354 GETITEM_NP(get_lame_version)
355 #undef GETITEM
356 #undef GETITEM_NP
357 if (errcnt2)
359 memset(&lame, 0, sizeof(lame));
361 LAME_DEBUG_LOADING("trying blade mode");
363 #ifdef SUPPORT_BLADE_MODE
364 // try getting blade API
365 *((void**)&bladeAPI.beInitStream) = (void *) GetProcAddress(dll, "beInitStream");
366 *((void**)&bladeAPI.beCloseStream) = (void *) GetProcAddress(dll, "beCloseStream");
367 *((void**)&bladeAPI.beEncodeChunkFloatS16NI) = (void *) GetProcAddress(dll, "beEncodeChunkFloatS16NI");
368 *((void**)&bladeAPI.beDeinitStream) = (void *) GetProcAddress(dll, "beDeinitStream");
369 *((void**)&bladeAPI.beVersion) = (void *) GetProcAddress(dll, "beVersion");
370 *((void**)&bladeAPI.beWriteInfoTag) = (void*) GetProcAddress(dll, "beWriteInfoTag");
373 if (bladeAPI.beInitStream &&
374 bladeAPI.beCloseStream &&
375 bladeAPI.beEncodeChunkFloatS16NI &&
376 bladeAPI.beDeinitStream &&
377 bladeAPI.beVersion)
379 LAME_DEBUG_LOADING("got blade mode");
380 errcnt2 = 0;
382 else
384 memset(&bladeAPI, 0, sizeof(bladeAPI));
386 #endif
387 if (errcnt2)
389 #ifdef _WIN32
390 FreeLibrary(dll);
391 #else
392 dlclose(dll);
393 #endif
394 return false;
398 LAME_DEBUG_LOADING("loaded normal mode");
400 lstrcpyn_safe(s_last_dll_file, name, sizeof(s_last_dll_file));
401 #ifdef _WIN32
402 // if (!strstr(name,"\\"))
403 GetModuleFileName(dll,s_last_dll_file, (DWORD)sizeof(s_last_dll_file));
404 #else
405 // if (!strstr(name,"/"))
407 Dl_info inf={0,};
408 dladdr((void*)lame.init,&inf);
409 if (inf.dli_fname)
410 lstrcpyn_safe(s_last_dll_file,inf.dli_fname,sizeof(s_last_dll_file));
412 #endif
414 return true;
418 #ifdef _WIN32
419 static bool tryLoadDLL(const char *extrapath, const char *dllname)
421 char me[1024];
423 if (extrapath)
425 lstrcpyn_safe(me,extrapath,sizeof(me)-64);
426 lstrcatn(me,"\\",sizeof(me));
427 lstrcatn(me,dllname,sizeof(me));
428 if (tryLoadDLL2(me)) return true;
431 GetModuleFileName(NULL,me,sizeof(me)-64);
433 char *p=me;
434 while (*p) p++;
435 while(p>=me && *p!='\\') p--;
437 strcpy(++p,dllname);
439 if (tryLoadDLL2(me) || tryLoadDLL2(dllname)) return true;
441 return false;
443 #elif defined(__APPLE__)
444 static bool tryLoadDLL(const char *extrapath)
446 char me[1024];
448 if (extrapath)
450 lstrcpyn_safe(me,extrapath,sizeof(me)-64);
451 lstrcatn(me,"/libmp3lame.dylib",sizeof(me));
452 if (tryLoadDLL2(me)) return true;
455 if (tryLoadDLL2("/Library/Application Support/libmp3lame.dylib") ||
456 tryLoadDLL2("/usr/local/lib/libmp3lame.dylib") ||
457 tryLoadDLL2("/usr/lib/libmp3lame.dylib") ||
458 tryLoadDLL2("libmp3lame.dylib")) return true;
460 bool ok=false;
461 CFBundleRef bund=CFBundleGetMainBundle();
462 if (bund)
464 CFURLRef url=CFBundleCopyBundleURL(bund);
465 if (url)
467 char buf[8192];
468 if (CFURLGetFileSystemRepresentation(url,true,(UInt8*)buf,sizeof(buf)-128))
470 char *p=buf;
471 while (*p) p++;
472 while (p>=buf && *p != '/') p--;
473 if (p>=buf)
475 strcat(buf,"/Contents/Plugins/libmp3lame.dylib");
476 ok = tryLoadDLL2(buf);
478 if (!ok)
480 strcpy(p,"/libmp3lame.dylib");
481 ok = tryLoadDLL2(buf);
483 if (!ok)
485 strcpy(p,"/Plugins/libmp3lame.dylib");
486 ok = tryLoadDLL2(buf);
490 CFRelease(url);
493 return ok;
495 #else // generic posix
496 static bool tryLoadDLL(const char *extrapath)
498 if (extrapath)
500 char me[1024];
501 lstrcpyn_safe(me,extrapath,sizeof(me)-64);
502 lstrcatn(me,"/libmp3lame.so",sizeof(me));
503 if (tryLoadDLL2(me)) return true;
505 if (tryLoadDLL2("/usr/local/lib/libmp3lame.so")||
506 tryLoadDLL2("/usr/lib/libmp3lame.so")||
507 tryLoadDLL2("libmp3lame.so")||
508 tryLoadDLL2("/usr/local/lib/libmp3lame.so.0")||
509 tryLoadDLL2("/usr/lib/libmp3lame.so.0")||
510 tryLoadDLL2("libmp3lame.so.0")) return true;
512 char tmp[64];
513 sprintf(tmp,"/proc/%d/exe",getpid());
514 char buf[1024];
515 buf[0]=0;
516 if (readlink(tmp,buf,sizeof(buf)-128)>0 && buf[0])
518 char *p = buf;
519 while (*p) p++;
520 while (p>buf && *p != '/') p--;
521 if (p>buf)
523 strcpy(p,"/Plugins/libmp3lame.so");
524 if (tryLoadDLL2(buf)) return true;
526 strcpy(p,"/libmp3lame.so");
527 if (tryLoadDLL2(buf)) return true;
530 return false;
532 #endif
535 void LameEncoder::InitDLL(const char *extrapath, bool forceRetry)
537 static int a;
538 if (a<0) return;
540 if (forceRetry) a=0;
541 else if (a > 30) return; // give up
543 a++;
545 #ifdef _WIN32
546 #ifdef _WIN64
547 if (tryLoadDLL(extrapath, "libmp3lame64.dll")||
548 tryLoadDLL(extrapath, "libmp3lame.dll")||
549 tryLoadDLL(extrapath, "lame_enc64.dll")||
550 tryLoadDLL(extrapath, "lame_enc.dll")) a = -1;
551 #else
552 if (tryLoadDLL(extrapath, "libmp3lame.dll") ||
553 tryLoadDLL(extrapath, "lame_enc.dll")) a = -1;
554 #endif
555 #else
556 if (tryLoadDLL(extrapath)) a=-1;
557 #endif
560 const char *LameEncoder::GetLibName() { return s_last_dll_file; }
562 const char *LameEncoder::GetInfo()
564 static char buf[128];
565 int ver = CheckDLL();
566 if (!ver) return NULL;
567 #ifdef SUPPORT_BLADE_MODE
568 if (ver == 2)
570 BE_VERSION ver={0,};
571 if (bladeAPI.beVersion) bladeAPI.beVersion(&ver);
572 snprintf(buf, sizeof(buf), "LAME/BladeAPI %d.%d", ver.byMajorVersion, ver.byMinorVersion);
573 return buf;
575 #endif
576 const char *p = lame.get_lame_version ? lame.get_lame_version() : NULL;
577 if (p && *p)
579 snprintf(buf, sizeof(buf), "LAME %s", p);
580 return buf;
582 return "LAME ?.??";
585 int LameEncoder::CheckDLL() // returns 1 for lame API, 2 for Blade, 0 for none
587 InitDLL();
588 if (!lame.close||
589 !lame.init||
590 !lame.set_in_samplerate||
591 !lame.set_num_channels||
592 !lame.set_out_samplerate||
593 !lame.set_quality||
594 !lame.set_mode||
595 !lame.set_brate||
596 !lame.init_params||
597 !lame.get_framesize||
598 !lame.encode_buffer_float||
599 !lame.encode_flush)
601 #ifdef SUPPORT_BLADE_MODE
602 if (bladeAPI.beInitStream&&
603 bladeAPI.beCloseStream&&
604 bladeAPI.beEncodeChunkFloatS16NI&&
605 bladeAPI.beDeinitStream&&
606 bladeAPI.beVersion) return 2;
607 #endif
608 return 0;
611 return 1;
615 LameEncoder::LameEncoder(int srate, int nch, int bitrate, int stereomode, int quality, int vbrmethod, int vbrquality, int vbrmax, int abr)
617 m_lamestate=0;
618 m_encmode = CheckDLL();
620 if (!m_encmode)
622 errorstat=1;
623 return;
626 errorstat=0;
627 m_nch=nch;
628 m_encoder_nch = stereomode == 3 ? 1 : m_nch;
630 #ifdef SUPPORT_BLADE_MODE
631 if (m_encmode==2)
633 BE_CONFIG beConfig;
634 memset(&beConfig,0,sizeof(beConfig));
635 beConfig.dwConfig = BE_CONFIG_LAME;
637 beConfig.format.LHV1.dwStructVersion = 1;
638 beConfig.format.LHV1.dwStructSize = sizeof(beConfig);
639 beConfig.format.LHV1.dwSampleRate = srate;
640 if (m_encoder_nch == 1) beConfig.format.LHV1.nMode = BE_MP3_MODE_MONO;
641 else beConfig.format.LHV1.nMode = stereomode; //bitrate >= 192 ? BE_MP3_MODE_STEREO : BE_MP3_MODE_JSTEREO;
643 beConfig.format.LHV1.dwBitrate=bitrate;
644 beConfig.format.LHV1.dwMaxBitrate=(vbrmethod!=-1?vbrmax:bitrate);
645 beConfig.format.LHV1.dwReSampleRate = srate;
647 // if mpeg 1, and bitrate is less than 32kbps per channel, switch to mpeg 2
648 if (beConfig.format.LHV1.dwReSampleRate >= 32000 && beConfig.format.LHV1.dwMaxBitrate/m_encoder_nch <= 32)
650 beConfig.format.LHV1.dwReSampleRate/=2;
652 beConfig.format.LHV1.dwMpegVersion = (beConfig.format.LHV1.dwReSampleRate < 32000 ? MPEG2 : MPEG1);
654 beConfig.format.LHV1.nPreset=quality;
656 beConfig.format.LHV1.bNoRes = 0;//1;
658 beConfig.format.LHV1.bWriteVBRHeader= 1;
659 beConfig.format.LHV1.bEnableVBR= vbrmethod!=-1;
660 beConfig.format.LHV1.nVBRQuality= vbrquality;
661 beConfig.format.LHV1.dwVbrAbr_bps = (vbrmethod!=-1?1000*abr:0);
662 beConfig.format.LHV1.nVbrMethod=(VBRMETHOD)vbrmethod;
665 /* LAME sets unwise bit if:
666 if (gfp->short_blocks == short_block_forced || gfp->short_blocks == short_block_dispensed || ((gfp->lowpassfreq == -1) && (gfp->highpassfreq == -1)) || // "-k"
667 (gfp->scale_left < gfp->scale_right) ||
668 (gfp->scale_left > gfp->scale_right) ||
669 (gfp->disable_reservoir && gfp->brate < 320) ||
670 gfp->noATH || gfp->ATHonly || (nAthType == 0) || gfp->in_samplerate <= 32000)
673 int out_size_bytes=0;
675 if (bladeAPI.beInitStream(&beConfig, (DWORD*)&in_size_samples, (DWORD*)&out_size_bytes, (PHBE_STREAM) &m_lamestate) != BE_ERR_SUCCESSFUL)
677 errorstat=2;
678 return;
680 if (out_size_bytes < 4096) out_size_bytes = 4096;
681 in_size_samples/=m_encoder_nch;
682 outtmp.Resize(out_size_bytes);
683 return;
685 #endif
687 m_lamestate=lame.init();
688 if (!m_lamestate)
690 errorstat=1;
691 return;
694 lame.set_in_samplerate(m_lamestate, srate);
695 lame.set_num_channels(m_lamestate,m_encoder_nch);
696 int outrate=srate;
698 int maxbr = (vbrmethod != -1 ? vbrmax : bitrate);
699 if (outrate>=32000 && maxbr <= 32*m_encoder_nch) outrate/=2;
701 lame.set_out_samplerate(m_lamestate,outrate);
702 lame.set_quality(m_lamestate,(quality>9 ||quality<0) ? 0 : quality);
703 lame.set_mode(m_lamestate,(MPEG_mode) (m_encoder_nch==1?3 :stereomode ));
704 lame.set_brate(m_lamestate,bitrate);
706 //int vbrmethod (-1 no vbr), int vbrquality (nVBRQuality), int vbrmax, int abr
707 if (vbrmethod != -1 && lame.set_VBR)
709 int vm=4; // mtrh
710 if (vbrmethod == 4) vm = 3; //ABR
711 lame.set_VBR(m_lamestate,vm);
713 if (lame.set_VBR_q) lame.set_VBR_q(m_lamestate,vbrquality);
715 if (vbrmethod == 4&&lame.set_VBR_mean_bitrate_kbps)
717 lame.set_VBR_mean_bitrate_kbps(m_lamestate,abr);
719 if (lame.set_VBR_max_bitrate_kbps)
721 lame.set_VBR_max_bitrate_kbps(m_lamestate,vbrmax);
723 if (lame.set_VBR_min_bitrate_kbps)
725 lame.set_VBR_min_bitrate_kbps(m_lamestate,bitrate);
728 lame.init_params(m_lamestate);
729 in_size_samples=lame.get_framesize(m_lamestate);
731 outtmp.Resize(65536);
734 void LameEncoder::Encode(float *in, int in_spls, int spacing)
736 if (errorstat) return;
738 if (in_spls > 0)
740 if (m_nch > 1 && m_encoder_nch==1)
742 // downmix
743 int x;
744 int pos=0;
745 int adv=2*spacing;
746 for (x = 0; x < in_spls; x ++)
748 float f=in[pos]+in[pos+1];
749 f*=16383.5f;
750 spltmp[0].Add(&f,sizeof(float));
751 pos+=adv;
754 else if (m_encoder_nch > 1) // deinterleave
756 int x;
757 int pos=0;
758 int adv=2*spacing;
759 for (x = 0; x < in_spls; x ++)
761 float f=in[pos];
762 f*=32767.0f;
763 spltmp[0].Add(&f,sizeof(float));
765 f=in[pos+1];
766 f*=32767.0f;
767 spltmp[1].Add(&f,sizeof(float));
769 pos+=adv;
772 else
774 int x;
775 int pos=0;
776 for (x = 0; x < in_spls; x ++)
778 float f=in[pos];
779 f*=32767.0f;
780 spltmp[0].Add(&f,sizeof(float));
782 pos+=spacing;
786 for (;;)
788 int a = spltmp[0].Available()/sizeof(float);
789 if (a >= in_size_samples) a = in_size_samples;
790 else if (a<1 || in_spls>0) break; // not enough samples available, and not flushing
792 int dwo;
793 #ifdef SUPPORT_BLADE_MODE
794 if (m_encmode==2)
796 DWORD outa=0;
797 if (bladeAPI.beEncodeChunkFloatS16NI(m_lamestate, a, (float*)spltmp[0].Get(), (float*)spltmp[m_encoder_nch > 1].Get(),
798 (unsigned char*)outtmp.Get(), &outa) != BE_ERR_SUCCESSFUL)
800 errorstat=3;
801 return;
803 dwo = (int)outa;
805 else
806 #endif
808 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());
810 outqueue.Add(outtmp.Get(),dwo);
811 spltmp[0].Advance(a*sizeof(float));
812 if (m_encoder_nch > 1) spltmp[1].Advance(a*sizeof(float));
815 if (in_spls<1)
817 #ifdef SUPPORT_BLADE_MODE
818 if (m_encmode==2)
820 DWORD dwo=0;
821 if (bladeAPI.beDeinitStream(m_lamestate, (unsigned char *)outtmp.Get(), &dwo) == BE_ERR_SUCCESSFUL && dwo>0)
822 outqueue.Add(outtmp.Get(),dwo);
824 else
825 #endif
827 int a=lame.encode_flush(m_lamestate,(unsigned char *)outtmp.Get(),outtmp.GetSize());
828 if (a>0) outqueue.Add(outtmp.Get(),a);
834 spltmp[0].Compact();
835 spltmp[1].Compact();
839 #ifdef _WIN32
841 static BOOL HasUTF8(const char *_str)
843 const unsigned char *str = (const unsigned char *)_str;
844 if (!str) return FALSE;
845 while (*str)
847 unsigned char c = *str;
848 if (c >= 0xC2) // discard overlongs
850 if (c <= 0xDF && str[1] >=0x80 && str[1] <= 0xBF) return TRUE;
851 else if (c <= 0xEF && str[1] >=0x80 && str[1] <= 0xBF && str[2] >=0x80 && str[2] <= 0xBF) return TRUE;
852 else if (c <= 0xF4 && str[1] >=0x80 && str[1] <= 0xBF && str[2] >=0x80 && str[2] <= 0xBF) return TRUE;
854 str++;
856 return FALSE;
858 #endif
860 LameEncoder::~LameEncoder()
862 #ifdef SUPPORT_BLADE_MODE
863 if (m_encmode==2 && m_lamestate)
865 if (m_vbrfile.Get()[0] && bladeAPI.beWriteInfoTag)
867 // support UTF-8 filenames
868 if (HasUTF8(m_vbrfile.Get()) && GetVersion()<0x80000000)
870 WCHAR wf[2048];
871 if (MultiByteToWideChar(CP_UTF8,MB_ERR_INVALID_CHARS,m_vbrfile.Get(),-1,wf,2048))
873 FILE *fp = _wfopen(wf,L"r+b");
874 if (fp)
876 char tmpspace[1024],tmpfn[2048];
877 GetTempPath(sizeof(tmpspace),tmpspace);
878 GetTempFileName(tmpspace,"lameenc",0,tmpfn);
879 FILE *tmpfp = fopen(tmpfn,"wb");
880 if (tmpfp)
882 fseek(fp,0,SEEK_SET);
883 int x=32; // 32kb
884 while(x--)
886 int a =fread(tmpspace,1,sizeof(tmpspace),fp);
887 if (a<1) break;
888 fwrite(tmpspace,1,a,tmpfp);
891 fclose(tmpfp);
893 bladeAPI.beWriteInfoTag(m_lamestate,tmpfn);
894 m_lamestate=0;
896 tmpfp = fopen(tmpfn,"r+b");
897 if (tmpfp)
899 fseek(tmpfp,0,SEEK_SET);
900 fseek(fp,0,SEEK_SET);
902 x=32; // 32kb
903 while(x--)
905 int a = fread(tmpspace,1,sizeof(tmpspace),tmpfp);
906 if (a<1) break;
907 fwrite(tmpspace,1,a,fp);
910 fclose(tmpfp);
913 DeleteFile(tmpfn);
915 fclose(fp);
922 if (m_lamestate) bladeAPI.beWriteInfoTag(m_lamestate,m_vbrfile.Get());
924 else bladeAPI.beCloseStream(m_lamestate);
925 m_lamestate=0;
926 return;
928 #endif
930 if (m_lamestate)
932 if (m_vbrfile.Get()[0] && lame.get_lametag_frame)
934 unsigned char buf[16384];
935 size_t a=lame.get_lametag_frame(m_lamestate,buf,sizeof(buf));
936 if (a>0 && a<=sizeof(buf))
938 FILE *fp=NULL;
939 #ifdef _WIN32
940 if (HasUTF8(m_vbrfile.Get()) && GetVersion()<0x80000000)
942 WCHAR wf[2048];
943 if (MultiByteToWideChar(CP_UTF8,MB_ERR_INVALID_CHARS,m_vbrfile.Get(),-1,wf,2048))
945 fp = _wfopen(wf,L"r+b");
948 #endif
949 if (!fp) fp = fopen(m_vbrfile.Get(),"r+b");
950 if (fp)
952 fseek(fp,0,SEEK_SET);
953 fwrite(buf,1,a,fp);
954 fclose(fp);
958 lame.close(m_lamestate);
959 m_lamestate=0;