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