Skip to content

Instantly share code, notes, and snippets.

@jaggzh
Created October 8, 2023 21:52
Show Gist options
  • Save jaggzh/876165693ba548ef6eedb9df8efabd3f to your computer and use it in GitHub Desktop.
Save jaggzh/876165693ba548ef6eedb9df8efabd3f to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
import numpy as np
import matplotlib.pyplot as plt
import sys
from audioproc import *
def find_peaks(energy, *, num_peaks, winsize):
en_len = len(energy)
spacing = en_len // num_peaks
cands = np.arange(spacing, en_len - spacing, spacing)
# Building initial list of energy windows
wins_start = np.arange(0, en_len - winsize, winsize)
en_wins = [{'st': start, 'en': min(start + winsize, en_len), 'e': energy[start:start + winsize], 'done': False}
for start in wins_start]
# Sorting energy windows by energy (desc) and creating index list
en_wins_idx_srt = sorted(range(len(en_wins)), key=lambda x: np.sum(en_wins[x]['e']), reverse=True)
# Remaining candidates
rem_cands = cands.copy()
# Final lists
final_cands = []
for win_idx in en_wins_idx_srt:
win = en_wins[win_idx]
if not win['done']:
for cand in rem_cands:
if win['st'] - spacing//2 <= cand <= win['en'] + spacing//2:
# Find the coordinate of the energy peak within the window
peak_coord = np.argmax(win['e']) + win['st']
# Add to final lists and remove from original lists
final_cands.append(peak_coord)
rem_cands = rem_cands[rem_cands != cand]
# Marking the energy window as done
win['done'] = True
# Function to mark all windows between two coordinates as done
def mark_windows_done(start, end):
for w in en_wins:
if start <= w['st'] <= end or start <= w['en'] <= end:
w['done'] = True
# Check both left and right from the peak_coord
for direction in [-1, 1]:
check_coord = peak_coord + direction
# Continue until final_cand or rem_cand or go out of bounds
while 0 <= check_coord < en_len:
if check_coord in final_cands:
mark_windows_done(min(check_coord, peak_coord), max(check_coord, peak_coord))
break
elif check_coord in rem_cands:
break
check_coord += direction
break
return final_cands
def plot_find_peaks(energy, num_peaks, winsize):
peaks = find_peaks(energy, num_peaks=num_peaks, winsize=winsize)
plt.plot(energy, label='Energy')
plt.vlines(peaks, ymin=0, ymax=np.max(energy), colors='darkblue', label='Peaks')
plt.legend()
plt.xlabel('Time')
plt.ylabel('Energy')
plt.title('Energy and Detected Peaks')
plt.show()
if __name__ == "__main__":
file=sys.argv[1]
au, osr = read_audio(file)
au = au[:osr*480] # crop
sr=2000
pf("Downsampling")
au = downsample_audio(au, sr=osr, tsr=sr)
pf("Calc energy")
energy = calculate_energy(au, sr*2, bludgeon=.1) # 2s windows
# energy = np.random.rand(1000) # Example energy array
# Parameters
num_peaks = 20
winsize = sr*2
pf("Finding peaks")
plot_find_peaks(energy, num_peaks=num_peaks, winsize=winsize)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment