So I’m trying to get some audio digitized off of tape. Unfortunately the old-school Audiograbber software that I used to use (uhh, circa 1998, when I was leaving high school) pulled the record-direct-to-MP3 feature out of their software. So, yeah, since I have a ton of RAM in my laptop (2 orders of magnitude more than I had back then!), I figured I’d just use Audacity and trade memory for time and record to uncompressed PCM, then compress. It’s a step backwards, but ho hum, that’s the rechtslage that we find ourselves in.
Of course, Audacity doesn’t come with an MP3 encoder due to royalty issues. And I didn’t really feel like downloading some random DLL from the site they link to in Brazil (where presumably the MPEG-LA doesn’t have much authority).
So I built LAME myself on Windows 8, using Microsoft Visual Studio 2012 Express, and a copy of NASM.
To get the build working, there were some tweaks that needed to be made to the Makefile.MSVC file that comes with the package. Since Audacity is a 32-bit executable, the tweaks tune it for a 32-bit output DLL.
First up, lib.exe command options at the top of the file:
MACHINE = /machine:I386 LIB_OPTS = /nologo $(MACHINE)
should be, adding Link Time Code Generation (ASLR and DEP get enabled by default, so you don’t need the /DYNAMICBASE /NXCOMPAT options):
MACHINE = /machine:X86 LIB_OPTS = /nologo $(MACHINE) /LTCG
There’s some detection of the Visual Studio 2012 environment variables you can add (you MUST use the uppercase version of the environment variable name, or nmake won’t resolve it!):
! ELSEIF "$(VISUALSTUDIOVERSION)" == "11.0" ! MESSAGE + using MSVC 11.0 32-Bit Compiler ! IF "$(CPU)" == "P1" ! MESSAGE + optimizing for Pentium (MMX) (may slow down PIII a few percent) ! ELSE ! MESSAGE + optimizing for Pentium II/III ! ENDIF
And then use the same sort of ELSEIF block to define some compiler optimizations:
! ELSEIF "$(VISUALSTUDIOVERSION)" == "11.0" CC_OPTS = /nologo /O2 /Ob2 /Oitxy /favor:blend /fp:precise /Qfast_transcendentals /Qpar /GL /GA /arch:SSE2
There’re two lines defining linker options that need to be changed from:
LN_OPTS = /nologo /opt:NOWIN98 /pdb:none LN_DLL = /nologo /DLL /opt:NOWIN98
to:
LN_OPTS = /nologo /pdb:none /LTCG LN_DLL = /nologo /DLL /LTCG
There’s the line defining the NASM command line to assemble certain objects, you need to change the “nasmw” command to be “nasm”, since that’s what the NASM executable is now called:
.nas.obj: @echo $Then I ran the whole thing with:
nmake -f Makefile.MSVC allAnd get the following error:
--- COMMON FRONTEND STUFF UPTODATE --- Microsoft (R) Windows (R) Resource Compiler Version 6.2.9200.16384 Copyright (C) Microsoft Corporation. All rights reserved. libmp3lame-static.lib(psymodel.obj) : error LNK2001: unresolved external symbol _static_assert_tab_mask_add_delta .outputlame.exe : fatal error LNK1120: 1 unresolved externals NMAKE : fatal error U1077: '"C:Program Files (x86)Microsoft Visual Studio 11.0 VCBINlink.EXE"' : return code '0x460' Stop.The offending code looks like this:
12345678910111213141516171819202122232425262728 /*This is the masking table:According to tonality, values are going from 0dB (TMN)to 9.3dB (NMT).After additive masking computation, 8dB are added, sofinal values are going from 8dB to 17.3dB*/static const FLOAT tab[] = {1.0 /*pow(10, -0) */ ,0.79433 /*pow(10, -0.1) */ ,0.63096 /*pow(10, -0.2) */ ,0.63096 /*pow(10, -0.2) */ ,0.63096 /*pow(10, -0.2) */ ,0.63096 /*pow(10, -0.2) */ ,0.63096 /*pow(10, -0.2) */ ,0.25119 /*pow(10, -0.6) */ ,0.11749 /*pow(10, -0.93) */};static const int tab_mask_add_delta[] = { 2, 2, 2, 1, 1, 1, 0, 0, -1 };#define STATIC_ASSERT_EQUAL_DIMENSION(A,B) {extern char static_assert_##A[dimension_of(A) == dimension_of(B) ? 1 : -1];(void) static_assert_##A;}inline static intmask_add_delta(int i){STATIC_ASSERT_EQUAL_DIMENSION(tab_mask_add_delta,tab);assert(i < (int)dimension_of(tab));return tab_mask_add_delta[i];}Which makes me hate the C preprocessor.
So I comment out the define's expansion. I guess it's useful, if those things ever have a size mismatch in the foreseeable future. The WTF-factor on that one feels pretty high, though, especially the preprocessor macro abuse and the fact that the two definitions are right next to each other, lending themselves to quick inspection. If they were cross-modules, or in separate files, I'd understand. (C needs to die, or learn from D)
Anyway, after that issue is removed, huzzah, it all builds:
--- COMMON FRONTEND STUFF UPTODATE --- Microsoft (R) Windows (R) Resource Compiler Version 6.2.9200.16384 Copyright (C) Microsoft Corporation. All rights reserved. Generating code Finished generating code --=* .outputlame.exe ready *=-- rtp.c mp3rtp.c Microsoft (R) Windows (R) Resource Compiler Version 6.2.9200.16384 Copyright (C) Microsoft Corporation. All rights reserved. Generating code Finished generating code --=* .outputmp3rtp.exe ready *=-- Creating library .outputlibmp3lame.lib and object .outputlibmp3lame.exp Generating code Finished generating code --=* .outputlibmp3lame.dll ready *=-- BladeMP3EncDll.c Microsoft (R) Windows (R) Resource Compiler Version 6.2.9200.16384 Copyright (C) Microsoft Corporation. All rights reserved. Creating library .outputlame_enc.lib and object .outputlame_enc.exp Generating code Finished generating code --=* .outputlame_enc.dll ready *=-- --=* all uptodate *=--And there you go! Now just copy the libmp3lame.dll file into Audacity's plugins directory, select it via the Audacity preferences, and it should work.
Update: Here's the Makefile.msvc.