From 1c0f9700fa1f9003f32df602d9a4f134a6fae7c2 Mon Sep 17 00:00:00 2001 From: Vesa Date: Sun, 1 Jun 2014 07:17:43 +0300 Subject: [PATCH 1/2] S.ex. models: implement support for sample-exact controls in fx-mixer Works for all faders and send knobs --- include/ValueBuffer.h | 23 +++++++++++++ src/core/FxMixer.cpp | 76 +++++++++++++++++++++++++++++++++++-------- 2 files changed, 85 insertions(+), 14 deletions(-) diff --git a/include/ValueBuffer.h b/include/ValueBuffer.h index b82844bca..a6731f425 100644 --- a/include/ValueBuffer.h +++ b/include/ValueBuffer.h @@ -122,6 +122,29 @@ public: } } + void multiply( float f ) + { + for( int i = 0; i < m_length; i++ ) + { + m_values[i] *= f; + } + } + + ValueBuffer & operator*=( const float & f ) + { + multiply( f ); + return *this; + } + + ValueBuffer & operator+=( const ValueBuffer & v ) + { + for( int i = 0; i < qMin( m_length, v.length() ); i++ ) + { + m_values[i] += v.values()[i]; + } + return *this; + } + static ValueBuffer interpolatedBuffer( float start, float end, int length ) { ValueBuffer vb = ValueBuffer( length ); diff --git a/src/core/FxMixer.cpp b/src/core/FxMixer.cpp index d2c79a972..222e214ef 100644 --- a/src/core/FxMixer.cpp +++ b/src/core/FxMixer.cpp @@ -32,7 +32,7 @@ #include "InstrumentTrack.h" #include "bb_track_container.h" - +#include "ValueBuffer.h" FxChannel::FxChannel( int idx, Model * _parent ) : m_fxChain( NULL ), @@ -42,7 +42,7 @@ FxChannel::FxChannel( int idx, Model * _parent ) : m_peakRight( 0.0f ), m_buffer( new sampleFrame[engine::mixer()->framesPerPeriod()] ), m_muteModel( false, _parent ), - m_volumeModel( 1.0, 0.0, 2.0, 0.01, _parent ), + m_volumeModel( 1.0, 0.0, 2.0, 0.001, _parent ), m_name(), m_lock(), m_channelIndex( idx ), @@ -79,10 +79,7 @@ void FxChannel::doProcessing( sampleFrame * _buf ) // 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. + // stage is to process inter-channel sends. if( m_muteModel.value() == false ) { @@ -103,17 +100,52 @@ 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(); + // figure out if we're getting sample-exact input + ValueBuffer * sendBuf = fxm->channelSendModel( senderIndex, m_channelIndex )->hasSampleExactData() + ? fxm->channelSendModel( senderIndex, m_channelIndex )->valueBuffer() + : NULL; + ValueBuffer * volBuf = sender->m_volumeModel.hasSampleExactData() + ? sender->m_volumeModel.valueBuffer() + : NULL; // mix it's output with this one's output sampleFrame * ch_buf = sender->m_buffer; - const float v = sender->m_volumeModel.value() * amt; - for( f_cnt_t f = 0; f < fpp; ++f ) + + // use sample-exact mixing if sample-exact values are available + if( ! volBuf && ! sendBuf ) // neither volume nor send has sample-exact data... { - _buf[f][0] += ch_buf[f][0] * v; - _buf[f][1] += ch_buf[f][1] * v; + const float v = sender->m_volumeModel.value() * fxm->channelSendModel( senderIndex, m_channelIndex )->value(); + for( f_cnt_t f = 0; f < fpp; ++f ) + { + _buf[f][0] += ch_buf[f][0] * v; + _buf[f][1] += ch_buf[f][1] * v; + } + } + else if( volBuf && sendBuf ) // both volume and send have sample-exact data + { + for( f_cnt_t f = 0; f < fpp; ++f ) + { + _buf[f][0] += ch_buf[f][0] * sendBuf->values()[f] * volBuf->values()[f]; + _buf[f][1] += ch_buf[f][1] * sendBuf->values()[f] * volBuf->values()[f]; + } + } + else if( volBuf ) // volume has sample-exact data but send does not + { + const float v = fxm->channelSendModel( senderIndex, m_channelIndex )->value(); + for( f_cnt_t f = 0; f < fpp; ++f ) + { + _buf[f][0] += ch_buf[f][0] * v * volBuf->values()[f]; + _buf[f][1] += ch_buf[f][1] * v * volBuf->values()[f]; + } + } + else // vice versa + { + const float v = sender->m_volumeModel.value(); + for( f_cnt_t f = 0; f < fpp; ++f ) + { + _buf[f][0] += ch_buf[f][0] * sendBuf->values()[f] * v; + _buf[f][1] += ch_buf[f][1] * sendBuf->values()[f] * v; + } } } @@ -488,7 +520,23 @@ void FxMixer::masterMix( sampleFrame * _buf ) } //m_fxChannels[0]->doProcessing( NULL ); - const float v = m_fxChannels[0]->m_volumeModel.value(); + // handle sample-exact data in master volume fader + ValueBuffer * volBuf = m_fxChannels[0]->m_volumeModel.hasSampleExactData() + ? m_fxChannels[0]->m_volumeModel.valueBuffer() + : NULL; + + if( volBuf ) + { + for( int f = 0; f < fpp; f++ ) + { + m_fxChannels[0]->m_buffer[f][0] *= volBuf->values()[f]; + m_fxChannels[0]->m_buffer[f][1] *= volBuf->values()[f]; + } + } + + const float v = volBuf + ? 1.0f + : m_fxChannels[0]->m_volumeModel.value(); MixHelpers::addMultiplied( _buf, m_fxChannels[0]->m_buffer, v, fpp ); m_fxChannels[0]->m_peakLeft *= engine::mixer()->masterGain(); From 43d1b30727cb81fcec478926579069a48393cf1a Mon Sep 17 00:00:00 2001 From: Vesa Date: Sun, 1 Jun 2014 15:25:02 +0300 Subject: [PATCH 2/2] FxMixer, ValueBuffer, etc. fixes --- include/FxMixer.h | 4 ++-- include/MixHelpers.h | 11 ++++++++-- include/ValueBuffer.h | 1 + plugins/Amplifier/Amplifier.cpp | 4 ++-- src/core/FxMixer.cpp | 38 ++++++++++----------------------- src/core/MixHelpers.cpp | 20 +++++++++++++++++ 6 files changed, 45 insertions(+), 33 deletions(-) diff --git a/include/FxMixer.h b/include/FxMixer.h index 7cecb7803..f8a7c86f6 100644 --- a/include/FxMixer.h +++ b/include/FxMixer.h @@ -22,8 +22,8 @@ * */ -#ifndef _FX_MIXER_H -#define _FX_MIXER_H +#ifndef FX_MIXER_H +#define FX_MIXER_H #include "Model.h" #include "Mixer.h" diff --git a/include/MixHelpers.h b/include/MixHelpers.h index a1ddd3307..baf841af4 100644 --- a/include/MixHelpers.h +++ b/include/MixHelpers.h @@ -22,11 +22,12 @@ * */ -#ifndef _MIX_HELPERS_H -#define _MIX_HELPERS_H +#ifndef MIX_HELPERS_H +#define MIX_HELPERS_H #include "lmms_basics.h" +class ValueBuffer; namespace MixHelpers { @@ -39,6 +40,12 @@ void add( sampleFrame* dst, const sampleFrame* src, int frames ); /*! \brief Add samples from src multiplied by coeffSrc to dst */ void addMultiplied( sampleFrame* dst, const sampleFrame* src, float coeffSrc, int frames ); +/*! \brief Add samples from src multiplied by coeffSrc and coeffSrcBuf to dst */ +void addMultipliedByBuffer( sampleFrame* dst, const sampleFrame* src, float coeffSrc, ValueBuffer * coeffSrcBuf, int frames ); + +/*! \brief Add samples from src multiplied by coeffSrc and coeffSrcBuf to dst */ +void addMultipliedByBuffers( sampleFrame* dst, const sampleFrame* src, ValueBuffer * coeffSrcBuf1, ValueBuffer * coeffSrcBuf2, int frames ); + /*! \brief Add samples from src multiplied by coeffSrcLeft/coeffSrcRight to dst */ void addMultipliedStereo( sampleFrame* dst, const sampleFrame* src, float coeffSrcLeft, float coeffSrcRight, int frames ); diff --git a/include/ValueBuffer.h b/include/ValueBuffer.h index a6731f425..7d9778721 100644 --- a/include/ValueBuffer.h +++ b/include/ValueBuffer.h @@ -26,6 +26,7 @@ #ifndef VALUE_BUFFER_H #define VALUE_BUFFER_H +#include #include "interpolation.h" #include diff --git a/plugins/Amplifier/Amplifier.cpp b/plugins/Amplifier/Amplifier.cpp index b256f7889..3ba9d224c 100644 --- a/plugins/Amplifier/Amplifier.cpp +++ b/plugins/Amplifier/Amplifier.cpp @@ -115,10 +115,10 @@ bool AmplifierEffect::processAudioBuffer( sampleFrame* buf, const fpp_t frames ) : m_ampControls.m_panModel.value(); const float left1 = pan <= 0 ? 1.0 - : 1.0 - m_ampControls.m_panModel.value( f ) * 0.01f; + : 1.0 - pan * 0.01f; const float right1 = pan >= 0 ? 1.0 - : 1.0 + m_ampControls.m_panModel.value( ) * 0.01f; + : 1.0 + pan * 0.01f; // second stage amplification const float left2 = leftBuf diff --git a/src/core/FxMixer.cpp b/src/core/FxMixer.cpp index 222e214ef..263b3df50 100644 --- a/src/core/FxMixer.cpp +++ b/src/core/FxMixer.cpp @@ -79,7 +79,7 @@ void FxChannel::doProcessing( sampleFrame * _buf ) // 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. + // stage is to process inter-channel sends. if( m_muteModel.value() == false ) { @@ -110,45 +110,29 @@ void FxChannel::doProcessing( sampleFrame * _buf ) // mix it's output with this one's output sampleFrame * ch_buf = sender->m_buffer; - - // use sample-exact mixing if sample-exact values are available + + // use sample-exact mixing if sample-exact values are available if( ! volBuf && ! sendBuf ) // neither volume nor send has sample-exact data... { const float v = sender->m_volumeModel.value() * fxm->channelSendModel( senderIndex, m_channelIndex )->value(); - for( f_cnt_t f = 0; f < fpp; ++f ) - { - _buf[f][0] += ch_buf[f][0] * v; - _buf[f][1] += ch_buf[f][1] * v; - } + MixHelpers::addMultiplied( _buf, ch_buf, v, fpp ); } else if( volBuf && sendBuf ) // both volume and send have sample-exact data { - for( f_cnt_t f = 0; f < fpp; ++f ) - { - _buf[f][0] += ch_buf[f][0] * sendBuf->values()[f] * volBuf->values()[f]; - _buf[f][1] += ch_buf[f][1] * sendBuf->values()[f] * volBuf->values()[f]; - } + MixHelpers::addMultipliedByBuffers( _buf, ch_buf, volBuf, sendBuf, fpp ); } else if( volBuf ) // volume has sample-exact data but send does not { const float v = fxm->channelSendModel( senderIndex, m_channelIndex )->value(); - for( f_cnt_t f = 0; f < fpp; ++f ) - { - _buf[f][0] += ch_buf[f][0] * v * volBuf->values()[f]; - _buf[f][1] += ch_buf[f][1] * v * volBuf->values()[f]; - } + MixHelpers::addMultipliedByBuffer( _buf, ch_buf, v, volBuf, fpp ); } else // vice versa { const float v = sender->m_volumeModel.value(); - for( f_cnt_t f = 0; f < fpp; ++f ) - { - _buf[f][0] += ch_buf[f][0] * sendBuf->values()[f] * v; - _buf[f][1] += ch_buf[f][1] * sendBuf->values()[f] * v; - } + MixHelpers::addMultipliedByBuffer( _buf, ch_buf, v, sendBuf, fpp ); } } - + // if sender channel hasInput, then we hasInput too if( sender->m_hasInput ) m_hasInput = true; } @@ -156,10 +140,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 ) { @@ -533,7 +517,7 @@ void FxMixer::masterMix( sampleFrame * _buf ) m_fxChannels[0]->m_buffer[f][1] *= volBuf->values()[f]; } } - + const float v = volBuf ? 1.0f : m_fxChannels[0]->m_volumeModel.value(); diff --git a/src/core/MixHelpers.cpp b/src/core/MixHelpers.cpp index 76e00cae3..9f5c2fb71 100644 --- a/src/core/MixHelpers.cpp +++ b/src/core/MixHelpers.cpp @@ -25,6 +25,7 @@ #include #include "MixHelpers.h" +#include "ValueBuffer.h" namespace MixHelpers @@ -105,6 +106,25 @@ void addMultiplied( sampleFrame* dst, const sampleFrame* src, float coeffSrc, in } +void addMultipliedByBuffer( sampleFrame* dst, const sampleFrame* src, float coeffSrc, ValueBuffer * coeffSrcBuf, int frames ) +{ + for( int f = 0; f < frames; ++f ) + { + dst[f][0] += src[f][0] * coeffSrc * coeffSrcBuf->values()[f]; + dst[f][1] += src[f][1] * coeffSrc * coeffSrcBuf->values()[f]; + } +} + +void addMultipliedByBuffers( sampleFrame* dst, const sampleFrame* src, ValueBuffer * coeffSrcBuf1, ValueBuffer * coeffSrcBuf2, int frames ) +{ + for( int f = 0; f < frames; ++f ) + { + dst[f][0] += src[f][0] * coeffSrcBuf1->values()[f] * coeffSrcBuf2->values()[f]; + dst[f][1] += src[f][1] * coeffSrcBuf1->values()[f] * coeffSrcBuf2->values()[f]; + } + +} + struct AddMultipliedStereoOp {