diff --git a/libs/fst/SConscript b/libs/fst/SConscript index 92c7504257..a543d72a50 100644 --- a/libs/fst/SConscript +++ b/libs/fst/SConscript @@ -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 +#include +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]) -env.Alias('tarball', env.Distribute (env['DISTTREE'], - fst_src + ['SConscript', - 'fst.h', - 'jackvst.h' - ] )) +vestige_headers = glob.glob ('vestige/*.h') + +env.Alias('tarball', env.Distribute (env['DISTTREE'], + fst_src + vestige_headers + + ['SConscript', + 'fst.h', + 'jackvst.h', + ] + )) diff --git a/libs/fst/fst.h b/libs/fst/fst.h index 2a0130667a..6ef5acf794 100644 --- a/libs/fst/fst.h +++ b/libs/fst/fst.h @@ -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 diff --git a/libs/fst/vestige/aeffectx.h b/libs/fst/vestige/aeffectx.h index 790c93e6dc..dda128f45e 100644 --- a/libs/fst/vestige/aeffectx.h +++ b/libs/fst/vestige/aeffectx.h @@ -26,6 +26,7 @@ #ifndef _AEFFECTX_H #define _AEFFECTX_H +#include #define audioMasterAutomate 0 #define audioMasterVersion 1 @@ -128,9 +129,18 @@ #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 diff --git a/libs/fst/vstwin.c b/libs/fst/vstwin.c index fc9ac0c999..09ca8f18d3 100644 --- a/libs/fst/vstwin.c +++ b/libs/fst/vstwin.c @@ -1,4 +1,6 @@ #include +#include +#include #include #include #include @@ -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); + /* we don't care about windows closing ... */ + return 0; + break; + 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); - } - } - 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); + /* 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); + + 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) { - + 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); + + 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_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); - } - 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; + 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; -#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 + 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; + 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, "\n" );