Merge pull request #243 from georgkrause/smoothing
Smoothing for discrete controls, thanks @georgkrause!main
commit
e4b8632005
|
@ -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"
|
||||
|
|
68
src/jack.cxx
68
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;
|
||||
|
|
24
src/jack.hxx
24
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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue