AVAudioEngine AVAudioUnitTimePitch und AVAudioUnitVarispeed

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • AVAudioEngine AVAudioUnitTimePitch und AVAudioUnitVarispeed

    Hallo Forum,

    ich bin neu in Swift und macOS Programmierung. Um Swift für macOS zu lernen habe ich mir ein Projekt ausgedacht. Ein Teil des Projektes erfordert es eine Audiodatei zu Laden, abzuspielen sowie Geschwindigkeit und Tonhöhe anzupassen.
    Wenn ich alles richtig Verstanden habe, sollte alles, was ich möchte mit der AVAudioEngine möglich sein.

    Ein Lauffähiges Setup des Audios habe ich durch diese zwei Tutorials hinbekommen.
    Gilt eigentlich für iOS aber das Framework gibt es auch für macOS - hackingwithswift
    Damit das Audio unter macOS auch funktioniert muss, nur ein MainMixer initialisiert werden, ohne diese war bzw. ist das Tutorial von iOS nicht auf macOS lauffähig bzw. es kommt ein Ton.
    Dies habe ich mir hier medium.com aus dem Quellcode herausgelesen.

    Play, geht bei mir ohne Probleme.
    Möchte ich jedoch Geschwindigkeit und Tonhöhe verändert, passiert einfach nichts (zumindest nichts hörbares)!

    Ich hoffe, ihr könnt mir hier helfen und sagen was ich falsch mache.

    C-Quellcode

    1. class ViewController: NSViewController {
    2. @IBOutlet weak var playButton: NSButton!
    3. @IBOutlet weak var stopButton: NSButton!
    4. @IBOutlet weak var volumeSlider: NSSlider!
    5. @IBOutlet weak var speedSlider: NSSlider!
    6. @IBOutlet var showVolume: NSTextField!
    7. @IBOutlet var showSpeed: NSTextField!
    8. let player = AVAudioPlayerNode()
    9. let engine = AVAudioEngine()
    10. let speedControl = AVAudioUnitVarispeed()
    11. let pitchControl = AVAudioUnitTimePitch()
    12. var fileURL: URL!
    13. ...
    14. // fileURL wird durch ein File Dialog path in URL.
    15. ...
    16. fileURL = URL(fileURLWithPath: url!.path)
    17. _ = engine.mainMixerNode
    18. do {
    19. let audioFile = try AVAudioFile(forReading: fileURL)
    20. //let format = audioFile.processingFormat
    21. engine.attach(player)
    22. engine.attach(speedControl)
    23. engine.attach(pitchControl)
    24. engine.connect(player, to: speedControl, format: nil)
    25. engine.connect(player, to: engine.mainMixerNode, format: nil)
    26. engine.connect(speedControl, to: pitchControl, format: nil)
    27. engine.connect(pitchControl, to: engine.mainMixerNode, format: nil)
    28. player.scheduleFile(audioFile, at: nil, completionHandler: nil)
    29. } catch let error {
    30. print(error.localizedDescription)
    31. }
    32. engine.prepare()
    33. do {
    34. try engine.start()
    35. } catch let error {
    36. print("Error: \(error.localizedDescription)")
    37. }
    38. } else {
    39. // Cancel Clicked
    40. return
    41. }
    42. }
    Alles anzeigen

    Play, Pause habe ich über einen Button realisiert was auch funktioniert. Was nur ein player.play() und player.pause() aufruft.
    Geschwindigkeit möchte ich über einen Slider realisieren, der dann diese Funktion aufruft.


    C-Quellcode

    1. @IBAction func setSpeed(_ sender: Any) {
    2. let number = speedSlider.floatValue / 100.0
    3. let formatted = String(format: "%.1f", number)
    4. let speed = (formatted as NSString).floatValue
    5. print("pitch: \(speed/2)")
    6. pitchControl.pitch = speed/2
    7. print("rate: \(speed)")
    8. speedControl.rate = speed
    9. showSpeed.floatValue = speed
    10. print("speed: \(speed)")
    11. }
    Alles anzeigen
    Egal was ich an speedControl.rate oder pitchControl.pitch übergebe, es ändert sich nichts.
    Testweise habe auch mal Werte gesetzt, wo ich die Enging einrichte, aber es passiert einfach nichts.

    Ich hoffe, ich konnte das Problem verständlich erklären.

    Schon mal vielen Dank im Voraus!
  • Hallo Mattes,

    alles klar, ich werde nicht mehr so schnell ein Post löschen. Sorry, dachte, der Post wäre noch nicht veröffentlicht und musste mich auch nochmal sammeln.

    Für alle die es Interessiert, ich hatte versucht die AVAudioEngine zum Laufen zu bekommen wie im hackingswift Artikel beschrieben. Was fehlte, um es auf macOS zum Laufen zu bekommen war ein "_ = engine.mainMixerNode", was ich in einem Quellcode auf medium.com gefunden hatte und einfach blind testete und hatte damit Erfolg.

    LG
  • Hi,

    1. ich muss meine Aussage mit dem Mixer zurückrufen. Aus irgend einen Grund geht das jetzt auch ohne. Hab einfach zu viel herumgespielt, um wirklich zu wissen, woran dies am Anfang lag.
    2. Hab den Fehler gefunden, warum Speed und Tonhöhe nicht funktionierten. Habe mir die Webseite hackingwithswift,die ich im ersten Post verlinkt habe, nochmal aufmerksam durchgelesen und hierbei fiel mir auf das ich mehrere enging connects hatte, sogar mehr als eigentlich notwendig.

    Für was der MainMixer wichtig ist, weiß ich noch nicht, aber da dieser Funktioniert hab ich es mal gelassen und auch in einer Variable gespeichert.

    Mein Code der Funktioniert sieht jetzt so aus.


    C-Quellcode

    1. override func viewDidLoad() {
    2. super.viewDidLoad()
    3. // Do any additional setup after loading the view.
    4. volumeSlider.floatValue = 10.0
    5. speedSlider.floatValue = 100.0
    6. volumeSlider.allowsTickMarkValuesOnly = true
    7. speedSlider.allowsTickMarkValuesOnly = true
    8. let dialog = NSOpenPanel()
    9. dialog.title = "Choose a file!"
    10. dialog.showsResizeIndicator = true
    11. dialog.showsHiddenFiles = false
    12. dialog.allowsMultipleSelection = false
    13. dialog.canChooseFiles = true
    14. dialog.canChooseDirectories = false
    15. if (dialog.runModal() == NSApplication.ModalResponse.OK) {
    16. let url = dialog.url
    17. fileURL = URL(fileURLWithPath: url!.path)
    18. let mixer = engine.mainMixerNode
    19. do {
    20. let audioFile = try AVAudioFile(forReading: fileURL)
    21. let format = audioFile.processingFormat
    22. engine.attach(player)
    23. engine.attach(speedControl)
    24. engine.attach(pitchControl)
    25. engine.connect(player, to: speedControl, format: format)
    26. engine.connect(speedControl, to: pitchControl, format: format)
    27. engine.connect(pitchControl, to: mixer, format: format)
    28. player.scheduleFile(audioFile, at: nil, completionHandler: nil)
    29. } catch let error {
    30. print(error.localizedDescription)
    31. }
    32. engine.prepare()
    33. do {
    34. try engine.start()
    35. } catch let error {
    36. print("self Error: \(error.localizedDescription)")
    37. }
    38. } else {
    39. // Cancel Clicked
    40. return
    41. }
    42. }
    Alles anzeigen
    Jetzt funktioniert Speed und Pitch perfekt.
    Muss nur noch rausfinden welche Tonhöhe bei welcher Geschwindigkeit.