/* * 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 #include #include "BladeMP3EncDLL.h" #include #include #include #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( char 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(char const* strErr) { MessageBoxA(NULL,strErr,"LAME_ENC.DLL",MB_OK|MB_ICONHAND); } #ifdef __cplusplus } #endif