diff options
Diffstat (limited to 'Src/Plugins/Encoder/enc_lame/BladeMP3EncDLL.c')
-rw-r--r-- | Src/Plugins/Encoder/enc_lame/BladeMP3EncDLL.c | 1028 |
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 |