This is the patch I wrote to allow the user to set a target compression ratio (rather than a bitrate) for determining the bitrate & stereo mode (regular Stereo vs Joint Stereo). I thought this would be useful for batch encoding when the source files are a mixture of mono & stereo, &/or of varying sample rates, which would of course be a pain in the butt to have to set separately. So, if we were to use a command line like "lame.exe --compression 5.2 infile.wav outfile.mp3", it would (should) encode all stereo 44kHz WAVs at 256kBit/sec, mono 32kHz WAVs at 96kBit/sec, & stereo 24kHz WAVs at 144kBit/sec, etc, without having to change the command line. Notes- 1- The altered files are lame.c & parse.c. I downloaded v3.70 just a few hours ago & retyped everything to that. I noticed there were some slight changes since v3.65 which is what I have on my home computer, but I think they're fine. I haven't altered any other files, including lame.h & parse.h, so I've probably missed something there. 2- I noticed how the arguments used "gfp->" at the start. I thought it would be best to use that for the extra arg, but I've never seen that before. I found the place where I *think* they've all been declared, so the variable I needed to use was included there. I hope it behaves. 3- Since this changes only "brate" & compression_ratio", I'd expect that "--compression floatval" would be freely interchangeable with "-b intval" in setting the low bitrate limit for VBR encodings. You could go as far as doing something similar for the maximum bitrate (by setting a minimum compression ratio) but I haven't done it. 4- I've probably forgotten a semicolon somewhere ;-) amongst other things, since I can't compile Lame on my home computer. Hope it works! Shawn ----- Start of patch ŻŻŻŻŻŻŻŻŻŻŻŻŻŻ /******************\ Purpose - To parse a new argument allowing the program set a compression ratio (by using "--compression floatval") Function - lame_parse_args() File - parse.c \******************/ if (argUsed>genre_last) { argUsed=255; fprintf(stderr,"Unknown genre: %s. Specifiy genre number \n", nextArg); } argUsed &= 255; c=(char)(argUsed); id3tag.used=1; argUsed = 1; strncpy(id3tag.genre, &c, 1); } ++ /* ++ If the user specifies a compression ratio, it will set the bitrate & stereo mode +(unless already specified) ++ Old frontends for Lame will probably set the bitrate ever ime, & this should be +able to overrule any bitrates set by them. ++ */ ++ else if (!strcmp(token, "lowpass") { ++ argUsed=1; ++ gfp->user_comp_ratio = atof( nextArg); /* to avoid rounding errors */ ++ ++ if (gfp->user_comp_ratio < 0.01) { ++ fprintf(stderr, "If you specify a compression ratio, it has to be positive. +You can also use \"1\" for the maximum bitrate.\n"); ++ exit(1) ++ } ++ } else if (strcmp(token, "lowpass")==0) { argUsed=1; gfp->lowpassfreq = (( 1000.0 * atof( nextArg ) ) + 0.5); if (gfp->lowpassfreq < 1) { fprintf(stderr,"Must specify lowpass with --lowpass freq, freq >= 0.001 kHz\n"); exit(1); } } /******************\ Purpose - To call a function which selects a valid bitrate based on input compression ratio. Function - lame_init_params() File - lame.c \******************/ gfp->mode_gr = (gfp->out_samplerate <= 24000) ? 1 : 2; /* mode_gr = 2 */ gfp->encoder_delay = ENCDELAY; gfp->framesize = gfp->mode_gr*576; ++ if (gfp->user_comp_ratio > 0.01) CalcBRFromCR(&gf); /* is this right? */ ++ /* If the user specified a compression ratio, it needs to set the bitrate here. if +the "-b" switch was used on the command line, it will be ignored. */ -- if (gfp->brate==0) { /* user didn't specify a bitrate, use default */ ++ if (gfp->brate==0) { /* User didn't specify a bitrate, nor a compression ratio. +Use default. */ gfp->brate=128; if (gfp->mode_gr==1) gfp->brate=64; } gfp->resample_ratio=1; if (gfp->out_samplerate != gfp->in_samplerate) gfp->resample_ratio = (FLOAT)gfp->in_samplerate/(FLOAT)gfp->out_samplerate; /******************\ Purpose - To select a bitrate from the given compression ratio Function - New function added - "CalcBRFromCR()" File - lame.c Notes- 1- Add this entire section somewhere useful within lame.c (probably near the end). 2- By the time we get here, we have a valid input & compression ratio & sample rate. This function assumes that. It also assumes that it's okay to change the bitrate. 3- This is the big kahuna for this patch. It's probably not very efficient though. At least this only has to happen once per file, however, if Lame is made to encode streams in which the sample rate keeps changing, it might be useful to call upon this function each time it changes so the compression quality stays about the same throughout. \******************/ void CalcBRFromCR(lame_global_flags *gfp) { /* Initialise constants & variables */ const int BRTableSize = 15; const int bitrate_table[2][BRTableSize] = { {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160} {0,32,40,48,56,64,80,96,112,128,160,192,224,256,320}}; /* I copied that table (above) from the start of "util.c". It should be consistent with the table in "util.c". (Perhaps that table should be set somewhere as a global constant) */ float AvailableBitrate = 0.0; int ClosestBitrate = 0; int UseTableRow = 0; /* Find out the bitrate needed... */ float RequestedBitrate = gfp->out_samplerate*16&gfp->stereo/(1000.0*gfp->user_comp_ratio); /* Find out which table row to use... */ if (gfp->out_samplerate==32000 || gfp->out_samplerate==44100 || gfp->out_samplerate==48000) UseTableRow = 1; /* Search through the table to find the bitrate with the closest match... */ int BRNumber = 1; float BRDeviation[2] = {0.0, 0.0}; /* Stores the ratio between the requested & available bitrate - first is current, second is previous. */ for (BRNumber = 1; BRNumber < BRTableSize; BRNumber++) { AvailableBitrate = bitrate_table[UseTableRow][BRNumber]; BRDeviation[1] = BRDeviation [0] /* Shuffle current to previous to make room for next */ BRDeviation[0] = RequestedBitrate / AvailableBitrate; if (RequestedBitrate < AvailableBitrate) break; /* Break if we've found the nearest bitrates. */ } } /* Decide which valid bitrate is closest to preferred & select it... */ if (BRDeviation[1] < 0.01) /* "Previous" deviation value is unchanged. Lowest bitrate isn't low enough, so the lowest bitrate has to do */ gfp->brate = bitrate_table[UseTableRow][1]; else if (BRDeviation > 1.00) /* We ran out of bitrates - Highest bitrate isn't high enough, so the highest will have to do. */ gfp-brate = bitrate_tabl[UseTableRow][BrTableSize - 1]; else { /* Looped once or more - preferred bitrate is somewhere between lowest & highest (usual) */ if ((BRDeviation[0] * BRDeviation[1] < 1) /* Lower bitrate was closer */ gfp->brate = bitrate_table[UseTableRow][BRNumber - 1]; else /* Higher bitrate was closer */ gfp->brate = bitrate_table[UseTableRow][BRNumber]; /* Now, having calculated the new bitrate, we should recalculate the compression ratio. */ compression_ratio = gfp->out_samplerate*16*gfp->stereo/(1000.0*gfp->brate); } /* End of "CalcBRFromCR()" /******************\ Purpose - To show a message indicating use of the "--compression" switch" Function - lame_print_config() File - lame.c Note - Someone's gonna have to fix this up, 'cause I've never used these "%" doohickeys before \******************/ if (gfp->resample_ratio!=1) { fprintf(stderr,"Resampling: input=%ikHz output=%ikHz\n", (int)in_samplerate,(int)out_samplerate); } ++ if(gfp->user_comp_ratio > 0.01) ++ fprintf(stderr, "Compression ratio of %.1fx requested. Using closest available +bitrate & ignoring \"-b\" switch.\n", /* This line could be a bit long... */ ++ gfp->user_comp_ratio); if (gfp->highpass2>0.0) fprintf(stderr, "Using polyphase highpass filter, transition band: %.0f Hz - %.0f Hz\n", gfp->highpass1*out_samplerate*500, gfp->highpass2*out_samplerate*500); /******************\ Purpose - To declare this variable we need to hold the compression ratio Function - lame_init() File - lame.c Note - This seems to be dealing with integer values. "user_comp_ratio" has to be a float! \******************/ gfp->version = 1; /* =1 Default: MPEG-1 */ gfp->mode = MPG_MD_JOINT_STEREO; gfp->mode_fixed=0; gfp->force_ms=0; gfp->brate=0; gfp->copyright=0; gfp->original=1; gfp->extension=0; gfp->error_protection=0; gfp->emphasis=0; gfp->in_samplerate=1000*44.1; gfp->out_samplerate=0; gfp->num_channels=2; gfp->num_samples=MAX_U_32_NUM; ++ gfp->user_comp_ratio = 0.0; gfp->inPath=NULL; gfp->outPath=NULL; id3tag.used=0; ____________ End of patch -- MP3 ENCODER mailing list ( http://geek.rcc.se/mp3encoder/ )