p5.js で「Koeiromap」をつかった音声合成を試してみる（JavaScript で試した話の続き）【2023年4月15日時点】

この記事の内容は、以下の記事を書いた時に試した「Koeiromap」を p5.js で扱う話です。

●音声合成ができる「Koeiromap」の情報を調べてみて JavaScript を使って軽く試してみる【2023年4月8日時点】 - Qiita
　https://qiita.com/youtoy/items/258ac8ed5313f64402a3

以下でツイートしていたような、音声合成の元になるテキストを Webページ上で入力して、ボタンを押したら音声合成が実行されるという形の、簡単なものを作って動かしてみました。

https://twitter.com/youtoy/status/1644572604903350272

なお Koeiromap では、テキストを指定する以外にも、いくつかのパラメータがあります。具体的には声を変化させるパラメータになるのですが、今回の内容では、まずはシンプルに音声合成用のテキストのみを指定する形で作っています。

## Koeiromap について
音声合成が行える「Koeiromap」については、[冒頭で紹介していた前の記事](　https://qiita.com/youtoy/items/258ac8ed5313f64402a3)に書いているので、詳細は[その記事](　https://qiita.com/youtoy/items/258ac8ed5313f64402a3)をご参照ください。

## 作ったもの
p5.js で実装した内容は、以下のとおりです。こちらは、[p5.js Web Editor](https://editor.p5js.org/)上で動作させており、その中の sketch.js の処理内容です。

```javascript:sketch.js
let voice;
let inputText;

function setup() {
  createCanvas(400, 400);
  background(220);

  voice = createAudio();

  inputText = createInput();
  inputText.position(20, 20);

  const button = createButton("音声合成を実行");
  button.position(inputText.x + 5 + inputText.width, 20);
  button.mousePressed(synthesizeSpeech);
}

function synthesizeSpeech() {
  const text = inputText.value();

  if (text) {
    synthesizeTextToSpeech(text);
  } else {
    console.log("音声合成用のテキストが入力されていません");
  }
}

function synthesizeTextToSpeech(inputText) {
  fetch("https://api.rinna.co.jp/models/cttse/koeiro", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      text: inputText,
    }),
  })
    .then((response) => response.json())
    .then((data) => {
      voice.src = data.audio;
      console.log(voice);
      voice.play();
    });
}
```

### プログラムの補足
#### 「Koeiromap」まわりの処理
Koeiromap絡みの処理は、基本的には[冒頭で紹介していた前の記事](　https://qiita.com/youtoy/items/258ac8ed5313f64402a3)と同じ感じです。Koeiromap絡みの処理の補足をご覧になりたい場合は、[その記事](　https://qiita.com/youtoy/items/258ac8ed5313f64402a3)の説明をご参照ください。

#### p5.js関連の処理
ここでは、p5.js関連の処理のところだけ、軽く補足します。

setup() の中では、UI を準備している処理がほとんどです。
今回の簡素な UI の主要な部分として、テキストボックスとボタンがあります。それらの作成や配置場所の指定などを setup() の中で行っています。

残りの部分は、音声合成に関する処理です。
音声合成の処理について、p5.js用にしている部分だけ補足します。具体的には、前の記事では以下のように説明していた、「wav形式の音声データがbase64エンコードされた文字列」を再生する部分に関するものです。
![「wav形式の音声データがbase64エンコードされた文字列」を再生する](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/2476e601-ca5d-c804-4acf-f5d847e59e9e.png)

Koeiromap がレスポンスとして返してくる音のデータは、「wav形式の音声データがbase64エンコードされた文字列」となっており、JavaScript で軽く試した際は「HTMLAudioElement を使った処理」で対応していました。

p5.js でも同じ処理で対応できるのですが、p5.js用の処理で試すことにしようと思い「[createAudio()](https://p5js.org/reference/#/p5/createAudio)」を使いました。関連する部分をピックアップすると、以下のとおりです。

```javascript
let voice;
...
  voice = createAudio();
...
      voice.src = data.audio;
      voice.play();
```

この処理を使った場合、作成されるのは「[p5.MediaElement](https://p5js.org/reference/#/p5.MediaElement)」になります。
その p5.MediaElement に音声データを設定する部分や再生する部分は、`voice.src` や `voice.play()` の部分です（以下の画像は、p5.MediaElement のページで、それに関連する説明が書かれた部分です）。
![p5.MediaElement](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/3eed50dc-d22d-5fce-0cf8-2bc7803ece8f.png)

p5.MediaElement は 1つあれば良いので、 setup() のところで作成しています。また、音声合成の実行は、ボタンを押すたびに Koeiromap からのデータを受けとって再生する流れになるので、データを受けとった時に `voice.src`　に都度データを設定して作成するという形です。

### 使い方
作った内容を実行すると、以下の画像のような画面がキャンバスに描画されます。

![インターフェース](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/468221e7-626a-dba1-7f14-c0d6dfe5cd14.png)

あとは、テキストボックスに何か音声合成で読み上げさせたいテキストを入れて、それから「音声合成を実行」と書かれたボタンを押してください。
ボタン押下後、Koeiromap から音声データを受けとるまでの時間が少しかかるので、押した瞬間に読み上げがされる感じではないですが、少しのタイムラグがあった後に音声合成による読み上げが行われると思います。