12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237 |
- /*
- * RemoteVstPlugin.cpp - LMMS VST Support Layer (RemotePlugin client)
- *
- * Copyright (c) 2005-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
- *
- * This file is part of LMMS - https://lmms.io
- *
- * Code partly taken from (X)FST:
- * Copyright (c) 2004 Paul Davis
- * Copyright (c) 2004 Torben Hohn
- * Copyright (c) 2002 Kjetil S. Matheussen
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program (see COPYING); if not, write to the
- * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301 USA.
- *
- */
- #include "lmmsconfig.h"
- #define BUILD_REMOTE_PLUGIN_CLIENT
- #include "RemotePlugin.h"
- #ifdef LMMS_HAVE_PTHREAD_H
- #include <pthread.h>
- #endif
- #ifdef LMMS_HAVE_FCNTL_H
- #include <fcntl.h>
- #endif
- #ifdef LMMS_BUILD_LINUX
- #ifndef NOMINMAX
- #define NOMINMAX
- #endif
- #ifndef O_BINARY
- #define O_BINARY 0
- #endif
- #ifdef LMMS_HAVE_SCHED_H
- #include <sched.h>
- #endif
- #include <wine/exception.h>
- #endif
- #define USE_WS_PREFIX
- #include <windows.h>
- #include <algorithm>
- #include <vector>
- #include <queue>
- #include <string>
- #include <iostream>
- #include <aeffectx.h>
- #if kVstVersion < 2400
- #define OLD_VST_SDK
- struct ERect
- {
- short top;
- short left;
- short bottom;
- short right;
- } ;
- #endif
- #include "lmms_basics.h"
- #include "Midi.h"
- #include "communication.h"
- #include "IoHelper.h"
- #include "VstSyncData.h"
- #ifdef LMMS_BUILD_WIN32
- #define USE_QT_SHMEM
- #endif
- #ifndef USE_QT_SHMEM
- #include <stdio.h>
- #include <stdlib.h>
- #include <sys/types.h>
- #include <sys/ipc.h>
- #include <sys/shm.h>
- #endif
- using namespace std;
- static VstHostLanguages hlang = LanguageEnglish;
- static bool EMBED = false;
- static bool EMBED_X11 = false;
- static bool EMBED_WIN32 = false;
- static bool HEADLESS = false;
- class RemoteVstPlugin;
- RemoteVstPlugin * __plugin = NULL;
- HWND __MessageHwnd = NULL;
- DWORD __processingThreadId = 0;
- class RemoteVstPlugin : public RemotePluginClient
- {
- public:
- #ifdef SYNC_WITH_SHM_FIFO
- RemoteVstPlugin( key_t _shm_in, key_t _shm_out );
- #else
- RemoteVstPlugin( const char * socketPath );
- #endif
- virtual ~RemoteVstPlugin();
- virtual bool processMessage( const message & _m );
- void init( const std::string & _plugin_file );
- void initEditor();
- void showEditor();
- void hideEditor();
- void destroyEditor();
- virtual void process( const sampleFrame * _in, sampleFrame * _out );
- virtual void processMidiEvent( const MidiEvent& event, const f_cnt_t offset );
- // set given sample-rate for plugin
- virtual void updateSampleRate()
- {
- SuspendPlugin suspend( this );
- pluginDispatch( effSetSampleRate, 0, 0,
- NULL, (float) sampleRate() );
- }
- // set given buffer-size for plugin
- virtual void updateBufferSize()
- {
- SuspendPlugin suspend( this );
- pluginDispatch( effSetBlockSize, 0, bufferSize() );
- }
- void setResumed( bool resumed )
- {
- m_resumed = resumed;
- pluginDispatch( effMainsChanged, 0, resumed ? 1 : 0 );
- }
- inline bool isResumed() const
- {
- return m_resumed;
- }
- inline bool isInitialized() const
- {
- return m_initialized;
- }
- // set given tempo
- void setBPM( const bpm_t _bpm )
- {
- m_bpm = _bpm;
- }
- // determine VST-version the plugin uses
- inline int pluginVersion()
- {
- return pluginDispatch( effGetVendorVersion );
- }
- // determine name of plugin
- const char * pluginName();
- // determine vendor of plugin
- const char * pluginVendorString();
- // determine product-string of plugin
- const char * pluginProductString();
- // determine name of current program
- const char * programName();
- // send name of current program back to host
- void sendCurrentProgramName();
- // do a complete parameter-dump and post it
- void getParameterDump();
- // read parameter-dump and set it for plugin
- void setParameterDump( const message & _m );
- // save settings chunk of plugin into file
- void saveChunkToFile( const std::string & _file );
- // restore settings chunk of plugin from file
- void loadChunkFromFile( const std::string & _file, int _len );
- // restore settings chunk of plugin from file
- void loadPresetFile( const std::string & _file );
- // sets given program index
- void setProgram( int index );
- // rotate current program by given offset
- void rotateProgram( int offset );
- // Load names of presets/programs
- void getProgramNames();
- // Save presets/programs
- void savePreset( const std::string & _file );
- // number of inputs
- virtual int inputCount() const
- {
- if( m_plugin )
- {
- return m_plugin->numInputs;
- }
- return 0;
- }
- // number of outputs
- virtual int outputCount() const
- {
- if( m_plugin )
- {
- return m_plugin->numOutputs;
- }
- return 0;
- }
- // has to be called as soon as input- or output-count changes
- int updateInOutCount();
- inline void lockShm()
- {
- pthread_mutex_lock( &m_shmLock );
- }
- inline bool tryLockShm()
- {
- return pthread_mutex_trylock( &m_shmLock ) == 0;
- }
- inline void unlockShm()
- {
- pthread_mutex_unlock( &m_shmLock );
- }
- inline bool isShmValid()
- {
- return m_shmValid;
- }
- inline void setShmIsValid( bool valid )
- {
- m_shmValid = valid;
- }
- inline bool isProcessing() const
- {
- return m_processing;
- }
- inline void setProcessing( bool processing )
- {
- m_processing = processing;
- }
- inline void queueMessage( const message & m ) {
- m_messageList.push( m );
- }
- inline bool shouldGiveIdle() const
- {
- return m_shouldGiveIdle;
- }
- inline void setShouldGiveIdle( bool shouldGiveIdle )
- {
- m_shouldGiveIdle = shouldGiveIdle;
- }
- void idle();
- void processUIThreadMessages();
- static DWORD WINAPI processingThread( LPVOID _param );
- static bool setupMessageWindow();
- static DWORD WINAPI guiEventLoop();
- static LRESULT CALLBACK wndProc( HWND hwnd, UINT uMsg,
- WPARAM wParam, LPARAM lParam );
- private:
- enum GuiThreadMessages
- {
- None,
- ProcessPluginMessage,
- GiveIdle,
- ClosePlugin
- } ;
- struct SuspendPlugin {
- SuspendPlugin( RemoteVstPlugin * plugin ) :
- m_plugin( plugin ),
- m_resumed( plugin->isResumed() )
- {
- if( m_resumed ) { m_plugin->setResumed( false ); }
- }
- ~SuspendPlugin()
- {
- if( m_resumed ) { m_plugin->setResumed( true ); }
- }
- private:
- RemoteVstPlugin * m_plugin;
- bool m_resumed;
- };
- // callback used by plugin for being able to communicate with it's host
- static intptr_t hostCallback( AEffect * _effect, int32_t _opcode,
- int32_t _index, intptr_t _value,
- void * _ptr, float _opt );
- bool load( const std::string & _plugin_file );
- int pluginDispatch( int cmd, int param1 = 0, int param2 = 0,
- void * p = NULL, float f = 0 )
- {
- if( m_plugin )
- {
- return m_plugin->dispatcher( m_plugin, cmd, param1, param2, p, f );
- }
- return 0;
- }
- std::string m_shortName;
- HINSTANCE m_libInst;
- AEffect * m_plugin;
- HWND m_window;
- intptr_t m_windowID;
- int m_windowWidth;
- int m_windowHeight;
- bool m_initialized;
- bool m_resumed;
- bool m_processing;
- std::queue<message> m_messageList;
- bool m_shouldGiveIdle;
- float * * m_inputs;
- float * * m_outputs;
- pthread_mutex_t m_shmLock;
- bool m_shmValid;
- typedef std::vector<VstMidiEvent> VstMidiEventList;
- VstMidiEventList m_midiEvents;
- bpm_t m_bpm;
- double m_currentSamplePos;
- int m_currentProgram;
- // host to plugin synchronisation data structure
- struct in
- {
- double lastppqPos;
- double m_Timestamp;
- int32_t m_lastFlags;
- } ;
- in * m_in;
- int m_shmID;
- VstSyncData* m_vstSyncData;
- } ;
- #ifdef SYNC_WITH_SHM_FIFO
- RemoteVstPlugin::RemoteVstPlugin( key_t _shm_in, key_t _shm_out ) :
- RemotePluginClient( _shm_in, _shm_out ),
- #else
- RemoteVstPlugin::RemoteVstPlugin( const char * socketPath ) :
- RemotePluginClient( socketPath ),
- #endif
- m_libInst( NULL ),
- m_plugin( NULL ),
- m_window( NULL ),
- m_windowID( 0 ),
- m_windowWidth( 0 ),
- m_windowHeight( 0 ),
- m_initialized( false ),
- m_resumed( false ),
- m_processing( false ),
- m_messageList(),
- m_shouldGiveIdle( false ),
- m_inputs( NULL ),
- m_outputs( NULL ),
- m_shmLock(),
- m_shmValid( false ),
- m_midiEvents(),
- m_bpm( 0 ),
- m_currentSamplePos( 0 ),
- m_currentProgram( -1 ),
- m_in( NULL ),
- m_shmID( -1 ),
- m_vstSyncData( NULL )
- {
- pthread_mutex_init( &m_shmLock, NULL );
- __plugin = this;
- #ifndef USE_QT_SHMEM
- key_t key;
- if( ( key = ftok( VST_SNC_SHM_KEY_FILE, 'R' ) ) == -1 )
- {
- perror( "RemoteVstPlugin.cpp::ftok" );
- }
- else
- { // connect to shared memory segment
- if( ( m_shmID = shmget( key, 0, 0 ) ) == -1 )
- {
- perror( "RemoteVstPlugin.cpp::shmget" );
- }
- else
- { // attach segment
- m_vstSyncData = (VstSyncData *)shmat(m_shmID, 0, 0);
- if( m_vstSyncData == (VstSyncData *)( -1 ) )
- {
- perror( "RemoteVstPlugin.cpp::shmat" );
- }
- }
- }
- #else
- m_vstSyncData = RemotePluginClient::getQtVSTshm();
- #endif
- if( m_vstSyncData == NULL )
- {
- fprintf(stderr, "RemoteVstPlugin.cpp: "
- "Failed to initialize shared memory for VST synchronization.\n"
- " (VST-host synchronization will be disabled)\n");
- m_vstSyncData = (VstSyncData*) malloc( sizeof( VstSyncData ) );
- m_vstSyncData->isPlaying = true;
- m_vstSyncData->timeSigNumer = 4;
- m_vstSyncData->timeSigDenom = 4;
- m_vstSyncData->ppqPos = 0;
- m_vstSyncData->isCycle = false;
- m_vstSyncData->hasSHM = false;
- m_vstSyncData->m_playbackJumped = false;
- m_vstSyncData->m_sampleRate = sampleRate();
- }
- m_in = ( in* ) new char[ sizeof( in ) ];
- m_in->lastppqPos = 0;
- m_in->m_Timestamp = -1;
- m_in->m_lastFlags = 0;
- // process until we have loaded the plugin
- while( 1 )
- {
- message m = receiveMessage();
- processMessage( m );
- if( m.id == IdVstLoadPlugin || m.id == IdQuit )
- {
- break;
- }
- }
- }
- RemoteVstPlugin::~RemoteVstPlugin()
- {
- destroyEditor();
- setResumed( false );
- pluginDispatch( effClose );
- #ifndef USE_QT_SHMEM
- // detach shared memory segment
- if( shmdt( m_vstSyncData ) == -1)
- {
- if( __plugin->m_vstSyncData->hasSHM )
- {
- perror( "~RemoteVstPlugin::shmdt" );
- }
- if( m_vstSyncData != NULL )
- {
- delete m_vstSyncData;
- m_vstSyncData = NULL;
- }
- }
- #endif
- if( m_libInst != NULL )
- {
- FreeLibrary( m_libInst );
- m_libInst = NULL;
- }
- delete[] m_inputs;
- delete[] m_outputs;
- pthread_mutex_destroy( &m_shmLock );
- }
- bool RemoteVstPlugin::processMessage( const message & _m )
- {
- if (! EMBED)
- {
- switch( _m.id )
- {
- case IdShowUI:
- showEditor();
- return true;
- case IdHideUI:
- hideEditor();
- return true;
- case IdToggleUI:
- if( m_window && IsWindowVisible( m_window ) )
- {
- hideEditor();
- }
- else
- {
- showEditor();
- }
- return true;
- case IdIsUIVisible:
- bool visible = m_window && IsWindowVisible( m_window );
- sendMessage( message( IdIsUIVisible )
- .addInt( visible ? 1 : 0 ) );
- return true;
- }
- }
- else if (EMBED && _m.id == IdShowUI)
- {
- ShowWindow( m_window, SW_SHOWNORMAL );
- UpdateWindow( m_window );
- return true;
- }
- switch( _m.id )
- {
- case IdVstLoadPlugin:
- init( _m.getString() );
- break;
- case IdVstSetTempo:
- setBPM( _m.getInt() );
- break;
- case IdVstSetLanguage:
- hlang = static_cast<VstHostLanguages>( _m.getInt() );
- break;
- case IdVstGetParameterDump:
- getParameterDump();
- break;
- case IdVstSetParameterDump:
- setParameterDump( _m );
- break;
- case IdSaveSettingsToFile:
- saveChunkToFile( _m.getString() );
- sendMessage( IdSaveSettingsToFile );
- break;
- case IdLoadSettingsFromFile:
- loadChunkFromFile( _m.getString( 0 ), _m.getInt( 1 ) );
- sendMessage( IdLoadSettingsFromFile );
- break;
- case IdLoadPresetFile:
- loadPresetFile( _m.getString( 0 ) );
- sendMessage( IdLoadPresetFile );
- break;
- case IdVstSetProgram:
- setProgram( _m.getInt( 0 ) );
- sendMessage( IdVstSetProgram );
- break;
- case IdVstCurrentProgram:
- sendMessage( message( IdVstCurrentProgram ).addInt( m_currentProgram ) );
- break;
- case IdVstRotateProgram:
- rotateProgram( _m.getInt( 0 ) );
- sendMessage( IdVstRotateProgram );
- break;
- case IdVstProgramNames:
- getProgramNames();
- break;
- case IdSavePresetFile:
- savePreset( _m.getString( 0 ) );
- sendMessage( IdSavePresetFile );
- break;
- case IdVstSetParameter:
- m_plugin->setParameter( m_plugin, _m.getInt( 0 ), _m.getFloat( 1 ) );
- //sendMessage( IdVstSetParameter );
- break;
- case IdVstIdleUpdate:
- {
- int newCurrentProgram = pluginDispatch( effGetProgram );
- if( newCurrentProgram != m_currentProgram )
- {
- m_currentProgram = newCurrentProgram;
- sendCurrentProgramName();
- }
- break;
- }
- default:
- return RemotePluginClient::processMessage( _m );
- }
- return true;
- }
- void RemoteVstPlugin::init( const std::string & _plugin_file )
- {
- if( load( _plugin_file ) == false )
- {
- sendMessage( IdVstFailedLoadingPlugin );
- return;
- }
- updateInOutCount();
- updateBufferSize();
- updateSampleRate();
- /* set program to zero */
- /* i comment this out because it breaks dfx Geometer
- * looks like we cant set programs for it
- *
- pluginDispatch( effSetProgram, 0, 0 ); */
- // request rate and blocksize
- setResumed( true );
- debugMessage( "creating editor\n" );
- initEditor();
- debugMessage( "editor successfully created\n" );
- // now post some information about our plugin
- sendMessage( message( IdVstPluginWindowID ).addInt( m_windowID ) );
- sendMessage( message( IdVstPluginEditorGeometry ).
- addInt( m_windowWidth ).
- addInt( m_windowHeight ) );
- sendMessage( message( IdVstPluginName ).addString( pluginName() ) );
- sendMessage( message( IdVstPluginVersion ).addInt( pluginVersion() ) );
- sendMessage( message( IdVstPluginVendorString ).
- addString( pluginVendorString() ) );
- sendMessage( message( IdVstPluginProductString ).
- addString( pluginProductString() ) );
- sendMessage( message( IdVstParameterCount ).
- addInt( m_plugin->numParams ) );
- sendMessage( IdInitDone );
- m_initialized = true;
- }
- static void close_check( FILE* fp )
- {
- if (!fp) {return;}
- if( fclose( fp ) )
- {
- perror( "close" );
- }
- }
- void RemoteVstPlugin::initEditor()
- {
- if( HEADLESS || m_window || !( m_plugin->flags & effFlagsHasEditor ) )
- {
- return;
- }
- HMODULE hInst = GetModuleHandle( NULL );
- if( hInst == NULL )
- {
- debugMessage( "initEditor(): can't get module handle\n" );
- return;
- }
- DWORD dwStyle;
- if (EMBED) {
- dwStyle = WS_POPUP | WS_SYSMENU | WS_BORDER;
- } else {
- dwStyle = WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX;
- }
- m_window = CreateWindowEx( WS_EX_APPWINDOW, "LVSL", pluginName(),
- dwStyle,
- 0, 0, 10, 10, NULL, NULL, hInst, NULL );
- if( m_window == NULL )
- {
- debugMessage( "initEditor(): cannot create editor window\n" );
- return;
- }
- pluginDispatch( effEditOpen, 0, 0, m_window );
- ERect * er;
- pluginDispatch( effEditGetRect, 0, 0, &er );
- m_windowWidth = er->right - er->left;
- m_windowHeight = er->bottom - er->top;
- RECT windowSize = { 0, 0, m_windowWidth, m_windowHeight };
- AdjustWindowRect( &windowSize, dwStyle, false );
- SetWindowPos( m_window, 0, 0, 0, windowSize.right - windowSize.left,
- windowSize.bottom - windowSize.top, SWP_NOACTIVATE |
- SWP_NOMOVE | SWP_NOZORDER );
- pluginDispatch( effEditTop );
- #ifdef LMMS_BUILD_LINUX
- m_windowID = (intptr_t) GetProp( m_window, "__wine_x11_whole_window" );
- #else
- // 64-bit versions of Windows use 32-bit handles for interoperability
- m_windowID = (intptr_t) m_window;
- #endif
- }
- void RemoteVstPlugin::showEditor() {
- if( !EMBED && !HEADLESS && m_window )
- {
- ShowWindow( m_window, SW_SHOWNORMAL );
- }
- }
- void RemoteVstPlugin::hideEditor() {
- if( !EMBED && !HEADLESS && m_window )
- {
- ShowWindow( m_window, SW_HIDE );
- }
- }
- void RemoteVstPlugin::destroyEditor()
- {
- if( m_window == NULL )
- {
- return;
- }
- pluginDispatch( effEditClose );
- // Destroying the window takes some time in Wine 1.8.5
- DestroyWindow( m_window );
- m_window = NULL;
- }
- bool RemoteVstPlugin::load( const std::string & _plugin_file )
- {
- if( ( m_libInst = LoadLibraryW( toWString(_plugin_file).c_str() ) ) == NULL )
- {
- // give VstPlugin class a chance to start 32 bit version of RemoteVstPlugin
- if( GetLastError() == ERROR_BAD_EXE_FORMAT )
- {
- sendMessage( IdVstBadDllFormat );
- }
- return false;
- }
- typedef AEffect * ( __stdcall * mainEntryPointer )
- ( audioMasterCallback );
- mainEntryPointer mainEntry = (mainEntryPointer)
- GetProcAddress( m_libInst, "VSTPluginMain" );
- if( mainEntry == NULL )
- {
- mainEntry = (mainEntryPointer)
- GetProcAddress( m_libInst, "VstPluginMain" );
- }
- if( mainEntry == NULL )
- {
- mainEntry = (mainEntryPointer)
- GetProcAddress( m_libInst, "main" );
- }
- if( mainEntry == NULL )
- {
- debugMessage( "could not find entry point\n" );
- return false;
- }
- m_plugin = mainEntry( hostCallback );
- if( m_plugin == NULL )
- {
- debugMessage( "mainEntry procedure returned NULL\n" );
- return false;
- }
- if( m_plugin->magic != kEffectMagic )
- {
- debugMessage( "File is not a VST plugin\n" );
- return false;
- }
- char id[5];
- sprintf( id, "%c%c%c%c", ((char *)&m_plugin->uniqueID)[3],
- ((char *)&m_plugin->uniqueID)[2],
- ((char *)&m_plugin->uniqueID)[1],
- ((char *)&m_plugin->uniqueID)[0] );
- id[4] = 0;
- sendMessage( message( IdVstPluginUniqueID ).addString( id ) );
- pluginDispatch( effOpen );
- return true;
- }
- void RemoteVstPlugin::process( const sampleFrame * _in, sampleFrame * _out )
- {
- // first we gonna post all MIDI-events we enqueued so far
- if( m_midiEvents.size() )
- {
- // since MIDI-events are not received immediately, we
- // have to have them stored somewhere even after
- // dispatcher-call, so we create static copies of the
- // data and post them
- #define MIDI_EVENT_BUFFER_COUNT 1024
- static char eventsBuffer[sizeof( VstEvents ) + sizeof( VstMidiEvent * ) * MIDI_EVENT_BUFFER_COUNT];
- static VstMidiEvent vme[MIDI_EVENT_BUFFER_COUNT];
- // first sort events chronologically, since some plugins
- // (e.g. Sinnah) can hang if they're out of order
- std::stable_sort( m_midiEvents.begin(), m_midiEvents.end(),
- []( const VstMidiEvent &a, const VstMidiEvent &b )
- {
- return a.deltaFrames < b.deltaFrames;
- } );
- VstEvents* events = (VstEvents *) eventsBuffer;
- events->reserved = 0;
- events->numEvents = m_midiEvents.size();
- int idx = 0;
- for( VstMidiEventList::iterator it = m_midiEvents.begin(); it != m_midiEvents.end(); ++it, ++idx )
- {
- memcpy( &vme[idx], &*it, sizeof( VstMidiEvent ) );
- events->events[idx] = (VstEvent *) &vme[idx];
- }
- m_midiEvents.clear();
- pluginDispatch( effProcessEvents, 0, 0, events );
- }
- // now we're ready to fetch sound from VST-plugin
- if( !tryLockShm() )
- {
- return;
- }
- if( !isShmValid() )
- {
- unlockShm();
- return;
- }
- for( int i = 0; i < inputCount(); ++i )
- {
- m_inputs[i] = &((float *) _in)[i * bufferSize()];
- }
- for( int i = 0; i < outputCount(); ++i )
- {
- m_outputs[i] = &((float *) _out)[i * bufferSize()];
- memset( m_outputs[i], 0, bufferSize() * sizeof( float ) );
- }
- #ifdef OLD_VST_SDK
- if( m_plugin->flags & effFlagsCanReplacing )
- {
- #endif
- m_plugin->processReplacing( m_plugin, m_inputs, m_outputs,
- bufferSize() );
- #ifdef OLD_VST_SDK
- }
- else
- {
- m_plugin->process( m_plugin, m_inputs, m_outputs,
- bufferSize() );
- }
- #endif
- unlockShm();
- m_currentSamplePos += bufferSize();
- }
- void RemoteVstPlugin::processMidiEvent( const MidiEvent& event, const f_cnt_t offset )
- {
- VstMidiEvent vme;
- vme.type = kVstMidiType;
- vme.byteSize = 24;
- vme.deltaFrames = offset;
- vme.flags = 0;
- vme.detune = 0;
- vme.noteLength = 0;
- vme.noteOffset = 0;
- vme.noteOffVelocity = 0;
- vme.reserved1 = 0;
- vme.reserved2 = 0;
- vme.midiData[0] = event.type() + event.channel();
- switch( event.type() )
- {
- case MidiPitchBend:
- vme.midiData[1] = event.pitchBend() & 0x7f;
- vme.midiData[2] = event.pitchBend() >> 7;
- break;
- // TODO: handle more special cases
- default:
- vme.midiData[1] = event.key();
- vme.midiData[2] = event.velocity();
- break;
- }
- vme.midiData[3] = 0;
- m_midiEvents.push_back( vme );
- }
- const char * RemoteVstPlugin::pluginName()
- {
- static char buf[32];
- buf[0] = 0;
- pluginDispatch( effGetEffectName, 0, 0, buf );
- buf[31] = 0;
- return buf;
- }
- const char * RemoteVstPlugin::pluginVendorString()
- {
- static char buf[64];
- buf[0] = 0;
- pluginDispatch( effGetVendorString, 0, 0, buf );
- buf[63] = 0;
- return buf;
- }
- const char * RemoteVstPlugin::pluginProductString()
- {
- static char buf[64];
- buf[0] = 0;
- pluginDispatch( effGetProductString, 0, 0, buf );
- buf[63] = 0;
- return buf;
- }
- const char * RemoteVstPlugin::programName()
- {
- static char buf[24];
- memset( buf, 0, sizeof( buf ) );
- pluginDispatch( effGetProgramName, 0, 0, buf );
- buf[23] = 0;
- return buf;
- }
- void RemoteVstPlugin::sendCurrentProgramName()
- {
- char presName[64];
- sprintf( presName, "%d/%d: %s", pluginDispatch( effGetProgram ) + 1, m_plugin->numPrograms, programName() );
- sendMessage( message( IdVstCurrentProgramName ).addString( presName ) );
- }
- void RemoteVstPlugin::getParameterDump()
- {
- message m( IdVstParameterDump );
- m.addInt( m_plugin->numParams );
- for( int i = 0; i < m_plugin->numParams; ++i )
- {
- char paramName[256];
- memset( paramName, 0, sizeof( paramName ) );
- pluginDispatch( effGetParamName, i, 0, paramName );
- paramName[sizeof(paramName)-1] = 0;
- m.addInt( i );
- m.addString( paramName );
- m.addFloat( m_plugin->getParameter( m_plugin, i ) );
- }
- sendMessage( m );
- }
- void RemoteVstPlugin::setParameterDump( const message & _m )
- {
- const int n = _m.getInt( 0 );
- const int params = ( n > m_plugin->numParams ) ?
- m_plugin->numParams : n;
- int p = 0;
- for( int i = 0; i < params; ++i )
- {
- VstParameterDumpItem item;
- item.index = _m.getInt( ++p );
- item.shortLabel = _m.getString( ++p );
- item.value = _m.getFloat( ++p );
- m_plugin->setParameter( m_plugin, item.index, item.value );
- }
- }
- void RemoteVstPlugin::saveChunkToFile( const std::string & _file )
- {
- if( m_plugin->flags & 32 )
- {
- void * chunk = NULL;
- const int len = pluginDispatch( 23, 0, 0, &chunk );
- if( len > 0 )
- {
- FILE* fp = F_OPEN_UTF8( _file, "wb" );
- if (!fp)
- {
- fprintf( stderr,
- "Error opening file for saving chunk.\n" );
- return;
- }
- if ( fwrite( chunk, 1, len, fp ) != len )
- {
- fprintf( stderr,
- "Error saving chunk to file.\n" );
- }
- close_check( fp );
- }
- }
- }
- void RemoteVstPlugin::setProgram( int program )
- {
- if( isInitialized() == false )
- {
- return;
- }
- if( program < 0 )
- {
- program = 0;
- }
- else if( program >= m_plugin->numPrograms )
- {
- program = m_plugin->numPrograms - 1;
- }
- pluginDispatch( effSetProgram, 0, program );
- sendCurrentProgramName();
- }
- void RemoteVstPlugin::rotateProgram( int offset )
- {
- if( isInitialized() == false )
- {
- return;
- }
- int newProgram = pluginDispatch( effGetProgram ) + offset;
- if( newProgram < 0 )
- {
- newProgram = 0;
- }
- else if( newProgram >= m_plugin->numPrograms )
- {
- newProgram = m_plugin->numPrograms - 1;
- }
- pluginDispatch( effSetProgram, 0, newProgram );
- sendCurrentProgramName();
- }
- void RemoteVstPlugin::getProgramNames()
- {
- char presName[1024+256*30];
- char curProgName[30];
- if (isInitialized() == false) return;
- bool progNameIndexed = ( pluginDispatch( 29, 0, -1, curProgName ) == 1 );
- if (m_plugin->numPrograms > 1) {
- if (progNameIndexed) {
- for (int i = 0; i< (m_plugin->numPrograms >= 256?256:m_plugin->numPrograms); i++)
- {
- pluginDispatch( 29, i, -1, curProgName );
- if (i == 0) sprintf( presName, "%s", curProgName );
- else sprintf( presName + strlen(presName), "|%s", curProgName );
- }
- }
- else
- {
- int currProgram = pluginDispatch( effGetProgram );
- for (int i = 0; i< (m_plugin->numPrograms >= 256?256:m_plugin->numPrograms); i++)
- {
- pluginDispatch( effSetProgram, 0, i );
- if (i == 0) sprintf( presName, "%s", programName() );
- else sprintf( presName + strlen(presName), "|%s", programName() );
- }
- pluginDispatch( effSetProgram, 0, currProgram );
- }
- } else sprintf( presName, "%s", programName() );
- presName[sizeof(presName)-1] = 0;
- sendMessage( message( IdVstProgramNames ).addString( presName ) );
- }
- inline unsigned int endian_swap(unsigned int& x)
- {
- return (x>>24) | ((x<<8) & 0x00FF0000) | ((x>>8) & 0x0000FF00) | (x<<24);
- }
- struct sBank
- {
- unsigned int chunkMagic;
- unsigned int byteSize;
- unsigned int fxMagic;
- unsigned int version;
- unsigned int fxID;
- unsigned int fxVersion;
- unsigned int numPrograms;
- char prgName[28];
- };
- void RemoteVstPlugin::savePreset( const std::string & _file )
- {
- unsigned int chunk_size = 0;
- sBank * pBank = ( sBank* ) new char[ sizeof( sBank ) ];
- char progName[ 128 ] = { 0 };
- char* data = NULL;
- const bool chunky = ( m_plugin->flags & ( 1 << 5 ) ) != 0;
- bool isPreset = _file.substr( _file.find_last_of( "." ) + 1 ) == "fxp";
- int presNameLen = _file.find_last_of( "/" ) + _file.find_last_of( "\\" ) + 2;
- if (isPreset)
- {
- for (size_t i = 0; i < _file.length() - 4 - presNameLen; i++)
- progName[i] = i < 23 ? _file[presNameLen + i] : 0;
- pluginDispatch( 4, 0, 0, progName );
- }
- if ( chunky )
- chunk_size = pluginDispatch( 23, isPreset, 0, &data );
- else {
- if (isPreset) {
- chunk_size = m_plugin->numParams * sizeof( float );
- data = new char[ chunk_size ];
- unsigned int* toUIntArray = reinterpret_cast<unsigned int*>( data );
- for ( int i = 0; i < m_plugin->numParams; i++ )
- {
- float value = m_plugin->getParameter( m_plugin, i );
- unsigned int * pValue = ( unsigned int * ) &value;
- toUIntArray[ i ] = endian_swap( *pValue );
- }
- } else chunk_size = (((m_plugin->numParams * sizeof( float )) + 56)*m_plugin->numPrograms);
- }
- pBank->chunkMagic = 0x4B6E6343;
- pBank->byteSize = chunk_size + ( chunky ? sizeof( int ) : 0 ) + 48;
- if (!isPreset) pBank->byteSize += 100;
- pBank->byteSize = endian_swap( pBank->byteSize );
- pBank->fxMagic = chunky ? 0x68435046 : 0x6B437846;
- if (!isPreset && chunky) pBank->fxMagic = 0x68434246;
- if (!isPreset &&!chunky) pBank->fxMagic = 0x6B427846;
- pBank->version = 0x01000000;
- unsigned int uIntToFile = (unsigned int) m_plugin->uniqueID;
- pBank->fxID = endian_swap( uIntToFile );
- uIntToFile = (unsigned int) pluginVersion();
- pBank->fxVersion = endian_swap( uIntToFile );
- uIntToFile = (unsigned int) chunky ? m_plugin->numPrograms : m_plugin->numParams;
- if (!isPreset &&!chunky) uIntToFile = (unsigned int) m_plugin->numPrograms;
- pBank->numPrograms = endian_swap( uIntToFile );
- FILE * stream = F_OPEN_UTF8( _file, "wb" );
- if (!stream)
- {
- fprintf( stderr,
- "Error opening file for saving preset.\n" );
- return;
- }
- fwrite ( pBank, 1, 28, stream );
- fwrite ( progName, 1, isPreset ? 28 : 128, stream );
- if ( chunky ) {
- uIntToFile = endian_swap( chunk_size );
- fwrite ( &uIntToFile, 1, 4, stream );
- }
- if (pBank->fxMagic != 0x6B427846 )
- fwrite ( data, 1, chunk_size, stream );
- else {
- int numPrograms = m_plugin->numPrograms;
- int currProgram = pluginDispatch( effGetProgram );
- chunk_size = (m_plugin->numParams * sizeof( float ));
- pBank->byteSize = chunk_size + 48;
- pBank->byteSize = endian_swap( pBank->byteSize );
- pBank->fxMagic = 0x6B437846;
- uIntToFile = (unsigned int) m_plugin->numParams;
- pBank->numPrograms = endian_swap( uIntToFile );
- data = new char[ chunk_size ];
- unsigned int* pValue,* toUIntArray = reinterpret_cast<unsigned int*>( data );
- float value;
- for (int j = 0; j < numPrograms; j++) {
- pluginDispatch( effSetProgram, 0, j );
- pluginDispatch( effGetProgramName, 0, 0, pBank->prgName );
- fwrite ( pBank, 1, 56, stream );
- for ( int i = 0; i < m_plugin->numParams; i++ )
- {
- value = m_plugin->getParameter( m_plugin, i );
- pValue = ( unsigned int * ) &value;
- toUIntArray[ i ] = endian_swap( *pValue );
- }
- fwrite ( data, 1, chunk_size, stream );
- }
- pluginDispatch( effSetProgram, 0, currProgram );
- }
- fclose( stream );
- if ( !chunky )
- delete[] data;
- delete[] (sBank*)pBank;
- }
- void RemoteVstPlugin::loadPresetFile( const std::string & _file )
- {
- void * chunk = NULL;
- unsigned int * pLen = new unsigned int[ 1 ];
- unsigned int len = 0;
- sBank * pBank = (sBank*) new char[ sizeof( sBank ) ];
- FILE * stream = F_OPEN_UTF8( _file, "rb" );
- if (!stream)
- {
- fprintf( stderr,
- "Error opening file for loading preset.\n" );
- return;
- }
- if ( fread ( pBank, 1, 56, stream ) != 56 )
- {
- fprintf( stderr, "Error loading preset file.\n" );
- }
- pBank->fxID = endian_swap( pBank->fxID );
- pBank->numPrograms = endian_swap( pBank->numPrograms );
- unsigned int toUInt;
- float * pFloat;
- if (m_plugin->uniqueID != pBank->fxID) {
- sendMessage( message( IdVstCurrentProgramName ).
- addString( "Error: Plugin UniqID not match" ) );
- fclose( stream );
- delete[] (unsigned int*)pLen;
- delete[] (sBank*)pBank;
- return;
- }
- if( _file.substr( _file.find_last_of( "." ) + 1 ) != "fxp" )
- fseek ( stream , 156 , SEEK_SET );
- if(pBank->fxMagic != 0x6B427846) {
- if(pBank->fxMagic != 0x6B437846) {
- if ( fread (pLen, 1, 4, stream) != 4 )
- {
- fprintf( stderr,
- "Error loading preset file.\n" );
- }
- chunk = new char[len = endian_swap(*pLen)];
- } else chunk = new char[len = sizeof(float)*pBank->numPrograms];
- if ( fread (chunk, len, 1, stream) != 1 )
- {
- fprintf( stderr, "Error loading preset file.\n" );
- }
- fclose( stream );
- }
- if(_file.substr(_file.find_last_of(".") + 1) == "fxp") {
- pBank->prgName[23] = 0;
- pluginDispatch( 4, 0, 0, pBank->prgName );
- if(pBank->fxMagic != 0x6B437846)
- pluginDispatch( 24, 1, len, chunk );
- else
- {
- unsigned int* toUIntArray = reinterpret_cast<unsigned int*>( chunk );
- for (int i = 0; i < pBank->numPrograms; i++ )
- {
- toUInt = endian_swap( toUIntArray[ i ] );
- pFloat = ( float* ) &toUInt;
- m_plugin->setParameter( m_plugin, i, *pFloat );
- }
- }
- } else {
- if(pBank->fxMagic != 0x6B427846) {
- pluginDispatch( 24, 0, len, chunk );
- } else {
- int numPrograms = pBank->numPrograms;
- unsigned int * toUIntArray;
- int currProgram = pluginDispatch( effGetProgram );
- chunk = new char[ len = sizeof(float)*m_plugin->numParams ];
- toUIntArray = reinterpret_cast<unsigned int *>( chunk );
- for (int i =0; i < numPrograms; i++) {
- if ( fread (pBank, 1, 56, stream) != 56 )
- {
- fprintf( stderr,
- "Error loading preset file.\n" );
- }
- if ( fread (chunk, len, 1, stream) != 1 )
- {
- fprintf( stderr,
- "Error loading preset file.\n" );
- }
- pluginDispatch( effSetProgram, 0, i );
- pBank->prgName[23] = 0;
- pluginDispatch( 4, 0, 0, pBank->prgName );
- for (int j = 0; j < m_plugin->numParams; j++ ) {
- toUInt = endian_swap( toUIntArray[ j ] );
- pFloat = ( float* ) &toUInt;
- m_plugin->setParameter( m_plugin, j, *pFloat );
- }
- }
- pluginDispatch( effSetProgram, 0, currProgram );
- fclose( stream );
- }
- }
- sendCurrentProgramName();
- delete[] (unsigned int*)pLen;
- delete[] (sBank*)pBank;
- delete[] (char*)chunk;
- }
- void RemoteVstPlugin::loadChunkFromFile( const std::string & _file, int _len )
- {
- char * chunk = new char[_len];
- FILE* fp = F_OPEN_UTF8( _file, "rb" );
- if (!fp)
- {
- fprintf( stderr,
- "Error opening file for loading chunk.\n" );
- return;
- }
- if ( fread( chunk, 1, _len, fp ) != _len )
- {
- fprintf( stderr, "Error loading chunk from file.\n" );
- }
- close_check( fp );
- pluginDispatch( effSetChunk, 0, _len, chunk );
- delete[] chunk;
- }
- int RemoteVstPlugin::updateInOutCount()
- {
- if( inputCount() == RemotePluginClient::inputCount() &&
- outputCount() == RemotePluginClient::outputCount() )
- {
- return 1;
- }
-
- if( GetCurrentThreadId() == __processingThreadId )
- {
- debugMessage( "Plugin requested I/O change from processing "
- "thread. Request denied; stability may suffer.\n" );
- return 0;
- }
- lockShm();
- setShmIsValid( false );
- unlockShm();
- delete[] m_inputs;
- delete[] m_outputs;
- m_inputs = NULL;
- m_outputs = NULL;
- setInputOutputCount( inputCount(), outputCount() );
- char buf[64];
- sprintf( buf, "inputs: %d output: %d\n", inputCount(), outputCount() );
- debugMessage( buf );
- if( inputCount() > 0 )
- {
- m_inputs = new float * [inputCount()];
- }
- if( outputCount() > 0 )
- {
- m_outputs = new float * [outputCount()];
- }
- return 1;
- }
- //#define DEBUG_CALLBACKS
- #ifdef DEBUG_CALLBACKS
- #define SHOW_CALLBACK __plugin->debugMessage
- #else
- #define SHOW_CALLBACK(...)
- #endif
- /* TODO:
- * - complete audioMasterGetTime-handling (bars etc.)
- * - implement audioMasterProcessEvents
- * - audioMasterGetVendorVersion: return LMMS-version (config.h!)
- * - audioMasterGetDirectory: return either VST-plugin-dir or LMMS-workingdir
- * - audioMasterOpenFileSelector: show QFileDialog?
- */
- intptr_t RemoteVstPlugin::hostCallback( AEffect * _effect, int32_t _opcode,
- int32_t _index, intptr_t _value,
- void * _ptr, float _opt )
- {
- static VstTimeInfo _timeInfo;
- #ifdef DEBUG_CALLBACKS
- char buf[64];
- sprintf( buf, "host-callback, opcode = %d\n", (int) _opcode );
- SHOW_CALLBACK( buf );
- #endif
- // workaround for early callbacks by some plugins
- if( __plugin && __plugin->m_plugin == NULL )
- {
- __plugin->m_plugin = _effect;
- }
- switch( _opcode )
- {
- case audioMasterAutomate:
- SHOW_CALLBACK( "amc: audioMasterAutomate\n" );
- // index, value, returns 0
- return 0;
- case audioMasterVersion:
- SHOW_CALLBACK( "amc: audioMasterVersion\n" );
- return 2300;
- case audioMasterCurrentId:
- SHOW_CALLBACK( "amc: audioMasterCurrentId\n" );
- // returns the unique id of a plug that's currently
- // loading
- return 0;
- case audioMasterIdle:
- SHOW_CALLBACK ("amc: audioMasterIdle\n" );
- // call application idle routine (this will
- // call effEditIdle for all open editors too)
- PostMessage( __MessageHwnd, WM_USER, GiveIdle, 0 );
- return 0;
- case audioMasterPinConnected:
- SHOW_CALLBACK( "amc: audioMasterPinConnected\n" );
- // inquire if an input or output is beeing connected;
- // index enumerates input or output counting from zero:
- // value is 0 for input and != 0 otherwise. note: the
- // return value is 0 for <true> such that older versions
- // will always return true.
- return 0;
- case audioMasterGetTime:
- SHOW_CALLBACK( "amc: audioMasterGetTime\n" );
- // returns const VstTimeInfo* (or 0 if not supported)
- // <value> should contain a mask indicating which
- // fields are required (see valid masks above), as some
- // items may require extensive conversions
- // Shared memory was initialised? - see song.cpp
- //assert( __plugin->m_vstSyncData != NULL );
- memset( &_timeInfo, 0, sizeof( _timeInfo ) );
- _timeInfo.samplePos = __plugin->m_currentSamplePos;
- _timeInfo.sampleRate = __plugin->m_vstSyncData->hasSHM ?
- __plugin->m_vstSyncData->m_sampleRate :
- __plugin->sampleRate();
- _timeInfo.flags = 0;
- _timeInfo.tempo = __plugin->m_vstSyncData->hasSHM ?
- __plugin->m_vstSyncData->m_bpm :
- __plugin->m_bpm;
- _timeInfo.timeSigNumerator = __plugin->m_vstSyncData->timeSigNumer;
- _timeInfo.timeSigDenominator = __plugin->m_vstSyncData->timeSigDenom;
- _timeInfo.flags |= kVstTempoValid;
- _timeInfo.flags |= kVstTimeSigValid;
- if( __plugin->m_vstSyncData->isCycle )
- {
- _timeInfo.cycleStartPos = __plugin->m_vstSyncData->cycleStart;
- _timeInfo.cycleEndPos = __plugin->m_vstSyncData->cycleEnd;
- _timeInfo.flags |= kVstCyclePosValid;
- _timeInfo.flags |= kVstTransportCycleActive;
- }
- if( __plugin->m_vstSyncData->ppqPos !=
- __plugin->m_in->m_Timestamp )
- {
- _timeInfo.ppqPos = __plugin->m_vstSyncData->ppqPos;
- __plugin->m_in->lastppqPos = __plugin->m_vstSyncData->ppqPos;
- __plugin->m_in->m_Timestamp = __plugin->m_vstSyncData->ppqPos;
- }
- else if( __plugin->m_vstSyncData->isPlaying )
- {
- if( __plugin->m_vstSyncData->hasSHM )
- {
- __plugin->m_in->lastppqPos +=
- __plugin->m_vstSyncData->m_bpm / 60.0
- * __plugin->m_vstSyncData->m_bufferSize
- / __plugin->m_vstSyncData->m_sampleRate;
- }
- else
- {
- __plugin->m_in->lastppqPos +=
- __plugin->m_bpm / 60.0
- * __plugin->bufferSize()
- / __plugin->sampleRate();
- }
- _timeInfo.ppqPos = __plugin->m_in->lastppqPos;
- }
- // _timeInfo.ppqPos = __plugin->m_vstSyncData->ppqPos;
- _timeInfo.flags |= kVstPpqPosValid;
- if( __plugin->m_vstSyncData->isPlaying )
- {
- _timeInfo.flags |= kVstTransportPlaying;
- }
- _timeInfo.barStartPos = ( (int) ( _timeInfo.ppqPos /
- ( 4 *__plugin->m_vstSyncData->timeSigNumer
- / (float) __plugin->m_vstSyncData->timeSigDenom ) ) ) *
- ( 4 * __plugin->m_vstSyncData->timeSigNumer
- / (float) __plugin->m_vstSyncData->timeSigDenom );
- _timeInfo.flags |= kVstBarsValid;
- if( ( _timeInfo.flags & ( kVstTransportPlaying | kVstTransportCycleActive ) ) !=
- ( __plugin->m_in->m_lastFlags & ( kVstTransportPlaying | kVstTransportCycleActive ) )
- || __plugin->m_vstSyncData->m_playbackJumped )
- {
- _timeInfo.flags |= kVstTransportChanged;
- }
- __plugin->m_in->m_lastFlags = _timeInfo.flags;
- #ifdef LMMS_BUILD_WIN64
- return (long long) &_timeInfo;
- #else
- return (long) &_timeInfo;
- #endif
- case audioMasterProcessEvents:
- SHOW_CALLBACK( "amc: audioMasterProcessEvents\n" );
- // VstEvents* in <ptr>
- return 0;
- case audioMasterIOChanged:
- SHOW_CALLBACK( "amc: audioMasterIOChanged\n" );
- // numInputs, numOutputs, and/or latency has changed
- return __plugin->updateInOutCount();
- #ifdef OLD_VST_SDK
- case audioMasterWantMidi:
- SHOW_CALLBACK( "amc: audioMasterWantMidi\n" );
- // <value> is a filter which is currently ignored
- return 1;
- case audioMasterSetTime:
- SHOW_CALLBACK( "amc: audioMasterSetTime\n" );
- // VstTimenfo* in <ptr>, filter in <value>, not
- // supported
- return 0;
- case audioMasterTempoAt:
- SHOW_CALLBACK( "amc: audioMasterTempoAt\n" );
- return __plugin->m_bpm * 10000;
- case audioMasterGetNumAutomatableParameters:
- SHOW_CALLBACK( "amc: audioMasterGetNumAutomatable"
- "Parameters\n" );
- return 5000;
- case audioMasterGetParameterQuantization:
- SHOW_CALLBACK( "amc: audioMasterGetParameter\n"
- "Quantization\n" );
- // returns the integer value for +1.0 representation,
- // or 1 if full single float precision is maintained
- // in automation. parameter index in <value> (-1: all,
- // any)
- return 1;
- case audioMasterNeedIdle:
- SHOW_CALLBACK( "amc: audioMasterNeedIdle\n" );
- // plug needs idle calls (outside its editor window)
- return 1;
- case audioMasterGetPreviousPlug:
- SHOW_CALLBACK( "amc: audioMasterGetPreviousPlug\n" );
- // input pin in <value> (-1: first to come), returns
- // cEffect*
- return 0;
- case audioMasterGetNextPlug:
- SHOW_CALLBACK( "amc: audioMasterGetNextPlug\n" );
- // output pin in <value> (-1: first to come), returns
- // cEffect*
- return 0;
- case audioMasterWillReplaceOrAccumulate:
- SHOW_CALLBACK( "amc: audioMasterWillReplaceOr"
- "Accumulate\n" );
- // returns: 0: not supported, 1: replace, 2: accumulate
- return 1;
- case audioMasterGetSpeakerArrangement:
- SHOW_CALLBACK( "amc: audioMasterGetSpeaker"
- "Arrangement\n" );
- // (long)input in <value>, output in <ptr>
- return 0;
- case audioMasterSetOutputSampleRate:
- SHOW_CALLBACK( "amc: audioMasterSetOutputSample"
- "Rate\n" );
- // for variable i/o, sample rate in <opt>
- return 0;
- case audioMasterSetIcon:
- SHOW_CALLBACK( "amc: audioMasterSetIcon\n" );
- // TODO
- // void* in <ptr>, format not defined yet
- return 0;
- case audioMasterOpenWindow:
- SHOW_CALLBACK( "amc: audioMasterOpenWindow\n" );
- // TODO
- // returns platform specific ptr
- return 0;
- case audioMasterCloseWindow:
- SHOW_CALLBACK( "amc: audioMasterCloseWindow\n" );
- // TODO
- // close window, platform specific handle in <ptr>
- return 0;
- #endif
- case audioMasterSizeWindow:
- {
- SHOW_CALLBACK( "amc: audioMasterSizeWindow\n" );
- if( __plugin->m_window == 0 )
- {
- return 0;
- }
- __plugin->m_windowWidth = _index;
- __plugin->m_windowHeight = _value;
- HWND window = __plugin->m_window;
- DWORD dwStyle = GetWindowLongPtr( window, GWL_STYLE );
- RECT windowSize = { 0, 0, (int) _index, (int) _value };
- AdjustWindowRect( &windowSize, dwStyle, false );
- SetWindowPos( window, 0, 0, 0,
- windowSize.right - windowSize.left,
- windowSize.bottom - windowSize.top,
- SWP_NOACTIVATE | SWP_NOMOVE |
- SWP_NOOWNERZORDER | SWP_NOZORDER );
- __plugin->sendMessage(
- message( IdVstPluginEditorGeometry ).
- addInt( __plugin->m_windowWidth ).
- addInt( __plugin->m_windowHeight ) );
- return 1;
- }
- case audioMasterGetSampleRate:
- SHOW_CALLBACK( "amc: audioMasterGetSampleRate\n" );
- return __plugin->sampleRate();
- case audioMasterGetBlockSize:
- SHOW_CALLBACK( "amc: audioMasterGetBlockSize\n" );
- return __plugin->bufferSize();
- case audioMasterGetInputLatency:
- SHOW_CALLBACK( "amc: audioMasterGetInputLatency\n" );
- return __plugin->bufferSize();
- case audioMasterGetOutputLatency:
- SHOW_CALLBACK( "amc: audioMasterGetOutputLatency\n" );
- return __plugin->bufferSize();
- case audioMasterGetCurrentProcessLevel:
- SHOW_CALLBACK( "amc: audioMasterGetCurrentProcess"
- "Level\n" );
- // returns: 0: not supported,
- // 1: currently in user thread (gui)
- // 2: currently in audio thread (where process is
- // called)
- // 3: currently in 'sequencer' thread (midi, timer etc)
- // 4: currently offline processing and thus in user
- // thread
- // other: not defined, but probably pre-empting user
- // thread.
- return 0;
- case audioMasterGetAutomationState:
- SHOW_CALLBACK( "amc: audioMasterGetAutomationState\n" );
- // returns 0: not supported, 1: off, 2:read, 3:write,
- // 4:read/write offline
- return 0;
- case audioMasterOfflineStart:
- SHOW_CALLBACK( "amc: audioMasterOfflineStart\n" );
- return 0;
- case audioMasterOfflineRead:
- SHOW_CALLBACK( "amc: audioMasterOfflineRead\n" );
- // ptr points to offline structure, see below.
- // return 0: error, 1 ok
- return 0;
- case audioMasterOfflineWrite:
- SHOW_CALLBACK( "amc: audioMasterOfflineWrite\n" );
- // same as read
- return 0;
- case audioMasterOfflineGetCurrentPass:
- SHOW_CALLBACK( "amc: audioMasterOfflineGetCurrent"
- "Pass\n" );
- return 0;
- case audioMasterOfflineGetCurrentMetaPass:
- SHOW_CALLBACK( "amc: audioMasterOfflineGetCurrentMeta"
- "Pass\n");
- return 0;
- case audioMasterGetVendorString:
- SHOW_CALLBACK( "amc: audioMasterGetVendorString\n" );
- // fills <ptr> with a string identifying the vendor
- // (max 64 char)
- strcpy( (char *) _ptr, "Tobias Doerffel" );
- return 1;
- case audioMasterGetProductString:
- SHOW_CALLBACK( "amc: audioMasterGetProductString\n" );
- // fills <ptr> with a string with product name
- // (max 64 char)
- strcpy( (char *) _ptr,
- "LMMS VST Support Layer (LVSL)" );
- return 1;
- case audioMasterGetVendorVersion:
- SHOW_CALLBACK( "amc: audioMasterGetVendorVersion\n" );
- // returns vendor-specific version
- return 1000;
- case audioMasterVendorSpecific:
- SHOW_CALLBACK( "amc: audioMasterVendorSpecific\n" );
- // no definition, vendor specific handling
- return 0;
- case audioMasterCanDo:
- SHOW_CALLBACK( "amc: audioMasterCanDo\n" );
- return !strcmp( (char *) _ptr, "sendVstEvents" ) ||
- !strcmp( (char *) _ptr, "sendVstMidiEvent" ) ||
- !strcmp( (char *) _ptr, "sendVstTimeInfo" ) ||
- !strcmp( (char *) _ptr, "sizeWindow" ) ||
- !strcmp( (char *) _ptr, "supplyIdle" );
- case audioMasterGetLanguage:
- SHOW_CALLBACK( "amc: audioMasterGetLanguage\n" );
- return hlang;
- case audioMasterGetDirectory:
- SHOW_CALLBACK( "amc: audioMasterGetDirectory\n" );
- // get plug directory, FSSpec on MAC, else char*
- return 0;
- case audioMasterUpdateDisplay:
- SHOW_CALLBACK( "amc: audioMasterUpdateDisplay\n" );
- // something has changed, update 'multi-fx' display
- PostMessage( __MessageHwnd, WM_USER, GiveIdle, 0 );
- return 0;
- #if kVstVersion > 2
- case audioMasterBeginEdit:
- SHOW_CALLBACK( "amc: audioMasterBeginEdit\n" );
- // begin of automation session (when mouse down),
- // parameter index in <index>
- return 0;
- case audioMasterEndEdit:
- SHOW_CALLBACK( "amc: audioMasterEndEdit\n" );
- // end of automation session (when mouse up),
- // parameter index in <index>
- return 0;
- case audioMasterOpenFileSelector:
- SHOW_CALLBACK( "amc: audioMasterOpenFileSelector\n" );
- // open a fileselector window with VstFileSelect*
- // in <ptr>
- return 0;
- #endif
- default:
- SHOW_CALLBACK( "amd: not handled" );
- break;
- }
- return 0;
- }
- void RemoteVstPlugin::idle()
- {
- if( isProcessing() )
- {
- setShouldGiveIdle( true );
- return;
- }
- setProcessing( true );
- pluginDispatch( effEditIdle );
- setShouldGiveIdle( false );
- setProcessing( false );
- // We might have received a message whilst idling
- processUIThreadMessages();
- }
- void RemoteVstPlugin::processUIThreadMessages()
- {
- setProcessing( true );
- while( m_messageList.size() )
- {
- processMessage( m_messageList.front() );
- m_messageList.pop();
- if( shouldGiveIdle() )
- {
- pluginDispatch( effEditIdle );
- setShouldGiveIdle( false );
- }
- }
- setProcessing( false );
- }
- DWORD WINAPI RemoteVstPlugin::processingThread( LPVOID _param )
- {
- __processingThreadId = GetCurrentThreadId();
- RemoteVstPlugin * _this = static_cast<RemoteVstPlugin *>( _param );
- RemotePluginClient::message m;
- while( ( m = _this->receiveMessage() ).id != IdQuit )
- {
- if( m.id == IdStartProcessing
- || m.id == IdMidiEvent
- || m.id == IdVstSetParameter
- || m.id == IdVstSetTempo )
- {
- _this->processMessage( m );
- }
- else if( m.id == IdChangeSharedMemoryKey )
- {
- _this->processMessage( m );
- _this->setShmIsValid( true );
- }
- else
- {
- PostMessage( __MessageHwnd,
- WM_USER,
- ProcessPluginMessage,
- (LPARAM) new message( m ) );
- }
- }
- // notify GUI thread about shutdown
- PostMessage( __MessageHwnd, WM_USER, ClosePlugin, 0 );
- return 0;
- }
- bool RemoteVstPlugin::setupMessageWindow()
- {
- HMODULE hInst = GetModuleHandle( NULL );
- if( hInst == NULL )
- {
- __plugin->debugMessage( "setupMessageWindow(): can't get "
- "module handle\n" );
- return false;
- }
- __MessageHwnd = CreateWindowEx( 0, "LVSL", "dummy",
- 0, 0, 0, 0, 0, NULL, NULL,
- hInst, NULL );
- // install GUI update timer
- SetTimer( __MessageHwnd, 1000, 50, NULL );
- return true;
- }
- DWORD WINAPI RemoteVstPlugin::guiEventLoop()
- {
- MSG msg;
- while( GetMessage( &msg, NULL, 0, 0 ) > 0 )
- {
- TranslateMessage( &msg );
- DispatchMessage( &msg );
- }
- return 0;
- }
- LRESULT CALLBACK RemoteVstPlugin::wndProc( HWND hwnd, UINT uMsg,
- WPARAM wParam, LPARAM lParam )
- {
- if( uMsg == WM_TIMER && __plugin->isInitialized() )
- {
- // give plugin some idle-time for GUI-update
- __plugin->idle();
- return 0;
- }
- else if( uMsg == WM_USER )
- {
- switch( wParam )
- {
- case ProcessPluginMessage:
- {
- message * m = (message *) lParam;
- __plugin->queueMessage( *m );
- delete m;
- if( !__plugin->isProcessing() )
- {
- __plugin->processUIThreadMessages();
- }
- return 0;
- }
- case GiveIdle:
- __plugin->idle();
- return 0;
- case ClosePlugin:
- PostQuitMessage(0);
- return 0;
- default:
- break;
- }
- }
- else if( uMsg == WM_SYSCOMMAND && (wParam & 0xfff0) == SC_CLOSE )
- {
- __plugin->hideEditor();
- return 0;
- }
- return DefWindowProc( hwnd, uMsg, wParam, lParam );
- }
- int main( int _argc, char * * _argv )
- {
- #ifdef SYNC_WITH_SHM_FIFO
- if( _argc < 4 )
- #else
- if( _argc < 3 )
- #endif
- {
- fprintf( stderr, "not enough arguments\n" );
- return -1;
- }
- OleInitialize(nullptr);
- #ifdef LMMS_BUILD_WIN32
- #ifndef __WINPTHREADS_VERSION
- // (non-portable) initialization of statically linked pthread library
- pthread_win32_process_attach_np();
- pthread_win32_thread_attach_np();
- #endif
- #endif
- #ifdef LMMS_BUILD_LINUX
- #ifdef LMMS_HAVE_SCHED_H
- // try to set realtime-priority
- struct sched_param sparam;
- sparam.sched_priority = ( sched_get_priority_max( SCHED_FIFO ) +
- sched_get_priority_min( SCHED_FIFO ) ) / 2;
- sched_setscheduler( 0, SCHED_FIFO, &sparam );
- #endif
- #endif
- #ifdef LMMS_BUILD_WIN32
- if( !SetPriorityClass( GetCurrentProcess(), HIGH_PRIORITY_CLASS ) )
- {
- printf( "Notice: could not set high priority.\n" );
- }
- #endif
- HMODULE hInst = GetModuleHandle( NULL );
- if( hInst == NULL )
- {
- return -1;
- }
- WNDCLASS wc;
- wc.style = CS_HREDRAW | CS_VREDRAW;
- wc.lpfnWndProc = RemoteVstPlugin::wndProc;
- wc.cbClsExtra = 0;
- wc.cbWndExtra = 0;
- wc.hInstance = hInst;
- wc.hIcon = LoadIcon( NULL, IDI_APPLICATION );
- wc.hCursor = LoadCursor( NULL, IDC_ARROW );
- wc.hbrBackground = NULL;
- wc.lpszMenuName = NULL;
- wc.lpszClassName = "LVSL";
- if( !RegisterClass( &wc ) )
- {
- return -1;
- }
- {
- #ifdef SYNC_WITH_SHM_FIFO
- int embedMethodIndex = 3;
- #else
- int embedMethodIndex = 2;
- #endif
- std::string embedMethod = _argv[embedMethodIndex];
- if ( embedMethod == "none" )
- {
- cerr << "Starting detached." << endl;
- EMBED = EMBED_X11 = EMBED_WIN32 = HEADLESS = false;
- }
- else if ( embedMethod == "win32" )
- {
- cerr << "Starting using Win32-native embedding." << endl;
- EMBED = EMBED_WIN32 = true; EMBED_X11 = HEADLESS = false;
- }
- else if ( embedMethod == "qt" )
- {
- cerr << "Starting using Qt-native embedding." << endl;
- EMBED = true; EMBED_X11 = EMBED_WIN32 = HEADLESS = false;
- }
- else if ( embedMethod == "xembed" )
- {
- cerr << "Starting using X11Embed protocol." << endl;
- EMBED = EMBED_X11 = true; EMBED_WIN32 = HEADLESS = false;
- }
- else if ( embedMethod == "headless" )
- {
- cerr << "Starting without UI." << endl;
- HEADLESS = true; EMBED = EMBED_X11 = EMBED_WIN32 = false;
- }
- else
- {
- cerr << "Unknown embed method " << embedMethod << ". Starting detached instead." << endl;
- EMBED = EMBED_X11 = EMBED_WIN32 = HEADLESS = false;
- }
- }
- // constructor automatically will process messages until it receives
- // a IdVstLoadPlugin message and processes it
- #ifdef SYNC_WITH_SHM_FIFO
- __plugin = new RemoteVstPlugin( atoi( _argv[1] ), atoi( _argv[2] ) );
- #else
- __plugin = new RemoteVstPlugin( _argv[1] );
- #endif
- if( __plugin->isInitialized() )
- {
- if( RemoteVstPlugin::setupMessageWindow() == false )
- {
- return -1;
- }
- if( CreateThread( NULL, 0, RemoteVstPlugin::processingThread,
- __plugin, 0, NULL ) == NULL )
- {
- __plugin->debugMessage( "could not create "
- "processingThread\n" );
- return -1;
- }
- RemoteVstPlugin::guiEventLoop();
- }
- delete __plugin;
- OleUninitialize();
- #ifdef LMMS_BUILD_WIN32
- #ifndef __WINPTHREADS_VERSION
- pthread_win32_thread_detach_np();
- pthread_win32_process_detach_np();
- #endif
- #endif
- return 0;
- }
|