Changes AutomationPattern to use nodes instead of raw float values (#5712)

This commit is contained in:
IanCaio
2021-02-28 06:48:15 -03:00
committed by GitHub
parent 05de59c085
commit e880e3cb2a
16 changed files with 1346 additions and 1282 deletions

View File

@@ -26,7 +26,6 @@
#ifndef AUTOMATION_EDITOR_H
#define AUTOMATION_EDITOR_H
#include <QtCore/QMutex>
#include <QVector>
#include <QWidget>
@@ -52,14 +51,15 @@ class TimeLineWidget;
class AutomationEditor : public QWidget, public JournallingObject
{
Q_OBJECT
Q_PROPERTY(QColor barLineColor READ barLineColor WRITE setBarLineColor)
Q_PROPERTY(QColor beatLineColor READ beatLineColor WRITE setBeatLineColor)
Q_PROPERTY(QColor lineColor READ lineColor WRITE setLineColor)
Q_PROPERTY(QColor vertexColor READ vertexColor WRITE setVertexColor)
Q_PROPERTY(QBrush scaleColor READ scaleColor WRITE setScaleColor)
Q_PROPERTY(QBrush graphColor READ graphColor WRITE setGraphColor)
Q_PROPERTY(QColor crossColor READ crossColor WRITE setCrossColor)
Q_PROPERTY(QColor backgroundShade READ backgroundShade WRITE setBackgroundShade)
Q_PROPERTY(QColor barLineColor MEMBER m_barLineColor)
Q_PROPERTY(QColor beatLineColor MEMBER m_beatLineColor)
Q_PROPERTY(QColor lineColor MEMBER m_lineColor)
Q_PROPERTY(QColor nodeInValueColor MEMBER m_nodeInValueColor)
Q_PROPERTY(QColor nodeOutValueColor MEMBER m_nodeOutValueColor)
Q_PROPERTY(QBrush scaleColor MEMBER m_scaleColor)
Q_PROPERTY(QBrush graphColor MEMBER m_graphColor)
Q_PROPERTY(QColor crossColor MEMBER m_crossColor)
Q_PROPERTY(QColor backgroundShade MEMBER m_backgroundShade)
public:
void setCurrentPattern(AutomationPattern * new_pattern);
@@ -80,30 +80,11 @@ public:
return "automationeditor";
}
// qproperty access methods
QColor barLineColor() const;
void setBarLineColor(const QColor & c);
QColor beatLineColor() const;
void setBeatLineColor(const QColor & c);
QColor lineColor() const;
void setLineColor(const QColor & c);
QBrush graphColor() const;
void setGraphColor(const QBrush & c);
QColor vertexColor() const;
void setVertexColor(const QColor & c);
QBrush scaleColor() const;
void setScaleColor(const QBrush & c);
QColor crossColor() const;
void setCrossColor(const QColor & c);
QColor backgroundShade() const;
void setBackgroundShade(const QColor & c);
enum EditModes
{
DRAW,
ERASE,
SELECT,
MOVE
DRAW_OUTVALUES
};
public slots:
@@ -126,13 +107,11 @@ protected:
float getLevel( int y );
int xCoordOfTick( int tick );
float yCoordOfLevel( float level );
inline void drawLevelTick( QPainter & p, int tick, float value);// bool is_selected ); //NEEDS Change in CSS
void removeSelection();
void selectAll();
void getSelectedValues(timeMap & selected_values );
inline void drawLevelTick(QPainter & p, int tick, float value);
timeMap::iterator getNodeAt(int x, int y, bool outValue = false, int r = 5);
void drawLine( int x0, float y0, int x1, float y1 );
void removePoints( int x0, int x1 );
protected slots:
void play();
@@ -148,11 +127,6 @@ protected slots:
void setProgressionType(int type);
void setTension();
void copySelectedValues();
void cutSelectedValues();
void pasteValues();
void deleteSelectedValues();
void updatePosition( const TimePos & t );
void zoomingXChanged();
@@ -167,8 +141,10 @@ private:
{
NONE,
MOVE_VALUE,
SELECT_VALUES,
MOVE_SELECTION
ERASE_VALUES,
MOVE_OUTVALUE,
RESET_OUTVALUES,
DRAW_LINE
} ;
// some constants...
@@ -187,7 +163,7 @@ private:
static QPixmap * s_toolDraw;
static QPixmap * s_toolErase;
static QPixmap * s_toolSelect;
static QPixmap * s_toolDrawOut;
static QPixmap * s_toolMove;
static QPixmap * s_toolYFlip;
static QPixmap * s_toolXFlip;
@@ -200,7 +176,6 @@ private:
FloatModel * m_tensionModel;
QMutex m_patternMutex;
AutomationPattern * m_pattern;
float m_minLevel;
float m_maxLevel;
@@ -219,13 +194,6 @@ private:
Actions m_action;
tick_t m_selectStartTick;
tick_t m_selectedTick;
float m_selectStartLevel;
float m_selectedLevels;
float m_moveStartLevel;
tick_t m_moveStartTick;
int m_moveXOffset;
float m_drawLastLevel;
@@ -235,9 +203,8 @@ private:
int m_y_delta;
bool m_y_auto;
timeMap m_valuesToCopy;
timeMap m_selValuesForMove;
// Time position (key) of automation node whose outValue is being dragged
int m_draggedOutValueKey;
EditModes m_editMode;
@@ -255,7 +222,8 @@ private:
QColor m_beatLineColor;
QColor m_lineColor;
QBrush m_graphColor;
QColor m_vertexColor;
QColor m_nodeInValueColor;
QColor m_nodeOutValueColor;
QBrush m_scaleColor;
QColor m_crossColor;
QColor m_backgroundShade;

153
include/AutomationNode.h Normal file
View File

@@ -0,0 +1,153 @@
/*
* AutomationNode.h - Declaration of class AutomationNode, which contains
* all information about an automation node
*
* Copyright (c) 2020 Ian Caio <iancaio_dev/at/hotmail.com>
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#ifndef AUTOMATION_NODE_H
#define AUTOMATION_NODE_H
// MACROs to help handling automation nodes
#define INVAL(x) ((x).value().getInValue())
#define OUTVAL(x) ((x).value().getOutValue())
#define OFFSET(x) ((x).value().getValueOffset())
#define INTAN(x) ((x).value().getInTangent())
#define OUTTAN(x) ((x).value().getOutTangent())
#define POS(x) ((x).key())
class AutomationPattern;
// Note: We use the default copy-assignment on the AutomationPattern constructor. It's
// fine for now as we don't have dynamic allocated members, but if any are added we should
// have an user-defined one to perform a deep-copy.
class AutomationNode
{
public:
AutomationNode(); // Dummy constructor for the QMap
AutomationNode(AutomationPattern* pat, float value, int pos);
AutomationNode(AutomationPattern* pat, float inValue, float outValue, int pos);
AutomationNode& operator+=(float f)
{
m_inValue += f;
m_outValue += f;
return *this;
}
AutomationNode& operator-=(float f)
{
m_inValue -= f;
m_outValue -= f;
return *this;
}
AutomationNode& operator*=(float f)
{
m_inValue *= f;
m_outValue *= f;
return *this;
}
AutomationNode& operator/=(float f)
{
m_inValue /= f;
m_outValue /= f;
return *this;
}
inline const float getInValue() const
{
return m_inValue;
}
void setInValue(float value);
inline const float getOutValue() const
{
return m_outValue;
}
void setOutValue(float value);
void resetOutValue();
/**
* @brief Gets the offset between inValue and outValue
* @return Float representing the offset between inValue and outValue
*/
inline const float getValueOffset() const
{
return m_outValue - m_inValue;
}
/**
* @brief Gets the tangent of the left side of the node
* @return Float with the tangent from the inValue side
*/
inline const float getInTangent() const
{
return m_inTangent;
}
/**
* @brief Sets the tangent of the left side of the node
* @param Float with the tangent for the inValue side
*/
inline void setInTangent(float tangent)
{
m_inTangent = tangent;
}
/**
* @brief Gets the tangent of the right side of the node
* @return Float with the tangent from the outValue side
*/
inline const float getOutTangent() const
{
return m_outTangent;
}
/**
* @brief Sets the tangent of the right side of the node
* @param Float with the tangent for the outValue side
*/
inline void setOutTangent(float tangent)
{
m_outTangent = tangent;
}
private:
// Pattern that this node belongs to
AutomationPattern* m_pattern;
// Time position of this node (matches the timeMap key)
int m_pos;
// Values of this node
float m_inValue;
float m_outValue;
// Slope at each point for calculating spline
// We might have discrete jumps between curves, so we possibly have
// two different tangents for each side of the curve. If inValue and
// outValue are equal, inTangent and outTangent are equal too.
float m_inTangent;
float m_outTangent;
};
#endif

View File

@@ -30,6 +30,7 @@
#include <QtCore/QMap>
#include <QtCore/QPointer>
#include "AutomationNode.h"
#include "TrackContentObject.h"
@@ -49,8 +50,8 @@ public:
CubicHermiteProgression
} ;
typedef QMap<int, float> timeMap;
typedef QVector<QPointer<AutomatableModel> > objectVector;
typedef QMap<int, AutomationNode> timeMap;
typedef QVector<QPointer<AutomatableModel>> objectVector;
AutomationPattern( AutomationTrack * _auto_track );
AutomationPattern( const AutomationPattern & _pat_to_copy );
@@ -77,12 +78,25 @@ public:
TimePos timeMapLength() const;
void updateLength();
TimePos putValue( const TimePos & time,
const float value,
const bool quantPos = true,
const bool ignoreSurroundingPoints = true );
TimePos putValue(
const TimePos & time,
const float value,
const bool quantPos = true,
const bool ignoreSurroundingPoints = true
);
void removeValue( const TimePos & time );
TimePos putValues(
const TimePos & time,
const float inValue,
const float outValue,
const bool quantPos = true,
const bool ignoreSurroundingPoints = true
);
void removeNode(const TimePos & time);
void removeNodes(const int tick0, const int tick1);
void resetNodes(const int tick0, const int tick1);
void recordValue(TimePos time, float value);
@@ -109,16 +123,6 @@ public:
return m_timeMap;
}
inline const timeMap & getTangents() const
{
return m_tangents;
}
inline timeMap & getTangents()
{
return m_tangents;
}
inline float getMin() const
{
return firstObject()->minValue<float>();
@@ -170,21 +174,26 @@ public slots:
private:
void cleanObjects();
void generateTangents();
void generateTangents( timeMap::const_iterator it, int numToGenerate );
void generateTangents(timeMap::iterator it, int numToGenerate);
float valueAt( timeMap::const_iterator v, int offset ) const;
// Mutex to make methods involving automation patterns thread safe
// Mutable so we can lock it from const objects
mutable QMutex m_patternMutex;
AutomationTrack * m_autoTrack;
QVector<jo_id_t> m_idsToResolve;
objectVector m_objects;
timeMap m_timeMap; // actual values
timeMap m_oldTimeMap; // old values for storing the values before setDragValue() is called.
timeMap m_tangents; // slope at each point for calculating spline
float m_tension;
bool m_hasAutomation;
ProgressionTypes m_progressionType;
bool m_dragging;
bool m_dragKeepOutValue; // Should we keep the current dragged node's outValue?
float m_dragOutValue; // The outValue of the dragged node's
bool m_isRecording;
float m_lastRecordedValue;
@@ -194,6 +203,7 @@ private:
static const float DEFAULT_MAX_VALUE;
friend class AutomationPatternView;
friend class AutomationNode;
} ;

View File

@@ -115,6 +115,7 @@ private:
void upgrade_1_2_0_rc3();
void upgrade_1_3_0();
void upgrade_noHiddenClipNames();
void upgrade_automationNodes();
// List of all upgrade methods
static const std::vector<UpgradeMethod> UPGRADE_METHODS;

View File

@@ -25,6 +25,7 @@
#ifndef INLINE_AUTOMATION_H
#define INLINE_AUTOMATION_H
#include "AutomationNode.h"
#include "AutomationPattern.h"
#include "shared_object.h"
@@ -53,12 +54,17 @@ public:
{
if( m_autoPattern != NULL && m_autoPattern->getTimeMap().isEmpty() == false )
{
// prevent saving inline automation if there's just one value which equals value
// of model which is going to be saved anyways
if( isAtInitValue() &&
m_autoPattern->getTimeMap().size() == 1 &&
m_autoPattern->getTimeMap().keys().first() == 0 &&
m_autoPattern->getTimeMap().values().first() == value() )
// Prevent saving inline automation if there's just one node at the beginning of
// the pattern, which has a InValue equal to the value of model (which is going
// to be saved anyways) and no offset between the InValue and OutValue
AutomationPattern::timeMap::const_iterator firstNode =
m_autoPattern->getTimeMap().begin();
if (isAtInitValue()
&& m_autoPattern->getTimeMap().size() == 1
&& POS(firstNode) == 0
&& INVAL(firstNode) == value()
&& OFFSET(firstNode) == 0)
{
return false;
}