vestige-based VST support, back-ported from 2.0-ongoing
[ardour.git] / libs / fst / fstinfofile.c
1 #include "fst.h"
2
3 #include <sys/types.h>
4 #include <sys/stat.h>
5 #include <unistd.h>
6
7 #include <stdlib.h>
8 #include <stddef.h>
9 #include <stdio.h>
10 #include <string.h>
11
12 #define MAX_STRING_LEN 256
13
14 #define FALSE 0
15 #define TRUE !FALSE
16
17 static char *read_string( FILE *fp ) {
18     char buf[MAX_STRING_LEN];
19
20     fgets( buf, MAX_STRING_LEN, fp );
21     if( strlen( buf ) < MAX_STRING_LEN ) {
22         
23         if( strlen(buf) )
24             buf[strlen(buf)-1] = 0;
25
26         return strdup( buf );
27     } else {
28         return NULL;
29     }
30 }
31
32 static FSTInfo *load_fst_info_file( char *filename ) {
33
34     FSTInfo *info = (FSTInfo *) malloc( sizeof( FSTInfo ) );
35     FILE *fp;
36     int i;
37
38
39     if( info == NULL )
40         return NULL;
41
42     fp = fopen( filename, "r" );
43     
44     if( fp == NULL ) {
45         free( info );
46         return NULL;
47     }
48
49     if( (info->name = read_string( fp )) == NULL ) goto error;
50     if( (info->creator = read_string( fp )) == NULL ) goto error;
51     if( 1 != fscanf( fp, "%d\n", &info->UniqueID ) ) goto error;
52     if( (info->Category = read_string( fp )) == NULL ) goto error;
53     if( 1 != fscanf( fp, "%d\n", &info->numInputs ) ) goto error;
54     if( 1 != fscanf( fp, "%d\n", &info->numOutputs ) ) goto error;
55     if( 1 != fscanf( fp, "%d\n", &info->numParams ) ) goto error;
56     if( 1 != fscanf( fp, "%d\n", &info->wantMidi ) ) goto error;
57     if( 1 != fscanf( fp, "%d\n", &info->hasEditor ) ) goto error;
58     if( 1 != fscanf( fp, "%d\n", &info->canProcessReplacing ) ) goto error;
59
60     if( (info->ParamNames = (char **) malloc( sizeof( char * ) * info->numParams )) == NULL ) goto error;
61     for( i=0; i<info->numParams; i++ ) {
62         if( (info->ParamNames[i] = read_string( fp )) == NULL ) goto error;
63     }
64     if( (info->ParamLabels = (char **) malloc( sizeof( char * ) * info->numParams )) == NULL ) goto error;
65     for( i=0; i<info->numParams; i++ ) {
66         if( (info->ParamLabels[i] = read_string( fp )) == NULL ) goto error;
67     }
68         
69
70     fclose( fp );
71     return info;
72
73 error:
74     fclose( fp );
75     free( info );
76     return NULL;
77 }
78
79 static int save_fst_info_file( FSTInfo *info, char *filename ) {
80
81     FILE *fp;
82     int i;
83
84
85     if( info == NULL ) {
86         fst_error( "info is NULL\n" );
87         return TRUE;
88     }
89
90     fp = fopen( filename, "w" );
91     
92     if( fp == NULL ) {
93         fst_error( "Cant write info file %s\n", filename );
94         return TRUE;
95     }
96
97     fprintf( fp, "%s\n", info->name );
98     fprintf( fp, "%s\n", info->creator );
99     fprintf( fp, "%d\n", info->UniqueID );
100     fprintf( fp, "%s\n", info->Category );
101     fprintf( fp, "%d\n", info->numInputs );
102     fprintf( fp, "%d\n", info->numOutputs );
103     fprintf( fp, "%d\n", info->numParams );
104     fprintf( fp, "%d\n", info->wantMidi );
105     fprintf( fp, "%d\n", info->hasEditor );
106     fprintf( fp, "%d\n", info->canProcessReplacing );
107
108     for( i=0; i<info->numParams; i++ ) {
109         fprintf( fp, "%s\n", info->ParamNames[i] );
110     }
111     for( i=0; i<info->numParams; i++ ) {
112         fprintf( fp, "%s\n", info->ParamLabels[i] );
113     }
114         
115
116     fclose( fp );
117
118     return FALSE;
119 }
120
121 static char *fst_dllpath_to_infopath( char *dllpath ) {
122     char *retval;
123     if( strstr( dllpath, ".dll" ) == NULL ) return NULL;
124     
125     retval = strdup( dllpath );
126     sprintf( retval + strlen(retval) - 4, ".fsi" );
127     return retval;
128 }
129
130 static int fst_info_file_is_valid( char *dllpath ) {
131     struct stat dllstat, fststat;
132     char *fstpath = fst_dllpath_to_infopath( dllpath );
133
134     if( !fstpath ) return FALSE;
135     
136     if( stat( dllpath, &dllstat ) ){ fst_error( "dll path %s invalid\n", dllpath );  return TRUE; }
137     if( stat( fstpath, &fststat ) ) return FALSE;
138
139     free( fstpath );
140     if( dllstat.st_mtime > fststat.st_mtime )
141         return FALSE;
142     else 
143         return TRUE;
144 }
145
146 static int fst_can_midi( FST *fst ) {
147         struct AEffect *plugin = fst->plugin;
148         int vst_version = plugin->dispatcher (plugin, effGetVstVersion, 0, 0, NULL, 0.0f);
149
150         if (vst_version >= 2) {
151                 
152                 /* should we send it VST events (i.e. MIDI) */
153                 
154                 if ((plugin->flags & effFlagsIsSynth) ||
155                     (plugin->dispatcher (plugin, effCanDo, 0, 0,(void*) "receiveVstEvents", 0.0f) > 0))
156                     return TRUE;
157         }
158         return FALSE;
159
160 }
161 static FSTInfo *fst_info_from_plugin( FST *fst ) {
162     FSTInfo *info = (FSTInfo *) malloc( sizeof( FSTInfo ) );
163     struct AEffect *plugin;
164     int i;
165     char creator[65];
166
167     if( ! fst ) {
168         fst_error( "fst is NULL\n" );
169         return NULL;
170     }
171
172     if( ! info ) return NULL;
173     
174     plugin = fst->plugin;
175     
176
177     info->name = strdup(fst->handle->name ); 
178     plugin->dispatcher (plugin, 47 /* effGetVendorString */, 0, 0, creator, 0);
179     if (strlen (creator) == 0) {
180       info->creator = strdup ("Unknown");
181     } else {
182       info->creator = strdup (creator);
183     }
184
185 #ifdef VESTIGE_HEADER
186     info->UniqueID = *((int32_t *) &plugin->unused_id);
187 #else
188     info->UniqueID = plugin->uniqueID;
189 #endif
190
191     info->Category = strdup( "None" );          // FIXME:  
192     info->numInputs = plugin->numInputs;
193     info->numOutputs = plugin->numOutputs;
194     info->numParams = plugin->numParams;
195     info->wantMidi = fst_can_midi( fst ); 
196     info->hasEditor = plugin->flags & effFlagsHasEditor ? TRUE : FALSE;
197     info->canProcessReplacing = plugin->flags & effFlagsCanReplacing ? TRUE : FALSE;
198
199     info->ParamNames = (char **) malloc( sizeof( char * ) * info->numParams );
200     info->ParamLabels = (char **) malloc( sizeof( char * ) * info->numParams );
201     for( i=0; i<info->numParams; i++ ) {
202         char name[20];
203         char label[9];
204         plugin->dispatcher (plugin,
205                             effGetParamName,
206                             i, 0, name, 0);
207         info->ParamNames[i] = strdup( name );
208         plugin->dispatcher (plugin,
209                             6 /* effGetParamLabel */,
210                             i, 0, label, 0);
211         info->ParamLabels[i] = strdup( label );
212     }
213     return info;
214 }
215
216 // most simple one :) could be sufficient.... 
217 static long simple_master_callback( struct AEffect *fx, long opcode, long index, long value, void *ptr, float opt ) {
218     if( opcode == audioMasterVersion )
219         return 2;
220     else
221         return 0;
222 }
223
224 FSTInfo *fst_get_info( char *dllpath ) {
225
226     if( fst_info_file_is_valid( dllpath ) ) {
227         FSTInfo *info;
228         char *fstpath = fst_dllpath_to_infopath( dllpath );
229
230         info = load_fst_info_file( fstpath );
231         free( fstpath );
232         return info;
233
234     } else {
235
236         FSTHandle *h;
237         FST *fst;
238         FSTInfo *info;
239         char *fstpath;
240
241         if( !(h = fst_load( dllpath )) ) return NULL;
242         if( !(fst = fst_instantiate( h, simple_master_callback, NULL )) ) {
243             fst_unload( h );
244             fst_error( "instantiate failed\n" );
245             return NULL;
246         }
247         fstpath = fst_dllpath_to_infopath( dllpath );
248         if( !fstpath ) {
249             fst_close( fst );
250             fst_unload( h );
251             fst_error( "get fst filename failed\n" );
252             return NULL;
253         }
254         info = fst_info_from_plugin( fst );
255         save_fst_info_file( info, fstpath );
256
257         free( fstpath );
258         fst_close( fst );
259         fst_unload( h );
260         return info;
261     }
262 }
263
264 void fst_free_info( FSTInfo *info ) {
265
266     int i;
267
268     for( i=0; i<info->numParams; i++ ) {
269         free( info->ParamNames[i] );
270         free( info->ParamLabels[i] );
271     }
272     free( info->name );
273     free( info->creator );
274     free( info->Category );
275     free( info );
276 }
277
278