# -*- coding: utf-8 -*-
"""
Created on Sun Dec 24 10:41:58 2022

@author: Loïc
title: detection of BBP in audios
"""

#%% Packages importations
print("\rImportation of packages...", end="\r")
import os
from datetime import datetime
import numpy as np
import pandas as pd
from librosa import load
import matplotlib.pyplot as plt
from matplotlib.patches import Ellipse
from scipy.signal import find_peaks, correlate
from scipy.stats import linregress
print("Importation of packages done!")

#%% Parameters
# Paths
print("\rSetting up parameters...", end="\r")
audio_f = "./../Audio_data"  # Path to recordings 
csv_f = "./../CSV_data"      # Path to data in csv
save_f = "./Results"         # Path to results

# For functions
sr = 512000             # sample rate of the recordings
cut_low = 50000         # frequency cut in highpass
num_order = 1           # order of the highpass filter
sound_thresh = 1e-5     # arbitrary threshold used for noise detection 
click_size = 100        # mean size of a click (observations) for rolling average
max_length = 500        # maximum length to consider a sound as a click
nfft = 8192             # it is high to estimate freq precisely (we dont need good time location)
hop_length = nfft//2    # if needed, reduce hop_length to be more precise in time
flip = 60               # if there are two many BBPs selected, uses more strict criteria

# soft criteria, we will have false positives but at least we detect all BBPs
mini_space = click_size*5   # minimal space between two clicks (avoids echoes)
ICI_space = int(0.020*sr)   # maximal space between two clicks to be a BBP
nb_mini_clicks = 15         # minimal number of clicks to be a BBP
d_amp = 0.1                 # max difference of amplitude between clicks of a BBP
irregularity = 2            # limit for irregularity in a BBP (the closer to 1, the better)
mean_nrg = 0.1              # max mean energy for clicks in BBP
print("Parameters ready to use!")


#%% Data
print("\rImportation of csv data", end="\r")
from BBPUtils import get_csv, butter_pass_filter, TeagerKaiser_operator, OLDget_BBPs
data_20_21, audio_paths = get_csv(csv_f, slash="/")
print("Importation of csv data complete!")


#%%## Detection of clicks in environnement #####
print("\nMain execution: Looking for clicks in recordings.")
BBP_all = np.empty((0,3)) # [idx file, sample position, idx BBP in file]

for file in range(len(audio_paths)):
    print(f"\r\tExecution for file {file+1} on {len(audio_paths)}", end='\r')
    # load signal
    signal = load(os.path.join(audio_f, audio_paths[file][4:8], audio_paths[file]),
        sr=None)[0]
    signal_high = butter_pass_filter(signal, cut_low, sr, 
                                     num_order, mode='high')  
    tk_signal = np.abs(TeagerKaiser_operator(signal_high))

    # load or find clicks
    signal_peaks = find_peaks(tk_signal, prominence=sound_thresh, distance=mini_space, 
        width=[0,max_length])[0]
    # security
    if len(signal_peaks)==0:
        # create empty list to avoid errors
        signal_peaks = np.array([0])

    # Compute ICI
    peaks_selection = OLDget_BBPs(signal_peaks, ICI_space, nb_mini_clicks)
    # security
    if len(peaks_selection) > flip:
        peaks_selection = OLDget_BBPs(signal_peaks, int(ICI_space/2), nb_mini_clicks)

    # Apply selection criteria
    d_amp_selection = np.array([np.mean(np.abs(tk_signal[selection[1:]]-tk_signal[selection[:-1]]))<d_amp
         for selection in peaks_selection])
    regularity = np.array([np.mean(np.abs(selection[1:]-selection[:-1])[1:]/np.abs(selection[1:]-selection[:-1])[:-1])<irregularity
        for selection in peaks_selection])
    nrg = np.array([np.mean(tk_signal[selection])< mean_nrg for selection in peaks_selection])
    keeping = np.where(np.logical_and(d_amp_selection, regularity, nrg))[0]

    # just to be sure, if linreg is negative then it is prbly a false positive (a click and its echoes (diminishing in amplitude))
    linreg = np.array([linregress(tk_signal[selection],selection)[2] 
                       for selection in peaks_selection])[keeping]
    lengths = np.array([len(selection) for selection in peaks_selection])[keeping]
    keeping = keeping[np.logical_or((linreg > -0.5),(lengths > 2*nb_mini_clicks))]

    # save results
    for i in keeping:
        curr_BBP = np.append(peaks_selection[i][...,np.newaxis],
                             np.array([i]*len(peaks_selection[i]))[...,np.newaxis],
                             axis=1)
        curr_BBP = np.append(np.array([file]*len(peaks_selection[i]))[...,np.newaxis],
                             curr_BBP, axis=1)
        BBP_all = np.append(BBP_all, curr_BBP, axis=0)
        
np.save(os.path.join(save_f, datetime.now().strftime("%d-%m-%y_%Hh%M") + "_BBP_all.npy"), 
    BBP_all)