File size: 2,295 Bytes
91491b1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
"""
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