2 * Copyright (C) 2016 Robin Gareus <robin@gareus.org>
3 * Copyright (C) 2012 Paul Davis
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
33 #include "pbd/gstdio_compat.h"
34 #include <glibmm/miscutils.h>
35 #include <glibmm/fileutils.h>
37 #include "ardour/mac_vst_support.h"
38 #include "pbd/basename.h"
39 #include "pbd/error.h"
43 #include <Carbon/Carbon.h>
45 /*Simple error handler stuff for VSTFX*/
47 void mac_vst_error (const char *fmt, ...)
53 vsnprintf (buffer, sizeof (buffer), fmt, ap);
54 mac_vst_error_callback (buffer);
58 /*default error handler callback*/
60 static void default_mac_vst_error_callback (const char *desc)
62 PBD::error << desc << endmsg;
65 void (*mac_vst_error_callback)(const char *desc) = &default_mac_vst_error_callback;
69 /*Create and return a pointer to a new VSTFX handle*/
74 VSTHandle* mac_vst = (VSTHandle *) calloc (1, sizeof (VSTHandle));
78 /*Create and return a pointer to a new mac_vst instance*/
83 VSTState* mac_vst = (VSTState *) calloc (1, sizeof (VSTState));
84 vststate_init (mac_vst);
88 /*This loads up a plugin, given the path to its .vst bundle and
89 * finds its main entry point etc */
92 mac_vst_load (const char *path)
96 /*Create a new handle we can use to reference the plugin*/
98 fhandle = mac_vst_handle_new ();
103 if (!(url = CFURLCreateFromFileSystemRepresentation (0, (const UInt8*)path, (CFIndex) strlen (path), true))) {
107 CFBundleRef bundleRef = CFBundleCreate (kCFAllocatorDefault, url);
110 if (bundleRef == 0) {
114 if (!CFBundleLoadExecutable (bundleRef)) {
115 CFRelease (bundleRef);
119 fhandle->name = strdup (path);
120 fhandle->dll = (void*) &bundleRef;
122 fhandle->main_entry = (main_entry_t)
123 CFBundleGetFunctionPointerForName (bundleRef, CFSTR("main_macho"));
125 if (!fhandle->main_entry) {
126 fhandle->main_entry = (main_entry_t)
127 CFBundleGetFunctionPointerForName (bundleRef, CFSTR("VSTPluginMain"));
130 if (fhandle->main_entry == 0) {
131 mac_vst_unload (fhandle);
135 fhandle->res_file_id = CFBundleOpenBundleResourceMap (bundleRef);
137 /*return the handle of the plugin*/
141 /*This unloads a plugin*/
144 mac_vst_unload (VSTHandle* fhandle)
146 if (fhandle->plugincnt)
148 /*Still have plugin instances - can't unload the library
149 - actually dlclose keeps an instance count anyway*/
154 /*Valid plugin loaded?*/
158 CFBundleRef* bundleRefPtr = (CFBundleRef*) fhandle->dll;
159 CFBundleCloseBundleResourceMap (*bundleRefPtr, (CFBundleRefNum)fhandle->res_file_id);
160 CFRelease (*bundleRefPtr);
166 free (fhandle->name);
169 /*Don't need the plugin handle any more*/
175 /*This instantiates a plugin*/
178 mac_vst_instantiate (VSTHandle* fhandle, audioMasterCallback amc, void* userptr)
180 VSTState* mac_vst = mac_vst_new ();
184 mac_vst_error ( "** ERROR ** VSTFX : The handle was 0\n" );
189 if ((mac_vst->plugin = fhandle->main_entry (amc)) == 0)
191 mac_vst_error ("** ERROR ** VSTFX : %s could not be instantiated :(\n", fhandle->name);
196 mac_vst->handle = fhandle;
197 mac_vst->plugin->user = userptr;
199 if (mac_vst->plugin->magic != kEffectMagic)
201 mac_vst_error ("** ERROR ** VSTFX : %s is not a VST plugin\n", fhandle->name);
206 mac_vst->plugin->dispatcher (mac_vst->plugin, effOpen, 0, 0, 0, 0);
208 /*May or May not need to 'switch the plugin on' here - unlikely
209 since FST doesn't and most plugins start up 'On' by default - I think this is the least of our worries*/
211 //mac_vst->plugin->dispatcher (mac_vst->plugin, effMainsChanged, 0, 1, 0, 0);
213 /* configure plugin to use Cocoa View */
214 mac_vst->plugin->dispatcher (mac_vst->plugin, effCanDo, 0, 0, const_cast<char*> ("hasCockosViewAsConfig"), 0.0f);
216 mac_vst->vst_version = mac_vst->plugin->dispatcher (mac_vst->plugin, effGetVstVersion, 0, 0, 0, 0);
218 mac_vst->handle->plugincnt++;
219 mac_vst->wantIdle = 0;
224 /*Close a mac_vst instance*/
226 void mac_vst_close (VSTState* mac_vst)
228 // assert that the GUI object is destoyed
232 mac_vst->plugin->dispatcher (mac_vst->plugin, effMainsChanged, 0, 0, 0, 0);
234 /*Calling dispatcher with effClose will cause the plugin's destructor to
235 be called, which will also remove the editor if it exists*/
237 mac_vst->plugin->dispatcher (mac_vst->plugin, effClose, 0, 0, 0, 0);
240 if (mac_vst->handle->plugincnt)
241 mac_vst->handle->plugincnt--;
243 /*mac_vst_unload will unload the dll if the instance count allows -
244 we need to do this because some plugins keep their own instance count
245 and (JUCE) manages the plugin UI in its own thread. When the plugins
246 internal instance count reaches zero, JUCE stops the UI thread and won't
247 restart it until the next time the library is loaded. If we don't unload
248 the lib JUCE will never restart*/
251 if (mac_vst->handle->plugincnt)
256 /*Valid plugin loaded - so we can unload it and 0 the pointer
257 to it. We can't free the handle here because we don't know what else
258 might need it. It should be / is freed when the plugin is deleted*/
260 if (mac_vst->handle->dll)
262 dlclose (mac_vst->handle->dll); //dlclose keeps its own reference count
263 mac_vst->handle->dll = 0;
268 #if 0 // TODO wrap dispatch
270 mac_vst_dispatch (VSTState* mac_vst, int op, int idx, intptr_t val, void* ptr, float opt)
272 const ResFileRefNum old_resources = CurResFile();
274 if (mac_vst->handle->res_file_id) {
275 UseResFile (mac_vst->handle->res_file_id);
278 mac_vst->plugin->dispatcher (mac_vst->plugin, op, idx, val, prt, opt);
280 const ResFileRefNum current_res = CurResFile();
281 if (current_res != old_resources) {
282 mac_vst->handle->res_file_id = current_res;
283 UseResFile (old_resources);