Skip to main content
Glama
kentaro
by kentaro

aivis-speech-synthesis

Convert text to high-quality speech using customizable parameters like speaker ID, style, speed, pitch, and volume. Integrate the tool via the AivisSpeech MCP Server API for AI-powered voice synthesis.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
intonation_scaleNoイントネーションのスケール(1.0が標準)
output_sampling_rateNo出力音声のサンプリングレート(Hz)
pitch_scaleNo音高のスケール(1.0が標準)
post_phoneme_lengthNo音声の末尾の無音時間(秒)
pre_phoneme_lengthNo音声の先頭の無音時間(秒)
speaker_idNo音声合成に使用するスピーカーのID
speed_scaleNo話速のスケール(1.0が標準)
style_idNo音声合成に使用するスタイルのID
textYes音声合成するテキスト
volume_scaleNo音量のスケール(1.0が標準)

Implementation Reference

  • Registers the MCP tool 'aivis-speech-synthesis' using mcpServer.tool(), defining schema and handler inline.
    this.mcpServer.tool( MCP_MODEL_ID, { text: z.string().describe('音声合成するテキスト'), speaker_id: z.number().optional().describe('音声合成に使用するスピーカーのID'), style_id: z.number().optional().describe('音声合成に使用するスタイルのID'), speed_scale: z.number().min(0.5).max(2.0).optional().default(1.0).describe('話速のスケール(1.0が標準)'), pitch_scale: z.number().min(0.5).max(2.0).optional().default(1.0).describe('音高のスケール(1.0が標準)'), intonation_scale: z.number().min(0.0).max(2.0).optional().default(1.0).describe('イントネーションのスケール(1.0が標準)'), volume_scale: z.number().min(0.0).max(2.0).optional().default(1.0).describe('音量のスケール(1.0が標準)'), pre_phoneme_length: z.number().min(0.0).max(1.0).optional().default(0.1).describe('音声の先頭の無音時間(秒)'), post_phoneme_length: z.number().min(0.0).max(1.0).optional().default(0.1).describe('音声の末尾の無音時間(秒)'), output_sampling_rate: z.number().optional().default(24000).describe('出力音声のサンプリングレート(Hz)'), }, async (params, extra) => { try { // デフォルトのスピーカーIDを.envから取得 const defaultSpeakerId = parseInt(process.env.AIVIS_SPEECH_SPEAKER_ID || '888753760', 10); // AivisSpeech APIリクエストの作成 const synthesisRequest: SynthesisRequest = { text: params.text, speaker: params.speaker_id || defaultSpeakerId, style_id: params.style_id, speed_scale: params.speed_scale, pitch_scale: params.pitch_scale, intonation_scale: params.intonation_scale, volume_scale: params.volume_scale, pre_phoneme_length: params.pre_phoneme_length, post_phoneme_length: params.post_phoneme_length, output_sampling_rate: params.output_sampling_rate, }; try { // AivisSpeech APIを呼び出して音声合成を実行 await aivisSpeechService.synthesize(synthesisRequest); // 正しいMCPレスポンス形式で返す return { content: [ { type: "text", text: `「${params.text}」の音声合成が完了しました` } ] }; } catch (synthesisError) { console.error('Synthesis error:', synthesisError); const errorMessage = synthesisError instanceof Error ? synthesisError.message : '音声合成処理中にエラーが発生しました'; return { content: [{ type: "text", text: `音声合成に失敗しました: ${errorMessage}` }], isError: true }; } } catch (error) { console.error('Request handling error:', error); const errorMessage = error instanceof Error ? error.message : '音声合成リクエストの処理中にエラーが発生しました'; return { content: [{ type: "text", text: `音声合成に失敗しました: ${errorMessage}` }], isError: true }; } } );
  • Zod input schema for the speech synthesis parameters.
    { text: z.string().describe('音声合成するテキスト'), speaker_id: z.number().optional().describe('音声合成に使用するスピーカーのID'), style_id: z.number().optional().describe('音声合成に使用するスタイルのID'), speed_scale: z.number().min(0.5).max(2.0).optional().default(1.0).describe('話速のスケール(1.0が標準)'), pitch_scale: z.number().min(0.5).max(2.0).optional().default(1.0).describe('音高のスケール(1.0が標準)'), intonation_scale: z.number().min(0.0).max(2.0).optional().default(1.0).describe('イントネーションのスケール(1.0が標準)'), volume_scale: z.number().min(0.0).max(2.0).optional().default(1.0).describe('音量のスケール(1.0が標準)'), pre_phoneme_length: z.number().min(0.0).max(1.0).optional().default(0.1).describe('音声の先頭の無音時間(秒)'), post_phoneme_length: z.number().min(0.0).max(1.0).optional().default(0.1).describe('音声の末尾の無音時間(秒)'), output_sampling_rate: z.number().optional().default(24000).describe('出力音声のサンプリングレート(Hz)'), },
  • Inline handler function that processes params, calls aivisSpeechService.synthesize(), and formats MCP response.
    async (params, extra) => { try { // デフォルトのスピーカーIDを.envから取得 const defaultSpeakerId = parseInt(process.env.AIVIS_SPEECH_SPEAKER_ID || '888753760', 10); // AivisSpeech APIリクエストの作成 const synthesisRequest: SynthesisRequest = { text: params.text, speaker: params.speaker_id || defaultSpeakerId, style_id: params.style_id, speed_scale: params.speed_scale, pitch_scale: params.pitch_scale, intonation_scale: params.intonation_scale, volume_scale: params.volume_scale, pre_phoneme_length: params.pre_phoneme_length, post_phoneme_length: params.post_phoneme_length, output_sampling_rate: params.output_sampling_rate, }; try { // AivisSpeech APIを呼び出して音声合成を実行 await aivisSpeechService.synthesize(synthesisRequest); // 正しいMCPレスポンス形式で返す return { content: [ { type: "text", text: `「${params.text}」の音声合成が完了しました` } ] }; } catch (synthesisError) { console.error('Synthesis error:', synthesisError); const errorMessage = synthesisError instanceof Error ? synthesisError.message : '音声合成処理中にエラーが発生しました'; return { content: [{ type: "text", text: `音声合成に失敗しました: ${errorMessage}` }], isError: true }; } } catch (error) { console.error('Request handling error:', error); const errorMessage = error instanceof Error ? error.message : '音声合成リクエストの処理中にエラーが発生しました'; return { content: [{ type: "text", text: `音声合成に失敗しました: ${errorMessage}` }], isError: true }; } }
  • synthesize() method implementing the core speech synthesis by calling AivisSpeech API endpoints /audio_query and /synthesis, generating WAV file, and playing it.
    async synthesize(params: SynthesisRequest): Promise<SynthesisResponse> { try { // 1. まずaudio_queryを取得 const queryUrl = `${this.baseUrl}/audio_query`; const queryResponse = await axios.post( queryUrl, null, { params: { text: params.text, speaker: params.speaker } } ); // 2. audio_queryを取得したら、必要に応じてパラメータを更新 const audioQuery = queryResponse.data; if (params.style_id !== undefined) { audioQuery.style_id = params.style_id; } if (params.speed_scale !== undefined) { audioQuery.speed_scale = params.speed_scale; } if (params.pitch_scale !== undefined) { audioQuery.pitch_scale = params.pitch_scale; } if (params.intonation_scale !== undefined) { audioQuery.intonation_scale = params.intonation_scale; } if (params.volume_scale !== undefined) { audioQuery.volume_scale = params.volume_scale; } if (params.pre_phoneme_length !== undefined) { audioQuery.pre_phoneme_length = params.pre_phoneme_length; } if (params.post_phoneme_length !== undefined) { audioQuery.post_phoneme_length = params.post_phoneme_length; } if (params.output_sampling_rate !== undefined) { audioQuery.output_sampling_rate = params.output_sampling_rate; } // 3. 更新したaudio_queryを使って音声合成 const synthesisUrl = `${this.baseUrl}/synthesis`; const synthesisResponse = await axios.post<ArrayBuffer>( synthesisUrl, audioQuery, { responseType: 'arraybuffer', params: { speaker: params.speaker }, headers: { 'Accept': 'audio/wav', 'Content-Type': 'application/json' } } ); // 音声データを一時ファイルに保存して再生 const audioData = synthesisResponse.data; const tempDir = path.join(process.cwd(), 'temp'); // 一時ディレクトリが存在しない場合は作成 if (!fs.existsSync(tempDir)) { fs.mkdirSync(tempDir, { recursive: true }); } // 一時ファイルのパスを生成 const audioFilePath = path.join(tempDir, `speech_${Date.now()}.wav`); // 音声データをファイルに書き込み fs.writeFileSync(audioFilePath, Buffer.from(audioData)); // node-wav-playerを使って音声を再生(メディアプレイヤーが立ち上がらない) try { await wavPlayer.play({ path: audioFilePath, sync: false // 非同期再生 }); } catch (playError) { console.error('Error playing audio:', playError); } return { audioData: synthesisResponse.data }; } catch (error) { console.error('Error in synthesize:', error); this.logDetailedError(error); throw new Error(`音声合成に失敗しました: ${this.getErrorMessage(error)}`); } }
  • SynthesisRequest interface defining the parameters passed to the synthesize helper.
    export interface SynthesisRequest { /** * 合成するテキスト */ text: string; /** * 話者ID */ speaker: number; /** * スタイルID */ style_id?: number; /** * 話速のスケール(1.0が標準) */ speed_scale?: number; /** * 音高のスケール(1.0が標準) */ pitch_scale?: number; /** * イントネーションのスケール(1.0が標準) */ intonation_scale?: number; /** * 音量のスケール(1.0が標準) */ volume_scale?: number; /** * 音声の先頭の無音時間(秒) */ pre_phoneme_length?: number; /** * 音声の末尾の無音時間(秒) */ post_phoneme_length?: number; /** * 出力音声のサンプリングレート(Hz) */ output_sampling_rate?: number; }

Other Tools

Related Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/kentaro/aivis-speech-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server