Extract acoustic indices from audio recordings

Acoustic indices can summarize aspects of the acoustic energy distribution in audio recordings and are widely used to characterize animal acoustic communities[1-3]. In this example, we will see how to eficiently compute multiple acoustic indices, and present basics post-processing posibilities. The audio recordings used in this example can be downloaded from the open GitHub repository (https://github.com/scikit-maad/scikit-maad/tree/production/data).

# sphinx_gallery_thumbnail_path = './_images/sphx_glr_plot_extract_alpha_indices_002.png'

import matplotlib.pyplot as plt
import pandas as pd
import os
from maad import sound, features
from maad.util import (
    date_parser, plot_correlation_map,
    plot_features_map, plot_features, false_Color_Spectro
    )

Set Variables

We list all spectral and temporal acoustic indices that will be computed.

SPECTRAL_FEATURES=['MEANf','VARf','SKEWf','KURTf','NBPEAKS','LEQf',
    'ENRf','BGNf','SNRf','Hf', 'EAS','ECU','ECV','EPS','EPS_KURT','EPS_SKEW','ACI',
    'NDSI','rBA','AnthroEnergy','BioEnergy','BI','ROU','ADI','AEI','LFC','MFC','HFC',
    'ACTspFract','ACTspCount','ACTspMean', 'EVNspFract','EVNspMean','EVNspCount',
    'TFSD','H_Havrda','H_Renyi','H_pairedShannon', 'H_gamma', 'H_GiniSimpson','RAOQ',
    'AGI','ROItotal','ROIcover'
    ]

TEMPORAL_FEATURES=['ZCR','MEANt', 'VARt', 'SKEWt', 'KURTt',
    'LEQt','BGNt', 'SNRt','MED', 'Ht','ACTtFraction', 'ACTtCount',
    'ACTtMean','EVNtFraction', 'EVNtMean', 'EVNtCount'
    ]

We parse the directory were the audio dataset is located in order to get a df with date and fullfilename. As the data were collected with a SM4 audio recording device we set the dateformat agument to ‘SM4’ in order to be able to parse the date from the filename. In case of Audiomoth, the date is coded as Hex in the filename. The path to the audio dataset is “../../data/indices/”.

df = date_parser("../../data/indices/", dateformat='SM4', verbose=True)

# remove index => Date becomes a column instead of an index. This is
# required as df_audio_ind, df_spec_ind and df_spec_ind_per_bin do not have
# date as index. Then we can concatenate all the dataframe.
#df = df.reset_index()
S4A03895_20190522_041500.wav
S4A03895_20190522_141500.wav
indices.csv
S4A03895_20190522_073000.wav
S4A03895_20190522_173000.wav
per_bin_indices.csv
S4A03895_20190522_010000.wav
S4A03895_20190522_014500.wav
S4A03895_20190522_110000.wav
S4A03895_20190522_114500.wav
S4A03895_20190522_213000.wav
S4A03895_20190522_180000.wav
S4A03895_20190522_184500.wav
S4A03895_20190522_080000.wav
S4A03895_20190522_084500.wav
S4A03895_20190522_221500.wav
S4A03895_20190522_203000.wav
S4A03895_20190522_094500.wav
S4A03895_20190522_090000.wav
S4A03895_20190522_194500.wav
S4A03895_20190522_190000.wav
S4A03895_20190522_231500.wav
S4A03895_20190522_151500.wav
S4A03895_20190522_051500.wav
S4A03895_20190522_104500.wav
S4A03895_20190522_100000.wav
S4A03895_20190522_004500.wav
S4A03895_20190522_000000.wav
S4A03895_20190522_163000.wav
S4A03895_20190522_063000.wav
S4A03895_20190522_223000.wav
S4A03895_20190522_211500.wav
S4A03895_20190522_071500.wav
S4A03895_20190522_171500.wav
S4A03895_20190522_024500.wav
S4A03895_20190522_020000.wav
S4A03895_20190522_124500.wav
S4A03895_20190522_120000.wav
S4A03895_20190522_043000.wav
S4A03895_20190522_143000.wav
S4A03895_20190522_161500.wav
S4A03895_20190522_061500.wav
S4A03895_20190522_153000.wav
S4A03895_20190522_053000.wav
S4A03895_20190522_130000.wav
S4A03895_20190522_134500.wav
S4A03895_20190522_030000.wav
S4A03895_20190522_034500.wav
S4A03895_20190522_233000.wav
S4A03895_20190522_201500.wav
S4A03895_20190522_193000.wav
S4A03895_20190522_093000.wav
S4A03895_20190522_200000.wav
S4A03895_20190522_204500.wav
S4A03895_20190522_003000.wav
S4A03895_20190522_103000.wav
S4A03895_20190522_060000.wav
S4A03895_20190522_064500.wav
S4A03895_20190522_160000.wav
S4A03895_20190522_164500.wav
S4A03895_20190522_031500.wav
S4A03895_20190522_131500.wav
S4A03895_20190522_174500.wav
S4A03895_20190522_170000.wav
S4A03895_20190522_074500.wav
S4A03895_20190522_070000.wav
S4A03895_20190522_113000.wav
S4A03895_20190522_013000.wav
S4A03895_20190522_121500.wav
S4A03895_20190522_021500.wav
S4A03895_20190522_083000.wav
S4A03895_20190522_183000.wav
S4A03895_20190522_214500.wav
S4A03895_20190522_210000.wav
S4A03895_20190522_054500.wav
S4A03895_20190522_050000.wav
S4A03895_20190522_154500.wav
S4A03895_20190522_150000.wav
S4A03895_20190522_033000.wav
S4A03895_20190522_133000.wav
S4A03895_20190522_001500.wav
S4A03895_20190522_101500.wav
S4A03895_20190522_234500.wav
S4A03895_20190522_230000.wav
S4A03895_20190522_191500.wav
S4A03895_20190522_091500.wav
S4A03895_20190522_220000.wav
S4A03895_20190522_224500.wav
S4A03895_20190522_081500.wav
S4A03895_20190522_181500.wav
S4A03895_20190522_123000.wav
S4A03895_20190522_023000.wav
S4A03895_20190522_140000.wav
S4A03895_20190522_144500.wav
S4A03895_20190522_040000.wav
S4A03895_20190522_044500.wav
S4A03895_20190522_111500.wav
S4A03895_20190522_011500.wav

Batch compute acoustic indices on the audio dataset

df_indices = pd.DataFrame()
df_indices_per_bin = pd.DataFrame()

for index, row in df.iterrows() :

    # get the full filename of the corresponding row
    fullfilename = row['file']
    # Save file basename
    path, filename = os.path.split(fullfilename)
    print ('\n**************************************************************')
    print (filename)

    #### Load the original sound (16bits) and get the sampling frequency fs
    try :
        wave,fs = sound.load(filename=fullfilename, channel='left', detrend=True, verbose=False)

    except:
        # Delete the row if the file does not exist or raise a value error (i.e. no EOF)
        df.drop(index, inplace=True)
        continue

    """ =======================================================================
                    Computation in the time domain
    ========================================================================"""

    # Parameters of the audio recorder. This is not a mandatory but it allows
    # to compute the sound pressure level of the audio file (dB SPL) as a
    # sonometer would do.
    S = -35         # Sensbility microphone-35dBV (SM4) / -18dBV (Audiomoth)
    G = 26+16       # Amplification gain (26dB (SM4 preamplifier))

    # compute all the audio indices and store them into a DataFrame
    # dB_threshold and rejectDuration are used to select audio events.
    df_audio_ind = features.all_temporal_alpha_indices(
        s=wave,
        fs=fs,
        gain=G,
        sensibility=S,
        dB_threshold=3,
        rejectDuration=0.01,
        verbose=False,
        display=False
        )

    """ =======================================================================
                    Computation in the frequency domain
    ========================================================================"""

    # Compute the Power Spectrogram Density (PSD) : Sxx_power
    Sxx_power,tn,fn,ext = sound.spectrogram (
        x=wave,
        fs=fs,
        window='hann',
        nperseg=1024,
        noverlap=1024//2,
        verbose=False,
        display=False,
        savefig=None
        )

    # compute all the spectral indices and store them into a DataFrame
    # flim_low, flim_mid, flim_hi corresponds to the frequency limits in Hz
    # that are required to compute somes indices (i.e. NDSI)
    # if R_compatible is set to 'soundecology', then the output are similar to
    # soundecology R package.
    # mask_param1 and mask_param2 are two parameters to find the regions of
    # interest (ROIs). These parameters need to be adapted to the dataset in
    # order to select ROIs
    df_spec_ind, df_spec_ind_per_bin = features.all_spectral_alpha_indices(
        Sxx_power=Sxx_power,
        tn=tn,
        fn=fn,
        flim_low=[0,1500],
        flim_mid=[1500,8000],
        flim_hi=[8000,20000],
        gain=G,
        sensitivity=S,
        verbose=False,
        R_compatible='soundecology',
        mask_param1=6,
        mask_param2=0.5,
        display=False)

    """ =======================================================================
                    Create a dataframe
    ========================================================================"""
    # First, we create a dataframe from row that contains the date and the
    # full filename. This is done by creating a DataFrame from row (ie. TimeSeries)
    # then transposing the DataFrame.
    df_row = pd.DataFrame(row)
    df_row =df_row.T
    df_row.index.name = 'Date'
    df_row = df_row.reset_index()

    # create a row with the different scalar indices
    row_scalar_indices =pd.concat(
        [df_row, df_audio_ind, df_spec_ind],
        axis=1
        )
    # add the row with scalar indices into the df_indices dataframe
    df_indices = pd.concat([df_indices, row_scalar_indices])

    # create a row with the different vector indices
    row_vector_indices = pd.concat(
        [df_row, df_spec_ind_per_bin],
        axis=1)

    # add vector indices into the df_indices_per_bin dataframe
    df_indices_per_bin = pd.concat([df_indices_per_bin, row_vector_indices])

# # Set back Date as index
df_indices = df_indices.set_index('Date')
df_indices_per_bin = df_indices_per_bin.set_index('Date')
**************************************************************
S4A03895_20190522_000000.wav

**************************************************************
S4A03895_20190522_001500.wav

**************************************************************
S4A03895_20190522_003000.wav

**************************************************************
S4A03895_20190522_004500.wav

**************************************************************
S4A03895_20190522_010000.wav

**************************************************************
S4A03895_20190522_011500.wav

**************************************************************
S4A03895_20190522_013000.wav

**************************************************************
S4A03895_20190522_014500.wav

**************************************************************
S4A03895_20190522_020000.wav

**************************************************************
S4A03895_20190522_021500.wav

**************************************************************
S4A03895_20190522_023000.wav

**************************************************************
S4A03895_20190522_024500.wav

**************************************************************
S4A03895_20190522_030000.wav

**************************************************************
S4A03895_20190522_031500.wav

**************************************************************
S4A03895_20190522_033000.wav

**************************************************************
S4A03895_20190522_034500.wav

**************************************************************
S4A03895_20190522_040000.wav

**************************************************************
S4A03895_20190522_041500.wav

**************************************************************
S4A03895_20190522_043000.wav

**************************************************************
S4A03895_20190522_044500.wav

**************************************************************
S4A03895_20190522_050000.wav

**************************************************************
S4A03895_20190522_051500.wav

**************************************************************
S4A03895_20190522_053000.wav

**************************************************************
S4A03895_20190522_054500.wav

**************************************************************
S4A03895_20190522_060000.wav

**************************************************************
S4A03895_20190522_061500.wav

**************************************************************
S4A03895_20190522_063000.wav

**************************************************************
S4A03895_20190522_064500.wav

**************************************************************
S4A03895_20190522_070000.wav

**************************************************************
S4A03895_20190522_071500.wav

**************************************************************
S4A03895_20190522_073000.wav

**************************************************************
S4A03895_20190522_074500.wav

**************************************************************
S4A03895_20190522_080000.wav

**************************************************************
S4A03895_20190522_081500.wav

**************************************************************
S4A03895_20190522_083000.wav

**************************************************************
S4A03895_20190522_084500.wav

**************************************************************
S4A03895_20190522_090000.wav

**************************************************************
S4A03895_20190522_091500.wav

**************************************************************
S4A03895_20190522_093000.wav

**************************************************************
S4A03895_20190522_094500.wav

**************************************************************
S4A03895_20190522_100000.wav

**************************************************************
S4A03895_20190522_101500.wav

**************************************************************
S4A03895_20190522_103000.wav

**************************************************************
S4A03895_20190522_104500.wav

**************************************************************
S4A03895_20190522_110000.wav

**************************************************************
S4A03895_20190522_111500.wav

**************************************************************
S4A03895_20190522_113000.wav

**************************************************************
S4A03895_20190522_114500.wav

**************************************************************
S4A03895_20190522_120000.wav

**************************************************************
S4A03895_20190522_121500.wav

**************************************************************
S4A03895_20190522_123000.wav

**************************************************************
S4A03895_20190522_124500.wav

**************************************************************
S4A03895_20190522_130000.wav

**************************************************************
S4A03895_20190522_131500.wav

**************************************************************
S4A03895_20190522_133000.wav

**************************************************************
S4A03895_20190522_134500.wav

**************************************************************
S4A03895_20190522_140000.wav

**************************************************************
S4A03895_20190522_141500.wav

**************************************************************
S4A03895_20190522_143000.wav

**************************************************************
S4A03895_20190522_144500.wav

**************************************************************
S4A03895_20190522_150000.wav

**************************************************************
S4A03895_20190522_151500.wav

**************************************************************
S4A03895_20190522_153000.wav

**************************************************************
S4A03895_20190522_154500.wav

**************************************************************
S4A03895_20190522_160000.wav

**************************************************************
S4A03895_20190522_161500.wav

**************************************************************
S4A03895_20190522_163000.wav

**************************************************************
S4A03895_20190522_164500.wav

**************************************************************
S4A03895_20190522_170000.wav

**************************************************************
S4A03895_20190522_171500.wav

**************************************************************
S4A03895_20190522_173000.wav

**************************************************************
S4A03895_20190522_174500.wav

**************************************************************
S4A03895_20190522_180000.wav

**************************************************************
S4A03895_20190522_181500.wav

**************************************************************
S4A03895_20190522_183000.wav

**************************************************************
S4A03895_20190522_184500.wav

**************************************************************
S4A03895_20190522_190000.wav

**************************************************************
S4A03895_20190522_191500.wav

**************************************************************
S4A03895_20190522_193000.wav

**************************************************************
S4A03895_20190522_194500.wav

**************************************************************
S4A03895_20190522_200000.wav

**************************************************************
S4A03895_20190522_201500.wav

**************************************************************
S4A03895_20190522_203000.wav

**************************************************************
S4A03895_20190522_204500.wav

**************************************************************
S4A03895_20190522_210000.wav

**************************************************************
S4A03895_20190522_211500.wav

**************************************************************
S4A03895_20190522_213000.wav

**************************************************************
S4A03895_20190522_214500.wav

**************************************************************
S4A03895_20190522_220000.wav

**************************************************************
S4A03895_20190522_221500.wav

**************************************************************
S4A03895_20190522_223000.wav

**************************************************************
S4A03895_20190522_224500.wav

**************************************************************
S4A03895_20190522_230000.wav

**************************************************************
S4A03895_20190522_231500.wav

**************************************************************
S4A03895_20190522_233000.wav

**************************************************************
S4A03895_20190522_234500.wav

Display results

After calculating all alpha indices (in audio and spectral domain), let’s have a look to the data. First, plot correlation map of all indices. We set the R threshold to 0 in order to have everything. If you want to focus on highly correlated indices set the threshold to 0.75 for instance.

fig, ax = plot_correlation_map(df_indices, R_threshold=0)
plot extract alpha indices

A graphical way to have a quick overview of the indices variation during a 24h cycle consists in plotting heatmaps of indices For a better view, we seperate spectral and audio indices.

plot_features_map(df_indices[SPECTRAL_FEATURES], mode='24h')
plot_features_map(df_indices[TEMPORAL_FEATURES], mode='24h')

# A more classical way to analyse variations of indices consists in plotting
# graphs. We choose to normalize rescale their value between 0 to 1 in order to
# compare their trend during a 24h cycle

fig, ax = plt.subplots(3,2, sharex=True, squeeze=True, figsize=(5,5))

fig, ax[0,0] = plot_features(df_indices[['Hf']],norm=True,mode='24h', ax=ax[0,0])
fig, ax[0,1] = plot_features(df_indices[['AEI']],norm=True,mode='24h', ax=ax[0,1])
fig, ax[1,0] = plot_features(df_indices[['NDSI']],norm=True,mode='24h', ax=ax[1,0])
fig, ax[1,1] = plot_features(df_indices[['ACI']],norm=True,mode='24h', ax=ax[1,1])
fig, ax[2,0] = plot_features(df_indices[['TFSD']],norm=True,mode='24h', ax=ax[2,0])
fig, ax[2,1] = plot_features(df_indices[['ROItotal']],norm=True,mode='24h', ax=ax[2,1])
  • plot extract alpha indices
  • plot extract alpha indices
  • plot extract alpha indices

Create false color spectrograms with 3 indices

fcs, triplet = false_Color_Spectro(
    df=df_indices_per_bin,
    indices = [
        'KURTt_per_bin',
        'EVNspCount_per_bin',
        'MEANt_per_bin'
        ],
    reverseLUT=False,
    unit='hours',
    permut=False,
    display=True,
    figsize=(4,7)
    )
False Color Spectro   [R:KURTt; G:EVNspCount; B:MEANt]

References

  1. Sueur, J., Farina, A., Gasc, A., Pieretti, N., & Pavoine, S. (2014). Acoustic Indices for Biodiversity Assessment and Landscape Investigation. Acta Acustica United with Acustica, 100(4), 772–781. https://doi.org/10.3813/AAA.918757
  2. Buxton, R. T., McKenna, M. F., Clapp, M., Meyer, E., Stabenau, E., Angeloni, L. M., Crooks, K., & Wittemyer, G. (2018). Efficacy of extracting indices from large-scale acoustic recordings to monitor biodiversity: Acoustical Monitoring. Conservation Biology, 32(5), 1174–1184. https://doi.org/10.1111/cobi.13119
  3. Towsey, M., Wimmer, J., Williamson, I., & Roe, P. (2014). The use of acoustic indices to determine avian species richness in audio-recordings of the environment. Ecological Informatics, 21, 110–119. https://doi.org/10.1016/j.ecoinf.2013.11.007

Total running time of the script: ( 0 minutes 19.277 seconds)

Gallery generated by Sphinx-Gallery