This commit is contained in:
CroneKorkN 2025-06-01 19:49:19 +02:00
parent d804d781c6
commit 407a5228bf
Signed by: cronekorkn
SSH key fingerprint: SHA256:v0410ZKfuO1QHdgKBsdQNF64xmTxOF8osF1LIqwTcVw

43
process
View file

@ -3,7 +3,7 @@ import os
import datetime import datetime
import numpy as np import numpy as np
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
import soundfile import soundfile as sf
from scipy.fft import rfft, rfftfreq from scipy.fft import rfft, rfftfreq
import shutil import shutil
import traceback import traceback
@ -36,20 +36,20 @@ def process_recording(filename):
# get data and metadata from recording # get data and metadata from recording
path = os.path.join(RECORDINGS_DIR, filename) path = os.path.join(RECORDINGS_DIR, filename)
sound, samplerate = soundfile.read(path) soundfile = sf.SoundFile(path)
samplerate = soundfile.samplerate
samples_per_block = int(BLOCK_SECONDS * samplerate) samples_per_block = int(BLOCK_SECONDS * samplerate)
overlapping_samples = int(samples_per_block * BLOCK_OVERLAP_FACTOR) overlapping_samples = int(samples_per_block * BLOCK_OVERLAP_FACTOR)
# chache data about current event sample_num = 0
current_event = None current_event = None
# read blocks of audio data with overlap from sound variable while sample_num < len(soundfile):
sample_num = 0 soundfile.seek(sample_num)
while sample_num < len(sound): block = soundfile.read(frames=samples_per_block, dtype='float32', always_2d=False)
# get block of audio data
block_start = sample_num if len(block) == 0:
block_end = min(sample_num + samples_per_block, len(sound)) break
block = sound[block_start:block_end]
# calculate FFT # calculate FFT
labels = rfftfreq(len(block), d=1/samplerate) labels = rfftfreq(len(block), d=1/samplerate)
@ -102,7 +102,8 @@ def process_recording(filename):
current_event['duration'] = duration current_event['duration'] = duration
print(f'🔊 {current_event['start_at'].strftime('%Y-%m-%d %H:%M:%S')} ({duration:.1f}s): {current_event['start_freq']:.1f}Hz->{current_event['end_freq']:.1f}Hz @{current_event['max_amplitude']:.0f}rDB') print(f'🔊 {current_event['start_at'].strftime('%Y-%m-%d %H:%M:%S')} ({duration:.1f}s): {current_event['start_freq']:.1f}Hz->{current_event['end_freq']:.1f}Hz @{current_event['max_amplitude']:.0f}rDB')
write_event(current_event=current_event, sound=sound, samplerate=samplerate) # read full audio clip again for writing
write_event(current_event=current_event, soundfile=soundfile, samplerate=samplerate)
current_event = None current_event = None
sample_num += DETECTION_DISTANCE_BLOCKS * samples_per_block sample_num += DETECTION_DISTANCE_BLOCKS * samples_per_block
@ -111,27 +112,31 @@ def process_recording(filename):
# write a spectrogram using the sound from start to end of the event # write a spectrogram using the sound from start to end of the event
def write_event(current_event, sound, samplerate): def write_event(current_event, soundfile, samplerate):
# date and filename
event_date = current_event['start_at'] - datetime.timedelta(seconds=PLOT_PADDING_START_SECONDS)
filename_prefix = event_date.strftime('%Y-%m-%d_%H-%M-%S.%f%z')
# event clip
event_start_sample = current_event['start_sample'] - samplerate * PLOT_PADDING_START_SECONDS event_start_sample = current_event['start_sample'] - samplerate * PLOT_PADDING_START_SECONDS
event_end_sample = current_event['end_sample'] + samplerate * PLOT_PADDING_END_SECONDS event_end_sample = current_event['end_sample'] + samplerate * PLOT_PADDING_END_SECONDS
event_clip = sound[event_start_sample:event_end_sample] total_samples = event_end_sample - event_start_sample
event = current_event['start_at'] - datetime.timedelta(seconds=PLOT_PADDING_START_SECONDS) soundfile.seek(event_start_sample)
filename_prefix = current_event['start_at'].strftime('%Y-%m-%d_%H-%M-%S.%f%z') event_clip = soundfile.read(frames=total_samples, dtype='float32', always_2d=False)
# write flac # write flac
flac_path = os.path.join(DETECTIONS_DIR, f"{filename_prefix}.flac") flac_path = os.path.join(DETECTIONS_DIR, f"{filename_prefix}.flac")
soundfile.write(flac_path, event_clip, samplerate, format='FLAC') sf.write(flac_path, event_clip, samplerate, format='FLAC')
# write spectrogram # write spectrogram
plt.figure(figsize=(8, 6)) plt.figure(figsize=(8, 6))
plt.specgram(event_clip, Fs=samplerate, NFFT=samplerate, noverlap=samplerate//2, cmap='inferno', vmin=-100, vmax=-10) plt.specgram(event_clip, Fs=samplerate, NFFT=samplerate, noverlap=samplerate//2, cmap='inferno', vmin=-100, vmax=-10)
plt.title(f"Bootshorn @{event.strftime('%Y-%m-%d %H:%M:%S%z')}") plt.title(f"Bootshorn @{event_date.strftime('%Y-%m-%d %H:%M:%S%z')}")
plt.xlabel(f"Time {current_event['duration']:.1f}s") plt.xlabel(f"Time {current_event['duration']:.1f}s")
plt.ylabel(f"Frequency {current_event['start_freq']:.1f}Hz -> {current_event['end_freq']:.1f}Hz") plt.ylabel(f"Frequency {current_event['start_freq']:.1f}Hz -> {current_event['end_freq']:.1f}Hz")
plt.colorbar(label="Intensity (rDB)") plt.colorbar(label="Intensity (rDB)")
plt.ylim(50, 1000) plt.ylim(50, 1000)
spectrogram_path = os.path.join(DETECTIONS_DIR, f"{filename_prefix}.png") plt.savefig(os.path.join(DETECTIONS_DIR, f"{filename_prefix}.png"))
plt.savefig(spectrogram_path)
plt.close() plt.close()