2 * Copyright (C) 2008-2011 Carl Hetherington <carl@carlh.net>
3 * Copyright (C) 2008-2014 David Robillard <d@drobilla.net>
4 * Copyright (C) 2008-2016 Paul Davis <paul@linuxaudiosystems.com>
5 * Copyright (C) 2013-2019 Robin Gareus <robin@gareus.org>
6 * Copyright (C) 2014 Ben Loftis <ben@harrisonconsoles.com>
7 * Copyright (C) 2015 Tim Mayberry <mojofunk@gmail.com>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 #include "ardour/meter.h"
27 #include "ardour/logmeter.h"
29 #include <gtkmm2ext/utils.h>
30 #include "pbd/fastlog.h"
32 #include "level_meter.h"
34 #include "gui_thread.h"
36 #include "public_editor.h"
37 #include "ui_config.h"
41 using namespace ARDOUR;
42 using namespace ARDOUR_UI_UTILS;
44 using namespace ArdourWidgets;
48 LevelMeterBase::LevelMeterBase (Session* s, PBD::EventLoop::InvalidationRecord* ir, FastMeter::Orientation o)
49 : parent_invalidator(ir)
51 , _meter_orientation(o)
52 , regular_meter_width (6)
55 , max_peak (minus_infinity())
56 , visible_meter_type (MeterType(0))
59 , max_visible_meters (0)
60 , color_changed (false)
64 Config->ParameterChanged.connect (_parameter_connection, parent_invalidator, boost::bind (&LevelMeterBase::parameter_changed, this, _1), gui_context());
65 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun(*this, &LevelMeterBase::parameter_changed));
66 UIConfiguration::instance().ColorsChanged.connect (sigc::mem_fun (*this, &LevelMeterBase::color_handler));
69 LevelMeterBase::~LevelMeterBase ()
71 _configuration_connection.disconnect();
72 _meter_type_connection.disconnect();
73 _parameter_connection.disconnect();
74 for (vector<MeterInfo>::iterator i = meters.begin(); i != meters.end(); i++) {
81 LevelMeterBase::set_meter (PeakMeter* meter)
83 _configuration_connection.disconnect();
84 _meter_type_connection.disconnect();
87 color_changed = true; // force update
90 _meter->ConfigurationChanged.connect (_configuration_connection, parent_invalidator, boost::bind (&LevelMeterBase::configuration_changed, this, _1, _2), gui_context());
91 _meter->MeterTypeChanged.connect (_meter_type_connection, parent_invalidator, boost::bind (&LevelMeterBase::meter_type_changed, this, _1), gui_context());
95 static float meter_lineup_cfg(MeterLineUp lul, float offset) {
97 case MeteringLineUp24:
99 case MeteringLineUp20:
101 case MeteringLineUp18:
103 case MeteringLineUp15:
111 static float meter_lineup(float offset) {
112 return meter_lineup_cfg (UIConfiguration::instance().get_meter_line_up_level(), offset);
115 static float vu_standard() {
116 // note - default meter config is +2dB (france)
117 switch (UIConfiguration::instance().get_meter_vu_standard()) {
119 case MeteringVUfrench: // 0VU = -2dBu
121 case MeteringVUamerican: // 0VU = 0dBu
123 case MeteringVUstandard: // 0VU = +4dBu
125 case MeteringVUeight: // 0VU = +8dBu
131 LevelMeterBase::update_meters ()
133 vector<MeterInfo>::iterator i;
140 uint32_t nmidi = _meter->input_streams().n_midi();
142 for (n = 0, i = meters.begin(); i != meters.end(); ++i, ++n) {
144 const float mpeak = _meter->meter_level(n, MeterMaxPeak);
145 if (mpeak > (*i).max_peak) {
146 (*i).max_peak = mpeak;
147 (*i).meter->set_highlight(mpeak >= UIConfiguration::instance().get_meter_peak());
149 if (mpeak > max_peak) {
154 (*i).meter->set (_meter->meter_level (n, MeterPeak));
156 MeterType meter_type = _meter->meter_type ();
157 const float peak = _meter->meter_level (n, meter_type);
158 if (meter_type == MeterPeak) {
159 (*i).meter->set (log_meter (peak));
160 } else if (meter_type == MeterPeak0dB) {
161 (*i).meter->set (log_meter0dB (peak));
162 } else if (meter_type == MeterIEC1NOR) {
163 (*i).meter->set (meter_deflect_nordic (peak + meter_lineup(0)));
164 } else if (meter_type == MeterIEC1DIN) {
165 (*i).meter->set (meter_deflect_din (peak + meter_lineup_cfg(UIConfiguration::instance().get_meter_line_up_din(), 3.0)));
166 } else if (meter_type == MeterIEC2BBC || meter_type == MeterIEC2EBU) {
167 (*i).meter->set (meter_deflect_ppm (peak + meter_lineup(0)));
168 } else if (meter_type == MeterVU) {
169 (*i).meter->set (meter_deflect_vu (peak + vu_standard() + meter_lineup(0)));
170 } else if (meter_type == MeterK12) {
171 (*i).meter->set (meter_deflect_k (peak, 12), meter_deflect_k(_meter->meter_level(n, MeterPeak), 12));
172 } else if (meter_type == MeterK14) {
173 (*i).meter->set (meter_deflect_k (peak, 14), meter_deflect_k(_meter->meter_level(n, MeterPeak), 14));
174 } else if (meter_type == MeterK20) {
175 (*i).meter->set (meter_deflect_k (peak, 20), meter_deflect_k(_meter->meter_level(n, MeterPeak), 20));
177 (*i).meter->set (log_meter (peak), log_meter(_meter->meter_level(n, MeterPeak)));
186 LevelMeterBase::parameter_changed (string p)
188 ENSURE_GUI_THREAD (*this, &LevelMeterBase::parameter_changed, p)
190 if (p == "meter-hold") {
191 vector<MeterInfo>::iterator i;
194 for (n = 0, i = meters.begin(); i != meters.end(); ++i, ++n) {
195 (*i).meter->set_hold_count ((uint32_t) floor(UIConfiguration::instance().get_meter_hold()));
198 else if (p == "meter-line-up-level") {
199 color_changed = true;
200 setup_meters (meter_length, regular_meter_width, thin_meter_width);
202 else if (p == "meter-style-led") {
203 color_changed = true;
204 setup_meters (meter_length, regular_meter_width, thin_meter_width);
206 else if (p == "meter-peak") {
207 vector<MeterInfo>::iterator i;
210 for (n = 0, i = meters.begin(); i != meters.end(); ++i, ++n) {
211 (*i).max_peak = minus_infinity();
217 LevelMeterBase::configuration_changed (ChanCount /*in*/, ChanCount /*out*/)
219 setup_meters (meter_length, regular_meter_width, thin_meter_width);
223 LevelMeterBase::meter_type_changed (MeterType t)
225 setup_meters (meter_length, regular_meter_width, thin_meter_width);
229 LevelMeterBase::hide_all_meters ()
231 for (vector<MeterInfo>::iterator i = meters.begin(); i != meters.end(); ++i) {
233 mtr_remove (*((*i).meter));
241 LevelMeterBase::set_max_audio_meter_count (uint32_t cnt)
243 if (cnt == max_visible_meters) {
246 color_changed = true; // force re-setup
247 max_visible_meters = cnt;
248 setup_meters (meter_length, regular_meter_width, thin_meter_width);
252 LevelMeterBase::setup_meters (int len, int initial_width, int thin_width)
257 return; /* do it later or never */
260 MeterType meter_type = _meter->meter_type ();
261 uint32_t nmidi = _meter->input_streams().n_midi();
262 uint32_t nmeters = _meter->input_streams().n_total();
263 regular_meter_width = initial_width;
264 thin_meter_width = thin_width;
275 width = regular_meter_width;
277 width = thin_meter_width;
280 width = rint (width * UIConfiguration::instance().get_ui_scale());
282 if ( meters.size() > 0
283 && nmidi == midi_count
284 && nmeters == meter_count
285 && meters[0].width == width
286 && meters[0].length == len
288 && meter_type == visible_meter_type) {
293 printf("Meter redraw: %s %s %s %s %s %s\n",
294 (meters.size() > 0) ? "yes" : "no",
295 (meters.size() > 0 && meters[0].width == width) ? "yes" : "no",
296 (meters.size() > 0 && meters[0].length == len) ? "yes" : "no",
297 (nmeters == meter_count) ? "yes" : "no",
298 (meter_type == visible_meter_type) ? "yes" : "no",
299 !color_changed ? "yes" : "no"
304 while (meters.size() < nmeters) {
305 meters.push_back (MeterInfo());
308 //cerr << "LevelMeterBase::setup_meters() called color_changed = " << color_changed << " colors: " << endl;//DEBUG
310 for (int32_t n = nmeters-1; nmeters && n >= 0 ; --n) {
314 int styleflags = UIConfiguration::instance().get_meter_style_led() ? 3 : 1;
315 b[0] = UIConfiguration::instance().color ("meter background bottom");
316 b[1] = UIConfiguration::instance().color ("meter background top");
317 b[2] = 0x991122ff; // red highlight gradient Bot
318 b[3] = 0x551111ff; // red highlight gradient Top
319 if ((uint32_t) n < nmidi) {
320 c[0] = UIConfiguration::instance().color ("midi meter color0");
321 c[1] = UIConfiguration::instance().color ("midi meter color1");
322 c[2] = UIConfiguration::instance().color ("midi meter color2");
323 c[3] = UIConfiguration::instance().color ("midi meter color3");
324 c[4] = UIConfiguration::instance().color ("midi meter color4");
325 c[5] = UIConfiguration::instance().color ("midi meter color5");
326 c[6] = UIConfiguration::instance().color ("midi meter color6");
327 c[7] = UIConfiguration::instance().color ("midi meter color7");
328 c[8] = UIConfiguration::instance().color ("midi meter color8");
329 c[9] = UIConfiguration::instance().color ("midi meter color9");
330 stp[0] = 115.0 * 32.0 / 128.0;
331 stp[1] = 115.0 * 64.0 / 128.0;
332 stp[2] = 115.0 * 100.0 / 128.0;
333 stp[3] = 115.0 * 112.0 / 128.0;
335 c[0] = UIConfiguration::instance().color ("meter color0");
336 c[1] = UIConfiguration::instance().color ("meter color1");
337 c[2] = UIConfiguration::instance().color ("meter color2");
338 c[3] = UIConfiguration::instance().color ("meter color3");
339 c[4] = UIConfiguration::instance().color ("meter color4");
340 c[5] = UIConfiguration::instance().color ("meter color5");
341 c[6] = UIConfiguration::instance().color ("meter color6");
342 c[7] = UIConfiguration::instance().color ("meter color7");
343 c[8] = UIConfiguration::instance().color ("meter color8");
344 c[9] = UIConfiguration::instance().color ("meter color9");
346 switch (meter_type) {
348 stp[0] = 115.0 * meter_deflect_k(-40, 20); //-20
349 stp[1] = 115.0 * meter_deflect_k(-20, 20); // 0
350 stp[2] = 115.0 * meter_deflect_k(-18, 20); // +2
351 stp[3] = 115.0 * meter_deflect_k(-16, 20); // +4
352 c[0] = c[1] = 0x008800ff;
353 c[2] = c[3] = 0x00ff00ff;
354 c[4] = c[5] = 0xffff00ff;
355 c[6] = c[7] = 0xffff00ff;
356 c[8] = c[9] = 0xff0000ff;
359 stp[0] = 115.0 * meter_deflect_k(-34, 14); //-20
360 stp[1] = 115.0 * meter_deflect_k(-14, 14); // 0
361 stp[2] = 115.0 * meter_deflect_k(-12, 14); // +2
362 stp[3] = 115.0 * meter_deflect_k(-10, 14); // +4
363 c[0] = c[1] = 0x008800ff;
364 c[2] = c[3] = 0x00ff00ff;
365 c[4] = c[5] = 0xffff00ff;
366 c[6] = c[7] = 0xffff00ff;
367 c[8] = c[9] = 0xff0000ff;
370 stp[0] = 115.0 * meter_deflect_k(-32, 12); //-20
371 stp[1] = 115.0 * meter_deflect_k(-12, 12); // 0
372 stp[2] = 115.0 * meter_deflect_k(-10, 12); // +2
373 stp[3] = 115.0 * meter_deflect_k( -8, 12); // +4
374 c[0] = c[1] = 0x008800ff;
375 c[2] = c[3] = 0x00ff00ff;
376 c[4] = c[5] = 0xffff00ff;
377 c[6] = c[7] = 0xffff00ff;
378 c[8] = c[9] = 0xff0000ff;
381 c[0] = c[1] = c[2] = c[3] = c[4] = c[5] = c[6] = c[7] = c[8] = c[9] =
382 UIConfiguration::instance().color ("meter color BBC");
383 stp[0] = stp[1] = stp[2] = stp[3] = 115.0;
386 stp[0] = 115.0 * meter_deflect_ppm(-24); // ignored
387 stp[1] = 115.0 * meter_deflect_ppm(-18);
388 stp[2] = 115.0 * meter_deflect_ppm( -9);
389 stp[3] = 115.0 * meter_deflect_ppm( 0); // ignored
391 c[6] = c[7] = c[8] = c[9];
394 stp[0] = 115.0 * meter_deflect_nordic(-30); // ignored
395 stp[1] = 115.0 * meter_deflect_nordic(-18);
396 stp[2] = 115.0 * meter_deflect_nordic(-12);
397 stp[3] = 115.0 * meter_deflect_nordic( -9); // ignored
398 c[0] = c[1] = c[2]; // bright-green
399 c[6] = c[7] = c[8] = c[9];
402 stp[0] = 115.0 * meter_deflect_din(-29); // ignored
403 stp[1] = 115.0 * meter_deflect_din(-18);
404 stp[2] = 115.0 * meter_deflect_din(-15); // ignored
405 stp[3] = 115.0 * meter_deflect_din( -9);
406 c[0] = c[2] = c[3] = c[1];
411 stp[0] = 115.0 * meter_deflect_vu(-26); // -6
412 stp[1] = 115.0 * meter_deflect_vu(-23); // -3
413 stp[2] = 115.0 * meter_deflect_vu(-20); // 0
414 stp[3] = 115.0 * meter_deflect_vu(-18); // +2
415 c[0] = c[2] = c[3] = c[4] = c[5] = c[1];
416 c[7] = c[8] = c[9] = c[6];
419 stp[1] = 89.125; // 115.0 * log_meter0dB(-9);
420 stp[2] = 106.375; // 115.0 * log_meter0dB(-3);
421 stp[3] = 115.0; // 115.0 * log_meter0dB(0);
422 switch (UIConfiguration::instance().get_meter_line_up_level()) {
423 case MeteringLineUp24:
424 stp[0] = 115.0 * log_meter0dB(-24);
426 case MeteringLineUp20:
427 stp[0] = 115.0 * log_meter0dB(-20);
430 case MeteringLineUp18:
431 stp[0] = 115.0 * log_meter0dB(-18);
433 case MeteringLineUp15:
434 stp[0] = 115.0 * log_meter0dB(-15);
437 default: // PEAK, RMS
438 stp[1] = 77.5; // 115 * log_meter(-9)
439 stp[2] = 92.5; // 115 * log_meter(-3)
440 stp[3] = 100.0; // 115 * log_meter(0)
441 switch (UIConfiguration::instance().get_meter_line_up_level()) {
442 case MeteringLineUp24:
445 case MeteringLineUp20:
449 case MeteringLineUp18:
452 case MeteringLineUp15:
458 if (meters[n].width != width || meters[n].length != len || color_changed || meter_type != visible_meter_type || nmidi != midi_count) {
459 bool hl = meters[n].meter ? meters[n].meter->get_highlight() : false;
460 meters[n].packed = false;
461 delete meters[n].meter;
462 meters[n].meter = new FastMeter ((uint32_t) floor (UIConfiguration::instance().get_meter_hold()), width, _meter_orientation, len,
463 c[0], c[1], c[2], c[3], c[4],
464 c[5], c[6], c[7], c[8], c[9],
465 b[0], b[1], b[2], b[3],
466 stp[0], stp[1], stp[2], stp[3],
469 meters[n].meter->set_highlight(hl);
470 meters[n].width = width;
471 meters[n].length = len;
472 meters[n].meter->add_events (Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK);
473 meters[n].meter->signal_button_press_event().connect (sigc::mem_fun (*this, &LevelMeterBase::meter_button_press), false);
474 meters[n].meter->signal_button_release_event().connect (sigc::mem_fun (*this, &LevelMeterBase::meter_button_release), false);
477 //pack_end (*meters[n].meter, false, false);
478 mtr_pack (*meters[n].meter);
479 meters[n].packed = true;
480 if (max_visible_meters == 0 || (uint32_t) n < max_visible_meters + nmidi) {
481 meters[n].meter->show_all ();
483 meters[n].meter->hide ();
487 color_changed = false;
488 visible_meter_type = meter_type;
490 meter_count = nmeters;
494 LevelMeterBase::meter_button_press (GdkEventButton* ev)
496 return static_cast<bool>(ButtonPress (ev)); /* EMIT SIGNAL */
500 LevelMeterBase::meter_button_release (GdkEventButton* ev)
502 if (ev->button == 1) {
503 clear_meters (false);
511 void LevelMeterBase::clear_meters (bool reset_highlight)
513 for (vector<MeterInfo>::iterator i = meters.begin(); i < meters.end(); i++) {
515 (*i).max_peak = minus_infinity();
517 (*i).meter->set_highlight(false);
519 max_peak = minus_infinity();
522 void LevelMeterBase::hide_meters ()
528 LevelMeterBase::color_handler ()
530 color_changed = true;
531 setup_meters (meter_length, regular_meter_width, thin_meter_width);
534 LevelMeterHBox::LevelMeterHBox(Session* s)
535 : LevelMeterBase(s, invalidator(*this))
542 LevelMeterHBox::~LevelMeterHBox() {}
545 LevelMeterHBox::mtr_pack(Gtk::Widget &w) {
546 pack_end (w, false, false);
550 LevelMeterHBox::mtr_remove(Gtk::Widget &w) {
555 LevelMeterVBox::LevelMeterVBox(Session* s)
556 : LevelMeterBase(s, invalidator(*this), FastMeter::Horizontal)
561 LevelMeterVBox::~LevelMeterVBox() {}
564 LevelMeterVBox::mtr_pack(Gtk::Widget &w) {
565 pack_end (w, false, false);
569 LevelMeterVBox::mtr_remove(Gtk::Widget &w) {