void AutomatableModelViewSlots::execConnectionDialog() { // TODO[pg]: Display a dialog with list of controllers currently in the song // in addition to any system MIDI controllers AutomatableModel* m = m_amv->modelUntyped(); m->displayName(); ControllerConnectionDialog d( (QWidget*) engine::mainWindow(), m ); if( d.exec() == 1 ) { // Actually chose something if( d.chosenController() ) { // Update if( m->controllerConnection() ) { m->controllerConnection()->setController( d.chosenController() ); } // New else { ControllerConnection* cc = new ControllerConnection( d.chosenController() ); m->setControllerConnection( cc ); //cc->setTargetName( m->displayName() ); } } // no controller, so delete existing connection else { removeConnection(); } } }
void AutomatableModelViewSlots::removeConnection() { AutomatableModel* m = m_amv->modelUntyped(); if( m->controllerConnection() ) { delete m->controllerConnection(); m->setControllerConnection( NULL ); } }
bool Controller::hasModel( const Model * m ) { QObjectList chldren = children(); for( int i = 0; i < chldren.size(); ++i ) { QObject * c = chldren.at(i); AutomatableModel * am = qobject_cast<AutomatableModel*>(c); if( am != NULL ) { if( am == m ) { return true; } ControllerConnection * cc = am->controllerConnection(); if( cc != NULL ) { if( cc->getController()->hasModel( m ) ) { return true; } } } } return false; }
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 ); }
void AutomatableModelView::addDefaultActions( QMenu* menu ) { AutomatableModel* model = modelUntyped(); AutomatableModelViewSlots* amvSlots = new AutomatableModelViewSlots( this, menu ); menu->addAction( embed::getIconPixmap( "reload" ), AutomatableModel::tr( "&Reset (%1%2)" ). arg( model->displayValue( model->initValue<float>() ) ). arg( m_unit ), model, SLOT( reset() ) ); menu->addSeparator(); menu->addAction( embed::getIconPixmap( "edit_copy" ), AutomatableModel::tr( "&Copy value (%1%2)" ). arg( model->displayValue( model->value<float>() ) ). arg( m_unit ), model, SLOT( copyValue() ) ); menu->addAction( embed::getIconPixmap( "edit_paste" ), AutomatableModel::tr( "&Paste value (%1%2)"). arg( model->displayValue( AutomatableModel::copiedValue() ) ). arg( m_unit ), model, SLOT( pasteValue() ) ); menu->addSeparator(); menu->addAction( embed::getIconPixmap( "automation" ), AutomatableModel::tr( "Edit song-global automation" ), amvSlots, SLOT( editSongGlobalAutomation() ) ); menu->addAction( QPixmap(), AutomatableModel::tr( "Remove song-global automation" ), amvSlots, SLOT( removeSongGlobalAutomation() ) ); menu->addSeparator(); if( model->hasLinkedModels() ) { menu->addAction( embed::getIconPixmap( "edit-delete" ), AutomatableModel::tr( "Remove all linked controls" ), amvSlots, SLOT( unlinkAllModels() ) ); menu->addSeparator(); } QString controllerTxt; if( model->controllerConnection() ) { Controller* cont = model->controllerConnection()->getController(); if( cont ) { controllerTxt = AutomatableModel::tr( "Connected to %1" ).arg( cont->name() ); } else { controllerTxt = AutomatableModel::tr( "Connected to controller" ); } QMenu* contMenu = menu->addMenu( embed::getIconPixmap( "controller" ), controllerTxt ); contMenu->addAction( embed::getIconPixmap( "controller" ), AutomatableModel::tr("Edit connection..."), amvSlots, SLOT( execConnectionDialog() ) ); contMenu->addAction( embed::getIconPixmap( "cancel" ), AutomatableModel::tr("Remove connection"), amvSlots, SLOT( removeConnection() ) ); } else { menu->addAction( embed::getIconPixmap( "controller" ), AutomatableModel::tr("Connect to controller..."), amvSlots, SLOT( execConnectionDialog() ) ); } }
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; }