How to Create a Text-to-Speech Audio Broadcast with PubNub and Raspberry Pi

According to Gartner, there will be nearly 21 billion devices connected to the Internet by the year 2020. That’s a lot of devices. While I have no doubt these predictions are reasonably correct, that doesn’t make it any easier to build applications that connect these devices together in useful ways. Fortunately, there are solutions that make this job easier.

Today we will make a Raspberry Pi speak from anywhere in the world using Node.js and PubNub. The Raspberry Pi has built-in audio so you can just attach a speaker to its headphone jack or a TV to its HDMI port.

Node.js is the de facto server-side JavaScript framework that we'll install on top of Debian Linux on the Raspberry Pi (aka Raspbian). Node.js was expressly built to handle communication over a network with minimal code. Recent versions of Node.js even support the new ECMAScript 2015 (a.k.a. JavaScript) language extensions, so our code will be even simpler and more compact. In this tutorial we will use the new arrow syntax to create clean event handlers.

PubNub is a Data Stream Network. It passes messages in real time from one device to another (for example, device1, device2, etc.) no matter where in the world they are. PubNub has clients for virtually any smart device and supports Node.js. We will use PubNub to send messages to a server running on a Raspberry Pi from a Linux-based command line script and then from a simple Web page.

Requirements

First, you need to have Node.js installed on your Raspberry Pi. While it used to be a hassle, getting Node on a recent Raspberry Pi is easy and well-documented on the official Node.js site. Use these instructions for Debian.

Using eSpeak To Convert Text Into Audio

We will use an open-source program called eSpeak, which converts plain text into audible speech, to do the actual speech synthesis. When text is supplied to this Linux-based command line program, it is converted into audio. It can also generate WAV files or phoneme maps. See the docs for more complex usage.

Start at the command line shell on your Raspberry Pi. You will need a video display and keyboard attached to your Pi, or else connect remotely via SSH. Now, at the Debian command prompt, install eSpeak with apt-get like this:

sudo apt-get install espeak

Let’s test that it’s working:

espeak “Greetings Earthling"

If you don’t hear anything, make sure you have speakers or a TV connected to your Raspberry Pi and that the sound is turned up.

Create a Node Server

We will walk through all of the JavaScript code below, but if you want to download the entire project, you can find everything you need in this GitHub repository.

First, create and select a sub-directory on the Debian installation where you'll save all your work. At the Debian command prompt, enter the following:

mkdir  /speakit
cd /speakit

Next, at the Debian command prompt; create a text file using the nano text editor (or another text editor of your choice) called server.js with the following code in it:

var ch = require('child_process');
var PubNub = require('pubnub');
 
var pubnub = PubNub.init({
    subscribe_key: "sub-c-692c1e9c-f564-11e5-ba5f-0619f8945a4f",
    publish_key:   "pub-c-850db8b0-39a4-40e3-bc37-cc35782d5a20"
});
 
pubnub.subscribe({
    channel:"text-to-speech",
    message: (msg) => speak(msg.text)
});
 
 
var speaking = false;
function speak(spk) {
    if(speaking) return;
    speaking = true;
    var proc = ch.spawn('espeak',[spk]);
    proc.on('close', () =>  speaking = false);
}

This code is the bare minimum to listen for messages and generate text.  The first two lines import the required libraries. The next lines initialize the PubNub connection. You can get your free API keys on PubNub’s website.
 
The meat of the code is in the middle. It subscribes to messages on the 'text-to-speech' channel. The channel can be any name you want. Just make sure you use the same channel name everywhere. Whenever a message comes in, it invokes the speak function. This function actually starts eSpeak in a background process to generate the audio. Notice that it uses the Boolean variable "speaking" to keep track of whether audio is already playing. This ensures that there is never more than one copy of eSpeak running at a time.
 
To be notified when eSpeak finishes, we must add a callback for the close event. Notice that this looks a bit strange with the => line. No, that doesn’t mean 'equals or greater than'. This is JavaScript's new ‘fat arrow’ syntax. It’s shorthand for creating function calls. This is new JavaScript syntax created in the last couple of years, and Node.js now supports it out of the box.
 
The proc.on(‘close’,()=>speaking = false) could be written in the old Javascript syntax as

proc.on(‘close’, function() {
   speaking = false;
});

I think you’ll agree that the new syntax is a lot cleaner and easier to read.
 
Before we run this script we need to have the PubNub module installed on the copy of Debian Linux that's running on the Raspberry Pi. Install it like this from the Debian command prompt:
 
npm install -- save pubnub
 
Now we can run server.js in the background like this:
 
node server.js &
 
The & tells the Raspberry Pi's Debian shell to run it in the background. This script will listen for messages and call eSpeak for each one. It will wait forever for new messages unless you kill it from the command line like this:
 
kill %1

Continued on page 2.

 

Comments (0)