💬
Google Text-to-Speech APIのPCMフォーマット
Google Cloud Platform (GCP)のText-to-Speech (TTS) APIを使用して、DartでPCMフォーマットの音声ファイルを生成する方法を紹介します。
特に新規性は無いのですが、LINEAR16(PCM)を要求したときに送られてくるコンテナフォーマットはWAVである、という点は落とし穴です。
pubspec.yaml
空のプロジェクトを作成し、以下の依存関係を追加してください。
pubspec.yaml
dependencies:
googleapis_auth: ^1.4.1
http: ^1.1.0
追加したら、dart pub get
を実行して依存関係を取得します。
main.dart
プログラムはシンプルです。サービス・クレデンシャルの保存場所を環境変GOOGLE_APPLICATION_CREDENTIALS
から読み込み、APIにリクエストを送信し、レスポンスをファイルに保存します。
main.dart
import 'dart:io';
import 'package:http/http.dart' as http;
import 'package:googleapis_auth/auth_io.dart';
import 'dart:convert';
// GCP Text-to-Speech API Endpoint
const String _ttsApiEndpoint =
'https://texttospeech.googleapis.com/v1/text:synthesize';
// Scope of the auth platform
const List<String> _scopes = ['https://www.googleapis.com/auth/cloud-platform'];
Future<void> synthesizeTextToPcm(String text, String outputFilename) async {
try {
// Get service account credentials from environment variable
// Make sure to set the environment variable before running the script
// Example: export GOOGLE_APPLICATION_CREDENTIALS="/path/to/your/service-account-file.json"
late String serviceAccountJson;
try {
serviceAccountJson = File(
Platform.environment['GOOGLE_APPLICATION_CREDENTIALS']!,
).readAsStringSync();
} catch (e) {
print('Error reading service credential file from local file system: $e');
print('Check the environment variable GOOGLE_APPLICATION_CREDENTIALS.');
return;
}
late AccessCredentials credentials;
try {
credentials = await obtainAccessCredentialsViaServiceAccount(
ServiceAccountCredentials.fromJson(jsonDecode(serviceAccountJson)),
_scopes,
http.Client(),
);
} catch (e) {
print('Error obtaining access privilege from server: $e');
print('Check whether the credential file is valid or not.');
return;
}
// Request body for the TTS API
final Map<String, dynamic> requestBody = {
'input': {'text': text},
'voice': {
'languageCode': 'ja_JP', 'ssmlGender': 'MALE',
},
'audioConfig': {
'audioEncoding': 'LINEAR16', // PCM
'sampleRateHertz': 24000,
'speakingRate': 1.0,
},
};
// HTTP POST request to the TTS API
final response = await http.post(
Uri.parse(_ttsApiEndpoint),
headers: {
'Authorization': 'Bearer ${credentials.accessToken.data}',
'Content-Type': 'application/json; charset=utf-8',
},
body: jsonEncode(requestBody),
);
if (response.statusCode == 200) {
// Parse the response
final Map<String, dynamic> responseData = jsonDecode(response.body);
final String audioContentBase64 = responseData['audioContent'];
// Decode the base64 audio content and write to file
final file = File(outputFilename);
await file.writeAsBytes(base64Decode(audioContentBase64));
print('Audio file is saved in $outputFilename.');
} else {
print('Failed to request API : ${response.statusCode}');
print('Error response: ${response.body}');
}
} catch (e) {
print('Unhandled Error: $e');
}
}
void main() async {
final outputFileName = 'dart_output.wav';
final textToConvert = 'こんにちは。';
await synthesizeTextToPcm(textToConvert, outputFileName);
}
サービス・クレデンシャルのJSONファイルを作成し、環境変数GOOGLE_APPLICATION_CREDENTIALS
にそのパスを設定してください。
export GOOGLE_APPLICATION_CREDENTIALS="/path/to/your/service-account-file.json"
プログラムを実行すると、dart_output.wav
というファイルが生成されます。オーディオ信号のエンコード形式はPCMです。しかしWAVコンテナに格納されているため、そのままWAVファイルとして再生できます。
LINEAR16(PCM)のコンテナ形式がWAVであることは、公式ドキュメントであるCloud Text-to-Speech basicsの冒頭に明記されています。
しかしながら、提供されるサンプル・コードはデータ形式がMP3であること、GeminiにPCMの例を訪ねると、拡張子を.pcmとして保存するコードを生成することから、「英語ドキュメントを最初から最後まで読んでからコーディングする人」以外は足を取られる可能性があります。
Discussion