| Title: | Soundscape Spectral Metrics |
|---|---|
| Description: | Accessible and flexible implementation of spectral ecoacoustic indices. The functions were design to accommodate a variety of sampling designs. Users can tailor calculations by specifying spectrogram time bin size, amplitude thresholds and normality tests. By simplifying computation and standardizing reproducible methods, the package aims to support ecoacoustics studies. |
| Authors: | Arthur Igor da Fonseca-Freire [aut, cre, cph], Weslley Geremias dos Santos [aut], Lucas Rodriguez Forti [aut] |
| Maintainer: | Arthur Igor da Fonseca-Freire <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 1.0.3 |
| Built: | 2026-05-22 05:47:14 UTC |
| Source: | https://github.com/arthurigorr/ruido |
Calculate the Acoustic Complexity Index values of a single audio using the methodology proposed in Pieretti, et al. 2011
ACIspec( soundfile, channel = "stereo", timeBin = 60, j = 5, targetSampRate = NULL, wl = 512, window = signal::hamming(wl), overlap = ceiling(length(window)/2) )ACIspec( soundfile, channel = "stereo", timeBin = 60, j = 5, targetSampRate = NULL, wl = 512, window = signal::hamming(wl), overlap = ceiling(length(window)/2) )
soundfile |
tuneR Wave object or path to a valid audio file |
channel |
channel where the metric values will be extract from. Available channels are: |
timeBin |
size (in seconds) of the time bin. Set to |
j |
size (in seconds) of the cluster interval. Set to |
targetSampRate |
desired sample rate of the audios. This argument is only used to down sample the audio. If |
wl |
window length of the spectrogram. Defaults to |
window |
window used to smooth the spectrogram. Switch to |
overlap |
overlap between the spectrogram windows. Defaults to |
The Acoustic Complexity Index (ACI) quantifies the average proportional change in spectral amplitude between adjacent time steps across frequency bins. Because biological sounds, particularly bird vocalizations, often exhibit rapid and irregular amplitude fluctuations over time, ACI captures this temporal variability as a proxy for acoustic complexity.
In Ruido, ACI is computed independently within each time bin. Within a time bin, the signal is further subdivided into smaller temporal segments, here referred to as cluster intervals .
For a given frequency bin , acoustic intensity values are evaluated across consecutive time steps within each cluster interval . The absolute differences between adjacent time steps are calculated as:
These differences are summed within each cluster interval:
where is the number of time steps in interval . The ACI for each cluster interval is then:
where is the total acoustic intensity within the same interval.
For each frequency bin , ACI values are summed across all cluster intervals within the time bin:
where is the number of cluster intervals in the time bin.
The result is a frequency-resolved representation of ACI for each time bin, rather than a single scalar value for the entire recording.
In the original formulation (Pieretti et al., 2011), ACI is further summed across all frequency bins:
where is the total number of frequency bins. This final aggregation step is not performed in this package.
This function returns a noise.matrix object.
Pieretti, N., Farina, A., & Morri, D. (2011). A new methodology to infer the singing activity of an avian community: The Acoustic Complexity Index (ACI). Ecological Indicators, 11(3), 868–873. https://doi.org/10.1016/j.ecolind.2010.11.005
### This is a secondary example using audio from a real soundscape ### These audios are originated from the Escutadô Project, a project ### that records the soundscapes of the brazilian semiarid # Getting audiofile from the online Zenodo library dir <- paste(tempdir(), "forExample", sep = "/") dir.create(dir) rec <- paste0("GAL24576_20250401_", sprintf("%06d", 0), ".wav") recDir <- paste(dir, rec , sep = "/") url <- paste0("https://zenodo.org/records/17575795/files/", rec, "?download=1") # Downloading the file, might take some time denpending on your internet download.file(url, destfile = recDir, mode = "wb") # Running the ACIspec function with all the default arguments aci <- ACIspec(recDir) # Here's the result aci # Plot ACI values plot(aci)### This is a secondary example using audio from a real soundscape ### These audios are originated from the Escutadô Project, a project ### that records the soundscapes of the brazilian semiarid # Getting audiofile from the online Zenodo library dir <- paste(tempdir(), "forExample", sep = "/") dir.create(dir) rec <- paste0("GAL24576_20250401_", sprintf("%06d", 0), ".wav") recDir <- paste(dir, rec , sep = "/") url <- paste0("https://zenodo.org/records/17575795/files/", rec, "?download=1") # Downloading the file, might take some time denpending on your internet download.file(url, destfile = recDir, mode = "wb") # Running the ACIspec function with all the default arguments aci <- ACIspec(recDir) # Here's the result aci # Plot ACI values plot(aci)
Calculate the Acoustic Activity Matrix using the methodology proposed in Burivalova 2018
activity( soundfile, channel = "stereo", timeBin = 60, dbThreshold = -90, targetSampRate = NULL, wl = 512, window = signal::hamming(wl), overlap = ceiling(length(window)/2), histbreaks = "FD", DCfix = TRUE, powthr = 10, bgnthr = 0.8, beta = TRUE )activity( soundfile, channel = "stereo", timeBin = 60, dbThreshold = -90, targetSampRate = NULL, wl = 512, window = signal::hamming(wl), overlap = ceiling(length(window)/2), histbreaks = "FD", DCfix = TRUE, powthr = 10, bgnthr = 0.8, beta = TRUE )
soundfile |
tuneR Wave object or path to a valid audio |
channel |
channel where the saturation values will be extract from. Available channels are: |
timeBin |
size (in seconds) of the time bin. Set to |
dbThreshold |
minimum allowed value of dB for the spectrograms. Set to |
targetSampRate |
desired sample rate of the audios. This argument is only used to down sample the audio. If |
wl |
window length of the spectrogram. Defaults to |
window |
window used to smooth the spectrogram. Switch to |
overlap |
overlap between the spectrogram windows. Defaults to |
histbreaks |
breaks used to calculate Background Noise. Available breaks are: |
DCfix |
if the DC offset should be removed before the metrics are calculated. Defaults to |
powthr |
single numeric value to calculate the activity matrix for soundscape power (in dB). Defaults to |
bgnthr |
single numeric value to calculate the activity matrix for background noise (in %). Defaults to |
beta |
how BGN thresholds are calculated. If |
To calculate the activity matrix, we use the methodology proposed by Burivalova 2018. We begin by applying the following formula to each time bin of the recording:
where is a user-defined threshold applied uniformly to both BGN and POW. We set 1 to active and 0 to inactive frequency windows.
This function returns a 0 and 1 matrix containing the activity for all time bins of the inputted file. The matrix's number of rows will equal to half the set window length (wl) and number of columns will equal the number of bins. Cells with the value of 1 represent the acoustically active frequency of a bin.
Burivalova, Z., Towsey, M., Boucher, T., Truskinger, A., Apelis, C., Roe, P., & Game, E. T. (2018). Using soundscapes to detect variable degrees of human influence on tropical forests in Papua New Guinea. Conservation Biology, 32(1), 205-215. https://doi.org/10.1111/cobi.12968
if (require("ggplot2")) { library(ggplot2) # We are going to load a sample noise.matrix object to demonstrate the basic usage of singleSat() # To understand about the origin of this noise.matrix, check: ?sampleBGN data("sampleBGN") # View the sample noise.matrix object sampleBGN # Run the function sat <- activity(sampleBGN) # Now we can plot the results for the left channel satLeft <- sat[,1:3] satDim <- dim(satLeft) numericTime <- seq(0, sum(sampleBGN@timeBins), by = sampleBGN@timeBins[1]) labels <- paste0(numericTime[-length(numericTime)], "-", numericTime[-1], "s") satDF <- data.frame(BIN = rep(paste0("BIN", seq(satDim[2])), each = satDim[1]), WIN = rep(seq(satDim[1]), satDim[2]), ACT = factor(c(sat), levels = c(0,1))) ggplot(satDF, aes(x = BIN, y = WIN, fill = ACT)) + geom_tile() + theme_bw() + scale_fill_manual(values = c("white", "black")) + scale_y_continuous(expand = c(0,0)) + scale_x_discrete(expand = c(0,0), labels = labels) + labs(x = "Time Bin", y = "Spectral Window") + guides(fill = guide_legend(title = "Activity")) }if (require("ggplot2")) { library(ggplot2) # We are going to load a sample noise.matrix object to demonstrate the basic usage of singleSat() # To understand about the origin of this noise.matrix, check: ?sampleBGN data("sampleBGN") # View the sample noise.matrix object sampleBGN # Run the function sat <- activity(sampleBGN) # Now we can plot the results for the left channel satLeft <- sat[,1:3] satDim <- dim(satLeft) numericTime <- seq(0, sum(sampleBGN@timeBins), by = sampleBGN@timeBins[1]) labels <- paste0(numericTime[-length(numericTime)], "-", numericTime[-1], "s") satDF <- data.frame(BIN = rep(paste0("BIN", seq(satDim[2])), each = satDim[1]), WIN = rep(seq(satDim[1]), satDim[2]), ACT = factor(c(sat), levels = c(0,1))) ggplot(satDF, aes(x = BIN, y = WIN, fill = ACT)) + geom_tile() + theme_bw() + scale_fill_manual(values = c("white", "black")) + scale_y_continuous(expand = c(0,0)) + scale_x_discrete(expand = c(0,0), labels = labels) + labs(x = "Time Bin", y = "Spectral Window") + guides(fill = guide_legend(title = "Activity")) }
Calculate the Background Noise and Soundscape Power values of a single audio using the methodology proposed in Towsey 2017
bgNoise( soundfile, channel = "stereo", timeBin = 60, dbThreshold = -90, targetSampRate = NULL, wl = 512, window = signal::hamming(wl), overlap = ceiling(length(window)/2), histbreaks = "FD", DCfix = TRUE )bgNoise( soundfile, channel = "stereo", timeBin = 60, dbThreshold = -90, targetSampRate = NULL, wl = 512, window = signal::hamming(wl), overlap = ceiling(length(window)/2), histbreaks = "FD", DCfix = TRUE )
soundfile |
tuneR Wave object or path to a valid audio file |
channel |
channel where the metric values will be extract from. Available channels are: |
timeBin |
size (in seconds) of the time bin. Set to |
dbThreshold |
minimum allowed value of dB for the spectrograms. Set to |
targetSampRate |
desired sample rate of the audios. This argument is only used to down sample the audio. If |
wl |
window length of the spectrogram. Defaults to |
window |
window used to smooth the spectrogram. Switch to |
overlap |
overlap between the spectrogram windows. Defaults to |
histbreaks |
breaks used to calculate Background Noise. Available breaks are: |
DCfix |
if the DC offset should be removed before the metrics are calculated. Defaults to |
Background Noise (BGN) is an acoustic metric that estimates the dominant baseline level of acoustic energy within a frequency window and time bin. It was described by Towsey (2017) based on the approach of Lamel et al. (1981).
For each frequency window and time bin , BGN is defined as the modal value of the intensity distribution (in dB), representing the most frequently occurring sound level:
This value approximates the continuous background component of the soundscape, filtering out transient acoustic events such as bird calls or other short-duration signals.
Soundscape Power (POW) quantifies the contrast between this baseline level and the strongest acoustic events within the same frequency window and time bin. It is defined as:
where is the maximum intensity observed. POW can be interpreted as a proxy for signal-to-noise ratio, with higher values indicating stronger or more prominent acoustic events relative to the background level.
This function returns a noise.matrix object
Towsey, M. W. (2017). The calculation of acoustic indices derived from long-duration recordings of the natural environment. In eprints.qut.edu.au. https://eprints.qut.edu.au/110634/
Lamel, L., Rabiner, L., Rosenberg, A., & Wilpon, J. (1981). An improved endpoint detector for isolated word recognition. IEEE Transactions on Acoustics, Speech, and Signal Processing, 29(4), 777-785 https://doi.org/10.1109/TASSP.1981.1163642
### For our main example we'll create an artificial audio with ### white noise to test its Background Noise # We'll use the package tuneR library(tuneR) # Define the audio sample rate, duration and number of samples samprate <- 12050 dur <- 60 n <- samprate * dur # Then we generate white noise set.seed(413) noise <- rnorm(n) # Linear fade-out envelope fade <- seq(1, 0, length.out = n) # Apply fade signal <- noise * fade wave <- Wave(left = signal, right = signal, samp.rate = samprate, bit = 16) # Heres our artificial audio wave # Running the bgNoise function with all the default arguments bgn <- bgNoise(wave) # See the results bgn # Plot background noise and soundscape power plot(bgn) ### This is a secondary example using audio from a real soundscape ### These audios are originated from the Escutadô Project, a project ### that records the soundscapes of the brazilian semiarid # Getting audiofile from the online Zenodo library dir <- paste(tempdir(), "forExample", sep = "/") dir.create(dir) rec <- paste0("GAL24576_20250401_", sprintf("%06d", 0), ".wav") recDir <- paste(dir, rec , sep = "/") url <- paste0("https://zenodo.org/records/17575795/files/", rec, "?download=1") # Downloading the file, might take some time denpending on your internet download.file(url, destfile = recDir, mode = "wb") # Running the bgNoise function with all the default arguments bgn <- bgNoise(recDir) # Here's the result bgn # Plot background noise and soundscape power values plot(bgn) # Plot the two indices against each other plot(bgn@values$left$BGN$BGN1, bgn@values$left$POW$POW1, xlab = "BGN (dB)", ylab = "POW (dB)", pch = 16) # Now lets test and plot their correlation BGNPOWlm <- lm(bgn@values$left$BGN$BGN1~bgn@values$left$POW$POW1) summary(BGNPOWlm) abline(lm(bgn@values$left$BGN$BGN1~bgn@values$left$POW$POW1), col = "red")### For our main example we'll create an artificial audio with ### white noise to test its Background Noise # We'll use the package tuneR library(tuneR) # Define the audio sample rate, duration and number of samples samprate <- 12050 dur <- 60 n <- samprate * dur # Then we generate white noise set.seed(413) noise <- rnorm(n) # Linear fade-out envelope fade <- seq(1, 0, length.out = n) # Apply fade signal <- noise * fade wave <- Wave(left = signal, right = signal, samp.rate = samprate, bit = 16) # Heres our artificial audio wave # Running the bgNoise function with all the default arguments bgn <- bgNoise(wave) # See the results bgn # Plot background noise and soundscape power plot(bgn) ### This is a secondary example using audio from a real soundscape ### These audios are originated from the Escutadô Project, a project ### that records the soundscapes of the brazilian semiarid # Getting audiofile from the online Zenodo library dir <- paste(tempdir(), "forExample", sep = "/") dir.create(dir) rec <- paste0("GAL24576_20250401_", sprintf("%06d", 0), ".wav") recDir <- paste(dir, rec , sep = "/") url <- paste0("https://zenodo.org/records/17575795/files/", rec, "?download=1") # Downloading the file, might take some time denpending on your internet download.file(url, destfile = recDir, mode = "wb") # Running the bgNoise function with all the default arguments bgn <- bgNoise(recDir) # Here's the result bgn # Plot background noise and soundscape power values plot(bgn) # Plot the two indices against each other plot(bgn@values$left$BGN$BGN1, bgn@values$left$POW$POW1, xlab = "BGN (dB)", ylab = "POW (dB)", pch = 16) # Now lets test and plot their correlation BGNPOWlm <- lm(bgn@values$left$BGN$BGN1~bgn@values$left$POW$POW1) summary(BGNPOWlm) abline(lm(bgn@values$left$BGN$BGN1~bgn@values$left$POW$POW1), col = "red")
Calculate the Acoustic Activity Matrix used in the the calculation of Soundscape Saturation using Burivalova 2018 methodology for a set of recordings
multActivity( soundpath, channel = "stereo", timeBin = 60, dbThreshold = -90, targetSampRate = NULL, wl = 512, window = signal::hamming(wl), overlap = ceiling(length(window)/2), histbreaks = "FD", DCfix = TRUE, powthr = 10, bgnthr = 0.8, beta = TRUE, backup = NULL )multActivity( soundpath, channel = "stereo", timeBin = 60, dbThreshold = -90, targetSampRate = NULL, wl = 512, window = signal::hamming(wl), overlap = ceiling(length(window)/2), histbreaks = "FD", DCfix = TRUE, powthr = 10, bgnthr = 0.8, beta = TRUE, backup = NULL )
soundpath |
single or multiple directories to your audio files |
channel |
channel where the saturation values will be extract from. Available channels are: |
timeBin |
size (in seconds) of the time bin. Set to |
dbThreshold |
minimum allowed value of dB for the spectrograms. Set to |
targetSampRate |
desired sample rate of the audios. This argument is only used to down sample the audio. If |
wl |
window length of the spectrogram. Defaults to |
window |
window used to smooth the spectrogram. Switch to |
overlap |
overlap between the spectrogram windows. Defaults to |
histbreaks |
breaks used to calculate Background Noise. Available breaks are: |
DCfix |
if the DC offset should be removed before the metrics are calculated. Defaults to |
powthr |
single numeric value to calculate the activity matrix for soundscape power (in dB). Defaults to |
bgnthr |
single numeric value to calculate the activity matrix for background noise (in %). Defaults to |
beta |
how BGN thresholds are calculated. If |
backup |
directory to save the backup. Defaults to |
In this function, we only generate activity matrices for an directory using Burivalova 2018 methodology. For each time bin of the recording we apply the following formula:
where is a user-defined threshold applied uniformly to both BGN and POW. We set 1 to active and 0 to inactive frequency windows.
If backup is set to a valid directory, a file named "SATBACKUP.RData" is automatically saved after every batch of five processed files. This file stores the current processing state and allows interrupted runs (e.g., due to manual termination, session crashes, or system shutdowns) to be resumed using satBackup().
To resume processing, pass the saved file (e.g., "path/SATBACKUP.RData") to satBackup(). Once a backup has been created, all original arguments and file paths must remain unchanged, unless they are explicitly modified within the saved .RData object.
A list containing five objects. The first and second objects (powthresh and bgnthresh) are the threshold values inputted as arguments into the function. The third (info) contains the following variables from every audio file: PATH, AUDIO, CHANNEL, DURATION, BIN, SAMPRATE.. The fourth object (values) contains a matrix with the the values of activity for each bin of each recording and the size of the bin in seconds. The fifth contains a list with errors that occurred with specific files during the function.
Burivalova, Z., Towsey, M., Boucher, T., Truskinger, A., Apelis, C., Roe, P., & Game, E. T. (2018). Using soundscapes to detect variable degrees of human influence on tropical forests in Papua New Guinea. Conservation Biology, 32(1), 205-215. https://doi.org/10.1111/cobi.12968
soundSat() and soundMat() to get saturation values. Also, check satBackup() if you are working with larger datasets and want some safety.
if (require("ggplot2") & require("patchwork")) { ### Generating an artificial audio for the example ## For this example we'll generate a sweep in a noisy soundscape library(ggplot2) library(patchwork) ### Downloading audiofiles from public Zenodo library dir <- paste0(tempdir(), "/forExamples") dir.create(dir) recName <- paste0("GAL24576_20250401_", sprintf("%06d", seq(0, 200000, by = 50000)), ".wav") recDir <- paste(dir, recName, sep = "/") for (rec in recName) { print(rec) url <- paste0("https://zenodo.org/records/17575795/files/", rec, "?download=1") download.file(url, destfile = paste(dir, rec, sep = "/"), mode = "wb") } time <- sapply(strsplit(recName, "_"), function(x) paste(substr(x[3], 1, 2), substr(x[3], 3, 4), substr(x[3], 5, 6), sep = ":")) date <- sapply(strsplit(recName, "_"), function(x) paste(substr(x[2], 1, 4), substr(x[2], 5, 6), substr(x[2], 7, 8), sep = "-")) dateTime <- as.POSIXct(paste(date, time)) timeLabels <- time[c(1, 7, 13, 19, 24)] timeBreaks <- as.character(dateTime[c(1, 7, 13, 19, 24)]) breaks <- round(c(1, cumsum(rep(256 / 6, 6)))) ### Running the function act <- multActivity(dir) plotN <- 1 sDim <- dim(act$values) sampRate <- act$info$SAMPRATE[1] kHz <- cumsum(c(0, rep(sampRate / 6, 6))) / 1000 plotList <- list() for (cha in c("left", "right")) { actCurrent <- act$values[, act$info$CHANNEL == cha] actCurrentDF <- data.frame( TIME = as.character(rep(dateTime, each = sDim[1])), SPEC = rep(seq(sDim[1]), sDim[2]), VAL = factor(c(unlist(actCurrent)), levels = c(0, 1)) ) plotList[[plotN]] <- ggplot(actCurrentDF, aes(x = TIME, y = SPEC, fill = VAL)) + geom_tile() + theme_classic() + scale_y_continuous(expand = c(NA, NA), labels = kHz, breaks = breaks) + scale_x_discrete(expand = c(0, 0), labels = time) + scale_fill_manual(values = c("white", "black"), labels = c("Inactive", "Active")) + guides(fill = guide_legend(title = "Acoustic Activity")) + labs( x = "Time of Day", y = "Frequency (kHz)", title = paste("Acoustic Activity in the", cha, "channel") ) plotN <- plotN + 1 } plotList[[1]] + plotList[[2]] + plot_layout(guide = "collect") unlink(recDir) unlink(dir) }if (require("ggplot2") & require("patchwork")) { ### Generating an artificial audio for the example ## For this example we'll generate a sweep in a noisy soundscape library(ggplot2) library(patchwork) ### Downloading audiofiles from public Zenodo library dir <- paste0(tempdir(), "/forExamples") dir.create(dir) recName <- paste0("GAL24576_20250401_", sprintf("%06d", seq(0, 200000, by = 50000)), ".wav") recDir <- paste(dir, recName, sep = "/") for (rec in recName) { print(rec) url <- paste0("https://zenodo.org/records/17575795/files/", rec, "?download=1") download.file(url, destfile = paste(dir, rec, sep = "/"), mode = "wb") } time <- sapply(strsplit(recName, "_"), function(x) paste(substr(x[3], 1, 2), substr(x[3], 3, 4), substr(x[3], 5, 6), sep = ":")) date <- sapply(strsplit(recName, "_"), function(x) paste(substr(x[2], 1, 4), substr(x[2], 5, 6), substr(x[2], 7, 8), sep = "-")) dateTime <- as.POSIXct(paste(date, time)) timeLabels <- time[c(1, 7, 13, 19, 24)] timeBreaks <- as.character(dateTime[c(1, 7, 13, 19, 24)]) breaks <- round(c(1, cumsum(rep(256 / 6, 6)))) ### Running the function act <- multActivity(dir) plotN <- 1 sDim <- dim(act$values) sampRate <- act$info$SAMPRATE[1] kHz <- cumsum(c(0, rep(sampRate / 6, 6))) / 1000 plotList <- list() for (cha in c("left", "right")) { actCurrent <- act$values[, act$info$CHANNEL == cha] actCurrentDF <- data.frame( TIME = as.character(rep(dateTime, each = sDim[1])), SPEC = rep(seq(sDim[1]), sDim[2]), VAL = factor(c(unlist(actCurrent)), levels = c(0, 1)) ) plotList[[plotN]] <- ggplot(actCurrentDF, aes(x = TIME, y = SPEC, fill = VAL)) + geom_tile() + theme_classic() + scale_y_continuous(expand = c(NA, NA), labels = kHz, breaks = breaks) + scale_x_discrete(expand = c(0, 0), labels = time) + scale_fill_manual(values = c("white", "black"), labels = c("Inactive", "Active")) + guides(fill = guide_legend(title = "Acoustic Activity")) + labs( x = "Time of Day", y = "Frequency (kHz)", title = paste("Acoustic Activity in the", cha, "channel") ) plotN <- plotN + 1 } plotList[[1]] + plotList[[2]] + plot_layout(guide = "collect") unlink(recDir) unlink(dir) }
This class object is generated by the bgNoise function. It can be read by soundSat.
Methods: show() and plot()
A noise.matrix object
valuesa list containing the values of BGN and POW. Indices are separated in individual data.frames by channel
timeBinsnumeric vector containing the duration of each time bin
sampRatesingle numeric string containing the audio's sampling rate
wlsingle numeric string containing the spectrogram's window length
channelsingle character string containing the channel or channels used to calculated the indices
Plot noise.matrix objects
## S4 method for signature 'noise.matrix,ANY' plot( x, channel = NULL, bin = 1, index = NULL, nbreaks = 5, yunit = c("hz", "khz"), main = NULL, xlab = NULL, ylab = "Frequency", col = c("blue", "red"), type = "p", draw0 = TRUE, box = TRUE, axes = TRUE, annotate = TRUE, ... )## S4 method for signature 'noise.matrix,ANY' plot( x, channel = NULL, bin = 1, index = NULL, nbreaks = 5, yunit = c("hz", "khz"), main = NULL, xlab = NULL, ylab = "Frequency", col = c("blue", "red"), type = "p", draw0 = TRUE, box = TRUE, axes = TRUE, annotate = TRUE, ... )
x |
an |
channel |
channel or channels to be ploted. By default, this set to |
bin |
temporal bin to be plotted. Defaults to |
index |
a character vector of length 1 or 2 with indexes to be plotted. Available indices are: |
nbreaks |
amount of breaks of the y axis. Defaults to |
yunit |
frequency unit to be used in plot. Available units are: |
main |
title for the plot. Set two strings if you are plotting and stereo noise.matrix. If set to |
xlab |
label for the x-axis. Changes depending on |
ylab |
label for the y-axis. Defaults to |
col |
plotting color for de indices. Defaults to |
type |
desired plot type. For details see base::plot |
draw0 |
if a stripped line should be drawn at 0. Defaults to |
box |
if a box should be drawn around the plot. Defaults to |
axes |
if axes should be drawn. Defaults to |
annotate |
if bin information should be added to the plot. Defaults to |
... |
further graphical parameters passed down to plot |
This is a method to quickly plot the results of bgNoise. This calls the helper function plotBGN, which is not meant to be used or seen by the user.
Plot noise.matrix objects
plotNOISE( x, channel, bin, index, nbreaks, yunit, main, xlab, ylab, col, type, draw0, box, axes, annotate, ... )plotNOISE( x, channel, bin, index, nbreaks, yunit, main, xlab, ylab, col, type, draw0, box, axes, annotate, ... )
x |
an |
channel |
channel or channels to be ploted. By default, this set to |
bin |
temporal bin to be plotted. Defaults to |
index |
a character vector of length 1 or 2 with indexes to be plotted. Available indices are: |
nbreaks |
amount of breaks of the y axis. Defaults to |
yunit |
frequency unit to be used in plot. Available units are: |
main |
title for the plot. Set two strings if you are plotting and stereo noise.matrix. If set to |
xlab |
label for the x-axis. Changes depending on |
ylab |
label for the y-axis. Defaults to |
col |
plotting color for de indices. Defaults to |
type |
desired plot type. For details see base::plot |
draw0 |
if a stripped line should be drawn at 0. Defaults to |
box |
if a box should be drawn around the plot. Defaults to |
axes |
if axes should be drawn. Defaults to |
annotate |
if bin information should be added to the plot. Defaults to |
... |
further graphical parameters passed down to plot |
This is a method to quickly plot the results of bgNoise. This calls the helper function plotBGN, which is not meant to be used or seen by the user.
This is a sample noise.matrix object generated by the bgNoise function. Used in the examples of: singleSat and activity
The original sound file was obtained from the Escutadô Project, an initiative aimed at recording soundscapes across the Brazilian semiarid region. The audio was recorded by an autonomous recorder (SM4) attached approximately 4'11" inches above ground on a metal rod installed in a Black Jurema (Mimosa tenuiflora) forest in Federal Rural University of the Semi-Arid (UFERSA), located in Mossoró, Rio Grande do Norte, Brazil. The recording was taken at midnight (00:00) and is 3 minutes long, with a sampling rate of 48 kHz and gain levels of 16 dB on the left channel and 10 dB on the right channel.
sampleBGNsampleBGN
sampleBGNA noise.matrix object with:
Background Noise and Soundscape Power values
Duration in seconds of each time bin
The recording's sample rate
The window length used to generate the spectrogram used to calculate the metrics
The channel or channels of the recording
https://zenodo.org/records/17243660
This function offers a way to continue an unfinished process of the soundSat(), soundMat() or multActivity() functions through a backup file.
Arguments can't be inputted nor changed since the function will automatically load them from the .RData file. However you may manually change them by editing the file (not recommended).
satBackup(backup)satBackup(backup)
backup |
path to the |
This functions returns the same output of soundSat(), soundMat() or multActivity()
## Not run: # It's impossible to demonstrate this function's intended use due to it's nature # However, here is how this function is used: ## This example will load an entire day of audios to your computer, so beware. ### Downloading audiofiles from public Zenodo library dir <- paste(tempdir(), "forExample", sep = "/") dir.create(dir) recName <- paste0("GAL24576_20250401_", sprintf("%06d", seq(0, 230000, by = 10000)),".wav") recDir <- paste(dir, recName, sep = "/") for(rec in recName) { print(rec) url <- paste0("https://zenodo.org/records/17575795/files/", rec, "?download=1") download.file(url, destfile = paste(dir, rec, sep = "/"), mode = "wb") } sat <- soundSat(dir, backup = dir) # Now pretend the process was interrupted (manually/your R crashed/your computer turned off) # We get the backup file list.files(dir) backupDir <- paste(dir, "SATBACKUP.RData", sep = "/") # To recall the backup you simply: satB <- satBackup(backupDir) head(satB$values) unlink(dir, recursive = TRUE) ## End(Not run)## Not run: # It's impossible to demonstrate this function's intended use due to it's nature # However, here is how this function is used: ## This example will load an entire day of audios to your computer, so beware. ### Downloading audiofiles from public Zenodo library dir <- paste(tempdir(), "forExample", sep = "/") dir.create(dir) recName <- paste0("GAL24576_20250401_", sprintf("%06d", seq(0, 230000, by = 10000)),".wav") recDir <- paste(dir, recName, sep = "/") for(rec in recName) { print(rec) url <- paste0("https://zenodo.org/records/17575795/files/", rec, "?download=1") download.file(url, destfile = paste(dir, rec, sep = "/"), mode = "wb") } sat <- soundSat(dir, backup = dir) # Now pretend the process was interrupted (manually/your R crashed/your computer turned off) # We get the backup file list.files(dir) backupDir <- paste(dir, "SATBACKUP.RData", sep = "/") # To recall the backup you simply: satB <- satBackup(backupDir) head(satB$values) unlink(dir, recursive = TRUE) ## End(Not run)
Single Soundscape Saturation Index
singleSat( soundfile, channel = "stereo", timeBin = 60, dbThreshold = -90, targetSampRate = NULL, wl = 512, window = signal::hamming(wl), overlap = ceiling(length(window)/2), histbreaks = "FD", DCfix = TRUE, powthr = 10, bgnthr = 0.8, beta = TRUE )singleSat( soundfile, channel = "stereo", timeBin = 60, dbThreshold = -90, targetSampRate = NULL, wl = 512, window = signal::hamming(wl), overlap = ceiling(length(window)/2), histbreaks = "FD", DCfix = TRUE, powthr = 10, bgnthr = 0.8, beta = TRUE )
soundfile |
tuneR Wave object, Ruido noise.matrix object or path to a valid audio |
channel |
channel where the background noise values will be extract from. Available channels are: |
timeBin |
size (in seconds) of the time bin. Set to |
dbThreshold |
minimum allowed value of dB for the spectrograms. Set to |
targetSampRate |
sample rate of the audios. Defaults to |
wl |
window length of the spectrogram. Defaults to |
window |
window used to smooth the spectrogram. Defaults to |
overlap |
overlap between the spectrogram windows. Defaults to |
histbreaks |
breaks used to calculate Background Noise. Available breaks are: |
DCfix |
if the DC offset should be removed before the metrics are calculated. Defaults to |
powthr |
a single value to evaluate the activity matrix for Soundscape Power (in %dB). Defaults to |
bgnthr |
a single value to evaluate the activity matrix for Background Noise (in %). Defaults to |
beta |
how BGN thresholds are calculated. If TRUE, BGN thresholds are computed using all recordings combined. |
Soundscape Saturation (SAT) quantifies the proportion of frequency bins that are acoustically active within a given time bin. It wasproposed by Burivalova et al. (2018) as a metric to evaluate the acoustic niche hypothesis.
For each time bin , an activity matrix is first constructed across frequency bins . A frequency bin is considered active if either its background level (BGN) or its soundscape power (POW) exceeds a defined threshold:
where is a user-defined threshold applied uniformly to both BGN and POW.
Soundscape saturation for time bin is then calculated as the proportion of active frequency bins:
where is the total number of frequency bins. Higher values of SAT indicate a greater fraction of the frequency spectrum being occupied by acoustic activity.
A list containing the saturation values for all time bins of the inputted file
Burivalova, Z., Towsey, M., Boucher, T., Truskinger, A., Apelis, C., Roe, P., & Game, E. T. (2018). Using soundscapes to detect variable degrees of human influence on tropical forests in Papua New Guinea. Conservation Biology, 32(1), 205-215. https://doi.org/10.1111/cobi.12968
soundSat() and soundMat() to work with multiple audio files and activity() to get only the activity matrix.
# First example: Using a Ruido noise.matrix object # We are going to load a sample noise.matrix object to demonstrate the basic usage of singleSat() # To understand about the origin of this noise.matrix, check: ?sampleBGN data("sampleBGN") # View the sample noise.matrix object sampleBGN # Run the function SAT <- singleSat(sampleBGN) # View the results SAT # Now lets plot our results to see the dynamics of soundscape saturation by minute maxV <- max(unlist(SAT)) minV <- min(unlist(SAT)) plot(x = c(1, 3), y = c(minV, maxV), type = "n", xlab = "Minute", ylab = "Soundscape Saturation (%)", xaxt = "n") lines(x = 1:3, SAT$left, col = "#1ECBE1", type = "b", pch = 16) axis(1, at = 1:3) lines(x = 1:3, SAT$right, col = "#E1341E", type = "b", pch = 16) legend("topright", legend = c("Left", "Right"), col = c("#1ECBE1", "#E1341E"), lty = 1, pch = 16) # Second example: Using a tuneR Wave-class object # Lets produce an artificial audio with the tuneR package to demonstrate that # the function can also read Wave-class objects (This is the same object used in # the example of bgNoise!) library(tuneR) oldpar <- par(no.readonly = TRUE) # Define parameters for the artificial audio samprate <- 12050 dur <- 59 n <- samprate * dur # White noise set.seed(413) noise <- rnorm(n) # Linear fade-out envelope fade <- seq(1, 0, length.out = n) # Apply fade signal <- noise * fade # Create Wave object wave <- Wave( left = signal, samp.rate = samprate, bit = 16 ) # Running singleSat() on the artificial audio sat <- singleSat(wave, timeBin = 10) # Now we can plot the results # In the left we have a periodogram and in the right saturaion values # along one minute par(mfrow = c(1,2)) image(periodogram(wave, width = 8192, normalize = FALSE), xlab = "Time (s)", ylab = "Frequency (hz)", axes = FALSE) axis(1, labels = seq(0,60, 10), at = seq(0,7e5,length.out = 7)) axis(2) plot(sat$mono, xlab = "Time (s)", ylab = "Soundscape Saturation (%)", type = "b", pch = 16, axes = FALSE) axis(1, labels = paste0(c("0-10","10-20","20-30","30-40","40-50","50-59"), "s"), at = 1:6) axis(2) par(oldpar) # Third example: Reading a file directly # Lets begin by loading an audio from the online Zenodo library and # read it directly with the function # Getting audiofile from the online Zenodo library dir <- paste(tempdir(), "forExample", sep = "/") dir.create(dir) rec <- paste0("GAL24576_20250401_", sprintf("%06d", 0),".wav") recDir <- paste(dir,rec , sep = "/") url <- paste0("https://zenodo.org/records/17575795/files/", rec, "?download=1") # Downloading the file, might take some time denpending on your internet download.file(url, destfile = recDir, mode = "wb") # Now we calculate soundscape saturation for both sides of the recording sat <- singleSat(recDir) # Printing the results print(sat) barplot(unlist(sat), col = c("darkgreen", "red"), names.arg = c("Left", "Right"), ylab = "Soundscape Saturation (%)") unlink(dir, recursive = TRUE)# First example: Using a Ruido noise.matrix object # We are going to load a sample noise.matrix object to demonstrate the basic usage of singleSat() # To understand about the origin of this noise.matrix, check: ?sampleBGN data("sampleBGN") # View the sample noise.matrix object sampleBGN # Run the function SAT <- singleSat(sampleBGN) # View the results SAT # Now lets plot our results to see the dynamics of soundscape saturation by minute maxV <- max(unlist(SAT)) minV <- min(unlist(SAT)) plot(x = c(1, 3), y = c(minV, maxV), type = "n", xlab = "Minute", ylab = "Soundscape Saturation (%)", xaxt = "n") lines(x = 1:3, SAT$left, col = "#1ECBE1", type = "b", pch = 16) axis(1, at = 1:3) lines(x = 1:3, SAT$right, col = "#E1341E", type = "b", pch = 16) legend("topright", legend = c("Left", "Right"), col = c("#1ECBE1", "#E1341E"), lty = 1, pch = 16) # Second example: Using a tuneR Wave-class object # Lets produce an artificial audio with the tuneR package to demonstrate that # the function can also read Wave-class objects (This is the same object used in # the example of bgNoise!) library(tuneR) oldpar <- par(no.readonly = TRUE) # Define parameters for the artificial audio samprate <- 12050 dur <- 59 n <- samprate * dur # White noise set.seed(413) noise <- rnorm(n) # Linear fade-out envelope fade <- seq(1, 0, length.out = n) # Apply fade signal <- noise * fade # Create Wave object wave <- Wave( left = signal, samp.rate = samprate, bit = 16 ) # Running singleSat() on the artificial audio sat <- singleSat(wave, timeBin = 10) # Now we can plot the results # In the left we have a periodogram and in the right saturaion values # along one minute par(mfrow = c(1,2)) image(periodogram(wave, width = 8192, normalize = FALSE), xlab = "Time (s)", ylab = "Frequency (hz)", axes = FALSE) axis(1, labels = seq(0,60, 10), at = seq(0,7e5,length.out = 7)) axis(2) plot(sat$mono, xlab = "Time (s)", ylab = "Soundscape Saturation (%)", type = "b", pch = 16, axes = FALSE) axis(1, labels = paste0(c("0-10","10-20","20-30","30-40","40-50","50-59"), "s"), at = 1:6) axis(2) par(oldpar) # Third example: Reading a file directly # Lets begin by loading an audio from the online Zenodo library and # read it directly with the function # Getting audiofile from the online Zenodo library dir <- paste(tempdir(), "forExample", sep = "/") dir.create(dir) rec <- paste0("GAL24576_20250401_", sprintf("%06d", 0),".wav") recDir <- paste(dir,rec , sep = "/") url <- paste0("https://zenodo.org/records/17575795/files/", rec, "?download=1") # Downloading the file, might take some time denpending on your internet download.file(url, destfile = recDir, mode = "wb") # Now we calculate soundscape saturation for both sides of the recording sat <- singleSat(recDir) # Printing the results print(sat) barplot(unlist(sat), col = c("darkgreen", "red"), names.arg = c("Left", "Right"), ylab = "Soundscape Saturation (%)") unlink(dir, recursive = TRUE)
Get the Soundscape Saturation matrix with all threshold combinations instead of the combination with the most normal distribution.
soundMat( soundpath, channel = "stereo", timeBin = 60, dbThreshold = -90, targetSampRate = NULL, wl = 512, window = signal::hamming(wl), overlap = ceiling(length(window)/2), histbreaks = "FD", DCfix = TRUE, powthr = c(5, 20, 1), bgnthr = c(0.5, 0.9, 0.05), beta = TRUE, backup = NULL )soundMat( soundpath, channel = "stereo", timeBin = 60, dbThreshold = -90, targetSampRate = NULL, wl = 512, window = signal::hamming(wl), overlap = ceiling(length(window)/2), histbreaks = "FD", DCfix = TRUE, powthr = c(5, 20, 1), bgnthr = c(0.5, 0.9, 0.05), beta = TRUE, backup = NULL )
soundpath |
single or multiple directories to your audio files |
channel |
channel where the saturation values will be extract from. Available channels are: |
timeBin |
size (in seconds) of the time bin. Set to |
dbThreshold |
minimum allowed value of dB for the spectrograms. Set to |
targetSampRate |
desired sample rate of the audios. This argument is only used to down sample the audio. If |
wl |
window length of the spectrogram. Defaults to |
window |
window used to smooth the spectrogram. Switch to |
overlap |
overlap between the spectrogram windows. Defaults to |
histbreaks |
breaks used to calculate Background Noise. Available breaks are: |
DCfix |
if the DC offset should be removed before the metrics are calculated. Defaults to |
powthr |
numeric vector of length three containing the the range of thresholds used to evaluate the Soundscape Power of the Activity Matrix (in dB). The values correspond to the minimum threshold, maximum threshold and step size respectively.
|
bgnthr |
numeric vector of length three containing the the range of thresholds used to evaluate the Background Noise of the Activity Matrix (in %). The values correspond to the minimum threshold, maximum threshold and step size respectively.
|
beta |
how BGN thresholds are calculated. If |
backup |
path to save the backup. Defaults to |
Check soundSat() to see how the indices are calculated.
A list containing three objects. The first (info) contains the following variables from every audio file: PATH, AUDIO, CHANNEL, DURATION, BIN, SAMPRATE. The second (values) contains saturation values from all possible threshold combinations. The third (errors) contains the error messages and the paths to the files that returned an error during processing.
Burivalova, Z., Towsey, M., Boucher, T., Truskinger, A., Apelis, C., Roe, P., & Game, E. T. (2018). Using soundscapes to detect variable degrees of human influence on tropical forests in Papua New Guinea. Conservation Biology, 32(1), 205-215. https://doi.org/10.1111/cobi.12968
soundSat() to get only the threshold with the most normal distribution and multActivity() to generate only activity matrices. Also, check satBackup() if you are working with larger datasets and want some safety.
oldpar <- par(no.readonly = TRUE) ### Downloading audiofiles from public Zenodo library dir <- paste(tempdir(), "forExample", sep = "/") dir.create(dir) recName <- paste0("GAL24576_20250401_", sprintf("%06d", seq(0, 200000, by = 50000)), ".wav") recDir <- paste(dir, recName, sep = "/") for (rec in recName) { print(rec) url <- paste0("https://zenodo.org/records/17575795/files/", rec, "?download=1") download.file(url, destfile = paste(dir, rec, sep = "/"), mode = "wb") } ### Running the function sat <- soundMat(dir) ### Plotting results sides <- sat$info$CHANNEL thresholds <- colnames(sat$values) split <- strsplit(thresholds, "/") shapNorm <- apply(sat$values, 2, function(x) if (var(x) == 0) { 0 } else { shapiro.test(x)$statistic }) shapPos <- which.max(shapNorm) par(mfrow = c(3, 2)) plot( sat$values[sides == "left", 1], main = paste0("POW = ", split[[1]][1], "dB | BGN = ", split[[1]][2], "%"), type = "b", ylim = c(0,1), xlab = "Time Index", ylab = "Soundsacpe Saturation (%)", col = "goldenrod" ) points(sat$values[sides == "right", 1], col = "maroon", type = "b") hist(sat$values[,1], main = paste("Histogram of POW = ", split[[1]][1], "dB | BGN = ", split[[1]][2], "%"), xlab = "Soundscape Saturation (%)") plot( sat$values[sides == "left", 144], main = paste0("POW = ", split[[144]][1], "dB | BGN = ", split[[144]][2], "%"), type = "b", ylim = c(0,1), xlab = "Time Index", ylab = "Soundsacpe Saturation (%)", col = "goldenrod" ) points(sat$values[sides == "right", 144], col = "maroon", type = "b") hist(sat$values[,144], main = paste("Histogram of POW = ", split[[144]][1], "dB | BGN = ", split[[144]][2], "%"), xlab = "Soundscape Saturation (%)") plot( sat$values[sides == "left", shapPos], main = paste0( "POW = ", split[[shapPos]][1], "dB | BGN = ", split[[shapPos]][2], "%", "\nshapiro.test. statistic (W): ", which.max(shapNorm) ), type = "b", ylim = c(0,1), xlab = "Time Index", ylab = "Soundsacpe Saturation (%)", col = "goldenrod" ) points(sat$values[sides == "right", shapPos], col = "maroon", type = "b") hist(sat$values[,shapPos], main = paste("Histogram of POW = ", split[[shapPos]][1], "dB | BGN = ", split[[shapPos]][2], "%"), xlab = "Soundscape Saturation (%)") unlink(dir, recursive = TRUE) par(oldpar)oldpar <- par(no.readonly = TRUE) ### Downloading audiofiles from public Zenodo library dir <- paste(tempdir(), "forExample", sep = "/") dir.create(dir) recName <- paste0("GAL24576_20250401_", sprintf("%06d", seq(0, 200000, by = 50000)), ".wav") recDir <- paste(dir, recName, sep = "/") for (rec in recName) { print(rec) url <- paste0("https://zenodo.org/records/17575795/files/", rec, "?download=1") download.file(url, destfile = paste(dir, rec, sep = "/"), mode = "wb") } ### Running the function sat <- soundMat(dir) ### Plotting results sides <- sat$info$CHANNEL thresholds <- colnames(sat$values) split <- strsplit(thresholds, "/") shapNorm <- apply(sat$values, 2, function(x) if (var(x) == 0) { 0 } else { shapiro.test(x)$statistic }) shapPos <- which.max(shapNorm) par(mfrow = c(3, 2)) plot( sat$values[sides == "left", 1], main = paste0("POW = ", split[[1]][1], "dB | BGN = ", split[[1]][2], "%"), type = "b", ylim = c(0,1), xlab = "Time Index", ylab = "Soundsacpe Saturation (%)", col = "goldenrod" ) points(sat$values[sides == "right", 1], col = "maroon", type = "b") hist(sat$values[,1], main = paste("Histogram of POW = ", split[[1]][1], "dB | BGN = ", split[[1]][2], "%"), xlab = "Soundscape Saturation (%)") plot( sat$values[sides == "left", 144], main = paste0("POW = ", split[[144]][1], "dB | BGN = ", split[[144]][2], "%"), type = "b", ylim = c(0,1), xlab = "Time Index", ylab = "Soundsacpe Saturation (%)", col = "goldenrod" ) points(sat$values[sides == "right", 144], col = "maroon", type = "b") hist(sat$values[,144], main = paste("Histogram of POW = ", split[[144]][1], "dB | BGN = ", split[[144]][2], "%"), xlab = "Soundscape Saturation (%)") plot( sat$values[sides == "left", shapPos], main = paste0( "POW = ", split[[shapPos]][1], "dB | BGN = ", split[[shapPos]][2], "%", "\nshapiro.test. statistic (W): ", which.max(shapNorm) ), type = "b", ylim = c(0,1), xlab = "Time Index", ylab = "Soundsacpe Saturation (%)", col = "goldenrod" ) points(sat$values[sides == "right", shapPos], col = "maroon", type = "b") hist(sat$values[,shapPos], main = paste("Histogram of POW = ", split[[shapPos]][1], "dB | BGN = ", split[[shapPos]][2], "%"), xlab = "Soundscape Saturation (%)") unlink(dir, recursive = TRUE) par(oldpar)
Calculate Soundscape Saturation for a combination of recordings using the methodology proposed in Burivalova 2018.
soundSat( soundpath, channel = "stereo", timeBin = 60, dbThreshold = -90, targetSampRate = NULL, wl = 512, window = signal::hamming(wl), overlap = ceiling(length(window)/2), histbreaks = "FD", DCfix = TRUE, powthr = c(5, 20, 1), bgnthr = c(0.5, 0.9, 0.05), normality = "ad.test", beta = TRUE, backup = NULL )soundSat( soundpath, channel = "stereo", timeBin = 60, dbThreshold = -90, targetSampRate = NULL, wl = 512, window = signal::hamming(wl), overlap = ceiling(length(window)/2), histbreaks = "FD", DCfix = TRUE, powthr = c(5, 20, 1), bgnthr = c(0.5, 0.9, 0.05), normality = "ad.test", beta = TRUE, backup = NULL )
soundpath |
single or multiple directories to your audio files |
channel |
channel where the saturation values will be extract from. Available channels are: |
timeBin |
size (in seconds) of the time bin. Set to |
dbThreshold |
minimum allowed value of dB for the spectrograms. Set to |
targetSampRate |
desired sample rate of the audios. This argument is only used to down sample the audio. If |
wl |
window length of the spectrogram. Defaults to |
window |
window used to smooth the spectrogram. Switch to |
overlap |
overlap between the spectrogram windows. Defaults to |
histbreaks |
breaks used to calculate Background Noise. Available breaks are: |
DCfix |
if the DC offset should be removed before the metrics are calculated. Defaults to |
powthr |
numeric vector of length three containing the the range of thresholds used to evaluate the Soundscape Power of the Activity Matrix (in dB). The values correspond to the minimum threshold, maximum threshold and step size respectively.
|
bgnthr |
numeric vector of length three containing the the range of thresholds used to evaluate the Background Noise of the Activity Matrix (in %). The values correspond to the minimum threshold, maximum threshold and step size respectively.
|
normality |
character string containing the normality test used to determine which threshold combination has the most normal distribution of values. We recommend to pick any test from the |
beta |
how BGN thresholds are calculated. If |
backup |
path to save the backup. Defaults to |
Soundscape Saturation (SAT) quantifies the proportion of frequency bins that are acoustically active within a given time bin. It wasproposed by Burivalova et al. (2018) as a metric to evaluate the acoustic niche hypothesis.
For each time bin , an activity matrix is first constructed across frequency bins . A frequency bin is considered active if either its background level (BGN) or its soundscape power (POW) exceeds a defined threshold:
where is a user-defined threshold applied uniformly to both BGN and POW.
Soundscape saturation for time bin is then calculated as the proportion of active frequency bins:
where is the total number of frequency bins. Higher values of SAT indicate a greater fraction of the frequency spectrum being occupied by acoustic activity.
After computing , the function evaluates all tested threshold values and selects the one that yields the most normally distributed set of saturation values across time bins. Normality is assessed to identify a threshold that best stabilizes the distribution of SAT.
If backup is set to a valid directory, a file named "SATBACKUP.RData" is automatically saved after every batch of five processed files. This file stores the current processing state and allows interrupted runs (e.g., due to manual termination, session crashes, or system shutdowns) to be resumed using satBackup().
To resume processing, pass the saved file (e.g., "path/SATBACKUP.RData") to satBackup(). Once a backup has been created, all original arguments and file paths must remain unchanged, unless they are explicitly modified within the saved .RData object.
A list containing five objects. The first and second objects (powthresh and bgnthresh) are the threshold values that yielded the most normal distribution of saturation values using the normality test set by the user. The third (normality) contains the statitics values of the normality test that yielded the most normal distribution. The fourth object (values) contains a data.frame with the the values of saturation for each bin of each recording and the size of the bin in seconds. The fifth contains a data.frame with errors that occurred with specific files during the function.
Burivalova, Z., Towsey, M., Boucher, T., Truskinger, A., Apelis, C., Roe, P., & Game, E. T. (2018). Using soundscapes to detect variable degrees of human influence on tropical forests in Papua New Guinea. Conservation Biology, 32(1), 205-215. https://doi.org/10.1111/cobi.12968
soundMat() to get saturation for ALL thresholds and multActivity() to get only activity values. Also, check satBackup() if you are working with bigger datasets.
### Downloading audiofiles from public Zenodo library dir <- paste(tempdir(), "forExample", sep = "/") dir.create(dir) recName <- paste0("GAL24576_20250401_", sprintf("%06d", seq(0, 200000, by = 50000)),".wav") recDir <- paste(dir, recName, sep = "/") for(rec in recDir) { print(rec) url <- paste0("https://zenodo.org/records/17575795/files/", basename(rec), "?download=1") download.file(url, destfile = rec, mode = "wb") } ### Running the function sat <- soundSat(dir) ### Preparing the plot timeSplit <- strsplit(sat$values$AUDIO, "_") sides <- sat$values$CHANNEL date <- sapply(timeSplit, function(x) x[2]) time <- sapply(timeSplit, function(x) substr(x[3],1,6)) datePos <- paste(substr(date,1,4), substr(date,5,6), substr(date,7,8), sep = "-") timePos <- paste(substr(time,1,2), substr(time,3,4), substr(time,5,6), sep = ":") dateTime <- as.POSIXct(paste(datePos, timePos), format = "%Y-%m-%d %H:%M:%OS") leftEar <- data.frame(SAT = sat$values$SAT[sides == "left"], HOUR = dateTime[sides == "left"]) rightEar <- data.frame(SAT = sat$values$SAT[sides == "right"], HOUR = dateTime[sides == "right"]) ### Plotting results plot(SAT~HOUR, data = leftEar, ylim = c(range(sat$values$SAT)), col = "darkgreen", pch = 16, ylab = "Soundscape Saturation (%)", xlab = "Time of Day", type = "b") points(SAT~HOUR, data = rightEar, ylim = c(range(sat$values$SAT)), col = "red", pch = 16, type = "b") legend("bottomright", legend = c("Left Ear", "Right Ear"), col = c("darkgreen", "red"), lty = 1) unlink(dir, recursive = TRUE)### Downloading audiofiles from public Zenodo library dir <- paste(tempdir(), "forExample", sep = "/") dir.create(dir) recName <- paste0("GAL24576_20250401_", sprintf("%06d", seq(0, 200000, by = 50000)),".wav") recDir <- paste(dir, recName, sep = "/") for(rec in recDir) { print(rec) url <- paste0("https://zenodo.org/records/17575795/files/", basename(rec), "?download=1") download.file(url, destfile = rec, mode = "wb") } ### Running the function sat <- soundSat(dir) ### Preparing the plot timeSplit <- strsplit(sat$values$AUDIO, "_") sides <- sat$values$CHANNEL date <- sapply(timeSplit, function(x) x[2]) time <- sapply(timeSplit, function(x) substr(x[3],1,6)) datePos <- paste(substr(date,1,4), substr(date,5,6), substr(date,7,8), sep = "-") timePos <- paste(substr(time,1,2), substr(time,3,4), substr(time,5,6), sep = ":") dateTime <- as.POSIXct(paste(datePos, timePos), format = "%Y-%m-%d %H:%M:%OS") leftEar <- data.frame(SAT = sat$values$SAT[sides == "left"], HOUR = dateTime[sides == "left"]) rightEar <- data.frame(SAT = sat$values$SAT[sides == "right"], HOUR = dateTime[sides == "right"]) ### Plotting results plot(SAT~HOUR, data = leftEar, ylim = c(range(sat$values$SAT)), col = "darkgreen", pch = 16, ylab = "Soundscape Saturation (%)", xlab = "Time of Day", type = "b") points(SAT~HOUR, data = rightEar, ylim = c(range(sat$values$SAT)), col = "red", pch = 16, type = "b") legend("bottomright", legend = c("Left Ear", "Right Ear"), col = c("darkgreen", "red"), lty = 1) unlink(dir, recursive = TRUE)