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, "https://lame.sourceforge.io/" );
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