2017-05-29 2 views
3

Je voudrais faire un égaliseur audio à 5 bandes (60Hz, 230Hz, 910Hz, 4kHz, 14kHz) en utilisant AVAudioEngine. Je voudrais avoir le gain d'entrée d'utilisateur par bande à travers un curseur vertical et ajuster en conséquence l'audio qui joue. J'ai essayé d'utiliser AVAudioUnitEQ pour ce faire, mais je n'entends aucune différence lors de la lecture de l'audio. J'ai essayé de coder en dur dans les valeurs pour spécifier un gain à chaque fréquence, mais cela ne fonctionne toujours pas. Voici le code que j'ai:Construire un égaliseur simple

var audioEngine: AVAudioEngine = AVAudioEngine() 
var equalizer: AVAudioUnitEQ! 
var audioPlayerNode: AVAudioPlayerNode = AVAudioPlayerNode() 
var audioFile: AVAudioFile! 

// in viewDidLoad(): 
equalizer = AVAudioUnitEQ(numberOfBands: 5) 
audioEngine.attach(audioPlayerNode) 
audioEngine.attach(equalizer) 
let bands = equalizer.bands 
let freqs = [60, 230, 910, 4000, 14000] 
audioEngine.connect(audioPlayerNode, to: equalizer, format: nil) 
audioEngine.connect(equalizer, to: audioEngine.outputNode, format: nil) 
for i in 0...(bands.count - 1) { 
    bands[i].frequency = Float(freqs[i]) 
} 

bands[0].gain = -10.0 
bands[0].filterType = .lowShelf 
bands[1].gain = -10.0 
bands[1].filterType = .lowShelf 
bands[2].gain = -10.0 
bands[2].filterType = .lowShelf 
bands[3].gain = 10.0 
bands[3].filterType = .highShelf 
bands[4].gain = 10.0 
bands[4].filterType = .highShelf 

do { 
    if let filepath = Bundle.main.path(forResource: "song", ofType: "mp3") { 
     let filepathURL = NSURL.fileURL(withPath: filepath) 
     audioFile = try AVAudioFile(forReading: filepathURL) 
     audioEngine.prepare() 
     try audioEngine.start() 
     audioPlayerNode.scheduleFile(audioFile, at: nil, completionHandler: nil) 
     audioPlayerNode.play() 
    } 
} catch _ {} 

Depuis les basses fréquences ont un gain de -10 et les hautes fréquences ont un gain de 10, il devrait y avoir une différence très perceptible lors de la lecture des médias. Cependant, lorsque le média commence à jouer, il sonne comme s'il était joué sans égaliseur. Je ne suis pas sûr de savoir pourquoi cela se produit, mais j'ai essayé plusieurs choses différentes pour déboguer. Je pensais que c'était peut-être l'ordre des fonctions, donc j'ai essayé de le changer pour que l'on appelle audioEngine.connect après avoir ajusté toutes les bandes, mais ça n'a pas fait de différence non plus.

J'ai essayé ce même code en utilisant un AVAudioUnitTimePitch, et cela a fonctionné parfaitement, donc je suis abasourdi de savoir pourquoi cela ne fonctionne pas avec AVAudioUnitEQ.

Je ne veux pas utiliser de bibliothèques tierces ou de cosses de cacao pour ce projet, je voudrais le faire en utilisant AVFoundation seul.

Toute aide serait grandement appréciée!

Merci d'avance.

Répondre

4

AVAudioUnitEQFilterParameters AVAudioUnitEQFilterParameters Documentation En regardant à travers la documentation, je remarquais que j'avais sali avec tous les paramètres sauf bypass et il semble que la modification de ce drapeau tout fixe! Donc, je crois que le problème principal ici est que chaque bande AVAudioUnitEQ ne doit pas être ignorée par les valeurs système fournies plutôt que par les valeurs définies par le programmeur.

Alors, je l'ai changé

for i in 0...(bands.count - 1) { 
    bands[i].frequency = Float(freqs[i]) 
} 

à

for i in 0...(bands.count - 1) { 
    bands[i].frequency = Float(freqs[i]) 
    bands[i].bypass  = false 
    bands[i].filtertype = .parametric 
} 

et tout commencé à travailler. De plus, pour faire un égaliseur efficace qui permet à l'utilisateur de modifier des fréquences individuelles, le filtertype pour chaque bande doit être réglé sur .parametric. Je ne suis toujours pas sûr de ce que je devrais définir la bande passante, mais je peux probablement vérifier en ligne pour cela ou simplement jouer avec elle jusqu'à ce que le son corresponde à une application d'égaliseur différente.