Upgrade Calf LADSPA plugins to 0.90 (#3987)

Upgrade Calf LADSPA plugins to 0.90
This commit is contained in:
Tres Finocchiaro
2018-04-15 21:38:37 -04:00
committed by GitHub
parent 0850b78104
commit ae0dd21df3
11 changed files with 456 additions and 32 deletions

View File

@@ -45,6 +45,7 @@ typedef enum BufferRates
typedef enum BufferData
{
TOGGLED,
ENUM,
INTEGER,
FLOATING,
TIME,

View File

@@ -179,6 +179,12 @@ public:
be described as [-0.1, 3.1]. */
bool isInteger( const ladspa_key_t & _plugin, uint32_t _port );
/* Indicates that a user interface would probably wish to provide a
stepped control taking only integer values. This is equal to isInteger,
but the number of values is usually small and may be better depicted
with a combo box. */
bool isEnum( const ladspa_key_t & _plugin, uint32_t _port );
/* Returns the name of the port. */
QString getPortName( const ladspa_key_t & _plugin, uint32_t _port );

View File

@@ -112,10 +112,10 @@ void LadspaControlDialog::updateEffectView( LadspaControls * _ctl )
{
if( (*it)->port()->proc == proc )
{
buffer_data_t this_port = (*it)->port()->data_type;
if( last_port != NONE &&
(*it)->port()->data_type == TOGGLED &&
!( (*it)->port()->data_type == TOGGLED &&
last_port == TOGGLED ) )
( this_port == TOGGLED || this_port == ENUM ) &&
( last_port != TOGGLED && last_port != ENUM ) )
{
++row;
col = 0;

View File

@@ -371,7 +371,11 @@ void LadspaEffect::pluginInstantiation()
}
p->scale = 1.0f;
if( manager->isPortToggled( m_key, port ) )
if( manager->isEnum( m_key, port ) )
{
p->data_type = ENUM;
}
else if( manager->isPortToggled( m_key, port ) )
{
p->data_type = TOGGLED;
}

View File

@@ -1,6 +1,8 @@
# Note:
# The last version of Calf that was LADSPA-capable is version 0.0.18.2
SET(CMAKE_CXX_STANDARD 11)
# Parse version info from autoconf
FILE(READ veal/configure.ac VERSION_FILE)
STRING(REPLACE "[" ";" VERSION_FILE ${VERSION_FILE} )
@@ -12,7 +14,7 @@ FILE(GLOB SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/veal/src/*.cpp")
LIST(SORT SOURCES)
# Skip files matching pattern
SET(FILE_PATTERNS "ctl;gui;gtk;session;connector;jack;rdf;draw;fluid;preset;lv2;benchmark;win")
SET(FILE_PATTERNS "ctl;gui;gtk;session;connector;jack;rdf;draw;fluid;preset;lv2;benchmark;win;plugin.cpp")
FOREACH(_item ${SOURCES})
FOREACH(_pattern ${FILE_PATTERNS})
IF(${_item} MATCHES ${_pattern})
@@ -29,6 +31,10 @@ INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/include"
INSTALL(TARGETS veal LIBRARY DESTINATION "${PLUGIN_DIR}/ladspa")
SET_TARGET_PROPERTIES(veal PROPERTIES PREFIX "")
# Disable OSC messaging, it's not mingw compatible
TARGET_COMPILE_DEFINITIONS(veal PRIVATE DISABLE_OSC=1)
SET(INLINE_FLAGS "")
IF("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
SET(INLINE_FLAGS "-finline-functions-called-once -finline-limit=80")
@@ -42,4 +48,3 @@ ENDIF()
IF(NOT LMMS_BUILD_APPLE AND NOT LMMS_BUILD_OPENBSD)
SET_TARGET_PROPERTIES(veal PROPERTIES LINK_FLAGS "${LINK_FLAGS} -shared -Wl,-no-undefined")
ENDIF()

View File

@@ -1,3 +1,7 @@
#define VERSION "${VERSION}"
#define PACKAGE_NAME "veal"
#define USE_LADSPA 1
#define PKGLIBDIR ""
// Namespace change to avoid conflict with LV2
#define calf_plugins veal_plugins

View File

@@ -968,6 +968,67 @@ void DataFile::upgrade_1_2_0_rc2_42()
}
/**
* Helper function to call a functor for all effect ports' DomElements,
* providing the functor with lists to add and remove DomElements. Helpful for
* patching port values from savefiles.
*/
template<class Ftor>
void iterate_ladspa_ports(QDomElement& effect, Ftor& ftor)
{
// Head back up the DOM to upgrade ports
QDomNodeList ladspacontrols = effect.elementsByTagName( "ladspacontrols" );
for( int m = 0; !ladspacontrols.item( m ).isNull(); ++m )
{
QList<QDomElement> addList, removeList;
QDomElement ladspacontrol = ladspacontrols.item( m ).toElement();
for( QDomElement port = ladspacontrol.firstChild().toElement();
!port.isNull(); port = port.nextSibling().toElement() )
{
QStringList parts = port.tagName().split("port");
// Not a "port"
if ( parts.size() < 2 )
{
continue;
}
int num = parts[1].toInt();
// From Qt's docs of QDomNode:
// * copying a QDomNode is OK, they still have the same
// pointer to the "internal" QDomNodePrivate.
// * Also, they are using linked lists, which means
// deleting or appending QDomNode does not invalidate
// any other pointers.
// => Inside ftor, you can (and should) push back the
// QDomElements by value, not references
// => The loops below for adding and removing don't
// invalidate any other QDomElements
ftor(port, num, addList, removeList);
}
// Add ports marked for adding
for ( QDomElement e : addList )
{
ladspacontrol.appendChild( e );
}
// Remove ports marked for removal
for ( QDomElement e : removeList )
{
ladspacontrol.removeChild( e );
}
}
}
// helper function if you need to print a QDomNode
QDebug operator<<(QDebug dbg, const QDomNode& node)
{
QString s;
QTextStream str(&s, QIODevice::WriteOnly);
node.save(str, 2);
dbg << qPrintable(s);
return dbg;
}
void DataFile::upgrade_1_3_0()
{
QDomNodeList list = elementsByTagName( "instrument" );
@@ -1009,6 +1070,8 @@ void DataFile::upgrade_1_3_0()
QDomNodeList attributes = key.elementsByTagName( "attribute" );
for( int k = 0; !attributes.item( k ).isNull(); ++k )
{
// Effect name changes
QDomElement attribute = attributes.item( k ).toElement();
if( attribute.attribute( "name" ) == "file" &&
( attribute.attribute( "value" ) == "calf" ||
@@ -1016,6 +1079,283 @@ void DataFile::upgrade_1_3_0()
{
attribute.setAttribute( "value", "veal" );
}
else if( attribute.attribute( "name" ) == "plugin" &&
attribute.attribute( "value" ) == "Sidechaincompressor" )
{
attribute.setAttribute( "value", "SidechainCompressor" );
}
else if( attribute.attribute( "name" ) == "plugin" &&
attribute.attribute( "value" ) == "Sidechaingate" )
{
attribute.setAttribute( "value", "SidechainGate" );
}
else if( attribute.attribute( "name" ) == "plugin" &&
attribute.attribute( "value" ) == "Multibandcompressor" )
{
attribute.setAttribute( "value", "MultibandCompressor" );
}
else if( attribute.attribute( "name" ) == "plugin" &&
attribute.attribute( "value" ) == "Multibandgate" )
{
attribute.setAttribute( "value", "MultibandGate" );
}
else if( attribute.attribute( "name" ) == "plugin" &&
attribute.attribute( "value" ) == "Multibandlimiter" )
{
attribute.setAttribute( "value", "MultibandLimiter" );
}
// Handle port changes
if( attribute.attribute( "name" ) == "plugin" &&
( attribute.attribute( "value" ) == "MultibandLimiter" ||
attribute.attribute( "value" ) == "MultibandCompressor" ||
attribute.attribute( "value" ) == "MultibandGate" ) )
{
auto fn = [&](QDomElement& port, int num, QList<QDomElement>&, QList<QDomElement>& removeList)
{
// Mark ports for removal
if ( num >= 18 && num <= 23 )
{
removeList << port;
}
// Bump higher ports up 6 positions
else if ( num >= 24 )
{
// port01...port010, etc
QString name( "port0" );
name.append( QString::number( num -6 ) );
port.setTagName( name );
}
};
iterate_ladspa_ports(effect, fn);
}
if( attribute.attribute( "name" ) == "plugin" &&
( attribute.attribute( "value" ) == "Pulsator" ) )
{
auto fn = [&](QDomElement& port, int num, QList<QDomElement>& addList, QList<QDomElement>& removeList)
{
switch(num)
{
case 16:
{
// old freq is now at port 25
QDomElement portCopy = createElement("port025");
portCopy.setAttribute("data", port.attribute("data"));
addList << portCopy;
// remove old freq port
removeList << port;
// set the "timing" port to choose port23+2=port25 (timing in Hz)
QDomElement timing = createElement("port022");
timing.setAttribute("data", 2);
addList << timing;
break;
}
// port 18 (modulation) => 17
case 17:
port.setTagName("port016");
break;
case 18:
{
// leave port 18 (offsetr), but add port 17 (offsetl)
QDomElement offsetl = createElement("port017");
offsetl.setAttribute("data", 0.0f);
addList << offsetl;
// additional: bash port 21 to 1
QDomElement pulsewidth = createElement("port021");
pulsewidth.setAttribute("data", 1.0f);
addList << pulsewidth;
break;
}
}
};
iterate_ladspa_ports(effect, fn);
}
if( attribute.attribute( "name" ) == "plugin" &&
( attribute.attribute( "value" ) == "VintageDelay" ) )
{
auto fn = [&](QDomElement& port, int num, QList<QDomElement>& addList, QList<QDomElement>& )
{
switch(num)
{
case 4:
{
// BPM is now port028
port.setTagName("port028");
// bash timing to BPM
QDomElement timing = createElement("port027");
timing.setAttribute("data", 0);
addList << timing;
// port 5 and 6 (in, out gain) need to be bashed to 1:
QDomElement input = createElement("port05");
input.setAttribute("data", 1.0f);
addList << input;
QDomElement output = createElement("port06");
output.setAttribute("data", 1.0f);
addList << output;
break;
}
default:
// all other ports increase by 10
QString name( "port0" );
name.append( QString::number( num + 10 ) );
port.setTagName( name );
}
};
iterate_ladspa_ports(effect, fn);
}
if( attribute.attribute( "name" ) == "plugin" &&
( ( attribute.attribute( "value" ) == "Equalizer5Band" )
|| ( attribute.attribute( "value" ) == "Equalizer8Band" )
|| ( attribute.attribute( "value" ) == "Equalizer12Band" ) ) )
{
// NBand equalizers got 4 q nobs inserted. We need to shift everything else...
// HOWEVER: 5 band eq has only 2 q nobs inserted (no LS/HS filters)
bool band5 = ( attribute.attribute( "value" ) == "Equalizer5Band" );
auto fn = [&](QDomElement& port, int num, QList<QDomElement>& addList, QList<QDomElement>& )
{
if(num == 4)
{
// don't modify port 4, but some other ones:
int zoom_port;
if(attribute.attribute( "value" ) == "Equalizer5Band")
zoom_port = 36;
else if(attribute.attribute( "value" ) == "Equalizer8Band")
zoom_port = 48;
else // 12 band
zoom_port = 64;
// bash zoom to 0.25
QString name( "port0" );
name.append( QString::number( zoom_port ) );
QDomElement timing = createElement(name);
timing.setAttribute("data", 0.25f);
addList << timing;
}
// the following code could be refactored, but I did careful code-reading
// to prevent copy-paste-errors
if(num == 18)
{
// 18 => 19
port.setTagName("port019");
// insert port 18 (q)
QDomElement q = createElement("port018");
q.setAttribute("data", 0.707f);
addList << q;
}
else if(num >= 19 && num <= 20)
{
// num += 1
QString name( "port0" );
name.append( QString::number( num + 1 ) );
port.setTagName( name );
}
else if(num == 21)
{
// 21 => 23
port.setTagName("port023");
// insert port 22 (q)
QDomElement q = createElement("port022");
q.setAttribute("data", 0.707f);
addList << q;
}
else if(num >= 22 && (num <= 23 || band5))
{
// num += 2
QString name( "port0" );
name.append( QString::number( num + 2 ) );
port.setTagName( name );
}
else if(num == 24 && !band5)
{
// 24 => 27
port.setTagName("port027");
// insert port 26 (q)
QDomElement q = createElement("port026");
q.setAttribute("data", 0.707f);
addList << q;
}
else if(num >= 25 && num <= 26 && !band5)
{
// num += 3
QString name( "port0" );
name.append( QString::number( num + 3 ) );
port.setTagName( name );
}
else if(num == 27 && !band5)
{
// 27 => 31
port.setTagName("port031");
// insert port 30 (q)
QDomElement q = createElement("port030");
q.setAttribute("data", 0.707f);
addList << q;
}
else if(num >= 28 && !band5)
{
// num += 4
QString name( "port0" );
name.append( QString::number( num + 4 ) );
port.setTagName( name );
}
};
iterate_ladspa_ports(effect, fn);
}
if( attribute.attribute( "name" ) == "plugin" &&
attribute.attribute( "value" ) == "Saturator" )
{
auto fn = [&](QDomElement& port, int num, QList<QDomElement>&, QList<QDomElement>& )
{
// These ports have been shifted a bit weird...
if( num == 7 )
{
port.setTagName("port015");
}
else if(num == 12)
{
port.setTagName("port016");
}
else if(num == 13)
{
port.setTagName("port017");
}
else if ( num >= 15 )
{
QString name( "port0" );
name.append( QString::number( num + 3 ) );
port.setTagName( name );
}
};
iterate_ladspa_ports(effect, fn);
}
if( attribute.attribute( "name" ) == "plugin" &&
attribute.attribute( "value" ) == "StereoTools" )
{
auto fn = [&](QDomElement& port, int num, QList<QDomElement>&, QList<QDomElement>& )
{
// This effect can not be back-ported due to bugs in the old version,
// or due to different behaviour. We thus port all parameters we can,
// and bash all new parameters (in this case, s.level and m.level) to
// their new defaults (both 1.0f in this case)
if( num == 23 || num == 25 )
{
port.setAttribute("data", 1.0f);
}
};
iterate_ladspa_ports(effect, fn);
}
}
}
}

View File

@@ -48,6 +48,8 @@ LadspaControl::LadspaControl( Model * _parent, port_desc_t * _port,
switch( m_port->data_type )
{
case TOGGLED:
m_toggledModel.setInitValue(
static_cast<bool>( m_port->def ) );
connect( &m_toggledModel, SIGNAL( dataChanged() ),
this, SLOT( ledChanged() ) );
if( m_port->def == 1.0f )
@@ -59,6 +61,7 @@ LadspaControl::LadspaControl( Model * _parent, port_desc_t * _port,
break;
case INTEGER:
case ENUM:
m_knobModel.setRange( static_cast<int>( m_port->max ),
static_cast<int>( m_port->min ),
1 + static_cast<int>( m_port->max -
@@ -117,6 +120,7 @@ LADSPA_Data LadspaControl::value()
case TOGGLED:
return static_cast<LADSPA_Data>( m_toggledModel.value() );
case INTEGER:
case ENUM:
case FLOATING:
return static_cast<LADSPA_Data>( m_knobModel.value() );
case TIME:
@@ -136,6 +140,7 @@ ValueBuffer * LadspaControl::valueBuffer()
{
case TOGGLED:
case INTEGER:
case ENUM:
return NULL;
case FLOATING:
return m_knobModel.valueBuffer();
@@ -159,6 +164,7 @@ void LadspaControl::setValue( LADSPA_Data _value )
m_toggledModel.setValue( static_cast<bool>( _value ) );
break;
case INTEGER:
case ENUM:
m_knobModel.setValue( static_cast<int>( _value ) );
break;
case FLOATING:
@@ -193,6 +199,7 @@ void LadspaControl::saveSettings( QDomDocument& doc,
m_toggledModel.saveSettings( doc, e, "data" );
break;
case INTEGER:
case ENUM:
case FLOATING:
m_knobModel.saveSettings( doc, e, "data" );
break;
@@ -216,35 +223,64 @@ void LadspaControl::loadSettings( const QDomElement& parent, const QString& name
QString linkModelName = "link";
QDomElement e = parent.namedItem( name ).toElement();
// COMPAT < 1.0.0: detect old data format where there's either no dedicated sub
// element or there's a direct sub element with automation link information
if( e.isNull() || e.hasAttribute( "id" ) )
if(e.isNull())
{
dataModelName = name;
linkModelName = name + "link";
e = parent;
// the port exists in the current effect, but not in the
// savefile => it's a new port, so load the default value
if( m_link )
m_linkEnabledModel.setValue(m_linkEnabledModel.initValue());
switch( m_port->data_type )
{
case TOGGLED:
m_toggledModel.setValue(m_toggledModel.initValue());
break;
case INTEGER:
case ENUM:
case FLOATING:
m_knobModel.setValue(m_knobModel.initValue());
break;
case TIME:
m_tempoSyncKnobModel.setValue(m_tempoSyncKnobModel.initValue());
break;
default:
printf("LadspaControl::loadSettings BAD BAD BAD\n");
break;
}
}
if( m_link )
else
{
m_linkEnabledModel.loadSettings( e, linkModelName );
}
switch( m_port->data_type )
{
case TOGGLED:
m_toggledModel.loadSettings( e, dataModelName );
break;
case INTEGER:
case FLOATING:
m_knobModel.loadSettings( e, dataModelName );
break;
case TIME:
m_tempoSyncKnobModel.loadSettings( e, dataModelName );
break;
default:
printf("LadspaControl::loadSettings BAD BAD BAD\n");
break;
// COMPAT < 1.0.0: detect old data format where there's either no dedicated sub
// element or there's a direct sub element with automation link information
if( e.isNull() || e.hasAttribute( "id" ) )
{
dataModelName = name;
linkModelName = name + "link";
e = parent;
}
if( m_link )
{
m_linkEnabledModel.loadSettings( e, linkModelName );
}
switch( m_port->data_type )
{
case TOGGLED:
m_toggledModel.loadSettings( e, dataModelName );
break;
case INTEGER:
case ENUM:
case FLOATING:
m_knobModel.loadSettings( e, dataModelName );
break;
case TIME:
m_tempoSyncKnobModel.loadSettings( e, dataModelName );
break;
default:
printf("LadspaControl::loadSettings BAD BAD BAD\n");
break;
}
}
}
@@ -259,6 +295,7 @@ void LadspaControl::linkControls( LadspaControl * _control )
BoolModel::linkModels( &m_toggledModel, _control->toggledModel() );
break;
case INTEGER:
case ENUM:
case FLOATING:
FloatModel::linkModels( &m_knobModel, _control->knobModel() );
break;
@@ -309,6 +346,7 @@ void LadspaControl::unlinkControls( LadspaControl * _control )
BoolModel::unlinkModels( &m_toggledModel, _control->toggledModel() );
break;
case INTEGER:
case ENUM:
case FLOATING:
FloatModel::unlinkModels( &m_knobModel, _control->knobModel() );
break;

View File

@@ -749,6 +749,31 @@ bool LadspaManager::isInteger( const ladspa_key_t & _plugin,
bool LadspaManager::isEnum( const ladspa_key_t & _plugin, uint32_t _port )
{
if( m_ladspaManagerMap.contains( _plugin )
&& _port < getPortCount( _plugin ) )
{
LADSPA_Descriptor_Function descriptorFunction =
m_ladspaManagerMap[_plugin]->descriptorFunction;
const LADSPA_Descriptor * descriptor =
descriptorFunction(
m_ladspaManagerMap[_plugin]->index );
LADSPA_PortRangeHintDescriptor hintDescriptor =
descriptor->PortRangeHints[_port].HintDescriptor;
// This is an LMMS extension to ladspa
return( LADSPA_IS_HINT_INTEGER( hintDescriptor ) &&
LADSPA_IS_HINT_TOGGLED( hintDescriptor ) );
}
else
{
return( false );
}
}
QString LadspaManager::getPortName( const ladspa_key_t & _plugin,
uint32_t _port )
{

View File

@@ -77,6 +77,7 @@ LadspaControlView::LadspaControlView( QWidget * _parent,
}
case INTEGER:
case ENUM:
case FLOATING:
knb = new Knob( knobBright_26, this, m_ctl->port()->name );
break;