Ripping Tapes with Linux--How To



Perhaps this should be a "how I did it"--it worked fine for me. An
html version of this explanation is available at
http://www.chaotrope.net/taperipping.html along with the script proper.

Ripping Tapes with Linux

Converting tapes to some more portable format, like MP3, usually
involves a lot of hand editing of the recorded sequences. I did not
want to take the time required to hand edit each recording. This
note
was generated out of transcoding books-on-tape, which have the
advantage of one track on each side of the tape. I would very much
like to have identified a tool which could split tracks
automatically,
but I did not succeed. The method here, though works well for these
books-on-tape.

For those who love code, the full script is located in the BASH
shell
script [1]wavbreak. This script is licensed under the GNU General
Public License, available at [2]http://www.gnu.org/licenses/gpl.txt.

Hook-Up

Wire your tape player's "line out" to your sound card's "line in".
Mute any microphone or alternate inputs, so that you do not
introduce
any unnecessary noise.

My tape player is a portable style journalist's recorder from the
mid-eighties. It has excellent outputs, though I believe this method
could be made to work with the headphone jack on a player, quality
will suffer though.

Input Levels

The most irritating part of the recording process was setting the
input level. I tried esd with the graphical VU meter included
(esdmeter?) but it would rail all the time and had no apparent
relationship to the ALSA mixer settings. In the end I used an
iterative method of recording a section, examining the levels with
Audacity, and then adjusting the input levels with alsamixer.

The recording command I used was arecord test.wav which I would
interrupt with Ctrl-C when I felt I had a representative sample.
Once
I had the levels set where I wanted them I saved them with alsactl
-f
ripping.alsa store so that they could easily be restored before my
next recording session. The restore command is alsactl -f
ripping.alsa
restore

Processing String

Although sox supports a noise reduction algorithm (Weiner filter, I
believe) I could not get it to work. It would run forever while the
output file grew to be much, much, larger than the input file.
Therefore, I did not use it.

To record the actual signal I set the sound card state where I
wanted
it (see above) and then ran the command nice -n -20 arecord -D
plughw:2 -c 2 -r 44100 -f S16 -t raw | nice -n -20 sox - s -w -r
44100
-c 2 -t raw - -c 1 tape.wav avg -l silence 1 00:00:01.0 2% -1
00:00:10.0 2% To go through the command line options one by one
nice
1. nice -n -20 ... runs this at maximim priority. You don't want to
get skips due to other tasks. On my system (Ubuntu/Dapper) I do
not need to be root to access the high priorities.

arecord
1. arecord use the ALSA recording utility.
2. -c 2 output two channels (stereo). The specific tapes I was
recoding were monaural, with one channel at zero. The result of
using -c 1 (which is what I really wanted) was that arecord
averaged a noise channel with a signal channel, resulting in
half
the amplitude.
3. -t raw sets the output to be raw PCM, and does not produce a
header. This is vital if you are piping to another application.
4. -D plughw:2 use the alsa device "plughw:2"; for reasons I really
do not understand using just "hw:2" did not work.
5. -r 44100 record at 44.1 KHz. Notice that many sound cards, such
as
SoundBlaster, only support 48 KHz natively. I would advise using
a
natively supported rate.
6. -f S16 uses 16 bits per sample of signed integer representation.
I
could have used 24 bits, but I had trouble getting the levels
set
when using 24 bit sampling.

sox
1. sox is the tool for working with command line sound in linux.
Actually there are better ones, but this works in almost all
cases, I've had trouble with ecasound and JACK in the past.
2. -s indicates the input is signed linear
3. -w and the input is 16 bits per sample
4. -r 44100 sampled at 44100 Hz
5. -c 2 using stereo
6. -t raw and the data is raw
7. - and finally that the input is STDIN (using a pipe).
8. -c 1 but the output will be one channel
9. tape.wav in a WAV file called tape.wav
10. avg -l and that conversion from stereo to single channel will
select only the left channel.
11. silence 1 00:00:01.0 2% -1 00:00:10.0 2% and that it will not
start recording until the sound level is greater than 2% of the
input dynamic range for at least one period of one second, and
that the recording will stop when the sound level falls below 2%
for at least one unit of 10 seconds. The minus sign in front of
the "1" means that the if sound is encountered again the record
will start again. However, there did not seem to be a way to
cause
this to generate a new file.

I ran the above command for each side of each tape, changing only
the
name of the output file.

Splitting and Converting

To navigate the sound with a CD MP3 player it is nice to have
recordings in sections of about five minutes. I used a script to
break
the large wav files into small ones while simultaneously compressing
with lame.
Normalizing

First, I want all the produced files at the same level, so I want to
determine the normalization parameter for the big file. I did that
with a command like: sox tape.wav -e stat > statsfile.txt 2>&1 which
places a bunch of statistics into the file called "statsfile.txt"
(using the BASH shell). I used a couple parameters from this
operation, in particular the volume setting to normalize and the
length of the file. Those lines look like:
Samples read: 88200
Length (seconds): 2.000000
Scaled by: 2147483647.0
Maximum amplitude: 0.008148
Minimum amplitude: -0.003723
Midline amplitude: 0.002213
Mean norm: 0.002433
Mean amplitude: 0.002428
RMS amplitude: 0.002609
Maximum delta: 0.006592
Minimum delta: 0.000000
Mean delta: 0.000476
RMS delta: 0.000756
Rough frequency: 2032
Volume adjustment: 122.727

The lines we need are the number from the "Volume adjustment:" line
and the number from the "Length (seconds):" line. I used some awk to
get the numbers, but I won't go into the specific commands here
(they're in the script).

I used a bunch of bc commands and eval to determine the number of
files to produce. However, the only real command of importance is
sox
tape.wav -r 44100 -c 1 -v $NORM -s -w -t raw - trim $TIME_START
$DURATION | lame -r -x -s 44.1 -m m --vbr-new - tape_segment.mp3 To
go
through this pedantically
sox
1. tape.wav the input file
2. -r 44100 the outpt sampling rate in Hz
3. -c 1 monaural
4. -v $NORM actually normalizes the sample. The volume adjustment
number is stored in the shell variable $NORM.
5. -s causes output to be signed
6. -w linear 16 bits per sample
7. -t raw use raw PCM on the output
8. - output to STDOUT
9. trim $TIME_START $DURATION causes sox to seek ahead in the file
$TIME_START seconds and then output $DURATION seconds. The
script
goes through the effort of determining when and where the
segments
will be taken.

lame
1. -r tells lame the input is raw PCM
2. -x forces byte swapping. I did not think this would be
necessary,
since everything was recorded on this little-endian machine, but
experiment proved this flag is needed.
3. -s 44.1 to indicate the sampling rate is 44.1 KHz
4. -m m using a single channel (monaural)
5. --vbr-new using variable rate, the latest version of the
algorithm.
6. - and the source file is STDIN
7. tape_segment.mp3 as the output file.

Finally, there may be gap issues using this method. Ideally we want
the songs to play with a no-gap setting, but I did not explore this
in
the interest of expedience.

April 29, 2006

Park Hays

References

1. http://www.chaotrope.net/wavbreak
2. http://www.gnu.org/licenses/gpl.txt

---------------------------------------------------- SCRIPT FOLLOWS
---------------------------------------------------------
#!/bin/bash
################################################################################
# Copyright 2006 Park Hays
#
# This program is free software; you can redistribute it and/or
modify
# it under the terms of the GNU General Public License as published
by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
02110-1301 USA
#
################################################################################

# Usage: wavbreak <infile> <outfile>
# where outfile will be created as a file like outfile-##.mp3. For
# example, running
# wavbreak monkey_squawk.wav ms
# will produce files like "ms-00.mp3" and "ms-01.mp3".

# Objective of script is to normalize entire file, then break into
# 5-minute segments and compress each segment into an mp3.

# assumes a couple seconds of noise in a file "noise.wav" recorded
# from a blank section of the tape (or selected using a graphical
# tool).

NOISE_FN=noise.wav
SMALL_LEN_MIN=5
VERBOSE=2
QUICKTEST=0
SMALL_LEN=`echo "$SMALL_LEN_MIN * 60" | bc`;

# Note that as of Apr 26, 2006 the de-noising in sox seems to be
broken.
# Even very short files seem never to finish.

# Signal processing order:
# noise-reduce -> file
# file -> normalize -> big_file
# big_file -> split, compress -> files

# Give myself two temporary files
TMP1=tmp-${RANDOM}.wav
TMP2=tmp-${RANDOM}.txt

NOISE_PROF_FN=${NOISE_FN}-profile

# Reduce the noise
if [ ! -f $NOISE_PROF_FN ] ; then
sox $NOISE_FN -e noiseprof ${NOISE_PROF_FN}
fi

if [ $VERBOSE -gt 1 ] ; then
echo Starting de-noise procedure to file $TMP1
fi

if [ $QUICKTEST -gt 0 ] ; then
echo "Disabling de-noise for rapid testing"
cp $1 $TMP1
else
sox $1 $TMP1 noisered $NOISE_PROF_FN
fi

# Determine normalization factor and other stats
if [ $VERBOSE -gt 1 ] ; then
echo Determining file statistics for normalization etc.
fi

STATS=`sox $TMP1 -e stat >$TMP2 2>&1`;
NORM=`grep Volume $TMP2 | awk '{print $NF}'`
LENGTH_SEC=`grep Length $TMP2 | awk '{print $NF}'`

if [ $VERBOSE -gt 2 ] ; then
echo Removing stats file \"$TMP2\"
fi
rm $TMP2

if [ $VERBOSE -gt 1 ] ; then
echo NORM is $NORM
echo LENGTH is $LENGTH_SEC
fi


# Apply the normalization while splitting and compressing
NUM_WHOLE_FILES=`echo "a = $LENGTH_SEC / $SMALL_LEN; a - (a % 1)" | bc`
if [ $VERBOSE ] ; then
echo Number of whole files is $NUM_WHOLE_FILES
fi

for i in `seq 1 $NUM_WHOLE_FILES` ; do

# Determine start & stop times
TIME_START=`echo "$SMALL_LEN * ($i - 1)" | bc`;

# Determine output file name
printf -v FILENUM %.2d $i
OFN=${2}-${FILENUM}.mp3;

if [ $VERBOSE -gt 1 ] ; then
echo Starting at $TIME_START
echo Stopping at $TIME_STOP
fi

if [ $VERBOSE ] ; then
echo Writing output to $OFN
fi

sox $TMP1 -r 44100 -c 1 -v $NORM -s -w -t raw - trim $TIME_START
$SMALL_LEN
| lame -r -x -s 44.1 -m m --vbr-new - $OFN
done

if [ $VERBOSE -gt 1 ] ; then
echo Done writing whole files, finishing with segment.
fi

# Get the last little bit
# Determine start & stop times
TIME_START=`echo "$NUM_WHOLE_FILES * $SMALL_LEN" | bc`
i=`expr $NUM_WHOLE_FILES + 1`

# Determine output file name
printf -v FILENUM %.2d $i
OFN="${2}-${FILENUM}.mp3"
if [ $VERBOSE ] ; then
echo Writing output to $OFN
fi

sox $TMP1 -r 44100 -c 1 -v $NORM -s -w -t raw - trim $TIME_START | lame
-r -x -s
44.1 -m m --vbr-new - $OFN

if [ $VERBOSE -gt 1 ] ; then
echo Removing temporary file \"$TMP1\"
fi

rm $TMP1

.



Relevant Pages

  • SUMMARY: ufsdump and ufsrestore
    ... > I need a simple script to dump a server mirrored with solstice disksuite ... > tape, then demonstrate how to recover it to a new disk. ... mt -f /dev/rmt/0 rewind ... echo "backing up root" ...
    (SunManagers)
  • Re: Please suggest a video capture software
    ... I will try writing a script for that. ... xawtv + streamer combination (streamer seems to work even when ... Being able to watch the video while recording is a rather basic thing. ... echo " red Script" ...
    (Debian-User)
  • Re: Legato question about tape redundancy
    ... Ok I decided to write a script just to rotate the tapes each ... time a backup runs- incremental or full, it stores the tape volume it ... echo "\nError..looks like a backup is running. ... Exit now.\n" ...
    (comp.unix.solaris)
  • Re: Re: ntbackup need more than one backup tape??
    ... I would deallocate the current tape and prepare it again. ... >Here is my script ... >echo off ... >>Jerold Schulman ...
    (microsoft.public.win2000.applications)
  • Re: [Full-disclosure] reduction of brute force login attempts via SSHthrough iptables --
    ... Anyhow its no problem at all to modify, so if you dont like it, just dont use it. ... on a lame script like this as long as it WORKS and is not insecure. ... echo "~ sorting out ip by ip" ... # echo "not enough failed logins, probably no attack from: ...
    (Full-Disclosure)