- Notifications
You must be signed in to change notification settings - Fork0
mottensmann/NocMigR2
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
Replacing earlier versionNocMigR
This package provides workflows for processing sound files, especiallycomprising bird vocalisations sampled with autonomous recording devices(e.g.,NocMig
,NFC
andAudioMoth
recordings), with a main emphasison (semi-)automatising the the detection and labelling of events withproper times-stamps. Resulting data can then be reviewed and validatedusingAudacity (recommended version3.0.2).
Among others, this package relies on the following libraries:
R packages:bioacoustics,seewave,tuneR,WarbleR
python:audioop,BirdNET-Analyzer,pydub
To install the package, usedevtools:
devtools::install_github("mottensmann/NocMigR2")
NocMigR2
depends onwarbleR
which is currently (as of 2024-07-26)missing on CRAN. If the installation above fails try:
devtools::install_github("maRce10/warbleR")
Load the package once installed:
library(NocMigR2)
Rename audio files using a string of the formYYYYMMDD_HHMMSS
thatdenotes the date and time of the recording start.
This convenient format is for example used by theAudioMoth), whereas otherpopular recording devices (e.g. PCM recorders by Olympus, Tascam andalike) typically use rather uninformative naming schemes (date +chronological number at best).rename_recording
retrieves thectime
(creation time) from audio files to compose a date_time('YYYYMMDD_HHMMSS'
}) string. Note, audio recorders vary in the wayindividual audio files are saved when in continuous recording mode.Supported options are:
ctime = 'first'
: (e.g. Olympus LS-3) Each audio file shares thectime of thefirst file. Thereforectime of subsequentrecordings are easily computed.ctime = 'each'
: (e.g. Sony PCM D100)Each audio file is handledindividually and therefore saved with uniquectime.
## Example:## new.name corresponds to creation time of package!## -------rename_recording(## path to file(s)path= system.file("extdata",package="NocMigR2"),## specify how to handle ctimesctime="first",## file extensionformat="wav",## only show new name.simulate=TRUE)#> old.name new.name#> 1 20211220_064253.wav 20240806_142737.wav
Retrieve time of dusk and dawn for a given location using thesuncalc package:
## Example## -------dusk2dawn(date= Sys.Date(),## Datelat=52.032090,## Latitude in decimal degreeslon=8.516775,# Longitude in decimal degreestz="CET")# Time zone#> dusk dawn string#> 1 2024-08-06 21:49:09 2024-08-07 05:18:52 6.8-7.8.2024, 21:49-05:18
Create header used to add a comment to observation listsornitho:
Composing a string describing a pastNocMig night followingrecommendations bySchützeet al 2022(HGON)using:
- Bright Sky (de Maeyer 2020) to retrieveweather data for a given location.
- suncalc to retrieve timeof dusk and dawn
## usage -------NocMig_meta(date= Sys.Date()-1,lat=52.032,lon=8.517)#> Teilliste 1: 5.8-6.8.2024, 21:51-05:17, trocken, 15°C, SE, 11 km/h#> Teilliste 2: 5.8-6.8.2024, 21:51-05:17, trocken, 14°C, SSW, 4 km/h
Create custom species list for target species:
Filters the extensiveBirdNET_GLOBAL_6K_V2.4_Labelsfile for selected target species. Target species can be selected basedon scientific species names or common species names in all languagescurrently supported byBirdNET-Analyzer.
## examples## --------BirdNET_species.list(## target speciesnames= c("Glaucidium passerinum","Bubo bubo"),sciNames=TRUE,BirdNET_path="../BirdNET-Analyzer/",species_list="Insert Path here ...",## only show df, not exporting to text file.write_text=FALSE)#> sciName comName#> 1 Bubo bubo Eurasian Eagle-Owl#> 2 Glaucidium passerinum Eurasian Pygmy-OwlBirdNET_species.list(names= c("Sperlingskauz","Uhu"),lang="de",sciNames=FALSE,BirdNET_path="../BirdNET-Analyzer/",species_list="Insert Path here ...",## only show df, not exporting to text file.write_text=FALSE)#> sciName comName#> 1 Bubo bubo Eurasian Eagle-Owl#> 2 Glaucidium passerinum Eurasian Pygmy-Owl
Using BirdNET-Analyzer to process audio data
- InstallingUbuntu environment.Windows Subsystem for Linux(WSL) works well for this purpose. seeWSL forexplanations
- SetupBirdNET-Analyzer following theSetupUbuntusection
Thenbash
code-chunks (shown below) can be executed using WSL. Pre-and post processing stays within R.
- SetupBirdNET-Analyzer following theSetupUbuntusection
Then, usingRStudioanalyzer.py
can be used by simply insertingbash
code-chunks withinRMarkdown documents!
Usinganalyzer.py
for detecting signals:
- Use the sample audio file for demonstration purposes:
## create temp folderdir.create("test_folder")#> Warning in dir.create("test_folder"): 'test_folder' already exists## Copy samplesample<- system.file("extdata","20211220_064253.wav",package="NocMigR2")file.copy(from=sample,to= file.path("test_folder","20211220_064253.wav"))
- Run
analyzer.py
(See documentationhere)
## bash## -----------------------------------## Set working dir to BirdNET-Analyzercd PATH TO BirdNET-Analyzer
## bash## ---------------## run analyze.pypython3 analyze.py --i /test_folder --o /test_folder --min_conf 0.7 --rtype'audacity' --threads 1 --locale'de'
## Example RStudio on Raspberry Pi 4## -----------------------------------------------------------------------------cd ../BirdNET-Analyzerpython3 analyze.py --i ../NocMigR2/test_folder --o ../NocMigR2/test_folder --min_conf 0.7 --rtype'audacity'
The functionBirdNET
(see?BirdNET for details) does the following:
- Reshape audacity labels created by
analyze.py
(with--rtype 'audacity'
) to include the event time estimated from filenames: [CreatesBirdNET.labels.txt
for eachBirdNET.results.txt
file] - Write records to BirdNET.xlsx as a template to simplify inspectionand verification of the records.
df<- BirdNET(path="test_folder/",## adding optional meta datameta= BirdNET_meta(Location="Place A",Lat=52,Lon=8,Device="Recorder B",Micro="Mic C",## analyze.py settingsMin_conf=0.7,Overlap=0,Sensitivity=1.0,Slist="BirdNET_V2.4"))#> Calculate total duration of 1 recordings:#> Created test_folder//BirdNET.xlsx
## load and show overview overviewstr(openxlsx::read.xlsx("test_folder/BirdNET.xlsx","Records"))#> 'data.frame': 1 obs. of 12 variables:#> $ Taxon : chr "Eurasian Pygmy-Owl"#> $ Detector : chr "BirdNET"#> $ ID : num NA#> $ T1 : num 44550#> $ T2 : num 44550#> $ Score : num 0.776#> $ Verification: num NA#> $ Correction : num NA#> $ Quality : num NA#> $ Comment : num NA#> $ T0 : num 44550#> $ File : chr "test_folder/20211220_064253.BirdNET.results.txt"str(openxlsx::read.xlsx("test_folder/BirdNET.xlsx","Meta"))#> 'data.frame': 1 obs. of 12 variables:#> $ Location : chr "Place A"#> $ Lat : num 52#> $ Lon : num 8#> $ From : num 44550#> $ To : num 44550#> $ Duration : chr "14.92 seconds"#> $ Device : chr "Recorder B"#> $ Micro : chr "Mic C"#> $ Min_conf : num 0.7#> $ Overlap : num 0#> $ Sensitivity: num 1#> $ Slist : chr "BirdNET_V2.4"
Extract detections and export them as wave files. For easier access toverify records files are named as ‘Species_Date_Time.WAV’ andcorresponding hyperlinks are inserted in the .xlsx file created withBirdNET()
(see below).
## extract events and add hyperlinkBirdNET_extract(path="test_folder",hyperlink=TRUE)#> Extract events ...
## show created dirslist.dirs("test_folder/extracted/",recursive=F)#> [1] "test_folder/extracted/Eurasian Pygmy-Owl"## show content for Eurasian Pygmy-OWllist.files("test_folder/extracted/Eurasian Pygmy-Owl/")#> [1] "Eurasian Pygmy-Owl_20211220_064259.WAV"
- Content of
xlsx file
Summary table of BirdNET detection ready for manual review &verification (attributes:Verification
,Correction
,Comment
).Automatically provided are BirdNET annotations (Taxon) along with thecorresponding confidence score (Score
) and event time (T1
= start,T2
= end). Manually recovered events may be added to the same file bysettingDetector = 'Manual'
or alike}
Under development
Archiveverified records (see screenshot above) usingBirdNET_archive
:
out<- BirdNET_archive(BirdNET_results="test_folder/BirdNET.xlsx",path2archive="test_folder",db="test_folder/db.xlsx",NocMig=FALSE,keep.false=TRUE)str(out)#> 'data.frame': 1 obs. of 19 variables:#> $ Date : chr "2021-12-20"#> $ Taxon : chr "Eurasian Pygmy-Owl"#> $ sum : int 1#> $ sum1 : int 0#> $ str1 : logi NA#> $ sum2 : int 1#> $ str2 : chr "06:1"#> $ Location : chr "Place A"#> $ Lat : num 52#> $ Lon : num 8#> $ From : POSIXct, format: "2021-12-20 06:42:53"#> $ To : POSIXct, format: "2021-12-20 06:43:07"#> $ Duration : chr "14.92 seconds"#> $ Device : chr "Recorder B"#> $ Micro : chr "Mic C"#> $ Min_conf : num 0.7#> $ Overlap : num 0#> $ Sensitivity: num 1#> $ Slist : chr "BirdNET_V2.4"## show folder structurelist.files("test_folder/")#> [1] "20211220_064253.BirdNET.labels.txt" "20211220_064253.BirdNET.results.txt"#> [3] "20211220_064253.wav" "BirdNET.xlsx"#> [5] "db.xlsx" "extracted"#> [7] "False positives" "True positives"
Mainly a backup from previous packageNocMigR)
Signal detection based on SNR (signal to noise ratio) wrappingthreshold_detection()
of thebioacoustics package.Additional parameters allow further fine-tuning by specifying frequencycharacteristics and call length of targets of interest.Note: For birdcalls usingBirdNET-Analyzer is therecommended alternative. Detections are exported as Audacity labelsusingseewave:
TD<- find_events(wav.file="test_folder/20211220_064253.wav",audacity=TRUE,# Write audacity labelsthreshold=8,# SNR in dbmin_dur=20,# min length in msmax_dur=300,# max length in msLPF=5000,# low-pass filter at 500 HzHPF=1000)# high-pass filter at 4 kHz## Review eventshead(TD$data$event_data[,c("filename","starting_time","duration","freq_max_amp")])#> filename starting_time duration freq_max_amp#> 1 20211220_064253.wav 00:00:06.169 169.07029 1483.850#> 2 20211220_064253.wav 00:00:06.638 192.29025 1647.574#> 3 20211220_064253.wav 00:00:07.481 116.09977 1790.988#> 4 20211220_064253.wav 00:00:07.872 150.20408 1900.730#> 5 20211220_064253.wav 00:00:08.365 94.33107 2032.121#> 6 20211220_064253.wav 00:00:08.945 29.02494 2180.925
Ifaudacity = TRUE
a file with labels for reviewing events inAudacity
is created (wrappingseewave::write.audacity()
).
- Extract detected events from raw audio file
Refines the output offind_events
by first adding a buffer (default 1second on both sides of the event) and subsequently merging overlappingselections (detections likely belonging to the same calling event) tomake the output more pretty. Additionally, allows to filter based onexpected frequencies (i.e., checks maximum amplitude frequency is withinthe frequency band defined byLPF
andHPF
). Returns a shortenedaudio file containing only the selected events (e.g,“20211220_064253_extracted.txt” along with the corresponding Audacitylabels“20211220_064253_extracted.txt”)
## extract events based on object TDdf<- extract_events(threshold_detection=TD,path="test_folder",format="wav",LPF=4000,HPF=1000,buffer=1)
Basic function to split large audio files in chunks.Internally callsthe python librarypydub withreticulate.:
Short audio segments are saved in a subfolder named ‘split’.
## split in segmentssplit_wave(file="20211220_064253.wav",# audio filepath="test_folder/",# foldersegment=3)# cut in 3 sec segments#> Split ...## show fileslist.files("test_folder/split/")#> [1] "20211220_064253.wav" "20211220_064256.wav" "20211220_064259.wav"#> [4] "20211220_064302.wav" "20211220_064305.wav"