Merge pull request #243 from georgkrause/smoothing

Smoothing for discrete controls, thanks @georgkrause!
main
Harry van Haaren 2018-07-14 12:21:04 +01:00 committed by GitHub
commit e4b8632005
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 130 additions and 85 deletions

View File

@ -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"

View File

@ -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;

View File

@ -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;

View File

@ -4,28 +4,29 @@
#include <assert.h>
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; i<nframes; i++) {
sendL[i]=m_sendvol*sendtrackL[i];
sendR[i]=m_sendvol*sendtrackR[i];
_sendVolLag += jack->smoothing_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;
}

View File

@ -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

View File

@ -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;
}
}

View File

@ -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