2 * RemoteVstPlugin.cpp - LMMS VST Support Layer (RemotePlugin client)
4 * Copyright (c) 2005-2010 Tobias Doerffel <tobydox/at/users.sourceforge.net>
6 * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
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
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.
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.
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.
31 #include "lmmsconfig.h"
33 #define BUILD_REMOTE_PLUGIN_CLIENT
35 #include "RemotePlugin.h"
37 #ifdef LMMS_HAVE_PTHREAD_H
41 #ifdef LMMS_HAVE_FCNTL_H
45 #ifdef LMMS_BUILD_LINUX
51 #ifdef LMMS_HAVE_SCHED_H
55 #include <wine/exception.h>
61 #ifdef LMMS_BUILD_WIN32
62 #ifdef LMMS_BUILD_WIN64
76 #if kVstVersion < 2400
91 #include "lmms_basics.h"
93 #include "communication.h"
97 static VstHostLanguages hlang
= LanguageEnglish
;
100 class RemoteVstPlugin
;
102 RemoteVstPlugin
* __plugin
= NULL
;
104 DWORD __GuiThreadID
= 0;
108 class RemoteVstPlugin
: public RemotePluginClient
111 RemoteVstPlugin( key_t _shm_in
, key_t _shm_out
);
112 virtual ~RemoteVstPlugin();
114 virtual bool processMessage( const message
& _m
);
116 void init( const std::string
& _plugin_file
);
119 virtual void process( const sampleFrame
* _in
, sampleFrame
* _out
);
122 virtual void processMidiEvent( const midiEvent
& _event
,
123 const f_cnt_t _offset
);
125 // set given sample-rate for plugin
126 virtual void updateSampleRate()
128 pluginDispatch( effSetSampleRate
, 0, 0,
129 NULL
, (float) sampleRate() );
132 // set given buffer-size for plugin
133 virtual void updateBufferSize()
135 pluginDispatch( effSetBlockSize
, 0, bufferSize() );
139 inline bool isInitialized() const
141 return m_initialized
;
146 void setBPM( const bpm_t _bpm
)
151 // determine VST-version the plugin uses
152 inline int pluginVersion()
154 return pluginDispatch( effGetVendorVersion
);
157 // determine name of plugin
158 const char * pluginName();
160 // determine vendor of plugin
161 const char * pluginVendorString();
163 // determine product-string of plugin
164 const char * pluginProductString();
166 // determine name of plugipn preset
167 const char * presetName();
169 // do a complete parameter-dump and post it
170 void getParameterDump();
172 // read parameter-dump and set it for plugin
173 void setParameterDump( const message
& _m
);
175 // post properties of specified parameter
176 void getParameterProperties( const int _idx
);
178 // save settings chunk of plugin into file
179 void saveChunkToFile( const std::string
& _file
);
181 // restore settings chunk of plugin from file
182 void loadChunkFromFile( const std::string
& _file
, int _len
);
184 // restore settings chunk of plugin from file
185 void loadChunkFromPresetFile( const std::string
& _file
);
187 // restore settings chunk of plugin from file
188 void rotateProgram( int _len
);
190 // Load names VST of presets/programs
191 void loadPrograms( int _len
);
193 // Save presets/programs
194 void savePreset( const std::string
& _file
);
197 virtual int inputCount() const
201 return m_plugin
->numInputs
;
207 virtual int outputCount() const
211 return m_plugin
->numOutputs
;
216 // has to be called as soon as input- or output-count changes
217 void updateInOutCount();
221 pthread_mutex_lock( &m_pluginLock
);
226 pthread_mutex_unlock( &m_pluginLock
);
229 static DWORD WINAPI
processingThread( LPVOID _param
);
230 static DWORD WINAPI
guiEventLoop( LPVOID _param
);
234 enum GuiThreadMessages
237 ProcessPluginMessage
,
242 // callback used by plugin for being able to communicate with it's host
243 static intptr_t hostCallback( AEffect
* _effect
, int32_t _opcode
,
244 int32_t _index
, intptr_t _value
,
245 void * _ptr
, float _opt
);
248 bool load( const std::string
& _plugin_file
);
250 // thread-safe dispatching of plugin
251 int pluginDispatch( int cmd
, int param1
= 0, int param2
= 0,
252 void * p
= NULL
, float f
= 0 )
258 ret
= m_plugin
->dispatcher( m_plugin
, cmd
, param1
,
265 std::string m_shortName
;
277 pthread_mutex_t m_pluginLock
;
283 typedef std::vector
<VstMidiEvent
> VstMidiEventList
;
284 VstMidiEventList m_midiEvents
;
287 double m_currentSamplePos
;
294 RemoteVstPlugin::RemoteVstPlugin( key_t _shm_in
, key_t _shm_out
) :
295 RemotePluginClient( _shm_in
, _shm_out
),
303 m_initialized( false ),
309 m_currentSamplePos( 0 )
311 pthread_mutex_init( &m_pluginLock
, NULL
);
315 // process until we have loaded the plugin
318 message m
= receiveMessage();
320 if( m
.id
== IdVstLoadPlugin
|| m
.id
== IdQuit
)
330 RemoteVstPlugin::~RemoteVstPlugin()
332 if( m_window
!= NULL
)
334 pluginDispatch( effEditClose
);
335 #ifdef LMMS_BUILD_LINUX
336 CloseWindow( m_window
);
341 if( m_libInst
!= NULL
)
343 FreeLibrary( m_libInst
);
350 pthread_mutex_destroy( &m_pluginLock
);
356 bool RemoteVstPlugin::processMessage( const message
& _m
)
360 case IdVstLoadPlugin
:
361 init( _m
.getString() );
364 #ifdef LMMS_BUILD_WIN32
365 case IdVstPluginWindowInformation
:
367 HWND top
= FindWindowEx( NULL
, NULL
, NULL
,
368 _m
.getString().c_str() );
369 m_window
= FindWindowEx( top
, NULL
, NULL
, NULL
);
375 setBPM( _m
.getInt() );
378 case IdVstSetLanguage
:
379 hlang
= static_cast<VstHostLanguages
>( _m
.getInt() );
382 case IdVstGetParameterDump
:
386 case IdVstSetParameterDump
:
387 setParameterDump( _m
);
390 case IdVstGetParameterProperties
:
391 getParameterProperties( _m
.getInt() );
394 case IdSaveSettingsToFile
:
395 saveChunkToFile( _m
.getString() );
396 sendMessage( IdSaveSettingsToFile
);
399 case IdLoadSettingsFromFile
:
400 loadChunkFromFile( _m
.getString( 0 ), _m
.getInt( 1 ) );
401 sendMessage( IdLoadSettingsFromFile
);
404 case IdLoadChunkFromPresetFile
:
405 loadChunkFromPresetFile( _m
.getString( 0 ) );
406 sendMessage( IdLoadChunkFromPresetFile
);
409 case IdRotateProgram
:
410 rotateProgram( _m
.getInt( 0 ) );
411 sendMessage( IdRotateProgram
);
415 loadPrograms( _m
.getInt( 0 ) );
416 sendMessage( IdLoadPrograms
);
420 savePreset( _m
.getString( 0 ) );
421 sendMessage( IdSavePreset
);
425 m_plugin
->setParameter( m_plugin
, _m
.getInt( 0 ), _m
.getFloat( 1 ) );
426 sendMessage( IdSetParameter
);
432 return RemotePluginClient::processMessage( _m
);
440 void RemoteVstPlugin::init( const std::string
& _plugin_file
)
442 if( load( _plugin_file
) == false )
444 sendMessage( IdVstFailedLoadingPlugin
);
450 /* set program to zero */
451 /* i comment this out because it breaks dfx Geometer
452 * looks like we cant set programs for it
454 pluginDispatch( effSetProgram, 0, 0 ); */
455 // request rate and blocksize
457 pluginDispatch( effMainsChanged
, 0, 1 );
459 debugMessage( "creating editor\n" );
461 debugMessage( "editor successfully created\n" );
464 // now post some information about our plugin
465 sendMessage( message( IdVstPluginWindowID
).addInt( m_windowID
) );
467 sendMessage( message( IdVstPluginEditorGeometry
).
468 addInt( m_windowWidth
).
469 addInt( m_windowHeight
) );
471 sendMessage( message( IdVstPluginName
).addString( pluginName() ) );
472 sendMessage( message( IdVstPluginVersion
).addInt( pluginVersion() ) );
473 sendMessage( message( IdVstPluginVendorString
).
474 addString( pluginVendorString() ) );
475 sendMessage( message( IdVstPluginProductString
).
476 addString( pluginProductString() ) );
477 sendMessage( message( IdVstParameterCount
).
478 addInt( m_plugin
->numParams
) );
480 sendMessage( IdInitDone
);
482 m_initialized
= true;
488 void RemoteVstPlugin::initEditor()
490 if( !( m_plugin
->flags
& effFlagsHasEditor
) )
496 HMODULE hInst
= GetModuleHandle( NULL
);
499 debugMessage( "initEditor(): can't get module handle\n" );
505 wc
.style
= CS_HREDRAW
| CS_VREDRAW
;
506 wc
.lpfnWndProc
= DefWindowProc
;
509 wc
.hInstance
= hInst
;
510 wc
.hIcon
= LoadIcon( NULL
, IDI_APPLICATION
);
511 wc
.hCursor
= LoadCursor( NULL
, IDC_ARROW
);
512 wc
.hbrBackground
= (HBRUSH
) GetStockObject( BLACK_BRUSH
);
513 wc
.lpszMenuName
= NULL
;
514 wc
.lpszClassName
= "LVSL";
516 if( !RegisterClass( &wc
) )
521 #ifdef LMMS_BUILD_LINUX
522 m_window
= CreateWindowEx( 0, "LVSL", m_shortName
.c_str(),
523 ( WS_OVERLAPPEDWINDOW
| WS_THICKFRAME
) & ~WS_MAXIMIZEBOX
,
524 0, 0, 10, 10, NULL
, NULL
, hInst
, NULL
);
527 m_windowID
= 1; // arbitrary value on win32 to signal
528 // vstPlugin-class that we have an editor
530 m_window
= CreateWindowEx( 0, "LVSL", m_shortName
.c_str(),
531 WS_CHILD
, 0, 0, 10, 10,
532 m_window
, NULL
, hInst
, NULL
);
534 if( m_window
== NULL
)
536 debugMessage( "initEditor(): cannot create editor window\n" );
541 pluginDispatch( effEditOpen
, 0, 0, m_window
);
544 pluginDispatch( effEditGetRect
, 0, 0, &er
);
546 m_windowWidth
= er
->right
- er
->left
;
547 m_windowHeight
= er
->bottom
- er
->top
;
549 SetWindowPos( m_window
, 0, 0, 0, m_windowWidth
+ 8,
550 m_windowHeight
+ 26, SWP_NOACTIVATE
|
551 SWP_NOMOVE
| SWP_NOZORDER
);
552 pluginDispatch( effEditTop
);
554 ShowWindow( m_window
, SW_SHOWNORMAL
);
555 UpdateWindow( m_window
);
557 #ifdef LMMS_BUILD_LINUX
558 m_windowID
= (Sint32
) GetProp( m_window
, "__wine_x11_whole_window" );
565 bool RemoteVstPlugin::load( const std::string
& _plugin_file
)
567 if( ( m_libInst
= LoadLibrary( _plugin_file
.c_str() ) ) == NULL
)
569 // give VstPlugin class a chance to start 32 bit version of RemoteVstPlugin
570 if( GetLastError() == ERROR_BAD_EXE_FORMAT
)
572 sendMessage( IdVstBadDllFormat
);
577 char * tmp
= strdup( _plugin_file
.c_str() );
578 m_shortName
= basename( tmp
);
581 typedef AEffect
* ( __stdcall
* mainEntryPointer
)
582 ( audioMasterCallback
);
583 mainEntryPointer mainEntry
= (mainEntryPointer
)
584 GetProcAddress( m_libInst
, "VSTPluginMain" );
585 if( mainEntry
== NULL
)
587 mainEntry
= (mainEntryPointer
)
588 GetProcAddress( m_libInst
, "VstPluginMain" );
590 if( mainEntry
== NULL
)
592 mainEntry
= (mainEntryPointer
)
593 GetProcAddress( m_libInst
, "main" );
595 if( mainEntry
== NULL
)
597 debugMessage( "could not find entry point\n" );
601 m_plugin
= mainEntry( hostCallback
);
602 if( m_plugin
== NULL
)
604 debugMessage( "mainEntry prodecure returned NULL\n" );
608 m_plugin
->user
= this;
610 if( m_plugin
->magic
!= kEffectMagic
)
613 sprintf( buf
, "%s is not a VST plugin\n",
614 _plugin_file
.c_str() );
621 sprintf( id
, "%c%c%c%c", ((char *)&m_plugin
->uniqueID
)[3],
622 ((char *)&m_plugin
->uniqueID
)[2],
623 ((char *)&m_plugin
->uniqueID
)[1],
624 ((char *)&m_plugin
->uniqueID
)[0] );
626 sendMessage( message( IdVstPluginUniqueID
).addString( id
) );
628 pluginDispatch( effOpen
);
636 void RemoteVstPlugin::process( const sampleFrame
* _in
, sampleFrame
* _out
)
638 // first we gonna post all MIDI-events we enqueued so far
639 if( m_midiEvents
.size() )
641 // since MIDI-events are not received immediately, we
642 // have to have them stored somewhere even after
643 // dispatcher-call, so we create static copies of the
644 // data and post them
645 #define MIDI_EVENT_BUFFER_COUNT 1024
646 static char event_buf
[sizeof( VstMidiEvent
* ) *
647 MIDI_EVENT_BUFFER_COUNT
+
648 sizeof( VstEvents
)];
649 static VstMidiEvent vme
[MIDI_EVENT_BUFFER_COUNT
];
650 VstEvents
* events
= (VstEvents
*) event_buf
;
651 events
->reserved
= 0;
652 events
->numEvents
= m_midiEvents
.size();
654 for( VstMidiEventList::iterator it
= m_midiEvents
.begin();
655 it
!= m_midiEvents
.end(); ++it
, ++idx
)
657 memcpy( &vme
[idx
], &*it
, sizeof( VstMidiEvent
) );
658 events
->events
[idx
] = (VstEvent
*) &vme
[idx
];
661 m_midiEvents
.clear();
662 pluginDispatch( effProcessEvents
, 0, 0, events
);
665 // now we're ready to fetch sound from VST-plugin
667 for( int i
= 0; i
< inputCount(); ++i
)
669 m_inputs
[i
] = &((float *) _in
)[i
* bufferSize()];
672 for( int i
= 0; i
< outputCount(); ++i
)
674 m_outputs
[i
] = &((float *) _out
)[i
* bufferSize()];
675 memset( m_outputs
[i
], 0, bufferSize() * sizeof( float ) );
679 if( m_plugin
->flags
& effFlagsCanReplacing
)
682 m_plugin
->processReplacing( m_plugin
, m_inputs
, m_outputs
,
688 m_plugin
->process( m_plugin
, m_inputs
, m_outputs
,
693 m_currentSamplePos
+= bufferSize();
700 void RemoteVstPlugin::processMidiEvent( const midiEvent
& _event
,
701 const f_cnt_t _offset
)
705 event
.type
= kVstMidiType
;
707 event
.deltaFrames
= _offset
;
710 event
.noteLength
= 0;
711 event
.noteOffset
= 0;
712 event
.noteOffVelocity
= 0;
715 event
.midiData
[0] = _event
.m_type
+ _event
.m_channel
;
716 switch( _event
.m_type
)
719 event
.midiData
[1] = _event
.m_data
.m_param
[0] & 0x7f;
720 event
.midiData
[2] = _event
.m_data
.m_param
[0] >> 7;
722 // TODO: handle more special cases
724 event
.midiData
[1] = _event
.key();
725 event
.midiData
[2] = _event
.velocity();
728 event
.midiData
[3] = 0;
729 m_midiEvents
.push_back( event
);
735 const char * RemoteVstPlugin::pluginName()
739 pluginDispatch( effGetEffectName
, 0, 0, buf
);
747 const char * RemoteVstPlugin::pluginVendorString()
751 pluginDispatch( effGetVendorString
, 0, 0, buf
);
759 const char * RemoteVstPlugin::pluginProductString()
763 pluginDispatch( effGetProductString
, 0, 0, buf
);
771 const char * RemoteVstPlugin::presetName()
776 m_plugin
->dispatcher(m_plugin
, effGetProgramName
, 0, 0, buf
, 0);
784 void RemoteVstPlugin::getParameterDump()
786 char curPresName
[30];
787 //VstParameterProperties vst_props;
788 message
m( IdVstParameterDump
);
789 m
.addInt( m_plugin
->numParams
);
790 for( int i
= 0; i
< m_plugin
->numParams
; ++i
)
792 //pluginDispatch( effGetParameterProperties, i, 0, &vst_props );
793 m_plugin
->dispatcher(m_plugin
, effGetParamName
, i
, 0, curPresName
, 0);
795 m
.addString( /*vst_props.shortLabel*/curPresName
);
796 m
.addFloat( m_plugin
->getParameter( m_plugin
, i
) );
804 void RemoteVstPlugin::setParameterDump( const message
& _m
)
806 const int n
= _m
.getInt( 0 );
807 const int params
= ( n
> m_plugin
->numParams
) ?
808 m_plugin
->numParams
: n
;
810 for( int i
= 0; i
< params
; ++i
)
812 VstParameterDumpItem item
;
813 item
.index
= _m
.getInt( ++p
);
814 item
.shortLabel
= _m
.getString( ++p
);
815 item
.value
= _m
.getFloat( ++p
);
816 m_plugin
->setParameter( m_plugin
, item
.index
, item
.value
);
823 void RemoteVstPlugin::getParameterProperties( const int _idx
)
825 VstParameterProperties p
;
826 pluginDispatch( effGetParameterProperties
, _idx
, 0, &p
);
827 message
m( IdVstParameterProperties
);
828 m
.addString( p
.label
);
829 m
.addString( p
.shortLabel
);
837 m
.addFloat( p
.minInteger
);
838 m
.addFloat( p
.maxInteger
);
839 m
.addFloat( ( p
.flags
& kVstParameterUsesFloatStep
) ?
840 p
.stepFloat
: p
.stepInteger
);
854 void RemoteVstPlugin::saveChunkToFile( const std::string
& _file
)
856 if( m_plugin
->flags
& 32 )
859 const int len
= pluginDispatch( 23, 0, 0, &chunk
);
862 int fd
= open( _file
.c_str(), O_WRONLY
| O_BINARY
);
863 write( fd
, chunk
, len
);
872 void RemoteVstPlugin::rotateProgram( int _len
)
875 if (isInitialized() == false) return;
877 currProgram
= m_plugin
->dispatcher(m_plugin
, effGetProgram
, 0, 0, 0, 0) + _len
;
878 if (currProgram
>= m_plugin
->numPrograms
) currProgram
= m_plugin
->numPrograms
- 1;
879 if (currProgram
< 0) currProgram
= 0;
880 m_plugin
->dispatcher(m_plugin
, effSetProgram
, 0, currProgram
++, 0, 0);
882 m_plugin
->dispatcher(m_plugin
, effSetProgram
, 0, _len
- 2, 0, 0);
883 currProgram
= _len
- 1;
887 sprintf( presName
, " %d/%d: %s", currProgram
, m_plugin
->numPrograms
, presetName() );
889 sendMessage( message( IdVstPluginPresetString
).addString( presName
) );
895 void RemoteVstPlugin::loadPrograms( int _len
)
898 char curProgName
[30];
899 if (isInitialized() == false) return;
900 bool progNameIndexed
= (m_plugin
->dispatcher(m_plugin
, 29, 0, -1, curProgName
, 0) == 1);
902 if (m_plugin
->numPrograms
> 1) {
903 if (progNameIndexed
) {
904 for (int i
= 0; i
< (m_plugin
->numPrograms
>= 256?256:m_plugin
->numPrograms
); i
++) {
905 m_plugin
->dispatcher(m_plugin
, 29, i
, -1, curProgName
, 0);
906 if (i
== 0) sprintf( presName
, "%s", curProgName
);
907 else sprintf( presName
+ strlen(presName
), "|%s", curProgName
);
910 int currProgram
= m_plugin
->dispatcher(m_plugin
, effGetProgram
, 0, 0, 0, 0);
911 for (int i
= 0; i
< (m_plugin
->numPrograms
>= 256?256:m_plugin
->numPrograms
); i
++) {
912 m_plugin
->dispatcher(m_plugin
, effSetProgram
, 0, i
, 0, 0);
913 if (i
== 0) sprintf( presName
, "%s", presetName() );
914 else sprintf( presName
+ strlen(presName
), "|%s", presetName() );
916 m_plugin
->dispatcher(m_plugin
, effSetProgram
, 0, currProgram
, 0, 0);
918 } else sprintf( presName
, "%s", presetName() );
920 sendMessage( message( IdVstPluginPresetsString
).addString( presName
) );
926 inline unsigned int endian_swap(unsigned int& x
)
928 return (x
>>24) | ((x
<<8) & 0x00FF0000) | ((x
>>8) & 0x0000FF00) | (x
<<24);
933 unsigned int chunkMagic
;
934 unsigned int byteSize
;
935 unsigned int fxMagic
;
936 unsigned int version
;
938 unsigned int fxVersion
;
939 unsigned int numPrograms
;
943 void RemoteVstPlugin::savePreset( const std::string
& _file
)
945 unsigned int chunk_size
= 0;
946 sBank
* pBank
= ( sBank
* ) new char[ sizeof( sBank
) ];
947 char progName
[ 128 ] = { 0 };
949 const bool chunky
= ( m_plugin
->flags
& ( 1 << 5 ) ) != 0;
950 bool isPreset
= _file
.substr( _file
.find_last_of( "." ) + 1 ) == "fxp";
951 int presNameLen
= _file
.find_last_of( "/" ) + _file
.find_last_of( "\\" ) + 2;
954 for (int i
= 0; i
< _file
.length() - 4 - presNameLen
; i
++)
955 progName
[i
] = i
< 23 ? _file
[presNameLen
+ i
] : 0;
956 m_plugin
->dispatcher(m_plugin
, 4, 0, 0, progName
, 0);
957 } // m_plugin->dispatcher( m_plugin, effGetProgramName, 0, 0, progName, 0.0f );
959 chunk_size
= m_plugin
->dispatcher( m_plugin
, 23, isPreset
, 0, &data
, false );
962 chunk_size
= m_plugin
->numParams
* sizeof( float );
963 data
= new char[ chunk_size
];
964 unsigned int* toUIntArray
= reinterpret_cast<unsigned int*>( data
);
965 for ( int i
= 0; i
< m_plugin
->numParams
; i
++ )
967 float value
= m_plugin
->getParameter( m_plugin
, i
);
968 unsigned int * pValue
= ( unsigned int * ) &value
;
969 toUIntArray
[ i
] = endian_swap( *pValue
);
971 } else chunk_size
= (((m_plugin
->numParams
* sizeof( float )) + 56)*m_plugin
->numPrograms
);
974 pBank
->chunkMagic
= 0x4B6E6343;
975 pBank
->byteSize
= chunk_size
+ ( chunky
? sizeof( int ) : 0 ) + 48;
976 if (!isPreset
) pBank
->byteSize
+= 100;
977 pBank
->byteSize
= endian_swap( pBank
->byteSize
);
978 pBank
->fxMagic
= chunky
? 0x68435046 : 0x6B437846;
979 if (!isPreset
&& chunky
) pBank
->fxMagic
= 0x68434246;
980 if (!isPreset
&&!chunky
) pBank
->fxMagic
= 0x6B427846;
982 pBank
->version
= 0x01000000;
983 unsigned int uIntToFile
= (unsigned int) m_plugin
->uniqueID
;
984 pBank
->fxID
= endian_swap( uIntToFile
);
985 uIntToFile
= (unsigned int) pluginVersion();
986 pBank
->fxVersion
= endian_swap( uIntToFile
);
987 uIntToFile
= (unsigned int) chunky
? m_plugin
->numPrograms
: m_plugin
->numParams
;
988 if (!isPreset
&&!chunky
) uIntToFile
= (unsigned int) m_plugin
->numPrograms
;
989 pBank
->numPrograms
= endian_swap( uIntToFile
);
991 FILE * stream
= fopen( _file
.c_str(), "w" );
992 fwrite ( pBank
, 1, 28, stream
);
993 fwrite ( progName
, 1, isPreset
? 28 : 128, stream
);
995 uIntToFile
= endian_swap( chunk_size
);
996 fwrite ( &uIntToFile
, 1, 4, stream
);
998 if (pBank
->fxMagic
!= 0x6B427846 )
999 fwrite ( data
, 1, chunk_size
, stream
);
1001 int numPrograms
= m_plugin
->numPrograms
;
1002 int currProgram
= m_plugin
->dispatcher(m_plugin
, effGetProgram
, 0, 0, 0, 0);
1003 chunk_size
= (m_plugin
->numParams
* sizeof( float ));
1004 pBank
->byteSize
= chunk_size
+ 48;
1005 pBank
->byteSize
= endian_swap( pBank
->byteSize
);
1006 pBank
->fxMagic
= 0x6B437846;
1007 uIntToFile
= (unsigned int) m_plugin
->numParams
;
1008 pBank
->numPrograms
= endian_swap( uIntToFile
);
1009 data
= new char[ chunk_size
];
1010 unsigned int* pValue
,* toUIntArray
= reinterpret_cast<unsigned int*>( data
);
1012 for (int j
= 0; j
< numPrograms
; j
++) {
1013 m_plugin
->dispatcher(m_plugin
, effSetProgram
, 0, j
, 0, 0);
1014 m_plugin
->dispatcher(m_plugin
, effGetProgramName
, 0, 0, pBank
->prgName
, 0);
1015 fwrite ( pBank
, 1, 56, stream
);
1016 for ( int i
= 0; i
< m_plugin
->numParams
; i
++ )
1018 value
= m_plugin
->getParameter( m_plugin
, i
);
1019 pValue
= ( unsigned int * ) &value
;
1020 toUIntArray
[ i
] = endian_swap( *pValue
);
1022 fwrite ( data
, 1, chunk_size
, stream
);
1024 m_plugin
->dispatcher(m_plugin
, effSetProgram
, 0, currProgram
, 0, 0);
1030 delete[] (sBank
*)pBank
;
1037 void RemoteVstPlugin::loadChunkFromPresetFile( const std::string
& _file
)
1039 void * chunk
= NULL
;
1040 unsigned int * pLen
= new unsigned int[ 1 ];
1042 sBank
* pBank
= (sBank
*) new char[ sizeof( sBank
) ];
1043 FILE * stream
= fopen( _file
.c_str(), "r" );
1044 fread ( pBank
, 1, 56, stream
);
1045 pBank
->fxID
= endian_swap( pBank
->fxID
);
1046 pBank
->numPrograms
= endian_swap( pBank
->numPrograms
);
1047 unsigned int toUInt
;
1050 if (m_plugin
->uniqueID
!= pBank
->fxID
) {
1051 sendMessage( message( IdVstPluginPresetString
).
1052 addString( "Error: Plugin UniqID not match" ) );
1054 delete[] (unsigned int*)pLen
;
1055 delete[] (sBank
*)pBank
;
1059 if( _file
.substr( _file
.find_last_of( "." ) + 1 ) != "fxp" )
1060 fseek ( stream
, 156 , SEEK_SET
);
1062 if(pBank
->fxMagic
!= 0x6B427846) {
1063 if(pBank
->fxMagic
!= 0x6B437846) {
1064 fread (pLen
, 1, 4, stream
);
1065 chunk
= new char[len
= endian_swap(*pLen
)];
1066 } else chunk
= new char[len
= sizeof(float)*pBank
->numPrograms
];
1067 fread (chunk
, len
, 1, stream
);
1071 if(_file
.substr(_file
.find_last_of(".") + 1) == "fxp") {
1072 pBank
->prgName
[23] = 0;
1073 m_plugin
->dispatcher(m_plugin
, 4, 0, 0, pBank
->prgName
, 0);
1074 if(pBank
->fxMagic
!= 0x6B437846)
1075 m_plugin
->dispatcher(m_plugin
, 24, 1, len
, chunk
, 0);
1077 unsigned int* toUIntArray
= reinterpret_cast<unsigned int*>( chunk
);
1078 for (int i
= 0; i
< pBank
->numPrograms
; i
++ ) {
1079 toUInt
= endian_swap( toUIntArray
[ i
] );
1080 pFloat
= ( float* ) &toUInt
;
1081 m_plugin
->setParameter( m_plugin
, i
, *pFloat
);
1085 if(pBank
->fxMagic
!= 0x6B427846) {
1086 m_plugin
->dispatcher(m_plugin
, 24, 0, len
, chunk
, 0);
1088 int numPrograms
= pBank
->numPrograms
;
1089 unsigned int * toUIntArray
;
1090 int currProgram
= m_plugin
->dispatcher(m_plugin
, effGetProgram
, 0, 0, 0, 0);
1091 chunk
= new char[ len
= sizeof(float)*m_plugin
->numParams
];
1092 toUIntArray
= reinterpret_cast<unsigned int *>( chunk
);
1093 for (int i
=0; i
< numPrograms
; i
++) {
1094 fread (pBank
, 1, 56, stream
);
1095 fread (chunk
, len
, 1, stream
);
1096 m_plugin
->dispatcher(m_plugin
, effSetProgram
, 0, i
, 0, 0);
1097 pBank
->prgName
[23] = 0;
1098 m_plugin
->dispatcher(m_plugin
, 4, 0, 0, pBank
->prgName
, 0);
1099 for (int j
= 0; j
< m_plugin
->numParams
; j
++ ) {
1100 toUInt
= endian_swap( toUIntArray
[ j
] );
1101 pFloat
= ( float* ) &toUInt
;
1102 m_plugin
->setParameter( m_plugin
, j
, *pFloat
);
1105 m_plugin
->dispatcher(m_plugin
, effSetProgram
, 0, currProgram
, 0, 0);
1110 int currProgram
= m_plugin
->dispatcher(m_plugin
, effGetProgram
, 0, 0, 0, 0) + 1;
1111 sprintf( presName
, " %d/%d: %s", currProgram
, m_plugin
->numPrograms
, presetName() );
1113 sendMessage( message( IdVstPluginPresetString
).addString( presName
) );
1115 delete[] (unsigned int*)pLen
;
1116 delete[] (sBank
*)pBank
;
1117 delete[] (char*)chunk
;
1123 void RemoteVstPlugin::loadChunkFromFile( const std::string
& _file
, int _len
)
1127 void * chunk
= NULL
;
1128 // various plugins need this in order to not crash when setting
1129 // chunk (also we let the plugin allocate "safe" memory this way)
1130 const int actualLen
= pluginDispatch( 23, 0, 0, &chunk
);
1132 // allocated buffer big enough?
1133 if( _len
> actualLen
)
1135 // no, then manually allocate a buffer
1136 buf
= new char[_len
];
1140 const int fd
= open( _file
.c_str(), O_RDONLY
| O_BINARY
);
1141 read( fd
, chunk
, _len
);
1143 pluginDispatch( 24, 0, _len
, chunk
);
1151 void RemoteVstPlugin::updateInOutCount()
1159 setInputCount( inputCount() );
1160 setOutputCount( outputCount() );
1163 sprintf( buf
, "inputs: %d output: %d\n", inputCount(), outputCount() );
1164 debugMessage( buf
);
1166 if( inputCount() > 0 )
1168 m_inputs
= new float * [inputCount()];
1171 if( outputCount() > 0 )
1173 m_outputs
= new float * [outputCount()];
1179 //#define DEBUG_CALLBACKS
1180 #ifdef DEBUG_CALLBACKS
1181 #define SHOW_CALLBACK __plugin->debugMessage
1183 #define SHOW_CALLBACK(...)
1188 * - complete audioMasterGetTime-handling (bars etc.)
1189 * - implement audioMasterProcessEvents
1190 * - audioMasterGetVendorVersion: return LMMS-version (config.h!)
1191 * - audioMasterGetDirectory: return either VST-plugin-dir or LMMS-workingdir
1192 * - audioMasterOpenFileSelector: show QFileDialog?
1194 intptr_t RemoteVstPlugin::hostCallback( AEffect
* _effect
, int32_t _opcode
,
1195 int32_t _index
, intptr_t _value
,
1196 void * _ptr
, float _opt
)
1198 static VstTimeInfo _timeInfo
;
1199 #ifdef DEBUG_CALLBACKS
1201 sprintf( buf
, "host-callback, opcode = %d\n", (int) _opcode
);
1202 SHOW_CALLBACK( buf
);
1205 // workaround for early callbacks by some plugins
1206 if( __plugin
&& __plugin
->m_plugin
== NULL
)
1208 __plugin
->m_plugin
= _effect
;
1213 case audioMasterAutomate
:
1214 SHOW_CALLBACK( "amc: audioMasterAutomate\n" );
1215 // index, value, returns 0
1216 _effect
->setParameter( _effect
, _index
, _opt
);
1219 case audioMasterVersion
:
1220 SHOW_CALLBACK( "amc: audioMasterVersion\n" );
1223 case audioMasterCurrentId
:
1224 SHOW_CALLBACK( "amc: audioMasterCurrentId\n" );
1225 // returns the unique id of a plug that's currently
1229 case audioMasterIdle
:
1230 SHOW_CALLBACK ("amc: audioMasterIdle\n" );
1231 // call application idle routine (this will
1232 // call effEditIdle for all open editors too)
1233 PostThreadMessage( __GuiThreadID
,
1234 WM_USER
, GiveIdle
, 0 );
1237 case audioMasterPinConnected
:
1238 SHOW_CALLBACK( "amc: audioMasterPinConnected\n" );
1239 // inquire if an input or output is beeing connected;
1240 // index enumerates input or output counting from zero:
1241 // value is 0 for input and != 0 otherwise. note: the
1242 // return value is 0 for <true> such that older versions
1243 // will always return true.
1246 case audioMasterGetTime
:
1247 SHOW_CALLBACK( "amc: audioMasterGetTime\n" );
1248 // returns const VstTimeInfo* (or 0 if not supported)
1249 // <value> should contain a mask indicating which
1250 // fields are required (see valid masks above), as some
1251 // items may require extensive conversions
1253 memset( &_timeInfo
, 0, sizeof( _timeInfo
) );
1255 _timeInfo
.samplePos
= __plugin
->m_currentSamplePos
;
1256 _timeInfo
.sampleRate
= __plugin
->sampleRate();
1257 _timeInfo
.flags
= 0;
1258 _timeInfo
.tempo
= __plugin
->m_bpm
;
1259 _timeInfo
.timeSigNumerator
= 4;
1260 _timeInfo
.timeSigDenominator
= 4;
1261 _timeInfo
.flags
|= (/* kVstBarsValid|*/kVstTempoValid
);
1262 _timeInfo
.flags
|= kVstTransportPlaying
;
1263 #ifdef LMMS_BUILD_WIN64
1264 return (long long) &_timeInfo
;
1266 return (long) &_timeInfo
;
1269 case audioMasterProcessEvents
:
1270 SHOW_CALLBACK( "amc: audioMasterProcessEvents\n" );
1271 // VstEvents* in <ptr>
1274 case audioMasterIOChanged
:
1275 __plugin
->updateInOutCount();
1276 SHOW_CALLBACK( "amc: audioMasterIOChanged\n" );
1277 // numInputs and/or numOutputs has changed
1281 case audioMasterWantMidi
:
1282 SHOW_CALLBACK( "amc: audioMasterWantMidi\n" );
1283 // <value> is a filter which is currently ignored
1286 case audioMasterSetTime
:
1287 SHOW_CALLBACK( "amc: audioMasterSetTime\n" );
1288 // VstTimenfo* in <ptr>, filter in <value>, not
1292 case audioMasterTempoAt
:
1293 SHOW_CALLBACK( "amc: audioMasterTempoAt\n" );
1294 return __plugin
->m_bpm
* 10000;
1296 case audioMasterGetNumAutomatableParameters
:
1297 SHOW_CALLBACK( "amc: audioMasterGetNumAutomatable"
1301 case audioMasterGetParameterQuantization
:
1302 SHOW_CALLBACK( "amc: audioMasterGetParameter\n"
1304 // returns the integer value for +1.0 representation,
1305 // or 1 if full single float precision is maintained
1306 // in automation. parameter index in <value> (-1: all,
1310 case audioMasterNeedIdle
:
1311 SHOW_CALLBACK( "amc: audioMasterNeedIdle\n" );
1312 // plug needs idle calls (outside its editor window)
1315 case audioMasterGetPreviousPlug
:
1316 SHOW_CALLBACK( "amc: audioMasterGetPreviousPlug\n" );
1317 // input pin in <value> (-1: first to come), returns
1321 case audioMasterGetNextPlug
:
1322 SHOW_CALLBACK( "amc: audioMasterGetNextPlug\n" );
1323 // output pin in <value> (-1: first to come), returns
1327 case audioMasterWillReplaceOrAccumulate
:
1328 SHOW_CALLBACK( "amc: audioMasterWillReplaceOr"
1330 // returns: 0: not supported, 1: replace, 2: accumulate
1333 case audioMasterGetSpeakerArrangement
:
1334 SHOW_CALLBACK( "amc: audioMasterGetSpeaker"
1336 // (long)input in <value>, output in <ptr>
1339 case audioMasterSetOutputSampleRate
:
1340 SHOW_CALLBACK( "amc: audioMasterSetOutputSample"
1342 // for variable i/o, sample rate in <opt>
1345 case audioMasterSetIcon
:
1346 SHOW_CALLBACK( "amc: audioMasterSetIcon\n" );
1348 // void* in <ptr>, format not defined yet
1351 case audioMasterOpenWindow
:
1352 SHOW_CALLBACK( "amc: audioMasterOpenWindow\n" );
1354 // returns platform specific ptr
1357 case audioMasterCloseWindow
:
1358 SHOW_CALLBACK( "amc: audioMasterCloseWindow\n" );
1360 // close window, platform specific handle in <ptr>
1364 case audioMasterSizeWindow
:
1365 SHOW_CALLBACK( "amc: audioMasterSizeWindow\n" );
1366 if( __plugin
->m_window
== 0 )
1370 __plugin
->m_windowWidth
= _index
;
1371 __plugin
->m_windowHeight
= _value
;
1372 SetWindowPos( __plugin
->m_window
, 0, 0, 0,
1373 _index
+ 8, _value
+ 26,
1374 SWP_NOACTIVATE
| SWP_NOMOVE
|
1375 SWP_NOOWNERZORDER
| SWP_NOZORDER
);
1376 __plugin
->sendMessage(
1377 message( IdVstPluginEditorGeometry
).
1378 addInt( __plugin
->m_windowWidth
).
1379 addInt( __plugin
->m_windowHeight
) );
1382 case audioMasterGetSampleRate
:
1383 SHOW_CALLBACK( "amc: audioMasterGetSampleRate\n" );
1384 return __plugin
->sampleRate();
1386 case audioMasterGetBlockSize
:
1387 SHOW_CALLBACK( "amc: audioMasterGetBlockSize\n" );
1389 return __plugin
->bufferSize();
1391 case audioMasterGetInputLatency
:
1392 SHOW_CALLBACK( "amc: audioMasterGetInputLatency\n" );
1393 return __plugin
->bufferSize();
1395 case audioMasterGetOutputLatency
:
1396 SHOW_CALLBACK( "amc: audioMasterGetOutputLatency\n" );
1397 return __plugin
->bufferSize();
1399 case audioMasterGetCurrentProcessLevel
:
1400 SHOW_CALLBACK( "amc: audioMasterGetCurrentProcess"
1402 // returns: 0: not supported,
1403 // 1: currently in user thread (gui)
1404 // 2: currently in audio thread (where process is
1406 // 3: currently in 'sequencer' thread (midi, timer etc)
1407 // 4: currently offline processing and thus in user
1409 // other: not defined, but probably pre-empting user
1413 case audioMasterGetAutomationState
:
1414 SHOW_CALLBACK( "amc: audioMasterGetAutomationState\n" );
1415 // returns 0: not supported, 1: off, 2:read, 3:write,
1416 // 4:read/write offline
1419 case audioMasterOfflineStart
:
1420 SHOW_CALLBACK( "amc: audioMasterOfflineStart\n" );
1423 case audioMasterOfflineRead
:
1424 SHOW_CALLBACK( "amc: audioMasterOfflineRead\n" );
1425 // ptr points to offline structure, see below.
1426 // return 0: error, 1 ok
1429 case audioMasterOfflineWrite
:
1430 SHOW_CALLBACK( "amc: audioMasterOfflineWrite\n" );
1434 case audioMasterOfflineGetCurrentPass
:
1435 SHOW_CALLBACK( "amc: audioMasterOfflineGetCurrent"
1439 case audioMasterOfflineGetCurrentMetaPass
:
1440 SHOW_CALLBACK( "amc: audioMasterOfflineGetCurrentMeta"
1444 case audioMasterGetVendorString
:
1445 SHOW_CALLBACK( "amc: audioMasterGetVendorString\n" );
1446 // fills <ptr> with a string identifying the vendor
1448 strcpy( (char *) _ptr
, "Tobias Doerffel" );
1451 case audioMasterGetProductString
:
1452 SHOW_CALLBACK( "amc: audioMasterGetProductString\n" );
1453 // fills <ptr> with a string with product name
1455 strcpy( (char *) _ptr
,
1456 "LMMS VST Support Layer (LVSL)" );
1459 case audioMasterGetVendorVersion
:
1460 SHOW_CALLBACK( "amc: audioMasterGetVendorVersion\n" );
1461 // returns vendor-specific version
1464 case audioMasterVendorSpecific
:
1465 SHOW_CALLBACK( "amc: audioMasterVendorSpecific\n" );
1466 // no definition, vendor specific handling
1469 case audioMasterCanDo
:
1470 SHOW_CALLBACK( "amc: audioMasterCanDo\n" );
1471 return !strcmp( (char *) _ptr
, "sendVstEvents" ) ||
1472 !strcmp( (char *) _ptr
, "sendVstMidiEvent" ) ||
1473 !strcmp( (char *) _ptr
, "sendVstTimeInfo" ) ||
1474 !strcmp( (char *) _ptr
, "sizeWindow" ) ||
1475 !strcmp( (char *) _ptr
, "supplyIdle" );
1477 case audioMasterGetLanguage
:
1478 SHOW_CALLBACK( "amc: audioMasterGetLanguage\n" );
1481 case audioMasterGetDirectory
:
1482 SHOW_CALLBACK( "amc: audioMasterGetDirectory\n" );
1483 // get plug directory, FSSpec on MAC, else char*
1486 case audioMasterUpdateDisplay
:
1487 SHOW_CALLBACK( "amc: audioMasterUpdateDisplay\n" );
1488 // something has changed, update 'multi-fx' display
1489 PostThreadMessage( __GuiThreadID
,
1490 WM_USER
, GiveIdle
, 0 );
1494 case audioMasterBeginEdit
:
1495 SHOW_CALLBACK( "amc: audioMasterBeginEdit\n" );
1496 // begin of automation session (when mouse down),
1497 // parameter index in <index>
1500 case audioMasterEndEdit
:
1501 SHOW_CALLBACK( "amc: audioMasterEndEdit\n" );
1502 // end of automation session (when mouse up),
1503 // parameter index in <index>
1506 case audioMasterOpenFileSelector
:
1507 SHOW_CALLBACK( "amc: audioMasterOpenFileSelector\n" );
1508 // open a fileselector window with VstFileSelect*
1513 SHOW_CALLBACK( "amd: not handled" );
1523 DWORD WINAPI
RemoteVstPlugin::processingThread( LPVOID _param
)
1525 RemoteVstPlugin
* _this
= static_cast<RemoteVstPlugin
*>( _param
);
1527 RemotePluginClient::message m
;
1528 while( ( m
= _this
->receiveMessage() ).id
!= IdQuit
)
1530 if( m
.id
== IdStartProcessing
|| m
.id
== IdMidiEvent
)
1532 _this
->processMessage( m
);
1536 PostThreadMessage( __GuiThreadID
,
1538 ProcessPluginMessage
,
1539 (LPARAM
) new message( m
) );
1543 // notify GUI thread about shutdown
1544 PostThreadMessage( __GuiThreadID
, WM_USER
, ClosePlugin
, 0 );
1552 DWORD WINAPI
RemoteVstPlugin::guiEventLoop( LPVOID _param
)
1554 RemoteVstPlugin
* _this
= static_cast<RemoteVstPlugin
*>( _param
);
1556 HMODULE hInst
= GetModuleHandle( NULL
);
1559 _this
->debugMessage( "guiEventLoop(): can't get "
1560 "module handle\n" );
1564 HWND timerWindow
= CreateWindowEx( 0, "LVSL", "dummy",
1565 0, 0, 0, 0, 0, NULL
, NULL
,
1567 // install GUI update timer
1568 SetTimer( timerWindow
, 1000, 50, NULL
);
1573 while( quit
== false && GetMessage( &msg
, NULL
, 0, 0 ) )
1575 TranslateMessage( &msg
);
1576 DispatchMessage( &msg
);
1578 if( msg
.message
== WM_TIMER
&& _this
->isInitialized() )
1580 // give plugin some idle-time for GUI-update
1581 _this
->pluginDispatch( effEditIdle
);
1583 else if( msg
.message
== WM_USER
)
1585 switch( msg
.wParam
)
1587 case ProcessPluginMessage
:
1589 message
* m
= (message
*) msg
.lParam
;
1590 _this
->processMessage( *m
);
1596 _this
->pluginDispatch( effEditIdle
);
1615 int main( int _argc
, char * * _argv
)
1619 fprintf( stderr
, "not enough arguments\n" );
1623 #ifdef LMMS_BUILD_WIN32
1624 // (non-portable) initialization of statically linked pthread library
1625 pthread_win32_process_attach_np();
1626 pthread_win32_thread_attach_np();
1629 #ifdef LMMS_BUILD_LINUX
1630 #ifdef LMMS_HAVE_SCHED_H
1631 // try to set realtime-priority
1632 struct sched_param sparam
;
1633 sparam
.sched_priority
= ( sched_get_priority_max( SCHED_FIFO
) +
1634 sched_get_priority_min( SCHED_FIFO
) ) / 2;
1635 sched_setscheduler( 0, SCHED_FIFO
, &sparam
);
1639 // constructor automatically will process messages until it receives
1640 // a IdVstLoadPlugin message and processes it
1641 __plugin
= new RemoteVstPlugin( atoi( _argv
[1] ), atoi( _argv
[2] ) );
1643 if( __plugin
->isInitialized() )
1645 __GuiThreadID
= GetCurrentThreadId();
1646 if( CreateThread( NULL
, 0, RemoteVstPlugin::processingThread
,
1647 __plugin
, 0, NULL
) == NULL
)
1649 __plugin
->debugMessage( "could not create "
1650 "processingThread\n" );
1653 RemoteVstPlugin::guiEventLoop( __plugin
);
1660 #ifdef LMMS_BUILD_WIN32
1661 pthread_win32_thread_detach_np();
1662 pthread_win32_process_detach_np();