soundSat: Soundscape Saturation Index

View source: R/soundSat.R

soundSatR Documentation

Soundscape Saturation Index

Description

Calculate Soundscape Saturation for a combination of recordings using the methodology proposed in Burivalova 2018.

Usage

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
)

Arguments

soundpath

single or multiple directories to your .wav audio files

channel

channel where the saturation values will be extracted from. Available channels are: "stereo", "mono", "left" or "right". Defaults to "stereo".

timeBin

size (in seconds) of the time bin. Set to NULL to use the entire audio as a single bin. Defaults to 60

dbThreshold

minimum allowed value of dB for the spectrograms. Set to NULL to leave db values unrestricted Defaults to -90, as set by Towsey 2017

targetSampRate

desired sample rate of the audios. This argument is only used to down sample the audio. If NULL, then audio's sample rate remains the same. Defaults to NULL

wl

window length of the spectrogram. Defaults to 512

window

window used to smooth the spectrogram. Switch to signal::hanning(wl) to use hanning instead. Defaults to signal::hamming(wl)

overlap

overlap between the spectrogram windows. Defaults to wl/2 (half the window length)

histbreaks

breaks used to calculate Background Noise. Available breaks are: "FD", ⁠"Sturges⁠", "scott" and 100. Defaults to "FD".
Can also be set to any numerical value to limit or increase the amount of breaks.

DCfix

if the DC offset should be removed before the metrics are calculated. Defaults to TRUE

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.
Defaults to c(5, 20, 1), which evaluates thresholds from 5 dB to 20 dB in increments of 1 dB

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.
Defaults to c(0.5, 0.9, 0.05), which evaluates thresholds from 50% to 90% in increments of 5%

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 nortest package. Defaults to "ad.test".
"ks.test" is not available. "shapiro.test" can be used, however we recommend using only when analyzing very few recordings

beta

how BGN thresholds are calculated. If TRUE, BGN thresholds are calculated using all recordings combined. If FALSE, BGN thresholds are calculated separately for each recording. Defaults to TRUE

backup

path to save the backup. Defaults to NULL

Details

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 m, an activity matrix a_{m,f} is first constructed across frequency bins f. A frequency bin is considered active if either its background level (BGN) or its soundscape power (POW) exceeds a defined threshold:

a_{m,f} = \begin{cases} 1, & \text{if } BGN_{m,f} > \theta_1 \ \text{ or } POW_{m,f} > \theta_2 \\ 0, & \text{otherwise} \end{cases}

where \theta is a user-defined threshold applied uniformly to both BGN and POW.

Soundscape saturation for time bin m is then calculated as the proportion of active frequency bins:

S_m = \frac{\sum_{f = 1}^{N} a_{m,f}}{N}

where N 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 S_m, 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.

Value

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 statistics values of the normality test that yielded the most normal distribution. The fourth object (values) contains a data.frame with 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.

References

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

See Also

soundMat() to get saturation for ALL thresholds and multActivity() to get only activity values. Also, check satBackup() if you are working with bigger datasets.

Examples


### 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)


Ruido documentation built on Sept. 2, 2026, 1:07 a.m.