Comparing OTs

 avatar
unknown
python
9 months ago
3.0 kB
15
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