AutomationPattern: removed magic value at position zero
In automation patterns there always had to be a value at position zero which also had a special semantic concerning the initial values of connected objects. However that logic was buggy and confusing. I therefore completely removed the neccessity for a value at position zero (automated value will be 0 until the first set point).
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
* AutomationPattern.h - declaration of class AutomationPattern, which contains
|
||||
* all information about an automation pattern
|
||||
*
|
||||
* Copyright (c) 2008-2010 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
* Copyright (c) 2008-2013 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
* Copyright (c) 2006-2008 Javier Serrano Polo <jasp00/at/users.sourceforge.net>
|
||||
*
|
||||
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
|
||||
@@ -109,6 +109,8 @@ public slots:
|
||||
|
||||
|
||||
private:
|
||||
void cleanObjects();
|
||||
|
||||
AutomationTrack * m_autoTrack;
|
||||
QVector<jo_id_t> m_idsToResolve;
|
||||
objectVector m_objects;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* AutomationPattern.cpp - implementation of class AutomationPattern which
|
||||
* holds dynamic values
|
||||
*
|
||||
* Copyright (c) 2008-2010 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
* Copyright (c) 2008-2013 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
* Copyright (c) 2006-2008 Javier Serrano Polo <jasp00/at/users.sourceforge.net>
|
||||
*
|
||||
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
|
||||
@@ -45,7 +45,6 @@ AutomationPattern::AutomationPattern( AutomationTrack * _auto_track ) :
|
||||
m_hasAutomation( false )
|
||||
{
|
||||
changeLength( midiTime( 1, 0 ) );
|
||||
m_timeMap[0] = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -101,12 +100,6 @@ void AutomationPattern::addObject( AutomatableModel * _obj, bool _search_dup )
|
||||
if( addIt )
|
||||
{
|
||||
m_objects += _obj;
|
||||
// been empty before?
|
||||
if( m_objects.size() == 1 && !hasAutomation() )
|
||||
{
|
||||
// then initialize default-value
|
||||
putValue( 0, _obj->value<float>(), false );
|
||||
}
|
||||
connect( _obj, SIGNAL( destroyed( jo_id_t ) ),
|
||||
this, SLOT( objectDestroyed( jo_id_t ) ),
|
||||
Qt::DirectConnection );
|
||||
@@ -152,6 +145,8 @@ midiTime AutomationPattern::putValue( const midiTime & _time,
|
||||
const float _value,
|
||||
const bool _quant_pos )
|
||||
{
|
||||
cleanObjects();
|
||||
|
||||
midiTime newTime = _quant_pos && engine::automationEditor() ?
|
||||
note::quantized( _time,
|
||||
engine::automationEditor()->quantization() ) :
|
||||
@@ -159,43 +154,7 @@ midiTime AutomationPattern::putValue( const midiTime & _time,
|
||||
|
||||
m_timeMap[newTime] = _value;
|
||||
|
||||
if( newTime == 0 )
|
||||
{
|
||||
for( objectVector::iterator it = m_objects.begin();
|
||||
it != m_objects.end(); )
|
||||
{
|
||||
if( *it )
|
||||
{
|
||||
( *it )->setValue( _value );
|
||||
++it;
|
||||
}
|
||||
else
|
||||
{
|
||||
it = m_objects.erase( it );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// just one automation value?
|
||||
if( m_timeMap.size() == 1 )
|
||||
{
|
||||
m_hasAutomation = m_objects.isEmpty(); // usually false
|
||||
for( objectVector::iterator it = m_objects.begin();
|
||||
it != m_objects.end(); ++it )
|
||||
{
|
||||
// default value differs from current value?
|
||||
if( *it && _value != ( *it )->initValue<float>() )
|
||||
{
|
||||
// then enable automating this object
|
||||
m_hasAutomation = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// in all other cases assume we have automation
|
||||
m_hasAutomation = true;
|
||||
}
|
||||
m_hasAutomation = true;
|
||||
|
||||
// we need to maximize our length in case we're part of a hidden
|
||||
// automation track as the user can't resize this pattern
|
||||
@@ -214,41 +173,22 @@ midiTime AutomationPattern::putValue( const midiTime & _time,
|
||||
|
||||
void AutomationPattern::removeValue( const midiTime & _time )
|
||||
{
|
||||
if( _time != 0 )
|
||||
cleanObjects();
|
||||
|
||||
m_timeMap.remove( _time );
|
||||
|
||||
if( getTrack() &&
|
||||
getTrack()->type() == track::HiddenAutomationTrack )
|
||||
{
|
||||
m_timeMap.remove( _time );
|
||||
|
||||
if( m_timeMap.size() == 1 )
|
||||
{
|
||||
const float val = m_timeMap[0];
|
||||
m_hasAutomation = false;
|
||||
for( objectVector::iterator it = m_objects.begin();
|
||||
it != m_objects.end(); )
|
||||
{
|
||||
if( *it )
|
||||
{
|
||||
( *it )->setValue( val );
|
||||
if( ( *it )->initValue<float>() != val )
|
||||
{
|
||||
m_hasAutomation = true;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
else
|
||||
{
|
||||
it = m_objects.erase( it );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( getTrack() &&
|
||||
getTrack()->type() == track::HiddenAutomationTrack )
|
||||
{
|
||||
changeLength( length() );
|
||||
}
|
||||
|
||||
emit dataChanged();
|
||||
changeLength( length() );
|
||||
}
|
||||
|
||||
if( m_timeMap.isEmpty() )
|
||||
{
|
||||
m_hasAutomation = false;
|
||||
}
|
||||
|
||||
emit dataChanged();
|
||||
}
|
||||
|
||||
|
||||
@@ -260,10 +200,22 @@ float AutomationPattern::valueAt( const midiTime & _time ) const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
timeMap::const_iterator v = m_timeMap.lowerBound( _time );
|
||||
|
||||
if( m_timeMap.contains( _time ) )
|
||||
{
|
||||
return m_timeMap[_time];
|
||||
}
|
||||
|
||||
// lowerBound returns next value with greater key, therefore we take
|
||||
// the previous element to get the current value
|
||||
return ( v != m_timeMap.begin() ) ? (v-1).value() : v.value();
|
||||
timeMap::ConstIterator v = m_timeMap.lowerBound( _time );
|
||||
|
||||
if( v == m_timeMap.begin() )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (v-1).value();
|
||||
}
|
||||
|
||||
|
||||
@@ -326,17 +278,7 @@ void AutomationPattern::loadSettings( const QDomElement & _this )
|
||||
}
|
||||
|
||||
m_hasAutomation = m_timeMap.size() > 0;
|
||||
if( m_hasAutomation == false )
|
||||
{
|
||||
for( objectVector::iterator it = m_objects.begin();
|
||||
it != m_objects.end(); ++it )
|
||||
{
|
||||
if( *it )
|
||||
{
|
||||
( *it )->setValue( m_timeMap[0] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int len = _this.attribute( "len" ).toInt();
|
||||
if( len <= 0 )
|
||||
{
|
||||
@@ -366,7 +308,7 @@ const QString AutomationPattern::name() const
|
||||
|
||||
void AutomationPattern::processMidiTime( const midiTime & _time )
|
||||
{
|
||||
if( _time >= 0 && m_hasAutomation )
|
||||
if( _time >= 0 && hasAutomation() )
|
||||
{
|
||||
const float val = valueAt( _time );
|
||||
for( objectVector::iterator it = m_objects.begin();
|
||||
@@ -502,9 +444,9 @@ void AutomationPattern::resolveAllIDs()
|
||||
|
||||
void AutomationPattern::clear()
|
||||
{
|
||||
const float val = firstObject()->value<float>();
|
||||
m_timeMap.clear();
|
||||
putValue( 0, val );
|
||||
|
||||
emit dataChanged();
|
||||
|
||||
if( engine::automationEditor() &&
|
||||
engine::automationEditor()->currentPattern() == this )
|
||||
@@ -537,6 +479,21 @@ void AutomationPattern::objectDestroyed( jo_id_t _id )
|
||||
|
||||
|
||||
|
||||
void AutomationPattern::cleanObjects()
|
||||
{
|
||||
for( objectVector::iterator it = m_objects.begin(); it != m_objects.end(); )
|
||||
{
|
||||
if( *it )
|
||||
{
|
||||
++it;
|
||||
}
|
||||
else
|
||||
{
|
||||
it = m_objects.erase( it );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#include "moc_AutomationPattern.cxx"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user