swift 3 FFT获取声音m4a的频率
Posted
技术标签:
【中文标题】swift 3 FFT获取声音m4a的频率【英文标题】:swift 3 FFT get frequency of sound m4a 【发布时间】:2016-12-04 16:04:12 【问题描述】:我是 ios 编程的初学者。 我必须为我的学校制定一个项目。目标是使用麦克风进行录音,然后应用高通滤波器并将其保存在 m4a 文件中。
在这个网站和许多其他网站上,我发现了很多相同的代码,但是随着 swift 3 的到来,这些代码不再起作用。
我首先使用 AVAudioPlayer 录制并保存从我的麦克风发出的声音。
然后我在 mpc 缓冲区中读取我的文件。
我从浮点数组的缓冲区中检索数据。
最后,我像我找到的示例一样应用 FFT。
如果我显示缓冲区的数据(来自缓冲区的浮点数表),这些数据包含一些内容。
如果我显示我的 VDSP 矢量,它包含数据。
但是当我应用 FFT 时,包含卷轴和虚数的 VDSP 输出结果返回“nan”值。
在这里,我不了解 FFT 的功能,也不了解 resutat“输出”是否包含频率,或者它是否只是包含频率的 VDSP 的参数之一。 (实数或虚数):
然后我想到对这些结果应用过滤器,然后将我的值放回逆 FFT 中,以便通过修改重建 m4a 文件。
如果你能向我解释我的方法是假的还是我的代码是假的
// recupere le lien du fichier audio a analysé
let url = getDocumentsDirectory().appendingPathComponent("recording.m4a")
// lancé l'audio dans le core AVaudioFile
let audioFile = try! AVAudioFile(forReading: url)
// nombre de frame dans l'audio
let frameCount = UInt32(audioFile.length)
print("frame count\(frameCount)")
//remplis un buffer avec les information du son et le nombre de framme
let buffer = AVAudioPCMBuffer(pcmFormat: audioFile.processingFormat, frameCapacity: frameCount)
do
//lecture de l'audio dans le buffer
try audioFile.read(into: buffer, frameCount:frameCount)
print("lecture ok")
catch
//lecture échouer
print(buffer.floatChannelData?.pointee ?? "aucune valeur float")
// printer le buffer de byte de l'audio
print("\n buffer: \n");
for k in 1...frameCount
print("value buffer \(buffer.floatChannelData?.pointee[Int(k)])");
// définit un fonction log2n
let log2n = UInt(round(log2(Double(frameCount))))
// définit la taille de buffer final potentiel
let bufferSizePOT = Int(1 << log2n)
//crée une structure FFT
//Si zéro est renvoyé, la routine n'a pas réussi à allouer de stockage
let fftSetup = vDSP_create_fftsetup(log2n, Int32(kFFTRadix2))
//print fft
print("valeur du fftSetup \(fftSetup)")
// create packed real input
// séparation des buffer en nombre réel et imaginaire :
var realp = [Float](repeating: 0.0, count: bufferSizePOT/2)
var imagp = [Float](repeating: 0.0, count: bufferSizePOT/2)
/*
print("\n real and image: \n");
for k in 0..<realp.count
print("value real \(realp[k]) et value imaginaire \(imagp[k])");
*/
// construit un vecteur double contenant les real et les imaginaire
var output = DSPSplitComplex(realp: &realp, imagp: &imagp)
buffer.floatChannelData?.withMemoryRebound(to: DSPComplex.self, capacity: bufferSizePOT/2)
/*
Copie le contenu d'un vecteur complexe intercalé C vers un vecteur complexe divisé Z; Précision unique.
void vDSP_ctoz(const DSPComplex *__C, vDSP_Stride __IC, const DSPSplitComplex *__Z, vDSP_Stride __IZ, vDSP_Length __N);
Paramètres
__C
Vecteur d'entrée complexe entrelacé à simple précision.
__IC
Stride pour C; Doit être un nombre pair.
__Z
Vecteur de sortie complexe à division simple.
za
Stride pour Z.
__N
Le nombre d'éléments à traiter.
*/
dspComplexStream in vDSP_ctoz(dspComplexStream, 2, &output, 1, UInt(bufferSizePOT / 2))
/*
calcul la série de fourier discrette du domaine temporel ver le domaine fréquentielle
paramètre :
func vDSP_fft_zrip(_ __Setup:
- --FFTSetup: l'objet FFTsetup
_ __C: pointeur sur le vecteur complex de sortie
_ __IC: pas entre les elements de --C, (a 1 pour des meilleures performance)
_ __Log2N: Il base 2 exposant du nombre d'éléments à traiter. Par exemple, pour traiter 1024 éléments,
spécifiez 10 pour le paramètre Log2N.
_ __Direction: FFTDirection : donne la direction de la discretisations.
time domain to the frequency domain = (forward).
frequency domain to the time domain (inverse).
)*/
vDSP_fft_zrip(fftSetup!, &output, 1, log2n, Int32(FFTDirection(FFT_FORWARD)))
print("\nSpectrum:\n");
for i in 0..<realp.count
print("value de i \(i), réel : \(output.realp[i]), imaginaire : \(imagp[i])");
var fft = [Float](repeating:0.0, count:Int(bufferSizePOT / 2))
let bufferOver2: vDSP_Length = vDSP_Length(bufferSizePOT / 2)
vDSP_zvmags(&output, 1, &fft, 1, bufferOver2)
for i in 0..<bufferSizePOT/2
print("value de buff2 \(fft[i])");
// termine le processus FFT
vDSP_destroy_fftsetup(fftSetup)
编辑:用过滤器低通播放歌曲并且不工作
engine = AVAudioEngine()
player = AVAudioPlayerNode()
player.volume = 1.0
let path = Bundle.main.path(forResource: "audio10to1000", ofType: "wav")!
let url = NSURL.fileURL(withPath: path)
let file = try? AVAudioFile(forReading: url)
var mainMixer = AVAudioMixerNode()
mainMixer = engine.mainMixerNode
engine.attach(player)
EQNode = AVAudioUnitEQ(numberOfBands: 1)
var filterParams = EQNode.bands[0] as AVAudioUnitEQFilterParameters
filterParams.filterType = .lowPass
filterParams.frequency = 500.0
filterParams.bypass = false
engine.attach(EQNode)
engine.connect(player, to: EQNode, format: file?.processingFormat)
engine.connect(EQNode, to: mainMixer, format: file?.processingFormat)
// engine.connect(player, to: mainMixer, format: file?.processingFormat)
player.scheduleFile(file!, at: nil, completionHandler: nil)
engine.prepare()
do
try engine.start()
catch _
print("******************* erreur *************")
player.play()
【问题讨论】:
您不需要 FFT 来应用高切滤波器。谷歌AVAudioUnitEQ
。如果您想自己实现一个,请先选择 FIR 或 IIR 解决方案:en.wikipedia.org/wiki/Low-pass_filter 玩得开心!
hiii 感谢您的帮助。我已经努力使用 AVAudioUnitEQ。它在mixernode中使用的所有效果(示例spitch)都可以正常工作。但 Eq 节点不起作用。这就是我的代码:3 天就可以了,没有任何工作......
没什么可改变的......再次感谢您的帮助只是为了确保我理解。当我使用 500 Hz 低通滤波器时。如果我的音频是一首以 10hz 开始的生成歌曲,然后在 10 秒内以 1000hz 结束,那么在一半的时间里我应该什么都听不到了?当我改变 EQ 的 gainGlobal 时,这项工作但 filterParams 中的增益没有任何改变..
如果你发一个示例项目的链接,我去看看。
drive.google.com/file/d/0B7qN8KEpAsYeQUZtOG9ab1R6Sjg/… 谢谢@shallowthought
【参考方案1】:
您的代码正在运行。您的设置不符合您的需求。
设置filterParams.gain = -96.0
(最小可能值)
低通滤波器没有bandwidth
,删除它。
为了更彻底的结果,首先将截止频率设置为 100 HZ:
filterParams.frequency = 100.0
您对低通滤波器结果的期望(截止频率以上 100% 的截止)与滤波器的实际情况不符。根据实现(使用的算法和顺序),过滤器或多或少会快速切断。
查看这个典型的过滤器响应from Wikipedia:
【讨论】:
您好,抱歉,我还需要您的帮助。我有音频的大小标签。我正在应用我需要的所有过滤器。但我不知道如何在我的音频中花时间,当噪音开始和结束时。你有什么想法吗? 我如何理解您想要做的是确定幅度(音量值)何时超过阈值。我做对了吗?当你真正开始听到/停止听到声音时。 好的,基本上,我需要帮助的是在样本中拾取某种声音。我要查找的信息是样本中声音开始和结束的时间(以时间单位(ms、s 或其他)为单位)。我的样本是一个人服用呼吸系统药物的录音。我减弱了环境噪音,这样我就可以得到那个人正在服药的部分。我想要那个人开始服药和声音结束的时间戳。 这里跑题了。 Lets chat.以上是关于swift 3 FFT获取声音m4a的频率的主要内容,如果未能解决你的问题,请参考以下文章