Digitizing Cassette Tapes

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 $<
	@nasm -f $(OFF) -i libmp3lame/i386/ -DWIN32 $< -o $@

Then I ran the whole thing with:

nmake -f Makefile.MSVC all

And 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:

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.

Bad Drivers

One of the things that Microsoft did in engineering the Windows 8 kernel was to eliminate and mitigate entire categories of kernel-mode memory exploits, by hardening the implementation with various new checks and removing code that would swallow multiple exceptions. The upside of this is that the kernel is more tamper-resistant. The downside (or upside, depending on how you look at it) is that buggy drivers now cause immediate kernel panics as soon as an offending operation is performed.

In other words, leaky, exploitable in-kernel drivers from days of old now cause the system to blue screen immediately when they do something wrong. This is actually the correct behavior and should help new driver devs catch problems early, but it also means my mid-2009 13″ MacBook Pro (model 5,5) has been blue screening like crazy ever since I installed Boot Camp 4.

It also means that, when these bugchecks are happening on Windows 8, they aren’t necessarily happening on Windows 7, or Vista, or XP. These could be points for investigation, by people wanting to develop exploits on those systems, because they would know exactly where the driver is doing something wrong in kernel memory.

Anyway, I got down and dirty and took a look at the minidumps being generated by the Boot Camp Services. There’s no official support for Windows 8 from Apple yet, but having drivers that are buggy on Windows 7 but that don’t immediately error out is probably also not a great thing.

Apple, take note, your Hardware Abstraction Layer driver is buggy:


Loading Dump File [C:WindowsMinidump21013-6162-01.dmp]
Mini Kernel Dump File: Only registers and stack trace are available

Symbol search path is: SRV*c:symbols*http://msdl.microsoft.com/download/symbols
Executable search path is:
Windows 8 Kernel Version 9200 MP (2 procs) Free x64
Product: WinNt, suite: TerminalServer SingleUserTS Personal
Built by: 9200.16461.amd64fre.win8_gdr.121119-1606
Machine Name:
Kernel base = 0xfffff803dfc78000 PsLoadedModuleList = 0xfffff803dff42a80
Debug session time: Sun Feb 10 12:36:21.739 2013 (UTC - 6:00)
System Uptime: 0 days 0:00:30.493
Loading Kernel Symbols
...............................................................
................................................................
.........................................
Loading User Symbols
Loading unloaded module list
.........
*******************************************************************************
* *
* Bugcheck Analysis *
* *
*******************************************************************************

Use !analyze -v to get detailed debugging information.

BugCheck 19, {20, fffffa800942bb50, fffffa800942bc10, c0c0001}

*** WARNING: Unable to verify timestamp for MacHALDriver.sys
*** ERROR: Module load completed but symbols could not be loaded for MacHALDriver.sys
Probably caused by : MacHALDriver.sys ( MacHALDriver+1714 )

Followup: MachineOwner

0: kd> !analyze -v
*******************************************************************************
* *
* Bugcheck Analysis *
* *
*******************************************************************************

BAD_POOL_HEADER (19)
The pool is already corrupt at the time of the current request.
This may or may not be due to the caller.
The internal pool links must be walked to figure out a possible cause of
the problem, and then special pool applied to the suspect tags or the driver
verifier to a suspect driver.
Arguments:
Arg1: 0000000000000020, a pool block header size is corrupt.
Arg2: fffffa800942bb50, The pool entry we were looking for within the page.
Arg3: fffffa800942bc10, The next pool entry.
Arg4: 000000000c0c0001, (reserved)

Debugging Details:
------------------

BUGCHECK_STR: 0x19_20

POOL_ADDRESS: GetPointerFromAddress: unable to read from fffff803dffce168
GetUlongFromAddress: unable to read from fffff803dffce1f8
fffffa800942bb50 Nonpaged pool

CUSTOMER_CRASH_COUNT: 1
DEFAULT_BUCKET_ID: WIN8_DRIVER_FAULT
PROCESS_NAME: Bootcamp.exe
CURRENT_IRQL: 1
IRP_ADDRESS: ffffffffffffff89
LAST_CONTROL_TRANSFER: from fffff803dfee8b95 to fffff803dfcf3340

STACK_TEXT:
fffff8800a1db8f8 fffff803dfee8b95 : 0000000000000019 0000000000000020 fffffa800942bb50 fffffa800942bc10 : nt!KeBugCheckEx
fffff8800a1db900 fffff803dfd2c229 : fffffa800942bb60 fffffa80095f9640 0000000000000001 0000000020206f49 : nt!ExFreePool+0xad3
fffff8800a1db9e0 fffff803dfd2a8ea : 0000000000000001 fffff8800a1dbaf0 0035003700000000 fffff8a002e9a2e0 : nt!IopCompleteRequest+0x79
fffff8800a1dbab0 fffff88008d39714 : 0000000000000000 00000000c0000000 fffffa800942bb80 000000009c402484 : nt!IopfCompleteRequest+0xa5a
fffff8800a1dbb90 0000000000000000 : 00000000c0000000 fffffa800942bb80 000000009c402484 0000000000000000 : MacHALDriver+0x1714

STACK_COMMAND: kb

FOLLOWUP_IP:
MacHALDriver+1714
fffff880`08d39714 ?? ???

SYMBOL_STACK_INDEX: 4
SYMBOL_NAME: MacHALDriver+1714
FOLLOWUP_NAME: MachineOwner
MODULE_NAME: MacHALDriver
IMAGE_NAME: MacHALDriver.sys
DEBUG_FLR_IMAGE_TIMESTAMP: 4d81c6e3
FAILURE_BUCKET_ID: 0x19_20_MacHALDriver+1714
BUCKET_ID: 0x19_20_MacHALDriver+1714

Followup: MachineOwner
---------

Update: The only way to fix these crashes was to uninstall the Boot Camp Services package from Windows. Unfortunately, that leaves the keyboard-backlighting inoperable, and probably some other stuff I can’t see, like processor throttling/idling (the Mac feels warmer during normal use now). Also, the weird thing about the crashes when they were happening was that they were inconsistent/nondeterministic, sometimes I’d get a blue screen right after logging in, and sometimes the system would run solid for hours until I had the misfortune of surreptitiously POKEing the wrong memory-mapped hardware address by trying to change the backlight levels or whatever.

Sigh.