diff --git a/src/config.hxx b/src/config.hxx index 6e07473..c594b29 100644 --- a/src/config.hxx +++ b/src/config.hxx @@ -70,8 +70,7 @@ #define LUPPP_RETURN_ERROR 2 // Smoothing value -#define SMOOTHING_CONST 0.05 - +#define SMOOTHING_CONST 0.005 /// debug.hxx for printing convienience #include "debug.hxx" diff --git a/src/jack.cxx b/src/jack.cxx index 706acaa..ff742b8 100644 --- a/src/jack.cxx +++ b/src/jack.cxx @@ -84,6 +84,9 @@ Jack::Jack( std::string name ) : lastnframes=0; samplerate = jack_get_sample_rate( client ); + // calculate smoothing value for current sample rate + smoothing_value = SMOOTHING_CONST * (44100.f / samplerate); + // construct Observer classes here, not in the initializer list as the Jack* // will be 0x0 until then. timeManager = new TimeManager(), @@ -199,13 +202,19 @@ Jack::Jack( std::string name ) : returnVol = 1.0f; - + returnVolLag = 1.0f; inputToMixEnable = false; + inputToMixEnableLag = 0.f; inputToSendEnable = false; + inputToSendEnableLag = 0.f; inputToKeyEnable = false; + inputToKeyEnableLag = 0.f; inputToMixVol = 0.f; + inputToMixVolLag = 0.f; inputToSendVol = 0.f; + inputToSendVolLag = 0.f; inputToXSideVol = 0.f; + inputToXSideVolLag = 0.f; /// prepare internal buffers buffers.audio[Buffers::SEND_L] = new float[ buffers.nframes ]; @@ -263,6 +272,7 @@ Jack::Jack( std::string name ) : /// setup DSP instances inputVol = 1.0f; + inputVolLag = 1.0f; masterVol = 0.75f; masterVolLag =0.75f; @@ -536,40 +546,48 @@ void Jack::processFrames(int nframes) /// mix input, reverb & post-sidechain in for(unsigned int i = 0; i < nframes; i++) { - float inputL = buffers.audio[Buffers::MASTER_INPUT_L][i] * inputVol; - float inputR = buffers.audio[Buffers::MASTER_INPUT_R][i] * inputVol; + // compute *lags für smoothing + inputToMixVolLag += smoothing_value * (inputToMixVol - inputToMixVolLag); + inputToSendVolLag += smoothing_value * (inputToSendVol - inputToSendVolLag); + inputToXSideVolLag += smoothing_value * (inputToXSideVol - inputToXSideVolLag); + returnVolLag += smoothing_value * (returnVol - returnVolLag); + inputVolLag += smoothing_value * (inputVol - inputVolLag); + + inputToKeyEnableLag += smoothing_value * (inputToKeyEnable - inputToKeyEnableLag); + inputToMixEnableLag += smoothing_value * (inputToMixEnable - inputToMixEnableLag); + inputToSendEnableLag += smoothing_value * (inputToSendEnable - inputToSendEnableLag); + + float inputL = buffers.audio[Buffers::MASTER_INPUT_L][i] * inputVolLag; + float inputR = buffers.audio[Buffers::MASTER_INPUT_R][i] * inputVolLag; float L = buffers.audio[Buffers::MASTER_OUT_L][i]; float R = buffers.audio[Buffers::MASTER_OUT_R][i]; float returnL = buffers.audio[Buffers::MASTER_RETURN_L][i]; float returnR = buffers.audio[Buffers::MASTER_RETURN_R][i]; - if ( inputToMixEnable ) { - // if sending to mix, scale by volume *and* by XSide send - float tmpL = inputL * inputToMixVol * (1-inputToXSideVol); - float tmpR = inputR * inputToMixVol * (1-inputToXSideVol); - L += tmpL; - R += tmpR; + // if sending to mix, scale by volume *and* by XSide send + float tmpL = inputL * inputToMixVolLag * inputToMixEnableLag; + float tmpR = inputR * inputToMixVolLag * inputToMixEnableLag; + L += tmpL * (1-inputToXSideVolLag); + R += tmpR * (1-inputToXSideVolLag); + + // post-mix-send amount: hence * inputToMixVol + buffers.audio[Buffers::SEND_L][i] += tmpL * inputToSendVolLag * inputToSendEnableLag; + buffers.audio[Buffers::SEND_R][i] += tmpR * inputToSendVolLag * inputToSendEnableLag; - if ( inputToSendEnable ) { - // post-mix-send amount: hence * inputToMixVol - buffers.audio[Buffers::SEND_L][i] += inputL * inputToSendVol * inputToMixVol; - buffers.audio[Buffers::SEND_R][i] += inputR * inputToSendVol * inputToMixVol; - } - } - if ( inputToKeyEnable ) { - buffers.audio[Buffers::SIDECHAIN_KEY_L][i] += inputL; - buffers.audio[Buffers::SIDECHAIN_KEY_R][i] += inputR; - } + + buffers.audio[Buffers::SIDECHAIN_KEY_L][i] += inputL * inputToKeyEnableLag; + buffers.audio[Buffers::SIDECHAIN_KEY_R][i] += inputR * inputToKeyEnableLag; + - buffers.audio[Buffers::SIDECHAIN_SIGNAL_L][i] += inputL * inputToXSideVol; - buffers.audio[Buffers::SIDECHAIN_SIGNAL_R][i] += inputR * inputToXSideVol; + buffers.audio[Buffers::SIDECHAIN_SIGNAL_L][i] += inputL * inputToXSideVolLag; + buffers.audio[Buffers::SIDECHAIN_SIGNAL_R][i] += inputR * inputToXSideVolLag; //compute master volume lag; - masterVolLag += SMOOTHING_CONST * (masterVol - masterVolLag); + masterVolLag += smoothing_value * (masterVol - masterVolLag); /// mixdown returns into master buffers - buffers.audio[Buffers::JACK_MASTER_OUT_L][i] = (L + returnL*returnVol) * masterVolLag; - buffers.audio[Buffers::JACK_MASTER_OUT_R][i] = (R + returnR*returnVol) * masterVolLag; + buffers.audio[Buffers::JACK_MASTER_OUT_L][i] = (L + returnL*returnVolLag) * masterVolLag; + buffers.audio[Buffers::JACK_MASTER_OUT_R][i] = (R + returnR*returnVolLag) * masterVolLag; /// write SEND content to JACK port buffers.audio[Buffers::JACK_SEND_OUT_L][i] = buffers.audio[Buffers::SEND_L][i]; @@ -589,7 +607,7 @@ void Jack::processFrames(int nframes) // instead of scaling whole buffer, just scale output by vol EventTrackSignalLevel e(-1, masterMeter->getLeftDB(), masterMeter->getRightDB() ); writeToGuiRingbuffer( &e ); - EventTrackSignalLevel e2(-2, inputMeter->getLeftDB() * inputVol, inputMeter->getRightDB() * inputVol ); + EventTrackSignalLevel e2(-2, inputMeter->getLeftDB() * inputVolLag, inputMeter->getRightDB() * inputVol ); writeToGuiRingbuffer( &e2 ); uiUpdateCounter = 0; diff --git a/src/jack.hxx b/src/jack.hxx index 23137b1..1284426 100644 --- a/src/jack.hxx +++ b/src/jack.hxx @@ -136,9 +136,11 @@ public: int bindingActive; JackSendReturn *getJackSendReturn(int t); + + float smoothing_value; private: int lastnframes; - jack_client_t* client; + jack_client_t* client; Buffers buffers; TimeManager* timeManager; @@ -157,21 +159,35 @@ private: // FX DBMeter* inputMeter; DBMeter* masterMeter; - - float inputVol; - /// _toMasterLag is a volume that lags behind _toMaster when setMaster() is called + + /// *Lag are values that lag behind their corresponding value /// This prohibits audible jumps when rapidly changing the volume + float inputVol; + float inputVolLag; + float masterVol; float masterVolLag; + float returnVol; + float returnVolLag; float inputToMixVol; + float inputToMixVolLag; + float inputToSendVol; + float inputToSendVolLag; + float inputToXSideVol; + float inputToXSideVolLag; bool inputToKeyEnable; + float inputToKeyEnableLag; + bool inputToMixEnable; + float inputToMixEnableLag; + bool inputToSendEnable; + float inputToSendEnableLag; // JACK member variables bool clientActive; diff --git a/src/jacksendreturn.cxx b/src/jacksendreturn.cxx index 2135ccb..a2bf1ac 100644 --- a/src/jacksendreturn.cxx +++ b/src/jacksendreturn.cxx @@ -4,28 +4,29 @@ #include extern Jack* jack; JackSendReturn::JackSendReturn(int trackid, AudioProcessor *prev, jack_client_t *client) - :m_trackid(trackid), m_previousProcessor(prev), m_sendvol(1.0f) + :_trackId(trackid), _previousProcessor(prev), _sendVol(1.0f) { char name[50]; int trackid_human = trackid + 1; sprintf(name, "Send_track_%d_l\n",trackid_human); - m_sendport_l=jack_port_register(client,name,JACK_DEFAULT_AUDIO_TYPE,JackPortIsOutput,0); + _sendPortL=jack_port_register(client,name,JACK_DEFAULT_AUDIO_TYPE,JackPortIsOutput,0); sprintf(name, "Send_track_%d_r\n",trackid_human); - m_sendport_r=jack_port_register(client,name,JACK_DEFAULT_AUDIO_TYPE,JackPortIsOutput,0); + _sendPortR=jack_port_register(client,name,JACK_DEFAULT_AUDIO_TYPE,JackPortIsOutput,0); sprintf(name, "Return_track_%d_l\n",trackid_human); - m_returnport_l=jack_port_register(client,name,JACK_DEFAULT_AUDIO_TYPE,JackPortIsInput,0); + _returnPortL=jack_port_register(client,name,JACK_DEFAULT_AUDIO_TYPE,JackPortIsInput,0); sprintf(name, "Return_track_%d_r\n",trackid_human); - m_returnport_r=jack_port_register(client,name,JACK_DEFAULT_AUDIO_TYPE,JackPortIsInput,0); - m_active=false; - m_counter=0; + _returnPortR=jack_port_register(client,name,JACK_DEFAULT_AUDIO_TYPE,JackPortIsInput,0); + _active=false; + _activeLag = 0; + _counter=0; } void JackSendReturn::process(unsigned int nframes, Buffers *buffers) { // index = first-track + (track * channels) - int trackoffset = m_trackid * NCHANNELS; + int trackoffset = _trackId * NCHANNELS; //Reset send buffer - int offset=m_counter%(buffers->nframes); + int offset=_counter%(buffers->nframes); float* sendtrackL=&(buffers->audio[Buffers::SEND_TRACK_0_L + trackoffset][0]); float* sendtrackR=&(buffers->audio[Buffers::SEND_TRACK_0_R + trackoffset][0]); @@ -37,12 +38,12 @@ void JackSendReturn::process(unsigned int nframes, Buffers *buffers) memset(sendtrackR,0,nframes*sizeof(float)); //Process previous AudioProcessor - m_previousProcessor->process(nframes,buffers); + _previousProcessor->process(nframes,buffers); - float* sendL=(float*)jack_port_get_buffer(m_sendport_l, (jack_nframes_t)(buffers->nframes)); - float* sendR=(float*)jack_port_get_buffer(m_sendport_r, (jack_nframes_t)(buffers->nframes)); - float* retL =(float*)jack_port_get_buffer(m_returnport_l,(jack_nframes_t)(buffers->nframes)); - float* retR =(float*)jack_port_get_buffer(m_returnport_r,(jack_nframes_t)(buffers->nframes)); + float* sendL=(float*)jack_port_get_buffer(_sendPortL, (jack_nframes_t)(buffers->nframes)); + float* sendR=(float*)jack_port_get_buffer(_sendPortR, (jack_nframes_t)(buffers->nframes)); + float* retL =(float*)jack_port_get_buffer(_returnPortL,(jack_nframes_t)(buffers->nframes)); + float* retR =(float*)jack_port_get_buffer(_returnPortR,(jack_nframes_t)(buffers->nframes)); if(offset) { sendL+=offset; @@ -52,31 +53,30 @@ void JackSendReturn::process(unsigned int nframes, Buffers *buffers) } for(int i=0; ismoothing_value * (_sendVol - _sendVolLag); + + sendL[i] = _sendVolLag * sendtrackL[i]; + sendR[i] = _sendVolLag * sendtrackR[i]; + + _activeLag += jack->smoothing_value * (float(_active) - _activeLag); + + rettrackL[i] = retL[i] * _activeLag + sendtrackL[i] * std::fabs(_activeLag - 1); + rettrackR[i] = retR[i] * _activeLag + sendtrackR[i] * std::fabs(_activeLag - 1); } if(offset) assert(offset+nframes==buffers->nframes); - if(m_active) { - memcpy(rettrackL,retL,nframes*sizeof(float)); - memcpy(rettrackR,retR,nframes*sizeof(float)); - } - else { - memcpy(rettrackL, sendtrackL,nframes*sizeof(float)); - memcpy(rettrackR, sendtrackR,nframes*sizeof(float)); - } - m_counter+=nframes; + _counter+=nframes; } void JackSendReturn::activate(bool act) { - m_active=act; + _active=act; } void JackSendReturn::sendVolume(float vol) { - m_sendvol=vol; + _sendVol=vol; } diff --git a/src/jacksendreturn.hxx b/src/jacksendreturn.hxx index e2fc3f6..4c0704c 100644 --- a/src/jacksendreturn.hxx +++ b/src/jacksendreturn.hxx @@ -37,21 +37,25 @@ public: //The process callback virtual void process(unsigned int nframes, Buffers* buffers); - //Activate the return chain. When m_active=true then Buffers::RETURN_TRACK_0+m_trackid gets the data + //Activate the return chain. When _active=true then Buffers::RETURN_TRACK_0+_trackid gets the data //from the return port. The send port always send the incoming data void activate(bool act); void sendVolume(float vol); private: - bool m_active; - float m_sendvol; - jack_port_t* m_sendport_l; - jack_port_t* m_sendport_r; - jack_port_t* m_returnport_l; - jack_port_t* m_returnport_r; - int m_trackid; - AudioProcessor* m_previousProcessor; - int m_counter; + bool _active; + float _activeLag; + + float _sendVol; + float _sendVolLag; + + jack_port_t* _sendPortL; + jack_port_t* _sendPortR; + jack_port_t* _returnPortL; + jack_port_t* _returnPortR; + int _trackId; + AudioProcessor* _previousProcessor; + int _counter; }; #endif diff --git a/src/trackoutput.cxx b/src/trackoutput.cxx index b026a99..339ec4b 100644 --- a/src/trackoutput.cxx +++ b/src/trackoutput.cxx @@ -51,7 +51,11 @@ TrackOutput::TrackOutput(int t, AudioProcessor* ap) : _toPostSidechainLag = 0.0; _toPostfaderActive = 0; + _toPostfaderActiveLag = 0; + _toKeyActive = 0; + _toKeyActiveLag = 0; + _toXSideActive = true; } @@ -132,7 +136,7 @@ void TrackOutput::process(unsigned int nframes, Buffers* buffers) int trackoffset = track * NCHANNELS; //compute master volume lag; - _toMasterLag += SMOOTHING_CONST * (_toMaster - _toMasterLag); + _toMasterLag += jack->smoothing_value * (_toMaster - _toMasterLag); // get & zero track buffer float* trackBufferL = buffers->audio[Buffers::RETURN_TRACK_0_L + trackoffset]; @@ -174,18 +178,22 @@ void TrackOutput::process(unsigned int nframes, Buffers* buffers) for(unsigned int i = 0; i < nframes; i++) { //compute master volume lag; - _toMasterLag += SMOOTHING_CONST * (_toMaster - _toMasterLag); + _toMasterLag += jack->smoothing_value * (_toMaster - _toMasterLag); // compute pan lag: - _panLLag += SMOOTHING_CONST * (_panL - _panLLag); - _panRLag += SMOOTHING_CONST * (_panR - _panRLag); + _panLLag += jack->smoothing_value * (_panL - _panLLag); + _panRLag += jack->smoothing_value * (_panR - _panRLag); // compute send volume lag: - _toSendLag += SMOOTHING_CONST * (_toSend - _toSendLag); + _toSendLag += jack->smoothing_value * (_toSend - _toSendLag); // compute sidechain signal lag - _toPostSidechainLag += SMOOTHING_CONST * (_toPostSidechain - _toPostSidechainLag); - + _toPostSidechainLag += jack->smoothing_value * (_toPostSidechain - _toPostSidechainLag); + + // compute discrete lag values + _toPostfaderActiveLag += jack->smoothing_value * (float(_toPostfaderActive) - _toPostfaderActiveLag); + _toKeyActiveLag += jack->smoothing_value * (float(_toKeyActive) - _toKeyActiveLag); + // * master for "post-fader" sends float tmpL = trackBufferL[i]; float tmpR = trackBufferR[i]; @@ -197,22 +205,18 @@ void TrackOutput::process(unsigned int nframes, Buffers* buffers) jackoutputL[i] = tmpL * _toMasterLag * (1-_toPostSidechainLag); if(jackoutputR) jackoutputR[i] = tmpR * _toMasterLag * (1-_toPostSidechainLag); - if ( _toPostfaderActive ) { - sendL[i] += tmpL * _toSendLag * _toMasterLag; - sendR[i] += tmpR * _toSendLag * _toMasterLag; - } - + + sendL[i] += tmpL * _toSendLag * _toMasterLag * _toPostfaderActiveLag; + sendR[i] += tmpR * _toSendLag * _toMasterLag * _toPostfaderActiveLag; + if ( _toXSideActive ) { postSidechainL[i] += tmpL * _toPostSidechainLag * _toMasterLag; postSidechainR[i] += tmpR * _toPostSidechainLag * _toMasterLag; } // turning down an element in the mix should *NOT* influence sidechaining - if ( _toKeyActive ) { - sidechainL[i] += tmpL; - sidechainR[i] += tmpR; - } - + sidechainL[i] += tmpL * _toKeyActiveLag; + sidechainR[i] += tmpR * _toKeyActiveLag; } } diff --git a/src/trackoutput.hxx b/src/trackoutput.hxx index 1ed2ebe..21428ae 100644 --- a/src/trackoutput.hxx +++ b/src/trackoutput.hxx @@ -80,7 +80,11 @@ private: float _toPostSidechainLag; bool _toPostfaderActive; + float _toPostfaderActiveLag; + bool _toKeyActive; + float _toKeyActiveLag; + bool _toXSideActive; /// Pointer to "previous" processor: the graph is backwards