From 808e18f20ace9b8d57cd6ef12881da1c91bf77aa Mon Sep 17 00:00:00 2001 From: Tres Finocchiaro Date: Tue, 11 Nov 2014 22:42:02 -0500 Subject: [PATCH 1/9] Set pitch range --- src/tracks/InstrumentTrack.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tracks/InstrumentTrack.cpp b/src/tracks/InstrumentTrack.cpp index 74a3378e8..da2804c1e 100644 --- a/src/tracks/InstrumentTrack.cpp +++ b/src/tracks/InstrumentTrack.cpp @@ -767,6 +767,7 @@ void InstrumentTrack::loadTrackSpecificSettings( const QDomElement & thisElement } node = node.nextSibling(); } + updatePitchRange(); engine::mixer()->unlock(); } From 269bbc3dae94fd804d7e03426f7a303350e28e3a Mon Sep 17 00:00:00 2001 From: Umcaruje Date: Fri, 14 Nov 2014 00:07:03 +0100 Subject: [PATCH 2/9] Fix misalignment in Song Editor --- src/core/track.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/track.cpp b/src/core/track.cpp index 5804a74be..9dfa5cfd3 100644 --- a/src/core/track.cpp +++ b/src/core/track.cpp @@ -893,7 +893,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 ) From 70508b0c372c988551d0a522e9d64b278a7c627f Mon Sep 17 00:00:00 2001 From: Lukas W Date: Fri, 14 Nov 2014 15:45:46 +0100 Subject: [PATCH 3/9] Don't display 'Help' action in context menus when there's no help text Fixes #1290 --- include/caption_menu.h | 6 ++++++ plugins/vibed/nine_button_selector.cpp | 5 ++--- plugins/vibed/vibed.cpp | 5 ++--- src/gui/widgets/ControllerView.cpp | 6 ++---- src/gui/widgets/EffectView.cpp | 6 ++---- src/gui/widgets/FxLine.cpp | 6 ++---- src/gui/widgets/caption_menu.cpp | 22 ++++++++++++++++++++++ src/gui/widgets/knob.cpp | 5 ++--- src/gui/widgets/tempo_sync_knob.cpp | 6 ++---- 9 files changed, 42 insertions(+), 25 deletions(-) diff --git a/include/caption_menu.h b/include/caption_menu.h index 0f70baadc..8d69e8704 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/vibed/nine_button_selector.cpp b/plugins/vibed/nine_button_selector.cpp index a1d80fb9e..b1a1b996f 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 4c1eba9cd..f48d2f6ee 100644 --- a/plugins/vibed/vibed.cpp +++ b/plugins/vibed/vibed.cpp @@ -755,9 +755,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/gui/widgets/ControllerView.cpp b/src/gui/widgets/ControllerView.cpp index 477e18fc7..f6f5160fc 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 25342dbdf..e3035315e 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 7a065d22d..0be3bce78 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 db839e8e4..8585bb578 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,27 @@ 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 = new QAction( embed::getIconPixmap("help"), tr("Help (not available)"), NULL); + helpAction->setDisabled(true); + addAction(helpAction); + } +} + + + + #include "moc_caption_menu.cxx" diff --git a/src/gui/widgets/knob.cpp b/src/gui/widgets/knob.cpp index e635cd3af..96b40a22f 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 12dd9067a..93979b4b6 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; From 9005dc39ca0c1bf2cff0d8ad9edb9930a8a48d09 Mon Sep 17 00:00:00 2001 From: Lukas W Date: Sat, 15 Nov 2014 17:46:07 +0100 Subject: [PATCH 4/9] Caption menu style fix --- data/themes/default/style.css | 2 -- src/gui/widgets/caption_menu.cpp | 3 +-- 2 files changed, 1 insertion(+), 4 deletions(-) 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/src/gui/widgets/caption_menu.cpp b/src/gui/widgets/caption_menu.cpp index 8585bb578..e239dc9e7 100644 --- a/src/gui/widgets/caption_menu.cpp +++ b/src/gui/widgets/caption_menu.cpp @@ -58,9 +58,8 @@ void captionMenu::addHelpAction() parent, SLOT( displayHelp() ) ); } else { - QAction* helpAction = new QAction( embed::getIconPixmap("help"), tr("Help (not available)"), NULL); + QAction* helpAction = addAction( embed::getIconPixmap("help"), tr("Help (not available)") ); helpAction->setDisabled(true); - addAction(helpAction); } } From c92774af27948a7065a68d1be5e5e3624dc87d00 Mon Sep 17 00:00:00 2001 From: Vesa Date: Sat, 15 Nov 2014 18:51:49 +0200 Subject: [PATCH 5/9] Improvement of FxMixer multithreading Use dynamic building of jobqueues with dependency counting: - At the start, each channel that has no dependencies is added automatically to the queue - Then, after each channel is processed, it increments the dep.counter of all its recipients - When a channel's dep.counter hits the amount of its dependencies (senders), it gets automatically added to the queue - The queue is finished when the master channel has been processed - Muted channels are automatically processed at the start regardless dependencies, because they don't have to care about senders, being muted Hopefully this will improve Fx Mixer performance. --- include/FxMixer.h | 8 ++-- src/core/FxMixer.cpp | 101 ++++++++++++++++++++++--------------------- 2 files changed, 56 insertions(+), 53 deletions(-) diff --git a/include/FxMixer.h b/include/FxMixer.h index 5c33e6fa8..c473e07d9 100644 --- a/include/FxMixer.h +++ b/include/FxMixer.h @@ -57,6 +57,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; @@ -65,7 +66,10 @@ class FxChannel : public ThreadableJob FxRouteVector m_receives; virtual bool requiresProcessing() const { return true; } - + + QAtomicInt m_dependenciesMet; + void incrementDeps(); + private: virtual void doProcessing( sampleFrame * _working_buffer ); }; @@ -189,8 +193,6 @@ private: void allocateChannelsTo(int num); QMutex m_sendsMutex; - void addChannelLeaf( FxChannel * ch, sampleFrame * buf ); - friend class MixerWorkerThread; friend class FxMixerView; diff --git a/src/core/FxMixer.cpp b/src/core/FxMixer.cpp index df05b1e6a..feb0f20fd 100644 --- a/src/core/FxMixer.cpp +++ b/src/core/FxMixer.cpp @@ -69,7 +69,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() ); @@ -84,6 +85,16 @@ FxChannel::~FxChannel() } +void FxChannel::incrementDeps() +{ + m_dependenciesMet.ref(); + if( m_dependenciesMet >= m_receives.size() ) + { + m_queued = true; + MixerWorkerThread::addJob( this ); + m_dependenciesMet = 0; + } +} void FxChannel::doProcessing( sampleFrame * _buf ) @@ -99,25 +110,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 ) { // get the send level... @@ -134,20 +134,34 @@ 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 + foreach( FxRoute * receiverRoute, m_sends ) + { + if( receiverRoute->receiver()->m_muteModel.value() == false ) + { + receiverRoute->receiver()->incrementDeps(); + } + } } @@ -462,42 +476,29 @@ 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(); + // 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 ); - addChannelLeaf( m_fxChannels[0], _buf ); + foreach( FxChannel * ch, m_fxChannels ) + { + ch->m_muted = ch->m_muteModel.value(); + if( ch->m_receives.size() == 0 || ch->m_muted ) + { + ch->m_queued = true; + MixerWorkerThread::addJob( ch ); + } + } while( m_fxChannels[0]->state() != ThreadableJob::Done ) { MixerWorkerThread::startAndWaitForJobs(); } - //m_sendsMutex.unlock(); const float v = m_fxChannels[0]->m_volumeModel.value(); MixHelpers::addSanitizedMultiplied( _buf, m_fxChannels[0]->m_buffer, v, fpp ); From ca06a10a4292f95c8922f4b089dbf7756078078c Mon Sep 17 00:00:00 2001 From: Vesa Date: Sat, 15 Nov 2014 21:11:40 +0200 Subject: [PATCH 6/9] Fix segfault when enabling/disabling sends while playing --- src/core/FxMixer.cpp | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/src/core/FxMixer.cpp b/src/core/FxMixer.cpp index feb0f20fd..2edcc4565 100644 --- a/src/core/FxMixer.cpp +++ b/src/core/FxMixer.cpp @@ -394,11 +394,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; } @@ -480,26 +478,30 @@ void FxMixer::masterMix( sampleFrame * _buf ) { const int fpp = engine::mixer()->framesPerPeriod(); - // 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 ) + if( m_sendsMutex.tryLock() ) { - ch->m_muted = ch->m_muteModel.value(); - if( ch->m_receives.size() == 0 || ch->m_muted ) + // 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_queued = true; - MixerWorkerThread::addJob( ch ); + ch->m_muted = ch->m_muteModel.value(); + if( ch->m_receives.size() == 0 || ch->m_muted ) + { + ch->m_queued = true; + MixerWorkerThread::addJob( ch ); + } } + while( m_fxChannels[0]->state() != ThreadableJob::Done ) + { + MixerWorkerThread::startAndWaitForJobs(); + } + m_sendsMutex.unlock(); } - while( m_fxChannels[0]->state() != ThreadableJob::Done ) - { - MixerWorkerThread::startAndWaitForJobs(); - } - + const float v = m_fxChannels[0]->m_volumeModel.value(); MixHelpers::addSanitizedMultiplied( _buf, m_fxChannels[0]->m_buffer, v, fpp ); From 8ef10f4f8198c92b8e518821477dd3ffe063212c Mon Sep 17 00:00:00 2001 From: Vesa Date: Sun, 16 Nov 2014 13:46:54 +0200 Subject: [PATCH 7/9] More updates to FxMixer - better handling of muted channels --- include/FxMixer.h | 1 + include/ThreadableJob.h | 5 +++++ src/core/FxMixer.cpp | 26 ++++++++++++++++++-------- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/include/FxMixer.h b/include/FxMixer.h index c473e07d9..88b5a0997 100644 --- a/include/FxMixer.h +++ b/include/FxMixer.h @@ -69,6 +69,7 @@ class FxChannel : public ThreadableJob QAtomicInt m_dependenciesMet; void incrementDeps(); + void processed(); private: virtual void doProcessing( sampleFrame * _working_buffer ); 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/src/core/FxMixer.cpp b/src/core/FxMixer.cpp index 2edcc4565..a83e84da8 100644 --- a/src/core/FxMixer.cpp +++ b/src/core/FxMixer.cpp @@ -85,6 +85,17 @@ 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(); @@ -155,13 +166,7 @@ void FxChannel::doProcessing( sampleFrame * _buf ) } // increment dependency counter of all receivers - foreach( FxRoute * receiverRoute, m_sends ) - { - if( receiverRoute->receiver()->m_muteModel.value() == false ) - { - receiverRoute->receiver()->incrementDeps(); - } - } + processed(); } @@ -489,7 +494,12 @@ void FxMixer::masterMix( sampleFrame * _buf ) foreach( FxChannel * ch, m_fxChannels ) { ch->m_muted = ch->m_muteModel.value(); - if( ch->m_receives.size() == 0 || ch->m_muted ) + 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 ); From 3e19bc8ddbc23b3e7a0411d5a21588444af46784 Mon Sep 17 00:00:00 2001 From: Vesa Date: Sun, 16 Nov 2014 14:14:35 +0200 Subject: [PATCH 8/9] Add a method to track value changes in AutomatableModel - this can be used by DSP code instead of signals/slots to improve performance --- include/AutomatableModel.h | 16 ++++++++++++++-- src/core/AutomatableModel.cpp | 4 ++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/include/AutomatableModel.h b/include/AutomatableModel.h index cc2764974..e8acac390 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 "JournallingObject.h" #include "Model.h" @@ -70,7 +70,8 @@ public: enum ScaleType { Linear, - Logarithmic + Logarithmic, + Decibel }; enum DataType @@ -239,6 +240,15 @@ public: return m_hasLinkedModels; } + bool isValueChanged() + { + if( m_valueChanged ) + { + m_valueChanged = false; + return true; + } + } + float globalAutomationValueAt( const MidiTime& time ); public slots: @@ -288,6 +298,8 @@ private: float m_step; float m_range; float m_centerValue; + + bool m_valueChanged; // most objects will need this temporarily (until sampleExact is // standard) diff --git a/src/core/AutomatableModel.cpp b/src/core/AutomatableModel.cpp index 12240d3b0..f2721a50a 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_hasLinkedModels( false ), m_controllerConnection( NULL ) @@ -234,6 +235,7 @@ void AutomatableModel::setValue( const float value ) (*it)->setJournalling( journalling ); } } + m_valueChanged = true; emit dataChanged(); } else @@ -327,6 +329,7 @@ void AutomatableModel::setAutomatedValue( const float value ) (*it)->setAutomatedValue( value ); } } + m_valueChanged = true; emit dataChanged(); } --m_setValueDepth; @@ -471,6 +474,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(); } } From f8c618b0edaca3bf0b1106ca4350cfdf79cf047a Mon Sep 17 00:00:00 2001 From: Vesa Date: Sun, 16 Nov 2014 14:51:50 +0200 Subject: [PATCH 9/9] Modify BassBooster to show how to replace signals/slots in DSP --- include/AutomatableModel.h | 4 +++ plugins/BassBooster/BassBooster.cpp | 33 +++++++++++++++++++++ plugins/BassBooster/BassBooster.h | 8 +++-- plugins/BassBooster/BassBoosterControls.cpp | 33 +-------------------- plugins/BassBooster/BassBoosterControls.h | 9 ++---- 5 files changed, 47 insertions(+), 40 deletions(-) diff --git a/include/AutomatableModel.h b/include/AutomatableModel.h index e8acac390..27c40ef82 100644 --- a/include/AutomatableModel.h +++ b/include/AutomatableModel.h @@ -240,6 +240,9 @@ 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 ) @@ -247,6 +250,7 @@ public: m_valueChanged = false; return true; } + return false; } float globalAutomationValueAt( const MidiTime& time ); 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 ea8614143..28d1a8f83 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