LoginSignup
1
4

More than 5 years have passed since last update.

Bing Speech APIを使ってテキストを読み上げた音データをバイナリで受け取る

Posted at

Bing Speech APIとは

https://azure.microsoft.com/ja-jp/services/cognitive-services/speech/
Microsoft AzureのCognitive Servicesの一つです。
Speech to Text API (音声認識)と Text to Speech API (音声合成)の二つから成ります。
今回はText to Speech APIの方を用いて、テキストを合成音声にしてもらおうと思います。
Ajax通信のためにjQueryを利用しています。

APIを用いてテキストを合成音声にする流れ

  1. 無料アカウントを作る。
  2. 30日間無料のBing Speech APIのAPIキーを取得する(キーは二つ出るけどどっち使っても変わらない)。
  3. APIキーをPOSTしてBearerトークンを取得する。
  4. 読み上げて欲しい文章の入ったSSMLとBearerトークンをPOSTしてバイナリデータを受け取る。
  5. 受け取ったバイナリデータをBase64にしてaudioタグのsrcに入れる。
  6. ボタンを押すと音が流れる。
  7. 楽しい🎉

細かい説明

今回のプログラムの中ではPOSTして取ってきたBearerトークンをもう一度POSTし直さなければならず、その部分は同期的に行わなければならないため、後半のバイナリデータを受け取るPOSTの部分を関数にして、前半のBearerトークンを取得する部分の関数の中にネスト状に入れています。
また、バイナリデータを受け取る部分はjQueryで実行すると書く量が増えると言うことだったので、その部分はXMLHttpRequestで実行しています。

ソースコード

main.js
//Tokenを取得する関数。この内部でバイナリの受け取りまで行うため、使用するときはこの関数を呼び出す。
function getToken(text) {
    var apikey = "API_KEY_IS_HERE";
    var uriBase = "https://api.cognitive.microsoft.com/sts/v1.0/issueToken";
    $.ajax({
        url: uriBase,
        beforeSend: function (xhrObj) {
            xhrObj.setRequestHeader("Content-Type", "text/plain");
            xhrObj.setRequestHeader("Ocp-Apim-Subscription-Key", apikey);
        },
        type: "POST",
    })
        .done(function (data) {
            console.log(data);
            receiveVoice(data,text); //ここで受け取ったBearerトークンを送り、バイナリデータを受け取る。
        })
        .fail(function (jqXHR, textStatus, errorThrown) {
            var errorString = (errorThrown === "") ? "Error. " : errorThrown + " (" + jqXHR.status + "): ";
            errorString += (jqXHR.responseText === "") ? "" : (jQuery.parseJSON(jqXHR.responseText).message) ?
                jQuery.parseJSON(jqXHR.responseText).message : jQuery.parseJSON(jqXHR.responseText).error.message;
            alert(errorString);
        });
}

//声データのバイナリを取得する関数。getTokenの中で呼び出される。
function receiveVoice(token,text) {
    var uribase = "https://speech.platform.bing.com/synthesize";
    var params = createParam(text);  //createParam関数は、読み上げて欲しい文章をSSMLに埋め込む関数。後述。
    $(function () {
        var xhr = new XMLHttpRequest();
        xhr.open('POST', uribase, true);
        xhr.setRequestHeader("X-Microsoft-OutputFormat", "audio-16khz-32kbitrate-mono-mp3");
        xhr.setRequestHeader("Content-Type", "application/ssml+xml");
        xhr.setRequestHeader("Authorization", "Bearer " + token);
        xhr.responseType = 'arraybuffer';
        xhr.onload = function (e) {
            console.log(this.response);
            var u8 = new Uint8Array(this.response);
            var binaryString = "";
            for (var i = 0; i < u8.byteLength; i++) {
                binaryString += String.fromCharCode(u8[i]);
            }
            var base = btoa(binaryString);
            console.log(base);
            var audio_init=document.getElementById("audio_init"); //HTMLの中にaudio_initという名前のdivタグを用意して入れる。
            audio_init.innerHTML="<audio controls src='data:audio/mp3;base64," + base + "'></audio>";
        };

        xhr.send(params);
    });
}

//SSMLを作る関数。
function createParam(str) {
    return '<speak version="1.0" xmlns="http://www.w3.org/2001/10/synthesis" xmlns:mstts="http://www.w3.org/2001/mstts" xml:lang="en-US"><voice xml:lang="en-US" name="Microsoft Server Speech Text to Speech Voice (en-US, ZiraRUS)">' + str + '</voice></speak>\n';
    //今回は英語で読み上げて欲しかったために言語は英語、話者は英語話者を利用している。
}

感想

別にバイナリデータで受け取らなくても、と途中からずっと思っていたが、何かの役に立てば幸いです。

参考

https://qiita.com/icoxfog417/items/1f5d7d4e5758deca349b
http://var.blog.jp/archives/62330155.html
https://qiita.com/kojiro_ueda/items/cb303ed11c1755a02ad5
https://qiita.com/yaegaki/items/909587a2dae20467c74a
https://qiita.com/Yarimizu14/items/f56123c738f12ad1844a
https://qiita.com/isseium/items/12b215b6eab26acd2afe
https://qiita.com/yaegaki/items/909587a2dae20467c74a

1
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
4