1 /*
2  * RemoteVstPlugin.cpp - LMMS VST Support Layer (RemotePlugin client)
3  *
4  * Copyright (c) 2005-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
5  *
6  * This file is part of LMMS - https://lmms.io
7  *
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
12  *
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.
17  *
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.
22  *
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.
27  *
28  */
29 
30 
31 #include "lmmsconfig.h"
32 
33 #define BUILD_REMOTE_PLUGIN_CLIENT
34 
35 #include "RemotePlugin.h"
36 
37 #ifdef LMMS_HAVE_PTHREAD_H
38 #include <pthread.h>
39 #endif
40 
41 #ifdef LMMS_HAVE_FCNTL_H
42 #include <fcntl.h>
43 #endif
44 
45 #ifdef LMMS_BUILD_LINUX
46 
47 #ifndef NOMINMAX
48 #define NOMINMAX
49 #endif
50 
51 #ifndef O_BINARY
52 #define O_BINARY 0
53 #endif
54 
55 #ifdef LMMS_HAVE_SCHED_H
56 #include <sched.h>
57 #endif
58 
59 #include <wine/exception.h>
60 
61 #endif
62 
63 #define USE_WS_PREFIX
64 #include <windows.h>
65 
66 #include <algorithm>
67 #include <vector>
68 #include <queue>
69 #include <string>
70 #include <iostream>
71 
72 #include <aeffectx.h>
73 
74 #if kVstVersion < 2400
75 
76 #define OLD_VST_SDK
77 
78 struct ERect
79 {
80     short top;
81     short left;
82     short bottom;
83     short right;
84 } ;
85 
86 #endif
87 
88 
89 #include "lmms_basics.h"
90 #include "Midi.h"
91 #include "communication.h"
92 #include "IoHelper.h"
93 
94 #include "VstSyncData.h"
95 
96 #ifdef LMMS_BUILD_WIN32
97 #define USE_QT_SHMEM
98 #endif
99 
100 #ifndef USE_QT_SHMEM
101 #include <stdio.h>
102 #include <stdlib.h>
103 #include <sys/types.h>
104 #include <sys/ipc.h>
105 #include <sys/shm.h>
106 #endif
107 
108 using namespace std;
109 
110 static VstHostLanguages hlang = LanguageEnglish;
111 
112 static bool EMBED = false;
113 static bool EMBED_X11 = false;
114 static bool EMBED_WIN32 = false;
115 static bool HEADLESS = false;
116 
117 class RemoteVstPlugin;
118 
119 RemoteVstPlugin * __plugin = NULL;
120 
121 HWND __MessageHwnd = NULL;
122 DWORD __processingThreadId = 0;
123 
124 
125 
126 class RemoteVstPlugin : public RemotePluginClient
127 {
128 public:
129 #ifdef SYNC_WITH_SHM_FIFO
130 	RemoteVstPlugin( key_t _shm_in, key_t _shm_out );
131 #else
132 	RemoteVstPlugin( const char * socketPath );
133 #endif
134 	virtual ~RemoteVstPlugin();
135 
136 	virtual bool processMessage( const message & _m );
137 
138 	void init( const std::string & _plugin_file );
139 	void initEditor();
140 	void showEditor();
141 	void hideEditor();
142 	void destroyEditor();
143 
144 	virtual void process( const sampleFrame * _in, sampleFrame * _out );
145 
146 
147 	virtual void processMidiEvent( const MidiEvent& event, const f_cnt_t offset );
148 
149 	// set given sample-rate for plugin
updateSampleRate()150 	virtual void updateSampleRate()
151 	{
152 		SuspendPlugin suspend( this );
153 		pluginDispatch( effSetSampleRate, 0, 0,
154 						NULL, (float) sampleRate() );
155 	}
156 
157 	// set given buffer-size for plugin
updateBufferSize()158 	virtual void updateBufferSize()
159 	{
160 		SuspendPlugin suspend( this );
161 		pluginDispatch( effSetBlockSize, 0, bufferSize() );
162 	}
163 
setResumed(bool resumed)164 	void setResumed( bool resumed )
165 	{
166 		m_resumed = resumed;
167 		pluginDispatch( effMainsChanged, 0, resumed ? 1 : 0 );
168 	}
169 
isResumed() const170 	inline bool isResumed() const
171 	{
172 		return m_resumed;
173 	}
174 
isInitialized() const175 	inline bool isInitialized() const
176 	{
177 		return m_initialized;
178 	}
179 
180 
181 	// set given tempo
setBPM(const bpm_t _bpm)182 	void setBPM( const bpm_t _bpm )
183 	{
184 		m_bpm = _bpm;
185 	}
186 
187 	// determine VST-version the plugin uses
pluginVersion()188 	inline int pluginVersion()
189 	{
190 		return pluginDispatch( effGetVendorVersion );
191 	}
192 
193 	// determine name of plugin
194 	const char * pluginName();
195 
196 	// determine vendor of plugin
197 	const char * pluginVendorString();
198 
199 	// determine product-string of plugin
200 	const char * pluginProductString();
201 
202 	// determine name of current program
203 	const char * programName();
204 
205 	// send name of current program back to host
206 	void sendCurrentProgramName();
207 
208 	// do a complete parameter-dump and post it
209 	void getParameterDump();
210 
211 	// read parameter-dump and set it for plugin
212 	void setParameterDump( const message & _m );
213 
214 	// save settings chunk of plugin into file
215 	void saveChunkToFile( const std::string & _file );
216 
217 	// restore settings chunk of plugin from file
218 	void loadChunkFromFile( const std::string & _file, int _len );
219 
220 	// restore settings chunk of plugin from file
221 	void loadPresetFile( const std::string & _file );
222 
223 	// sets given program index
224 	void setProgram( int index );
225 
226 	// rotate current program by given offset
227 	void rotateProgram( int offset );
228 
229 	// Load names of presets/programs
230 	void getProgramNames();
231 
232 	// Save presets/programs
233 	void savePreset( const std::string & _file );
234 
235 	// number of inputs
inputCount() const236 	virtual int inputCount() const
237 	{
238 		if( m_plugin )
239 		{
240 			return m_plugin->numInputs;
241 		}
242 		return 0;
243 	}
244 
245 	// number of outputs
outputCount() const246 	virtual int outputCount() const
247 	{
248 		if( m_plugin )
249 		{
250 			return m_plugin->numOutputs;
251 		}
252 		return 0;
253 	}
254 
255 	// has to be called as soon as input- or output-count changes
256 	int updateInOutCount();
257 
lockShm()258 	inline void lockShm()
259 	{
260 		pthread_mutex_lock( &m_shmLock );
261 	}
262 
tryLockShm()263 	inline bool tryLockShm()
264 	{
265 		return pthread_mutex_trylock( &m_shmLock ) == 0;
266 	}
267 
unlockShm()268 	inline void unlockShm()
269 	{
270 		pthread_mutex_unlock( &m_shmLock );
271 	}
272 
isShmValid()273 	inline bool isShmValid()
274 	{
275 		return m_shmValid;
276 	}
277 
setShmIsValid(bool valid)278 	inline void setShmIsValid( bool valid )
279 	{
280 		m_shmValid = valid;
281 	}
282 
isProcessing() const283 	inline bool isProcessing() const
284 	{
285 		return m_processing;
286 	}
287 
setProcessing(bool processing)288 	inline void setProcessing( bool processing )
289 	{
290 		m_processing = processing;
291 	}
292 
queueMessage(const message & m)293 	inline void queueMessage( const message & m ) {
294 		m_messageList.push( m );
295 	}
296 
shouldGiveIdle() const297 	inline bool shouldGiveIdle() const
298 	{
299 		return m_shouldGiveIdle;
300 	}
301 
setShouldGiveIdle(bool shouldGiveIdle)302 	inline void setShouldGiveIdle( bool shouldGiveIdle )
303 	{
304 		m_shouldGiveIdle = shouldGiveIdle;
305 	}
306 
307 	void idle();
308 	void processUIThreadMessages();
309 
310 	static DWORD WINAPI processingThread( LPVOID _param );
311 	static bool setupMessageWindow();
312 	static DWORD WINAPI guiEventLoop();
313 	static LRESULT CALLBACK wndProc( HWND hwnd, UINT uMsg,
314 					WPARAM wParam, LPARAM lParam );
315 
316 
317 private:
318 	enum GuiThreadMessages
319 	{
320 		None,
321 		ProcessPluginMessage,
322 		GiveIdle,
323 		ClosePlugin
324 	} ;
325 
326 	struct SuspendPlugin {
SuspendPluginRemoteVstPlugin::SuspendPlugin327 		SuspendPlugin( RemoteVstPlugin * plugin ) :
328 			m_plugin( plugin ),
329 			m_resumed( plugin->isResumed() )
330 		{
331 			if( m_resumed ) { m_plugin->setResumed( false ); }
332 		}
333 
~SuspendPluginRemoteVstPlugin::SuspendPlugin334 		~SuspendPlugin()
335 		{
336 			if( m_resumed ) { m_plugin->setResumed( true ); }
337 		}
338 
339 	private:
340 		RemoteVstPlugin * m_plugin;
341 		bool m_resumed;
342 	};
343 
344 	// callback used by plugin for being able to communicate with it's host
345 	static intptr_t hostCallback( AEffect * _effect, int32_t _opcode,
346 					int32_t _index, intptr_t _value,
347 					void * _ptr, float _opt );
348 
349 
350 	bool load( const std::string & _plugin_file );
351 
pluginDispatch(int cmd,int param1=0,int param2=0,void * p=NULL,float f=0)352 	int pluginDispatch( int cmd, int param1 = 0, int param2 = 0,
353 					void * p = NULL, float f = 0 )
354 	{
355 		if( m_plugin )
356 		{
357 			return m_plugin->dispatcher( m_plugin, cmd, param1, param2, p, f );
358 		}
359 		return 0;
360 	}
361 
362 
363 	std::string m_shortName;
364 
365 	HINSTANCE m_libInst;
366 
367 	AEffect * m_plugin;
368 	HWND m_window;
369 	intptr_t m_windowID;
370 	int m_windowWidth;
371 	int m_windowHeight;
372 
373 	bool m_initialized;
374 	bool m_resumed;
375 
376 	bool m_processing;
377 
378 	std::queue<message> m_messageList;
379 	bool m_shouldGiveIdle;
380 
381 
382 	float * * m_inputs;
383 	float * * m_outputs;
384 
385 	pthread_mutex_t m_shmLock;
386 	bool m_shmValid;
387 
388 	typedef std::vector<VstMidiEvent> VstMidiEventList;
389 	VstMidiEventList m_midiEvents;
390 
391 	bpm_t m_bpm;
392 	double m_currentSamplePos;
393 	int m_currentProgram;
394 
395 	// host to plugin synchronisation data structure
396 	struct in
397 	{
398 		double lastppqPos;
399 		double m_Timestamp;
400 		int32_t m_lastFlags;
401 	} ;
402 
403 	in * m_in;
404 
405 	int m_shmID;
406 	VstSyncData* m_vstSyncData;
407 
408 } ;
409 
410 
411 
412 
413 #ifdef SYNC_WITH_SHM_FIFO
RemoteVstPlugin(key_t _shm_in,key_t _shm_out)414 RemoteVstPlugin::RemoteVstPlugin( key_t _shm_in, key_t _shm_out ) :
415 	RemotePluginClient( _shm_in, _shm_out ),
416 #else
417 RemoteVstPlugin::RemoteVstPlugin( const char * socketPath ) :
418 	RemotePluginClient( socketPath ),
419 #endif
420 	m_libInst( NULL ),
421 	m_plugin( NULL ),
422 	m_window( NULL ),
423 	m_windowID( 0 ),
424 	m_windowWidth( 0 ),
425 	m_windowHeight( 0 ),
426 	m_initialized( false ),
427 	m_resumed( false ),
428 	m_processing( false ),
429 	m_messageList(),
430 	m_shouldGiveIdle( false ),
431 	m_inputs( NULL ),
432 	m_outputs( NULL ),
433 	m_shmLock(),
434 	m_shmValid( false ),
435 	m_midiEvents(),
436 	m_bpm( 0 ),
437 	m_currentSamplePos( 0 ),
438 	m_currentProgram( -1 ),
439 	m_in( NULL ),
440 	m_shmID( -1 ),
441 	m_vstSyncData( NULL )
442 {
443 	pthread_mutex_init( &m_shmLock, NULL );
444 
445 	__plugin = this;
446 
447 #ifndef USE_QT_SHMEM
448 	key_t key;
449 	if( ( key = ftok( VST_SNC_SHM_KEY_FILE, 'R' ) ) == -1 )
450 	{
451 		perror( "RemoteVstPlugin.cpp::ftok" );
452 	}
453 	else
454 	{	// connect to shared memory segment
455 		if( ( m_shmID = shmget( key, 0, 0 ) ) == -1 )
456 		{
457 			perror( "RemoteVstPlugin.cpp::shmget" );
458 		}
459 		else
460 		{	// attach segment
461 			m_vstSyncData = (VstSyncData *)shmat(m_shmID, 0, 0);
462 			if( m_vstSyncData == (VstSyncData *)( -1 ) )
463 			{
464 				perror( "RemoteVstPlugin.cpp::shmat" );
465 			}
466 		}
467 	}
468 #else
469 	m_vstSyncData = RemotePluginClient::getQtVSTshm();
470 #endif
471 	if( m_vstSyncData == NULL )
472 	{
473 		fprintf(stderr, "RemoteVstPlugin.cpp: "
474 			"Failed to initialize shared memory for VST synchronization.\n"
475 			" (VST-host synchronization will be disabled)\n");
476 		m_vstSyncData = (VstSyncData*) malloc( sizeof( VstSyncData ) );
477 		m_vstSyncData->isPlaying = true;
478 		m_vstSyncData->timeSigNumer = 4;
479 		m_vstSyncData->timeSigDenom = 4;
480 		m_vstSyncData->ppqPos = 0;
481 		m_vstSyncData->isCycle = false;
482 		m_vstSyncData->hasSHM = false;
483 		m_vstSyncData->m_playbackJumped = false;
484 		m_vstSyncData->m_sampleRate = sampleRate();
485 	}
486 
487 	m_in = ( in* ) new char[ sizeof( in ) ];
488 	m_in->lastppqPos = 0;
489 	m_in->m_Timestamp = -1;
490 	m_in->m_lastFlags = 0;
491 
492 	// process until we have loaded the plugin
493 	while( 1 )
494 	{
495 		message m = receiveMessage();
496 		processMessage( m );
497 		if( m.id == IdVstLoadPlugin || m.id == IdQuit )
498 		{
499 			break;
500 		}
501 	}
502 }
503 
504 
505 
506 
~RemoteVstPlugin()507 RemoteVstPlugin::~RemoteVstPlugin()
508 {
509 	destroyEditor();
510 	setResumed( false );
511 	pluginDispatch( effClose );
512 #ifndef USE_QT_SHMEM
513 	// detach shared memory segment
514 	if( shmdt( m_vstSyncData ) == -1)
515 	{
516 		if( __plugin->m_vstSyncData->hasSHM )
517 		{
518 			perror( "~RemoteVstPlugin::shmdt" );
519 		}
520 		if( m_vstSyncData != NULL )
521 		{
522 			delete m_vstSyncData;
523 			m_vstSyncData = NULL;
524 		}
525 	}
526 #endif
527 
528 	if( m_libInst != NULL )
529 	{
530 		FreeLibrary( m_libInst );
531 		m_libInst = NULL;
532 	}
533 
534 	delete[] m_inputs;
535 	delete[] m_outputs;
536 
537 	pthread_mutex_destroy( &m_shmLock );
538 }
539 
540 
541 
542 
processMessage(const message & _m)543 bool RemoteVstPlugin::processMessage( const message & _m )
544 {
545 	if (! EMBED)
546 	{
547 		switch( _m.id )
548 		{
549 		case IdShowUI:
550 			showEditor();
551 			return true;
552 
553 		case IdHideUI:
554 			hideEditor();
555 			return true;
556 
557 		case IdToggleUI:
558 			if( m_window && IsWindowVisible( m_window ) )
559 			{
560 				hideEditor();
561 			}
562 			else
563 			{
564 				showEditor();
565 			}
566 			return true;
567 
568 		case IdIsUIVisible:
569 			bool visible = m_window && IsWindowVisible( m_window );
570 			sendMessage( message( IdIsUIVisible )
571 						 .addInt( visible ? 1 : 0 ) );
572 			return true;
573 		}
574 	}
575 	else if (EMBED && _m.id == IdShowUI)
576 	{
577 		ShowWindow( m_window, SW_SHOWNORMAL );
578 		UpdateWindow( m_window );
579 		return true;
580 	}
581 
582 	switch( _m.id )
583 	{
584 		case IdVstLoadPlugin:
585 			init( _m.getString() );
586 			break;
587 
588 		case IdVstSetTempo:
589 			setBPM( _m.getInt() );
590 			break;
591 
592 		case IdVstSetLanguage:
593 			hlang = static_cast<VstHostLanguages>( _m.getInt() );
594 			break;
595 
596 		case IdVstGetParameterDump:
597 			getParameterDump();
598 			break;
599 
600 		case IdVstSetParameterDump:
601 			setParameterDump( _m );
602 			break;
603 
604 		case IdSaveSettingsToFile:
605 			saveChunkToFile( _m.getString() );
606 			sendMessage( IdSaveSettingsToFile );
607 			break;
608 
609 		case IdLoadSettingsFromFile:
610 			loadChunkFromFile( _m.getString( 0 ), _m.getInt( 1 ) );
611 			sendMessage( IdLoadSettingsFromFile );
612 			break;
613 
614 		case IdLoadPresetFile:
615 			loadPresetFile( _m.getString( 0 ) );
616 			sendMessage( IdLoadPresetFile );
617 			break;
618 
619 		case IdVstSetProgram:
620 			setProgram( _m.getInt( 0 ) );
621 			sendMessage( IdVstSetProgram );
622 			break;
623 
624 		case IdVstCurrentProgram:
625 			sendMessage( message( IdVstCurrentProgram ).addInt( m_currentProgram ) );
626 			break;
627 
628 		case IdVstRotateProgram:
629 			rotateProgram( _m.getInt( 0 ) );
630 			sendMessage( IdVstRotateProgram );
631 			break;
632 
633 		case IdVstProgramNames:
634 			getProgramNames();
635 			break;
636 
637 		case IdSavePresetFile:
638 			savePreset( _m.getString( 0 ) );
639 			sendMessage( IdSavePresetFile );
640 			break;
641 
642 		case IdVstSetParameter:
643 			m_plugin->setParameter( m_plugin, _m.getInt( 0 ), _m.getFloat( 1 ) );
644 			//sendMessage( IdVstSetParameter );
645 			break;
646 
647 
648 		case IdVstIdleUpdate:
649 		{
650 			int newCurrentProgram = pluginDispatch( effGetProgram );
651 			if( newCurrentProgram != m_currentProgram )
652 			{
653 				m_currentProgram = newCurrentProgram;
654 				sendCurrentProgramName();
655 			}
656 
657 			break;
658 		}
659 
660 		default:
661 			return RemotePluginClient::processMessage( _m );
662 	}
663 	return true;
664 }
665 
666 
667 
668 
init(const std::string & _plugin_file)669 void RemoteVstPlugin::init( const std::string & _plugin_file )
670 {
671 	if( load( _plugin_file ) == false )
672 	{
673 		sendMessage( IdVstFailedLoadingPlugin );
674 		return;
675 	}
676 
677 	updateInOutCount();
678 	updateBufferSize();
679 	updateSampleRate();
680 
681 	/* set program to zero */
682 	/* i comment this out because it breaks dfx Geometer
683 	 * looks like we cant set programs for it
684 	 *
685 	pluginDispatch( effSetProgram, 0, 0 ); */
686 	// request rate and blocksize
687 
688 	setResumed( true );
689 
690 	debugMessage( "creating editor\n" );
691 	initEditor();
692 	debugMessage( "editor successfully created\n" );
693 
694 
695 	// now post some information about our plugin
696 	sendMessage( message( IdVstPluginWindowID ).addInt( m_windowID ) );
697 
698 	sendMessage( message( IdVstPluginEditorGeometry ).
699 						addInt( m_windowWidth ).
700 						addInt( m_windowHeight ) );
701 
702 	sendMessage( message( IdVstPluginName ).addString( pluginName() ) );
703 	sendMessage( message( IdVstPluginVersion ).addInt( pluginVersion() ) );
704 	sendMessage( message( IdVstPluginVendorString ).
705 					addString( pluginVendorString() ) );
706 	sendMessage( message( IdVstPluginProductString ).
707 					addString( pluginProductString() ) );
708 	sendMessage( message( IdVstParameterCount ).
709 					addInt( m_plugin->numParams ) );
710 
711 	sendMessage( IdInitDone );
712 
713 	m_initialized = true;
714 }
715 
716 
717 
718 
close_check(FILE * fp)719 static void close_check( FILE* fp )
720 {
721 	if (!fp) {return;}
722 	if( fclose( fp ) )
723 	{
724 		perror( "close" );
725 	}
726 }
727 
728 
729 
730 
initEditor()731 void RemoteVstPlugin::initEditor()
732 {
733 	if( HEADLESS || m_window || !( m_plugin->flags & effFlagsHasEditor ) )
734 	{
735 		return;
736 	}
737 
738 
739 	HMODULE hInst = GetModuleHandle( NULL );
740 	if( hInst == NULL )
741 	{
742 		debugMessage( "initEditor(): can't get module handle\n" );
743 		return;
744 	}
745 
746 
747 	DWORD dwStyle;
748 	if (EMBED) {
749 		dwStyle = WS_POPUP | WS_SYSMENU | WS_BORDER;
750 	} else {
751 		dwStyle = WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX;
752 	}
753 
754 	m_window = CreateWindowEx( WS_EX_APPWINDOW, "LVSL", pluginName(),
755 		dwStyle,
756 		0, 0, 10, 10, NULL, NULL, hInst, NULL );
757 	if( m_window == NULL )
758 	{
759 		debugMessage( "initEditor(): cannot create editor window\n" );
760 		return;
761 	}
762 
763 
764 	pluginDispatch( effEditOpen, 0, 0, m_window );
765 
766 	ERect * er;
767 	pluginDispatch( effEditGetRect, 0, 0, &er );
768 
769 	m_windowWidth = er->right - er->left;
770 	m_windowHeight = er->bottom - er->top;
771 
772 	RECT windowSize = { 0, 0, m_windowWidth, m_windowHeight };
773 	AdjustWindowRect( &windowSize, dwStyle, false );
774 	SetWindowPos( m_window, 0, 0, 0, windowSize.right - windowSize.left,
775 			windowSize.bottom - windowSize.top, SWP_NOACTIVATE |
776 						SWP_NOMOVE | SWP_NOZORDER );
777 	pluginDispatch( effEditTop );
778 
779 #ifdef LMMS_BUILD_LINUX
780 	m_windowID = (intptr_t) GetProp( m_window, "__wine_x11_whole_window" );
781 #else
782 	// 64-bit versions of Windows use 32-bit handles for interoperability
783 	m_windowID = (intptr_t) m_window;
784 #endif
785 }
786 
787 
788 
789 
showEditor()790 void RemoteVstPlugin::showEditor() {
791 	if( !EMBED && !HEADLESS && m_window )
792 	{
793 		ShowWindow( m_window, SW_SHOWNORMAL );
794 	}
795 }
796 
797 
798 
799 
hideEditor()800 void RemoteVstPlugin::hideEditor() {
801 	if( !EMBED && !HEADLESS && m_window )
802 	{
803 		ShowWindow( m_window, SW_HIDE );
804 	}
805 }
806 
807 
808 
809 
destroyEditor()810 void RemoteVstPlugin::destroyEditor()
811 {
812 	if( m_window == NULL )
813 	{
814 		return;
815 	}
816 
817 	pluginDispatch( effEditClose );
818 	// Destroying the window takes some time in Wine 1.8.5
819 	DestroyWindow( m_window );
820 	m_window = NULL;
821 }
822 
823 
824 
825 
load(const std::string & _plugin_file)826 bool RemoteVstPlugin::load( const std::string & _plugin_file )
827 {
828 	if( ( m_libInst = LoadLibraryW( toWString(_plugin_file).c_str() ) ) == NULL )
829 	{
830 		// give VstPlugin class a chance to start 32 bit version of RemoteVstPlugin
831 		if( GetLastError() == ERROR_BAD_EXE_FORMAT )
832 		{
833 			sendMessage( IdVstBadDllFormat );
834 		}
835 		return false;
836 	}
837 
838 	typedef AEffect * ( __stdcall * mainEntryPointer )
839 						( audioMasterCallback );
840 	mainEntryPointer mainEntry = (mainEntryPointer)
841 				GetProcAddress( m_libInst, "VSTPluginMain" );
842 	if( mainEntry == NULL )
843 	{
844 		mainEntry = (mainEntryPointer)
845 				GetProcAddress( m_libInst, "VstPluginMain" );
846 	}
847 	if( mainEntry == NULL )
848 	{
849 		mainEntry = (mainEntryPointer)
850 				GetProcAddress( m_libInst, "main" );
851 	}
852 	if( mainEntry == NULL )
853 	{
854 		debugMessage( "could not find entry point\n" );
855 		return false;
856 	}
857 
858 	m_plugin = mainEntry( hostCallback );
859 	if( m_plugin == NULL )
860 	{
861 		debugMessage( "mainEntry procedure returned NULL\n" );
862 		return false;
863 	}
864 
865 	if( m_plugin->magic != kEffectMagic )
866 	{
867 		debugMessage( "File is not a VST plugin\n" );
868 		return false;
869 	}
870 
871 
872 	char id[5];
873 	sprintf( id, "%c%c%c%c", ((char *)&m_plugin->uniqueID)[3],
874 					 ((char *)&m_plugin->uniqueID)[2],
875 					 ((char *)&m_plugin->uniqueID)[1],
876 					 ((char *)&m_plugin->uniqueID)[0] );
877 	id[4] = 0;
878 	sendMessage( message( IdVstPluginUniqueID ).addString( id ) );
879 
880 	pluginDispatch( effOpen );
881 
882 	return true;
883 }
884 
885 
886 
887 
process(const sampleFrame * _in,sampleFrame * _out)888 void RemoteVstPlugin::process( const sampleFrame * _in, sampleFrame * _out )
889 {
890 	// first we gonna post all MIDI-events we enqueued so far
891 	if( m_midiEvents.size() )
892 	{
893 		// since MIDI-events are not received immediately, we
894 		// have to have them stored somewhere even after
895 		// dispatcher-call, so we create static copies of the
896 		// data and post them
897 #define MIDI_EVENT_BUFFER_COUNT		1024
898 		static char eventsBuffer[sizeof( VstEvents ) + sizeof( VstMidiEvent * ) * MIDI_EVENT_BUFFER_COUNT];
899 		static VstMidiEvent vme[MIDI_EVENT_BUFFER_COUNT];
900 
901 		// first sort events chronologically, since some plugins
902 		// (e.g. Sinnah) can hang if they're out of order
903 		std::stable_sort( m_midiEvents.begin(), m_midiEvents.end(),
904 				[]( const VstMidiEvent &a, const VstMidiEvent &b )
905 				{
906 					return a.deltaFrames < b.deltaFrames;
907 				} );
908 
909 		VstEvents* events = (VstEvents *) eventsBuffer;
910 		events->reserved = 0;
911 		events->numEvents = m_midiEvents.size();
912 
913 		int idx = 0;
914 		for( VstMidiEventList::iterator it = m_midiEvents.begin(); it != m_midiEvents.end(); ++it, ++idx )
915 		{
916 			memcpy( &vme[idx], &*it, sizeof( VstMidiEvent ) );
917 			events->events[idx] = (VstEvent *) &vme[idx];
918 		}
919 
920 		m_midiEvents.clear();
921 		pluginDispatch( effProcessEvents, 0, 0, events );
922 	}
923 
924 	// now we're ready to fetch sound from VST-plugin
925 
926 	if( !tryLockShm() )
927 	{
928 		return;
929 	}
930 
931 	if( !isShmValid() )
932 	{
933 		unlockShm();
934 		return;
935 	}
936 
937 	for( int i = 0; i < inputCount(); ++i )
938 	{
939 		m_inputs[i] = &((float *) _in)[i * bufferSize()];
940 	}
941 
942 	for( int i = 0; i < outputCount(); ++i )
943 	{
944 		m_outputs[i] = &((float *) _out)[i * bufferSize()];
945 		memset( m_outputs[i], 0, bufferSize() * sizeof( float ) );
946 	}
947 
948 #ifdef OLD_VST_SDK
949 	if( m_plugin->flags & effFlagsCanReplacing )
950 	{
951 #endif
952 		m_plugin->processReplacing( m_plugin, m_inputs, m_outputs,
953 								bufferSize() );
954 #ifdef OLD_VST_SDK
955 	}
956 	else
957 	{
958 		m_plugin->process( m_plugin, m_inputs, m_outputs,
959 								bufferSize() );
960 	}
961 #endif
962 
963 	unlockShm();
964 
965 	m_currentSamplePos += bufferSize();
966 }
967 
968 
969 
970 
processMidiEvent(const MidiEvent & event,const f_cnt_t offset)971 void RemoteVstPlugin::processMidiEvent( const MidiEvent& event, const f_cnt_t offset )
972 {
973 	VstMidiEvent vme;
974 
975 	vme.type = kVstMidiType;
976 	vme.byteSize = 24;
977 	vme.deltaFrames = offset;
978 	vme.flags = 0;
979 	vme.detune = 0;
980 	vme.noteLength = 0;
981 	vme.noteOffset = 0;
982 	vme.noteOffVelocity = 0;
983 	vme.reserved1 = 0;
984 	vme.reserved2 = 0;
985 	vme.midiData[0] = event.type() + event.channel();
986 
987 	switch( event.type() )
988 	{
989 		case MidiPitchBend:
990 			vme.midiData[1] = event.pitchBend() & 0x7f;
991 			vme.midiData[2] = event.pitchBend() >> 7;
992 			break;
993 		// TODO: handle more special cases
994 		default:
995 			vme.midiData[1] = event.key();
996 			vme.midiData[2] = event.velocity();
997 			break;
998 	}
999 	vme.midiData[3] = 0;
1000 
1001 	m_midiEvents.push_back( vme );
1002 }
1003 
1004 
1005 
1006 
pluginName()1007 const char * RemoteVstPlugin::pluginName()
1008 {
1009 	static char buf[32];
1010 	buf[0] = 0;
1011 	pluginDispatch( effGetEffectName, 0, 0, buf );
1012 	buf[31] = 0;
1013 	return buf;
1014 }
1015 
1016 
1017 
1018 
pluginVendorString()1019 const char * RemoteVstPlugin::pluginVendorString()
1020 {
1021 	static char buf[64];
1022 	buf[0] = 0;
1023 	pluginDispatch( effGetVendorString, 0, 0, buf );
1024 	buf[63] = 0;
1025 	return buf;
1026 }
1027 
1028 
1029 
1030 
pluginProductString()1031 const char * RemoteVstPlugin::pluginProductString()
1032 {
1033 	static char buf[64];
1034 	buf[0] = 0;
1035 	pluginDispatch( effGetProductString, 0, 0, buf );
1036 	buf[63] = 0;
1037 	return buf;
1038 }
1039 
1040 
1041 
1042 
programName()1043 const char * RemoteVstPlugin::programName()
1044 {
1045 	static char buf[24];
1046 
1047 	memset( buf, 0, sizeof( buf ) );
1048 
1049 	pluginDispatch( effGetProgramName, 0, 0, buf );
1050 
1051 	buf[23] = 0;
1052 
1053 	return buf;
1054 }
1055 
1056 
1057 
sendCurrentProgramName()1058 void RemoteVstPlugin::sendCurrentProgramName()
1059 {
1060 	char presName[64];
1061 	sprintf( presName, "%d/%d: %s", pluginDispatch( effGetProgram ) + 1, m_plugin->numPrograms, programName() );
1062 
1063 	sendMessage( message( IdVstCurrentProgramName ).addString( presName ) );
1064 }
1065 
1066 
1067 
getParameterDump()1068 void RemoteVstPlugin::getParameterDump()
1069 {
1070 	message m( IdVstParameterDump );
1071 	m.addInt( m_plugin->numParams );
1072 
1073 	for( int i = 0; i < m_plugin->numParams; ++i )
1074 	{
1075 		char paramName[256];
1076 		memset( paramName, 0, sizeof( paramName ) );
1077 		pluginDispatch( effGetParamName, i, 0, paramName );
1078 		paramName[sizeof(paramName)-1] = 0;
1079 
1080 		m.addInt( i );
1081 		m.addString( paramName );
1082 		m.addFloat( m_plugin->getParameter( m_plugin, i ) );
1083 	}
1084 
1085 	sendMessage( m );
1086 }
1087 
1088 
1089 
1090 
setParameterDump(const message & _m)1091 void RemoteVstPlugin::setParameterDump( const message & _m )
1092 {
1093 	const int n = _m.getInt( 0 );
1094 	const int params = ( n > m_plugin->numParams ) ?
1095 					m_plugin->numParams : n;
1096 	int p = 0;
1097 	for( int i = 0; i < params; ++i )
1098 	{
1099 		VstParameterDumpItem item;
1100 		item.index = _m.getInt( ++p );
1101 		item.shortLabel = _m.getString( ++p );
1102 		item.value = _m.getFloat( ++p );
1103 		m_plugin->setParameter( m_plugin, item.index, item.value );
1104 	}
1105 }
1106 
1107 
1108 
1109 
saveChunkToFile(const std::string & _file)1110 void RemoteVstPlugin::saveChunkToFile( const std::string & _file )
1111 {
1112 	if( m_plugin->flags & 32 )
1113 	{
1114 		void * chunk = NULL;
1115 		const int len = pluginDispatch( 23, 0, 0, &chunk );
1116 		if( len > 0 )
1117 		{
1118 			FILE* fp = F_OPEN_UTF8( _file, "wb" );
1119 			if (!fp)
1120 			{
1121 				fprintf( stderr,
1122 					"Error opening file for saving chunk.\n" );
1123 				return;
1124 			}
1125 			if ( fwrite( chunk, 1, len, fp ) != len )
1126 			{
1127 				fprintf( stderr,
1128 					"Error saving chunk to file.\n" );
1129 			}
1130 			close_check( fp );
1131 		}
1132 	}
1133 }
1134 
1135 
1136 
1137 
setProgram(int program)1138 void RemoteVstPlugin::setProgram( int program )
1139 {
1140 	if( isInitialized() == false )
1141 	{
1142 		return;
1143 	}
1144 
1145 	if( program < 0 )
1146 	{
1147 		program = 0;
1148 	}
1149 	else if( program >= m_plugin->numPrograms )
1150 	{
1151 		program = m_plugin->numPrograms - 1;
1152 	}
1153 	pluginDispatch( effSetProgram, 0, program );
1154 
1155 	sendCurrentProgramName();
1156 }
1157 
1158 
1159 
1160 
rotateProgram(int offset)1161 void RemoteVstPlugin::rotateProgram( int offset )
1162 {
1163 	if( isInitialized() == false )
1164 	{
1165 		return;
1166 	}
1167 
1168 	int newProgram = pluginDispatch( effGetProgram ) + offset;
1169 
1170 	if( newProgram < 0 )
1171 	{
1172 		newProgram = 0;
1173 	}
1174 	else if( newProgram >= m_plugin->numPrograms )
1175 	{
1176 		newProgram = m_plugin->numPrograms - 1;
1177 	}
1178 	pluginDispatch( effSetProgram, 0, newProgram );
1179 
1180 	sendCurrentProgramName();
1181 }
1182 
1183 
1184 
1185 
getProgramNames()1186 void RemoteVstPlugin::getProgramNames()
1187 {
1188 	char presName[1024+256*30];
1189 	char curProgName[30];
1190 	if (isInitialized() == false) return;
1191 	bool progNameIndexed = ( pluginDispatch( 29, 0, -1, curProgName ) == 1 );
1192 
1193 	if (m_plugin->numPrograms > 1) {
1194 		if (progNameIndexed) {
1195 			for (int i = 0; i< (m_plugin->numPrograms >= 256?256:m_plugin->numPrograms); i++)
1196 			{
1197 				pluginDispatch( 29, i, -1, curProgName );
1198 				if (i == 0) 	sprintf( presName, "%s", curProgName );
1199 				else		sprintf( presName + strlen(presName), "|%s", curProgName );
1200 			}
1201 		}
1202 		else
1203 		{
1204 			int currProgram = pluginDispatch( effGetProgram );
1205 			for (int i = 0; i< (m_plugin->numPrograms >= 256?256:m_plugin->numPrograms); i++)
1206 			{
1207 				pluginDispatch( effSetProgram, 0, i );
1208 				if (i == 0) 	sprintf( presName, "%s", programName() );
1209 				else		sprintf( presName + strlen(presName), "|%s", programName() );
1210 			}
1211 			pluginDispatch( effSetProgram, 0, currProgram );
1212 		}
1213 	} else sprintf( presName, "%s", programName() );
1214 
1215 	presName[sizeof(presName)-1] = 0;
1216 
1217 	sendMessage( message( IdVstProgramNames ).addString( presName ) );
1218 }
1219 
1220 
1221 
1222 
endian_swap(unsigned int & x)1223 inline unsigned int endian_swap(unsigned int& x)
1224 {
1225     return (x>>24) | ((x<<8) & 0x00FF0000) | ((x>>8) & 0x0000FF00) | (x<<24);
1226 }
1227 
1228 struct sBank
1229 {
1230 	unsigned int chunkMagic;
1231 	unsigned int byteSize;
1232 	unsigned int fxMagic;
1233 	unsigned int version;
1234 	unsigned int fxID;
1235 	unsigned int fxVersion;
1236 	unsigned int numPrograms;
1237 	char prgName[28];
1238 };
1239 
savePreset(const std::string & _file)1240 void RemoteVstPlugin::savePreset( const std::string & _file )
1241 {
1242 	unsigned int chunk_size = 0;
1243 	sBank * pBank = ( sBank* ) new char[ sizeof( sBank ) ];
1244 	char progName[ 128 ] = { 0 };
1245 	char* data = NULL;
1246 	const bool chunky = ( m_plugin->flags & ( 1 << 5 ) ) != 0;
1247 	bool isPreset = _file.substr( _file.find_last_of( "." ) + 1 )  == "fxp";
1248 	int presNameLen = _file.find_last_of( "/" ) + _file.find_last_of( "\\" ) + 2;
1249 
1250 	if (isPreset)
1251 	{
1252 		for (size_t i = 0; i < _file.length() - 4 - presNameLen; i++)
1253 			progName[i] = i < 23 ? _file[presNameLen + i] : 0;
1254 		pluginDispatch( 4, 0, 0, progName );
1255 	}
1256 	if ( chunky )
1257 		chunk_size = pluginDispatch( 23, isPreset, 0, &data );
1258 	else {
1259 		if (isPreset) {
1260 			chunk_size = m_plugin->numParams * sizeof( float );
1261 			data = new char[ chunk_size ];
1262 			unsigned int* toUIntArray = reinterpret_cast<unsigned int*>( data );
1263 			for ( int i = 0; i < m_plugin->numParams; i++ )
1264 			{
1265 				float value = m_plugin->getParameter( m_plugin, i );
1266 				unsigned int * pValue = ( unsigned int * ) &value;
1267 				toUIntArray[ i ] = endian_swap( *pValue );
1268 			}
1269 		} else chunk_size = (((m_plugin->numParams * sizeof( float )) + 56)*m_plugin->numPrograms);
1270 	}
1271 
1272 	pBank->chunkMagic = 0x4B6E6343;
1273 	pBank->byteSize = chunk_size + ( chunky ? sizeof( int ) : 0 ) + 48;
1274 	if (!isPreset) pBank->byteSize += 100;
1275 	pBank->byteSize = endian_swap( pBank->byteSize );
1276 	pBank->fxMagic = chunky ? 0x68435046 : 0x6B437846;
1277 	if (!isPreset && chunky) pBank->fxMagic = 0x68434246;
1278 	if (!isPreset &&!chunky) pBank->fxMagic = 0x6B427846;
1279 
1280 	pBank->version = 0x01000000;
1281 	unsigned int uIntToFile = (unsigned int) m_plugin->uniqueID;
1282 	pBank->fxID = endian_swap( uIntToFile );
1283 	uIntToFile = (unsigned int) pluginVersion();
1284 	pBank->fxVersion = endian_swap( uIntToFile );
1285 	uIntToFile = (unsigned int) chunky ? m_plugin->numPrograms : m_plugin->numParams;
1286 	if (!isPreset &&!chunky) uIntToFile = (unsigned int) m_plugin->numPrograms;
1287 	pBank->numPrograms = endian_swap( uIntToFile );
1288 
1289 	FILE * stream = F_OPEN_UTF8( _file, "wb" );
1290 	if (!stream)
1291 	{
1292 		fprintf( stderr,
1293 			"Error opening file for saving preset.\n" );
1294 		return;
1295 	}
1296 	fwrite ( pBank, 1, 28, stream );
1297 	fwrite ( progName, 1, isPreset ? 28 : 128, stream );
1298 	if ( chunky ) {
1299 		uIntToFile = endian_swap( chunk_size );
1300 		fwrite ( &uIntToFile, 1, 4, stream );
1301 	}
1302 	if (pBank->fxMagic != 0x6B427846 )
1303 		fwrite ( data, 1, chunk_size, stream );
1304 	else {
1305 		int numPrograms = m_plugin->numPrograms;
1306 		int currProgram = pluginDispatch( effGetProgram );
1307 		chunk_size = (m_plugin->numParams * sizeof( float ));
1308 		pBank->byteSize = chunk_size + 48;
1309 		pBank->byteSize = endian_swap( pBank->byteSize );
1310 		pBank->fxMagic = 0x6B437846;
1311 		uIntToFile = (unsigned int) m_plugin->numParams;
1312 		pBank->numPrograms = endian_swap( uIntToFile );
1313 		data = new char[ chunk_size ];
1314 		unsigned int* pValue,* toUIntArray = reinterpret_cast<unsigned int*>( data );
1315 		float value;
1316 		for (int j = 0; j < numPrograms; j++) {
1317 			pluginDispatch( effSetProgram, 0, j );
1318 			pluginDispatch( effGetProgramName, 0, 0, pBank->prgName );
1319 			fwrite ( pBank, 1, 56, stream );
1320 			for ( int i = 0; i < m_plugin->numParams; i++ )
1321 			{
1322 				value = m_plugin->getParameter( m_plugin, i );
1323 				pValue = ( unsigned int * ) &value;
1324 				toUIntArray[ i ] = endian_swap( *pValue );
1325 			}
1326 			fwrite ( data, 1, chunk_size, stream );
1327 		}
1328 		pluginDispatch( effSetProgram, 0, currProgram );
1329 	}
1330 	fclose( stream );
1331 
1332 	if ( !chunky )
1333 		delete[] data;
1334 	delete[] (sBank*)pBank;
1335 
1336 }
1337 
1338 
1339 
1340 
loadPresetFile(const std::string & _file)1341 void RemoteVstPlugin::loadPresetFile( const std::string & _file )
1342 {
1343 	void * chunk = NULL;
1344 	unsigned int * pLen = new unsigned int[ 1 ];
1345 	unsigned int len = 0;
1346 	sBank * pBank = (sBank*) new char[ sizeof( sBank ) ];
1347 	FILE * stream = F_OPEN_UTF8( _file, "rb" );
1348 	if (!stream)
1349 	{
1350 		fprintf( stderr,
1351 			"Error opening file for loading preset.\n" );
1352 		return;
1353 	}
1354 	if ( fread ( pBank, 1, 56, stream ) != 56 )
1355 	{
1356 		fprintf( stderr, "Error loading preset file.\n" );
1357 	}
1358         pBank->fxID = endian_swap( pBank->fxID );
1359 	pBank->numPrograms = endian_swap( pBank->numPrograms );
1360 	unsigned int toUInt;
1361 	float * pFloat;
1362 
1363 	if (m_plugin->uniqueID != pBank->fxID) {
1364 		sendMessage( message( IdVstCurrentProgramName ).
1365 					addString( "Error: Plugin UniqID not match" ) );
1366 		fclose( stream );
1367 		delete[] (unsigned int*)pLen;
1368 		delete[] (sBank*)pBank;
1369 		return;
1370 	}
1371 
1372 	if( _file.substr( _file.find_last_of( "." ) + 1 ) != "fxp" )
1373 		fseek ( stream , 156 , SEEK_SET );
1374 
1375 	if(pBank->fxMagic != 0x6B427846) {
1376 		if(pBank->fxMagic != 0x6B437846) {
1377 			if ( fread (pLen, 1, 4, stream) != 4 )
1378 			{
1379 				fprintf( stderr,
1380 					"Error loading preset file.\n" );
1381 			}
1382 			chunk = new char[len = endian_swap(*pLen)];
1383 		} else chunk = new char[len = sizeof(float)*pBank->numPrograms];
1384 		if ( fread (chunk, len, 1, stream) != 1 )
1385 		{
1386 			fprintf( stderr, "Error loading preset file.\n" );
1387 		}
1388 		fclose( stream );
1389 	}
1390 
1391 	if(_file.substr(_file.find_last_of(".") + 1) == "fxp") {
1392 		pBank->prgName[23] = 0;
1393 		pluginDispatch( 4, 0, 0, pBank->prgName );
1394 		if(pBank->fxMagic != 0x6B437846)
1395 			pluginDispatch( 24, 1, len, chunk );
1396 		else
1397 		{
1398 			unsigned int* toUIntArray = reinterpret_cast<unsigned int*>( chunk );
1399 			for (int i = 0; i < pBank->numPrograms; i++ )
1400 			{
1401 				toUInt = endian_swap( toUIntArray[ i ] );
1402 				pFloat = ( float* ) &toUInt;
1403 				m_plugin->setParameter( m_plugin, i, *pFloat );
1404 			}
1405 		}
1406 	} else {
1407 		if(pBank->fxMagic != 0x6B427846) {
1408 			pluginDispatch( 24, 0, len, chunk );
1409 		} else {
1410 			int numPrograms = pBank->numPrograms;
1411 			unsigned int * toUIntArray;
1412 			int currProgram = pluginDispatch( effGetProgram );
1413 			chunk = new char[ len = sizeof(float)*m_plugin->numParams ];
1414 			toUIntArray = reinterpret_cast<unsigned int *>( chunk );
1415 			for (int i =0; i < numPrograms; i++) {
1416 				if ( fread (pBank, 1, 56, stream) != 56 )
1417 				{
1418 					fprintf( stderr,
1419 					"Error loading preset file.\n" );
1420 				}
1421 				if ( fread (chunk, len, 1, stream) != 1 )
1422 				{
1423 					fprintf( stderr,
1424 					"Error loading preset file.\n" );
1425 				}
1426 				pluginDispatch( effSetProgram, 0, i );
1427 				pBank->prgName[23] = 0;
1428 				pluginDispatch( 4, 0, 0, pBank->prgName );
1429 				for (int j = 0; j < m_plugin->numParams; j++ ) {
1430 					toUInt = endian_swap( toUIntArray[ j ] );
1431 					pFloat = ( float* ) &toUInt;
1432 					m_plugin->setParameter( m_plugin, j, *pFloat );
1433 				}
1434 			}
1435 			pluginDispatch( effSetProgram, 0, currProgram );
1436 			fclose( stream );
1437 		}
1438 	}
1439 
1440 	sendCurrentProgramName();
1441 
1442 	delete[] (unsigned int*)pLen;
1443 	delete[] (sBank*)pBank;
1444 	delete[] (char*)chunk;
1445 }
1446 
1447 
1448 
1449 
loadChunkFromFile(const std::string & _file,int _len)1450 void RemoteVstPlugin::loadChunkFromFile( const std::string & _file, int _len )
1451 {
1452 	char * chunk = new char[_len];
1453 
1454 	FILE* fp = F_OPEN_UTF8( _file, "rb" );
1455 	if (!fp)
1456 	{
1457 		fprintf( stderr,
1458 			"Error opening file for loading chunk.\n" );
1459 		return;
1460 	}
1461 	if ( fread( chunk, 1, _len, fp ) != _len )
1462 	{
1463 		fprintf( stderr, "Error loading chunk from file.\n" );
1464 	}
1465 	close_check( fp );
1466 
1467 	pluginDispatch( effSetChunk, 0, _len, chunk );
1468 
1469 	delete[] chunk;
1470 }
1471 
1472 
1473 
1474 
updateInOutCount()1475 int RemoteVstPlugin::updateInOutCount()
1476 {
1477 	if( inputCount() == RemotePluginClient::inputCount() &&
1478 		outputCount() == RemotePluginClient::outputCount() )
1479 	{
1480 		return 1;
1481 	}
1482 
1483 	if( GetCurrentThreadId() == __processingThreadId )
1484 	{
1485 		debugMessage( "Plugin requested I/O change from processing "
1486 			"thread. Request denied; stability may suffer.\n" );
1487 		return 0;
1488 	}
1489 
1490 	lockShm();
1491 
1492 	setShmIsValid( false );
1493 
1494 	unlockShm();
1495 
1496 	delete[] m_inputs;
1497 	delete[] m_outputs;
1498 
1499 	m_inputs = NULL;
1500 	m_outputs = NULL;
1501 
1502 	setInputOutputCount( inputCount(), outputCount() );
1503 
1504 	char buf[64];
1505 	sprintf( buf, "inputs: %d  output: %d\n", inputCount(), outputCount() );
1506 	debugMessage( buf );
1507 
1508 	if( inputCount() > 0 )
1509 	{
1510 		m_inputs = new float * [inputCount()];
1511 	}
1512 
1513 	if( outputCount() > 0 )
1514 	{
1515 		m_outputs = new float * [outputCount()];
1516 	}
1517 
1518 	return 1;
1519 }
1520 
1521 
1522 
1523 //#define DEBUG_CALLBACKS
1524 #ifdef DEBUG_CALLBACKS
1525 #define SHOW_CALLBACK __plugin->debugMessage
1526 #else
1527 #define SHOW_CALLBACK(...)
1528 #endif
1529 
1530 
1531 /* TODO:
1532  * - complete audioMasterGetTime-handling (bars etc.)
1533  * - implement audioMasterProcessEvents
1534  * - audioMasterGetVendorVersion: return LMMS-version (config.h!)
1535  * - audioMasterGetDirectory: return either VST-plugin-dir or LMMS-workingdir
1536  * - audioMasterOpenFileSelector: show QFileDialog?
1537  */
hostCallback(AEffect * _effect,int32_t _opcode,int32_t _index,intptr_t _value,void * _ptr,float _opt)1538 intptr_t RemoteVstPlugin::hostCallback( AEffect * _effect, int32_t _opcode,
1539 					int32_t _index, intptr_t _value,
1540 						void * _ptr, float _opt )
1541 {
1542 	static VstTimeInfo _timeInfo;
1543 #ifdef DEBUG_CALLBACKS
1544 	char buf[64];
1545 	sprintf( buf, "host-callback, opcode = %d\n", (int) _opcode );
1546 	SHOW_CALLBACK( buf );
1547 #endif
1548 
1549 	// workaround for early callbacks by some plugins
1550 	if( __plugin && __plugin->m_plugin == NULL )
1551 	{
1552 		__plugin->m_plugin = _effect;
1553 	}
1554 
1555 	switch( _opcode )
1556 	{
1557 		case audioMasterAutomate:
1558 			SHOW_CALLBACK( "amc: audioMasterAutomate\n" );
1559 			// index, value, returns 0
1560 			return 0;
1561 
1562 		case audioMasterVersion:
1563 			SHOW_CALLBACK( "amc: audioMasterVersion\n" );
1564 			return 2300;
1565 
1566 		case audioMasterCurrentId:
1567 			SHOW_CALLBACK( "amc: audioMasterCurrentId\n" );
1568 			// returns the unique id of a plug that's currently
1569 			// loading
1570 			return 0;
1571 
1572 		case audioMasterIdle:
1573 			SHOW_CALLBACK ("amc: audioMasterIdle\n" );
1574 			// call application idle routine (this will
1575 			// call effEditIdle for all open editors too)
1576 			PostMessage( __MessageHwnd, WM_USER, GiveIdle, 0 );
1577 			return 0;
1578 
1579 		case audioMasterPinConnected:
1580 			SHOW_CALLBACK( "amc: audioMasterPinConnected\n" );
1581 			// inquire if an input or output is beeing connected;
1582 			// index enumerates input or output counting from zero:
1583 			// value is 0 for input and != 0 otherwise. note: the
1584 			// return value is 0 for <true> such that older versions
1585 			// will always return true.
1586 			return 0;
1587 
1588 		case audioMasterGetTime:
1589 			SHOW_CALLBACK( "amc: audioMasterGetTime\n" );
1590 			// returns const VstTimeInfo* (or 0 if not supported)
1591 			// <value> should contain a mask indicating which
1592 			// fields are required (see valid masks above), as some
1593 			// items may require extensive conversions
1594 
1595 			// Shared memory was initialised? - see song.cpp
1596 			//assert( __plugin->m_vstSyncData != NULL );
1597 
1598 			memset( &_timeInfo, 0, sizeof( _timeInfo ) );
1599 			_timeInfo.samplePos = __plugin->m_currentSamplePos;
1600 			_timeInfo.sampleRate = __plugin->m_vstSyncData->hasSHM ?
1601 							__plugin->m_vstSyncData->m_sampleRate :
1602 							__plugin->sampleRate();
1603 			_timeInfo.flags = 0;
1604 			_timeInfo.tempo = __plugin->m_vstSyncData->hasSHM ?
1605 							__plugin->m_vstSyncData->m_bpm :
1606 							__plugin->m_bpm;
1607 			_timeInfo.timeSigNumerator = __plugin->m_vstSyncData->timeSigNumer;
1608 			_timeInfo.timeSigDenominator = __plugin->m_vstSyncData->timeSigDenom;
1609 			_timeInfo.flags |= kVstTempoValid;
1610 			_timeInfo.flags |= kVstTimeSigValid;
1611 
1612 			if( __plugin->m_vstSyncData->isCycle )
1613 			{
1614 				_timeInfo.cycleStartPos = __plugin->m_vstSyncData->cycleStart;
1615 				_timeInfo.cycleEndPos = __plugin->m_vstSyncData->cycleEnd;
1616 				_timeInfo.flags |= kVstCyclePosValid;
1617 				_timeInfo.flags |= kVstTransportCycleActive;
1618 			}
1619 
1620 			if( __plugin->m_vstSyncData->ppqPos !=
1621 							__plugin->m_in->m_Timestamp )
1622 			{
1623 				_timeInfo.ppqPos = __plugin->m_vstSyncData->ppqPos;
1624 				__plugin->m_in->lastppqPos = __plugin->m_vstSyncData->ppqPos;
1625 				__plugin->m_in->m_Timestamp = __plugin->m_vstSyncData->ppqPos;
1626 			}
1627 			else if( __plugin->m_vstSyncData->isPlaying )
1628 			{
1629 				if( __plugin->m_vstSyncData->hasSHM )
1630 				{
1631 					__plugin->m_in->lastppqPos +=
1632 						__plugin->m_vstSyncData->m_bpm / 60.0
1633 						* __plugin->m_vstSyncData->m_bufferSize
1634 						/ __plugin->m_vstSyncData->m_sampleRate;
1635 				}
1636 				else
1637 				{
1638 					__plugin->m_in->lastppqPos +=
1639 						__plugin->m_bpm / 60.0
1640 						* __plugin->bufferSize()
1641 						/ __plugin->sampleRate();
1642 				}
1643 				_timeInfo.ppqPos = __plugin->m_in->lastppqPos;
1644 			}
1645 //			_timeInfo.ppqPos = __plugin->m_vstSyncData->ppqPos;
1646 			_timeInfo.flags |= kVstPpqPosValid;
1647 
1648 			if( __plugin->m_vstSyncData->isPlaying )
1649 			{
1650 				_timeInfo.flags |= kVstTransportPlaying;
1651 			}
1652 			_timeInfo.barStartPos = ( (int) ( _timeInfo.ppqPos /
1653 				( 4 *__plugin->m_vstSyncData->timeSigNumer
1654 				/ (float) __plugin->m_vstSyncData->timeSigDenom ) ) ) *
1655 				( 4 * __plugin->m_vstSyncData->timeSigNumer
1656 				/ (float) __plugin->m_vstSyncData->timeSigDenom );
1657 
1658 			_timeInfo.flags |= kVstBarsValid;
1659 
1660 			if( ( _timeInfo.flags & ( kVstTransportPlaying | kVstTransportCycleActive ) ) !=
1661 				( __plugin->m_in->m_lastFlags & ( kVstTransportPlaying | kVstTransportCycleActive ) )
1662 				|| __plugin->m_vstSyncData->m_playbackJumped )
1663 			{
1664 				_timeInfo.flags |= kVstTransportChanged;
1665 			}
1666 			__plugin->m_in->m_lastFlags = _timeInfo.flags;
1667 
1668 #ifdef LMMS_BUILD_WIN64
1669 			return (long long) &_timeInfo;
1670 #else
1671 			return (long) &_timeInfo;
1672 #endif
1673 
1674 		case audioMasterProcessEvents:
1675 			SHOW_CALLBACK( "amc: audioMasterProcessEvents\n" );
1676 			// VstEvents* in <ptr>
1677 			return 0;
1678 
1679 		case audioMasterIOChanged:
1680 			SHOW_CALLBACK( "amc: audioMasterIOChanged\n" );
1681 			// numInputs, numOutputs, and/or latency has changed
1682 			return __plugin->updateInOutCount();
1683 
1684 #ifdef OLD_VST_SDK
1685 		case audioMasterWantMidi:
1686 			SHOW_CALLBACK( "amc: audioMasterWantMidi\n" );
1687 			// <value> is a filter which is currently ignored
1688 			return 1;
1689 
1690 		case audioMasterSetTime:
1691 			SHOW_CALLBACK( "amc: audioMasterSetTime\n" );
1692 			// VstTimenfo* in <ptr>, filter in <value>, not
1693 			// supported
1694 			return 0;
1695 
1696 		case audioMasterTempoAt:
1697 			SHOW_CALLBACK( "amc: audioMasterTempoAt\n" );
1698 			return __plugin->m_bpm * 10000;
1699 
1700 		case audioMasterGetNumAutomatableParameters:
1701 			SHOW_CALLBACK( "amc: audioMasterGetNumAutomatable"
1702 							"Parameters\n" );
1703 			return 5000;
1704 
1705 		case audioMasterGetParameterQuantization:
1706 			SHOW_CALLBACK( "amc: audioMasterGetParameter\n"
1707 							"Quantization\n" );
1708 			// returns the integer value for +1.0 representation,
1709 			// or 1 if full single float precision is maintained
1710 			// in automation. parameter index in <value> (-1: all,
1711 			// any)
1712 			return 1;
1713 
1714 		case audioMasterNeedIdle:
1715 			SHOW_CALLBACK( "amc: audioMasterNeedIdle\n" );
1716 			// plug needs idle calls (outside its editor window)
1717 			return 1;
1718 
1719 		case audioMasterGetPreviousPlug:
1720 			SHOW_CALLBACK( "amc: audioMasterGetPreviousPlug\n" );
1721 			// input pin in <value> (-1: first to come), returns
1722 			// cEffect*
1723 			return 0;
1724 
1725 		case audioMasterGetNextPlug:
1726 			SHOW_CALLBACK( "amc: audioMasterGetNextPlug\n" );
1727 			// output pin in <value> (-1: first to come), returns
1728 			// cEffect*
1729 			return 0;
1730 
1731 		case audioMasterWillReplaceOrAccumulate:
1732 			SHOW_CALLBACK( "amc: audioMasterWillReplaceOr"
1733 							"Accumulate\n" );
1734 			// returns: 0: not supported, 1: replace, 2: accumulate
1735 			return 1;
1736 
1737 		case audioMasterGetSpeakerArrangement:
1738 			SHOW_CALLBACK( "amc: audioMasterGetSpeaker"
1739 							"Arrangement\n" );
1740 			// (long)input in <value>, output in <ptr>
1741 			return 0;
1742 
1743 		case audioMasterSetOutputSampleRate:
1744 			SHOW_CALLBACK( "amc: audioMasterSetOutputSample"
1745 								"Rate\n" );
1746 			// for variable i/o, sample rate in <opt>
1747 			return 0;
1748 
1749 		case audioMasterSetIcon:
1750 			SHOW_CALLBACK( "amc: audioMasterSetIcon\n" );
1751 			// TODO
1752 			// void* in <ptr>, format not defined yet
1753 			return 0;
1754 
1755 		case audioMasterOpenWindow:
1756 			SHOW_CALLBACK( "amc: audioMasterOpenWindow\n" );
1757 			// TODO
1758 			// returns platform specific ptr
1759 			return 0;
1760 
1761 		case audioMasterCloseWindow:
1762 			SHOW_CALLBACK( "amc: audioMasterCloseWindow\n" );
1763 			// TODO
1764 			// close window, platform specific handle in <ptr>
1765 			return 0;
1766 #endif
1767 
1768 		case audioMasterSizeWindow:
1769 		{
1770 			SHOW_CALLBACK( "amc: audioMasterSizeWindow\n" );
1771 			if( __plugin->m_window == 0 )
1772 			{
1773 				return 0;
1774 			}
1775 			__plugin->m_windowWidth = _index;
1776 			__plugin->m_windowHeight = _value;
1777 			HWND window = __plugin->m_window;
1778 			DWORD dwStyle = GetWindowLongPtr( window, GWL_STYLE );
1779 			RECT windowSize = { 0, 0, (int) _index, (int) _value };
1780 			AdjustWindowRect( &windowSize, dwStyle, false );
1781 			SetWindowPos( window, 0, 0, 0,
1782 					windowSize.right - windowSize.left,
1783 					windowSize.bottom - windowSize.top,
1784 					SWP_NOACTIVATE | SWP_NOMOVE |
1785 					SWP_NOOWNERZORDER | SWP_NOZORDER );
1786 			__plugin->sendMessage(
1787 				message( IdVstPluginEditorGeometry ).
1788 					addInt( __plugin->m_windowWidth ).
1789 					addInt( __plugin->m_windowHeight ) );
1790 			return 1;
1791 		}
1792 
1793 		case audioMasterGetSampleRate:
1794 			SHOW_CALLBACK( "amc: audioMasterGetSampleRate\n" );
1795 			return __plugin->sampleRate();
1796 
1797 		case audioMasterGetBlockSize:
1798 			SHOW_CALLBACK( "amc: audioMasterGetBlockSize\n" );
1799 
1800 			return __plugin->bufferSize();
1801 
1802 		case audioMasterGetInputLatency:
1803 			SHOW_CALLBACK( "amc: audioMasterGetInputLatency\n" );
1804 			return __plugin->bufferSize();
1805 
1806 		case audioMasterGetOutputLatency:
1807 			SHOW_CALLBACK( "amc: audioMasterGetOutputLatency\n" );
1808 			return __plugin->bufferSize();
1809 
1810 		case audioMasterGetCurrentProcessLevel:
1811 			SHOW_CALLBACK( "amc: audioMasterGetCurrentProcess"
1812 								"Level\n" );
1813 			// returns: 0: not supported,
1814 			// 1: currently in user thread (gui)
1815 			// 2: currently in audio thread (where process is
1816 			//    called)
1817 			// 3: currently in 'sequencer' thread (midi, timer etc)
1818 			// 4: currently offline processing and thus in user
1819 			//    thread
1820 			// other: not defined, but probably pre-empting user
1821 			//        thread.
1822 			return 0;
1823 
1824 		case audioMasterGetAutomationState:
1825 			SHOW_CALLBACK( "amc: audioMasterGetAutomationState\n" );
1826 			// returns 0: not supported, 1: off, 2:read, 3:write,
1827 			// 4:read/write offline
1828 			return 0;
1829 
1830 		case audioMasterOfflineStart:
1831 			SHOW_CALLBACK( "amc: audioMasterOfflineStart\n" );
1832 			return 0;
1833 
1834 		case audioMasterOfflineRead:
1835 			SHOW_CALLBACK( "amc: audioMasterOfflineRead\n" );
1836 			// ptr points to offline structure, see below.
1837 			// return 0: error, 1 ok
1838 			return 0;
1839 
1840 		case audioMasterOfflineWrite:
1841 			SHOW_CALLBACK( "amc: audioMasterOfflineWrite\n" );
1842 			// same as read
1843 			return 0;
1844 
1845 		case audioMasterOfflineGetCurrentPass:
1846 			SHOW_CALLBACK( "amc: audioMasterOfflineGetCurrent"
1847 								"Pass\n" );
1848 			return 0;
1849 
1850 		case audioMasterOfflineGetCurrentMetaPass:
1851 			SHOW_CALLBACK( "amc: audioMasterOfflineGetCurrentMeta"
1852 								"Pass\n");
1853 			return 0;
1854 
1855 		case audioMasterGetVendorString:
1856 			SHOW_CALLBACK( "amc: audioMasterGetVendorString\n" );
1857 			// fills <ptr> with a string identifying the vendor
1858 			// (max 64 char)
1859 			strcpy( (char *) _ptr, "Tobias Doerffel" );
1860 			return 1;
1861 
1862 		case audioMasterGetProductString:
1863 			SHOW_CALLBACK( "amc: audioMasterGetProductString\n" );
1864 			// fills <ptr> with a string with product name
1865 			// (max 64 char)
1866 			strcpy( (char *) _ptr,
1867 					"LMMS VST Support Layer (LVSL)" );
1868 			return 1;
1869 
1870 		case audioMasterGetVendorVersion:
1871 			SHOW_CALLBACK( "amc: audioMasterGetVendorVersion\n" );
1872 			// returns vendor-specific version
1873 			return 1000;
1874 
1875 		case audioMasterVendorSpecific:
1876 			SHOW_CALLBACK( "amc: audioMasterVendorSpecific\n" );
1877 			// no definition, vendor specific handling
1878 			return 0;
1879 
1880 		case audioMasterCanDo:
1881 			SHOW_CALLBACK( "amc: audioMasterCanDo\n" );
1882 			return !strcmp( (char *) _ptr, "sendVstEvents" ) ||
1883 				!strcmp( (char *) _ptr, "sendVstMidiEvent" ) ||
1884 				!strcmp( (char *) _ptr, "sendVstTimeInfo" ) ||
1885 				!strcmp( (char *) _ptr, "sizeWindow" ) ||
1886 				!strcmp( (char *) _ptr, "supplyIdle" );
1887 
1888 		case audioMasterGetLanguage:
1889 			SHOW_CALLBACK( "amc: audioMasterGetLanguage\n" );
1890 			return hlang;
1891 
1892 		case audioMasterGetDirectory:
1893 			SHOW_CALLBACK( "amc: audioMasterGetDirectory\n" );
1894 			// get plug directory, FSSpec on MAC, else char*
1895 			return 0;
1896 
1897 		case audioMasterUpdateDisplay:
1898 			SHOW_CALLBACK( "amc: audioMasterUpdateDisplay\n" );
1899 			// something has changed, update 'multi-fx' display
1900 			PostMessage( __MessageHwnd, WM_USER, GiveIdle, 0 );
1901 			return 0;
1902 
1903 #if kVstVersion > 2
1904 		case audioMasterBeginEdit:
1905 			SHOW_CALLBACK( "amc: audioMasterBeginEdit\n" );
1906 			// begin of automation session (when mouse down),
1907 			// parameter index in <index>
1908 			return 0;
1909 
1910 		case audioMasterEndEdit:
1911 			SHOW_CALLBACK( "amc: audioMasterEndEdit\n" );
1912 			// end of automation session (when mouse up),
1913 			// parameter index in <index>
1914 			return 0;
1915 
1916 		case audioMasterOpenFileSelector:
1917 			SHOW_CALLBACK( "amc: audioMasterOpenFileSelector\n" );
1918 			// open a fileselector window with VstFileSelect*
1919 			// in <ptr>
1920 			return 0;
1921 #endif
1922 		default:
1923 			SHOW_CALLBACK( "amd: not handled" );
1924 			break;
1925 	}
1926 
1927 	return 0;
1928 }
1929 
1930 
1931 
1932 
idle()1933 void RemoteVstPlugin::idle()
1934 {
1935 	if( isProcessing() )
1936 	{
1937 		setShouldGiveIdle( true );
1938 		return;
1939 	}
1940 	setProcessing( true );
1941 	pluginDispatch( effEditIdle );
1942 	setShouldGiveIdle( false );
1943 	setProcessing( false );
1944 	// We might have received a message whilst idling
1945 	processUIThreadMessages();
1946 }
1947 
1948 
1949 
1950 
processUIThreadMessages()1951 void RemoteVstPlugin::processUIThreadMessages()
1952 {
1953 	setProcessing( true );
1954 	while( m_messageList.size() )
1955 	{
1956 		processMessage( m_messageList.front() );
1957 		m_messageList.pop();
1958 		if( shouldGiveIdle() )
1959 		{
1960 			pluginDispatch( effEditIdle );
1961 			setShouldGiveIdle( false );
1962 		}
1963 	}
1964 	setProcessing( false );
1965 }
1966 
1967 
1968 
1969 
processingThread(LPVOID _param)1970 DWORD WINAPI RemoteVstPlugin::processingThread( LPVOID _param )
1971 {
1972 	__processingThreadId = GetCurrentThreadId();
1973 
1974 	RemoteVstPlugin * _this = static_cast<RemoteVstPlugin *>( _param );
1975 
1976 	RemotePluginClient::message m;
1977 	while( ( m = _this->receiveMessage() ).id != IdQuit )
1978         {
1979 		if( m.id == IdStartProcessing
1980 			|| m.id == IdMidiEvent
1981 			|| m.id == IdVstSetParameter
1982 			|| m.id == IdVstSetTempo )
1983 		{
1984 			_this->processMessage( m );
1985 		}
1986 		else if( m.id == IdChangeSharedMemoryKey )
1987 		{
1988 			_this->processMessage( m );
1989 			_this->setShmIsValid( true );
1990 		}
1991 		else
1992 		{
1993 			PostMessage( __MessageHwnd,
1994 					WM_USER,
1995 					ProcessPluginMessage,
1996 					(LPARAM) new message( m ) );
1997 		}
1998 	}
1999 
2000 	// notify GUI thread about shutdown
2001 	PostMessage( __MessageHwnd, WM_USER, ClosePlugin, 0 );
2002 
2003 	return 0;
2004 }
2005 
2006 
2007 
2008 
setupMessageWindow()2009 bool RemoteVstPlugin::setupMessageWindow()
2010 {
2011 	HMODULE hInst = GetModuleHandle( NULL );
2012 	if( hInst == NULL )
2013 	{
2014 		__plugin->debugMessage( "setupMessageWindow(): can't get "
2015 							"module handle\n" );
2016 		return false;
2017 	}
2018 
2019 	__MessageHwnd = CreateWindowEx( 0, "LVSL", "dummy",
2020 						0, 0, 0, 0, 0, NULL, NULL,
2021 								hInst, NULL );
2022 	// install GUI update timer
2023 	SetTimer( __MessageHwnd, 1000, 50, NULL );
2024 
2025 	return true;
2026 }
2027 
2028 
2029 
2030 
guiEventLoop()2031 DWORD WINAPI RemoteVstPlugin::guiEventLoop()
2032 {
2033 	MSG msg;
2034 	while( GetMessage( &msg, NULL, 0, 0 ) > 0 )
2035 	{
2036 		TranslateMessage( &msg );
2037 		DispatchMessage( &msg );
2038 	}
2039 
2040 	return 0;
2041 }
2042 
2043 
2044 
2045 
wndProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)2046 LRESULT CALLBACK RemoteVstPlugin::wndProc( HWND hwnd, UINT uMsg,
2047 						WPARAM wParam, LPARAM lParam )
2048 {
2049 	if( uMsg == WM_TIMER && __plugin->isInitialized() )
2050 	{
2051 		// give plugin some idle-time for GUI-update
2052 		__plugin->idle();
2053 		return 0;
2054 	}
2055 	else if( uMsg == WM_USER )
2056 	{
2057 		switch( wParam )
2058 		{
2059 			case ProcessPluginMessage:
2060 			{
2061 				message * m = (message *) lParam;
2062 				__plugin->queueMessage( *m );
2063 				delete m;
2064 				if( !__plugin->isProcessing() )
2065 				{
2066 					__plugin->processUIThreadMessages();
2067 				}
2068 				return 0;
2069 			}
2070 
2071 			case GiveIdle:
2072 				__plugin->idle();
2073 				return 0;
2074 
2075 			case ClosePlugin:
2076 				PostQuitMessage(0);
2077 				return 0;
2078 
2079 			default:
2080 				break;
2081 		}
2082 	}
2083 	else if( uMsg == WM_SYSCOMMAND && (wParam & 0xfff0) == SC_CLOSE )
2084 	{
2085 		__plugin->hideEditor();
2086 		return 0;
2087 	}
2088 
2089 	return DefWindowProc( hwnd, uMsg, wParam, lParam );
2090 }
2091 
2092 
2093 
2094 
main(int _argc,char ** _argv)2095 int main( int _argc, char * * _argv )
2096 {
2097 #ifdef SYNC_WITH_SHM_FIFO
2098 	if( _argc < 4 )
2099 #else
2100 	if( _argc < 3 )
2101 #endif
2102 	{
2103 		fprintf( stderr, "not enough arguments\n" );
2104 		return -1;
2105 	}
2106 
2107 	OleInitialize(nullptr);
2108 
2109 #ifdef LMMS_BUILD_WIN32
2110 #ifndef __WINPTHREADS_VERSION
2111 	// (non-portable) initialization of statically linked pthread library
2112 	pthread_win32_process_attach_np();
2113 	pthread_win32_thread_attach_np();
2114 #endif
2115 #endif
2116 
2117 #ifdef LMMS_BUILD_LINUX
2118 #ifdef LMMS_HAVE_SCHED_H
2119 	// try to set realtime-priority
2120 	struct sched_param sparam;
2121 	sparam.sched_priority = ( sched_get_priority_max( SCHED_FIFO ) +
2122 				sched_get_priority_min( SCHED_FIFO ) ) / 2;
2123 	sched_setscheduler( 0, SCHED_FIFO, &sparam );
2124 #endif
2125 #endif
2126 
2127 #ifdef LMMS_BUILD_WIN32
2128 	if( !SetPriorityClass( GetCurrentProcess(), HIGH_PRIORITY_CLASS ) )
2129 	{
2130 		printf( "Notice: could not set high priority.\n" );
2131 	}
2132 #endif
2133 
2134 	HMODULE hInst = GetModuleHandle( NULL );
2135 	if( hInst == NULL )
2136 	{
2137 		return -1;
2138 	}
2139 
2140 	WNDCLASS wc;
2141 	wc.style = CS_HREDRAW | CS_VREDRAW;
2142 	wc.lpfnWndProc = RemoteVstPlugin::wndProc;
2143 	wc.cbClsExtra = 0;
2144 	wc.cbWndExtra = 0;
2145 	wc.hInstance = hInst;
2146 	wc.hIcon = LoadIcon( NULL, IDI_APPLICATION );
2147 	wc.hCursor = LoadCursor( NULL, IDC_ARROW );
2148 	wc.hbrBackground = NULL;
2149 	wc.lpszMenuName = NULL;
2150 	wc.lpszClassName = "LVSL";
2151 
2152 	if( !RegisterClass( &wc ) )
2153 	{
2154 		return -1;
2155 	}
2156 
2157 	{
2158 	#ifdef SYNC_WITH_SHM_FIFO
2159 		int embedMethodIndex = 3;
2160 	#else
2161 		int embedMethodIndex = 2;
2162 	#endif
2163 		std::string embedMethod = _argv[embedMethodIndex];
2164 
2165 		if ( embedMethod == "none" )
2166 		{
2167 			cerr << "Starting detached." << endl;
2168 			EMBED = EMBED_X11 = EMBED_WIN32 = HEADLESS = false;
2169 		}
2170 		else if ( embedMethod == "win32" )
2171 		{
2172 			cerr << "Starting using Win32-native embedding." << endl;
2173 			EMBED = EMBED_WIN32 = true; EMBED_X11 = HEADLESS = false;
2174 		}
2175 		else if ( embedMethod == "qt" )
2176 		{
2177 			cerr << "Starting using Qt-native embedding." << endl;
2178 			EMBED = true; EMBED_X11 = EMBED_WIN32 = HEADLESS = false;
2179 		}
2180 		else if ( embedMethod == "xembed" )
2181 		{
2182 			cerr << "Starting using X11Embed protocol." << endl;
2183 			EMBED = EMBED_X11 = true; EMBED_WIN32 = HEADLESS = false;
2184 		}
2185 		else if ( embedMethod == "headless" )
2186 		{
2187 			cerr << "Starting without UI." << endl;
2188 			HEADLESS = true; EMBED = EMBED_X11 = EMBED_WIN32 = false;
2189 		}
2190 		else
2191 		{
2192 			cerr << "Unknown embed method " << embedMethod << ". Starting detached instead." << endl;
2193 			EMBED = EMBED_X11 = EMBED_WIN32 = HEADLESS = false;
2194 		}
2195 	}
2196 
2197 	// constructor automatically will process messages until it receives
2198 	// a IdVstLoadPlugin message and processes it
2199 #ifdef SYNC_WITH_SHM_FIFO
2200 	__plugin = new RemoteVstPlugin( atoi( _argv[1] ), atoi( _argv[2] ) );
2201 #else
2202 	__plugin = new RemoteVstPlugin( _argv[1] );
2203 #endif
2204 
2205 	if( __plugin->isInitialized() )
2206 	{
2207 		if( RemoteVstPlugin::setupMessageWindow() == false )
2208 		{
2209 			return -1;
2210 		}
2211 		if( CreateThread( NULL, 0, RemoteVstPlugin::processingThread,
2212 						__plugin, 0, NULL ) == NULL )
2213 		{
2214 			__plugin->debugMessage( "could not create "
2215 							"processingThread\n" );
2216 			return -1;
2217 		}
2218 		RemoteVstPlugin::guiEventLoop();
2219 	}
2220 
2221 
2222 	delete __plugin;
2223 
2224 	OleUninitialize();
2225 
2226 #ifdef LMMS_BUILD_WIN32
2227 #ifndef __WINPTHREADS_VERSION
2228 	pthread_win32_thread_detach_np();
2229 	pthread_win32_process_detach_np();
2230 #endif
2231 #endif
2232 
2233 	return 0;
2234 
2235 }
2236 
2237