1 /*
2  * AutomatableModel.cpp - some implementations of AutomatableModel-class
3  *
4  * Copyright (c) 2008-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
5  *
6  * This file is part of LMMS - https://lmms.io
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public
19  * License along with this program (see COPYING); if not, write to the
20  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA 02110-1301 USA.
22  *
23  */
24 
25 #include "AutomatableModel.h"
26 
27 #include "lmms_math.h"
28 
29 #include "AutomationPattern.h"
30 #include "ControllerConnection.h"
31 #include "LocaleHelper.h"
32 #include "Mixer.h"
33 #include "ProjectJournal.h"
34 
35 float AutomatableModel::s_copiedValue = 0;
36 long AutomatableModel::s_periodCounter = 0;
37 
38 
39 
AutomatableModel(DataType type,const float val,const float min,const float max,const float step,Model * parent,const QString & displayName,bool defaultConstructed)40 AutomatableModel::AutomatableModel( DataType type,
41 						const float val, const float min, const float max, const float step,
42 						Model* parent, const QString & displayName, bool defaultConstructed ) :
43 	Model( parent, displayName, defaultConstructed ),
44 	m_dataType( type ),
45 	m_scaleType( Linear ),
46 	m_minValue( min ),
47 	m_maxValue( max ),
48 	m_step( step ),
49 	m_range( max - min ),
50 	m_centerValue( m_minValue ),
51 	m_valueChanged( false ),
52 	m_setValueDepth( 0 ),
53 	m_hasStrictStepSize( false ),
54 	m_hasLinkedModels( false ),
55 	m_controllerConnection( NULL ),
56 	m_valueBuffer( static_cast<int>( Engine::mixer()->framesPerPeriod() ) ),
57 	m_lastUpdatedPeriod( -1 ),
58 	m_hasSampleExactData( false )
59 
60 {
61 	m_value = fittedValue( val );
62 	setInitValue( val );
63 }
64 
65 
66 
67 
~AutomatableModel()68 AutomatableModel::~AutomatableModel()
69 {
70 	while( m_linkedModels.empty() == false )
71 	{
72 		m_linkedModels.last()->unlinkModel( this );
73 		m_linkedModels.erase( m_linkedModels.end() - 1 );
74 	}
75 
76 	if( m_controllerConnection )
77 	{
78 		delete m_controllerConnection;
79 	}
80 
81 	m_valueBuffer.clear();
82 
83 	emit destroyed( id() );
84 }
85 
86 
87 
88 
isAutomated() const89 bool AutomatableModel::isAutomated() const
90 {
91 	return AutomationPattern::isAutomated( this );
92 }
93 
94 
saveSettings(QDomDocument & doc,QDomElement & element,const QString & name)95 void AutomatableModel::saveSettings( QDomDocument& doc, QDomElement& element, const QString& name )
96 {
97 	if( isAutomated() || m_scaleType != Linear )
98 	{
99 		// automation needs tuple of data (name, id, value)
100 		// scale type also needs an extra value
101 		// => it must be appended as a node
102 		QDomElement me = doc.createElement( name );
103 		me.setAttribute( "id", ProjectJournal::idToSave( id() ) );
104 		me.setAttribute( "value", m_value );
105 		me.setAttribute( "scale_type", m_scaleType == Logarithmic ? "log" : "linear" );
106 		element.appendChild( me );
107 	}
108 	else
109 	{
110 		// non automation, linear scale (default), can be saved as attribute
111 		element.setAttribute( name, m_value );
112 	}
113 
114 	if( m_controllerConnection && m_controllerConnection->getController()->type()
115 				!= Controller::DummyController )
116 	{
117 		QDomElement controllerElement;
118 
119 		// get "connection" element (and create it if needed)
120 		QDomNode node = element.namedItem( "connection" );
121 		if( node.isElement() )
122 		{
123 			controllerElement = node.toElement();
124 		}
125 		else
126 		{
127 			controllerElement = doc.createElement( "connection" );
128 			element.appendChild( controllerElement );
129 		}
130 
131 		QDomElement element = doc.createElement( name );
132 		m_controllerConnection->saveSettings( doc, element );
133 
134 		controllerElement.appendChild( element );
135 	}
136 }
137 
138 
139 
140 
loadSettings(const QDomElement & element,const QString & name)141 void AutomatableModel::loadSettings( const QDomElement& element, const QString& name )
142 {
143 	// compat code
144 	QDomNode node = element.namedItem( AutomationPattern::classNodeName() );
145 	if( node.isElement() )
146 	{
147 		node = node.namedItem( name );
148 		if( node.isElement() )
149 		{
150 			AutomationPattern * p = AutomationPattern::globalAutomationPattern( this );
151 			p->loadSettings( node.toElement() );
152 			setValue( p->valueAt( 0 ) );
153 			// in older projects we sometimes have odd automations
154 			// with just one value in - eliminate if necessary
155 			if( !p->hasAutomation() )
156 			{
157 				delete p;
158 			}
159 			return;
160 		}
161 		// logscales were not existing at this point of time
162 		// so they can be ignored
163 	}
164 
165 	QDomNode connectionNode = element.namedItem( "connection" );
166 	// reads controller connection
167 	if( connectionNode.isElement() )
168 	{
169 		QDomNode thisConnection = connectionNode.toElement().namedItem( name );
170 		if( thisConnection.isElement() )
171 		{
172 			setControllerConnection( new ControllerConnection( (Controller*)NULL ) );
173 			m_controllerConnection->loadSettings( thisConnection.toElement() );
174 			//m_controllerConnection->setTargetName( displayName() );
175 		}
176 	}
177 
178 	// models can be stored as elements (port00) or attributes (port10):
179 	// <ladspacontrols port10="4.41">
180 	//   <port00 value="4.41" id="4249278"/>
181 	// </ladspacontrols>
182 	// element => there is automation data, or scaletype information
183 	node = element.namedItem( name );
184 	if( node.isElement() )
185 	{
186 			changeID( node.toElement().attribute( "id" ).toInt() );
187 			setValue( LocaleHelper::toFloat( node.toElement().attribute( "value" ) ) );
188 			if( node.toElement().hasAttribute( "scale_type" ) )
189 			{
190 				if( node.toElement().attribute( "scale_type" ) == "linear" )
191 				{
192 					setScaleType( Linear );
193 				}
194 				else if( node.toElement().attribute( "scale_type" ) == "log" )
195 				{
196 					setScaleType( Logarithmic );
197 				}
198 			}
199 	}
200 	else
201 	{
202 
203 		setScaleType( Linear );
204 
205 		if( element.hasAttribute( name ) )
206 			// attribute => read the element's value from the attribute list
207 		{
208 			setInitValue( LocaleHelper::toFloat( element.attribute( name ) ) );
209 		}
210 		else
211 		{
212 			reset();
213 		}
214 	}
215 }
216 
217 
218 
219 
setValue(const float value)220 void AutomatableModel::setValue( const float value )
221 {
222 	m_oldValue = m_value;
223 	++m_setValueDepth;
224 	const float old_val = m_value;
225 
226 	m_value = fittedValue( value );
227 	if( old_val != m_value )
228 	{
229 		// add changes to history so user can undo it
230 		addJournalCheckPoint();
231 
232 		// notify linked models
233 		for( AutoModelVector::Iterator it = m_linkedModels.begin(); it != m_linkedModels.end(); ++it )
234 		{
235 			if( (*it)->m_setValueDepth < 1 && (*it)->fittedValue( value ) != (*it)->m_value )
236 			{
237 				bool journalling = (*it)->testAndSetJournalling( isJournalling() );
238 				(*it)->setValue( value );
239 				(*it)->setJournalling( journalling );
240 			}
241 		}
242 		m_valueChanged = true;
243 		emit dataChanged();
244 	}
245 	else
246 	{
247 		emit dataUnchanged();
248 	}
249 	--m_setValueDepth;
250 }
251 
252 
253 
254 
logToLinearScale(T value) const255 template<class T> T AutomatableModel::logToLinearScale( T value ) const
256 {
257 	return castValue<T>( ::logToLinearScale( minValue<float>(), maxValue<float>(), static_cast<float>( value ) ) );
258 }
259 
260 
scaledValue(float value) const261 float AutomatableModel::scaledValue( float value ) const
262 {
263 	return m_scaleType == Linear
264 		? value
265 		: logToLinearScale<float>( ( value - minValue<float>() ) / m_range );
266 }
267 
268 
inverseScaledValue(float value) const269 float AutomatableModel::inverseScaledValue( float value ) const
270 {
271 	return m_scaleType == Linear
272 		? value
273 		: ::linearToLogScale( minValue<float>(), maxValue<float>(), value );
274 }
275 
276 
277 
displayValue(const float val) const278 QString AutomatableModel::displayValue( const float val ) const
279 {
280 	switch( m_dataType )
281 	{
282 		case Float: return QString::number( castValue<float>( scaledValue( val ) ) );
283 		case Integer: return QString::number( castValue<int>( scaledValue( val ) ) );
284 		case Bool: return QString::number( castValue<bool>( scaledValue( val ) ) );
285 	}
286 	return "0";
287 }
288 
289 
290 
291 //! @todo: this should be moved into a maths header
292 template<class T>
roundAt(T & value,const T & where,const T & step_size)293 void roundAt( T& value, const T& where, const T& step_size )
294 {
295 	if( qAbs<float>( value - where )
296 		< typeInfo<float>::minEps() * qAbs<float>( step_size ) )
297 	{
298 		value = where;
299 	}
300 }
301 
302 
303 
304 
305 template<class T>
roundAt(T & value,const T & where) const306 void AutomatableModel::roundAt( T& value, const T& where ) const
307 {
308 	::roundAt(value, where, m_step);
309 }
310 
311 
312 
313 
setAutomatedValue(const float value)314 void AutomatableModel::setAutomatedValue( const float value )
315 {
316 	m_oldValue = m_value;
317 	++m_setValueDepth;
318 	const float oldValue = m_value;
319 
320 	const float scaled_value = scaledValue( value );
321 
322 	m_value = fittedValue( scaled_value );
323 
324 	if( oldValue != m_value )
325 	{
326 		// notify linked models
327 		for( AutoModelVector::Iterator it = m_linkedModels.begin();
328 									it != m_linkedModels.end(); ++it )
329 		{
330 			if( (*it)->m_setValueDepth < 1 &&
331 				(*it)->fittedValue( m_value ) != (*it)->m_value )
332 			{
333 				(*it)->setAutomatedValue( value );
334 			}
335 		}
336 		m_valueChanged = true;
337 		emit dataChanged();
338 	}
339 	--m_setValueDepth;
340 }
341 
342 
343 
344 
setRange(const float min,const float max,const float step)345 void AutomatableModel::setRange( const float min, const float max,
346 							const float step )
347 {
348 	if( ( m_maxValue != max ) || ( m_minValue != min ) )
349 	{
350 		m_minValue = min;
351 		m_maxValue = max;
352 		if( m_minValue > m_maxValue )
353 		{
354 			qSwap<float>( m_minValue, m_maxValue );
355 		}
356 		m_range = m_maxValue - m_minValue;
357 
358 		setStep( step );
359 
360 		// re-adjust value
361 		setValue( value<float>() );
362 
363 		emit propertiesChanged();
364 	}
365 }
366 
367 
368 
369 
setStep(const float step)370 void AutomatableModel::setStep( const float step )
371 {
372 	if( m_step != step )
373 	{
374 		m_step = step;
375 		emit propertiesChanged();
376 	}
377 }
378 
379 
380 
381 
fittedValue(float value) const382 float AutomatableModel::fittedValue( float value ) const
383 {
384 	value = tLimit<float>( value, m_minValue, m_maxValue );
385 
386 	if( m_step != 0 && m_hasStrictStepSize )
387 	{
388 		value = nearbyintf( value / m_step ) * m_step;
389 	}
390 
391 	roundAt( value, m_maxValue );
392 	roundAt( value, m_minValue );
393 	roundAt( value, 0.0f );
394 
395 	if( value < m_minValue )
396 	{
397 		return m_minValue;
398 	}
399 	else if( value > m_maxValue )
400 	{
401 		return m_maxValue;
402 	}
403 
404 	return value;
405 }
406 
407 
408 
409 
410 
linkModel(AutomatableModel * model)411 void AutomatableModel::linkModel( AutomatableModel* model )
412 {
413 	if( !m_linkedModels.contains( model ) && model != this )
414 	{
415 		m_linkedModels.push_back( model );
416 		m_hasLinkedModels = true;
417 
418 		if( !model->hasLinkedModels() )
419 		{
420 			QObject::connect( this, SIGNAL( dataChanged() ),
421 					model, SIGNAL( dataChanged() ), Qt::DirectConnection );
422 		}
423 	}
424 }
425 
426 
427 
428 
unlinkModel(AutomatableModel * model)429 void AutomatableModel::unlinkModel( AutomatableModel* model )
430 {
431 	AutoModelVector::Iterator it = qFind( m_linkedModels.begin(), m_linkedModels.end(), model );
432 	if( it != m_linkedModels.end() )
433 	{
434 		m_linkedModels.erase( it );
435 	}
436 	m_hasLinkedModels = !m_linkedModels.isEmpty();
437 }
438 
439 
440 
441 
442 
443 
linkModels(AutomatableModel * model1,AutomatableModel * model2)444 void AutomatableModel::linkModels( AutomatableModel* model1, AutomatableModel* model2 )
445 {
446 	if (!model1->m_linkedModels.contains( model2 ) && model1 != model2)
447 	{
448 		// copy data
449 		model1->m_value = model2->m_value;
450 		if (model1->valueBuffer() && model2->valueBuffer())
451 		{
452 			std::copy_n(model2->valueBuffer()->data(),
453 				model1->valueBuffer()->length(),
454 				model1->valueBuffer()->data());
455 		}
456 		// send dataChanged() before linking (because linking will
457 		// connect the two dataChanged() signals)
458 		emit model1->dataChanged();
459 		// finally: link the models
460 		model1->linkModel( model2 );
461 		model2->linkModel( model1 );
462 	}
463 }
464 
465 
466 
467 
unlinkModels(AutomatableModel * model1,AutomatableModel * model2)468 void AutomatableModel::unlinkModels( AutomatableModel* model1, AutomatableModel* model2 )
469 {
470 	model1->unlinkModel( model2 );
471 	model2->unlinkModel( model1 );
472 }
473 
474 
475 
476 
unlinkAllModels()477 void AutomatableModel::unlinkAllModels()
478 {
479 	for( AutomatableModel* model : m_linkedModels )
480 	{
481 		unlinkModels( this, model );
482 	}
483 
484 	m_hasLinkedModels = false;
485 }
486 
487 
488 
489 
setControllerConnection(ControllerConnection * c)490 void AutomatableModel::setControllerConnection( ControllerConnection* c )
491 {
492 	m_controllerConnection = c;
493 	if( c )
494 	{
495 		QObject::connect( m_controllerConnection, SIGNAL( valueChanged() ),
496 				this, SIGNAL( dataChanged() ), Qt::DirectConnection );
497 		QObject::connect( m_controllerConnection, SIGNAL( destroyed() ), this, SLOT( unlinkControllerConnection() ) );
498 		m_valueChanged = true;
499 		emit dataChanged();
500 	}
501 }
502 
503 
504 
505 
controllerValue(int frameOffset) const506 float AutomatableModel::controllerValue( int frameOffset ) const
507 {
508 	if( m_controllerConnection )
509 	{
510 		float v = 0;
511 		switch(m_scaleType)
512 		{
513 		case Linear:
514 			v = minValue<float>() + ( range() * controllerConnection()->currentValue( frameOffset ) );
515 			break;
516 		case Logarithmic:
517 			v = logToLinearScale(
518 				controllerConnection()->currentValue( frameOffset ));
519 			break;
520 		default:
521 			qFatal("AutomatableModel::controllerValue(int)"
522 				"lacks implementation for a scale type");
523 			break;
524 		}
525 		if( typeInfo<float>::isEqual( m_step, 1 ) && m_hasStrictStepSize )
526 		{
527 			return qRound( v );
528 		}
529 		return v;
530 	}
531 
532 	AutomatableModel* lm = m_linkedModels.first();
533 	if( lm->controllerConnection() )
534 	{
535 		return fittedValue( lm->controllerValue( frameOffset ) );
536 	}
537 
538 	return fittedValue( lm->m_value );
539 }
540 
541 
valueBuffer()542 ValueBuffer * AutomatableModel::valueBuffer()
543 {
544 	QMutexLocker m( &m_valueBufferMutex );
545 	// if we've already calculated the valuebuffer this period, return the cached buffer
546 	if( m_lastUpdatedPeriod == s_periodCounter )
547 	{
548 		return m_hasSampleExactData
549 			? &m_valueBuffer
550 			: NULL;
551 	}
552 
553 	float val = m_value; // make sure our m_value doesn't change midway
554 
555 	ValueBuffer * vb;
556 	if( m_controllerConnection && m_controllerConnection->getController()->isSampleExact() )
557 	{
558 		vb = m_controllerConnection->valueBuffer();
559 		if( vb )
560 		{
561 			float * values = vb->values();
562 			float * nvalues = m_valueBuffer.values();
563 			switch( m_scaleType )
564 			{
565 			case Linear:
566 				for( int i = 0; i < m_valueBuffer.length(); i++ )
567 				{
568 					nvalues[i] = minValue<float>() + ( range() * values[i] );
569 				}
570 				break;
571 			case Logarithmic:
572 				for( int i = 0; i < m_valueBuffer.length(); i++ )
573 				{
574 					nvalues[i] = logToLinearScale( values[i] );
575 				}
576 				break;
577 			default:
578 				qFatal("AutomatableModel::valueBuffer() "
579 					"lacks implementation for a scale type");
580 				break;
581 			}
582 			m_lastUpdatedPeriod = s_periodCounter;
583 			m_hasSampleExactData = true;
584 			return &m_valueBuffer;
585 		}
586 	}
587 	AutomatableModel* lm = NULL;
588 	if( m_hasLinkedModels )
589 	{
590 		lm = m_linkedModels.first();
591 	}
592 	if( lm && lm->controllerConnection() && lm->controllerConnection()->getController()->isSampleExact() )
593 	{
594 		vb = lm->valueBuffer();
595 		float * values = vb->values();
596 		float * nvalues = m_valueBuffer.values();
597 		for( int i = 0; i < vb->length(); i++ )
598 		{
599 			nvalues[i] = fittedValue( values[i] );
600 		}
601 		m_lastUpdatedPeriod = s_periodCounter;
602 		m_hasSampleExactData = true;
603 		return &m_valueBuffer;
604 	}
605 
606 	if( m_oldValue != val )
607 	{
608 		m_valueBuffer.interpolate( m_oldValue, val );
609 		m_oldValue = val;
610 		m_lastUpdatedPeriod = s_periodCounter;
611 		m_hasSampleExactData = true;
612 		return &m_valueBuffer;
613 	}
614 
615 	// if we have no sample-exact source for a ValueBuffer, return NULL to signify that no data is available at the moment
616 	// in which case the recipient knows to use the static value() instead
617 	m_lastUpdatedPeriod = s_periodCounter;
618 	m_hasSampleExactData = false;
619 	return NULL;
620 }
621 
622 
unlinkControllerConnection()623 void AutomatableModel::unlinkControllerConnection()
624 {
625 	if( m_controllerConnection )
626 	{
627 		m_controllerConnection->disconnect( this );
628 	}
629 
630 	m_controllerConnection = NULL;
631 }
632 
633 
634 
635 
setInitValue(const float value)636 void AutomatableModel::setInitValue( const float value )
637 {
638 	m_initValue = fittedValue( value );
639 	bool journalling = testAndSetJournalling( false );
640 	setValue( value );
641 	m_oldValue = m_value;
642 	setJournalling( journalling );
643 	emit initValueChanged( value );
644 }
645 
646 
647 
648 
reset()649 void AutomatableModel::reset()
650 {
651 	setValue( initValue<float>() );
652 }
653 
654 
655 
656 
copyValue()657 void AutomatableModel::copyValue()
658 {
659 	s_copiedValue = value<float>();
660 }
661 
662 
663 
664 
pasteValue()665 void AutomatableModel::pasteValue()
666 {
667 	setValue( copiedValue() );
668 }
669 
670 
671 
globalAutomationValueAt(const MidiTime & time)672 float AutomatableModel::globalAutomationValueAt( const MidiTime& time )
673 {
674 	// get patterns that connect to this model
675 	QVector<AutomationPattern *> patterns = AutomationPattern::patternsForModel( this );
676 	if( patterns.isEmpty() )
677 	{
678 		// if no such patterns exist, return current value
679 		return m_value;
680 	}
681 	else
682 	{
683 		// of those patterns:
684 		// find the patterns which overlap with the miditime position
685 		QVector<AutomationPattern *> patternsInRange;
686 		for( QVector<AutomationPattern *>::ConstIterator it = patterns.begin(); it != patterns.end(); it++ )
687 		{
688 			int s = ( *it )->startPosition();
689 			int e = ( *it )->endPosition();
690 			if( s <= time && e >= time ) { patternsInRange += ( *it ); }
691 		}
692 
693 		AutomationPattern * latestPattern = NULL;
694 
695 		if( ! patternsInRange.isEmpty() )
696 		{
697 			// if there are more than one overlapping patterns, just use the first one because
698 			// multiple pattern behaviour is undefined anyway
699 			latestPattern = patternsInRange[0];
700 		}
701 		else
702 		// if we find no patterns at the exact miditime, we need to search for the last pattern before time and use that
703 		{
704 			int latestPosition = 0;
705 
706 			for( QVector<AutomationPattern *>::ConstIterator it = patterns.begin(); it != patterns.end(); it++ )
707 			{
708 				int e = ( *it )->endPosition();
709 				if( e <= time && e > latestPosition )
710 				{
711 					latestPosition = e;
712 					latestPattern = ( *it );
713 				}
714 			}
715 		}
716 
717 		if( latestPattern )
718 		{
719 			// scale/fit the value appropriately and return it
720 			const float value = latestPattern->valueAt( time - latestPattern->startPosition() );
721 			const float scaled_value = scaledValue( value );
722 			return fittedValue( scaled_value );
723 		}
724 		// if we still find no pattern, the value at that time is undefined so
725 		// just return current value as the best we can do
726 		else return m_value;
727 	}
728 }
729 
getRoundedValue() const730 float FloatModel::getRoundedValue() const
731 {
732 	return qRound( value() / step<float>() ) * step<float>();
733 }
734 
735 
736 
737 
getDigitCount() const738 int FloatModel::getDigitCount() const
739 {
740 	float steptemp = step<float>();
741 	int digits = 0;
742 	while ( steptemp < 1 )
743 	{
744 		steptemp = steptemp * 10.0f;
745 		digits++;
746 	}
747 	return digits;
748 }
749 
750