13
0

GUI combined Latency/TailTime widget

This commit is contained in:
Robin Gareus 2024-08-31 01:12:28 +02:00
parent 6d47758671
commit aa5dbdd770
Signed by: rgareus
GPG Key ID: A090BCE02CF57F04
7 changed files with 167 additions and 60 deletions

View File

@ -51,6 +51,7 @@
#include "ardour/lv2_plugin.h"
#include "ardour/plugin.h"
#include "ardour/plugin_insert.h"
#include "ardour/region_fx_plugin.h"
#include "ardour/session.h"
#include "lv2_plugin_ui.h"
@ -85,7 +86,7 @@ extern VST3PluginUI* create_mac_vst3_gui (std::shared_ptr<ARDOUR::PlugInsertBase
#include "ardour_window.h"
#include "gui_thread.h"
#include "keyboard.h"
#include "latency_gui.h"
#include "timectl_gui.h"
#include "new_plugin_preset_dialog.h"
#include "plugin_dspload_ui.h"
#include "plugin_eq_gui.h"
@ -537,6 +538,8 @@ PlugUIBase::PlugUIBase (std::shared_ptr<PlugInsertBase> pib)
, cpuload_expander (_("CPU Profile"))
, latency_gui (0)
, latency_dialog (0)
, tailtime_gui (0)
, tailtime_dialog (0)
, eqgui (0)
, stats_gui (0)
, preset_gui (0)
@ -555,6 +558,7 @@ PlugUIBase::PlugUIBase (std::shared_ptr<PlugInsertBase> pib)
set_tooltip (_pin_management_button, _("Show Plugin Pin Management Dialog"));
set_tooltip (_bypass_button, _("Disable signal processing by the plugin"));
set_tooltip (_latency_button, _("Edit Plugin Delay/Latency Compensation"));
set_tooltip (_tailtime_button, _("Edit Plugin tail time"));
_no_load_preset = 0;
update_preset_list ();
@ -565,6 +569,11 @@ PlugUIBase::PlugUIBase (std::shared_ptr<PlugInsertBase> pib)
_latency_button.signal_clicked.connect (sigc::mem_fun (*this, &PlugUIBase::latency_button_clicked));
set_latency_label ();
_tailtime_button.set_icon (ArdourIcon::TailTimeClock);
_tailtime_button.add_elements (ArdourButton::Text);
_tailtime_button.signal_clicked.connect (sigc::mem_fun (*this, &PlugUIBase::tailtime_button_clicked));
set_tailtime_label ();
_add_button.set_name ("generic button");
_add_button.set_icon (ArdourIcon::PsetAdd);
_add_button.signal_clicked.connect (sigc::mem_fun (*this, &PlugUIBase::add_plugin_setting));
@ -636,6 +645,11 @@ PlugUIBase::PlugUIBase (std::shared_ptr<PlugInsertBase> pib)
_pi->LatencyChanged.connect (*this, invalidator (*this), boost::bind (&PlugUIBase::set_latency_label, this), gui_context ());
automation_state_changed ();
}
shared_ptr<TailTime> tt = std::dynamic_pointer_cast<ARDOUR::TailTime> (_pib);
if (tt) {
tt->TailTimeChanged.connect (*this, invalidator (*this), boost::bind (&PlugUIBase::set_tailtime_label, this), gui_context ());
}
}
PlugUIBase::~PlugUIBase ()
@ -645,6 +659,8 @@ PlugUIBase::~PlugUIBase ()
delete preset_gui;
delete latency_gui;
delete latency_dialog;
delete tailtime_gui;
delete tailtime_dialog;
delete preset_dialog;
delete _focus_out_image;
@ -696,6 +712,9 @@ PlugUIBase::add_common_widgets (Gtk::HBox* b, bool with_focus)
b->pack_end (_pin_management_button, false, false);
b->pack_start (_latency_button, false, false, 4);
}
else if (std::dynamic_pointer_cast<ARDOUR::RegionFxPlugin> (_pib)) {
b->pack_start (_tailtime_button, false, false, 4);
}
}
void
@ -709,13 +728,26 @@ PlugUIBase::set_latency_label ()
_latency_button.set_text (samples_as_time_string (l, sr, true));
}
void
PlugUIBase::set_tailtime_label ()
{
auto rfx = std::dynamic_pointer_cast<ARDOUR::RegionFxPlugin> (_pib); /* may be NULL */
if (!rfx) {
return;
}
samplecnt_t const l = rfx->effective_tailtime ();
float const sr = rfx->session ().sample_rate ();
_tailtime_button.set_text (samples_as_time_string (l, sr, true));
}
void
PlugUIBase::latency_button_clicked ()
{
assert (_pi);
if (!latency_gui) {
latency_gui = new LatencyGUI (*(_pi.get ()), _pi->session ().sample_rate (), _pi->session ().get_block_size ());
latency_gui = new TimeCtlGUI (*(_pi.get ()), _pi->session ().sample_rate (), _pi->session ().get_block_size ());
latency_dialog = new ArdourWindow (_("Edit Latency"));
/* use both keep-above and transient for to try cover as many
different WM's as possible.
@ -732,6 +764,29 @@ PlugUIBase::latency_button_clicked ()
latency_dialog->show_all ();
}
void
PlugUIBase::tailtime_button_clicked ()
{
auto rfx = std::dynamic_pointer_cast<ARDOUR::RegionFxPlugin> (_pib); /* may be NULL */
assert (rfx);
if (!tailtime_gui) {
tailtime_gui = new TimeCtlGUI (*dynamic_cast<TailTime*>(rfx.get()), rfx->session ().sample_rate (), rfx->session ().get_block_size ());
tailtime_dialog = new ArdourWindow (_("Edit Tail Time"));
/* use both keep-above and transient for to try cover as many
different WM's as possible.
*/
tailtime_dialog->set_keep_above (true);
Window* win = dynamic_cast<Window*> (_bypass_button.get_toplevel ());
if (win) {
tailtime_dialog->set_transient_for (*win);
}
tailtime_dialog->add (*tailtime_gui);
}
tailtime_gui->refresh ();
tailtime_dialog->show_all ();
}
void
PlugUIBase::processor_active_changed (std::weak_ptr<Processor> weak_p)
{

View File

@ -81,7 +81,7 @@ namespace ArdourWidgets {
class FastMeter;
}
class LatencyGUI;
class TimeCtlGUI;
class ArdourWindow;
class PluginEqGui;
class PluginLoadStatsGui;
@ -110,6 +110,7 @@ public:
void update_preset ();
void latency_button_clicked ();
void tailtime_button_clicked ();
virtual bool on_window_show(const std::string& /*title*/) { return true; }
virtual void on_window_hide() {}
@ -157,6 +158,8 @@ protected:
Gtk::Expander cpuload_expander;
/** a button which, when clicked, opens the latency GUI */
ArdourWidgets::ArdourButton _latency_button;
/** a button which, when clicked, opens the tailtime GUI */
ArdourWidgets::ArdourButton _tailtime_button;
/** a button which sets all controls' automation setting to Manual */
ArdourWidgets::ArdourButton automation_manual_all_button;
/** a button which sets all controls' automation setting to Play */
@ -169,9 +172,13 @@ protected:
ArdourWidgets::ArdourButton automation_latch_all_button;
void set_latency_label ();
LatencyGUI* latency_gui;
TimeCtlGUI* latency_gui;
ArdourWindow* latency_dialog;
void set_tailtime_label ();
TimeCtlGUI* tailtime_gui;
ArdourWindow* tailtime_dialog;
PluginEqGui* eqgui;
PluginLoadStatsGui* stats_gui;
PluginPresetsUI* preset_gui;

View File

@ -35,7 +35,7 @@
#include "context_menu_helper.h"
#include "gui_thread.h"
#include "latency_gui.h"
#include "timectl_gui.h"
#include "port_insert_ui.h"
#include "timers.h"
#include "utils.h"
@ -282,7 +282,7 @@ PortInsertUI::edit_latency_button_clicked ()
{
assert (_pi);
if (!_latency_gui) {
_latency_gui = new LatencyGUI (*(_pi.get ()), _pi->session ().sample_rate (), _pi->session ().get_block_size ());
_latency_gui = new TimeCtlGUI (*(_pi.get ()), _pi->session ().sample_rate (), _pi->session ().get_block_size ());
_latency_dialog = new ArdourWindow (_("Edit Latency"));
/* use both keep-above and transient for to try cover as many
different WM's as possible.

View File

@ -31,7 +31,7 @@ namespace ARDOUR
class PortInsert;
}
class LatencyGUI;
class TimeCtlGUI;
class MTDM;
class PortInsertUI : public Gtk::VBox
@ -78,7 +78,7 @@ private:
Gtk::HBox _latency_hbox;
Gtk::Window* _parent;
LatencyGUI* _latency_gui;
TimeCtlGUI* _latency_gui;
ArdourWindow* _latency_dialog;
sigc::connection _latency_timeout;

View File

@ -29,10 +29,12 @@
#include "pbd/unwind.h"
#include "ardour/latent.h"
#include "ardour/rc_configuration.h"
#include "ardour/tailtime.h"
#include "gtkmm2ext/utils.h"
#include "latency_gui.h"
#include "timectl_gui.h"
#include "utils.h"
#include "pbd/i18n.h"
@ -50,46 +52,66 @@ static const gchar *_unit_strings[] = {
0
};
std::vector<std::string> LatencyGUI::unit_strings;
std::vector<std::string> TimeCtlGUI::unit_strings;
std::string
LatencyBarController::get_label (double&)
TimeCtlBarController::get_label (double&)
{
return ARDOUR_UI_UTILS::samples_as_time_string (
_latency_gui->adjustment.get_value(), _latency_gui->sample_rate, true);
_timectl_gui->adjustment.get_value(), _timectl_gui->sample_rate, true);
}
void
LatencyGUIControllable::set_value (double v, PBD::Controllable::GroupControlDisposition group_override)
TimeCtlGUIControllable::set_value (double v, PBD::Controllable::GroupControlDisposition group_override)
{
_latency_gui->adjustment.set_value (v);
_timectl_gui->adjustment.set_value (v);
}
double
LatencyGUIControllable::get_value () const
TimeCtlGUIControllable::get_value () const
{
return _latency_gui->adjustment.get_value ();
return _timectl_gui->adjustment.get_value ();
}
double
LatencyGUIControllable::lower() const
TimeCtlGUIControllable::lower() const
{
return _latency_gui->adjustment.get_lower ();
return _timectl_gui->adjustment.get_lower ();
}
double
LatencyGUIControllable::upper() const
TimeCtlGUIControllable::upper() const
{
return _latency_gui->adjustment.get_upper ();
return _timectl_gui->adjustment.get_upper ();
}
LatencyGUI::LatencyGUI (Latent& l, samplepos_t sr, samplepos_t psz)
: _latent (l)
TimeCtlGUI::TimeCtlGUI (Latent& l, samplepos_t sr, samplepos_t psz)
: _latent (&l)
, _tailtime (0)
, sample_rate (sr)
, period_size (psz)
, _ignore_change (false)
, adjustment (0, 0.0, sample_rate, 1.0, sample_rate / 1000.0f) /* max 1 second, step by samples, page by msecs */
, bc (adjustment, this)
, reset_button (_("Reset"))
{
init ();
}
TimeCtlGUI::TimeCtlGUI (TailTime& t, samplepos_t sr, samplepos_t psz)
: _latent (0)
, _tailtime (&t)
, sample_rate (sr)
, period_size (psz)
, _ignore_change (false)
, adjustment (0, 0.0, 20 * sample_rate, sample_rate / 1000.f, 1.0, sample_rate / 2.0f) /* max 20 second, step by msec, page by 0.5 sec */
, bc (adjustment, this)
, reset_button (_("Reset"))
{
init ();
}
void
TimeCtlGUI::init ()
{
Widget* w;
@ -116,17 +138,21 @@ LatencyGUI::LatencyGUI (Latent& l, samplepos_t sr, samplepos_t psz)
hbox2.pack_start (plus_button);
hbox2.pack_start (units_combo, true, true);
minus_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &LatencyGUI::change_latency_from_button), -1));
plus_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &LatencyGUI::change_latency_from_button), 1));
reset_button.signal_clicked().connect (sigc::mem_fun (*this, &LatencyGUI::reset));
minus_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &TimeCtlGUI::change_from_button), -1));
plus_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &TimeCtlGUI::change_from_button), 1));
reset_button.signal_clicked().connect (sigc::mem_fun (*this, &TimeCtlGUI::reset));
/* Limit value to adjustment range (max = sample_rate).
* Otherwise if the signal_latency() is larger than the adjustment's max,
* LatencyGUI::finish() would set the adjustment's max value as custom-latency.
* TimeCtlGUI::finish() would set the adjustment's max value as custom-latency.
*/
adjustment.set_value (std::min (sample_rate, _latent.signal_latency ()));
if (_latent) {
adjustment.set_value (std::min (sample_rate, _latent->signal_latency ()));
} else if (_tailtime) {
adjustment.set_value (std::min (sample_rate, _tailtime->signal_tailtime ()));
}
adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &LatencyGUI::finish));
adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &TimeCtlGUI::finish));
bc.set_size_request (-1, 25);
bc.set_name (X_("ProcessorControlSlider"));
@ -137,32 +163,46 @@ LatencyGUI::LatencyGUI (Latent& l, samplepos_t sr, samplepos_t psz)
}
void
LatencyGUI::finish ()
TimeCtlGUI::finish ()
{
if (_ignore_change) {
return;
}
samplepos_t new_value = (samplepos_t) adjustment.get_value();
_latent.set_user_latency (new_value);
if (_latent) {
_latent->set_user_latency (new_value);
} else if (_tailtime) {
_tailtime->set_user_tailtime (new_value);
}
}
void
LatencyGUI::reset ()
TimeCtlGUI::reset ()
{
_latent.unset_user_latency ();
if (_latent) {
_latent->unset_user_latency ();
PBD::Unwinder<bool> uw (_ignore_change, true);
adjustment.set_value (std::min (sample_rate, _latent.signal_latency ()));
adjustment.set_value (std::min (sample_rate, _latent->signal_latency ()));
} else if (_tailtime) {
_tailtime->unset_user_tailtime ();
PBD::Unwinder<bool> uw (_ignore_change, true);
adjustment.set_value (std::min<samplecnt_t> (Config->get_max_tail_samples (), _tailtime->signal_tailtime ()));
}
}
void
LatencyGUI::refresh ()
TimeCtlGUI::refresh ()
{
PBD::Unwinder<bool> uw (_ignore_change, true);
adjustment.set_value (std::min (sample_rate, _latent.effective_latency ()));
if (_latent) {
adjustment.set_value (std::min (sample_rate, _latent->effective_latency ()));
} else if (_tailtime) {
adjustment.set_value (std::min<samplecnt_t> (Config->get_max_tail_samples (),_tailtime->effective_tailtime ()));
}
}
void
LatencyGUI::change_latency_from_button (int dir)
TimeCtlGUI::change_from_button (int dir)
{
std::string unitstr = units_combo.get_active_text();
double shift = 0.0;

View File

@ -2,7 +2,7 @@
* Copyright (C) 2007-2017 Paul Davis <paul@linuxaudiosystems.com>
* Copyright (C) 2009 Carl Hetherington <carl@carlh.net>
* Copyright (C) 2009 David Robillard <d@drobilla.net>
* Copyright (C) 2017-2019 Robin Gareus <robin@gareus.org>
* Copyright (C) 2017-2024 Robin Gareus <robin@gareus.org>
*
* 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
@ -19,8 +19,8 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef __gtk2_ardour_latency_gui_h__
#define __gtk2_ardour_latency_gui_h__
#ifndef __gtk2_ardour_timectl_gui_h__
#define __gtk2_ardour_timectl_gui_h__
#include <vector>
#include <string>
@ -38,16 +38,17 @@
namespace ARDOUR {
class Latent;
class TailTime;
}
class LatencyGUI;
class TimeCtlGUI;
class LatencyGUIControllable : public PBD::Controllable
class TimeCtlGUIControllable : public PBD::Controllable
{
public:
LatencyGUIControllable (LatencyGUI* g)
TimeCtlGUIControllable (TimeCtlGUI* g)
: PBD::Controllable ("ignoreMe")
, _latency_gui (g)
, _timectl_gui (g)
{}
void set_value (double v, PBD::Controllable::GroupControlDisposition group_override);
@ -62,44 +63,48 @@ public:
}
private:
LatencyGUI* _latency_gui;
TimeCtlGUI* _timectl_gui;
};
class LatencyBarController : public ArdourWidgets::BarController
class TimeCtlBarController : public ArdourWidgets::BarController
{
public:
LatencyBarController (Gtk::Adjustment& adj, LatencyGUI* g)
: BarController (adj, std::shared_ptr<PBD::Controllable> (new LatencyGUIControllable (g)))
, _latency_gui (g)
TimeCtlBarController (Gtk::Adjustment& adj, TimeCtlGUI* g)
: BarController (adj, std::shared_ptr<PBD::Controllable> (new TimeCtlGUIControllable (g)))
, _timectl_gui (g)
{
set_digits (0);
}
private:
LatencyGUI* _latency_gui;
TimeCtlGUI* _timectl_gui;
std::string get_label (double&);
};
class LatencyGUI : public Gtk::VBox
class TimeCtlGUI : public Gtk::VBox
{
public:
LatencyGUI (ARDOUR::Latent&, samplepos_t sample_rate, samplepos_t period_size);
~LatencyGUI() { }
TimeCtlGUI (ARDOUR::Latent&, samplepos_t sample_rate, samplepos_t period_size);
TimeCtlGUI (ARDOUR::TailTime&, samplepos_t sample_rate, samplepos_t period_size);
~TimeCtlGUI() { }
void refresh ();
private:
void init ();
void reset ();
void finish ();
ARDOUR::Latent& _latent;
ARDOUR::Latent* _latent;
ARDOUR::TailTime* _tailtime;
samplepos_t sample_rate;
samplepos_t period_size;
bool _ignore_change;
Gtk::Adjustment adjustment;
LatencyBarController bc;
TimeCtlBarController bc;
Gtk::HBox hbox1;
Gtk::HBox hbox2;
Gtk::HButtonBox hbbox;
@ -108,12 +113,12 @@ private:
Gtk::Button reset_button;
Gtk::ComboBoxText units_combo;
void change_latency_from_button (int dir);
void change_from_button (int dir);
friend class LatencyBarController;
friend class LatencyGUIControllable;
friend class TimeCtlBarController;
friend class TimeCtlGUIControllable;
static std::vector<std::string> unit_strings;
};
#endif /* __gtk2_ardour_latency_gui_h__ */
#endif /* __gtk2_ardour_timectl_gui_h__ */

View File

@ -139,7 +139,6 @@ gtk2_ardour_sources = [
'hit.cc',
'keyboard.cc',
'keyeditor.cc',
'latency_gui.cc',
'led.cc',
'level_meter.cc',
'library_download_dialog.cc',
@ -301,6 +300,7 @@ gtk2_ardour_sources = [
'time_fx_dialog.cc',
'time_info_box.cc',
'time_selection.cc',
'timectl_gui.cc',
'timers.cc',
'track_record_axis.cc',
'track_selection.cc',