尝试在 Python 中获取 .wav 文件的频率

新手上路,请多包涵

我想做的事情看起来很简单:我想确切地知道在给定时间 .wav 文件中有哪些频率;即“从时间 n 毫秒到 n + 10 毫秒,声音的平均频率为 x 赫兹”。我见过人们谈论傅里叶变换和 Goertzel 算法,以及各种模块,我似乎无法弄清楚如何去做我所描述的事情。

我正在寻找的是像这个伪代码这样的解决方案,或者至少是一个可以做一些类似于伪代码的事情的解决方案:

 import some_module_that_can_help_me_do_this as freq

file = 'output.wav'
start_time = 1000  # Start 1000 milliseconds into the file
end_time = 1010  # End 10 milliseconds thereafter

print("Average frequency = " + str(freq.average(start_time, end_time)) + " hz")

我没有数学背景,所以我不想了解实现细节。

原文由 Dante Falzone 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.4k
2 个回答

如果你想检测声音的 音调(你似乎这样做了),那么就 Python 库而言,你最好的选择是 aubio 。请参阅此 示例 以进行实施。

 import sys
from aubio import source, pitch

win_s = 4096
hop_s = 512

s = source(your_file, samplerate, hop_s)
samplerate = s.samplerate

tolerance = 0.8

pitch_o = pitch("yin", win_s, hop_s, samplerate)
pitch_o.set_unit("midi")
pitch_o.set_tolerance(tolerance)

pitches = []
confidences = []

total_frames = 0
while True:
    samples, read = s()
    pitch = pitch_o(samples)[0]
    pitches += [pitch]
    confidence = pitch_o.get_confidence()
    confidences += [confidence]
    total_frames += read
    if read < hop_s: break

print("Average frequency = " + str(np.array(pitches).mean()) + " hz")

请务必查看有关音调检测方法的 文档

我还认为您可能对在不使用任何特殊库的情况下估计平均频率和其他一些音频参数感兴趣。让我们只使用 numpy 吧!这应该可以让您更好地了解如何计算此类音频功能。它基于 seewave 包中的 specprop 。检查文档以了解计算特征的含义。

 import numpy as np

def spectral_properties(y: np.ndarray, fs: int) -> dict:
    spec = np.abs(np.fft.rfft(y))
    freq = np.fft.rfftfreq(len(y), d=1 / fs)
    spec = np.abs(spec)
    amp = spec / spec.sum()
    mean = (freq * amp).sum()
    sd = np.sqrt(np.sum(amp * ((freq - mean) ** 2)))
    amp_cumsum = np.cumsum(amp)
    median = freq[len(amp_cumsum[amp_cumsum <= 0.5]) + 1]
    mode = freq[amp.argmax()]
    Q25 = freq[len(amp_cumsum[amp_cumsum <= 0.25]) + 1]
    Q75 = freq[len(amp_cumsum[amp_cumsum <= 0.75]) + 1]
    IQR = Q75 - Q25
    z = amp - amp.mean()
    w = amp.std()
    skew = ((z ** 3).sum() / (len(spec) - 1)) / w ** 3
    kurt = ((z ** 4).sum() / (len(spec) - 1)) / w ** 4

    result_d = {
        'mean': mean,
        'sd': sd,
        'median': median,
        'mode': mode,
        'Q25': Q25,
        'Q75': Q75,
        'IQR': IQR,
        'skew': skew,
        'kurt': kurt
    }

    return result_d

原文由 Lukasz Tracewski 发布,翻译遵循 CC BY-SA 4.0 许可协议

这个答案很晚,但你可以试试这个:

(注意:我对此几乎不值得称赞,因为我从其他 SO 帖子和这篇关于使用 Python 的 FFT 的精彩文章中获得了大部分内容: https ://realpython.com/python-scipy-fft/)

 import numpy as np
from scipy.fft import *
from scipy.io import wavfile

def freq(file, start_time, end_time):

    # Open the file and convert to mono
    sr, data = wavfile.read(file)
    if data.ndim > 1:
        data = data[:, 0]
    else:
        pass

    # Return a slice of the data from start_time to end_time
    dataToRead = data[int(start_time * sr / 1000) : int(end_time * sr / 1000) + 1]

    # Fourier Transform
    N = len(dataToRead)
    yf = rfft(dataToRead)
    xf = rfftfreq(N, 1 / sr)

    # Uncomment these to see the frequency spectrum as a plot
    # plt.plot(xf, np.abs(yf))
    # plt.show()

    # Get the most dominant frequency and return it
    idx = np.argmax(np.abs(yf))
    freq = xf[idx]
    return freq

此代码适用于任何 .wav 文件,但它可能略有偏差,因为它只返回最主要的频率,也因为它只使用音频的第一个通道(如果不是单声道)。

如果您想了解有关傅里叶变换工作原理的更多信息,请观看 3blue1brown 制作的带有直观解释的视频: https ://www.youtube.com/watch?v=spUNpyF58BY

原文由 kidkoder432 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
logo
Stack Overflow 翻译
子站问答
访问
宣传栏