void LadspaEffect::pluginDestruction() { if( !isOkay() ) { return; } delete m_controls; for( ch_cnt_t proc = 0; proc < processorCount(); proc++ ) { Ladspa2LMMS * manager = Engine::getLADSPAManager(); manager->deactivate( m_key, m_handles[proc] ); manager->cleanup( m_key, m_handles[proc] ); for( int port = 0; port < m_portCount; port++ ) { port_desc_t * pp = m_ports.at( proc ).at( port ); if( m_inPlaceBroken || pp->rate != CHANNEL_OUT ) { if( pp->buffer) MM_FREE( pp->buffer ); } delete pp; } m_ports[proc].clear(); } m_ports.clear(); m_handles.clear(); m_portControls.clear(); }
LadspaEffect::LadspaEffect( Model * _parent, const Descriptor::SubPluginFeatures::Key * _key ) : Effect( &ladspaeffect_plugin_descriptor, _parent, _key ), m_controls( NULL ), m_maxSampleRate( 0 ), m_key( LadspaSubPluginFeatures::subPluginKeyToLadspaKey( _key ) ) { Ladspa2LMMS * manager = Engine::getLADSPAManager(); if( manager->getDescription( m_key ) == NULL ) { if( !Engine::suppressMessages() ) { QMessageBox::warning( 0, tr( "Effect" ), tr( "Unknown LADSPA plugin %1 requested." ). arg( m_key.second ), QMessageBox::Ok, QMessageBox::NoButton ); } setOkay( false ); return; } setDisplayName( manager->getShortName( m_key ) ); pluginInstantiation(); connect( Engine::mixer(), SIGNAL( sampleRateChanged() ), this, SLOT( changeSampleRate() ) ); }
void LadspaSubPluginFeatures::listSubPluginKeys( const Plugin::Descriptor * _desc, KeyList & _kl ) const { Ladspa2LMMS * lm = Engine::getLADSPAManager(); l_sortable_plugin_t plugins; switch( m_type ) { case Plugin::Instrument: plugins = lm->getInstruments(); break; case Plugin::Effect: plugins = lm->getValidEffects(); //plugins += lm->getInvalidEffects(); break; case Plugin::Tool: plugins = lm->getAnalysisTools(); break; case Plugin::Other: plugins = lm->getOthers(); break; default: break; } for( l_sortable_plugin_t::const_iterator it = plugins.begin(); it != plugins.end(); ++it ) { if( lm->getDescription( ( *it ).second )->inputChannels <= Engine::mixer()->audioDev()->channels() ) { _kl.push_back( ladspaKeyToSubPluginKey( _desc, ( *it ).first, ( *it ).second ) ); } } }
void LadspaSubPluginFeatures::fillDescriptionWidget( QWidget * _parent, const Key * _key ) const { const ladspa_key_t & lkey = subPluginKeyToLadspaKey( _key ); Ladspa2LMMS * lm = Engine::getLADSPAManager(); QLabel * label = new QLabel( _parent ); label->setText( QWidget::tr( "Name: " ) + lm->getName( lkey ) ); QLabel* fileInfo = new QLabel( _parent ); fileInfo->setText( QWidget::tr( "File: %1" ).arg( lkey.first ) ); QWidget * maker = new QWidget( _parent ); QHBoxLayout * l = new QHBoxLayout( maker ); l->setMargin( 0 ); l->setSpacing( 0 ); QLabel * maker_label = new QLabel( maker ); maker_label->setText( QWidget::tr( "Maker: " ) ); maker_label->setAlignment( Qt::AlignTop ); QLabel * maker_content = new QLabel( maker ); maker_content->setText( lm->getMaker( lkey ) ); maker_content->setWordWrap( true ); l->addWidget( maker_label ); l->addWidget( maker_content, 1 ); QWidget * copyright = new QWidget( _parent ); l = new QHBoxLayout( copyright ); l->setMargin( 0 ); l->setSpacing( 0 ); copyright->setMinimumWidth( _parent->minimumWidth() ); QLabel * copyright_label = new QLabel( copyright ); copyright_label->setText( QWidget::tr( "Copyright: " ) ); copyright_label->setAlignment( Qt::AlignTop ); QLabel * copyright_content = new QLabel( copyright ); copyright_content->setText( lm->getCopyright( lkey ) ); copyright_content->setWordWrap( true ); l->addWidget( copyright_label ); l->addWidget( copyright_content, 1 ); QLabel * requiresRealTime = new QLabel( _parent ); requiresRealTime->setText( QWidget::tr( "Requires Real Time: " ) + ( lm->hasRealTimeDependency( lkey ) ? QWidget::tr( "Yes" ) : QWidget::tr( "No" ) ) ); QLabel * realTimeCapable = new QLabel( _parent ); realTimeCapable->setText( QWidget::tr( "Real Time Capable: " ) + ( lm->isRealTimeCapable( lkey ) ? QWidget::tr( "Yes" ) : QWidget::tr( "No" ) ) ); QLabel * inplaceBroken = new QLabel( _parent ); inplaceBroken->setText( QWidget::tr( "In Place Broken: " ) + ( lm->isInplaceBroken( lkey ) ? QWidget::tr( "Yes" ) : QWidget::tr( "No" ) ) ); QLabel * channelsIn = new QLabel( _parent ); channelsIn->setText( QWidget::tr( "Channels In: " ) + QString::number( lm->getDescription( lkey )->inputChannels ) ); QLabel * channelsOut = new QLabel( _parent ); channelsOut->setText( QWidget::tr( "Channels Out: " ) + QString::number( lm->getDescription( lkey )->outputChannels ) ); }
void LadspaEffect::pluginInstantiation() { m_maxSampleRate = maxSamplerate( displayName() ); Ladspa2LMMS * manager = Engine::getLADSPAManager(); // Calculate how many processing units are needed. const ch_cnt_t lmms_chnls = Engine::mixer()->audioDev()->channels(); int effect_channels = manager->getDescription( m_key )->inputChannels; setProcessorCount( lmms_chnls / effect_channels ); // get inPlaceBroken property m_inPlaceBroken = manager->isInplaceBroken( m_key ); // Categorize the ports, and create the buffers. m_portCount = manager->getPortCount( m_key ); int inputch = 0; int outputch = 0; LADSPA_Data * inbuf [2]; inbuf[0] = NULL; inbuf[1] = NULL; for( ch_cnt_t proc = 0; proc < processorCount(); proc++ ) { multi_proc_t ports; for( int port = 0; port < m_portCount; port++ ) { port_desc_t * p = new PortDescription; p->name = manager->getPortName( m_key, port ); p->proc = proc; p->port_id = port; p->control = NULL; p->buffer = NULL; // Determine the port's category. if( manager->isPortAudio( m_key, port ) ) { if( p->name.toUpper().contains( "IN" ) && manager->isPortInput( m_key, port ) ) { p->rate = CHANNEL_IN; p->buffer = MM_ALLOC( LADSPA_Data, Engine::mixer()->framesPerPeriod() ); inbuf[ inputch ] = p->buffer; inputch++; } else if( p->name.toUpper().contains( "OUT" ) && manager->isPortOutput( m_key, port ) ) { p->rate = CHANNEL_OUT; if( ! m_inPlaceBroken && inbuf[ outputch ] ) { p->buffer = inbuf[ outputch ]; outputch++; } else { p->buffer = MM_ALLOC( LADSPA_Data, Engine::mixer()->framesPerPeriod() ); m_inPlaceBroken = true; } } else if( manager->isPortInput( m_key, port ) ) { p->rate = AUDIO_RATE_INPUT; p->buffer = MM_ALLOC( LADSPA_Data, Engine::mixer()->framesPerPeriod() ); } else { p->rate = AUDIO_RATE_OUTPUT; p->buffer = MM_ALLOC( LADSPA_Data, Engine::mixer()->framesPerPeriod() ); } } else { p->buffer = MM_ALLOC( LADSPA_Data, 1 ); if( manager->isPortInput( m_key, port ) ) { p->rate = CONTROL_RATE_INPUT; } else { p->rate = CONTROL_RATE_OUTPUT; } } p->scale = 1.0f; if( manager->isPortToggled( m_key, port ) ) { p->data_type = TOGGLED; } else if( manager->isInteger( m_key, port ) ) { p->data_type = INTEGER; } else if( p->name.toUpper().contains( "(SECONDS)" ) ) { p->data_type = TIME; p->scale = 1000.0f; int loc = p->name.toUpper().indexOf( "(SECONDS)" ); p->name.replace( loc, 9, "(ms)" ); } else if( p->name.toUpper().contains( "(S)" ) ) { p->data_type = TIME; p->scale = 1000.0f; int loc = p->name.toUpper().indexOf( "(S)" ); p->name.replace( loc, 3, "(ms)" ); } else if( p->name.toUpper().contains( "(MS)" ) ) { p->data_type = TIME; int loc = p->name.toUpper().indexOf( "(MS)" ); p->name.replace( loc, 4, "(ms)" ); } else { p->data_type = FLOATING; } // Get the range and default values. p->max = manager->getUpperBound( m_key, port ); if( p->max == NOHINT ) { p->max = p->name.toUpper() == "GAIN" ? 10.0f : 1.0f; } if( manager->areHintsSampleRateDependent( m_key, port ) ) { p->max *= m_maxSampleRate; } p->min = manager->getLowerBound( m_key, port ); if( p->min == NOHINT ) { p->min = 0.0f; } if( manager->areHintsSampleRateDependent( m_key, port ) ) { p->min *= m_maxSampleRate; } p->def = manager->getDefaultSetting( m_key, port ); if( p->def == NOHINT ) { if( p->data_type != TOGGLED ) { p->def = ( p->min + p->max ) / 2.0f; } else { p->def = 1.0f; } } else if( manager->areHintsSampleRateDependent( m_key, port ) ) { p->def *= m_maxSampleRate; } p->max *= p->scale; p->min *= p->scale; p->def *= p->scale; p->value = p->def; p->suggests_logscale = manager->isLogarithmic( m_key, port ); ports.append( p ); // For convenience, keep a separate list of the ports that are used // to control the processors. if( p->rate == AUDIO_RATE_INPUT || p->rate == CONTROL_RATE_INPUT ) { p->control_id = m_portControls.count(); m_portControls.append( p ); } } m_ports.append( ports ); } // Instantiate the processing units. m_descriptor = manager->getDescriptor( m_key ); if( m_descriptor == NULL ) { QMessageBox::warning( 0, "Effect", "Can't get LADSPA descriptor function: " + m_key.second, QMessageBox::Ok, QMessageBox::NoButton ); setOkay( false ); return; } if( m_descriptor->run == NULL ) { QMessageBox::warning( 0, "Effect", "Plugin has no processor: " + m_key.second, QMessageBox::Ok, QMessageBox::NoButton ); setDontRun( true ); } for( ch_cnt_t proc = 0; proc < processorCount(); proc++ ) { LADSPA_Handle effect = manager->instantiate( m_key, m_maxSampleRate ); if( effect == NULL ) { QMessageBox::warning( 0, "Effect", "Can't get LADSPA instance: " + m_key.second, QMessageBox::Ok, QMessageBox::NoButton ); setOkay( false ); return; } m_handles.append( effect ); } // Connect the ports. for( ch_cnt_t proc = 0; proc < processorCount(); proc++ ) { for( int port = 0; port < m_portCount; port++ ) { port_desc_t * pp = m_ports.at( proc ).at( port ); if( !manager->connectPort( m_key, m_handles[proc], port, pp->buffer ) ) { QMessageBox::warning( 0, "Effect", "Failed to connect port: " + m_key.second, QMessageBox::Ok, QMessageBox::NoButton ); setDontRun( true ); return; } } } // Activate the processing units. for( ch_cnt_t proc = 0; proc < processorCount(); proc++ ) { manager->activate( m_key, m_handles[proc] ); } m_controls = new LadspaControls( this ); }