Home‎ > ‎DroidBuilder's Tutorials‎ > ‎

Advanced SpeakJet Shield TTS Programming

Please note:
As of Arduino 1.0 some changes were made to the print function and byte keyword. Therefore some changes are required in the code presented below to get them to run in Arduino 1.0! Lines such as
speakJet.print(223, BYTE); need to be changed to speakJet.write(223); (essentially "print" changes to "write"; and "BYTE" is removed). Also note that the .pde extension in the filename has been changed to .ino in Arduino 1.0 (the .pde extension was also used in Processing sketches and the extension changed  in Arduino 1.0 to avoid further confusion)!

Note for SpeakJet Shield TTS v1.3 or later:
wherever #define txPin 2  appears, change it to #define txPin 6
wherever #define rxPin 3 appears, change it to #define rxPin 5
wherever #define busyPin 4 appears, change it to #define busyPin 7

This tutorial will cover some more advanced programming techniques for the SpeakJet Shield TTS. This will include some simple examples of sound effects, changing voices, and speaking what is sent via the serial USB connection.

If you have not gone through the Programming the SpeakJet Shield TTS tutorial, I suggest doing so now. This tutorial expands upon that tutorial; and I don't wish to repeat much of the information already given.

Check the SpeakJet Shield TTS Configuration:

Click on photo for a larger version.

When the SpeakJet Shield TTS is configured so that the post shunts are placed on the headers shown in the above photo, it can use text-to-speech capability. If you wish to have a bit more flexibility with speech effects, such as changing voices on the fly, the SpeakJet Shield TTS can also be configured as a SpeakJet Shield Basic. Just be aware that this is at the cost of text-to-speech capability and ease of programming! More information on configuring the SpeakJet Shield TTS as a Basic can be found at Programming the SpeakJet Shield Basic tutorial.

SpeakJet Shield TTS Sound Effects:

The SpeakJet IC in the SpeakJet Shield TTS is capable of making a large variety of sound effects. Even when configured to use the text-to-speech capability; it is still capable of creating many of them.
If you look at page 16 of the SpeakJet User Manual (in Table E); you will note that SpeakJet MSA codes 200 through 254 are predefined sound effects. These predefined codes are very easy to use with the SpeakJet Shield TTS and you can teach your SpeakJet Shield TTS to make some very cool sound effects along with speech for your Arduino projects!

There are several ways we can use to send these codes to the SpeakJet Shield TTS, each of them is shown below. Within the SpeakJet Shield TTS, the TTS256 text-to-code IC is used to implement text-to-speech capability.  This complicates creating voice effects, but sound effects are simply passed through. The TTS256 ignores any code that isn't a printable ASCII code and passes it through to the SpeakJet IC. The first two example sketches below take advantage of this fact.

Copy and paste the following sketch
to the Arduino IDE (or you can download TTS_R2D2demo_1.pde  which also appears in the "Attachments" section at the bottom of this page), compile and upload it to the Arduino. You may need to reset the Arduino after uploading.

For Arduino 22 or earlier:

TTS_R2D2demo_1.pde

// written by Galen Raben
// www.droidbuilder.com
// TTS_R2D2demo_1.pde
// Demonstrates how to combine speech and sound effects
// with the SpeakJet Shield TTS
// 5-15-2010
//set up a SoftwareSerial port for Speakjet Shield
//rxPin: the pin on which to receive serial data from TTS256
//txPin: the pin on which to transmit serial data to the TTS256
#include <SoftwareSerial.h>
#define txPin 2
#define rxPin 3

SoftwareSerial speakJet =  SoftwareSerial(rxPin, txPin);

void
setup(){
  // initialize the serial communications with the SpeakJet-TTS256
  pinMode(rxPin, INPUT);
  pinMode(txPin, OUTPUT);
  speakJet.begin(9600);

  // set the data rate for the SoftwareSerial port

  delay(500); // wait a moment for the Arduino resets to finish

  speakJet.print("I can sound like R2D2"); // send speech

  // send sound effects
  speakJet.print(223, BYTE);  // B3
  speakJet.print(4, BYTE);    // pause4
  speakJet.print(222, BYTE);  // B2
  speakJet.print(5, BYTE);    // pause5
  speakJet.print(207, BYTE);  // R7
  speakJet.print(4, BYTE);    // pause4
  speakJet.print(238, BYTE);  // C8
  speakJet.println();
}

void loop() {}

For Arduino 1.0 or later:

TTS_R2D2demo_1.ino

// TTS_R2D2demo_1.ino
// written by Galen Raben / www.droidbuilder.com
// 5-15-2010
// revised 7-9-2012 for arduino 1.0

// Demonstrates how to combine speech and sound effects
// with the SpeakJet Shield TTS

//set up a SoftwareSerial port for Speakjet Shield
//rxPin: the pin on which to receive serial data from TTS256
//txPin: the pin on which to transmit serial data to the TTS256
#include <SoftwareSerial.h>
#define txPin 2
#define rxPin 3
SoftwareSerial speakJet =  SoftwareSerial(rxPin, txPin);

void setup(){
  // initialize the serial communications with the SpeakJet-TTS256
  pinMode(rxPin, INPUT);
  pinMode(txPin, OUTPUT);
  speakJet.begin(9600); // set the data rate for the SoftwareSerial port
  delay(500); // wait a moment for the Arduino resets to finish

  speakJet.print("I can sound like R2D2"); // send speech
  // send sound effects
  speakJet.write(223);  // B3
  speakJet.write(4);    // pause4
  speakJet.write(222);  // B2
  speakJet.write(5);    // pause5
  speakJet.write(207);  // R7
  speakJet.write(4);    // pause4
  speakJet.write(238);  // C8
  speakJet.println();
}

void loop() {}


This second sketch shows another method that is similar though with a twist. Sound effects and speech is sent in a single line in the sketch, BUT the downside is the sound effect codes have to be sent in hexidecimal (note the upside is that it is compatible with Arduino 1.0 with no changes!). In this sketch I used the exact sound effect data as the sketch above -so you can see how the two methods compare...

Copy and paste the following sketch to the Arduino IDE (or you can download TTS_R2D2demo_2.pde which also appears in the "Attachments" section at the bottom of this page), compile and upload to the Arduino. You may need to reset the Arduino after uploading.

Compatible with all versions of Arduino!
:

TTS_R2_D2demo_2.ino

// TTS_R2D2demo_2.pde.ino
// written by Galen Raben / www.droidbuilder.com
// 5-15-2010
// Demonstrates a method of combining speech and sound effects
// with the SpeakJet Shield TTS

//set up a SoftwareSerial port for Speakjet Shield
//rxPin: the pin on which to receive serial data from TTS256
//txPin: the pin on which to transmit serial data to the TTS256
#include <SoftwareSerial.h>
#define txPin 2
#define rxPin 3
SoftwareSerial speakJet =  SoftwareSerial(rxPin, txPin);

void setup(){
  // initialize the serial communications with the SpeakJet-TTS256
  pinMode(rxPin, INPUT);
  pinMode(txPin, OUTPUT);
  speakJet.begin(9600); // set the data rate for the SoftwareSerial port
  delay(500); // wait a moment for the Arduino resets to finish

  // R2D2 beeps:     223, 4, 222, 5, 207, 4, 238
  // hexidecimal:     DF  04  DE  05  CF  04  EE
  speakJet.println("I can sound like R2D2 \xDF\x04\xDE\x05\xCF\x04\xEE"); // send speech & sounds
}

void loop() {}


Handshaking on the SpeakJet Shield TTS:

Two types of handshaking are available on the SpeakJet Shield TTS; "Buffer-half" and "Busy". Handshaking is often needed when you have long sequences of speech and sound effects. If the speech you are trying to generate stutters , stops or makes unexpected noises partway through the sequence; it is likely the buffer of the SpeakJet IC has overflowed, this indicates you need to use handshaking. For the examples shown in this tutorial, I use "Busy" handshaking, but you may also use "Buffer-Half"; the effect on the resulting speech is similar.

To implement handshaking, you will need to add the following code to your Arduino speech sketch.
Add to the sketch defines (v1.2 and earlier boards):
#define busyPin 4
(v1.3 and later boards):
#define busyPin 7

Add to sketch setup section:
pinMode(busyPin, INPUT);

Add this function to the sketch:

void SJBusy(){
  delay(20); // wait 12ms minimum before checking SpeakJet busy pin
  while(digitalRead(busyPin)){
    delay(250); // wait here while SpeakJet is busy (pin 4 is true)

  }
  delay(250); // a bit more delay
}

And wherever in your sketch you need to wait for the SpeakJet to catch up:
SJBusy();

You will see examples of using this function in some of the later sketches...

Changing Voices on the SpeakJet Shield TTS:

With the TTS256 text-to-speech enabled, changing voices on the SpeakJet Shield TTS is possible, but does not have the flexibility as when the board is configured as a SpeakJet Shield Basic. On page 3 of the TTS256 Datasheet you will see a reference to a "Pass Through Mode". This is initiated by sending "passthru on" to the TTS256. In the following sketch I demonstrate the proper way to initiate and terminate Pass Through Mode. However you will find there are some caveats when using this mode! At this time I do not know of a way to initiate this mode without the SpeakJet announcing "passthru on". Also I  do not know a way to change multiple voices on the fly. It appears the voice can only be changed once within a given sketch! The following sketch shows how to do four different voices - but remember only one can be active at a time! Sketches using this mode also seem to be somewhat unstable - they may not properly initialize after uploading the sketch. You may need to reset the Arduino multiple times to get it to behave!

Copy and paste the following sketch to the Arduino IDE (or you can download TTSNewVoice.pde which also appears in the "Attachments" section at the bottom of this page), compile and upload to the Arduino. You may need to reset the Arduino after uploading!

If you have trouble with this sketch, you may need to reset the Arduino several times! At some point you should hear the shield say "pass thru on" and then say "hello world" in a new voice. I don't know a way to disable the "passthru on" phrase from being spoken. Consider it a success if you hear it :-) Try the other voices I wrote in the example code for you You will find a line of code in the "void loop" called changeVoice2 - this is the line you need to modify.  Note that changeVoice1 is the "normal"
SpeakJet voice, changeVoice2 and changeVoice3 are different pitches, changeVoice4 is my attempt at a StarWars battledroid voice (perhaps familiar to those of you who watch "StarWars: The Clone Wars" cartoon series).

Anyway, all that said, here is my example sketch (note I haven't modified this for Arduino 1.0 yet):

Arduino 22 or earlier:

TTSNewVoice.pde

// TTSNewVoice.pde
// example of changing voices on Speakjet Shield TTS
// with the text-to-speech enabled

// 10-24-2010
// DroidBuilder.com / Galen Raben

// set up a SoftwareSerial port for Speakjet Shield
#include <SoftwareSerial.h>
// rxPin: the pin on which to receive serial data from TTS256
// txPin: the pin on which to transmit serial data to the TTS256
// busyPin: the pin monitoring SpeakJet busy status
#define txPin 2
#define rxPin 3
#define busyPin 4
// set up a new serial port for Speakjet Shield
SoftwareSerial speakJet =  SoftwareSerial(rxPin, txPin);

void setup(){
  // init serial communications with the SpeakJet-TTS256
  pinMode(rxPin, INPUT);
  pinMode(txPin, OUTPUT);
  pinMode(busyPin, INPUT);
  speakJet.begin(9600); // set the data rate for the SoftwareSerial port
  delay(500); // wait a moment for the Arduino resets to finish (speaks "ready")
}

void loop() {
  changeVoice2(); // only works once in a loop, other changes are ignored
  speakJet.println("Hello world"); // send it to the SpeakJet
  SJBusy();
}

void changeVoice1() { // default voice
  speakJet.println("passthruon"); // init TTS256 passthru
  speakJet.print(13, BYTE); // send cr
  speakJet.print(20, BYTE); // vol
  speakJet.print(96, BYTE); //  0-127 default 96
  speakJet.print(21, BYTE); // speed
  speakJet.print(114, BYTE); //  0-127 default 114
  speakJet.print(22, BYTE); // pitch
  speakJet.print(88, BYTE); //  0-255 default 88
  speakJet.print(23, BYTE); // bend
  speakJet.print(5, BYTE); //  0-15 default 5
  speakJet.println("X"); // terminate passthruon
  speakJet.println(10, BYTE); // add linefeed (\x0A)
  delay(500);
}

void changeVoice2() { // higher pitch voice
  speakJet.println("passthruon");
  speakJet.print(13, BYTE);
  speakJet.print(20, BYTE);
  speakJet.print(96, BYTE);
  speakJet.print(21, BYTE);
  speakJet.print(114, BYTE);
  speakJet.print(22, BYTE); // pitch
  speakJet.print(120, BYTE); // <-- set pitch higher
  speakJet.print(23, BYTE);
  speakJet.print(5, BYTE);
  speakJet.println("X");
  speakJet.println(10, BYTE);
  delay(500);
}

void changeVoice3() { // lower pitch voice
  speakJet.println("passthruon");
  speakJet.print(13, BYTE);
  speakJet.print(20, BYTE);
  speakJet.print(96, BYTE);
  speakJet.print(21, BYTE);
  speakJet.print(114, BYTE);
  speakJet.print(22, BYTE); // pitch
  speakJet.print(60, BYTE); // <-- set pitch lower
  speakJet.print(23, BYTE);
  speakJet.print(5, BYTE);
  speakJet.println("X");
  speakJet.println(10, BYTE);
  delay(500);
}

void changeVoice4() { // StarWars droid voice 
  speakJet.println("passthruon");

  speakJet.print(13, BYTE);
  speakJet.print(20, BYTE);
  speakJet.print(96, BYTE);
  speakJet.print(21, BYTE); // speed
  speakJet.print(120, BYTE); // <-- set speed higer
  speakJet.print(22, BYTE); // pitch
  speakJet.print(120, BYTE); // <-- set pitch higher
  speakJet.print(23, BYTE); // bend
  speakJet.print(12, BYTE); // <-- set bend higher
  speakJet.println("X");
  speakJet.println(10, BYTE);
  delay(500);
}

void SJBusy(){
  delay(20); // wait 12ms minimum before checking SpeakJet busy pin
  while(digitalRead(busyPin)){
    delay(250); // wait here while SpeakJet is busy (pin 4 is true)
  }
  delay(250); // a bit more delay may be needed
}

NOTE: THIS SECTION IS UNDER DEVELOPMENT!
Video demo of this sketch coming someday...
Too much to do and not enough free time to get that done for now!
An Example of Serial (USB) Data Passing on the SpeakJet Shield TTS:

The following sketch is an example of how to pass serial data from a host computer, through the Arduino to the SpeakJet Shield TTS. This is a fun sketch with numerous potential uses! You can type and send messages to it via the Arduino Serial Monitor or other serial terminal program and the Arduino/SpeakJet Shield TTS will speak what you send! This sketch is rudimentary, but with a bit more coding and the addition of another Arduino with an Ethernet or WiFi shield this could be used to read and speak your email or twitter messages!

The sketch as it is written, has a limit of roughly 240 characters or so per message sent to it. The sketch could be modified to handle much longer messages by breaking
the messages up into individual words or grouping them; but I'll leave that as an exercise for you! At some later time, I may write and post a sketch which can do this.

Copy and paste the following sketch (or you can download TalkingTerm.pde which also appears in the "Attachments" section at the bottom of this page) to the Arduino Development Environment, compile and upload it. You may get a series of random noises while the sketch uploads. When the sketch finishes uploading, open the Serial Monitor in the Arduino Environment, you will also need to reset the Arduino after opening the Serial Monitor. Type a letter or number and press send. The SpeakJet Shield TTS should respond with "talking term ready" after resetting and afterwords should respond to any messages you send. If instead, the SpeakJet Shield TTS remained silent, you probably will need to reset the Arduino and try again.

Compatible with ALL Arduino versions!:

TalkingTerm.ino

// TalkingTerm.pde / TalkingTerm.ino - Talking terminal demo for SpeakJet Shield TTS
// written by Galen Raben / www.droidbuider.com
// original sketch written 8-1-2009, last modified 5-15-2010

// Demonstrates "serial pass-thru" where text you type at your computer
// is passed thru the Arduino and spoken by the SpeakJet Shield TTS.

// set up a new serial port for Speakjet Shield
// rxPin: the pin on which to receive serial data from TTS256
// txPin: the pin on which to transmit serial data to the TTS256
#include <SoftwareSerial.h>
#define txPin 2
#define rxPin 3
#define busyPin 4

// set the data rate for the Speakjet Shield SoftwareSerial port
SoftwareSerial speakJet = SoftwareSerial(rxPin, txPin);

char sayThis[256]; // string (char array) that holds bytes of incoming string

// read a string from the serial and store it in an array
// this bit of code adapted from WilsonSerialIO.pde
// http://userwww.sfsu.edu/~swilson/

void readSerialString (char *strArray) {
int i = 0;
if(Serial.available()) {
//Serial.print("reading Serial String: "); //optional: for confirmation
while (Serial.available()){
strArray[i] = Serial.read();
i++;
Serial.print(strArray[(i-1)]); // for confirmation
}
strArray[i] = '\0'; // append a proper null to end of string
Serial.println(); // for confirmation
}
}

void setup(){
// initialize the serial communications with PC:
Serial.begin(9600);
// initialize the serial communications with the SpeakJet-TTS256
pinMode(rxPin, INPUT);
pinMode(txPin, OUTPUT);
speakJet.begin(9600);
// make sure we are ready to start talking!
delay(200); // this delay minimizes random spoken text in TTS256 buffer
speakJet.println("Talking term ready");
SJBusy(); // wait for speakjet buffer to empty
sayThis[0] = '\0';
// clear speakjet buffer

}

void loop()
{
// get string sent from PC
readSerialString(sayThis);
// speak it!
speakJet.println(sayThis);
SJBusy(); // wait for speakjet buffer to empty
sayThis[0] = '\0'; // clear speakjet buffer before getting next string
}

void SJBusy(){
delay(20); // wait 12ms minimum before checking SpeakJet busy pin
while(digitalRead(busyPin)){
delay(250); // wait here while SpeakJet is busy (pin 4 is true)
}
delay(250); // a bit more delay after busyPin goes false
}

NOTE: THIS SECTION IS UNDER DEVELOPMENT!
Video demo of this sketch and more stuff coming someday soon...
Too much to do and not enough free time!



Creative Commons License
SpeakJet Shield TTS/Basic by Galen Raben is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License.
Permissions beyond the scope of this license may be available by email.

Code samples given in this document are released into the public domain.

© 2012 Galen Raben/DroidBuilder.com


ċ
TTSNewVoice.pde
(3k)
Galen Raben,
Dec 21, 2010, 4:45 PM
ċ
TTS_R2D2demo_1.pde
(1k)
Galen Raben,
May 15, 2010, 11:36 PM
ċ
TTS_R2D2demo_2.pde
(1k)
Galen Raben,
May 16, 2010, 12:15 AM
ċ
TalkingTerm.pde
(2k)
Galen Raben,
May 16, 2010, 12:19 AM
Comments