RemoteVstPlugin.cpp 50 KB

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