1 /***********************************************************/
2 /*vstfx infofile - module to manage info files */
3 /*containing cached information about a plugin. e.g. its */
4 /*name, creator etc etc */
5 /***********************************************************/
21 #include <glib/gstdio.h>
23 #include "ardour/vstfx.h"
25 #define MAX_STRING_LEN 256
27 static char* read_string(FILE *fp)
29 char buf[MAX_STRING_LEN];
31 if (!fgets( buf, MAX_STRING_LEN, fp )) {
35 if(strlen(buf) < MAX_STRING_LEN) {
37 buf[strlen(buf)-1] = 0;
45 static VSTFXInfo* load_vstfx_info_file(FILE* fp)
50 if ((info = (VSTFXInfo*) malloc(sizeof(VSTFXInfo))) == 0) {
54 if((info->name = read_string(fp)) == 0) goto error;
55 if((info->creator = read_string(fp)) == 0) goto error;
56 if(1 != fscanf(fp, "%d\n", &info->UniqueID)) goto error;
57 if((info->Category = read_string(fp)) == 0) goto error;
58 if(1 != fscanf(fp, "%d\n", &info->numInputs)) goto error;
59 if(1 != fscanf(fp, "%d\n", &info->numOutputs)) goto error;
60 if(1 != fscanf(fp, "%d\n", &info->numParams)) goto error;
61 if(1 != fscanf(fp, "%d\n", &info->wantMidi)) goto error;
62 if(1 != fscanf(fp, "%d\n", &info->hasEditor)) goto error;
63 if(1 != fscanf(fp, "%d\n", &info->canProcessReplacing)) goto error;
65 if((info->ParamNames = (char **) malloc(sizeof(char*)*info->numParams)) == 0) {
69 for (i=0; i<info->numParams; i++) {
70 if((info->ParamNames[i] = read_string(fp)) == 0) goto error;
73 if ((info->ParamLabels = (char **) malloc(sizeof(char*)*info->numParams)) == 0) {
77 for (i=0; i < info->numParams; i++) {
78 if((info->ParamLabels[i] = read_string(fp)) == 0) goto error;
88 static int save_vstfx_info_file(VSTFXInfo *info, FILE* fp)
93 vstfx_error("** ERROR ** VSTFXinfofile : info ptr is 0\n");
98 vstfx_error("** ERROR ** VSTFXinfofile : file ptr is 0\n");
102 fprintf( fp, "%s\n", info->name );
103 fprintf( fp, "%s\n", info->creator );
104 fprintf( fp, "%d\n", info->UniqueID );
105 fprintf( fp, "%s\n", info->Category );
106 fprintf( fp, "%d\n", info->numInputs );
107 fprintf( fp, "%d\n", info->numOutputs );
108 fprintf( fp, "%d\n", info->numParams );
109 fprintf( fp, "%d\n", info->wantMidi );
110 fprintf( fp, "%d\n", info->hasEditor );
111 fprintf( fp, "%d\n", info->canProcessReplacing );
113 for (i=0; i < info->numParams; i++) {
114 fprintf(fp, "%s\n", info->ParamNames[i]);
117 for (i=0; i < info->numParams; i++) {
118 fprintf(fp, "%s\n", info->ParamLabels[i]);
124 static char* vstfx_infofile_stat (char *dllpath, struct stat* statbuf, int personal)
132 if (strstr (dllpath, ".so" ) == 0) {
137 dir_path = g_build_filename (g_get_home_dir(), ".fst", NULL);
139 dir_path = g_path_get_dirname (dllpath);
142 base = g_path_get_basename (dllpath);
143 blen = strlen (base) + 2; // null char and '.'
144 basename = (char*) g_malloc (blen);
145 snprintf (basename, blen, ".%s.fsi", base);
148 path = g_build_filename (dir_path, basename, NULL);
154 if (g_file_test (path, GFileTest (G_FILE_TEST_EXISTS|G_FILE_TEST_IS_REGULAR))) {
156 /* info file exists in same location as the shared object, so
157 check if its current and up to date
163 if (stat (dllpath, &dllstat) == 0) {
164 if (stat(path, statbuf) == 0) {
165 if (dllstat.st_mtime <= statbuf->st_mtime) {
166 /* plugin is older than info file */
179 static FILE* vstfx_infofile_for_read (char* dllpath)
181 struct stat own_statbuf;
182 struct stat sys_statbuf;
186 own_info = vstfx_infofile_stat (dllpath, &own_statbuf, 1);
187 sys_info = vstfx_infofile_stat (dllpath, &sys_statbuf, 0);
191 if (own_statbuf.st_mtime <= sys_statbuf.st_mtime) {
192 /* system info file is newer, use it */
193 return fopen (sys_info, "r");
196 return fopen (own_info, "r");
203 static FILE* vstfx_infofile_create (char* dllpath, int personal)
211 if (strstr (dllpath, ".so" ) == 0) {
216 dir_path = g_build_filename (g_get_home_dir(), ".fst", NULL);
218 /* if the directory doesn't yet exist, try to create it */
220 if (!g_file_test (dir_path, G_FILE_TEST_IS_DIR)) {
221 if (g_mkdir (dir_path, 0700)) {
227 dir_path = g_path_get_dirname (dllpath);
230 base = g_path_get_basename (dllpath);
231 blen = strlen (base) + 2; // null char and '.'
232 basename = (char*) g_malloc (blen);
233 snprintf (basename, blen, ".%s.fsi", base);
236 path = g_build_filename (dir_path, basename, NULL);
241 FILE* f = fopen (path, "w");
247 static FILE* vstfx_infofile_for_write (char* dllpath)
251 if ((f = vstfx_infofile_create (dllpath, 0)) == 0) {
252 f = vstfx_infofile_create (dllpath, 1);
258 static int vstfx_can_midi(VSTFX *vstfx)
260 struct AEffect *plugin = vstfx->plugin;
262 int vst_version = plugin->dispatcher (plugin, effGetVstVersion, 0, 0, 0, 0.0f);
264 if (vst_version >= 2)
266 /* should we send it VST events (i.e. MIDI) */
268 if ((plugin->flags & effFlagsIsSynth) || (plugin->dispatcher (plugin, effCanDo, 0, 0,(void*) "receiveVstEvents", 0.0f) > 0))
274 static VSTFXInfo* vstfx_info_from_plugin(VSTFX *vstfx)
277 VSTFXInfo* info = (VSTFXInfo*) malloc(sizeof(VSTFXInfo));
279 struct AEffect *plugin;
282 /*We need to init the creator because some plugins
283 fail to implement getVendorString, and so won't stuff the
284 string with any name*/
286 char creator[65] = "Unknown\0";
290 vstfx_error( "** ERROR ** VSTFXinfofile : vstfx ptr is 0\n" );
297 plugin = vstfx->plugin;
299 info->name = strdup(vstfx->handle->name );
301 /*If the plugin doesn't bother to implement GetVendorString we will
302 have pre-stuffed the string with 'Unkown' */
304 plugin->dispatcher (plugin, effGetVendorString, 0, 0, creator, 0);
306 /*Some plugins DO implement GetVendorString, but DON'T put a name in it
307 so if its just a zero length string we replace it with 'Unknown' */
309 if (strlen(creator) == 0) {
310 info->creator = strdup("Unknown");
312 info->creator = strdup (creator);
315 info->UniqueID = plugin->uniqueID;
317 info->Category = strdup("None"); // FIXME:
318 info->numInputs = plugin->numInputs;
319 info->numOutputs = plugin->numOutputs;
320 info->numParams = plugin->numParams;
321 info->wantMidi = vstfx_can_midi(vstfx);
322 info->hasEditor = plugin->flags & effFlagsHasEditor ? true : false;
323 info->canProcessReplacing = plugin->flags & effFlagsCanReplacing ? true : false;
324 info->ParamNames = (char **) malloc(sizeof(char*)*info->numParams);
325 info->ParamLabels = (char **) malloc(sizeof(char*)*info->numParams);
327 for(i=0; i < info->numParams; i++) {
331 /*Not all plugins give parameters labels as well as names*/
333 strcpy(name, "No Name");
334 strcpy(label, "No Label");
336 plugin->dispatcher (plugin, effGetParamName, i, 0, name, 0);
337 info->ParamNames[i] = strdup(name);
339 //NOTE: 'effGetParamLabel' is no longer defined in vestige headers
340 //plugin->dispatcher (plugin, effGetParamLabel, i, 0, label, 0);
341 info->ParamLabels[i] = strdup(label);
346 /* A simple 'dummy' audiomaster callback which should be ok,
347 we will only be instantiating the plugin in order to get its info*/
349 static intptr_t simple_master_callback(struct AEffect *, int32_t opcode, int32_t, intptr_t, void *, float)
351 if (opcode == audioMasterVersion)
357 /*Try to get plugin info - first by looking for a .fsi cache of the
358 data, and if that doesn't exist, load the plugin, get its data and
359 then cache it for future ref*/
361 VSTFXInfo *vstfx_get_info(char *dllpath)
368 if ((infofile = vstfx_infofile_for_read (dllpath)) != 0) {
370 info = load_vstfx_info_file (infofile);
375 if(!(h = vstfx_load(dllpath)))
378 if(!(vstfx = vstfx_instantiate(h, simple_master_callback, 0))) {
380 vstfx_error( "** ERROR ** VSTFXinfofile : Instantiate failed\n" );
384 infofile = vstfx_infofile_for_write (dllpath);
389 vstfx_error("cannot create new FST info file for plugin");
393 info = vstfx_info_from_plugin(vstfx);
395 save_vstfx_info_file(info, infofile);
404 void vstfx_free_info(VSTFXInfo *info )
408 for(i=0; i < info->numParams; i++)
410 free(info->ParamNames[i]);
411 free(info->ParamLabels[i]);
416 free(info->Category);