0

I have a Mac OS desktop app which hosts virtual instrument plugins as AVAudioUnitMIDIInstrument. My app is basically a music sequencer. I would like to trigger instruments that use drum loops and/or arpeggiators. This requires sending some sort of timing information to the AVAudioUnitMIDIInstrument. How do I do this? My guess is that I need to send either a MidiMetaEvent, or perhaps regular MidiTimestamp info. How do I do this? I don't see any methods on AVAudioUnitMidiInstrument that do this. Here are the methods I see:

func sendController(UInt8, withValue: UInt8, onChannel: UInt8)
Send a MIDI controller event to the instrument.

func sendMIDIEvent(UInt8, data1: UInt8)
Sends a MIDI event which contains one data byte to the instrument.

func sendMIDIEvent(UInt8, data1: UInt8, data2: UInt8)
Sends a MIDI event which contains two data bytes to the instrument.

func sendMIDISysExEvent(Data)
Sends a MIDI System Exclusive event to the instrument.

func sendPitchBend(UInt16, onChannel: UInt8)
Sends a MIDI Pitch Bend event to the instrument.

func sendPressure(UInt8, onChannel: UInt8)
Sends a MIDI channel pressure event to the instrument.

func sendPressure(forKey: UInt8, withValue: UInt8, onChannel: UInt8)
Sends a MIDI Polyphonic key pressure event to the instrument.

func sendProgramChange(UInt8, bankMSB: UInt8, bankLSB: UInt8, onChannel: UInt8)
Sends MIDI Program Change and Bank Select events to the instrument.

func sendProgramChange(UInt8, onChannel: UInt8)
Sends MIDI Program Change and Bank Select events to the instrument.

func startNote(UInt8, withVelocity: UInt8, onChannel: UInt8)
Sends a MIDI Note On event to the instrument.

func stopNote(UInt8, onChannel: UInt8)
Sends a MIDI Note Off event to the instrument
matt
  • 515,959
  • 87
  • 875
  • 1,141
dmann200
  • 529
  • 4
  • 11
  • What do you mean by "some sort of timing information"? In MIDI terms, what is it you want to send? – matt Aug 03 '20 at 21:20
  • Drum Loops and Arpeggiators are tempo locked to the host sequencer. I need to transmit whatever information is needed to synchronize these plugins with the host sequencer. As I don't know what the appropriate mechanism is (hence my question) I cannot tell you what format that timing information should be. – dmann200 Aug 04 '20 at 22:06
  • So this sounds like a MIDI question rather than a programming question? – matt Aug 04 '20 at 22:46
  • No it is not a MIDI question. This is a question specifically about the Apple AVFoundation API and how to encode and send specific types of midi events (namely meta events and/or MidiTimeCode) that do not appear to be available in the methods I listed above. Yes it relates to MIDI but I know how to do this in MIDI. I do not know how to use it using Apple's API. – dmann200 Aug 05 '20 at 23:26
  • Sorry, I misunderstood your "I don't know what the appropriate mechanism is". You know how to do in MIDI, so tell me how? – matt Aug 05 '20 at 23:44

1 Answers1

0

The way that audio plugins get timing information is by setting a callback function that calls your host and retrieves information such as time signature, tempo and position.

import Foundation import AVFoundation import AudioToolbox import CoreAudioKit

class AudioNodeFactory{
    class func instrument(description: AudioComponentDescription, context: AUHostMusicalContextBlock?) -> AVAudioUnitMIDIInstrument{
        let plugin = AVAudioUnitMIDIInstrument(audioComponentDescription: description)
        plugin.auAudioUnit.musicalContextBlock = context
        return plugin
    }
}

A musical context block looks something like this:


func getMusicalContext(currentTempo : UnsafeMutablePointer<Double>?,
                        timeSignatureNumerator : UnsafeMutablePointer<Double>?,
                        timeSignatureDenominator : UnsafeMutablePointer<Int>?,
                        currentBeatPosition: UnsafeMutablePointer<Double>?,
                        sampleOffsetToNextBeat : UnsafeMutablePointer<Int>?,
                        currentMeasureDownbeatPosition: UnsafeMutablePointer<Double>?) -> Bool {
     if self.delegate == nil { return false }
     let context = self.delegate!.musicalContext
     currentTempo?.pointee = context.currentTempo
     timeSignatureNumerator?.pointee = context.timeSignatureNumerator
     timeSignatureDenominator?.pointee = context.timeSignatureDenominator
     currentBeatPosition?.pointee = context.currentBeatPosition
     sampleOffsetToNextBeat?.pointee = context.sampleOffsetToNextBeat
     currentMeasureDownbeatPosition?.pointee = context.currentMeasureDownbeatPosition
     return true
 }
dmann200
  • 529
  • 4
  • 11