Ben Loftis
3f297f7dab
Always give ArdourButton a chance to handle Press or Release events if you override them. This allows ArdourButtons to do the "Pressed" animation And it now correctly eats the event so button clicks don't select the channelstrip.
512 lines
15 KiB
C++
512 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)
|
|
{
|
|
set_session (s);
|
|
Config->ParameterChanged.connect (_parameter_connection, parent_invalidator, boost::bind (&LevelMeterBase::parameter_changed, this, _1), gui_context());
|
|
UI::instance()->theme_changed.connect (sigc::mem_fun(*this, &LevelMeterBase::on_theme_changed));
|
|
ColorsChanged.connect (sigc::mem_fun (*this, &LevelMeterBase::color_handler));
|
|
max_peak = minus_infinity();
|
|
meter_type = MeterPeak;
|
|
}
|
|
|
|
void
|
|
LevelMeterBase::on_theme_changed()
|
|
{
|
|
style_changed = true;
|
|
}
|
|
|
|
LevelMeterBase::~LevelMeterBase ()
|
|
{
|
|
for (vector<MeterInfo>::iterator i = meters.begin(); i != meters.end(); i++) {
|
|
delete (*i).meter;
|
|
}
|
|
}
|
|
|
|
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(Config->get_meter_line_up_level(), offset);
|
|
}
|
|
|
|
static float vu_standard() {
|
|
// note - default meter config is +2dB (france)
|
|
switch (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 >= 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(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(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 = Config->get_meter_style_led() ? 3 : 1;
|
|
b[0] = ARDOUR_UI::config()->get_canvasvar_MeterBackgroundBot();
|
|
b[1] = ARDOUR_UI::config()->get_canvasvar_MeterBackgroundTop();
|
|
b[2] = 0x991122ff; // red highlight gradient Bot
|
|
b[3] = 0x551111ff; // red highlight gradient Top
|
|
if (n < nmidi) {
|
|
c[0] = ARDOUR_UI::config()->get_canvasvar_MidiMeterColor0();
|
|
c[1] = ARDOUR_UI::config()->get_canvasvar_MidiMeterColor1();
|
|
c[2] = ARDOUR_UI::config()->get_canvasvar_MidiMeterColor2();
|
|
c[3] = ARDOUR_UI::config()->get_canvasvar_MidiMeterColor3();
|
|
c[4] = ARDOUR_UI::config()->get_canvasvar_MidiMeterColor4();
|
|
c[5] = ARDOUR_UI::config()->get_canvasvar_MidiMeterColor5();
|
|
c[6] = ARDOUR_UI::config()->get_canvasvar_MidiMeterColor6();
|
|
c[7] = ARDOUR_UI::config()->get_canvasvar_MidiMeterColor7();
|
|
c[8] = ARDOUR_UI::config()->get_canvasvar_MidiMeterColor8();
|
|
c[9] = ARDOUR_UI::config()->get_canvasvar_MidiMeterColor9();
|
|
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()->get_canvasvar_MeterColor0();
|
|
c[1] = ARDOUR_UI::config()->get_canvasvar_MeterColor1();
|
|
c[2] = ARDOUR_UI::config()->get_canvasvar_MeterColor2();
|
|
c[3] = ARDOUR_UI::config()->get_canvasvar_MeterColor3();
|
|
c[4] = ARDOUR_UI::config()->get_canvasvar_MeterColor4();
|
|
c[5] = ARDOUR_UI::config()->get_canvasvar_MeterColor5();
|
|
c[6] = ARDOUR_UI::config()->get_canvasvar_MeterColor6();
|
|
c[7] = ARDOUR_UI::config()->get_canvasvar_MeterColor7();
|
|
c[8] = ARDOUR_UI::config()->get_canvasvar_MeterColor8();
|
|
c[9] = ARDOUR_UI::config()->get_canvasvar_MeterColor9();
|
|
|
|
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_by_name ("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[2] = c[3] = c[1]; // dark-green
|
|
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[1] = c[2] = c[3] = 0x00aa00ff;
|
|
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[1] = c[2] = c[3] = c[4] = c[5] = 0x00aa00ff;
|
|
c[6] = c[7] = c[8] = c[9] = 0xff8800ff;
|
|
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 (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 (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);
|
|
}
|