Initial commit - Navi.FM v3
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
import librosa
|
||||
|
||||
# Monkeypatch for pyloudnorm which uses the deprecated scipy.signal.hann
|
||||
import scipy.signal
|
||||
import scipy.signal.windows
|
||||
if not hasattr(scipy.signal, 'hann'):
|
||||
scipy.signal.hann = scipy.signal.windows.hann
|
||||
|
||||
import pyloudnorm as pyln
|
||||
import numpy as np
|
||||
|
||||
def analyze_audio(file_path: str) -> dict:
|
||||
"""Analyzes an audio file and returns metadata."""
|
||||
try:
|
||||
# Load audio (mono, original sample rate to preserve frequency content)
|
||||
y, sr = librosa.load(file_path, sr=None, mono=True)
|
||||
|
||||
# BPM
|
||||
tempo, _ = librosa.beat.beat_track(y=y, sr=sr)
|
||||
if isinstance(tempo, np.ndarray):
|
||||
bpm = float(tempo[0])
|
||||
else:
|
||||
bpm = float(tempo)
|
||||
|
||||
# Key extraction using chroma (simplified root note extraction)
|
||||
chroma = librosa.feature.chroma_cqt(y=y, sr=sr)
|
||||
key_idx = np.argmax(np.sum(chroma, axis=1))
|
||||
keys = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B']
|
||||
key = keys[key_idx]
|
||||
|
||||
# Energy (RMS)
|
||||
rms = librosa.feature.rms(y=y)
|
||||
energy = float(np.mean(rms))
|
||||
|
||||
# Spectral Centroid (Brightness)
|
||||
cent = librosa.feature.spectral_centroid(y=y, sr=sr)
|
||||
spectral_centroid = float(np.mean(cent))
|
||||
|
||||
# Onset Density (Danceability/Rhythm)
|
||||
onset_env = librosa.onset.onset_strength(y=y, sr=sr)
|
||||
onsets = librosa.onset.onset_detect(onset_envelope=onset_env, sr=sr)
|
||||
duration_sec = len(y) / sr
|
||||
onset_density = len(onsets) / duration_sec if duration_sec > 0 else 0
|
||||
|
||||
# LUFS
|
||||
meter = pyln.Meter(sr) # create BS.1770 meter
|
||||
lufs = meter.integrated_loudness(y)
|
||||
|
||||
return {
|
||||
"bpm": bpm,
|
||||
"key": key,
|
||||
"energy": energy,
|
||||
"spectral_centroid": spectral_centroid,
|
||||
"onset_density": float(onset_density),
|
||||
"lufs": float(lufs)
|
||||
}
|
||||
except Exception as e:
|
||||
print(f"Error analyzing {file_path}: {e}")
|
||||
return None
|
||||
Reference in New Issue
Block a user