audio: use resamply for audio resampling
This commit is contained in:
@@ -40,7 +40,6 @@ async def main():
|
|||||||
"Respond bot",
|
"Respond bot",
|
||||||
DailyParams(
|
DailyParams(
|
||||||
audio_out_enabled=True,
|
audio_out_enabled=True,
|
||||||
audio_out_sample_rate=16000,
|
|
||||||
vad_enabled=True,
|
vad_enabled=True,
|
||||||
vad_analyzer=SileroVADAnalyzer(),
|
vad_analyzer=SileroVADAnalyzer(),
|
||||||
vad_audio_passthrough=True,
|
vad_audio_passthrough=True,
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ dependencies = [
|
|||||||
"protobuf~=4.25.4",
|
"protobuf~=4.25.4",
|
||||||
"pydantic~=2.8.2",
|
"pydantic~=2.8.2",
|
||||||
"pyloudnorm~=0.1.1",
|
"pyloudnorm~=0.1.1",
|
||||||
"scipy~=1.14.1",
|
"resampy~=0.4.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[project.urls]
|
[project.urls]
|
||||||
|
|||||||
@@ -7,15 +7,14 @@
|
|||||||
import audioop
|
import audioop
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import pyloudnorm as pyln
|
import pyloudnorm as pyln
|
||||||
from scipy import signal
|
import resampy
|
||||||
|
|
||||||
|
|
||||||
def resample_audio(audio: bytes, original_rate: int, target_rate: int) -> bytes:
|
def resample_audio(audio: bytes, original_rate: int, target_rate: int) -> bytes:
|
||||||
if original_rate == target_rate:
|
if original_rate == target_rate:
|
||||||
return audio
|
return audio
|
||||||
audio_data = np.frombuffer(audio, dtype=np.int16)
|
audio_data = np.frombuffer(audio, dtype=np.int16)
|
||||||
num_samples = int(len(audio) * target_rate / original_rate)
|
resampled_audio = resampy.resample(audio_data, original_rate, target_rate)
|
||||||
resampled_audio = signal.resample(audio_data, num_samples)
|
|
||||||
return resampled_audio.astype(np.int16).tobytes()
|
return resampled_audio.astype(np.int16).tobytes()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ from typing import AsyncGenerator, Optional
|
|||||||
from loguru import logger
|
from loguru import logger
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
from pipecat.audio.utils import resample_audio
|
||||||
from pipecat.frames.frames import (
|
from pipecat.frames.frames import (
|
||||||
ErrorFrame,
|
ErrorFrame,
|
||||||
Frame,
|
Frame,
|
||||||
@@ -45,7 +46,7 @@ class AWSTTSService(TTSService):
|
|||||||
aws_access_key_id: str,
|
aws_access_key_id: str,
|
||||||
region: str,
|
region: str,
|
||||||
voice_id: str = "Joanna",
|
voice_id: str = "Joanna",
|
||||||
sample_rate: int = 16000,
|
sample_rate: int = 24000,
|
||||||
params: InputParams = InputParams(),
|
params: InputParams = InputParams(),
|
||||||
**kwargs,
|
**kwargs,
|
||||||
):
|
):
|
||||||
@@ -178,7 +179,8 @@ class AWSTTSService(TTSService):
|
|||||||
"OutputFormat": "pcm",
|
"OutputFormat": "pcm",
|
||||||
"VoiceId": self._voice_id,
|
"VoiceId": self._voice_id,
|
||||||
"Engine": self._settings["engine"],
|
"Engine": self._settings["engine"],
|
||||||
"SampleRate": str(self._settings["sample_rate"]),
|
# AWS only supports 8000 and 16000 for PCM. We select 16000.
|
||||||
|
"SampleRate": "16000",
|
||||||
}
|
}
|
||||||
|
|
||||||
# Filter out None values
|
# Filter out None values
|
||||||
@@ -198,7 +200,8 @@ class AWSTTSService(TTSService):
|
|||||||
chunk = audio_data[i : i + chunk_size]
|
chunk = audio_data[i : i + chunk_size]
|
||||||
if len(chunk) > 0:
|
if len(chunk) > 0:
|
||||||
await self.stop_ttfb_metrics()
|
await self.stop_ttfb_metrics()
|
||||||
frame = TTSAudioRawFrame(chunk, self._settings["sample_rate"], 1)
|
resampled = resample_audio(chunk, 16000, self._settings["sample_rate"])
|
||||||
|
frame = TTSAudioRawFrame(resampled, self._settings["sample_rate"], 1)
|
||||||
yield frame
|
yield frame
|
||||||
|
|
||||||
yield TTSStoppedFrame()
|
yield TTSStoppedFrame()
|
||||||
|
|||||||
@@ -151,19 +151,19 @@ class XTTSService(TTSService):
|
|||||||
async for chunk in r.content.iter_chunked(1024):
|
async for chunk in r.content.iter_chunked(1024):
|
||||||
if len(chunk) > 0:
|
if len(chunk) > 0:
|
||||||
await self.stop_ttfb_metrics()
|
await self.stop_ttfb_metrics()
|
||||||
# Append new chunk to the buffer
|
# Append new chunk to the buffer.
|
||||||
buffer.extend(chunk)
|
buffer.extend(chunk)
|
||||||
|
|
||||||
# Check if buffer has enough data for processing
|
# Check if buffer has enough data for processing.
|
||||||
while (
|
while (
|
||||||
len(buffer) >= 48000
|
len(buffer) >= 48000
|
||||||
): # Assuming at least 0.5 seconds of audio data at 24000 Hz
|
): # Assuming at least 0.5 seconds of audio data at 24000 Hz
|
||||||
# Process the buffer up to a safe size for resampling
|
# Process the buffer up to a safe size for resampling.
|
||||||
process_data = buffer[:48000]
|
process_data = buffer[:48000]
|
||||||
# Remove processed data from buffer
|
# Remove processed data from buffer.
|
||||||
buffer = buffer[48000:]
|
buffer = buffer[48000:]
|
||||||
|
|
||||||
# Resample the audio from 24000 Hz
|
# XTTS uses 24000 so we need to resample to our desired rate.
|
||||||
resampled_audio = resample_audio(
|
resampled_audio = resample_audio(
|
||||||
bytes(process_data), 24000, self._sample_rate
|
bytes(process_data), 24000, self._sample_rate
|
||||||
)
|
)
|
||||||
@@ -171,7 +171,7 @@ class XTTSService(TTSService):
|
|||||||
frame = TTSAudioRawFrame(resampled_audio, self._sample_rate, 1)
|
frame = TTSAudioRawFrame(resampled_audio, self._sample_rate, 1)
|
||||||
yield frame
|
yield frame
|
||||||
|
|
||||||
# Process any remaining data in the buffer
|
# Process any remaining data in the buffer.
|
||||||
if len(buffer) > 0:
|
if len(buffer) > 0:
|
||||||
resampled_audio = resample_audio(bytes(buffer), 24000, self._sample_rate)
|
resampled_audio = resample_audio(bytes(buffer), 24000, self._sample_rate)
|
||||||
frame = TTSAudioRawFrame(resampled_audio, self._sample_rate, 1)
|
frame = TTSAudioRawFrame(resampled_audio, self._sample_rate, 1)
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ pydantic~=2.8.2
|
|||||||
pyloudnorm~=0.1.1
|
pyloudnorm~=0.1.1
|
||||||
pyht~=0.1.4
|
pyht~=0.1.4
|
||||||
python-dotenv~=1.0.1
|
python-dotenv~=1.0.1
|
||||||
scipy~=1.14.1
|
resampy~=0.4.3
|
||||||
silero-vad~=5.1
|
silero-vad~=5.1
|
||||||
together~=1.2.7
|
together~=1.2.7
|
||||||
transformers~=4.44.0
|
transformers~=4.44.0
|
||||||
|
|||||||
Reference in New Issue
Block a user