[Google Cloud Text-to-Speech API(V1)] Javaでテキストを音声に変換する

Cloud Text-to-Speech API V1(Java)を使用して、
テキストを音声に変換する方法についてご紹介します。

:::note info
APIを利用する環境の準備から始める場合や、コードを実行する際は、
[⧉[Google Cloud Text-to-Speech API(V1)] JavaでText-to-Speech APIを使ってみる](https://qiita.com/doran/items/9edbd7d4ed11c5c4ec5f)
を参照ください。
:::

|No||目次|
|---|---|---|
|1||[テキストを変換(同期)](#1-テキストを変換同期)|
||1|[スコープ](#11-スコープ)|
||2|[実行](#12-実行)|
||3|[レスポンスの内容](#13-レスポンスの内容)|
|2||[長いテキストを変換(非同期)](#2-長いテキストを変換非同期)|
||1|[スコープ](#21-スコープ)|
||2|[実行](#22-実行)|
||3|[レスポンスの内容](#23-レスポンスの内容)|

## 1. テキストを変換(同期)
テキストを音声に変換します。
変換した音声はすぐ(同期的)に取得できます。
変換に時間がかかるような長いテキストは、[2. 長いテキストを変換(非同期)](#2-長いテキストを変換非同期)の方を利用ください。

### 1.1. スコープ
OAuth2.0でこのAPIを実行するには、以下のスコープを指定してください。
サービスアカウントで実行する場合はスコープの指定は不要です。
```
https://www.googleapis.com/auth/cloud-platform
```

### 1.2. 実行

```java
public static void main(String[] args) throws Exception{
    try(TextToSpeechClient client = getTextToSpeechClient()){
        SynthesizeSpeechRequest.Builder builder = SynthesizeSpeechRequest.newBuilder();
        
        SynthesisInput.Builder input = SynthesisInput.newBuilder();
        input.setText("こんにちは");
        builder.setInput(input.build());
        
        VoiceSelectionParams.Builder voice = VoiceSelectionParams.newBuilder();
        voice.setLanguageCode("ja");
        builder.setVoice(voice.build());
        
        AudioConfig.Builder audioConfig = AudioConfig.newBuilder();
        audioConfig.setAudioEncoding(AudioEncoding.MP3);
        builder.setAudioConfig(audioConfig.build());
        
        SynthesizeSpeechResponse response = client.synthesizeSpeech(builder.build());
        ByteString bytes = response.getAudioContent();
        try (OutputStream out = new FileOutputStream("output.mp3")) {
            out.write(bytes.toByteArray());
        }
    }
}
```
#### 1.2.1. HTTPリクエスト
POST:　https:\//texttospeech.googleapis.com/v1/text:synthesize
が実行されます。

#### 1.2.2. クエリパラメータ
クエリパラメータはありません。

#### 1.2.3. リクエストボディ
SynthesizeSpeechRequest.Builderのsetメソッドにより、リクエストボディを追加できます。
build()メソッドでSynthesizeSpeechRequestインスタンスを取得し、
getAudioContent()に渡します。

|メソッド|引数|説明|
|---|---|---|
|setInput|[SynthesisInput](#synthesisinput)|【必須】合成するテキストの入力情報|
|setVoice|[VoiceSelectionParams](#voiceselectionparams)|【必須】音声の情報|
|setAudioConfig|[AudioConfig](#audioconfig)|【必須】オーディオの構成|

#### SynthesisInput
|メソッド|引数|説明|
|---|---|---|
|setText|String|【setSsmlとどちらか一方が必須】<br>合成されるテキスト|
|setSsml|String|【setTextとどちらか一方が必須】<br>合成される[⧉ 音声合成マークアップ言語(SSML)](https://cloud.google.com/text-to-speech/docs/ssml?hl=ja)|

#### VoiceSelectionParams
|メソッド|引数|説明|
|---|---|---|
|setLanguageCode|String|【必須】合成するテキストの言語<br><br>[⧉ サポートされている音声と言語](https://cloud.google.com/text-to-speech/docs/voices?hl=ja)の「言語コード」を指定|
|setName|String|音声名<br><br>[⧉ サポートされている音声と言語](https://cloud.google.com/text-to-speech/docs/voices?hl=ja)の「音声名」を指定|
|setSsmlGender|[SsmlVoiceGender(enum)](#ssmlvoicegender)|声の優先性別|
|setCustomVoice|[CustomVoiceParams](#customvoiceparams)|カスタムボイス|

#### CustomVoiceParams
|メソッド|引数|説明|
|---|---|---|
|setModel|String||カスタム音声を合成するAutoMLモデル名|
|setReportedUsage|[ReportedUsage(enum)](#reportedusage)|報告される合成音声の使用法|

#### ReportedUsage
|定義値|内容|
|---|---|
|REPORTED_USAGE_UNSPECIFIED|未指定|
|REALTIME|合成されたオーディオがダウンロードできず一度しか使用できないシナリオ|
|OFFLINE|合成されたオーディオがダウンロード可能で再利用できるシナリオ|

#### AudioConfig
|メソッド|引数|説明|
|---|---|---|
|setAudioEncoding|[AudioEncoding(enum)](#audioencoding)|【必須】出力ファイル形式|
|setSpeakingRate|double|話す速度(0.25〜4.0)|
|setPitch|double|話す感覚(-20.0〜20.0)
|setVolumeGainDb|double|ボリュームゲイン(dB)(-96.0〜16.0)|
|setSampleRateHertz|int|合成サンプルレート(ヘルツ)|
|setAddEffectsProfileId|String|[音声プロファイルID](#音声プロファイルid)|

#### AudioEncoding
|定義値|内容|
|---|---|
|AUDIO_ENCODING_UNSPECIFIED|未指定|
|LINEAR16|非圧縮16ビット符号付きリトルエンディアンサンプル(リニアPCM)|
|MP3|32kbpsのMP3オーディオ<br>[長いテキストを変換(非同期)](#2-長いテキストを変換非同期)では**使用不可**|
|OGG_OPUS|Opusでエンコードされたオーディオをoggコンテナーにラップ<br>[長いテキストを変換(非同期)](#2-長いテキストを変換非同期)では**使用不可**|
|MULAW|G.711PCMU/mu-lawを使用して14ビットオーディオサンプルを圧縮した8ビットサンプル<br>[長いテキストを変換(非同期)](#2-長いテキストを変換非同期)では**使用不可**|
|ALAW|G.711PCMU/A-lawを使用して14ビットオーディオサンプルを圧縮した8ビットサンプル<br>[長いテキストを変換(非同期)](#2-長いテキストを変換非同期)では**使用不可**|

#### SsmlVoiceGender
|定義値|内容|
|---|---|
|SSML_VOICE_GENDER_UNSPECIFIED|性別不詳|
|MALE|男性の声|
|FEMALE|女性の声|
|NEUTRAL|性別を問わない声(未サポート)|

#### 音声プロファイルID
|音声プロファイルID|使用に適したデバイスの例|
|---|---|
|wearable-class-device|スマートウォッチやその他のウェアラブル|
|handset-class-device|スマートフォン|
|headphone-class-device|オーディオ再生用のイヤフォンやヘッドフォン|
|small-bluetooth-speaker-class-device|小型の家庭用スピーカー|
|medium-bluetooth-speaker-class-device|家庭用スマートスピーカー|
|large-home-entertainment-class-device|家庭用エンターテイメントシステムやスマートテレビ|
|large-automotive-class-device|車載用スピーカー|
|telephony-class-application|インタラクティブ音声レスポンス(IVR)システム|

### 1.3. レスポンスの内容
#### SynthesizeSpeechResponse
|メソッド|戻り値|説明|
|---|---|---|
|getAudioContent|ByteString|エンコードされたオーディオデータバイト|

## 2. 長いテキストを変換(非同期)
非同期で長いテキストを音声に変換します。

変換された音声ファイルはCloud Storageに出力されます。
変換される[音声ファイルの形式は、LINEAR16のみ](#audioencoding)対応されています。

出力するCloud StorageはAPIからアクセスできるように
保存先のプロジェクトにIAM権限の設定を忘れないでください。

### 2.1. スコープ
OAuth2.0でこのAPIを実行するには、以下のスコープを指定してください。
サービスアカウントで実行する場合はスコープの指定は不要です。
```
https://www.googleapis.com/auth/cloud-platform
```

### 2.2. 実行

```java
public static void main(String[] args) throws Exception{
    try(TextToSpeechLongAudioSynthesizeClient client = getTextToSpeechLongAudioSynthesizeClient()){
        SynthesizeLongAudioRequest.Builder builder = SynthesizeLongAudioRequest.newBuilder();
        builder.setParent(String.format(
            "projects/%s/locations/%s","プロジェクトID","ロケーションID"));
        builder.setOutputGcsUri(String.format(
            "gs://%s/%s","バケット名","出力するファイル名"));
        
        SynthesisInput.Builder input = SynthesisInput.newBuilder();
        input.setText("こんにちは");           //必須
        builder.setInput(input.build());
        
        VoiceSelectionParams.Builder voice = VoiceSelectionParams.newBuilder();
        voice.setName("ja-JP-Standard-A");  //必須
        voice.setLanguageCode("ja-JP");     //必須
        
        builder.setVoice(voice.build());
        
        AudioConfig.Builder audioConfig = AudioConfig.newBuilder();
        audioConfig.setAudioEncoding(AudioEncoding.LINEAR16); //必須
        builder.setAudioConfig(audioConfig.build());
        
        OperationFuture<SynthesizeLongAudioResponse,SynthesizeLongAudioMetadata>  response = client.synthesizeLongAudioAsync(builder.build());
        System.out.println(response.getName());
    }
}
```
#### 2.2.1. HTTPリクエスト
POST:　https:\//texttospeech.googleapis.com/v1/projects/{プロジェクトID}/locations/{ロケーションID}:synthesizeLongAudio
が実行されます。

#### 2.2.2. クエリパラメータ
クエリパラメータはありません。

#### 2.2.3. リクエストボディ
SynthesizeSpeechRequest.Builderのsetメソッドにより、リクエストボディを追加できます。
build()メソッドでSynthesizeSpeechRequestインスタンスを取得し、
getAudioContent()に渡します。

|メソッド|引数|説明|
|---|---|---|
|setInput|[SynthesisInput](#synthesisinput)|【必須】合成するテキストの入力情報|
|setVoice|[VoiceSelectionParams](#voiceselectionparams)|【必須】音声の情報|
|setAudioConfig|[AudioConfig](#audioconfig)|【必須】オーディオの構成|
|setOutputGcsUri|String|【必須】合成結果を出力するCloudStorageURI<br>形式：gs://{バケット名}/{出力するファイル名}|


### 2.3. レスポンスの内容
#### OperationFuture<SynthesizeLongAudioResponse,SynthesizeLongAudioMetadata>
|メソッド|戻り値|説明|
|---|---|---|
|getName|String|サーバーによって割り当てられた名前<br>形式："projects/{プロジェクトID}/locations/{ロケーションID}/operations/{オペレーションID}"|
|getMetadata|ApiFuture\<[SynthesizeLongAudioMetadata](#synthesizelongaudiometadata)\>|操作に関連付けられたサービス固有のメタデータ|
|isDone|boolean|操作がまだ進行中であるか|
|getPollingFuture|RetryingFuture\<[OperationSnapshot](#operationsnapshot)\>|失敗またはキャンセルされた場合の操作のエラー結果|
|get|SynthesizeLongAudioResponse|成功した場合の操作の通常の応答|

#### SynthesizeLongAudioMetadata
|メソッド|戻り値|説明|
|---|---|---|
|getStartTime|Timestamp|リクエストを受信した時刻|
|getProgressPercentage|double|最新の処理更新の進行状況(%)|

#### OperationSnapshot
|メソッド|戻り値|説明|
|---|---|---|
|getErrorCode|StatusCode|エラーコード|
|getErrorMessage|String|開発者向けのエラーメッセージ|

<br>
<br>
おしまい。。