1 /*
2  * AutomatableModel.h - declaration of class AutomatableModel
3  *
4  * Copyright (c) 2007-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 #ifndef AUTOMATABLE_MODEL_H
26 #define AUTOMATABLE_MODEL_H
27 
28 #include <QtCore/QMap>
29 #include <QtCore/QMutex>
30 
31 #include "JournallingObject.h"
32 #include "Model.h"
33 #include "MidiTime.h"
34 #include "ValueBuffer.h"
35 #include "MemoryManager.h"
36 
37 // simple way to map a property of a view to a model
38 #define mapPropertyFromModelPtr(type,getfunc,setfunc,modelname)	\
39 		public:													\
40 			type getfunc() const								\
41 			{													\
42 				return (type) modelname->value();				\
43 			}													\
44 		public slots:											\
45 			void setfunc( const type val )						\
46 			{													\
47 				modelname->setValue( val );						\
48 			}
49 
50 #define mapPropertyFromModel(type,getfunc,setfunc,modelname)	\
51 		public:													\
52 			type getfunc() const								\
53 			{													\
54 				return (type) modelname.value();				\
55 			}													\
56 		public slots:											\
57 			void setfunc( const type val )						\
58 			{													\
59 				modelname.setValue( (float) val );				\
60 			}
61 
62 
63 
64 class ControllerConnection;
65 
66 class EXPORT AutomatableModel : public Model, public JournallingObject
67 {
68 	Q_OBJECT
69 	MM_OPERATORS
70 public:
71 	typedef QVector<AutomatableModel *> AutoModelVector;
72 
73 	enum ScaleType
74 	{
75 		Linear,
76 		Logarithmic,
77 		Decibel
78 	};
79 
80 	enum DataType
81 	{
82 		Float,
83 		Integer,
84 		Bool
85 	} ;
86 
87 	AutomatableModel( DataType type,
88 						const float val = 0,
89 						const float min = 0,
90 						const float max = 0,
91 						const float step = 0,
92 						Model* parent = NULL,
93 						const QString& displayName = QString(),
94 						bool defaultConstructed = false );
95 
96 	virtual ~AutomatableModel();
97 
98 
copiedValue()99 	static float copiedValue()
100 	{
101 		return s_copiedValue;
102 	}
103 
104 	bool isAutomated() const;
isAutomatedOrControlled()105 	bool isAutomatedOrControlled() const
106 	{
107 		return isAutomated() || m_controllerConnection != NULL;
108 	}
109 
controllerConnection()110 	ControllerConnection* controllerConnection() const
111 	{
112 		return m_controllerConnection;
113 	}
114 
115 
116 	void setControllerConnection( ControllerConnection* c );
117 
118 
119 	template<class T>
castValue(const float v)120 	static T castValue( const float v )
121 	{
122 		return (T)( v );
123 	}
124 
125 	template<bool>
castValue(const float v)126 	static bool castValue( const float v )
127 	{
128 		return ( qRound( v ) != 0 );
129 	}
130 
131 
132 	template<class T>
133 	inline T value( int frameOffset = 0 ) const
134 	{
135 		if( unlikely( m_hasLinkedModels || m_controllerConnection != NULL ) )
136 		{
137 			return castValue<T>( controllerValue( frameOffset ) );
138 		}
139 
140 		return castValue<T>( m_value );
141 	}
142 
143 	float controllerValue( int frameOffset ) const;
144 
145 	//! @brief Function that returns sample-exact data as a ValueBuffer
146 	//! @return pointer to model's valueBuffer when s.ex.data exists, NULL otherwise
147 	ValueBuffer * valueBuffer();
148 
149 	template<class T>
initValue()150 	T initValue() const
151 	{
152 		return castValue<T>( m_initValue );
153 	}
154 
isAtInitValue()155 	bool isAtInitValue() const
156 	{
157 		return m_value == m_initValue;
158 	}
159 
160 	template<class T>
minValue()161 	T minValue() const
162 	{
163 		return castValue<T>( m_minValue );
164 	}
165 
166 	template<class T>
maxValue()167 	T maxValue() const
168 	{
169 		return castValue<T>( m_maxValue );
170 	}
171 
172 	template<class T>
step()173 	T step() const
174 	{
175 		return castValue<T>( m_step );
176 	}
177 
178 	//! @brief Returns value scaled with the scale type and min/max values of this model
179 	float scaledValue( float value ) const;
180 	//! @brief Returns value applied with the inverse of this model's scale type
181 	float inverseScaledValue( float value ) const;
182 
183 	void setInitValue( const float value );
184 
185 	void setAutomatedValue( const float value );
186 	void setValue( const float value );
187 
incValue(int steps)188 	void incValue( int steps )
189 	{
190 		setValue( m_value + steps * m_step );
191 	}
192 
range()193 	float range() const
194 	{
195 		return m_range;
196 	}
197 
198 	void setRange( const float min, const float max, const float step = 1 );
setScaleType(ScaleType sc)199 	void setScaleType( ScaleType sc ) {
200 		m_scaleType = sc;
201 	}
202 	void setScaleLogarithmic( bool setToTrue = true )
203 	{
204 		setScaleType( setToTrue ? Logarithmic : Linear );
205 	}
isScaleLogarithmic()206 	bool isScaleLogarithmic() const
207 	{
208 		return m_scaleType == Logarithmic;
209 	}
210 
211 	void setStep( const float step );
212 
centerValue()213 	float centerValue() const
214 	{
215 		return m_centerValue;
216 	}
217 
setCenterValue(const float centerVal)218 	void setCenterValue( const float centerVal )
219 	{
220 		m_centerValue = centerVal;
221 	}
222 
223 	//! link @p m1 and @p m2, let @p m1 take the values of @p m2
224 	static void linkModels( AutomatableModel* m1, AutomatableModel* m2 );
225 	static void unlinkModels( AutomatableModel* m1, AutomatableModel* m2 );
226 
227 	void unlinkAllModels();
228 
229 	/**
230 	 * @brief Saves settings (value, automation links and controller connections) of AutomatableModel into
231 	 *  specified DOM element using <name> as attribute/node name
232 	 * @param doc TODO
233 	 * @param element Where this option shall be saved.
234 	 *  Depending on the model, this can be done in an attribute or in a subnode.
235 	 * @param name Name to store this model as.
236 	 */
237 	virtual void saveSettings( QDomDocument& doc, QDomElement& element, const QString& name );
238 
239 	/*! \brief Loads settings (value, automation links and controller connections) of AutomatableModel from
240 				specified DOM element using <name> as attribute/node name */
241 	virtual void loadSettings( const QDomElement& element, const QString& name );
242 
nodeName()243 	virtual QString nodeName() const
244 	{
245 		return "automatablemodel";
246 	}
247 
248 	QString displayValue( const float val ) const;
249 
hasLinkedModels()250 	bool hasLinkedModels() const
251 	{
252 		return m_hasLinkedModels;
253 	}
254 
255 	// a way to track changed values in the model and avoid using signals/slots - useful for speed-critical code.
256 	// note that this method should only be called once per period since it resets the state of the variable - so if your model
257 	// has to be accessed by more than one object, then this function shouldn't be used.
isValueChanged()258 	bool isValueChanged()
259 	{
260 		if( m_valueChanged || valueBuffer() )
261 		{
262 			m_valueChanged = false;
263 			return true;
264 		}
265 		return false;
266 	}
267 
268 	float globalAutomationValueAt( const MidiTime& time );
269 
hasStrictStepSize()270 	bool hasStrictStepSize() const
271 	{
272 		return m_hasStrictStepSize;
273 	}
274 
setStrictStepSize(const bool b)275 	void setStrictStepSize( const bool b )
276 	{
277 		m_hasStrictStepSize = b;
278 	}
279 
incrementPeriodCounter()280 	static void incrementPeriodCounter()
281 	{
282 		++s_periodCounter;
283 	}
284 
resetPeriodCounter()285 	static void resetPeriodCounter()
286 	{
287 		s_periodCounter = 0;
288 	}
289 
290 public slots:
291 	virtual void reset();
292 	virtual void copyValue();
293 	virtual void pasteValue();
294 	void unlinkControllerConnection();
295 
296 
297 protected:
298 	//! returns a value which is in range between min() and
299 	//! max() and aligned according to the step size (step size 0.05 -> value
300 	//! 0.12345 becomes 0.10 etc.). You should always call it at the end after
301 	//! doing your own calculations.
302 	float fittedValue( float value ) const;
303 
304 
305 private:
saveSettings(QDomDocument & doc,QDomElement & element)306 	virtual void saveSettings( QDomDocument& doc, QDomElement& element )
307 	{
308 		saveSettings( doc, element, "value" );
309 	}
310 
loadSettings(const QDomElement & element)311 	virtual void loadSettings( const QDomElement& element )
312 	{
313 		loadSettings( element, "value" );
314 	}
315 
316 	void linkModel( AutomatableModel* model );
317 	void unlinkModel( AutomatableModel* model );
318 
319 	//! @brief Scales @value from linear to logarithmic.
320 	//! Value should be within [0,1]
321 	template<class T> T logToLinearScale( T value ) const;
322 
323 	//! rounds @a value to @a where if it is close to it
324 	//! @param value will be modified to rounded value
325 	template<class T> void roundAt( T &value, const T &where ) const;
326 
327 
328 	DataType m_dataType;
329 	ScaleType m_scaleType; //!< scale type, linear by default
330 	float m_value;
331 	float m_initValue;
332 	float m_minValue;
333 	float m_maxValue;
334 	float m_step;
335 	float m_range;
336 	float m_centerValue;
337 
338 	bool m_valueChanged;
339 
340 	// currently unused?
341 	float m_oldValue;
342 	int m_setValueDepth;
343 
344 	// used to determine if step size should be applied strictly (ie. always)
345 	// or only when value set from gui (default)
346 	bool m_hasStrictStepSize;
347 
348 	AutoModelVector m_linkedModels;
349 	bool m_hasLinkedModels;
350 
351 
352 	//! NULL if not appended to controller, otherwise connection info
353 	ControllerConnection* m_controllerConnection;
354 
355 
356 	static float s_copiedValue;
357 
358 	ValueBuffer m_valueBuffer;
359 	long m_lastUpdatedPeriod;
360 	static long s_periodCounter;
361 
362 	bool m_hasSampleExactData;
363 
364 	// prevent several threads from attempting to write the same vb at the same time
365 	QMutex m_valueBufferMutex;
366 
367 signals:
368 	void initValueChanged( float val );
369 	void destroyed( jo_id_t id );
370 
371 } ;
372 
373 
374 
375 
376 
377 #define defaultTypedMethods(type)								\
378 	type value( int frameOffset = 0 ) const						\
379 	{															\
380 		return AutomatableModel::value<type>( frameOffset );	\
381 	}															\
382 																\
383 	type initValue() const										\
384 	{															\
385 		return AutomatableModel::initValue<type>();				\
386 	}															\
387 																\
388 	type minValue() const										\
389 	{															\
390 		return AutomatableModel::minValue<type>();				\
391 	}															\
392 																\
393 	type maxValue() const										\
394 	{															\
395 		return AutomatableModel::maxValue<type>();				\
396 	}															\
397 
398 
399 // some typed AutomatableModel-definitions
400 
401 class FloatModel : public AutomatableModel
402 {
403 public:
404 	FloatModel( float val = 0, float min = 0, float max = 0, float step = 0,
405 				Model * parent = NULL,
406 				const QString& displayName = QString(),
407 				bool defaultConstructed = false ) :
AutomatableModel(Float,val,min,max,step,parent,displayName,defaultConstructed)408 		AutomatableModel( Float, val, min, max, step, parent, displayName, defaultConstructed )
409 	{
410 	}
411 	float getRoundedValue() const;
412 	int getDigitCount() const;
413 	defaultTypedMethods(float);
414 
415 } ;
416 
417 
418 class IntModel : public AutomatableModel
419 {
420 public:
421 	IntModel( int val = 0, int min = 0, int max = 0,
422 				Model* parent = NULL,
423 				const QString& displayName = QString(),
424 				bool defaultConstructed = false ) :
425 		AutomatableModel( Integer, val, min, max, 1, parent, displayName, defaultConstructed )
426 	{
427 	}
428 
429 	defaultTypedMethods(int);
430 
431 } ;
432 
433 
434 class BoolModel : public AutomatableModel
435 {
436 public:
437 	BoolModel( const bool val = false,
438 				Model* parent = NULL,
439 				const QString& displayName = QString(),
440 				bool defaultConstructed = false ) :
441 		AutomatableModel( Bool, val, false, true, 1, parent, displayName, defaultConstructed )
442 	{
443 	}
444 
445 	defaultTypedMethods(bool);
446 
447 } ;
448 
449 typedef QMap<AutomatableModel*, float> AutomatedValueMap;
450 
451 #endif
452 
453