RemoteVstPlugin.cpp 51 KB

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