Skip to content

Commit

Permalink
Replace audioop for python 3.13+
Browse files Browse the repository at this point in the history
  • Loading branch information
markbackman committed Dec 17, 2024
1 parent f3112a8 commit 4036c2a
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 14 deletions.
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ Website = "https://pipecat.ai"
[project.optional-dependencies]
anthropic = [ "anthropic~=0.40.0" ]
assemblyai = [ "assemblyai~=0.34.0" ]
audio = [ "soundfile~=0.12.1" ]
aws = [ "boto3~=1.35.27" ]
azure = [ "azure-cognitiveservices-speech~=1.41.1", "openai~=1.57.2" ]
canonical = [ "aiofiles~=24.1.0" ]
Expand Down
56 changes: 43 additions & 13 deletions src/pipecat/audio/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
# SPDX-License-Identifier: BSD 2-Clause License
#

import audioop
import sys

import numpy as np
import pyloudnorm as pyln
import resampy
Expand Down Expand Up @@ -74,21 +75,50 @@ def exp_smoothing(value: float, prev_value: float, factor: float) -> float:
return prev_value + factor * (value - prev_value)


def ulaw_to_pcm(ulaw_bytes: bytes, in_sample_rate: int, out_sample_rate: int):
# Convert μ-law to PCM
in_pcm_bytes = audioop.ulaw2lin(ulaw_bytes, 2)
if sys.version_info >= (3, 13):
try:
import io

import soundfile as sf

def ulaw_to_pcm(ulaw_bytes: bytes, in_sample_rate: int, out_sample_rate: int) -> bytes:
with io.BytesIO(ulaw_bytes) as buf:
data, _ = sf.read(
buf, channels=1, samplerate=in_sample_rate, format="RAW", subtype="ULAW"
)
if in_sample_rate != out_sample_rate:
data = resampy.resample(data, in_sample_rate, out_sample_rate)
return (data * 32767).astype(np.int16).tobytes()

def pcm_to_ulaw(pcm_bytes: bytes, in_sample_rate: int, out_sample_rate: int) -> bytes:
data = np.frombuffer(pcm_bytes, dtype=np.int16).astype(np.float32) / 32767.0
if in_sample_rate != out_sample_rate:
data = resampy.resample(data, in_sample_rate, out_sample_rate)
with io.BytesIO() as buf:
sf.write(buf, data, out_sample_rate, format="RAW", subtype="ULAW")
return buf.getvalue()
except ImportError:
raise ImportError(
"For Python 3.13+, please install soundfile: pip install pipecat-ai[audio]"
)

else:
import audioop

# Resample
out_pcm_bytes = audioop.ratecv(in_pcm_bytes, 2, 1, in_sample_rate, out_sample_rate, None)[0]
def ulaw_to_pcm(ulaw_bytes: bytes, in_sample_rate: int, out_sample_rate: int):
# Convert μ-law to PCM
in_pcm_bytes = audioop.ulaw2lin(ulaw_bytes, 2)

return out_pcm_bytes
# Resample
out_pcm_bytes = audioop.ratecv(in_pcm_bytes, 2, 1, in_sample_rate, out_sample_rate, None)[0]

return out_pcm_bytes

def pcm_to_ulaw(pcm_bytes: bytes, in_sample_rate: int, out_sample_rate: int):
# Resample
in_pcm_bytes = audioop.ratecv(pcm_bytes, 2, 1, in_sample_rate, out_sample_rate, None)[0]
def pcm_to_ulaw(pcm_bytes: bytes, in_sample_rate: int, out_sample_rate: int):
# Resample
in_pcm_bytes = audioop.ratecv(pcm_bytes, 2, 1, in_sample_rate, out_sample_rate, None)[0]

# Convert PCM to μ-law
ulaw_bytes = audioop.lin2ulaw(in_pcm_bytes, 2)
# Convert PCM to μ-law
ulaw_bytes = audioop.lin2ulaw(in_pcm_bytes, 2)

return ulaw_bytes
return ulaw_bytes
13 changes: 12 additions & 1 deletion src/pipecat/serializers/twilio.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,24 @@

import base64
import json
import sys

from pydantic import BaseModel

from pipecat.audio.utils import ulaw_to_pcm, pcm_to_ulaw
from pipecat.frames.frames import AudioRawFrame, Frame, InputAudioRawFrame, StartInterruptionFrame
from pipecat.serializers.base_serializer import FrameSerializer, FrameSerializerType

if sys.version_info >= (3, 13):
try:
from pipecat.audio.utils import pcm_to_ulaw, ulaw_to_pcm
except ImportError:
raise ImportError(
"Audio processing support required for TwilioFrameSerializer. "
"Please install with: pip install pipecat-ai[audio]"
)
else:
from pipecat.audio.utils import pcm_to_ulaw, ulaw_to_pcm


class TwilioFrameSerializer(FrameSerializer):
class InputParams(BaseModel):
Expand Down

0 comments on commit 4036c2a

Please sign in to comment.