bioacoustic-synthesis
Builds synthetic soundscapes by mixing isolated vocalisations into field-recorded backgrounds at controlled signal-to-noise ratios. Because every source signal is known before it is mixed, each placement carries an analytically derived label — presence, time span, time-frequency box, and time-frequency mask — with no hand annotation.
Install
pip install bioacoustic-synthesis
Quick start
bioacoustic-synthesis -c config.yaml
Useful flags: -i reviews each generated soundscape interactively, -n caps the
number of source files used per class, and -s fixes the RNG seed. Omit -s and
a seed is drawn at random and written into the output's generation_config.yaml,
so any run can be reproduced after the fact.
Input
Three folders of audio, all pointed at from the config. Formats: .wav, .flac,
.mp3.
Positives — isolated vocalisations, one subfolder per class. The subfolder name becomes the class label. Each clip should contain the target call and as little else as possible, since everything in the clip is placed into the mix and counted as signal when the SNR is set.
vocalisations/
├── petroica_australis/
│ ├── clip_001.wav
│ └── clip_002.wav
└── prosthemadera_novaeseelandiae/
└── clip_003.wav
Negatives — isolated contaminants: rain, wind gusts, machinery, handling noise, anything that a detector should learn to reject. These are placed like vocalisations, at a comparable SNR, and generate no labels.
Backgrounds — clean ambience carrying none of the positive classes, since any
call present here becomes an unlabelled positive in the output. Each file must be
longer than length_seconds so a window can be cropped from it; shorter files
are reassigned to the negatives pool. Background diversity is the single largest
influence on how well a detector trained on the result generalises, so favour many
distinct recordings over long ones.
Optionally, a tags.csv in a positives or negatives folder with a filename
column attaches arbitrary metadata to each record.
Configuration
Everything is driven by one YAML file. See config.example.yaml:
paths:
vocalisations: [corpora/vocalisations]
negative: [corpora/negatives]
noise: [corpora/backgrounds]
output: output
synthesis:
n_soundscapes: 1000
length_seconds: 10
sample_rate: 32000
# How many events land in each soundscape, drawn uniformly in range
positive_overlay_range: [1, 4]
negative_overlay_range: [0, 2]
# Consecutive plays of the same source clip, and the gap between them
repetitions: [1, 3]
repetitions_spacing_s: [0.5, 3.0]
# True dB power ratios, measured where the overlay actually has energy
snr_db_range: [0, 25]
negative_snr_db_range: [0, 10]
# Label definition: a pixel joins the mask at this many dB above the local
# noise floor, and a placement is rejected if too little of its mask survives
mask_threshold_db: 1
minimum_mask_area_px: 200
edge_fade_ms: 50
# Whether band-limited backgrounds are usable, and the tolerance for calling
# a recording full-band
allow_bandpass: true
bandpass_tolerance_hz: 500
synthetic_noise:
white: true
pink: true
brown: true
probability: 0.5
db_range: [-46.0, -30.0]
spectrogram:
n_fft: 2048
win_length: 2048
hop_length: 512
log_base: 10.0
output:
include_audio: true
include_spectrogram: true
include_boxes: true
include_masks: true
include_presence: true
include_simple_labels: true
overwrite: true
color_mode: HSV # HSV, RGB, or L (greyscale)
target_db: -10.0
generate_raw_dataset: false
ignore_classes: []
proportions:
species: {}
noise: {}
Output
Written to <output>/artificial_dataset/:
| Path | Contents |
|---|---|
sound_files/ |
the mixed soundscape, 16-bit PCM WAV |
images/ |
the rendered spectrogram, 640×640 JPEG, PCEN-normalised, log-frequency |
labels/ |
class ids present in the soundscape, space separated |
presence/ |
1000-bin boolean array over the window, .npy |
box_labels/ |
time-frequency boxes in YOLO format |
unetplusplus_masks/ |
paired PNGs — image, per-instance mask, per-class mask |
provenance.csv |
every placement: source file, species, sample range, SNR |
species_value_map.csv |
class id to label |
dataset.yaml |
class map for YOLO training |
generation_config.yaml |
the config used, plus the seeds and limits the run applied |
example/ |
the first three soundscapes as audio and annotated figures |
Each placement is labelled at four levels of detail, all derived from the same source signal:
| Presence | Time span | Time-frequency box | Time-frequency mask |
The mask is the primary label. It marks every spectrogram pixel where the
isolated source sits at least mask_threshold_db above the noise floor measured
at that placement, so it follows the call's actual structure rather than a
rectangle around it. The box is the mask's extent, and the time span and presence
labels are progressive reductions of the same measurement. A placement whose mask
is smaller than minimum_mask_area_px is discarded and redrawn, which keeps the
faintest events out of the labels rather than labelling something invisible.
Setting generate_raw_dataset: true produces a second, parallel dataset from
unisolated source clips, for comparing what the isolation contributes.
Licence
GNU GPLv3
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file bioacoustic_synthesis-0.1.0.tar.gz.
File metadata
- Download URL: bioacoustic_synthesis-0.1.0.tar.gz
- Upload date:
- Size: 49.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.7.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0a305a6f18a5b47089ec30011d00d35d16c7c85e78331737bc094dbc5dff5d81
|
|
| MD5 |
0e0a68baf4f356dd3a875a3c07a7ec10
|
|
| BLAKE2b-256 |
33f9fd5eb294f51d44dbbefc29cf8ae1e29bf29c6590a478d2c18d0cb83aa25a
|
File details
Details for the file bioacoustic_synthesis-0.1.0-py3-none-any.whl.
File metadata
- Download URL: bioacoustic_synthesis-0.1.0-py3-none-any.whl
- Upload date:
- Size: 51.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.7.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
86dd40c5aba120622d7b48a0f22a9f253cf0e2725d39ccd3b13d650e4a4ef73c
|
|
| MD5 |
0729cfddeaa8ce231d0cb4b39b0d5078
|
|
| BLAKE2b-256 |
f0e96be9e79639a4046a43a0ba2f2108d29cd80912efcfed27e676fb238bf405
|