1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751
|
<!--startcut ==============================================-->
<!-- *** BEGIN HTML header *** -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML><HEAD>
<title>Linux based Radio Timeshifting LG #94</title>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#0000FF" VLINK="#0000AF"
ALINK="#FF0000">
<!-- *** END HTML header *** -->
<!-- *** BEGIN navbar *** -->
<A HREF="lalji.html"><< Prev</A> | <A HREF="index.html">TOC</A> | <A HREF="../index.html">Front Page</A> | <A HREF="http://www.linuxgazette.com/cgi-bin/talkback/all.py?site=LG&article=http://www.linuxgazette.com/issue94/yan-fa.html">Talkback</A> | <A HREF="../faq/index.html">FAQ</A> | <A HREF="zhuralev.html">Next >></A>
<!-- *** END navbar *** -->
<!--endcut ============================================================-->
<TABLE BORDER><TR><TD WIDTH="200">
<A HREF="http://www.linuxgazette.com/">
<IMG ALT="LINUX GAZETTE" SRC="../gx/2002/lglogo_200x41.png"
WIDTH="200" HEIGHT="41" border="0"></A>
<BR CLEAR="all">
<SMALL>...<I>making Linux just a little more fun!</I></SMALL>
</TD><TD WIDTH="380">
<CENTER>
<BIG><BIG><STRONG><FONT COLOR="maroon">Linux based Radio Timeshifting</FONT></STRONG></BIG></BIG>
<BR>
<STRONG>By <A HREF="../authors/yan-fa.html">Yan-Fa Li</A></STRONG>
</CENTER>
</TD></TR>
</TABLE>
<P>
<!-- END header -->
<h2>1.0 Introduction</h2>
Like a lot of gadget freaks I have a Tivo in the living room. Now while
one could argue that thanks to an infestation of Clear Channel there
really isn't much of interest to listen to anymore, there is still
public radio. I listen to a lot of NPR while driving in the car, and I
often find I miss programs I find interesting, or worse, I arrive at my
destination and have to stop listening. So naturally I'd been thinking
for some months now, why not invest some time and effort and look at
how to build a PRR (Personal Radio Recorder).
<p>
Obviously I'm not the only one. There are now some commercial
offerings like <a href="http://radioyourway.com/">this</a>,
and quite a few people appear to have done <a
href="http://gary.burd.info/content/articles/fmcapture.html">projects</a>
to timeshift radio. There's even a <a
href="http://osl.iu.edu/~tveldhui/radio/">how-to</a>,
and slashdot had a big thread about it <a
href="http://ask.slashdot.org/askslashdot/03/01/10/1053222.shtml?tid=137">recently</a>.
<p>
These notes are all based on using RedHat Linux 7.3, so your mileage may
vary if using something like SuSe or Mandrake. I believe they already
come with Alsa, for example, so you can skip those parts that involve
installing them if your system already comes pre-installed with it.
<p>
<h3>The Basics</h3>
Pretty much all the projects I've seen out there have the same things
in common. They use one of three kinds of setup:
<p>
<ul>
<li>A regular analog radio tuned to a single station connected
to the line-in of your PC. Pros: really cheap and easy.
Cons: single station only.
<li>A programmable tuner card with radio function and built
in audio device. Pros: self contained solution, no sound
card required. Cons: PCs are quite noisy electrically;
perhaps a lack of Linux drivers.
<li>An external programmable Radio and the line-in, like the popular
but discontinued DSB-R100 radio from D-link. Pros: programmable
by the PC; replaceable antenna; outside of the computer. Cons:
possible lack of drivers and potentially more expensive than the
other two options.
</ul>
Naturally I picked the USB radio, since I wanted the flexibility of being
able to replace the radio easily, and knew that drivers already existed
in the Linux kernel for this device under the Video For Linux APIs.
<p>
<h2>3. Architecture</h2>
I had a few requirements:
<ol>
<li> Output straight to mp3, and avoid creating any intermediate
wave files. Two hours of Prairie Home Companion, for example,
would be 1.2GB as 44KHz wave files, so this is definitely
something to be avoided.
<li> Decent ID3 tags so the files had some useful info contained
within them rather than just in the filename.
<li> An automated system of reaping the files at regular intervals
to avoid eating up huge amounts of disk. NPR is highly
topical and current and generally not something I want to
archive long term.
</ol>
<p>
The basic capture system ended up looking like this:
<pre>
Alsa HW Interface -> [ ecasound ] -> < Wav Stream > -> [ lame encoder ] -> < mp3 >
</pre>
Nice and simple. It just requires a little syntactic sugar to hold
it all together. Since I wanted to encode VBR mp3s on the fly I had a
few worries about CPU usage. I also planned installing it on my main
file server since it's always on and therefore an ideal candidate.
Using an 850MHz celeron, my tests showed the load to be about 40-50%
while capturing and encoding. This still left plenty of CPU for other
tasks like serving files, ssh and http.
<p>
Your mileage will of course vary if you're running X for example, which
notoriously causes skipping with sound cards. However, since my system
is a dedicated file server I've long stopped running a GUI on it. It
never became an issue, but keep it in mind for your target system. <p>
<h3>Encoding FM in real-time as MP3</h3>
A little googling got me a wealth of excellent information about FM
mp3 encoding. Firstly, FM has a hard cut off for all frequencies above
15KHz at the transmitter, so any information above that can be safely
ignored while encoding; secondly, the optimal bitrates for FM appear
to be somewhere between 96 and 112kbits, since it's mostly voice with
only a modicum of music and we're already saving 5KHz in the frequency
range anyway. We therefore have more than enough bits remaining to get
a faithful encoding. Thirdly, since I was planning on using Lame encoder,
joint stereo was a must. Not only is the joint stereo mode of Lame
excellent, but it also leaves more bits for the encoding.
<h3>Hardware Constraints</h3>
At a bare minimum, I wouldn't recommend anything slower than a 450MHz
Pentium III for this task, though if you are willing to switch to Average
Bit Rate and a slightly lower encoding rate from the one I've used, you
could possibly get away with a well tuned 350MHz PII. Having a disk
on the system itself is also optional, as it only needs to keep up with
~112kbps of data plus network overhead, so one could create a completely
diskless system that booted off the network or a flash card which dumped
all its recordings back to the network.
<p>
Check out <a href="http://compgeeks.com">compgeeks</a> or <a
href="http://computersurplusoutlet.com">CSO</a> for low end systems
which would be suitable for this duty.
<p>
<h2>4.0 Recording Audio Under Linux</h2>
This is actually a bigger challenge than it seems. While a large number
of audio cards are supported by Linux for playback, not very many are all
that great for recording. A great source of information can be found
at the Alsa Project <a href="http://www.alsa-project.org/alsa-doc/">web
site</a>. Having already used Alsa on a number of systems and projects
previously, I decided to use it for the PRR project. And don't forget,
it's the future of Linux audio, as it's already in the 2.6 kernels.
<p>
The next problem is figuring out what to use to do
the actual recording. After looking at a variety of
solutions such as sox and alsarecord, I settled on using <a
href="http://www.wakkanet.fi/~kaiv/ecasound/">Ecasound</a>. While it's
probably overkill for this project, some of the features I liked were
the built-in audio conversion routines, the ability to specify realtime
scheduling under Linux if run by root, and support for writing data to
stdout. Audio is really a real-time sort of task with hard requirements
on meeting certain scheduling goals, so being able to specify this was
a big plus for Ecasound. Unix pipes also avoids the creation of large
temporary data files keeping disk requirements down to manageable levels.
<p>
<h3>Preparing to Set Up Alsa Sound System</h3>
First things first, identify what kind of sound card you have and
figure out whether it's supported by Alsa. As I said earlier, not all
audio cards are very good for recording. Interestingly enough, the sound
card I ended up using is one of the most inexpensive available and yet
it works quite well. <p>
I ended up using a <a
href="http://alsa-project.org/alsa-doc/doc-php/template.php3?company=Hercules&card=Game+Fortissimo+II&chip=CS4624&module=cs46xx">
Cirrus Logic 46XX</a> (Hercules Fortissmo) series card. I picked one
these up in the sfbay area for ~35USD at retail. I'm pretty sure they're
not much more than that elsewhere. Alsa has pretty good support for
them and for FM recording they work just fine. I had started out with a
CMI8738, an even cheaper card at around ~20USD, but I could not make it
record audio without a horrible whine and very poor input gain. It was
just fine for playback, but pretty much useless as a recording device.
<p>
Detailed instructions for setting up Alsa are on their website listed
card by card. But here are a few notes before you start. Firstly, Alsa
really needs the kernel source you are compiling against and your running
kernel to be the same. So for example, on a typical RedHat installation,
say 2.4.18-26.7, you would need the same kernel sources installed in
your <code>/usr/src/linux-2.4/</code> directory. By default, this is
not the case, because RedHat specifically renames the kernel sources to
use the extra version string "custom".
<p>
To avoid this problem just re-compile, re-install and boot your new
redhat kernel before attempting to install Alsa. If you don't know how
to do this there are lot of good instructions on the net and I suggest
you look some up before proceeding. If you want the default RedHat
options, simply use something like:
<pre>
cd /usr/src/linux-2.4
make mrproper && \
make oldconfig && \
make dep clean bzImage modules MAKE='make -j2'
</pre>
This will rebuild your kernel sources. You will need to install this
and reboot using it. How you do that depends on whether you're using lilo or
grub, and is beyond the scope of these instructions.
<h3>Additional Build Notes For RedHat Kernel Users</h3>
There's also a problem which seems to happen on RedHat 2.4.20 kernels, which
is quite infruriating. I suspect it's because of all the scheduler
patches they've been packporting from the 2.5 series. Anyway, whenever
you run configure it deletes the file include/linux/workqueue.h from the
working directory. This has the unfortunate side effect of letting the
compile proceed cleanly, but refuse to load because of unknown symbols.
Most annoying. The fix is simple. Run configure, and before running
make once again to compile, un-tar the workqueue.h file from the tarball
again. Something like:
<pre>
tar jxvf alsa-driver-0.9.5.tar.bz2 alsa-driver-0.9.5/include/linux/workqueue.h
</pre>
works for the 0.9.5 release. This will prevent the dreaded complaints about
being unable to install modules due to failed dependencies.
<h3>Building and Installing Alsa</h3>
Assuming you've got your new kernel running, download the Alsa drivers
package, and compile and install it as root. Next, download the Alsa
library package, compile and install this. Finally, at a bare minimum
you'll need the Alsa Utils, otherwise you won't be able to do anything
useful like unmute the audio. Tools and OSS compat are nice to have
but not required at this point.
<p>
As an additional note, by default, recent versions of Alsa install
themselves in the default system paths. Older versions installed
themselves in /usr/local, and on RedHat systems this would cause problems
because the dynamic loader wasn't configured to look there for libraries.
This would cause configure scripts to fail to find libraries and
generally not compile. This is actually pretty easy to fix, just
add the /usr/local/lib path to /etc/ld.so.conf and re-run ldconfig.
This will update your ld cache and also dynamic libs that have been
installed there to run. FYI, this is also one of the main reasons why
a lot of open source packages fail to compile on RedHat systems.
<p>
The new drivers will install in your currently running kernel directory.
You will need to reconfigure your modules.conf to reflect the new sound
card set up. This normally involves removing the entries added by kudzu,
or disabling them using a '#' sign and then adding the new driver
entries. Here's the one from my CS46XX setup:
<pre>
# ALSA portion
alias char-major-116 snd cards_limit=1 device_mode=0660
post-install snd alsactl restore
alias snd-card-0 snd-cs46xx
# module options
# OSS/Free portion
alias char-major-14 soundcore
alias sound-slot-0 snd-card-0
# card #1
alias sound-service-0-0 snd-mixer-oss
alias sound-service-0-1 snd-seq-oss
alias sound-service-0-3 snd-pcm-oss
alias sound-service-0-8 snd-seq-oss
alias sound-service-0-12 snd-pcm-oss
</pre>
Notice the post-install directive. This lets you restore audio settings
on reboots as soon as the driver loads. You can also achieve this by
modifying the <code>/etc/rc.local</code> too, but I like this way better
in case I need to unload the driver. You can also add a pre-remove
directive if you like to save any settings you may have changed before
unloading the sound modules. I prefer to restore to known defaults.
<p>
Next we need to add an entry to the <code>rc.local</code> file. For
whatever reason, the OSS emulation drivers don't load automatically. KDE
complains for example when starting artsd because the sound system hasn't
initialized while it's trying to load. You can force OSS emulation to
pre-load by adding:
<pre>
modprobe snd-pcm-oss
setpci -s 01:09 latency_timer=60
</pre>
to the end of rc.local. The first entry loads the pcm oss driver and
keeps apps which depend on OSS being there to stay none the wiser.
The second entry adjusts the PCI timers for the sound card to give it
a little more time on the bus; that part is optional. I find tweaking
the PCI bus helps avoid pops and clicks in the audio. If you do choose
to tweak your PCI latency this way, remember to use lspci
to find the correct device number for your card. The one listed here
is for my system bus and will likely be different on your system.
<p>
It's probably easiest at this point just to just reboot one more time,
however if you're confident about what you're doing, manually remove
the old OSS audio drivers using <code>rmmod</code> and do a
<pre>modprobe snd-pcm-oss</pre>
Follow up with a <code>lsmod</code> and you should see a lot of bright
and shiny new alsa drivers loaded:
<pre>
Module Size Used by Not tainted
snd-pcm-oss 45668 0
snd-mixer-oss 16536 0 [snd-pcm-oss]
snd-cs46xx 79156 0 (autoclean)
snd-rawmidi 18656 0 (autoclean) [snd-cs46xx]
snd-seq-device 6316 0 (autoclean) [snd-rawmidi]
snd-ac97-codec 44640 0 (autoclean) [snd-cs46xx]
snd-pcm 83264 0 (autoclean) [snd-pcm-oss snd-cs46xx]
snd-timer 19560 0 (autoclean) [snd-pcm]
snd-page-alloc 8520 0 (autoclean) [snd-cs46xx snd-pcm]
gameport 3412 0 (autoclean) [snd-cs46xx]
snd 43140 0 [snd-pcm-oss snd-mixer-oss snd-cs46xx snd-rawmidi snd-seq-device snd-ac97-codec snd-pcm snd-timer]
soundcore 6532 6 [snd]
</pre>
This is an excerpt from a working system. Test it by playing some audio,
anything you have handy will do, like mpg123 for example. Though on a
RedHat system, you'll actually have to download and compile and install
it yourself since they no longer ship mpeg decoders due to patent issues
with Fraunhofer and Philips.
<h2>5.0 Additional Packages to Downloaded</h2>
<h3>Download and Compile ECASOUND</h3>
Since you now have an installed and working alsa sound system, you do have
it working, don't you ? It is now a good time to get ecasound downloaded and
running.
I did my initial implementation using 2.2.1, but I recently upgraded
to 2.2.3 as it seems to have a lot of bugfixes specifically for use with
Alsa. Building it should be fairly straightforward, since it's GNU
autoconf based. Just follow the INSTALL instructions.
<p>
If you want a slightly more optimized build, and you're using a version
of GCC that supports more advanced x86 optimizations, (gcc 3.2 or higher),
I would recommend the following configure line on an PII and above system.
This especially includes the new FPGA2 Celerons.
<pre>
CXXFLAGS='-O2 -march=i686' CFLAGS='-O2 -march=i686' ./configure
</pre>
Or the even more aggressive:
<pre>
CXXFLAGS='-O2 -march=i686 -msse -mmmx' CFLAGS='-O2 -march=i686 -mmmx -msse' ./configure
</pre>
However, be warned this second version may not compile correctly and could
cause more problems than it's worth. On the other hand, it probably
wouldn't hurt to at least give it a try and see if it makes a difference
on your system. In my particular case I see gains in the 2-4% range
with these optimizations.
<h3>Download and Compile Lame</h3>
Now download Lame 3.93.1 and compile that. It's also gnu configure based
so you can use the same flags as we used above. Install it.
I'll also recommend downloading and installing your favorite
mp3 player such as <a href="xmms.org">xmms</a> or <a
href="http://mpg321.sourceforge.net">mpg321</a> as it will be useful
while testing the installation.
<h2>6.0 Configuring The Recording Devices</h2>
This is probably the hardest part of getting this all running. I found
the easiest thing to do was set the volumes before the recording was
going, using the <code>alsamixer</code> tool. It's a curses based
program that lets you adjust sliders for various audio devices and
lets you take a trial and error approach to your particular sound card.
The basic trick is to put the devices you are interested in capturing
from, into capture mode. If anyone has better information on how to
configure this using a command line interface, please drop me a line.
<p>
If you go into the <code>alsamixer</code> interface you'll see a group of
sliders that have values from 0 to 100. Bars which have 6 hyphens above
them are potential capture sources. Because each sound card appears to
have slightly different DACs it's not always clear which ones to activate
to enable recording. <p>
Using a combination of trial and error and <code>ecasound</code>, I was
able to test which devices were capable of recording. Having a pair
of speakers hooked up to the speaker out at this point is very useful,
but headphones would be just as useful at this point too. Typically you
want line-in device. Crank up the volume to around 70%. If you're using
a Video 4 Linux radio you can use the 'radio' util to tune in and turn
on the radio device giving you a source of audio. The Dlink radio is a
line device, meaning it has fixed volume so how loud it sounds will be
directly related to how loud you set the line-in volume.
<P>
If you've hooked it up correctly to the line-in of your sound card
you should now hear some audio. Adjust the volume until it doesn't
sound distorted. Distorted audio will a) sound horrible and b) make
your mp3s sound really crappy. Just play it by ear (sic), and get it to
where it sounds reasonably clear and undistorted. Remember it's FM so
it's already lost about 5KHz of fidelity from being converted, so don't
expect miracles. You may need to look for sources of noise and reposition
your antenna. This will vary from installation to installation.
<h3>Notes on Noise</h3>
Because the source is analog, you really need to pay close attention to
sources of electrical noise, devices such as other computers or monitors
are electrically very noisy. For example, I recently discovered that I
was getting an annoying pulsing static sound from my setup. Turns out
the routing of the audio cable was a little too close to power cords.
A simple re-route solved the problem, but as with a lot of audio you
have to do regular sound checks to make sure you haven't introduced a
new source of interference.
<h2>7.0 Gluing it all together</h2>
So now we have the basic infrastructure going, we need to do some simple
glue scripting to make it all work together. I wrote a couple of
simple scripts to do the functions I needed. The first one is to do
the actual recording. It's started via cron jobs. It simply invokes
all the programs in a big fat pipe with ecasound at the head and lame
at the tail. Works quite well. The name of the file to be created and
any pertinent parameters are passed in via Cron. It's written in bash
and is quite easy to understand.
<h3>Recordshow2: the capture script</h3>
<pre>
#!/bin/bash
echo "Recordshow2 (c)2003 Yan-Fa Li (yanfali@best.com) under GNU LGPL"
# FREQUENCY TIMEINMINS "PROGRAM NAME"
#set -x
tune_channel()
{
echo -n "Tuning to FM Channel $1..."
# Reset and Turn on and Tune Radio
$RADIO -qm 2>/dev/null && sleep 1 && $RADIO -qf $1
}
record_program()
{
echo "Recording $TITLE for $1 Minutes ($TIME seconds) to:"
echo -e "\t$FILENAME"
# Record and Pipe to Lame
TITLE2=${TITLE#*/}
$ARECORD $APARMS | $LAME $LPARMS - "$FILENAME" \
--tt "$TITLE2 on $DATE" \
--ta "KQED/NPR" \
--ty `date +"%Y"` \
--tg 101 \
--tc "$COMMENT"
if [ $? -ne 0 ]
then
echo -n "Error Recording - Check the Soundcard Isn't Recording"
echo " Already"
turn_radio_off
exit 1
fi
}
fix_permissions()
{
# Correct Permissions
if [ -f "$FILENAME" ]
then
chown $OWNER "$FILENAME"
chmod 664 "$FILENAME"
fi
}
turn_radio_off()
{
echo -n "Turning off Radio..."
# Turn off Radio
$RADIO -qm
}
#
# Main Program
#
# Arg Check
if [ $# -ne 3 ]
then
echo "usage: `basename $0` FREQUENCY TIME_IN_MINS \"NAME_OF_PROGRAM\""
exit -1
fi
DEST=/mnt/music/radio
declare -i TIME=$2
TIME=TIME*60
OWNER="yan:music"
RADIO=/usr/bin/radio
ARECORD=/usr/local/bin/ecasound
APARMS="-b 512 -i alsahw,default -o:stdout -t $TIME"
LAME=/usr/local/bin/lame
LPARMS="-r -x -mj -s44.1" # required for ecasound
# -r raw pcm input
# -x swap bytes
# -mj join stereo
# -s incoming sample rate
LPARMS=$LPARMS" -V5 --vbr-new -q0 -b112 --lowpass 15 --cwlimit 10"
# Thanks to: http://www.jthz.com/mp3/ for the settings
# -V5 encoding speed
# --vbr-new
# -q0 highest quality
# -b112 bitrate of 112Kbps
# --lowpass 15 filter all frequencies above 15KHz (FM cutoff)
# --cwlimit 10 acoustic model
DATE=`date +"%a %b %d %Y (%k:%M)"`
SIMPLEDATE=`date +"%Y-%m-%d-%a"`
FILENAME="$DEST/$3-$SIMPLEDATE.mp3"
TITLE="$3"
COMMENT="$1 MHz"
echo "`basename $0`: Recording Started on "$DATE
# Call it twice to avoid radio coming up mute
tune_channel $1
tune_channel $1
record_program $2
fix_permissions
turn_radio_off
echo "`basename $0`: Recording Ended on "`date +"%a %b %e, %Y %k:%M"`
</pre>
<h3>Example Crontab</h3>
<pre>
# usage: recordshow2 FREQUENCY TIME_IN_MINS "NAME_OF_PROGRAM"
# leave a minute at the end otherwise you'll overlap the audio
# device and fail to record
#
# Weekdays
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/etc/radio
MAILTO=root
HOME=/
# Daily
0 9 * * Mon-Fri recordshow2 88.5 59 "Forum/Forum H1"
0 10 * * Mon-Fri recordshow2 88.5 59 "Forum/Forum H2"
0 11 * * Mon-Fri recordshow2 88.5 59 "Talk of the Nation/Talk Of The Nation H1"
0 12 * * Mon-Fri recordshow2 88.5 59 "Talk of the Nation/Talk Of The Nation H2"
0 13 * * Mon-Fri recordshow2 88.5 59 "Fresh Air/Fresh Air"
0 16 * * Mon-Fri recordshow2 88.5 29 "Market Place/Marketplace"
30 16 * * Mon-Fri recordshow2 88.5 119 "All Things Considered/All Things Considered"
0 21 * * Mon-Fri recordshow2 88.5 59 "BBC World Service/BBC World Service"
# Weekly Recordings
# Thursday
30 18 * * Thu recordshow2 88.5 29 "Pacific Time/Pacific Time"
# Saturday
0 11 * * Sat recordshow2 88.5 59 "WaitWait/Wait Wait Don't Tell Me"
0 12 * * Sat recordshow2 88.5 59 "This American Life/This American Life"
0 18 * * Sat recordshow2 88.5 119 "Prarie Home Companion/Prarie Home Companion"
# Sunday - in case you messed up saturday
# Sunday
0 11 * * Sun recordshow2 88.5 119 "Prarie Home Companion/Prarie Home Companion"
# Maintenance
0 1 * * Sun weekly_file_cleanup.rb
</pre>
<h3>File Administration</h3>
The second script is more of a util script. Remember my requirement
about automatically removing files after a certain time ? What this script
does is that it scans the date when the file was created and after a
predetermined time, two weeks in my case, it deletes them. I used ruby,
because I was learning it and it actually made writing the program
quite easy. Go figure. Feel free to re-write it in bash, but it really
was much easier to write it in ruby. See for yourself.
<p>
Because there are some recordings I don't ever want to delete, usually
weekly programs, I added the ability to ignore a directory by simply
writing the file .donotreap into the directory. It'll bail on this
directory if it finds it. As a secondary safe guard it will also only
delete mp3 files. Everything else will be ignored. It's not fancy but
it works quite well.
<pre>
#!/usr/bin/ruby -w
=begin
Simple script to clean up the Timeshifted Radio Directories
Looks for files more than two weeks old and removes them
=end
puts "Timeshifted Radio File Cleaner v0.1"
puts "(c) 2003 Yan-Fa Li (yanfali@best.com) under GNU LGPL"
Dir.chdir("/mnt/raid5/music/radio")
TWOWEEKS = 60 * 60 * 24 * 7 * 2
file_list=Dir["**"]
# Find All Directories
dir_list = []
file_list.each { |x| dir_list << x if File.ftype(x) == "directory" }
topdir = Dir.pwd
# Recurse through all directories
dir_list.each do |x|
Dir.chdir(topdir + "/" + x)
# Do Not Reap Flagged Directories
next if File.zero?(".donotreap")
puts "Entering Directory: #{x}"
# Build File List and Filter on name mp3
file_list=Dir["**"]
puts "\tFound #{file_list.length} Files Total"
file_list.each { |y| file_list.delete(y) if not y.include?("mp3") }
puts "\tFound #{file_list.length} MP3 Files"
# Find Files Older than 2 Weeks
del_list = []
file_list.each { |y|
del_list << y if (Time.now - File.stat(y).mtime) > TWOWEEKS }
puts "\t#{del_list.length} Files Scheduled For Deletion"
next if del_list.length == 0
del_list.each { |z| File.delete(z) }
end
</pre>
<h2>8.0 Bugs and Things To Do</h2>
One recurring problem which I have not been able to fix is that
occasionally the recording will be skewed and sound slightly off.
I haven't been able to figure out what's causing it. Most of the
time the recordings are pristine, but every so often one will be off.
You can still listen to it, but it sounds likes it's slightly off
frequency or tinny. Since I'm streaming the audio straight into the
recording software and then compressing, it could be any one of those
elements in the chain; keeping around large wave files is not an option.
Upgrading to the latest greatest versions has not helped. It could also
be the sound card itself. It doesn't bug me enough to want to fix it,
though I do lose some recordings that way. If anyone out there knows
what it might be, I'd appreciate a heads up.
<p>
Since it pretty much all just works, I haven't messed with it much.
I recently used a lot of the recordings on a long road trip: iPods
rule. But I do have a few ideas on things that would be nice to have.
First, it'd be great to scrape NPR program listings and get the
details for each recording, attaching a reference file to each mp3
or changing the id3 comment to match the program listing.
<p>
Second, a dedicated scheduler would also be great. Right now if you
have a clash in using the recording device, due to overruns, the second
recording fails because the audio device is busy. Having a dedicated
scheduler that is recording centric would pretty much fix this problem.
I know Tivo has something similar so it's obviously a known problem
with known solutions. Cron is the wrong solution for this, so the
work around is of course to deliberately stop recording a minute sooner
than necessary. In general this works very well.
<p>
Third, it would be great to have a web based interface for interacting
with the recordings, changing programs to be recorded and listening,
say via shoutcast, to stuff that's already been recorded. I'm far too
lazy to write it myself, so I leave it as a challenge to all you
out there :D
<h2>9.0 Summary</h2>
As you can see, it's a little bit of work to set up Linux to timeshift
radio, but it's really not that difficult. I've been using it now
for about six months and it's a real pleasure not having to miss any
shows that catch my attention while driving. PBS is a great source of
material and I strongly encourage you to support your local station.
When combined with a portable music player like an iPod, long car rides
become much more enjoyable. <p>
The good news about building one is that things will be getting much
easier in the 2.6 timeframe because of the integration of Alsa sound
system into the mainline kernel. While the files it generates by default
are quite large, you can reduce that footprint by choosing a lower
encoding bitrate than my default of 112kbps. As low as 64kbps should
sound fine for just voice, though music will sound pretty horrible at
this bitrate. I haven't experimented with OGG or any other formats
as I don't have portable players that support alternative formats, but
changing it to support them should be a simple matter of modifying the
backend a bit. <p>
Any <a href="mailto:yanfali@best.com">feedback</a> or comments are appreciated,
and if you have a solution to my occasional bad recordings drop me a line.
<!-- *** BEGIN author bio *** -->
<P>
<P>
<!-- *** BEGIN bio *** -->
<P>
<img ALIGN="LEFT" ALT="[BIO]" SRC="../gx/2002/note.png">
<em>
</em>
<br CLEAR="all">
<!-- *** END bio *** -->
<!-- *** END author bio *** -->
<!-- *** BEGIN copyright *** -->
<hr>
<CENTER><SMALL><STRONG>
Copyright © 2003, Yan-Fa Li.
Copying license <A HREF="../copying.html">http://www.linuxgazette.com/copying.html</A><BR>
Published in Issue 94 of <i>Linux Gazette</i>, September 2003
</STRONG></SMALL></CENTER>
<!-- *** END copyright *** -->
<HR>
<!--startcut ==========================================================-->
<CENTER>
<!-- *** BEGIN navbar *** -->
<A HREF="lalji.html"><< Prev</A> | <A HREF="index.html">TOC</A> | <A HREF="../index.html">Front Page</A> | <A HREF="http://www.linuxgazette.com/cgi-bin/talkback/all.py?site=LG&article=http://www.linuxgazette.com/issue94/yan-fa.html">Talkback</A> | <A HREF="../faq/index.html">FAQ</A> | <A HREF="zhuralev.html">Next >></A>
<!-- *** END navbar *** -->
</CENTER>
</BODY></HTML>
<!--endcut ============================================================-->
|