3

I'm wondering what the best way is to have a AKSequencer (actually an AKMusicTrack) output it's MIDI to an external device.

I have gotten it to work, but I feel like there is probably a more efficient way.

The way I've done it:

I've made subclass of AKPolyphonicNode ("MyPolyphonicNode")

I've used this to init a subclass of AKMIDINode ("MyMIDINode"),

class MyMIDINode:AKMIDINODE {

init(...) {
        ...
        let myPolyphonicNode = MyPolyphonicNode()
        super.init(node: myPolyphonicNode, midiOutputName: "myMIDIOutput")
        ...
        }

//etc

}

and setMIDIoutput of the output of the AKMusicTrack to the midiIn of the AKMIDINode subclass:

track.setMIDIOutput(myMIDINode.midiIn) 

Then in the MyPolyphonicNode subclass, I've overriden:

override func play(noteNumber: MIDINoteNumber, velocity: MIDIVelocity, frequency: Double) {
    myDelegate.myDelegateFunction(noteNumber:MIDINoteNumber, velocity:MIDIVelocity, channel:myChannel)
    }

And in its delegate:

let midi:AKMIDI //set in the init

enableMIDI(midi.client, name: "midiClient") //also in the init

func myDelegateFunction(noteNumber:MIDINoteNumber, velocity:MIDIVelocity, channel:MIDIChannelNumber) {
            midi.sendEvent(AKMIDIEvent(noteOn: noteNumber, velocity: velocity, channel: channel))
        }

This works, but I am thinking there is probably a way of telling the AKMusicTracks directly to output externally without doing all this?

narco
  • 830
  • 8
  • 21

1 Answers1

2

A simpler solution is to use AKMIDICallbackInstrument, although it is the same basic idea. It is easy to set up:

callbackInst = AKMIDICallbackInstrument()
track.setMIDIOutput(callbackInst.midiIn)

You need to provide a callback function which will trigger external MIDI:

callbackInst.callback = { statusByte, note, velocity in 
    //  NB: in the next AudioKit release, there will be an easier init for AKMIDIStatus: 
    //  let status = AKMIDIStatus(statusByte: statusByte)
    let status = AKMIDIStatus(rawValue: Int(statusByte >> 4))
    switch status {
        case .noteOn:
            midi.sendNoteOnMessage(noteNumber: note, velocity: velocity)
        case .noteOff:
            midi.sendNoteOffMessage(noteNumber: note, velocity: velocity)
        default:
            // etc.
    }

This function will be called whenever events on the AKMusicTrack are played

c_booth
  • 2,185
  • 1
  • 13
  • 22
  • Great. Seems to work, and is at least a little simpler :) The only thing is, I did get an error from your code, and the following seems to be what it wanted: let status = AKMIDIStatus(rawValue: statusByte.rawValue) – narco Dec 08 '18 at 11:39
  • Hmm. This only seems to work for Note on's and note offs, and not for midi controllers. I tried to extend AKCallbackInstrument to include a receivedMIDIController function, as per AKMIDIListener protocol, but it doesn't seem to be the correct thing to do... – narco Jan 06 '19 at 08:52