voice-changerのAPIクライアント開発:Pythonでの音声変換リクエスト送信
1. はじめに:リアルタイム音声変換の課題と解決策
リアルタイム音声変換(Real-time Voice Changer)技術は、ライブ配信、オンライン会議、ゲームなど多様なシーンで活用されています。しかし、既存のGUIツールではカスタムアプリケーションへの組み込みが困難であり、開発者はAPI(Application Programming Interface)を介した音声変換リクエスト送信機能が必要とされています。本記事では、Pythonを用いてvoice-changerのAPIクライアントを開発し、音声変換リクエストを送信する方法について詳しく解説します。
1.1 この記事で学べること
- voice-changerのAPIインターフェース仕様
- Pythonによる音声入力デバイスの選択と録音
- WebSocketを用いたリアルタイム音声データ送信
- REST APIを介した音声変換リクエストの実装
- エラーハンドリングとパフォーマンス最適化手法
2. voice-changerのAPIインターフェース仕様
voice-changerは、WebSocketとREST APIの2種類のインターフェースを提供しています。それぞれの特徴と用途について説明します。
2.1 WebSocketインターフェース
WebSocketインターフェースは、リアルタイム性が要求されるシーンに適しています。サーバーとクライアント間で双方向の通信を確立し、低遅延で音声データを送受信することができます。
2.1.1 接続先URL
ws://<サーバーアドレス>:18888/test
2.1.2 イベント種類
| イベント名 | 送信元 | 説明 | データ形式 |
|---|---|---|---|
request_message | クライアント | 音声変換リクエスト | [timestamp: number, audio_data: bytes] |
response | サーバー | 音声変換結果 | [timestamp: number, audio_data: bytes, performance: object] |
2.2 REST APIインターフェース
REST APIインターフェースは、非リアルタイムな音声変換処理に適しています。HTTPリクエストを送信し、音声ファイルの変換結果を受け取ることができます。
2.2.1 エンドポイント
http://<サーバーアドレス>:18888/test
2.2.2 リクエスト/レスポンス形式
リクエスト:
{
"timestamp": 1622505600000,
"buffer": "<base64エンコードされた音声データ>"
}
レスポンス:
{
"timestamp": 1622505600000,
"changedVoiceBase64": "<base64エンコードされた変換後の音声データ>"
}
3. 開発環境の準備
3.1 必要なパッケージのインストール
音声変換APIクライアントを開発するために、以下のPythonパッケージが必要です。
pip install pyaudio socketio-client requests numpy
3.2 プロジェクトのクローン
voice-changerのリポジトリをクローンします。
git clone https://gitcode.com/gh_mirrors/vo/voice-changer
cd voice-changer
3.3 サーバーの起動
音声変換サーバーを起動します。デフォルトではポート18888で待ち受けます。
python server/MMVCServerSIO.py
4. 音声入力デバイスの選択
音声を録音するために、使用可能なオーディオデバイスの一覧を取得し、適切なデバイスを選択する必要があります。
4.1 オーディオデバイス一覧の取得
voice-changerに含まれるaudio_device_list.pyを使用して、使用可能なオーディオデバイスの一覧を取得します。
import pyaudio
import json
audio = pyaudio.PyAudio()
audio_input_devices = []
audio_output_devices = []
host_apis = []
for api_index in range(audio.get_host_api_count()):
host_apis.append(audio.get_host_api_info_by_index(api_index)['name'])
for x in range(0, audio.get_device_count()):
device = audio.get_device_info_by_index(x)
try:
deviceName = device['name'].encode('shift-jis').decode('utf-8')
except (UnicodeDecodeError, UnicodeEncodeError):
deviceName = device['name']
deviceIndex = device['index']
hostAPI = host_apis[device['hostApi']]
if device['maxInputChannels'] > 0:
audio_input_devices.append({"kind": "audioinput", "index": deviceIndex, "name": deviceName, "hostAPI": hostAPI})
if device['maxOutputChannels'] > 0:
audio_output_devices.append({"kind": "audiooutput", "index": deviceIndex, "name": deviceName, "hostAPI": hostAPI})
audio_devices = {
"audio_input_devices": audio_input_devices,
"audio_output_devices": audio_output_devices
}
print(json.dumps(audio_devices, indent=2, ensure_ascii=False))
実行結果は以下のようになります。
{
"audio_input_devices": [
{
"kind": "audioinput",
"index": 0,
"name": "Built-in Microphone",
"hostAPI": "Core Audio"
}
],
"audio_output_devices": [
{
"kind": "audiooutput",
"index": 1,
"name": "Built-in Output",
"hostAPI": "Core Audio"
}
]
}
4.2 デバイスインデックスの選択
入力デバイスと出力デバイスのインデックスをメモしておきます。ここでは、入力デバイスインデックスを0、出力デバイスインデックスを1とします。
5. WebSocketを用いたリアルタイム音声変換クライアント
WebSocketを使用して、リアルタイムで音声データをサーバーに送信し、変換された音声を受信するクライアントを実装します。
5.1 クライアントの実装
import argparse
import pyaudio
import struct
import socketio
import ssl
import time
import numpy as np
from datetime import datetime
# 定数の定義
BUFFER_SIZE = 2048 * 2 * 10
SAMPLING_RATE = 44100
GAIN = 10
class VoiceChangerClient:
def __init__(self, url, input_device_index, output_device_index=-1):
self.url = url
self.input_device_index = input_device_index
self.output_device_index = output_device_index
self.audio = pyaudio.PyAudio()
self.audio_input_stream = None
self.audio_output_stream = None
self.sio = None
self.connected = False
def setup_audio_streams(self):
# 入力ストリームの設定
self.audio_input_stream = self.audio.open(
format=pyaudio.paInt16,
channels=1,
rate=SAMPLING_RATE,
frames_per_buffer=BUFFER_SIZE,
input_device_index=self.input_device_index,
input=True
)
# 出力ストリームの設定 (指定されている場合)
if self.output_device_index >= 0:
self.audio_output_stream = self.audio.open(
format=pyaudio.paInt16,
channels=1,
rate=SAMPLING_RATE,
frames_per_buffer=BUFFER_SIZE,
output_device_index=self.output_device_index,
output=True
)
def connect(self):
# WebSocketクライアントの設定
self.sio = socketio.Client(ssl_verify=False)
# イベントハンドラの定義
@self.sio.event(namespace='/test')
def connect():
print(f'Connected to {self.url}')
self.connected = True
@self.sio.event(namespace='/test')
def disconnect():
print('Disconnected from server')
self.connected = False
@self.sio.event(namespace='/test')
def response(msg):
timestamp = msg[0]
response_time = time.time() * 1000 - timestamp
audio_data = msg[1]
performance = msg[2]
print(f"RT: {response_time:.2f} msec, Performance: {performance}")
# 音声データの処理と再生
if self.audio_output_stream:
# データのアンパックとゲイン調整
unpacked_data = np.array(struct.unpack('<%sh' % (len(audio_data) // struct.calcsize('<h')), audio_data))
unpacked_data = unpacked_data * GAIN
packed_data = struct.pack('<%sh' % len(unpacked_data), *unpacked_data)
# 音声の再生
self.audio_output_stream.write(packed_data)
# サーバーへの接続
self.sio.connect(self.url)
def start(self):
self.setup_audio_streams()
self.connect()
try:
while self.connected:
# 音声データの録音
in_wav = self.audio_input_stream.read(BUFFER_SIZE, exception_on_overflow=False)
# サーバーへの送信
if self.connected:
self.sio.emit('request_message', [time.time() * 1000, in_wav], namespace="/test")
# 短い待機
time.sleep(0.01)
except KeyboardInterrupt:
print("Stopping client...")
finally:
self.cleanup()
def cleanup(self):
# ストリームのクローズ
if self.audio_input_stream:
self.audio_input_stream.stop_stream()
self.audio_input_stream.close()
if self.audio_output_stream:
self.audio_output_stream.stop_stream()
self.audio_output_stream.close()
# オーディオインスタンスの終了
self.audio.terminate()
# WebSocket接続の切断
if self.sio and self.sio.connected:
self.sio.disconnect()
def main():
parser = argparse.ArgumentParser(description='Voice Changer WebSocket Client')
parser.add_argument('--url', type=str, default='http://localhost:18888', help='Server URL')
parser.add_argument('--input', type=int, required=True, help='Input device index')
parser.add_argument('--output', type=int, default=-1, help='Output device index')
args = parser.parse_args()
client = VoiceChangerClient(args.url, args.input, args.output)
client.start()
if __name__ == '__main__':
main()
5.2 クライアントの実行
以下のコマンドを実行して、クライアントを起動します。
python voice_changer_client.py --input 0 --output 1
ここで、--input 0は入力デバイスのインデックス、--output 1は出力デバイスのインデックスを指定しています。
6. REST APIを用いた音声変換クライアント
REST APIを使用して、音声ファイルをアップロードし、変換された音声を受け取るクライアントを実装します。
6.1 クライアントの実装
import requests
import base64
import struct
import numpy as np
import wave
import argparse
class VoiceChangerRESTClient:
def __init__(self, base_url):
self.base_url = base_url
self.endpoint = f"{self.base_url}/test"
def convert_audio(self, audio_file_path, output_file_path):
# 音声ファイルの読み込み
with wave.open(audio_file_path, 'rb') as wf:
params = wf.getparams()
audio_data = wf.readframes(params.nframes)
# 音声データのBase64エンコード
audio_base64 = base64.b64encode(audio_data).decode('utf-8')
# リクエストデータの作成
request_data = {
"timestamp": int(time.time() * 1000),
"buffer": audio_base64
}
# APIリクエストの送信
response = requests.post(self.endpoint, json=request_data)
response.raise_for_status()
# レスポンスデータの処理
result = response.json()
converted_audio_base64 = result["changedVoiceBase64"]
converted_audio_data = base64.b64decode(converted_audio_base64)
# 変換後の音声ファイルの保存
with wave.open(output_file_path, 'wb') as wf:
wf.setparams(params)
wf.writeframes(converted_audio_data)
print(f"Converted audio saved to {output_file_path}")
def main():
parser = argparse.ArgumentParser(description='Voice Changer REST API Client')
parser.add_argument('--url', type=str, default='http://localhost:18888', help='Server URL')
parser.add_argument('--input', type=str, required=True, help='Input audio file path')
parser.add_argument('--output', type=str, required=True, help='Output audio file path')
args = parser.parse_args()
client = VoiceChangerRESTClient(args.url)
client.convert_audio(args.input, args.output)
if __name__ == '__main__':
import time
main()
6.2 クライアントの実行
以下のコマンドを実行して、音声ファイルを変換します。
python voice_changer_rest_client.py --input input.wav --output output.wav
7. エラーハンドリングとパフォーマンス最適化
7.1 エラーハンドリングの実装
音声変換クライアントには、さまざまなエラーが発生する可能性があります。代表的なエラーとそのハンドリング方法を紹介します。
# WebSocketクライアントのエラーハンドリング例
@self.sio.event(namespace='/test')
def connect_error(data):
print(f"Connection error: {data}")
self.connected = False
# 再接続の試行
while not self.connected:
try:
print("Attempting to reconnect...")
self.sio.connect(self.url)
time.sleep(5)
except Exception as e:
print(f"Reconnection failed: {e}")
time.sleep(5)
7.2 パフォーマンス最適化の手法
リアルタイム音声変換では低遅延が要求されます。以下はパフォーマンスを向上させるための手法です。
-
バッファサイズの調整
- バッファサイズを小さくすることで遅延を減少させることができますが、音声の途切れが発生する可能性があります。適切なサイズを見つけるためには実験が必要です。
-
非同期処理の導入
- 音声データの送受信を非同期で行うことで、メインスレッドの負荷を軽減します。
# 非同期で音声データを送信する例
import threading
def send_audio_data(self):
while self.connected:
if self.audio_queue.qsize() > 0:
audio_data = self.audio_queue.get()
self.sio.emit('request_message', [time.time() * 1000, audio_data], namespace="/test")
time.sleep(0.001)
# キューとスレッドの初期化
self.audio_queue = queue.Queue()
self.send_thread = threading.Thread(target=self.send_audio_data, daemon=True)
self.send_thread.start()
- データ圧縮
- 音声データを圧縮して送信することで、ネットワーク帯域を節約し、遅延を減少させることができます。
8. 応用例:音声変換を組み込んだアプリケーション
8.1 マイク入力をリアルタイムで変換するアプリケーション
先に実装したWebSocketクライアントを使用して、マイク入力をリアルタイムで変換するアプリケーションを作成できます。これはオンライン会議やゲームでの使用に適しています。
8.2 音声ファイルの一括変換ツール
REST APIクライアントを拡張して、複数の音声ファイルを一括で変換するツールを作成することができます。
def batch_convert(self, input_dir, output_dir):
import os
os.makedirs(output_dir, exist_ok=True)
for filename in os.listdir(input_dir):
if filename.endswith('.wav'):
input_path = os.path.join(input_dir, filename)
output_path = os.path.join(output_dir, filename)
self.convert_audio(input_path, output_path)
print(f"Converted: {filename}")
9. まとめと今後の展望
本記事では、voice-changerのAPIクライアントをPythonで開発する方法を詳しく解説しました。WebSocketを用いたリアルタイム音声変換とREST APIを用いたファイル変換の両方について説明し、エラーハンドリングやパフォーマンス最適化の手法も紹介しました。
今後の展望としては、以下のような機能追加が考えられます。
- 複数の音声変換モデルを切り替える機能
- 音声品質設定の調整機能
- GUIによる操作インターフェースの追加
これらの機能を実装することで、より使いやすく汎用的な音声変換クライアントを開発することができます。
10. 参考文献
- voice-changer GitHub Repository
- PyAudio Documentation
- Socket.IO Client Documentation
- FastAPI Documentation
この記事が、voice-changerのAPIクライアント開発に役立つことを願っています。何か問題があれば、ぜひissueやコメントをお寄せください。
最後まで読んでいただきありがとうございます!
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



