From aefc9832f8eacab039adab6fc77f53a6ebb54be9 Mon Sep 17 00:00:00 2001 From: Vesa Date: Thu, 15 May 2014 03:02:42 +0300 Subject: [PATCH] Initial implementation for two additional methods in AutomatableModel, AutomationPattern: These methods are used to fetch the automated value of a model at a given MidiTime These are still untested but that shouldn't be a problem since they aren't actually used by anything yet... but I'll be doing some testing and bugfixing (if needed) for them later. These will be an important step in making sampletracks eventually be reliably playable from any position, and more generically, being able to reliably convert MidiTime to real time. Of course they can be useful for other things too (not sure what though, yet). --- include/AutomatableModel.h | 2 ++ include/AutomationPattern.h | 1 + src/core/AutomatableModel.cpp | 64 ++++++++++++++++++++++++++++++++++ src/core/AutomationPattern.cpp | 45 ++++++++++++++++++++++++ 4 files changed, 112 insertions(+) diff --git a/include/AutomatableModel.h b/include/AutomatableModel.h index 10ee252e9..206cdafa8 100644 --- a/include/AutomatableModel.h +++ b/include/AutomatableModel.h @@ -29,6 +29,7 @@ #include "JournallingObject.h" #include "Model.h" +#include "MidiTime.h" // simple way to map a property of a view to a model @@ -239,6 +240,7 @@ public: return m_hasLinkedModels; } + float globalAutomationValueAt( const MidiTime& time ); public slots: virtual void reset(); diff --git a/include/AutomationPattern.h b/include/AutomationPattern.h index aea64947e..8b9cc6d14 100644 --- a/include/AutomationPattern.h +++ b/include/AutomationPattern.h @@ -152,6 +152,7 @@ public: static bool isAutomated( const AutomatableModel * _m ); + static QVector patternsForModel( const AutomatableModel * _m ); static AutomationPattern * globalAutomationPattern( AutomatableModel * _m ); static void resolveAllIDs(); diff --git a/src/core/AutomatableModel.cpp b/src/core/AutomatableModel.cpp index a647b3451..7b962252b 100644 --- a/src/core/AutomatableModel.cpp +++ b/src/core/AutomatableModel.cpp @@ -555,6 +555,70 @@ void AutomatableModel::pasteValue() +float AutomatableModel::globalAutomationValueAt( const MidiTime& time ) +{ + // get patterns that connect to this model + QVector 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 patterns_in_range; + for( QVector::ConstIterator it = patterns.begin(); it != patterns.end(); it++ ) + { + int s = ( *it )->startPosition(); + int e = ( *it )->endPosition(); + if( s <= time && e >= time ) { patterns_in_range += ( *it ); } + } + + AutomationPattern * latest_pattern = NULL; + + if( ! patterns_in_range.isEmpty() ) + { + // if there are more than one overlapping patterns, just use the first one because + // multiple pattern behaviour is undefined anyway + latest_pattern = patterns_in_range[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 latest_position = 0; + + for( QVector::ConstIterator it = patterns.begin(); it != patterns.end(); it++ ) + { + int e = ( *it )->endPosition(); + if( e <= time && e > latest_position ) + { + latest_position = e; + latest_pattern = ( *it ); + } + } + } + + if( latest_pattern ) + { + // scale/fit the value appropriately and return it + const float value = latest_pattern->valueAt( time ); + const float scaled_value = + ( m_scaleType == Linear ) + ? value + : logToLinearScale( + // fits value into [0,1]: + (value - minValue()) / maxValue() + ); + 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; + } +} + #include "moc_AutomatableModel.cxx" diff --git a/src/core/AutomationPattern.cpp b/src/core/AutomationPattern.cpp index 49f154732..94025a389 100644 --- a/src/core/AutomationPattern.cpp +++ b/src/core/AutomationPattern.cpp @@ -551,6 +551,51 @@ bool AutomationPattern::isAutomated( const AutomatableModel * _m ) } +/*! \brief returns a list of all the automation patterns everywhere that are connected to a specific model + * \param _m the model we want to look for + */ +QVector AutomationPattern::patternsForModel( const AutomatableModel * _m ) +{ + QVector patterns; + TrackContainer::TrackList l; + l += engine::getSong()->tracks(); + l += engine::getBBTrackContainer()->tracks(); + l += engine::getSong()->globalAutomationTrack(); + + // go through all tracks... + for( TrackContainer::TrackList::ConstIterator it = l.begin(); it != l.end(); ++it ) + { + // we want only automation tracks... + if( ( *it )->type() == track::AutomationTrack || + ( *it )->type() == track::HiddenAutomationTrack ) + { + // get patterns in those tracks.... + const track::tcoVector & v = ( *it )->getTCOs(); + // go through all the patterns... + for( track::tcoVector::ConstIterator j = v.begin(); j != v.end(); ++j ) + { + AutomationPattern * a = dynamic_cast( *j ); + // check that the pattern has automation + if( a && a->hasAutomation() ) + { + // now check is the pattern is connected to the model we want by going through all the connections + // of the pattern + bool has_object = false; + for( objectVector::const_iterator k = a->m_objects.begin(); k != a->m_objects.end(); ++k ) + { + if( *k == _m ) + { + has_object = true; + } + } + // if the patterns is connected to the model, add it to the list + if( has_object ) { patterns += a; } + } + } + } + } + return patterns; +}