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()
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
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 ... –
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. –