如何从.wav文件中提取特定的频率范围?

5

我是一位新手,对声音处理非常陌生,所以我的问题可能很简单。 我想做的是使用 R 从 WAV 文件中提取特定的频率范围(比如 150-400 Hz)。换句话说,我想创建另一个仅包含我指定频率组件(150 到 400 Hz 或其他)的 wave 文件(wave2)。

我在网上看到了一些资料,发现可以通过 FFT 分析来实现这个目的,��问题随之而来。

假设我有以下代码:

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

我们得到的图形如下:

enter image description here

好的,有两个峰值。如果我们想知道它们对应的频率是多少,只需要找出:
order(Mod(x)[1:22050], decreasing=T)[1:10]
[1] 441 881 882 880 883 442 440 879 884 878

前两个值与我用来创建声音的频率非常接近:

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

所以,现在问题来了:如果我想从声音中删除频率范围内的频率,比如说(1, 500)怎么办?如何选择(并保存)只有范围(1, 500)的部分? 我的期望是,我的新声音(删除了频率)会接近于简单的Sine(freq=880, duration=1)(我知道,它不可能完全像这样!)。 这种可能吗?
我相当确定fft(DATA, inverse = TRUE)是我需要的。但我不确定,并且不知道该如何继续。
3个回答

3
如果您不想编程,可以使用 Praat。
Praat是一款免费的科学软件程序,用于语音语音学分析。您还可以使用它来编辑任何声音的频谱(删除频率等),然后将结果导出为新的声音文件。

2
也许我理解有误,但您已经得到了答案,对吗?从您的帖子中可以看出:
order(Mod(x)[1:22050], decreasing=T)[1:10]
[1] 441 881 882 880 883 442 440 879 884 878 

只需收集所有大于500的值:

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

生成新信号只需重复构建原始信号的步骤:
junk2 <- Sine(0, 1)    
for (i in 1:length(junk1)) {     
    junk2 <- junk2 + Sine(junk1[i], 1)    
}    
junk2.s <- as.vector(junk2$sound)    

保持值在500以下:

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

哎呀,这也太简单了吧XD 感谢您的回答!只是一个快速的问题,可能会成为我下一个官方问题:结果声音很糟糕,不完全是我想要的。您知道如何改进fft分析吗?有更好的方法来提取频率吗? - Tommaso
@Tommaso;我认为“不好听”的声音是由于多个频率造成的。从你的程序中,尝试以下操作:play(s1) play(s2)play(s3)。正是频率的混合导致了“不好听”的声音。也许你可以选择一个范围内的中间/中位数频率,而不是提取一系列频率。 - bill_080
@Tommaso;糟糕,时间不够了...选择中位数频率可以通过(junk1 <- median(junk[junk > 500]))来完成。 - bill_080
@Tommaso;在调试play()函数时,我发现了一些奇怪的结果。长话短说,尝试使用play(s3)play(s3/2)s3由两个频率组成。如果你建立了Z个频率,请将其除以Z来播放。 - bill_080
我得出了和你一样的结论。问题在于将输出缩放到(-1,1)范围内。这可以通过库soundnormalize函数来完成。在FFT分析后,我尝试重建原始声音。绘制plot(normalize(s3[1:600]))plot(normalize(junk4[1:600]+junk2[1:600]))(junk2包含频率> 500,junk4频率< 500),将向您展示一个相当不错的结果(尽管我必须找到更好的近似值)。谢谢你的帮助,贝尔! - Tommaso

1

看看CRAN上的“signal”包,那里应该有一个滤波函数可以做到。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接