Audiobus: Use your music apps together.

What is Audiobus?Audiobus is an award-winning music app for iPhone and iPad which lets you use your other music apps together. Chain effects on your favourite synth, run the output of apps or Audio Units into an app like GarageBand or Loopy, or select a different audio interface output for each app. Route MIDI between apps — drive a synth from a MIDI sequencer, or add an arpeggiator to your MIDI keyboard — or sync with your external MIDI gear. And control your entire setup from a MIDI controller.

Download on the App Store

Audiobus is the app that makes the rest of your setup better.

Help with AUv3 hosting code - audioUnit.requestViewController fails to compile!

Hi All,

Still beavering away with my app and decided to reinvestigate allowing AUv3 to be used as instruments. I've looked at the Apple docs and various code examples and come up with the following which I hoped would work. However, the line:

audioUnit.requestViewController { vc in
            // Assign view controller in completion handler
            viewController = vc
          }

throws a compiler error saying:

Value of type 'AudioUnit' (aka 'OpaquePointer') has no member 'requestViewController'

while everything I've read suggests it really does.

Sorry to hassle but if anyone could shed light on what I'm getting wrong here, I'd be grateful.

Thanks in advance,

Jes

import Foundation
import CoreAudioKit
import AVFoundation
import SwiftUI
import UIKit

// Access the singleton AVAudioUnitComponentManager instance.
let auManager = AVAudioUnitComponentManager.shared()


// Retrieve audio unit components by description.
let description = AudioComponentDescription(componentType: kAudioUnitType_MusicDevice,
                                            componentSubType: 0,
                                            componentManufacturer: 0,
                                            componentFlags: 0,
                                            componentFlagsMask: 0)
let componentsByDesc = auManager.components(matching: description)

// Retrieve audio unit components by predicate.
let predicate = NSPredicate(format: "typeName CONTAINS 'Effect'")
let componentsByPredicate = auManager.components(matching: predicate)

// Retrieve audio unit components by test.
let componentsByTest = auManager.components { component, _ in
    return component.typeName == AVAudioUnitTypeMusicDevice
}

// A SwiftUI view that represents an audio unit's view controller
struct AudioUnitView: UIViewControllerRepresentable {
    // The AVAudioUnit instance
    let audioUnit: AVAudioUnit

    // The view controller property
    @State private var viewController: UIViewController?

    func makeUIViewController(context: Context) -> UIViewController {

        let audioUnit = self.audioUnit.audioUnit

        // Create placeholder controller
        var viewController = UIViewController()

        // This is the line causing the issue.  Commenting it out lets the program work but obviously without displaying the AU

      audioUnit.requestViewController { vc in
        // Assign view controller in completion handler
        viewController = vc
      }

      return viewController
    }

    // Updates the state of the specified view controller with new information from SwiftUI
    func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
        // No need to update anything for now
    }
}

struct AUv3View: View {

    // The array of AVAudioUnitComponent objects
    let components: [AVAudioUnitComponent]

    // The state variable to store the selected component
    @State private var selectedComponent: AVAudioUnitComponent?

    // The state variable to store the instantiated audio unit
    @State private var audioUnit: AVAudioUnit?

    var body: some View {
        VStack {
            // A list that displays the names of the components
            List(components, id: \.self, selection: $selectedComponent) { component in
                Text(component.name)
            }
            // A button that instantiates the selected component
            Button("Instantiate") {
                instantiateAudioUnit()
            }
            // A text view that shows the details of the instantiated audio unit
            Text(audioUnit?.name ?? "No audio unit instantiated")
            // A view that shows the user interface of the instantiated audio unit
            AudioUnitView(audioUnit: audioUnit ?? AVAudioUnit())
                .frame(width: 300, height: 300)
                .border(Color.black)
        }
    }

    // A function that instantiates the selected component using AVAudioUnit class method
    func instantiateAudioUnit() {
        guard let component = selectedComponent else { return }
        let description = component.audioComponentDescription
        AVAudioUnit.instantiate(with: description, options: []) { avAudioUnit, error in
            guard error == nil else {
                print(error!.localizedDescription)
                return
            }
            // Audio unit successfully instantiated.
            // Connect it to AVAudioEngine to use.
            DispatchQueue.main.async {
                self.audioUnit = avAudioUnit
            }
        }
    }
}

Comments

  • The audio unit type you currently have is just a typealias for an opaque pointer, which means it won’t have any properties or methods you’re expecting and is designed for interfacing with C-based APIs. I haven’t run the code yet, but it looks like you might want to access the auAudioUnit property of your AVAudioUnit instead.

  • @TonalityApp said:
    The audio unit type you currently have is just a typealias for an opaque pointer, which means it won’t have any properties or methods you’re expecting and is designed for interfacing with C-based APIs. I haven’t run the code yet, but it looks like you might want to access the auAudioUnit property of your AVAudioUnit instead.

    Awesome spot - Thanks so much! x

  • Hmm, still can't get any AU's to display though.

    Here's the complete code so far, if anyone can shed a light...

    import Foundation
    import CoreAudioKit
    import AVFoundation
    import SwiftUI
    import UIKit
    
    // Access the singleton AVAudioUnitComponentManager instance.
    let auManager = AVAudioUnitComponentManager.shared()
    
    
    // Retrieve audio unit components by description.
    let description = AudioComponentDescription(componentType: kAudioUnitType_MusicDevice,
                                                componentSubType: 0,
                                                componentManufacturer: 0,
                                                componentFlags: 0,
                                                componentFlagsMask: 0)
    let componentsByDesc = auManager.components(matching: description)
    
    // Retrieve audio unit components by predicate.
    let predicate = NSPredicate(format: "typeName CONTAINS 'Effect'")
    let componentsByPredicate = auManager.components(matching: predicate)
    
    // Retrieve audio unit components by test.
    let componentsByTest = auManager.components { component, _ in
        return component.typeName == AVAudioUnitTypeMusicDevice
    }
    
    let engine = AVAudioEngine()
    
    // A SwiftUI view that represents an audio unit's view controller
    struct AudioUnitView: UIViewControllerRepresentable {
        // The AVAudioUnit instance
        let audioUnit: AVAudioUnit
    
        // The view controller property
        @State private var viewController: UIViewController?
    
        func makeUIViewController(context: Context) -> UIViewController {
    
            let audioUnit = self.audioUnit.auAudioUnit
    
            // Create placeholder controller
            var viewController = UIViewController()
    
            // This is the line causing the issue.  Commenting it out lets the program work but obviously without displaying the AU
    
          audioUnit.requestViewController { vc in
            // Assign view controller in completion handler
              viewController = vc!
          }
    
          return viewController
        }
    
        // Updates the state of the specified view controller with new information from SwiftUI
        func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
            // No need to update anything for now
        }
    }
    
    struct AUv3View: View {
    
        // The array of AVAudioUnitComponent objects
        let components: [AVAudioUnitComponent]
    
        // The state variable to store the selected component
        @State private var selectedComponent: AVAudioUnitComponent?
    
        // The state variable to store the instantiated audio unit
        @State private var audioUnit: AVAudioUnit?
    
        var body: some View {
            VStack {
                // A list that displays the names of the components
                List(components, id: \.self, selection: $selectedComponent) { component in
                    Text(component.name)
                }
                // A button that instantiates the selected component
                Button("Instantiate") {
                    instantiateAudioUnit()
                }
                // A text view that shows the details of the instantiated audio unit
                Text(audioUnit?.name ?? "No audio unit instantiated")
                // A view that shows the user interface of the instantiated audio unit
                AudioUnitView(audioUnit: audioUnit ?? AVAudioUnit())
                    .frame(width: .infinity, height: .infinity)
                    .border(Color.black)
            }
        }
    
        // A function that instantiates the selected component using AVAudioUnit class method
        func instantiateAudioUnit() {
            guard let component = selectedComponent else { return }
            let description = component.audioComponentDescription
    
    
    
            AVAudioUnit.instantiate(with: description, options: []) { avAudioUnit, error in
                guard error == nil else {
                    print(error!.localizedDescription)
                    return
                }
                // Audio unit successfully instantiated.
                // Connect it to AVAudioEngine to use.
    
                engine.attach(avAudioUnit!)
                engine.connect(avAudioUnit!, to: engine.mainMixerNode, format: nil)
    
                DispatchQueue.main.async {
                    self.audioUnit = avAudioUnit
                }
            }
        }
    }
    
Sign In or Register to comment.