rewrote VST support layer to use the new remotePlugin-framework

git-svn-id: https://lmms.svn.sf.net/svnroot/lmms/trunk/lmms@1542 0778d3d1-df1d-0410-868b-ea421aaaa00d
This commit is contained in:
Tobias Doerffel
2008-09-03 16:07:15 +00:00
parent 014ecfa901
commit 5b98f07f22
11 changed files with 439 additions and 973 deletions

View File

@@ -1,3 +1,26 @@
2008-09-03 Tobias Doerffel <tobydox/at/users/dot/sourceforge/dot/net>
* plugins/vst_base/communication.h:
* plugins/vst_base/vst_plugin.h:
* plugins/vst_base/vst_plugin.cpp:
* plugins/vst_base/remote_vst_plugin.cpp:
* plugins/vst_base/CMakeLists.txt:
* plugins/vst_effect/vst_effect.h:
* plugins/vst_effect/vst_effect.cpp:
* plugins/vestige/vestige.h:
* plugins/vestige/vestige.cpp:
* include/aeffectx.h:
rewrote VST support layer to use the new remotePlugin-framework
* include/remote_plugin.h:
* src/core/remote_plugin.cpp:
- added channel splitting mode
- made initial wait optional
- messages now can be constructed and set inline
* CMakeLists.txt:
added hint about removing CMakeCache.txt when libsndfile is missing
2008-09-02 Tobias Doerffel <tobydox/at/users/dot/sourceforge/dot/net>
* cmake/modules/Win32Toolchain.cmake:

View File

@@ -118,7 +118,7 @@ int kVstTempoValid = 1 << 10;
int kVstTransportPlaying = 1 << 1;
class VSTPlugin;
class remoteVstPlugin;
class VstMidiEvent
@@ -221,7 +221,7 @@ public:
// flags 24-27
int flags;
// Fill somewhere 28-2b
VSTPlugin * user;
remoteVstPlugin * user;
// Zeroes 2c-2f 30-33 34-37 38-3b
char empty3[4 + 4 + 4 + 4];
// 1.0f 3c-3f

View File

@@ -35,7 +35,7 @@
#include "gui_templates.h"
#include "instrument_play_handle.h"
#include "instrument_track.h"
#include "lvsl_client.h"
#include "vst_plugin.h"
#include "note_play_handle.h"
#include "pixmap_button.h"
#include "song.h"
@@ -153,7 +153,7 @@ void vestigeInstrument::setParameter( const QString & _param,
PLUGIN_NAME::getIconPixmap( "logo", 24, 24 ),
0 );
m_pluginMutex.lock();
m_plugin = new remoteVSTPlugin( m_pluginDLL );
m_plugin = new vstPlugin( m_pluginDLL );
if( m_plugin->failed() )
{
m_pluginMutex.unlock();
@@ -263,11 +263,11 @@ void vestigeInstrument::playNote( notePlayHandle * _n, bool, sampleFrame * )
const int k = getInstrumentTrack()->masterKey( _n );
if( m_runningNotes[k] > 0 )
{
m_plugin->enqueueMidiEvent( midiEvent( MidiNoteOff, 0,
m_plugin->processMidiEvent( midiEvent( MidiNoteOff, 0,
k, 0 ), 0 );
}
++m_runningNotes[k];
m_plugin->enqueueMidiEvent( midiEvent( MidiNoteOn, 0, k,
m_plugin->processMidiEvent( midiEvent( MidiNoteOn, 0, k,
_n->getVolume() ), _n->offset() );
// notify when the handle stops, call to deleteNotePluginData
_n->m_pluginData = _n;
@@ -286,7 +286,7 @@ void vestigeInstrument::deleteNotePluginData( notePlayHandle * _n )
const int k = getInstrumentTrack()->masterKey( _n );
if( --m_runningNotes[k] <= 0 )
{
m_plugin->enqueueMidiEvent(
m_plugin->processMidiEvent(
midiEvent( MidiNoteOff, 0, k, 0 ), 0 );
}
}
@@ -302,7 +302,7 @@ bool vestigeInstrument::handleMidiEvent( const midiEvent & _me,
m_pluginMutex.lock();
if( m_plugin != NULL )
{
m_plugin->enqueueMidiEvent( _me, _time );
m_plugin->processMidiEvent( _me, _time );
}
m_pluginMutex.unlock();
return( TRUE );
@@ -489,7 +489,7 @@ void vestigeInstrumentView::noteOffAll( void )
{
for( int key = 0; key < NumKeys; ++key )
{
m_vi->m_plugin->enqueueMidiEvent(
m_vi->m_plugin->processMidiEvent(
midiEvent( MidiNoteOff, 0, key, 0 ), 0 );
}
}

View File

@@ -40,7 +40,7 @@ class QPixmap;
class QPushButton;
class pixmapButton;
class remoteVSTPlugin;
class vstPlugin;
class vestigeInstrument : public instrument
@@ -90,7 +90,7 @@ private:
int m_runningNotes[NumKeys];
remoteVSTPlugin * m_plugin;
vstPlugin * m_plugin;
QMutex m_pluginMutex;
QString m_pluginDLL;

View File

@@ -2,22 +2,21 @@ IF(LMMS_HAVE_VST)
INCLUDE(BuildPlugin)
BUILD_PLUGIN(vstbase vst_base.cpp lvsl_client.cpp lvsl_client.h communication.h MOCFILES lvsl_client.h)
SET_TARGET_PROPERTIES(vstbase PROPERTIES COMPILE_FLAGS "-D_FORTIFY_SOURCE=0")
BUILD_PLUGIN(vstbase vst_base.cpp vst_plugin.cpp vst_plugin.h communication.h MOCFILES vst_plugin.h)
IF(LMMS_HOST_X86_64)
SET(EXTRA_FLAGS -m32 -Wb,--as-cmd='as --32',--ld-cmd='ld -melf_i386' -L/usr/lib32)
ENDIF(LMMS_HOST_X86_64)
ADD_CUSTOM_COMMAND(
SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/lvsl_server.cpp
SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/remote_vst_plugin.cpp
COMMAND wineg++
ARGS -I${CMAKE_BINARY_DIR} -I${CMAKE_SOURCE_DIR}/include -I${CMAKE_INSTALL_PREFIX}/include/wine/windows -I/usr/include/wine/windows ${CMAKE_CURRENT_SOURCE_DIR}/lvsl_server.cpp -mwindows -lpthread ${EXTRA_FLAGS} -o lvsl_server
ARGS -I${CMAKE_BINARY_DIR} -I${CMAKE_SOURCE_DIR}/include -I${CMAKE_INSTALL_PREFIX}/include/wine/windows -I/usr/include/wine/windows ${CMAKE_CURRENT_SOURCE_DIR}/remote_vst_plugin.cpp -mwindows -lpthread ${EXTRA_FLAGS} -o remote_vst_plugin
TARGET vstbase
OUTPUTS lvsl_server.exe.so
OUTPUTS remote_vst_plugin
)
SET_DIRECTORY_PROPERTIES(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES lvsl_server.exe.so)
SET_DIRECTORY_PROPERTIES(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES remote_vst_plugin.exe.so)
INSTALL(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/lvsl_server ${CMAKE_CURRENT_BINARY_DIR}/lvsl_server.exe.so DESTINATION ${PLUGIN_DIR})
INSTALL(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/remote_vst_plugin ${CMAKE_CURRENT_BINARY_DIR}/remote_vst_plugin.exe.so DESTINATION ${PLUGIN_DIR})
ENDIF(LMMS_HAVE_VST)

View File

@@ -27,84 +27,19 @@
#ifndef _COMMUNICATION_H
#define _COMMUNICATION_H
#include "lmmsconfig.h"
#ifdef LMMS_HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <string>
template<typename T>
inline T readValue( int _fd = 0 )
{
T i;
read( _fd, &i, sizeof( i ) );
return( i );
}
template<typename T>
inline void writeValue( const T & _i, int _fd = 1 )
{
write( _fd, &_i, sizeof( _i ) );
}
static inline std::string readString( int _fd = 0 )
{
Sint16 len = readValue<Sint16>( _fd );
char * sc = new char[len + 1];
read( _fd, sc, len );
sc[len] = '\0';
std::string s( sc );
delete[] sc;
return( s );
}
static inline void writeString( const char * _str, int _fd = 1 )
{
int len = strlen( _str );
writeValue<Sint16>( len, _fd );
write( _fd, _str, len );
}
#include "remote_plugin.h"
struct vstParameterDumpItem
{
Sint32 index;
char shortLabel[8];
int32_t index;
std::string shortLabel;
float value;
} ;
// summarized version of VstParameterProperties-struct - useful because client
// doesn't have to know about the latter one
struct vstParamProperties
{
char label[64];
char shortLabel[8];
char categoryLabel[24];
float minValue;
float maxValue;
float step;
Sint16 category;
} ;
enum hostLanguages
enum VstHostLanguages
{
LanguageEnglish = 1,
LanguageGerman,
@@ -116,49 +51,32 @@ enum hostLanguages
enum vstRemoteCommands
enum VstRemoteMessageIDs
{
// client -> server
VST_LOAD_PLUGIN = 0,
VST_CLOSE_PLUGIN,
VST_SHOW_EDITOR,
VST_PROCESS,
VST_ENQUEUE_MIDI_EVENT,
VST_SAMPLE_RATE,
VST_BUFFER_SIZE,
VST_BPM,
VST_LANGUAGE,
VST_GET_PARAMETER_COUNT = 20,
VST_GET_PARAMETER_DUMP,
VST_SET_PARAMETER_DUMP,
VST_GET_PARAMETER_PROPERTIES,
// vstPlugin -> remoteVstPlugin
IdVstLoadPlugin = IdUserBase,
IdVstClosePlugin,
IdVstSetTempo,
IdVstSetLanguage,
IdVstGetParameterCount,
IdVstGetParameterDump,
IdVstSetParameterDump,
IdVstGetParameterProperties,
// server -> client
VST_INITIALIZATION_DONE = 100,
VST_FAILED_LOADING_PLUGIN,
VST_QUIT_ACK,
VST_SHM_KEY_AND_SIZE,
VST_INPUT_COUNT,
VST_OUTPUT_COUNT,
VST_PLUGIN_XID,
VST_PLUGIN_EDITOR_GEOMETRY,
VST_PROCESS_DONE,
VST_PLUGIN_NAME,
VST_PLUGIN_VERSION,
VST_PLUGIN_VENDOR_STRING,
VST_PLUGIN_PRODUCT_STRING,
VST_PARAMETER_COUNT,
VST_PARAMETER_DUMP,
VST_PARAMETER_PROPERTIES,
VST_GET_SAMPLE_RATE = 120,
VST_GET_BUFFER_SIZE,
VST_DEBUG_MSG = 200,
VST_UNDEFINED_CMD
// remoteVstPlugin -> vstPlugin
IdVstFailedLoadingPlugin,
IdVstPluginWindowID,
IdVstPluginEditorGeometry,
IdVstPluginName,
IdVstPluginVersion,
IdVstPluginVendorString,
IdVstPluginProductString,
IdVstParameterCount,
IdVstParameterDump,
IdVstParameterProperties
} ;
#endif

View File

@@ -30,30 +30,14 @@
#include "lmmsconfig.h"
#define BUILD_REMOTE_PLUGIN_CLIENT
#include "remote_plugin.h"
#ifdef LMMS_HAVE_PTHREAD_H
#include <pthread.h>
#endif
#ifdef LMMS_HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef LMMS_HAVE_SYS_IPC_H
#include <sys/ipc.h>
#endif
#ifdef LMMS_HAVE_SYS_SHM_H
#include <sys/shm.h>
#endif
#ifdef LMMS_HAVE_STDARG_H
#include <stdarg.h>
#endif
#ifdef LMMS_HAVE_SIGNAL_H
#include <signal.h>
#endif
#ifdef LMMS_HAVE_SCHED_H
#include <sched.h>
#endif
@@ -101,36 +85,23 @@ static pthread_key_t ejmpbuf_key;
#endif
static hostLanguages hlang = LanguageEnglish;
static VstHostLanguages hlang = LanguageEnglish;
class VSTPlugin;
class remoteVstPlugin;
VSTPlugin * plugin = NULL;
void lvsMessage( const char * _fmt, ... )
{
va_list ap;
char buffer[512];
va_start( ap, _fmt );
vsnprintf( buffer, sizeof( buffer ), _fmt, ap );
writeValue<Sint16>( VST_DEBUG_MSG, 1 );
writeString( buffer, 1 );
va_end( ap );
}
remoteVstPlugin * __plugin = NULL;
class VSTPlugin
class remoteVstPlugin : public remotePluginClient
{
public:
VSTPlugin( void );
remoteVstPlugin( key_t _shm_in, key_t _shm_out );
virtual ~remoteVstPlugin();
~VSTPlugin();
virtual bool processMessage( const message & _m );
void init( const std::string & _plugin_file );
@@ -143,23 +114,33 @@ public:
}
}
void process( void );
virtual bool process( const sampleFrame * _in, sampleFrame * _out );
// enqueue given MIDI-event to be processed the next time process() is
// called
void enqueueMidiEvent( const midiEvent & _event,
const f_cnt_t _frames_ahead );
virtual void processMidiEvent( const midiEvent & _event,
const f_cnt_t _offset );
// set given sample-rate for plugin
void setSampleRate( const sample_rate_t _rate )
void updateSampleRate( void )
{
m_plugin->dispatcher( m_plugin, effSetSampleRate, 0, 0, NULL,
(float) _rate );
m_sampleRate = _rate;
if( m_plugin )
{
m_plugin->dispatcher( m_plugin, effSetSampleRate, 0, 0,
NULL, (float) sampleRate() );
}
}
// set given block-size for plugin
void setBlockSize( const fpp_t _bsize );
// set given buffer-size for plugin
void updateBufferSize( void )
{
if( m_plugin )
{
m_plugin->dispatcher( m_plugin, effSetBlockSize, 0,
bufferSize(), NULL, 0.0f );
}
}
// set given tempo
void setBPM( const bpm_t _bpm )
@@ -168,7 +149,7 @@ public:
}
// determine VST-version the plugin uses
Sint32 pluginVersion( void ) const
int pluginVersion( void ) const
{
return( m_plugin->dispatcher( m_plugin,
effGetVendorVersion, 0, 0, NULL, 0.0f ) );
@@ -184,30 +165,28 @@ public:
const char * pluginProductString( void ) const;
// do a complete parameter-dump and post it
void getParameterDump( void ) const;
void getParameterDump( void );
// read parameter-dump and set it for plugin
void setParameterDump( void );
void setParameterDump( const message & _m );
// post properties of specified parameter
void getParameterProperties( const Sint32 _idx );
void getParameterProperties( const int _idx );
// number of inputs
ch_cnt_t inputCount( void ) const
virtual int inputCount( void ) const
{
return( m_plugin->numInputs );
}
// number of outputs
ch_cnt_t outputCount( void ) const
virtual int outputCount( void ) const
{
return( m_plugin->numOutputs );
}
// called once at initialization and everytime number of inputs/outputs
// or block-size changes and is responsible for resizing shared memory
// and inform client about changed shm-keys, input/output-count etc.
void resizeSharedMemory( void );
// has to be called as soon as input- or output-count changes
void updateInOutCount( void );
private:
@@ -233,25 +212,21 @@ private:
AEffect * m_plugin;
HWND m_window;
Sint32 m_windowXID;
Sint16 m_windowWidth;
Sint16 m_windowHeight;
Sint32 m_windowID;
int m_windowWidth;
int m_windowHeight;
pthread_mutex_t m_lock;
pthread_cond_t m_windowStatusChange;
DWORD m_guiThreadID;
fpp_t m_blockSize;
float * m_shm;
float * * m_inputs;
float * * m_outputs;
std::list<VstMidiEvent> m_midiEvents;
bpm_t m_bpm;
sample_rate_t m_sampleRate;
double m_currentSamplePos;
} ;
@@ -259,98 +234,30 @@ private:
VSTPlugin::VSTPlugin( void ) :
remoteVstPlugin::remoteVstPlugin( key_t _shm_in, key_t _shm_out ) :
remotePluginClient( _shm_in, _shm_out ),
m_shortName( "" ),
m_libInst( NULL ),
m_plugin( NULL ),
m_window( NULL ),
m_windowXID( 0 ),
m_windowID( 0 ),
m_windowWidth( 0 ),
m_windowHeight( 0 ),
m_lock(),
m_windowStatusChange(),
m_guiThreadID( 0 ),
m_blockSize( 0 ),
m_shm( NULL ),
m_inputs( NULL ),
m_outputs( NULL ),
m_midiEvents(),
m_bpm( 0 ),
m_sampleRate( 44100 ),
m_currentSamplePos( 0 )
{
}
void VSTPlugin::init( const std::string & _plugin_file )
remoteVstPlugin::~remoteVstPlugin()
{
if( load( _plugin_file ) == false )
{
writeValue<Sint16>( VST_FAILED_LOADING_PLUGIN );
return;
}
/* set program to zero */
/* i comment this out because it breaks dfx Geometer
* looks like we cant set programs for it
*
m_plugin->dispatcher( m_plugin, effSetProgram, 0, 0, NULL, 0.0f); */
// request rate and blocksize
writeValue<Sint16>( VST_GET_SAMPLE_RATE );
writeValue<Sint16>( VST_GET_BUFFER_SIZE );
m_plugin->dispatcher( m_plugin, effMainsChanged, 0, 1, NULL, 0.0f );
if( CreateThread( NULL, 0, guiEventLoop, this, 0, NULL ) == NULL )
{
lvsMessage( "could not create GUI-thread" );
return;
}
pthread_cond_wait( &m_windowStatusChange, &m_lock);
// now post some information about our plugin
writeValue<Sint16>( VST_PLUGIN_XID );
writeValue<Sint32>( m_windowXID );
if( m_windowXID != 0 )
{
writeValue<Sint16>( VST_PLUGIN_EDITOR_GEOMETRY );
writeValue<Sint16>( m_windowWidth );
writeValue<Sint16>( m_windowHeight );
}
writeValue<Sint16>( VST_PLUGIN_NAME );
writeString( pluginName() );
writeValue<Sint16>( VST_PLUGIN_VERSION );
writeValue<Sint32>( pluginVersion() );
writeValue<Sint16>( VST_PLUGIN_VENDOR_STRING );
writeString( pluginVendorString() );
writeValue<Sint16>( VST_PLUGIN_PRODUCT_STRING );
writeString( pluginProductString() );
writeValue<Sint16>( VST_PARAMETER_COUNT );
writeValue<Sint32>( (Sint32) m_plugin->numParams );
// tell client that we've done everything so far
writeValue<Sint16>( VST_INITIALIZATION_DONE );
}
VSTPlugin::~VSTPlugin()
{
// acknowledge quit
writeValue<Sint16>( VST_QUIT_ACK );
if( m_window != NULL )
{
// notify GUI-thread
@@ -373,17 +280,105 @@ VSTPlugin::~VSTPlugin()
delete[] m_inputs;
delete[] m_outputs;
if( m_shm != NULL )
{
shmdt( m_shm );
}
}
bool VSTPlugin::load( const std::string & _plugin_file )
bool remoteVstPlugin::processMessage( const message & _m )
{
switch( _m.id )
{
case IdVstLoadPlugin:
init( _m.getString() );
break;
case IdShowUI:
showEditor();
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 IdVstGetParameterProperties:
getParameterProperties( _m.getInt() );
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();
/* set program to zero */
/* i comment this out because it breaks dfx Geometer
* looks like we cant set programs for it
*
m_plugin->dispatcher( m_plugin, effSetProgram, 0, 0, NULL, 0.0f); */
// request rate and blocksize
m_plugin->dispatcher( m_plugin, effMainsChanged, 0, 1, NULL, 0.0f );
if( CreateThread( NULL, 0, guiEventLoop, this, 0, NULL ) == NULL )
{
fprintf( stderr, "could not create GUI-thread\n" );
return;
}
pthread_cond_wait( &m_windowStatusChange, &m_lock);
// now post some information about our plugin
sendMessage( message( IdVstPluginWindowID ).addInt( m_windowID ) );
if( m_windowID != 0 )
{
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 );
}
bool remoteVstPlugin::load( const std::string & _plugin_file )
{
if( ( m_libInst = LoadLibraryA( _plugin_file.c_str() ) ) ==
NULL )
@@ -413,7 +408,8 @@ bool VSTPlugin::load( const std::string & _plugin_file )
if( m_plugin->magic != kEffectMagic )
{
lvsMessage( "%s is not a VST plugin\n", _plugin_file.c_str() );
fprintf( stderr, "%s is not a VST plugin\n",
_plugin_file.c_str() );
}
m_plugin->dispatcher( m_plugin, effOpen, 0, 0, 0, 0 );
@@ -423,7 +419,7 @@ bool VSTPlugin::load( const std::string & _plugin_file )
void VSTPlugin::process( void )
bool remoteVstPlugin::process( const sampleFrame * _in, sampleFrame * _out )
{
// first we gonna post all MIDI-events we enqueued so far
if( m_midiEvents.size() )
@@ -440,7 +436,7 @@ void VSTPlugin::process( void )
VstEvents * events = (VstEvents *) event_buf;
events->reserved = 0;
events->numEvents = m_midiEvents.size();
Sint16 idx = 0;
int idx = 0;
for( std::list<VstMidiEvent>::iterator it =
m_midiEvents.begin();
it != m_midiEvents.end(); ++it, ++idx )
@@ -456,36 +452,33 @@ void VSTPlugin::process( void )
// now we're ready to fetch sound from VST-plugin
for( ch_cnt_t i = 0; i < inputCount(); ++i )
for( int i = 0; i < inputCount(); ++i )
{
m_inputs[i] = &m_shm[i * m_blockSize];
m_inputs[i] = &((float *) _in)[i * bufferSize()];
}
for( ch_cnt_t i = 0; i < outputCount(); ++i )
for( int i = 0; i < outputCount(); ++i )
{
m_outputs[i] = &m_shm[( i + inputCount() ) * m_blockSize];
memset( m_outputs[i], 0, m_blockSize * sizeof( float ) );
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,
m_blockSize );
m_plugin->processReplacing( m_plugin, m_inputs, m_outputs,
bufferSize() );
#ifdef OLD_VST_SDK
}
else
{
m_plugin->process( m_plugin, m_inputs, m_outputs,
m_blockSize );
bufferSize() );
}
#endif
m_currentSamplePos += m_blockSize;
writeValue<Sint16>( VST_PROCESS_DONE );
m_currentSamplePos += bufferSize();
// give plugin some idle-time for GUI-update and so on...
m_plugin->dispatcher( m_plugin, effEditIdle, 0, 0, NULL, 0 );
@@ -495,14 +488,14 @@ void VSTPlugin::process( void )
void VSTPlugin::enqueueMidiEvent( const midiEvent & _event,
const f_cnt_t _frames_ahead )
void remoteVstPlugin::processMidiEvent( const midiEvent & _event,
const f_cnt_t _offset )
{
VstMidiEvent event;
event.type = kVstMidiType;
event.byteSize = 24;
event.deltaFrames = _frames_ahead;
event.deltaFrames = _offset;
event.flags = 0;
event.detune = 0;
event.noteLength = 0;
@@ -530,23 +523,7 @@ void VSTPlugin::enqueueMidiEvent( const midiEvent & _event,
void VSTPlugin::setBlockSize( const fpp_t _bsize )
{
if( _bsize == m_blockSize )
{
return;
}
m_blockSize = _bsize;
resizeSharedMemory();
m_plugin->dispatcher( m_plugin, effSetBlockSize, 0, _bsize, NULL,
0.0f );
}
const char * VSTPlugin::pluginName( void ) const
const char * remoteVstPlugin::pluginName( void ) const
{
static char buf[32];
buf[0] = 0;
@@ -558,7 +535,7 @@ const char * VSTPlugin::pluginName( void ) const
const char * VSTPlugin::pluginVendorString( void ) const
const char * remoteVstPlugin::pluginVendorString( void ) const
{
static char buf[64];
buf[0] = 0;
@@ -570,7 +547,7 @@ const char * VSTPlugin::pluginVendorString( void ) const
const char * VSTPlugin::pluginProductString( void ) const
const char * remoteVstPlugin::pluginProductString( void ) const
{
static char buf[64];
buf[0] = 0;
@@ -582,118 +559,100 @@ const char * VSTPlugin::pluginProductString( void ) const
void VSTPlugin::getParameterDump( void ) const
void remoteVstPlugin::getParameterDump( void )
{
VstParameterProperties vst_props;
vstParameterDumpItem dump_item;
writeValue<Sint16>( VST_PARAMETER_DUMP );
writeValue<Sint32>( (Sint32) m_plugin->numParams );
for( Sint32 i = 0; i < m_plugin->numParams; ++i )
message m( IdVstParameterDump );
m.addInt( m_plugin->numParams );
for( int i = 0; i < m_plugin->numParams; ++i )
{
dump_item.index = i;
m_plugin->dispatcher( m_plugin, effGetParameterProperties, i, 0,
&vst_props, 0.0f );
memcpy( dump_item.shortLabel, vst_props.shortLabel,
sizeof( dump_item.shortLabel ) );
dump_item.value = m_plugin->getParameter( m_plugin, i );
writeValue<vstParameterDumpItem>( dump_item );
m_plugin->dispatcher( m_plugin, effGetParameterProperties, i,
0, &vst_props, 0.0f );
m.addInt( i );
m.addString( vst_props.shortLabel );
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 VSTPlugin::setParameterDump( void )
void remoteVstPlugin::getParameterProperties( const int _idx )
{
const Sint32 sz = readValue<Sint32>();
const Sint32 params = ( sz > m_plugin->numParams ) ?
m_plugin->numParams : sz;
for( Sint32 i = 0; i < params; ++i )
{
vstParameterDumpItem dump_item =
readValue<vstParameterDumpItem>();
m_plugin->setParameter( m_plugin, dump_item.index,
dump_item.value );
}
}
void VSTPlugin::getParameterProperties( const Sint32 _idx )
{
VstParameterProperties vst_props;
VstParameterProperties p;
m_plugin->dispatcher( m_plugin, effGetParameterProperties, _idx, 0,
&vst_props, 0.0f );
vstParamProperties props;
memcpy( props.label, vst_props.label, sizeof( props.label ) );
memcpy( props.shortLabel, vst_props.shortLabel,
sizeof( props.shortLabel) );
&p, 0.0f );
message m( IdVstParameterProperties );
m.addString( p.label );
m.addString( p.shortLabel );
m.addString(
#if kVstVersion > 2
memcpy( props.categoryLabel, vst_props.categoryLabel,
sizeof( props.categoryLabel ) );
p.categoryLabel
#else
""
#endif
props.minValue = vst_props.minInteger;
props.maxValue = vst_props.maxInteger;
props.step = ( vst_props.flags & kVstParameterUsesFloatStep ) ?
vst_props.stepFloat :
vst_props.stepInteger;
);
m.addFloat( p.minInteger );
m.addFloat( p.maxInteger );
m.addFloat( ( p.flags & kVstParameterUsesFloatStep ) ?
p.stepFloat : p.stepInteger );
m.addInt(
#if kVstVersion > 2
props.category = vst_props.category;
p.category
#else
0
#endif
writeValue<Sint16>( VST_PARAMETER_PROPERTIES );
writeValue<vstParamProperties>( props );
);
sendMessage( m );
}
void VSTPlugin::resizeSharedMemory( void )
void remoteVstPlugin::updateInOutCount( void )
{
delete[] m_inputs;
delete[] m_outputs;
size_t s = ( inputCount() + outputCount() ) * m_blockSize *
sizeof( float );
if( m_shm != NULL )
{
shmdt( m_shm );
}
int shm_id;
Uint16 shm_key = 0;
while( ( shm_id = shmget( ++shm_key, s, IPC_CREAT | IPC_EXCL |
0600 ) ) == -1 )
{
}
m_shm = (float *) shmat( shm_id, 0, 0 );
setInputCount( inputCount() );
setOutputCount( outputCount() );
if( inputCount() > 0 )
{
m_inputs = new float * [inputCount()];
}
if( outputCount() > 0 )
{
m_outputs = new float * [outputCount()];
}
writeValue<Sint16>( VST_INPUT_COUNT );
writeValue<ch_cnt_t>( inputCount() );
writeValue<Sint16>( VST_OUTPUT_COUNT );
writeValue<ch_cnt_t>( outputCount() );
writeValue<Sint16>( VST_SHM_KEY_AND_SIZE );
writeValue<Uint16>( shm_key );
writeValue<Uint32>( s );
}
#define DEBUG_CALLBACKS
#ifdef DEBUG_CALLBACKS
#define SHOW_CALLBACK lvsMessage
#define SHOW_CALLBACK printf
#else
#define SHOW_CALLBACK(...)
#endif
@@ -706,7 +665,7 @@ void VSTPlugin::resizeSharedMemory( void )
* - audioMasterGetDirectory: return either VST-plugin-dir or LMMS-workingdir
* - audioMasterOpenFileSelector: show QFileDialog?
*/
VstIntPtr VSTPlugin::hostCallback( AEffect * _effect, VstInt32 _opcode,
VstIntPtr remoteVstPlugin::hostCallback( AEffect * _effect, VstInt32 _opcode,
VstInt32 _index, VstIntPtr _value,
void * _ptr, float _opt )
{
@@ -756,10 +715,10 @@ VstIntPtr VSTPlugin::hostCallback( AEffect * _effect, VstInt32 _opcode,
memset( &_timeInfo, 0, sizeof( _timeInfo ) );
_timeInfo.samplePos = plugin->m_currentSamplePos;
_timeInfo.sampleRate = plugin->m_sampleRate;
_timeInfo.samplePos = __plugin->m_currentSamplePos;
_timeInfo.sampleRate = __plugin->sampleRate();
_timeInfo.flags = 0;
_timeInfo.tempo = plugin->m_bpm;
_timeInfo.tempo = __plugin->m_bpm;
_timeInfo.timeSigNumerator = 4;
_timeInfo.timeSigDenominator = 4;
_timeInfo.flags |= (/* kVstBarsValid|*/kVstTempoValid );
@@ -773,7 +732,7 @@ VstIntPtr VSTPlugin::hostCallback( AEffect * _effect, VstInt32 _opcode,
return( 0 );
case audioMasterIOChanged:
plugin->resizeSharedMemory();
__plugin->updateInOutCount();
//SHOW_CALLBACK( "amc: audioMasterIOChanged\n" );
// numInputs and/or numOutputs has changed
return( 0 );
@@ -792,7 +751,7 @@ VstIntPtr VSTPlugin::hostCallback( AEffect * _effect, VstInt32 _opcode,
case audioMasterTempoAt:
//SHOW_CALLBACK( "amc: audioMasterTempoAt\n" );
return( plugin->m_bpm * 10000 );
return( __plugin->m_bpm * 10000 );
case audioMasterGetNumAutomatableParameters:
SHOW_CALLBACK( "amc: audioMasterGetNumAutomatable"
@@ -864,36 +823,37 @@ VstIntPtr VSTPlugin::hostCallback( AEffect * _effect, VstInt32 _opcode,
case audioMasterSizeWindow:
//SHOW_CALLBACK( "amc: audioMasterSizeWindow\n" );
if( plugin->m_window == 0 )
if( __plugin->m_window == 0 )
{
return( 0 );
}
plugin->m_windowWidth = _index;
plugin->m_windowHeight = _value;
SetWindowPos( plugin->m_window, 0, 0, 0,
__plugin->m_windowWidth = _index;
__plugin->m_windowHeight = _value;
SetWindowPos( __plugin->m_window, 0, 0, 0,
_index + 8, _value + 26,
SWP_NOACTIVATE | SWP_NOMOVE |
SWP_NOOWNERZORDER | SWP_NOZORDER );
writeValue<Sint16>( VST_PLUGIN_EDITOR_GEOMETRY );
writeValue<Sint16>( plugin->m_windowWidth );
writeValue<Sint16>( plugin->m_windowHeight );
__plugin->sendMessage(
message( IdVstPluginEditorGeometry ).
addInt( __plugin->m_windowWidth ).
addInt( __plugin->m_windowHeight ) );
return( 1 );
case audioMasterGetSampleRate:
//SHOW_CALLBACK( "amc: audioMasterGetSampleRate\n" );
return( plugin->m_sampleRate );
return( __plugin->sampleRate() );
case audioMasterGetBlockSize:
//SHOW_CALLBACK( "amc: audioMasterGetBlockSize\n" );
return( plugin->m_blockSize );
return( __plugin->bufferSize() );
case audioMasterGetInputLatency:
//SHOW_CALLBACK( "amc: audioMasterGetInputLatency\n" );
return( plugin->m_blockSize );
return( __plugin->bufferSize() );
case audioMasterGetOutputLatency:
//SHOW_CALLBACK( "amc: audioMasterGetOutputLatency\n" );
return( plugin->m_blockSize );
return( __plugin->bufferSize() );
case audioMasterGetCurrentProcessLevel:
SHOW_CALLBACK( "amc: audioMasterGetCurrentProcess"
@@ -1019,16 +979,16 @@ VstIntPtr VSTPlugin::hostCallback( AEffect * _effect, VstInt32 _opcode,
DWORD WINAPI VSTPlugin::guiEventLoop( LPVOID _param )
DWORD WINAPI remoteVstPlugin::guiEventLoop( LPVOID _param )
{
VSTPlugin * _this = static_cast<VSTPlugin *>( _param );
remoteVstPlugin * _this = static_cast<remoteVstPlugin *>( _param );
_this->m_guiThreadID = GetCurrentThreadId();
// "guard point" to trap errors that occur during plugin loading
#ifdef LMMS_HAVE_TLS
if( sigsetjmp( ejmpbuf, 1 ) )
{
lvsMessage( "creating the editor for %s failed",
fprintf( stderr, "creating the editor for %s failed\n",
_this->m_shortName.c_str() );
pthread_cond_signal( &_this->m_windowStatusChange );
return( 1 );
@@ -1064,7 +1024,7 @@ DWORD WINAPI VSTPlugin::guiEventLoop( LPVOID _param )
HMODULE hInst = GetModuleHandleA( NULL );
if( hInst == NULL )
{
lvsMessage( "can't get module handle" );
fprintf( stderr, "can't get module handle\n" );
pthread_cond_signal( &_this->m_windowStatusChange );
return( 1 );
}
@@ -1075,14 +1035,14 @@ DWORD WINAPI VSTPlugin::guiEventLoop( LPVOID _param )
~WS_MAXIMIZEBOX ),
0, 0, 1, 1, NULL, NULL, hInst, NULL ) ) == NULL )
{
lvsMessage( "cannot create editor window" );
fprintf( stderr, "cannot create editor window\n" );
pthread_cond_signal( &_this->m_windowStatusChange );
return( 1 );
}
ShowWindow( _this->m_window, SW_SHOWMINIMIZED );
ShowWindow( _this->m_window, SW_HIDE );
_this->m_windowXID = (Sint32) GetPropA( _this->m_window,
_this->m_windowID = (Sint32) GetPropA( _this->m_window,
"__wine_x11_whole_window" );
@@ -1148,13 +1108,25 @@ DWORD WINAPI VSTPlugin::guiEventLoop( LPVOID _param )
int main( void )
int main( int _argc, char * * _argv )
{
if( _argc < 3 )
{
fprintf( stderr, "not enough arguments\n" );
return( -1 );
}
#ifdef LMMS_BUILD_WIN32
// (non-portable) initialization of statically linked pthread library
pthread_win32_process_attach_np();
pthread_win32_thread_attach_np();
#endif
// WINE-startup
HMODULE hInst = GetModuleHandleA( NULL );
if( hInst == NULL )
{
lvsMessage( "can't get module handle" );
fprintf( stderr, "can't get module handle\n" );
return( -1 );
}
@@ -1182,84 +1154,28 @@ int main( void )
sched_get_priority_min( SCHED_FIFO ) ) / 2;
if( sched_setscheduler( 0, SCHED_FIFO, &sparam ) == -1 )
{
lvsMessage( "could not set realtime priority for VST-server" );
fprintf( stderr, "could not set realtime priority for "
"remoteVstPlugin\n" );
}
#endif
Sint16 cmd;
while( ( cmd = readValue<Sint16>() ) != VST_CLOSE_PLUGIN )
{
switch( cmd )
{
case VST_LOAD_PLUGIN:
plugin = new VSTPlugin();
plugin->init( readString() );
break;
__plugin = new remoteVstPlugin( atoi( _argv[1] ), atoi( _argv[2] ) );
case VST_SHOW_EDITOR:
plugin->showEditor();
break;
case VST_PROCESS:
plugin->process();
break;
case VST_ENQUEUE_MIDI_EVENT:
{
MidiEventTypes type =
readValue<MidiEventTypes>();
Sint8 channel = readValue<Sint8>();
Uint16 param1 = readValue<Uint16>();
Uint16 param2 = readValue<Uint16>();
const midiEvent ev = midiEvent( type, channel,
param1, param2 );
const f_cnt_t fr_ahead = readValue<f_cnt_t>();
plugin->enqueueMidiEvent( ev, fr_ahead );
break;
}
case VST_SAMPLE_RATE:
plugin->setSampleRate(
readValue<sample_rate_t>() );
break;
case VST_BUFFER_SIZE:
plugin->setBlockSize( readValue<fpp_t>() );
break;
case VST_BPM:
plugin->setBPM( readValue<bpm_t>() );
break;
case VST_LANGUAGE:
hlang = readValue<hostLanguages>();
break;
case VST_GET_PARAMETER_DUMP:
plugin->getParameterDump();
break;
case VST_SET_PARAMETER_DUMP:
plugin->setParameterDump();
break;
case VST_GET_PARAMETER_PROPERTIES:
plugin->getParameterProperties(
readValue<Sint32>() );
break;
default:
lvsMessage( "unhandled message: %d\n",
(int) cmd );
break;
}
remotePluginClient::message m;
while( ( m = __plugin->receiveMessage() ).id != IdQuit )
{
__plugin->processMessage( m );
}
delete plugin;
delete __plugin;
return( 0 );
#ifdef LMMS_BUILD_WIN32
pthread_win32_thread_detach_np();
pthread_win32_process_detach_np();
#endif
return 0;
}

View File

@@ -1,5 +1,5 @@
/*
* lvsl_client.cpp - client for LVSL Server
* vst_plugin.cpp - implementation of vstPlugin class
*
* Copyright (c) 2005-2008 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
@@ -23,50 +23,17 @@
*/
#include "lvsl_client.h"
#include "lmmsconfig.h"
#include "vst_plugin.h"
#include <QtCore/QCoreApplication>
#include <QtCore/QDir>
#include <QtCore/QEventLoop>
#include <QtCore/QFileInfo>
#include <QtCore/QLocale>
#include <QtCore/QTime>
#include <QtGui/QMdiArea>
#include <QtGui/QMdiSubWindow>
#include <QtGui/QX11EmbedContainer>
#include <QtGui/QX11Info>
#include <QtXml/QDomDocument>
#ifdef LMMS_HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef LMMS_HAVE_SIGNAL_H
#include <signal.h>
#endif
#include <cstdio>
#ifdef LMMS_HAVE_SYS_IPC_H
#include <sys/ipc.h>
#endif
#ifdef LMMS_HAVE_SYS_SHM_H
#include <sys/shm.h>
#endif
#ifdef LMMS_HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#ifdef LMMS_HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#ifdef LMMS_HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif
#include "config_mgr.h"
#include "engine.h"
@@ -76,54 +43,23 @@
remoteVSTPlugin::remoteVSTPlugin( const QString & _plugin ) :
vstPlugin::vstPlugin( const QString & _plugin ) :
QObject(),
m_failed( TRUE ),
journallingObject(),
remotePlugin( "remote_vst_plugin", false ),
m_plugin( _plugin ),
m_pluginWidget( NULL ),
m_pluginXID( 0 ),
m_pluginPID( -1 ),
m_serverInFD( -1 ),
m_serverOutFD( -1 ),
m_serverMutex(),
m_pluginWindowID( 0 ),
m_name( "" ),
m_version( 0 ),
m_vendorString( "" ),
m_productString( "" ),
m_inputCount( 0 ),
m_outputCount( 0 ),
m_shmID( -1 ),
m_shm( NULL ),
m_shmSize( 0 ),
m_initialized( FALSE )
m_productString( "" )
{
pipe( m_pipes[0] );
pipe( m_pipes[1] );
if( ( m_pluginPID = fork() ) < 0 )
{
printf( "fork() failed!\n" );
return;
}
else if( m_pluginPID == 0 )
{
dup2( m_pipes[0][0], 0 );
dup2( m_pipes[1][1], 1 );
QString lvsl_server_exec = configManager::inst()->pluginDir() +
QDir::separator() +
"lvsl_server";
execlp( lvsl_server_exec.toAscii().constData(),
lvsl_server_exec.toAscii().constData(),
NULL );
exit( 0 );
}
m_serverInFD = m_pipes[1][0];
m_serverOutFD = m_pipes[0][1];
setSplittedChannels( true );
lock();
writeValueS<Sint16>( VST_LANGUAGE );
hostLanguages hlang = LanguageEnglish;
VstHostLanguages hlang = LanguageEnglish;
switch( QLocale::system().language() )
{
case QLocale::German: hlang = LanguageGerman; break;
@@ -133,7 +69,8 @@ remoteVSTPlugin::remoteVSTPlugin( const QString & _plugin ) :
case QLocale::Japanese: hlang = LanguageJapanese; break;
default: break;
}
writeValueS<hostLanguages>( hlang );
sendMessage( message( IdVstSetLanguage ).addInt( hlang ) );
QString p = m_plugin;
if( QFileInfo( p ).dir().isRelative() )
@@ -141,81 +78,31 @@ remoteVSTPlugin::remoteVSTPlugin( const QString & _plugin ) :
p = configManager::inst()->vstDir() + QDir::separator() + p;
}
writeValueS<Sint16>( VST_LOAD_PLUGIN );
writeStringS( p.toAscii().constData() );
sendMessage( message( IdVstLoadPlugin ).addString( p.toStdString() ) );
waitForInitDone();
unlock();
while( 1 )
{
Sint16 cmd = VST_UNDEFINED_CMD;
if( messagesLeft() == TRUE )
{
cmd = processNextMessage();
}
if( cmd == VST_INITIALIZATION_DONE )
{
m_failed = FALSE;
break;
}
else if( cmd == VST_FAILED_LOADING_PLUGIN )
{
break;
}
QCoreApplication::processEvents( QEventLoop::AllEvents, 50 );
}
}
remoteVSTPlugin::~remoteVSTPlugin()
vstPlugin::~vstPlugin()
{
if( m_failed == FALSE )
if( m_pluginWidget != NULL &&
m_pluginWidget->parentWidget() != NULL &&
dynamic_cast<QMdiSubWindow *>(
m_pluginWidget->parentWidget() ) != NULL )
{
setShmKeyAndSize( 0, 0 );
// tell server to quit and wait for acknowledge
writeValueS<Sint16>( VST_CLOSE_PLUGIN );
QTime t;
t.start();
while( t.elapsed() < 1000 )
{
if( messagesLeft() == TRUE &&
processNextMessage() == VST_QUIT_ACK )
{
//m_pluginPID = 0;
break;
}
}
if( m_pluginWidget != NULL &&
m_pluginWidget->parentWidget() != NULL &&
dynamic_cast<QMdiSubWindow *>(
m_pluginWidget->parentWidget() ) != NULL )
{
delete m_pluginWidget->parentWidget();
}
// timeout?
/* if( m_pluginPID != 0 )
{*/
kill( m_pluginPID, SIGTERM );
kill( m_pluginPID, SIGKILL );
//}
// remove process from PCB
waitpid( m_pluginPID, NULL, 0 );
// close all sides of our pipes
close( m_pipes[0][0] );
close( m_pipes[0][1] );
close( m_pipes[1][0] );
close( m_pipes[1][1] );
/* close( m_serverInFD );
close( m_serverOutFD );*/
delete m_pluginWidget->parentWidget();
}
}
QWidget * remoteVSTPlugin::showEditor( QWidget * _parent )
QWidget * vstPlugin::showEditor( QWidget * _parent )
{
if( m_pluginWidget != NULL )
{
@@ -226,7 +113,7 @@ QWidget * remoteVSTPlugin::showEditor( QWidget * _parent )
return( m_pluginWidget );
}
if( m_pluginXID == 0 )
if( m_pluginWindowID == 0 )
{
return( NULL );
}
@@ -236,20 +123,22 @@ QWidget * remoteVSTPlugin::showEditor( QWidget * _parent )
m_pluginWidget->setWindowTitle( name() );
if( _parent == NULL )
{
engine::getMainWindow()->workspace()->addSubWindow( m_pluginWidget )
engine::getMainWindow()->workspace()->addSubWindow(
m_pluginWidget )
->setAttribute( Qt::WA_DeleteOnClose, FALSE );
}
#ifdef LMMS_BUILD_LINUX
QX11EmbedContainer * xe = new QX11EmbedContainer( m_pluginWidget );
xe->embedClient( m_pluginXID );
xe->embedClient( m_pluginWindowID );
xe->setFixedSize( m_pluginGeometry );
//xe->setAutoDelete( FALSE );
xe->show();
#endif
m_pluginWidget->show();
lock();
writeValueS<Sint16>( VST_SHOW_EDITOR );
unlock();
showUI();
return( m_pluginWidget );
}
@@ -257,7 +146,7 @@ QWidget * remoteVSTPlugin::showEditor( QWidget * _parent )
void remoteVSTPlugin::hideEditor( void )
void vstPlugin::hideEditor( void )
{
if( m_pluginWidget != NULL && m_pluginWidget->parentWidget() )
{
@@ -268,116 +157,7 @@ void remoteVSTPlugin::hideEditor( void )
bool remoteVSTPlugin::process( const sampleFrame * _in_buf,
sampleFrame * _out_buf, bool _wait )
{
const fpp_t frames = engine::getMixer()->framesPerPeriod();
if( m_shm == NULL )
{
// m_shm being zero means we didn't initialize everything so
// far so process one message each time (and hope we get
// information like SHM-key etc.) until we process messages
// in a later stage of this procedure
if( m_shmSize == 0 && messagesLeft() == TRUE )
{
(void) processNextMessage();
}
if( _out_buf != NULL )
{
engine::getMixer()->clearAudioBuffer( _out_buf,
frames );
}
return( FALSE );
}
memset( m_shm, 0, m_shmSize );
ch_cnt_t inputs = tMax<ch_cnt_t>( m_inputCount, DEFAULT_CHANNELS );
if( _in_buf != NULL && inputs > 0 )
{
for( ch_cnt_t ch = 0; ch < inputs; ++ch )
{
for( fpp_t frame = 0; frame < frames; ++frame )
{
m_shm[ch * frames + frame] = _in_buf[frame][ch];
}
}
}
lock();
writeValueS<Sint16>( VST_PROCESS );
unlock();
m_initialized = TRUE;
if( _wait )
{
waitForProcessingFinished( _out_buf );
}
return( TRUE );
}
bool remoteVSTPlugin::waitForProcessingFinished( sampleFrame * _out_buf )
{
if( !m_initialized || _out_buf == NULL || m_outputCount == 0 )
{
return( FALSE );
}
// wait until server signals that process()ing is done
while( processNextMessage() != VST_PROCESS_DONE )
{
// hopefully scheduler gives process-time to plugin...
usleep( 10 );
}
const fpp_t frames = engine::getMixer()->framesPerPeriod();
const ch_cnt_t outputs = tMax<ch_cnt_t>( m_outputCount,
DEFAULT_CHANNELS );
if( outputs != DEFAULT_CHANNELS )
{
// clear buffer, if plugin didn't fill up both channels
engine::getMixer()->clearAudioBuffer( _out_buf, frames );
}
for( ch_cnt_t ch = 0; ch < outputs; ++ch )
{
for( fpp_t frame = 0; frame < frames; ++frame )
{
_out_buf[frame][ch] = m_shm[( m_inputCount + ch ) *
frames + frame];
}
}
return( TRUE );
}
void remoteVSTPlugin::enqueueMidiEvent( const midiEvent & _event,
const f_cnt_t _frames_ahead )
{
lock();
writeValueS<Sint16>( VST_ENQUEUE_MIDI_EVENT );
writeValueS<MidiEventTypes>( _event.m_type );
writeValueS<Sint8>( _event.m_channel );
writeValueS<Uint16>( _event.m_data.m_param[0] );
writeValueS<Uint16>( _event.m_data.m_param[1] );
writeValueS<f_cnt_t>( _frames_ahead );
unlock();
}
void remoteVSTPlugin::loadSettings( const QDomElement & _this )
void vstPlugin::loadSettings( const QDomElement & _this )
{
if( pluginWidget() != NULL )
{
@@ -407,7 +187,7 @@ void remoteVSTPlugin::loadSettings( const QDomElement & _this )
void remoteVSTPlugin::saveSettings( QDomDocument & _doc, QDomElement & _this )
void vstPlugin::saveSettings( QDomDocument & _doc, QDomElement & _this )
{
if( pluginWidget() != NULL )
{
@@ -425,36 +205,31 @@ void remoteVSTPlugin::saveSettings( QDomDocument & _doc, QDomElement & _this )
void remoteVSTPlugin::setTempo( bpm_t _bpm )
void vstPlugin::setTempo( bpm_t _bpm )
{
lock();
writeValueS<Sint16>( VST_BPM );
writeValueS<bpm_t>( _bpm );
sendMessage( message( IdVstSetTempo ).addInt( _bpm ) );
unlock();
}
void remoteVSTPlugin::updateSampleRate( void )
void vstPlugin::updateSampleRate( void )
{
lock();
writeValueS<Sint16>( VST_SAMPLE_RATE );
writeValueS<sample_rate_t>(
engine::getMixer()->processingSampleRate() );
sendMessage( message( IdSampleRateInformation ).
addInt( engine::getMixer()->processingSampleRate() ) );
unlock();
}
const QMap<QString, QString> & remoteVSTPlugin::parameterDump( void )
const QMap<QString, QString> & vstPlugin::parameterDump( void )
{
writeValueS<Sint16>( VST_GET_PARAMETER_DUMP );
while( processNextMessage() != VST_PARAMETER_DUMP )
{
}
sendMessage( IdVstGetParameterDump );
waitForMessage( IdVstParameterDump );
return( m_parameterDump );
}
@@ -462,127 +237,43 @@ const QMap<QString, QString> & remoteVSTPlugin::parameterDump( void )
void remoteVSTPlugin::setParameterDump( const QMap<QString, QString> & _pdump )
void vstPlugin::setParameterDump( const QMap<QString, QString> & _pdump )
{
writeValueS<Sint16>( VST_SET_PARAMETER_DUMP );
writeValueS<Sint32>( _pdump.size() );
message m( IdVstSetParameterDump );
m.addInt( _pdump.size() );
for( QMap<QString, QString>::const_iterator it = _pdump.begin();
it != _pdump.end(); ++it )
{
const vstParameterDumpItem dump_item =
const vstParameterDumpItem item =
{
( *it ).section( ':', 0, 0 ).toInt(),
"",
( *it ).section( ':', 1, 1 ).toFloat()
} ;
writeValueS<vstParameterDumpItem>( dump_item );
m.addInt( item.index );
m.addString( item.shortLabel );
m.addFloat( item.value );
}
}
void remoteVSTPlugin::setShmKeyAndSize( Uint16 _key, size_t _size )
{
if( m_shm != NULL && m_shmSize > 0 )
{
shmdt( m_shm );
m_shm = NULL;
m_shmSize = 0;
}
// only called for detaching SHM?
if( _size == 0 )
{
return;
}
int shm_id = shmget( _key, _size, 0 );
if( shm_id == -1 )
{
printf( "failed getting shared memory\n" );
}
else
{
m_shm = (float *) shmat( shm_id, 0, 0 );
// TODO: error-checking
}
}
bool remoteVSTPlugin::messagesLeft( void ) const
{
fd_set rfds;
FD_ZERO( &rfds );
FD_SET( m_serverInFD, &rfds );
timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 1; // can we use 0 here?
return( select( m_serverInFD + 1, &rfds, NULL, NULL, &tv ) > 0 );
}
Sint16 remoteVSTPlugin::processNextMessage( void )
{
fd_set rfds;
FD_ZERO( &rfds );
FD_SET( m_serverInFD, &rfds );
if( select( m_serverInFD + 1, &rfds, NULL, NULL, NULL ) <= 0 )
{
return( VST_UNDEFINED_CMD );
}
lock();
Sint16 cmd = readValueS<Sint16>();
switch( cmd )
sendMessage( m );
unlock();
}
bool vstPlugin::processMessage( const message & _m )
{
switch( _m.id )
{
case VST_DEBUG_MSG:
printf( "debug message from server: %s\n",
readStringS().c_str() );
case IdVstPluginWindowID:
m_pluginWindowID = _m.getInt();
break;
case VST_GET_SAMPLE_RATE:
writeValueS<Sint16>( VST_SAMPLE_RATE );
// handle is the same
writeValueS<sample_rate_t>(
engine::getMixer()->processingSampleRate() );
break;
case VST_GET_BUFFER_SIZE:
writeValueS<Sint16>( VST_BUFFER_SIZE );
// handle is the same
writeValueS<fpp_t>(
engine::getMixer()->framesPerPeriod() );
break;
case VST_SHM_KEY_AND_SIZE:
case IdVstPluginEditorGeometry:
{
Uint16 shm_key = readValueS<Uint16>();
size_t shm_size = readValueS<Uint32>();
setShmKeyAndSize( shm_key, shm_size );
break;
}
case VST_INPUT_COUNT:
m_inputCount = readValueS<ch_cnt_t>();
break;
case VST_OUTPUT_COUNT:
m_outputCount = readValueS<ch_cnt_t>();
break;
case VST_PLUGIN_XID:
m_pluginXID = readValueS<Sint32>();
break;
case VST_PLUGIN_EDITOR_GEOMETRY:
{
const Sint16 w = readValueS<Sint16>();
const Sint16 h = readValueS<Sint16>();
const int w = _m.getInt( 0 );
const int h = _m.getInt( 1 );
m_pluginGeometry = QSize( w, h );
if( m_pluginWidget != NULL )
{
@@ -598,50 +289,48 @@ Sint16 remoteVSTPlugin::processNextMessage( void )
break;
}
case VST_PLUGIN_NAME:
m_name = readStringS().c_str();
case IdVstPluginName:
m_name = _m.getQString();
break;
case VST_PLUGIN_VERSION:
m_version = readValueS<Sint32>();
case IdVstPluginVersion:
m_version = _m.getInt();
break;
case VST_PLUGIN_VENDOR_STRING:
m_vendorString = readStringS().c_str();
case IdVstPluginVendorString:
m_vendorString = _m.getQString();
break;
case VST_PLUGIN_PRODUCT_STRING:
m_productString = readStringS().c_str();
case IdVstPluginProductString:
m_productString = _m.getQString();
break;
case VST_PARAMETER_DUMP:
case IdVstParameterDump:
{
m_parameterDump.clear();
const Sint32 num_params = readValueS<Sint32>();
for( Sint32 i = 0; i < num_params; ++i )
const int num_params = _m.getInt();
int p = 0;
for( int i = 0; i < num_params; ++i )
{
vstParameterDumpItem dump_item =
readValueS<vstParameterDumpItem>();
m_parameterDump["param" + QString::number( dump_item.index )] =
QString::number( dump_item.index ) + ":" +
// QString( dump_item.shortLabel ) + ":" +
QString::number( dump_item.value );
vstParameterDumpItem item;
item.index = _m.getInt( ++p );
item.shortLabel = _m.getString( ++p );
item.value = _m.getFloat( ++p );
m_parameterDump["param" + QString::number( item.index )] =
QString::number( item.index ) + ":" +
// QString( item.shortLabel ) + ":" +
QString::number( item.value );
}
break;
}
case VST_PROCESS_DONE:
case VST_QUIT_ACK:
case VST_UNDEFINED_CMD:
default:
break;
return remotePlugin::processMessage( _m );
}
unlock();
return true;
return( cmd );
}
#include "moc_lvsl_client.cxx"
#include "moc_vst_plugin.cxx"

View File

@@ -1,5 +1,5 @@
/*
* lvsl_client.h - client for LVSL Server
* vst_plugin.h - declaration of vstPlugin class
*
* Copyright (c) 2005-2008 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
@@ -23,26 +23,28 @@
*/
#ifndef _LVSL_CLIENT_H
#define _LVSL_CLIENT_H
#ifndef _VST_PLUGIN_H
#define _VST_PLUGIN_H
#include <QtCore/QString>
#include <QtCore/QMutex>
#include <QtGui/QWidget>
#include "mixer.h"
#include "communication.h"
#include "midi.h"
#include "journalling_object.h"
#include "communication.h"
#include "remote_plugin.h"
class remoteVSTPlugin : public QObject, public journallingObject
class vstPlugin : public QObject, public journallingObject, public remotePlugin
{
Q_OBJECT
public:
remoteVSTPlugin( const QString & _plugin );
virtual ~remoteVSTPlugin();
vstPlugin( const QString & _plugin );
virtual ~vstPlugin();
virtual bool processMessage( const message & _m );
QWidget * showEditor( QWidget * _parent = NULL );
void hideEditor( void );
@@ -67,42 +69,16 @@ public:
return( m_productString );
}
// if _wait == TRUE, process() calls waitForProcessingFinished()
// immediately, otherwise, _out_buf can be zero and you've to call
// waitForProcessingFinished() on your own
bool process( const sampleFrame * _in_buf, sampleFrame * _out_buf,
bool _wait );
bool waitForProcessingFinished( sampleFrame * _out_buf );
void enqueueMidiEvent( const midiEvent & _event,
const f_cnt_t _frames_ahead );
const QMap<QString, QString> & parameterDump( void );
void setParameterDump( const QMap<QString, QString> & _pdump );
inline Uint8 inputCount( void ) const
{
return( m_inputCount );
}
inline Uint8 outputCount( void ) const
{
return( m_outputCount );
}
inline QWidget * pluginWidget( void )
{
return( m_pluginWidget != NULL ?
m_pluginWidget->parentWidget() : NULL );
}
inline bool failed( void ) const
{
return( m_failed );
}
virtual void loadSettings( const QDomElement & _this );
virtual void saveSettings( QDomDocument & _doc, QDomElement & _this );
@@ -118,57 +94,11 @@ public slots:
private:
template<typename T>
inline T readValueS( void ) const
{
return( ::readValue<T>( m_serverInFD ) );
}
template<typename T>
inline void writeValueS( const T & _i ) const
{
::writeValue<T>( _i, m_serverOutFD );
}
inline std::string readStringS( void ) const
{
return( ::readString( m_serverInFD ) );
}
inline void writeStringS( const char * _str ) const
{
::writeString( _str, m_serverOutFD );
}
inline void lock( void )
{
m_serverMutex.lock();
}
inline void unlock( void )
{
m_serverMutex.unlock();
}
bool messagesLeft( void ) const;
Sint16 processNextMessage( void );
void setShmKeyAndSize( const Uint16 _key, const size_t _size );
bool m_failed;
QString m_plugin;
QWidget * m_pluginWidget;
Sint32 m_pluginXID;
int m_pluginWindowID;
QSize m_pluginGeometry;
int m_pluginPID;
int m_pipes[2][2];
int m_serverInFD;
int m_serverOutFD;
QMutex m_serverMutex;
QString m_name;
Sint32 m_version;
QString m_vendorString;
@@ -176,15 +106,6 @@ private:
QMap<QString, QString> m_parameterDump;
Uint8 m_inputCount;
Uint8 m_outputCount;
int m_shmID;
float * m_shm;
size_t m_shmSize;
bool m_initialized;
} ;

View File

@@ -125,20 +125,20 @@ bool vstEffect::processAudioBuffer( sampleFrame * _buf, const fpp_t _frames )
void vstEffect::openPlugin( const QString & _plugin )
{
textFloat * tf = textFloat::displayMessage(
remoteVSTPlugin::tr( "Loading plugin" ),
remoteVSTPlugin::tr(
vstPlugin::tr( "Loading plugin" ),
vstPlugin::tr(
"Please wait while loading VST-plugin..." ),
PLUGIN_NAME::getIconPixmap( "logo", 24, 24 ), 0 );
m_pluginMutex.lock();
m_plugin = new remoteVSTPlugin( _plugin );
m_plugin = new vstPlugin( _plugin );
if( m_plugin->failed() )
{
m_pluginMutex.unlock();
closePlugin();
delete tf;
QMessageBox::information( NULL,
remoteVSTPlugin::tr( "Failed loading VST-plugin" ),
remoteVSTPlugin::tr( "The VST-plugin %1 could not "
vstPlugin::tr( "Failed loading VST-plugin" ),
vstPlugin::tr( "The VST-plugin %1 could not "
"be loaded for some reason.\n"
"If it runs with other VST-"
"software under Linux, please "
@@ -147,7 +147,7 @@ void vstEffect::openPlugin( const QString & _plugin )
QMessageBox::Ok );
return;
}
remoteVSTPlugin::connect( engine::getSong(),
vstPlugin::connect( engine::getSong(),
SIGNAL( tempoChanged( bpm_t ) ),
m_plugin, SLOT( setTempo( bpm_t ) ) );
m_plugin->setTempo( engine::getSong()->getTempo() );

View File

@@ -29,7 +29,7 @@
#include <QtCore/QMutex>
#include "effect.h"
#include "lvsl_client.h"
#include "vst_plugin.h"
#include "vst_effect_control_dialog.h"
#include "vst_effect_controls.h"
@@ -61,7 +61,7 @@ private:
void openPlugin( const QString & _plugin );
void closePlugin( void );
remoteVSTPlugin * m_plugin;
vstPlugin * m_plugin;
QMutex m_pluginMutex;
effectKey m_key;