Fix automation processing in BB tracks (#3481)

Fixes #3464
This commit is contained in:
Lukas W
2017-04-06 23:10:00 +02:00
committed by GitHub
parent b5ac3161c9
commit 96a00300e8
7 changed files with 201 additions and 93 deletions

View File

@@ -90,7 +90,7 @@ void BBTrackContainer::updateAfterTrackAdd()
tact_t BBTrackContainer::lengthOfBB( int _bb )
tact_t BBTrackContainer::lengthOfBB( int _bb ) const
{
MidiTime max_length = MidiTime::ticksPerTact();
@@ -239,6 +239,20 @@ void BBTrackContainer::createTCOsForBB( int _bb )
}
}
AutomatedValueMap BBTrackContainer::automatedValuesAt(MidiTime time, int tcoNum) const
{
Q_ASSERT(tcoNum >= 0);
Q_ASSERT(time.getTicks() >= 0);
auto length_tacts = lengthOfBB(tcoNum);
auto length_ticks = length_tacts * MidiTime::ticksPerTact();
if (time > length_ticks) {
time = length_ticks;
}
return TrackContainer::automatedValuesAt(time + (MidiTime::ticksPerTact() * tcoNum), tcoNum);
}

View File

@@ -378,7 +378,7 @@ void Song::processNextBuffer()
if( ( f_cnt_t ) currentFrame == 0 )
{
processAutomations(trackList, m_playPos[m_playMode], framesToPlay, tcoNum);
processAutomations(trackList, m_playPos[m_playMode], framesToPlay);
// loop through all tracks and play them
for( int i = 0; i < trackList.size(); ++i )
@@ -401,58 +401,45 @@ void Song::processNextBuffer()
}
}
void Song::processAutomations(const TrackList &tracklist, MidiTime timeStart, fpp_t frames, int tcoNum)
void Song::processAutomations(const TrackList &tracklist, MidiTime timeStart, fpp_t)
{
QVector<AutomationTrack*> tracks;
if(m_playMode == Mode_PlaySong)
{
tracks << m_globalAutomationTrack;
}
for( Track* track : tracklist)
{
if (track->type() == Track::AutomationTrack || track->type() == Track::HiddenAutomationTrack)
{
tracks << dynamic_cast<AutomationTrack*>(track);
}
}
std::remove_if(tracks.begin(), tracks.end(), std::mem_fn(&Track::isMuted));
Track::tcoVector tcos;
AutomatedValueMap values;
if (tcoNum < 0)
{
// Collect all relevant patterns, sorted by start position
MidiTime timeEnd = timeStart + static_cast<int>(frames / Engine::framesPerTick());
for (AutomationTrack* track: tracks)
{
track->getTCOsInRange(tcos, 0, timeEnd);
}
values = automatedValuesAt(tcos, timeStart);
}
else
{
if (tracklist.size() != 1)
{
qWarning() << "processAutomations called with specified tcoNum but not exactly one track";
}
for (AutomationTrack* track: tracks)
{
TrackContentObject* tco = track->getTCO(tcoNum);
auto p = dynamic_cast<AutomationPattern *>(tco);
for (AutomatableModel* object : p->objects())
{
values[object] = p->valueAt(timeStart);
}
tcos << tco;
}
}
QSet<const AutomatableModel*> recordedModels;
TrackContainer* container = this;
int tcoNum = -1;
switch (m_playMode)
{
case Mode_PlaySong:
break;
case Mode_PlayBB:
{
Q_ASSERT(tracklist.size() == 1);
Q_ASSERT(tracklist.at(0)->type() == Track::BBTrack);
auto bbTrack = dynamic_cast<BBTrack*>(tracklist.at(0));
auto bbContainer = Engine::getBBTrackContainer();
container = bbContainer;
tcoNum = bbTrack->index();
}
break;
default:
return;
}
values = container->automatedValuesAt(timeStart, tcoNum);
TrackList tracks = container->tracks();
Track::tcoVector tcos;
for (Track* track : tracks)
{
if (track->type() == Track::AutomationTrack) {
track->getTCOsInRange(tcos, 0, timeStart);
}
}
// Process recording
for (TrackContentObject* tco : tcos)
{
@@ -849,35 +836,10 @@ AutomationPattern * Song::tempoAutomationPattern()
return AutomationPattern::globalAutomationPattern( &m_tempoModel );
}
AutomatedValueMap Song::automatedValuesAt(const Track::tcoVector &tcos, MidiTime time)
AutomatedValueMap Song::automatedValuesAt(MidiTime time, int tcoNum) const
{
AutomatedValueMap valueMap;
for(TrackContentObject* tco : tcos)
{
if (tco->isMuted() || tco->startPosition() > time) {
continue;
}
AutomationPattern* p = dynamic_cast<AutomationPattern *>(tco);
if (!p) {
qCritical() << "automatedValuesAt: tco passed is not an automation pattern";
continue;
}
if (! p->hasAutomation()) {
continue;
}
MidiTime relTime = time - p->startPosition();
float value = p->valueAt(relTime);
for (AutomatableModel* model : p->objects())
{
valueMap[model] = value;
}
}
return valueMap;
return TrackContainer::automatedValuesFromTracks(TrackList(tracks()) << m_globalAutomationTrack, time, tcoNum);
}

View File

@@ -29,12 +29,16 @@
#include <QDomElement>
#include <QWriteLocker>
#include "AutomationPattern.h"
#include "AutomationTrack.h"
#include "BBTrack.h"
#include "BBTrackContainer.h"
#include "TrackContainer.h"
#include "InstrumentTrack.h"
#include "GuiApplication.h"
#include "MainWindow.h"
#include "Song.h"
#include "GuiApplication.h"
#include "MainWindow.h"
TrackContainer::TrackContainer() :
Model( NULL ),
@@ -234,6 +238,85 @@ bool TrackContainer::isEmpty() const
AutomatedValueMap TrackContainer::automatedValuesAt(MidiTime time, int tcoNum) const
{
return automatedValuesFromTracks(tracks(), time, tcoNum);
}
AutomatedValueMap TrackContainer::automatedValuesFromTracks(const TrackList &tracks, MidiTime time, int tcoNum)
{
Track::tcoVector tcos;
for (Track* track: tracks)
{
if (track->isMuted()) {
continue;
}
switch(track->type())
{
case Track::AutomationTrack:
case Track::HiddenAutomationTrack:
case Track::BBTrack:
if (tcoNum < 0) {
track->getTCOsInRange(tcos, 0, time);
} else {
Q_ASSERT(track->numOfTCOs() > tcoNum);
tcos << track->getTCO(tcoNum);
}
default:
break;
}
}
AutomatedValueMap valueMap;
Q_ASSERT(std::is_sorted(tcos.begin(), tcos.end(), TrackContentObject::comparePosition));
for(TrackContentObject* tco : tcos)
{
if (tco->isMuted() || tco->startPosition() > time) {
continue;
}
if (auto* p = dynamic_cast<AutomationPattern *>(tco))
{
if (! p->hasAutomation()) {
continue;
}
MidiTime relTime = time - p->startPosition();
float value = p->valueAt(relTime);
for (AutomatableModel* model : p->objects())
{
valueMap[model] = value;
}
}
else if (auto* bb = dynamic_cast<BBTCO *>(tco))
{
auto bbIndex = dynamic_cast<class BBTrack*>(bb->getTrack())->index();
auto bbContainer = Engine::getBBTrackContainer();
MidiTime bbTime = time - tco->startPosition();
bbTime = std::min(bbTime, tco->length());
bbTime = bbTime % (bbContainer->lengthOfBB(bbIndex) * MidiTime::ticksPerTact());
auto bbValues = bbContainer->automatedValuesAt(bbTime, bbIndex);
for (auto it=bbValues.begin(); it != bbValues.end(); it++)
{
// override old values, bb track with the highest index takes precedence
valueMap[it.key()] = it.value();
}
}
else
{
continue;
}
}
return valueMap;
};