Signal processing · In the CV
Audio Pattern Detection
Created a tool that finds and timestamps every repeat of a short sound in a long recording.
- Python
- Librosa
- NumPy
- SciPy
About
A Python tool that counts how many times a short template sound appears in a longer recording. It compares their Mel spectrograms and prints the number of matches with their timestamps.
Source code
audiodetect.py
import librosa
import numpy as np
from scipy.signal import find_peaks
import matplotlib.pyplot as plt
import time
def detect_words_spectrogram(target_file, template_file, threshold=0.7):
"""
Detects audio patterns using a highly efficient Mel Spectrogram matching method.
"""
try:
SR = 16000 # Standard sample rate for speech
y_target, _ = librosa.load(target_file, sr=SR)
y_template, _ = librosa.load(template_file, sr=SR)
print(f"Audio loaded. Target: {len(y_target)/SR:.2f}s, Template: {len(y_template)/SR:.2f}s")
except Exception as e:
print(f"Error loading files: {e}")
return 0, []
# 1. Feature Extraction using Spectrograms [cite: 22]
n_fft = 2048
hop_length = 512
S_target_db = librosa.power_to_db(librosa.feature.melspectrogram(y=y_target, sr=SR, n_fft=n_fft, hop_length=hop_length))
S_template_db = librosa.power_to_db(librosa.feature.melspectrogram(y=y_template, sr=SR, n_fft=n_fft, hop_length=hop_length))
# 2. Pattern Matching [cite: 23]
print("Performing fast feature matching...")
start_time = time.time()
template_h, template_w = S_template_db.shape
target_h, target_w = S_target_db.shape
similarity_scores = np.zeros(target_w)
for i in range(target_w - template_w):
window = S_target_db[:, i:i+template_w]
similarity = np.sum(window * S_template_db)
similarity_scores[i] = similarity
similarity_scores = (similarity_scores - np.min(similarity_scores)) / (np.max(similarity_scores) - np.min(similarity_scores))
end_time = time.time()
print(f"Matching complete in {end_time - start_time:.2f} seconds.")
# 3. Find and Count Occurrences
min_distance_frames = int((len(y_template) / SR) / (hop_length / SR))
peaks, _ = find_peaks(similarity_scores, height=threshold, distance=min_distance_frames)
num_occurrences = len(peaks)
detected_times = librosa.frames_to_time(peaks, sr=SR, hop_length=hop_length)
# 4. Visualization
print("Calculation complete. Generating plot...")
plt.figure(figsize=(15, 8))
# ... (Plotting code remains the same)
# ====================================================================
# ⬇️ The script pauses HERE until you close the plot ⬇️
# ====================================================================
plt.show()
return num_occurrences, detected_times
# --- Main Execution ---
if __name__ == "__main__":
TARGET_AUDIO_FILE = 'target.wav'
TEMPLATE_AUDIO_FILE = 'template.wav'
DETECTION_THRESHOLD = 0.7
print("Starting audio pattern detection (Spectrogram Feature Matching)...")
count, times = detect_words_spectrogram(TARGET_AUDIO_FILE, TEMPLATE_AUDIO_FILE, threshold=DETECTION_THRESHOLD)
# --- This section runs AFTER you close the plot window ---
# It will print the results in the format you want.
print("\n" + "="*30)
print(" DETECTION RESULTS")
print("="*30)
print(f"Total number of occurrences found: {count}")
if count > 0:
print("Detected at the following times (seconds):")
for i, t in enumerate(times):
# This line produces the format from your image (e.g., "1: 25.50s")
print(f" {i+1}: {t:.2f}s")