## ----install_packages, message=FALSE, eval=FALSE------------------------------
# install.packages("bioacoustics")
# 
# # The bioacoustics package may also be installed from GitHub using devtools as follows:
# install.packages("devtools")
# devtools::install_github("wavx/bioacoustics") # For the latest, unstable version
# 
# install.packages("warbleR")
# install.packages("randomForest")

## ----load_packages, message=FALSE, eval=FALSE---------------------------------
# # Load the packages
# library(warbleR)
# library(bioacoustics)
# library(tools)
# library(randomForest)

## ----xeno1, message=FALSE, eval=FALSE-----------------------------------------
# df1 = query_xc(qword ='Catharus bicknelli type:call cnt:"United States"', download = FALSE)
# df1 = df1[df1$Vocalization_type=="call",]
# df1 = df1[df1$Quality=="A",]
# df1 = df1[1:9,]

## ----xeno2, message=FALSE, results='hold', eval=FALSE-------------------------
# df2 = query_xc(qword ='Setophaga magnolia type:song cnt:"Canada"', download = FALSE)
# df2 = df2[df2$Quality=="A",]
# df2 = df2[1:9,]

## ----xeno3, message=FALSE, results='hold', eval=FALSE-------------------------
# df3 = query_xc(qword ='Passerella iliaca type:song cnt:"Canada"', download = FALSE)
# df3 = df3[df3$Vocalization_type=="song",]
# df3 = df3[df3$Quality %in% c("A", "B"),]
# df3 = df3[1:9,]
# 
# df = rbind(df1,df2,df3)
# rm(df1,df2,df3)

## ----xeno4, eval=FALSE--------------------------------------------------------
# # Visualize your data frame
# View(df)
# 
# # We will work in the R temp directory
# wd <- tempdir()
# 
# # Create a data directory if it does not exist
# data_dir <- file.path(wd, "data")
# 
# if(!dir.exists(data_dir))
#   dir.create(data_dir)
# 
# # Download the MP3 files into your data directory
# quer_xc(X = df, download = TRUE, path = data_dir)

## ----read_audio, eval=FALSE---------------------------------------------------
# CATBIC <- read_audio(file.path(data_dir, "Catharus-bicknelli-54864.mp3"))
# CATBIC

## ----metadata,eval=FALSE------------------------------------------------------
# 
# metadata(CATBIC)
# 

## ----spectro0, eval=FALSE-----------------------------------------------------
# # Set plot margins to 0
# par(mar = c(0, 0, 0, 0), oma = c(0, 0, 0, 0))
# 
# # Display with spectro()
# ticks <- c(from = 1000, to = 20000, by = 1000) # frequency tick marks from 1 to
#                                                # 20 kHz, and steps at each 1 kHz
# temp_slice <- c(from = 1, to = 10) # in seconds
# spectro(CATBIC, tlim = temp_slice, FFT_size = 512, ticks_y = ticks)

## ----help, eval=FALSE---------------------------------------------------------
# # Access the arguments of the spectro function
# ?spectro
# ?fspec

## ----spectro1, eval=FALSE-----------------------------------------------------
# # Set plot margins to 0
# par(mar = c(0, 0, 0, 0), oma = c(0, 0, 0, 0))
# 
# # Display the spectrogram with spectro()
# ticks <- c(from = 1000, to = 20000, by = 1000) # frequency tick marks from 1 to
#                                                # 20 kHz, 1 kHz steps
# temp_slice <- c(from = 2, to = 3.5) # in seconds
# spectro(CATBIC, tlim = temp_slice, FFT_size = 512, ticks_y = ticks)
# 
# # fspec() gives you the spectrogram matrix with energy values (dB)
# spec_mx <- fspec(CATBIC, tlim = temp_slice, FFT_size = 512, rotate = TRUE)
# 
# # You can display the spectrogram with image()
# image(spec_mx, xaxt = "n", yaxt = "n")

## ----filter, eval=FALSE-------------------------------------------------------
# temp_slice <- c(from = 2.5, to = 3.5)
# freq_slice <- c(from = 1500, to = 20000)
# spec_o <- fspec(CATBIC, tlim = temp_slice, flim = freq_slice, FFT_size = 512, rotate = TRUE)
# 
# ## min and max (range) dB intensity
# range(spec_o) # -120 (min) to 0 dB (max)
# # Note that the tolerance of your recorders depends on the number of bits.
# # 16-bit recorders offer only around -96 dB tolerance and sound pressure above
# # this level is clipped to 0 dB.
# 
# ## Let's try a filter by mean + sd intensity
# spec_f <- fspec(CATBIC, tlim = temp_slice, flim = freq_slice, FFT_size = 512, rotate = TRUE)
# spec_f[spec_f < mean(spec_f) + sd(spec_f)] <- -120
# # Works well with high intensity audio events, but leads to
# # false negatives (missed events) otherwise.
# 
# par(mar = c(0, 0, 0, 0), oma = c(0, 0, 0, 0))
# image(spec_o, xaxt="n", yaxt="n")
# image(spec_f, xaxt="n", yaxt="n")

## ----threshold_help, eval=FALSE-----------------------------------------------
# # Access the arguments of the threshold_detection function
# ?threshold_detection

## ----threshold1, eval=FALSE---------------------------------------------------
# # Set each argument according to the targeted audio events
# TD <- threshold_detection(
#   CATBIC, # Either a path to an audio file (see ?read_audio), or a Wave object
#   threshold = 12, # 12 dB SNR sensitivity for the detection algorithm
#   time_exp = 1, # Time expansion factor of 1. Only needed for bat recordings.
#   min_dur = 140, # Minimum duration threshold of 140 milliseconds (ms)
#   max_dur = 440, # Maximum duration threshold of 440 ms
#   min_TBE = 10, # Minimum time window between two audio events of 10 milliseconds
#   max_TBE = 5000, # Maximum time window between two audio events, here 5 seconds
#   EDG = 0.996, # Temporal masking with Exponential Decay Gain from 0 to 1
#   LPF = 10000, # Low-Pass Filter of 10 kHz
#   HPF = 1000, # High-Pass Filter of 1 kHz
#   FFT_size = 256, # Size of the Fast Fourrier Transform (FFT) window
#   FFT_overlap = 0.875, # Percentage of overlap between two FFT windows
# 
#   start_thr = 25, # 25 dB threshold at the start of the audio event
#   end_thr = 30, # 30 dB threshold at the end of the audio event
#   SNR_thr = 10, # 10 dB SNR threshold at which the extraction of the audio event stops
#   angle_thr = 45, # 45° of angle at which the extraction of the audio event stops
#   duration_thr = 440, # Noise estimation is resumed after 440 ms
#   NWS = 1000, # Time window length of 1 s used for background noise estimation
#   KPE = 1e-05, # Process Error parameter of the Kalman filter (for smoothing)
#   KME = 1e-04, # Measurement Error parameter of the Kalman filter (for smoothing)
# 
#   settings = FALSE, #  Save on a list the above parameters set with this function
#   acoustic_feat = TRUE, # Extracts the acoustic and signal quality parameters
#   metadata = FALSE, # Extracts on a list the metadata embedded with the Wave file
#   spectro_dir = file.path(tempdir(), "Spectros"), # Directory where to save the spectrograms
#   time_scale = 1, # Time resolution of 2 ms for spectrogram display
#   ticks = TRUE # Tick marks and their intervals are drawn on the y-axis (frequencies)
# )
# 
# # Get the number of extracted audio events
# nrow(TD$data$event_data)

## ----threshold2, eval=FALSE---------------------------------------------------
# # Let's try various settings, starting with 1024 FFT size instead of 256.
# TD <- threshold_detection(
#   CATBIC, threshold = 12, time_exp = 1, min_dur = 140, max_dur = 440,
#   min_TBE = 10, max_TBE = 5000, EDG = 0.996, LPF = 10000, HPF = 1000,
#   FFT_size = 1024, FFT_overlap = 0.875, start_thr = 25, end_thr = 30,
#   SNR_thr = 10, angle_thr = 45, duration_thr = 440, NWS = 1000,
#   KPE = 1e-05, KME = 1e-04, settings = FALSE, acoustic_feat = TRUE,
#   metadata = FALSE, spectro_dir = file.path(tempdir(), "Spectros"), time_scale = 1,
#   ticks = c(1000, 10000, 1000) # Tick marks from 1 to 10 kHz with 1 kHz interval
# )
# 
# # Take a look at the spectrograms and compare them with the previous extraction.
# nrow(TD$data$event_data) # Only three audio events!

## ----threshold3, eval=FALSE---------------------------------------------------
# CATBIC <- read_audio(file.path(data_dir, "Catharus-bicknelli-54864.mp3"))
# TD <- threshold_detection(
#   CATBIC, threshold = 12, time_exp = 1, min_dur = 140, max_dur = 440, min_TBE = 10,
#   max_TBE = Inf, EDG = 0.996, LPF = 10000, HPF = 1000, FFT_size = 256, FFT_overlap = 0.875,
#   start_thr = 22, end_thr = 30, SNR_thr = 10, angle_thr = 125, duration_thr = 440, NWS = 1000,
#   KPE = 1e-05, KME = 1e-05, settings = FALSE, acoustic_feat = TRUE, metadata = FALSE
# )

## ----features1, eval=FALSE----------------------------------------------------
# # Acoustic features are stored in a data frame called event_data,
# # stored by order of detection.
# 
# View(TD$data$event_data) # Contains the filename and the time of detection in the
#                          # recording, and 26 extracted features.

## ----features2, eval=FALSE----------------------------------------------------
# # Start and end of the 5th extracted audio event (in samples)
# c(TD$data$event_start[[5]], TD$data$event_end[[5]])
# 
# # Remember you just have to divide by the sample rate to retrieve the time (s)
# c(TD$data$event_start[[5]], TD$data$event_end[[5]]) / slot(CATBIC, "samp.rate")

## ----features3, eval=FALSE----------------------------------------------------
# par(mar = c(1,1, 1, 1), oma = c(1, 1, 1, 1))
# 
# # Amplitude track of the 5th audio event
# plot(TD$data$amp_track[[5]], type = "l")
# 
# # Frequency track of the 5th audio event
# plot(TD$data$freq_track[[5]], type = "l")

## ----blob0, eval=FALSE--------------------------------------------------------
# # Access the arguments of the blob_detection function
# ?blob_detection

## ----blob1, eval=FALSE--------------------------------------------------------
# # Use the bat recording stored in the package
# data(myotis)
# 
# # Set each argument according to the targeted audio events
# BD <- blob_detection(
#   myotis, # Either a path to an audio file (see ?read_audio), or a Wave object
#   time_exp = 10, # Time expansion factor of 10 for time expanded recordings.
#   min_dur = 1.5, # Minimum duration threshold of 1.5 milliseconds (ms)
#   max_dur = 80, # Maximum duration threshold of 80 ms
#   min_area = 40, # minimum number of 40 pixels in the blob
#   min_TBE = 20, # Minimum time window between two audio events of 20 milliseconds
#   EDG = 0.996, # Temporal masking with Exponential Decay Gain from 0 to 1
#   LPF = slot(myotis, "samp.rate") * 10 / 2, # Low-Pass Filter at the Nyquist frequency
#   HPF = 16000, # High-Pass Filter of 16 kHz
#   FFT_size = 256, # Size of the Fast Fourrier Transform (FFT) window
#   FFT_overlap = 0.875, # Percentage of overlap between two FFT windows
# 
#   blur = 2, # Gaussian smoothing function with a factor of 2 for blurring the spectrogram
#   bg_substract = 20, # Foreground extraction with a mean filter applied on the spectrogram
#   contrast_boost = 20, # Edge contrast enhancement filter of the spectrogram contour
# 
#   settings = FALSE, #  Save on a list the above parameters set with this function
#   acoustic_feat = TRUE, # Extracts the acoustic and signal quality parameters
#   metadata = FALSE, # Extracts on a list the metadata embedded with the Wave file
#   spectro_dir = file.path(tempdir(), "Spectros"), # HTML page with spectrograms by order of detection
#   time_scale = 0.1, # Time resolution of 2 ms for spectrogram display
#   ticks = TRUE # Tick marks and their intervals are drawn on y-axis (frequencies)
# )
# 
# # Get the number of extracted audio events
# nrow(BD$data$event_data)

## ----blob2, eval=FALSE--------------------------------------------------------
# # Let's try various settings, starting with 512 FFT size instead of 256.
# BD <- blob_detection(
#   myotis, time_exp = 10, FFT_size = 512, settings = FALSE, acoustic_feat = TRUE,
#   metadata = FALSE, spectro_dir = file.path(tempdir(), "Spectros"), time_scale = 0.1, ticks = TRUE
# )
# 
# # Take a look at the spectrograms and compare them with the previous extraction.
# nrow(BD$data$event_data) # Only 6 audio events!

## ----blobfeat1, eval=FALSE----------------------------------------------------
# # Acoustic features
# head(BD$data)

## ----classification1, eval=FALSE----------------------------------------------
# # Get the filepath for each MP3 file
# files <- dir(data_dir, recursive = TRUE, full.names = TRUE, pattern = "[.]mp3$")
# 
# # Detect and extract audio events
# TDs <- setNames(
#   lapply(
#     files,
#     threshold_detection,
#     threshold = 12, min_dur = 140, max_dur = 440, min_TBE = 50, max_TBE = Inf,
#     LPF = 8000, HPF = 1500, FFT_size = 256, start_thr = 30, end_thr = 20,
#     SNR_thr = 10, angle_thr = 125, duration_thr = 400, spectro_dir = NULL,
#     NWS = 2000, KPE = 0.00001, time_scale = 2, EDG = 0.996
#   ),
#   basename(file_path_sans_ext(files))
# )
# 
# # Keep only files with data in it
# TDs <- TDs[lapply(TDs, function(x) length(x$data)) > 0]
# 
# # Keep the extracted feature and merge in a single data frame for further analysis
# Event_data <- do.call("rbind", c(lapply(TDs, function(x) x$data$event_data), list(stringsAsFactors = FALSE)))
# nrow(Event_data) # 355 audio events extracted
# 
# # Compute the number of extracted CATBIC calls
# sum(startsWith(Event_data$filename, "Cat"))
# 
# # Add a "Class" column: "CATBIC" vs. other species of birds "OTHERS"
# classes <- as.factor(ifelse(startsWith(Event_data$filename, "Cat"), "CATBIC", "OTHERS"))
# Event_data <- cbind(data.frame(Class = classes), Event_data)
# 
# # Get rid of the filename and time in the recording
# Event_data$filename <- Event_data$starting_time <- NULL

## ----classification2, eval=FALSE----------------------------------------------
# # Split the data in 60% Training / 40% Test sets
# train <- sample(1:nrow(Event_data), round(nrow(Event_data) * .6))
# Train <- Event_data[train,]
# 
# test <- setdiff(1:nrow(Event_data), train)
# Test <- Event_data[test,]
# 
# # Train a random forest classifier
# set.seed(666)
# rf <- randomForest(Class ~ duration + freq_max_amp + freq_max + freq_min +
#                            bandwidth + freq_start + freq_center + freq_end +
#                            freq_knee + fc + freq_bw_knee_fc + bin_max_amp +
#                            pc_freq_max_amp + pc_freq_max + pc_freq_min +
#                            pc_knee + temp_bw_knee_fc + slope + kalman_slope +
#                            curve_neg + curve_pos_start + curve_pos_end +
#                            mid_offset + smoothness + snr + hd + smoothness,
#                    data = Train, importance = FALSE, proximity = FALSE,
#                    replace = TRUE, ntree = 4000, mtry = 4)
# 
# # Look at the confusion matrix of the training set
# rf$confusion # looks good, but...
# 
# # Let's make predictions with our classifier on a test set
# table(Test[,1], predict(rf, Test[,-1], type = "response")) # not bad!
# 
# # To look at the predictions
# head(predict(rf, Test[,-1], type = "prob"))

## ----keras1, eval=FALSE-------------------------------------------------------
# # Run if keras is installed on your machine
# library(keras)
# 
# # Build the training set
# Y_train <- to_categorical(as.integer(Train[,1]) - 1) # One hot encoding
# 
# # X as matrix
# X_train <- as.matrix(Train[,-1])
# 
# # Build the test set
# Y_test <- to_categorical(as.integer(Test[,1]) - 1)
# Y_test <- Y_test[,-1]
# X_test <- as.matrix(Test[,-1])
# 
# # Build the sequential model
# mod0 <- keras_model_sequential()
# mod0 %>%
#   # Input shape layer = c(samples, rows, cols, channels)
#   layer_reshape(input_shape=ncol(X_train),target_shape=c(1,1,ncol(X_train))) %>%
#   # First conv 2d layer with 128 neurons, kernel size of 8 x 8 and stride of 1 x 1
#   layer_conv_2d(128, c(8,8), c(1,1), padding='same') %>%
#   layer_batch_normalization() %>%
#   layer_activation("relu") %>%
#   layer_dropout(0.2) %>%
#   # Second conv 2d layer with 256 neurons, kernel size of 5 x 5 and stride of 1 x 1
#   layer_conv_2d(256, c(5,5), c(1,1), padding='same') %>%
#   layer_batch_normalization() %>%
#   layer_activation("relu") %>%
#   layer_dropout(0.2) %>%
#   # Third conv 2d layer with 128 neurons, kernel size of 3 x 3 and stride of 1 x 1
#   layer_conv_2d(128, c(3,3), c(1,1), padding='same') %>%
#   layer_batch_normalization() %>%
#   layer_activation("relu") %>%
#   layer_dropout(0.2) %>%
#   # Average pooling layer
#   layer_global_average_pooling_2d() %>%
#   # Activation output layer with 2 classes
#   layer_dense(units = ncol(Y_train),  activation='softmax')
# 
# # Model compile
# mod0 %>% compile(loss = 'categorical_crossentropy',
#                  optimizer = "adam",
#                  metrics = "categorical_accuracy")
# 
# 
# # Add a callback to reduce the learning rate when reaching the plateau
# reduce_lr <- callback_reduce_lr_on_plateau(monitor = 'loss', factor = 0.5,
#                                            patience = 50, min_lr = 0.0001)
# # Start learning
# mod0 %>% fit(X_train, Y_train, batch_size = 32, epochs = 50,
#              validation_data = list(X_test, Y_test),
#              verbose = 1, callbacks = reduce_lr)
# 
# # Score on the test set
# score <- mod0 %>% evaluate(X_test, Y_test, batch_size = 32)
# score

## ----keras2, eval=FALSE-------------------------------------------------------
# # Look at predictions and build a confusion matrix
# Pred <- as.factor(predict_classes(mod0, X_test, batch_size = 32, verbose = 1))
# table(Y_test[,2], Pred)
# 
# # To look at the prediction values
# Prob <- round(predict_proba(mod0, X_test, batch_size = 32, verbose = 1), 2)

