Loopy Pro: Create music, your way.

What is Loopy Pro?Loopy Pro is a powerful, flexible, and intuitive live looper, sampler, clip launcher and DAW for iPhone and iPad. At its core, it allows you to record and layer sounds in real-time to create complex musical arrangements. But it doesn’t stop there—Loopy Pro offers advanced tools to customize your workflow, build dynamic performance setups, and create a seamless connection between instruments, effects, and external gear.

Use it for live looping, sequencing, arranging, mixing, and much more. Whether you're a live performer, a producer, or just experimenting with sound, Loopy Pro helps you take control of your creative process.

Download on the App Store

Loopy Pro is your all-in-one musical toolkit. Try it for free today.

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.