heavy changes in VST-support-layer

git-svn-id: https://lmms.svn.sf.net/svnroot/lmms/trunk/lmms@73 0778d3d1-df1d-0410-868b-ea421aaaa00d
This commit is contained in:
Tobias Doerffel
2006-01-31 08:10:43 +00:00
parent bce6158cb7
commit f0cfa20676
9 changed files with 1933 additions and 24 deletions

View File

@@ -1,3 +1,18 @@
2006-01-30 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* plugins/vestige/fstclient.h:
* plugins/vestige/fstclient.cpp:
- renamed to lvsl_client.*
- when waiting for plugin to have finished process()ing, usleep() some
micro-seconds for allowing better scheduling
* plugins/vestige/lvsl_server.c:
- merged code from fstserver.cpp, fstserver.h and fstcore.c into one
source-file and removed rests of the old FST-API which makes all
the VST-code MUCH more cleaner and less redundant (LVSL = LMMS VST
Support Layer)
- VST SDK 2.4 compatibility (no need to fix headers with 2.4!)
2006-01-29 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* plugins/bit_invader/bit_invader.cpp:
@@ -6,7 +21,7 @@
them in a loop
* plugins/bit_invader/graph.cpp:
- update after settings new sample
- update after setting new sample
* src/tracks/pattern.cpp:
- disable auto-cleanup during pattern-freeze

View File

@@ -295,7 +295,7 @@ lmms_SOURCES = \
EXTRA_DIST = $(lmms_EMBEDDED_RESOURCES) aeffectx_h_fix.patch
EXTRA_DIST = $(lmms_EMBEDDED_RESOURCES) vst_sdk23_headers.diff
CLEANFILES = $(lmms_MOC) ./embedded_resources.h

View File

@@ -2,8 +2,8 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.50)
AC_INIT(lmms, 0.1.2-cvs20060129, tobydox/at/users/dot/sourceforge/dot/net)
AM_INIT_AUTOMAKE(lmms, 0.1.2-cvs20060129)
AC_INIT(lmms, 0.1.2-cvs20060130, tobydox/at/users/dot/sourceforge/dot/net)
AM_INIT_AUTOMAKE(lmms, 0.1.2-cvs20060130)
AM_CONFIG_HEADER(config.h)
@@ -162,16 +162,15 @@ AC_ARG_WITH(vst,
[enable support for builtin VST-plugin-hosting]), [ with_vst=yes ], [ with_vst=no ])
AH_TEMPLATE(HAVE_VST_AEFFECTX_H, [Define to 1 if you have the <aeffectx.h> header file.])
if test "x$with_vst" = "xyes" ; then
ORIG_CFLAGS=$CFLAGS
ORIG_CPPFLAGS=$CPPFLAGS
CFLAGS="$CLFAGS -I./include"
CPPFLAGS="$CPPFLAGS -I./include"
AC_CHECK_HEADER(aeffectx.h, HAVE_VST_AEFFECTX_H="true")
if test -z "$HAVE_VST_AEFFECTX_H" ; then
ORIG_CFLAGS=$CFLAGS
ORIG_CPPFLAGS=$CPPFLAGS
CFLAGS="$CLFAGS -I./include"
CPPFLAGS="$CPPFLAGS -I./include"
AC_CHECK_HEADER(aeffectx.h, HAVE_VST_AEFFECTX_H="true")
CFLAGS="$ORIG_CFLAGS"
CPPFLAGS="$ORIG_CPPFLAGS"
fi
CFLAGS="$ORIG_CFLAGS"
CPPFLAGS="$ORIG_CPPFLAGS"
AC_CHECK_PROG(WINEGCC, winegcc, /usr/bin/winegcc,,/usr/bin)
AC_CHECK_LIB([wine], [wine_init])
if test ! -z "$WINEGCC" ; then
@@ -649,8 +648,8 @@ else
echo " = http://www.steinberg.de/Steinberg/ygrabit/vstsdk/OnlineDoc/source/common/AEffect.h"
echo " = http://www.steinberg.de/Steinberg/ygrabit/vstsdk/OnlineDoc/source/common/aeffectx.h"
echo " ="
echo " = and put the mentioned files into /usr/include/ or ./include. Make sure, they're"
echo " = patched with file vst_sdk23_headers.diff!"
echo " = and put the mentioned files into /usr/include/ or ./include. Make sure,"
echo "= they're patched with file vst_sdk23_headers.diff!"
echo " = Otherwise (now!) configure will disable LMMS's support for built-in VST-"
echo " = plugin-usage. If you do not intend to use VST-plugins with LMMS you can "
echo " = ignore this warning."

View File

@@ -21,19 +21,26 @@ EMBEDDED_RESOURCES = $(wildcard *png)
EXTRA_DIST = $(EMBEDDED_RESOURCES)
CLEANFILES = $(MOC_FILES) ./embedded_resources.h xfst.exe.so
pkglib_LTLIBRARIES = libvestige.la
libvestige_la_SOURCES = vestige.cpp vestige.h fstclient.cpp fstclient.h
libvestige_la_SOURCES = vestige.cpp vestige.h lvsl_client.cpp lvsl_client.h
$(libvestige_la_SOURCES): ./embedded_resources.h
CC = winegcc
pkglib_PROGRAMS = xfst_server
xfst_server_SOURCES = fstserver.cpp fstcore.c fstserver.h communication.h
xfst_server_LDFLAGS = -mwindows -L/usr/X11R6/lib -lX11 -lpthread -o $(pkglib_PROGRAMS)
xfst_server_LINK = wineg++
CC = wineg++
pkglib_PROGRAMS = lvsl_server
lvsl_server_SOURCES = lvsl_server.c communication.h
lvsl_server_LDFLAGS = -mwindows -L/usr/X11R6/lib -lX11 -lpthread -o $(pkglib_PROGRAMS)
lvsl_server_LINK = wineg++
nobase_pkglib_DATA = $(pkglib_PROGRAMS).exe.so
CLEANFILES = $(MOC_FILES) ./embedded_resources.h $(nobase_pkglib_DATA)
install-exec-hook:
cd $(DESTDIR)$(pkglibdir) ; \
strip $(nobase_pkglib_DATA)

View File

@@ -1,8 +1,14 @@
#ifndef _COMMUNICATION_H
#define _COMMUNICATION_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#include <string.h>
#endif
#include <string>

View File

@@ -0,0 +1,538 @@
/*
* lvsl_client.cpp - client for LVSL Server
*
* Copyright (c) 2005-2006 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
*
* 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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#include "qt3support.h"
#ifdef QT4
#include <QApplication>
#include <QX11EmbedWidget>
#include <QX11Info>
#include <QTime>
#else
#include <qapplication.h>
#include "qxembed.h"
#define QX11EmbedWidget QXEmbed
#define embedInto embed
#endif
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_SIGNAL_H
#include <signal.h>
#endif
#include <cstdio>
#ifdef HAVE_SYS_IPC_H
#include <sys/ipc.h>
#endif
#ifdef HAVE_SYS_SHM_H
#include <sys/shm.h>
#endif
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#include "templates.h"
#include "config_mgr.h"
#include "lmms_main_win.h"
#include "lvsl_client.h"
remoteVSTPlugin::remoteVSTPlugin( const QString & _plugin ) :
m_failed( TRUE ),
m_plugin( _plugin ),
m_pluginWidget( NULL ),
m_pluginWID( 0 ),
m_pluginPID( -1 ),
m_serverInFD( -1 ),
m_serverOutFD( -1 ),
m_serverMutex(),
m_name( "" ),
m_version( 0 ),
m_vendorString( "" ),
m_productString( "" ),
m_inputCount( 0 ),
m_outputCount( 0 ),
m_shmID( -1 ),
m_shm( NULL ),
m_shmSize( 0 )
{
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() +
"lvsl_server";
execlp( lvsl_server_exec.
#ifdef QT4
toAscii().constData(),
#else
ascii(),
#endif
lvsl_server_exec.
#ifdef QT4
toAscii().constData(),
#else
ascii(),
#endif
"", NULL );
return;
}
m_serverInFD = m_pipes[1][0];
m_serverOutFD = m_pipes[0][1];
lock();
writeValueS<Sint16>( VST_LOAD_PLUGIN );
writeStringS( m_plugin.
#ifdef QT4
toAscii().constData()
#else
ascii()
#endif
);
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;
}
#ifdef QT4
QApplication::processEvents( QEventLoop::AllEvents, 50 );
#else
qApp->processEvents( 50 );
#endif
}
}
remoteVSTPlugin::~remoteVSTPlugin()
{
if( m_failed == FALSE )
{
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->hide();
delete m_pluginWidget;
}
// timeout?
/* if( m_pluginPID != 0 )
{*/
kill( m_pluginPID, SIGTERM );
//}
// 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 );*/
}
}
#include <X11/Xlib.h>
void remoteVSTPlugin::showEditor( void )
{
if( m_pluginWidget != NULL )
{
m_pluginWidget->show();
return;
}
if( m_pluginWID == 0 )
{
return;
}
XWindowAttributes attr;
XGetWindowAttributes(
#ifdef QT4
QX11Info::display(),
#else
qt_xdisplay(),
#endif
m_pluginWID, &attr );
m_pluginWidget = new QWidget( lmmsMainWin::inst()->workspace() );
m_pluginWidget->setFixedSize( attr.width, attr.height );
m_pluginWidget->setWindowTitle( name() );
QX11EmbedWidget * xe = new QX11EmbedWidget( m_pluginWidget );
xe->embedInto( m_pluginWID );
xe->setFixedSize( attr.width, attr.height );
//xe->setAutoDelete( FALSE );
m_pluginWidget->show();
xe->show();
lock();
writeValueS<Sint16>( VST_SHOW_EDITOR );
unlock();
}
void remoteVSTPlugin::hideEditor( void )
{
if( m_pluginWidget != NULL )
{
m_pluginWidget->hide();
}
}
void remoteVSTPlugin::process( const sampleFrame * _in_buf,
sampleFrame * _out_buf )
{
const Uint32 frames = mixer::inst()->framesPerAudioBuffer();
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 later stage of this procedure
if( m_shmSize == 0 && messagesLeft() == TRUE )
{
(void) processNextMessage();
}
mixer::inst()->clearAudioBuffer( _out_buf, frames );
return;
}
memset( m_shm, 0, m_shmSize );
Uint8 inputs = tMax<Uint8>( m_inputCount, DEFAULT_CHANNELS );
if( _in_buf != NULL && inputs > 0 )
{
for( Uint8 ch = 0; ch < inputs; ++ch )
{
for( Uint32 frame = 0; frame < frames; ++frame )
{
m_shm[ch*frames+frame] = _in_buf[frame][ch];
}
}
}
lock();
writeValueS<Sint16>( VST_PROCESS );
unlock();
if( _out_buf != NULL && m_outputCount > 0 )
{
// wait until server signals that process()ing is done
while( processNextMessage() != VST_PROCESS_DONE )
{
// allow better scheduling (we're just waiting)
usleep( 10 );
}
Uint8 outputs = tMax<Uint8>( m_outputCount, DEFAULT_CHANNELS );
if( outputs != DEFAULT_CHANNELS )
{
// clear buffer, if plugin doesn't fill up both channels
mixer::inst()->clearAudioBuffer( _out_buf, frames );
}
for( Uint8 ch = 0; ch < outputs; ++ch )
{
for( Uint32 frame = 0; frame < frames; ++frame )
{
_out_buf[frame][ch] = m_shm[(m_inputCount+ch)*
frames+frame];
}
}
}
}
void remoteVSTPlugin::enqueueMidiEvent( const midiEvent & _event,
const Uint32 _frames_ahead )
{
lock();
writeValueS<Sint16>( VST_ENQUEUE_MIDI_EVENT );
writeValueS<midiEvent>( _event );
writeValueS<Uint32>( _frames_ahead );
unlock();
}
void remoteVSTPlugin::setBPM( Uint16 _bpm )
{
lock();
writeValueS<Sint16>( VST_BPM );
writeValueS<Uint16>( _bpm );
unlock();
}
const QMap<QString, QString> & remoteVSTPlugin::parameterDump( void )
{
writeValueS<Sint16>( VST_GET_PARAMETER_DUMP );
while( processNextMessage() != VST_PARAMETER_DUMP )
{
}
return( m_parameterDump );
}
void remoteVSTPlugin::setParameterDump( const QMap<QString, QString> & _pdump )
{
writeValueS<Sint16>( VST_SET_PARAMETER_DUMP );
writeValueS<Sint32>( _pdump.size() );
for( QMap<QString, QString>::const_iterator it = _pdump.begin();
it != _pdump.end(); ++it )
{
vstParameterDumpItem dump_item =
{
( *it ).section( ':', 0, 0 ).toInt(),
"",
( *it ).section( ':', 1, 1 ).toFloat()
} ;
writeValueS<vstParameterDumpItem>( dump_item );
}
}
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
}
}
void remoteVSTPlugin::setPluginXID( const Sint32 _plugin_xid )
{
m_pluginWID = _plugin_xid;
}
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 )
{
case VST_DEBUG_MSG:
printf( "debug message from server: %s\n",
readStringS().c_str() );
break;
case VST_GET_SAMPLE_RATE:
writeValueS<Sint16>( VST_SAMPLE_RATE );
// handle is the same
writeValueS<Sint32>( mixer::inst()->sampleRate() );
break;
case VST_GET_BUFFER_SIZE:
writeValueS<Sint16>( VST_BUFFER_SIZE );
// handle is the same
writeValueS<Uint32>(
mixer::inst()->framesPerAudioBuffer() );
break;
case VST_SHM_KEY_AND_SIZE:
{
Uint16 shm_key = readValueS<Uint16>();
size_t shm_size = readValueS<size_t>();
setShmKeyAndSize( shm_key, shm_size );
break;
}
case VST_INPUT_COUNT:
m_inputCount = readValueS<Uint8>();
break;
case VST_OUTPUT_COUNT:
m_outputCount = readValueS<Uint8>();
break;
case VST_PLUGIN_XID:
setPluginXID( readValueS<Sint32>() );
break;
case VST_PLUGIN_NAME:
m_name = readStringS().c_str();
break;
case VST_PLUGIN_VERSION:
m_version = readValueS<Sint32>();
break;
case VST_PLUGIN_VENDOR_STRING:
m_vendorString = readStringS().c_str();
break;
case VST_PLUGIN_PRODUCT_STRING:
m_productString = readStringS().c_str();
break;
case VST_PARAMETER_DUMP:
{
m_parameterDump.clear();
const Sint32 num_params = readValueS<Sint32>();
for( Sint32 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 );
}
break;
}
case VST_PROCESS_DONE:
case VST_QUIT_ACK:
case VST_UNDEFINED_CMD:
default:
break;
}
unlock();
return( cmd );
}

View File

@@ -0,0 +1,180 @@
/*
* lvsl_client.h - client for LVSL Server
*
* Copyright (c) 2005-2006 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
*
* 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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
#ifndef _LVSL_CLIENT_H
#define _LVSL_CLIENT_H
#include "qt3support.h"
#ifdef QT4
#include <QString>
#include <QMutex>
#else
#include <qstring.h>
#include <qmutex.h>
#endif
#include "mixer.h"
#include "communication.h"
#include "midi.h"
class remoteVSTPlugin
{
public:
remoteVSTPlugin( const QString & _plugin );
~remoteVSTPlugin();
void showEditor( void );
void hideEditor( void );
inline const QString & name( void ) const
{
return( m_name );
}
inline Sint32 version( void ) const
{
return( m_version );
}
inline const QString & vendorString( void ) const
{
return( m_vendorString );
}
inline const QString & productString( void ) const
{
return( m_productString );
}
void FASTCALL process( const sampleFrame * _in_buf,
sampleFrame * _out_buf );
void FASTCALL enqueueMidiEvent( const midiEvent & _event,
const Uint32 _frames_ahead );
void FASTCALL setBPM( const Uint16 _bpm );
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 );
}
inline bool failed( void ) const
{
return( m_failed );
}
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 FASTCALL setShmKeyAndSize( const Uint16 _key, const size_t _size );
void FASTCALL setPluginXID( const Sint32 _plugin_xid );
bool m_failed;
QString m_plugin;
QWidget * m_pluginWidget;
Sint32 m_pluginWID;
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;
QString m_productString;
QMap<QString, QString> m_parameterDump;
Uint8 m_inputCount;
Uint8 m_outputCount;
int m_shmID;
float * m_shm;
size_t m_shmSize;
} ;
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -59,7 +59,7 @@
#include "spc_bg_hndl_widget.h"
#include "vestige.h"
#include "text_float.h"
#include "fstclient.h"
#include "lvsl_client.h"
#include "embed.cpp"