Merge pull request #506 from andrewcsmith/patch-2
[supercollider.git] / server / scsynth / SC_Lib_Cintf.cpp
blob72d2e13cc2fc6bc38b39e6dcd6200aaadae7b8df
1 /*
2 SuperCollider real time audio synthesis system
3 Copyright (c) 2002 James McCartney. All rights reserved.
4 http://www.audiosynth.com
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 #include "SC_Lib_Cintf.h"
24 #include "SC_CoreAudio.h"
25 #include "SC_UnitDef.h"
26 #include "SC_BufGen.h"
27 #include "SC_World.h"
28 #include "SC_WorldOptions.h"
29 #include "SC_StringParser.h"
30 #include "SC_InterfaceTable.h"
31 #include "SC_DirUtils.h"
32 #include <stdexcept>
33 #ifndef _MSC_VER
34 #include <dirent.h>
35 #endif //_MSC_VER
37 #ifndef _WIN32
38 #include <dlfcn.h>
39 #endif
41 #ifdef _WIN32
42 #include "SC_Win32Utils.h"
43 #else
44 #include <libgen.h>
45 #endif
47 // Plugin directory in resource directory
48 #if defined(_WIN32) && defined(_DEBUG)
49 # define SC_PLUGIN_DIR_NAME "plugins_debug"
50 #else
51 # define SC_PLUGIN_DIR_NAME "plugins"
52 #endif
54 // Extension for binary plugins
55 #ifndef SC_PLUGIN_EXT
56 # define SC_PLUGIN_EXT ".scx"
57 #endif
60 #ifndef _WIN32
61 # include <sys/param.h>
62 #endif
64 #ifdef __APPLE__
65 extern "C" {
66 #include <mach-o/dyld.h>
67 #include <mach-o/getsect.h>
69 char gTempVal;
70 #endif
72 Malloc gMalloc;
73 HashTable<SC_LibCmd, Malloc> *gCmdLib;
74 HashTable<struct UnitDef, Malloc> *gUnitDefLib = 0;
75 HashTable<struct BufGen, Malloc> *gBufGenLib = 0;
76 HashTable<struct PlugInCmd, Malloc> *gPlugInCmds = 0;
77 extern struct InterfaceTable gInterfaceTable;
78 SC_LibCmd* gCmdArray[NUMBER_OF_COMMANDS];
80 void initMiscCommands();
81 static bool PlugIn_LoadDir(const char *dirname, bool reportError);
83 #ifdef __APPLE__
84 void read_section(const struct mach_header *mhp, unsigned long slide, const char *segname, const char *sectname)
86 u_int32_t size;
87 char *sect = getsectdatafromheader(mhp, segname, sectname, &size);
88 if(!sect) return;
90 char *start = sect + slide;
91 char *end = start + size;
93 while(start != end) {
94 gTempVal += *(char *)start;
95 start++;
98 #endif
100 extern void IO_Load(InterfaceTable *table);
101 extern void Osc_Load(InterfaceTable *table);
102 extern void Delay_Load(InterfaceTable *table);
103 extern void BinaryOp_Load(InterfaceTable *table);
104 extern void Filter_Load(InterfaceTable *table);
105 extern void Gendyn_Load(InterfaceTable *table);
106 extern void LF_Load(InterfaceTable *table);
107 extern void Noise_Load(InterfaceTable *table);
108 extern void MulAdd_Load(InterfaceTable *table);
109 extern void Grain_Load(InterfaceTable *table);
110 extern void Pan_Load(InterfaceTable *table);
111 extern void Reverb_Load(InterfaceTable *table);
112 extern void Trigger_Load(InterfaceTable *table);
113 extern void UnaryOp_Load(InterfaceTable *table);
114 extern void DiskIO_Load(InterfaceTable *table);
115 extern void Test_Load(InterfaceTable *table);
116 extern void PhysicalModeling_Load(InterfaceTable *table);
117 extern void Demand_Load(InterfaceTable *table);
118 extern void DynNoise_Load(InterfaceTable *table);
119 extern void FFT_UGens_Load(InterfaceTable *table);
120 extern void iPhone_Load(InterfaceTable *table);
122 void initialize_library(const char *uGensPluginPath)
124 gCmdLib = new HashTable<SC_LibCmd, Malloc>(&gMalloc, 64, true);
125 gUnitDefLib = new HashTable<UnitDef, Malloc>(&gMalloc, 512, true);
126 gBufGenLib = new HashTable<BufGen, Malloc>(&gMalloc, 512, true);
127 gPlugInCmds = new HashTable<PlugInCmd, Malloc>(&gMalloc, 64, true);
129 initMiscCommands();
131 #ifdef STATIC_PLUGINS
132 IO_Load(&gInterfaceTable);
133 Osc_Load(&gInterfaceTable);
134 Delay_Load(&gInterfaceTable);
135 BinaryOp_Load(&gInterfaceTable);
136 Filter_Load(&gInterfaceTable);
137 Gendyn_Load(&gInterfaceTable);
138 LF_Load(&gInterfaceTable);
139 Noise_Load(&gInterfaceTable);
140 MulAdd_Load(&gInterfaceTable);
141 Grain_Load(&gInterfaceTable);
142 Pan_Load(&gInterfaceTable);
143 Reverb_Load(&gInterfaceTable);
144 Trigger_Load(&gInterfaceTable);
145 UnaryOp_Load(&gInterfaceTable);
146 DiskIO_Load(&gInterfaceTable);
147 PhysicalModeling_Load(&gInterfaceTable);
148 Test_Load(&gInterfaceTable);
149 Demand_Load(&gInterfaceTable);
150 DynNoise_Load(&gInterfaceTable);
151 #if defined(SC_IPHONE) && !TARGET_IPHONE_SIMULATOR
152 iPhone_Load(&gInterfaceTable);
153 #endif
154 FFT_UGens_Load(&gInterfaceTable);
155 return;
156 #endif
158 // If uGensPluginPath is supplied, it is exclusive.
159 bool loadUGensExtDirs = true;
160 if(uGensPluginPath){
161 loadUGensExtDirs = false;
162 SC_StringParser sp(uGensPluginPath, SC_STRPARSE_PATHDELIMITER);
163 while (!sp.AtEnd()) {
164 PlugIn_LoadDir(const_cast<char *>(sp.NextToken()), true);
168 if(loadUGensExtDirs) {
169 #ifdef SC_PLUGIN_DIR
170 // load globally installed plugins
171 if (sc_DirectoryExists(SC_PLUGIN_DIR)) {
172 PlugIn_LoadDir(SC_PLUGIN_DIR, true);
174 #endif
175 // load default plugin directory
176 char pluginDir[MAXPATHLEN];
177 sc_GetResourceDirectory(pluginDir, MAXPATHLEN);
178 sc_AppendToPath(pluginDir, MAXPATHLEN, SC_PLUGIN_DIR_NAME);
180 if (sc_DirectoryExists(pluginDir)) {
181 PlugIn_LoadDir(pluginDir, true);
185 // get extension directories
186 char extensionDir[MAXPATHLEN];
187 if (!sc_IsStandAlone() && loadUGensExtDirs) {
188 // load system extension plugins
189 sc_GetSystemExtensionDirectory(extensionDir, MAXPATHLEN);
190 PlugIn_LoadDir(extensionDir, false);
192 // load user extension plugins
193 sc_GetUserExtensionDirectory(extensionDir, MAXPATHLEN);
194 PlugIn_LoadDir(extensionDir, false);
196 // load user plugin directories
197 SC_StringParser sp(getenv("SC_PLUGIN_PATH"), SC_STRPARSE_PATHDELIMITER);
198 while (!sp.AtEnd()) {
199 PlugIn_LoadDir(const_cast<char *>(sp.NextToken()), true);
202 #ifdef __APPLE__
203 /* on darwin plugins are lazily loaded (dlopen uses mmap internally), which can produce audible
204 glitches when UGens have to be paged-in. to work around this we preload all the plugins by
205 iterating through their memory space. */
207 #ifndef __x86_64__
208 /* seems to cause a stack corruption on llvm-gcc-4.2, sdk 10.5 on 10.6 */
210 unsigned long images = _dyld_image_count();
211 for(unsigned long i = 0; i < images; i++) {
212 const mach_header *hdr = _dyld_get_image_header(i);
213 unsigned long slide = _dyld_get_image_vmaddr_slide(i);
214 const char *name = _dyld_get_image_name(i);
215 uint32_t size;
216 char *sect;
218 if(!strcmp(name + (strlen(name) - 4), ".scx")) {
219 read_section(hdr, slide, "__TEXT", "__text");
220 read_section(hdr, slide, "__TEXT", "__const");
221 read_section(hdr, slide, "__TEXT", "__cstring");
222 read_section(hdr, slide, "__TEXT", "__picsymbol_stub");
223 read_section(hdr, slide, "__TEXT", "__symbol_stub");
224 read_section(hdr, slide, "__TEXT", "__const");
225 read_section(hdr, slide, "__TEXT", "__literal4");
226 read_section(hdr, slide, "__TEXT", "__literal8");
228 read_section(hdr, slide, "__DATA", "__data");
229 read_section(hdr, slide, "__DATA", "__la_symbol_ptr");
230 read_section(hdr, slide, "__DATA", "__nl_symbol_ptr");
231 read_section(hdr, slide, "__DATA", "__dyld");
232 read_section(hdr, slide, "__DATA", "__const");
233 read_section(hdr, slide, "__DATA", "__mod_init_func");
234 read_section(hdr, slide, "__DATA", "__bss");
235 read_section(hdr, slide, "__DATA", "__common");
237 read_section(hdr, slide, "__IMPORT", "__jump_table");
238 read_section(hdr, slide, "__IMPORT", "__pointers");
241 #endif
243 #endif
246 typedef int (*InfoFunction)();
248 bool checkAPIVersion(void * f, const char * filename)
250 if (f) {
251 InfoFunction fn = (InfoFunction)f;
252 if ((*fn)() == sc_api_version)
253 return true;
255 scprintf("*** ERROR: API Version Mismatch: %s\n", filename);
256 return false;
259 static bool PlugIn_Load(const char *filename)
261 #ifdef _WIN32
263 HINSTANCE hinstance = LoadLibrary( filename );
264 if (!hinstance) {
265 char *s;
266 DWORD lastErr = GetLastError();
267 FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
268 0, lastErr , 0, (char*)&s, 1, 0 );
269 scprintf("*** ERROR: LoadLibrary '%s' err '%s'\n", filename, s);
270 LocalFree( s );
271 return false;
274 void *apiVersionPtr = (void *)GetProcAddress( hinstance, "api_version" );
275 if (!checkAPIVersion(apiVersionPtr, filename)) {
276 FreeLibrary(hinstance);
277 return false;
280 void *ptr = (void *)GetProcAddress( hinstance, "load" );
281 if (!ptr) {
282 char *s;
283 FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
284 0, GetLastError(), 0, (char*)&s, 1, 0 );
285 scprintf("*** ERROR: GetProcAddress err '%s'\n", s);
286 LocalFree( s );
288 FreeLibrary(hinstance);
289 return false;
292 LoadPlugInFunc loadFunc = (LoadPlugInFunc)ptr;
293 (*loadFunc)(&gInterfaceTable);
295 // FIXME: at the moment we never call FreeLibrary() on a loaded plugin
297 return true;
299 #else
301 void* handle = dlopen(filename, RTLD_NOW);
303 if (!handle) {
304 scprintf("*** ERROR: dlopen '%s' err '%s'\n", filename, dlerror());
305 dlclose(handle);
306 return false;
309 void *apiVersionPtr = (void *)dlsym( handle, "api_version" );
310 if (!checkAPIVersion(apiVersionPtr, filename)) {
311 dlclose(handle);
312 return false;
315 void *ptr = dlsym(handle, "load");
316 if (!ptr) {
317 scprintf("*** ERROR: dlsym load err '%s'\n", dlerror());
318 dlclose(handle);
319 return false;
322 LoadPlugInFunc loadFunc = (LoadPlugInFunc)ptr;
323 (*loadFunc)(&gInterfaceTable);
325 return true;
327 #endif
330 static bool PlugIn_LoadDir(const char *dirname, bool reportError)
332 bool success = true;
334 SC_DirHandle *dir = sc_OpenDir(dirname);
335 if (!dir) {
336 if (reportError) {
337 scprintf("*** ERROR: open directory failed '%s'\n", dirname); fflush(stdout);
339 return false;
342 int firstCharOffset = strlen(dirname)+1;
344 for (;;) {
345 char diritem[MAXPATHLEN];
346 bool skipItem = true;
347 bool validItem = sc_ReadDir(dir, dirname, diritem, skipItem);
348 if (!validItem) break;
349 if (skipItem || (*(diritem+firstCharOffset) == '.')) continue; // skip files+folders whose first char is a dot
351 if (sc_DirectoryExists(diritem)) {
352 success = PlugIn_LoadDir(diritem, reportError);
353 } else {
354 int dnamelen = strlen(diritem);
355 int extlen = strlen(SC_PLUGIN_EXT);
356 char *extptr = diritem+dnamelen-extlen;
357 if (strncmp(extptr, SC_PLUGIN_EXT, extlen) == 0) {
358 success = PlugIn_Load(diritem);
362 if (!success) continue;
365 sc_CloseDir(dir);
366 return success;