2009-12-25 01:59:39 +01:00
|
|
|
|
|
|
|
|
|
/*******************************************************************************/
|
|
|
|
|
/* Copyright (C) 2009 Jonathan Moore Liles */
|
|
|
|
|
/* */
|
|
|
|
|
/* 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 the file COPYING. If not,write to the Free Software */
|
|
|
|
|
/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
|
|
|
|
/*******************************************************************************/
|
|
|
|
|
|
|
|
|
|
/* Filter module. Can host LADPSA Plugins, or can be inherited from to make internal
|
|
|
|
|
modules with special features and appearance. */
|
|
|
|
|
|
2010-01-17 04:51:14 +01:00
|
|
|
|
#include "const.h"
|
|
|
|
|
|
2010-01-25 03:12:10 +01:00
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <vector>
|
|
|
|
|
#include <string>
|
|
|
|
|
#include <ladspa.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <math.h>
|
2009-12-25 01:59:39 +01:00
|
|
|
|
|
2012-02-26 03:01:35 +01:00
|
|
|
|
#include <FL/fl_draw.H>
|
2009-12-25 01:59:39 +01:00
|
|
|
|
#include <FL/Fl_Group.H>
|
2010-01-25 03:12:10 +01:00
|
|
|
|
#include <FL/Fl_Menu_Button.H>
|
2009-12-25 01:59:39 +01:00
|
|
|
|
|
2010-01-25 03:12:10 +01:00
|
|
|
|
#include "Plugin_Module.H"
|
2009-12-25 01:59:39 +01:00
|
|
|
|
|
2010-02-01 07:25:16 +01:00
|
|
|
|
#include "debug.h"
|
2009-12-25 01:59:39 +01:00
|
|
|
|
|
|
|
|
|
#define HAVE_LIBLRDF 1
|
|
|
|
|
#include "LADSPAInfo.h"
|
|
|
|
|
|
2013-03-14 02:02:45 +01:00
|
|
|
|
#include "Chain.H"
|
2009-12-25 01:59:39 +01:00
|
|
|
|
#include "Engine/Engine.H"
|
|
|
|
|
|
2013-03-14 02:02:45 +01:00
|
|
|
|
#include <dsp.h>
|
|
|
|
|
|
2009-12-25 01:59:39 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static LADSPAInfo *ladspainfo;
|
2010-01-20 08:43:22 +01:00
|
|
|
|
Thread* Plugin_Module::plugin_discover_thread;
|
2009-12-25 01:59:39 +01:00
|
|
|
|
|
|
|
|
|
/* keep this out of the header to avoid spreading ladspa.h dependency */
|
|
|
|
|
struct Plugin_Module::ImplementationData
|
|
|
|
|
{
|
|
|
|
|
const LADSPA_Descriptor *descriptor;
|
|
|
|
|
// std::vector<LADSPA_Data*> m_LADSPABufVec;
|
2009-12-25 20:16:07 +01:00
|
|
|
|
std::vector<LADSPA_Handle> handle;
|
2009-12-25 01:59:39 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2010-01-19 08:47:46 +01:00
|
|
|
|
Plugin_Module::Plugin_Module ( ) : Module( 50, 35, name() )
|
2009-12-25 01:59:39 +01:00
|
|
|
|
{
|
|
|
|
|
init();
|
|
|
|
|
|
|
|
|
|
end();
|
2009-12-28 06:25:28 +01:00
|
|
|
|
|
|
|
|
|
log_create();
|
2009-12-25 01:59:39 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Plugin_Module::~Plugin_Module ( )
|
|
|
|
|
{
|
2009-12-28 06:25:28 +01:00
|
|
|
|
log_destroy();
|
2009-12-25 20:16:07 +01:00
|
|
|
|
plugin_instances( 0 );
|
2009-12-25 01:59:39 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2009-12-28 06:25:28 +01:00
|
|
|
|
void
|
|
|
|
|
Plugin_Module::get ( Log_Entry &e ) const
|
|
|
|
|
{
|
|
|
|
|
// char s[512];
|
|
|
|
|
// snprintf( s, sizeof( s ), "ladspa:%lu", _idata->descriptor->UniqueID );
|
|
|
|
|
e.add( ":plugin_id", _idata->descriptor->UniqueID );
|
|
|
|
|
|
2013-03-16 01:47:38 +01:00
|
|
|
|
/* these help us display the module on systems which are missing this plugin */
|
|
|
|
|
e.add( ":plugin_ins", _plugin_ins );
|
|
|
|
|
e.add( ":plugin_outs", _plugin_outs );
|
|
|
|
|
|
2009-12-28 06:25:28 +01:00
|
|
|
|
Module::get( e );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
Plugin_Module::set ( Log_Entry &e )
|
|
|
|
|
{
|
|
|
|
|
for ( int i = 0; i < e.size(); ++i )
|
|
|
|
|
{
|
|
|
|
|
const char *s, *v;
|
|
|
|
|
|
|
|
|
|
e.get( i, &s, &v );
|
|
|
|
|
|
|
|
|
|
if ( ! strcmp( s, ":plugin_id" ) )
|
|
|
|
|
{
|
|
|
|
|
load( (unsigned long) atoll ( v ) );
|
|
|
|
|
}
|
2013-03-16 01:47:38 +01:00
|
|
|
|
else if ( ! strcmp( s, ":plugin_ins" ) )
|
|
|
|
|
{
|
|
|
|
|
_plugin_ins = atoi( v );
|
|
|
|
|
}
|
|
|
|
|
else if ( ! strcmp( s, ":plugin_outs" ) )
|
|
|
|
|
{
|
|
|
|
|
_plugin_outs = atoi( v );
|
|
|
|
|
}
|
2009-12-28 06:25:28 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Module::set( e );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2009-12-25 01:59:39 +01:00
|
|
|
|
|
2010-01-18 04:59:56 +01:00
|
|
|
|
void
|
|
|
|
|
Plugin_Module::add_plugins_to_menu ( Fl_Menu_Button *menu )
|
|
|
|
|
{
|
2010-01-20 08:43:22 +01:00
|
|
|
|
Plugin_Module::Plugin_Info *pia = Plugin_Module::get_all_plugins();
|
2010-01-18 04:59:56 +01:00
|
|
|
|
|
|
|
|
|
char path[1024];
|
|
|
|
|
for ( Plugin_Module::Plugin_Info *pi = pia; pi->path; ++pi )
|
|
|
|
|
{
|
2010-01-28 05:39:27 +01:00
|
|
|
|
snprintf( path, sizeof( path ), "Plugin/%s", pi->path );
|
2010-01-18 04:59:56 +01:00
|
|
|
|
|
2010-01-18 06:27:51 +01:00
|
|
|
|
menu->add(path, 0, NULL, new unsigned long( pi->id ), 0 );
|
2010-01-18 04:59:56 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
delete[] pia;
|
|
|
|
|
}
|
|
|
|
|
|
2009-12-25 01:59:39 +01:00
|
|
|
|
/* allow the user to pick a plugin */
|
|
|
|
|
Plugin_Module *
|
|
|
|
|
Plugin_Module::pick_plugin ( void )
|
|
|
|
|
{
|
|
|
|
|
/**************/
|
|
|
|
|
/* build menu */
|
|
|
|
|
/**************/
|
|
|
|
|
|
|
|
|
|
Fl_Menu_Button *menu = new Fl_Menu_Button( 0, 0, 400, 400 );
|
|
|
|
|
menu->type( Fl_Menu_Button::POPUP3 );
|
|
|
|
|
|
2010-01-20 08:43:22 +01:00
|
|
|
|
Plugin_Module::Plugin_Info *pia = Plugin_Module::get_all_plugins();
|
2009-12-25 01:59:39 +01:00
|
|
|
|
|
|
|
|
|
for ( Plugin_Module::Plugin_Info *pi = pia; pi->path; ++pi )
|
|
|
|
|
{
|
|
|
|
|
menu->add(pi->path, 0, NULL, pi, 0 );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
menu->popup();
|
|
|
|
|
|
|
|
|
|
if ( menu->value() <= 0 )
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
/************************/
|
|
|
|
|
/* load selected plugin */
|
|
|
|
|
/************************/
|
|
|
|
|
|
|
|
|
|
Plugin_Module::Plugin_Info *pi = (Plugin_Module::Plugin_Info*)menu->menu()[ menu->value() ].user_data();
|
|
|
|
|
|
2010-01-17 02:28:05 +01:00
|
|
|
|
if ( ! pi )
|
|
|
|
|
return NULL;
|
|
|
|
|
|
2009-12-28 06:25:28 +01:00
|
|
|
|
Plugin_Module *m = new Plugin_Module();
|
2009-12-25 01:59:39 +01:00
|
|
|
|
|
2009-12-28 06:25:28 +01:00
|
|
|
|
m->load( pi->id );
|
2009-12-25 01:59:39 +01:00
|
|
|
|
|
|
|
|
|
delete[] pia;
|
|
|
|
|
|
|
|
|
|
return m;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
Plugin_Module::init ( void )
|
|
|
|
|
{
|
|
|
|
|
_idata = new Plugin_Module::ImplementationData();
|
2009-12-25 20:16:07 +01:00
|
|
|
|
_idata->handle.clear();
|
2013-03-16 01:54:37 +01:00
|
|
|
|
/* module will be bypassed until plugin is loaded */
|
|
|
|
|
_bypass = true;
|
2009-12-25 20:16:07 +01:00
|
|
|
|
_crosswire = false;
|
2009-12-25 01:59:39 +01:00
|
|
|
|
|
|
|
|
|
align( (Fl_Align)FL_ALIGN_CENTER | FL_ALIGN_INSIDE );
|
2013-03-16 01:47:38 +01:00
|
|
|
|
// color( (Fl_Color)fl_color_average( FL_MAGENTA, FL_WHITE, 0.5f ) );
|
2013-03-15 01:30:50 +01:00
|
|
|
|
|
2009-12-25 01:59:39 +01:00
|
|
|
|
int tw, th, tx, ty;
|
|
|
|
|
|
|
|
|
|
bbox( tx, ty, tw, th );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
Plugin_Module::can_support_inputs ( int n )
|
|
|
|
|
{
|
|
|
|
|
/* this is the simple case */
|
|
|
|
|
if ( plugin_ins() == n )
|
|
|
|
|
return plugin_outs();
|
|
|
|
|
/* e.g. MONO going into STEREO */
|
|
|
|
|
/* we'll duplicate our inputs */
|
|
|
|
|
else if ( n < plugin_ins() &&
|
|
|
|
|
1 == n )
|
|
|
|
|
{
|
|
|
|
|
return plugin_outs();
|
|
|
|
|
}
|
|
|
|
|
/* e.g. STEREO going into MONO */
|
|
|
|
|
/* we'll run multiple instances of the plugin */
|
|
|
|
|
else if ( n > plugin_ins() &&
|
2009-12-25 20:16:07 +01:00
|
|
|
|
( plugin_ins() == 1 && plugin_outs() == 1 ) )
|
2009-12-25 01:59:39 +01:00
|
|
|
|
{
|
2009-12-25 20:16:07 +01:00
|
|
|
|
return n;
|
2009-12-25 01:59:39 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
Plugin_Module::configure_inputs( int n )
|
|
|
|
|
{
|
2010-01-17 03:42:47 +01:00
|
|
|
|
int inst = _idata->handle.size();
|
2009-12-25 20:16:07 +01:00
|
|
|
|
|
2010-01-17 03:42:47 +01:00
|
|
|
|
if ( ninputs() != n )
|
2009-12-25 20:16:07 +01:00
|
|
|
|
{
|
2010-01-17 03:42:47 +01:00
|
|
|
|
_crosswire = false;
|
2009-12-25 01:59:39 +01:00
|
|
|
|
|
2010-01-17 03:42:47 +01:00
|
|
|
|
if ( n != ninputs() )
|
2009-12-25 20:16:07 +01:00
|
|
|
|
{
|
2010-01-17 03:42:47 +01:00
|
|
|
|
if ( 1 == n && plugin_ins() > 1 )
|
|
|
|
|
{
|
|
|
|
|
DMESSAGE( "Cross-wiring plugin inputs" );
|
|
|
|
|
_crosswire = true;
|
|
|
|
|
|
|
|
|
|
audio_input.clear();
|
|
|
|
|
|
|
|
|
|
for ( int i = n; i--; )
|
|
|
|
|
audio_input.push_back( Port( this, Port::INPUT, Port::AUDIO ) );
|
|
|
|
|
}
|
|
|
|
|
else if ( n >= plugin_ins() &&
|
|
|
|
|
( plugin_ins() == 1 && plugin_outs() == 1 ) )
|
|
|
|
|
{
|
|
|
|
|
DMESSAGE( "Running multiple instances of plugin" );
|
|
|
|
|
|
|
|
|
|
audio_input.clear();
|
|
|
|
|
audio_output.clear();
|
|
|
|
|
|
|
|
|
|
for ( int i = n; i--; )
|
|
|
|
|
{
|
|
|
|
|
add_port( Port( this, Port::INPUT, Port::AUDIO ) );
|
|
|
|
|
add_port( Port( this, Port::OUTPUT, Port::AUDIO ) );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inst = n;
|
|
|
|
|
}
|
|
|
|
|
else if ( n == plugin_ins() )
|
|
|
|
|
{
|
|
|
|
|
DMESSAGE( "Plugin input configuration is a perfect match" );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
DMESSAGE( "Unsupported input configuration" );
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2009-12-25 20:16:07 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
2009-12-25 01:59:39 +01:00
|
|
|
|
|
2013-03-16 01:47:38 +01:00
|
|
|
|
if ( loaded() )
|
|
|
|
|
{
|
|
|
|
|
bool b = bypass();
|
2013-03-16 01:54:37 +01:00
|
|
|
|
|
2013-03-16 01:47:38 +01:00
|
|
|
|
if ( !b )
|
|
|
|
|
deactivate();
|
2009-12-25 01:59:39 +01:00
|
|
|
|
|
2013-03-16 01:47:38 +01:00
|
|
|
|
if ( plugin_instances( inst ) )
|
|
|
|
|
instances( inst );
|
|
|
|
|
else
|
|
|
|
|
return false;
|
2009-12-25 01:59:39 +01:00
|
|
|
|
|
2013-03-16 01:47:38 +01:00
|
|
|
|
if ( !b )
|
|
|
|
|
activate();
|
|
|
|
|
}
|
2009-12-25 01:59:39 +01:00
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2010-01-20 08:43:22 +01:00
|
|
|
|
void *
|
2010-02-01 07:23:01 +01:00
|
|
|
|
Plugin_Module::discover_thread ( void * )
|
2010-01-20 08:43:22 +01:00
|
|
|
|
{
|
|
|
|
|
THREAD_ASSERT( Plugin_Discover );
|
|
|
|
|
|
|
|
|
|
DMESSAGE( "Discovering plugins in the background" );
|
|
|
|
|
|
|
|
|
|
ladspainfo = new LADSPAInfo();
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Spawn a background thread for plugin discovery */
|
|
|
|
|
void
|
|
|
|
|
Plugin_Module::spawn_discover_thread ( void )
|
|
|
|
|
{
|
|
|
|
|
if ( plugin_discover_thread )
|
|
|
|
|
{
|
|
|
|
|
FATAL( "Plugin discovery thread is already running or has completed" );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
plugin_discover_thread = new Thread( "Plugin_Discover" );
|
|
|
|
|
|
|
|
|
|
plugin_discover_thread->clone( &Plugin_Module::discover_thread, NULL );
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-05 03:57:00 +01:00
|
|
|
|
void
|
|
|
|
|
Plugin_Module::join_discover_thread ( void )
|
|
|
|
|
{
|
|
|
|
|
plugin_discover_thread->join();
|
|
|
|
|
}
|
|
|
|
|
|
2009-12-25 01:59:39 +01:00
|
|
|
|
/* return a list of available plugins */
|
|
|
|
|
Plugin_Module::Plugin_Info *
|
2010-01-20 08:43:22 +01:00
|
|
|
|
Plugin_Module::get_all_plugins ( void )
|
2009-12-25 01:59:39 +01:00
|
|
|
|
{
|
|
|
|
|
if ( !ladspainfo )
|
2010-01-20 08:43:22 +01:00
|
|
|
|
{
|
|
|
|
|
if ( ! plugin_discover_thread )
|
|
|
|
|
ladspainfo = new LADSPAInfo();
|
|
|
|
|
else
|
|
|
|
|
plugin_discover_thread->join();
|
|
|
|
|
}
|
2009-12-25 01:59:39 +01:00
|
|
|
|
|
|
|
|
|
std::vector<LADSPAInfo::PluginEntry> plugins = ladspainfo->GetMenuList();
|
|
|
|
|
|
|
|
|
|
Plugin_Info* pi = new Plugin_Info[plugins.size() + 1];
|
|
|
|
|
|
|
|
|
|
int j = 0;
|
|
|
|
|
for (std::vector<LADSPAInfo::PluginEntry>::iterator i=plugins.begin();
|
|
|
|
|
i!=plugins.end(); i++, j++)
|
|
|
|
|
{
|
|
|
|
|
pi[j].path = i->Name.c_str();
|
|
|
|
|
pi[j].id = i->UniqueID;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return pi;
|
|
|
|
|
}
|
|
|
|
|
|
2009-12-25 20:16:07 +01:00
|
|
|
|
bool
|
|
|
|
|
Plugin_Module::plugin_instances ( unsigned int n )
|
|
|
|
|
{
|
|
|
|
|
if ( _idata->handle.size() > n )
|
|
|
|
|
{
|
|
|
|
|
for ( int i = _idata->handle.size() - n; i--; )
|
|
|
|
|
{
|
2010-01-15 08:54:25 +01:00
|
|
|
|
DMESSAGE( "Destroying plugin instance" );
|
|
|
|
|
|
2009-12-25 20:16:07 +01:00
|
|
|
|
LADSPA_Handle h = _idata->handle.back();
|
|
|
|
|
|
|
|
|
|
if ( _idata->descriptor->deactivate )
|
|
|
|
|
_idata->descriptor->deactivate( h );
|
|
|
|
|
if ( _idata->descriptor->cleanup )
|
|
|
|
|
_idata->descriptor->cleanup( h );
|
|
|
|
|
|
|
|
|
|
_idata->handle.pop_back();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if ( _idata->handle.size() < n )
|
|
|
|
|
{
|
|
|
|
|
for ( int i = n - _idata->handle.size(); i--; )
|
|
|
|
|
{
|
|
|
|
|
LADSPA_Handle h;
|
|
|
|
|
|
|
|
|
|
DMESSAGE( "Instantiating plugin..." );
|
|
|
|
|
|
2010-01-17 02:24:09 +01:00
|
|
|
|
if ( ! (h = _idata->descriptor->instantiate( _idata->descriptor, Engine::sample_rate() ) ) )
|
2009-12-25 20:16:07 +01:00
|
|
|
|
{
|
|
|
|
|
WARNING( "Failed to instantiate plugin" );
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DMESSAGE( "Instantiated: %p", h );
|
|
|
|
|
|
|
|
|
|
_idata->handle.push_back( h );
|
|
|
|
|
|
|
|
|
|
DMESSAGE( "Connecting control ports..." );
|
|
|
|
|
|
|
|
|
|
int ij = 0;
|
|
|
|
|
int oj = 0;
|
|
|
|
|
for ( unsigned int k = 0; k < _idata->descriptor->PortCount; ++k )
|
|
|
|
|
{
|
|
|
|
|
if ( LADSPA_IS_PORT_CONTROL( _idata->descriptor->PortDescriptors[k] ) )
|
|
|
|
|
{
|
|
|
|
|
if ( LADSPA_IS_PORT_INPUT( _idata->descriptor->PortDescriptors[k] ) )
|
|
|
|
|
_idata->descriptor->connect_port( h, k, (LADSPA_Data*)control_input[ij++].buffer() );
|
|
|
|
|
else if ( LADSPA_IS_PORT_OUTPUT( _idata->descriptor->PortDescriptors[k] ) )
|
|
|
|
|
_idata->descriptor->connect_port( h, k, (LADSPA_Data*)control_output[oj++].buffer() );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// connect ports to magic bogus value to aid debugging.
|
|
|
|
|
for ( unsigned int k = 0; k < _idata->descriptor->PortCount; ++k )
|
|
|
|
|
if ( LADSPA_IS_PORT_AUDIO( _idata->descriptor->PortDescriptors[k] ) )
|
|
|
|
|
_idata->descriptor->connect_port( h, k, (LADSPA_Data*)0x42 );
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2013-03-14 02:02:45 +01:00
|
|
|
|
void
|
|
|
|
|
Plugin_Module::bypass ( bool v )
|
|
|
|
|
{
|
|
|
|
|
if ( v != bypass() )
|
|
|
|
|
{
|
|
|
|
|
if ( v )
|
|
|
|
|
deactivate();
|
|
|
|
|
else
|
|
|
|
|
activate();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-12-25 01:59:39 +01:00
|
|
|
|
bool
|
2009-12-28 06:25:28 +01:00
|
|
|
|
Plugin_Module::load ( unsigned long id )
|
2009-12-25 01:59:39 +01:00
|
|
|
|
{
|
2009-12-28 06:25:28 +01:00
|
|
|
|
if ( !ladspainfo )
|
2010-01-20 08:43:22 +01:00
|
|
|
|
{
|
|
|
|
|
if ( ! plugin_discover_thread )
|
|
|
|
|
ladspainfo = new LADSPAInfo();
|
|
|
|
|
else
|
|
|
|
|
plugin_discover_thread->join();
|
|
|
|
|
}
|
2009-12-28 06:25:28 +01:00
|
|
|
|
|
|
|
|
|
_idata->descriptor = ladspainfo->GetDescriptorByID( id );
|
|
|
|
|
|
2009-12-25 01:59:39 +01:00
|
|
|
|
_plugin_ins = _plugin_outs = 0;
|
|
|
|
|
|
2013-03-16 01:47:38 +01:00
|
|
|
|
if ( ! _idata->descriptor )
|
|
|
|
|
{
|
|
|
|
|
/* unknown plugin ID */
|
|
|
|
|
WARNING( "Unknown plugin ID: %lu", id );
|
|
|
|
|
label( "----" );
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
label( _idata->descriptor->Name );
|
|
|
|
|
|
2009-12-25 01:59:39 +01:00
|
|
|
|
if ( _idata->descriptor )
|
|
|
|
|
{
|
|
|
|
|
if ( LADSPA_IS_INPLACE_BROKEN( _idata->descriptor->Properties ) )
|
|
|
|
|
{
|
|
|
|
|
WARNING( "Cannot use this plugin because it is incapable of processing audio in-place" );
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
else if ( ! LADSPA_IS_HARD_RT_CAPABLE( _idata->descriptor->Properties ) )
|
|
|
|
|
{
|
|
|
|
|
WARNING( "Cannot use this plugin because it is incapable of hard real-time operation" );
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MESSAGE( "Name: %s", _idata->descriptor->Name );
|
|
|
|
|
|
|
|
|
|
for ( unsigned int i = 0; i < _idata->descriptor->PortCount; ++i )
|
|
|
|
|
{
|
|
|
|
|
if ( LADSPA_IS_PORT_AUDIO( _idata->descriptor->PortDescriptors[i] ) )
|
|
|
|
|
{
|
|
|
|
|
if ( LADSPA_IS_PORT_INPUT( _idata->descriptor->PortDescriptors[i] ) )
|
|
|
|
|
{
|
|
|
|
|
add_port( Port( this, Port::INPUT, Port::AUDIO, _idata->descriptor->PortNames[ i ] ) );
|
|
|
|
|
_plugin_ins++;
|
|
|
|
|
}
|
|
|
|
|
else if (LADSPA_IS_PORT_OUTPUT(_idata->descriptor->PortDescriptors[i]))
|
|
|
|
|
{
|
|
|
|
|
_plugin_outs++;
|
|
|
|
|
add_port( Port( this, Port::OUTPUT, Port::AUDIO, _idata->descriptor->PortNames[ i ] ) );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MESSAGE( "Plugin has %i inputs and %i outputs", _plugin_ins, _plugin_outs);
|
|
|
|
|
|
|
|
|
|
for ( unsigned int i = 0; i < _idata->descriptor->PortCount; ++i )
|
|
|
|
|
{
|
|
|
|
|
if ( LADSPA_IS_PORT_CONTROL( _idata->descriptor->PortDescriptors[i] ) )
|
|
|
|
|
{
|
2009-12-25 20:16:07 +01:00
|
|
|
|
Port::Direction d = Port::INPUT;
|
2009-12-25 01:59:39 +01:00
|
|
|
|
|
|
|
|
|
if ( LADSPA_IS_PORT_INPUT( _idata->descriptor->PortDescriptors[i] ) )
|
|
|
|
|
{
|
|
|
|
|
d = Port::INPUT;
|
|
|
|
|
}
|
|
|
|
|
else if ( LADSPA_IS_PORT_OUTPUT( _idata->descriptor->PortDescriptors[i] ) )
|
|
|
|
|
{
|
|
|
|
|
d = Port::OUTPUT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Port p( this, d, Port::CONTROL, _idata->descriptor->PortNames[ i ] );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LADSPA_PortRangeHintDescriptor hd = _idata->descriptor->PortRangeHints[i].HintDescriptor;
|
|
|
|
|
|
|
|
|
|
if ( LADSPA_IS_HINT_BOUNDED_BELOW(hd) )
|
|
|
|
|
{
|
|
|
|
|
p.hints.ranged = true;
|
|
|
|
|
p.hints.minimum = _idata->descriptor->PortRangeHints[i].LowerBound;
|
2012-07-16 10:07:18 +02:00
|
|
|
|
if ( LADSPA_IS_HINT_SAMPLE_RATE(hd) )
|
|
|
|
|
{
|
|
|
|
|
p.hints.minimum *= Engine::sample_rate();
|
|
|
|
|
}
|
2009-12-25 01:59:39 +01:00
|
|
|
|
}
|
|
|
|
|
if ( LADSPA_IS_HINT_BOUNDED_ABOVE(hd) )
|
|
|
|
|
{
|
|
|
|
|
p.hints.ranged = true;
|
|
|
|
|
p.hints.maximum = _idata->descriptor->PortRangeHints[i].UpperBound;
|
2012-07-16 10:07:18 +02:00
|
|
|
|
if ( LADSPA_IS_HINT_SAMPLE_RATE(hd) )
|
|
|
|
|
{
|
|
|
|
|
p.hints.maximum *= Engine::sample_rate();
|
|
|
|
|
}
|
2009-12-25 01:59:39 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( LADSPA_IS_HINT_HAS_DEFAULT(hd) )
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
float Max=1.0f, Min=-1.0f, Default=0.0f;
|
|
|
|
|
int Port=i;
|
|
|
|
|
|
|
|
|
|
// Get the bounding hints for the port
|
|
|
|
|
LADSPA_PortRangeHintDescriptor HintDesc=_idata->descriptor->PortRangeHints[Port].HintDescriptor;
|
|
|
|
|
if (LADSPA_IS_HINT_BOUNDED_BELOW(HintDesc))
|
|
|
|
|
{
|
|
|
|
|
Min=_idata->descriptor->PortRangeHints[Port].LowerBound;
|
|
|
|
|
if (LADSPA_IS_HINT_SAMPLE_RATE(HintDesc))
|
|
|
|
|
{
|
2010-01-17 02:24:09 +01:00
|
|
|
|
Min*=Engine::sample_rate();
|
2009-12-25 01:59:39 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (LADSPA_IS_HINT_BOUNDED_ABOVE(HintDesc))
|
|
|
|
|
{
|
|
|
|
|
Max=_idata->descriptor->PortRangeHints[Port].UpperBound;
|
|
|
|
|
if (LADSPA_IS_HINT_SAMPLE_RATE(HintDesc))
|
|
|
|
|
{
|
2010-01-17 02:24:09 +01:00
|
|
|
|
Max*=Engine::sample_rate();
|
2009-12-25 01:59:39 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef LADSPA_VERSION
|
|
|
|
|
// We've got a version of the header that supports port defaults
|
|
|
|
|
if (LADSPA_IS_HINT_HAS_DEFAULT(HintDesc)) {
|
|
|
|
|
// LADSPA_HINT_DEFAULT_0 is assumed anyway, so we don't check for it
|
|
|
|
|
if (LADSPA_IS_HINT_DEFAULT_1(HintDesc)) {
|
|
|
|
|
Default = 1.0f;
|
|
|
|
|
} else if (LADSPA_IS_HINT_DEFAULT_100(HintDesc)) {
|
|
|
|
|
Default = 100.0f;
|
|
|
|
|
} else if (LADSPA_IS_HINT_DEFAULT_440(HintDesc)) {
|
|
|
|
|
Default = 440.0f;
|
|
|
|
|
} else {
|
|
|
|
|
// These hints may be affected by SAMPLERATE, LOGARITHMIC and INTEGER
|
|
|
|
|
if (LADSPA_IS_HINT_DEFAULT_MINIMUM(HintDesc) &&
|
|
|
|
|
LADSPA_IS_HINT_BOUNDED_BELOW(HintDesc)) {
|
|
|
|
|
Default=_idata->descriptor->PortRangeHints[Port].LowerBound;
|
|
|
|
|
} else if (LADSPA_IS_HINT_DEFAULT_MAXIMUM(HintDesc) &&
|
|
|
|
|
LADSPA_IS_HINT_BOUNDED_ABOVE(HintDesc)) {
|
|
|
|
|
Default=_idata->descriptor->PortRangeHints[Port].UpperBound;
|
|
|
|
|
} else if (LADSPA_IS_HINT_BOUNDED_BELOW(HintDesc) &&
|
|
|
|
|
LADSPA_IS_HINT_BOUNDED_ABOVE(HintDesc)) {
|
|
|
|
|
// These hints require both upper and lower bounds
|
|
|
|
|
float lp = 0.0f, up = 0.0f;
|
|
|
|
|
float min = _idata->descriptor->PortRangeHints[Port].LowerBound;
|
|
|
|
|
float max = _idata->descriptor->PortRangeHints[Port].UpperBound;
|
|
|
|
|
if (LADSPA_IS_HINT_DEFAULT_LOW(HintDesc)) {
|
|
|
|
|
lp = 0.75f;
|
|
|
|
|
up = 0.25f;
|
|
|
|
|
} else if (LADSPA_IS_HINT_DEFAULT_MIDDLE(HintDesc)) {
|
|
|
|
|
lp = 0.5f;
|
|
|
|
|
up = 0.5f;
|
|
|
|
|
} else if (LADSPA_IS_HINT_DEFAULT_HIGH(HintDesc)) {
|
|
|
|
|
lp = 0.25f;
|
|
|
|
|
up = 0.75f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (LADSPA_IS_HINT_LOGARITHMIC(HintDesc)) {
|
|
|
|
|
|
|
|
|
|
p.hints.type = Port::Hints::LOGARITHMIC;
|
|
|
|
|
|
|
|
|
|
if (min==0.0f || max==0.0f) {
|
|
|
|
|
// Zero at either end means zero no matter
|
|
|
|
|
// where hint is at, since:
|
|
|
|
|
// log(n->0) -> Infinity
|
|
|
|
|
Default = 0.0f;
|
|
|
|
|
} else {
|
|
|
|
|
// Catch negatives
|
|
|
|
|
bool neg_min = min < 0.0f ? true : false;
|
|
|
|
|
bool neg_max = max < 0.0f ? true : false;
|
|
|
|
|
|
|
|
|
|
if (!neg_min && !neg_max) {
|
2009-12-28 06:25:28 +01:00
|
|
|
|
Default = exp(::log(min) * lp + ::log(max) * up);
|
2009-12-25 01:59:39 +01:00
|
|
|
|
} else if (neg_min && neg_max) {
|
2009-12-28 06:25:28 +01:00
|
|
|
|
Default = -exp(::log(-min) * lp + ::log(-max) * up);
|
2009-12-25 01:59:39 +01:00
|
|
|
|
} else {
|
|
|
|
|
// Logarithmic range has asymptote
|
|
|
|
|
// so just use linear scale
|
|
|
|
|
Default = min * lp + max * up;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
Default = min * lp + max * up;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (LADSPA_IS_HINT_SAMPLE_RATE(HintDesc)) {
|
2010-01-17 02:24:09 +01:00
|
|
|
|
Default *= Engine::sample_rate();
|
2009-12-25 01:59:39 +01:00
|
|
|
|
}
|
|
|
|
|
if (LADSPA_IS_HINT_INTEGER(HintDesc)) {
|
|
|
|
|
if ( p.hints.ranged &&
|
|
|
|
|
0 == p.hints.minimum &&
|
|
|
|
|
1 == p.hints.maximum )
|
|
|
|
|
p.hints.type = Port::Hints::BOOLEAN;
|
|
|
|
|
else
|
|
|
|
|
p.hints.type = Port::Hints::INTEGER;
|
|
|
|
|
Default = floorf(Default);
|
|
|
|
|
}
|
|
|
|
|
if (LADSPA_IS_HINT_TOGGLED(HintDesc)){
|
|
|
|
|
p.hints.type = Port::Hints::BOOLEAN;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
Default = 0.0f;
|
|
|
|
|
#endif
|
|
|
|
|
p.hints.default_value = Default;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float *control_value = new float;
|
|
|
|
|
|
|
|
|
|
*control_value = p.hints.default_value;
|
|
|
|
|
|
|
|
|
|
p.connect_to( control_value );
|
|
|
|
|
|
|
|
|
|
add_port( p );
|
|
|
|
|
|
|
|
|
|
DMESSAGE( "Plugin has control port \"%s\" (default: %f)", _idata->descriptor->PortNames[ i ], p.hints.default_value );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
WARNING( "Failed to load plugin" );
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2013-03-16 01:54:37 +01:00
|
|
|
|
int instances = plugin_instances( 1 );
|
|
|
|
|
|
|
|
|
|
if ( instances )
|
|
|
|
|
{
|
|
|
|
|
bypass( false );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return instances;
|
2009-12-25 01:59:39 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
Plugin_Module::set_input_buffer ( int n, void *buf )
|
|
|
|
|
{
|
2009-12-25 20:16:07 +01:00
|
|
|
|
LADSPA_Handle h;
|
|
|
|
|
|
|
|
|
|
if ( instances() > 1 )
|
|
|
|
|
{
|
|
|
|
|
h = _idata->handle[n];
|
|
|
|
|
n = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
h = _idata->handle[0];
|
|
|
|
|
|
2009-12-25 01:59:39 +01:00
|
|
|
|
for ( unsigned int i = 0; i < _idata->descriptor->PortCount; ++i )
|
|
|
|
|
if ( LADSPA_IS_PORT_INPUT( _idata->descriptor->PortDescriptors[i] ) &&
|
|
|
|
|
LADSPA_IS_PORT_AUDIO( _idata->descriptor->PortDescriptors[i] ) )
|
|
|
|
|
if ( n-- == 0 )
|
2009-12-25 20:16:07 +01:00
|
|
|
|
_idata->descriptor->connect_port( h, i, (LADSPA_Data*)buf );
|
2009-12-25 01:59:39 +01:00
|
|
|
|
}
|
|
|
|
|
|
2013-03-16 01:47:38 +01:00
|
|
|
|
bool
|
|
|
|
|
Plugin_Module::loaded ( void ) const
|
|
|
|
|
{
|
|
|
|
|
return _idata->descriptor;
|
|
|
|
|
}
|
|
|
|
|
|
2009-12-25 01:59:39 +01:00
|
|
|
|
void
|
|
|
|
|
Plugin_Module::set_output_buffer ( int n, void *buf )
|
|
|
|
|
{
|
2009-12-25 20:16:07 +01:00
|
|
|
|
LADSPA_Handle h;
|
|
|
|
|
|
|
|
|
|
if ( instances() > 1 )
|
|
|
|
|
{
|
|
|
|
|
h = _idata->handle[n];
|
|
|
|
|
n = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
h = _idata->handle[0];
|
|
|
|
|
|
2009-12-25 01:59:39 +01:00
|
|
|
|
for ( unsigned int i = 0; i < _idata->descriptor->PortCount; ++i )
|
|
|
|
|
if ( LADSPA_IS_PORT_OUTPUT( _idata->descriptor->PortDescriptors[i] ) &&
|
|
|
|
|
LADSPA_IS_PORT_AUDIO( _idata->descriptor->PortDescriptors[i] ) )
|
|
|
|
|
if ( n-- == 0 )
|
2009-12-25 20:16:07 +01:00
|
|
|
|
_idata->descriptor->connect_port( h, i, (LADSPA_Data*)buf );
|
2009-12-25 01:59:39 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
Plugin_Module::activate ( void )
|
|
|
|
|
{
|
2013-03-16 01:47:38 +01:00
|
|
|
|
if ( !loaded() )
|
|
|
|
|
return;
|
|
|
|
|
|
2013-03-15 01:31:46 +01:00
|
|
|
|
DMESSAGE( "Activating plugin \"%s\"", label() );
|
|
|
|
|
|
2013-03-16 01:54:37 +01:00
|
|
|
|
if ( !bypass() )
|
2009-12-25 01:59:39 +01:00
|
|
|
|
FATAL( "Attempt to activate already active plugin" );
|
|
|
|
|
|
2013-03-15 01:31:46 +01:00
|
|
|
|
if ( chain() )
|
|
|
|
|
chain()->engine()->lock();
|
2013-03-14 02:02:45 +01:00
|
|
|
|
|
2009-12-25 01:59:39 +01:00
|
|
|
|
if ( _idata->descriptor->activate )
|
2009-12-25 20:16:07 +01:00
|
|
|
|
for ( unsigned int i = 0; i < _idata->handle.size(); ++i )
|
|
|
|
|
_idata->descriptor->activate( _idata->handle[i] );
|
|
|
|
|
|
2013-03-16 01:54:37 +01:00
|
|
|
|
_bypass = false;
|
2013-03-14 02:02:45 +01:00
|
|
|
|
|
2013-03-15 01:31:46 +01:00
|
|
|
|
if ( chain() )
|
|
|
|
|
chain()->engine()->unlock();
|
2009-12-25 01:59:39 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
Plugin_Module::deactivate( void )
|
|
|
|
|
{
|
2013-03-16 01:47:38 +01:00
|
|
|
|
if ( !loaded() )
|
|
|
|
|
return;
|
|
|
|
|
|
2013-03-15 01:31:46 +01:00
|
|
|
|
DMESSAGE( "Deactivating plugin \"%s\"", label() );
|
|
|
|
|
|
|
|
|
|
if ( chain() )
|
|
|
|
|
chain()->engine()->lock();
|
2013-03-14 02:02:45 +01:00
|
|
|
|
|
2013-03-16 01:54:37 +01:00
|
|
|
|
_bypass = true;
|
2013-03-14 02:02:45 +01:00
|
|
|
|
|
2009-12-25 01:59:39 +01:00
|
|
|
|
if ( _idata->descriptor->deactivate )
|
2009-12-25 20:16:07 +01:00
|
|
|
|
for ( unsigned int i = 0; i < _idata->handle.size(); ++i )
|
2013-03-14 02:02:45 +01:00
|
|
|
|
_idata->descriptor->deactivate( _idata->handle[i] );
|
2009-12-25 20:16:07 +01:00
|
|
|
|
|
2013-03-15 01:31:46 +01:00
|
|
|
|
if ( chain() )
|
|
|
|
|
chain()->engine()->unlock();
|
2009-12-25 01:59:39 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2009-12-25 20:16:07 +01:00
|
|
|
|
Plugin_Module::handle_port_connection_change ( void )
|
2009-12-25 01:59:39 +01:00
|
|
|
|
{
|
2009-12-25 20:16:07 +01:00
|
|
|
|
// DMESSAGE( "Connecting audio ports" );
|
|
|
|
|
|
2013-03-16 01:47:38 +01:00
|
|
|
|
if ( loaded() )
|
2009-12-25 01:59:39 +01:00
|
|
|
|
{
|
2013-03-16 01:47:38 +01:00
|
|
|
|
if ( _crosswire )
|
|
|
|
|
{
|
|
|
|
|
for ( int i = 0; i < plugin_ins(); ++i )
|
|
|
|
|
set_input_buffer( i, audio_input[0].buffer() );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
for ( unsigned int i = 0; i < audio_input.size(); ++i )
|
|
|
|
|
set_input_buffer( i, audio_input[i].buffer() );
|
|
|
|
|
}
|
2009-12-25 01:59:39 +01:00
|
|
|
|
|
2013-03-16 01:47:38 +01:00
|
|
|
|
for ( unsigned int i = 0; i < audio_output.size(); ++i )
|
|
|
|
|
set_output_buffer( i, audio_output[i].buffer() );
|
|
|
|
|
}
|
2009-12-25 20:16:07 +01:00
|
|
|
|
}
|
|
|
|
|
|
2010-01-25 03:12:10 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**********/
|
|
|
|
|
/* Engine */
|
|
|
|
|
/**********/
|
|
|
|
|
|
2009-12-25 20:16:07 +01:00
|
|
|
|
void
|
2010-01-30 09:35:32 +01:00
|
|
|
|
Plugin_Module::process ( nframes_t nframes )
|
2009-12-25 20:16:07 +01:00
|
|
|
|
{
|
|
|
|
|
handle_port_connection_change();
|
2009-12-25 01:59:39 +01:00
|
|
|
|
|
2013-03-16 01:54:37 +01:00
|
|
|
|
if ( !bypass() )
|
2013-03-14 02:02:45 +01:00
|
|
|
|
{
|
2009-12-25 20:16:07 +01:00
|
|
|
|
for ( unsigned int i = 0; i < _idata->handle.size(); ++i )
|
2010-01-30 09:35:32 +01:00
|
|
|
|
_idata->descriptor->run( _idata->handle[i], nframes );
|
2013-03-14 02:02:45 +01:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* If this is a mono to stereo plugin, then duplicate the input channel... */
|
|
|
|
|
/* There's not much we can do to automatically support other configurations. */
|
|
|
|
|
if ( ninputs() == 1 && noutputs() == 2 )
|
|
|
|
|
{
|
|
|
|
|
buffer_copy( (sample_t*)audio_output[1].buffer(), (sample_t*)audio_input[0].buffer(), nframes );
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-12-25 01:59:39 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|