diff --git a/libs/ardour/ardour/logmeter.h b/libs/ardour/ardour/logmeter.h new file mode 100644 index 0000000000..6846af1f69 --- /dev/null +++ b/libs/ardour/ardour/logmeter.h @@ -0,0 +1,172 @@ +/* + Copyright (C) 2000-2007 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __ardour_gtk_log_meter_h__ +#define __ardour_gtk_log_meter_h__ + +#include "ardour/dB.h" + +#if 1 +static inline float +_log_meter (float power, double lower_db, double upper_db, double non_linearity) +{ + return (power < lower_db ? 0.0 : pow((power-lower_db)/(upper_db-lower_db), non_linearity)); +} + +static inline float +alt_log_meter (float power) +{ + return _log_meter (power, -192.0, 0.0, 8.0); +} +#endif + +/* prototypes - avoid compiler warning */ +static inline float log_meter (float db); +static inline float meter_deflect_ppm (float); +static inline float meter_deflect_din (float); +static inline float meter_deflect_nordic (float); +static inline float meter_deflect_vu (float); +static inline float meter_deflect_k (float, float); + + + +static inline float +log_meter (float db) +{ + float def = 0.0f; /* Meter deflection %age */ + + if (db < -70.0f) { + def = 0.0f; + } else if (db < -60.0f) { + def = (db + 70.0f) * 0.25f; + } else if (db < -50.0f) { + def = (db + 60.0f) * 0.5f + 2.5f; + } else if (db < -40.0f) { + def = (db + 50.0f) * 0.75f + 7.5f; + } else if (db < -30.0f) { + def = (db + 40.0f) * 1.5f + 15.0f; + } else if (db < -20.0f) { + def = (db + 30.0f) * 2.0f + 30.0f; + } else if (db < 6.0f) { + def = (db + 20.0f) * 2.5f + 50.0f; + } else { + def = 115.0f; + } + + /* 115 is the deflection %age that would be + when db=6.0. this is an arbitrary + endpoint for our scaling. + */ + + return def/115.0f; +} + +static inline float +log_meter0dB (float db) +{ + float def = 0.0f; /* Meter deflection %age */ + + if (db < -70.0f) { + def = 0.0f; + } else if (db < -60.0f) { + def = (db + 70.0f) * 0.25f; + } else if (db < -50.0f) { + def = (db + 60.0f) * 0.5f + 2.5f; + } else if (db < -40.0f) { + def = (db + 50.0f) * 0.75f + 7.5f; + } else if (db < -30.0f) { + def = (db + 40.0f) * 1.5f + 15.0f; + } else if (db < -20.0f) { + def = (db + 30.0f) * 2.0f + 30.0f; + } else if (db < 0.0f) { + def = (db + 20.0f) * 2.5f + 50.0f; + } else { + def = 100.0f; + } + return def/100.0f; +} + +static inline float +meter_deflect_ppm (float db) +{ + if (db < -30) { + // 2.258 == ((-30 + 32.0)/ 28.0) / 10^(-30 / 20); + return (dB_to_coefficient(db) * 2.258769757f); + } else { + const float rv = (db + 32.0f) / 28.0f; + if (rv < 1.0) { + return rv; + } else { + return 1.0; + } + } +} + +static inline float +meter_deflect_din (float db) +{ + float rv = dB_to_coefficient(db); + rv = sqrtf (sqrtf (2.3676f * rv)) - 0.1803f; + if (rv >= 1.0) { + return 1.0; + } else { + return (rv > 0 ? rv : 0.0); + } +} + +static inline float +meter_deflect_nordic (float db) +{ + if (db < -60) { + return 0.0; + } else { + const float rv = (db + 60.0f) / 54.0f; + if (rv < 1.0) { + return rv; + } else { + return 1.0; + } + } +} + +static inline float +meter_deflect_vu (float db) +{ + const float rv = 6.77165f * dB_to_coefficient(db); + if (rv > 1.0) return 1.0; + return rv; +} + +static inline float +meter_deflect_k (float db, float krange) +{ + db+=krange; + if (db < -40.0f) { + return (dB_to_coefficient(db) * 500.0f / (krange + 45.0f)); + } else { + const float rv = (db + 45.0f) / (krange + 45.0f); + if (rv < 1.0) { + return rv; + } else { + return 1.0; + } + } +} + +#endif /* __ardour_gtk_log_meter_h__ */ diff --git a/libs/surfaces/push2/level_meter.cc b/libs/surfaces/push2/level_meter.cc new file mode 100644 index 0000000000..212644ae0c --- /dev/null +++ b/libs/surfaces/push2/level_meter.cc @@ -0,0 +1,506 @@ +/* + Copyright (C) 2002 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include + +#include "ardour/meter.h" +#include "ardour/logmeter.h" +#include "ardour/rc_configuration.h" + +#include +#include + +#include "pbd/fastlog.h" +#include "pbd/i18n.h" + +#include "canvas/box.h" +#include "canvas/meter.h" + +#include "level_meter.h" +#include "push2.h" + +using namespace ARDOUR; +using namespace PBD; +using namespace Gtkmm2ext; +using namespace std; +using namespace ArdourSurface; +using namespace ArdourCanvas; + +LevelMeter::LevelMeter (Push2& p, Item* parent, int len, Meter::Orientation o) + : Container (parent) + , p2 (p) + , _meter (0) + , _meter_orientation(o) + , regular_meter_width (6) + , meter_length (len) + , thin_meter_width(2) + , max_peak (minus_infinity()) + , meter_type (MeterPeak) + , visible_meter_type (MeterType(0)) + , midi_count (0) + , meter_count (0) + , max_visible_meters (0) +{ + Config->ParameterChanged.connect (_parameter_connection, invalidator(*this), boost::bind (&LevelMeter::parameter_changed, this, _1), &p2); + + if (_meter_orientation == Meter::Vertical) { + meter_packer = new HBox (this); + } else { + meter_packer = new VBox (this); + } + + meter_packer->set_collapse_on_hide (true); +} + +LevelMeter::~LevelMeter () +{ + _configuration_connection.disconnect(); + _meter_type_connection.disconnect(); + _parameter_connection.disconnect(); + for (vector::iterator i = meters.begin(); i != meters.end(); i++) { + delete (*i).meter; + } + meters.clear(); +} + +void +LevelMeter::set_meter (PeakMeter* meter) +{ + _configuration_connection.disconnect(); + _meter_type_connection.disconnect(); + + _meter = meter; + + if (_meter) { + _meter->ConfigurationChanged.connect (_configuration_connection, invalidator(*this), boost::bind (&LevelMeter::configuration_changed, this, _1, _2), &p2); + _meter->TypeChanged.connect (_meter_type_connection, invalidator (*this), boost::bind (&LevelMeter::meter_type_changed, this, _1), &p2); + } + + setup_meters (meter_length, regular_meter_width, thin_meter_width); +} + +static float meter_lineup_cfg(MeterLineUp lul, float offset) { + switch (lul) { + case MeteringLineUp24: + return offset + 6.0; + case MeteringLineUp20: + return offset + 2.0; + case MeteringLineUp18: + return offset; + case MeteringLineUp15: + return offset - 3.0; + default: + break; + } + return offset; +} + +static float meter_lineup(float offset) { + return meter_lineup_cfg (MeteringLineUp24, offset); + //return meter_lineup_cfg (UIConfiguration::instance().get_meter_line_up_level(), offset); +} + +static float vu_standard() { + return 0; +#if 0 + // note - default meter config is +2dB (france) + switch (UIConfiguration::instance().get_meter_vu_standard()) { + default: + case MeteringVUfrench: // 0VU = -2dBu + return 0; + case MeteringVUamerican: // 0VU = 0dBu + return -2; + case MeteringVUstandard: // 0VU = +4dBu + return -6; + case MeteringVUeight: // 0VU = +8dBu + return -10; + } +#endif +} + +float +LevelMeter::update_meters () +{ + vector::iterator i; + uint32_t n; + + if (!_meter) { + return 0.0f; + } + + uint32_t nmidi = _meter->input_streams().n_midi(); + + for (n = 0, i = meters.begin(); i != meters.end(); ++i, ++n) { + if ((*i).packed) { + const float mpeak = _meter->meter_level(n, MeterMaxPeak); + if (mpeak > (*i).max_peak) { + (*i).max_peak = mpeak; + //(*i).meter->set_highlight(mpeak >= UIConfiguration::instance().get_meter_peak()); + (*i).meter->set_highlight (mpeak >= 2.0); + } + if (mpeak > max_peak) { + max_peak = mpeak; + } + + if (n < nmidi) { + (*i).meter->set (_meter->meter_level (n, MeterPeak)); + } else { + const float peak = _meter->meter_level (n, meter_type); + if (meter_type == MeterPeak) { + (*i).meter->set (log_meter (peak)); + } else if (meter_type == MeterPeak0dB) { + (*i).meter->set (log_meter0dB (peak)); + } else if (meter_type == MeterIEC1NOR) { + (*i).meter->set (meter_deflect_nordic (peak + meter_lineup(0))); + } else if (meter_type == MeterIEC1DIN) { + // (*i).meter->set (meter_deflect_din (peak + meter_lineup_cfg(UIConfiguration::instance().get_meter_line_up_din(), 3.0))); + } else if (meter_type == MeterIEC2BBC || meter_type == MeterIEC2EBU) { + (*i).meter->set (meter_deflect_ppm (peak + meter_lineup(0))); + } else if (meter_type == MeterVU) { + (*i).meter->set (meter_deflect_vu (peak + vu_standard() + meter_lineup(0))); + } else if (meter_type == MeterK12) { + (*i).meter->set (meter_deflect_k (peak, 12), meter_deflect_k(_meter->meter_level(n, MeterPeak), 12)); + } else if (meter_type == MeterK14) { + (*i).meter->set (meter_deflect_k (peak, 14), meter_deflect_k(_meter->meter_level(n, MeterPeak), 14)); + } else if (meter_type == MeterK20) { + (*i).meter->set (meter_deflect_k (peak, 20), meter_deflect_k(_meter->meter_level(n, MeterPeak), 20)); + } else { // RMS + (*i).meter->set (log_meter (peak), log_meter(_meter->meter_level(n, MeterPeak))); + } + } + } + } + return max_peak; +} + +void +LevelMeter::parameter_changed (string p) +{ + if (p == "meter-hold") { + vector::iterator i; + uint32_t n; + + for (n = 0, i = meters.begin(); i != meters.end(); ++i, ++n) { + //(*i).meter->set_hold_count ((uint32_t) floor(UIConfiguration::instance().get_meter_hold())); + (*i).meter->set_hold_count (20); + } + } + else if (p == "meter-line-up-level") { + setup_meters (meter_length, regular_meter_width, thin_meter_width); + } + else if (p == "meter-style-led") { + setup_meters (meter_length, regular_meter_width, thin_meter_width); + } + else if (p == "meter-peak") { + vector::iterator i; + uint32_t n; + + for (n = 0, i = meters.begin(); i != meters.end(); ++i, ++n) { + (*i).max_peak = minus_infinity(); + } + } +} + +void +LevelMeter::configuration_changed (ChanCount /*in*/, ChanCount /*out*/) +{ + setup_meters (meter_length, regular_meter_width, thin_meter_width); +} + +void +LevelMeter::meter_type_changed (MeterType t) +{ + meter_type = t; + setup_meters (meter_length, regular_meter_width, thin_meter_width); +} + +void +LevelMeter::hide_all_meters () +{ + for (vector::iterator i = meters.begin(); i != meters.end(); ++i) { + if ((*i).packed) { + meter_packer->remove ((*i).meter); + (*i).packed = false; + } + } + meter_count = 0; +} + +void +LevelMeter::set_max_audio_meter_count (uint32_t cnt) +{ + if (cnt == max_visible_meters) { + return; + } + max_visible_meters = cnt; + setup_meters (meter_length, regular_meter_width, thin_meter_width); +} + +void +LevelMeter::setup_meters (int len, int initial_width, int thin_width) +{ + + if (!_meter) { + hide_all_meters (); + return; /* do it later or never */ + } + + uint32_t nmidi = _meter->input_streams().n_midi(); + uint32_t nmeters = _meter->input_streams().n_total(); + regular_meter_width = initial_width; + thin_meter_width = thin_width; + meter_length = len; + + guint16 width; + + if (nmeters == 0) { + hide_all_meters (); + return; + } + + if (nmeters <= 2) { + width = regular_meter_width; + } else { + width = thin_meter_width; + } + + if ( meters.size() > 0 + && nmidi == midi_count + && nmeters == meter_count + && meters[0].width == width + && meters[0].length == len + && meter_type == visible_meter_type) { + return; + } + +#if 0 + printf("Meter redraw: %s %s %s %s %s %s\n", + (meters.size() > 0) ? "yes" : "no", + (meters.size() > 0 && meters[0].width == width) ? "yes" : "no", + (meters.size() > 0 && meters[0].length == len) ? "yes" : "no", + (nmeters == meter_count) ? "yes" : "no", + (meter_type == visible_meter_type) ? "yes" : "no", + !color_changed ? "yes" : "no" + ); +#endif + + hide_all_meters (); + while (meters.size() < nmeters) { + meters.push_back (MeterInfo()); + } + + //cerr << "LevelMeter::setup_meters() called color_changed = " << color_changed << " colors: " << endl;//DEBUG + + for (int32_t n = nmeters-1; nmeters && n >= 0 ; --n) { +#if 0 + uint32_t c[10]; + uint32_t b[4]; + float stp[4]; + int styleflags = UIConfiguration::instance().get_meter_style_led() ? 3 : 1; + b[0] = UIConfiguration::instance().color ("meter background bottom"); + b[1] = UIConfiguration::instance().color ("meter background top"); + b[2] = 0x991122ff; // red highlight gradient Bot + b[3] = 0x551111ff; // red highlight gradient Top + if ((uint32_t) n < nmidi) { + c[0] = UIConfiguration::instance().color ("midi meter color0"); + c[1] = UIConfiguration::instance().color ("midi meter color1"); + c[2] = UIConfiguration::instance().color ("midi meter color2"); + c[3] = UIConfiguration::instance().color ("midi meter color3"); + c[4] = UIConfiguration::instance().color ("midi meter color4"); + c[5] = UIConfiguration::instance().color ("midi meter color5"); + c[6] = UIConfiguration::instance().color ("midi meter color6"); + c[7] = UIConfiguration::instance().color ("midi meter color7"); + c[8] = UIConfiguration::instance().color ("midi meter color8"); + c[9] = UIConfiguration::instance().color ("midi meter color9"); + stp[0] = 115.0 * 32.0 / 128.0; + stp[1] = 115.0 * 64.0 / 128.0; + stp[2] = 115.0 * 100.0 / 128.0; + stp[3] = 115.0 * 112.0 / 128.0; + } else { + c[0] = UIConfiguration::instance().color ("meter color0"); + c[1] = UIConfiguration::instance().color ("meter color1"); + c[2] = UIConfiguration::instance().color ("meter color2"); + c[3] = UIConfiguration::instance().color ("meter color3"); + c[4] = UIConfiguration::instance().color ("meter color4"); + c[5] = UIConfiguration::instance().color ("meter color5"); + c[6] = UIConfiguration::instance().color ("meter color6"); + c[7] = UIConfiguration::instance().color ("meter color7"); + c[8] = UIConfiguration::instance().color ("meter color8"); + c[9] = UIConfiguration::instance().color ("meter color9"); + + switch (meter_type) { + case MeterK20: + stp[0] = 115.0 * meter_deflect_k(-40, 20); //-20 + stp[1] = 115.0 * meter_deflect_k(-20, 20); // 0 + stp[2] = 115.0 * meter_deflect_k(-18, 20); // +2 + stp[3] = 115.0 * meter_deflect_k(-16, 20); // +4 + c[0] = c[1] = 0x008800ff; + c[2] = c[3] = 0x00ff00ff; + c[4] = c[5] = 0xffff00ff; + c[6] = c[7] = 0xffff00ff; + c[8] = c[9] = 0xff0000ff; + break; + case MeterK14: + stp[0] = 115.0 * meter_deflect_k(-34, 14); //-20 + stp[1] = 115.0 * meter_deflect_k(-14, 14); // 0 + stp[2] = 115.0 * meter_deflect_k(-12, 14); // +2 + stp[3] = 115.0 * meter_deflect_k(-10, 14); // +4 + c[0] = c[1] = 0x008800ff; + c[2] = c[3] = 0x00ff00ff; + c[4] = c[5] = 0xffff00ff; + c[6] = c[7] = 0xffff00ff; + c[8] = c[9] = 0xff0000ff; + break; + case MeterK12: + stp[0] = 115.0 * meter_deflect_k(-32, 12); //-20 + stp[1] = 115.0 * meter_deflect_k(-12, 12); // 0 + stp[2] = 115.0 * meter_deflect_k(-10, 12); // +2 + stp[3] = 115.0 * meter_deflect_k( -8, 12); // +4 + c[0] = c[1] = 0x008800ff; + c[2] = c[3] = 0x00ff00ff; + c[4] = c[5] = 0xffff00ff; + c[6] = c[7] = 0xffff00ff; + c[8] = c[9] = 0xff0000ff; + break; + case MeterIEC2BBC: + c[0] = c[1] = c[2] = c[3] = c[4] = c[5] = c[6] = c[7] = c[8] = c[9] = + UIConfiguration::instance().color ("meter color BBC"); + stp[0] = stp[1] = stp[2] = stp[3] = 115.0; + break; + case MeterIEC2EBU: + stp[0] = 115.0 * meter_deflect_ppm(-24); // ignored + stp[1] = 115.0 * meter_deflect_ppm(-18); + stp[2] = 115.0 * meter_deflect_ppm( -9); + stp[3] = 115.0 * meter_deflect_ppm( 0); // ignored + c[3] = c[2] = c[1]; + c[6] = c[7] = c[8] = c[9]; + break; + case MeterIEC1NOR: + stp[0] = 115.0 * meter_deflect_nordic(-30); // ignored + stp[1] = 115.0 * meter_deflect_nordic(-18); + stp[2] = 115.0 * meter_deflect_nordic(-12); + stp[3] = 115.0 * meter_deflect_nordic( -9); // ignored + c[0] = c[1] = c[2]; // bright-green + c[6] = c[7] = c[8] = c[9]; + break; + case MeterIEC1DIN: + stp[0] = 115.0 * meter_deflect_din(-29); // ignored + stp[1] = 115.0 * meter_deflect_din(-18); + stp[2] = 115.0 * meter_deflect_din(-15); // ignored + stp[3] = 115.0 * meter_deflect_din( -9); + c[0] = c[2] = c[3] = c[1]; + c[4] = c[6]; + c[5] = c[7]; + break; + case MeterVU: + stp[0] = 115.0 * meter_deflect_vu(-26); // -6 + stp[1] = 115.0 * meter_deflect_vu(-23); // -3 + stp[2] = 115.0 * meter_deflect_vu(-20); // 0 + stp[3] = 115.0 * meter_deflect_vu(-18); // +2 + c[0] = c[2] = c[3] = c[4] = c[5] = c[1]; + c[7] = c[8] = c[9] = c[6]; + break; + case MeterPeak0dB: + stp[1] = 89.125; // 115.0 * log_meter0dB(-9); + stp[2] = 106.375; // 115.0 * log_meter0dB(-3); + stp[3] = 115.0; // 115.0 * log_meter0dB(0); + switch (UIConfiguration::instance().get_meter_line_up_level()) { + case MeteringLineUp24: + stp[0] = 115.0 * log_meter0dB(-24); + break; + case MeteringLineUp20: + stp[0] = 115.0 * log_meter0dB(-20); + break; + default: + case MeteringLineUp18: + stp[0] = 115.0 * log_meter0dB(-18); + break; + case MeteringLineUp15: + stp[0] = 115.0 * log_meter0dB(-15); + } + break; + default: // PEAK, RMS + stp[1] = 77.5; // 115 * log_meter(-9) + stp[2] = 92.5; // 115 * log_meter(-3) + stp[3] = 100.0; // 115 * log_meter(0) + switch (UIConfiguration::instance().get_meter_line_up_level()) { + case MeteringLineUp24: + stp[0] = 42.0; + break; + case MeteringLineUp20: + stp[0] = 50.0; + break; + default: + case MeteringLineUp18: + stp[0] = 55.0; + break; + case MeteringLineUp15: + stp[0] = 62.5; + break; + } + } + } + +#endif + if (meters[n].width != width || meters[n].length != len || meter_type != visible_meter_type || nmidi != midi_count) { + bool hl = meters[n].meter ? meters[n].meter->get_highlight() : false; + meters[n].packed = false; + delete meters[n].meter; + meters[n].meter = new Meter (this->canvas(), 32, width, _meter_orientation, len); + meters[n].meter->set_highlight(hl); + meters[n].width = width; + meters[n].length = len; + } + + meter_packer->pack_start (meters[n].meter); + meters[n].packed = true; + if (max_visible_meters == 0 || (uint32_t) n < max_visible_meters + nmidi) { + meters[n].meter->show (); + } else { + meters[n].meter->hide (); + } + } + + visible_meter_type = meter_type; + midi_count = nmidi; + meter_count = nmeters; +} + +void +LevelMeter::set_type(MeterType t) +{ + meter_type = t; + _meter->set_type(t); +} + +void LevelMeter::clear_meters (bool reset_highlight) +{ + for (vector::iterator i = meters.begin(); i < meters.end(); i++) { + (*i).meter->clear(); + (*i).max_peak = minus_infinity(); + if (reset_highlight) + (*i).meter->set_highlight(false); + } + max_peak = minus_infinity(); +} + +void LevelMeter::hide_meters () +{ + hide_all_meters(); +} diff --git a/libs/surfaces/push2/level_meter.h b/libs/surfaces/push2/level_meter.h new file mode 100644 index 0000000000..04f4ca21fe --- /dev/null +++ b/libs/surfaces/push2/level_meter.h @@ -0,0 +1,106 @@ +/* + Copyright (C) 2011-2016 Paul Davis + Author: Carl Hetherington + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __ardour_push2_level_meter_h__ +#define __ardour_push2_level_meter_h__ + +#include "canvas/container.h" +#include "canvas/meter.h" + +namespace ARDOUR { + class Session; + class PeakMeter; +} + +namespace ArdourCanvas { + class Box; +} + +namespace ArdourSurface +{ + +class Push2; + +class LevelMeter : public ArdourCanvas::Container, public sigc::trackable +{ + public: + LevelMeter (Push2& p2, Item* parent, int len, ArdourCanvas::Meter::Orientation o = ArdourCanvas::Meter::Vertical); + virtual ~LevelMeter (); + + virtual void set_meter (ARDOUR::PeakMeter* meter); + + void update_gain_sensitive (); + + float update_meters (); + void update_meters_falloff (); + void clear_meters (bool reset_highlight = true); + void hide_meters (); + void setup_meters (int len=0, int width=3, int thin=2); + void set_max_audio_meter_count (uint32_t cnt = 0); + + void set_type (ARDOUR::MeterType); + ARDOUR::MeterType get_type () { return meter_type; } + + private: + Push2& p2; + ARDOUR::PeakMeter* _meter; + ArdourCanvas::Meter::Orientation _meter_orientation; + ArdourCanvas::Box* meter_packer; + + struct MeterInfo { + ArdourCanvas::Meter* meter; + gint16 width; + int length; + bool packed; + float max_peak; + + MeterInfo() { + meter = 0; + width = 0; + length = 0; + packed = false; + max_peak = -INFINITY; + } + }; + + guint16 regular_meter_width; + int meter_length; + guint16 thin_meter_width; + std::vector meters; + float max_peak; + ARDOUR::MeterType meter_type; + ARDOUR::MeterType visible_meter_type; + uint32_t midi_count; + uint32_t meter_count; + uint32_t max_visible_meters; + + PBD::ScopedConnection _configuration_connection; + PBD::ScopedConnection _meter_type_connection; + PBD::ScopedConnection _parameter_connection; + + void hide_all_meters (); + + void parameter_changed (std::string); + void configuration_changed (ARDOUR::ChanCount in, ARDOUR::ChanCount out); + void meter_type_changed (ARDOUR::MeterType); +}; + +} + +#endif /* __ardour_push2_level_meter_h__ */