Here is the patch applied to the stable 0.4 branch. The feature is the
same, but a bug is fixed where the value of the control could continue to
change after the last control point.
On Sat, Dec 7, 2013 at 8:21 PM, John Serafino <[email protected]> wrote:
> It works like a charm for me, despite my not having tried to compile
> master branch in months. As I suspected, it is super awesome. I'm not
> official by any means, but I'm pretty sure that once this sees the right
> eyes there will be no problem getting it integrated into the program.
>
>
> On Sat, Dec 7, 2013 at 10:27 AM, John Serafino <[email protected]> wrote:
>
>> I'll try it with the master branch and report back then. I personally
>> don't use the master branch though, so if this was patched against
>> stable-0.4, I would love to use it in my primary version of the program and
>> rave about it on my webshow.
>>
>> It's weird. I don't know what's up with the archive and your message.
>>
>>
>> On Sat, Dec 7, 2013 at 9:29 AM, Joel Muzzerall
>> <[email protected]>wrote:
>>
>>> Thanks.
>>>
>>> It's patched against the master git branch. I don't know if that is
>>> what is being developed on right now. I can try to put the changes on a
>>> different branch if there's another one that's being used for development.
>>>
>>> My last message doesn't appear correctly on the mailing list archive.
>>> Does anybody know why?
>>>
>>>
>>> On Sat, Dec 7, 2013 at 11:21 AM, John Serafino <[email protected]>wrote:
>>>
>>>> This looks awesome. Which version of LMMS is it patched against? Latest
>>>> GIT? Most recent stable release?
>>>>
>>>>
>>>> On Sat, Dec 7, 2013 at 9:04 AM, Joel Muzzerall <
>>>> [email protected]> wrote:
>>>>
>>>>> Hi guys.
>>>>>
>>>>> I am a fan of the software.
>>>>>
>>>>> I've been working on a new feature for the automation editor, this
>>>>> item from the roadmap:
>>>>>
>>>>> - add option for smooth lines and curves as opposed to sudden changes
>>>>>
>>>>> Right now it allows people to choose between the default handling of
>>>>> control points and a new mode which causes the value of the control to
>>>>> change linearly over time. Please let me know if I am on the right track
>>>>> here and if I have missed anything. If this is something that you guys
>>>>> think could be added to the program, I would also like to add a third
>>>>> option for curves.
>>>>>
>>>>> --
>>>>> Joel Muzzerall
>>>>>
>>>>>
>>>>> ------------------------------------------------------------------------------
>>>>> Sponsored by Intel(R) XDK
>>>>> Develop, test and display web and hybrid apps with a single code base.
>>>>> Download it for free now!
>>>>>
>>>>> http://pubads.g.doubleclick.net/gampad/clk?id=111408631&iu=/4140/ostg.clktrk
>>>>> _______________________________________________
>>>>> LMMS-devel mailing list
>>>>> [email protected]
>>>>> https://lists.sourceforge.net/lists/listinfo/lmms-devel
>>>>>
>>>>>
>>>>
>>>>
>>>> --
>>>> Johnny
>>>>
>>>
>>>
>>>
>>> --
>>> Joel Muzzerall
>>>
>>
>>
>>
>> --
>> Johnny
>>
>
>
>
> --
> Johnny
>
--
Joel Muzzerall
diff --git a/data/themes/default/progression_discrete.png b/data/themes/default/progression_discrete.png
new file mode 100644
index 0000000000000000000000000000000000000000..b28bb29c6c127f5550e7d57991f2b63ae4639cc4
GIT binary patch
literal 443
zcmV;s0Yv_ZP)<h;3K|Lk000e1NJLTq000;O000;W1^@s6;CDUv00006VoOIv0RI60
z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru-3uK6FdmYg5Rw1@0Z2(i
zK~zY`wUxh013?hRe}ikHASehqusAzkAf1i)2<Ma7-V<D#)+eyb*;ojQh}tNz$P>sF
z!lhCaN%WGn*gbNA+y&0tubG|wGqc}*v%5k8qds&_7X8O(D&c#Oq!2{Lk3(aF$h4){
zS%tCyxh;bXddqikbPRX5s{@p6AYU&4`jxuSRf892h>Am)WtddDVGAgL+0<Ell<$Gg
z=3JY$s(T9KA<m%U5cJet0s;7bs(skHYW%8?s6o$&?3BUh!~g2N4A+<T9_S3T29aiM
zuxlB--?(A0Gc0PL9o*(Ns3e8`14jv3_NmaBqY`Rc4MuUjGhT(xB-h~A5rZ|$;O*QE
zgS|~e;t+h#O@bsvlx;Xc5Y7LEQsf^y_ogbC03W~?kZZRNYysPLP6iwn-lC-e%kW|Y
ljDa89*8(<-sB{;n{{g^MzF!~uq>umr002ovPDHLkV1nqUy|DlQ
literal 0
HcmV?d00001
diff --git a/data/themes/default/progression_linear.png b/data/themes/default/progression_linear.png
new file mode 100644
index 0000000000000000000000000000000000000000..8059e793fd9e510aff19d71d7f93d413daefa1eb
GIT binary patch
literal 627
zcmV-(0*w8MP)<h;3K|Lk000e1NJLTq000;O000;W1^@s6;CDUv00006VoOIv0RI60
z0RN!9r;`8x010qNS#tmY3ljhU3ljkVnw%H_000McNliru-3uK6HYc0GKO6u60su)w
zK~zY`wbjo{R8bTM@Xys(CKO45LJM1@r0Z6-3IBu%!bl=$6ST0lLP$HeZd$Z%;m&a*
z5fl;CBE%LFN>LCl0^L*;rRnpwm^b5_#y2y9e&KQMIq&?s=iGa4ki+^cy;th_Hw&7g
zzmL^5N>dfSJW-*gsmeO!h0Rdpph}An7N_^l;PMDBU$k~mlt9%!K>X6wwi6FAj=%PS
zxkn`B33gIMm2i#phTyj7lwed8YyTD6WT}%t+%D8fBKI@?YG66?U?2V^{eA3gSD30%
zj*j76j-SNm$YTm^>S%zCrNY|3$IyTBKN!K=7A*)*X2g#21To$78;hx-J>=anH6K%h
z1$NyrH6Bx+YCHJ7&``icv?3U2()<s&DEOAidPH{xcSOAcPiKW>aeB80Ib6p;ixQm2
z9B$$sZs9~jo#5x|I$1|n`{6c^dz$sD0ng@z%01X31Y#rvV=)@e@r4v()LEocI-Tv{
z`}11R1S@Tnr!Dj><$F+R+_e^sZM;d%bh=1Z*El;^J2{hWIc_(=(dwv3!6*hDB)YOZ
z*2@wsA9R4;&1w&}4k7z&*aY}G<KtljIMXeJ@&x^Twc&T5SX~p6Y;h<kP3<1GLR24i
zuPUd)CVt=-wlbw7IF6H<&NeRPX3?Gwi|{UUu#tPAkK$N1kuKD${{tiq`&_lyq;LQL
N002ovPDHLkV1lmc7vKN@
literal 0
HcmV?d00001
diff --git a/include/AutomationEditor.h b/include/AutomationEditor.h
index 1a90f2a..a1ed7f1 100644
--- a/include/AutomationEditor.h
+++ b/include/AutomationEditor.h
@@ -95,6 +95,10 @@ protected:
static inline void drawValueRect( QPainter & _p, int _x, int _y,
int _width, int _height,
const bool _is_selected );
+ static inline void drawValueSlope( QPainter & _p, int _x1, int _y1,
+ int _x2, int _y2,
+ int grid_gottom,
+ const bool _is_selected );
void removeSelection();
void selectAll();
void getSelectedValues( timeMap & _selected_values );
@@ -113,6 +117,9 @@ protected slots:
void selectButtonToggled();
void moveButtonToggled();
+ void discreteButtonToggled();
+ void linearButtonToggled();
+
void copySelectedValues();
void cutSelectedValues();
void pasteValues();
@@ -176,6 +183,9 @@ private:
toolButton * m_selectButton;
toolButton * m_moveButton;
+ toolButton * m_discreteButton;
+ toolButton * m_linearButton;
+
toolButton * m_cutButton;
toolButton * m_copyButton;
toolButton * m_pasteButton;
diff --git a/include/AutomationPattern.h b/include/AutomationPattern.h
index 1d144d9..4ab388f 100644
--- a/include/AutomationPattern.h
+++ b/include/AutomationPattern.h
@@ -41,6 +41,12 @@ class EXPORT AutomationPattern : public trackContentObject
{
Q_OBJECT
public:
+ enum ProgressionTypes
+ {
+ DiscreteProgression,
+ LinearProgression
+ } ;
+
typedef QMap<int, float> timeMap;
typedef QVector<QPointer<AutomatableModel> > objectVector;
@@ -52,6 +58,13 @@ public:
const AutomatableModel * firstObject() const;
+ // progression-type stuff
+ inline ProgressionTypes progressionType() const
+ {
+ return m_progressionType;
+ }
+ void setProgressionType( ProgressionTypes _new_progression_type );
+
virtual midiTime length() const;
midiTime putValue( const midiTime & _time, const float _value,
@@ -116,6 +129,7 @@ private:
objectVector m_objects;
timeMap m_timeMap; // actual values
bool m_hasAutomation;
+ ProgressionTypes m_progressionType;
friend class AutomationPatternView;
diff --git a/src/core/AutomationPattern.cpp b/src/core/AutomationPattern.cpp
index e4cb69f..dec7eda 100644
--- a/src/core/AutomationPattern.cpp
+++ b/src/core/AutomationPattern.cpp
@@ -41,7 +41,8 @@
AutomationPattern::AutomationPattern( AutomationTrack * _auto_track ) :
trackContentObject( _auto_track ),
m_autoTrack( _auto_track ),
- m_objects()
+ m_objects(),
+ m_progressionType( DiscreteProgression )
{
changeLength( midiTime( 1, 0 ) );
}
@@ -52,7 +53,8 @@ AutomationPattern::AutomationPattern( AutomationTrack * _auto_track ) :
AutomationPattern::AutomationPattern( const AutomationPattern & _pat_to_copy ) :
trackContentObject( _pat_to_copy.m_autoTrack ),
m_autoTrack( _pat_to_copy.m_autoTrack ),
- m_objects( _pat_to_copy.m_objects )
+ m_objects( _pat_to_copy.m_objects ),
+ m_progressionType( _pat_to_copy.m_progressionType )
{
for( timeMap::const_iterator it = _pat_to_copy.m_timeMap.begin();
it != _pat_to_copy.m_timeMap.end(); ++it )
@@ -115,6 +117,20 @@ void AutomationPattern::addObject( AutomatableModel * _obj, bool _search_dup )
+void AutomationPattern::setProgressionType(
+ ProgressionTypes _new_progression_type )
+{
+ if ( _new_progression_type == DiscreteProgression ||
+ _new_progression_type == LinearProgression )
+ {
+ m_progressionType = _new_progression_type;
+ emit dataChanged();
+ }
+}
+
+
+
+
const AutomatableModel * AutomationPattern::firstObject() const
{
AutomatableModel * m;
@@ -213,8 +229,17 @@ float AutomationPattern::valueAt( const midiTime & _time ) const
{
return 0;
}
-
- return (v-1).value();
+ else if ( m_progressionType == DiscreteProgression ||
+ v == m_timeMap.end() )
+ {
+ return (v-1).value();
+ }
+ else
+ {
+ float slope = (v.value() - (v-1).value()) /
+ (v.key() - (v-1).key());
+ return (v-1).value() + (_time - (v-1).key()) * slope;
+ }
}
@@ -225,6 +250,7 @@ void AutomationPattern::saveSettings( QDomDocument & _doc, QDomElement & _this )
_this.setAttribute( "pos", startPosition() );
_this.setAttribute( "len", trackContentObject::length() );
_this.setAttribute( "name", name() );
+ _this.setAttribute( "prog", QString::number( progressionType() ) );
for( timeMap::const_iterator it = m_timeMap.begin();
it != m_timeMap.end(); ++it )
@@ -256,6 +282,8 @@ void AutomationPattern::loadSettings( const QDomElement & _this )
movePosition( _this.attribute( "pos" ).toInt() );
setName( _this.attribute( "name" ) );
+ setProgressionType( static_cast<ProgressionTypes>( _this.attribute(
+ "prog" ).toInt() ) );
for( QDomNode node = _this.firstChild(); !node.isNull();
node = node.nextSibling() )
diff --git a/src/gui/AutomationEditor.cpp b/src/gui/AutomationEditor.cpp
index d87b7bf..c08aeb0 100644
--- a/src/gui/AutomationEditor.cpp
+++ b/src/gui/AutomationEditor.cpp
@@ -238,6 +238,39 @@ AutomationEditor::AutomationEditor() :
"mode. You can also press 'Shift+M' on your keyboard "
"to activate this mode." ) );
+ m_discreteButton = new toolButton( embed::getIconPixmap(
+ "progression_discrete" ),
+ tr( "Discrete progression" ),
+ this, SLOT( discreteButtonToggled() ),
+ m_toolBar );
+ m_discreteButton->setCheckable( true );
+ m_discreteButton->setChecked( true );
+
+ m_linearButton = new toolButton( embed::getIconPixmap(
+ "progression_linear" ),
+ tr( "Linear progression" ),
+ this, SLOT( linearButtonToggled() ),
+ m_toolBar );
+ m_linearButton->setCheckable( true );
+
+ tool_button_group = new QButtonGroup( this );
+ tool_button_group->addButton( m_discreteButton );
+ tool_button_group->addButton( m_linearButton );
+ tool_button_group->setExclusive( true );
+
+ m_discreteButton->setWhatsThis(
+ tr( "Click here to choose discrete progressions for this "
+ "automation pattern. The value of the connected "
+ "object will remain constant between control points "
+ "and be set immediately to the new value when each "
+ "control point is reached." ) );
+ m_linearButton->setWhatsThis(
+ tr( "Click here to choose linear progressions for this "
+ "automation pattern. The value of the connected "
+ "object will change at a steady rate over time "
+ "between control points to reach the correct value at "
+ "each control point without a sudden change." ) );
+
m_cutButton = new toolButton( embed::getIconPixmap( "edit_cut" ),
tr( "Cut selected values (Ctrl+X)" ),
this, SLOT( cutSelectedValues() ),
@@ -332,6 +365,9 @@ AutomationEditor::AutomationEditor() :
tb_layout->addWidget( m_selectButton );
tb_layout->addWidget( m_moveButton );
tb_layout->addSpacing( 10 );
+ tb_layout->addWidget( m_discreteButton );
+ tb_layout->addWidget( m_linearButton );
+ tb_layout->addSpacing( 10 );
tb_layout->addWidget( m_cutButton );
tb_layout->addWidget( m_copyButton );
tb_layout->addWidget( m_pasteButton );
@@ -430,6 +466,20 @@ void AutomationEditor::updateAfterPatternChange()
return;
}
+ if( m_pattern->progressionType() ==
+ AutomationPattern::DiscreteProgression &&
+ !m_discreteButton->isChecked() )
+ {
+ m_discreteButton->setChecked( true );
+ }
+
+ if( m_pattern->progressionType() ==
+ AutomationPattern::LinearProgression &&
+ !m_linearButton->isChecked() )
+ {
+ m_linearButton->setChecked( true );
+ }
+
m_minLevel = m_pattern->firstObject()->minValue<float>();
m_maxLevel = m_pattern->firstObject()->maxValue<float>();
m_step = m_pattern->firstObject()->step<float>();
@@ -484,6 +534,34 @@ inline void AutomationEditor::drawValueRect( QPainter & _p,
+inline void AutomationEditor::drawValueSlope( QPainter & _p,
+ int _x1, int _y1,
+ int _x2, int _y2,
+ int grid_bottom,
+ const bool _is_selected )
+{
+ QPainterPath path;
+ path.moveTo( _x1, _y1 );
+ path.lineTo( _x2, _y2 );
+ path.lineTo( _x2, grid_bottom );
+ path.lineTo( _x1, grid_bottom );
+ path.closeSubpath();
+
+ QColor current_color( 0xFF, 0xB0, 0x00 );
+ if( _is_selected == TRUE )
+ {
+ current_color.setRgb( 0x00, 0x40, 0xC0 );
+ }
+
+ _p.fillPath( path, current_color );
+
+ _p.drawLine( _x1 - 1, _y1, _x1 + 1, _y1 );
+ _p.drawLine( _x1, _y1 - 1, _x1, _y1 + 1 );
+}
+
+
+
+
void AutomationEditor::removeSelection()
{
m_selectStartTick = 0;
@@ -1440,12 +1518,17 @@ void AutomationEditor::paintEvent( QPaintEvent * _pe )
break;
}
+ timeMap::iterator it_next = ( it+1 != time_map.end() ) ?
+ it+1 : it;
+
+ const float next_level = it_next.value();
+ Sint32 next_pos_ticks = it_next.key();
+
int rect_width;
+ int next_x = width();
if( it+1 != time_map.end() )
{
- timeMap::iterator it_prev = it+1;
- Sint32 next_pos_ticks = it_prev.key();
- int next_x = ( next_pos_ticks
+ next_x = ( next_pos_ticks
- m_currentPosition ) * m_ppt /
DefaultTicksPerTact;
// skip this value if not in visible area at all
@@ -1491,6 +1574,7 @@ void AutomationEditor::paintEvent( QPaintEvent * _pe )
// we've done and checked all, lets draw the
// value
int y_start;
+ int next_y;
int rect_height;
if( m_y_auto )
{
@@ -1498,6 +1582,10 @@ void AutomationEditor::paintEvent( QPaintEvent * _pe )
- ( grid_bottom - TOP_MARGIN )
* ( level - m_minLevel )
/ ( m_maxLevel - m_minLevel ) );
+ next_y = (int)( grid_bottom
+ - ( grid_bottom - TOP_MARGIN )
+ * ( next_level - m_minLevel )
+ / ( m_maxLevel - m_minLevel ) );
int y_end = (int)( grid_bottom
+ ( grid_bottom - TOP_MARGIN )
* m_minLevel
@@ -1506,14 +1594,29 @@ void AutomationEditor::paintEvent( QPaintEvent * _pe )
}
else
{
- y_start = (int)( grid_bottom - ( level
- - m_bottomLevel )
- * m_y_delta );
- rect_height = (int)( level * m_y_delta );
+ y_start = (int)( grid_bottom
+ - ( level - m_bottomLevel )
+ * m_y_delta );
+ next_y = (int)( grid_bottom
+ - ( next_level - m_bottomLevel )
+ * m_y_delta );
+ rect_height = (int)(
+ level * m_y_delta );
+ }
+ if( m_pattern->progressionType() ==
+ AutomationPattern::DiscreteProgression )
+ {
+ drawValueRect( p, x + VALUES_WIDTH,
+ y_start, rect_width,
+ rect_height, is_selected );
+ }
+ else
+ {
+ drawValueSlope( p, x + VALUES_WIDTH,
+ y_start, next_x + VALUES_WIDTH,
+ next_y, grid_bottom,
+ is_selected );
}
- drawValueRect( p, x + VALUES_WIDTH, y_start,
- rect_width, rect_height,
- is_selected );
}
else printf("not in range\n");
++it;
@@ -1864,6 +1967,36 @@ void AutomationEditor::moveButtonToggled()
+void AutomationEditor::discreteButtonToggled()
+{
+ if ( validPattern() )
+ {
+ QMutexLocker m( &m_patternMutex );
+ m_pattern->setProgressionType(
+ AutomationPattern::DiscreteProgression );
+ engine::getSong()->setModified();
+ update();
+ }
+}
+
+
+
+
+void AutomationEditor::linearButtonToggled()
+{
+ if ( validPattern() )
+ {
+ QMutexLocker m( &m_patternMutex );
+ m_pattern->setProgressionType(
+ AutomationPattern::LinearProgression );
+ engine::getSong()->setModified();
+ update();
+ }
+}
+
+
+
+
void AutomationEditor::selectAll()
{
QMutexLocker m( &m_patternMutex );
diff --git a/src/gui/AutomationPatternView.cpp b/src/gui/AutomationPatternView.cpp
index bc8db5c..632ea9b 100644
--- a/src/gui/AutomationPatternView.cpp
+++ b/src/gui/AutomationPatternView.cpp
@@ -257,8 +257,28 @@ void AutomationPatternView::paintEvent( QPaintEvent * )
{
x2 = (float)( width() - TCO_BORDER_WIDTH );
}
- p.fillRect( QRectF( x1, 0.0f, x2-x1, it.value() ),
+
+ if( m_pat->progressionType() ==
+ AutomationPattern::DiscreteProgression ||
+ it+1 == m_pat->getTimeMap().end() )
+ {
+ p.fillRect( QRectF( x1, 0.0f, x2-x1, it.value() ),
lin2grad );
+ }
+ else
+ {
+ AutomationPattern::timeMap::const_iterator it_next =
+ it+1;
+
+ QPainterPath path;
+ path.moveTo( x1, it.value() );
+ path.lineTo( x2, it_next.value() );
+ path.lineTo( x2, 0.0f );
+ path.lineTo( x1, 0.0f );
+ path.closeSubpath();
+
+ p.fillPath( path, lin2grad );
+ }
}
p.resetMatrix();
------------------------------------------------------------------------------
Sponsored by Intel(R) XDK
Develop, test and display web and hybrid apps with a single code base.
Download it for free now!
http://pubads.g.doubleclick.net/gampad/clk?id=111408631&iu=/4140/ostg.clktrk
_______________________________________________
LMMS-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/lmms-devel