This page describes the internal architecture, deployment workflow, plugin system, and extension mechanisms used by SAMLab.
Explore recordings
Open WAV files, navigate by time, zoom by frequency, adjust dynamic range, and play segments directly from the interface.
Annotate events
Select regions in time and frequency, assign categories, edit or delete annotations, and save deployment-level annotation CSV files.
Run analyses
Choose one or more automatic analysis plugins, view detected events, and export deployment indicators and detected event tables.
How SAMLab is structured
SAMLab is structured around a PySide6 graphical interface, reusable processing modules, and an extensible plugin system. Computational work is moved into Qt worker threads so the interface remains responsive while plugins run.
Main application
samlab.py defines the MainWindow class and coordinates the main application workflow, including: menu actions, spectrogram visualisation, deployment navigation, event browsing, audio playback, plugin execution, and manual annotation tools.
The graphical interface integrates matplotlib visualisation widgets with PySide6 controls to provide interactive exploration of large underwater acoustic recordings.
Core modules
The modules/ package contains the reusable components used throughout the application, including: graphical dialogs, spectrogram and navigation drawing routines, deployment analysis workflows, shared data models, plugin selection interfaces, status and progress windows, and multithreaded worker classes.
Workers Threads
Long-running computational tasks are executed in Qt worker threads to prevent the graphical interface from freezing during deployment analyses or plugin execution. Worker classes are responsible for:
executing plugins asynchronously, updating progress windows, handling cancellation requests, and returning detected events and indicators back to the main application thread.
This architecture allows SAMLab to process large deployments while maintaining an interactive user experience.
SAMLab user Workflow
1 Open audio
Use File → Open File… or double click in the Deployment Navigation Graph of a deployment to load a WAV file into SAMLab.
2 Inspect
Move through time, zoom into a frequency band of the spectrogram representation, adjust FFT size, dynamic range, etc.
3 Analyze
Use Analyze → Analyze current File… or Analyze Deployment…, choose specific plugins for acoustic event detection, and review automatically detected events.
4 Annotate
Use manual annotation tools to draw time-frequency boxes, classify acoustic events, and save annotations.
Deployment Analysis workflow
Deployment analysis loads deployment_info.mat, scans all *.WAV files within a deployment directory1, executes the selected analysis plugins on each recording, exports deployment indicators to deployment_indicators.csv, and stores detected events in the HDF5 file detected_events.h5.
The workflow also supports:
- interrupted-analysis recovery,
- partial reprocessing,
- resumable deployment analyses,
- deployment-level visualisation of extracted indicators.
Deployment indicators can later be visualised through the deployment navigation interface for rapid inspection of long-term acoustic trends.
Plugin architecture
Analysis plugins are located in the analysis_plugins/ package and are dynamically discovered through:
plugin_loader.discover_plugins(analysis_plugins)
Each plugin exposes metadata such as:
- plugin name,
- description,
- version,
- outputs
This metadata is used to automatically populate the plugin selection interface and integrate plugin outputs into deployment analyses and event visualisation workflows.
Plugins can operate either on:
- individual recordings,
- or complete deployment processing pipelines.
A plugin declares its outputs once in outputs.
outputs["events"]lists the event types the plugin can produce.outputs["indicators"]declares the file-level indicators and their data types.
The analyze() method returns an event DataFrame and an indicator dictionary whose keys match outputs["indicators"]. Indicators consist of summarized event information, such as the number of events of a given type, and are used for graphical navigation through the deployment in the Deployment Navigation Graph.
Adding a new analysis plugin
A SAMLab analysis plugin is a Python class with metadata and an analyze() method. The method receives the audio array, sampling rate, DSP calibration, band calibration, and a verbosity flag. It returns two objects: events and file-level indicators.
1. Create a new file
Place your plugin in the analysis_plugins/ package, for example:
analysis_plugins/my_detector.py
2. Implement the plugin class
import numpy as np
import pandas as pd
import time
from modules.models import EVENT_FIELDS_TYPES
class MyDetector:
name = "MyDetector"
description = "Detects a custom acoustic event and reports one indicator."
version = "1.0.0"
outputs = {
"events": [
{
"type": "MDE",
"tag": "My Detector Event",
}
],
"indicators": {
"MyDetector_Count [#]": int,
},
}
def analyze(self, x, fs, dsp, bands, verbose=False):
"""
Returns
-------
events : pandas.DataFrame
Rows describing detected events, or an empty event DataFrame.
indicators : dict
File-level values matching outputs["indicators"].
"""
start_time = time.time()
events = pd.DataFrame({
name: pd.Series(dtype=dtype)
for name, dtype in EVENT_FIELDS_TYPES
})
indicators = {
key: np.nan
for key in self.outputs["indicators"]
}
event_type = self.outputs["events"][0]["type"]
event_tag = self.outputs["events"][0]["tag"]
if verbose:
print("Running My Detector...")
x = np.asarray(x, dtype=float)
threshold = np.mean(np.abs(x)) + 4 * np.std(x)
hits = np.flatnonzero(np.abs(x) > threshold)
if hits.size:
start = int(hits[0])
end = int(hits[-1])
events.loc[len(events)] = {
"start": np.uint32(start),
"end": np.uint32(end),
"fmin": np.float32(0.0),
"fmax": np.float32(fs / 2),
"f0": np.float32(np.nan),
"BW": np.float32(np.nan),
"ICI": np.float32(np.nan),
"SPL": np.float32(np.nan),
"score": np.int8(1),
"user": np.float32(np.nan),
"type": event_type,
"tag": event_tag,
"Tdata": np.nan,
"Fdata": np.nan,
}
indicators["MyDetector_Count [#]"] = int(len(events))
if verbose:
print(f"Analysis finished in {time.time()-start_time:.2f} s")
return events, indicators
3. Pandas “events” fields expected by SAMLab
| Field | Meaning |
start, end | Event limits in samples, not seconds. |
fmin, fmax | Frequency bounds in Hz. |
f0, BW, ICI, SPL | Event central frequency, Bandwidth, Inter Event Interval, and Sound Pressure level (used by the miniature event navigation graph and combo box). |
score | Detection score or confidence value. |
| Human-readable event label shown in the spectrogram. |
type | Compact event code used internally and for filtering. |
Tdata, Fdata | Contour points for time-frequency tracks; use np.nan if not applicable. |
4. Match returned indicators to declared output
If your plugin declares two indicators in outputs:
"indicators": {
"Number of events A [#]": int,
"Number of events B [#]": int
}
, remember to fill the values :
indicators[""] = np.sum(events["type"] == "A")Number of events A [#]
indicators[""] = np.sum(events["type"] == "B")Number of events B [#]
These values become extra columns in deployment_indicators.csv.
5. Test the plugin
1 Import test
Start SAMLab and check that your plugin appears in the selector with the right name, description, and version.
2 Single file
Run it on a short WAV file and confirm that the event list, spectrogram boxes, and indicators look correct.
3 Deployment
Run it on a small deployment folder and check CSV/HDF5 outputs.
4 Resume
For long analyses, verify that interrupted deployment analysis resumes without corrupting results.
Plugin programming rules
- Do not modify
xin place unless you intentionally want downstream plugins to see the modified signal. Preferx = np.asarray(x, dtype=float). - Return an empty
DataFramerather thanNonewhen no events are found. - Keep long loops interrupt-friendly where possible; SAMLab can request interruption between plugins and files.
- Use printed progress messages sparingly; they appear in the status window when verbose mode is enabled.
- Keep metadata stable. Changing
nameor indicator names inoutputs["indicators"]affects deployment resume logic and CSV compatibility.
AGPLv3 licensing
Open-source distribution
SAMLab can be distributed under the GNU Affero General Public License v3. This means users may run, study, share, and modify the software under the AGPLv3 terms.
Commercial licensing
Commercial licenses are available for organisations wishing to use, modify, distribute, integrate, or provide SAMLab as part of proprietary, OEM, SaaS, or industrial products without complying with the AGPLv3 requirements.
This page is not legal advice. Before public release, include a complete LICENSE file containing the AGPLv3 text, preserve copyright notices, and decide whether plugins are distributed as AGPLv3 code, separate optional extensions, or dual-licensed modules.
SAMLab — Submarine Acoustic Monitoring Laboratory
Copyright © 2026 Universitat Politècnica de València and contributors.
- Deployment requirement: a deployment folder should contain
deployment_info.matplus WAV files named with date and time, for exampleXXX_N_1_YYYYMMDD_HHMMSS.WAV. ↩︎