RemoteVstPlugin.cpp 50 KB

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