First of the month (more or less) and therefore time for another Exclusive Freebie! This month ActiveDen author flashanctuary offers up an interesting tool making use of the Google Text-To-Speech API. Check it out after the jump!
Using the Unofficial Text-To-Speech Google API
Not so long ago, google added a new cool feature to the google translate system named the text-to-speech function. Is isn’t an official API, but anyone can make use of the service. All you need to do is access a url which generates an mp3 file. This file can be played in flash like any mp3 file.
Step 1: Creating the text-to-speech Class
The first step is to create the text-to-speech class. Open flash and select the file menu, new submenu and new action script file. Then save this file on the hard-disk in your desired package. Let’s name this class and file Text2Speech.as.
package com.flashanctuary.text2speech
{
// flash imports
import flash.events.Event;
import flash.media.Sound;
import flash.media.SoundChannel;
import flash.media.SoundTransform;
import flash.net.URLRequest;
/**
* Text2Speech Main class
*/
public class Text2Speech
{
public function Text2Speech() : void
{
}
}
}
Step 2: Declaring Necessary Variables
First, we need the url constant link to the Google API. Another constant declared regards the google api limitation: it can not play a string which is longer than 100 characters. Of course, my flash file plays phrases longer than 100 characters, I’ll explain how later on.
Other variables that we need inlcude: the text to be played, an array to contain phrases of maximum 100 character from the text, the current sentence position to be played at one moment, the language where to play the text. We also need three variables to play the sound: a Sound variable, a SoundChannel variable and a SoundTransform variable.
// google api link private static const url : String = "http://translate.google.com/translate_tts?"; // maximum number of characters supported by google api private static const noOfMaxChars : Number = 100; // private var _text : String; private var _sentences : Array; private var _sentencePosition : int; // private var sound : Sound; private var soundChannel : SoundChannel; private var sTransform : SoundTransform; // private var _volume : Number = 0.5; private var _currentPosition : Number = 0; // private var _language : String;
Step 3: Let’s Initialize it!
Now we would need a public function to initialize this class: this will contain the text we want to play and the language.
public function init(language : String, text : String) : void
{
// set language
_language = language;
// if the number of chars is longer than the maximum number of chars supported
// the the text will be split
if (text.length <= noOfMaxChars)
{
initSound(url + "tl=" + language + "&q=" + text);
}
else
{
_sentences = new Array();
// split text
divideText(text);
_sentencePosition = 0;
// begin palying the first part of the text
initSound(url + "tl=" + language + "&q=" + _sentences[_sentencePosition]);
}
}
Step 4: Trim Text
If our text length is longer than the supported number of characters, than we must split it into sentences of a maximum of 100 characters. In order to do this, we create a recursive function to go through all the text and insert the sentences of maximum 100 characters in an array.
private function divideText(str : String) : void
{
var substr : String;
if (str.length >= noOfMaxChars)
{
substr = str.substring(0, noOfMaxChars + 1);
}
else
{
substr = str;
}
if (substr.charAt(substr.length - 1) != " " && str.length >= noOfMaxChars)
{
var index : int = substr.lastIndexOf(" ");
substr = str.substring(0, index);
}
_sentences.push(substr);
if (str.substring(substr.length + 1, str.length).length > 0)
{
divideText(str.substring(substr.length + 1, str.length));
}
}
Step 5: Play the Sentences
From now on, the process is similiar to when you create an mp3 player. Firstly, we initialize the sound variables that I spoke about in the first instance and after this we begin to play the first sentence from the whole sentences array.
When this sentence has finished playing, we go and play the next one (when the SOUND_COMPLETE events is happening). And so on and so forth until all maximum 100 characters sentences from our initial text are played.
public function initSound(path : String) : void
{
// reset sounds chanels, sound and sound transform if they are not null
if (soundChannel != null)
{
stopSound();
soundChannel = null;
}
if (sound != null)
{
sound = null;
}
if (sTransform != null)
{
sTransform = null;
}
_currentPosition = 0;
// create the new sound and begin playing
sound = new Sound(new URLRequest(path));
soundChannel = new SoundChannel();
sTransform = new SoundTransform(_volume);
playSound();
}
public function playSound() : void
{
soundChannel = sound.play(_currentPosition);
soundChannel.addEventListener(Event.SOUND_COMPLETE, soundComplete);
soundChannel.soundTransform = sTransform;
}
public function stopSound() : void
{
_currentPosition = soundChannel.position;
if (soundChannel.hasEventListener(Event.SOUND_COMPLETE))
{
soundChannel.removeEventListener(Event.SOUND_COMPLETE, soundComplete);
}
soundChannel.stop();
}
private function soundComplete(evt : Event) : void
{
stopSound();
// when the current sound is complete go to the next group of charcters and play that part
if (_sentences != null)
{
if (_sentencePosition < _sentences.length - 1)
{
_sentencePosition++;
initSound(url + "tl=" + _language + "&q=" + _sentences[_sentencePosition]);
}
}
}
Step 6: How to use This Class
You would probably now ask how this class can be used in one of your projects. Well, this is very simple: you just need to create one instance
of this class and initialize it with your desired language and text. All languages supported are listed and can be found at http://translate.google.com.
// create the new text to speech variable var t2s : Text2Speech = new Text2Speech(); // initialize the text to speech class instance with the language desired and the text t2s.init(language_abbreviation, text_to_play);
Sound Playing Issues
You have possibly already noticed in the preview that sometimes a cut-off appears when a sound ends and another one begins. This problem can be easily solved by loading all sounds before playing them back. This method implies a longer loading time, especially when the chosen text to play back is very long. The best solution for the time being seems to be the above one, but should anyone have a better one, you are most welcome to leave a comment!
Conclusion
I’ve spent a long time trying to find a solution for this text-to-speech problem so I can use it in Flash. It seems google has solved it and the solution is these days easy and accessible for all developers.
This is my first contribution to Activetuts+, I hope you have learned something useful, enjoy the file and thank you for reading!
nice!
great idea!
great code!!!
Hey! Awesome, thanks for sharing it
Wow anther great tutorial from the tuts ppl this site is getting better and better every day i am loving it great job thanks all.
Yes indeedy, flashanctuary did a great job with this submission – glad you’re enjoying the site!
Awesome town! Now my plan for a Flash Stephen Hawking can be realised! :D
Glad that you like it guys!
Great post, I didn’t know this was possible.
is it just me or does the demo have an error? (dutch)
it says: IOErrorEVent text=Error#2032: Streamerror
Error #2044: Niet-afgehandelde IOErrorEvent:. text=Error #2032: Streamfout.
at com.flashanctuary.text2speech::Text2Speech/initSound()[D:\ActiveDen\Text2Speech\Active Unhandled Den\Main\I - Source\com\flashanctuary\text2speech\Text2Speech.as:99]
at com.flashanctuary.text2speech::Text2Speech/init()[D:\ActiveDen\Text2Speech\ActiveDen\Main\I - Source\com\flashanctuary\text2speech\Text2Speech.as:59]
at com.flashanctuary::Main/releaseFunction()[D:\ActiveDen\Text2Speech\ActiveDen\Main\I - Source\com\flashanctuary\Main.as:172]
at com.flashanctuary::Main/releaseHandler()[D:\ActiveDen\Text2Speech\ActiveDen\Main\I - Source\com\flashanctuary\Main.as:255]
Yeh same here, tis a shame i was looking forward to testing this.
Odd… what text are you guys using to test it?
Woowwww really cool !!
I just tested it again and all is working…
really really cool !!! :)
can we change the voice ?
Error #2044: Unhandled IOErrorEvent:. text=Error #2032: Stream Error.
at com.flashanctuary.text2speech::Text2Speech/initSound()[D:\ActiveDen\Text2Speech\ActiveDen\Main\I - Source\com\flashanctuary\text2speech\Text2Speech.as:99]
at com.flashanctuary.text2speech::Text2Speech/init()[D:\ActiveDen\Text2Speech\ActiveDen\Main\I - Source\com\flashanctuary\text2speech\Text2Speech.as:59]
at com.flashanctuary::Main/releaseFunction()[D:\ActiveDen\Text2Speech\ActiveDen\Main\I - Source\com\flashanctuary\Main.as:172]
at com.flashanctuary::Main/releaseHandler()[D:\ActiveDen\Text2Speech\ActiveDen\Main\I - Source\com\flashanctuary\Main.as:255]
:o(
What text did you enter, Fredrik?
This is marvelous. I have been thinking for some time about how we could teach Flash to speak. Now its all done here. It works very well.
I have not yet explored it or the coding but one thing that comes to mind is – can this work on a mobile in Flash Lite perhaps ? Ok it will still need to access the Google thingy ?
Thanks again.
Paul
Hi guys,
Please can you tell us what text did you enter when you got that error. for sure I can fix this, but I really must know when it is happening.
Thank you
@ mat
I don’t think we can change the voice. There is a specific voice for every language provided by google.
Thanks
Text: hello language: English
Error #2044: Unhandled IOErrorEvent:. text=Error #2032: Stream Error.
at com.flashanctuary.text2speech::Text2Speech/initSound()[D:\ActiveDen\Text2Speech\ActiveDen\Main\I - Source\com\flashanctuary\text2speech\Text2Speech.as:99]
at com.flashanctuary.text2speech::Text2Speech/init()[D:\ActiveDen\Text2Speech\ActiveDen\Main\I - Source\com\flashanctuary\text2speech\Text2Speech.as:59]
at com.flashanctuary::Main/releaseFunction()[D:\ActiveDen\Text2Speech\ActiveDen\Main\I - Source\com\flashanctuary\Main.as:172]
at com.flashanctuary::Main/releaseHandler()[D:\ActiveDen\Text2Speech\ActiveDen\Main\I - Source\com\flashanctuary\Main.as:255]
:(
Thanks for that. I found the lag between sounds difficult to fix so what I did was split the sentences at every comma or full-stop taking advantage of the delay that happens then anyway eg
private function divideText(str:String):void
{
_sentences=str.split(/[.,]+/)
}
so as long as the sentence has a comma or full-stop every 100 characters it sound OK
Very nice David, but if there is no comma and no point? In this case we will have a problem.
Very similar to class i submit on AD a few months ago on the forum but fine ,and I explained there what the problem with the Api key .
The Api key is not official so many will get error or browser silence like IE atc` if they hold flash 9 ` so this is still under experiment, last time i talk to Google regarding this been official with flash use ,so this should not been implement yet, unless you are using FF3 no problem
Hmm, interesting — thanks for sharing :) So this is a Flash Player issue? Or a browser issue?
Ola Michael
Well the first Text-To-Speech API was release a year ago i think in November 2009 with 100 characters limitation
TTS available in the browser would boost your accessibility and improve usability for people on-the-go (will work on Android also).
but Flash and loading .mp3′s across domains are mot that good friends, this is why some browser block it so you get error .
So again on AD it was a few 2-5 month ago cant remember, i submit a class and little solution with php (server side proxy script) will get you around that easily enough .
How its been done? well I think visiting AD forum will do only good for you guys (:
and i rarely visit here so I don’t know exactly how things work around here ….
adios.
Tsafi
It’s weird because I never got that error that you are saying about even if I tested and tested and tested million times…
hey this is cool but it doesn’t work when you put the .swf online google blocks it, even your example doesn’t work. I think you need to proxy the google page, anyone know how?
Hmm, if a proxy’s the issue then check out this Quick Tip: Using Google App Engine as a Proxy Server.
Thanks for pointing this out. Spent a couple of hours looking for this.
Hi,
I don’t think is about google blocking, it is working online as you can see in the tutorial demo.
Thank you
Hi,
This don’t work for me in IE and Opera
Error #2044: Unhandled IOErrorEvent:. text=Error #2032: Stream Error.
at com.flashanctuary.text2speech::Text2Speech/initSound()[D:\ActiveDen\Text2Speech\ActiveDen\Main\I - Source\com\flashanctuary\text2speech\Text2Speech.as:99]
at com.flashanctuary.text2speech::Text2Speech/init()[D:\ActiveDen\Text2Speech\ActiveDen\Main\I - Source\com\flashanctuary\text2speech\Text2Speech.as:59]
at com.flashanctuary::Main/releaseFunction()[D:\ActiveDen\Text2Speech\ActiveDen\Main\I - Source\com\flashanctuary\Main.as:172]
at com.flashanctuary::Main/releaseHandler()[D:\ActiveDen\Text2Speech\ActiveDen\Main\I - Source\com\flashanctuary\Main.as:255]
But the code is good, this work local with Flash Player 10 if published to .exe
Unfortunately this don’t work in AIR :)
Hi.
I am getting this error for any text from simple and small to large
Error #2044: Unhandled IOErrorEvent:. text=Error #2032: Stream Error.
same application in case if i execute from Flex builder 3 in debug works fine.
In flex this IO 2032 error is a big problem for any reason they have only one error message, earlier also I strugled later i will able to resolve but this i tried all possiblities no luck.
can anyone through some suggestions.
This is in continue to my earlier message, I have enabled the trace to see the problem and this is what i am getting …
Warning: Failed to load policy file from http://translate.google.com/crossdomain.xml
*** Security Sandbox Violation ***
Connection to http://translate.google.com/translate_tts?tl=en&q=val1 of 148.0-AGRIFOS is above 430. halted – not permitted from http://localhost:8080/magma/ge/viewer/GEFrame.swf
Error: Request for resource at http://translate.google.com/translate_tts?tl=en&q=val1 of 148.0-AGRIFOS is above 430. by requestor from http://localhost:8080/magma/ge/viewer/GEFrame.swf is denied due to lack of policy file permissions.
any help is appericated.
It works for me on Firefox 3.x and Safari 5.2 and fails on Google Chrome 7, IE 8 and Opera 10.6.
wow..amazing.
how can this be implemented in a website?
Send me an email about this and I can explain :)
flashanctuary@live.com
Thanks
glad to be here! this is a useful service. perhaps can also be used as an accessibility tool on website.
Is there a way to change the playback speed?
No, this is a sound.
Thanks
This don’t work for me.
mac os x 10.6.6
safari 5.0.3
flash player 10,1,102,64
So is this working or not?? Are there more language’s to select?? Or more voices for example male??
It work for me. FF
Hello, I’m using proxy to get sound to my adobe air application, but after bigger traffic I get 302 error with
captcha code to prove I’m human. Seems to be new google restriction?
This is not working for me and my users. :(
http://www.driller-vocabulary.com/proxy.php?url=http://translate.google.com/translate_tts&tl=en&q=car
Any ideas how to overcome it? I wrote to google, but don’t know, if they send me any replay.
Hi,
I found this site that offers speech to text based voip call recording. It is based on Ozeki VoIP SIP SDK. Available: http://www.voip-sip-sdk.com/p_…
After the first tests it seems suitable for me. I can recommend it for others in need of similar solution.
BR