aboutsummaryrefslogtreecommitdiff
path: root/Src/Plugins/Encoder/enc_lame/BladeMP3EncDLL.c
diff options
context:
space:
mode:
authorJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
committerJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
commit20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch)
tree12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/Plugins/Encoder/enc_lame/BladeMP3EncDLL.c
parent537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff)
downloadwinamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz
Initial community commit
Diffstat (limited to 'Src/Plugins/Encoder/enc_lame/BladeMP3EncDLL.c')
-rw-r--r--Src/Plugins/Encoder/enc_lame/BladeMP3EncDLL.c1028
1 files changed, 1028 insertions, 0 deletions
diff --git a/Src/Plugins/Encoder/enc_lame/BladeMP3EncDLL.c b/Src/Plugins/Encoder/enc_lame/BladeMP3EncDLL.c
new file mode 100644
index 00000000..e982cad2
--- /dev/null
+++ b/Src/Plugins/Encoder/enc_lame/BladeMP3EncDLL.c
@@ -0,0 +1,1028 @@
+/*
+* Blade DLL Interface for LAME.
+*
+* Copyright (c) 1999 - 2002 A.L. Faber
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Library General Public
+* License as published by the Free Software Foundation; either
+* version 2 of the License, or (at your option) any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Library General Public License for more details.
+*
+* You should have received a copy of the GNU Library General Public
+* License along with this library; if not, write to the
+* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+* Boston, MA 02111-1307, USA.
+*/
+
+#include <windows.h>
+#include <Windef.h>
+#include "BladeMP3EncDLL.h"
+#include <assert.h>
+#include <stdio.h>
+
+#include <lame/lame.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define Min(A, B) ((A) < (B) ? (A) : (B))
+#define Max(A, B) ((A) > (B) ? (A) : (B))
+
+#define _RELEASEDEBUG 0
+
+ // lame_enc DLL version number
+ const BYTE MAJORVERSION = 1;
+ const BYTE MINORVERSION = 32;
+
+
+ // Local variables
+ static DWORD dwSampleBufferSize = 0;
+ static HMODULE gs_hModule = NULL;
+ static BOOL gs_bLogFile = FALSE;
+ static lame_global_flags* gfp_save = NULL;
+
+ // Local function prototypes
+ static void dump_config(lame_global_flags* gfp);
+ static void DebugPrintf(const char* pzFormat, ...);
+ static void DispErr(wchar_t const* strErr);
+ static void PresetOptions(lame_global_flags* gfp, LONG myPreset);
+
+
+ static void DebugPrintf(const char* pzFormat, ...)
+ {
+ char szBuffer[1024] = { '\0', };
+ char szFileName[MAX_PATH + 1] = { '\0', };
+ va_list ap;
+
+ // Get the full module (DLL) file name
+ GetModuleFileNameA(gs_hModule,
+ szFileName,
+ sizeof(szFileName));
+
+ // change file name extention
+ szFileName[strlen(szFileName) - 3] = 't';
+ szFileName[strlen(szFileName) - 2] = 'x';
+ szFileName[strlen(szFileName) - 1] = 't';
+
+ // start at beginning of the list
+ va_start(ap, pzFormat);
+
+ // copy it to the string buffer
+ _vsnprintf(szBuffer, sizeof(szBuffer), pzFormat, ap);
+
+ // log it to the file?
+ if (gs_bLogFile)
+ {
+ FILE* fp = NULL;
+
+ // try to open the log file
+ fp = fopen(szFileName, "a+");
+
+ // check file open result
+ if (fp)
+ {
+ // write string to the file
+ fputs(szBuffer, fp);
+
+ // close the file
+ fclose(fp);
+ }
+ }
+
+#if defined _DEBUG || defined _RELEASEDEBUG
+ OutputDebugStringA(szBuffer);
+#endif
+
+ va_end(ap);
+ }
+
+
+ static void PresetOptions(lame_global_flags* gfp, LONG myPreset)
+ {
+ switch (myPreset)
+ {
+ /*-1*/case LQP_NOPRESET:
+ break;
+
+ /*0*/case LQP_NORMAL_QUALITY:
+ /* lame_set_quality( gfp, 5 );*/
+ break;
+
+ /*1*/case LQP_LOW_QUALITY:
+ lame_set_quality(gfp, 9);
+ break;
+
+ /*2*/case LQP_HIGH_QUALITY:
+ lame_set_quality(gfp, 2);
+ break;
+
+ /*3*/case LQP_VOICE_QUALITY: // --voice flag for experimental voice mode
+ lame_set_mode(gfp, MONO);
+ lame_set_preset(gfp, 56);
+ break;
+
+ /*4*/case LQP_R3MIX: // --R3MIX
+ lame_set_preset(gfp, R3MIX);
+ break;
+
+ /*5*/case LQP_VERYHIGH_QUALITY:
+ lame_set_quality(gfp, 0);
+ break;
+
+ /*6*/case LQP_STANDARD: // --PRESET STANDARD
+ lame_set_preset(gfp, STANDARD);
+ break;
+
+ /*7*/case LQP_FAST_STANDARD: // --PRESET FAST STANDARD
+ lame_set_preset(gfp, STANDARD_FAST);
+ break;
+
+ /*8*/case LQP_EXTREME: // --PRESET EXTREME
+ lame_set_preset(gfp, EXTREME);
+ break;
+
+ /*9*/case LQP_FAST_EXTREME: // --PRESET FAST EXTREME:
+ lame_set_preset(gfp, EXTREME_FAST);
+ break;
+
+ /*10*/case LQP_INSANE: // --PRESET INSANE
+ lame_set_preset(gfp, INSANE);
+ break;
+
+ /*11*/case LQP_ABR: // --PRESET ABR
+ // handled in beInitStream
+ break;
+
+ /*12*/case LQP_CBR: // --PRESET CBR
+ // handled in beInitStream
+ break;
+
+ /*13*/case LQP_MEDIUM: // --PRESET MEDIUM
+ lame_set_preset(gfp, MEDIUM);
+ break;
+
+ /*14*/case LQP_FAST_MEDIUM: // --PRESET FAST MEDIUM
+ lame_set_preset(gfp, MEDIUM_FAST);
+ break;
+
+ /*1000*/case LQP_PHONE:
+ lame_set_mode(gfp, MONO);
+ lame_set_preset(gfp, 16);
+ break;
+
+ /*2000*/case LQP_SW:
+ lame_set_mode(gfp, MONO);
+ lame_set_preset(gfp, 24);
+ break;
+
+ /*3000*/case LQP_AM:
+ lame_set_mode(gfp, MONO);
+ lame_set_preset(gfp, 40);
+ break;
+
+ /*4000*/case LQP_FM:
+ lame_set_preset(gfp, 112);
+ break;
+
+ /*5000*/case LQP_VOICE:
+ lame_set_mode(gfp, MONO);
+ lame_set_preset(gfp, 56);
+ break;
+
+ /*6000*/case LQP_RADIO:
+ lame_set_preset(gfp, 112);
+ break;
+
+ /*7000*/case LQP_TAPE:
+ lame_set_preset(gfp, 112);
+ break;
+
+ /*8000*/case LQP_HIFI:
+ lame_set_preset(gfp, 160);
+ break;
+
+ /*9000*/case LQP_CD:
+ lame_set_preset(gfp, 192);
+ break;
+
+ /*10000*/case LQP_STUDIO:
+ lame_set_preset(gfp, 256);
+ break;
+
+ }
+ }
+
+
+ __declspec(dllexport) BE_ERR beInitStream(PBE_CONFIG pbeConfig, PDWORD dwSamples, PDWORD dwBufferSize, PHBE_STREAM phbeStream)
+ {
+ int actual_bitrate;
+ //2001-12-18
+ BE_CONFIG lameConfig = { 0, };
+ int nInitReturn = 0;
+ lame_global_flags* gfp = NULL;
+
+ // Init the global flags structure
+ gfp = lame_init();
+ *phbeStream = (HBE_STREAM)gfp;
+
+ // clear out structure
+ memset(&lameConfig, 0x00, CURRENT_STRUCT_SIZE);
+
+ // Check if this is a regular BLADE_ENCODER header
+ if (pbeConfig->dwConfig != BE_CONFIG_LAME)
+ {
+ int nCRC = pbeConfig->format.mp3.bCRC;
+ int nVBR = (nCRC >> 12) & 0x0F;
+
+ // Copy parameter from old Blade structure
+ lameConfig.format.LHV1.dwSampleRate = pbeConfig->format.mp3.dwSampleRate;
+ //for low bitrates, LAME will automatically downsample for better
+ //sound quality. Forcing output samplerate = input samplerate is not a good idea
+ //unless the user specifically requests it:
+ //lameConfig.format.LHV1.dwReSampleRate=pbeConfig->format.mp3.dwSampleRate;
+ lameConfig.format.LHV1.nMode = (pbeConfig->format.mp3.byMode & 0x0F);
+ lameConfig.format.LHV1.dwBitrate = pbeConfig->format.mp3.wBitrate;
+ lameConfig.format.LHV1.bPrivate = pbeConfig->format.mp3.bPrivate;
+ lameConfig.format.LHV1.bOriginal = pbeConfig->format.mp3.bOriginal;
+ lameConfig.format.LHV1.bCRC = nCRC & 0x01;
+ lameConfig.format.LHV1.bCopyright = pbeConfig->format.mp3.bCopyright;
+
+ // Fill out the unknowns
+ lameConfig.format.LHV1.dwStructSize = CURRENT_STRUCT_SIZE;
+ lameConfig.format.LHV1.dwStructVersion = CURRENT_STRUCT_VERSION;
+
+ // Get VBR setting from fourth nibble
+ if (nVBR > 0)
+ {
+ lameConfig.format.LHV1.bWriteVBRHeader = TRUE;
+ lameConfig.format.LHV1.bEnableVBR = TRUE;
+ lameConfig.format.LHV1.nVBRQuality = nVBR - 1;
+ }
+
+ // Get Quality from third nibble
+ lameConfig.format.LHV1.nPreset = ((nCRC >> 8) & 0x0F);
+
+ }
+ else
+ {
+ // Copy the parameters
+ memcpy(&lameConfig, pbeConfig, pbeConfig->format.LHV1.dwStructSize);
+ }
+
+ // --------------- Set arguments to LAME encoder -------------------------
+
+ // Set input sample frequency
+ lame_set_in_samplerate(gfp, lameConfig.format.LHV1.dwSampleRate);
+
+ // disable INFO/VBR tag by default.
+ // if this tag is used, the calling program must call beWriteVBRTag()
+ // after encoding. But the original DLL documentation does not
+ // require the
+ // app to call beWriteVBRTag() unless they have specifically
+ // set LHV1.bWriteVBRHeader=TRUE. Thus the default setting should
+ // be disabled.
+ lame_set_bWriteVbrTag(gfp, 0);
+
+ //2001-12-18 Dibrom's ABR preset stuff
+
+ if (lameConfig.format.LHV1.nPreset == LQP_ABR) // --ALT-PRESET ABR
+ {
+ actual_bitrate = lameConfig.format.LHV1.dwVbrAbr_bps / 1000;
+
+ // limit range
+ if (actual_bitrate > 320)
+ {
+ actual_bitrate = 320;
+ }
+
+ if (actual_bitrate < 8)
+ {
+ actual_bitrate = 8;
+ }
+
+ lame_set_preset(gfp, actual_bitrate);
+ }
+
+ // end Dibrom's ABR preset 2001-12-18 ****** START OF CBR
+
+ if (lameConfig.format.LHV1.nPreset == LQP_CBR) // --ALT-PRESET CBR
+ {
+ actual_bitrate = lameConfig.format.LHV1.dwBitrate;
+ lame_set_preset(gfp, actual_bitrate);
+ lame_set_VBR(gfp, vbr_off);
+ }
+
+ // end Dibrom's CBR preset 2001-12-18
+
+ // The following settings only used when preset is not one of the LAME QUALITY Presets
+ if ((int)lameConfig.format.LHV1.nPreset < (int)LQP_STANDARD)
+ {
+ switch (lameConfig.format.LHV1.nMode)
+ {
+ case BE_MP3_MODE_STEREO:
+ lame_set_mode(gfp, STEREO);
+ lame_set_num_channels(gfp, 2);
+ break;
+ case BE_MP3_MODE_JSTEREO:
+ lame_set_mode(gfp, JOINT_STEREO);
+ //lame_set_force_ms( gfp, bForceMS ); // no check box to force this?
+ lame_set_num_channels(gfp, 2);
+ break;
+ case BE_MP3_MODE_MONO:
+ lame_set_mode(gfp, MONO);
+ lame_set_num_channels(gfp, 1);
+ break;
+ case BE_MP3_MODE_DUALCHANNEL:
+ lame_set_mode(gfp, DUAL_CHANNEL);
+ lame_set_num_channels(gfp, 2);
+ break;
+ default:
+ {
+ DebugPrintf("Invalid lameConfig.format.LHV1.nMode, value is %d\n", lameConfig.format.LHV1.nMode);
+ return BE_ERR_INVALID_FORMAT_PARAMETERS;
+ }
+ }
+
+ if (lameConfig.format.LHV1.bEnableVBR)
+ {
+ /* set VBR quality */
+ lame_set_VBR_q(gfp, lameConfig.format.LHV1.nVBRQuality);
+
+ /* select proper VBR method */
+ switch (lameConfig.format.LHV1.nVbrMethod)
+ {
+ case VBR_METHOD_NONE:
+ lame_set_VBR(gfp, vbr_off);
+ break;
+
+ case VBR_METHOD_DEFAULT:
+ lame_set_VBR(gfp, vbr_default);
+ break;
+
+ case VBR_METHOD_OLD:
+ lame_set_VBR(gfp, vbr_rh);
+ break;
+
+ case VBR_METHOD_MTRH:
+ case VBR_METHOD_NEW:
+ /*
+ * the --vbr-mtrh commandline switch is obsolete.
+ * now --vbr-mtrh is known as --vbr-new
+ */
+ lame_set_VBR(gfp, vbr_mtrh);
+ break;
+
+ case VBR_METHOD_ABR:
+ lame_set_VBR(gfp, vbr_abr);
+ break;
+
+ default:
+ /* unsupported VBR method */
+ assert(FALSE);
+ }
+ }
+ else
+ {
+ /* use CBR encoding method, so turn off VBR */
+ lame_set_VBR(gfp, vbr_off);
+ }
+
+ /* Set bitrate. (CDex users always specify bitrate=Min bitrate when using VBR) */
+ lame_set_brate(gfp, lameConfig.format.LHV1.dwBitrate);
+
+ /* check if we have to use ABR, in order to backwards compatible, this
+ * condition should still be checked indepedent of the nVbrMethod method
+ */
+ if (lameConfig.format.LHV1.dwVbrAbr_bps > 0)
+ {
+ /* set VBR method to ABR */
+ lame_set_VBR(gfp, vbr_abr);
+
+ /* calculate to kbps, round to nearest kbps */
+ lame_set_VBR_mean_bitrate_kbps(gfp, (lameConfig.format.LHV1.dwVbrAbr_bps + 500) / 1000);
+
+ /* limit range */
+ if (lame_get_VBR_mean_bitrate_kbps(gfp) > 320)
+ {
+ lame_set_VBR_mean_bitrate_kbps(gfp, 320);
+ }
+
+ if (lame_get_VBR_mean_bitrate_kbps(gfp) < 8)
+ {
+ lame_set_VBR_mean_bitrate_kbps(gfp, 8);
+ }
+ }
+
+ }
+
+ // First set all the preset options
+ if (LQP_NOPRESET != lameConfig.format.LHV1.nPreset)
+ {
+ PresetOptions(gfp, lameConfig.format.LHV1.nPreset);
+ }
+
+
+ // Set frequency resampling rate, if specified
+ if (lameConfig.format.LHV1.dwReSampleRate > 0)
+ {
+ lame_set_out_samplerate(gfp, lameConfig.format.LHV1.dwReSampleRate);
+ }
+
+
+ switch (lameConfig.format.LHV1.nMode)
+ {
+ case BE_MP3_MODE_MONO:
+ lame_set_mode(gfp, MONO);
+ lame_set_num_channels(gfp, 1);
+ break;
+
+ default:
+ break;
+ }
+
+
+ // Use strict ISO encoding?
+ lame_set_strict_ISO(gfp, (lameConfig.format.LHV1.bStrictIso) ? 1 : 0);
+
+ // Set copyright flag?
+ if (lameConfig.format.LHV1.bCopyright)
+ {
+ lame_set_copyright(gfp, 1);
+ }
+
+ // Do we have to tag it as non original
+ if (!lameConfig.format.LHV1.bOriginal)
+ {
+ lame_set_original(gfp, 0);
+ }
+ else
+ {
+ lame_set_original(gfp, 1);
+ }
+
+ // Add CRC?
+ if (lameConfig.format.LHV1.bCRC)
+ {
+ lame_set_error_protection(gfp, 1);
+ }
+ else
+ {
+ lame_set_error_protection(gfp, 0);
+ }
+
+ // Set private bit?
+ if (lameConfig.format.LHV1.bPrivate)
+ {
+ lame_set_extension(gfp, 1);
+ }
+ else
+ {
+ lame_set_extension(gfp, 0);
+ }
+
+
+ // Set VBR min bitrate, if specified
+ if (lameConfig.format.LHV1.dwBitrate > 0)
+ {
+ lame_set_VBR_min_bitrate_kbps(gfp, lameConfig.format.LHV1.dwBitrate);
+ }
+
+ // Set Maxbitrate, if specified
+ if (lameConfig.format.LHV1.dwMaxBitrate > 0)
+ {
+ lame_set_VBR_max_bitrate_kbps(gfp, lameConfig.format.LHV1.dwMaxBitrate);
+ }
+ // Set bit resovoir option
+ if (lameConfig.format.LHV1.bNoRes)
+ {
+ lame_set_disable_reservoir(gfp, 1);
+ }
+
+ // check if the VBR tag is required
+ if (lameConfig.format.LHV1.bWriteVBRHeader)
+ {
+ lame_set_bWriteVbrTag(gfp, 1);
+ }
+ else
+ {
+ lame_set_bWriteVbrTag(gfp, 0);
+ }
+
+ // Override Quality setting, use HIGHBYTE = NOT LOWBYTE to be backwards compatible
+ if ((lameConfig.format.LHV1.nQuality & 0xFF) ==
+ ((~(lameConfig.format.LHV1.nQuality >> 8)) & 0xFF))
+ {
+ lame_set_quality(gfp, lameConfig.format.LHV1.nQuality & 0xFF);
+ }
+
+ if (0 != (nInitReturn = lame_init_params(gfp)))
+ {
+ return nInitReturn;
+ }
+
+ //LAME encoding call will accept any number of samples.
+ if (0 == lame_get_version(gfp))
+ {
+ // For MPEG-II, only 576 samples per frame per channel
+ *dwSamples = 576 * lame_get_num_channels(gfp);
+ }
+ else
+ {
+ // For MPEG-I, 1152 samples per frame per channel
+ *dwSamples = 1152 * lame_get_num_channels(gfp);
+ }
+
+ // Set the input sample buffer size, so we know what we can expect
+ dwSampleBufferSize = *dwSamples;
+
+ // Set MP3 buffer size, conservative estimate
+ *dwBufferSize = (DWORD)(1.25 * (*dwSamples / lame_get_num_channels(gfp)) + 7200);
+
+ // For debugging purposes
+ dump_config(gfp);
+
+ // Everything went OK, thus return SUCCESSFUL
+ return BE_ERR_SUCCESSFUL;
+ }
+
+
+
+ __declspec(dllexport) BE_ERR beFlushNoGap(HBE_STREAM hbeStream, PBYTE pOutput, PDWORD pdwOutput)
+ {
+ int nOutputSamples = 0;
+
+ lame_global_flags* gfp = (lame_global_flags*)hbeStream;
+
+ // Init the global flags structure
+ nOutputSamples = lame_encode_flush_nogap(gfp, pOutput, LAME_MAXMP3BUFFER);
+
+ if (nOutputSamples < 0)
+ {
+ *pdwOutput = 0;
+ return BE_ERR_BUFFER_TOO_SMALL;
+ }
+ else
+ {
+ *pdwOutput = nOutputSamples;
+ }
+
+ return BE_ERR_SUCCESSFUL;
+ }
+
+ __declspec(dllexport) BE_ERR beDeinitStream(HBE_STREAM hbeStream, PBYTE pOutput, PDWORD pdwOutput)
+ {
+ int nOutputSamples = 0;
+
+ lame_global_flags* gfp = (lame_global_flags*)hbeStream;
+
+ nOutputSamples = lame_encode_flush(gfp, pOutput, 0);
+
+ if (nOutputSamples < 0)
+ {
+ *pdwOutput = 0;
+ return BE_ERR_BUFFER_TOO_SMALL;
+ }
+ else
+ {
+ *pdwOutput = nOutputSamples;
+ }
+
+ return BE_ERR_SUCCESSFUL;
+ }
+
+
+ __declspec(dllexport) BE_ERR beCloseStream(HBE_STREAM hbeStream)
+ {
+ lame_global_flags* gfp = (lame_global_flags*)hbeStream;
+
+ // lame will be close in VbrWriteTag function
+ if (!lame_get_bWriteVbrTag(gfp))
+ {
+ // clean up of allocated memory
+ lame_close(gfp);
+
+ gfp_save = NULL;
+ }
+ else
+ {
+ gfp_save = (lame_global_flags*)hbeStream;
+ }
+
+ // DeInit encoder
+ return BE_ERR_SUCCESSFUL;
+ }
+
+
+
+ __declspec(dllexport) VOID beVersion(PBE_VERSION pbeVersion)
+ {
+ // DLL Release date
+ char lpszDate[20] = { '\0', };
+ char lpszTemp[5] = { '\0', };
+ lame_version_t lv = { 0, };
+
+
+ // Set DLL interface version
+ pbeVersion->byDLLMajorVersion = MAJORVERSION;
+ pbeVersion->byDLLMinorVersion = MINORVERSION;
+
+ get_lame_version_numerical(&lv);
+
+ // Set Engine version number (Same as Lame version)
+ pbeVersion->byMajorVersion = (BYTE)lv.major;
+ pbeVersion->byMinorVersion = (BYTE)lv.minor;
+ pbeVersion->byAlphaLevel = (BYTE)lv.alpha;
+ pbeVersion->byBetaLevel = (BYTE)lv.beta;
+
+#ifdef MMX_choose_table
+ pbeVersion->byMMXEnabled = 1;
+#else
+ pbeVersion->byMMXEnabled = 0;
+#endif
+
+ memset(pbeVersion->btReserved, 0, sizeof(pbeVersion->btReserved));
+
+ // Get compilation date
+ strcpy(lpszDate, __DATE__);
+
+ // Get the first three character, which is the month
+ strncpy(lpszTemp, lpszDate, 3);
+ lpszTemp[3] = '\0';
+ pbeVersion->byMonth = 1;
+
+ // Set month
+ if (strcmp(lpszTemp, "Jan") == 0) pbeVersion->byMonth = 1;
+ if (strcmp(lpszTemp, "Feb") == 0) pbeVersion->byMonth = 2;
+ if (strcmp(lpszTemp, "Mar") == 0) pbeVersion->byMonth = 3;
+ if (strcmp(lpszTemp, "Apr") == 0) pbeVersion->byMonth = 4;
+ if (strcmp(lpszTemp, "May") == 0) pbeVersion->byMonth = 5;
+ if (strcmp(lpszTemp, "Jun") == 0) pbeVersion->byMonth = 6;
+ if (strcmp(lpszTemp, "Jul") == 0) pbeVersion->byMonth = 7;
+ if (strcmp(lpszTemp, "Aug") == 0) pbeVersion->byMonth = 8;
+ if (strcmp(lpszTemp, "Sep") == 0) pbeVersion->byMonth = 9;
+ if (strcmp(lpszTemp, "Oct") == 0) pbeVersion->byMonth = 10;
+ if (strcmp(lpszTemp, "Nov") == 0) pbeVersion->byMonth = 11;
+ if (strcmp(lpszTemp, "Dec") == 0) pbeVersion->byMonth = 12;
+
+ // Get day of month string (char [4..5])
+ pbeVersion->byDay = (BYTE)atoi(lpszDate + 4);
+
+ // Get year of compilation date (char [7..10])
+ pbeVersion->wYear = (WORD)atoi(lpszDate + 7);
+
+ memset(pbeVersion->zHomepage, 0x00, BE_MAX_HOMEPAGE);
+
+ strcpy(pbeVersion->zHomepage, "http://www.mp3dev.org/");
+ }
+
+ __declspec(dllexport) BE_ERR beEncodeChunk(HBE_STREAM hbeStream, DWORD nSamples,
+ PSHORT pSamples, PBYTE pOutput, PDWORD pdwOutput)
+ {
+ // Encode it
+ int dwSamples;
+ int nOutputSamples = 0;
+ lame_global_flags* gfp = (lame_global_flags*)hbeStream;
+
+ dwSamples = nSamples / lame_get_num_channels(gfp);
+
+ // old versions of lame_enc.dll required exactly 1152 samples
+ // and worked even if nSamples accidently set to 2304
+ // simulate this behavoir:
+ if (1 == lame_get_num_channels(gfp) && nSamples == 2304)
+ {
+ dwSamples /= 2;
+ }
+
+
+ if (1 == lame_get_num_channels(gfp))
+ {
+ nOutputSamples = lame_encode_buffer(gfp, pSamples, pSamples, dwSamples, pOutput, 0);
+ }
+ else
+ {
+ nOutputSamples = lame_encode_buffer_interleaved(gfp, pSamples, dwSamples, pOutput, 0);
+ }
+
+
+ if (nOutputSamples < 0)
+ {
+ *pdwOutput = 0;
+ return BE_ERR_BUFFER_TOO_SMALL;
+ }
+ else
+ {
+ *pdwOutput = (DWORD)nOutputSamples;
+ }
+
+ return BE_ERR_SUCCESSFUL;
+ }
+
+
+ // accept floating point audio samples, scaled to the range of a signed 16-bit
+ // integer (within +/- 32768), in non-interleaved channels -- DSPguru, jd
+ __declspec(dllexport) BE_ERR beEncodeChunkFloatS16NI(HBE_STREAM hbeStream, DWORD nSamples,
+ PFLOAT buffer_l, PFLOAT buffer_r, PBYTE pOutput, PDWORD pdwOutput)
+ {
+ int nOutputSamples;
+ lame_global_flags* gfp = (lame_global_flags*)hbeStream;
+
+ nOutputSamples = lame_encode_buffer_float(gfp, buffer_l, buffer_r, nSamples, pOutput, 0);
+
+ if (nOutputSamples >= 0)
+ {
+ *pdwOutput = (DWORD)nOutputSamples;
+ }
+ else
+ {
+ *pdwOutput = 0;
+ return BE_ERR_BUFFER_TOO_SMALL;
+ }
+
+ return BE_ERR_SUCCESSFUL;
+ }
+
+ static int
+ maybeSyncWord(FILE* fpStream)
+ {
+ unsigned char mp3_frame_header[4];
+ size_t nbytes = fread(mp3_frame_header, 1, sizeof(mp3_frame_header), fpStream);
+ if (nbytes != sizeof(mp3_frame_header)) {
+ return -1;
+ }
+ if (mp3_frame_header[0] != 0xffu) {
+ return -1; /* doesn't look like a sync word */
+ }
+ if ((mp3_frame_header[1] & 0xE0u) != 0xE0u) {
+ return -1; /* doesn't look like a sync word */
+ }
+ return 0;
+ }
+
+ static int
+ skipId3v2(FILE* fpStream, size_t lametag_frame_size)
+ {
+ size_t nbytes;
+ size_t id3v2TagSize = 0;
+ unsigned char id3v2Header[10];
+
+ /* seek to the beginning of the stream */
+ if (fseek(fpStream, 0, SEEK_SET) != 0) {
+ return -2; /* not seekable, abort */
+ }
+ /* read 10 bytes in case there's an ID3 version 2 header here */
+ nbytes = fread(id3v2Header, 1, sizeof(id3v2Header), fpStream);
+ if (nbytes != sizeof(id3v2Header)) {
+ return -3; /* not readable, maybe opened Write-Only */
+ }
+ /* does the stream begin with the ID3 version 2 file identifier? */
+ if (!strncmp((char*)id3v2Header, "ID3", 3)) {
+ /* the tag size (minus the 10-byte header) is encoded into four
+ * bytes where the most significant bit is clear in each byte
+ */
+ id3v2TagSize = (((id3v2Header[6] & 0x7f) << 21)
+ | ((id3v2Header[7] & 0x7f) << 14)
+ | ((id3v2Header[8] & 0x7f) << 7)
+ | (id3v2Header[9] & 0x7f))
+ + sizeof id3v2Header;
+ }
+ /* Seek to the beginning of the audio stream */
+ if (fseek(fpStream, id3v2TagSize, SEEK_SET) != 0) {
+ return -2;
+ }
+ if (maybeSyncWord(fpStream) != 0) {
+ return -1;
+ }
+ if (fseek(fpStream, id3v2TagSize + lametag_frame_size, SEEK_SET) != 0) {
+ return -2;
+ }
+ if (maybeSyncWord(fpStream) != 0) {
+ return -1;
+ }
+ /* OK, it seems we found our LAME-Tag/Xing frame again */
+ /* Seek to the beginning of the audio stream */
+ if (fseek(fpStream, id3v2TagSize, SEEK_SET) != 0) {
+ return -2;
+ }
+ return 0;
+ }
+
+ static BE_ERR
+ updateLameTagFrame(lame_global_flags* gfp, FILE* fpStream)
+ {
+ size_t n = lame_get_lametag_frame(gfp, 0, 0); /* ask for bufer size */
+
+ if (n > 0)
+ {
+ unsigned char* buffer = 0;
+ size_t m = 1;
+
+ if (0 != skipId3v2(fpStream, n))
+ {
+ DispErr("Error updating LAME-tag frame:\n\n"
+ "can't locate old frame\n");
+ return BE_ERR_INVALID_FORMAT_PARAMETERS;
+ }
+
+ buffer = (unsigned char*)malloc(n);
+
+ if (buffer == 0)
+ {
+ DispErr("Error updating LAME-tag frame:\n\n"
+ "can't allocate frame buffer\n");
+ return BE_ERR_INVALID_FORMAT_PARAMETERS;
+ }
+
+ /* Put it all to disk again */
+ n = lame_get_lametag_frame(gfp, buffer, n);
+ if (n > 0)
+ {
+ m = fwrite(buffer, n, 1, fpStream);
+ }
+ free(buffer);
+
+ if (m != 1)
+ {
+ DispErr("Error updating LAME-tag frame:\n\n"
+ "couldn't write frame into file\n");
+ return BE_ERR_INVALID_FORMAT_PARAMETERS;
+ }
+ }
+ return BE_ERR_SUCCESSFUL;
+ }
+
+ __declspec(dllexport) BE_ERR beWriteInfoTag(HBE_STREAM hbeStream,
+ LPCSTR lpszFileName)
+ {
+ FILE* fpStream = NULL;
+ BE_ERR beResult = BE_ERR_SUCCESSFUL;
+
+ lame_global_flags* gfp = (lame_global_flags*)hbeStream;
+
+ if (NULL != gfp)
+ {
+ // Do we have to write the VBR tag?
+ if (lame_get_bWriteVbrTag(gfp))
+ {
+ // Try to open the file
+ fpStream = fopen(lpszFileName, "rb+");
+
+ // Check file open result
+ if (NULL == fpStream)
+ {
+ beResult = BE_ERR_INVALID_FORMAT_PARAMETERS;
+ DispErr("Error updating LAME-tag frame:\n\n"
+ "can't open file for reading and writing\n");
+ }
+ else
+ {
+ beResult = updateLameTagFrame(gfp, fpStream);
+
+ // Close the file stream
+ fclose(fpStream);
+ }
+ }
+
+ // clean up of allocated memory
+ lame_close(gfp);
+ }
+ else
+ {
+ beResult = BE_ERR_INVALID_FORMAT_PARAMETERS;
+ }
+
+ // return result
+ return beResult;
+ }
+
+ // for backwards compatiblity
+ __declspec(dllexport) BE_ERR beWriteVBRHeader(LPCSTR lpszFileName)
+ {
+ return beWriteInfoTag((HBE_STREAM)gfp_save, lpszFileName);
+ }
+
+
+ BOOL APIENTRY DllMain(HANDLE hModule,
+ DWORD ul_reason_for_call,
+ LPVOID lpReserved)
+ {
+ (void)lpReserved;
+ gs_hModule = (HMODULE)hModule;
+
+ switch (ul_reason_for_call)
+ {
+ case DLL_PROCESS_ATTACH:
+ // Enable debug/logging?
+ gs_bLogFile = GetPrivateProfileIntA("Debug", "WriteLogFile", gs_bLogFile, "lame_enc.ini");
+ break;
+ case DLL_THREAD_ATTACH:
+ break;
+ case DLL_THREAD_DETACH:
+ break;
+ case DLL_PROCESS_DETACH:
+ break;
+ }
+ return TRUE;
+ }
+
+
+ static void dump_config(lame_global_flags* gfp)
+ {
+ DebugPrintf("\n\nLame_enc configuration options:\n");
+ DebugPrintf("==========================================================\n");
+
+ DebugPrintf("version =%d\n", lame_get_version(gfp));
+ DebugPrintf("Layer =3\n");
+ DebugPrintf("mode =");
+ switch (lame_get_mode(gfp))
+ {
+ case STEREO: DebugPrintf("Stereo\n"); break;
+ case JOINT_STEREO: DebugPrintf("Joint-Stereo\n"); break;
+ case DUAL_CHANNEL: DebugPrintf("Forced Stereo\n"); break;
+ case MONO: DebugPrintf("Mono\n"); break;
+ case NOT_SET: /* FALLTROUGH */
+ default: DebugPrintf("Error (unknown)\n"); break;
+ }
+
+ DebugPrintf("Input sample rate =%.1f kHz\n", lame_get_in_samplerate(gfp) / 1000.0);
+ DebugPrintf("Output sample rate =%.1f kHz\n", lame_get_out_samplerate(gfp) / 1000.0);
+
+ DebugPrintf("bitrate =%d kbps\n", lame_get_brate(gfp));
+ DebugPrintf("Quality Setting =%d\n", lame_get_quality(gfp));
+
+ DebugPrintf("Low pass frequency =%d\n", lame_get_lowpassfreq(gfp));
+ DebugPrintf("Low pass width =%d\n", lame_get_lowpasswidth(gfp));
+
+ DebugPrintf("High pass frequency =%d\n", lame_get_highpassfreq(gfp));
+ DebugPrintf("High pass width =%d\n", lame_get_highpasswidth(gfp));
+
+ DebugPrintf("No short blocks =%d\n", lame_get_no_short_blocks(gfp));
+ DebugPrintf("Force short blocks =%d\n", lame_get_force_short_blocks(gfp));
+
+ DebugPrintf("de-emphasis =%d\n", lame_get_emphasis(gfp));
+ DebugPrintf("private flag =%d\n", lame_get_extension(gfp));
+
+ DebugPrintf("copyright flag =%d\n", lame_get_copyright(gfp));
+ DebugPrintf("original flag =%d\n", lame_get_original(gfp));
+ DebugPrintf("CRC =%s\n", lame_get_error_protection(gfp) ? "on" : "off");
+ DebugPrintf("Fast mode =%s\n", (lame_get_quality(gfp)) ? "enabled" : "disabled");
+ DebugPrintf("Force mid/side stereo =%s\n", (lame_get_force_ms(gfp)) ? "enabled" : "disabled");
+ DebugPrintf("Disable Reservoir =%d\n", lame_get_disable_reservoir(gfp));
+ DebugPrintf("Allow diff-short =%d\n", lame_get_allow_diff_short(gfp));
+ DebugPrintf("Interchannel masking =%f\n", lame_get_interChRatio(gfp));
+ DebugPrintf("Strict ISO Encoding =%s\n", (lame_get_strict_ISO(gfp)) ? "Yes" : "No");
+ DebugPrintf("Scale =%5.2f\n", lame_get_scale(gfp));
+
+ DebugPrintf("VBR =%s, VBR_q =%d, VBR method =",
+ (lame_get_VBR(gfp) != vbr_off) ? "enabled" : "disabled",
+ lame_get_VBR_q(gfp));
+
+ switch (lame_get_VBR(gfp))
+ {
+ case vbr_off: DebugPrintf("vbr_off\n"); break;
+ case vbr_mt: DebugPrintf("vbr_mt \n"); break;
+ case vbr_rh: DebugPrintf("vbr_rh \n"); break;
+ case vbr_mtrh: DebugPrintf("vbr_mtrh \n"); break;
+ case vbr_abr:
+ DebugPrintf("vbr_abr (average bitrate %d kbps)\n", lame_get_VBR_mean_bitrate_kbps(gfp));
+ break;
+ default:
+ DebugPrintf("error, unknown VBR setting\n");
+ break;
+ }
+
+ DebugPrintf("Vbr Min bitrate =%d kbps\n", lame_get_VBR_min_bitrate_kbps(gfp));
+ DebugPrintf("Vbr Max bitrate =%d kbps\n", lame_get_VBR_max_bitrate_kbps(gfp));
+
+ DebugPrintf("Write VBR Header =%s\n", (lame_get_bWriteVbrTag(gfp)) ? "Yes" : "No");
+ DebugPrintf("VBR Hard min =%d\n", lame_get_VBR_hard_min(gfp));
+
+ DebugPrintf("ATH Only =%d\n", lame_get_ATHonly(gfp));
+ DebugPrintf("ATH short =%d\n", lame_get_ATHshort(gfp));
+ DebugPrintf("ATH no =%d\n", lame_get_noATH(gfp));
+ DebugPrintf("ATH type =%d\n", lame_get_ATHtype(gfp));
+ DebugPrintf("ATH lower =%f\n", lame_get_ATHlower(gfp));
+ DebugPrintf("ATH aa =%d\n", lame_get_athaa_type(gfp));
+ //DebugPrintf("ATH aa loudapprox =%d\n", lame_get_athaa_loudapprox( gfp ) );
+ DebugPrintf("ATH aa sensitivity =%f\n", lame_get_athaa_sensitivity(gfp));
+
+ DebugPrintf("Experimental nspsytune =%d\n", lame_get_exp_nspsytune(gfp));
+ DebugPrintf("Experimental X =%d\n", lame_get_experimentalX(gfp));
+ DebugPrintf("Experimental Y =%d\n", lame_get_experimentalY(gfp));
+ DebugPrintf("Experimental Z =%d\n", lame_get_experimentalZ(gfp));
+ }
+
+
+ static void DispErr(wchar_t const* strErr)
+ {
+ MessageBox(NULL, strErr, L"LAME_ENC.DLL", MB_OK | MB_ICONHAND);
+ }
+
+#ifdef __cplusplus
+}
+#endif