Created
October 8, 2023 21:52
-
-
Save jaggzh/876165693ba548ef6eedb9df8efabd3f to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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