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).
This commit is contained in:
Vesa
2014-05-15 03:02:42 +03:00
parent fd89e4c5e6
commit aefc9832f8
4 changed files with 112 additions and 0 deletions

View File

@@ -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();

View File

@@ -152,6 +152,7 @@ public:
static bool isAutomated( const AutomatableModel * _m );
static QVector<AutomationPattern *> patternsForModel( const AutomatableModel * _m );
static AutomationPattern * globalAutomationPattern( AutomatableModel * _m );
static void resolveAllIDs();

View File

@@ -555,6 +555,70 @@ void AutomatableModel::pasteValue()
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 *> patterns_in_range;
for( QVector<AutomationPattern *>::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<AutomationPattern *>::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<float>()) / maxValue<float>()
);
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"

View File

@@ -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 *> AutomationPattern::patternsForModel( const AutomatableModel * _m )
{
QVector<AutomationPattern *> 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<AutomationPattern *>( *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;
}