Changes AutomationPattern to use nodes instead of raw float values (#5712)
This commit is contained in:
@@ -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
153
include/AutomationNode.h
Normal 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
|
||||
@@ -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;
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user