diff --git a/data/themes/default/style.css b/data/themes/default/style.css index 1598264b9..005cc579d 100644 --- a/data/themes/default/style.css +++ b/data/themes/default/style.css @@ -83,13 +83,11 @@ QMenu::item:selected { color: white; font-weight:bold; background-color: #747474; - margin:3px; } QMenu::item:disabled { color: #747474; background-color: #c9c9c9; - margin:0px; font-size:12px; font-weight: normal; padding: 4px 32px 4px 20px; diff --git a/include/AutomatableModel.h b/include/AutomatableModel.h index db770890a..49e66c762 100644 --- a/include/AutomatableModel.h +++ b/include/AutomatableModel.h @@ -25,7 +25,7 @@ #ifndef AUTOMATABLE_MODEL_H #define AUTOMATABLE_MODEL_H -#include +#include "lmms_math.h" #include #include "JournallingObject.h" @@ -72,7 +72,8 @@ public: enum ScaleType { Linear, - Logarithmic + Logarithmic, + Decibel }; enum DataType @@ -249,6 +250,19 @@ public: return m_hasLinkedModels; } + // a way to track changed values in the model and avoid using signals/slots - useful for speed-critical code. + // note that this method should only be called once per period since it resets the state of the variable - so if your model + // has to be accessed by more than one object, then this function shouldn't be used. + bool isValueChanged() + { + if( m_valueChanged ) + { + m_valueChanged = false; + return true; + } + return false; + } + float globalAutomationValueAt( const MidiTime& time ); bool hasStrictStepSize() const @@ -318,6 +332,8 @@ private: float m_step; float m_range; float m_centerValue; + + bool m_valueChanged; // currently unused? float m_oldValue; diff --git a/include/FxMixer.h b/include/FxMixer.h index 721f35250..f1ac405d0 100644 --- a/include/FxMixer.h +++ b/include/FxMixer.h @@ -59,6 +59,7 @@ class FxChannel : public ThreadableJob QMutex m_lock; int m_channelIndex; // what channel index are we bool m_queued; // are we queued up for rendering yet? + bool m_muted; // are we muted? updated per period so we don't have to call m_muteModel.value() twice // pointers to other channels that this one sends to FxRouteVector m_sends; @@ -69,6 +70,11 @@ class FxChannel : public ThreadableJob virtual bool requiresProcessing() const { return true; } void unmuteForSolo(); + + QAtomicInt m_dependenciesMet; + void incrementDeps(); + void processed(); + private: virtual void doProcessing( sampleFrame * _working_buffer ); }; @@ -196,10 +202,13 @@ private: void allocateChannelsTo(int num); QMutex m_sendsMutex; +<<<<<<< HEAD void addChannelLeaf( FxChannel * ch, sampleFrame * buf ); int m_lastSoloed; +======= +>>>>>>> stable-1.1 friend class MixerWorkerThread; friend class FxMixerView; diff --git a/include/ThreadableJob.h b/include/ThreadableJob.h index 0a7655c51..c3da4c547 100644 --- a/include/ThreadableJob.h +++ b/include/ThreadableJob.h @@ -61,6 +61,11 @@ public: { m_state = Queued; } + + inline void done() + { + m_state = Done; + } void process( sampleFrame* workingBuffer = NULL ) { diff --git a/include/caption_menu.h b/include/caption_menu.h index 7bd3441c3..e8141e739 100644 --- a/include/caption_menu.h +++ b/include/caption_menu.h @@ -38,6 +38,12 @@ public: captionMenu( const QString & _title, QWidget * _parent = 0 ); virtual ~captionMenu(); + /// + /// \brief Adds a "Help" action displaying the Menu's parent's WhatsThis + /// text when selected. + /// + void addHelpAction(); + } ; diff --git a/plugins/BassBooster/BassBooster.cpp b/plugins/BassBooster/BassBooster.cpp index dbbde8ff0..38a9bced3 100644 --- a/plugins/BassBooster/BassBooster.cpp +++ b/plugins/BassBooster/BassBooster.cpp @@ -52,6 +52,9 @@ BassBoosterEffect::BassBoosterEffect( Model* parent, const Descriptor::SubPlugin m_bbFX( DspEffectLibrary::FastBassBoost( 70.0f, 1.0f, 2.8f ) ), m_bbControls( this ) { + changeFrequency(); + changeGain(); + changeRatio(); } @@ -70,6 +73,10 @@ bool BassBoosterEffect::processAudioBuffer( sampleFrame* buf, const fpp_t frames { return( false ); } + // check out changed controls + if( m_bbControls.m_freqModel.isValueChanged() ) { changeFrequency(); } + if( m_bbControls.m_gainModel.isValueChanged() ) { changeGain(); } + if( m_bbControls.m_ratioModel.isValueChanged() ) { changeRatio(); } double outSum = 0.0; const float d = dryLevel(); @@ -91,6 +98,32 @@ bool BassBoosterEffect::processAudioBuffer( sampleFrame* buf, const fpp_t frames } +inline void BassBoosterEffect::changeFrequency() +{ + const sample_t fac = engine::mixer()->processingSampleRate() / 44100.0f; + + m_bbFX.leftFX().setFrequency( m_bbControls.m_freqModel.value() * fac ); + m_bbFX.rightFX().setFrequency( m_bbControls.m_freqModel.value() * fac ); +} + + + + +inline void BassBoosterEffect::changeGain() +{ + m_bbFX.leftFX().setGain( m_bbControls.m_gainModel.value() ); + m_bbFX.rightFX().setGain( m_bbControls.m_gainModel.value() ); +} + + + + +inline void BassBoosterEffect::changeRatio() +{ + m_bbFX.leftFX().setRatio( m_bbControls.m_ratioModel.value() ); + m_bbFX.rightFX().setRatio( m_bbControls.m_ratioModel.value() ); +} + diff --git a/plugins/BassBooster/BassBooster.h b/plugins/BassBooster/BassBooster.h index b52302465..ad7c6c457 100644 --- a/plugins/BassBooster/BassBooster.h +++ b/plugins/BassBooster/BassBooster.h @@ -23,8 +23,8 @@ */ -#ifndef _BASS_BOOSTER_H -#define _BASS_BOOSTER_H +#ifndef BASS_BOOSTER_H +#define BASS_BOOSTER_H #include "Effect.h" #include "DspEffectLibrary.h" @@ -45,6 +45,10 @@ public: private: + void changeFrequency(); + void changeGain(); + void changeRatio(); + DspEffectLibrary::MonoToStereoAdaptor m_bbFX; BassBoosterControls m_bbControls; diff --git a/plugins/BassBooster/BassBoosterControls.cpp b/plugins/BassBooster/BassBoosterControls.cpp index 69a3952c7..13fd8463f 100644 --- a/plugins/BassBooster/BassBoosterControls.cpp +++ b/plugins/BassBooster/BassBoosterControls.cpp @@ -37,48 +37,17 @@ BassBoosterControls::BassBoosterControls( BassBoosterEffect* effect ) : m_gainModel( 1.0f, 0.1f, 5.0f, 0.05f, this, tr( "Gain" ) ), m_ratioModel( 2.0f, 0.1f, 10.0f, 0.1f, this, tr( "Ratio" ) ) { - connect( &m_freqModel, SIGNAL( dataChanged() ), this, SLOT( changeFrequency() ) ); - connect( &m_gainModel, SIGNAL( dataChanged() ), this, SLOT( changeGain() ) ); - connect( &m_ratioModel, SIGNAL( dataChanged() ), this, SLOT( changeRatio() ) ); connect( engine::mixer(), SIGNAL( sampleRateChanged() ), this, SLOT( changeFrequency() ) ); - - changeFrequency(); - changeGain(); - changeRatio(); } - - void BassBoosterControls::changeFrequency() { - const sample_t fac = engine::mixer()->processingSampleRate() / 44100.0f; - - m_effect->m_bbFX.leftFX().setFrequency( m_freqModel.value() * fac ); - m_effect->m_bbFX.rightFX().setFrequency( m_freqModel.value() * fac ); + m_effect->changeFrequency(); } - -void BassBoosterControls::changeGain() -{ - m_effect->m_bbFX.leftFX().setGain( m_gainModel.value() ); - m_effect->m_bbFX.rightFX().setGain( m_gainModel.value() ); -} - - - - -void BassBoosterControls::changeRatio() -{ - m_effect->m_bbFX.leftFX().setRatio( m_ratioModel.value() ); - m_effect->m_bbFX.rightFX().setRatio( m_ratioModel.value() ); -} - - - - void BassBoosterControls::loadSettings( const QDomElement& _this ) { m_freqModel.loadSettings( _this, "freq" ); diff --git a/plugins/BassBooster/BassBoosterControls.h b/plugins/BassBooster/BassBoosterControls.h index b26a31e18..5df888bc1 100644 --- a/plugins/BassBooster/BassBoosterControls.h +++ b/plugins/BassBooster/BassBoosterControls.h @@ -22,8 +22,8 @@ * */ -#ifndef _BASSBOOSTER_CONTROLS_H -#define _BASSBOOSTER_CONTROLS_H +#ifndef BASSBOOSTER_CONTROLS_H +#define BASSBOOSTER_CONTROLS_H #include "EffectControls.h" #include "BassBoosterControlDialog.h" @@ -62,9 +62,6 @@ public: private slots: void changeFrequency(); - void changeGain(); - void changeRatio(); - private: BassBoosterEffect* m_effect; @@ -73,7 +70,7 @@ private: FloatModel m_ratioModel; friend class BassBoosterControlDialog; - + friend class BassBoosterEffect; } ; #endif diff --git a/plugins/vibed/nine_button_selector.cpp b/plugins/vibed/nine_button_selector.cpp index 2e5eb74c3..4fbdbf6c9 100644 --- a/plugins/vibed/nine_button_selector.cpp +++ b/plugins/vibed/nine_button_selector.cpp @@ -251,9 +251,8 @@ void nineButtonSelector::updateButton( int _new_button ) void nineButtonSelector::contextMenuEvent( QContextMenuEvent * ) { - captionMenu contextMenu( windowTitle() ); - contextMenu.addAction( embed::getIconPixmap( "help" ), tr( "&Help" ), - this, SLOT( displayHelp() ) ); + captionMenu contextMenu( windowTitle(), this ); + contextMenu.addHelpAction(); contextMenu.exec( QCursor::pos() ); } diff --git a/plugins/vibed/vibed.cpp b/plugins/vibed/vibed.cpp index 7772e6d86..f2d0f0ed7 100644 --- a/plugins/vibed/vibed.cpp +++ b/plugins/vibed/vibed.cpp @@ -756,9 +756,8 @@ void vibedView::normalizeClicked() void vibedView::contextMenuEvent( QContextMenuEvent * ) { - captionMenu contextMenu( model()->displayName() ); - contextMenu.addAction( embed::getIconPixmap( "help" ), tr( "&Help" ), - this, SLOT( displayHelp() ) ); + captionMenu contextMenu( model()->displayName(), this ); + contextMenu.addHelpAction(); contextMenu.exec( QCursor::pos() ); } diff --git a/src/core/AutomatableModel.cpp b/src/core/AutomatableModel.cpp index 544ebf9d6..0cc15c9f6 100644 --- a/src/core/AutomatableModel.cpp +++ b/src/core/AutomatableModel.cpp @@ -47,6 +47,7 @@ AutomatableModel::AutomatableModel( DataType type, m_step( step ), m_range( max - min ), m_centerValue( m_minValue ), + m_valueChanged( false ), m_setValueDepth( 0 ), m_hasStrictStepSize( false ), m_hasLinkedModels( false ), @@ -240,6 +241,7 @@ void AutomatableModel::setValue( const float value ) (*it)->setJournalling( journalling ); } } + m_valueChanged = true; emit dataChanged(); } else @@ -334,6 +336,7 @@ void AutomatableModel::setAutomatedValue( const float value ) (*it)->setAutomatedValue( value ); } } + m_valueChanged = true; emit dataChanged(); } --m_setValueDepth; @@ -478,6 +481,7 @@ void AutomatableModel::setControllerConnection( ControllerConnection* c ) { QObject::connect( m_controllerConnection, SIGNAL( valueChanged() ), this, SIGNAL( dataChanged() ) ); QObject::connect( m_controllerConnection, SIGNAL( destroyed() ), this, SLOT( unlinkControllerConnection() ) ); + m_valueChanged = true; emit dataChanged(); } } diff --git a/src/core/FxMixer.cpp b/src/core/FxMixer.cpp index 55f18a286..9c52700d1 100644 --- a/src/core/FxMixer.cpp +++ b/src/core/FxMixer.cpp @@ -70,7 +70,8 @@ FxChannel::FxChannel( int idx, Model * _parent ) : m_name(), m_lock(), m_channelIndex( idx ), - m_queued( false ) + m_queued( false ), + m_dependenciesMet( 0 ) { engine::mixer()->clearAudioBuffer( m_buffer, engine::mixer()->framesPerPeriod() ); @@ -85,6 +86,27 @@ FxChannel::~FxChannel() } +inline void FxChannel::processed() +{ + foreach( FxRoute * receiverRoute, m_sends ) + { + if( receiverRoute->receiver()->m_muted == false ) + { + receiverRoute->receiver()->incrementDeps(); + } + } +} + +void FxChannel::incrementDeps() +{ + m_dependenciesMet.ref(); + if( m_dependenciesMet >= m_receives.size() ) + { + m_queued = true; + MixerWorkerThread::addJob( this ); + m_dependenciesMet = 0; + } +} void FxChannel::unmuteForSolo() { @@ -107,25 +129,14 @@ void FxChannel::doProcessing( sampleFrame * _buf ) // this improves cache hit rate _buf = m_buffer; - if( m_muteModel.value() == false ) + if( m_muted == false ) { - // OK, we are not muted, so we go recursively through all the channels - // which send to us (our children)... foreach( FxRoute * senderRoute, m_receives ) { FxChannel * sender = senderRoute->sender(); FloatModel * sendModel = senderRoute->amount(); if( ! sendModel ) qFatal( "Error: no send model found from %d to %d", senderRoute->senderIndex(), m_channelIndex ); - // wait for the sender job - either it's just been queued yet, - // then ThreadableJob::process() will process it now within this - // thread - otherwise it has been is is being processed by another - // thread and we just have to wait for it to finish - while( sender->state() != ThreadableJob::Done ) - { - sender->process(); - } - if( sender->m_hasInput || sender->m_stillRunning ) { // figure out if we're getting sample-exact input @@ -158,20 +169,28 @@ void FxChannel::doProcessing( sampleFrame * _buf ) m_hasInput = true; } } + + + const float v = m_volumeModel.value(); + + if( m_hasInput ) + { + // only start fxchain when we have input... + m_fxChain.startRunning(); + } + + m_stillRunning = m_fxChain.processAudioBuffer( _buf, fpp, m_hasInput ); + + m_peakLeft = qMax( m_peakLeft, engine::mixer()->peakValueLeft( _buf, fpp ) * v ); + m_peakRight = qMax( m_peakRight, engine::mixer()->peakValueRight( _buf, fpp ) * v ); } - - const float v = m_volumeModel.value(); - - if( m_hasInput ) + else { - // only start fxchain when we have input... - m_fxChain.startRunning(); + m_peakLeft = m_peakRight = 0.0f; } - m_stillRunning = m_fxChain.processAudioBuffer( _buf, fpp, m_hasInput ); - - m_peakLeft = qMax( m_peakLeft, engine::mixer()->peakValueLeft( _buf, fpp ) * v ); - m_peakRight = qMax( m_peakRight, engine::mixer()->peakValueRight( _buf, fpp ) * v ); + // increment dependency counter of all receivers + processed(); } @@ -456,11 +475,9 @@ void FxMixer::deleteChannelSend( FxRoute * route ) bool FxMixer::isInfiniteLoop( fx_ch_t sendFrom, fx_ch_t sendTo ) { if( sendFrom == sendTo ) return true; - //m_sendsMutex.lock(); FxChannel * from = m_fxChannels[sendFrom]; FxChannel * to = m_fxChannels[sendTo]; bool b = checkInfiniteLoop( from, to ); - //m_sendsMutex.unlock(); return b; } @@ -538,42 +555,38 @@ void FxMixer::prepareMasterMix() -void FxMixer::addChannelLeaf( FxChannel * ch, sampleFrame * buf ) -{ - // if we're muted or this channel is seen already, discount it - if( ch->m_queued ) - { - return; - } - - foreach( FxRoute * senderRoute, ch->m_receives ) - { - addChannelLeaf( senderRoute->sender(), buf ); - } - - // add this channel to job list - ch->m_queued = true; - MixerWorkerThread::addJob( ch ); -} - - - void FxMixer::masterMix( sampleFrame * _buf ) { const int fpp = engine::mixer()->framesPerPeriod(); - // recursively loop through channel dependency chain - // and add all channels to job list that have no dependencies - // when the channel completes it will check its parent to see if it needs - // to be processed. - //m_sendsMutex.lock(); - MixerWorkerThread::resetJobQueue( MixerWorkerThread::JobQueue::Dynamic ); - addChannelLeaf( m_fxChannels[0], _buf ); - while( m_fxChannels[0]->state() != ThreadableJob::Done ) + if( m_sendsMutex.tryLock() ) { - MixerWorkerThread::startAndWaitForJobs(); + // add the channels that have no dependencies (no incoming senders, ie. no receives) + // to the jobqueue. The channels that have receives get added when their senders get processed, which + // is detected by dependency counting. + // also instantly add all muted channels as they don't need to care about their senders, and can just increment the deps of + // their recipients right away. + MixerWorkerThread::resetJobQueue( MixerWorkerThread::JobQueue::Dynamic ); + foreach( FxChannel * ch, m_fxChannels ) + { + ch->m_muted = ch->m_muteModel.value(); + if( ch->m_muted ) // instantly "process" muted channels + { + ch->processed(); + ch->done(); + } + else if( ch->m_receives.size() == 0 ) + { + ch->m_queued = true; + MixerWorkerThread::addJob( ch ); + } + } + while( m_fxChannels[0]->state() != ThreadableJob::Done ) + { + MixerWorkerThread::startAndWaitForJobs(); + } + m_sendsMutex.unlock(); } - //m_sendsMutex.unlock(); // handle sample-exact data in master volume fader ValueBuffer * volBuf = m_fxChannels[0]->m_volumeModel.valueBuffer(); diff --git a/src/core/track.cpp b/src/core/track.cpp index b6640937f..3f60713e4 100644 --- a/src/core/track.cpp +++ b/src/core/track.cpp @@ -1044,7 +1044,7 @@ void trackContentWidget::updateBackground() // draw lines pmp.setPen( QPen( QColor( 0, 0, 0, 160 ), 1 ) ); // horizontal line - pmp.drawLine( 0, 0, w*2, 0 ); + pmp.drawLine( 0, h-1, w*2, h-1 ); // vertical lines for( float x = 0; x < w * 2; x += ppt ) diff --git a/src/gui/widgets/ControllerView.cpp b/src/gui/widgets/ControllerView.cpp index 05f9ba17d..3d0185ab4 100644 --- a/src/gui/widgets/ControllerView.cpp +++ b/src/gui/widgets/ControllerView.cpp @@ -176,14 +176,12 @@ void ControllerView::modelChanged() void ControllerView::contextMenuEvent( QContextMenuEvent * ) { - QPointer contextMenu = new captionMenu( model()->displayName() ); + QPointer contextMenu = new captionMenu( model()->displayName(), this ); contextMenu->addAction( embed::getIconPixmap( "cancel" ), tr( "&Remove this plugin" ), this, SLOT( deleteController() ) ); contextMenu->addSeparator(); - contextMenu->addAction( embed::getIconPixmap( "help" ), - tr( "&Help" ), - this, SLOT( displayHelp() ) ); + contextMenu->addHelpAction(); contextMenu->exec( QCursor::pos() ); delete contextMenu; } diff --git a/src/gui/widgets/EffectView.cpp b/src/gui/widgets/EffectView.cpp index 17e0daed8..3ecb785c3 100644 --- a/src/gui/widgets/EffectView.cpp +++ b/src/gui/widgets/EffectView.cpp @@ -245,7 +245,7 @@ void EffectView::closeEffects() void EffectView::contextMenuEvent( QContextMenuEvent * ) { - QPointer contextMenu = new captionMenu( model()->displayName() ); + QPointer contextMenu = new captionMenu( model()->displayName(), this ); contextMenu->addAction( embed::getIconPixmap( "arp_up" ), tr( "Move &up" ), this, SLOT( moveUp() ) ); @@ -257,9 +257,7 @@ void EffectView::contextMenuEvent( QContextMenuEvent * ) tr( "&Remove this plugin" ), this, SLOT( deletePlugin() ) ); contextMenu->addSeparator(); - contextMenu->addAction( embed::getIconPixmap( "help" ), - tr( "&Help" ), - this, SLOT( displayHelp() ) ); + contextMenu->addHelpAction(); contextMenu->exec( QCursor::pos() ); delete contextMenu; } diff --git a/src/gui/widgets/FxLine.cpp b/src/gui/widgets/FxLine.cpp index e940694c0..b97e551d7 100644 --- a/src/gui/widgets/FxLine.cpp +++ b/src/gui/widgets/FxLine.cpp @@ -183,7 +183,7 @@ void FxLine::mouseDoubleClickEvent( QMouseEvent * ) void FxLine::contextMenuEvent( QContextMenuEvent * ) { FxMixer * mix = engine::fxMixer(); - QPointer contextMenu = new captionMenu( mix->effectChannel( m_channelIndex )->m_name ); + QPointer contextMenu = new captionMenu( mix->effectChannel( m_channelIndex )->m_name, this ); if( m_channelIndex != 0 ) // no move-options in master { contextMenu->addAction( tr( "Move &left" ), this, SLOT( moveChannelLeft() ) ); @@ -199,9 +199,7 @@ void FxLine::contextMenuEvent( QContextMenuEvent * ) contextMenu->addSeparator(); } - contextMenu->addAction( embed::getIconPixmap( "help" ), - tr( "&Help" ), - this, SLOT( displayHelp() ) ); + contextMenu->addHelpAction(); contextMenu->exec( QCursor::pos() ); delete contextMenu; } diff --git a/src/gui/widgets/caption_menu.cpp b/src/gui/widgets/caption_menu.cpp index 3c2540823..2ae6b5a91 100644 --- a/src/gui/widgets/caption_menu.cpp +++ b/src/gui/widgets/caption_menu.cpp @@ -24,6 +24,7 @@ #include "caption_menu.h" +#include "embed.h" @@ -45,6 +46,19 @@ captionMenu::~captionMenu() +void captionMenu::addHelpAction() +{ + QWidget* parent = (QWidget*) this->parent(); + if (parent == NULL) + return; - + if (! parent->whatsThis().isEmpty()) { + addAction( embed::getIconPixmap( "help" ), tr( "&Help" ), + parent, SLOT( displayHelp() ) ); + } + else { + QAction* helpAction = addAction( embed::getIconPixmap("help"), tr("Help (not available)") ); + helpAction->setDisabled(true); + } +} diff --git a/src/gui/widgets/knob.cpp b/src/gui/widgets/knob.cpp index f4e808554..60acf72e1 100644 --- a/src/gui/widgets/knob.cpp +++ b/src/gui/widgets/knob.cpp @@ -481,11 +481,10 @@ void knob::contextMenuEvent( QContextMenuEvent * ) // an QApplication::restoreOverrideCursor()-call... mouseReleaseEvent( NULL ); - captionMenu contextMenu( model()->displayName() ); + captionMenu contextMenu( model()->displayName(), this ); addDefaultActions( &contextMenu ); contextMenu.addSeparator(); - contextMenu.addAction( embed::getIconPixmap( "help" ), tr( "&Help" ), - this, SLOT( displayHelp() ) ); + contextMenu.addHelpAction(); contextMenu.exec( QCursor::pos() ); } diff --git a/src/gui/widgets/tempo_sync_knob.cpp b/src/gui/widgets/tempo_sync_knob.cpp index 36820c4ad..1131ba441 100644 --- a/src/gui/widgets/tempo_sync_knob.cpp +++ b/src/gui/widgets/tempo_sync_knob.cpp @@ -83,7 +83,7 @@ void TempoSyncKnob::contextMenuEvent( QContextMenuEvent * ) { mouseReleaseEvent( NULL ); - captionMenu contextMenu( model()->displayName() ); + captionMenu contextMenu( model()->displayName(), this ); addDefaultActions( &contextMenu ); contextMenu.addSeparator(); @@ -147,9 +147,7 @@ void TempoSyncKnob::contextMenuEvent( QContextMenuEvent * ) } - contextMenu.addSeparator(); - contextMenu.addAction( embed::getIconPixmap( "help" ), tr( "&Help" ), - this, SLOT( displayHelp() ) ); + contextMenu.addHelpAction(); contextMenu.exec( QCursor::pos() ); delete syncMenu; diff --git a/src/tracks/InstrumentTrack.cpp b/src/tracks/InstrumentTrack.cpp index 66f0c75a8..dfc4e9278 100644 --- a/src/tracks/InstrumentTrack.cpp +++ b/src/tracks/InstrumentTrack.cpp @@ -806,6 +806,7 @@ void InstrumentTrack::loadTrackSpecificSettings( const QDomElement & thisElement } node = node.nextSibling(); } + updatePitchRange(); unlock(); } @@ -1585,10 +1586,3 @@ void InstrumentTrackWindow::loadSettings( const QDomElement& thisElement ) m_itv->m_tlb->setChecked( true ); } } - - - - - - -