float AutomatableModel::globalAutomationValueAt( const MidiTime& time ) { // get patterns that connect to this model QVector<AutomationPattern *> patterns = AutomationPattern::patternsForModel( this ); if( patterns.isEmpty() ) { // if no such patterns exist, return current value return m_value; } else { // of those patterns: // find the patterns which overlap with the miditime position QVector<AutomationPattern *> patternsInRange; for( QVector<AutomationPattern *>::ConstIterator it = patterns.begin(); it != patterns.end(); it++ ) { int s = ( *it )->startPosition(); int e = ( *it )->endPosition(); if( s <= time && e >= time ) { patternsInRange += ( *it ); } } AutomationPattern * latestPattern = NULL; if( ! patternsInRange.isEmpty() ) { // if there are more than one overlapping patterns, just use the first one because // multiple pattern behaviour is undefined anyway latestPattern = patternsInRange[0]; } else // if we find no patterns at the exact miditime, we need to search for the last pattern before time and use that { int latestPosition = 0; for( QVector<AutomationPattern *>::ConstIterator it = patterns.begin(); it != patterns.end(); it++ ) { int e = ( *it )->endPosition(); if( e <= time && e > latestPosition ) { latestPosition = e; latestPattern = ( *it ); } } } if( latestPattern ) { // scale/fit the value appropriately and return it const float value = latestPattern->valueAt( time - latestPattern->startPosition() ); const float scaled_value = scaledValue( value ); return fittedValue( scaled_value ); } // if we still find no pattern, the value at that time is undefined so // just return current value as the best we can do else return m_value; } }
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() ) { node = node.namedItem( name ); if( node.isElement() ) { AutomationPattern * p = AutomationPattern::globalAutomationPattern( this ); p->loadSettings( node.toElement() ); setValue( p->valueAt( 0 ) ); // in older projects we sometimes have odd automations // with just one value in - eliminate if necessary if( !p->hasAutomation() ) { delete p; } 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 ); if( thisConnection.isElement() ) { setControllerConnection( new ControllerConnection( (Controller*)NULL ) ); m_controllerConnection->loadSettings( thisConnection.toElement() ); //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 ) ) // attribute => read the element's value from the attribute list { setInitValue( element.attribute( name ).toFloat() ); } else { reset(); } }