π
June 20, 2024
Would you like to enjoy the thrill of having your computer speak the time in a mechanical, computerized voice?
You do? Great! This is completely possible in bash from the command line or a script.
We are not talking about any fancy GUI-based voice assistance. We are talking about typing a command that tells time, and we will look at two ways of achieving this using espeak and saytime.
Install espeak and saytime
We will need these programs, so let’s install them now.
sudo apt install espeak saytime
Let’s look at the espeak technique first.
espeak
First, be able to generate a time of your choosing using date. Here is one example:
date '+%A, %B %d, %Y, %I:%M %p'
Output
Thursday, June 20, 2024, 10:19 AM
To make this talk, pipe the output to espeak.
date '+%A, %B %d, %Y, %I:%M %p' | espeak
Oooh! Was that not beautiful? If espeak and your Linux audio are working correctly, you should hear a harsh, 1980’s mechanical, impersonal voice speak the date and time to you.
Let’s make the speech more fitting.
date '+%A, %B %d, %Y, %I:%M %p...Shall we play a game?' | espeak
Aaah! That is better. Not sure about you, but I know which game I will select if a text-based BBS menu appears…
Altering date’s format string will change the text that is spoken.
Controlling espeak
The default espeak might talk a little fast, so man espeak will display a large variety of options to alter the speech.
date '+%A, %B %d, %Y, %I:%M %p...Shall we play a game?' | espeak -v other/en-n -g 15
This speaks the time with a slight accent on the English. English systems will use a default English voice, but other voices are possible. Voice files are located in /usr/lib/x86_64-linux-gnu/espeak-data/voices, so peruse them to see what is available.
Voices use country codes. en is for English, fr is for French, and so on. Using fr (French) only adds a French accent to the English speech for text that cannot be translated into French. It does not perform a 100% translation between languages unless your locale is French, for example.
To use a voice with espeak, add the -v option with a relative path to the voice file. Here is the time spoken in English with a French accent:
date '+%A, %B %d, %Y, %I:%M %p...Shall we play a game?' | espeak -v fr -g 15
Umm…I think. Some of that sounded like gibberish on my system, so I might not have all necessary voice files. Trial and error is necessary here.
Some voice files are located in subdirectories within /usr/lib/x86_64-linux-gnu/espeak-data/voices. To use one, such as Russian, provide the relative path europe/ru so espeak can locate the ru file.
date '+%A, %B %d, %Y, %I:%M %p...Shall we play a game?' | espeak -v europe/ru -g 15
Output
Full dictionary is not installed for 'ru'
This is an example of not having all language files installed for a given locale. espeak will still try its best, but it will default to English or whatever your current locale might be.
Some voices alter the speech audio. For example, mb/mb-af1-en sounds like a grumpy bullfrog.
date '+%A, %B %d, %Y, %I:%M %p...Shall we play a game?' | espeak -v mb/mb-af1-en -g 15
Output
mbrola: mbrola: No such file or directory mbrowrap error: mbrola exited with status 1 mbrola voice not found
The -g option controls the duration gap between words for better understanding. 10ms is the default. 15 represents 15ms to add more delay.
Partial Translation
Numbers, dates, and times, are usually translated and spoken in the specified language voice when possible, but English text remains English text if the system locale is English. By altering the date string, we can hear a different translation for the given day and time.
Begin with the date string you want to read to make sure that it is printable.
date '+%A, %l:%M'
Then, pipe to espeak.
date '+%A, %l:%M' | espeak -v en-us -g 15 -s 130
This voices the day and time in American English. By default, my system defaults to British English, so the accent between the two voices sounds different.
-g slows down the word gap duration to 15ms, and -s slows the spoken word speed to better understand the speech. Now, let’s try this in a few different languages by specifying different voices.
date '+%A, %l:%M' | espeak -v de -g 15 -s 130Β # German date '+%A, %l:%M' | espeak -v fr -g 15 -s 130 # French date '+%A, %l:%M' | espeak -v en -g 15 -s 130 # British English date '+%A, %l:%M' | espeak -v asia/zh -g 15 -s 130 # Chinese date '+%A, %l:%M' | espeak -v asia/fa-en-us -g 15 -s 130 # Iranian (fa) English? date '+%A, %l:%M' | espeak -v europe/cy -g 15 -s 130 # Welsh date '+%A, %l:%M' | espeak -v test/gd -g 15 -s 130 # Scottish?
Consult the espeak-ng documentation for a full list of espeak languages to understand what the codes mean.
Notice that sometimes the day is spoken in a different language and other times it defaults to English. As I understand, the system needs the proper locale installed for a given language for full day/month name translation. Numbers, such as the time, are usually spoken in the target language. Anything that cannot be translated defaults to your system locale, which is British English in this example.
saytime
Another program dedicated to speaking the current system time is saytime. (You probably never knew that this existed, did you?)
Just run saytime to hear it in action.
saytime
Hmm. That was okay, but you might see a number of error messages as each phrase is spoken. This is especially noticeable if you are using S/PDIF optical output for your audio connection. (This also happens with espeak.)
sox WARN alsa: can't encode 0-bit Unknown or not applicable
Try specifying the output type with -t alsa.
saytime -t alsa
Much better. The voice sounds like an uncertain baseball sports announcer who knows nothing about baseball and has to consult his premade script, but the voice is much more understandable and natural than espeak.
Customizing saytime
We can customize the time format a little similar to date. By default, saytime uses %P%l%M%S as its default format string. Suppose we just want the hour and minutes.
saytime -t alsa -f %l%M
This omits the “The time is” spoken prefix, which is represented by %P.
If you want to hear a 24-hour clock, use the %k option.
saytime -t alsa -f %P%k%M%S
saytime only reports the current system time and does not perform any language translation like espeak does.
Changing Voices
The saytime voice sounds better than espeak in my opinion, but it is not as customizable.
Voice files for saytime are .au files located in /usr/share/saytime. That is all. In theory, you should be able to create your own sound files and use those with the -d option, but I have not tried this. Other than that, saytime is English, and no other default voices are available. Still a good program if all you need is the current time spoken in English.
Repeating Time
If you want to make yourself climb a wall and pray for somebody to rescue form self-induced torture, try using the -r1 option to repeat saytime nonstop.
saytime -t alsa -f %P%k%M%S -r1
This runs saytime as a background process, so you will need to kill the process to make it stop.
ps aux | egrep saytime kill 370223 # Replace 370223 with the PID of saytime
Conclusion
There you have it! Two ways of making Linux speak the current time from a terminal. If it works from a terminal, then it will work from a script too…maybe.
espeak is more flexible because it speaks whatever text you feed to it and will even translate a few things to other languages, but it sounds metallic and impersonal — like a malicious computer that wants to take over your life.
saytime is a simple program that only reports the current time in a much more friendly, understandable voice, but it cannot be customized the way espeak can.
Either option adds a little flair to the command line and can add unexpected fun for unsuspecting users.
Enjoy!