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.
32 #include "pbd/gstdio_compat.h"
33 #include <glibmm/miscutils.h>
34 #include <glibmm/fileutils.h>
36 #include "ardour/mac_vst_support.h"
37 #include "pbd/basename.h"
38 #include "pbd/error.h"
42 #include <Carbon/Carbon.h>
44 /*Simple error handler stuff for VSTFX*/
46 void mac_vst_error (const char *fmt, ...)
52 vsnprintf (buffer, sizeof (buffer), fmt, ap);
53 mac_vst_error_callback (buffer);
57 /*default error handler callback*/
59 static void default_mac_vst_error_callback (const char *desc)
61 PBD::error << desc << endmsg;
64 void (*mac_vst_error_callback)(const char *desc) = &default_mac_vst_error_callback;
68 /*Create and return a pointer to a new VSTFX handle*/
73 VSTHandle* mac_vst = (VSTHandle *) calloc (1, sizeof (VSTHandle));
77 /*Create and return a pointer to a new mac_vst instance*/
82 VSTState* mac_vst = (VSTState *) calloc (1, sizeof (VSTState));
87 /*This loads up a plugin, given the path to its .vst bundle and
88 * finds its main entry point etc */
91 mac_vst_load (const char *path)
95 /*Create a new handle we can use to reference the plugin*/
97 fhandle = mac_vst_handle_new ();
102 if (!(url = CFURLCreateFromFileSystemRepresentation (0, (const UInt8*)path, (CFIndex) strlen (path), true))) {
106 CFBundleRef bundleRef = CFBundleCreate (kCFAllocatorDefault, url);
109 if (bundleRef == 0) {
113 if (!CFBundleLoadExecutable (bundleRef)) {
114 CFRelease (bundleRef);
118 fhandle->name = strdup (path);
119 fhandle->dll = (void*) &bundleRef;
121 fhandle->main_entry = (main_entry_t)
122 CFBundleGetFunctionPointerForName (bundleRef, CFSTR("main_macho"));
124 if (!fhandle->main_entry) {
125 fhandle->main_entry = (main_entry_t)
126 CFBundleGetFunctionPointerForName (bundleRef, CFSTR("VSTPluginMain"));
129 if (fhandle->main_entry == 0) {
130 mac_vst_unload (fhandle);
134 fhandle->res_file_id = CFBundleOpenBundleResourceMap (bundleRef);
136 /*return the handle of the plugin*/
140 /*This unloads a plugin*/
143 mac_vst_unload (VSTHandle* fhandle)
145 if (fhandle->plugincnt)
147 /*Still have plugin instances - can't unload the library
148 - actually dlclose keeps an instance count anyway*/
153 /*Valid plugin loaded?*/
157 CFBundleRef* bundleRefPtr = (CFBundleRef*) fhandle->dll;
158 CFBundleCloseBundleResourceMap (*bundleRefPtr, (CFBundleRefNum)fhandle->res_file_id);
159 CFRelease (*bundleRefPtr);
165 free (fhandle->name);
168 /*Don't need the plugin handle any more*/
174 /*This instantiates a plugin*/
177 mac_vst_instantiate (VSTHandle* fhandle, audioMasterCallback amc, void* userptr)
179 VSTState* mac_vst = mac_vst_new ();
183 mac_vst_error ( "** ERROR ** VSTFX : The handle was 0\n" );
188 if ((mac_vst->plugin = fhandle->main_entry (amc)) == 0)
190 mac_vst_error ("** ERROR ** VSTFX : %s could not be instantiated :(\n", fhandle->name);
195 mac_vst->handle = fhandle;
196 mac_vst->plugin->user = userptr;
198 if (mac_vst->plugin->magic != kEffectMagic)
200 mac_vst_error ("** ERROR ** VSTFX : %s is not a VST plugin\n", fhandle->name);
205 mac_vst->plugin->dispatcher (mac_vst->plugin, effOpen, 0, 0, 0, 0);
207 /*May or May not need to 'switch the plugin on' here - unlikely
208 since FST doesn't and most plugins start up 'On' by default - I think this is the least of our worries*/
210 //mac_vst->plugin->dispatcher (mac_vst->plugin, effMainsChanged, 0, 1, 0, 0);
212 /* configure plugin to use Cocoa View */
213 mac_vst->plugin->dispatcher (mac_vst->plugin, effCanDo, 0, 0, const_cast<char*> ("hasCockosViewAsConfig"), 0.0f);
215 mac_vst->vst_version = mac_vst->plugin->dispatcher (mac_vst->plugin, effGetVstVersion, 0, 0, 0, 0);
217 mac_vst->handle->plugincnt++;
218 mac_vst->wantIdle = 0;
223 /*Close a mac_vst instance*/
225 void mac_vst_close (VSTState* mac_vst)
227 // assert that the GUI object is destoyed
231 mac_vst->plugin->dispatcher (mac_vst->plugin, effMainsChanged, 0, 0, 0, 0);
233 /*Calling dispatcher with effClose will cause the plugin's destructor to
234 be called, which will also remove the editor if it exists*/
236 mac_vst->plugin->dispatcher (mac_vst->plugin, effClose, 0, 0, 0, 0);
239 if (mac_vst->handle->plugincnt)
240 mac_vst->handle->plugincnt--;
242 /*mac_vst_unload will unload the dll if the instance count allows -
243 we need to do this because some plugins keep their own instance count
244 and (JUCE) manages the plugin UI in its own thread. When the plugins
245 internal instance count reaches zero, JUCE stops the UI thread and won't
246 restart it until the next time the library is loaded. If we don't unload
247 the lib JUCE will never restart*/
250 if (mac_vst->handle->plugincnt)
255 /*Valid plugin loaded - so we can unload it and 0 the pointer
256 to it. We can't free the handle here because we don't know what else
257 might need it. It should be / is freed when the plugin is deleted*/
259 if (mac_vst->handle->dll)
261 dlclose (mac_vst->handle->dll); //dlclose keeps its own reference count
262 mac_vst->handle->dll = 0;
267 #if 0 // TODO wrap dispatch
269 mac_vst_dispatch (VSTState* mac_vst, int op, int idx, intptr_t val, void* ptr, float opt)
271 const ResFileRefNum old_resources = CurResFile();
273 if (mac_vst->handle->res_file_id) {
274 UseResFile (mac_vst->handle->res_file_id);
277 mac_vst->plugin->dispatcher (mac_vst->plugin, op, idx, val, prt, opt);
279 const ResFileRefNum current_res = CurResFile();
280 if (current_res != old_resources) {
281 mac_vst->handle->res_file_id = current_res;
282 UseResFile (old_resources);