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
|