Version 1 of A Radio Recorder

Updated 2004-01-01 04:02:30

A Snack based application.

I enjoy talk radio, but some of my favorite shows play when I don't have access to a radio (like when I'm sleeping, for example). I finally got around to enabling the sound card on my UNIX server (Slackware 8 based). I installed the Linux Alsa drivers, which appear to work just fine.

Anyway, I figured I could just connect the Line-out from an available radio into the Line-in of the UNIX server machine, and record the programs. Well, being a Tcl kind of guy, I immediately thought of using Snack. I wanted the output to be in mp3 format, so I also have to use another application (Snack doesn't support mp3 for output). The following is a summary of the process, which might be useful to a few others.

Here are the components that make up my Radio Recorder:

  • cronjob - schedules the recordings. UNIX only, but other platforms have equivalents.
  • Tcl - Needed for Snack. Available for all platforms.
  • Snack - Extension to Tcl. Controls the audio card mixer and reads the Line-in and writes to WAV format. Available for all platforms.
  • lame - An mp3 encoder that converts the WAV output from Snack to mp3 format. Available for all platforms.

Here's the small Tcl program that's the core of the process. Since it's not a Wish application, it does a 'package require sound' instead of 'package require snack'. The snack package includes widgets, so you can't load it into a tclsh application. It sets the gain for the Line-in, reads the Line-in at 16000 sampling (remember, I'm recording talk radio, so this is plenty) and writes to stdout in WAV format. It takes one parameter, the number of seconds to record.

  #!/bin/sh
  # \
  exec tclsh "$0" "$@"

  package require sound

  set ::left  90
  set ::right 90

  snack::mixer volume IGain left right

  snack::sound ss -channel stdout -rate 16000 -channels Mono
  ss record -input Line1 -fileformat WAV

  after [expr [lindex $argv 0] * 1000] exit

  vwait forever

The output from this program is piped through lame to write the final output to an mp3 file. One hour of recording generates a ~10 MB file.

Here is an example shell script that gets run from a crontab entry. It creates a 1 hour time-stamped recording, storing it on a network accessible drive

  #!/bin/sh

  DEST=/mnt/bilbo/windows/MP3/Radio/DougMcIntyre

  TOD=`date +%d%b%Y_%H%M%S`
  exec /usr/local/bin/tclsh $HOME/radio/radiorecorder.tcl 3600 | /usr/local/bin/lame - $DEST/DougMcIntyre$TOD.mp3

That's it. I have various cronjobs that make hours of recordings of my favorite programs. I use Snackamp [L1 ] to play back the radio shows on any of my Windows or UNIX machines. My next step will be to get an AM/FM tuner card that I can install in the server (anyone know of a good one?).

Marty Backe 07 Aug 2002


I've updated the program to take pairs of command line arguments, specifying start and stop times (in seconds). This was done because some of the radio programs I record are syndicated and therefore have precise, dependable commercial breaks. I can have the recording start and stop, thus avoiding the recording of commercials (and helping to reduce file size).

 #!/bin/sh
 # \
 exec tclsh "$0" "$@"

 package require sound

 #
 # Parse input parameters. Each parameter consists of a start time, colon, and
 # stop time. All times are in seconds, referenced to the program start time.
 #
 if {$argc == 0} {
     puts "ERROR: At least one start/stop time must be provided."
     exit 255
 }
 foreach parameter $argv {
     set     splitList [split $parameter :]
     lappend recordTimesList $splitList
 }


 set ::left  90
 set ::right 90 

 snack::mixer volume IGain left right

 snack::sound ss -channel stdout -rate 16000 -channels Mono
 ss record -input Line1 -fileformat WAV
 ss pause

 #
 # Create a series of events to start and stop the recording
 #
 foreach times $recordTimesList {
     set startTime [expr {[lindex $times 0] * 1000}]
     set stopTime  [expr {[lindex $times 1] * 1000}] 

     after $startTime {ss pause}
     after $stopTime  {ss pause}
 }

 #
 # Setup for program exit after the last stop
 #
 set lastTimeIndex [expr {$argc - 1}]
 set exitTime [lindex [lindex $recordTimesList $lastTimeIndex] 1]
 set exitTime [expr {$exitTime * 1000}]
 incr exitTime 10
 after $exitTime exit

 vwait forever

And here's the driver shell script, run from a cronjob.

 #!/bin/sh

 DEST=/mnt/bilbo_extra/MP3/Radio/DennisPrager

 TOD=`date +%d%b%Y_%H%M%S`

exec /usr/local/bin/tclsh $HOME/radio/radiorecorder.tcl 330:1025 1265:1805 2060:2405 2645:3125 3320:3530 | /usr/local/bin/lame - $DEST/DennisPrager$TOD.mp3 > /dev/null