Search code examples
iosswiftavfoundationios9midi

Playing a single midi note from gs_instruments in iOS / Swift


I'm looking to play a single midi note on an iOS app using Swift.

Here's what I have so far, but unfortunately this crashes with an error.

func initAudio(){

    let engine = AVAudioEngine()
    self.sampler = AVAudioUnitSampler()
    engine.attachNode(self.sampler!)
    engine.connect(self.sampler!, to: engine.outputNode, format: nil)

    guard let soundbank = NSBundle.mainBundle().URLForResource("gs_instruments", withExtension: "dls") else {

        print("Could not initalize soundbank.")
        return
    }

    let melodicBank:UInt8 = UInt8(kAUSampler_DefaultMelodicBankMSB)
    let gmHarpsichord:UInt8 = 6
    do {

        try self.sampler!.loadSoundBankInstrumentAtURL(soundbank, program: gmHarpsichord, bankMSB: melodicBank, bankLSB: 0)

    }catch {
        print("An error occurred \(error)")
        return
    }

    self.sampler!.startNote(60, withVelocity: 64, onChannel: 0)
}

Here's the error message:

Unable to start playing the low note. Error code: -10867 'ç’ˇˇ'
2015-11-25 15:10:07.419 Demo[774:139850] 15:10:07.418 ERROR:    [0x19eaf4000] AVAudioUnitMIDIInstrument.mm:103: -[AVAudioUnitMIDIInstrument startNote:withVelocity:onChannel:]: error -10867
2015-11-25 15:10:07.419 Demo[774:139850] *** Terminating app due to uncaught exception 'com.apple.coreaudio.avfaudio', reason: 'error -10867'

Solution

  • Solution

    The AVAudioEngine needs to be started before usage (error -10867 means "not initialized").

    Add try engine.start() inside the Do-Catch:

    do {
        try engine.start()
        try self.sampler!.loadSoundBankInstrumentAtURL(soundbank, program: gmHarpsichord, bankMSB: melodicBank, bankLSB: 0)
    }catch {
        print("An error occurred \(error)")
        return
    }
    

    About the error code

    In your error message there's this line:

    2015-11-25 15:10:07.419 Demo[774:139850] 15:10:07.418 ERROR: [0x19eaf4000] AVAudioUnitMIDIInstrument.mm:103: -[AVAudioUnitMIDIInstrument startNote:withVelocity:onChannel:]: error -10867

    We see that the emitter of the error code is AVAudioUnitMIDIInstrument, which inherits from AVAudioUnit: these things come from the "AudioUnit" framework which is located in OS X's System folder.

    AudioUnit 's error codes are defined in this header file:

    /System/Library/Frameworks/AudioUnit.framework/Versions/A/Headers/AUComponent.h

    The part that is relevant for us:

    CF_ENUM(OSStatus) {
        kAudioUnitErr_InvalidProperty           = -10879,
        kAudioUnitErr_InvalidParameter          = -10878,
        kAudioUnitErr_InvalidElement            = -10877,
        kAudioUnitErr_NoConnection              = -10876,
        kAudioUnitErr_FailedInitialization      = -10875,
        kAudioUnitErr_TooManyFramesToProcess    = -10874,
        kAudioUnitErr_InvalidFile               = -10871,
        kAudioUnitErr_UnknownFileType           = -10870,
        kAudioUnitErr_FileNotSpecified          = -10869,
        kAudioUnitErr_FormatNotSupported        = -10868,
        kAudioUnitErr_Uninitialized             = -10867,
        kAudioUnitErr_InvalidScope              = -10866,
        kAudioUnitErr_PropertyNotWritable       = -10865,
        kAudioUnitErr_CannotDoInCurrentContext  = -10863,
        kAudioUnitErr_InvalidPropertyValue      = -10851,
        kAudioUnitErr_PropertyNotInUse          = -10850,
        kAudioUnitErr_Initialized               = -10849,
        kAudioUnitErr_InvalidOfflineRender      = -10848,
        kAudioUnitErr_Unauthorized              = -10847,
        kAudioComponentErr_InstanceInvalidated  = -66749,
    };