Text to Speech
Implements a voice synthesiser using a single hardware PWM pin.
Note that you must add an amplifier board to drive the loud speaker. Do NOT connect a loudspeaker directly to your micro controller!!
This software works by changing the duty cycle of a 20kHz carrier frequency.
You can build a suitable amplifier yourself very cheaply without any SMD components and the board is just over an inch square:
I have uploaded my Eagle schematic and board files at http://www.societyofrobots.com/member_tutorials/node/216 but it would also be easy to use strip board if you don't want to make a PCB.
In brief: the amplifier input starts with R2 and C1 which filters out the 20kHz carrier frequency. C2 then passes the audio signal to the amplifier IC1. R3 is a trimmer to set the required output volume. R5 and LED1 provide a 'power on' indicator. The jumper allows you to select whether you are using the power from your robot board or from a separate battery.
Alternatively: there are some commercial boards available - just make sure the amplifier you use has a low-pass filter that filters out this 20kHz or add R2, C1 and C2 yourself.
If your robot goes outdoors then I suggest you use a Mylar speaker rather than a paper one - as they survive damp conditions without falling apart! Also make sure the speaker you purchase is easy to mount. If there are no screw holes on the speaker then you will need to hot glue it into place.
Finally some notes about speech quality:
1. In order to keep the software as small as possible then it uses 4 bit audio samples at a low sampling frequency. So don't expect the quality to be high fidelity - it's very retro!!
2. The quality is also effected by all the other interrupts that are going on depending on your application.
3. The logic to convert English text into sounds is quite complex and not always bullet proof
4. The output is better is the speaker is in some kind of box. Try cupping the loadspeaker in your hands to hear what I mean!
My website, http://webbot.org.uk has some example outputs as WAV files so that you can 'hear before you make'.
The synthesiser is an output stream and so you can access it via the various print commands provided by all streams. It can also be set to be the standard output, or standard error, destination stream.
The simplest method to output some text, assuming you have called it 'speech' in Project Designer, is:
speech.print("Death to all humans\n");
speech << "Death to all humans\n");
or even better because it uses less RAM:
speech.print_P( PSTR("Death to all humans\n") );
Note that it will queue up the text until it finds a '\n' at which point it will start talking.
Generating audio waveforms is difficult at the best of times and if your board is also talking to other sensors, motors and servos then it is even harder in a single tasking environment! I make no apologies for this.
So if the speech output is satisfactory until such time as you add all your other code then I suggest that you think about having a separate board just for speech. This board could receive the text via UART, I2C or SPI - all of which are supported using WebbotLib - and can then speak the text whilst your main board is going at full speed. Of course this board could be very simple, and cheap, such as the $50 Robot board from Society of Robots http://www.societyofrobots.com/robot_tutorial.shtml but using an ATMega328P rather than the ATMega8.
- getPitch - Returns the current voice pitch.
- print - Prints the value of a number, or a string, to the stream.
- print_P - Prints a string from program memory to the stream.
- println - Sends a carriage return line feed sequence to the stream to indicate the end of a line of text.
- read - Reads the next byte from the device. This will return EOF, the end of file marker, if there are no characters available - otherwise it will return the next byte.
- setPitch - Set the voice pitch.
- write - Writes a single byte to the output stream. The returned value is normally the same value as the byte just written but on some devices it can return EOF to indicate a write error. For eaxmple: writing a byte out to a file stored on a µSD card may return EOF if there is no available space.
- write - Writes out a sequence of bytes from a given position in RAM. The returned value is the number of bytes actually written. This would only be less than the reqested number of bytes if there is an error writing to the stream.
- write_P - Writes out a sequence of bytes from a given position in program memory. The returned value is the number of bytes actually written. This would only be less than the reqested number of bytes if there is an error writing to the stream.