1 /*
2 *	Blade DLL Interface for LAME.
3 *
4 *	Copyright (c) 1999 - 2002 A.L. Faber
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA  02111-1307, USA.
20 */
21 
22 #include <windows.h>
23 #include <Windef.h>
24 #include "BladeMP3EncDLL.h"
25 #include <assert.h>
26 #include <stdio.h>
27 
28 #include <lame.h>
29 
30 #ifdef	__cplusplus
31 extern "C" {
32 #endif
33 
34 #define         Min(A, B)       ((A) < (B) ? (A) : (B))
35 #define         Max(A, B)       ((A) > (B) ? (A) : (B))
36 
37 #define _RELEASEDEBUG 0
38 
39 // lame_enc DLL version number
40 const BYTE MAJORVERSION = 1;
41 const BYTE MINORVERSION = 32;
42 
43 
44 // Local variables
45 static DWORD				dwSampleBufferSize=0;
46 static HMODULE				gs_hModule=NULL;
47 static BOOL					gs_bLogFile=FALSE;
48 static lame_global_flags*	gfp_save = NULL;
49 
50 // Local function prototypes
51 static void dump_config( 	lame_global_flags*	gfp );
52 static void DebugPrintf( const char* pzFormat, ... );
53 static void DispErr( char const* strErr );
54 static void PresetOptions( lame_global_flags *gfp, LONG myPreset );
55 
56 
DebugPrintf(const char * pzFormat,...)57 static void DebugPrintf(const char* pzFormat, ...)
58 {
59     char	szBuffer[1024]={'\0',};
60     char	szFileName[MAX_PATH+1]={'\0',};
61     va_list ap;
62 
63     // Get the full module (DLL) file name
64     GetModuleFileNameA(	gs_hModule,
65         szFileName,
66         sizeof( szFileName ) );
67 
68     // change file name extention
69     szFileName[ strlen(szFileName) - 3 ] = 't';
70     szFileName[ strlen(szFileName) - 2 ] = 'x';
71     szFileName[ strlen(szFileName) - 1 ] = 't';
72 
73     // start at beginning of the list
74     va_start(ap, pzFormat);
75 
76     // copy it to the string buffer
77     _vsnprintf(szBuffer, sizeof(szBuffer), pzFormat, ap);
78 
79     // log it to the file?
80     if ( gs_bLogFile )
81     {
82         FILE* fp = NULL;
83 
84         // try to open the log file
85         fp=fopen( szFileName, "a+" );
86 
87         // check file open result
88         if (fp)
89         {
90             // write string to the file
91             fputs(szBuffer,fp);
92 
93             // close the file
94             fclose(fp);
95         }
96     }
97 
98 #if defined _DEBUG || defined _RELEASEDEBUG
99     OutputDebugStringA( szBuffer );
100 #endif
101 
102     va_end(ap);
103 }
104 
105 
PresetOptions(lame_global_flags * gfp,LONG myPreset)106 static void PresetOptions( lame_global_flags *gfp, LONG myPreset )
107 {
108     switch (myPreset)
109     {
110         /*-1*/case LQP_NOPRESET:
111             break;
112 
113         /*0*/case LQP_NORMAL_QUALITY:
114             /*	lame_set_quality( gfp, 5 );*/
115             break;
116 
117         /*1*/case LQP_LOW_QUALITY:
118              lame_set_quality( gfp, 9 );
119              break;
120 
121         /*2*/case LQP_HIGH_QUALITY:
122              lame_set_quality( gfp, 2 );
123              break;
124 
125         /*3*/case LQP_VOICE_QUALITY:				// --voice flag for experimental voice mode
126              lame_set_mode( gfp, MONO );
127              lame_set_preset( gfp, 56);
128              break;
129 
130         /*4*/case LQP_R3MIX:					// --R3MIX
131              lame_set_preset( gfp, R3MIX);
132              break;
133 
134         /*5*/case LQP_VERYHIGH_QUALITY:
135              lame_set_quality( gfp, 0 );
136              break;
137 
138         /*6*/case LQP_STANDARD:				// --PRESET STANDARD
139             lame_set_preset( gfp, STANDARD);
140             break;
141 
142         /*7*/case LQP_FAST_STANDARD:				// --PRESET FAST STANDARD
143             lame_set_preset( gfp, STANDARD_FAST);
144             break;
145 
146         /*8*/case LQP_EXTREME:				// --PRESET EXTREME
147             lame_set_preset( gfp, EXTREME);
148             break;
149 
150         /*9*/case LQP_FAST_EXTREME:				// --PRESET FAST EXTREME:
151             lame_set_preset( gfp, EXTREME_FAST);
152             break;
153 
154         /*10*/case LQP_INSANE:				// --PRESET INSANE
155             lame_set_preset( gfp, INSANE);
156             break;
157 
158         /*11*/case LQP_ABR:					// --PRESET ABR
159             // handled in beInitStream
160             break;
161 
162         /*12*/case LQP_CBR:					// --PRESET CBR
163             // handled in beInitStream
164             break;
165 
166         /*13*/case LQP_MEDIUM:					// --PRESET MEDIUM
167             lame_set_preset( gfp, MEDIUM);
168             break;
169 
170         /*14*/case LQP_FAST_MEDIUM:					// --PRESET FAST MEDIUM
171             lame_set_preset( gfp, MEDIUM_FAST);
172             break;
173 
174         /*1000*/case LQP_PHONE:
175             lame_set_mode( gfp, MONO );
176             lame_set_preset( gfp, 16);
177             break;
178 
179         /*2000*/case LQP_SW:
180             lame_set_mode( gfp, MONO );
181             lame_set_preset( gfp, 24);
182             break;
183 
184         /*3000*/case LQP_AM:
185             lame_set_mode( gfp, MONO );
186             lame_set_preset( gfp, 40);
187             break;
188 
189         /*4000*/case LQP_FM:
190             lame_set_preset( gfp, 112);
191             break;
192 
193         /*5000*/case LQP_VOICE:
194             lame_set_mode( gfp, MONO );
195             lame_set_preset( gfp, 56);
196             break;
197 
198         /*6000*/case LQP_RADIO:
199             lame_set_preset( gfp, 112);
200             break;
201 
202         /*7000*/case LQP_TAPE:
203             lame_set_preset( gfp, 112);
204             break;
205 
206         /*8000*/case LQP_HIFI:
207             lame_set_preset( gfp, 160);
208             break;
209 
210         /*9000*/case LQP_CD:
211             lame_set_preset( gfp, 192);
212             break;
213 
214         /*10000*/case LQP_STUDIO:
215             lame_set_preset( gfp, 256);
216             break;
217 
218     }
219 }
220 
221 
beInitStream(PBE_CONFIG pbeConfig,PDWORD dwSamples,PDWORD dwBufferSize,PHBE_STREAM phbeStream)222 __declspec(dllexport) BE_ERR	beInitStream(PBE_CONFIG pbeConfig, PDWORD dwSamples, PDWORD dwBufferSize, PHBE_STREAM phbeStream)
223 {
224     int actual_bitrate;
225     //2001-12-18
226     BE_CONFIG			lameConfig = { 0, };
227     int					nInitReturn = 0;
228     lame_global_flags*	gfp = NULL;
229 
230     // Init the global flags structure
231     gfp = lame_init();
232     *phbeStream = (HBE_STREAM)gfp;
233 
234     // clear out structure
235     memset(&lameConfig,0x00,CURRENT_STRUCT_SIZE);
236 
237     // Check if this is a regular BLADE_ENCODER header
238     if (pbeConfig->dwConfig!=BE_CONFIG_LAME)
239     {
240         int nCRC=pbeConfig->format.mp3.bCRC;
241         int nVBR=(nCRC>>12)&0x0F;
242 
243         // Copy parameter from old Blade structure
244         lameConfig.format.LHV1.dwSampleRate	=pbeConfig->format.mp3.dwSampleRate;
245         //for low bitrates, LAME will automatically downsample for better
246         //sound quality.  Forcing output samplerate = input samplerate is not a good idea
247         //unless the user specifically requests it:
248         //lameConfig.format.LHV1.dwReSampleRate=pbeConfig->format.mp3.dwSampleRate;
249         lameConfig.format.LHV1.nMode		=(pbeConfig->format.mp3.byMode&0x0F);
250         lameConfig.format.LHV1.dwBitrate	=pbeConfig->format.mp3.wBitrate;
251         lameConfig.format.LHV1.bPrivate		=pbeConfig->format.mp3.bPrivate;
252         lameConfig.format.LHV1.bOriginal	=pbeConfig->format.mp3.bOriginal;
253         lameConfig.format.LHV1.bCRC		=nCRC&0x01;
254         lameConfig.format.LHV1.bCopyright	=pbeConfig->format.mp3.bCopyright;
255 
256         // Fill out the unknowns
257         lameConfig.format.LHV1.dwStructSize=CURRENT_STRUCT_SIZE;
258         lameConfig.format.LHV1.dwStructVersion=CURRENT_STRUCT_VERSION;
259 
260         // Get VBR setting from fourth nibble
261         if ( nVBR>0 )
262         {
263             lameConfig.format.LHV1.bWriteVBRHeader = TRUE;
264             lameConfig.format.LHV1.bEnableVBR = TRUE;
265             lameConfig.format.LHV1.nVBRQuality = nVBR-1;
266         }
267 
268         // Get Quality from third nibble
269         lameConfig.format.LHV1.nPreset=((nCRC>>8)&0x0F);
270 
271     }
272     else
273     {
274         // Copy the parameters
275         memcpy(&lameConfig,pbeConfig,pbeConfig->format.LHV1.dwStructSize);
276     }
277 
278     // --------------- Set arguments to LAME encoder -------------------------
279 
280     // Set input sample frequency
281     lame_set_in_samplerate( gfp, lameConfig.format.LHV1.dwSampleRate );
282 
283     // disable INFO/VBR tag by default.
284     // if this tag is used, the calling program must call beWriteVBRTag()
285     // after encoding.  But the original DLL documentation does not
286     // require the
287     // app to call beWriteVBRTag() unless they have specifically
288     // set LHV1.bWriteVBRHeader=TRUE.  Thus the default setting should
289     // be disabled.
290     lame_set_bWriteVbrTag( gfp, 0 );
291 
292     //2001-12-18 Dibrom's ABR preset stuff
293 
294     if(lameConfig.format.LHV1.nPreset == LQP_ABR)		// --ALT-PRESET ABR
295     {
296         actual_bitrate = lameConfig.format.LHV1.dwVbrAbr_bps / 1000;
297 
298         // limit range
299         if( actual_bitrate > 320)
300         {
301             actual_bitrate = 320;
302         }
303 
304         if( actual_bitrate < 8 )
305         {
306             actual_bitrate = 8;
307         }
308 
309         lame_set_preset( gfp, actual_bitrate );
310     }
311 
312     // end Dibrom's ABR preset 2001-12-18 ****** START OF CBR
313 
314     if(lameConfig.format.LHV1.nPreset == LQP_CBR)		// --ALT-PRESET CBR
315     {
316         actual_bitrate = lameConfig.format.LHV1.dwBitrate;
317         lame_set_preset(gfp, actual_bitrate);
318         lame_set_VBR(gfp, vbr_off);
319     }
320 
321     // end Dibrom's CBR preset 2001-12-18
322 
323     // The following settings only used when preset is not one of the LAME QUALITY Presets
324     if ( (int)lameConfig.format.LHV1.nPreset < (int) LQP_STANDARD )
325     {
326         switch ( lameConfig.format.LHV1.nMode )
327         {
328         case BE_MP3_MODE_STEREO:
329             lame_set_mode( gfp, STEREO );
330             lame_set_num_channels( gfp, 2 );
331             break;
332         case BE_MP3_MODE_JSTEREO:
333             lame_set_mode( gfp, JOINT_STEREO );
334             //lame_set_force_ms( gfp, bForceMS ); // no check box to force this?
335             lame_set_num_channels( gfp, 2 );
336             break;
337         case BE_MP3_MODE_MONO:
338             lame_set_mode( gfp, MONO );
339             lame_set_num_channels( gfp, 1 );
340             break;
341         case BE_MP3_MODE_DUALCHANNEL:
342             lame_set_mode( gfp, DUAL_CHANNEL );
343             lame_set_num_channels( gfp, 2 );
344             break;
345         default:
346             {
347                 DebugPrintf("Invalid lameConfig.format.LHV1.nMode, value is %d\n",lameConfig.format.LHV1.nMode);
348                 return BE_ERR_INVALID_FORMAT_PARAMETERS;
349             }
350         }
351 
352         if ( lameConfig.format.LHV1.bEnableVBR )
353         {
354             /* set VBR quality */
355             lame_set_VBR_q( gfp, lameConfig.format.LHV1.nVBRQuality );
356 
357             /* select proper VBR method */
358             switch ( lameConfig.format.LHV1.nVbrMethod)
359             {
360             case VBR_METHOD_NONE:
361                 lame_set_VBR( gfp, vbr_off );
362                 break;
363 
364             case VBR_METHOD_DEFAULT:
365                 lame_set_VBR( gfp, vbr_default );
366                 break;
367 
368             case VBR_METHOD_OLD:
369                 lame_set_VBR( gfp, vbr_rh );
370                 break;
371 
372             case VBR_METHOD_MTRH:
373             case VBR_METHOD_NEW:
374                 /*
375                 * the --vbr-mtrh commandline switch is obsolete.
376                 * now --vbr-mtrh is known as --vbr-new
377                 */
378                 lame_set_VBR( gfp, vbr_mtrh );
379                 break;
380 
381             case VBR_METHOD_ABR:
382                 lame_set_VBR( gfp, vbr_abr );
383                 break;
384 
385             default:
386                 /* unsupported VBR method */
387                 assert( FALSE );
388             }
389         }
390         else
391         {
392             /* use CBR encoding method, so turn off VBR */
393             lame_set_VBR( gfp, vbr_off );
394         }
395 
396         /* Set bitrate.  (CDex users always specify bitrate=Min bitrate when using VBR) */
397         lame_set_brate( gfp, lameConfig.format.LHV1.dwBitrate );
398 
399         /* check if we have to use ABR, in order to backwards compatible, this
400         * condition should still be checked indepedent of the nVbrMethod method
401         */
402         if (lameConfig.format.LHV1.dwVbrAbr_bps > 0 )
403         {
404             /* set VBR method to ABR */
405             lame_set_VBR( gfp, vbr_abr );
406 
407             /* calculate to kbps, round to nearest kbps */
408             lame_set_VBR_mean_bitrate_kbps( gfp, ( lameConfig.format.LHV1.dwVbrAbr_bps + 500 ) / 1000 );
409 
410             /* limit range */
411             if( lame_get_VBR_mean_bitrate_kbps( gfp ) > 320)
412             {
413                 lame_set_VBR_mean_bitrate_kbps( gfp, 320 );
414             }
415 
416             if( lame_get_VBR_mean_bitrate_kbps( gfp ) < 8 )
417             {
418                 lame_set_VBR_mean_bitrate_kbps( gfp, 8 );
419             }
420         }
421 
422     }
423 
424     // First set all the preset options
425     if ( LQP_NOPRESET !=  lameConfig.format.LHV1.nPreset )
426     {
427         PresetOptions( gfp, lameConfig.format.LHV1.nPreset );
428     }
429 
430 
431     // Set frequency resampling rate, if specified
432     if ( lameConfig.format.LHV1.dwReSampleRate > 0 )
433     {
434         lame_set_out_samplerate( gfp, lameConfig.format.LHV1.dwReSampleRate );
435     }
436 
437 
438     switch ( lameConfig.format.LHV1.nMode )
439     {
440     case BE_MP3_MODE_MONO:
441         lame_set_mode( gfp, MONO );
442         lame_set_num_channels( gfp, 1 );
443         break;
444 
445     default:
446         break;
447     }
448 
449 
450     // Use strict ISO encoding?
451     lame_set_strict_ISO( gfp, ( lameConfig.format.LHV1.bStrictIso ) ? 1 : 0 );
452 
453     // Set copyright flag?
454     if ( lameConfig.format.LHV1.bCopyright )
455     {
456         lame_set_copyright( gfp, 1 );
457     }
458 
459     // Do we have to tag  it as non original
460     if ( !lameConfig.format.LHV1.bOriginal )
461     {
462         lame_set_original( gfp, 0 );
463     }
464     else
465     {
466         lame_set_original( gfp, 1 );
467     }
468 
469     // Add CRC?
470     if ( lameConfig.format.LHV1.bCRC )
471     {
472         lame_set_error_protection( gfp, 1 );
473     }
474     else
475     {
476         lame_set_error_protection( gfp, 0 );
477     }
478 
479     // Set private bit?
480     if ( lameConfig.format.LHV1.bPrivate )
481     {
482         lame_set_extension( gfp, 1 );
483     }
484     else
485     {
486         lame_set_extension( gfp, 0 );
487     }
488 
489 
490     // Set VBR min bitrate, if specified
491     if ( lameConfig.format.LHV1.dwBitrate > 0 )
492     {
493         lame_set_VBR_min_bitrate_kbps( gfp, lameConfig.format.LHV1.dwBitrate );
494     }
495 
496     // Set Maxbitrate, if specified
497     if ( lameConfig.format.LHV1.dwMaxBitrate > 0 )
498     {
499         lame_set_VBR_max_bitrate_kbps( gfp, lameConfig.format.LHV1.dwMaxBitrate );
500     }
501     // Set bit resovoir option
502     if ( lameConfig.format.LHV1.bNoRes )
503     {
504         lame_set_disable_reservoir( gfp,1 );
505     }
506 
507     // check if the VBR tag is required
508     if ( lameConfig.format.LHV1.bWriteVBRHeader )
509     {
510         lame_set_bWriteVbrTag( gfp, 1 );
511     }
512     else
513     {
514         lame_set_bWriteVbrTag( gfp, 0 );
515     }
516 
517     // Override Quality setting, use HIGHBYTE = NOT LOWBYTE to be backwards compatible
518     if (	( lameConfig.format.LHV1.nQuality & 0xFF ) ==
519         ((~( lameConfig.format.LHV1.nQuality >> 8 )) & 0xFF) )
520     {
521         lame_set_quality( gfp, lameConfig.format.LHV1.nQuality & 0xFF );
522     }
523 
524     if ( 0 != ( nInitReturn = lame_init_params( gfp ) ) )
525     {
526         return nInitReturn;
527     }
528 
529     //LAME encoding call will accept any number of samples.
530     if ( 0 == lame_get_version( gfp ) )
531     {
532         // For MPEG-II, only 576 samples per frame per channel
533         *dwSamples= 576 * lame_get_num_channels( gfp );
534     }
535     else
536     {
537         // For MPEG-I, 1152 samples per frame per channel
538         *dwSamples= 1152 * lame_get_num_channels( gfp );
539     }
540 
541     // Set the input sample buffer size, so we know what we can expect
542     dwSampleBufferSize = *dwSamples;
543 
544     // Set MP3 buffer size, conservative estimate
545     *dwBufferSize=(DWORD)( 1.25 * ( *dwSamples / lame_get_num_channels( gfp ) ) + 7200 );
546 
547     // For debugging purposes
548     dump_config( gfp );
549 
550     // Everything went OK, thus return SUCCESSFUL
551     return BE_ERR_SUCCESSFUL;
552 }
553 
554 
555 
beFlushNoGap(HBE_STREAM hbeStream,PBYTE pOutput,PDWORD pdwOutput)556 __declspec(dllexport) BE_ERR	beFlushNoGap(HBE_STREAM hbeStream, PBYTE pOutput, PDWORD pdwOutput)
557 {
558     int nOutputSamples = 0;
559 
560     lame_global_flags*	gfp = (lame_global_flags*)hbeStream;
561 
562     // Init the global flags structure
563     nOutputSamples = lame_encode_flush_nogap( gfp, pOutput, LAME_MAXMP3BUFFER );
564 
565     if ( nOutputSamples < 0 )
566     {
567         *pdwOutput = 0;
568         return BE_ERR_BUFFER_TOO_SMALL;
569     }
570     else
571     {
572         *pdwOutput = nOutputSamples;
573     }
574 
575     return BE_ERR_SUCCESSFUL;
576 }
577 
beDeinitStream(HBE_STREAM hbeStream,PBYTE pOutput,PDWORD pdwOutput)578 __declspec(dllexport) BE_ERR	beDeinitStream(HBE_STREAM hbeStream, PBYTE pOutput, PDWORD pdwOutput)
579 {
580     int nOutputSamples = 0;
581 
582     lame_global_flags*	gfp = (lame_global_flags*)hbeStream;
583 
584     nOutputSamples = lame_encode_flush( gfp, pOutput, 0 );
585 
586     if ( nOutputSamples < 0 )
587     {
588         *pdwOutput = 0;
589         return BE_ERR_BUFFER_TOO_SMALL;
590     }
591     else
592     {
593         *pdwOutput = nOutputSamples;
594     }
595 
596     return BE_ERR_SUCCESSFUL;
597 }
598 
599 
beCloseStream(HBE_STREAM hbeStream)600 __declspec(dllexport) BE_ERR	beCloseStream(HBE_STREAM hbeStream)
601 {
602     lame_global_flags*	gfp = (lame_global_flags*)hbeStream;
603 
604     // lame will be close in VbrWriteTag function
605     if ( !lame_get_bWriteVbrTag( gfp ) )
606     {
607         // clean up of allocated memory
608         lame_close( gfp );
609 
610         gfp_save = NULL;
611     }
612     else
613     {
614         gfp_save = (lame_global_flags*)hbeStream;
615     }
616 
617     // DeInit encoder
618     return BE_ERR_SUCCESSFUL;
619 }
620 
621 
622 
beVersion(PBE_VERSION pbeVersion)623 __declspec(dllexport) VOID		beVersion(PBE_VERSION pbeVersion)
624 {
625     // DLL Release date
626     char lpszDate[20]	= { '\0', };
627     char lpszTemp[5]	= { '\0', };
628     lame_version_t lv   = { 0, };
629 
630 
631     // Set DLL interface version
632     pbeVersion->byDLLMajorVersion=MAJORVERSION;
633     pbeVersion->byDLLMinorVersion=MINORVERSION;
634 
635     get_lame_version_numerical ( &lv );
636 
637     // Set Engine version number (Same as Lame version)
638     pbeVersion->byMajorVersion = (BYTE)lv.major;
639     pbeVersion->byMinorVersion = (BYTE)lv.minor;
640     pbeVersion->byAlphaLevel   = (BYTE)lv.alpha;
641     pbeVersion->byBetaLevel    = (BYTE)lv.beta;
642 
643 #ifdef MMX_choose_table
644     pbeVersion->byMMXEnabled=1;
645 #else
646     pbeVersion->byMMXEnabled=0;
647 #endif
648 
649     memset( pbeVersion->btReserved, 0, sizeof( pbeVersion->btReserved ) );
650 
651     // Get compilation date
652     strcpy(lpszDate,__DATE__);
653 
654     // Get the first three character, which is the month
655     strncpy(lpszTemp,lpszDate,3);
656     lpszTemp[3] = '\0';
657     pbeVersion->byMonth=1;
658 
659     // Set month
660     if (strcmp(lpszTemp,"Jan")==0)	pbeVersion->byMonth = 1;
661     if (strcmp(lpszTemp,"Feb")==0)	pbeVersion->byMonth = 2;
662     if (strcmp(lpszTemp,"Mar")==0)	pbeVersion->byMonth = 3;
663     if (strcmp(lpszTemp,"Apr")==0)	pbeVersion->byMonth = 4;
664     if (strcmp(lpszTemp,"May")==0)	pbeVersion->byMonth = 5;
665     if (strcmp(lpszTemp,"Jun")==0)	pbeVersion->byMonth = 6;
666     if (strcmp(lpszTemp,"Jul")==0)	pbeVersion->byMonth = 7;
667     if (strcmp(lpszTemp,"Aug")==0)	pbeVersion->byMonth = 8;
668     if (strcmp(lpszTemp,"Sep")==0)	pbeVersion->byMonth = 9;
669     if (strcmp(lpszTemp,"Oct")==0)	pbeVersion->byMonth = 10;
670     if (strcmp(lpszTemp,"Nov")==0)	pbeVersion->byMonth = 11;
671     if (strcmp(lpszTemp,"Dec")==0)	pbeVersion->byMonth = 12;
672 
673     // Get day of month string (char [4..5])
674     pbeVersion->byDay = (BYTE) atoi( lpszDate + 4 );
675 
676     // Get year of compilation date (char [7..10])
677     pbeVersion->wYear = (WORD) atoi( lpszDate + 7 );
678 
679     memset( pbeVersion->zHomepage, 0x00, BE_MAX_HOMEPAGE );
680 
681     strcpy( pbeVersion->zHomepage, "http://www.mp3dev.org/" );
682 }
683 
beEncodeChunk(HBE_STREAM hbeStream,DWORD nSamples,PSHORT pSamples,PBYTE pOutput,PDWORD pdwOutput)684 __declspec(dllexport) BE_ERR	beEncodeChunk(HBE_STREAM hbeStream, DWORD nSamples,
685                                               PSHORT pSamples, PBYTE pOutput, PDWORD pdwOutput)
686 {
687     // Encode it
688     int dwSamples;
689     int	nOutputSamples = 0;
690     lame_global_flags*	gfp = (lame_global_flags*)hbeStream;
691 
692     dwSamples = nSamples / lame_get_num_channels( gfp );
693 
694     // old versions of lame_enc.dll required exactly 1152 samples
695     // and worked even if nSamples accidently set to 2304
696     // simulate this behavoir:
697     if ( 1 == lame_get_num_channels( gfp ) && nSamples == 2304)
698     {
699         dwSamples/= 2;
700     }
701 
702 
703     if ( 1 == lame_get_num_channels( gfp ) )
704     {
705         nOutputSamples = lame_encode_buffer(gfp,pSamples,pSamples,dwSamples,pOutput,0);
706     }
707     else
708     {
709         nOutputSamples = lame_encode_buffer_interleaved(gfp,pSamples,dwSamples,pOutput,0);
710     }
711 
712 
713     if ( nOutputSamples < 0 )
714     {
715         *pdwOutput=0;
716         return BE_ERR_BUFFER_TOO_SMALL;
717     }
718     else
719     {
720         *pdwOutput = (DWORD)nOutputSamples;
721     }
722 
723     return BE_ERR_SUCCESSFUL;
724 }
725 
726 
727 // accept floating point audio samples, scaled to the range of a signed 16-bit
728 //  integer (within +/- 32768), in non-interleaved channels  -- DSPguru, jd
beEncodeChunkFloatS16NI(HBE_STREAM hbeStream,DWORD nSamples,PFLOAT buffer_l,PFLOAT buffer_r,PBYTE pOutput,PDWORD pdwOutput)729 __declspec(dllexport) BE_ERR	beEncodeChunkFloatS16NI(HBE_STREAM hbeStream, DWORD nSamples,
730                                                         PFLOAT buffer_l, PFLOAT buffer_r, PBYTE pOutput, PDWORD pdwOutput)
731 {
732     int nOutputSamples;
733     lame_global_flags*	gfp = (lame_global_flags*)hbeStream;
734 
735     nOutputSamples = lame_encode_buffer_float(gfp,buffer_l,buffer_r,nSamples,pOutput,0);
736 
737     if ( nOutputSamples >= 0 )
738     {
739         *pdwOutput = (DWORD) nOutputSamples;
740     }
741     else
742     {
743         *pdwOutput=0;
744         return BE_ERR_BUFFER_TOO_SMALL;
745     }
746 
747     return BE_ERR_SUCCESSFUL;
748 }
749 
750 static int
maybeSyncWord(FILE * fpStream)751 maybeSyncWord(FILE* fpStream)
752 {
753     unsigned char mp3_frame_header[4];
754     size_t nbytes = fread(mp3_frame_header, 1, sizeof(mp3_frame_header), fpStream);
755     if ( nbytes != sizeof(mp3_frame_header) ) {
756         return -1;
757     }
758     if ( mp3_frame_header[0] != 0xffu ) {
759         return -1; /* doesn't look like a sync word */
760     }
761     if ( (mp3_frame_header[1] & 0xE0u) != 0xE0u ) {
762         return -1; /* doesn't look like a sync word */
763     }
764     return 0;
765 }
766 
767 static int
skipId3v2(FILE * fpStream,size_t lametag_frame_size)768 skipId3v2(FILE * fpStream, size_t lametag_frame_size)
769 {
770     size_t  nbytes;
771     size_t  id3v2TagSize = 0;
772     unsigned char id3v2Header[10];
773 
774     /* seek to the beginning of the stream */
775     if (fseek(fpStream, 0, SEEK_SET) != 0) {
776         return -2;  /* not seekable, abort */
777     }
778     /* read 10 bytes in case there's an ID3 version 2 header here */
779     nbytes = fread(id3v2Header, 1, sizeof(id3v2Header), fpStream);
780     if (nbytes != sizeof(id3v2Header)) {
781         return -3;  /* not readable, maybe opened Write-Only */
782     }
783     /* does the stream begin with the ID3 version 2 file identifier? */
784     if (!strncmp((char *) id3v2Header, "ID3", 3)) {
785         /* the tag size (minus the 10-byte header) is encoded into four
786         * bytes where the most significant bit is clear in each byte
787         */
788         id3v2TagSize = (((id3v2Header[6] & 0x7f) << 21)
789             | ((id3v2Header[7] & 0x7f) << 14)
790             | ((id3v2Header[8] & 0x7f) << 7)
791             | (id3v2Header[9] & 0x7f))
792             + sizeof id3v2Header;
793     }
794     /* Seek to the beginning of the audio stream */
795     if ( fseek(fpStream, id3v2TagSize, SEEK_SET) != 0 ) {
796         return -2;
797     }
798     if ( maybeSyncWord(fpStream) != 0) {
799         return -1;
800     }
801     if ( fseek(fpStream, id3v2TagSize+lametag_frame_size, SEEK_SET) != 0 ) {
802         return -2;
803     }
804     if ( maybeSyncWord(fpStream) != 0) {
805         return -1;
806     }
807     /* OK, it seems we found our LAME-Tag/Xing frame again */
808     /* Seek to the beginning of the audio stream */
809     if ( fseek(fpStream, id3v2TagSize, SEEK_SET) != 0 ) {
810         return -2;
811     }
812     return 0;
813 }
814 
815 static BE_ERR
updateLameTagFrame(lame_global_flags * gfp,FILE * fpStream)816 updateLameTagFrame(lame_global_flags* gfp, FILE* fpStream)
817 {
818     size_t n = lame_get_lametag_frame( gfp, 0, 0 ); /* ask for bufer size */
819 
820     if ( n > 0 )
821     {
822         unsigned char* buffer = 0;
823         size_t m = 1;
824 
825         if ( 0 != skipId3v2(fpStream, n) )
826         {
827             DispErr( "Error updating LAME-tag frame:\n\n"
828                      "can't locate old frame\n" );
829             return BE_ERR_INVALID_FORMAT_PARAMETERS;
830         }
831 
832         buffer = (unsigned char*)malloc( n );
833 
834         if ( buffer == 0 )
835         {
836             DispErr( "Error updating LAME-tag frame:\n\n"
837                      "can't allocate frame buffer\n" );
838             return BE_ERR_INVALID_FORMAT_PARAMETERS;
839         }
840 
841         /* Put it all to disk again */
842         n = lame_get_lametag_frame( gfp, buffer, n );
843         if ( n > 0 )
844         {
845             m = fwrite( buffer, n, 1, fpStream );
846         }
847         free( buffer );
848 
849         if ( m != 1 )
850         {
851             DispErr( "Error updating LAME-tag frame:\n\n"
852                      "couldn't write frame into file\n" );
853             return BE_ERR_INVALID_FORMAT_PARAMETERS;
854         }
855     }
856     return BE_ERR_SUCCESSFUL;
857 }
858 
beWriteInfoTag(HBE_STREAM hbeStream,LPCSTR lpszFileName)859 __declspec(dllexport) BE_ERR beWriteInfoTag( HBE_STREAM hbeStream,
860                                             LPCSTR lpszFileName )
861 {
862     FILE* fpStream	= NULL;
863     BE_ERR beResult	= BE_ERR_SUCCESSFUL;
864 
865     lame_global_flags*	gfp = (lame_global_flags*)hbeStream;
866 
867     if ( NULL != gfp )
868     {
869         // Do we have to write the VBR tag?
870         if ( lame_get_bWriteVbrTag( gfp ) )
871         {
872             // Try to open the file
873             fpStream=fopen( lpszFileName, "rb+" );
874 
875             // Check file open result
876             if ( NULL == fpStream )
877             {
878                 beResult = BE_ERR_INVALID_FORMAT_PARAMETERS;
879                 DispErr( "Error updating LAME-tag frame:\n\n"
880                          "can't open file for reading and writing\n" );
881             }
882             else
883             {
884                 beResult = updateLameTagFrame( gfp, fpStream );
885 
886                 // Close the file stream
887                 fclose( fpStream );
888             }
889         }
890 
891         // clean up of allocated memory
892         lame_close( gfp );
893     }
894     else
895     {
896         beResult = BE_ERR_INVALID_FORMAT_PARAMETERS;
897     }
898 
899     // return result
900     return beResult;
901 }
902 
903 // for backwards compatiblity
beWriteVBRHeader(LPCSTR lpszFileName)904 __declspec(dllexport) BE_ERR beWriteVBRHeader(LPCSTR lpszFileName)
905 {
906     return beWriteInfoTag( (HBE_STREAM)gfp_save, lpszFileName );
907 }
908 
909 
DllMain(HANDLE hModule,DWORD ul_reason_for_call,LPVOID lpReserved)910 BOOL APIENTRY DllMain(HANDLE hModule,
911                       DWORD  ul_reason_for_call,
912                       LPVOID lpReserved)
913 {
914     (void) lpReserved;
915     gs_hModule = (HMODULE) hModule;
916 
917     switch( ul_reason_for_call )
918     {
919     case DLL_PROCESS_ATTACH:
920         // Enable debug/logging?
921         gs_bLogFile = GetPrivateProfileIntA("Debug","WriteLogFile",gs_bLogFile,"lame_enc.ini");
922         break;
923     case DLL_THREAD_ATTACH:
924         break;
925     case DLL_THREAD_DETACH:
926         break;
927     case DLL_PROCESS_DETACH:
928         break;
929     }
930     return TRUE;
931 }
932 
933 
dump_config(lame_global_flags * gfp)934 static void dump_config( lame_global_flags* gfp )
935 {
936     DebugPrintf("\n\nLame_enc configuration options:\n");
937     DebugPrintf("==========================================================\n");
938 
939     DebugPrintf("version                =%d\n",lame_get_version( gfp ) );
940     DebugPrintf("Layer                  =3\n");
941     DebugPrintf("mode                   =");
942     switch ( lame_get_mode( gfp ) )
943     {
944     case STEREO:       DebugPrintf( "Stereo\n" ); break;
945     case JOINT_STEREO: DebugPrintf( "Joint-Stereo\n" ); break;
946     case DUAL_CHANNEL: DebugPrintf( "Forced Stereo\n" ); break;
947     case MONO:         DebugPrintf( "Mono\n" ); break;
948     case NOT_SET:      /* FALLTROUGH */
949     default:           DebugPrintf( "Error (unknown)\n" ); break;
950     }
951 
952     DebugPrintf("Input sample rate      =%.1f kHz\n", lame_get_in_samplerate( gfp ) /1000.0 );
953     DebugPrintf("Output sample rate     =%.1f kHz\n", lame_get_out_samplerate( gfp ) /1000.0 );
954 
955     DebugPrintf("bitrate                =%d kbps\n", lame_get_brate( gfp ) );
956     DebugPrintf("Quality Setting        =%d\n", lame_get_quality( gfp ) );
957 
958     DebugPrintf("Low pass frequency     =%d\n", lame_get_lowpassfreq( gfp ) );
959     DebugPrintf("Low pass width         =%d\n", lame_get_lowpasswidth( gfp ) );
960 
961     DebugPrintf("High pass frequency    =%d\n", lame_get_highpassfreq( gfp ) );
962     DebugPrintf("High pass width        =%d\n", lame_get_highpasswidth( gfp ) );
963 
964     DebugPrintf("No short blocks        =%d\n", lame_get_no_short_blocks( gfp ) );
965     DebugPrintf("Force short blocks     =%d\n", lame_get_force_short_blocks( gfp ) );
966 
967     DebugPrintf("de-emphasis            =%d\n", lame_get_emphasis( gfp ) );
968     DebugPrintf("private flag           =%d\n", lame_get_extension( gfp ) );
969 
970     DebugPrintf("copyright flag         =%d\n", lame_get_copyright( gfp ) );
971     DebugPrintf("original flag          =%d\n",	lame_get_original( gfp ) );
972     DebugPrintf("CRC                    =%s\n", lame_get_error_protection( gfp ) ? "on" : "off" );
973     DebugPrintf("Fast mode              =%s\n", ( lame_get_quality( gfp ) )? "enabled" : "disabled" );
974     DebugPrintf("Force mid/side stereo  =%s\n", ( lame_get_force_ms( gfp ) )?"enabled":"disabled" );
975     DebugPrintf("Disable Reservoir      =%d\n", lame_get_disable_reservoir( gfp ) );
976     DebugPrintf("Allow diff-short       =%d\n", lame_get_allow_diff_short( gfp ) );
977     DebugPrintf("Interchannel masking   =%f\n", lame_get_interChRatio( gfp ) );
978     DebugPrintf("Strict ISO Encoding    =%s\n", ( lame_get_strict_ISO( gfp ) ) ?"Yes":"No");
979     DebugPrintf("Scale                  =%5.2f\n", lame_get_scale( gfp ) );
980 
981     DebugPrintf("VBR                    =%s, VBR_q =%d, VBR method =",
982         ( lame_get_VBR( gfp ) !=vbr_off ) ? "enabled": "disabled",
983         lame_get_VBR_q( gfp ) );
984 
985     switch ( lame_get_VBR( gfp ) )
986     {
987     case vbr_off:	DebugPrintf( "vbr_off\n" );	break;
988     case vbr_mt :	DebugPrintf( "vbr_mt \n" );	break;
989     case vbr_rh :	DebugPrintf( "vbr_rh \n" );	break;
990     case vbr_mtrh:	DebugPrintf( "vbr_mtrh \n" );	break;
991     case vbr_abr:
992         DebugPrintf( "vbr_abr (average bitrate %d kbps)\n", lame_get_VBR_mean_bitrate_kbps( gfp ) );
993         break;
994     default:
995         DebugPrintf("error, unknown VBR setting\n");
996         break;
997     }
998 
999     DebugPrintf("Vbr Min bitrate        =%d kbps\n", lame_get_VBR_min_bitrate_kbps( gfp ) );
1000     DebugPrintf("Vbr Max bitrate        =%d kbps\n", lame_get_VBR_max_bitrate_kbps( gfp ) );
1001 
1002     DebugPrintf("Write VBR Header       =%s\n", ( lame_get_bWriteVbrTag( gfp ) ) ?"Yes":"No");
1003     DebugPrintf("VBR Hard min           =%d\n", lame_get_VBR_hard_min( gfp ) );
1004 
1005     DebugPrintf("ATH Only               =%d\n", lame_get_ATHonly( gfp ) );
1006     DebugPrintf("ATH short              =%d\n", lame_get_ATHshort( gfp ) );
1007     DebugPrintf("ATH no                 =%d\n", lame_get_noATH( gfp ) );
1008     DebugPrintf("ATH type               =%d\n", lame_get_ATHtype( gfp ) );
1009     DebugPrintf("ATH lower              =%f\n", lame_get_ATHlower( gfp ) );
1010     DebugPrintf("ATH aa                 =%d\n", lame_get_athaa_type( gfp ) );
1011     //DebugPrintf("ATH aa  loudapprox     =%d\n", lame_get_athaa_loudapprox( gfp ) );
1012     DebugPrintf("ATH aa  sensitivity    =%f\n", lame_get_athaa_sensitivity( gfp ) );
1013 
1014     DebugPrintf("Experimental nspsytune =%d\n", lame_get_exp_nspsytune( gfp ) );
1015     DebugPrintf("Experimental X         =%d\n", lame_get_experimentalX( gfp ) );
1016     DebugPrintf("Experimental Y         =%d\n", lame_get_experimentalY( gfp ) );
1017     DebugPrintf("Experimental Z         =%d\n", lame_get_experimentalZ( gfp ) );
1018 }
1019 
1020 
DispErr(char const * strErr)1021 static void DispErr(char const* strErr)
1022 {
1023     MessageBoxA(NULL,strErr,"LAME_ENC.DLL",MB_OK|MB_ICONHAND);
1024 }
1025 
1026 #ifdef	__cplusplus
1027 }
1028 #endif
1029