I have a couple of MIDI apps which use available devices on the Mac to record and play MIDI.
I have a number of virtual software instruments, AU and VST plugins which load into DAWs like Logic Pro or Digital Performer. Is there a way to access these plugins from Xojo? I have MBS plugins but haven’t found routines to do this.
Christian,
Thanks to your help in pointing out the direction to take, I’ve been able to load virtual instruments. These are AVComponents that are type “Music Device”, plug-ins that are software synths which can be triggered by MIDI events as well as code. Apple’s terminology is a little confusing because the component used to load them is AVAudioUnitSampler. The component contains the file path and the instrument is loaded by the Constructor.
Anyway, using the Audio Components Xojo example, I was able to load the instruments. This code loads and lists each instrument and plays a middle C (if there’s a default sound).
I’m posting this to save others the work of figuring this out. You’ll need a ListBox (“List”) in a window to get this working.
Thanks
Var m As New AVAudioUnitComponentManagerMBS
Var a() As AVAudioUnitComponentMBS = m.allComponents
Var Engine As AVAudioEngineMBS
For Each c As AVAudioUnitComponentMBS In a
Var d As AVAudioComponentDescriptionMBS = c.audioComponentDescription
If c.LocalizedTypeName = "Music Device" Then
List.AddRow c.Name, c.ManufacturerName, c.LocalizedTypeName, c.VersionString, d.componentType+" "+d.componentSubType
app.DoEvents ' just to update the listbox
Var MD As AVAudioUnitSamplerMBS
Try
MD = New AVAudioUnitSamplerMBS(d) ' this loads the virtual instrument
End
Engine = New AVAudioEngineMBS
Engine.attachNode MD
Engine.connect(MD, Engine.mainMixerNode, Nil)
Var error As NSErrorMBS
If Not Engine.startAndReturnError(error) Then
MessageBox("Error starting audio engine")
End
MD.sendMIDIEvent(&h90, 64, 100) ' play middle C
SleepMBS(.5)
MD.sendMIDIEvent(&h90, 64, 0)
SleepMBS(.5)
End
Next
Thanks very much for sharing this. Have you taken it any further?
I converted your code into a small project, where the AUmanager, AUengine and the AUs themselves (in an array) are persistent properties instead of existing only in a loop in this method. With a few other changes (no DoEvents for example).
It’s very interesting, something I’ve wanted to have for a long time, but beyond listing the audio units, it doesn’t work. I changed the sendMIDIEvent to respond to clicking on a listbox row, but there is no audio output (doesn’t surprise me).
I think first we need the views for the instruments. This appears to be an NSView property: AudioUnit(n).CreateView Did you by chance get that to work? There is a need for a working demo project. Maybe I’ve missed something?
Hi, Aaron. I just saw your post. Here is the code I’m using to load a virtual software instrument. AVcomponents is an array of AVAudioUnitComponentsMBS which I’ve filtered to include only type “Music Device”. “index” is an index into that array. There are a few other global properties it references which you should be able to figure out (VSTWindow, Engine). After calling this routine, a window opens with the virtual instrument where you can play it from its keyboard or control it using MBS documented methods.
Sub SetupVirtual(index As integer)
If AVcomponents(index).Name = myThruOutName And Engine <> Nil then Return
myVirtualSynth = New myVirtualClass(AVcomponents(index).audioComponentDescription)
Engine = Nil
Engine = New AVAudioEngineMBS
Engine.attachNode myVirtualSynth
Engine.connect(myVirtualSynth, Engine.mainMixerNode, Nil)
Var error As NSErrorMBS
If Not Engine.startAndReturnError(error) Then
MessageBox(“Error starting audio engine”)
End
Var w As New NSWindowMBS(VSTWindow)
Var preferredSize As New NSSizeMBS(2000,1000)
’ view is property of window
Var view As NSViewMBS = myVirtualSynth.CreateView(preferredSize)
’ set position
view.setFrameOrigin(New NSPointMBS(0, 0))
VSTWindow.Height = view.frameHeight
VSTWindow.Width = view.frameWidth
’ add to window
w.contentView.addSubview view
virtualFlag = True
End