Iffat Jahan
CV

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.pyPython script · 82 lines · 3.3 KB
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")