Logscales, merged.
This commit is contained in:
@@ -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 );
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user