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