Comparing OTs

 avatar
unknown
python
a month ago
3.0 kB
3
Indexable
import os
import librosa
import librosa.display
import numpy as np
from scipy.signal import butter, lfilter
from scipy.io import wavfile
import matplotlib.pyplot as plt

def butter_bandpass(lowcut, highcut, fs, order=5):
    nyquist = 0.5 * fs
    low = lowcut / nyquist
    high = highcut / nyquist
    b, a = butter(order, [low, high], btype='band')
    return b, a

def butter_bandpass_filter(data, lowcut, highcut, fs, order=5):
    b, a = butter_bandpass(lowcut, highcut, fs, order=order)
    y = lfilter(b, a, data)
    return y


AUDIO_DIR = 'data/audio'
MP3s = [os.path.join(AUDIO_DIR, o) for o in os.listdir(AUDIO_DIR) if o.endswith('.mp3')]

fig, ax = plt.subplots(figsize=(12, 6))

# Create frequency bins (logarithmically spaced in the audible range)
bins = np.logspace(np.log10(20), np.log10(20000), 20)  # 20 bins from 20Hz to 20kHz

# First pass: calculate the maximum amplitude across all files
max_amplitude = 0
all_binned_spectra = []

for mp3 in MP3s:
    # Load the audio
    y, sr = librosa.load(mp3)
    
    # Compute the frequency distribution
    spectrum = np.abs(np.fft.rfft(y))
    freq = np.fft.rfftfreq(len(y), 1/sr)
    
    # Bin the spectrum data
    binned_spectrum = np.zeros_like(bins[:-1])
    for j in range(len(bins) - 1):
        mask = (freq >= bins[j]) & (freq < bins[j+1])
        if np.any(mask):
            binned_spectrum[j] = np.mean(spectrum[mask])
    
    # Track the maximum value across all files
    file_max = np.max(binned_spectrum)
    if file_max > max_amplitude:
        max_amplitude = file_max
    
    all_binned_spectra.append(binned_spectrum)

# Second pass: plot with normalization against the global maximum
for i, mp3 in enumerate(MP3s):
    # Get basename for display
    basename = os.path.basename(mp3).replace('.mp3', '')
    
    # Normalize using the global maximum value
    binned_spectrum = all_binned_spectra[i] / max_amplitude
    
    # Plot the binned frequency distribution
    ax.plot(bins[:-1], binned_spectrum, label=basename, alpha=0.7)

# Set labels and title
ax.set_xlabel('Frequency')
ax.set_ylabel('Normed Amplitude')
ax.set_title('Frequency Distributions - OTs in JS Comparison (first clips)')
ax.set_xscale('log')
ax.grid(True, which="both", ls="-", alpha=0.5)
ax.set_xlim(20, 15000)  # Focus on audible range

# Format x-axis with standard frequency labels
frequencies = [20, 50, 100, 200, 500, 1000, 2000, 5000, 10000]
ax.set_xticks(frequencies)
ax.set_xticklabels([f'{f}Hz' if f < 1000 else f'{f//1000}kHz' for f in frequencies])

ax.legend()

plt.tight_layout()

# Save the plot
plt.savefig('data/audio_frequency_distributions.png')

# Apply bandpass filters and save filtered audio
for i, mp3 in enumerate(MP3s):
    # Get basename for display
    basename = os.path.basename(mp3).replace('.mp3', '')
    
    # Load the audio
    y, sr = librosa.load(mp3)
    
    # Apply the bandpass filter
    y_filtered = butter_bandpass_filter(y, lowcut, highcut, fs)

    wavfile.write(f'data/audio/{basename}_filtered.wav', sr, y_filtered.astype(np.float32))

Editor is loading...
Leave a Comment