deepfake-shield-api / utils /audio_processor.py
adidtiya
Deploy Deepfake Shield Backend v2.0
91491b1
Raw History Blame Contribute Delete
2.3 kB
"""
audio_processor.py
==================
Utilitas untuk preprocessing audio chunk sebelum dianalisis.
"""
import numpy as np
import librosa
import io
import soundfile as sf
from typing import Tuple, Optional
def bytes_to_audio(audio_bytes: bytes) -> Tuple[np.ndarray, int]:
"""
Konversi bytes audio ke numpy array PCM.
Mendukung format: WAV, MP3, OGG, FLAC.
Returns:
Tuple (audio_array float32 mono, sample_rate)
"""
buffer = io.BytesIO(audio_bytes)
# Coba baca dengan soundfile terlebih dahulu
try:
audio, sr = sf.read(buffer, dtype='float32')
except Exception:
# Fallback ke librosa (lebih lambat tapi mendukung lebih banyak format)
buffer.seek(0)
audio, sr = librosa.load(buffer, sr=None, mono=True)
return audio, sr
# Konversi stereo ke mono jika diperlukan
if audio.ndim == 2:
audio = np.mean(audio, axis=1)
return audio, sr
def normalize_audio(audio: np.ndarray) -> np.ndarray:
"""
Normalisasi amplitudo audio ke range [-1.0, 1.0].
Mencegah saturasi dan memastikan konsistensi input model.
"""
max_val = np.max(np.abs(audio))
if max_val > 0:
audio = audio / max_val
return audio
def split_audio_chunks(
audio: np.ndarray,
sample_rate: int,
chunk_duration: float = 2.0,
overlap: float = 0.5
) -> list:
"""
Bagi audio panjang menjadi chunks kecil dengan overlap.
Args:
audio : Array audio PCM
sample_rate : Sample rate (Hz)
chunk_duration: Durasi setiap chunk (detik)
overlap : Overlap antar chunk (detik)
Returns:
List of numpy arrays, masing-masing adalah satu chunk
"""
chunk_samples = int(chunk_duration * sample_rate)
hop_samples = int((chunk_duration - overlap) * sample_rate)
chunks = []
start = 0
while start + chunk_samples <= len(audio):
chunk = audio[start:start + chunk_samples]
chunks.append(chunk)
start += hop_samples
# Tambahkan sisa audio jika belum masuk (dengan padding)
if start < len(audio):
remainder = audio[start:]
padded = np.pad(remainder, (0, chunk_samples - len(remainder)))
chunks.append(padded)
return chunks