From ccb5a4ea7757ff26d8f5f2701be94e196467f91c Mon Sep 17 00:00:00 2001 From: Danny McRae Date: Wed, 9 Aug 2006 00:49:22 +0000 Subject: [PATCH] move or delete effects partial save and load for effects git-svn-id: https://lmms.svn.sf.net/svnroot/lmms/trunk/lmms@296 0778d3d1-df1d-0410-868b-ea421aaaa00d --- ChangeLog | 25 +++++ include/effect.h | 6 +- include/effect_chain.h | 8 +- include/effect_tab_widget.h | 3 +- include/ladspa_browser.h | 1 + include/ladspa_control.h | 14 ++- include/rack_plugin.h | 32 +++++- include/rack_view.h | 26 ++++- src/core/effect.cpp | 26 ++++- src/core/effect_chain.cpp | 110 ++++++++++++++----- src/core/effect_tab_widget.cpp | 14 +++ src/core/ladspa_browser.cpp | 55 +++++++++- src/tracks/instrument_track.cpp | 9 ++ src/widgets/ladspa_control.cpp | 38 ++++++- src/widgets/rack_plugin.cpp | 156 +++++++++++++++++++++++++- src/widgets/rack_view.cpp | 188 +++++++++++++++++++++++++++++--- 16 files changed, 635 insertions(+), 76 deletions(-) diff --git a/ChangeLog b/ChangeLog index bc6d089c4..ac241b72f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,28 @@ +2006-08-08 Danny McRae + * include/effect.h: + * include/effect_chain.h: + * include/effect_tab_widget.h: + * include/ladspa_browser.h: + * include/ladspa_control.h: + * include/ladspa_control_dialog.h: + * include/rack_plugin.h: + * include/rack_view.h: + * src/core/effect.cpp: + * src/core/effect_chain.cpp: + * src/core/effect_tab_widget.cpp: + * src/core/ladspa_browser.cpp: + * src/core/ladspa_control_dialog.cpp: + * src/tracks/instrument_track.cpp: + * src/widgets/ladspa_control.cpp: + * src/widgets/rack_plugin.cpp: + * src/widgets/rack_view.cpp: + -added ability to change the order of effects or delete them + -partial save and load support + -still getting spurious segfaults when twoddling with knobs, + the textFloat associated with the knob is being reparented to + NULL(?!), but works well enough to at least hear what things + sound like with effects + 2006-08-07 Danny McRae * include/oscillator.h: * plugins/vibed/vibrating_string.h: diff --git a/include/effect.h b/include/effect.h index 616a53678..c71c84e2a 100644 --- a/include/effect.h +++ b/include/effect.h @@ -32,6 +32,8 @@ #include #endif +#include + #include "qt3support.h" #include "engine.h" @@ -136,7 +138,8 @@ private: ch_cnt_t m_processors; Uint16 m_effectChannels; Uint16 m_portCount; - + fpab_t m_bufferSize; + const LADSPA_Descriptor * m_descriptor; vvector m_handles; @@ -155,6 +158,7 @@ private: float m_wetDry; float m_gate; + QMutex m_processLock; }; #endif diff --git a/include/effect_chain.h b/include/effect_chain.h index 59144b3c8..8e0615600 100644 --- a/include/effect_chain.h +++ b/include/effect_chain.h @@ -28,6 +28,8 @@ #include "ladspa_manager.h" #ifdef LADSPA_SUPPORT +#include + #include "qt3support.h" #include "engine.h" @@ -42,8 +44,10 @@ public: ~effectChain(); void FASTCALL appendEffect( effect * _effect ); + void FASTCALL deleteEffect( effect * _effect ); + void FASTCALL moveDown( effect * _effect ); + void FASTCALL moveUp( effect * _effect ); bool FASTCALL processAudioBuffer( surroundSampleFrame * _buf, const fpab_t _frames ); - void FASTCALL swapEffects( effect * _eff1, effect * _eff2 ); void setRunning( void ); bool isRunning( void ); @@ -61,7 +65,7 @@ private: effect_list_t m_effects; bool m_bypassed; - + QMutex m_processLock; }; #endif diff --git a/include/effect_tab_widget.h b/include/effect_tab_widget.h index baeb566d1..2da934b97 100644 --- a/include/effect_tab_widget.h +++ b/include/effect_tab_widget.h @@ -69,8 +69,7 @@ public: virtual ~effectTabWidget(); - virtual void FASTCALL saveSettings( QDomDocument & _doc, - QDomElement & _parent ); + virtual void FASTCALL saveSettings( QDomDocument & _doc, QDomElement & _parent ); virtual void FASTCALL loadSettings( const QDomElement & _this ); inline virtual QString nodeName( void ) const { diff --git a/include/ladspa_browser.h b/include/ladspa_browser.h index ec000fbdb..185fa7b96 100644 --- a/include/ladspa_browser.h +++ b/include/ladspa_browser.h @@ -64,6 +64,7 @@ public: public slots: void showPorts( const ladspa_key_t & _key ); void testLADSPA( const ladspa_key_t & _key ); + void displayHelp( void ); private: tabBar * m_tabBar; diff --git a/include/ladspa_control.h b/include/ladspa_control.h index 73f8acf7d..b89b01bb8 100644 --- a/include/ladspa_control.h +++ b/include/ladspa_control.h @@ -30,7 +30,7 @@ #include -#include "engine.h" +#include "journalling_object.h" #include "instrument_track.h" #include "knob.h" #include "led_checkbox.h" @@ -38,7 +38,7 @@ typedef struct portDescription port_desc_t; -class ladspaControl : public QWidget, public engineObject +class ladspaControl : public QWidget, public journallingObject { Q_OBJECT public: @@ -46,11 +46,21 @@ public: ~ladspaControl(); LADSPA_Data getValue( void ); + void FASTCALL setValue( LADSPA_Data _value ); + + virtual void FASTCALL saveSettings( QDomDocument & _doc, QDomElement & _parent ); + virtual void FASTCALL loadSettings( const QDomElement & _this ); + inline virtual QString nodeName( void ) const + { + return( "port" ); + } private: port_desc_t * m_port; ledCheckBox * m_toggle; knob * m_knob; + + QMutex m_processLock; }; #endif diff --git a/include/rack_plugin.h b/include/rack_plugin.h index e0c631573..0106cd56a 100644 --- a/include/rack_plugin.h +++ b/include/rack_plugin.h @@ -51,17 +51,41 @@ public: rackPlugin( QWidget * _parent, ladspa_key_t _key, instrumentTrack * _track, engine * _engine ); ~rackPlugin(); - QString nodeName( void ) const + inline effect * getEffect() { - return( "plugin" ); + return( m_effect ); } + inline const ladspa_key_t & getKey( void ) + { + return( m_key ); + } + + virtual void FASTCALL saveSettings( QDomDocument & _doc, QDomElement & _parent ); + virtual void FASTCALL loadSettings( const QDomElement & _this ); + inline virtual QString nodeName( void ) const + { + return( "effect" ); + } + public slots: void editControls( void ); void bypassed( bool _state ); void setWetDry( float _value ); void setAutoQuit( float _value ); void setGate( float _value ); + void moveUp( void ); + void moveDown( void ); + void deletePlugin( void ); + void displayHelp( void ); + +signals: + void moveUp( rackPlugin * _plugin ); + void moveDown( rackPlugin * _plugin ); + void deletePlugin( rackPlugin * _plugin ); + +protected: + void contextMenuEvent( QContextMenuEvent * _me ); private: ledCheckBox * m_bypass; @@ -74,6 +98,10 @@ private: QPushButton * m_editButton; effect * m_effect; ladspaControlDialog * m_controlView; + instrumentTrack * m_track; + QMenu * m_contextMenu; + ladspa_key_t m_key; + QString m_name; }; #endif diff --git a/include/rack_view.h b/include/rack_view.h index 36b677950..cb98eaa2a 100644 --- a/include/rack_view.h +++ b/include/rack_view.h @@ -34,12 +34,13 @@ #include #include "types.h" -#include "engine.h" +#include "journalling_object.h" #include "rack_plugin.h" #include "instrument_track.h" +#include "ladspa_2_lmms.h" -class rackView: public QWidget, public engineObject +class rackView: public QWidget, public journallingObject { Q_OBJECT @@ -48,16 +49,31 @@ public: ~rackView(); void addPlugin( ladspa_key_t _key ); + + virtual void FASTCALL saveSettings( QDomDocument & _doc, QDomElement & _parent ); + virtual void FASTCALL loadSettings( const QDomElement & _this ); + inline virtual QString nodeName( void ) const + { + return( "rack" ); + } +public slots: + void moveUp( rackPlugin * _plugin ); + void moveDown( rackPlugin * _plugin ); + void deletePlugin( rackPlugin * _plugin ); + private: - QPtrList m_rackInserts; - int m_insertIndex; + void redraw(); + + vvector m_rackInserts; QVBoxLayout * m_mainLayout; QScrollView * m_scrollView; - QVBox * m_rack; instrumentTrack * m_instrumentTrack; + Uint32 m_lastY; + + ladspa2LMMS * m_ladspa; }; #endif diff --git a/src/core/effect.cpp b/src/core/effect.cpp index a041688df..c0db0ab83 100644 --- a/src/core/effect.cpp +++ b/src/core/effect.cpp @@ -66,7 +66,7 @@ effect::effect( const ladspa_key_t & _key, engine * _engine ) : m_processors = lmms_chnls / m_effectChannels; // Categorize the ports, and create the buffers. - fpab_t buffer_size = configManager::inst()->value( "mixer", "framesperaudiobuffer" ).toInt(); + m_bufferSize = configManager::inst()->value( "mixer", "framesperaudiobuffer" ).toInt(); m_portCount = m_ladspa->getPortCount( _key ); for( ch_cnt_t proc = 0; proc < m_processors; proc++ ) @@ -87,7 +87,7 @@ effect::effect( const ladspa_key_t & _key, engine * _engine ) : // with some prepackaged plugins that were segfaulting // during cleanup. It was easier to troubleshoot with the // memory management all taking place in one file. - p->buffer = new LADSPA_Data[buffer_size]; + p->buffer = new LADSPA_Data[m_bufferSize]; if( p->name.upper().contains( "IN" ) && m_ladspa->isPortInput( _key, port ) ) { @@ -240,6 +240,8 @@ effect::~effect() return; } + m_processLock.lock(); + for( ch_cnt_t proc = 0; proc < m_processors; proc++ ) { m_ladspa->deactivate( m_key, m_handles[proc] ); @@ -253,6 +255,8 @@ effect::~effect() } m_ports.clear(); m_handles.clear(); + + m_processLock.unlock(); } @@ -260,7 +264,7 @@ effect::~effect() bool FASTCALL effect::processAudioBuffer( surroundSampleFrame * _buf, const fpab_t _frames ) { - if( !m_okay || m_noRun || !m_running || m_bypass ) + if( !m_okay || m_noRun || !m_running || m_bypass || !m_processLock.tryLock() ) { return( FALSE ); } @@ -343,8 +347,9 @@ bool FASTCALL effect::processAudioBuffer( surroundSampleFrame * _buf, const fpab } } - // Check whether we need to continue processing input. - if( out_sum <= ( m_gate * _frames * channel ) ) + // Check whether we need to continue processing input. Restart the + // counter if the threshold has been exceeded. + if( out_sum <= ( m_gate ) ) { m_bufferCount++; if( m_bufferCount > m_silenceTimeout ) @@ -353,7 +358,12 @@ bool FASTCALL effect::processAudioBuffer( surroundSampleFrame * _buf, const fpab m_bufferCount = 0; } } + else + { + m_bufferCount = 0; + } + m_processLock.unlock(); return( m_running ); } @@ -365,7 +375,9 @@ void FASTCALL effect::setControl( Uint16 _control, LADSPA_Data _value ) { return; } + m_processLock.lock(); m_controls[_control]->value = _value; + m_processLock.unlock(); } @@ -373,7 +385,9 @@ void FASTCALL effect::setControl( Uint16 _control, LADSPA_Data _value ) void FASTCALL effect::setGate( float _level ) { - m_gate = _level; + m_processLock.lock(); + m_gate = _level * _level * m_processors * m_bufferSize; + m_processLock.unlock(); } diff --git a/src/core/effect_chain.cpp b/src/core/effect_chain.cpp index ffd66eefa..0523463ca 100644 --- a/src/core/effect_chain.cpp +++ b/src/core/effect_chain.cpp @@ -40,11 +40,13 @@ effectChain::effectChain( engine * _engine ): effectChain::~ effectChain() { + m_processLock.lock(); for( Uint32 eff = 0; eff < m_effects.count(); eff++ ) { free( m_effects[eff] ); } m_effects.clear(); + m_processLock.unlock(); } @@ -52,7 +54,84 @@ effectChain::~ effectChain() void FASTCALL effectChain::appendEffect( effect * _effect ) { + m_processLock.lock(); m_effects.append( _effect ); + m_processLock.unlock(); +} + + + +void FASTCALL effectChain::deleteEffect( effect * _effect ) +{ + m_processLock.lock(); + effect_list_t::iterator which = NULL; + for( effect_list_t::iterator it = m_effects.begin(); it != m_effects.end(); it++ ) + { + if( (*it) == _effect ) + { + which = it; + break; + } + } + + if( which != NULL ) + { + m_effects.erase( which ); + } + + m_processLock.unlock(); +} + + + + +void FASTCALL effectChain::moveDown( effect * _effect ) +{ + m_processLock.lock(); + + if( _effect != m_effects.last() ) + { + int i = 0; + for( effect_list_t::iterator it = m_effects.begin(); it != m_effects.end(); it++, i++ ) + { + if( (*it) == _effect ) + { + break; + } + } + + effect * temp = m_effects[i + 1]; + m_effects[i + 1] = _effect; + m_effects[i] = temp; + } + + m_processLock.unlock(); +} + + + + +void FASTCALL effectChain::moveUp( effect * _effect ) +{ + m_processLock.lock(); + + if( _effect != m_effects.first() ) + { + int i = 0; + for( effect_list_t::iterator it = m_effects.begin(); it != m_effects.end(); it++, i++ ) + { + if( (*it) == _effect ) + { + break; + } + } + + effect * temp = m_effects[i - 1]; + m_effects[i - 1] = _effect; + m_effects[i] = temp; + } + + m_processLock.unlock(); } @@ -60,7 +139,7 @@ void FASTCALL effectChain::appendEffect( effect * _effect ) bool FASTCALL effectChain::processAudioBuffer( surroundSampleFrame * _buf, const fpab_t _frames ) { - if( m_bypassed ) + if( m_bypassed || ! m_processLock.tryLock() ) { return( FALSE ); } @@ -70,6 +149,7 @@ bool FASTCALL effectChain::processAudioBuffer( surroundSampleFrame * _buf, const { more_effects |= (*it)->processAudioBuffer( _buf, _frames ); } + m_processLock.unlock(); return( more_effects ); } @@ -107,36 +187,8 @@ bool effectChain::isRunning( void ) } return( running ); } - - -void FASTCALL effectChain::swapEffects( effect * _eff1, effect * _eff2 ) -{ - Uint32 eff1_loc = m_effects.count(); - Uint32 eff2_loc = m_effects.count(); - - Uint32 count = 0; - for( effect_list_t::iterator it = m_effects.begin(); it != m_effects.end(); it++ ) - { - if( (*it) == _eff1 ) - { - eff1_loc = count; - } - if( (*it) == _eff2 ) - { - eff2_loc = count; - } - count++; - } - - if( eff1_loc < m_effects.count() && eff2_loc < m_effects.count() ) - { - m_effects[eff1_loc] = _eff2; - m_effects[eff2_loc] = _eff1; - } -} - #endif #endif diff --git a/src/core/effect_tab_widget.cpp b/src/core/effect_tab_widget.cpp index 7b2b08e76..4f236df0b 100644 --- a/src/core/effect_tab_widget.cpp +++ b/src/core/effect_tab_widget.cpp @@ -87,6 +87,7 @@ effectTabWidget::~effectTabWidget() void effectTabWidget::saveSettings( QDomDocument & _doc, QDomElement & _this ) { _this.setAttribute( "fxdisabled", !m_effectsGroupBox->isActive() ); + m_rack->saveState( _doc, _this ); } @@ -96,6 +97,19 @@ void effectTabWidget::saveSettings( QDomDocument & _doc, QDomElement & _this ) void effectTabWidget::loadSettings( const QDomElement & _this ) { m_effectsGroupBox->setState( !_this.attribute( "fxdisabled" ).toInt() ); + + QDomNode node = _this.firstChild(); + while( !node.isNull() ) + { + if( node.isElement() ) + { + if( m_rack->nodeName() == node.nodeName() ) + { + m_rack->restoreState( node.toElement() ); + } + } + node = node.nextSibling(); + } } diff --git a/src/core/ladspa_browser.cpp b/src/core/ladspa_browser.cpp index 5f7fd944c..edcc8e05e 100644 --- a/src/core/ladspa_browser.cpp +++ b/src/core/ladspa_browser.cpp @@ -33,10 +33,12 @@ #ifdef QT4 #include +#include #else #include +#include #endif @@ -194,14 +196,16 @@ ladspaBrowser::ladspaBrowser( engine * _engine ) : btn_layout->setSpacing( 0 ); btn_layout->setMargin( 0 ); - QPushButton * cancel_btn = new QPushButton( embed::getIconPixmap( - "cancel" ), - tr( "Close" ), - buttons ); + QPushButton * help_btn = new QPushButton( embed::getIconPixmap( "help" ), "", buttons ); + connect( help_btn, SIGNAL( clicked() ), this, SLOT( displayHelp() ) ); + + QPushButton * cancel_btn = new QPushButton( embed::getIconPixmap( "cancel" ), tr( "Close" ), buttons ); connect( cancel_btn, SIGNAL( clicked() ), this, SLOT( reject() ) ); btn_layout->addStretch(); btn_layout->addSpacing( 10 ); + btn_layout->addWidget( help_btn ); + btn_layout->addSpacing( 10 ); btn_layout->addWidget( cancel_btn ); btn_layout->addSpacing( 10 ); @@ -213,6 +217,37 @@ ladspaBrowser::ladspaBrowser( engine * _engine ) : show(); +#ifdef QT4 + this->setWhatsThis( +#else + QWhatsThis::add( this, +#endif + tr( +"This dialog displays information on all of the LADSPA plugins LMMS was " +"able to locate. The plugins are divided into five categories based " +"upon an interpretation of the port types and names.\n\n" + +"Available Effects are those that can be used by LMMS. In order for LMMS " +"to be able to use an effect, it must, first and foremost, be an effect, " +"which is to say, it has to have both input channels and output channels. " +"LMMS identifies an input channel as an audio rate port containing 'in' in " +"the name. Output channels are identified by the letters 'out'. Furthermore, " +"the effect must have the same number of inputs and outputs and be real time " +"capable.\n\n" + +"Unavailable Effects are those that were identified as effects, but either " +"didn't have the same number of input and output channels or weren't real " +"time capable.\n\n" + +"Instruments are plugins for which only output channels were identified.\n\n" + +"Analysis Tools are plugins for which only input channels were identified.\n\n" + +"Don't Knows are plugins for which no input or output channels were " +"identified.\n\n" + +"Double clicking any of the plugins will bring up information on the " +"ports." ) ); } @@ -255,6 +290,18 @@ void ladspaBrowser::testLADSPA( const ladspa_key_t & _key ) + +void ladspaBrowser::displayHelp( void ) +{ +#ifdef QT4 + QWhatsThis::showText( mapToGlobal( rect().bottomRight() ), whatsThis() ); +#else + QWhatsThis::display( QWhatsThis::textFor( this ), mapToGlobal( rect().bottomRight() ) ); +#endif +} + + + #include "ladspa_browser.moc" #endif diff --git a/src/tracks/instrument_track.cpp b/src/tracks/instrument_track.cpp index 824500f67..d0076d868 100644 --- a/src/tracks/instrument_track.cpp +++ b/src/tracks/instrument_track.cpp @@ -1091,6 +1091,9 @@ void instrumentTrack::saveTrackSpecificSettings( QDomDocument & _doc, m_envWidget->saveState( _doc, _this ); m_arpWidget->saveState( _doc, _this ); m_midiWidget->saveState( _doc, _this ); +#ifdef LADSPA_SUPPORT + m_effWidget->saveState( _doc, _this ); +#endif } @@ -1126,6 +1129,12 @@ void instrumentTrack::loadTrackSpecificSettings( const QDomElement & _this ) { m_midiWidget->restoreState( node.toElement() ); } +#ifdef LADSPA_SUPPORT + else if( m_effWidget->nodeName() == node.nodeName() ) + { + m_effWidget->restoreState( node.toElement() ); + } +#endif else if( automationPattern::classNodeName() != node.nodeName() ) { diff --git a/src/widgets/ladspa_control.cpp b/src/widgets/ladspa_control.cpp index d0f86403d..8c88f7332 100644 --- a/src/widgets/ladspa_control.cpp +++ b/src/widgets/ladspa_control.cpp @@ -35,7 +35,7 @@ ladspaControl::ladspaControl( QWidget * _parent, port_desc_t * _port, engine * _engine, instrumentTrack * _track ) : QWidget( _parent, "ladspaControl" ), - engineObject( _engine ), + journallingObject( _engine ), m_port( _port ), m_toggle( NULL ), m_knob( NULL ) @@ -112,6 +112,42 @@ LADSPA_Data ladspaControl::getValue( void ) } + + +void ladspaControl::setValue( LADSPA_Data _value ) +{ + switch( m_port->data_type ) + { + case TOGGLED: + m_toggle->setChecked( static_cast( _value ) ); + break; + case INTEGER: + m_knob->setValue( static_cast( _value ) ); + break; + case FLOAT: + m_knob->setValue( static_cast( _value ) ); + break; + default: + printf("ladspaControl::setValue BAD BAD BAD\n"); + break; + } +} + + + + +void FASTCALL ladspaControl::saveSettings( QDomDocument & _doc, QDomElement & _this ) +{ +} + + + + +void FASTCALL ladspaControl::loadSettings( const QDomElement & _this ) +{ +} + + #include "ladspa_control.moc" #endif diff --git a/src/widgets/rack_plugin.cpp b/src/widgets/rack_plugin.cpp index fb89f9153..182e02a57 100644 --- a/src/widgets/rack_plugin.cpp +++ b/src/widgets/rack_plugin.cpp @@ -46,6 +46,9 @@ #include #include +#define addSeparator insertSeparator +#define addMenu insertItem + #endif #include "rack_plugin.h" @@ -54,15 +57,21 @@ #include "ladspa_2_lmms.h" #include "ladspa_control_dialog.h" #include "audio_port.h" +#include "embed.h" rackPlugin::rackPlugin( QWidget * _parent, ladspa_key_t _key, instrumentTrack * _track, engine * _engine ) : QWidget( _parent, "rackPlugin" ), - journallingObject( _engine ) + journallingObject( _engine ), + m_track( _track ), + m_contextMenu( NULL ), + m_key( _key ) { m_effect = new effect( _key, eng() ); _track->getAudioPort()->getEffects()->appendEffect( m_effect ); + m_name = m_effect->getName(); + setFixedSize( 210, 58 ); setPaletteBackgroundColor( QColor( 99, 99, 99 ) ); @@ -71,6 +80,7 @@ rackPlugin::rackPlugin( QWidget * _parent, ladspa_key_t _key, instrumentTrack * m_bypass = new ledCheckBox( "", this, tr( "Turn the effect off" ), eng(), _track ); connect( m_bypass, SIGNAL( toggled( bool ) ), this, SLOT( bypassed( bool ) ) ); + toolTip::add( m_bypass, tr( "On/Off" ) ); m_bypass->setChecked( TRUE ); m_bypass->move( 3, 3 ); #ifdef QT4 @@ -94,7 +104,7 @@ rackPlugin::rackPlugin( QWidget * _parent, ladspa_key_t _key, instrumentTrack * QWhatsThis::add( m_wetDry, #endif tr( -"The wet/dry knob sets the ratio between the input signal and the effect that shows up in the output." ) ); +"The Wet/Dry knob sets the ratio between the input signal and the effect that shows up in the output." ) ); m_autoQuit = new knob( knobBright_26, this, tr( "Decay" ), eng(), _track ); connect( m_autoQuit, SIGNAL( valueChanged( float ) ), this, SLOT( setAutoQuit( float ) ) ); @@ -109,7 +119,7 @@ rackPlugin::rackPlugin( QWidget * _parent, ladspa_key_t _key, instrumentTrack * QWhatsThis::add( m_autoQuit, #endif tr( -"The decay knob controls how many buffers of silence must pass before the plugin stops processing. Smaller values " +"The Decay knob controls how many buffers of silence must pass before the plugin stops processing. Smaller values " "will reduce the CPU overhead but run the risk of clipping the tail on delay effects." ) ); m_gate = new knob( knobBright_26, this, tr( "Decay" ), eng(), _track ); @@ -125,7 +135,7 @@ rackPlugin::rackPlugin( QWidget * _parent, ladspa_key_t _key, instrumentTrack * QWhatsThis::add( m_gate, #endif tr( -"The gate knob controls the signal level that is considered to be 'silence' while deciding when to stop processing " +"The Gate knob controls the signal level that is considered to be 'silence' while deciding when to stop processing " "signals." ) ); m_editButton = new QPushButton( this, "Controls" ); @@ -142,12 +152,47 @@ rackPlugin::rackPlugin( QWidget * _parent, ladspa_key_t _key, instrumentTrack * m_label->setGeometry( 5, 38, 200, 20 ); m_controlView = new ladspaControlDialog( this, m_effect, eng(), _track ); + +#ifdef QT4 + this->setWhatsThis( +#else + QWhatsThis::add( this, +#endif + tr( +"Effect plugins function as a chained series of effects where the signal will " +"be processed from top to bottom.\n\n" + +"The On/Off switch allows you to bypass a given plugin at any point in " +"time.\n\n" + +"The Wet/Dry knob controls the balance between the input signal and the " +"effected signal that is the resulting output from the effect. The input " +"for one stage is the output from the previous stage, so the 'dry' signal " +"for effects lower in the chain contains all of the previous effects.\n\n" + +"The Decay knob controls how long the signal will continue to be processed " +"after the notes have been released. The effect will stop processing signals " +"when the signal has dropped below a given threshold for a given length of " +"time. This knob sets the 'given length of time'. Longer times will require " +"more CPU, so this number should be set low for most effects. It needs to be " +"bumped up for effects that produce lengthy periods of silence, e.g. " +"delays.\n\n" + +"The Gate knob controls the 'given threshold' for the effect's auto shutdown. " +"The clock for the 'given length of time' will begin as soon as the processed " +"signal level drops below the level specified with this knob.\n\n" + +"The Controls button opens a dialog for editing the effect's parameters.\n\n" + +"Right clicking will bring up a context menu where you can change the order " +"in which the effects are processed or delete an effect altogether." ) ); } rackPlugin::~rackPlugin() { + delete m_effect; } @@ -189,6 +234,109 @@ void rackPlugin::setGate( float _value ) } + + +void rackPlugin::contextMenuEvent( QContextMenuEvent * ) +{ + m_contextMenu = new QMenu( this ); +#ifdef QT4 + m_contextMenu->setTitle( m_effect->getName() ); +#else + QLabel * caption = new QLabel( "" + QString( m_effect->getName() ) + "", this ); + caption->setPaletteBackgroundColor( QColor( 0, 0, 192 ) ); + caption->setAlignment( Qt::AlignCenter ); + m_contextMenu->addAction( caption ); +#endif + m_contextMenu->addAction( embed::getIconPixmap( "arp_up_on" ), tr( "Move &up" ), this, SLOT( moveUp() ) ); + m_contextMenu->addAction( embed::getIconPixmap( "arp_down_on" ), tr( "Move &down" ), this, SLOT( moveDown() ) ); + m_contextMenu->addSeparator(); + m_contextMenu->addAction( embed::getIconPixmap( "cancel" ), tr( "&Remove this plugin" ), this, SLOT( deletePlugin() ) ); + m_contextMenu->addSeparator(); + m_contextMenu->addAction( embed::getIconPixmap( "help" ), tr( "&Help" ), this, SLOT( displayHelp() ) ); + m_contextMenu->exec( QCursor::pos() ); + if( m_contextMenu != NULL ) + { + delete m_contextMenu; + } +} + + + + +void rackPlugin::moveUp() +{ + if( m_contextMenu != NULL ) + { + delete m_contextMenu; + m_contextMenu = NULL; + } + emit( moveUp( this ) ); +} + + + + +void rackPlugin::moveDown() +{ + if( m_contextMenu != NULL ) + { + delete m_contextMenu; + m_contextMenu = NULL; + } + emit( moveDown( this ) ); +} + + + +void rackPlugin::deletePlugin() +{ + if( m_contextMenu != NULL ) + { + delete m_contextMenu; + m_contextMenu = NULL; + } + emit( deletePlugin( this ) ); +} + + + + +void rackPlugin::displayHelp( void ) +{ +#ifdef QT4 + QWhatsThis::showText( mapToGlobal( rect().bottomRight() ), whatsThis() ); +#else + QWhatsThis::display( QWhatsThis::textFor( this ), mapToGlobal( rect().bottomRight() ) ); +#endif +} + + + + +void FASTCALL rackPlugin::saveSettings( QDomDocument & _doc, QDomElement & _this ) +{ + _this.setAttribute( "on", m_bypass->isChecked() ); + _this.setAttribute( "wet", m_wetDry->value() ); + _this.setAttribute( "autoquit", m_autoQuit->value() ); + _this.setAttribute( "gate", m_gate->value() ); + m_controlView->saveState( _doc, _this ); +} + + + + +void FASTCALL rackPlugin::loadSettings( const QDomElement & _this ) +{ + m_bypass->setChecked( _this.attribute( "on" ).toInt() ); + m_wetDry->setValue( _this.attribute( "wet" ).toFloat() ); + m_autoQuit->setValue( _this.attribute( "autoquit" ).toFloat() ); + m_gate->setValue( _this.attribute( "gate" ).toFloat() ); + m_controlView->loadSettings( _this ); +} + + + + #include "rack_plugin.moc" #endif diff --git a/src/widgets/rack_view.cpp b/src/widgets/rack_view.cpp index f82629549..727973794 100644 --- a/src/widgets/rack_view.cpp +++ b/src/widgets/rack_view.cpp @@ -27,13 +27,17 @@ #include "ladspa_manager.h" #ifdef LADSPA_SUPPORT +#include + #include "rack_view.h" +#include "audio_port.h" rackView::rackView( QWidget * _parent, engine * _engine, instrumentTrack * _track ): QWidget( _parent, "rackView" ), - engineObject( _engine ), - m_instrumentTrack( _track ) + journallingObject( _engine ), + m_instrumentTrack( _track ), + m_ladspa( eng()->getLADSPAManager() ) { setFixedSize( 230, 180 ); @@ -43,25 +47,13 @@ rackView::rackView( QWidget * _parent, engine * _engine, instrumentTrack * _trac m_scrollView->setVScrollBarMode( QScrollView::AlwaysOn ); m_mainLayout->addWidget( m_scrollView ); - m_rack = new QVBox( m_scrollView->viewport() ); - m_scrollView->addChild( m_rack ); - - m_rackInserts.setAutoDelete( TRUE ); + m_lastY = 0; } rackView::~rackView() { - m_rackInserts.setAutoDelete( TRUE ); - while( ! m_rackInserts.isEmpty() ) - { - m_rackInserts.removeFirst(); - } - - delete m_rack; - delete m_scrollView; - delete m_mainLayout; } @@ -69,13 +61,173 @@ rackView::~rackView() void rackView::addPlugin( ladspa_key_t _key ) { - rackPlugin * plugin = new rackPlugin( m_rack, _key, m_instrumentTrack, eng() ); + rackPlugin * plugin = new rackPlugin( m_scrollView->viewport(), _key, m_instrumentTrack, eng() ); + connect( plugin, SIGNAL( moveUp( rackPlugin * ) ), this, SLOT( moveUp( rackPlugin * ) ) ); + connect( plugin, SIGNAL( moveDown( rackPlugin * ) ), this, SLOT( moveDown( rackPlugin * ) ) ); + connect( plugin, SIGNAL( deletePlugin( rackPlugin * ) ), this, SLOT( deletePlugin( rackPlugin * ) ) ); + m_scrollView->addChild( plugin ); + m_scrollView->moveChild( plugin, 0, m_lastY ); + plugin->show(); + m_lastY += plugin->height(); + m_scrollView->resizeContents( 210, m_lastY ); m_rackInserts.append( plugin ); - m_rackInserts.current()->repaint(); - m_rackInserts.current()->show(); } + + +void rackView::moveUp( rackPlugin * _plugin ) +{ + if( _plugin != m_rackInserts.first() ) + { + int i = 0; + for( vvector::iterator it = m_rackInserts.begin(); it != m_rackInserts.end(); it++, i++ ) + { + if( (*it) == _plugin ) + { + break; + } + } + + rackPlugin * temp = m_rackInserts[ i - 1 ]; + + m_rackInserts[i - 1] = _plugin; + m_rackInserts[i] = temp; + + redraw(); + } +} + + + + +void rackView::moveDown( rackPlugin * _plugin ) +{ + m_instrumentTrack->getAudioPort()->getEffects()->moveDown( _plugin->getEffect() ); + if( _plugin != m_rackInserts.last() ) + { + int i = 0; + for( vvector::iterator it = m_rackInserts.begin(); it != m_rackInserts.end(); it++, i++ ) + { + if( (*it) == _plugin ) + { + break; + } + } + + rackPlugin * temp = m_rackInserts.at( i + 1 ); + + m_rackInserts[i + 1] = _plugin; + m_rackInserts[i] = temp; + + redraw(); + } +} + + + + +void rackView::deletePlugin( rackPlugin * _plugin ) +{ + m_instrumentTrack->getAudioPort()->getEffects()->deleteEffect( _plugin->getEffect() ); + + m_scrollView->removeChild( _plugin ); + + vvector::iterator loc = NULL; + for( vvector::iterator it = m_rackInserts.begin(); it != m_rackInserts.end(); it++ ) + { + if( (*it) == _plugin ) + { + loc = it; + break; + } + } + + if( loc != NULL ) + { + delete _plugin; + m_rackInserts.erase( loc ); + redraw(); + } +} + + + + +void rackView::redraw() +{ + m_lastY = 0; + for( vvector::iterator it = m_rackInserts.begin(); it != m_rackInserts.end(); it++ ) + { + m_scrollView->moveChild( (*it), 0, m_lastY ); + m_lastY += (*it)->height(); + } + m_scrollView->resizeContents( 210, m_lastY ); +} + + + + +void FASTCALL rackView::saveSettings( QDomDocument & _doc, QDomElement & _this ) +{ + _this.setAttribute( "plugins", m_rackInserts.count() ); + for( vvector::iterator it = m_rackInserts.begin(); it != m_rackInserts.end(); it++ ) + { + ladspa_key_t key = (*it)->getKey(); + _this.setAttribute( "label", key.first ); + _this.setAttribute( "lib", key.second ); + _this.setAttribute( "name", m_ladspa->getName( key ) ); + _this.setAttribute( "maker", m_ladspa->getMaker( key ) ); + (*it)->saveState( _doc, _this ); + } +} + + + + +void FASTCALL rackView::loadSettings( const QDomElement & _this ) +{ + int plugin_cnt = _this.attribute( "plugins" ).toInt(); + QString lib = _this.attribute( "lib" ); + QString label = _this.attribute( "label" ); + for( int i = 0; i < plugin_cnt; i++ ) + { + printf( "%s, %s\n", lib.ascii(), label.ascii() ); + ladspa_key_t key( label, lib ); + if( m_ladspa->getDescriptor( key ) != NULL ) + { + addPlugin( key ); + + QDomNode node = _this.firstChild(); + while( !node.isNull() ) + { + if( node.isElement() ) + { + if( m_rackInserts.last()->nodeName() == node.nodeName() ) + { + m_rackInserts.last()->restoreState( node.toElement() ); + } + } + node = node.nextSibling(); + } + } + else + { + QString name = _this.attribute( "name" ); + QString maker = _this.attribute( "maker" ); + QString message = "Couldn't find " + name + " from:\n\n"; + message += "Library: " + lib + "\n"; + message += "Label: " + label + "\n"; + message += "Maker: " + maker; + + QMessageBox::information( 0, tr( "Uknown plugin" ), message, QMessageBox::Ok ); + } + } + +} + + + #include "rack_view.moc" #endif