File size: 1,682 Bytes
127b976
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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

from __future__ import annotations

from typing import Dict, List

import numpy as np
import torch
import torchaudio


def load_audio_mono(path: str, target_sr: int = 16000):
    wav, sr = torchaudio.load(path)
    wav = wav.mean(dim=0)
    if sr != target_sr:
        wav = torchaudio.functional.resample(wav, sr, target_sr)
        sr = target_sr
    return wav, sr


def audio_quality_report(path: str, target_sr: int = 16000) -> Dict:
    wav, sr = load_audio_mono(path, target_sr)
    x = wav.detach().cpu().numpy().astype(float)

    if len(x) == 0:
        return {"warnings": ["Audio appears empty."], "metrics": {"duration_sec": 0.0}}

    duration = len(x) / sr
    rms = float(np.sqrt(np.mean(x ** 2)) + 1e-12)
    peak = float(np.max(np.abs(x)) + 1e-12)
    silence_ratio = float(np.mean(np.abs(x) < 1e-4))
    clipping_ratio = float(np.mean(np.abs(x) > 0.98))

    warnings: List[str] = []
    if duration < 1.0:
        warnings.append("Audio is very short; prediction may be unreliable.")
    if rms < 0.005:
        warnings.append("Audio volume is very low.")
    if clipping_ratio > 0.01:
        warnings.append("Audio may be clipped or distorted.")
    if silence_ratio > 0.70:
        warnings.append("Audio contains a lot of silence.")
    if peak < 0.02:
        warnings.append("Audio peak level is very low.")

    return {
        "warnings": warnings,
        "metrics": {
            "sample_rate": sr,
            "duration_sec": duration,
            "rms": rms,
            "peak": peak,
            "silence_ratio": silence_ratio,
            "clipping_ratio": clipping_ratio,
        },
    }