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->ptr1 = userptr;
199 if (mac_vst->plugin->magic != kEffectMagic)
201 mac_vst_error ("** ERROR ** VSTFX : %s is not a VST plugin\n", fhandle->name);
207 /* scanning.. or w/o master-callback userptr == 0, open now.
209 * Session::vst_callback needs a pointer to the AEffect
210 * ((VSTPlugin*)userptr)->_plugin = vstfx->plugin
211 * before calling effOpen, because effOpen may call back
213 mac_vst->plugin->dispatcher (mac_vst->plugin, effOpen, 0, 0, 0, 0);
214 mac_vst->vst_version = mac_vst->plugin->dispatcher (mac_vst->plugin, effGetVstVersion, 0, 0, 0, 0);
216 /* configure plugin to use Cocoa View */
217 mac_vst->plugin->dispatcher (mac_vst->plugin, effCanDo, 0, 0, const_cast<char*> ("hasCockosViewAsConfig"), 0.0f);
220 mac_vst->handle->plugincnt++;
221 mac_vst->wantIdle = 0;
226 /*Close a mac_vst instance*/
228 void mac_vst_close (VSTState* mac_vst)
230 // assert that the GUI object is destoyed
234 mac_vst->plugin->dispatcher (mac_vst->plugin, effMainsChanged, 0, 0, 0, 0);
236 /*Calling dispatcher with effClose will cause the plugin's destructor to
237 be called, which will also remove the editor if it exists*/
239 mac_vst->plugin->dispatcher (mac_vst->plugin, effClose, 0, 0, 0, 0);
242 if (mac_vst->handle->plugincnt)
243 mac_vst->handle->plugincnt--;
245 /*mac_vst_unload will unload the dll if the instance count allows -
246 we need to do this because some plugins keep their own instance count
247 and (JUCE) manages the plugin UI in its own thread. When the plugins
248 internal instance count reaches zero, JUCE stops the UI thread and won't
249 restart it until the next time the library is loaded. If we don't unload
250 the lib JUCE will never restart*/
253 if (mac_vst->handle->plugincnt)
258 /*Valid plugin loaded - so we can unload it and 0 the pointer
259 to it. We can't free the handle here because we don't know what else
260 might need it. It should be / is freed when the plugin is deleted*/
262 if (mac_vst->handle->dll)
264 dlclose (mac_vst->handle->dll); //dlclose keeps its own reference count
265 mac_vst->handle->dll = 0;
270 #if 0 // TODO wrap dispatch
272 mac_vst_dispatch (VSTState* mac_vst, int op, int idx, intptr_t val, void* ptr, float opt)
274 const ResFileRefNum old_resources = CurResFile();
276 if (mac_vst->handle->res_file_id) {
277 UseResFile (mac_vst->handle->res_file_id);
280 mac_vst->plugin->dispatcher (mac_vst->plugin, op, idx, val, prt, opt);
282 const ResFileRefNum current_res = CurResFile();
283 if (current_res != old_resources) {
284 mac_vst->handle->res_file_id = current_res;
285 UseResFile (old_resources);