Mixer: Implement slow fall off for meters.

This commit is contained in:
Jonathan Moore Liles 2020-11-06 18:35:55 -08:00
parent c808c53d6c
commit f5b215066a
11 changed files with 177 additions and 171 deletions

View File

@ -370,7 +370,7 @@ Chain::configure_ports ( void )
client()->lock(); client()->lock();
for ( int i = 0; i < modules(); ++i ) for ( int i = 0; i < modules(); ++i )
{ {
module( i )->configure_inputs( nouts ); module( i )->configure_inputs( nouts );
nouts = module( i )->noutputs(); nouts = module( i )->noutputs();
} }
@ -573,6 +573,9 @@ Chain::insert ( Module *m, Module *n )
{ {
client()->lock(); client()->lock();
Module::sample_rate( client()->sample_rate() );
n->resize_buffers( client()->nframes() );
if ( !m ) if ( !m )
{ {
if ( modules() == 0 && n->can_support_inputs( 0 ) >= 0 ) if ( modules() == 0 && n->can_support_inputs( 0 ) >= 0 )
@ -938,7 +941,7 @@ Chain::buffer_size ( nframes_t nframes )
int int
Chain::sample_rate_change ( nframes_t nframes ) Chain::sample_rate_change ( nframes_t nframes )
{ {
Module::set_sample_rate ( nframes ); Module::sample_rate ( nframes );
for ( int i = 0; i < modules(); ++i ) for ( int i = 0; i < modules(); ++i )
{ {
Module *m = module(i); Module *m = module(i);

View File

@ -82,14 +82,6 @@ DPM::DPM ( int X, int Y, int W, int H, const char *L ) :
} }
{
/* smoothing.cutoff(25); */
smoothing.cutoff(200);
smoothing.sample_rate(30000);
smoothing.reset(-70.0f);
/* clear initial hump */
}
resize( X,Y,W,H); resize( X,Y,W,H);
} }
@ -164,6 +156,7 @@ void DPM::bbox ( int &X, int &Y, int &W, int &H )
H = h(); H = h();
} }
void void
DPM::draw ( void ) DPM::draw ( void )
{ {
@ -220,63 +213,51 @@ DPM::draw ( void )
} }
_last_drawn_hi_segment = v; _last_drawn_hi_segment = v;
for ( int p = lo; p <= hi; p++ ) for ( int p = lo; p <= hi; p++ )
{ {
Fl_Color c; Fl_Color c;
if ( p <= v ) if ( p <= v )
{ {
if ( p == clipv ) if ( p == clipv )
c = fl_color_average( FL_YELLOW, div_color( p ), 0.40 ); c = fl_color_average( FL_YELLOW, div_color( p ), 0.40 );
else else
c = div_color( p ); c = div_color( p );
} }
else if ( p == pv ) else if ( p == pv )
c = div_color( p ); c = div_color( p );
else else
c = fl_darker( FL_BACKGROUND_COLOR );//FL_DARK1; // fl_color_average( FL_BACKGROUND_COLOR, FL_BLACK, 0.50f );// FL_BACKGROUND_COLOR; //dim_div_color( p ); c = fl_darker( FL_BACKGROUND_COLOR );//FL_DARK1; // fl_color_average( FL_BACKGROUND_COLOR, FL_BLACK, 0.50f );// FL_BACKGROUND_COLOR; //dim_div_color( p );
if ( ! active ) if ( ! active )
c = fl_inactive( c ); c = fl_inactive( c );
int yy = 0; int yy = 0;
int xx = 0; int xx = 0;
if ( type() == FL_HORIZONTAL ) if ( type() == FL_HORIZONTAL )
{ {
xx = X + p * bw; xx = X + p * bw;
fl_rectf( xx + 1, Y, bw - 1, H, c ); fl_rectf( xx + 1, Y, bw - 1, H, c );
} }
else else
{ {
yy = Y + H - ((p+1) * bh); yy = Y + H - ((p+1) * bh);
fl_rectf( X, yy + 1, W, bh - 1, c ); fl_rectf( X, yy + 1, W, bh - 1, c );
} }
/* } */
/* else */
/* { */
/* if ( type() == FL_HORIZONTAL ) */
/* fl_draw_box( box(), X + (p * bw), Y, bw, H, c ); */
/* else */
/* fl_draw_box( box(), X, Y + H - ((p + 1) * bh), W, bh, c ); */
/* } */
} }
/* fl_color( fl_color_add_alpha( FL_WHITE, 127 ) ); */
/* for ( int i = 0; i < 50; i++ ) */
/* { */
/* int yy = Y + i * H / 50; */
/* if ( type() == FL_VERTICAL ) */
/* { */
/* int ww = i % 2 == 0 ? W : W / 2; */
/* fl_line( X + ((W/2) - ww/2), yy, X + ww - 1, yy ); */
/* } */
/* } */
fl_pop_clip(); fl_pop_clip();
} }
void
DPM::update ( void )
{
/* do falloff */
float f = value() - 0.33f;
if ( f < -70.0f )
f = -78.0f;
value(f);
}

View File

@ -22,7 +22,6 @@
#include <FL/Fl_Valuator.H> // for FL_HORIZONTAL and FL_VERTICAL #include <FL/Fl_Valuator.H> // for FL_HORIZONTAL and FL_VERTICAL
#include "Meter.H" #include "Meter.H"
#include "dsp.h"
class DPM : public Meter class DPM : public Meter
{ {
@ -31,11 +30,7 @@ class DPM : public Meter
int _segments; int _segments;
int _pixels_per_segment; int _pixels_per_segment;
int _last_drawn_hi_segment; int _last_drawn_hi_segment;
Value_Smoothing_Filter smoothing;
float _value;
int pos ( float v ) int pos ( float v )
{ {
float pv = deflection( v ) * ( _segments - 1 ); float pv = deflection( v ) * ( _segments - 1 );
@ -58,8 +53,7 @@ class DPM : public Meter
{ {
return _dim_gradient[ i * 127 / _segments ]; return _dim_gradient[ i * 127 / _segments ];
} }
protected: protected:
virtual void draw_label ( void ); virtual void draw_label ( void );
@ -70,34 +64,28 @@ protected:
public: public:
DPM ( int X, int Y, int W, int H, const char *L = 0 ); DPM ( int X, int Y, int W, int H, const char *L = 0 );
void value ( float v )
{
sample_t buf[1];
if ( smoothing.apply( buf, 1, v ) )
v = buf[0];
if ( _value != v )
{
if ( pos( v ) != pos( _value ) )
Meter::value( v );
}
_value = v;
}
float value ( void ) const
{
return _value;
}
void pixels_per_segment ( int v ) { _pixels_per_segment = v; } void pixels_per_segment ( int v ) { _pixels_per_segment = v; }
float dim ( void ) const { return _dim; } float dim ( void ) const { return _dim; }
void dim ( float v ) { _dim = v; if ( visible_r() ) redraw(); } void dim ( float v ) { _dim = v; if ( visible_r() ) redraw(); }
virtual void value ( float v )
{
/* only trigger redraw for changes at or above our resolution*/
if ( pos( value() ) != pos( v ) && visible_r() )
damage( FL_DAMAGE_USER1 );
Meter::value( v );
}
virtual float value ( void ) { return Meter::value(); }
void update ( void );
static static
void void
blend ( int nbreaks, int* b, Fl_Color *c, Fl_Color bc ) blend ( int nbreaks, int* b, Fl_Color *c, Fl_Color bc )

View File

@ -275,7 +275,7 @@ Group::name ( const char *n )
if ( !active() ) if ( !active() )
{ {
Client::init( ename ); Client::init( ename );
Module::set_sample_rate( sample_rate() ); Module::sample_rate( sample_rate() );
} }
else else
{ {

View File

@ -84,17 +84,14 @@ public:
virtual void value ( float v ) virtual void value ( float v )
{ {
if ( visible_r() ) _value = v;
damage( FL_DAMAGE_USER1 );
if ( _value > _peak )
_value = v; _peak = _value;
if ( _value > _peak )
_peak = _value;
} }
virtual float value ( void ) const { return _value; } virtual float value ( void ) const { return _value; }
float peak ( void ) const { return _peak; } virtual float peak ( void ) const { return _peak; }
void reset ( void ) { _peak = -80.0f; redraw(); } void reset ( void ) { _peak = -80.0f; redraw(); }

View File

@ -35,6 +35,7 @@
#include "Chain.H" #include "Chain.H"
#include "DPM.H" #include "DPM.H"
#include "dsp.h"
#include "FL/test_press.H" #include "FL/test_press.H"
@ -64,8 +65,9 @@ Meter_Indicator_Module::Meter_Indicator_Module ( bool is_default )
end(); end();
control_value = new float[1]; control_value = new float[1*2];
*control_value = -70.0f; control_value[0] =
control_value[1] = 0;
align( (Fl_Align)(FL_ALIGN_CENTER | FL_ALIGN_INSIDE ) ); align( (Fl_Align)(FL_ALIGN_CENTER | FL_ALIGN_INSIDE ) );
@ -158,37 +160,29 @@ Meter_Indicator_Module::update ( void )
// A little hack to detect that the connected module's number // A little hack to detect that the connected module's number
// of control outs has changed. // of control outs has changed.
Port *p = control_input[0].connected_port(); Port *p = control_input[0].connected_port();
for ( int i = 0; i < dpm_pack->children(); ++i )
{
DPM *o = (DPM*)dpm_pack->child(i);
if ( dpm_pack->children() != p->hints.dimensions ) float dB = CO_DB( control_value[i] );
{
/* engine->lock(); */ if ( dB > o->value() )
o->value( dB );
dpm_pack->clear(); o->update();
/* else */
/* { */
/* /\* do falloff *\/ */
/* float f = o->value() - 0.75f; */
/* if ( f < -70.0f ) */
/* f = -70.0f; */
/* o->value( f ); */
/* } */
control_value = new float[p->hints.dimensions]; control_value[i] = 0;
}
for ( int i = p->hints.dimensions; i--; )
{
DPM *dpm = new DPM( x(), y(), w(), h() );
dpm->type( FL_VERTICAL );
dpm_pack->add( dpm );
control_value[i] = -70.0f;
dpm->value( -70.0f );
}
/* engine->unlock(); */
}
else
{
for ( int i = 0; i < dpm_pack->children(); ++i )
{
((DPM*)dpm_pack->child( i ))->value( control_value[i] );
control_value[i] = -70.0f;
}
}
} }
} }
@ -248,7 +242,7 @@ Meter_Indicator_Module::handle_control_changed ( Port *p )
control_value = new float[p->hints.dimensions]; control_value = new float[p->hints.dimensions];
for ( int i = p->hints.dimensions; i--; ) for ( int i = 0; i < p->hints.dimensions; i++ )
{ {
DPM *dpm = new DPM( x(), y(), w(), h() ); DPM *dpm = new DPM( x(), y(), w(), h() );
dpm->type( FL_VERTICAL ); dpm->type( FL_VERTICAL );
@ -257,8 +251,10 @@ Meter_Indicator_Module::handle_control_changed ( Port *p )
dpm_pack->add( dpm ); dpm_pack->add( dpm );
dpm_pack->redraw(); dpm_pack->redraw();
control_value[i] = -70.0f; control_value[i] = 0;
dpm->value( -70.0f );
dpm->value( CO_DB( control_value[i] ));
} }
redraw(); redraw();
@ -276,12 +272,22 @@ Meter_Indicator_Module::process ( nframes_t )
if ( control_input[0].connected() ) if ( control_input[0].connected() )
{ {
Port *p = control_input[0].connected_port(); Port *p = control_input[0].connected_port();
volatile float *cv = control_value;
float *pv = (float*)control_input[0].buffer();
for ( int i = 0; i < p->hints.dimensions; ++i ) for ( int i = 0; i < p->hints.dimensions; ++i )
{ {
float dB = ((float*)control_input[0].buffer())[i]; /* peak value since we last checked */
if ( dB > control_value[i]) if ( *pv > *cv )
control_value[i] = dB; {
*cv = *pv;
/* reset now that we've got it */
*pv = 0;
}
cv++;
pv++;
} }
} }
} }

View File

@ -42,19 +42,22 @@ Meter_Module::Meter_Module ( )
dpm_pack->spacing( 1 ); dpm_pack->spacing( 1 );
control_value = 0; control_value = 0;
peaks = 0;
meter_sample_period_count = 0;
meter_sample_periods = 0;
color( fl_darker( fl_darker( FL_BACKGROUND_COLOR ))); color( fl_darker( fl_darker( FL_BACKGROUND_COLOR )));
end(); end();
Port p( this, Port::OUTPUT, Port::CONTROL, "dB level" ); Port p( this, Port::OUTPUT, Port::CONTROL, "peak level" );
p.hints.type = Port::Hints::LOGARITHMIC; p.hints.type = Port::Hints::LINEAR;
p.hints.ranged = true; p.hints.ranged = true;
p.hints.maximum = 6.0f; p.hints.maximum = 10.0f;
p.hints.minimum = -70.0f; p.hints.minimum = 0.0f;
p.hints.dimensions = 1; p.hints.dimensions = 1;
p.connect_to( new float[1] ); p.connect_to( new float[1] );
p.control_value_no_callback( -70.0f ); p.control_value_no_callback( 0 );
add_port( p ); add_port( p );
@ -71,6 +74,8 @@ Meter_Module::~Meter_Module ( )
void Meter_Module::resize ( int X, int Y, int W, int H ) void Meter_Module::resize ( int X, int Y, int W, int H )
{ {
Fl_Group::resize(X,Y,W,H); Fl_Group::resize(X,Y,W,H);
@ -93,8 +98,12 @@ Meter_Module::update ( void )
{ {
for ( int i = dpm_pack->children(); i--; ) for ( int i = dpm_pack->children(); i--; )
{ {
((DPM*)dpm_pack->child( i ))->value( control_value[i] ); DPM* o = ((DPM*)dpm_pack->child( i ));
control_value[i] = -70.0f;
o->value( CO_DB( control_value[i] ) );
o->update();
control_value[i] = 0;
} }
} }
@ -117,7 +126,6 @@ Meter_Module::configure_inputs ( int n )
add_port( Port( this, Port::INPUT, Port::AUDIO ) ); add_port( Port( this, Port::INPUT, Port::AUDIO ) );
add_port( Port( this, Port::OUTPUT, Port::AUDIO ) ); add_port( Port( this, Port::OUTPUT, Port::AUDIO ) );
} }
} }
else else
@ -132,16 +140,20 @@ Meter_Module::configure_inputs ( int n )
audio_input.pop_back(); audio_input.pop_back();
audio_output.back().disconnect(); audio_output.back().disconnect();
audio_output.pop_back(); audio_output.pop_back();
smoothing.pop_back();
} }
} }
/* DMESSAGE( "sample rate: %lu, nframes: %lu", sample_rate(), this->nframes() ); */
control_output[0].hints.dimensions = n; control_output[0].hints.dimensions = n;
delete[] (float*)control_output[0].buffer(); delete[] (float*)control_output[0].buffer();
{ {
float *f = new float[n]; float *f = new float[n];
for ( int i = n; i--; ) for ( int i = n; i--; )
f[i] = -70.0f; f[i] = 0;
control_output[0].connect_to( f ); control_output[0].connect_to( f );
} }
@ -151,7 +163,7 @@ Meter_Module::configure_inputs ( int n )
control_value = new float[n]; control_value = new float[n];
for ( int i = n; i--; ) for ( int i = n; i--; )
control_value[i] = -70.0f; control_value[i] = 0;
if ( control_output[0].connected() ) if ( control_output[0].connected() )
control_output[0].connected_port()->module()->handle_control_changed( control_output[0].connected_port() ); control_output[0].connected_port()->module()->handle_control_changed( control_output[0].connected_port() );
@ -193,11 +205,19 @@ Meter_Module::process ( nframes_t nframes )
{ {
for ( unsigned int i = 0; i < audio_input.size(); ++i ) for ( unsigned int i = 0; i < audio_input.size(); ++i )
{ {
// float dB = 20 * log10( get_peak_sample( (float*)audio_input[i].buffer(), nframes ) / 2.0f ); const float peak = buffer_get_peak( (sample_t*) audio_input[i].buffer(), nframes );
const float dB = 20 * log10( buffer_get_peak( (sample_t*) audio_input[i].buffer(), nframes ) );
/* const float RMS = sqrtf( peak / (float)nframes); */
((float*)control_output[0].buffer())[i] = dB; /* since the GUI only updates at 20 or 30hz, there's no point in doing this more often than necessary. */
if (dB > control_value[i])
control_value[i] = dB; /* need to store this separately from other peaks as it must be reset each time we do a round of smoothing output */
/* store peak value */
if ( peak > ((float*)control_output[0].buffer())[i] )
((float*)control_output[0].buffer())[i] = peak;
if ( peak > control_value[i] )
control_value[i] = peak;
} }
} }

View File

@ -20,6 +20,8 @@
#pragma once #pragma once
#include "Module.H" #include "Module.H"
#include "dsp.h"
#include <vector>
class Fl_Scalepack; class Fl_Scalepack;
@ -27,8 +29,19 @@ class Meter_Module : public Module
{ {
Fl_Scalepack *dpm_pack; Fl_Scalepack *dpm_pack;
std::vector <Value_Smoothing_Filter> smoothing;
volatile float *control_value; volatile float *control_value;
volatile float *peaks;
int meter_sample_periods; /* no need to do computations every
* buffer when the gui only updates at
* 30Hz. So only do it every n
* buffers */
int meter_sample_period_count;
void set_smoothing_sample_rate ( nframes_t nframes, nframes_t sample_rate );
public: public:
Meter_Module ( ); Meter_Module ( );

View File

@ -416,7 +416,7 @@ Mixer::update_cb ( void )
{ {
Fl::repeat_timeout( _update_interval, &Mixer::update_cb, this ); Fl::repeat_timeout( _update_interval, &Mixer::update_cb, this );
if ( active_r() && visible_r() ) /* if ( active_r() && visible_r() ) */
{ {
for ( int i = 0; i < mixer_strips->children(); i++ ) for ( int i = 0; i < mixer_strips->children(); i++ )
{ {
@ -591,7 +591,7 @@ Mixer::Mixer ( int X, int Y, int W, int H, const char *L ) :
resize( X,Y,W,H ); resize( X,Y,W,H );
update_frequency( 30 ); update_frequency( 24 );
Fl::add_timeout( FEEDBACK_UPDATE_FREQ, send_feedback_cb, this ); Fl::add_timeout( FEEDBACK_UPDATE_FREQ, send_feedback_cb, this );

View File

@ -46,10 +46,10 @@ class Module : public Fl_Group, public Loggable {
int _ins; int _ins;
int _outs; int _outs;
int _instances; int _instances;
nframes_t _nframes;
Chain *_chain; Chain *_chain;
bool _is_default; bool _is_default;
nframes_t _nframes;
static nframes_t _sample_rate; static nframes_t _sample_rate;
static Module *_copied_module_empty; static Module *_copied_module_empty;
static char *_copied_module_settings; static char *_copied_module_settings;
@ -181,12 +181,14 @@ public:
_by_number_path = NULL; _by_number_path = NULL;
} }
nframes_t nframes ( void ) const { return _nframes; }
void nframes ( nframes_t n) { _nframes = n; }
const char *name ( void ) const { return _name; } const char *name ( void ) const { return _name; }
Type type ( void ) const { return _type; } Type type ( void ) const { return _type; }
Direction direction ( void ) const { return _direction; } Direction direction ( void ) const { return _direction; }
Module * module ( void ) const { return _module; } Module * module ( void ) const { return _module; }
nframes_t nframes ( void ) const { return _nframes; }
void buffer ( void *buf, nframes_t nframes ) { _buf = buf; _nframes = nframes; }; void buffer ( void *buf, nframes_t nframes ) { _buf = buf; _nframes = nframes; };
void *buffer ( void ) const { return _buf; } void *buffer ( void ) const { return _buf; }
@ -368,7 +370,6 @@ public:
LOG_NAME_FUNC( Module ); LOG_NAME_FUNC( Module );
nframes_t nframes ( void ) const { return _nframes; }
virtual void resize_buffers ( nframes_t v ) { _nframes = v; } virtual void resize_buffers ( nframes_t v ) { _nframes = v; }
@ -548,7 +549,9 @@ protected:
bool add_aux_port ( bool input, const char *prefix, int n , JACK::Port::type_e type ); bool add_aux_port ( bool input, const char *prefix, int n , JACK::Port::type_e type );
public: public:
nframes_t sample_rate ( void ) const { return Module::_sample_rate; }
static nframes_t sample_rate ( void ) { return Module::_sample_rate; }
nframes_t nframes ( void ) { return _nframes; }
void auto_connect_outputs(); void auto_connect_outputs();
@ -561,7 +564,7 @@ public:
bool add_aux_audio_input ( const char *prefix, int n ); bool add_aux_audio_input ( const char *prefix, int n );
bool add_aux_cv_input ( const char *prefix, int n ); bool add_aux_cv_input ( const char *prefix, int n );
static void set_sample_rate ( nframes_t srate ) { _sample_rate = srate; } static void sample_rate ( nframes_t srate ) { _sample_rate = srate; }
void command_open_parameter_editor(); void command_open_parameter_editor();
virtual void command_activate ( void ); virtual void command_activate ( void );

View File

@ -199,24 +199,17 @@ buffer_get_peak ( const sample_t * __restrict__ buf, nframes_t nframes )
{ {
const sample_t * buf_ = (const sample_t*) assume_aligned(buf); const sample_t * buf_ = (const sample_t*) assume_aligned(buf);
float pmax = 0.0f; float p = 0.0f;
float pmin = 0.0f;
while (nframes--) while (nframes--)
{ {
const float v = *buf_++; const float v = fabsf( *buf_++ );
if ( v > pmax ) if ( v > p )
pmax = v; p = v;
if ( v < pmin )
pmin = v;
} }
pmax = fabsf(pmax); return p;
pmin = fabsf(pmin);
return pmax > pmin ? pmax : pmin;
} }
void void
@ -266,6 +259,8 @@ Value_Smoothing_Filter::apply( sample_t * __restrict__ dst, nframes_t nframes, f
dst_[i] = g2; dst_[i] = g2;
} }
g2 += 1e-10f; /* denormal protection */
if ( fabsf( gt - g2 ) < 0.0001f ) if ( fabsf( gt - g2 ) < 0.0001f )
g2 = gt; g2 = gt;