Problem: I have a 40gb HD on an old P/133 running Debian that serves as my mp3 server. It is plugged into the stereo, so I can listen for days without having to mess with the stereo. This is not the problem.

The problem is that half the time I have no clue what I'm listening to. The server has no monitor, so I operate it via ssh, but I'm not *always* at the controlling terminal either. I download a lot of music from emusic.com and occasionally I will borrow a CD (from a friend or the library) and rip it. So my collection of mp3s is significantly larger than my memory.

Now I could use MP3::Info to list the songs to the terminal as they play, but that still requires me to keep an open terminal, and to run to the computer to see what's playing if I want to know. Better would be a way that would allow me to get song information at the same time I get the songs. You know, like on the radio.

Enter Compu Kasem. Through the magic of speech synthesis and a little Perl glue, the cyber DJ accepts a playlist (optional shuffle), announces the songs before and after they play, as well as the time (again, easier than hunting down a clock). Requires the Festival speech synthesizer and uses the 'aumix' audio utility to set the volume. Also, for now, works only with mp3 files (sorry Ogg-philes) via the mpg123 (or mpg321) application/library.

Also, while a song is playing, you can use the following commands:
. increase volume
, decrease volume
(space) skip song
1234567890 set volume to 10% to 100% (in 10% increments)

To do list includes: build set of routines for speech functions, include variety of song introduction/recap phrases, only announcing time in fifteen minute intervals, perhaps grabbing news headlines and/or weather information and inserting those between songs.

Update: of course there are several modules for dealing with Festival servers (i.e. running festival as a daemon rather than piping to it, as I do here). So this is on the to-do list, because it will probably cause less lag (as starting the festival client after before each song is a bit slow).
#!/usr/bin/perl -w use strict; use Audio::Play::MPG123; use MP3::Info; use Term::ReadKey; use Getopt::Long; my $shuffle; GetOptions( "shuffle" => \$shuffle ); my $DEBUG = 1; my $max_vol = 100; my $VOLUME = 70; my $speech_speed = 3; #a single digit between 0 and 9 my @playlist; if( @ARGV ) { @playlist = @ARGV; } else { say_error( "No playlist given. Please select some songs for me to p +lay!" ); } if( $shuffle ) #Shuffle songs in playlist { #fisher-yates shuffle from Perl Cookbook my $array = \@playlist; my $i; for( $i = @$array; --$i; ) { my $j = int rand ($i+1); next if $i==$j; @$array[$i,$j] = @$array[$j,$i]; } } my $key; my( $this_artist, $last_artist ); my( $this_album, $last_album ); my( $this_song, $last_song ); my( $this_year, $last_year ); ReadMode 3; # Turn off controls keys for( @playlist ) { print "Starting song '$_'\n" if $DEBUG; my $song = MP3::Info->new( $_ ); my $this_artist = $song->artist; my $this_album = $song->album; my $this_song = $song->title; my $this_year = $song->year; my $prev_vol = $VOLUME; set_vol( $max_vol ); print "Doing DJ routine\n" if $DEBUG; open( VOICE, "| festival --pipe" ) or die "$!"; print VOICE "(voice_rab_diphone)"; print VOICE "(Parameter.set 'Duration_Stretch 1.$speech_speed)"; if( $last_song ){ print VOICE "(SayText \"That was $last_artist with the song $last_ +song\")"; my $the_time = get_time(); print VOICE "(SayText \"The time is now $the_time\")"; } print VOICE "(SayText \"Here is $this_song played by $this_artist\ +")"; close VOICE; $last_artist = $this_artist; $last_album = $this_album; $last_song = $this_song; $last_year = $this_year; set_vol( $prev_vol ); print "Running player for this song\n" if $DEBUG; my $player = new Audio::Play::MPG123; $player->load( $_ ); my $stopper = 0; until( $player->state == 0 or $stopper) { unless (not defined ($key = ReadKey(-1))) { if( $key =~ /^\d$/ ) { $key = 10 unless $key; set_vol( $key * 10 ); } elsif( $key eq '.' ) { set_vol( $VOLUME + 1 ); } elsif( $key eq ',' ) { set_vol( $VOLUME - 1 ); } elsif( $key eq ' ' ) { print "Skipping to next song\n" if $DEBUG; $player->stop; $stopper = 1; next; } } $player->poll(1); } } ReadMode 0; # Reset tty mode before exiting sub say_error { my $err_msg = shift or die "No error given: $!"; my $prev_vol = $VOLUME; set_vol( $max_vol ); open( VOICE, "| festival --pipe" ) or die "$!"; print VOICE "(voice_rab_diphone)"; print VOICE "(Parameter.set 'Duration_Stretch 1.$speech_speed)"; print VOICE "(SayText \"$err_msg\")"; close VOICE; set_vol( $prev_vol ); } sub get_time { my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime +(time); my $time; if( $min == 0 && $hour == 0 ) { $time = "midnight"; } elsif( $min == 0 && $hour == 12 ) { $time = "noon"; } elsif( $hour < 12 && $min <= 30) { $time = "$min minutes after $hour in the morning"; } elsif( $hour < 12 && $min > 30) { my $bmin = 60 - $min; $hour++; $time = "$bmin minutes before $hour in the morning"; } elsif( $hour == 12 && $min <= 30) { $time = "$min minutes after $hour in the afternoon"; } elsif( $hour == 12 && $min > 30) { my $bmin = 60 - $min; $hour++; $time = "$bmin minutes before $hour in the afternoon"; } elsif( $hour > 12 && $min <= 30) { $hour -= 12; $time = "$min minutes after $hour in the morning"; } elsif( $hour > 12 && $min > 30) { $hour -= 12; my $bmin = 60 - $min; $hour++; $time = "$bmin minutes before $hour in the morning"; } else { $time = "I have no idea what time it is!"; } return $time } sub set_vol { $VOLUME = shift || return; $VOLUME = 100 if $VOLUME >= 100; $VOLUME = 0 if $VOLUME < 0; system( "aumix -v $VOLUME" ); }

In reply to Compu Kasem (a Cyber-DJ) by ichimunki

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.