Search code examples
raudiofftfrequency-analysis

How to extract a specific frequency range from a .wav file?


I'm really new on sound processing, so maybe my question will be trivial. What I want to do is to extract a specific frequency range (let's say 150-400 Hz) from a wav file, using R. In other words, I want to create another wave file (wave2) that contains only the frequency component that I specify (150 to 400 Hz, or what else).

I read something on the net, and I discovered out that this can be done with a FFT analysis, and here's come the problems.

Suppose I've this code:

library(sound)
s1 <- Sine(440, 1)
s2 <- Sine(880, 1)
s3 <- s1 + s2

s3.s <- as.vector(s3$sound)
  # s3.s is now a vector, with length 44100; 
  # bitrate is 44100 (by default)
  # so total time of s3 is 1sec.

  # now I calculate frequencies
N <- length(s3.s)   # 44100
k <- c(0:(N-1))
Fs <- 44100         # sampling rate
T <- N / Fs
freq <- k / T
x <- fft(s3.s) / N

plot(freq[1:22050], x[1:22050], type="l") # we need just the first half of FFT computation

The plot we obtain is:

enter image description here

Well, there are two peaks. If we want to know to what frequency they correspond, just find:

order(Mod(x)[1:22050], decreasing=T)[1:10]
[1] 441 881 882 880 883 442 440 879 884 878

First two values are really near to the frequency I've used to create my sound:

        real     computed
 Freq1: 440   |  441 
 Freq2: 880   |  881 

So, now comes the problem: how to proceed, if I want to delete from my sound the frequencies in the range, say, (1, 500) ? And how to select (and save) only the range (1, 500) ? What I attend, is that my new sound (with deleted frequencies) will be something near to simple Sine(freq=880, duration=1) (I know, it cannot be exactly like so!). Is that possible?

I'm pretty sure that fft(DATA, inverse = TRUE) is what I need. But I'm not sure, and however I don't know how to proceed.


Solution

  • Maybe I missed the point, but don't you already have your answer? From your post:

    order(Mod(x)[1:22050], decreasing=T)[1:10]
    [1] 441 881 882 880 883 442 440 879 884 878 
    

    Simply collect all values above 500:

    junk <- order(Mod(x)[1:22050], decreasing=T)[1:10]
    (junk1 <- junk[junk > 500])
    [1] 881 882 880 883 879 884 878
    

    To generate the new signal simply repeat what you did to build the original signal:

    junk2 <- Sine(0, 1)    
    for (i in 1:length(junk1)) {     
        junk2 <- junk2 + Sine(junk1[i], 1)    
    }    
    junk2.s <- as.vector(junk2$sound)    
    

    To keep the values below 500:

    (junk3 <- junk[junk <= 500])
    [1] 441 442 440