Quantcast
Channel: ProgrammableWeb - Node.js
Viewing all articles
Browse latest Browse all 1601

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

$
0
0
Primary Target Audience: 
Primary Channel: 
Primary category: 
Contributed Content: 
Yes
Related Companies: 
Related APIs: 
PubNub
Related Languages: 
Product: 

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.

Continued from page 1.

Send a Message

Now let's create a little program to send it some messages. Make a file called speakit.js. Load it with the following contents and save it to the /speakit directory:

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.publish({
    channel:"text-to-speech",
    message: {
        text:process.argv[2]
    },
    callback: () => process.exit(0)
});

This script is even simpler than the one before. It connects to PubNub’s network (using the keys from your free PubNub account), then publishes a single message containing the input text from the command line. Once the message is sent, it exits. Again, I’m using the arrow syntax to make the callbacks cleaner. Also note that I’m using the same channel name as the server.
 
Now we can run speakit.js like this:
 
node speakit.js “Greetings Earthling"
 
Of course, this isn’t very interesting because we are running the speakit script on the same computer as server.js. We could have just run eSpeak by hand. Let’s build a simple Web page so we can make the Raspberry Pi talk from anywhere.

Create a WebPage

Create a file called speakit.html with the following contents and save it to the /speakit directory on the Raspberry Pi:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Text To Speech on a Raspberry Pi with PubNub</title>
    <script src="https://cdn.pubnub.com/pubnub-3.14.4.min.js"></script>
</head>
<body>
 
<input id='text' type="text"/>
<button id="send">speak it</button>
 
<script type="text/javascript">
    var pubnub = PUBNUB({
        subscribe_key: "sub-c-692c1e9c-f564-11e5-ba5f-0619f8945a4f",
        publish_key:   "pub-c-850db8b0-39a4-40e3-bc37-cc35782d5a20"    });
    document.getElementById("send").addEventListener("click",function(){
        var text = document.getElementById('text').value;
        pubnub.publish({
            channel : "text-to-speech",
            message : {text:text},
        })
    });
</script>
</body>
</html>

This HTML page is pretty simple. It imports the Web version of the PubNub API with a script tag at the top. Then it creates a text input field and a button to send it. Thanks to modern Web standards, we don’t need any special frameworks or tools like jQuery to build this.
 
The script code sets up a connection to PubNub (just like we did in the server-side code) then adds an event listener to the send button.  When the user clicks send, it will get the text string from the text field and publish it to the same channel as before.
 
Now you can put this Web page on a Web server somewhere, and anyone can make your Raspberry Pi speak! Because the Web page and the server use the same publish and subscribe keys, they can communicate through the PubNub network without knowing the IP addresses of each other. Or don’t. You can also just copy this html to a laptop and load it locally from your hard drive. It doesn’t matter if the Web page is on a public server or not. As long as the laptop you load it from can connect to the Internet, then message will get through. Even if the Raspberry Pi is behind a NAT firewall, it will still work. As long as both ends can reach out to the general Internet, messages can be sent.

Next Steps

Connecting devices to each other is actually pretty easy with Node.js and PubNub. Using a Data Stream Network like PubNub lets you focus on what the application does rather than worrying about connectivity.
 
In the future, you could expand this demo by letting the client control the pitch and speed of the voice. eSpeak has options to change all of this. For example, replace the line that spawns eSpeak in server.js with this:

var proc = ch.spawn('espeak',['-s 300', '-p 0', spk]);

This changes the speed to 300, which is about twice as fast as normal human speech. You can also change the pitch with the -p value between 0 and 99. Fifty is neutral. The change above makes the computer speak fast with a low voice.
 
eSpeak has many other fun options to play with, such as language settings and the generation of WAV files, that are useful for long-form text to speech. The full source to this demo is here. In the future you could set it up to speak the time every hour, read tweets to you whenever a hashtag is used, or say funny things to your friends at a party. The possibilities are limitless.

Summary: 
According to Gartner, there will be nearly 21 billion devices connected to the Internet by the year 2020. That’s a lot of devices that need to be connected in useful ways. This article shows you the steps to make a Raspberry Pi speak from anywhere in the world using Node.js and PubNub.
Content type group: 
Articles

Viewing all articles
Browse latest Browse all 1601

Trending Articles