I said I was looking into getting FIFOs working so that the filesize requirements would be reduced. It’s also more efficient this way. I was heavily influenced by the two scripts created by Daniel Howard.
So here’s how it works. You get to create two scripts. The first one is for recording. It’s an all-purpose script that I called record.sh. Here is the code:
[bash]#!/bin/bash
#
# record.sh
#
# Use mplayer to capture the stream
# at $STREAM to the file $FILE
#
# example: record.sh my_radio_show 60 mms://someserver.com/stream
DIR=/home/shawn/PodCasts #directory where to save the file
TEMPDIR=/tmp
# Don’t edit anything below this line
#######################################################
DATE=`date +%d-%b-%Y` # Save the date as DD-Mmm-YYYY
YEAR=`date +%Y` # Save just the year as YYYY
NAME=$1
DURATION=$2 # enough to catch the show, plus a bit
STREAM=$3
TEMPFILE=$TEMPDIR/$NAME-$DATE
FILE=$DIR/$NAME-$DATE # Where to save it
# Capture Stream
mkfifo $TEMPFILE.wav
mkfifo $TEMPFILE-silenced.wav
# The lame settings below are optimized for voice encoding
# The sox command below strips out any silent portions
lame -S -a -m m –ty “$YEAR” –vbr-new -V 9 –lowpass 13.4 –athaa-sensitivity 1 \
–resample 32 $TEMPFILE-silenced.wav $FILE.mp3 >/dev/null &
sox $TEMPFILE.wav -c 1 $TEMPFILE-silenced.wav \
silence 1 0.2 0.5% -1 0.2 0.5% >/dev/null&
/usr/bin/mplayer -quiet -cache 500 \
-ao pcm:file=”$TEMPFILE.wav” -vc dummy -vo null \
-noframedrop $STREAM >/dev/null&
sleep 5
# get the pid of all processes started in this script.
PIDS=`ps auxww | grep $TEMPFILE | awk ‘{print $2}’`
# the & turns the capture into a background job
sleep `echo ${DURATION}*60 | bc` # wait for the show to be over
kill $PIDS # kill the stream capture
rm $TEMPFILE.wav
rm $TEMPFILE-silenced.wav[/bash]
This script takes three args:
- the name of the show you’re recording. This will be used in the final filename with the current date appended.
- the length of the show in minutes
- the URI of the stream (often
mms://orhttp://)
This integrates very well with another script that will hold all the data for the shows we want to record and automatically set the start times for us. Here is my script that I called today.sh
[bash]#!/bin/sh
#
# today.sh — schedule what programs you want to rip today using the
# recorder script.
# Non-obvious paths
RECORDER=$HOME/bin/record.sh
RECORDER_HI=$HOME/bin/record-hi.sh
# Set up stations
KFI=”http://a814.l1977144512.c19771.g.lm.akamaistream.net/D/814/19771/v0001/reflector:44512?MSWMExt=.asf”
WXNT=mms://wmc1.liquidviewer.net/WXNT
WPGB=”http://84.53.144.36:80/D/1046/20063/v0001/reflector:43803?MSWMExt=.asf”
KOZZ=mms://lotusradio-kozz.wm.llnwd.net/lotusradio_kozz
# What day is it?
TODAY=`date +%a`
# EVERY DAY
#everyday() {}
# WEEKDAYS
weekday() {
# “Record John_Ziegler for three hours, starting at 7:00pm.”
echo $RECORDER John_Ziegler 180 $KFI | at 7:00pm
echo $RECORDER Glenn_Beck 180 $WPGB | at 6:00am
}
# MONDAY
if [ $TODAY = "Mon" ]; then
# everyday
weekday
fi
# TUESDAY
if [ $TODAY = "Tue" ]; then
# everyday
weekday
fi
# WEDNESDAY
if [ $TODAY = "Wed" ]; then
# everyday
weekday
fi
# THURSDAY
if [ $TODAY = "Thu" ]; then
# everyday
weekday
fi
# FRIDAY
if [ $TODAY = "Fri" ]; then
# everyday
weekday
fi
# SATURDAY
if [ $TODAY = "Sat" ]; then
# everyday
echo $RECORDER Handel_On_The_Law 300 $KFI | at 6:00am
echo $RECORDER Dr_Dean_Edell 60 $KFI | at 2:00pm
fi
# SUNDAY
if [ $TODAY = "Sun" ]; then
# everyday
echo $RECORDER Jesus_Christ_Show 180 $KFI | at 6:00am
echo $RECORDER Glenn_Beck 180 $WPGB | at 10:00am
echo $RECORDER_HI Dr_Demento 120 $KOZZ | at 10:00pm
fi[/bash]
Using this as a template you might notice another script being referred to. record.sh has audio processing optimized for talk radio. For higher quality and stereo, you need to change a few things. You can download all of the scripts mentioned here at the bottom of this post.
To finish off this solution you need to run today.sh at some point after 12:00am and before the start of the earliest program you wish to record. I set mine to run daily at 1:00am.
[code]# Schedule recordings for today from radio streams
0 1 * * * /home/shawn/bin/today.sh >& /dev/null[/code]
Downloads:
11 Responses to “Record Streaming Audio with Linux: Part II”
SWEET! My prior work has been recycled and improved upon! :)
:) :) :)
Thanks,
-danny
on March 3rd, 2006 at 11:10 am #
[...] check out the comments that follow for tips and tricks, especially Shawn Dowler who has gone and wrote a page about his revised versions of thescripts. [...]
I was working on my own solution, but I knew it was lacking some things, so when I found your implementation I was very impressed. I especially liked the way you killed all the processes. That was what I was looking for when I found your scripts. Your scripts were great, so I merged what I had with what you had done and I’m very pleased with the results.
I especially like your today script. It is so much nicer than what I was doing before. Now I have a central human-readable place to keep all the program scheduling data outside of my crontab.
Beautiful! Easy to understand the code, easy to implement, very useful results. Just what every Linux user dreams of. Thank you and congrats!
Thanks for this solution the scheduling of online programs was one of the items causing me to dual boot. Now I have one less reason to keep my XP partition. I just wish that it did not take me 5 days to find this solution after I started looking for it on the net! Again THANK YOU and also to all the authors of the pages that were referenced.
The only problem I am having getting this to work in Ubuntu is with RECORD_HI, but RECORD works great. I will figure that our soon enough, but this was a great start.
@Michael Brehm:
I’m glad that I could help you find a way to solve your problems using Free Software. I love to hear stories like yours, and the thanks are always appreciated!
Your script is great, I’m trying to implement now, but I have a question as to why you are running lame, then sox, and finally mplayer. I’m sure this is correct, I am just wondering why?
Again, your script is tight, good work :-)
mxwlpxwl
@mxwlpxwl:
The sox command was a late addition as I noticed some of the stations were including long periods of silence in place of certain commercials. It doesn’t happen as much anymore, but it still happens every now and again. The sox command just strips out silence, nothing more. You could leave it out, but it doesn’t change much if you leave it in, so I just put it in for all of them.
I’m glad you like the scripts. Remember, I didn’t come up with the concept, I just improved upon the original design.
Hi,
how can I add a simple frontend which permits to insert:
1) the location where to save the stream
2) the url
2) the recording time
Moreover I would like to be able to start and stop the recording using a record and a stop button.
I’ve done in the past a simple gui using perl, but I don’t know how to modify the script in order to stop the registration using the gui
Hi,
I’ve done the following script which acts as a “wizard” with some pop up that enables the user to pass the input to the recorder.
Do you like it?
Do you think is it possible to modify it in order to pause the recording?
Thank you,
Xwang
[bash]
#!/bin/bash
# radioRecoder.sh
# v0.2.0 – 20080808 :-)
# Xwang
# Released under GPL 2.0 and following (can you help me and tell if it is GPL3 compliant?)
# This script acts as a wizard enabling the user to select the URL to listen and eventually rip it after having specified
# the directory and the file name
# The cancel button is used to go to the previous page
# To exit the program press cancel in the URL page and follow the instruction
# TBD
# check if parameter is passed or not
# modify parmeters so that recording can be done without user iteration
# capture Ctrl-C in order to clean all temporary files and kill opened processes before closing
# put confirmation on registration stop
# open the directory where last file has been saved (maybe asking for it) at the end of the recording
# translate messanges
#
# assign as default stream value the one passed ad first parameters if any (check TBD)
STREAM=$1
TEMPDIR=/tmp
# inizialize variables
EXIT=1
STATE=1
PIDlistener2=”"
PIDrecorder2=”"
while [ $EXIT -eq 1 ]
do
case $STATE in
0)
kdialog –title “RadioRecorder” –yesno “Do you want to exit the program?”
EXIT=$?
if [ $EXIT -eq 1 ]
then
STATE=1
fi
;;
1)
# ask radio stream URL
STREAM=`kdialog –title “RadioRecorder” –inputbox “Insert the radio stream url” $1 `
STREAMBUTTON=$?
if [ $STREAMBUTTON -eq 1 ]
then
STATE=0
else
# start mplayer in background to listen to the radio only if the ok button has been selected else exit
# xterm -e mplayer -vo null -vc null -cache 512 $STREAM&
mplayer -vo null -vc null -cache 512 $STREAM&
PIDlistener=$! # listener PID
while [ -z $PIDlistener2 ]
do
#repeat the check till PIDlistener2 is correctly detected
PIDlistener2=`ps -ef| awk ‘$3 == ‘$PIDlistener’ { print $2 }’`
done
STATE=2
fi
;;
2)
# select action to do
ACTION=`kdialog –title “RadioRecorder” –menu “Select an action:” 1 “Change URL” 2 “Record stream”`
ACTIONBUTTON=$?
if [ $ACTIONBUTTON -eq 1 ]
then
ACTION=$ACTIONBUTTON # if cancel is selected go back to url dialog
fi
if [ $ACTION -eq 1 ]
then
#if Change URL or Cancel has been selected kill listener and go back to URL page
#kill listener processes
kill -9 $PIDlistener2
kill -9 $PIDlistener
# reinitialize PID variables
PIDlistener=”"
PIDlistener2=”"
STATE=1
else
STATE=3
fi
;;
3)
# ask destination directory — default home
DIR=$HOME
DIR=`kdialog –title “RadioRecorder – Select destination directory” –getexistingdirectory $DIR` #default destination directory is the user home
DIRBUTTON=$?
if [ $DIRBUTTON -eq 1 ]
then
#if Cancel has been selected go back to action page
STATE=2
else
STATE=4
fi
;;
4)
# ask file name at which will be added the date and eventually record stream
FILENAME=”radio”
FILENAME=`kdialog –title “RadioRecorder – Save as” –inputbox “Insert the file name (date will be automatically added)” $FILENAME`
FILENAMEBUTTON=$?
if [ $FILENAMEBUTTON -eq 1 ]
then
#if Cancel has been selected go back to action page
STATE=3
else
#capture stream
DATE=`date +%Y_%m_%d_%H%M%S`
TEMPFILE=$TEMPDIR/$FILENAME-$DATE
FILE=$DIR/$FILENAME-$DATE
mkfifo $TEMPFILE.wav
lame $TEMPFILE.wav $FILE.mp3>/dev/null&
PIDconverter=$! #converter PIN
# xterm -e mplayer -cache 512 -vo null -vc null -ao pcm:fast:file=”$TEMPFILE.wav” $STREAM>/dev/null&
mplayer -cache 512 -vo null -vc null -ao pcm:fast:file=”$TEMPFILE.wav” $STREAM>/dev/null&
PIDrecorder=$! #recorder PIN
while [ -z $PIDrecorder2 ]
do
#repeat the check till PIDrecorder2 is correctly detected
PIDrecorder2=`ps -ef| awk ‘$3 == ‘$PIDrecorder’ { print $2 }’`
done
kdialog –msgbox “Press OK button to stop recording”
#stop recording
#kill converter
kill -9 $PIDconverter
#kill recorder processes
kill -9 $PIDrecorder2
kill -9 $PIDrecorder
# reinitialize PID variables
PIDconverter=”"
PIDrecorder=”"
PIDrecorder2=”"
#removing temporary file
rm $TEMPFILE.wav
#go back to action page
STATE=2
fi
;;
esac
done
kdialog –title “RadioRecorder” –msgbox “Thank you for using radioRecorder”
echo “Bye Bye”
exit
[/bash]
Quite honestly, I don’t know how you would accomplish pausing the recording. It’s streaming live, so you certainly can’t stop that part, but it may be possible to divert the stream through the fifos to
/dev/nullwhen a button is pressed and go back again afterward.I honestly don’t have the “code fu” to do anything like that or to answer your question without a lot of fiddling and researching. I’m glad that you find the code useful, and I do appreciate your posting here with updates when you make interesting modifications.