読者です 読者をやめる 読者になる 読者になる

凹みTips

C++、JavaScript、Unity、ガジェット等の Tips について雑多に書いています。

非公式 GoogleTTS API から音声ファイルを取得する

C++

背景

Ubuntu 11.10 環境で Open JTalk で TTS(Text to Speech)させようとしたら 10.04 の時のように簡単に導入できなかったので、他の TTS 手段を探していて行き着きました。

はじめに

Google TTS は Google 翻訳で結果を喋らせたりするときに使われています。これは非公式ですが API を叩くと利用することができます(参考:Googleのテキスト読み上げ非公式API発見 | TechCrunch Japan)。

(2012/03/19 「!」が含まれているとエラーになってしまっていたので修正)
こいつを C++ で引っ張ってきてしまおう、ということをやってみます。

CLXを利用してデータを取得

CLXは本家によると以下のようなものです。

CLX C++ Libraries は,文字列処理やネットワークプログラミングの補助などを行うための, ヘッダファイルのみで構成された C++ ライブラリです. CLX C++ Libraries は, BSDライセンスで配布しています.ソースコードの複製・改変は自由ですが, 自己責任でお願い致します.

ヘッダオンリで動くのでコンパイルも楽々です。
インストールも簡単です。

ここからファイルを落としてきて解凍&パスの通った場所に配置するだけです。

Ubuntu での例
tar xzvf clx_0.18.2.tar.gz
sudo mv clx /usr/local/include/

ではでは早速 Google TTS に接続してファイルを落としてきましょう。

test.cpp
#include <fstream>
#include <clx/http.h>
#include <clx/uri.h>

int main() {
	// 接続&データ取得
	clx::http session(clx::uri::encode("translate.google.com"));
	session.get(clx::uri::encode("/translate_tts?tl=ja&q=aiueo"));

	// 出力
	std::ofstream ofs("test.mp3", std::ios::binary);
	ofs << session.body() << std::endl;
}

コンパイルオプションはいりません。

g++ test.cpp

で、実行すると「えーあいーゆーいーおー」としゃべる mp3 が出来ます。

日本語を翻訳する

しかし「aiueo」のところを「あいうえお」などとした場合は、良く分からない言葉をしゃべる mp3 になってしまいます。これは User-Agent を見て弾かれていることが原因のようです(参考:Google TTS(日本語)を使う | www.ffffine.net)。ソースを見てみましたが、clx::http 内では特に User-Agent を与えていません。そして外部からこれを設定するような関数もありません。ので、直接 http.h をいじって、User-Agent をごまかしてしまいます。

clx/http.h - 242行目
query << "Host: " << host_ << "\r\n";                           
query << "User-Agent: Mozilla/5.5\r\n"; // 追記

これで次のように「aiueo」部分を変えたファイルをコンパイルすれば正常に再生されます。

#include <fstream>
#include <clx/http.h>
#include <clx/uri.h>

int main() {
	// 接続&データ取得
	clx::http session(clx::uri::encode("translate.google.com"));
	session.get(clx::uri::encode("/translate_tts?tl=ja&q=ゆっくりしていってね!"));

	// 出力
	std::ofstream ofs("yukkuri.mp3", std::ios::binary);
	ofs << session.body() << std::endl;
}

CLX 便利です。

失敗編

Boost.Asioを使ってみた
#include <fstream>
#include <iostream>
#include <string>
#include <boost/asio.hpp>
#include <boost/format.hpp>

int main(int argc, char const* argv[])
{
	// 喋らせたい言葉
	const std::string text = "ゆっくりしていってね";

	// google tts に接続
	boost::asio::ip::tcp::iostream s( "translate.google.com", "http" );

	// 送信
	std::cout << argv[1] << std::endl;
	s << boost::format("GET /translate_tts?tl=ja&q=%1% HTTP/1.1\r\n") % text;
	s << "Host: translate.google.com\r\n";
	s << "User-Agent:Mozilla/5.5\r\n";
	s << "\r\n";
	s << std::flush;

	// 受信
	std::ofstream fout("test.mpg", std::ios::binary);
	std::string buf;
	while(std::getline(s, buf)) {
		fout << buf << std::endl;
	}
}

勝手に終わってくれない。。ので Ctrl + C して終了するとファイルは出来ています。ただ最後がちょっと途切れる。

cpp-netlibを使ってみようとした

Proposed for Boost な cpp-netlib を使おうとしたのですが、ちょっと大変そうだったので断念。。 Boost に組み込まれてから再チャレンジしようと思います。

おわりに

rti さんも作られていたようです!