Skip to content

Commit

Permalink
Fix automation processing in BB tracks (LMMS#3481)
Browse files Browse the repository at this point in the history
Fixes LMMS#3464
  • Loading branch information
lukas-w authored Apr 6, 2017
1 parent 3dde45b commit 338c2ea
Show file tree
Hide file tree
Showing 7 changed files with 194 additions and 86 deletions.
3 changes: 2 additions & 1 deletion include/BBTrackContainer.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class EXPORT BBTrackContainer : public TrackContainer
return "bbtrackcontainer";
}

tact_t lengthOfBB( int _bb );
tact_t lengthOfBB( int _bb ) const;
inline tact_t lengthOfCurrentBB()
{
return lengthOfBB( currentBB() );
Expand All @@ -62,6 +62,7 @@ class EXPORT BBTrackContainer : public TrackContainer
void fixIncorrectPositions();
void createTCOsForBB( int _bb );

AutomatedValueMap automatedValuesAt(MidiTime time, int tcoNum) const override;

public slots:
void play();
Expand Down
5 changes: 3 additions & 2 deletions include/Song.h
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,8 @@ class EXPORT Song : public TrackContainer
return m_globalAutomationTrack;
}

static AutomatedValueMap automatedValuesAt(const Track::tcoVector& tcos, MidiTime time);
//TODO: Add Q_DECL_OVERRIDE when Qt4 is dropped
AutomatedValueMap automatedValuesAt(MidiTime time, int tcoNum = -1) const;

// file management
void createNewProject();
Expand Down Expand Up @@ -326,7 +327,7 @@ private slots:

void removeAllControllers();

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

AutomationTrack * m_globalAutomationTrack;

Expand Down
3 changes: 3 additions & 0 deletions include/TrackContainer.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,14 @@ class EXPORT TrackContainer : public Model, public JournallingObject
return m_TrackContainerType;
}

virtual AutomatedValueMap automatedValuesAt(MidiTime time, int tcoNum = -1) const;

signals:
void trackAdded( Track * _track );

protected:
static AutomatedValueMap automatedValuesFromTracks(const TrackList &tracks, MidiTime timeStart, int tcoNum = -1);

mutable QReadWriteLock m_tracksMutex;

private:
Expand Down
16 changes: 15 additions & 1 deletion src/core/BBTrackContainer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down Expand Up @@ -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);
}




Expand Down
102 changes: 32 additions & 70 deletions src/core/Song.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 )
Expand All @@ -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;
AutomatedValueMap values;

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));
QSet<const AutomatableModel*> recordedModels;

Track::tcoVector tcos;
AutomatedValueMap values;
TrackContainer* container = this;
int tcoNum = -1;

if (tcoNum < 0)
switch (m_playMode)
{
// 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
case Mode_PlaySong:
break;
case Mode_PlayBB:
{
if (tracklist.size() != 1)
{
qWarning() << "processAutomations called with specified tcoNum but not exactly one track";
}
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;
}

for (AutomationTrack* track: tracks)
{
TrackContentObject* tco = track->getTCO(tcoNum);
auto p = dynamic_cast<AutomationPattern *>(tco);
values = container->automatedValuesAt(timeStart, tcoNum);
TrackList tracks = container->tracks();

for (AutomatableModel* object : p->objects())
{
values[object] = p->valueAt(timeStart);
}
tcos << tco;
Track::tcoVector tcos;
for (Track* track : tracks)
{
if (track->type() == Track::AutomationTrack) {
track->getTCOsInRange(tcos, 0, timeStart);
}
}

QSet<const AutomatableModel*> recordedModels;
// Process recording
for (TrackContentObject* tco : tcos)
{
Expand Down Expand Up @@ -849,35 +836,10 @@ AutomationPattern * Song::tempoAutomationPattern()
return AutomationPattern::globalAutomationPattern( &m_tempoModel );
}

AutomatedValueMap Song::automatedValuesAt(const Track::tcoVector &tcos, MidiTime time)
{
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;
AutomatedValueMap Song::automatedValuesAt(MidiTime time, int tcoNum) const
{
return TrackContainer::automatedValuesFromTracks(TrackList(tracks()) << m_globalAutomationTrack, time, tcoNum);
}


Expand Down
87 changes: 85 additions & 2 deletions src/core/TrackContainer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 ),
Expand Down Expand Up @@ -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;
};



Expand Down
Loading

0 comments on commit 338c2ea

Please sign in to comment.