user12970144
user12970144

Reputation: 21

Detect specific frequency in audio file using R

I have an audio recording wav file of a cricket chirping, every so often a chirp occurs for ~ 0.01 seconds at about 20kHz. I would like to use R to detect at what times during the recording the specific frequency (20kHz) occurs/starts.

Wave Object

Number of Samples:      4041625
Duration (seconds):     91.65
Samplingrate (Hertz):   44100
Channels (Mono/Stereo): Mono
PCM (integer format):   TRUE
Bit (8/16/24/32/64):    16 

Upvotes: 2

Views: 679

Answers (2)

Andrew Chisholm
Andrew Chisholm

Reputation: 6567

As @anddt says, dfreq is a good option although it often requires some tuning of various parameters such as threshold and wl. Here's a toy example with some made up data containing noise.

library(seewave)
library(tuneR)

chirp = sine(freq = 20000, duration = 0.01, xunit = 'time')
silence_0.2 = silence(duration = 0.2, xunit = 'time')
silence_0.1 = silence(duration = 0.1, xunit = 'time')
noise_0.2 = noise(kind='pink', duration=0.2, xunit = 'time')
noise_0.1 = noise(kind='pink', duration=0.1, xunit = 'time')
signal = bind(silence_0.2, chirp, noise_0.1, silence_0.2, chirp, silence_0.1, noise_0.2, chirp, noise_0.2, silence_0.2)

# threshold removes noise, wl is the window length of the fourier transform, smaller 
# values give more accuracy for time but noise gets more troublesome
peaks = data.frame(dfreq(signal, threshold = 10, wl = 128, plot=F))
peaks[is.na(peaks)] = 0
names(peaks) = c('time', 'frequency')
peaks$frequency[peaks$frequency < 19.9 | peaks$frequency > 20.1] = 0

startindices = which(diff(peaks$frequency) > 19)
endindices = which(diff(peaks$frequency) < -19)
starttimes = peaks[startindices, 1]
endtimes = peaks[endindices, 1]

plot(signal, col='grey')
abline(v = starttimes, col='green')
abline(v = endtimes, col='red')

The result looks like this. Green vertical lines for the starts, and red vertical lines for the ends of chirps.

enter image description here

Upvotes: 1

anddt
anddt

Reputation: 1641

I do believe dfreq from the seewave package is what you're after. The method returns the dominant frequency (the one with the highest amplitude) over time (in seconds). Here's an exampleof how you could get that information:

library(tuneR)
library(seewave)

# Read audio file
crickets <- readWave("~/crickets.wav")

# Get dominant frequency
d <- dfreq(crickets, plot = FALSE)

head(d)

#               x        y
# [1,] 0.00000000 0.000000
# [2,] 0.02332295 0.000000
# [3,] 0.04664589 0.000000
# [4,] 0.06996884 0.000000
# [5,] 0.09329179 0.000000
# [6,] 0.11661474 2.583984

Upvotes: 1

Related Questions