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

尝试在Python中获取.wav文件的频率,python,python-3.x,audio,wav,Python,Python 3.x,Audio,Wav,我知道关于Python中.wav文件的问题几乎被打得要死,但我非常沮丧,因为似乎没有人的答案对我有用。我试图做的事情对我来说似乎相对简单:我想确切地知道在给定时间.wav文件中有哪些频率。我想知道,例如,“从n毫秒到n+10毫秒,声音的平均频率是x赫兹”。我看到人们谈论傅里叶变换和戈尔采尔算法,以及各种模块,我似乎不知道如何实现我所描述的。我试着查找诸如“在python中查找wav文件的频率”之类的内容大约20次,但都没有结果。有人能帮我吗 我所寻找的是一个类似于此伪代码的解决方案,或者至少是一

我知道关于Python中.wav文件的问题几乎被打得要死,但我非常沮丧,因为似乎没有人的答案对我有用。我试图做的事情对我来说似乎相对简单:我想确切地知道在给定时间.wav文件中有哪些频率。我想知道,例如,“从n毫秒到n+10毫秒,声音的平均频率是x赫兹”。我看到人们谈论傅里叶变换和戈尔采尔算法,以及各种模块,我似乎不知道如何实现我所描述的。我试着查找诸如“在python中查找wav文件的频率”之类的内容大约20次,但都没有结果。有人能帮我吗

我所寻找的是一个类似于此伪代码的解决方案,或者至少是一个可以实现伪代码所要实现的功能的解决方案:

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")

请假设(我相信你会知道)我是个数学白痴。这是我在这里的第一个问题,所以请温柔些

尝试下面的内容,它对我来说很有用,我生成了一个频率为1234的正弦波文件

从scipy.io导入wavfile
def freq(文件、开始时间、结束时间):
采样率,数据=wavfile.read(文件)
起始点=整数(采样率*起始时间/1000)
结束点=整数(采样率*结束时间/1000)
长度=(结束时间-开始时间)/1000
计数器=0
对于范围内的i(起点、终点):
如果数据[i]<0且数据[i+1]>0:
计数器+=1
返回计数器/长度
频率(“正弦波形”,10002100)
1231.8181818181818
编辑:对循环进行了一些清理

如果您想检测声音的声音(看起来您是这样做的),那么就Python库而言,您的最佳选择是。请参考此文件以了解实施情况

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")
导入系统 来自aubio导入源,沥青 win_s=4096 hop_s=512 s=源(您的_文件、采样器、跃点) samplerate=s.samplerate 公差=0.8 音高=音高(“阴”,赢,跳,采样器) 音高设置单位(“midi”) 螺距设置公差(公差) 音高=[] 信任=[] 总帧数=0 尽管如此: 样本,读取=s() 螺距=螺距(样本)[0] 音高+=[音高] 信心=投球获得信心() 信心+=[信心] 总帧数+=读取 如果读取 务必检查俯仰检测方法

我还认为您可能对估计平均频率和其他一些音频参数感兴趣,而不需要使用任何特殊的库。让我们用numpy!这将使您更好地了解如何计算这些音频功能。这是基于包装上的。检查文档中计算特征的含义

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
将numpy导入为np
def光谱特性(y:np.ndarray,fs:int)->dict:
规格=np.abs(np.fft.rfft(y))
freq=np.fft.rfftfreq(len(y),d=1/fs)
规格=np.abs(规格)
amp=规格/规格总和()
平均值=(频率*amp).sum()
sd=np.sqrt(np.sum(安培*((频率-平均值)**2)))
amp_cumsum=np.cumsum(amp)

中位数=freq[len(amp_cumsum[amp_cumsum]amp_cumsum我感觉到了OPs的挫折感——如果有人需要:

#!/usr/bin/env python

import librosa
import sys
import numpy as np
import matplotlib.pyplot as plt
import librosa.display

np.set_printoptions(threshold=sys.maxsize)

filename = 'filename.wav'
Fs = 44100
clip, sample_rate = librosa.load(filename, sr=Fs)

n_fft = 1024  # frame length 
start = 0 

hop_length=512

#commented out code to display Spectrogram
X = librosa.stft(clip, n_fft=n_fft, hop_length=hop_length)
#Xdb = librosa.amplitude_to_db(abs(X))
#plt.figure(figsize=(14, 5))
#librosa.display.specshow(Xdb, sr=Fs, x_axis='time', y_axis='hz') 
#If to pring log of frequencies  
#librosa.display.specshow(Xdb, sr=Fs, x_axis='time', y_axis='log')
#plt.colorbar()

#librosa.display.waveplot(clip, sr=Fs)
#plt.show()

#now print all values 

t_samples = np.arange(clip.shape[0]) / Fs
t_frames = np.arange(X.shape[1]) * hop_length / Fs
#f_hertz = np.arange(N / 2 + 1) * Fs / N       # Works only when N is even
f_hertz = np.fft.rfftfreq(n_fft, 1 / Fs)         # Works also when N is odd

#example
print('Time (seconds) of last sample:', t_samples[-1])
print('Time (seconds) of last frame: ', t_frames[-1])
print('Frequency (Hz) of last bin:   ', f_hertz[-1])

print('Time (seconds) :', len(t_samples))

#prints array of time frames 
print('Time of frames (seconds) : ', t_frames)
#prints array of frequency bins
print('Frequency (Hz) : ', f_hertz)

print('Number of frames : ', len(t_frames))
print('Number of bins : ', len(f_hertz))

#This code is working to printout frame by frame intensity of each frequency
#on top line gives freq bins
curLine = 'Bins,'
for b in range(1, len(f_hertz)):
    curLine += str(f_hertz[b]) + ','
print(curLine)

curLine = ''
for f in range(1, len(t_frames)):
    curLine = str(t_frames[f]) + ','
    for b in range(1, len(f_hertz)): #for each frame, we get list of bin values printed
        curLine += str("%.02f" % np.abs(X[b, f])) + ','
        #remove format of the float for full details if needed
        #curLine += str(np.abs(X[b, f])) + ','
        #print other useful info like phase of frequency bin b at frame f.
        #curLine += str("%.02f" % np.angle(X[b, f])) + ',' 
    print(curLine)

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

(注意:我应该得到很少的赞扬,因为我从其他SO帖子和这篇关于使用Python进行FFT的伟大文章中获得了大部分信息:)

此代码可以用于任何
.wav
文件,但可能会稍微关闭,因为它只返回最主要的频率,并且只使用音频的第一个通道(如果不是单声道)


如果您想进一步了解傅里叶变换的工作原理,请查看3blue1brown的视频,并提供一个直观的解释:

查看相关:您是指主频吗?请注意,任何真实音频信号都包含各种频率的混合。您可以简单地计算平均值(例如,从@Primusa共享的链接),但我怀疑这是你要找的。是的,这听起来像我要找的。对于我的
输出.wav
文件,我使用的是我自己在卡西欧上播放的录音,所以录音中会有噪音。这就是我想要的主频吗?正确。我的代码对你有用吗?谢谢,但似乎有问题。当我在这里的代码中(对于
freq
调用,使用适当的print语句),它给出了一个错误
ValueError:具有多个元素的数组的真值是不明确的。请使用a.any()或a.all()
。因此,我尝试将第10行更改为
if data[I].all()<0和data[I+1].all()>0:
然后
如果数据[i].any()<0和数据[i+1].any()>0:
,但这两次我都得到了
0.0
,不管我为开始/结束指定了什么时间。奇怪的是,你能分享文件和传递给这个函数的开始/结束时间吗?你运行的是哪个版本的Python?运行的是Python 3.7。下面是引发
ValueError
https://pastebin.com/aT4F4bg40.0
,无论我使用什么开始/结束时间:
https://pastebin.com/CB9TwbLT
这里有一个也只返回
0.0
https://pastebin.com/rCSw5Rc4
此算法只能在信号中存在单一频率的情况下工作。本质上,它是一种简化的wa计算过零率的y。工作得非常好,但我必须调整一些东西。它首先给我一个错误,说
置信度
没有定义,我不确定如何计算它,所以我只是将它硬编码为0.8。然后它给我一个串联类型错误,因为
np.array(pitchs).mean()
不返回字符串,所以我
str()
编辑了它,现在它工作得很好。感谢您感谢Hanks@kitty4537为
#!/usr/bin/env python

import librosa
import sys
import numpy as np
import matplotlib.pyplot as plt
import librosa.display

np.set_printoptions(threshold=sys.maxsize)

filename = 'filename.wav'
Fs = 44100
clip, sample_rate = librosa.load(filename, sr=Fs)

n_fft = 1024  # frame length 
start = 0 

hop_length=512

#commented out code to display Spectrogram
X = librosa.stft(clip, n_fft=n_fft, hop_length=hop_length)
#Xdb = librosa.amplitude_to_db(abs(X))
#plt.figure(figsize=(14, 5))
#librosa.display.specshow(Xdb, sr=Fs, x_axis='time', y_axis='hz') 
#If to pring log of frequencies  
#librosa.display.specshow(Xdb, sr=Fs, x_axis='time', y_axis='log')
#plt.colorbar()

#librosa.display.waveplot(clip, sr=Fs)
#plt.show()

#now print all values 

t_samples = np.arange(clip.shape[0]) / Fs
t_frames = np.arange(X.shape[1]) * hop_length / Fs
#f_hertz = np.arange(N / 2 + 1) * Fs / N       # Works only when N is even
f_hertz = np.fft.rfftfreq(n_fft, 1 / Fs)         # Works also when N is odd

#example
print('Time (seconds) of last sample:', t_samples[-1])
print('Time (seconds) of last frame: ', t_frames[-1])
print('Frequency (Hz) of last bin:   ', f_hertz[-1])

print('Time (seconds) :', len(t_samples))

#prints array of time frames 
print('Time of frames (seconds) : ', t_frames)
#prints array of frequency bins
print('Frequency (Hz) : ', f_hertz)

print('Number of frames : ', len(t_frames))
print('Number of bins : ', len(f_hertz))

#This code is working to printout frame by frame intensity of each frequency
#on top line gives freq bins
curLine = 'Bins,'
for b in range(1, len(f_hertz)):
    curLine += str(f_hertz[b]) + ','
print(curLine)

curLine = ''
for f in range(1, len(t_frames)):
    curLine = str(t_frames[f]) + ','
    for b in range(1, len(f_hertz)): #for each frame, we get list of bin values printed
        curLine += str("%.02f" % np.abs(X[b, f])) + ','
        #remove format of the float for full details if needed
        #curLine += str(np.abs(X[b, f])) + ','
        #print other useful info like phase of frequency bin b at frame f.
        #curLine += str("%.02f" % np.angle(X[b, f])) + ',' 
    print(curLine)
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