FST code from 2.X branch
authorPaul Davis <paul@linuxaudiosystems.com>
Thu, 16 Apr 2009 00:43:41 +0000 (00:43 +0000)
committerPaul Davis <paul@linuxaudiosystems.com>
Thu, 16 Apr 2009 00:43:41 +0000 (00:43 +0000)
git-svn-id: svn://localhost/ardour2/branches/3.0@4981 d708f5d6-7413-0410-9779-e7cbd77b26cf

libs/fst/SConscript
libs/fst/fst.h
libs/fst/vestige/aeffectx.h
libs/fst/vstwin.c

index 92c750425777bc18411044c889101f59965b75d5..a543d72a501ae4f7cbb0b7e9299fdaa0f58368f0 100644 (file)
@@ -8,21 +8,63 @@ import glob
 fst_src = glob.glob('*.c')
 
 Import('env install_prefix libraries')
-fst = env.Clone(CC="winegcc")
+fst = env.Clone()
 fst.Append (CPPPATH=".")
-fst.Merge ([libraries['glib2']])
+fst.Merge ([
+        libraries['jack'],
+        libraries['glib2']
+        ])
+
+#
+# See if JACK supports jack_set_thread_creator()
+#
+
+jack_test_source_file = """
+#include <jack/jack.h>
+#include <pthread.h>
+int
+my_pthread_create (pthread_t* thread_id, const pthread_attr_t* attr, void *(*function)(void*), void* arg)
+{
+    return 0;
+}
+int main(int argc, char **argv)
+{
+    jack_set_thread_creator (my_pthread_create);
+    return 0;
+}
+"""
+def CheckJackSetThreadCreator(context):
+    context.Message('Checking for jack_set_thread_creator()...')
+    result = context.TryLink(jack_test_source_file, '.c')
+    context.Result(result)
+    return result
+
+
+conf = Configure(fst, custom_tests = {
+       'CheckJackSetThreadCreator' : CheckJackSetThreadCreator,
+})
+
+if conf.CheckJackSetThreadCreator():
+    fst.Append(CCFLAGS="-DHAVE_JACK_SET_THREAD_CREATOR")
+
+fst = conf.Finish ()
 
 if fst['VST']:
+    fst.Replace(CC = ("winegcc"))
     a = fst.Object ('fst', 'fst.c')
     b = fst.Object ('fstinfofile', 'fstinfofile.c')
     c = fst.Object ('vstwin', 'vstwin.c')
     d = fst.Object ('vsti', 'vsti.c')
-
-    Default([a,b,c,d])
+    e = fst.Object ('thread', 'thread.c')
+    Default([a,b,c,d,e])
     
+vestige_headers = glob.glob ('vestige/*.h')
+
 env.Alias('tarball', env.Distribute (env['DISTTREE'],
-                                     fst_src + ['SConscript',
-                                                'fst.h',
-                                                'jackvst.h'
-                                                ] ))
+                                     fst_src + vestige_headers +
+                                     ['SConscript',
+                                      'fst.h',
+                                      'jackvst.h',
+                                      ] 
+                                     ))
 
index 2a0130667a54974da5c7a3841dbef9d0543c4d42..6ef5acf7946f966a79fcd7dadcf272bec5fa3c68 100644 (file)
@@ -80,8 +80,10 @@ struct _FST
     int        height;
     int                wantIdle;
     int         destroy;
+    int         vst_version;
 
     int                want_program;
+    int         current_program;
     float      *want_params;
     float      *set_params;
 
@@ -105,6 +107,7 @@ extern "C" {
 #endif
 
 extern int        fst_init (void* possible_hmodule);
+extern void       fst_exit ();
 
 extern FSTHandle* fst_load (const char*);
 extern int        fst_unload (FSTHandle*);
@@ -133,6 +136,9 @@ extern int fst_load_state (FST * fst, char * filename);
  */
 extern int fst_save_state (FST * fst, char * filename);
 
+extern int wine_pthread_create (pthread_t* thread_id, const pthread_attr_t* attr, void *(*function)(void*), void* arg);
+
+
 #ifdef __cplusplus
 }
 #endif
index 790c93e6dcb82b19b55586d3c1838f842fe1925c..dda128f45eeb4837d1467c299bc7fe7172f1a84f 100644 (file)
@@ -26,6 +26,7 @@
 #ifndef _AEFFECTX_H
 #define _AEFFECTX_H
 
+#include <stdint.h>
 
 #define audioMasterAutomate 0
 #define audioMasterVersion 1
 #define kVstLangEnglish 1
 #define kVstMidiType 1
 #define kVstTransportPlaying (1 << 1)
-#define kVstParameterUsesFloatStep (1 << 2)
+
+/* validity flags for a VstTimeINfo structure this info comes from the web */
+
+#define kVstNanosValid (1 << 8)
+#define kVstPpqPosValid (1 << 9)
 #define kVstTempoValid (1 << 10)
 #define kVstBarsValid (1 << 11)
+#define kVstCyclePosValid (1 << 12)
+#define kVstTimeSigValid (1 << 13)
+#define kVstSmpteValid (1 << 14)
+#define kVstClockValid (1 << 15)
+
 #define kVstTransportChanged 1
 
 typedef struct VstMidiEvent
@@ -182,27 +192,49 @@ typedef struct VstEvents
        VstEvent * events[];
 } VstEvents;
 
+/* constants from http://www.rawmaterialsoftware.com/juceforum/viewtopic.php?t=3740&sid=183f74631fee71a493316735e2b9f28b */
 
-
-
-// Not finished, neither really used
-typedef struct VstParameterProperties
+enum Vestige2StringConstants
 {
-       float stepFloat;
-       char label[64];
-       int flags;
-       int minInteger;
-       int maxInteger;
-       int stepInteger;
-       char shortLabel[8];
-       int category;
-       char categoryLabel[24];
-       char empty[128];
-
-} VstParameterProperties;
-
-
-
+       VestigeMaxNameLen       = 64,
+       VestigeMaxLabelLen      = 64,
+       VestigeMaxShortLabelLen = 8,
+       VestigeMaxCategLabelLen = 24,
+       VestigeMaxFileNameLen   = 100
+}; 
+
+/* this struct taken from http://asseca.com/vst-24-specs/efGetParameterProperties.html */
+struct VstParameterProperties
+{
+    float stepFloat;              /* float step */
+    float smallStepFloat;         /* small float step */
+    float largeStepFloat;         /* large float step */
+    char label[VestigeMaxLabelLen];  /* parameter label */
+    int32_t flags;               /* @see VstParameterFlags */
+    int32_t minInteger;          /* integer minimum */
+    int32_t maxInteger;          /* integer maximum */
+    int32_t stepInteger;         /* integer step */
+    int32_t largeStepInteger;    /* large integer step */
+    char shortLabel[VestigeMaxShortLabelLen]; /* short label, recommended: 6 + delimiter */
+    int16_t displayIndex;        /* index where this parameter should be displayed (starting with 0) */
+    int16_t category;            /* 0: no category, else group index + 1 */
+    int16_t numParametersInCategory; /* number of parameters in category */
+    int16_t reserved;            /* zero */
+    char categoryLabel[VestigeMaxCategLabelLen]; /* category label, e.g. "Osc 1"  */
+    char future[16];              /* reserved for future use */
+};
+
+/* this enum taken from http://asseca.com/vst-24-specs/efGetParameterProperties.html */
+enum VstParameterFlags
+{
+       kVstParameterIsSwitch                = 1 << 0,  /* parameter is a switch (on/off) */
+       kVstParameterUsesIntegerMinMax       = 1 << 1,  /* minInteger, maxInteger valid */
+       kVstParameterUsesFloatStep           = 1 << 2,  /* stepFloat, smallStepFloat, largeStepFloat valid */
+       kVstParameterUsesIntStep             = 1 << 3,  /* stepInteger, largeStepInteger valid */
+       kVstParameterSupportsDisplayIndex    = 1 << 4,  /* displayIndex valid */
+       kVstParameterSupportsDisplayCategory = 1 << 5,  /* category, etc. valid */
+       kVstParameterCanRamp                 = 1 << 6   /* set if parameter value can ramp up/down */
+};
 
 typedef struct AEffect
 {
@@ -253,30 +285,26 @@ typedef struct AEffect
 
 typedef struct VstTimeInfo
 {
-       // 00
-       double samplePos;
-       // 08
-       double sampleRate;
-       // unconfirmed 10 18
-       char empty1[8 + 8];
-       // 20?
-       double tempo;
-       // unconfirmed 28 30 38
-       char empty2[8 + 8 + 8];
-       // 40?
-       int timeSigNumerator;
-       // 44?
-       int timeSigDenominator;
-       // unconfirmed 48 4c 50
-       char empty3[4 + 4 + 4];
-       // 54
-       int flags;
+    /* info from online documentation of VST provided by Steinberg */
+
+    double samplePos;
+    double sampleRate;
+    double nanoSeconds;
+    double ppqPos;
+    double tempo;
+    double barStartPos;
+    double cycleStartPos;
+    double cycleEndPos;
+    double timeSigNumerator;
+    double timeSigDenominator;
+    long   smpteOffset;
+    long   smpteFrameRate;
+    long   samplesToNextClock;
+    long   flags;
 
 } VstTimeInfo;
 
 
-
-
 typedef long int (* audioMasterCallback)( AEffect * , long int , long int ,
                                                long int , void * , float );
 // we don't use it, may be noise
index fc9ac0c9997bb5d5100740c619075f375aeedd65..09ca8f18d32d9109f2340b9e10e367cd16b2a4f2 100644 (file)
@@ -1,4 +1,6 @@
 #include <stdio.h>
+#include <jack/jack.h>
+#include <jack/thread.h>
 #include <libgen.h>
 #include <windows.h>
 #include <winnt.h>
@@ -24,11 +26,7 @@ static FST* fst_first = NULL;
 const char magic[] = "FST Plugin State v002";
 
 DWORD  gui_thread_id = 0;
-
-extern boolean g_quit;
-
-
-
+static int gui_quit = 0;
 
 #define DELAYED_WINDOW 1
 
@@ -36,12 +34,11 @@ extern boolean g_quit;
 static LRESULT WINAPI 
 my_window_proc (HWND w, UINT msg, WPARAM wp, LPARAM lp)
 {
-       FST* fst=NULL;
-       LRESULT result;
-
-//     if (msg != WM_TIMER) {
-//             fst_error ("window callback handler, msg = 0x%x win=%p\n", msg, w);
-//     }
+#if 0
+       if (msg != WM_TIMER) {
+               fst_error ("window callback handler, msg = 0x%x win=%p\n", msg, w);
+       }
+#endif
 
        switch (msg) {
        case WM_KEYUP:
@@ -49,47 +46,21 @@ my_window_proc (HWND w, UINT msg, WPARAM wp, LPARAM lp)
                break;
 
        case WM_CLOSE:
-               //printf("wtf.\n" );
-               PostQuitMessage (0);
-       case WM_DESTROY:
-       case WM_NCDESTROY:
-               /* we should never get these */
-               //return 0;
-               break;
-#if 0
-       case WM_PAINT:
-                       if ((fst = GetPropA (w, "fst_ptr")) != NULL) {
-                               if (fst->window && !fst->been_activated) {
-                                       fst->been_activated = TRUE;
-                                       pthread_cond_signal (&fst->window_status_change);
-                                       pthread_mutex_unlock (&fst->lock);
-                               }
-                       }
+               /* we don't care about windows closing ... */
+               return 0;
                break;
-#endif
 
-#if 0  
-       case WM_TIMER:
-               fst = GetPropA( w, "fst_ptr" );
-               if( !fst ) {
-                   printf( "Timer without fst_ptr Prop :(\n" );
-                   return 0;
-               }
-
-               fst->plugin->dispatcher(fst->plugin, effEditIdle, 0, 0, NULL, 0.0f);
-               if( fst->wantIdle )
-                   fst->plugin->dispatcher(fst->plugin, 53, 0, 0, NULL, 0.0f);
+       case WM_DESTROY:
+       case WM_NCDESTROY:
+               /* we don't care about windows being destroyed ... */
                return 0;
-#endif
-
-
+               break;
 
        default:
                break;
        }
 
        return DefWindowProcA (w, msg, wp, lp );
-       //return 0;
 }
 
 static FST* 
@@ -100,6 +71,7 @@ fst_new ()
        pthread_cond_init (&fst->window_status_change, NULL);
        pthread_cond_init (&fst->plugin_dispatcher_called, NULL);
        fst->want_program = -1;
+       fst->current_program = -1;
        return fst;
 }
 
@@ -114,7 +86,6 @@ DWORD WINAPI gui_event_loop (LPVOID param)
 {
        MSG msg;
        FST* fst;
-       char c;
        HMODULE hInst;
        HWND window;
 
@@ -141,75 +112,98 @@ DWORD WINAPI gui_event_loop (LPVOID param)
                fst_error ("cannot set timer on dummy window");
        }
 
-       while (GetMessageA (&msg, NULL, 0,0)) {
+       while (!gui_quit) {
+
+               if (!GetMessageA (&msg, NULL, 0,0)) {
+                       if (!gui_quit) {
+                               fprintf (stderr, "QUIT message received by Windows GUI thread - ignored\n");
+                               continue;
+                       } else {
+                               break;
+                       }
+               }
+
                TranslateMessage( &msg );
                DispatchMessageA (&msg);
 
                /* handle window creation requests, destroy requests, 
                   and run idle callbacks 
                */
-               
-               if( msg.message == WM_TIMER  ) {
-                   pthread_mutex_lock (&plugin_mutex);
-again:
-                   for (fst = fst_first; fst; fst = fst->next) {
-
-                       if (fst->destroy) {
-                           if (fst->window) {
-                               fst->plugin->dispatcher( fst->plugin, effEditClose, 0, 0, NULL, 0.0 );
-                               CloseWindow (fst->window);
-                               fst->window = NULL;
-                               fst->destroy = FALSE;
-                           }
-                           fst_event_loop_remove_plugin (fst);
-                           fst->been_activated = FALSE;
-                           pthread_mutex_lock (&fst->lock);
-                           pthread_cond_signal (&fst->window_status_change);
-                           pthread_mutex_unlock (&fst->lock);
-                           goto again;
-                       } 
-
-                       if (fst->window == NULL) {
-                           pthread_mutex_lock (&fst->lock);
-                           fst_error ("Creating window for FST plugin %s", fst->handle->name);
-                           if (fst_create_editor (fst)) {
-                               fst_error ("cannot create editor for plugin %s", fst->handle->name);
-                               fst_event_loop_remove_plugin (fst);
-                               pthread_cond_signal (&fst->window_status_change);
-                               pthread_mutex_unlock (&fst->lock);
-                               goto again;
-                           }
-                           /* condition/unlock: it was signalled & unlocked in fst_create_editor()   */
-                       }
-                       if(fst->want_program != -1 ) {
-                               fst->plugin->dispatcher (fst->plugin, effSetProgram, 0, fst->want_program, NULL, 0);
-                               fst->want_program = -1; 
-                       }
-                       
-                       if(fst->dispatcher_wantcall) {
 
+               if (msg.message == WM_TIMER) {
+                       pthread_mutex_lock (&plugin_mutex);
+                   
+again:
+                       for (fst = fst_first; fst; fst = fst->next) {
+                               
                                pthread_mutex_lock (&fst->lock);
-                               fst->dispatcher_retval = fst->plugin->dispatcher( fst->plugin, fst->dispatcher_opcode,
-                                                                                 fst->dispatcher_index,
-                                                                                 fst->dispatcher_val,
-                                                                                 fst->dispatcher_ptr,
-                                                                                 fst->dispatcher_opt );
-                               fst->dispatcher_wantcall = 0;
-                               pthread_cond_signal (&fst->plugin_dispatcher_called);
-                               pthread_mutex_unlock (&fst->lock);
-                       }
 
-                       pthread_mutex_lock (&fst->lock);
-                       fst->plugin->dispatcher (fst->plugin, effEditIdle, 0, 0, NULL, 0);
-                       if( fst->wantIdle ) {
-                               fst->plugin->dispatcher (fst->plugin, 53, 0, 0, NULL, 0);
+                               if (fst->destroy) {
+                                       fprintf (stderr, "%s scheduled for destroy\n", fst->handle->name);
+                                       if (fst->window) {
+                                               fst->plugin->dispatcher( fst->plugin, effEditClose, 0, 0, NULL, 0.0 );
+                                               CloseWindow (fst->window);
+                                               fst->window = NULL;
+                                               fst->destroy = FALSE;
+                                       }
+                                       fst_event_loop_remove_plugin (fst);
+                                       fst->been_activated = FALSE;
+                                       pthread_cond_signal (&fst->window_status_change);
+                                       pthread_mutex_unlock (&fst->lock);
+                                       goto again;
+                               } 
+                               
+                               if (fst->window == NULL) {
+                                       if (fst_create_editor (fst)) {
+                                               fst_error ("cannot create editor for plugin %s", fst->handle->name);
+                                               fst_event_loop_remove_plugin (fst);
+                                               pthread_cond_signal (&fst->window_status_change);
+                                               pthread_mutex_unlock (&fst->lock);
+                                               goto again;
+                                       } else {
+                                               /* condition/unlock: it was signalled & unlocked in fst_create_editor()   */
+                                       }
+                               }
+
+                               if (fst->want_program != -1 ) {
+                                       if (fst->vst_version >= 2) {
+                                               fst->plugin->dispatcher (fst->plugin, 67 /* effBeginSetProgram */, 0, 0, NULL, 0);
+                                       }
+
+                                       fst->plugin->dispatcher (fst->plugin, effSetProgram, 0, fst->want_program, NULL, 0);
+
+                                       if (fst->vst_version >= 2) {
+                                               fst->plugin->dispatcher (fst->plugin, 68 /* effEndSetProgram */, 0, 0, NULL, 0);
+                                       }
+                                       /* did it work? */
+                                       fst->current_program = fst->plugin->dispatcher (fst->plugin, 3, /* effGetProgram */ 0, 0, NULL, 0);
+                                       fst->want_program = -1; 
+                               }
+                               
+                               if(fst->dispatcher_wantcall) {
+                                       fst->dispatcher_retval = fst->plugin->dispatcher( fst->plugin, 
+                                                                                         fst->dispatcher_opcode,
+                                                                                         fst->dispatcher_index,
+                                                                                         fst->dispatcher_val,
+                                                                                         fst->dispatcher_ptr,
+                                                                                         fst->dispatcher_opt );
+                                       fst->dispatcher_wantcall = 0;
+                                       pthread_cond_signal (&fst->plugin_dispatcher_called);
+                               }
+                               
+                               fst->plugin->dispatcher (fst->plugin, effEditIdle, 0, 0, NULL, 0);
+
+                               if( fst->wantIdle ) {
+                                       fst->plugin->dispatcher (fst->plugin, 53, 0, 0, NULL, 0);
+                               }
+
+                               pthread_mutex_unlock (&fst->lock);
                        }
-                       pthread_mutex_unlock (&fst->lock);
-                   }
-                   pthread_mutex_unlock (&plugin_mutex);
+                       pthread_mutex_unlock (&plugin_mutex);
+                       
                }
        }
-       fprintf (stderr, "VST GUI EVENT LOOP THREAD EXIT\n");
+
        return 0;
 }
 
@@ -220,37 +214,25 @@ fst_init (void* possible_hmodule)
        HMODULE hInst;
        
        if (possible_hmodule) {
-         hInst = (HMODULE) possible_hmodule;
+               hInst = (HMODULE) possible_hmodule;
        } else if ((hInst = GetModuleHandleA (NULL)) == NULL) {
-         fst_error ("can't get module handle");
-         return -1;
-       }
-    wclass.cbSize = sizeof(WNDCLASSEX);
-    wclass.style = 0;
-    wclass.lpfnWndProc = my_window_proc;
-    wclass.cbClsExtra = 0;
-    wclass.cbWndExtra = 0;
-    wclass.hInstance = hInst;
-    wclass.hIcon = LoadIcon(hInst, "FST");
-    wclass.hCursor = LoadCursor(0, IDI_APPLICATION);
+               fst_error ("can't get module handle");
+               return -1;
+       }
+
+       wclass.cbSize = sizeof(WNDCLASSEX);
+       wclass.style = 0;
+       wclass.lpfnWndProc = my_window_proc;
+       wclass.cbClsExtra = 0;
+       wclass.cbWndExtra = 0;
+       wclass.hInstance = hInst;
+       wclass.hIcon = LoadIcon(hInst, "FST");
+       wclass.hCursor = LoadCursor(0, IDI_APPLICATION);
 //    wclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
-    wclass.lpszMenuName = "MENU_FST";
-    wclass.lpszClassName = "FST";
-    wclass.hIconSm = 0;
+       wclass.lpszMenuName = "MENU_FST";
+       wclass.lpszClassName = "FST";
+       wclass.hIconSm = 0;
 
-#if 0
-       wc.style = 0;
-       wc.lpfnWndProc = my_window_proc;
-       wc.cbClsExtra = 0;
-       wc.cbWndExtra = 0;
-       wc.hInstance = hInst;
-       wc.hIcon = LoadIconA( hInst, "FST");
-       wc.hCursor = LoadCursorA( NULL, IDI_APPLICATION );
-       wc.hbrBackground = GetStockObject( BLACK_BRUSH );
-       wc.lpszMenuName = "FSTMENU";
-       wc.lpszClassName = "FST";
-       //wc.hIconSm = 0;
-#endif
 
        if (!RegisterClassExA(&wclass)){
                printf( "Class register failed :(\n" );
@@ -263,9 +245,21 @@ fst_init (void* possible_hmodule)
                fst_error ("could not create new thread proxy");
                return -1;
        }
+
+#ifdef HAVE_JACK_SET_THREAD_CREATOR
+       jack_set_thread_creator (wine_pthread_create);
+#endif
+
        return 0;
 }
 
+void
+fst_exit ()
+{
+       gui_quit = 1;
+       PostQuitMessage (0);
+}
+
 int
 fst_run_editor (FST* fst)
 {
@@ -319,7 +313,6 @@ int
 fst_create_editor (FST* fst)
 {
        HMODULE hInst;
-       char class[20];
        HWND window;
        struct ERect* er;
 
@@ -372,9 +365,7 @@ fst_create_editor (FST* fst)
        //SetWindowPos (fst->window, 0, 0, 0, er->right-er->left+8, er->bottom-er->top+26, SWP_NOMOVE|SWP_NOZORDER);
        
        fst->xid = (int) GetPropA (window, "__wine_x11_whole_window");
-       printf( "And xid = %x\n", fst->xid );
        fst->been_activated = TRUE;
-       printf ("Signalling window ready\n");
        pthread_cond_signal (&fst->window_status_change);
        pthread_mutex_unlock (&fst->lock);
 
@@ -385,25 +376,24 @@ void
 fst_move_window_into_view (FST* fst)
 {
         if (fst->window) {
-         SetWindowPos (fst->window, 0, 0, 0, fst->width, fst->height+24, 0);
-         ShowWindow (fst->window, SW_SHOWNA);
+               SetWindowPos (fst->window, 0, 0, 0, fst->width, fst->height+24, 0);
+               ShowWindow (fst->window, SW_SHOWNA);
        }
 }
 
 void
 fst_destroy_editor (FST* fst)
 {
-       FST* p;
-       FST* prev;
-
        pthread_mutex_lock (&fst->lock);
        if (fst->window) {
+               fprintf (stderr, "mark %s for destroy\n", fst->handle->name);
                fst->destroy = TRUE;
                //if (!PostThreadMessageA (gui_thread_id, WM_USER, 0, 0)) {
                //if (!PostThreadMessageA (gui_thread_id, WM_QUIT, 0, 0)) {
                //      fst_error ("could not post message to gui thread");
                //}
                pthread_cond_wait (&fst->window_status_change, &fst->lock);
+               fprintf (stderr, "%s editor destroyed\n", fst->handle->name);
 
        }
        pthread_mutex_unlock (&fst->lock);
@@ -481,7 +471,7 @@ fst_load_vst_library(const char * path)
 FSTHandle*
 fst_load (const char *path)
 {
-       char* buf, *buf2;
+       char* buf;
        FSTHandle* fhandle;
        char* period;
 
@@ -585,6 +575,8 @@ fst_instantiate (FSTHandle* fhandle, audioMasterCallback amc, void* userptr)
        fst->plugin->dispatcher (fst->plugin, effOpen, 0, 0, 0, 0);
        //fst->plugin->dispatcher (fst->plugin, effMainsChanged, 0, 0, NULL, 0);
 
+       fst->vst_version = fst->plugin->dispatcher (fst->plugin, effGetVstVersion, 0, 0, 0, 0);
+       
        fst->handle->plugincnt++;
        fst->wantIdle = 0;
 
@@ -742,7 +734,6 @@ int fst_save_state (FST * fst, char * filename)
                char effectName[64];
                char vendorString[64];
                int success;
-               unsigned length;
 
                // write header
                fprintf( f, "<plugin_state>\n" );