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 fgets( buf, MAX_STRING_LEN, fp );
33 if(strlen(buf) < MAX_STRING_LEN)
36 buf[strlen(buf)-1] = 0;
46 static VSTFXInfo* load_vstfx_info_file(FILE* fp)
51 if ((info = (VSTFXInfo*) malloc(sizeof(VSTFXInfo))) == NULL) {
55 if((info->name = read_string(fp)) == NULL) goto error;
56 if((info->creator = read_string(fp)) == NULL) goto error;
57 if(1 != fscanf(fp, "%d\n", &info->UniqueID)) goto error;
58 if((info->Category = read_string(fp)) == NULL) goto error;
59 if(1 != fscanf(fp, "%d\n", &info->numInputs)) goto error;
60 if(1 != fscanf(fp, "%d\n", &info->numOutputs)) goto error;
61 if(1 != fscanf(fp, "%d\n", &info->numParams)) goto error;
62 if(1 != fscanf(fp, "%d\n", &info->wantMidi)) goto error;
63 if(1 != fscanf(fp, "%d\n", &info->hasEditor)) goto error;
64 if(1 != fscanf(fp, "%d\n", &info->canProcessReplacing)) goto error;
66 if((info->ParamNames = (char **) malloc(sizeof(char*)*info->numParams)) == NULL) {
70 for (i=0; i<info->numParams; i++) {
71 if((info->ParamNames[i] = read_string(fp)) == NULL) goto error;
74 if ((info->ParamLabels = (char **) malloc(sizeof(char*)*info->numParams)) == NULL) {
78 for (i=0; i < info->numParams; i++) {
79 if((info->ParamLabels[i] = read_string(fp)) == NULL) goto error;
89 static int save_vstfx_info_file(VSTFXInfo *info, FILE* fp)
94 vstfx_error("** ERROR ** VSTFXinfofile : info ptr is NULL\n");
99 vstfx_error("** ERROR ** VSTFXinfofile : file ptr is NULL\n");
103 fprintf( fp, "%s\n", info->name );
104 fprintf( fp, "%s\n", info->creator );
105 fprintf( fp, "%d\n", info->UniqueID );
106 fprintf( fp, "%s\n", info->Category );
107 fprintf( fp, "%d\n", info->numInputs );
108 fprintf( fp, "%d\n", info->numOutputs );
109 fprintf( fp, "%d\n", info->numParams );
110 fprintf( fp, "%d\n", info->wantMidi );
111 fprintf( fp, "%d\n", info->hasEditor );
112 fprintf( fp, "%d\n", info->canProcessReplacing );
114 for (i=0; i < info->numParams; i++) {
115 fprintf(fp, "%s\n", info->ParamNames[i]);
118 for (i=0; i < info->numParams; i++) {
119 fprintf(fp, "%s\n", info->ParamLabels[i]);
125 static char* vstfx_infofile_stat (char *dllpath, struct stat* statbuf, int personal)
133 if (strstr (dllpath, ".so" ) == NULL) {
138 dir_path = g_build_filename (g_get_home_dir(), ".fst", NULL);
140 dir_path = g_path_get_dirname (dllpath);
143 base = g_path_get_basename (dllpath);
144 blen = strlen (base) + 2; // null char and '.'
145 basename = (char*) g_malloc (blen);
146 snprintf (basename, blen, ".%s.fsi", base);
149 path = g_build_filename (dir_path, basename, NULL);
155 if (g_file_test (path, GFileTest (G_FILE_TEST_EXISTS|G_FILE_TEST_IS_REGULAR))) {
157 /* info file exists in same location as the shared object, so
158 check if its current and up to date
164 if (stat (dllpath, &dllstat) == 0) {
165 if (stat(path, statbuf) == 0) {
166 if (dllstat.st_mtime <= statbuf->st_mtime) {
167 /* plugin is older than info file */
180 static FILE* vstfx_infofile_for_read (char* dllpath)
182 struct stat own_statbuf;
183 struct stat sys_statbuf;
187 own_info = vstfx_infofile_stat (dllpath, &own_statbuf, 1);
188 sys_info = vstfx_infofile_stat (dllpath, &sys_statbuf, 0);
192 if (own_statbuf.st_mtime <= sys_statbuf.st_mtime) {
193 /* system info file is newer, use it */
194 return fopen (sys_info, "r");
197 return fopen (own_info, "r");
204 static FILE* vstfx_infofile_create (char* dllpath, int personal)
212 if (strstr (dllpath, ".so" ) == NULL) {
217 dir_path = g_build_filename (g_get_home_dir(), ".fst", NULL);
219 /* if the directory doesn't yet exist, try to create it */
221 if (!g_file_test (dir_path, G_FILE_TEST_IS_DIR)) {
222 if (g_mkdir (dir_path, 0700)) {
228 dir_path = g_path_get_dirname (dllpath);
231 base = g_path_get_basename (dllpath);
232 blen = strlen (base) + 2; // null char and '.'
233 basename = (char*) g_malloc (blen);
234 snprintf (basename, blen, ".%s.fsi", base);
237 path = g_build_filename (dir_path, basename, NULL);
242 FILE* f = fopen (path, "w");
248 static FILE* vstfx_infofile_for_write (char* dllpath)
252 if ((f = vstfx_infofile_create (dllpath, 0)) == NULL) {
253 f = vstfx_infofile_create (dllpath, 1);
259 static int vstfx_can_midi(VSTFX *vstfx)
261 struct AEffect *plugin = vstfx->plugin;
263 int vst_version = plugin->dispatcher (plugin, effGetVstVersion, 0, 0, NULL, 0.0f);
265 if (vst_version >= 2)
267 /* should we send it VST events (i.e. MIDI) */
269 if ((plugin->flags & effFlagsIsSynth) || (plugin->dispatcher (plugin, effCanDo, 0, 0,(void*) "receiveVstEvents", 0.0f) > 0))
275 static VSTFXInfo* vstfx_info_from_plugin(VSTFX *vstfx)
278 VSTFXInfo* info = (VSTFXInfo*) malloc(sizeof(VSTFXInfo));
280 struct AEffect *plugin;
283 /*We need to init the creator because some plugins
284 fail to implement getVendorString, and so won't stuff the
285 string with any name*/
287 char creator[65] = "Unknown\0";
291 vstfx_error( "** ERROR ** VSTFXinfofile : vstfx ptr is NULL\n" );
298 plugin = vstfx->plugin;
300 info->name = strdup(vstfx->handle->name );
302 /*If the plugin doesn't bother to implement GetVendorString we will
303 have pre-stuffed the string with 'Unkown' */
305 plugin->dispatcher (plugin, effGetVendorString, 0, 0, creator, 0);
307 /*Some plugins DO implement GetVendorString, but DON'T put a name in it
308 so if its just a zero length string we replace it with 'Unknown' */
310 if (strlen(creator) == 0) {
311 info->creator = strdup("Unknown");
313 info->creator = strdup (creator);
316 info->UniqueID = plugin->uniqueID;
318 info->Category = strdup("None"); // FIXME:
319 info->numInputs = plugin->numInputs;
320 info->numOutputs = plugin->numOutputs;
321 info->numParams = plugin->numParams;
322 info->wantMidi = vstfx_can_midi(vstfx);
323 info->hasEditor = plugin->flags & effFlagsHasEditor ? true : false;
324 info->canProcessReplacing = plugin->flags & effFlagsCanReplacing ? true : false;
325 info->ParamNames = (char **) malloc(sizeof(char*)*info->numParams);
326 info->ParamLabels = (char **) malloc(sizeof(char*)*info->numParams);
328 for(i=0; i < info->numParams; i++) {
332 /*Not all plugins give parameters labels as well as names*/
334 strcpy(name, "No Name");
335 strcpy(label, "No Label");
337 plugin->dispatcher (plugin, effGetParamName, i, 0, name, 0);
338 info->ParamNames[i] = strdup(name);
340 //NOTE: 'effGetParamLabel' is no longer defined in vestige headers
341 //plugin->dispatcher (plugin, effGetParamLabel, i, 0, label, 0);
342 info->ParamLabels[i] = strdup(label);
347 /* A simple 'dummy' audiomaster callback which should be ok,
348 we will only be instantiating the plugin in order to get its info*/
350 static intptr_t simple_master_callback(struct AEffect *, int32_t opcode, int32_t, intptr_t, void *, float)
352 if (opcode == audioMasterVersion)
358 /*Try to get plugin info - first by looking for a .fsi cache of the
359 data, and if that doesn't exist, load the plugin, get its data and
360 then cache it for future ref*/
362 VSTFXInfo *vstfx_get_info(char *dllpath)
369 if ((infofile = vstfx_infofile_for_read (dllpath)) != NULL) {
371 info = load_vstfx_info_file (infofile);
376 if(!(h = vstfx_load(dllpath)))
379 if(!(vstfx = vstfx_instantiate(h, simple_master_callback, NULL))) {
381 vstfx_error( "** ERROR ** VSTFXinfofile : Instantiate failed\n" );
385 infofile = vstfx_infofile_for_write (dllpath);
390 vstfx_error("cannot create new FST info file for plugin");
394 info = vstfx_info_from_plugin(vstfx);
396 save_vstfx_info_file(info, infofile);
405 void vstfx_free_info(VSTFXInfo *info )
409 for(i=0; i < info->numParams; i++)
411 free(info->ParamNames[i]);
412 free(info->ParamLabels[i]);
417 free(info->Category);