(For more resources related to this topic, see here.)
To create the Processing sketches for this project, we will need to install the Processing library ttslib. This library is a wrapper around the FreeTTS Java library that helps us to write a sketch that reads out text. We will learn how to change the voice parameters of the kevin16 voice of the FreeTTS package to make our robot’s voices distinguishable. We will also create a parser that is able to read the Shakespeare script and which generates text-line objects that allow our script to know which line is read by which robot.
A Drama thread will be used to control the text-to-speech objects, and the draw() method of our sketch will print the script on the screen while our robots perform it, just in case one of them forgets a line. Finally, we will use some cardboard boxes and a pair of cheap speakers to create the robots and their stage. The following figure shows how the robots work:
Since the 18th century, inventors have tried to build talking machines (with varying success). Talking toys swamped the market in the 1980s and 90s. In every decent Sci-Fi novel, computers and robots are capable of speaking. So how could building talking robots not be awesome? And what could be more appropriate to put these speaking capabilities to test than performing a Shakespeare play? So as you see, building actor robots is officially awesome, just in case your non-geek family members should ask.
We will split this project into four tasks that will guide you through the general on of the robots from beginning to end. Here is a short overview of what we are going to do:
Since Processing has no speaking capabilities out of the box, our first task is adding an external library using the new Processing Library Manager. We will use the ttslib package, which is a wrapper library around the FreeTTS library.
We will also create a short, speaking Processing sketch to check the installation.
import guru.ttslib.*;
TTS tts;
void setup() {
tts = new TTS();
}
void draw() {
}
void mousePressed() {
tts.speak("Hello, I am a Computer");
}
In steps 1 to 3, we installed an additional library to Processing. The ttslib is a wrapper library around the FreeTTS text-to-speech engine.
Then we created a simple Processing sketch that imports the installed library and creates an instance of the TTS class. The TTS objects match the speakers we need in our sketches. In this case, we created only one speaker and added a mousePressed() method that calls the speak() method of our tts object.
In this part of the project, we are going to create a Drama thread and teach Processing how to read a Shakespeare script. This thread runs in the background and is controlling the performance. We focus on reading and executing the play in this task, and add the speakers in the next one.
Our sketch needs to know which line of the script is read by which robot. So we need to convert the Shakespeare script into a more machine-readable format. For every line of text, we need to know which speaker should read the line. So we take the script and add the letter J and a separation character that is used nowhere else in the script, in front of every line our Juliet-Robot should speak, and we add R and the separation letter for every line our Romeo-Robot should speak. After all these steps, our text file looks something like the following:
R# Lady, by yonder blessed moon I vow,
R# That tips with silver all these fruit-tree tops --
J# O, swear not by the moon, the inconstant moon,
J# That monthly changes in her circled orb,
J# Lest that thy love prove likewise variable.
R# What shall I swear by?
J# Do not swear at all.
J# Or if thou wilt, swear by thy gracious self,
J# Which is the god of my idolatry,
J# And I'll believe thee.
Let’s write our parser:
void setup() {
String[] rawLines = loadStrings
( "romeo_and_juliet.txt" );
}
public class Line {
String speaker;
String text;
public Line( String speaker, String text ) {
this.speaker = speaker;
this.text = text;
}
}
void setup() {
String[] rawLines = loadStrings
( "romeo_and_juliet.txt" );
ArrayList lines = new ArrayList();
for ( int i=0; i<rawLines.length; i++) {
if (!"".equals(rawLines[i])) {
String[] tmp = rawLines[i].split("#");
lines.add( new Line( tmp[0], tmp[1].trim() ));
}
}
}
public class Drama extends Thread {
int current;
ArrayList lines;
boolean running;
public Drama( ArrayList lines ) {
this.lines = lines;
current = 0;
running = false;
}
public int getCurrent() {
return current;
}
public Line getLine( int num ) {
if ( num >=0 && num < lines.size()) {
return (Line)lines.get( num );
} else {
return null;
}
}
public boolean isRunning() {
return running;
}
}
public void run() {
running = true;
for ( int i =0; i < lines.size(); i++) {
current = i;
Line l = (Line)lines.get(i);
System.out.println( l.text );
delay( 1 );
}
running = false;
}
Drama drama;
void setup() {
String[] rawLines = loadStrings
( "romeo_and_juliet.txt" );
ArrayList lines = new ArrayList();
for ( int i=0; i<rawLines.length; i++) {
if (!"".equals(rawLines[i])) {
String[] tmp = rawLines[i].split("#");
lines.add( new Line( tmp[0], tmp[1].trim() ));
}
}
drama = new Drama( lines );
}
void mousePressed() {
if ( !drama.isRunning()) {
drama.start();
}
}
void draw() {
background(255);
textAlign(CENTER);
fill(0);
text( "Click here for Drama", width/2, height/2 );
}
void setup() {
size( 800, 400 );
String[] rawLines = loadStrings
( "romeo_and_juliet.txt" );
ArrayList lines = new ArrayList();
for ( int i=0; i<rawLines.length; i++) {
if (!"".equals(rawLines[i])) {
String[] tmp = rawLines[i].split("#");
lines.add( new Line( tmp[0], tmp[1].trim() ));
}
}
drama = new Drama( lines );
}
println(PFont.list());
void setup() {
size( 800, 400 );
textFont( createFont( "Georgia", 24 ));
...
In this section, we wrote the code that parses a text file and generates a list of Line objects. These objects are then used by a Drama thread that runs in the background as soon as anyone clicks on the sketch window. Currently, the Drama thread prints out the text line on the console.
In steps 6 to 8, we created the Line class. This class is a very simple, so-called Plain Old Java Object (POJO) that holds our text lines, but it doesn’t add any functionality.
The code that is controlling the performance of our play was created in steps 10 to 12. We created a thread that is able to run in the background, since in the next step we want to be able to use the draw() method and some TTS objects simultaneously.
The code block in step 12 defines a Boolean variable named running, which we used in the mousePressed() method to check if the sketch is already running or should be started.
In step 17, we used the list() method of the PFont class to get a list of installed fonts. This is a very common pattern in Processing. You would use the same approach to get a list of installed midi-interfaces, web-cams, serial-ports, and so on.
I remember deciding to pursue my first IT certification, the CompTIA A+. I had signed…
Key takeaways The transformer architecture has proved to be revolutionary in outperforming the classical RNN…
Once we learn how to deploy an Ubuntu server, how to manage users, and how…
Key-takeaways: Clean code isn’t just a nice thing to have or a luxury in software projects; it's a necessity. If we…
While developing a web application, or setting dynamic pages and meta tags we need to deal with…
Software architecture is one of the most discussed topics in the software industry today, and…