void AutomatableModel::setAutomatedValue( const float value ) { ++m_setValueDepth; const float oldValue = m_value; const float scaled_value = ( m_scaleType == Linear ) ? value : logToLinearScale( // fits value into [0,1]: (value - minValue<float>()) / maxValue<float>() ); m_value = fittedValue( scaled_value ); if( oldValue != m_value ) { // notify linked models for( AutoModelVector::Iterator it = m_linkedModels.begin(); it != m_linkedModels.end(); ++it ) { if( (*it)->m_setValueDepth < 1 && !(*it)->fittedValue( m_value ) != (*it)->m_value ) { // @TOBY: don't take m_value, but better: value, // otherwise, we convert to log twice? (*it)->setAutomatedValue( m_value ); } } emit dataChanged(); } --m_setValueDepth; }
float AutomatableModel::controllerValue( int frameOffset ) const { if( m_controllerConnection ) { float v = 0; switch(m_scaleType) { case Linear: v = minValue<float>() + ( range() * controllerConnection()->currentValue( frameOffset ) ); break; case Logarithmic: v = logToLinearScale( controllerConnection()->currentValue( frameOffset )); break; default: qFatal("AutomatableModel::controllerValue(int)" "lacks implementation for a scale type"); break; } if( typeInfo<float>::isEqual( m_step, 1 ) && m_hasStrictStepSize ) { return qRound( v ); } return v; } AutomatableModel* lm = m_linkedModels.first(); if( lm->controllerConnection() ) { return fittedValue( lm->controllerValue( frameOffset ) ); } return fittedValue( lm->m_value ); }
ValueBuffer * AutomatableModel::valueBuffer() { // if we've already calculated the valuebuffer this period, return the cached buffer if( m_lastUpdatedPeriod == s_periodCounter ) { return m_hasSampleExactData ? &m_valueBuffer : NULL; } QMutexLocker m( &m_valueBufferMutex ); if( m_lastUpdatedPeriod == s_periodCounter ) { return m_hasSampleExactData ? &m_valueBuffer : NULL; } float val = m_value; // make sure our m_value doesn't change midway ValueBuffer * vb; if( m_controllerConnection && m_controllerConnection->getController()->isSampleExact() ) { vb = m_controllerConnection->valueBuffer(); if( vb ) { float * values = vb->values(); float * nvalues = m_valueBuffer.values(); switch( m_scaleType ) { case Linear: for( int i = 0; i < m_valueBuffer.length(); i++ ) { nvalues[i] = minValue<float>() + ( range() * values[i] ); } break; case Logarithmic: for( int i = 0; i < m_valueBuffer.length(); i++ ) { nvalues[i] = logToLinearScale( values[i] ); } break; default: qFatal("AutomatableModel::valueBuffer() " "lacks implementation for a scale type"); break; } m_lastUpdatedPeriod = s_periodCounter; m_hasSampleExactData = true; return &m_valueBuffer; } } AutomatableModel* lm = NULL; if( m_hasLinkedModels ) { lm = m_linkedModels.first(); } if( lm && lm->controllerConnection() && lm->controllerConnection()->getController()->isSampleExact() ) { vb = lm->valueBuffer(); float * values = vb->values(); float * nvalues = m_valueBuffer.values(); for( int i = 0; i < vb->length(); i++ ) { nvalues[i] = fittedValue( values[i] ); } m_lastUpdatedPeriod = s_periodCounter; m_hasSampleExactData = true; return &m_valueBuffer; } if( m_oldValue != val ) { m_valueBuffer.interpolate( m_oldValue, val ); m_oldValue = val; m_lastUpdatedPeriod = s_periodCounter; m_hasSampleExactData = true; return &m_valueBuffer; } // if we have no sample-exact source for a ValueBuffer, return NULL to signify that no data is available at the moment // in which case the recipient knows to use the static value() instead m_lastUpdatedPeriod = s_periodCounter; m_hasSampleExactData = false; return NULL; }