From 407a5228bf8332887ceeedf3755c6a63990b801a Mon Sep 17 00:00:00 2001 From: CroneKorkN Date: Sun, 1 Jun 2025 19:49:19 +0200 Subject: [PATCH] wip --- process | 43 ++++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/process b/process index bc8d198..3dfee66 100755 --- a/process +++ b/process @@ -3,7 +3,7 @@ import os import datetime import numpy as np import matplotlib.pyplot as plt -import soundfile +import soundfile as sf from scipy.fft import rfft, rfftfreq import shutil import traceback @@ -36,20 +36,20 @@ def process_recording(filename): # get data and metadata from recording 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) overlapping_samples = int(samples_per_block * BLOCK_OVERLAP_FACTOR) - # chache data about current event + sample_num = 0 current_event = None - # read blocks of audio data with overlap from sound variable - sample_num = 0 - while sample_num < len(sound): - # get block of audio data - block_start = sample_num - block_end = min(sample_num + samples_per_block, len(sound)) - block = sound[block_start:block_end] + while sample_num < len(soundfile): + soundfile.seek(sample_num) + block = soundfile.read(frames=samples_per_block, dtype='float32', always_2d=False) + + if len(block) == 0: + break # calculate FFT labels = rfftfreq(len(block), d=1/samplerate) @@ -102,7 +102,8 @@ def process_recording(filename): 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') - 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 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 -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_end_sample = current_event['end_sample'] + samplerate * PLOT_PADDING_END_SECONDS - event_clip = sound[event_start_sample:event_end_sample] - event = current_event['start_at'] - datetime.timedelta(seconds=PLOT_PADDING_START_SECONDS) - filename_prefix = current_event['start_at'].strftime('%Y-%m-%d_%H-%M-%S.%f%z') + total_samples = event_end_sample - event_start_sample + soundfile.seek(event_start_sample) + event_clip = soundfile.read(frames=total_samples, dtype='float32', always_2d=False) # write 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 plt.figure(figsize=(8, 6)) 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.ylabel(f"Frequency {current_event['start_freq']:.1f}Hz -> {current_event['end_freq']:.1f}Hz") plt.colorbar(label="Intensity (rDB)") plt.ylim(50, 1000) - spectrogram_path = os.path.join(DETECTIONS_DIR, f"{filename_prefix}.png") - plt.savefig(spectrogram_path) + plt.savefig(os.path.join(DETECTIONS_DIR, f"{filename_prefix}.png")) plt.close()