From f5b215066a143643b32d807a3035e45cd3232767 Mon Sep 17 00:00:00 2001 From: Jonathan Moore Liles Date: Fri, 6 Nov 2020 18:35:55 -0800 Subject: [PATCH] Mixer: Implement slow fall off for meters. --- mixer/src/Chain.C | 7 +- mixer/src/DPM.C | 105 ++++++++++++----------------- mixer/src/DPM.H | 44 +++++------- mixer/src/Group.C | 2 +- mixer/src/Meter.H | 13 ++-- mixer/src/Meter_Indicator_Module.C | 78 +++++++++++---------- mixer/src/Meter_Module.C | 50 +++++++++----- mixer/src/Meter_Module.H | 13 ++++ mixer/src/Mixer.C | 4 +- mixer/src/Module.H | 13 ++-- nonlib/dsp.C | 19 ++---- 11 files changed, 177 insertions(+), 171 deletions(-) diff --git a/mixer/src/Chain.C b/mixer/src/Chain.C index 015c925..ef4f9dd 100644 --- a/mixer/src/Chain.C +++ b/mixer/src/Chain.C @@ -370,7 +370,7 @@ Chain::configure_ports ( void ) client()->lock(); for ( int i = 0; i < modules(); ++i ) - { + { module( i )->configure_inputs( nouts ); nouts = module( i )->noutputs(); } @@ -573,6 +573,9 @@ Chain::insert ( Module *m, Module *n ) { client()->lock(); + Module::sample_rate( client()->sample_rate() ); + n->resize_buffers( client()->nframes() ); + if ( !m ) { if ( modules() == 0 && n->can_support_inputs( 0 ) >= 0 ) @@ -938,7 +941,7 @@ Chain::buffer_size ( nframes_t nframes ) int Chain::sample_rate_change ( nframes_t nframes ) { - Module::set_sample_rate ( nframes ); + Module::sample_rate ( nframes ); for ( int i = 0; i < modules(); ++i ) { Module *m = module(i); diff --git a/mixer/src/DPM.C b/mixer/src/DPM.C index 680baf1..8273bef 100644 --- a/mixer/src/DPM.C +++ b/mixer/src/DPM.C @@ -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); } @@ -164,6 +156,7 @@ void DPM::bbox ( int &X, int &Y, int &W, int &H ) H = h(); } + void DPM::draw ( void ) { @@ -220,63 +213,51 @@ DPM::draw ( void ) } _last_drawn_hi_segment = v; - + for ( int p = lo; p <= hi; p++ ) { - Fl_Color c; - - if ( p <= v ) - { - if ( p == clipv ) - c = fl_color_average( FL_YELLOW, div_color( p ), 0.40 ); - else - c = div_color( p ); - } - else if ( p == pv ) - c = div_color( p ); - 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 ); - - if ( ! active ) - c = fl_inactive( c ); - - int yy = 0; - int xx = 0; - - if ( type() == FL_HORIZONTAL ) - { - xx = X + p * bw; - fl_rectf( xx + 1, Y, bw - 1, H, c ); - } - else - { - yy = Y + H - ((p+1) * bh); - 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 c; + + if ( p <= v ) + { + if ( p == clipv ) + c = fl_color_average( FL_YELLOW, div_color( p ), 0.40 ); + else + c = div_color( p ); + } + else if ( p == pv ) + c = div_color( p ); + 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 ); + + if ( ! active ) + c = fl_inactive( c ); + + int yy = 0; + int xx = 0; + + if ( type() == FL_HORIZONTAL ) + { + xx = X + p * bw; + fl_rectf( xx + 1, Y, bw - 1, H, c ); + } + else + { + yy = Y + H - ((p+1) * bh); + fl_rectf( X, yy + 1, W, bh - 1, 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(); } + +void +DPM::update ( void ) +{ + /* do falloff */ + float f = value() - 0.33f; + if ( f < -70.0f ) + f = -78.0f; + + value(f); +} diff --git a/mixer/src/DPM.H b/mixer/src/DPM.H index c079c55..71c1b82 100644 --- a/mixer/src/DPM.H +++ b/mixer/src/DPM.H @@ -22,7 +22,6 @@ #include // for FL_HORIZONTAL and FL_VERTICAL #include "Meter.H" -#include "dsp.h" class DPM : public Meter { @@ -31,11 +30,7 @@ class DPM : public Meter int _segments; int _pixels_per_segment; int _last_drawn_hi_segment; - - Value_Smoothing_Filter smoothing; - float _value; - int pos ( float v ) { float pv = deflection( v ) * ( _segments - 1 ); @@ -58,8 +53,7 @@ class DPM : public Meter { return _dim_gradient[ i * 127 / _segments ]; } - - + protected: virtual void draw_label ( void ); @@ -70,34 +64,28 @@ protected: public: + 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; } float dim ( void ) const { return _dim; } 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 void blend ( int nbreaks, int* b, Fl_Color *c, Fl_Color bc ) diff --git a/mixer/src/Group.C b/mixer/src/Group.C index 9052a47..40e3cee 100644 --- a/mixer/src/Group.C +++ b/mixer/src/Group.C @@ -275,7 +275,7 @@ Group::name ( const char *n ) if ( !active() ) { Client::init( ename ); - Module::set_sample_rate( sample_rate() ); + Module::sample_rate( sample_rate() ); } else { diff --git a/mixer/src/Meter.H b/mixer/src/Meter.H index ce61263..32eb41c 100644 --- a/mixer/src/Meter.H +++ b/mixer/src/Meter.H @@ -84,17 +84,14 @@ public: virtual void value ( float v ) { - if ( visible_r() ) - damage( FL_DAMAGE_USER1 ); - - _value = v; - - if ( _value > _peak ) - _peak = _value; + _value = v; + + if ( _value > _peak ) + _peak = _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(); } diff --git a/mixer/src/Meter_Indicator_Module.C b/mixer/src/Meter_Indicator_Module.C index 0a2a3fd..f56abda 100644 --- a/mixer/src/Meter_Indicator_Module.C +++ b/mixer/src/Meter_Indicator_Module.C @@ -35,6 +35,7 @@ #include "Chain.H" #include "DPM.H" +#include "dsp.h" #include "FL/test_press.H" @@ -64,8 +65,9 @@ Meter_Indicator_Module::Meter_Indicator_Module ( bool is_default ) end(); - control_value = new float[1]; - *control_value = -70.0f; + control_value = new float[1*2]; + control_value[0] = + control_value[1] = 0; 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 // of control outs has changed. 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 ) - { -/* engine->lock(); */ + float dB = CO_DB( control_value[i] ); + + 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]; - - 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; - } - } + control_value[i] = 0; + } } } @@ -248,7 +242,7 @@ Meter_Indicator_Module::handle_control_changed ( Port *p ) 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->type( FL_VERTICAL ); @@ -257,8 +251,10 @@ Meter_Indicator_Module::handle_control_changed ( Port *p ) dpm_pack->add( dpm ); dpm_pack->redraw(); - control_value[i] = -70.0f; - dpm->value( -70.0f ); + control_value[i] = 0; + + dpm->value( CO_DB( control_value[i] )); + } redraw(); @@ -276,12 +272,22 @@ Meter_Indicator_Module::process ( nframes_t ) if ( control_input[0].connected() ) { 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 ) { - float dB = ((float*)control_input[0].buffer())[i]; - if ( dB > control_value[i]) - control_value[i] = dB; + /* peak value since we last checked */ + if ( *pv > *cv ) + { + *cv = *pv; + /* reset now that we've got it */ + *pv = 0; + } + + cv++; + pv++; } } } diff --git a/mixer/src/Meter_Module.C b/mixer/src/Meter_Module.C index 2727764..6fbfc83 100644 --- a/mixer/src/Meter_Module.C +++ b/mixer/src/Meter_Module.C @@ -42,19 +42,22 @@ Meter_Module::Meter_Module ( ) dpm_pack->spacing( 1 ); control_value = 0; + peaks = 0; + meter_sample_period_count = 0; + meter_sample_periods = 0; color( fl_darker( fl_darker( FL_BACKGROUND_COLOR ))); end(); - Port p( this, Port::OUTPUT, Port::CONTROL, "dB level" ); - p.hints.type = Port::Hints::LOGARITHMIC; + Port p( this, Port::OUTPUT, Port::CONTROL, "peak level" ); + p.hints.type = Port::Hints::LINEAR; p.hints.ranged = true; - p.hints.maximum = 6.0f; - p.hints.minimum = -70.0f; + p.hints.maximum = 10.0f; + p.hints.minimum = 0.0f; p.hints.dimensions = 1; p.connect_to( new float[1] ); - p.control_value_no_callback( -70.0f ); + p.control_value_no_callback( 0 ); add_port( p ); @@ -71,6 +74,8 @@ Meter_Module::~Meter_Module ( ) + + void Meter_Module::resize ( int X, int Y, int W, int H ) { Fl_Group::resize(X,Y,W,H); @@ -93,8 +98,12 @@ Meter_Module::update ( void ) { for ( int i = dpm_pack->children(); i--; ) { - ((DPM*)dpm_pack->child( i ))->value( control_value[i] ); - control_value[i] = -70.0f; + DPM* o = ((DPM*)dpm_pack->child( i )); + + 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::OUTPUT, Port::AUDIO ) ); - } } else @@ -132,16 +140,20 @@ Meter_Module::configure_inputs ( int n ) audio_input.pop_back(); audio_output.back().disconnect(); audio_output.pop_back(); + + smoothing.pop_back(); } } + /* DMESSAGE( "sample rate: %lu, nframes: %lu", sample_rate(), this->nframes() ); */ + control_output[0].hints.dimensions = n; delete[] (float*)control_output[0].buffer(); { float *f = new float[n]; for ( int i = n; i--; ) - f[i] = -70.0f; + f[i] = 0; control_output[0].connect_to( f ); } @@ -151,7 +163,7 @@ Meter_Module::configure_inputs ( int n ) control_value = new float[n]; for ( int i = n; i--; ) - control_value[i] = -70.0f; + control_value[i] = 0; if ( control_output[0].connected() ) 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 ) { -// float dB = 20 * log10( get_peak_sample( (float*)audio_input[i].buffer(), nframes ) / 2.0f ); - const float dB = 20 * log10( buffer_get_peak( (sample_t*) audio_input[i].buffer(), nframes ) ); + const float peak = buffer_get_peak( (sample_t*) audio_input[i].buffer(), nframes ); + + /* const float RMS = sqrtf( peak / (float)nframes); */ - ((float*)control_output[0].buffer())[i] = dB; - if (dB > control_value[i]) - control_value[i] = dB; + /* since the GUI only updates at 20 or 30hz, there's no point in doing this more often than necessary. */ + + /* 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; } } diff --git a/mixer/src/Meter_Module.H b/mixer/src/Meter_Module.H index eee143f..5488782 100644 --- a/mixer/src/Meter_Module.H +++ b/mixer/src/Meter_Module.H @@ -20,6 +20,8 @@ #pragma once #include "Module.H" +#include "dsp.h" +#include class Fl_Scalepack; @@ -27,8 +29,19 @@ class Meter_Module : public Module { Fl_Scalepack *dpm_pack; + std::vector smoothing; + 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: Meter_Module ( ); diff --git a/mixer/src/Mixer.C b/mixer/src/Mixer.C index d5e11a4..e5d10d2 100644 --- a/mixer/src/Mixer.C +++ b/mixer/src/Mixer.C @@ -416,7 +416,7 @@ Mixer::update_cb ( void ) { 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++ ) { @@ -591,7 +591,7 @@ Mixer::Mixer ( int X, int Y, int W, int H, const char *L ) : resize( X,Y,W,H ); - update_frequency( 30 ); + update_frequency( 24 ); Fl::add_timeout( FEEDBACK_UPDATE_FREQ, send_feedback_cb, this ); diff --git a/mixer/src/Module.H b/mixer/src/Module.H index 7258244..294ddfb 100644 --- a/mixer/src/Module.H +++ b/mixer/src/Module.H @@ -46,10 +46,10 @@ class Module : public Fl_Group, public Loggable { int _ins; int _outs; int _instances; - nframes_t _nframes; Chain *_chain; bool _is_default; + nframes_t _nframes; static nframes_t _sample_rate; static Module *_copied_module_empty; static char *_copied_module_settings; @@ -181,12 +181,14 @@ public: _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; } Type type ( void ) const { return _type; } Direction direction ( void ) const { return _direction; } 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 ) const { return _buf; } @@ -368,7 +370,6 @@ public: LOG_NAME_FUNC( Module ); - nframes_t nframes ( void ) const { return _nframes; } 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 ); 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(); @@ -561,7 +564,7 @@ public: bool add_aux_audio_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(); virtual void command_activate ( void ); diff --git a/nonlib/dsp.C b/nonlib/dsp.C index 3ff8663..a934de2 100644 --- a/nonlib/dsp.C +++ b/nonlib/dsp.C @@ -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); - float pmax = 0.0f; - float pmin = 0.0f; + float p = 0.0f; while (nframes--) { - const float v = *buf_++; + const float v = fabsf( *buf_++ ); - if ( v > pmax ) - pmax = v; - - if ( v < pmin ) - pmin = v; + if ( v > p ) + p = v; } - pmax = fabsf(pmax); - pmin = fabsf(pmin); - - return pmax > pmin ? pmax : pmin; + return p; } void @@ -266,6 +259,8 @@ Value_Smoothing_Filter::apply( sample_t * __restrict__ dst, nframes_t nframes, f dst_[i] = g2; } + g2 += 1e-10f; /* denormal protection */ + if ( fabsf( gt - g2 ) < 0.0001f ) g2 = gt;