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

Reply via email to