RemoteVstPlugin: fixed too short arrays for preset names
[lmms.git] / plugins / vst_base / RemoteVstPlugin.cpp
blob030bb5b64177f709387139ad444dd623c23091f1
1 /*
2 * RemoteVstPlugin.cpp - LMMS VST Support Layer (RemotePlugin client)
4 * Copyright (c) 2005-2010 Tobias Doerffel <tobydox/at/users.sourceforge.net>
6 * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
8 * Code partly taken from (X)FST:
9 * Copyright (c) 2004 Paul Davis
10 * Copyright (c) 2004 Torben Hohn
11 * Copyright (c) 2002 Kjetil S. Matheussen
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public
15 * License as published by the Free Software Foundation; either
16 * version 2 of the License, or (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * General Public License for more details.
23 * You should have received a copy of the GNU General Public
24 * License along with this program (see COPYING); if not, write to the
25 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
26 * Boston, MA 02110-1301 USA.
31 #include "lmmsconfig.h"
33 #define BUILD_REMOTE_PLUGIN_CLIENT
35 #include "RemotePlugin.h"
37 #ifdef LMMS_HAVE_PTHREAD_H
38 #include <pthread.h>
39 #endif
41 #ifdef LMMS_HAVE_FCNTL_H
42 #include <fcntl.h>
43 #endif
45 #ifdef LMMS_BUILD_LINUX
47 #ifndef O_BINARY
48 #define O_BINARY 0
49 #endif
51 #ifdef LMMS_HAVE_SCHED_H
52 #include <sched.h>
53 #endif
55 #include <wine/exception.h>
57 #endif
59 #include <windows.h>
61 #ifdef LMMS_BUILD_WIN32
62 #ifdef LMMS_BUILD_WIN64
63 #include "basename.c"
64 #else
65 #include <libgen.h>
66 #endif
67 #endif
70 #include <vector>
71 #include <string>
74 #include <aeffectx.h>
76 #if kVstVersion < 2400
78 #define OLD_VST_SDK
80 struct ERect
82 short top;
83 short left;
84 short bottom;
85 short right;
86 } ;
88 #endif
91 #include "lmms_basics.h"
92 #include "midi.h"
93 #include "communication.h"
97 static VstHostLanguages hlang = LanguageEnglish;
100 class RemoteVstPlugin;
102 RemoteVstPlugin * __plugin = NULL;
104 DWORD __GuiThreadID = 0;
108 class RemoteVstPlugin : public RemotePluginClient
110 public:
111 RemoteVstPlugin( key_t _shm_in, key_t _shm_out );
112 virtual ~RemoteVstPlugin();
114 virtual bool processMessage( const message & _m );
116 void init( const std::string & _plugin_file );
117 void initEditor();
119 virtual void process( const sampleFrame * _in, sampleFrame * _out );
122 virtual void processMidiEvent( const midiEvent & _event,
123 const f_cnt_t _offset );
125 // set given sample-rate for plugin
126 virtual void updateSampleRate()
128 pluginDispatch( effSetSampleRate, 0, 0,
129 NULL, (float) sampleRate() );
132 // set given buffer-size for plugin
133 virtual void updateBufferSize()
135 pluginDispatch( effSetBlockSize, 0, bufferSize() );
139 inline bool isInitialized() const
141 return m_initialized;
145 // set given tempo
146 void setBPM( const bpm_t _bpm )
148 m_bpm = _bpm;
151 // determine VST-version the plugin uses
152 inline int pluginVersion()
154 return pluginDispatch( effGetVendorVersion );
157 // determine name of plugin
158 const char * pluginName();
160 // determine vendor of plugin
161 const char * pluginVendorString();
163 // determine product-string of plugin
164 const char * pluginProductString();
166 // determine name of plugipn preset
167 const char * presetName();
169 // do a complete parameter-dump and post it
170 void getParameterDump();
172 // read parameter-dump and set it for plugin
173 void setParameterDump( const message & _m );
175 // post properties of specified parameter
176 void getParameterProperties( const int _idx );
178 // save settings chunk of plugin into file
179 void saveChunkToFile( const std::string & _file );
181 // restore settings chunk of plugin from file
182 void loadChunkFromFile( const std::string & _file, int _len );
184 // restore settings chunk of plugin from file
185 void loadChunkFromPresetFile( const std::string & _file );
187 // restore settings chunk of plugin from file
188 void rotateProgram( int _len );
190 // Load names VST of presets/programs
191 void loadPrograms( int _len );
193 // Save presets/programs
194 void savePreset( const std::string & _file );
196 // number of inputs
197 virtual int inputCount() const
199 if( m_plugin )
201 return m_plugin->numInputs;
203 return 0;
206 // number of outputs
207 virtual int outputCount() const
209 if( m_plugin )
211 return m_plugin->numOutputs;
213 return 0;
216 // has to be called as soon as input- or output-count changes
217 void updateInOutCount();
219 inline void lock()
221 pthread_mutex_lock( &m_pluginLock );
224 inline void unlock()
226 pthread_mutex_unlock( &m_pluginLock );
229 static DWORD WINAPI processingThread( LPVOID _param );
230 static DWORD WINAPI guiEventLoop( LPVOID _param );
233 private:
234 enum GuiThreadMessages
236 None,
237 ProcessPluginMessage,
238 GiveIdle,
239 ClosePlugin
242 // callback used by plugin for being able to communicate with it's host
243 static intptr_t hostCallback( AEffect * _effect, int32_t _opcode,
244 int32_t _index, intptr_t _value,
245 void * _ptr, float _opt );
248 bool load( const std::string & _plugin_file );
250 // thread-safe dispatching of plugin
251 int pluginDispatch( int cmd, int param1 = 0, int param2 = 0,
252 void * p = NULL, float f = 0 )
254 int ret = 0;
255 lock();
256 if( m_plugin )
258 ret = m_plugin->dispatcher( m_plugin, cmd, param1,
259 param2, p, f );
261 unlock();
262 return ret;
265 std::string m_shortName;
267 HINSTANCE m_libInst;
269 AEffect * m_plugin;
270 HWND m_window;
271 Sint32 m_windowID;
272 int m_windowWidth;
273 int m_windowHeight;
275 bool m_initialized;
277 pthread_mutex_t m_pluginLock;
280 float * * m_inputs;
281 float * * m_outputs;
283 typedef std::vector<VstMidiEvent> VstMidiEventList;
284 VstMidiEventList m_midiEvents;
286 bpm_t m_bpm;
287 double m_currentSamplePos;
294 RemoteVstPlugin::RemoteVstPlugin( key_t _shm_in, key_t _shm_out ) :
295 RemotePluginClient( _shm_in, _shm_out ),
296 m_shortName( "" ),
297 m_libInst( NULL ),
298 m_plugin( NULL ),
299 m_window( NULL ),
300 m_windowID( 0 ),
301 m_windowWidth( 0 ),
302 m_windowHeight( 0 ),
303 m_initialized( false ),
304 m_pluginLock(),
305 m_inputs( NULL ),
306 m_outputs( NULL ),
307 m_midiEvents(),
308 m_bpm( 0 ),
309 m_currentSamplePos( 0 )
311 pthread_mutex_init( &m_pluginLock, NULL );
313 __plugin = this;
315 // process until we have loaded the plugin
316 while( 1 )
318 message m = receiveMessage();
319 processMessage( m );
320 if( m.id == IdVstLoadPlugin || m.id == IdQuit )
322 break;
330 RemoteVstPlugin::~RemoteVstPlugin()
332 if( m_window != NULL )
334 pluginDispatch( effEditClose );
335 #ifdef LMMS_BUILD_LINUX
336 CloseWindow( m_window );
337 #endif
338 m_window = NULL;
341 if( m_libInst != NULL )
343 FreeLibrary( m_libInst );
344 m_libInst = NULL;
347 delete[] m_inputs;
348 delete[] m_outputs;
350 pthread_mutex_destroy( &m_pluginLock );
356 bool RemoteVstPlugin::processMessage( const message & _m )
358 switch( _m.id )
360 case IdVstLoadPlugin:
361 init( _m.getString() );
362 break;
364 #ifdef LMMS_BUILD_WIN32
365 case IdVstPluginWindowInformation:
367 HWND top = FindWindowEx( NULL, NULL, NULL,
368 _m.getString().c_str() );
369 m_window = FindWindowEx( top, NULL, NULL, NULL );
370 break;
372 #endif
374 case IdVstSetTempo:
375 setBPM( _m.getInt() );
376 break;
378 case IdVstSetLanguage:
379 hlang = static_cast<VstHostLanguages>( _m.getInt() );
380 break;
382 case IdVstGetParameterDump:
383 getParameterDump();
384 break;
386 case IdVstSetParameterDump:
387 setParameterDump( _m );
388 break;
390 case IdVstGetParameterProperties:
391 getParameterProperties( _m.getInt() );
392 break;
394 case IdSaveSettingsToFile:
395 saveChunkToFile( _m.getString() );
396 sendMessage( IdSaveSettingsToFile );
397 break;
399 case IdLoadSettingsFromFile:
400 loadChunkFromFile( _m.getString( 0 ), _m.getInt( 1 ) );
401 sendMessage( IdLoadSettingsFromFile );
402 break;
404 case IdLoadChunkFromPresetFile:
405 loadChunkFromPresetFile( _m.getString( 0 ) );
406 sendMessage( IdLoadChunkFromPresetFile );
407 break;
409 case IdRotateProgram:
410 rotateProgram( _m.getInt( 0 ) );
411 sendMessage( IdRotateProgram );
412 break;
414 case IdLoadPrograms:
415 loadPrograms( _m.getInt( 0 ) );
416 sendMessage( IdLoadPrograms );
417 break;
419 case IdSavePreset:
420 savePreset( _m.getString( 0 ) );
421 sendMessage( IdSavePreset );
422 break;
424 case IdSetParameter:
425 m_plugin->setParameter( m_plugin, _m.getInt( 0 ), _m.getFloat( 1 ) );
426 sendMessage( IdSetParameter );
427 break;
431 default:
432 return RemotePluginClient::processMessage( _m );
434 return true;
440 void RemoteVstPlugin::init( const std::string & _plugin_file )
442 if( load( _plugin_file ) == false )
444 sendMessage( IdVstFailedLoadingPlugin );
445 return;
448 updateInOutCount();
450 /* set program to zero */
451 /* i comment this out because it breaks dfx Geometer
452 * looks like we cant set programs for it
454 pluginDispatch( effSetProgram, 0, 0 ); */
455 // request rate and blocksize
457 pluginDispatch( effMainsChanged, 0, 1 );
459 debugMessage( "creating editor\n" );
460 initEditor();
461 debugMessage( "editor successfully created\n" );
464 // now post some information about our plugin
465 sendMessage( message( IdVstPluginWindowID ).addInt( m_windowID ) );
467 sendMessage( message( IdVstPluginEditorGeometry ).
468 addInt( m_windowWidth ).
469 addInt( m_windowHeight ) );
471 sendMessage( message( IdVstPluginName ).addString( pluginName() ) );
472 sendMessage( message( IdVstPluginVersion ).addInt( pluginVersion() ) );
473 sendMessage( message( IdVstPluginVendorString ).
474 addString( pluginVendorString() ) );
475 sendMessage( message( IdVstPluginProductString ).
476 addString( pluginProductString() ) );
477 sendMessage( message( IdVstParameterCount ).
478 addInt( m_plugin->numParams ) );
480 sendMessage( IdInitDone );
482 m_initialized = true;
488 void RemoteVstPlugin::initEditor()
490 if( !( m_plugin->flags & effFlagsHasEditor ) )
492 return;
496 HMODULE hInst = GetModuleHandle( NULL );
497 if( hInst == NULL )
499 debugMessage( "initEditor(): can't get module handle\n" );
500 return;
504 WNDCLASS wc;
505 wc.style = CS_HREDRAW | CS_VREDRAW;
506 wc.lpfnWndProc = DefWindowProc;
507 wc.cbClsExtra = 0;
508 wc.cbWndExtra = 0;
509 wc.hInstance = hInst;
510 wc.hIcon = LoadIcon( NULL, IDI_APPLICATION );
511 wc.hCursor = LoadCursor( NULL, IDC_ARROW );
512 wc.hbrBackground = (HBRUSH) GetStockObject( BLACK_BRUSH );
513 wc.lpszMenuName = NULL;
514 wc.lpszClassName = "LVSL";
516 if( !RegisterClass( &wc ) )
518 return;
521 #ifdef LMMS_BUILD_LINUX
522 m_window = CreateWindowEx( 0, "LVSL", m_shortName.c_str(),
523 ( WS_OVERLAPPEDWINDOW | WS_THICKFRAME ) & ~WS_MAXIMIZEBOX,
524 0, 0, 10, 10, NULL, NULL, hInst, NULL );
526 #else
527 m_windowID = 1; // arbitrary value on win32 to signal
528 // vstPlugin-class that we have an editor
530 m_window = CreateWindowEx( 0, "LVSL", m_shortName.c_str(),
531 WS_CHILD, 0, 0, 10, 10,
532 m_window, NULL, hInst, NULL );
533 #endif
534 if( m_window == NULL )
536 debugMessage( "initEditor(): cannot create editor window\n" );
537 return;
541 pluginDispatch( effEditOpen, 0, 0, m_window );
543 ERect * er;
544 pluginDispatch( effEditGetRect, 0, 0, &er );
546 m_windowWidth = er->right - er->left;
547 m_windowHeight = er->bottom - er->top;
549 SetWindowPos( m_window, 0, 0, 0, m_windowWidth + 8,
550 m_windowHeight + 26, SWP_NOACTIVATE |
551 SWP_NOMOVE | SWP_NOZORDER );
552 pluginDispatch( effEditTop );
554 ShowWindow( m_window, SW_SHOWNORMAL );
555 UpdateWindow( m_window );
557 #ifdef LMMS_BUILD_LINUX
558 m_windowID = (Sint32) GetProp( m_window, "__wine_x11_whole_window" );
559 #endif
565 bool RemoteVstPlugin::load( const std::string & _plugin_file )
567 if( ( m_libInst = LoadLibrary( _plugin_file.c_str() ) ) == NULL )
569 // give VstPlugin class a chance to start 32 bit version of RemoteVstPlugin
570 if( GetLastError() == ERROR_BAD_EXE_FORMAT )
572 sendMessage( IdVstBadDllFormat );
574 return false;
577 char * tmp = strdup( _plugin_file.c_str() );
578 m_shortName = basename( tmp );
579 free( tmp );
581 typedef AEffect * ( __stdcall * mainEntryPointer )
582 ( audioMasterCallback );
583 mainEntryPointer mainEntry = (mainEntryPointer)
584 GetProcAddress( m_libInst, "VSTPluginMain" );
585 if( mainEntry == NULL )
587 mainEntry = (mainEntryPointer)
588 GetProcAddress( m_libInst, "VstPluginMain" );
590 if( mainEntry == NULL )
592 mainEntry = (mainEntryPointer)
593 GetProcAddress( m_libInst, "main" );
595 if( mainEntry == NULL )
597 debugMessage( "could not find entry point\n" );
598 return false;
601 m_plugin = mainEntry( hostCallback );
602 if( m_plugin == NULL )
604 debugMessage( "mainEntry prodecure returned NULL\n" );
605 return false;
608 m_plugin->user = this;
610 if( m_plugin->magic != kEffectMagic )
612 char buf[256];
613 sprintf( buf, "%s is not a VST plugin\n",
614 _plugin_file.c_str() );
615 debugMessage( buf );
616 return false;
620 char id[5];
621 sprintf( id, "%c%c%c%c", ((char *)&m_plugin->uniqueID)[3],
622 ((char *)&m_plugin->uniqueID)[2],
623 ((char *)&m_plugin->uniqueID)[1],
624 ((char *)&m_plugin->uniqueID)[0] );
625 id[4] = 0;
626 sendMessage( message( IdVstPluginUniqueID ).addString( id ) );
628 pluginDispatch( effOpen );
630 return true;
636 void RemoteVstPlugin::process( const sampleFrame * _in, sampleFrame * _out )
638 // first we gonna post all MIDI-events we enqueued so far
639 if( m_midiEvents.size() )
641 // since MIDI-events are not received immediately, we
642 // have to have them stored somewhere even after
643 // dispatcher-call, so we create static copies of the
644 // data and post them
645 #define MIDI_EVENT_BUFFER_COUNT 1024
646 static char event_buf[sizeof( VstMidiEvent * ) *
647 MIDI_EVENT_BUFFER_COUNT +
648 sizeof( VstEvents )];
649 static VstMidiEvent vme[MIDI_EVENT_BUFFER_COUNT];
650 VstEvents * events = (VstEvents *) event_buf;
651 events->reserved = 0;
652 events->numEvents = m_midiEvents.size();
653 int idx = 0;
654 for( VstMidiEventList::iterator it = m_midiEvents.begin();
655 it != m_midiEvents.end(); ++it, ++idx )
657 memcpy( &vme[idx], &*it, sizeof( VstMidiEvent ) );
658 events->events[idx] = (VstEvent *) &vme[idx];
661 m_midiEvents.clear();
662 pluginDispatch( effProcessEvents, 0, 0, events );
665 // now we're ready to fetch sound from VST-plugin
667 for( int i = 0; i < inputCount(); ++i )
669 m_inputs[i] = &((float *) _in)[i * bufferSize()];
672 for( int i = 0; i < outputCount(); ++i )
674 m_outputs[i] = &((float *) _out)[i * bufferSize()];
675 memset( m_outputs[i], 0, bufferSize() * sizeof( float ) );
678 #ifdef OLD_VST_SDK
679 if( m_plugin->flags & effFlagsCanReplacing )
681 #endif
682 m_plugin->processReplacing( m_plugin, m_inputs, m_outputs,
683 bufferSize() );
684 #ifdef OLD_VST_SDK
686 else
688 m_plugin->process( m_plugin, m_inputs, m_outputs,
689 bufferSize() );
691 #endif
693 m_currentSamplePos += bufferSize();
700 void RemoteVstPlugin::processMidiEvent( const midiEvent & _event,
701 const f_cnt_t _offset )
703 VstMidiEvent event;
705 event.type = kVstMidiType;
706 event.byteSize = 24;
707 event.deltaFrames = _offset;
708 event.flags = 0;
709 event.detune = 0;
710 event.noteLength = 0;
711 event.noteOffset = 0;
712 event.noteOffVelocity = 0;
713 event.reserved1 = 0;
714 event.reserved2 = 0;
715 event.midiData[0] = _event.m_type + _event.m_channel;
716 switch( _event.m_type )
718 case MidiPitchBend:
719 event.midiData[1] = _event.m_data.m_param[0] & 0x7f;
720 event.midiData[2] = _event.m_data.m_param[0] >> 7;
721 break;
722 // TODO: handle more special cases
723 default:
724 event.midiData[1] = _event.key();
725 event.midiData[2] = _event.velocity();
726 break;
728 event.midiData[3] = 0;
729 m_midiEvents.push_back( event );
735 const char * RemoteVstPlugin::pluginName()
737 static char buf[32];
738 buf[0] = 0;
739 pluginDispatch( effGetEffectName, 0, 0, buf );
740 buf[31] = 0;
741 return buf;
747 const char * RemoteVstPlugin::pluginVendorString()
749 static char buf[64];
750 buf[0] = 0;
751 pluginDispatch( effGetVendorString, 0, 0, buf );
752 buf[63] = 0;
753 return buf;
759 const char * RemoteVstPlugin::pluginProductString()
761 static char buf[64];
762 buf[0] = 0;
763 pluginDispatch( effGetProductString, 0, 0, buf );
764 buf[63] = 0;
765 return buf;
771 const char * RemoteVstPlugin::presetName()
773 static char buf[32];
774 buf[0] = 0;
776 m_plugin->dispatcher(m_plugin, effGetProgramName, 0, 0, buf, 0);
778 buf[31] = 0;
779 return buf;
784 void RemoteVstPlugin::getParameterDump()
786 char curPresName[30];
787 //VstParameterProperties vst_props;
788 message m( IdVstParameterDump );
789 m.addInt( m_plugin->numParams );
790 for( int i = 0; i < m_plugin->numParams; ++i )
792 //pluginDispatch( effGetParameterProperties, i, 0, &vst_props );
793 m_plugin->dispatcher(m_plugin, effGetParamName, i, 0, curPresName, 0);
794 m.addInt( i );
795 m.addString( /*vst_props.shortLabel*/curPresName );
796 m.addFloat( m_plugin->getParameter( m_plugin, i ) );
798 sendMessage( m );
804 void RemoteVstPlugin::setParameterDump( const message & _m )
806 const int n = _m.getInt( 0 );
807 const int params = ( n > m_plugin->numParams ) ?
808 m_plugin->numParams : n;
809 int p = 0;
810 for( int i = 0; i < params; ++i )
812 VstParameterDumpItem item;
813 item.index = _m.getInt( ++p );
814 item.shortLabel = _m.getString( ++p );
815 item.value = _m.getFloat( ++p );
816 m_plugin->setParameter( m_plugin, item.index, item.value );
823 void RemoteVstPlugin::getParameterProperties( const int _idx )
825 VstParameterProperties p;
826 pluginDispatch( effGetParameterProperties, _idx, 0, &p );
827 message m( IdVstParameterProperties );
828 m.addString( p.label );
829 m.addString( p.shortLabel );
830 m.addString(
831 #if kVstVersion > 2
832 p.categoryLabel
833 #else
835 #endif
837 m.addFloat( p.minInteger );
838 m.addFloat( p.maxInteger );
839 m.addFloat( ( p.flags & kVstParameterUsesFloatStep ) ?
840 p.stepFloat : p.stepInteger );
841 m.addInt(
842 #if kVstVersion > 2
843 p.category
844 #else
846 #endif
848 sendMessage( m );
854 void RemoteVstPlugin::saveChunkToFile( const std::string & _file )
856 if( m_plugin->flags & 32 )
858 void * chunk = NULL;
859 const int len = pluginDispatch( 23, 0, 0, &chunk );
860 if( len > 0 )
862 int fd = open( _file.c_str(), O_WRONLY | O_BINARY );
863 write( fd, chunk, len );
864 close( fd );
872 void RemoteVstPlugin::rotateProgram( int _len )
874 int currProgram;
875 if (isInitialized() == false) return;
876 if (_len <= 1) {
877 currProgram = m_plugin->dispatcher(m_plugin, effGetProgram, 0, 0, 0, 0) + _len;
878 if (currProgram >= m_plugin->numPrograms) currProgram = m_plugin->numPrograms - 1;
879 if (currProgram < 0) currProgram = 0;
880 m_plugin->dispatcher(m_plugin, effSetProgram, 0, currProgram++, 0, 0);
881 } else {
882 m_plugin->dispatcher(m_plugin, effSetProgram, 0, _len - 2, 0, 0);
883 currProgram = _len - 1;
886 char presName[64];
887 sprintf( presName, " %d/%d: %s", currProgram, m_plugin->numPrograms, presetName() );
889 sendMessage( message( IdVstPluginPresetString ).addString( presName ) );
895 void RemoteVstPlugin::loadPrograms( int _len )
897 char presName[4096];
898 char curProgName[30];
899 if (isInitialized() == false) return;
900 bool progNameIndexed = (m_plugin->dispatcher(m_plugin, 29, 0, -1, curProgName, 0) == 1);
902 if (m_plugin->numPrograms > 1) {
903 if (progNameIndexed) {
904 for (int i = 0; i< (m_plugin->numPrograms >= 256?256:m_plugin->numPrograms); i++) {
905 m_plugin->dispatcher(m_plugin, 29, i, -1, curProgName, 0);
906 if (i == 0) sprintf( presName, "%s", curProgName );
907 else sprintf( presName + strlen(presName), "|%s", curProgName );
909 } else {
910 int currProgram = m_plugin->dispatcher(m_plugin, effGetProgram, 0, 0, 0, 0);
911 for (int i = 0; i< (m_plugin->numPrograms >= 256?256:m_plugin->numPrograms); i++) {
912 m_plugin->dispatcher(m_plugin, effSetProgram, 0, i, 0, 0);
913 if (i == 0) sprintf( presName, "%s", presetName() );
914 else sprintf( presName + strlen(presName), "|%s", presetName() );
916 m_plugin->dispatcher(m_plugin, effSetProgram, 0, currProgram, 0, 0);
918 } else sprintf( presName, "%s", presetName() );
920 sendMessage( message( IdVstPluginPresetsString ).addString( presName ) );
926 inline unsigned int endian_swap(unsigned int& x)
928 return (x>>24) | ((x<<8) & 0x00FF0000) | ((x>>8) & 0x0000FF00) | (x<<24);
931 struct sBank
933 unsigned int chunkMagic;
934 unsigned int byteSize;
935 unsigned int fxMagic;
936 unsigned int version;
937 unsigned int fxID;
938 unsigned int fxVersion;
939 unsigned int numPrograms;
940 char prgName[28];
943 void RemoteVstPlugin::savePreset( const std::string & _file )
945 unsigned int chunk_size = 0;
946 sBank * pBank = ( sBank* ) new char[ sizeof( sBank ) ];
947 char progName[ 128 ] = { 0 };
948 char* data = NULL;
949 const bool chunky = ( m_plugin->flags & ( 1 << 5 ) ) != 0;
950 bool isPreset = _file.substr( _file.find_last_of( "." ) + 1 ) == "fxp";
951 int presNameLen = _file.find_last_of( "/" ) + _file.find_last_of( "\\" ) + 2;
953 if (isPreset) {
954 for (int i = 0; i < _file.length() - 4 - presNameLen; i++)
955 progName[i] = i < 23 ? _file[presNameLen + i] : 0;
956 m_plugin->dispatcher(m_plugin, 4, 0, 0, progName, 0);
957 } // m_plugin->dispatcher( m_plugin, effGetProgramName, 0, 0, progName, 0.0f );
958 if ( chunky )
959 chunk_size = m_plugin->dispatcher( m_plugin, 23, isPreset, 0, &data, false );
960 else {
961 if (isPreset) {
962 chunk_size = m_plugin->numParams * sizeof( float );
963 data = new char[ chunk_size ];
964 unsigned int* toUIntArray = reinterpret_cast<unsigned int*>( data );
965 for ( int i = 0; i < m_plugin->numParams; i++ )
967 float value = m_plugin->getParameter( m_plugin, i );
968 unsigned int * pValue = ( unsigned int * ) &value;
969 toUIntArray[ i ] = endian_swap( *pValue );
971 } else chunk_size = (((m_plugin->numParams * sizeof( float )) + 56)*m_plugin->numPrograms);
974 pBank->chunkMagic = 0x4B6E6343;
975 pBank->byteSize = chunk_size + ( chunky ? sizeof( int ) : 0 ) + 48;
976 if (!isPreset) pBank->byteSize += 100;
977 pBank->byteSize = endian_swap( pBank->byteSize );
978 pBank->fxMagic = chunky ? 0x68435046 : 0x6B437846;
979 if (!isPreset && chunky) pBank->fxMagic = 0x68434246;
980 if (!isPreset &&!chunky) pBank->fxMagic = 0x6B427846;
982 pBank->version = 0x01000000;
983 unsigned int uIntToFile = (unsigned int) m_plugin->uniqueID;
984 pBank->fxID = endian_swap( uIntToFile );
985 uIntToFile = (unsigned int) pluginVersion();
986 pBank->fxVersion = endian_swap( uIntToFile );
987 uIntToFile = (unsigned int) chunky ? m_plugin->numPrograms : m_plugin->numParams;
988 if (!isPreset &&!chunky) uIntToFile = (unsigned int) m_plugin->numPrograms;
989 pBank->numPrograms = endian_swap( uIntToFile );
991 FILE * stream = fopen( _file.c_str(), "w" );
992 fwrite ( pBank, 1, 28, stream );
993 fwrite ( progName, 1, isPreset ? 28 : 128, stream );
994 if ( chunky ) {
995 uIntToFile = endian_swap( chunk_size );
996 fwrite ( &uIntToFile, 1, 4, stream );
998 if (pBank->fxMagic != 0x6B427846 )
999 fwrite ( data, 1, chunk_size, stream );
1000 else {
1001 int numPrograms = m_plugin->numPrograms;
1002 int currProgram = m_plugin->dispatcher(m_plugin, effGetProgram, 0, 0, 0, 0);
1003 chunk_size = (m_plugin->numParams * sizeof( float ));
1004 pBank->byteSize = chunk_size + 48;
1005 pBank->byteSize = endian_swap( pBank->byteSize );
1006 pBank->fxMagic = 0x6B437846;
1007 uIntToFile = (unsigned int) m_plugin->numParams;
1008 pBank->numPrograms = endian_swap( uIntToFile );
1009 data = new char[ chunk_size ];
1010 unsigned int* pValue,* toUIntArray = reinterpret_cast<unsigned int*>( data );
1011 float value;
1012 for (int j = 0; j < numPrograms; j++) {
1013 m_plugin->dispatcher(m_plugin, effSetProgram, 0, j, 0, 0);
1014 m_plugin->dispatcher(m_plugin, effGetProgramName, 0, 0, pBank->prgName, 0);
1015 fwrite ( pBank, 1, 56, stream );
1016 for ( int i = 0; i < m_plugin->numParams; i++ )
1018 value = m_plugin->getParameter( m_plugin, i );
1019 pValue = ( unsigned int * ) &value;
1020 toUIntArray[ i ] = endian_swap( *pValue );
1022 fwrite ( data, 1, chunk_size, stream );
1024 m_plugin->dispatcher(m_plugin, effSetProgram, 0, currProgram, 0, 0);
1026 fclose( stream );
1028 if ( !chunky )
1029 delete[] data;
1030 delete[] (sBank*)pBank;
1037 void RemoteVstPlugin::loadChunkFromPresetFile( const std::string & _file )
1039 void * chunk = NULL;
1040 unsigned int * pLen = new unsigned int[ 1 ];
1041 unsigned int len;
1042 sBank * pBank = (sBank*) new char[ sizeof( sBank ) ];
1043 FILE * stream = fopen( _file.c_str(), "r" );
1044 fread ( pBank, 1, 56, stream );
1045 pBank->fxID = endian_swap( pBank->fxID );
1046 pBank->numPrograms = endian_swap( pBank->numPrograms );
1047 unsigned int toUInt;
1048 float * pFloat;
1050 if (m_plugin->uniqueID != pBank->fxID) {
1051 sendMessage( message( IdVstPluginPresetString ).
1052 addString( "Error: Plugin UniqID not match" ) );
1053 fclose( stream );
1054 delete[] (unsigned int*)pLen;
1055 delete[] (sBank*)pBank;
1056 return;
1059 if( _file.substr( _file.find_last_of( "." ) + 1 ) != "fxp" )
1060 fseek ( stream , 156 , SEEK_SET );
1062 if(pBank->fxMagic != 0x6B427846) {
1063 if(pBank->fxMagic != 0x6B437846) {
1064 fread (pLen, 1, 4, stream);
1065 chunk = new char[len = endian_swap(*pLen)];
1066 } else chunk = new char[len = sizeof(float)*pBank->numPrograms];
1067 fread (chunk, len, 1, stream);
1068 fclose( stream );
1071 if(_file.substr(_file.find_last_of(".") + 1) == "fxp") {
1072 pBank->prgName[23] = 0;
1073 m_plugin->dispatcher(m_plugin, 4, 0, 0, pBank->prgName, 0);
1074 if(pBank->fxMagic != 0x6B437846)
1075 m_plugin->dispatcher(m_plugin, 24, 1, len, chunk, 0);
1076 else {
1077 unsigned int* toUIntArray = reinterpret_cast<unsigned int*>( chunk );
1078 for (int i = 0; i < pBank->numPrograms; i++ ) {
1079 toUInt = endian_swap( toUIntArray[ i ] );
1080 pFloat = ( float* ) &toUInt;
1081 m_plugin->setParameter( m_plugin, i, *pFloat );
1084 } else {
1085 if(pBank->fxMagic != 0x6B427846) {
1086 m_plugin->dispatcher(m_plugin, 24, 0, len, chunk, 0);
1087 } else {
1088 int numPrograms = pBank->numPrograms;
1089 unsigned int * toUIntArray;
1090 int currProgram = m_plugin->dispatcher(m_plugin, effGetProgram, 0, 0, 0, 0);
1091 chunk = new char[ len = sizeof(float)*m_plugin->numParams ];
1092 toUIntArray = reinterpret_cast<unsigned int *>( chunk );
1093 for (int i =0; i < numPrograms; i++) {
1094 fread (pBank, 1, 56, stream);
1095 fread (chunk, len, 1, stream);
1096 m_plugin->dispatcher(m_plugin, effSetProgram, 0, i, 0, 0);
1097 pBank->prgName[23] = 0;
1098 m_plugin->dispatcher(m_plugin, 4, 0, 0, pBank->prgName, 0);
1099 for (int j = 0; j < m_plugin->numParams; j++ ) {
1100 toUInt = endian_swap( toUIntArray[ j ] );
1101 pFloat = ( float* ) &toUInt;
1102 m_plugin->setParameter( m_plugin, j, *pFloat );
1105 m_plugin->dispatcher(m_plugin, effSetProgram, 0, currProgram, 0, 0);
1106 fclose( stream );
1109 char presName[64];
1110 int currProgram = m_plugin->dispatcher(m_plugin, effGetProgram, 0, 0, 0, 0) + 1;
1111 sprintf( presName, " %d/%d: %s", currProgram, m_plugin->numPrograms, presetName() );
1113 sendMessage( message( IdVstPluginPresetString ).addString( presName ) );
1115 delete[] (unsigned int*)pLen;
1116 delete[] (sBank*)pBank;
1117 delete[] (char*)chunk;
1123 void RemoteVstPlugin::loadChunkFromFile( const std::string & _file, int _len )
1125 char * buf = NULL;
1127 void * chunk = NULL;
1128 // various plugins need this in order to not crash when setting
1129 // chunk (also we let the plugin allocate "safe" memory this way)
1130 const int actualLen = pluginDispatch( 23, 0, 0, &chunk );
1132 // allocated buffer big enough?
1133 if( _len > actualLen )
1135 // no, then manually allocate a buffer
1136 buf = new char[_len];
1137 chunk = buf;
1140 const int fd = open( _file.c_str(), O_RDONLY | O_BINARY );
1141 read( fd, chunk, _len );
1142 close( fd );
1143 pluginDispatch( 24, 0, _len, chunk );
1145 delete[] buf;
1151 void RemoteVstPlugin::updateInOutCount()
1153 delete[] m_inputs;
1154 delete[] m_outputs;
1156 m_inputs = NULL;
1157 m_outputs = NULL;
1159 setInputCount( inputCount() );
1160 setOutputCount( outputCount() );
1162 char buf[64];
1163 sprintf( buf, "inputs: %d output: %d\n", inputCount(), outputCount() );
1164 debugMessage( buf );
1166 if( inputCount() > 0 )
1168 m_inputs = new float * [inputCount()];
1171 if( outputCount() > 0 )
1173 m_outputs = new float * [outputCount()];
1179 //#define DEBUG_CALLBACKS
1180 #ifdef DEBUG_CALLBACKS
1181 #define SHOW_CALLBACK __plugin->debugMessage
1182 #else
1183 #define SHOW_CALLBACK(...)
1184 #endif
1187 /* TODO:
1188 * - complete audioMasterGetTime-handling (bars etc.)
1189 * - implement audioMasterProcessEvents
1190 * - audioMasterGetVendorVersion: return LMMS-version (config.h!)
1191 * - audioMasterGetDirectory: return either VST-plugin-dir or LMMS-workingdir
1192 * - audioMasterOpenFileSelector: show QFileDialog?
1194 intptr_t RemoteVstPlugin::hostCallback( AEffect * _effect, int32_t _opcode,
1195 int32_t _index, intptr_t _value,
1196 void * _ptr, float _opt )
1198 static VstTimeInfo _timeInfo;
1199 #ifdef DEBUG_CALLBACKS
1200 char buf[64];
1201 sprintf( buf, "host-callback, opcode = %d\n", (int) _opcode );
1202 SHOW_CALLBACK( buf );
1203 #endif
1205 // workaround for early callbacks by some plugins
1206 if( __plugin && __plugin->m_plugin == NULL )
1208 __plugin->m_plugin = _effect;
1211 switch( _opcode )
1213 case audioMasterAutomate:
1214 SHOW_CALLBACK( "amc: audioMasterAutomate\n" );
1215 // index, value, returns 0
1216 _effect->setParameter( _effect, _index, _opt );
1217 return 0;
1219 case audioMasterVersion:
1220 SHOW_CALLBACK( "amc: audioMasterVersion\n" );
1221 return 2300;
1223 case audioMasterCurrentId:
1224 SHOW_CALLBACK( "amc: audioMasterCurrentId\n" );
1225 // returns the unique id of a plug that's currently
1226 // loading
1227 return 0;
1229 case audioMasterIdle:
1230 SHOW_CALLBACK ("amc: audioMasterIdle\n" );
1231 // call application idle routine (this will
1232 // call effEditIdle for all open editors too)
1233 PostThreadMessage( __GuiThreadID,
1234 WM_USER, GiveIdle, 0 );
1235 return 0;
1237 case audioMasterPinConnected:
1238 SHOW_CALLBACK( "amc: audioMasterPinConnected\n" );
1239 // inquire if an input or output is beeing connected;
1240 // index enumerates input or output counting from zero:
1241 // value is 0 for input and != 0 otherwise. note: the
1242 // return value is 0 for <true> such that older versions
1243 // will always return true.
1244 return 1;
1246 case audioMasterGetTime:
1247 SHOW_CALLBACK( "amc: audioMasterGetTime\n" );
1248 // returns const VstTimeInfo* (or 0 if not supported)
1249 // <value> should contain a mask indicating which
1250 // fields are required (see valid masks above), as some
1251 // items may require extensive conversions
1253 memset( &_timeInfo, 0, sizeof( _timeInfo ) );
1255 _timeInfo.samplePos = __plugin->m_currentSamplePos;
1256 _timeInfo.sampleRate = __plugin->sampleRate();
1257 _timeInfo.flags = 0;
1258 _timeInfo.tempo = __plugin->m_bpm;
1259 _timeInfo.timeSigNumerator = 4;
1260 _timeInfo.timeSigDenominator = 4;
1261 _timeInfo.flags |= (/* kVstBarsValid|*/kVstTempoValid );
1262 _timeInfo.flags |= kVstTransportPlaying;
1263 #ifdef LMMS_BUILD_WIN64
1264 return (long long) &_timeInfo;
1265 #else
1266 return (long) &_timeInfo;
1267 #endif
1269 case audioMasterProcessEvents:
1270 SHOW_CALLBACK( "amc: audioMasterProcessEvents\n" );
1271 // VstEvents* in <ptr>
1272 return 0;
1274 case audioMasterIOChanged:
1275 __plugin->updateInOutCount();
1276 SHOW_CALLBACK( "amc: audioMasterIOChanged\n" );
1277 // numInputs and/or numOutputs has changed
1278 return 0;
1280 #ifdef OLD_VST_SDK
1281 case audioMasterWantMidi:
1282 SHOW_CALLBACK( "amc: audioMasterWantMidi\n" );
1283 // <value> is a filter which is currently ignored
1284 return 1;
1286 case audioMasterSetTime:
1287 SHOW_CALLBACK( "amc: audioMasterSetTime\n" );
1288 // VstTimenfo* in <ptr>, filter in <value>, not
1289 // supported
1290 return 0;
1292 case audioMasterTempoAt:
1293 SHOW_CALLBACK( "amc: audioMasterTempoAt\n" );
1294 return __plugin->m_bpm * 10000;
1296 case audioMasterGetNumAutomatableParameters:
1297 SHOW_CALLBACK( "amc: audioMasterGetNumAutomatable"
1298 "Parameters\n" );
1299 return 5000;
1301 case audioMasterGetParameterQuantization:
1302 SHOW_CALLBACK( "amc: audioMasterGetParameter\n"
1303 "Quantization\n" );
1304 // returns the integer value for +1.0 representation,
1305 // or 1 if full single float precision is maintained
1306 // in automation. parameter index in <value> (-1: all,
1307 // any)
1308 return 1;
1310 case audioMasterNeedIdle:
1311 SHOW_CALLBACK( "amc: audioMasterNeedIdle\n" );
1312 // plug needs idle calls (outside its editor window)
1313 return 1;
1315 case audioMasterGetPreviousPlug:
1316 SHOW_CALLBACK( "amc: audioMasterGetPreviousPlug\n" );
1317 // input pin in <value> (-1: first to come), returns
1318 // cEffect*
1319 return 0;
1321 case audioMasterGetNextPlug:
1322 SHOW_CALLBACK( "amc: audioMasterGetNextPlug\n" );
1323 // output pin in <value> (-1: first to come), returns
1324 // cEffect*
1325 return 0;
1327 case audioMasterWillReplaceOrAccumulate:
1328 SHOW_CALLBACK( "amc: audioMasterWillReplaceOr"
1329 "Accumulate\n" );
1330 // returns: 0: not supported, 1: replace, 2: accumulate
1331 return 1;
1333 case audioMasterGetSpeakerArrangement:
1334 SHOW_CALLBACK( "amc: audioMasterGetSpeaker"
1335 "Arrangement\n" );
1336 // (long)input in <value>, output in <ptr>
1337 return 0;
1339 case audioMasterSetOutputSampleRate:
1340 SHOW_CALLBACK( "amc: audioMasterSetOutputSample"
1341 "Rate\n" );
1342 // for variable i/o, sample rate in <opt>
1343 return 0;
1345 case audioMasterSetIcon:
1346 SHOW_CALLBACK( "amc: audioMasterSetIcon\n" );
1347 // TODO
1348 // void* in <ptr>, format not defined yet
1349 return 0;
1351 case audioMasterOpenWindow:
1352 SHOW_CALLBACK( "amc: audioMasterOpenWindow\n" );
1353 // TODO
1354 // returns platform specific ptr
1355 return 0;
1357 case audioMasterCloseWindow:
1358 SHOW_CALLBACK( "amc: audioMasterCloseWindow\n" );
1359 // TODO
1360 // close window, platform specific handle in <ptr>
1361 return 0;
1362 #endif
1364 case audioMasterSizeWindow:
1365 SHOW_CALLBACK( "amc: audioMasterSizeWindow\n" );
1366 if( __plugin->m_window == 0 )
1368 return 0;
1370 __plugin->m_windowWidth = _index;
1371 __plugin->m_windowHeight = _value;
1372 SetWindowPos( __plugin->m_window, 0, 0, 0,
1373 _index + 8, _value + 26,
1374 SWP_NOACTIVATE | SWP_NOMOVE |
1375 SWP_NOOWNERZORDER | SWP_NOZORDER );
1376 __plugin->sendMessage(
1377 message( IdVstPluginEditorGeometry ).
1378 addInt( __plugin->m_windowWidth ).
1379 addInt( __plugin->m_windowHeight ) );
1380 return 1;
1382 case audioMasterGetSampleRate:
1383 SHOW_CALLBACK( "amc: audioMasterGetSampleRate\n" );
1384 return __plugin->sampleRate();
1386 case audioMasterGetBlockSize:
1387 SHOW_CALLBACK( "amc: audioMasterGetBlockSize\n" );
1389 return __plugin->bufferSize();
1391 case audioMasterGetInputLatency:
1392 SHOW_CALLBACK( "amc: audioMasterGetInputLatency\n" );
1393 return __plugin->bufferSize();
1395 case audioMasterGetOutputLatency:
1396 SHOW_CALLBACK( "amc: audioMasterGetOutputLatency\n" );
1397 return __plugin->bufferSize();
1399 case audioMasterGetCurrentProcessLevel:
1400 SHOW_CALLBACK( "amc: audioMasterGetCurrentProcess"
1401 "Level\n" );
1402 // returns: 0: not supported,
1403 // 1: currently in user thread (gui)
1404 // 2: currently in audio thread (where process is
1405 // called)
1406 // 3: currently in 'sequencer' thread (midi, timer etc)
1407 // 4: currently offline processing and thus in user
1408 // thread
1409 // other: not defined, but probably pre-empting user
1410 // thread.
1411 return 0;
1413 case audioMasterGetAutomationState:
1414 SHOW_CALLBACK( "amc: audioMasterGetAutomationState\n" );
1415 // returns 0: not supported, 1: off, 2:read, 3:write,
1416 // 4:read/write offline
1417 return 0;
1419 case audioMasterOfflineStart:
1420 SHOW_CALLBACK( "amc: audioMasterOfflineStart\n" );
1421 return 0;
1423 case audioMasterOfflineRead:
1424 SHOW_CALLBACK( "amc: audioMasterOfflineRead\n" );
1425 // ptr points to offline structure, see below.
1426 // return 0: error, 1 ok
1427 return 0;
1429 case audioMasterOfflineWrite:
1430 SHOW_CALLBACK( "amc: audioMasterOfflineWrite\n" );
1431 // same as read
1432 return 0;
1434 case audioMasterOfflineGetCurrentPass:
1435 SHOW_CALLBACK( "amc: audioMasterOfflineGetCurrent"
1436 "Pass\n" );
1437 return 0;
1439 case audioMasterOfflineGetCurrentMetaPass:
1440 SHOW_CALLBACK( "amc: audioMasterOfflineGetCurrentMeta"
1441 "Pass\n");
1442 return 0;
1444 case audioMasterGetVendorString:
1445 SHOW_CALLBACK( "amc: audioMasterGetVendorString\n" );
1446 // fills <ptr> with a string identifying the vendor
1447 // (max 64 char)
1448 strcpy( (char *) _ptr, "Tobias Doerffel" );
1449 return 1;
1451 case audioMasterGetProductString:
1452 SHOW_CALLBACK( "amc: audioMasterGetProductString\n" );
1453 // fills <ptr> with a string with product name
1454 // (max 64 char)
1455 strcpy( (char *) _ptr,
1456 "LMMS VST Support Layer (LVSL)" );
1457 return 1;
1459 case audioMasterGetVendorVersion:
1460 SHOW_CALLBACK( "amc: audioMasterGetVendorVersion\n" );
1461 // returns vendor-specific version
1462 return 1000;
1464 case audioMasterVendorSpecific:
1465 SHOW_CALLBACK( "amc: audioMasterVendorSpecific\n" );
1466 // no definition, vendor specific handling
1467 return 0;
1469 case audioMasterCanDo:
1470 SHOW_CALLBACK( "amc: audioMasterCanDo\n" );
1471 return !strcmp( (char *) _ptr, "sendVstEvents" ) ||
1472 !strcmp( (char *) _ptr, "sendVstMidiEvent" ) ||
1473 !strcmp( (char *) _ptr, "sendVstTimeInfo" ) ||
1474 !strcmp( (char *) _ptr, "sizeWindow" ) ||
1475 !strcmp( (char *) _ptr, "supplyIdle" );
1477 case audioMasterGetLanguage:
1478 SHOW_CALLBACK( "amc: audioMasterGetLanguage\n" );
1479 return hlang;
1481 case audioMasterGetDirectory:
1482 SHOW_CALLBACK( "amc: audioMasterGetDirectory\n" );
1483 // get plug directory, FSSpec on MAC, else char*
1484 return 0;
1486 case audioMasterUpdateDisplay:
1487 SHOW_CALLBACK( "amc: audioMasterUpdateDisplay\n" );
1488 // something has changed, update 'multi-fx' display
1489 PostThreadMessage( __GuiThreadID,
1490 WM_USER, GiveIdle, 0 );
1491 return 0;
1493 #if kVstVersion > 2
1494 case audioMasterBeginEdit:
1495 SHOW_CALLBACK( "amc: audioMasterBeginEdit\n" );
1496 // begin of automation session (when mouse down),
1497 // parameter index in <index>
1498 return 0;
1500 case audioMasterEndEdit:
1501 SHOW_CALLBACK( "amc: audioMasterEndEdit\n" );
1502 // end of automation session (when mouse up),
1503 // parameter index in <index>
1504 return 0;
1506 case audioMasterOpenFileSelector:
1507 SHOW_CALLBACK( "amc: audioMasterOpenFileSelector\n" );
1508 // open a fileselector window with VstFileSelect*
1509 // in <ptr>
1510 return 0;
1511 #endif
1512 default:
1513 SHOW_CALLBACK( "amd: not handled" );
1514 break;
1517 return 0;
1523 DWORD WINAPI RemoteVstPlugin::processingThread( LPVOID _param )
1525 RemoteVstPlugin * _this = static_cast<RemoteVstPlugin *>( _param );
1527 RemotePluginClient::message m;
1528 while( ( m = _this->receiveMessage() ).id != IdQuit )
1530 if( m.id == IdStartProcessing || m.id == IdMidiEvent )
1532 _this->processMessage( m );
1534 else
1536 PostThreadMessage( __GuiThreadID,
1537 WM_USER,
1538 ProcessPluginMessage,
1539 (LPARAM) new message( m ) );
1543 // notify GUI thread about shutdown
1544 PostThreadMessage( __GuiThreadID, WM_USER, ClosePlugin, 0 );
1546 return 0;
1552 DWORD WINAPI RemoteVstPlugin::guiEventLoop( LPVOID _param )
1554 RemoteVstPlugin * _this = static_cast<RemoteVstPlugin *>( _param );
1556 HMODULE hInst = GetModuleHandle( NULL );
1557 if( hInst == NULL )
1559 _this->debugMessage( "guiEventLoop(): can't get "
1560 "module handle\n" );
1561 return -1;
1564 HWND timerWindow = CreateWindowEx( 0, "LVSL", "dummy",
1565 0, 0, 0, 0, 0, NULL, NULL,
1566 hInst, NULL );
1567 // install GUI update timer
1568 SetTimer( timerWindow, 1000, 50, NULL );
1570 MSG msg;
1572 bool quit = false;
1573 while( quit == false && GetMessage( &msg, NULL, 0, 0 ) )
1575 TranslateMessage( &msg );
1576 DispatchMessage( &msg );
1578 if( msg.message == WM_TIMER && _this->isInitialized() )
1580 // give plugin some idle-time for GUI-update
1581 _this->pluginDispatch( effEditIdle );
1583 else if( msg.message == WM_USER )
1585 switch( msg.wParam )
1587 case ProcessPluginMessage:
1589 message * m = (message *) msg.lParam;
1590 _this->processMessage( *m );
1591 delete m;
1592 break;
1595 case GiveIdle:
1596 _this->pluginDispatch( effEditIdle );
1597 break;
1599 case ClosePlugin:
1600 quit = true;
1601 break;
1603 default:
1604 break;
1609 return 0;
1615 int main( int _argc, char * * _argv )
1617 if( _argc < 3 )
1619 fprintf( stderr, "not enough arguments\n" );
1620 return -1;
1623 #ifdef LMMS_BUILD_WIN32
1624 // (non-portable) initialization of statically linked pthread library
1625 pthread_win32_process_attach_np();
1626 pthread_win32_thread_attach_np();
1627 #endif
1629 #ifdef LMMS_BUILD_LINUX
1630 #ifdef LMMS_HAVE_SCHED_H
1631 // try to set realtime-priority
1632 struct sched_param sparam;
1633 sparam.sched_priority = ( sched_get_priority_max( SCHED_FIFO ) +
1634 sched_get_priority_min( SCHED_FIFO ) ) / 2;
1635 sched_setscheduler( 0, SCHED_FIFO, &sparam );
1636 #endif
1637 #endif
1639 // constructor automatically will process messages until it receives
1640 // a IdVstLoadPlugin message and processes it
1641 __plugin = new RemoteVstPlugin( atoi( _argv[1] ), atoi( _argv[2] ) );
1643 if( __plugin->isInitialized() )
1645 __GuiThreadID = GetCurrentThreadId();
1646 if( CreateThread( NULL, 0, RemoteVstPlugin::processingThread,
1647 __plugin, 0, NULL ) == NULL )
1649 __plugin->debugMessage( "could not create "
1650 "processingThread\n" );
1651 return -1;
1653 RemoteVstPlugin::guiEventLoop( __plugin );
1657 delete __plugin;
1660 #ifdef LMMS_BUILD_WIN32
1661 pthread_win32_thread_detach_np();
1662 pthread_win32_process_detach_np();
1663 #endif
1665 return 0;