wip
This commit is contained in:
parent
6c06c42e85
commit
cf5b1396b1
1 changed files with 26 additions and 11 deletions
37
process
37
process
|
@ -1,13 +1,13 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import os
|
import os
|
||||||
import concurrent.futures
|
|
||||||
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
|
||||||
import scipy.signal
|
|
||||||
from scipy.fft import rfft, rfftfreq
|
from scipy.fft import rfft, rfftfreq
|
||||||
import shutil
|
import shutil
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
|
||||||
RECORDINGS_DIR = "recordings"
|
RECORDINGS_DIR = "recordings"
|
||||||
PROCESSED_RECORDINGS_DIR = "recordings/processed"
|
PROCESSED_RECORDINGS_DIR = "recordings/processed"
|
||||||
|
@ -23,6 +23,7 @@ DETECTION_DISTANCE_SECONDS = 30 # seconds (minimum time between detections)
|
||||||
DETECTION_DISTANCE_BLOCKS = DETECTION_DISTANCE_SECONDS // BLOCK_SECONDS # number of blocks to skip after a detection
|
DETECTION_DISTANCE_BLOCKS = DETECTION_DISTANCE_SECONDS // BLOCK_SECONDS # number of blocks to skip after a detection
|
||||||
BLOCK_OVERLAP_FACTOR = 0.9 # overlap between blocks (0.2 means 20% overlap)
|
BLOCK_OVERLAP_FACTOR = 0.9 # overlap between blocks (0.2 means 20% overlap)
|
||||||
MIN_SIGNAL_QUALITY = 1000.0 # maximum noise level (relative DB) to consider a detection valid
|
MIN_SIGNAL_QUALITY = 1000.0 # maximum noise level (relative DB) to consider a detection valid
|
||||||
|
PLOT_PADDING_SECONDS = 2 # seconds (padding before and after the event in the plot)
|
||||||
|
|
||||||
def process_recording(filename):
|
def process_recording(filename):
|
||||||
print('processing', filename)
|
print('processing', filename)
|
||||||
|
@ -78,6 +79,8 @@ def process_recording(filename):
|
||||||
current_event = {
|
current_event = {
|
||||||
'start_at': block_date,
|
'start_at': block_date,
|
||||||
'end_at': block_date,
|
'end_at': block_date,
|
||||||
|
'start_sample': sample_num,
|
||||||
|
'end_sample': sample_num + samples_per_block,
|
||||||
'start_freq': max_freq,
|
'start_freq': max_freq,
|
||||||
'end_freq': max_freq,
|
'end_freq': max_freq,
|
||||||
'max_amplitude': max_amplitude,
|
'max_amplitude': max_amplitude,
|
||||||
|
@ -86,6 +89,7 @@ def process_recording(filename):
|
||||||
current_event.update({
|
current_event.update({
|
||||||
'end_at': block_date,
|
'end_at': block_date,
|
||||||
'end_freq': max_freq,
|
'end_freq': max_freq,
|
||||||
|
'end_sample': sample_num + samples_per_block,
|
||||||
'max_amplitude': max(max_amplitude, current_event['max_amplitude']),
|
'max_amplitude': max(max_amplitude, current_event['max_amplitude']),
|
||||||
})
|
})
|
||||||
print(f'- {block_date.strftime('%Y-%m-%d %H:%M:%S')}: {max_amplitude:.1f}rDB @ {max_freq:.1f}Hz (signal {signal_quality:.3f}x)')
|
print(f'- {block_date.strftime('%Y-%m-%d %H:%M:%S')}: {max_amplitude:.1f}rDB @ {max_freq:.1f}Hz (signal {signal_quality:.3f}x)')
|
||||||
|
@ -95,8 +99,7 @@ def process_recording(filename):
|
||||||
duration = (current_event['end_at'] - current_event['start_at']).total_seconds()
|
duration = (current_event['end_at'] - current_event['start_at']).total_seconds()
|
||||||
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_clip()
|
write_event(current_event=current_event, sound=sound, samplerate=samplerate)
|
||||||
write_plot()
|
|
||||||
|
|
||||||
current_event = None
|
current_event = None
|
||||||
sample_num += DETECTION_DISTANCE_BLOCKS * samples_per_block
|
sample_num += DETECTION_DISTANCE_BLOCKS * samples_per_block
|
||||||
|
@ -105,12 +108,25 @@ def process_recording(filename):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def write_clip():
|
def write_event(current_event, sound, samplerate):
|
||||||
pass
|
# write a spectrogram using the sound from start to end of the event
|
||||||
|
event_start_sample = current_event['start_sample'] - samplerate * PLOT_PADDING_SECONDS
|
||||||
|
event_end_sample = current_event['end_sample'] + samplerate * PLOT_PADDING_SECONDS
|
||||||
def write_plot():
|
event_clip = sound[event_start_sample:event_end_sample]
|
||||||
pass
|
plot_start_date = current_event['start_at'] - datetime.timedelta(seconds=PLOT_PADDING_SECONDS)
|
||||||
|
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 @{plot_start_date.strftime('%Y-%m-%d %H:%M:%S')}")
|
||||||
|
plt.xlabel("Time (s)")
|
||||||
|
plt.ylabel("Frequency (Hz)")
|
||||||
|
plt.colorbar(label="Intensity (dB)")
|
||||||
|
plt.ylim(50, 1000)
|
||||||
|
spectrogram_path = os.path.join(DETECTIONS_DIR, f"{current_event['start_at'].strftime('%Y-%m-%d_%H-%M-%S.%f%z')}.png")
|
||||||
|
plt.savefig(spectrogram_path)
|
||||||
|
plt.close()
|
||||||
|
# write flac
|
||||||
|
flac_path = os.path.join(DETECTIONS_DIR, f"{current_event['start_at'].strftime('%Y-%m-%d_%H-%M-%S.%f%z')}.flac")
|
||||||
|
soundfile.write(flac_path, event_clip, samplerate, format='FLAC')
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
@ -124,7 +140,6 @@ def main():
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error processing {filename}: {e}")
|
print(f"Error processing {filename}: {e}")
|
||||||
# print stacktrace
|
# print stacktrace
|
||||||
import traceback
|
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue