| Level: Intermediate Nathan Harrington (harrington.nathan@gmail.com), Programmer, IBM
23 Jan 2007 "You've got mail" is so 20th century. Use Perl and Sound eXchange (SoX) to play sound files on your Linux® or Windows® computer based on the content of incoming e-mail messages. Your system can compose and blend certain sounds to give you a heads-up on the who, what, and why of your in-box content.
Developers have long made advancements in visual notifications of arriving e-mail. Today, we see everything from simple icons changing color and shape to pop-up notifications to detailed summaries from sliding windows. Developers have not spent as much effort making sound notifications deliver anything beyond the recorded AOL voice effusing, "You've got mail." In the open source world, the best to hope for is your computer tooting different sound files based on the account or storage area where your e-mail landed.
This article shows how to create and play back custom sound files based on the content of incoming e-mail messages. SoX -- the Swiss Army knife of sound processing programs -- and simple keyword matching will be used to create custom sound files played back upon receipt of e-mail. No more simple ding to indicate the arrival of an e-mail regardless of recipient, sender, or subject. You can now hear a ding-bang-whoosh signifying an e-mail from your manager, or a bell-squawk-chirp to let you know your bank statement is available.
Requirements
Hardware
This article was developed in part on an Intel® Pentium® 4 with 256 MB of RAM. You need at least a Pentium I processor with 64 MB of RAM if you are running Linux. The customary increase in processing power is required if you intend to use SoX on Win32, as this article demonstrates. The more sound samples you intend to process per notification, the more powerful your hardware should be to reduce the time spent synthesizing your alert sounds. A Pentium II class or newer CPU should suffice for most situations.
Software
A newer (V2.4 or later) version of Linux is recommended, as the presence of the aplay utility (included with alsa) will make usage of the script seamless. You will also need Perl with the following modules: IO::Socket::SSL and Mail::POP3Client. You can install these with the command cpan -i <module_name> on Win32 and Linux. If you intend to use the emailMixer.pl program on Win32, configure your build environment using one of the many options available for compiling Perl modules. Most mainstream Linux distributions include the tools necessary for building these modules.
Sound file selection
The approach to computing and building informational sound effects about new e-mail is based on three components. To provide the most information in the least amount of time and without potential confusion from the plethora of sounds, a simple time-division approach was taken. Selection of sound files requires the individual files to have peak sound interest at short, middle, or long durations. This relatively subjective term produces a sound bank selection with immediate sound output, gradual peak and decline, and a third group with a gradual crescendo. Combining these files according to the various input parameters associated with the e-mail contents produces a sound that's rich in meaning. See Resources for examples of what this sounds like.
The sound files included with the OpenOffice distribution provide an interesting body of samples to work with. For our purposes, we will use the space2, space3, (long-duration) sparcle, (medium) glasses, and laser (short) sound effects from the /usr/lib/ooo-1.1/share/gallery/sounds/ directory (on Fedora Core 3). KDE_Dialog_Disappear.wav (renamed to notify.wav) was chosen to be the default e-mail notification, which we will use if no keywords match.
Example sound configuration file
The emailMixer.pl program reads the specified config file (emailMixer.config by default) for the sound files you wish to mix, depending on the location of a keyword match. Consider the following example:
Listing 1. Example emailMixer.config file
From: _#_ Nathan _#_ glasses.wav
Subject: _#_ IBM _#_ sparcle.wav
Body _#_ developerWorks _#_ space2.wav
DefaultSound _#_ defaultSound _#_ notify.wav
|
The format of the emailMixer.config file is message part <delimiter> keyword(s) <delimiter> sound file. In this example, if the word "Nathan" is in the From area, the glasses.wav file is specified. This is our short-peak duration sound effect, while sparcle.wav is the medium-duration effect played when the Subject header contains "IBM." The final two lines indicate mixing of the long-duration space2.wav sound effect upon matching "developerWorks" in the body of the message and to play just the notify.wav file if there are no keyword matches.
Note that if you want to search the message headers, you need to specify the exact header name. For example, "from" or "From:" will not precisely match the header "From:" due to the absence of a colon and the presence of a leading space, respectively.
Installation of SoX
Before you begin processing sound files, download and install SoX. This will provide all the tools needed to build, process, and mix the sound files necessary for useful e-mail notification (see Resources). On most modern Linux distributions, you should already have SoX installed. In a Win32 environment, download and unpack the binaries in the same directory that the emailMixer.pl program and your sound effects are in.
Sound file preprocessing
Included with the SoX code distribution is the program soxmix, which will combine two files and optionally apply user-specified effects. The soxmix program requires that the files to be mixed together be the same data type and sample rates. The sound effects we selected are in different formats, two being Signed 16 bit Little Endian, Rate 22050 Hz and two others being Unsigned 8 bit, Rate 11025 Hz. Using SoX, they can all be converted to the same format to allow the soxmix program to process them correctly. Use the command sox space2.wav -r 11025 -c1 -b downSample_space2.wav polyphase to change the format of the space2.wav file from Signed 16 bit Little Endian, Rate 22050 Hz to Unsigned 8 bit, Rate 11025 Hz. If you see error messages regarding forcing the format to unsigned, don't panic as this is not actually an error condition. Test the output file's correctness by playing it back. If it sounds OK, it's fine.
Note the "polyphase" option on the end of the SoX command. This is important to preserve the pitch of the file while altering its sample rate. If you remove the polyphase option, you will increase or decrease the pitch of the output sample, depending on the output rate selected. After you've created your modified file with SoX, rename it to the expected filename with mv downSample_space2.wav space2.wav . Make sure you complete this process for any sound file you plan to include in the emailMixer.config file.
The emailMixer.pl program
Now that you have your environment in place, your sound effects selected and preprocessed, and your required Perl modules configured, let's look at the emailMixer.pl program.
First up are the program parameters:
Listing 2. Main program parameters
#!/usr/bin/perl -w
# emailMixer.pl - create notification sound files based on keywords in e-mails
use strict;
use Mail::POP3Client;
use IO::Socket::SSL;
# required for Win32 usage only
#use Win32::Sound;
my $userName = 'accountname@gmail.com';
my $passWord = 'password';
my $mailHost = 'pop.gmail.com';
my $port = '995';
my $pop = ""; # mail object
my %kwHash = (); # for matching words with sounds
my @soundList = (); # sounds to mix together
my $cmd = ""; # commands to run
my $firstSound = ""; # base sound to mix with
my $defaultSound = "notify.wav";
my $msgHead = ""; # headers from e-mail message
my $msgBody = ""; # body from e-mail message
|
Make sure you uncomment the Win32::Sound line if you plan to run this program in a Win32 environment. Watch for the sound playing line at the end of the file as well, as you'll need to uncomment it also to play sounds on a Win32 machine. You'll need to update the account name and password sections, of course. Note that this code and environment description focuses on using a Gmail account for mail processing. The code here is not specific, though, and should work on any POP3 mailbox.
The subroutines section begins next, with the readKeyWordFile section leading off:
Listing 3. readKeyWordFile subroutine
# readKeyWordFile reads keywords, match location and sound files from
# emailMixer.config. format is: message part _#_ word(s) _#_ sound file
sub readKeyWordFile
{
open(KWFILE,"emailMixer.config") or die "no emailMixer file: $!";
while(<KWFILE>){
# ignore comment lines
if( !/^#/ ){
chomp($_);
my @arrLine = split "_#_";
$arrLine[0] =~ s/ //g;
$kwHash{ $arrLine[0] }{ $arrLine[1] } = $arrLine[2];
}#if not a comment line
}#for each line in file
close(KWFILE);
}#readKeyWordFile
|
The emailMixer.config file will contain the section, keywords, and sound effects specified to search when the program runs. The readKeyWordFile subroutine builds a simple hash of the contents of the emailMixer.config file for later searching, considering any lines that begin with # as comments.
Next up is the checkMail subroutine:
Listing 4. checkMail subroutine
#setup the mail connection to Gmail
sub checkMail
{
print "hmm checking \n";
$pop = new Mail::POP3Client( USER => $userName,
PASSWORD => $passWord,
HOST => $mailHost,
PORT => $port,
USESSL => 'true',
DEBUG => 0,
);
die "no messages\n" if( $pop->Count() < 1 );
$msgHead = $pop->Head(1);
$msgBody = $pop->Body(1);
$pop->Close();
}#checkMail
|
Using the Mail::POP3Client, this subroutine will download all new messages from the Gmail POP in-box. For our purposes, we will only use the contents of the first message, if one exists. After we store the contents of the headers and body in temporary variables, the pop->Close() command is issued to tell the Gmail servers that the mail has been retrieved. To set the retrieval or read status using a different program, comment out the pop->Close() line, and the message will stay in the in-box until removed. For more options on environment setup and methods for seamlessly integrating the emailMixer.pl program with your existing mail setup, see the "Environment Configuration" section.
With the internal program environment subroutines in place, we can specify a simple keyword matching subroutine:
Listing 5. matchWords subroutine
# select the appropriate header file and look for matches
sub matchWords
{
my $locPart = $_[0];
my $locWords = $_[1];
my $msgString = "";
if( $locPart =~ /:/ )
{
# if the area for searching is a header
for( split '\n', $msgHead )
{
if( /^$locPart/i ){
$msgString = $_;
last;
}
}#for each line in the headers
}else
{
# if not searching a header, must be the body
$msgString = $msgBody;
}#if a header match
for my $checkWord ( split " ", $locWords )
{
$checkWord =~ s/ //g;
if( $msgString =~ /$checkWord/i )
{
return(1);
}#if from match
}#for each check word
}#matchWords
|
The matchWords subroutine takes two arguments: location to search, and words to search for. If the location to search is one of the headers in a typical message, we need to set the string to search msgString to the content of the header. Otherwise, the body must be checked for the specified string(s). For each word specified in the configuration file to search for in the specified location, return 1 to the main program to let it know a match was found.
With our subroutines finished, we can move onto the main program.
Listing 6. Main program check and search
# MAIN PROGRAM
readKeyWordFile();
checkMail();
# for each part of the message speciified
for my $msgPart( keys %kwHash )
{
# for all the keywords for the part of the message specified
for my $keyWords ( keys %{ $kwHash{$msgPart} } )
{
if( matchWords( $msgPart, $keyWords ) )
{
push @soundList, $kwHash{$msgPart}{$keyWords};
}
}#for each key word listing
}#for each message part
|
After reading the initialization file, the presence of new e-mail is checked. If a message is found, the program continues checking each of the search locations for the specified word(s). If a match is found, the array of sounds to be combined is added to, based on the defined sound file from the configuration in emailMixer.config.
Next up is the actual building of the sound file, and finally playing it out.
Listing 7. Main program sound build and play
if( $#soundList != -1 )
{
$firstSound = $soundList[0];
my $count = 0;
shift(@soundList);
for my $sndFile ( @soundList )
{
$cmd = qq{ soxmix $firstSound $sndFile out$count.wav };
$cmd = `$cmd`;
$firstSound = "out$count.wav";
$count++;
}
}else
{
$firstSound = $defaultSound;
}#if sounds found
# for Linux
$cmd = `aplay $firstSound`;
#for Win32
#Win32::Sound::Play("$firstSound");
|
If there was a match of any of the words to search for in the entire message, play the sound built based on those matches. You may wish to modify this behavior to always include your default notification sound and simply overlay your matching sound files. For our purposes, I felt it was better to provide an additional layer of differentiation separating the match/dissonance sounds completely. Assuming at least one match was found, the main program will then continuously overlay the matching sound files to build a single output file. For example, in the for my $sndFile ( @soundList ) loop above, if the entire criteria specified (IBM, developerWorks, nathan ) matches, the commands issued inside the loop will be what we see here.
soxmix glasses.wav sparcle.wav out0.wav
soxmix space2.wav out0.wav out1.wav
|
The final commands need to be modified to play back your generated sound file accurately. Make sure you choose the Win32 playback option if your machine is under the influence of Redmond.
Environment configuration
Now that you have an idea of how the program works, let's configure your environment for effective use of the emailMixer.pl program.
One simple approach is to configure your Gmail account to archive every e-mail after it is downloaded by a POP client. This way, the emailMixer.pl program will download all new messages every time it is run, and Gmail will display the online read status under the All Mail view. You can then skip over the in-box view entirely and work only in the All Mail view as your in-box messages are monitored and processed by the emailMixer.pl program. Alternatively, you could set up a POP-only e-mail account for Gmail, where your messages are automatically forwarded from your main account to the POP-only account. Configure the POP-only account to automatically delete messages after accessed over POP. This will enable you to use your in-box on your main account the standard way and use the emailMixer.pl program to check the POP-only account's e-mail.
If you prefer to download your e-mail from Gmail and work with it locally, consider running emailMixer.pl with the pop->close line commented out. This will tell the server that the messages were not downloaded entirely, which will then allow your standard message retrieval program, such as Thunderbird, to download the message in its entirety.
Further examples
As an end-to-end example, let's say you started a new job with a local university. You want all of your e-mail messages received from an .edu address to have a specific long-duration sound, with particular interest shown in the short- and medium-duration areas if they are regarding "account" and addressed to "Nathan." Use the following emailMixer.config file:
Listing 8. .edu example emailMixer.config file
From: _#_ Nathan _#_ glasses.wav
Subject: _#_ IBM _#_ sparcle.wav
Body _#_ developerWorks _#_ space2.wav
DefaultSound _#_ defaultSound _#_ notify.wav
From: _#_ .edu _#_ space3.wav
Body _#_ account _#_ laser.wav
|
This will play a mix of the space3, laser, and glasses sounds when your paycheck-to-bank-account e-mail comes in.
Of course, the sound files used here and our configuration examples are just starting points. You can use your own sound files and configurations to go well beyond our humble examples.
Download Description | Name | Size | Download method |
---|
Samples | os-audio.zip | 171KB | HTTP |
---|
Resources Learn
-
Check out Sound eXchange (SoX) at SourceForge.net.
-
Hear examples of what the e-mail mixer sounds like: Glasses, sparce, space2 and Glasses, laser, space3.
-
Some of the sounds used in this article are from the OpenOffice suite.
-
"Enable C++ applications for Web services using XML-RPC" is a step-by-step guide to exposing C++ methods as services.
-
Visit the developerWorks Architecture zone to get the resources you need to advance your skills in the architecture arena.
-
Stay current with developerWorks technical events and webcasts.
-
Check out upcoming conferences, trade shows, webcasts, and other Events around the world that are of interest to IBM open source developers.
-
Visit the developerWorks Open source zone for extensive how-to information, tools, and project updates to help you develop with open source technologies and use them with IBM's products.
-
To listen to interesting interviews and discussions for software developers, be sure to check out developerWorks podcasts.
Get products and technologies
-
Innovate your next open source development project with IBM trial software, available for download or on DVD.
Discuss
About the author | | | Nathan Harrington is a programmer at IBM currently working with Linux and resource-locating technologies. |
Rate this page
| |