better VST support and bugfixes

git-svn-id: https://lmms.svn.sf.net/svnroot/lmms/trunk/lmms@77 0778d3d1-df1d-0410-868b-ea421aaaa00d
This commit is contained in:
Tobias Doerffel
2006-02-06 12:52:58 +00:00
parent af3d57b67f
commit de00678815
43 changed files with 966 additions and 668 deletions

View File

@@ -126,7 +126,7 @@ bSynth::~bSynth()
delete[] sample_shape;
}
sampleType bSynth::nextStringSample( void )
sample_t bSynth::nextStringSample( void )
{
@@ -135,7 +135,7 @@ sampleType bSynth::nextStringSample( void )
sample_realindex -= sample_length;
}
sampleType sample;
sample_t sample;
if (interpolation) {
@@ -705,7 +705,7 @@ void bitInvader::playNote( notePlayHandle * _n )
bSynth * ps = static_cast<bSynth *>( _n->m_pluginData );
for( Uint32 frame = 0; frame < frames; ++frame )
{
const sampleType cur = ps->nextStringSample();
const sample_t cur = ps->nextStringSample();
for( Uint8 chnl = 0; chnl < DEFAULT_CHANNELS; ++chnl )
{
buf[frame][chnl] = cur;

View File

@@ -56,7 +56,7 @@ public:
bSynth(float* sample, int length, float _pitch, bool _interpolation, float factor);
virtual ~bSynth();
sampleType nextStringSample();
sample_t nextStringSample();
private:

View File

@@ -148,7 +148,7 @@ void pluckedStringSynth::playNote( notePlayHandle * _n )
pluckSynth * ps = static_cast<pluckSynth *>( _n->m_pluginData );
for( Uint32 frame = 0; frame < frames; ++frame )
{
const sampleType cur = ps->nextStringSample();
const sample_t cur = ps->nextStringSample();
for( Uint8 chnl = 0; chnl < DEFAULT_CHANNELS; ++chnl )
{
buf[frame][chnl] = cur;
@@ -178,7 +178,7 @@ pluckSynth::delayLine * FASTCALL pluckSynth::initDelayLine( int _len )
dl->length = _len;
if( _len > 0 )
{
dl->data = new sampleType[_len];
dl->data = new sample_t[_len];
}
else
{

View File

@@ -46,16 +46,16 @@ public:
pluckSynth::freeDelayLine( m_lowerRail );
}
inline sampleType nextStringSample( void )
inline sample_t nextStringSample( void )
{
// Output at pickup position
sampleType outsamp = rgDlAccess( m_upperRail, m_pickupLoc );
sample_t outsamp = rgDlAccess( m_upperRail, m_pickupLoc );
outsamp += lgDlAccess( m_lowerRail, m_pickupLoc );
// Sample traveling into "bridge"
sampleType ym0 = lgDlAccess( m_lowerRail, 1 );
sample_t ym0 = lgDlAccess( m_lowerRail, 1 );
// Sample to "nut"
sampleType ypM = rgDlAccess( m_upperRail,
sample_t ypM = rgDlAccess( m_upperRail,
m_upperRail->length - 2 );
// String state update
@@ -72,10 +72,10 @@ public:
private:
struct delayLine
{
sampleType * data;
sample_t * data;
int length;
sampleType * pointer;
sampleType * end;
sample_t * pointer;
sample_t * end;
} ;
delayLine * m_upperRail;
@@ -100,9 +100,9 @@ private:
* wave travels one sample to the left), turning the previous
* position into an "effective" x = L position for the next
* iteration. */
static inline void lgDlUpdate( delayLine * _dl, sampleType _insamp )
static inline void lgDlUpdate( delayLine * _dl, sample_t _insamp )
{
register sampleType * ptr = _dl->pointer;
register sample_t * ptr = _dl->pointer;
*ptr = _insamp;
++ptr;
if( ptr > _dl->end )
@@ -118,9 +118,9 @@ private:
* "effective" x = 0 position for the next iteration. The
* "bridge-reflected" sample from lower delay-line is then placed
* into this position. */
static inline void rgDlUpdate( delayLine * _dl, sampleType _insamp )
static inline void rgDlUpdate( delayLine * _dl, sample_t _insamp )
{
register sampleType * ptr = _dl->pointer;
register sample_t * ptr = _dl->pointer;
--ptr;
if( ptr < _dl->data )
{
@@ -133,9 +133,9 @@ private:
/* dlAccess(dl, position);
* Returns sample "position" samples into delay-line's past.
* Position "0" points to the most recently inserted sample. */
static inline sampleType dlAccess( delayLine * _dl, int _position )
static inline sample_t dlAccess( delayLine * _dl, int _position )
{
sampleType * outpos = _dl->pointer + _position;
sample_t * outpos = _dl->pointer + _position;
while( outpos < _dl->data )
{
outpos += _dl->length;
@@ -163,7 +163,7 @@ private:
* is equal to the current upper delay-line pointer position (x = 0).
* In a right-going delay-line, position increases to the right, and
* delay increases to the right => left = past and right = future. */
static inline sampleType rgDlAccess( delayLine * _dl, int _position )
static inline sample_t rgDlAccess( delayLine * _dl, int _position )
{
return( dlAccess( _dl, _position ) );
}
@@ -173,14 +173,14 @@ private:
* is equal to the current lower delay-line pointer position (x = 0).
* In a left-going delay-line, position increases to the right, and
* delay DEcreases to the right => left = future and right = past. */
static inline sampleType lgDlAccess( delayLine * _dl, int _position )
static inline sample_t lgDlAccess( delayLine * _dl, int _position )
{
return( dlAccess( _dl, _position ) );
}
static inline sampleType bridgeReflection( sampleType _insamp )
static inline sample_t bridgeReflection( sample_t _insamp )
{
static sampleType state = 0.0f; // filter memory
static sample_t state = 0.0f; // filter memory
// Implement a one-pole lowpass with feedback coefficient = 0.5
return( state = state*0.5f + _insamp*0.5f );
}

View File

@@ -1,3 +1,29 @@
/*
* communication.h - header file defining stuff concerning communication between
* LVSL-server and -client
*
* 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 _COMMUNICATION_H
#define _COMMUNICATION_H
@@ -79,6 +105,18 @@ struct vstParamProperties
} ;
enum hostLanguages
{
LVSL_LANG_ENGLISH = 1,
LVSL_LANG_GERMAN,
LVSL_LANG_FRENCH,
LVSL_LANG_ITALIAN,
LVSL_LANG_SPANISH,
LVSL_LANG_JAPANESE
} ;
enum vstRemoteCommands
{
// client -> server
@@ -90,6 +128,7 @@ enum vstRemoteCommands
VST_SAMPLE_RATE,
VST_BUFFER_SIZE,
VST_BPM,
VST_LANGUAGE,
VST_GET_PARAMETER_COUNT = 20,
VST_GET_PARAMETER_DUMP,
VST_SET_PARAMETER_DUMP,
@@ -103,6 +142,7 @@ enum vstRemoteCommands
VST_INPUT_COUNT,
VST_OUTPUT_COUNT,
VST_PLUGIN_XID,
VST_PLUGIN_EDITOR_GEOMETRY,
VST_PROCESS_DONE,
VST_PLUGIN_NAME,
VST_PLUGIN_VERSION,

View File

@@ -35,6 +35,8 @@
#else
#include <qapplication.h>
#include <qlocale.h>
#include "qxembed.h"
#define QX11EmbedWidget QXEmbed
@@ -80,11 +82,12 @@
remoteVSTPlugin::remoteVSTPlugin( const QString & _plugin ) :
m_failed( TRUE ),
m_plugin( _plugin ),
m_pluginWidget( NULL ),
m_pluginWID( 0 ),
m_pluginXID( 0 ),
m_pluginPID( -1 ),
m_serverInFD( -1 ),
m_serverOutFD( -1 ),
@@ -132,6 +135,20 @@ remoteVSTPlugin::remoteVSTPlugin( const QString & _plugin ) :
m_serverOutFD = m_pipes[0][1];
lock();
writeValueS<Sint16>( VST_LANGUAGE );
hostLanguages hlang = LVSL_LANG_ENGLISH;
switch( QLocale::system().language() )
{
case QLocale::German: hlang = LVSL_LANG_GERMAN; break;
case QLocale::French: hlang = LVSL_LANG_FRENCH; break;
case QLocale::Italian: hlang = LVSL_LANG_ITALIAN; break;
case QLocale::Spanish: hlang = LVSL_LANG_SPANISH; break;
case QLocale::Japanese: hlang = LVSL_LANG_JAPANESE; break;
default: break;
}
writeValueS<hostLanguages>( hlang );
writeValueS<Sint16>( VST_LOAD_PLUGIN );
writeStringS( m_plugin.
#ifdef QT4
@@ -210,8 +227,6 @@ remoteVSTPlugin::~remoteVSTPlugin()
#include <X11/Xlib.h>
void remoteVSTPlugin::showEditor( void )
{
@@ -220,29 +235,21 @@ void remoteVSTPlugin::showEditor( void )
m_pluginWidget->show();
return;
}
if( m_pluginWID == 0 )
if( m_pluginXID == 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->setFixedSize( m_pluginGeometry );
m_pluginWidget->setWindowTitle( name() );
m_pluginWidget->show();
QX11EmbedWidget * xe = new QX11EmbedWidget( m_pluginWidget );
xe->embedInto( m_pluginWID );
xe->setFixedSize( attr.width, attr.height );
xe->embedInto( m_pluginXID );
xe->setFixedSize( m_pluginGeometry );
//xe->setAutoDelete( FALSE );
m_pluginWidget->show();
xe->show();
lock();
@@ -267,14 +274,14 @@ void remoteVSTPlugin::hideEditor( void )
void remoteVSTPlugin::process( const sampleFrame * _in_buf,
sampleFrame * _out_buf )
{
const Uint32 frames = mixer::inst()->framesPerAudioBuffer();
const fpab_t 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
// information like SHM-key etc.) until we process messages
// in a later stage of this procedure
if( m_shmSize == 0 && messagesLeft() == TRUE )
{
(void) processNextMessage();
@@ -285,15 +292,15 @@ void remoteVSTPlugin::process( const sampleFrame * _in_buf,
memset( m_shm, 0, m_shmSize );
Uint8 inputs = tMax<Uint8>( m_inputCount, DEFAULT_CHANNELS );
ch_cnt_t inputs = tMax<ch_cnt_t>( m_inputCount, DEFAULT_CHANNELS );
if( _in_buf != NULL && inputs > 0 )
{
for( Uint8 ch = 0; ch < inputs; ++ch )
for( ch_cnt_t ch = 0; ch < inputs; ++ch )
{
for( Uint32 frame = 0; frame < frames; ++frame )
for( fpab_t frame = 0; frame < frames; ++frame )
{
m_shm[ch*frames+frame] = _in_buf[frame][ch];
m_shm[ch * frames + frame] = _in_buf[frame][ch];
}
}
}
@@ -307,19 +314,21 @@ void remoteVSTPlugin::process( const sampleFrame * _in_buf,
// wait until server signals that process()ing is done
while( processNextMessage() != VST_PROCESS_DONE )
{
// allow better scheduling (we're just waiting)
// hopefully scheduler gives process-time to plugin...
usleep( 10 );
}
Uint8 outputs = tMax<Uint8>( m_outputCount, DEFAULT_CHANNELS );
ch_cnt_t outputs = tMax<ch_cnt_t>( m_outputCount,
DEFAULT_CHANNELS );
if( outputs != DEFAULT_CHANNELS )
{
// clear buffer, if plugin doesn't fill up both channels
// clear buffer, if plugin didn't fill up both channels
mixer::inst()->clearAudioBuffer( _out_buf, frames );
}
for( Uint8 ch = 0; ch < outputs; ++ch )
for( ch_cnt_t ch = 0; ch < outputs; ++ch )
{
for( Uint32 frame = 0; frame < frames; ++frame )
for( fpab_t frame = 0; frame < frames; ++frame )
{
_out_buf[frame][ch] = m_shm[(m_inputCount+ch)*
frames+frame];
@@ -376,7 +385,7 @@ void remoteVSTPlugin::setParameterDump( const QMap<QString, QString> & _pdump )
for( QMap<QString, QString>::const_iterator it = _pdump.begin();
it != _pdump.end(); ++it )
{
vstParameterDumpItem dump_item =
const vstParameterDumpItem dump_item =
{
( *it ).section( ':', 0, 0 ).toInt(),
"",
@@ -397,6 +406,7 @@ void remoteVSTPlugin::setShmKeyAndSize( Uint16 _key, size_t _size )
m_shm = NULL;
m_shmSize = 0;
}
// only called for detaching SHM?
if( _size == 0 )
{
@@ -418,14 +428,6 @@ void remoteVSTPlugin::setShmKeyAndSize( Uint16 _key, size_t _size )
void remoteVSTPlugin::setPluginXID( const Sint32 _plugin_xid )
{
m_pluginWID = _plugin_xid;
}
bool remoteVSTPlugin::messagesLeft( void ) const
{
fd_set rfds;
@@ -462,13 +464,14 @@ Sint16 remoteVSTPlugin::processNextMessage( void )
case VST_GET_SAMPLE_RATE:
writeValueS<Sint16>( VST_SAMPLE_RATE );
// handle is the same
writeValueS<Sint32>( mixer::inst()->sampleRate() );
writeValueS<sample_rate_t>(
mixer::inst()->sampleRate() );
break;
case VST_GET_BUFFER_SIZE:
writeValueS<Sint16>( VST_BUFFER_SIZE );
// handle is the same
writeValueS<Uint32>(
writeValueS<fpab_t>(
mixer::inst()->framesPerAudioBuffer() );
break;
@@ -481,17 +484,36 @@ Sint16 remoteVSTPlugin::processNextMessage( void )
}
case VST_INPUT_COUNT:
m_inputCount = readValueS<Uint8>();
m_inputCount = readValueS<ch_cnt_t>();
break;
case VST_OUTPUT_COUNT:
m_outputCount = readValueS<Uint8>();
m_outputCount = readValueS<ch_cnt_t>();
break;
case VST_PLUGIN_XID:
setPluginXID( readValueS<Sint32>() );
m_pluginXID = readValueS<Sint32>();
break;
case VST_PLUGIN_EDITOR_GEOMETRY:
{
const Sint16 w = readValueS<Sint16>();
const Sint16 h = readValueS<Sint16>();
m_pluginGeometry = QSize( w, h );
if( m_pluginWidget != NULL )
{
m_pluginWidget->setFixedSize(
m_pluginGeometry );
if( m_pluginWidget->childAt( 0, 0 ) != NULL )
{
m_pluginWidget->childAt( 0, 0
)->setFixedSize(
m_pluginGeometry );
}
}
break;
}
case VST_PLUGIN_NAME:
m_name = readStringS().c_str();
break;

View File

@@ -144,14 +144,13 @@ private:
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;
Sint32 m_pluginXID;
QSize m_pluginGeometry;
int m_pluginPID;
int m_pipes[2][2];

View File

@@ -56,19 +56,19 @@
#include <signal.h>
#endif
#ifdef HAVE_SCHED_H
#include <sched.h>
#endif
#include <windows.h>
#include <wine/exception.h>
#include <vector>
#include <list>
#include <string>
#include "types.h"
#include "midi.h"
#include "communication.h"
#include <aeffectx.h>
#if kVstVersion < 2400
@@ -89,6 +89,11 @@ struct ERect
#endif
#include "types.h"
#include "midi.h"
#include "communication.h"
#ifdef HAVE_TLS
static __thread int ejmpbuf_valid = false;
static __thread jmp_buf ejmpbuf;
@@ -98,6 +103,9 @@ static pthread_key_t ejmpbuf_key;
#endif
static hostLanguages hlang = LVSL_LANG_ENGLISH;
class VSTPlugin;
VSTPlugin * plugin = NULL;
@@ -140,20 +148,21 @@ public:
// enqueue given MIDI-event to be processed the next time process() is
// called
void enqueueMidiEvent( const midiEvent & _event,
const Uint32 _frames_ahead );
const f_cnt_t _frames_ahead );
// set given sample-rate for plugin
void setSampleRate( const Sint32 _rate )
void setSampleRate( const sample_rate_t _rate )
{
m_plugin->dispatcher( m_plugin, effSetSampleRate, 0, 0, NULL,
(float) _rate );
m_sampleRate = _rate;
}
// set given block-size for plugin
void setBlockSize( const Uint32 _bsize );
void setBlockSize( const fpab_t _bsize );
// set given tempo
void setBPM( const Uint16 _bpm )
void setBPM( const bpm_t _bpm )
{
m_bpm = _bpm;
}
@@ -184,13 +193,13 @@ public:
void getParameterProperties( const Sint32 _idx );
// number of inputs
Uint8 inputCount( void ) const
ch_cnt_t inputCount( void ) const
{
return( m_plugin->numInputs );
}
// number of outputs
Uint8 outputCount( void ) const
ch_cnt_t outputCount( void ) const
{
return( m_plugin->numOutputs );
}
@@ -224,22 +233,26 @@ private:
AEffect * m_plugin;
HWND m_window;
int m_windowXID;
Sint32 m_windowXID;
Sint16 m_windowWidth;
Sint16 m_windowHeight;
pthread_mutex_t m_lock;
pthread_cond_t m_windowStatusChange;
DWORD m_guiThreadID;
Uint32 m_blockSize;
fpab_t m_blockSize;
float * m_shm;
float * * m_inputs;
float * * m_outputs;
std::vector<VstMidiEvent> m_midiEvents;
std::list<VstMidiEvent> m_midiEvents;
Uint16 m_bpm;
bpm_t m_bpm;
sample_rate_t m_sampleRate;
double m_currentSamplePos;
} ;
@@ -252,6 +265,8 @@ VSTPlugin::VSTPlugin( const std::string & _plugin_file ) :
m_plugin( NULL ),
m_window( NULL ),
m_windowXID( 0 ),
m_windowWidth( 0 ),
m_windowHeight( 0 ),
m_lock(),
m_windowStatusChange(),
m_guiThreadID( 0 ),
@@ -260,7 +275,9 @@ VSTPlugin::VSTPlugin( const std::string & _plugin_file ) :
m_inputs( NULL ),
m_outputs( NULL ),
m_midiEvents(),
m_bpm( 0 )
m_bpm( 0 ),
m_sampleRate( 44100 ),
m_currentSamplePos( 0 )
{
if( load( _plugin_file ) == false )
{
@@ -293,6 +310,13 @@ VSTPlugin::VSTPlugin( const std::string & _plugin_file ) :
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() );
@@ -364,9 +388,9 @@ bool VSTPlugin::load( const std::string & _plugin_file )
m_shortName = basename( tmp );
free( tmp );
typedef AEffect * ( * mainEntry )( audioMasterCallback );
typedef AEffect * ( __stdcall * mainEntry )( audioMasterCallback );
mainEntry main_entry = (mainEntry) GetProcAddress( m_libInst,
"main" );
"main" );
if( main_entry == NULL )
{
return( false );
@@ -402,19 +426,22 @@ void VSTPlugin::process( void )
// dispatcher-call, so we create static copies of the
// data and post them
#define MIDI_EVENT_BUFFER_COUNT 1024
static char event_buf[sizeof(VstMidiEvent * ) *
static char event_buf[sizeof( VstMidiEvent * ) *
MIDI_EVENT_BUFFER_COUNT +
sizeof( VstEvents )];
static VstMidiEvent vme[MIDI_EVENT_BUFFER_COUNT];
VstEvents * events = (VstEvents *) event_buf;
events->reserved = 0;
events->numEvents = m_midiEvents.size();
for( unsigned int i = 0; i < m_midiEvents.size(); ++i )
Sint16 idx = 0;
for( std::list<VstMidiEvent>::iterator it =
m_midiEvents.begin();
it != m_midiEvents.end(); ++it, ++idx )
{
memcpy( &vme[i], &m_midiEvents[i],
sizeof( VstMidiEvent ) );
events->events[i] = (VstEvent *) &vme[i];
memcpy( &vme[idx], &*it, sizeof( VstMidiEvent ) );
events->events[idx] = (VstEvent *) &vme[idx];
}
m_midiEvents.clear();
m_plugin->dispatcher( m_plugin, effProcessEvents, 0, 0, events,
0.0f );
@@ -422,15 +449,14 @@ void VSTPlugin::process( void )
// now we're ready to fetch sound from VST-plugin
for( int i = 0; i < inputCount(); ++i )
for( ch_cnt_t i = 0; i < inputCount(); ++i )
{
m_inputs[i] = &m_shm[i * m_blockSize];
}
for( int i = 0; i < outputCount(); ++i )
for( ch_cnt_t i = 0; i < outputCount(); ++i )
{
m_outputs[i] = &m_shm[( i + inputCount() ) *
m_blockSize];
m_outputs[i] = &m_shm[( i + inputCount() ) * m_blockSize];
}
#ifdef OLD_VST_SDK
@@ -449,6 +475,8 @@ void VSTPlugin::process( void )
}
#endif
m_currentSamplePos += m_blockSize;
writeValue<Sint16>( VST_PROCESS_DONE );
// give plugin some idle-time for GUI-update and so on...
@@ -460,7 +488,7 @@ void VSTPlugin::process( void )
void VSTPlugin::enqueueMidiEvent( const midiEvent & _event,
const Uint32 _frames_ahead )
const f_cnt_t _frames_ahead )
{
VstMidiEvent event;
@@ -484,12 +512,13 @@ void VSTPlugin::enqueueMidiEvent( const midiEvent & _event,
void VSTPlugin::setBlockSize( const Uint32 _bsize )
void VSTPlugin::setBlockSize( const Uint16 _bsize )
{
if( _bsize == m_blockSize )
{
return;
}
m_blockSize = _bsize;
resizeSharedMemory();
m_plugin->dispatcher( m_plugin, effSetBlockSize, 0, _bsize, NULL,
@@ -612,7 +641,7 @@ void VSTPlugin::resizeSharedMemory( void )
int shm_id;
Uint16 shm_key = 0;
while( ( shm_id = shmget( ++shm_key, s, IPC_CREAT | IPC_EXCL |
0666 ) ) == -1 )
0666 ) ) == -1 )
{
}
@@ -628,10 +657,10 @@ void VSTPlugin::resizeSharedMemory( void )
}
writeValue<Sint16>( VST_INPUT_COUNT );
writeValue<Uint8>( inputCount() );
writeValue<ch_cnt_t>( inputCount() );
writeValue<Sint16>( VST_OUTPUT_COUNT );
writeValue<Uint8>( outputCount() );
writeValue<ch_cnt_t>( outputCount() );
writeValue<Sint16>( VST_SHM_KEY_AND_SIZE );
writeValue<Uint16>( shm_key );
@@ -648,6 +677,13 @@ void VSTPlugin::resizeSharedMemory( void )
#endif
/* TODO:
* - complete audioMasterGetTime-handling (bars etc.)
* - implement audioMasterProcessEvents
* - audioMasterGetVendorVersion: return LMMS-version (config.h!)
* - audioMasterGetDirectory: return either VST-plugin-dir or LMMS-workingdir
* - audioMasterOpenFileSelector: show QFileDialog?
*/
VstIntPtr VSTPlugin::hostCallback( AEffect * _effect, VstInt32 _opcode,
VstInt32 _index, VstIntPtr _value,
void * _ptr, float _opt )
@@ -664,8 +700,7 @@ VstIntPtr VSTPlugin::hostCallback( AEffect * _effect, VstInt32 _opcode,
case audioMasterVersion:
//SHOW_CALLBACK( "amc: audioMasterVersion\n" );
// vst version, currently 2 (0 for older)
return( 2 );
return( 2300 );
case audioMasterCurrentId:
SHOW_CALLBACK( "amc: audioMasterCurrentId\n" );
@@ -682,7 +717,7 @@ VstIntPtr VSTPlugin::hostCallback( AEffect * _effect, VstInt32 _opcode,
return( 0 );
case audioMasterPinConnected:
SHOW_CALLBACK( "amc: audioMasterPinConnected\n" );
//SHOW_CALLBACK( "amc: audioMasterPinConnected\n" );
// inquire if an input or output is beeing connected;
// index enumerates input or output counting from zero:
// value is 0 for input and != 0 otherwise. note: the
@@ -699,8 +734,8 @@ VstIntPtr VSTPlugin::hostCallback( AEffect * _effect, VstInt32 _opcode,
memset( &_timeInfo, 0, sizeof( _timeInfo ) );
_timeInfo.samplePos = 0;
// TODO: _timeInfo.sampleRate = mixer::inst()->sampleRate();
_timeInfo.samplePos = plugin->m_currentSamplePos;
_timeInfo.sampleRate = plugin->m_sampleRate;
_timeInfo.flags = 0;
_timeInfo.tempo = plugin->m_bpm;
_timeInfo.timeSigNumerator = 4;
@@ -717,7 +752,7 @@ VstIntPtr VSTPlugin::hostCallback( AEffect * _effect, VstInt32 _opcode,
case audioMasterIOChanged:
plugin->resizeSharedMemory();
SHOW_CALLBACK( "amc: audioMasterIOChanged\n" );
//SHOW_CALLBACK( "amc: audioMasterIOChanged\n" );
// numInputs and/or numOutputs has changed
return( 0 );
@@ -725,21 +760,22 @@ VstIntPtr VSTPlugin::hostCallback( AEffect * _effect, VstInt32 _opcode,
case audioMasterWantMidi:
//SHOW_CALLBACK( "amc: audioMasterWantMidi\n" );
// <value> is a filter which is currently ignored
return( 0 );
return( 1 );
case audioMasterSetTime:
SHOW_CALLBACK( "amc: audioMasterSetTime\n" );
// VstTimenfo* in <ptr>, filter in <value>, not
// supported
return( 0 );
case audioMasterTempoAt:
SHOW_CALLBACK( "amc: audioMasterTempoAt\n" );
//SHOW_CALLBACK( "amc: audioMasterTempoAt\n" );
return( plugin->m_bpm * 10000 );
case audioMasterGetNumAutomatableParameters:
SHOW_CALLBACK( "amc: audioMasterGetNumAutomatable"
"Parameters\n" );
return( 0 );
return( 5000 );
case audioMasterGetParameterQuantization:
SHOW_CALLBACK( "amc: audioMasterGetParameter\n"
@@ -748,12 +784,12 @@ VstIntPtr VSTPlugin::hostCallback( AEffect * _effect, VstInt32 _opcode,
// or 1 if full single float precision is maintained
// in automation. parameter index in <value> (-1: all,
// any)
return( 0 );
return( 1 );
case audioMasterNeedIdle:
//SHOW_CALLBACK( "amc: audioMasterNeedIdle\n" );
// plug needs idle calls (outside its editor window)
return( 0 );
return( 1 );
case audioMasterGetPreviousPlug:
SHOW_CALLBACK( "amc: audioMasterGetPreviousPlug\n" );
@@ -805,30 +841,37 @@ VstIntPtr VSTPlugin::hostCallback( AEffect * _effect, VstInt32 _opcode,
#endif
case audioMasterSizeWindow:
// TODO using lmms-main-window-size
SHOW_CALLBACK( "amc: audioMasterSizeWindow\n" );
// index: width, value: height
return( 0 );
//SHOW_CALLBACK( "amc: audioMasterSizeWindow\n" );
if( plugin->m_window == 0 )
{
return( 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 );
return( 1 );
case audioMasterGetSampleRate:
// TODO using mixer-call
SHOW_CALLBACK( "amc: audioMasterGetSampleRate\n" );
return( 0 );
//SHOW_CALLBACK( "amc: audioMasterGetSampleRate\n" );
return( plugin->m_sampleRate );
case audioMasterGetBlockSize:
// TODO using mixer-call
SHOW_CALLBACK( "amc: audioMasterGetBlockSize\n" );
return( 0 );
//SHOW_CALLBACK( "amc: audioMasterGetBlockSize\n" );
return( plugin->m_blockSize );
case audioMasterGetInputLatency:
// TODO using mixer-call
SHOW_CALLBACK( "amc: audioMasterGetInputLatency\n" );
return( 0 );
//SHOW_CALLBACK( "amc: audioMasterGetInputLatency\n" );
return( plugin->m_blockSize );
case audioMasterGetOutputLatency:
// TODO using mixer-call
SHOW_CALLBACK( "amc: audioMasterGetOutputLatency\n" );
return( 0 );
//SHOW_CALLBACK( "amc: audioMasterGetOutputLatency\n" );
return( plugin->m_blockSize );
case audioMasterGetCurrentProcessLevel:
SHOW_CALLBACK( "amc: audioMasterGetCurrentProcess"
@@ -876,22 +919,22 @@ VstIntPtr VSTPlugin::hostCallback( AEffect * _effect, VstInt32 _opcode,
return( 0 );
case audioMasterGetVendorString:
SHOW_CALLBACK( "amc: audioMasterGetVendorString\n" );
//SHOW_CALLBACK( "amc: audioMasterGetVendorString\n" );
// fills <ptr> with a string identifying the vendor
// (max 64 char)
strcpy( (char *) _ptr, "LAD");
return( 0 );
strcpy( (char *) _ptr, "Tobias Doerffel & others");
return( 1 );
case audioMasterGetProductString:
SHOW_CALLBACK( "amc: audioMasterGetProductString\n" );
//SHOW_CALLBACK( "amc: audioMasterGetProductString\n" );
// fills <ptr> with a string with product name
// (max 64 char)
strcpy( (char *) _ptr, "XFST-Server" );
return( 0 );
strcpy( (char *) _ptr,
"LMMS VST Support Layer (LVSL)" );
return( 1 );
case audioMasterGetVendorVersion:
SHOW_CALLBACK( "amc: audioMasterGetVendorVersion\n" );
// TODO
// returns vendor-specific version
return( 1000 );
@@ -901,19 +944,18 @@ VstIntPtr VSTPlugin::hostCallback( AEffect * _effect, VstInt32 _opcode,
return( 0 );
case audioMasterCanDo:
SHOW_CALLBACK( "amc: audioMasterCanDo\n" );
// string in ptr, see below
return( 0 );
//SHOW_CALLBACK( "amc: audioMasterCanDo\n" );
return( !strcmp( (char *) _ptr, "sendVstEvents" ) ||
!strcmp( (char *) _ptr, "sendVstMidiEvent" ) ||
!strcmp( (char *) _ptr, "sendVstTimeInfo" ) ||
!strcmp( (char *) _ptr, "sizeWindow" ) );
case audioMasterGetLanguage:
SHOW_CALLBACK( "amc: audioMasterGetLanguage\n" );
// TODO
// see enum
return( 0 );
//SHOW_CALLBACK( "amc: audioMasterGetLanguage\n" );
return( hlang );
case audioMasterGetDirectory:
SHOW_CALLBACK( "amc: audioMasterGetDirectory\n" );
// TODO
// get plug directory, FSSpec on MAC, else char*
return( 0 );
@@ -1015,7 +1057,7 @@ DWORD WINAPI VSTPlugin::guiEventLoop( LPVOID _param )
return( 1 );
}
_this->m_windowXID = (int) GetPropA( _this->m_window,
_this->m_windowXID = (Sint32) GetPropA( _this->m_window,
"__wine_x11_whole_window" );
@@ -1026,13 +1068,18 @@ DWORD WINAPI VSTPlugin::guiEventLoop( LPVOID _param )
_this->m_plugin->dispatcher( _this->m_plugin, effEditGetRect, 0, 0,
&er, 0 );
/* const int width = er->right - er->left;
const int height = er->bottom - er->top;*/
_this->m_windowWidth = er->right - er->left;
_this->m_windowHeight = er->bottom - er->top;
SetWindowPos( _this->m_window, 0, 0, 0, er->right - er->left + 8,
er->bottom-er->top + 26, SWP_NOACTIVATE | SWP_NOREDRAW |
SWP_NOMOVE | SWP_NOZORDER );
SetWindowPos( _this->m_window, 0, 0, 0, _this->m_windowWidth + 8,
_this->m_windowHeight + 26,
SWP_NOACTIVATE /*| SWP_NOREDRAW*/ | SWP_NOMOVE |
SWP_NOOWNERZORDER | SWP_NOZORDER );
#ifdef HAVE_TLS
ejmpbuf_valid = false;
#else
*ejmpbuf_valid = false;
#endif
pthread_cond_signal( &_this->m_windowStatusChange );
@@ -1050,7 +1097,9 @@ DWORD WINAPI VSTPlugin::guiEventLoop( LPVOID _param )
switch( msg.wParam )
{
case SHOW_EDITOR:
ShowWindow( _this->m_window, SW_SHOW );
ShowWindow( _this->m_window,
SW_SHOWNORMAL );
UpdateWindow( _this->m_window );
break;
case CLOSE_PLUGIN:
@@ -1098,6 +1147,17 @@ int main( void )
return( -1 );
}
#ifdef HAVE_SCHED_H
// try to set realtime-priority
struct sched_param sparam;
sparam.sched_priority = ( sched_get_priority_max( SCHED_FIFO ) +
sched_get_priority_min( SCHED_FIFO ) ) / 2;
if( sched_setscheduler( 0, SCHED_FIFO, &sparam ) == -1 )
{
lvsMessage( "could not set realtime priority for VST-server" );
}
#endif
Sint16 cmd;
while( ( cmd = readValue<Sint16>() ) != VST_CLOSE_PLUGIN )
{
@@ -1118,22 +1178,27 @@ int main( void )
case VST_ENQUEUE_MIDI_EVENT:
{
const midiEvent ev = readValue<midiEvent>();
const Uint32 fr_ahead = readValue<Uint32>();
const f_cnt_t fr_ahead = readValue<f_cnt_t>();
plugin->enqueueMidiEvent( ev, fr_ahead );
break;
}
case VST_SAMPLE_RATE:
plugin->setSampleRate( readValue<Sint32>() );
plugin->setSampleRate(
readValue<sample_rate_t>() );
break;
case VST_BUFFER_SIZE:
plugin->setBlockSize( readValue<Uint32>() );
plugin->setBlockSize( readValue<fpab_t>() );
break;
case VST_BPM:
plugin->setBPM( readValue<Uint16>() );
plugin->setBPM( readValue<bpm_t>() );
break;
case VST_LANGUAGE:
hlang = readValue<hostLanguages>();
break;
case VST_GET_PARAMETER_DUMP: