Logscales temporary commit.

This commit is contained in:
Johannes Lorenz
2014-04-05 08:15:35 +02:00
parent bd691e6d68
commit 1f5ef70d2c
6 changed files with 151 additions and 29 deletions

View File

@@ -60,13 +60,19 @@
class ControllerConnection;
#include <cstdio>
class EXPORT AutomatableModel : public Model, public JournallingObject
{
Q_OBJECT
public:
typedef QVector<AutomatableModel *> AutoModelVector;
enum ScaleType
{
Linear,
Logarithmic
};
enum DataType
{
Float,
@@ -175,6 +181,14 @@ public:
}
void setRange( const float min, const float max, const float step = 1 );
void setScaleType( ScaleType sc ) {
printf("Settings scale to: %d\n", (int)sc);
m_scaleType = sc;
}
void setScaleLogarithmic( bool set_to_true = true )
{
setScaleType(set_to_true ? Logarithmic : Linear);
}
void setStep( const float step );
@@ -193,8 +207,14 @@ public:
void unlinkAllModels();
/*! \brief Saves settings (value, automation links and controller connections) of AutomatableModel into
specified DOM element using <name> as attribute/node name */
/**
* @brief Saves settings (value, automation links and controller connections) of AutomatableModel into
* specified DOM element using <name> as attribute/node name
* @param doc TODO
* @param element Where this option shall be saved.
* Depending on the model, this can be done in an attribute or in a subnode.
* @param name Name to store this model as.
*/
virtual void saveSettings( QDomDocument& doc, QDomElement& element, const QString& name );
/*! \brief Loads settings (value, automation links and controller connections) of AutomatableModel from
@@ -248,8 +268,13 @@ private:
void linkModel( AutomatableModel* model );
void unlinkModel( AutomatableModel* model );
//! rounds @a value to @a where if it is close to it
//! @param value will be modified to rounded value
template<class T> void round_at(T &value, const T &where) const;
DataType m_dataType;
ScaleType m_scaleType; //! scale type, linear by default
float m_value;
float m_initValue;
float m_minValue;
@@ -267,6 +292,7 @@ private:
bool m_hasLinkedModels;
//! NULL if not appended to controller, otherwise connection info
ControllerConnection* m_controllerConnection;

View File

@@ -100,7 +100,7 @@ protected:
//virtual controllerDialog * createDialog( QWidget * _parent );
Controller * m_controller;
QString m_targetName;
int m_controllerId;
int m_controllerId;
bool m_ownsController;

View File

@@ -51,6 +51,8 @@ typedef enum BufferData
NONE
} buffer_data_t;
//! This struct is used to hold port descriptions internally
//! which where received from the ladspa plugin
typedef struct PortDescription
{
QString name;
@@ -64,6 +66,9 @@ typedef struct PortDescription
LADSPA_Data min;
LADSPA_Data def;
LADSPA_Data value;
//! This is true iff ladspa suggests logscale
//! Note however that the model can still decide to use a linear scale
bool suggests_logscale;
LADSPA_Data * buffer;
LadspaControl * control;
} port_desc_t;

View File

@@ -305,12 +305,12 @@ void LadspaEffect::pluginInstantiation()
// Determine the port's category.
if( manager->isPortAudio( m_key, port ) )
{
// Nasty manual memory management--was having difficulty
// with some prepackaged plugins that were segfaulting
// during cleanup. It was easier to troubleshoot with the
// memory management all taking place in one file.
// Nasty manual memory management--was having difficulty
// with some prepackaged plugins that were segfaulting
// during cleanup. It was easier to troubleshoot with the
// memory management all taking place in one file.
p->buffer =
new LADSPA_Data[engine::mixer()->framesPerPeriod()];
new LADSPA_Data[engine::mixer()->framesPerPeriod()];
if( p->name.toUpper().contains( "IN" ) &&
manager->isPortInput( m_key, port ) )
@@ -430,6 +430,7 @@ void LadspaEffect::pluginInstantiation()
p->value = p->def;
p->suggests_logscale = manager->isLogarithmic( m_key, port );
ports.append( p );

View File

@@ -39,6 +39,7 @@ AutomatableModel::AutomatableModel( DataType type,
Model* parent, const QString & displayName, bool defaultConstructed ) :
Model( parent, displayName, defaultConstructed ),
m_dataType( type ),
m_scaleType( Linear ),
m_value( val ),
m_initValue( val ),
m_minValue( min ),
@@ -85,21 +86,30 @@ bool AutomatableModel::isAutomated() const
void AutomatableModel::saveSettings( QDomDocument& doc, QDomElement& element, const QString& name )
{
bool automated_or_controlled = false;
if( isAutomated() )
{
// automation needs tuple of data (name, id, value)
// => it must be appended as a node
QDomElement me = doc.createElement( name );
me.setAttribute( "id", id() );
me.setAttribute( "value", m_value );
element.appendChild( me );
automated_or_controlled = true;
}
else
{
// non automation => can be saved as attribute
element.setAttribute( name, m_value );
}
if( m_controllerConnection )
{
QDomElement controllerElement;
// get "connection" element (and create it if needed)
QDomNode node = element.namedItem( "connection" );
if( node.isElement() )
{
@@ -115,6 +125,15 @@ void AutomatableModel::saveSettings( QDomDocument& doc, QDomElement& element, co
m_controllerConnection->saveSettings( doc, element );
controllerElement.appendChild( element );
automated_or_controlled = true;
}
if(automated_or_controlled && (m_scaleType != Linear))
{ // note: if we have more scale types than two, make
// a mapper function enums <-> string
if(m_scaleType == Logarithmic)
element.setAttribute("scale_type", "log");
}
}
@@ -123,6 +142,15 @@ void AutomatableModel::saveSettings( QDomDocument& doc, QDomElement& element, co
void AutomatableModel::loadSettings( const QDomElement& element, const QString& name )
{
// read scale type and overwrite default scale type
if(element.hasAttribute("scale_type")) // wrong in most cases
{
if(element.attribute("scale_type") == "log")
setScaleType(Logarithmic);
}
else
setScaleType(Linear);
// compat code
QDomNode node = element.namedItem( AutomationPattern::classNodeName() );
if( node.isElement() )
@@ -141,9 +169,12 @@ void AutomatableModel::loadSettings( const QDomElement& element, const QString&
}
return;
}
// logscales were not existing at this point of time
// so they can be ignored
}
QDomNode connectionNode = element.namedItem( "connection" );
// reads controller connection
if( connectionNode.isElement() )
{
QDomNode thisConnection = connectionNode.toElement().namedItem( name );
@@ -154,14 +185,20 @@ void AutomatableModel::loadSettings( const QDomElement& element, const QString&
//m_controllerConnection->setTargetName( displayName() );
}
}
// models can be stored as elements (port00) or attributes (port10):
// <ladspacontrols port10="4.41">
// <port00 value="4.41" id="4249278"/>
// </ladspacontrols>
// element => there is automation data
node = element.namedItem( name );
if( node.isElement() )
{
changeID( node.toElement().attribute( "id" ).toInt() );
setValue( node.toElement().attribute( "value" ).toFloat() );
}
else if( element.hasAttribute( name ) )
if( node.isElement() )
{
changeID( node.toElement().attribute( "id" ).toInt() );
setValue( node.toElement().attribute( "value" ).toFloat() );
}
else if( element.hasAttribute( name ) )
// attribute => read the element's value from the attribute list
{
setInitValue( element.attribute( name ).toFloat() );
}
@@ -207,12 +244,34 @@ void AutomatableModel::setValue( const float value )
//! @brief Scales @value from linear to logarithmic.
//! Value should be within [0,1]
template<class T> T log_to_linear_scale(T min, T max, T value)
// we get min and max from the class => TODO
{
printf("scale: in: %f, out: %f\n",value, exp((log(max)-log(min)) * value + log(min)));
return exp((log(max)-log(min)) * value + log(min));
}
void AutomatableModel::setAutomatedValue( const float value )
{
++m_setValueDepth;
const float oldValue = m_value;
m_value = fittedValue( value );
const float scaled_value =
(m_scaleType == Linear)
? value
: log_to_linear_scale(
minValue<float>(), maxValue<float>(),
// fit value into [0,1]:
(value - minValue<float>()) / maxValue<float>()
);
m_value = fittedValue( scaled_value );
if( oldValue != m_value )
{
// notify linked models
@@ -223,6 +282,8 @@ void AutomatableModel::setAutomatedValue( const float value )
!(*it)->fittedValue( m_value ) !=
(*it)->m_value )
{
// @TOBY: don't take m_value, but better: value,
// otherwise, we convert to log twice?
(*it)->setAutomatedValue( m_value );
}
}
@@ -271,6 +332,19 @@ void AutomatableModel::setStep( const float step )
template<class T>
void AutomatableModel::round_at(T& value, const T& where) const
{
if( qAbs<float>( value - where )
< typeInfo<float>::minEps() * qAbs<float>( m_step ) )
{
value = where;
}
}
float AutomatableModel::fittedValue( float value ) const
{
value = tLimit<float>( value, m_minValue, m_maxValue );
@@ -280,17 +354,9 @@ float AutomatableModel::fittedValue( float value ) const
value = nearbyintf( value / m_step ) * m_step;
}
// correct rounding error at the border
if( qAbs<float>( value - m_maxValue ) < typeInfo<float>::minEps() * qAbs<float>( m_step ) )
{
value = m_maxValue;
}
// correct rounding error if value = 0
if( qAbs<float>( value ) < typeInfo<float>::minEps() * qAbs<float>( m_step ) )
{
value = 0;
}
round_at(value, m_maxValue, m_step);
round_at(value, m_minValue, m_step);
round_at(value, 0, m_step);
if( value < m_minValue )
{
@@ -384,11 +450,27 @@ void AutomatableModel::setControllerConnection( ControllerConnection* c )
float AutomatableModel::controllerValue( int frameOffset ) const
{
if( m_controllerConnection )
{
const float v = minValue<float>() + ( range() * controllerConnection()->currentValue( frameOffset ) );
float v;
switch(m_scaleType)
{
case Linear:
v = minValue<float>() + ( range() * controllerConnection()->currentValue( frameOffset ) );
break;
case Logarithmic:
v = log_to_linear_scale(minValue<float>(), maxValue<float>(),
controllerConnection()->currentValue( frameOffset ));
break;
default:
qFatal("AutomatableModel::controllerValue(int)"
"lacks implementation for a scale type");
v = 0; // suppress warning...
break;
}
if( typeInfo<float>::isEqual( m_step, 1 ) )
{
return qRound( v );

View File

@@ -54,6 +54,8 @@ LadspaControl::LadspaControl( Model * _parent, port_desc_t * _port,
{
m_toggledModel.setValue( true );
}
// TODO: careful: we must prevent saved scales
m_toggledModel.setScaleLogarithmic(m_port->suggests_logscale);
break;
case INTEGER:
@@ -65,6 +67,8 @@ LadspaControl::LadspaControl( Model * _parent, port_desc_t * _port,
static_cast<int>( m_port->def ) );
connect( &m_knobModel, SIGNAL( dataChanged() ),
this, SLOT( knobChanged() ) );
// TODO: careful: we must prevent saved scales
m_knobModel.setScaleLogarithmic(m_port->suggests_logscale);
break;
case FLOATING:
@@ -76,6 +80,8 @@ LadspaControl::LadspaControl( Model * _parent, port_desc_t * _port,
m_knobModel.setInitValue( m_port->def );
connect( &m_knobModel, SIGNAL( dataChanged() ),
this, SLOT( knobChanged() ) );
// TODO: careful: we must prevent saved scales
m_knobModel.setScaleLogarithmic(m_port->suggests_logscale);
break;
case TIME:
@@ -85,6 +91,8 @@ LadspaControl::LadspaControl( Model * _parent, port_desc_t * _port,
m_tempoSyncKnobModel.setInitValue( m_port->def );
connect( &m_tempoSyncKnobModel, SIGNAL( dataChanged() ),
this, SLOT( tempoKnobChanged() ) );
// TODO: careful: we must prevent saved scales
m_tempoSyncKnobModel.setScaleLogarithmic(m_port->suggests_logscale);
break;
default: