From d9d085d14e8258340d61f3e2402ee05bc675cbd4 Mon Sep 17 00:00:00 2001 From: Vesa Date: Fri, 27 Jun 2014 18:21:18 +0300 Subject: [PATCH 1/4] FxMixer: rewrite mixer routing --- include/FxMixer.h | 55 +++++++- src/core/FxMixer.cpp | 311 ++++++++++++++++++++++--------------------- 2 files changed, 212 insertions(+), 154 deletions(-) diff --git a/include/FxMixer.h b/include/FxMixer.h index 8136d9ed4..0857d696d 100644 --- a/include/FxMixer.h +++ b/include/FxMixer.h @@ -32,7 +32,8 @@ #include "ThreadableJob.h" - +class FxRoute; +typedef QVector FxRouteVector; class FxChannel : public ThreadableJob { @@ -58,11 +59,10 @@ class FxChannel : public ThreadableJob bool m_queued; // are we queued up for rendering yet? // pointers to other channels that this one sends to - QVector m_sends; - QVector m_sendAmount; + FxRouteVector m_sends; // pointers to other channels that send to this one - QVector m_receives; + FxRouteVector m_receives; virtual bool requiresProcessing() const { return true; } @@ -71,6 +71,43 @@ class FxChannel : public ThreadableJob }; +class FxRoute : public QObject +{ + public: + FxRoute( FxChannel * from, FxChannel * to, float amount ); + virtual ~FxRoute(); + + fx_ch_t senderIndex() const + { + return m_from->m_channelIndex; + } + + fx_ch_t receiverIndex() const + { + return m_to->m_channelIndex; + } + + FloatModel * amount() const + { + return m_amount; + } + + FxChannel * sender() const + { + return m_from; + } + + FxChannel * receiver() const + { + return m_to; + } + + private: + FxChannel * m_from; + FxChannel * m_to; + FloatModel * m_amount; +}; + class EXPORT FxMixer : public JournallingObject, public Model { @@ -100,13 +137,16 @@ public: // it is safe to call even if the send already exists void createChannelSend(fx_ch_t fromChannel, fx_ch_t toChannel, float amount = 1.0f); + void createRoute( FxChannel * from, FxChannel * to, float amount ); // delete the connection made by createChannelSend void deleteChannelSend(fx_ch_t fromChannel, fx_ch_t toChannel); + void deleteChannelSend( FxRoute * route ); // determine if adding a send from sendFrom to // sendTo would result in an infinite mixer loop. bool isInfiniteLoop(fx_ch_t fromChannel, fx_ch_t toChannel); + bool checkInfiniteLoop( FxChannel * from, FxChannel * to ); // return the FloatModel of fromChannel sending its output to the input of // toChannel. NULL if there is no send. @@ -129,11 +169,16 @@ public: // reset a channel's name, fx, sends, etc void clearChannel(fx_ch_t channelIndex); + // rename channels when moving etc. if they still have their original name + void validateChannelName( int index, int oldIndex ); + inline fx_ch_t numChannels() const { return m_fxChannels.size(); } + FxRouteVector m_fxRoutes; + private: // the fx channels in the mixer. index 0 is always master. QVector m_fxChannels; @@ -142,7 +187,7 @@ private: void allocateChannelsTo(int num); QMutex m_sendsMutex; - void addChannelLeaf( int _ch, sampleFrame * _buf ); + 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 961d6f8d6..59e32e3a6 100644 --- a/src/core/FxMixer.cpp +++ b/src/core/FxMixer.cpp @@ -34,6 +34,25 @@ #include "bb_track_container.h" +FxRoute::FxRoute( FxChannel * from, FxChannel * to, float amount ) : + m_from( from ), + m_to( to ) +{ + //qDebug( "created: %d to %d", m_from->m_channelIndex, m_to->m_channelIndex ); + // create send amount model + m_amount = new FloatModel( amount, 0, 1, 0.001, NULL, + tr( "Amount to send from channel %1 to channel %2" ).arg( m_from->m_channelIndex, m_to->m_channelIndex ) ); +} + + +FxRoute::~FxRoute() +{ + // remove send model + delete m_amount; +} + + + FxChannel::FxChannel( int idx, Model * _parent ) : m_fxChain( NULL ), m_hasInput( false ), @@ -65,7 +84,6 @@ FxChannel::~FxChannel() void FxChannel::doProcessing( sampleFrame * _buf ) { - FxMixer * fxm = engine::fxMixer(); const fpp_t fpp = engine::mixer()->framesPerPeriod(); // ignore the passed _buf @@ -77,20 +95,15 @@ void FxChannel::doProcessing( sampleFrame * _buf ) // this improves cache hit rate _buf = m_buffer; - // SMF: OK, due to the fact, that the data from the audio-tracks has been - // written into our buffer already, all which needs to be done at this - // stage is to process inter-channel sends. I really don't like the idea - // of using threads for this -- it just doesn't make any sense and wastes - // cpu-cylces... so I just go through every child of this channel and - // call the acc. doProcessing() directly. - if( m_muteModel.value() == false ) { // OK, we are not muted, so we go recursively through all the channels // which send to us (our children)... - foreach( fx_ch_t senderIndex, m_receives ) + foreach( FxRoute * senderRoute, m_receives ) { - FxChannel * sender = fxm->effectChannel( senderIndex ); + 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 @@ -104,8 +117,7 @@ void FxChannel::doProcessing( sampleFrame * _buf ) if( sender->m_hasInput || sender->m_stillRunning ) { // get the send level... - const float amt = - fxm->channelSendModel( senderIndex, m_channelIndex )->value(); + const float amt = sendModel->value(); // mix it's output with this one's output sampleFrame * ch_buf = sender->m_buffer; @@ -116,7 +128,7 @@ void FxChannel::doProcessing( sampleFrame * _buf ) _buf[f][1] += ch_buf[f][1] * v; } } - + // if sender channel hasInput, then we hasInput too if( sender->m_hasInput ) m_hasInput = true; } @@ -124,10 +136,10 @@ void FxChannel::doProcessing( sampleFrame * _buf ) const float v = m_volumeModel.value(); - if( m_hasInput ) + if( m_hasInput ) { // only start fxchain when we have input... - m_fxChain.startRunning(); + m_fxChain.startRunning(); } if( m_hasInput || m_stillRunning ) { @@ -152,12 +164,12 @@ FxMixer::FxMixer() : FxMixer::~FxMixer() { + while( ! m_fxRoutes.isEmpty() ) + { + deleteChannelSend( m_fxRoutes.first() ); + } for( int i = 0; i < m_fxChannels.size(); ++i ) { - for( int j = 0; j < m_fxChannels[i]->m_sendAmount.size(); ++j) - { - delete m_fxChannels[i]->m_sendAmount[j]; - } delete m_fxChannels[i]; } } @@ -177,10 +189,12 @@ int FxMixer::createChannel() } -void FxMixer::deleteChannel(int index) +void FxMixer::deleteChannel( int index ) { m_fxChannels[index]->m_lock.lock(); + FxChannel * ch = m_fxChannels[index]; + // go through every instrument and adjust for the channel index change TrackContainer::TrackList tracks; tracks += engine::getSong()->tracks(); @@ -207,52 +221,34 @@ void FxMixer::deleteChannel(int index) } // delete all of this channel's sends and receives - while( ! m_fxChannels[index]->m_sends.isEmpty() ) + while( ! ch->m_sends.isEmpty() ) { - deleteChannelSend( index, m_fxChannels[index]->m_sends.first() ); + deleteChannelSend( ch->m_sends.first() ); } - while( ! m_fxChannels[index]->m_receives.isEmpty() ) + while( ! ch->m_receives.isEmpty() ) { - deleteChannelSend( m_fxChannels[index]->m_receives.first(), index ); - } - - for(int i=0; im_sends.size(); ++j) - { - if( m_fxChannels[i]->m_sends[j] > index ) - { - // subtract 1 to make up for the missing channel - --m_fxChannels[i]->m_sends[j]; - } - } - for(int j=0; jm_receives.size(); ++j) - { - if( m_fxChannels[i]->m_receives[j] > index ) - { - // subtract 1 to make up for the missing channel - --m_fxChannels[i]->m_receives[j]; - } - } - + deleteChannelSend( ch->m_receives.first() ); } // actually delete the channel delete m_fxChannels[index]; m_fxChannels.remove(index); + + for( int i = index; i < m_fxChannels.size(); ++i ) + { + validateChannelName( i, i + 1 ); + } } -void FxMixer::moveChannelLeft(int index) +void FxMixer::moveChannelLeft( int index ) { // can't move master or first channel if( index <= 1 || index >= m_fxChannels.size() ) { return; } - m_sendsMutex.lock(); // channels to swap int a = index - 1, b = index; @@ -283,122 +279,132 @@ void FxMixer::moveChannelLeft(int index) } } - for(int i=0; im_sends.size(); ++j) - { - if( m_fxChannels[i]->m_sends[j] == a ) - { - m_fxChannels[i]->m_sends[j] = b; - } - else if( m_fxChannels[i]->m_sends[j] == b ) - { - m_fxChannels[i]->m_sends[j] = a; - } - } - for(int j=0; jm_receives.size(); ++j) - { - if( m_fxChannels[i]->m_receives[j] == a ) - { - m_fxChannels[i]->m_receives[j] = b; - } - else if( m_fxChannels[i]->m_receives[j] == b ) - { - m_fxChannels[i]->m_receives[j] = a; - } - } - } - // actually do the swap FxChannel * tmpChannel = m_fxChannels[a]; m_fxChannels[a] = m_fxChannels[b]; m_fxChannels[b] = tmpChannel; - m_sendsMutex.unlock(); + + validateChannelName( a, b ); + validateChannelName( b, a ); } -void FxMixer::moveChannelRight(int index) +void FxMixer::moveChannelRight( int index ) { - moveChannelLeft(index+1); + moveChannelLeft( index + 1 ); } -void FxMixer::createChannelSend(fx_ch_t fromChannel, fx_ch_t toChannel, - float amount) +void FxMixer::createChannelSend( fx_ch_t fromChannel, fx_ch_t toChannel, + float amount ) { +// qDebug( "requested: %d to %d", fromChannel, toChannel ); // find the existing connection FxChannel * from = m_fxChannels[fromChannel]; - for(int i=0; im_sends.size(); ++i){ - if( from->m_sends[i] == toChannel ) + FxChannel * to = m_fxChannels[toChannel]; + + for( int i=0; im_sends.size(); ++i ) + { + if( from->m_sends[i]->receiver() == to ) { // simply adjust the amount - from->m_sendAmount[i]->setValue(amount); + from->m_sends[i]->amount()->setValue( amount ); return; } } // connection does not exist. create a new one - m_sendsMutex.lock(); - // add to from's sends - from->m_sends.push_back(toChannel); - from->m_sendAmount.push_back(new FloatModel(amount, 0, 1, 0.001, NULL, - tr("Amount to send"))); + createRoute( from, to, amount ); +} - // add to to's receives - m_fxChannels[toChannel]->m_receives.push_back(fromChannel); + +void FxMixer::createRoute( FxChannel * from, FxChannel * to, float amount ) +{ + if( from == to ) + { + return; + } + m_sendsMutex.lock(); + FxRoute * route = new FxRoute( from, to, amount ); + + // add us to from's sends + from->m_sends.append( route ); + + // add us to to's receives + to->m_receives.append( route ); + + // add us to fxmixer's list + engine::fxMixer()->m_fxRoutes.append( route ); m_sendsMutex.unlock(); } - // delete the connection made by createChannelSend -void FxMixer::deleteChannelSend(fx_ch_t fromChannel, fx_ch_t toChannel) +void FxMixer::deleteChannelSend( fx_ch_t fromChannel, fx_ch_t toChannel ) { // delete the send FxChannel * from = m_fxChannels[fromChannel]; FxChannel * to = m_fxChannels[toChannel]; - m_sendsMutex.lock(); - // find and delete the send entry - for(int i=0; im_sends.size(); ++i) { - if( from->m_sends[i] == toChannel ) - { - // delete this index - delete from->m_sendAmount[i]; - from->m_sendAmount.remove(i); - from->m_sends.remove(i); - break; - } - } - // find and delete the receive entry - for(int i=0; im_receives.size(); ++i) + // find and delete the send entry + for( int i = 0; i < from->m_sends.size(); ++i ) { - if( to->m_receives[i] == fromChannel ) + if( from->m_sends[i]->receiver() == to ) { - // delete this index - to->m_receives.remove(i); + deleteChannelSend( from->m_sends[i] ); break; } } +} + + +void FxMixer::deleteChannelSend( FxRoute * route ) +{ + m_sendsMutex.lock(); + // remove us from from's sends + route->sender()->m_sends.remove( route->sender()->m_sends.indexOf( route ) ); + // remove us from to's receives + route->receiver()->m_receives.remove( route->receiver()->m_receives.indexOf( route ) ); + // remove us from fxmixer's list + engine::fxMixer()->m_fxRoutes.remove( engine::fxMixer()->m_fxRoutes.indexOf( route ) ); + delete route; m_sendsMutex.unlock(); } -bool FxMixer::isInfiniteLoop(fx_ch_t sendFrom, fx_ch_t sendTo) { +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; +} + + +bool FxMixer::checkInfiniteLoop( FxChannel * from, FxChannel * to ) +{ // can't send master to anything - if( sendFrom == 0 ) return true; + if( from == m_fxChannels[0] ) + { + return true; + } // can't send channel to itself - if( sendFrom == sendTo ) return true; + if( from == to ) + { + return true; + } // follow sendTo's outputs recursively looking for something that sends // to sendFrom - for(int i=0; im_sends.size(); ++i) + for( int i=0; i < to->m_sends.size(); ++i ) { - if( isInfiniteLoop( sendFrom, m_fxChannels[sendTo]->m_sends[i] ) ) + if( checkInfiniteLoop( from, to->m_sends[i]->receiver() ) ) { return true; } @@ -409,13 +415,23 @@ bool FxMixer::isInfiniteLoop(fx_ch_t sendFrom, fx_ch_t sendTo) { // how much does fromChannel send its output to the input of toChannel? -FloatModel * FxMixer::channelSendModel(fx_ch_t fromChannel, fx_ch_t toChannel) +FloatModel * FxMixer::channelSendModel( fx_ch_t fromChannel, fx_ch_t toChannel ) { - FxChannel * from = m_fxChannels[fromChannel]; - for(int i=0; im_sends.size(); ++i){ - if( from->m_sends[i] == toChannel ) - return from->m_sendAmount[i]; + if( fromChannel == toChannel ) + { + return NULL; } + FxChannel * from = m_fxChannels[fromChannel]; + FxChannel * to = m_fxChannels[toChannel]; + + foreach( FxRoute * route, from->m_sends ) + { + if( route->receiver() == to ) + { + return route->amount(); + } + } + return NULL; } @@ -423,15 +439,6 @@ FloatModel * FxMixer::channelSendModel(fx_ch_t fromChannel, fx_ch_t toChannel) void FxMixer::mixToChannel( const sampleFrame * _buf, fx_ch_t _ch ) { - // SMF: it seems like here the track-channels are mixed in... but from where - // is this called and when and why...?!? - // - // OK, found it (git grep is your friend...): This is the next part, - // where there is a mix between push and pull model inside the core, as - // the audio-tracks *push* their data into the fx-channels hopefully just - // before the Mixer-Channels are processed... Sorry to say this: but this - // took me senseless hours to find out and is silly, too... - if( m_fxChannels[_ch]->m_muteModel.value() == false ) { m_fxChannels[_ch]->m_lock.lock(); @@ -452,24 +459,22 @@ void FxMixer::prepareMasterMix() -void FxMixer::addChannelLeaf( int _ch, sampleFrame * _buf ) +void FxMixer::addChannelLeaf( FxChannel * ch, sampleFrame * buf ) { - FxChannel * thisCh = m_fxChannels[_ch]; - // if we're muted or this channel is seen already, discount it - if( thisCh->m_queued ) + if( ch->m_queued ) { return; } - foreach( const int senderIndex, thisCh->m_receives ) + foreach( FxRoute * senderRoute, ch->m_receives ) { - addChannelLeaf( senderIndex, _buf ); + addChannelLeaf( senderRoute->sender(), buf ); } // add this channel to job list - thisCh->m_queued = true; - MixerWorkerThread::addJob( thisCh ); + ch->m_queued = true; + MixerWorkerThread::addJob( ch ); } @@ -482,15 +487,14 @@ void FxMixer::masterMix( sampleFrame * _buf ) // 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(); + //m_sendsMutex.lock(); MixerWorkerThread::resetJobQueue( MixerWorkerThread::JobQueue::Dynamic ); - addChannelLeaf( 0, _buf ); + addChannelLeaf( m_fxChannels[0], _buf ); while( m_fxChannels[0]->state() != ThreadableJob::Done ) { MixerWorkerThread::startAndWaitForJobs(); } - //m_fxChannels[0]->doProcessing( NULL ); - m_sendsMutex.unlock(); + //m_sendsMutex.unlock(); const float v = m_fxChannels[0]->m_volumeModel.value(); MixHelpers::addMultiplied( _buf, m_fxChannels[0]->m_buffer, v, fpp ); @@ -532,7 +536,7 @@ void FxMixer::clearChannel(fx_ch_t index) ch->m_volumeModel.setValue( 1.0f ); ch->m_muteModel.setValue( false ); ch->m_name = ( index == 0 ) ? tr( "Master" ) : tr( "FX %1" ).arg( index ); - ch->m_volumeModel.setDisplayName(ch->m_name ); + ch->m_volumeModel.setDisplayName( ch->m_name ); // send only to master if( index > 0) @@ -540,17 +544,17 @@ void FxMixer::clearChannel(fx_ch_t index) // delete existing sends while( ! ch->m_sends.isEmpty() ) { - deleteChannelSend( index, ch->m_sends.first() ); + deleteChannelSend( ch->m_sends.first() ); } // add send to master - createChannelSend(index, 0); + createChannelSend( index, 0 ); } // delete receives while( ! ch->m_receives.isEmpty() ) { - deleteChannelSend( ch->m_receives.first(), index ); + deleteChannelSend( ch->m_receives.first() ); } } @@ -575,8 +579,8 @@ void FxMixer::saveSettings( QDomDocument & _doc, QDomElement & _this ) QDomElement sendsDom = _doc.createElement( QString( "send" ) ); fxch.appendChild( sendsDom ); - sendsDom.setAttribute( "channel", ch->m_sends[si] ); - ch->m_sendAmount[si]->saveSettings( _doc, sendsDom, "amount"); + sendsDom.setAttribute( "channel", ch->m_sends[si]->receiverIndex() ); + ch->m_sends[si]->amount()->saveSettings( _doc, sendsDom, "amount" ); } } } @@ -589,7 +593,7 @@ void FxMixer::allocateChannelsTo(int num) createChannel(); // delete the default send to master - deleteChannelSend(m_fxChannels.size()-1, 0); + deleteChannelSend( m_fxChannels.size()-1, 0 ); } } @@ -626,7 +630,7 @@ void FxMixer::loadSettings( const QDomElement & _this ) { thereIsASend = true; int sendTo = chDataItem.attribute( "channel" ).toInt(); - allocateChannelsTo( sendTo) ; + allocateChannelsTo( sendTo ) ; float amount = chDataItem.attribute( "amount" ).toFloat(); createChannelSend( num, sendTo, amount ); } @@ -642,10 +646,19 @@ void FxMixer::loadSettings( const QDomElement & _this ) // create a send from every channel into master for( int i=1; im_name == tr( "FX %1" ).arg( oldIndex ) ) + { + fxc->m_name = tr( "FX %1" ).arg( index ); + } +} From 9243d94484125a3e97bc57d2bcd7e5c1a926c04b Mon Sep 17 00:00:00 2001 From: Vesa Date: Fri, 27 Jun 2014 23:17:21 +0300 Subject: [PATCH 2/4] Fix qstring arg --- data/themes/default/mixer_send_off.png | Bin 1022 -> 817 bytes data/themes/default/mixer_send_on.png | Bin 1675 -> 1476 bytes include/FxLine.h | 3 ++- src/core/FxMixer.cpp | 2 +- src/gui/widgets/FxLine.cpp | 17 ++++++++++++++--- 5 files changed, 17 insertions(+), 5 deletions(-) diff --git a/data/themes/default/mixer_send_off.png b/data/themes/default/mixer_send_off.png index 1be1ad54f20a570b743b38e04939c58705777d5d..3033c4962ac871abc3d18064610d04fa93c9a224 100644 GIT binary patch delta 752 zcmV8?PLTPJ@4nMp)JR7l6|mCH*TQ5431lMERRD)=B97m3;UfJ|a`f}kL} z5H~^##ck-S{dZbuH+3i7b<<^ns3?kYp)i7pAh)BizruCh&*gIYgA|>Z znD`33Z#J9Qw*Bma&%mc@wfZptpeV|lX0u7F)p}G=(==&{qM)iOp-@QrRaHe*RTM=* z(=?B-2k!vXKcd67Z38eqKF-R@3PVFf7>2>Y!2y{}MrLhoZ80@9MIw=4b8{2RvRGVP z#C2WH&d%7_*Z_aPvMdUP0y{f9vJoM~s1)r!vxS8POw%Nv&(qh}C&dmA4>3)Xdc7{Y zo1L9yZ*R}n&i?*BBO@cEQYmh4Z!rwR<5xSw(Lp#IrdTX;dU^`Lz`y_i#bS|ixh&%v zjRuKCf}^7&pQvFNSe8XN9A` zb*`_kiAH~;G#U-b&&pOa3faU4g+>bg#=)gqhCQYw`m{|rVVkzeh0 zd!$?ZCDC?8R<0D?3CcXxL``}_MNLWnpJ?j5d|=u`;t itzNHZ{{LfN9lrsB8gN&s`5a^b0000(-2L1<-Dlq^60002_L%V+f000SaNLh0L01FcU01FcV0GgZ_00007bV*G` z2i^t~3K=EzpCYG`TPJ@5W=TXrR7l6=l;2NVWf;dl@2{SgZfb}ytTYuOT>z6!r1wU) zB}+^+F1p?AZ}2bi&P(q|%)D}jq!<>>NFbzuS%B39yC$uz&?*Fv14_?1uNSA3)=@6z z<(}l^JkN8^`+VQ;^9x=T5uL{EPw##8_x_)wQ6~~bNTd)ny(WK7G>X^sh{xjuzK?G$ zf#;#L!S|XN6CoOnA|&{pPqZ(Fk_v4MhtHp*oxZ2D-+cY$DUR+0{j2uJsMg9p`|a2F zP8yAbR1(p;my|7C0G6{iHq?Ev1c1aR02^AL-@E_46N`;@;>a%EHi+(2N*T{;|`oH=1nkR|t z*RGRDBp4eTd+EAuZ*NnrR(Z1VBmrz*2&$AKnM{&Sr~g;8jE|3_wPs^u0~^-i{PbEZ zNXg{nB#lOc*>7ig^z$Q(F)S}Hlbz3!ozLR?K1)kW936ihVT_?tsbGxZ!FLbH&Sxo= zN*o^_GchrNP>LX+H)s$9C?U{V^KkAVw{F~G=EE7Z*6i)?k(thL^Ttga$Dv-YQz#UW zQnIkHfYur(;xKe&h)ShGxm-qTjS>PSyN0AYy^)B6>$>Fgd1|{g78e(pdVdOlot+(O zwHmJL0$*fD<^ra^-_|o9WGIzO zEG;j!eUBF(lgs5eJUj$o?ANHdTN@rU)IhpGM%Bn zzrSs#QYnNGY;A3w+eoK!blm98v{TCEGHdH=TupypZToVoxi-_&G!G9CbJ9Ekz;#_# zS69j9atsU(bd=5XW-5fhS|}EajEszsOeWjkWdjPXbDVr9oioO%o(8p@O=bhEwPDa!(^)K*pyi_l94>roEw?}Z zBo}ca$32<$4-7r~=U{I%J$Y^O%3E)5Ub_4`N_TI{m=ifSoyLU!IT1rF8X+Ew0)lwF hFIKMBp7Kh{zn$S?DU}6j-~a#s07*qoM6LruV1k0Z$EW}R diff --git a/data/themes/default/mixer_send_on.png b/data/themes/default/mixer_send_on.png index 5982ea3f69d31aca2dadd375bf160bec493251c1..776398e9fc3ed65e2164aadc2d6407229b7f325d 100644 GIT binary patch delta 1415 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 O0000m_channelIndex, m_to->m_channelIndex ); // create send amount model m_amount = new FloatModel( amount, 0, 1, 0.001, NULL, - tr( "Amount to send from channel %1 to channel %2" ).arg( m_from->m_channelIndex, m_to->m_channelIndex ) ); + tr( "Amount to send from channel %1 to channel %2" ).arg( m_from->m_channelIndex ).arg( m_to->m_channelIndex ) ); } diff --git a/src/gui/widgets/FxLine.cpp b/src/gui/widgets/FxLine.cpp index ce696cc10..ea8f6353d 100644 --- a/src/gui/widgets/FxLine.cpp +++ b/src/gui/widgets/FxLine.cpp @@ -41,6 +41,7 @@ const int FxLine::FxLineHeight = 287; QPixmap * FxLine::s_sendBgArrow = NULL; +QPixmap * FxLine::s_receiveBgArrow = NULL; FxLine::FxLine( QWidget * _parent, FxMixerView * _mv, int _channelIndex) : QWidget( _parent ), @@ -51,6 +52,10 @@ FxLine::FxLine( QWidget * _parent, FxMixerView * _mv, int _channelIndex) : { s_sendBgArrow = new QPixmap( embed::getIconPixmap( "send_bg_arrow", 29, 56 ) ); } + if( ! s_receiveBgArrow ) + { + s_receiveBgArrow = new QPixmap( embed::getIconPixmap( "receive_bg_arrow", 29, 56 ) ); + } setFixedSize( 33, FxLineHeight ); setAttribute( Qt::WA_OpaquePaintEvent, true ); @@ -103,7 +108,7 @@ void FxLine::setChannelIndex(int index) { } -void FxLine::drawFxLine( QPainter* p, const FxLine *fxLine, const QString& name, bool isActive, bool sendToThis ) +void FxLine::drawFxLine( QPainter* p, const FxLine *fxLine, const QString& name, bool isActive, bool sendToThis, bool receiveFromThis ) { int width = fxLine->rect().width(); int height = fxLine->rect().height(); @@ -126,7 +131,11 @@ void FxLine::drawFxLine( QPainter* p, const FxLine *fxLine, const QString& name, // draw the mixer send background if( sendToThis ) { - p->drawPixmap( 2, 0, 29, 56, *FxLine::s_sendBgArrow ); + p->drawPixmap( 2, 0, 29, 56, *s_sendBgArrow ); + } + else if( receiveFromThis ) + { + p->drawPixmap( 2, 0, 29, 56, *s_receiveBgArrow ); } // draw the channel name @@ -148,11 +157,13 @@ void FxLine::paintEvent( QPaintEvent * ) FxMixer * mix = engine::fxMixer(); bool sendToThis = mix->channelSendModel( m_mv->currentFxLine()->m_channelIndex, m_channelIndex ) != NULL; + bool receiveFromThis = mix->channelSendModel( + m_channelIndex, m_mv->currentFxLine()->m_channelIndex ) != NULL; QPainter painter; painter.begin( this ); drawFxLine( &painter, this, mix->effectChannel( m_channelIndex )->m_name, - m_mv->currentFxLine() == this, sendToThis ); + m_mv->currentFxLine() == this, sendToThis, receiveFromThis ); painter.end(); } From 31b82fe50b8ebf277744067b603f4a1c3aabefbe Mon Sep 17 00:00:00 2001 From: Vesa Date: Fri, 27 Jun 2014 23:19:06 +0300 Subject: [PATCH 3/4] Receive arrow --- data/themes/default/receive_bg_arrow.png | Bin 0 -> 289 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 data/themes/default/receive_bg_arrow.png diff --git a/data/themes/default/receive_bg_arrow.png b/data/themes/default/receive_bg_arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..f456176e0f16c2d02029b88bd46bd772aa4d8e7f GIT binary patch literal 289 zcmeAS@N?(olHy`uVBq!ia0vp^vOsLX!3HE5KYi{3Qk(@Ik;M!Q+`=Ht$S`Y;1W=H@ z#M9T6{T`dNu!Z54nZcSsA;}Wgh!W@g+}zZ>5(ej@)Wnk16ovB4k_-iRPv3y>Mm}+% zqS>A?09!e~Et_hQopqJDuFn3u~Xyxx1|^}=bt?|q58 zVkSB5-ih?ZD;k=hAnf$MMlEYrQ9(>FVdQ&MBb@09(FnwEzGB literal 0 HcmV?d00001 From 0058b1064fd194fbaba083fe388ef939741bef51 Mon Sep 17 00:00:00 2001 From: Vesa Date: Sat, 28 Jun 2014 10:06:52 +0300 Subject: [PATCH 4/4] Update channel send model names properly --- include/FxMixer.h | 2 ++ src/core/FxMixer.cpp | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/include/FxMixer.h b/include/FxMixer.h index 0857d696d..1b24bb54b 100644 --- a/include/FxMixer.h +++ b/include/FxMixer.h @@ -101,6 +101,8 @@ class FxRoute : public QObject { return m_to; } + + void updateName(); private: FxChannel * m_from; diff --git a/src/core/FxMixer.cpp b/src/core/FxMixer.cpp index a8f96c6c6..331d2b45d 100644 --- a/src/core/FxMixer.cpp +++ b/src/core/FxMixer.cpp @@ -52,6 +52,15 @@ FxRoute::~FxRoute() } +void FxRoute::updateName() +{ + if( m_amount) + { + m_amount->setDisplayName( + tr( "Amount to send from channel %1 to channel %2" ).arg( m_from->m_channelIndex ).arg( m_to->m_channelIndex ) ); + } +} + FxChannel::FxChannel( int idx, Model * _parent ) : m_fxChain( NULL ), @@ -661,4 +670,16 @@ void FxMixer::validateChannelName( int index, int oldIndex ) { fxc->m_name = tr( "FX %1" ).arg( index ); } + // set correct channel index + fxc->m_channelIndex = index; + + // now check all routes and update names of the send models + foreach( FxRoute * r, fxc->m_sends ) + { + r->updateName(); + } + foreach( FxRoute * r, fxc->m_receives ) + { + r->updateName(); + } }