(この記事は Node.js の Advent Calendar 2025 の記事【2つ目】にする予定です)
はじめに
この記事は、以下の記事を書いた時にも扱った VOICEVOX の話です。
●ブラウザの JavaScript で VOICEVOX をシンプルに扱う(HTML + JavaScript での簡単なお試し) - Qiita
https://qiita.com/youtoy/items/9caab75e1ec0565cef60
上記の記事ではブラウザ上の処理で VOICEVOX を扱いましたが、今回は Node.js を使います。また、VOICEVOX の出力ファイルは WAV になりますが、それを FFmpeg を使って MP3 に変換します(変換処理は、Node.js の処理で行います)。
さっそく試す
音声合成と WAV での保存
まずは FFmpeg による変換を行わない、音声合成結果を WAV で保存する処理を試します。
用いるコード
用いるコードは、以下のとおりです、
import fs from "fs";
const BASE_URL = "http://127.0.0.1:50021";
async function synthesizeSpeech(text, speaker = 3, outputPath = "output.wav") {
try {
console.log("クエリを作成中");
const queryResponse = await fetch(
`${BASE_URL}/audio_query?text=${encodeURIComponent(
text
)}&speaker=${speaker}`,
{ method: "POST" }
);
if (!queryResponse.ok) {
throw new Error(`クエリ作成失敗: ${queryResponse.status}`);
}
const audioQuery = await queryResponse.json();
console.log("音声合成を実行中");
const synthesisResponse = await fetch(
`${BASE_URL}/synthesis?speaker=${speaker}`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(audioQuery),
}
);
if (!synthesisResponse.ok) {
throw new Error(`音声合成失敗: ${synthesisResponse.status}`);
}
const audioBuffer = await synthesisResponse.arrayBuffer();
fs.writeFileSync(outputPath, Buffer.from(audioBuffer));
console.log(`音声ファイルを保存しました: ${outputPath}`);
} catch (error) {
console.error("エラーが発生しました:", error.message);
}
}
synthesizeSpeech("VOICEVOXでの音声合成です。");
// synthesizeSpeech("VOICEVOXでの音声合成です。", 1, "output01.wav");
基本的な処理の流れは、Node.js の標準機能の fetch() を使った 2段階の処理と、WAV の保存の処理です。「2段階の処理」というのは、VOICEVOX の「音声合成用のクエリの処理」と「音声合成の処理」です。
上記では、 synthesizeSpeech("VOICEVOXでの音声合成です。") という音声合成用のテキストを指定するだけの使い方もできます。また synthesizeSpeech("VOICEVOXでの音声合成です。", 1, "output01.wav") という使い方で「話者選択と出力ファイル名の指定」も行えます。
音声合成用のテキストのみ指定した場合は、話者は「ずんだもん(ID = 3)」とし、出力ファイル名は「output.wav」となるようにしています。
参照した情報
VOICEVOX を使った処理に関しては、以下のドキュメントなどを参照しました。
●voicevox_engine API Document
https://voicevox.github.io/voicevox_engine/api/
●VOICEVOX/voicevox_engine: 無料で使える中品質なテキスト読み上げソフトウェア、VOICEVOXの音声合成エンジン
https://github.com/VOICEVOX/voicevox_engine
音声合成と MP3 への変換
以下で、Node.js の処理で FFmpeg を使った WAV ⇒ MP3 の変換も行っています。
import fs from "fs";
import { exec } from "child_process";
import { promisify } from "util";
const BASE_URL = "http://127.0.0.1:50021";
const execAsync = promisify(exec);
async function synthesizeSpeech(
text,
speaker = 3,
outputWavPath = "output.wav",
outputMp3Path = null
) {
try {
console.log("クエリを作成中");
const queryResponse = await fetch(
`${BASE_URL}/audio_query?text=${encodeURIComponent(
text
)}&speaker=${speaker}`,
{ method: "POST" }
);
if (!queryResponse.ok) {
throw new Error(`クエリ作成失敗: ${queryResponse.status}`);
}
const audioQuery = await queryResponse.json();
console.log("音声合成を実行中");
const synthesisResponse = await fetch(
`${BASE_URL}/synthesis?speaker=${speaker}`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(audioQuery),
}
);
if (!synthesisResponse.ok) {
throw new Error(`音声合成失敗: ${synthesisResponse.status}`);
}
const audioBuffer = await synthesisResponse.arrayBuffer();
fs.writeFileSync(outputWavPath, Buffer.from(audioBuffer));
console.log(`WAVファイルを保存しました: ${outputWavPath}`);
if (outputMp3Path) {
console.log("mp3 に変換中");
const cmd = `ffmpeg -y -i "${outputWavPath}" "${outputMp3Path}"`;
await execAsync(cmd);
console.log(`MP3ファイルを保存しました: ${outputMp3Path}`);
}
} catch (error) {
console.error("エラーが発生しました:", error.message || error);
}
}
synthesizeSpeech(
"VOICEVOXでの音声合成です。",
3,
"output_01.wav",
"output_01.mp3"
);
FFmpeg の実行は、Node.js標準機能の「Child process」を使っています。
FFmpeg を使ったコマンドは、以下のパラメータ指定を行わないシンプルな内容です。
ffmpeg -y -i 【入力ファイル(WAV)】 【出力ファイル(MP3)】
上記を実行することで、音声合成の結果を MP3 で保存できることが確認できました。