Videos
How do I get Google Cloud text to speech API key?
Is text to speech free on Google Cloud?
Is Google Cloud text to speech good?
If you like to read your text out loud to catch awkward sentences, you may want to try text-to-speech. Unfortunately the free alternatives sound horrible, and the available text-to-speech apps offering premium voices are expensive, especially if you're revising an entire novel. There is however a workaround, it's a little involved, but you only have to do it once.
Guide: How to generate text-to-speech using Google's Wavenet voices for free. (And legally.)
Wavenet is the artificial voice API used in Google assistant, among others, and sounds considerably more natural than the free alternatives. If you register a Google cloud account, you can activate the the Cloud text-to-speech API and get 1 million characters a month for free directly from Google. Search for it in the API library, and it pops right up.
Be aware that if you exceed the allotted amount of characters, you'll be charged $16 for another million. A million characters is enough for at least 150 000 words though, so you will most likely never come even near running that risk.
The trick is now to take your newly acquired characters and generate an actual voice with them. You do that with an extension to Chrome called "Wavenet for Chrome", surprisingly. Install it and head back to Google cloud to generate an API key. Instructions are provided by the extension, or can be found with a google search. Generate the key and paste it into the extension. The configuration is now done.
You access the extension via the right-click menu, so you need to use a web text editor that doesn't override it. Google docs and Word won't work. I use Wavemaker, but any simple editor will do.
Choose the voice you want in the extension and open your text in the editor. Select the part you want to generate, right-click and select "Download as MP3". This saves you from wasting characters by generating the same text over and over. Open your new file in the MP3-player of your choice and there you go. Easy peasy lemon squeezy.
Do you have cURL installed? You can check by doing curl -V.
If you don't have it installed, you can follow the steps here
If your problem is with the response returned, or the lack thereof, I would recommend using the API key instead of the service account key.
These are all the steps you need to get to the the API key
- Create a project (or use an existing one) in the Cloud Console.
- Make sure that billing is enabled for your project.
- Enable the Text-to-Speech API.
- Create an API key.
And then you can use the curl command like so
Curl -H "X-Goog-Api-Key: PUT_YOUR_API_KEY_HERE" \
-H "Content-Type: application/json; charset=utf-8" \
--data "{
'input':{
'text':'Android is a mobile operating system developed by Google,
based on the Linux kernel and designed primarily for
touchscreen mobile devices such as smartphones and tablets.'
},
'voice':{
'languageCode':'en-gb',
'name':'en-GB-Standard-A',
'ssmlGender':'FEMALE'
},
'audioConfig':{
'audioEncoding':'MP3'
}
}" "https://texttospeech.googleapis.com/v1beta1/text:synthesize" > synthesize-text.txt
{ "audioConfig": { "audioEncoding": "LINEAR16", "effectsProfileId": [ "handset-class-device" ], "pitch": -0.8, "speakingRate": 1 }, "input": { "text": "edited by (❁𝚜𝚊𝚖𝚒𝚛𝚊ꚠ)" }, "voice": { "languageCode": "en-US", "name": "en-US-Wavenet-F" } }
Old answer:
Try using this URL: http://translate.google.com/translate_tts?tl=en&q=Hello%20World It will automatically generate a wav file which you can easily get with an HTTP request through any .net programming.
Edit:
Ohh Google, you thought you could prevent people from using your wonderful service with flimsy http header verification.
Here is a solution to get a response in multiple languages (I'll try to add more as we go):
NodeJS
// npm install `request`
const fs = require('fs');
const request = require('request');
const text = 'Hello World';
const options = {
url: `https://translate.google.com/translate_tts?ie=UTF-8&q=${encodeURIComponent(text)}&tl=en&client=tw-ob`,
headers: {
'Referer': 'http://translate.google.com/',
'User-Agent': 'stagefright/1.2 (Linux;Android 5.0)'
}
}
request(options)
.pipe(fs.createWriteStream('tts.mp3'))
Curl
curl 'https://translate.google.com/translate_tts?ie=UTF-8&q=Hello%20Everyone&tl=en&client=tw-ob' -H 'Referer: http://translate.google.com/' -H 'User-Agent: stagefright/1.2 (Linux;Android 5.0)' > google_tts.mp3
Note that the headers are based on @Chris Cirefice's example, if they stop working at some point I'll attempt to recreate conditions for this code to function. All credits for the current headers go to him and the wonderful tool that is WireShark. (also thanks to Google for not patching this)
In an update to Schahriar SaffarShargh's answer, Google has recently implemented a 'Google abuse' feature, making it impossible to send just any regular old HTTP GET to a URL such as:
http://translate.google.com/translate_tts?tl=en&q=Hello%20World
which worked just fine and dandy previously. Now, following such a link presents you with a CAPTCHA. This also affects HTTP GET requests out-of-browser (such as with cURL), because using that URL gives a redirect to the abuse protection page (the CAPTCHA).
To start, you have to add the query parameter client to the request URL:
http://translate.google.com/translate_tts?tl=en&q=Hello%20World&client=t
Google Translate sends &client=t, so you should too.
Before you make that HTTP request, make sure that you set the Referer header:
Referer: http://translate.google.com/
Evidently, the User-Agent header is also required, but interestingly enough it can be blank:
User-Agent:
Edit: NOTE - on some user-agents, such as Android 4.X, the custom User-Agent header is not sent, meaning that Google will not service the request. In order to solve that problem, I simply set the User-Agent to a valid one, such as stagefright/1.2 (Linux;Android 5.0). Use Wireshark to debug requests (as I did) if Google's servers are not responding, and ensure that these headers are being set properly in the GET! Google will respond with a 503 Service Unavailable if the request fails, followed by a redirect to the CAPTCHA page.
This solution is a bit brittle; it is entirely possible that Google will change the way they handle these requests in the future, so in the end I would suggest asking Google to make a real API endpoint (free or paid) that we can use without feeling dirty for faking HTTP headers.
Edit 2: For those interested, this cURL command should work perfectly fine to download an mp3 of Hello in English:
curl 'http://translate.google.com/translate_tts?ie=UTF-8&q=Hello&tl=en&client=t' -H 'Referer: http://translate.google.com/' -H 'User-Agent: stagefright/1.2 (Linux;Android 5.0)' > google_tts.mp3
As you may notice, I have set both the Referer and User-Agent headers in the request, as well as added the client=t parameter to the querystring. You may use https instead of http, your choice!
Edit 3: Google now requires a token for each GET request (noted by tk in the querystring). Below is the revised cURL command that will correctly download a TTS mp3:
curl 'https://translate.google.com/translate_tts?ie=UTF-8&q=hello&tl=en&tk=995126.592330&client=t' -H 'user-agent: stagefright/1.2 (Linux;Android 5.0)' -H 'referer: https://translate.google.com/' > google_tts.mp3
Notice the &tk=995126.592330 in the querystring; this is the new token. I obtained this token by pressing the speaker icon on translate.google.com and looking at the GET request. I simply added this querystring parameter to the previous cURL command, and it works.
NOTE: obviously this solution is very frail, and breaks at the whim of the architects at Google who introduce new things like tokens required for the requests. This token may not work tomorrow (though I will check and report back)... the point is, it is not wise to rely on this method; instead, one should turn to a commercial TTS solution, especially if using TTS in production.
For further explanation of the token generation and what you might be able to do about it, see Boude's answer.
If this solution breaks any time in the future, please leave a comment on this answer so that we can attempt to find a fix for it!