2016-12-04 2 views
1

Ich bin ein Anfänger in Programmierung ios. Ich muss ein Projekt für meine Schule machen. Das Ziel ist, eine Aufnahme mit dem Mikrofon zu machen, dann einen Hochpassfilter anzuwenden und es in einer m4a-Datei zu speichern.swift 3 FFT bekommen Frequenz von Ton m4a

Auf dieser Seite und vielen anderen fand ich eine Menge identischen Code, aber mit der Ankunft von Swift 3, ist der Code nicht mehr funktional.

Ich beginne mit der Aufnahme und Speichern, was aus meinem Mikrofon mit AVAudioPlayer kommt.

Dann lese ich meine Datei in einem MPC-Puffer.

Ich erhalte die Daten aus dem Puffer in einem Float-Array.

Und schließlich, ich verwende eine FFT wie die Beispiele, die ich gefunden habe.

Wenn ich die Daten des Puffers (Float-Tabelle aus dem Puffer) anzeigen, enthalten diese etwas.

Wenn ich meinen VDSP-Vektor anzeige, enthält er die Daten.

Aber wenn ich die FFT anwende, gibt das Ergebnis meiner VDSP-Ausgabe, die die Rolle und das Imaginäre enthält, "Nan" -Werte zurück.

Hier verstehe ich nicht die Funktionsweise der FFT und ich verstehe nicht, wenn das resutat "output" die Frequenzen enthält oder wenn es nur einer der Parameter meines VDSP ist, die sie enthalten. (Real oder imaginär):

Ich dachte dann, einen Filter auf diese Ergebnisse anzuwenden und dann meine Werte zurück in eine inverse FFT zu setzen, um die m4a-Datei mit den Modifikationen zu rekonstruieren.

Wenn könnten Sie mir erklären, wenn meine Methode falsch ist oder wenn es mein Code ist, dass

// 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: juster play Song mit Tiefpassfilter und arbeitet nicht

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

Sie FFT nicht benötigen einen hohen Cut-Filter anzuwenden. Google für 'AVAudioUnitEQ'. Wenn Sie selbst eines implementieren möchten, gehen Sie zuerst zu einer FIR oder IIR Lösung: https://en.wikipedia.org/wiki/Low-pass_filter Viel Spaß! – shallowThought

+0

hiii danke für Ihre Hilfe. Ich habe versucht, das AVAudioUnitEQ zu verwenden. Alle Effekte (Beispielspitch), die es im Mixernode verwendet, funktionieren einwandfrei. aber der Eq-Knoten funktioniert nicht. das ist mein Code: 3 Tage darauf nichts als Arbeit ... –

+0

Nichts zu ändern ... Danke noch einmal für Ihre Hilfe Nur um sicher zu sein, verstehe ich. Wenn ich einen 500 Hz Tiefpassfilter verwende. Wenn mein Audio ein generierender Song ist, der um 10 Uhr beginnt und dann in 10 Sekunden bei 1000 Hz endet, sollte ich zur Hälfte nichts mehr hören? wenn ich gainGlobal des EQ ändere, diese Arbeit, aber Gewinn in filterParams ändern nichts. –

Antwort

1

Ihren Code funktioniert. Ihre Einstellungen entsprechen nicht Ihren Anforderungen.

  • Set filterParams.gain = -96.0 (der mininimal mögliche Wert)

  • Ein Tiefpassfilter keine bandwidth hat, löschen.

Für radikaleren Ergebnisse setzten die Grenzfrequenz zunächst auf 100 Hz:

  • filterParams.frequency = 100.0

Ihre Erwartung an das Ergebnis eines Tiefpassfilter (Schneiden von 100% über den Cutoff Frequenz) entspricht nicht der Realität von Filtern. Je nach Implementierung (verwendeter Algorithmus und Reihenfolge) schneidet ein Filter mehr oder weniger schnell ab.

Sehen Sie diese typische Filterantwort from Wikipedia:

+0

Hallo, tut mir leid, aber ich brauche noch einmal Ihre Hilfe. Ich habe Magnitudenreiter des Audio. Ich habe alle Filter angewendet, die ich brauche. Aber ich weiß nicht, wie ich mir die Zeit in meinem Audio nehmen kann, als ein Geräusch begann und endete. Haben Sie eine Idee? –

+0

Wie ich verstehe, was Sie tun möchten, ist herauszufinden, wenn die Amplitude (Volumenwert) einen Schwellenwert überschreitet. Habe ich das richtig verstanden? Wenn du hörst oder hörst, hörst du. – shallowThought

+0

Ok, also im Grunde brauche ich Hilfe bei der Aufnahme eines bestimmten Sounds innerhalb einer Probe. Die Information, nach der ich suche, ist die Zeit, in der dieser Sound in der Probe in Zeiteinheiten (ms, s oder was auch immer) beginnt und endet. Meine Probe ist ein aufgezeichnetes Geräusch einer Person, die eine Atemwegsmedizin einnimmt. Ich dämpfe die Umgebungsgeräusche, damit ich genau den Teil bekomme, an dem die Person das Medikament einnimmt. Und ich möchte die Zeitstempel, wenn diese Person beginnt, die Medizin zu nehmen und wenn der Ton endet. –