File size: 2,517 Bytes
2b668de
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""
===============================================================================
features/mel_spectrogram.py — Mel Spectrogram Extraction
===============================================================================

"""

import numpy as np
import librosa
from config import N_MELS, N_FFT, HOP_LENGTH, FMAX, MEL_POWER

N_MELS = 128
N_FFT = 1024
HOP_LENGTH = 512
FMAX = 8000
MEL_POWER = 2.0  # 2.0 = power spectrogram (standard), 1.0 = energy spectrogram

# Toggle whether to scale the final output dB array to exactly [0.0, 1.0]
# HIGHLY RECOMMENDED for CNN inputs to keep gradients stable.
# why did I choose to use min-max scaling here? 
# because the log-mel spectrogram can have a wide range of values depending on the loudness of the audio, 
# and scaling it to [0.0, 1.0] ensures that the CNN receives inputs in a consistent range
# which will make the weights explode in different directions when The data is fed to the CNN
# all weights will be standradized 
APPLY_MIN_MAX_SCALING = True

def extract_mel_spectrogram(audio, sr):
    """
    Extract a log-mel spectrogram from an audio waveform.

    Notes
    -----
    - The output is in log (dB) scale, normalized per-sample.
    - ref=np.max in power_to_db means 0 dB = the loudest point in this sample.
      All other values are negative dB below the peak.
    - This per-sample normalization is important because sala7's augmentation
      thresholds and EL sir's CNN batch normalization depend on consistent
      value ranges.

    """
    mel_spec = librosa.feature.melspectrogram(
          y=audio,
          sr=sr,
          n_fft=N_FFT,
          hop_length=HOP_LENGTH,
          n_mels=N_MELS,
          fmax=FMAX,
          power=MEL_POWER
      )

      # Convert to log scale (dB)
      # Using ref=np.max sets the absolute loudest point in this file to 0 dB, 
      # making all other values negative relative to the peak.
    log_mel_spec = librosa.power_to_db(mel_spec, ref=np.max) # so here I get the loudest point in the array and make it my refrence to be the zero decibel

      # Per-sample normalization to [0.0, 1.0]
    if APPLY_MIN_MAX_SCALING:
        # Prevent division by zero if the file is completely silent
        ptp = log_mel_spec.max() - log_mel_spec.min()
        if ptp > 1e-6:
            log_mel_spec = (log_mel_spec - log_mel_spec.min()) / ptp
        else:
            # If the file is just silent static, zero it out entirely
            log_mel_spec = np.zeros_like(log_mel_spec)

    return log_mel_spec