/* * LadspaControl.cpp - model for controlling a LADSPA port * * Copyright (c) 2008-2014 Tobias Doerffel * Copyright (c) 2006-2008 Danny McRae * * This file is part of LMMS - https://lmms.io * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program (see COPYING); if not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA. * */ #include #include "LadspaControl.h" #include "LadspaBase.h" LadspaControl::LadspaControl( Model * _parent, port_desc_t * _port, bool _link ) : Model( _parent ), m_link( _link ), m_port( _port ), m_linkEnabledModel( _link, this, tr( "Link channels" ) ), m_toggledModel( false, this, m_port->name ), m_knobModel( 0, 0, 0, 1, this, m_port->name ), m_tempoSyncKnobModel( 0, 0, 0, 1, m_port->max, this, m_port->name ) { if( m_link ) { connect( &m_linkEnabledModel, SIGNAL( dataChanged() ), this, SLOT( linkStateChanged() ), Qt::DirectConnection ); } switch( m_port->data_type ) { case TOGGLED: m_toggledModel.setInitValue( static_cast( m_port->def ) ); connect( &m_toggledModel, SIGNAL( dataChanged() ), this, SLOT( ledChanged() ) ); if( m_port->def == 1.0f ) { m_toggledModel.setValue( true ); } // TODO: careful: we must prevent saved scales m_toggledModel.setScaleLogarithmic( m_port->suggests_logscale ); break; case INTEGER: case ENUM: m_knobModel.setRange( static_cast( m_port->max ), static_cast( m_port->min ), 1 + static_cast( m_port->max - m_port->min ) / 400 ); m_knobModel.setInitValue( static_cast( m_port->def ) ); connect( &m_knobModel, SIGNAL( dataChanged() ), this, SLOT( knobChanged() ) ); // TODO: careful: we must prevent saved scales m_knobModel.setScaleLogarithmic( m_port->suggests_logscale ); break; case FLOATING: m_knobModel.setRange( m_port->min, m_port->max, ( m_port->max - m_port->min ) / ( m_port->name.toUpper() == "GAIN" && m_port->max == 10.0f ? 4000.0f : ( m_port->suggests_logscale ? 8000.0f : 800.0f ) ) ); m_knobModel.setInitValue( m_port->def ); connect( &m_knobModel, SIGNAL( dataChanged() ), this, SLOT( knobChanged() ) ); // TODO: careful: we must prevent saved scales m_knobModel.setScaleLogarithmic( m_port->suggests_logscale ); break; case TIME: m_tempoSyncKnobModel.setRange( m_port->min, m_port->max, ( m_port->max - m_port->min ) / 800.0f ); m_tempoSyncKnobModel.setInitValue( m_port->def ); connect( &m_tempoSyncKnobModel, SIGNAL( dataChanged() ), this, SLOT( tempoKnobChanged() ) ); // TODO: careful: we must prevent saved scales m_tempoSyncKnobModel.setScaleLogarithmic( m_port->suggests_logscale ); break; default: break; } } LadspaControl::~LadspaControl() { } LADSPA_Data LadspaControl::value() { switch( m_port->data_type ) { case TOGGLED: return static_cast( m_toggledModel.value() ); case INTEGER: case ENUM: case FLOATING: return static_cast( m_knobModel.value() ); case TIME: return static_cast( m_tempoSyncKnobModel.value() ); default: qWarning( "LadspaControl::value(): BAD BAD BAD\n" ); break; } return 0; } ValueBuffer * LadspaControl::valueBuffer() { switch( m_port->data_type ) { case TOGGLED: case INTEGER: case ENUM: return NULL; case FLOATING: return m_knobModel.valueBuffer(); case TIME: return m_tempoSyncKnobModel.valueBuffer(); default: qWarning( "LadspaControl::valueBuffer(): BAD BAD BAD\n" ); break; } return NULL; } void LadspaControl::setValue( LADSPA_Data _value ) { switch( m_port->data_type ) { case TOGGLED: m_toggledModel.setValue( static_cast( _value ) ); break; case INTEGER: case ENUM: m_knobModel.setValue( static_cast( _value ) ); break; case FLOATING: m_knobModel.setValue( static_cast( _value ) ); break; case TIME: m_tempoSyncKnobModel.setValue( static_cast( _value ) ); break; default: printf("LadspaControl::setValue BAD BAD BAD\n"); break; } } void LadspaControl::saveSettings( QDomDocument& doc, QDomElement& parent, const QString& name ) { QDomElement e = doc.createElement( name ); if( m_link ) { m_linkEnabledModel.saveSettings( doc, e, "link" ); } switch( m_port->data_type ) { case TOGGLED: m_toggledModel.saveSettings( doc, e, "data" ); break; case INTEGER: case ENUM: case FLOATING: m_knobModel.saveSettings( doc, e, "data" ); break; case TIME: m_tempoSyncKnobModel.saveSettings( doc, e, "data" ); break; default: printf("LadspaControl::saveSettings BAD BAD BAD\n"); break; } parent.appendChild( e ); } void LadspaControl::loadSettings( const QDomElement& parent, const QString& name ) { QString dataModelName = "data"; QString linkModelName = "link"; QDomElement e = parent.namedItem( name ).toElement(); if(e.isNull()) { // the port exists in the current effect, but not in the // savefile => it's a new port, so load the default value if( m_link ) m_linkEnabledModel.setValue(m_linkEnabledModel.initValue()); switch( m_port->data_type ) { case TOGGLED: m_toggledModel.setValue(m_toggledModel.initValue()); break; case INTEGER: case ENUM: case FLOATING: m_knobModel.setValue(m_knobModel.initValue()); break; case TIME: m_tempoSyncKnobModel.setValue(m_tempoSyncKnobModel.initValue()); break; default: printf("LadspaControl::loadSettings BAD BAD BAD\n"); break; } } else { // COMPAT < 1.0.0: detect old data format where there's either no dedicated sub // element or there's a direct sub element with automation link information if( e.isNull() || e.hasAttribute( "id" ) ) { dataModelName = name; linkModelName = name + "link"; e = parent; } if( m_link ) { m_linkEnabledModel.loadSettings( e, linkModelName ); } switch( m_port->data_type ) { case TOGGLED: m_toggledModel.loadSettings( e, dataModelName ); break; case INTEGER: case ENUM: case FLOATING: m_knobModel.loadSettings( e, dataModelName ); break; case TIME: m_tempoSyncKnobModel.loadSettings( e, dataModelName ); break; default: printf("LadspaControl::loadSettings BAD BAD BAD\n"); break; } } } void LadspaControl::linkControls( LadspaControl * _control ) { switch( m_port->data_type ) { case TOGGLED: BoolModel::linkModels( &m_toggledModel, _control->toggledModel() ); break; case INTEGER: case ENUM: case FLOATING: FloatModel::linkModels( &m_knobModel, _control->knobModel() ); break; case TIME: TempoSyncKnobModel::linkModels( &m_tempoSyncKnobModel, _control->tempoSyncKnobModel() ); break; default: break; } } void LadspaControl::ledChanged() { emit changed( m_port->port_id, static_cast( m_toggledModel.value() ) ); } void LadspaControl::knobChanged() { emit changed( m_port->port_id, static_cast( m_knobModel.value() ) ); } void LadspaControl::tempoKnobChanged() { emit changed( m_port->port_id, static_cast( m_tempoSyncKnobModel.value() ) ); } void LadspaControl::unlinkControls( LadspaControl * _control ) { switch( m_port->data_type ) { case TOGGLED: BoolModel::unlinkModels( &m_toggledModel, _control->toggledModel() ); break; case INTEGER: case ENUM: case FLOATING: FloatModel::unlinkModels( &m_knobModel, _control->knobModel() ); break; case TIME: TempoSyncKnobModel::unlinkModels( &m_tempoSyncKnobModel, _control->tempoSyncKnobModel() ); break; default: break; } } void LadspaControl::linkStateChanged() { emit linkChanged( m_port->control_id, m_linkEnabledModel.value() ); } void LadspaControl::setLink( bool _state ) { m_linkEnabledModel.setValue( _state ); }