Skip to content

Commit

Permalink
Automation refactorings & record fix
Browse files Browse the repository at this point in the history
  • Loading branch information
lukas-w committed Mar 21, 2017
1 parent 554f901 commit 42fcaed
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 77 deletions.
1 change: 1 addition & 0 deletions include/AutomatableModel.h
Expand Up @@ -444,6 +444,7 @@ class BoolModel : public AutomatableModel

} ;

using AutomatedValueMap = QMap<AutomatableModel*, float>;

#endif

5 changes: 3 additions & 2 deletions include/AutomationPattern.h
Expand Up @@ -59,6 +59,7 @@ class EXPORT AutomationPattern : public TrackContentObject
bool addObject( AutomatableModel * _obj, bool _search_dup = true );

const AutomatableModel * firstObject() const;
const objectVector& objects() const;

// progression-type stuff
inline ProgressionTypes progressionType() const
Expand All @@ -82,6 +83,8 @@ class EXPORT AutomationPattern : public TrackContentObject
void removeValue( const MidiTime & _time,
const bool _quant_pos = true );

void recordValue(MidiTime time, float value);

MidiTime setDragValue( const MidiTime & _time, const float _value,
const bool _quant_pos = true );

Expand Down Expand Up @@ -140,8 +143,6 @@ class EXPORT AutomationPattern : public TrackContentObject
static const QString classNodeName() { return "automationpattern"; }
QString nodeName() const { return classNodeName(); }

void processMidiTime( const MidiTime & _time );

virtual TrackContentObjectView * createView( TrackView * _tv );


Expand Down
5 changes: 3 additions & 2 deletions include/Song.h
Expand Up @@ -31,7 +31,6 @@
#include <QtCore/QVector>

#include "TrackContainer.h"
#include "AutomatableModel.h"
#include "Controller.h"
#include "MeterModel.h"
#include "VstSyncController.h"
Expand Down Expand Up @@ -97,7 +96,6 @@ class EXPORT Song : public TrackContainer


void processNextBuffer();
void processAutomations(const TrackList& tracks, MidiTime timeStart, fpp_t frames, int tcoNum);

inline int getMilliseconds() const
{
Expand Down Expand Up @@ -206,6 +204,8 @@ class EXPORT Song : public TrackContainer
return m_globalAutomationTrack;
}

static AutomatedValueMap automatedValuesAt(const Track::tcoVector& tcos, MidiTime time);

// file management
void createNewProject();
void createNewProjectFromTemplate( const QString & templ );
Expand Down Expand Up @@ -326,6 +326,7 @@ private slots:

void removeAllControllers();

void processAutomations(const TrackList& tracks, MidiTime timeStart, fpp_t frames, int tcoNum);

AutomationTrack * m_globalAutomationTrack;

Expand Down
69 changes: 22 additions & 47 deletions src/core/AutomationPattern.cpp
Expand Up @@ -109,16 +109,9 @@ AutomationPattern::~AutomationPattern()

bool AutomationPattern::addObject( AutomatableModel * _obj, bool _search_dup )
{
if( _search_dup )
if( _search_dup && m_objects.contains(_obj) )
{
for( objectVector::iterator it = m_objects.begin();
it != m_objects.end(); ++it )
{
if( *it == _obj )
{
return false;
}
}
return false;
}

// the automation track is unconnected and there is nothing in the track
Expand Down Expand Up @@ -183,6 +176,11 @@ const AutomatableModel * AutomationPattern::firstObject() const
return &_fm;
}

const AutomationPattern::objectVector& AutomationPattern::objects() const
{
return m_objects;
}




Expand Down Expand Up @@ -265,6 +263,21 @@ void AutomationPattern::removeValue( const MidiTime & _time,



void AutomationPattern::recordValue(MidiTime time, float value)
{
if( value != m_lastRecordedValue )
{
putValue( time, value, true );
m_lastRecordedValue = value;
}
else if( valueAt( time ) != value )
{
removeValue( time, false );
}
}




/**
* @brief Set the position of the point that is being draged.
Expand Down Expand Up @@ -618,44 +631,6 @@ const QString AutomationPattern::name() const



void AutomationPattern::processMidiTime( const MidiTime & time )
{
if( ! isRecording() )
{
if( time >= 0 && hasAutomation() )
{
const float val = valueAt( time );
for( objectVector::iterator it = m_objects.begin();
it != m_objects.end(); ++it )
{
if( *it )
{
( *it )->setAutomatedValue( val );
}

}
}
}
else
{
if( time >= 0 && time < length() && ! m_objects.isEmpty() )
{
const float value = static_cast<float>( firstObject()->value<float>() );
if( value != m_lastRecordedValue )
{
putValue( time, value, true );
m_lastRecordedValue = value;
}
else if( valueAt( time ) != value )
{
removeValue( time, false );
}
}
}
}



TrackContentObjectView * AutomationPattern::createView( TrackView * _tv )
{
return new AutomationPatternView( this, _tv );
Expand Down
90 changes: 64 additions & 26 deletions src/core/Song.cpp
Expand Up @@ -31,6 +31,7 @@
#include <QMessageBox>
#include <QApplication>

#include <functional>
#include <math.h>

#include "AutomationTrack.h"
Expand Down Expand Up @@ -424,50 +425,63 @@ void Song::processAutomations(const TrackList &tracklist, MidiTime timeStart, fp
tracks << dynamic_cast<AutomationTrack*>(track);
}
}
std::remove_if(tracks.begin(), tracks.end(), std::mem_fn(&Track::isMuted));

MidiTime time_end = timeStart + static_cast<int>(frames / Engine::framesPerTick());
Track::tcoVector tcos;
AutomatedValueMap values;

// Collect all relevant patterns, sorted by start position
QVector<TrackContentObject*> tcos;
for (Track* track: tracks)
if (tcoNum < 0)
{
if(track->isMuted())
// Collect all relevant patterns, sorted by start position
MidiTime timeEnd = timeStart + static_cast<int>(frames / Engine::framesPerTick());
for (AutomationTrack* track: tracks)
{
continue;
track->getTCOsInRange(tcos, 0, timeEnd);
}
std::remove_if(tcos.begin(), tcos.end(), std::mem_fn(&TrackContentObject::isMuted));

int tco_begin = 0, tco_end = track->numOfTCOs();
if( tcoNum >= 0 )
values = automatedValuesAt(tcos, timeStart);
}
else
{
if (tracklist.size() != 1)
{
tco_begin = tcoNum;
tco_end = tcoNum + 1;
qCritical() << "processAutomations called with specified tcoNum but more than one track";
return;
}

for (int i = tco_begin; i < tco_end; i++)
{
TrackContentObject* tco = track->getTCO(i);

// Skip this TCO if it's muted or not contained in the time period we're processing
if( tco->isMuted() || tco->startPosition() > time_end)
{
continue;
}
Track* track = tracklist.at(1);
TrackContentObject* tco = track->getTCO(tcoNum);
auto p = dynamic_cast<AutomationPattern *>(tco);

tcos.insert(std::upper_bound(tcos.begin(), tcos.end(), tco, TrackContentObject::comparePosition), tco);
for (AutomatableModel* object : p->objects())
{
values[object] = p->valueAt(timeStart);
}
tcos << tco;
}

for(TrackContentObject* tco : tcos)
QSet<const AutomatableModel*> recordedModels;
// Process recording
for (TrackContentObject* tco : tcos)
{
auto p = dynamic_cast<AutomationPattern *>(tco);

if (tcoNum < 0)
MidiTime relTime = timeStart - p->startPosition();
if (p->isRecording() && relTime >= 0 && relTime < p->length())
{
p->processMidiTime(timeStart - p->startPosition());
const AutomatableModel* recordedModel = p->firstObject();
p->recordValue(relTime, recordedModel->value<float>());

recordedModels << recordedModel;
}
else
}

// Apply values
for (auto it = values.cbegin(); it != values.cend(); it++)
{
if (! recordedModels.contains(it.key()))
{
p->processMidiTime(timeStart);
it.key()->setAutomatedValue(it.value());
}
}
}
Expand Down Expand Up @@ -838,6 +852,30 @@ AutomationPattern * Song::tempoAutomationPattern()
return AutomationPattern::globalAutomationPattern( &m_tempoModel );
}

AutomatedValueMap Song::automatedValuesAt(const Track::tcoVector &tcos, MidiTime time)
{
AutomatedValueMap valueMap;

for(TrackContentObject* tco : tcos)
{
AutomationPattern* p = dynamic_cast<AutomationPattern *>(tco);
if (!p) {
qCritical() << "automatedValuesAt: tco passed is not an automation pattern";
continue;
}

MidiTime relTime = time - p->startPosition();
float value = p->valueAt(relTime);

for (AutomatableModel* model : p->objects())
{
valueMap[model] = value;
}
}

return valueMap;
}




Expand Down

0 comments on commit 42fcaed

Please sign in to comment.