Robin Gareus
7235ece898
This reverts commit d00e035fe0
.
..which introduced a bug.
Meter count and type may change when switching the meter point or simply
when selecting a different track in the editor-mixer. Additional meters
were not unpacked and remained on canvas.
Ideally we'd just remove the excess meters or meters where the type
changed, but that's far more complex than just repacking them all.
511 lines
15 KiB
C++
511 lines
15 KiB
C++
/*
|
|
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 <limits.h>
|
|
|
|
#include "ardour/meter.h"
|
|
|
|
#include <gtkmm2ext/utils.h>
|
|
#include "pbd/fastlog.h"
|
|
|
|
#include "ardour_ui.h"
|
|
#include "global_signals.h"
|
|
#include "level_meter.h"
|
|
#include "utils.h"
|
|
#include "logmeter.h"
|
|
#include "gui_thread.h"
|
|
#include "keyboard.h"
|
|
#include "public_editor.h"
|
|
|
|
#include "i18n.h"
|
|
|
|
using namespace ARDOUR;
|
|
using namespace ARDOUR_UI_UTILS;
|
|
using namespace PBD;
|
|
using namespace Gtkmm2ext;
|
|
using namespace Gtk;
|
|
using namespace std;
|
|
|
|
LevelMeterBase::LevelMeterBase (Session* s, PBD::EventLoop::InvalidationRecord* ir, FastMeter::Orientation o)
|
|
: parent_invalidator(ir)
|
|
, _meter (0)
|
|
, _meter_orientation(o)
|
|
, regular_meter_width (6)
|
|
, meter_length (0)
|
|
, thin_meter_width(2)
|
|
, max_peak (minus_infinity())
|
|
, meter_type (MeterPeak)
|
|
, color_changed (false)
|
|
{
|
|
set_session (s);
|
|
|
|
Config->ParameterChanged.connect (_parameter_connection, parent_invalidator, boost::bind (&LevelMeterBase::parameter_changed, this, _1), gui_context());
|
|
ARDOUR_UI::config()->ParameterChanged.connect (sigc::mem_fun(*this, &LevelMeterBase::parameter_changed));
|
|
ColorsChanged.connect (sigc::mem_fun (*this, &LevelMeterBase::color_handler));
|
|
}
|
|
|
|
LevelMeterBase::~LevelMeterBase ()
|
|
{
|
|
_configuration_connection.disconnect();
|
|
_meter_type_connection.disconnect();
|
|
_parameter_connection.disconnect();
|
|
for (vector<MeterInfo>::iterator i = meters.begin(); i != meters.end(); i++) {
|
|
delete (*i).meter;
|
|
}
|
|
meters.clear();
|
|
}
|
|
|
|
void
|
|
LevelMeterBase::set_meter (PeakMeter* meter)
|
|
{
|
|
_configuration_connection.disconnect();
|
|
_meter_type_connection.disconnect();
|
|
|
|
_meter = meter;
|
|
color_changed = true;
|
|
|
|
if (_meter) {
|
|
_meter->ConfigurationChanged.connect (_configuration_connection, parent_invalidator, boost::bind (&LevelMeterBase::configuration_changed, this, _1, _2), gui_context());
|
|
_meter->TypeChanged.connect (_meter_type_connection, parent_invalidator, boost::bind (&LevelMeterBase::meter_type_changed, this, _1), gui_context());
|
|
}
|
|
}
|
|
|
|
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 (ARDOUR_UI::config()->get_meter_line_up_level(), offset);
|
|
}
|
|
|
|
static float vu_standard() {
|
|
// note - default meter config is +2dB (france)
|
|
switch (ARDOUR_UI::config()->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;
|
|
}
|
|
}
|
|
|
|
float
|
|
LevelMeterBase::update_meters ()
|
|
{
|
|
vector<MeterInfo>::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 >= ARDOUR_UI::config()->get_meter_peak());
|
|
}
|
|
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 == 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(ARDOUR_UI::config()->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
|
|
LevelMeterBase::parameter_changed (string p)
|
|
{
|
|
ENSURE_GUI_THREAD (*this, &LevelMeterBase::parameter_changed, p)
|
|
|
|
if (p == "meter-hold") {
|
|
vector<MeterInfo>::iterator i;
|
|
uint32_t n;
|
|
|
|
for (n = 0, i = meters.begin(); i != meters.end(); ++i, ++n) {
|
|
(*i).meter->set_hold_count ((uint32_t) floor(ARDOUR_UI::config()->get_meter_hold()));
|
|
}
|
|
}
|
|
else if (p == "meter-line-up-level") {
|
|
color_changed = true;
|
|
setup_meters (meter_length, regular_meter_width, thin_meter_width);
|
|
}
|
|
else if (p == "meter-style-led") {
|
|
color_changed = true;
|
|
setup_meters (meter_length, regular_meter_width, thin_meter_width);
|
|
}
|
|
else if (p == "meter-peak") {
|
|
vector<MeterInfo>::iterator i;
|
|
uint32_t n;
|
|
|
|
for (n = 0, i = meters.begin(); i != meters.end(); ++i, ++n) {
|
|
(*i).max_peak = minus_infinity();
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
LevelMeterBase::configuration_changed (ChanCount /*in*/, ChanCount /*out*/)
|
|
{
|
|
color_changed = true;
|
|
setup_meters (meter_length, regular_meter_width, thin_meter_width);
|
|
}
|
|
|
|
void
|
|
LevelMeterBase::meter_type_changed (MeterType t)
|
|
{
|
|
meter_type = t;
|
|
color_changed = true;
|
|
setup_meters (meter_length, regular_meter_width, thin_meter_width);
|
|
MeterTypeChanged(t);
|
|
}
|
|
|
|
void
|
|
LevelMeterBase::hide_all_meters ()
|
|
{
|
|
for (vector<MeterInfo>::iterator i = meters.begin(); i != meters.end(); ++i) {
|
|
if ((*i).packed) {
|
|
mtr_remove (*((*i).meter));
|
|
(*i).packed = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
LevelMeterBase::setup_meters (int len, int initial_width, int thin_width)
|
|
{
|
|
hide_all_meters ();
|
|
|
|
if (!_meter) {
|
|
return; /* do it later or never */
|
|
}
|
|
|
|
int32_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) {
|
|
return;
|
|
}
|
|
|
|
if (nmeters <= 2) {
|
|
width = regular_meter_width;
|
|
} else {
|
|
width = thin_meter_width;
|
|
}
|
|
|
|
while (meters.size() < nmeters) {
|
|
meters.push_back (MeterInfo());
|
|
}
|
|
|
|
//cerr << "LevelMeterBase::setup_meters() called color_changed = " << color_changed << " colors: " << endl;//DEBUG
|
|
|
|
for (int32_t n = nmeters-1; nmeters && n >= 0 ; --n) {
|
|
uint32_t c[10];
|
|
uint32_t b[4];
|
|
float stp[4];
|
|
int styleflags = ARDOUR_UI::config()->get_meter_style_led() ? 3 : 1;
|
|
b[0] = ARDOUR_UI::config()->color ("meter background bottom");
|
|
b[1] = ARDOUR_UI::config()->color ("meter background top");
|
|
b[2] = 0x991122ff; // red highlight gradient Bot
|
|
b[3] = 0x551111ff; // red highlight gradient Top
|
|
if (n < nmidi) {
|
|
c[0] = ARDOUR_UI::config()->color ("midi meter color0");
|
|
c[1] = ARDOUR_UI::config()->color ("midi meter color1");
|
|
c[2] = ARDOUR_UI::config()->color ("midi meter color2");
|
|
c[3] = ARDOUR_UI::config()->color ("midi meter color3");
|
|
c[4] = ARDOUR_UI::config()->color ("midi meter color4");
|
|
c[5] = ARDOUR_UI::config()->color ("midi meter color5");
|
|
c[6] = ARDOUR_UI::config()->color ("midi meter color6");
|
|
c[7] = ARDOUR_UI::config()->color ("midi meter color7");
|
|
c[8] = ARDOUR_UI::config()->color ("midi meter color8");
|
|
c[9] = ARDOUR_UI::config()->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] = ARDOUR_UI::config()->color ("meter color0");
|
|
c[1] = ARDOUR_UI::config()->color ("meter color1");
|
|
c[2] = ARDOUR_UI::config()->color ("meter color2");
|
|
c[3] = ARDOUR_UI::config()->color ("meter color3");
|
|
c[4] = ARDOUR_UI::config()->color ("meter color4");
|
|
c[5] = ARDOUR_UI::config()->color ("meter color5");
|
|
c[6] = ARDOUR_UI::config()->color ("meter color6");
|
|
c[7] = ARDOUR_UI::config()->color ("meter color7");
|
|
c[8] = ARDOUR_UI::config()->color ("meter color8");
|
|
c[9] = ARDOUR_UI::config()->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] =
|
|
ARDOUR_UI::config()->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;
|
|
default: // PEAK, RMS
|
|
stp[1] = 77.5; // 115 * log_meter(-10)
|
|
stp[2] = 92.5; // 115 * log_meter(-3)
|
|
stp[3] = 100.0; // 115 * log_meter(0)
|
|
switch (ARDOUR_UI::config()->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;
|
|
}
|
|
}
|
|
}
|
|
if (meters[n].width != width || meters[n].length != len || color_changed || meter_type != visible_meter_type) {
|
|
bool hl = meters[n].meter ? meters[n].meter->get_highlight() : false;
|
|
meters[n].packed = false;
|
|
delete meters[n].meter;
|
|
meters[n].meter = new FastMeter ((uint32_t) floor (ARDOUR_UI::config()->get_meter_hold()), width, _meter_orientation, len,
|
|
c[0], c[1], c[2], c[3], c[4],
|
|
c[5], c[6], c[7], c[8], c[9],
|
|
b[0], b[1], b[2], b[3],
|
|
stp[0], stp[1], stp[2], stp[3],
|
|
styleflags
|
|
);
|
|
meters[n].meter->set_highlight(hl);
|
|
meters[n].width = width;
|
|
meters[n].length = len;
|
|
meters[n].meter->add_events (Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK);
|
|
meters[n].meter->signal_button_press_event().connect (sigc::mem_fun (*this, &LevelMeterBase::meter_button_press), false);
|
|
meters[n].meter->signal_button_release_event().connect (sigc::mem_fun (*this, &LevelMeterBase::meter_button_release), false);
|
|
}
|
|
|
|
//pack_end (*meters[n].meter, false, false);
|
|
mtr_pack (*meters[n].meter);
|
|
meters[n].meter->show_all ();
|
|
meters[n].packed = true;
|
|
}
|
|
//show();
|
|
color_changed = false;
|
|
visible_meter_type = meter_type;
|
|
}
|
|
|
|
void
|
|
LevelMeterBase::set_type(MeterType t)
|
|
{
|
|
meter_type = t;
|
|
_meter->set_type(t);
|
|
}
|
|
|
|
bool
|
|
LevelMeterBase::meter_button_press (GdkEventButton* ev)
|
|
{
|
|
return !!ButtonPress (ev); /* EMIT SIGNAL */
|
|
}
|
|
|
|
bool
|
|
LevelMeterBase::meter_button_release (GdkEventButton* ev)
|
|
{
|
|
if (ev->button == 1) {
|
|
clear_meters (false);
|
|
}
|
|
ButtonRelease(ev);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void LevelMeterBase::clear_meters (bool reset_highlight)
|
|
{
|
|
for (vector<MeterInfo>::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 LevelMeterBase::hide_meters ()
|
|
{
|
|
hide_all_meters();
|
|
}
|
|
|
|
void
|
|
LevelMeterBase::color_handler ()
|
|
{
|
|
color_changed = true;
|
|
setup_meters (meter_length, regular_meter_width, thin_meter_width);
|
|
}
|
|
|
|
LevelMeterHBox::LevelMeterHBox(Session* s)
|
|
: LevelMeterBase(s, invalidator(*this))
|
|
{
|
|
set_spacing(1);
|
|
show();
|
|
}
|
|
|
|
|
|
LevelMeterHBox::~LevelMeterHBox() {}
|
|
|
|
void
|
|
LevelMeterHBox::mtr_pack(Gtk::Widget &w) {
|
|
pack_end (w, false, false);
|
|
}
|
|
|
|
void
|
|
LevelMeterHBox::mtr_remove(Gtk::Widget &w) {
|
|
remove (w);
|
|
}
|
|
|
|
|
|
LevelMeterVBox::LevelMeterVBox(Session* s)
|
|
: LevelMeterBase(s, invalidator(*this), FastMeter::Horizontal)
|
|
{
|
|
set_spacing(1);
|
|
show();
|
|
}
|
|
LevelMeterVBox::~LevelMeterVBox() {}
|
|
|
|
void
|
|
LevelMeterVBox::mtr_pack(Gtk::Widget &w) {
|
|
pack_end (w, false, false);
|
|
}
|
|
|
|
void
|
|
LevelMeterVBox::mtr_remove(Gtk::Widget &w) {
|
|
remove (w);
|
|
}
|