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:
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user