swift 3 FFT得到声音m4a的频率

swift 3 FFT get frequency of sound m4a

我是编程初学者ios。 我必须为我的学校做一个项目。目标是用麦克风录音,然后应用高通滤波器并将其保存在 m4a 文件中。

在这个网站和许多其他网站上,我发现了很多相同的代码,但是随着 swift 3 的到来,代码不再起作用。

我首先使用 AVAudioPlayer 录制和保存从我的麦克风中传出的内容。

然后我在 mpc 缓冲区中读取我的文件。

我从浮点数组中的缓冲区中检索数据。

最后,我像找到的示例一样应用 FFT。

如果我显示缓冲区的数据(table 来自缓冲区的浮点数)这些包含一些东西。

如果我显示我的 VDSP 矢量,它包含数据。

但是当我应用 FFT 时,我的 VDSP 输出结果包含卷轴和虚数 returns "nan" 值。

这里我不明白 FFT 的功能,我不明白结果 "output" 是否包含频率,或者它是否只是我的 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()

您的代码正在运行。您的设置不符合您的需求。

  • 设置filterParams.gain = -96.0(最小可能值)

  • 一个低通滤波器没有bandwidth,删掉。

要获得更激进的结果,请先将截止频率设置为 100 HZ:

  • filterParams.frequency = 100.0

您对低通滤波器结果的期望(截止频率以上 100% 的削减)与滤波器的实际情况不符。根据实现(使用的算法和顺序),过滤器或多或少会快速切断。

查看此典型过滤器响应 from Wikipedia