0
votes

I am a beginner in programming ios. I have to make a project for my school. The goal is to make a recording with the microphone then apply a high pass filter and save it in an m4a file.

On this site and many others, I found a lot of identical code but yet with the arrival of swift 3, the code is no longer functional.

I start by recording and saving what comes out of my microphone with AVAudioPlayer.

Then I read my file in an mpc buffer.

I retrieve the data from the buffer in a float array.

And finally, I apply a FFT like the examples I found.

If I display the data of the buffer (table of float coming from the buffer) these contain something.

If I display my VDSP vector it contains the data.

But when I apply the FFT, the result of my VDSP output that contains the reel and the imaginary returns "nan" values.

Here I do not understand the functioning of the FFT and I do not understand if the resutat "output" contains the frequencies or if it is only one of the parameters of my VDSP that contain them. (Real or imaginary):

I then thought of applying a filter on these results and then putting my values ​​back into an inverse FFT in order to reconstruct the m4a file with the modifications.

If you could explain to me if my method is false or if it is my code that

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

EDIT : juste play song with filter low pass and dont work

 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()
1
You do not need FFT to apply a high cut filter. Google for AVAudioUnitEQ. If you want to implement one yourself, first go for a FIR or IIR solution: en.wikipedia.org/wiki/Low-pass_filter Have fun!shallowThought
hiii thanks you for your help. i have tried hard to use the AVAudioUnitEQ. all effect (example spitch) it use in the mixernode work fine. but the Eq node dont work. thats my code : 3 days on it ans nothing work...Cyril Jeanneret
Nothing to change ... thank you again for your help Just to be sure I understand. When I use a 500 Hz low-pass filter. If my audio is a generating song that starts at 10hz then ends at 1000hz in 10 seconds, at half the time I should not hear anything anymore? when i change gainGlobal of the EQ, this work but gain in filterParams change nothing..Cyril Jeanneret
If you post a link to the sample project, I will have a look.shallowThought

1 Answers

1
votes

Your code is working. Your settings are not fitting your needs.

  • Set filterParams.gain = -96.0 (the mininimal possible value)

  • A low pass filter has no bandwidth, delete it.

For more radical results set the cutoff frequency to 100 HZ first:

  • filterParams.frequency = 100.0

Your expectation to the result of a low pass filter (cutting of 100% above cutoff frequency) does not fit the reality of filters. Depending on the implementation (used algorithm and order) a filter cuts off more or less fast.

See this typical filter response from Wikipedia: