summaryrefslogtreecommitdiff
path: root/gtk2_ardour
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2007-06-27 22:06:35 +0000
committerPaul Davis <paul@linuxaudiosystems.com>2007-06-27 22:06:35 +0000
commitb5af3bb8e313e13166cc54c60a14e5492e674065 (patch)
treed27e045a17bae47e63cde89173a53fb30ffa298b /gtk2_ardour
parent34be8c21198441a4f8ceac35da12250cafa2d1c2 (diff)
allow user tweaking of everything that might have inherent latency; add GUI for track level adjustment and widget that can be (but is not yet) embedded in a plugin GUI
git-svn-id: svn://localhost/ardour2/trunk@2075 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'gtk2_ardour')
-rw-r--r--gtk2_ardour/SConscript1
-rw-r--r--gtk2_ardour/latency_gui.cc167
-rw-r--r--gtk2_ardour/latency_gui.h61
-rw-r--r--gtk2_ardour/mixer_strip.cc5
-rw-r--r--gtk2_ardour/route_params_ui.cc113
-rw-r--r--gtk2_ardour/route_params_ui.h18
-rw-r--r--gtk2_ardour/route_ui.cc11
-rw-r--r--gtk2_ardour/route_ui.h2
8 files changed, 332 insertions, 46 deletions
diff --git a/gtk2_ardour/SConscript b/gtk2_ardour/SConscript
index 3643d3ad32..384e312e62 100644
--- a/gtk2_ardour/SConscript
+++ b/gtk2_ardour/SConscript
@@ -152,6 +152,7 @@ gtk-custom-ruler.c
io_selector.cc
keyboard.cc
ladspa_pluginui.cc
+latency_gui.cc
location_ui.cc
main.cc
marker.cc
diff --git a/gtk2_ardour/latency_gui.cc b/gtk2_ardour/latency_gui.cc
new file mode 100644
index 0000000000..0146bfdaa8
--- /dev/null
+++ b/gtk2_ardour/latency_gui.cc
@@ -0,0 +1,167 @@
+#define __STDC_FORMAT_MACROS 1
+#include <inttypes.h>
+
+#include <ardour/latent.h>
+#include <gtkmm2ext/utils.h>
+
+#include "latency_gui.h"
+
+#include "i18n.h"
+
+using namespace PBD;
+using namespace Gtk;
+using namespace Gtkmm2ext;
+using namespace sigc;
+using namespace ARDOUR;
+
+
+static const gchar *_unit_strings[] = {
+ N_("sample"),
+ N_("msec"),
+ N_("period"),
+ 0
+};
+
+std::vector<std::string> LatencyGUI::unit_strings;
+
+void
+LatencyGUI::latency_printer (char *buf, unsigned int bufsize)
+{
+ double nframes = adjustment.get_value();
+
+ if (nframes < (sample_rate / 1000.0)) {
+ snprintf (buf, bufsize, "%" PRId64 " samples", (nframes64_t) rint (nframes));
+ } else {
+ snprintf (buf, bufsize, "%.2g msecs" , nframes / (sample_rate / 1000.0));
+ }
+}
+
+LatencyGUI::LatencyGUI (Latent& l, nframes64_t sr, nframes64_t psz)
+ : _latent (l),
+ initial_value (_latent.signal_latency()),
+ sample_rate (sr),
+ period_size (psz),
+ /* max 1 second, step by frames, page by msecs */
+ adjustment (initial_value, 0.0, sample_rate, 1.0, sample_rate / 1000.0f),
+ bc (adjustment, ignored, sigc::mem_fun (*this, &LatencyGUI::latency_printer)),
+ reset_button (_("Automatic"))
+{
+ Widget* w;
+
+ if (unit_strings.empty()) {
+ unit_strings = I18N (_unit_strings);
+ }
+
+ set_popdown_strings (units_combo, unit_strings);
+ units_combo.set_active_text (unit_strings.front());
+
+ w = manage (new Image (Stock::ADD, ICON_SIZE_BUTTON));
+ w->show ();
+ plus_button.add (*w);
+ w = manage (new Image (Stock::REMOVE, ICON_SIZE_BUTTON));
+ w->show ();
+ minus_button.add (*w);
+
+ hbox1.pack_start (bc, true, true);
+
+ hbox2.set_homogeneous (false);
+ hbox2.set_spacing (12);
+ hbox2.pack_start (reset_button);
+ hbox2.pack_start (minus_button);
+ hbox2.pack_start (plus_button);
+ hbox2.pack_start (units_combo, true, true);
+
+ minus_button.signal_clicked().connect (bind (mem_fun (*this, &LatencyGUI::change_latency_from_button), -1));
+ plus_button.signal_clicked().connect (bind (mem_fun (*this, &LatencyGUI::change_latency_from_button), 1));
+ reset_button.signal_clicked().connect (mem_fun (*this, &LatencyGUI::reset));
+
+ adjustment.signal_value_changed().connect (mem_fun (*this, &LatencyGUI::finish));
+
+ bc.set_size_request (-1, 25);
+ bc.set_style (BarController::LeftToRight);
+ bc.set_use_parent (true);
+ bc.set_name (X_("PluginSlider"));
+
+ set_spacing (12);
+ pack_start (hbox1, true, true);
+ pack_start (hbox2, true, true);
+}
+
+void
+LatencyGUI::finish ()
+{
+ nframes64_t new_value = (nframes64_t) adjustment.get_value();
+ if (new_value != initial_value) {
+ _latent.set_user_latency (new_value);
+ }
+}
+
+void
+LatencyGUI::reset ()
+{
+ _latent.set_user_latency (0);
+ adjustment.set_value (initial_value);
+}
+
+void
+LatencyGUI::refresh ()
+{
+ initial_value = _latent.signal_latency();
+ adjustment.set_value (initial_value);
+}
+
+void
+LatencyGUI::change_latency_from_button (int dir)
+{
+ Glib::ustring unitstr = units_combo.get_active_text();
+ double shift;
+
+ if (unitstr == unit_strings[0]) {
+ shift = 1;
+ } else if (unitstr == unit_strings[1]) {
+ shift = (sample_rate / 1000.0);
+ } else if (unitstr == unit_strings[2]) {
+ shift = period_size;
+ } else {
+ fatal << string_compose (_("programming error: %1 (%2)"), X_("illegal string in latency GUI units combo"), unitstr)
+ << endmsg;
+ /*NOTREACHED*/
+ }
+
+ if (dir > 0) {
+ adjustment.set_value (adjustment.get_value() + shift);
+ } else {
+ adjustment.set_value (adjustment.get_value() - shift);
+ }
+}
+
+LatencyDialog::LatencyDialog (const Glib::ustring& title, Latent& l, nframes64_t sr, nframes64_t psz)
+ : ArdourDialog (title, false, true),
+ lwidget (l, sr, psz)
+{
+
+ get_vbox()->pack_start (lwidget);
+ add_button (Stock::CANCEL, RESPONSE_CANCEL);
+ add_button (Stock::APPLY, RESPONSE_REJECT);
+ add_button (Stock::OK, RESPONSE_ACCEPT);
+
+ show_all ();
+
+ while (true) {
+ int ret = run ();
+
+ switch (ret) {
+ case RESPONSE_ACCEPT:
+ return;
+ break;
+
+ case RESPONSE_REJECT:
+ lwidget.finish ();
+ break;
+ default:
+ return;
+ }
+ }
+}
+
+
diff --git a/gtk2_ardour/latency_gui.h b/gtk2_ardour/latency_gui.h
new file mode 100644
index 0000000000..49f22fa266
--- /dev/null
+++ b/gtk2_ardour/latency_gui.h
@@ -0,0 +1,61 @@
+#include <vector>
+#include <string>
+
+#include <gtkmm/dialog.h>
+#include <gtkmm/box.h>
+#include <gtkmm/button.h>
+#include <gtkmm/adjustment.h>
+
+#include <gtkmm2ext/barcontroller.h>
+#include <pbd/controllable.h>
+
+#include <ardour/types.h>
+
+#include "ardour_dialog.h"
+
+namespace ARDOUR {
+ class Latent;
+}
+
+class LatencyGUI : public Gtk::VBox
+{
+ public:
+ LatencyGUI (ARDOUR::Latent&, nframes64_t sample_rate, nframes64_t period_size);
+ ~LatencyGUI() { }
+
+ void finish ();
+ void reset ();
+ void refresh ();
+
+ private:
+ ARDOUR::Latent& _latent;
+ nframes64_t initial_value;
+ nframes64_t sample_rate;
+ nframes64_t period_size;
+ PBD::IgnorableControllable ignored;
+
+ Gtk::Adjustment adjustment;
+ Gtkmm2ext::BarController bc;
+ Gtk::HBox hbox1;
+ Gtk::HBox hbox2;
+ Gtk::HButtonBox hbbox;
+ Gtk::Button minus_button;
+ Gtk::Button plus_button;
+ Gtk::Button reset_button;
+ Gtk::ComboBoxText units_combo;
+
+ void change_latency_from_button (int dir);
+ void latency_printer (char* buf, unsigned int bufsize);
+
+ static std::vector<std::string> unit_strings;
+};
+
+class LatencyDialog : public ArdourDialog
+{
+ public:
+ LatencyDialog (const Glib::ustring& title, ARDOUR::Latent&, nframes64_t sample_rate, nframes64_t period_size);
+ ~LatencyDialog() {}
+
+ private:
+ LatencyGUI lwidget;
+};
diff --git a/gtk2_ardour/mixer_strip.cc b/gtk2_ardour/mixer_strip.cc
index cb57f9809c..40571d3e91 100644
--- a/gtk2_ardour/mixer_strip.cc
+++ b/gtk2_ardour/mixer_strip.cc
@@ -984,6 +984,11 @@ MixerStrip::build_route_ops_menu ()
items.push_back (CheckMenuElem (_("Active"), mem_fun (*this, &RouteUI::toggle_route_active)));
route_active_menu_item = dynamic_cast<CheckMenuItem *> (&items.back());
route_active_menu_item->set_active (_route->active());
+
+ items.push_back (SeparatorElem());
+
+ items.push_back (MenuElem (_("Adjust latency"), mem_fun (*this, &RouteUI::adjust_latency)));
+
items.push_back (SeparatorElem());
items.push_back (CheckMenuElem (_("Invert Polarity"), mem_fun (*this, &RouteUI::toggle_polarity)));
polarity_menu_item = dynamic_cast<CheckMenuItem *> (&items.back());
diff --git a/gtk2_ardour/route_params_ui.cc b/gtk2_ardour/route_params_ui.cc
index 51b1c9e26b..7807cd4a84 100644
--- a/gtk2_ardour/route_params_ui.cc
+++ b/gtk2_ardour/route_params_ui.cc
@@ -18,6 +18,8 @@
*/
#include <algorithm>
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
#include <glibmm/thread.h>
#include <gtkmm2ext/utils.h>
@@ -58,7 +60,9 @@ using namespace sigc;
RouteParams_UI::RouteParams_UI ()
: ArdourDialog ("track/bus inspector"),
+ latency_apply_button (Stock::APPLY),
track_menu(0)
+
{
pre_insert_box = 0;
post_insert_box = 0;
@@ -66,12 +70,14 @@ RouteParams_UI::RouteParams_UI ()
_output_iosel = 0;
_active_pre_view = 0;
_active_post_view = 0;
-
+ latency_widget = 0;
+
using namespace Notebook_Helpers;
input_frame.set_shadow_type(Gtk::SHADOW_NONE);
output_frame.set_shadow_type(Gtk::SHADOW_NONE);
-
+ latency_frame.set_shadow_type (Gtk::SHADOW_NONE);
+
notebook.set_show_tabs (true);
notebook.set_show_border (true);
notebook.set_name ("RouteParamNotebook");
@@ -92,7 +98,6 @@ RouteParams_UI::RouteParams_UI ()
route_select_scroller.add(route_display);
route_select_scroller.set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
-
route_select_frame.set_name("RouteSelectBaseFrame");
route_select_frame.set_shadow_type (Gtk::SHADOW_IN);
route_select_frame.add(route_select_scroller);
@@ -103,12 +108,17 @@ RouteParams_UI::RouteParams_UI ()
notebook.pages().push_back (TabElem (output_frame, _("Outputs")));
notebook.pages().push_back (TabElem (pre_redir_hpane, _("Pre-fader Redirects")));
notebook.pages().push_back (TabElem (post_redir_hpane, _("Post-fader Redirects")));
+ notebook.pages().push_back (TabElem (latency_frame, _("Latency")));
notebook.set_name ("InspectorNotebook");
title_label.set_name ("RouteParamsTitleLabel");
update_title();
+ latency_packer.set_spacing (18);
+ latency_button_box.pack_start (latency_apply_button);
+ delay_label.set_alignment (0, 0.5);
+
// changeable area
route_param_frame.set_name("RouteParamsBaseFrame");
route_param_frame.set_shadow_type (Gtk::SHADOW_IN);
@@ -116,7 +126,6 @@ RouteParams_UI::RouteParams_UI ()
route_hpacker.pack_start (notebook, true, true);
-
route_vpacker.pack_start (title_label, false, false);
route_vpacker.pack_start (route_hpacker, true, true);
@@ -142,6 +151,7 @@ RouteParams_UI::RouteParams_UI ()
title += _("Track/Bus Inspector");
set_title (title.get_string());
+
// events
route_display.get_selection()->signal_changed().connect(mem_fun(*this, &RouteParams_UI::route_selected));
route_display.get_column(0)->signal_clicked().connect(mem_fun(*this, &RouteParams_UI::show_track_menu));
@@ -253,6 +263,55 @@ RouteParams_UI::cleanup_processor_boxes()
}
void
+RouteParams_UI::refresh_latency ()
+{
+ if (latency_widget) {
+ latency_widget->refresh();
+
+ char buf[128];
+ snprintf (buf, sizeof (buf), _("Playback delay: %u samples"), _route->initial_delay());
+ delay_label.set_text (buf);
+ }
+}
+
+void
+RouteParams_UI::cleanup_latency_frame ()
+{
+ if (latency_widget) {
+ latency_frame.remove ();
+ latency_packer.remove (*latency_widget);
+ latency_packer.remove (latency_button_box);
+ latency_packer.remove (delay_label);
+ delete latency_widget;
+ latency_widget = 0;
+ latency_conn.disconnect ();
+ delay_conn.disconnect ();
+ latency_apply_conn.disconnect ();
+ }
+}
+
+void
+RouteParams_UI::setup_latency_frame ()
+{
+ latency_widget = new LatencyGUI (*(_route.get()), session->frame_rate(), session->engine().frames_per_cycle());
+
+ char buf[128];
+ snprintf (buf, sizeof (buf), _("Playback delay: %u samples"), _route->initial_delay());
+ delay_label.set_text (buf);
+
+ latency_packer.pack_start (*latency_widget, false, false);
+ latency_packer.pack_start (latency_button_box, false, false);
+ latency_packer.pack_start (delay_label);
+
+ latency_apply_conn = latency_apply_button.signal_clicked().connect (mem_fun (*latency_widget, &LatencyGUI::finish));
+ latency_conn = _route->signal_latency_changed.connect (mem_fun (*this, &RouteParams_UI::refresh_latency));
+ delay_conn = _route->initial_delay_changed.connect (mem_fun (*this, &RouteParams_UI::refresh_latency));
+
+ latency_frame.add (latency_packer);
+ latency_frame.show_all ();
+}
+
+void
RouteParams_UI::setup_io_frames()
{
cleanup_io_frames();
@@ -387,6 +446,7 @@ RouteParams_UI::session_gone ()
cleanup_pre_view();
cleanup_post_view();
cleanup_processor_boxes();
+ cleanup_latency_frame ();
_route.reset ((Route*) 0);
_pre_processor.reset ((Processor*) 0);
@@ -402,6 +462,7 @@ RouteParams_UI::route_selected()
{
Glib::RefPtr<TreeSelection> selection = route_display.get_selection();
TreeModel::iterator iter = selection->get_selected(); // only used with Gtk::SELECTION_SINGLE
+
if(iter) {
//If anything is selected
boost::shared_ptr<Route> route = (*iter)[route_display_columns.route] ;
@@ -419,6 +480,7 @@ RouteParams_UI::route_selected()
cleanup_pre_view();
cleanup_post_view();
cleanup_io_frames();
+ cleanup_latency_frame ();
}
// update the other panes with the correct info
@@ -427,6 +489,7 @@ RouteParams_UI::route_selected()
setup_io_frames();
setup_processor_boxes();
+ setup_latency_frame ();
// bind to redirects changed event for this route
_route_conn = route->processors_changed.connect (mem_fun(*this, &RouteParams_UI::processors_changed));
@@ -434,6 +497,7 @@ RouteParams_UI::route_selected()
track_input_label.set_text (_route->name());
update_title();
+
} else {
// no selection
if (_route) {
@@ -444,6 +508,7 @@ RouteParams_UI::route_selected()
cleanup_pre_view();
cleanup_post_view();
cleanup_processor_boxes();
+ cleanup_latency_frame ();
_route.reset ((Route*) 0);
_pre_processor.reset ((Processor*) 0);
@@ -454,52 +519,19 @@ RouteParams_UI::route_selected()
}
}
-//void
-//RouteParams_UI::route_unselected (gint row, gint col, GdkEvent *ev)
-//{
-// if (_route) {
-// _route_conn.disconnect();
-
- // remove from view
-// cleanup_io_frames();
-// cleanup_pre_view();
-// cleanup_post_view();
-// cleanup_processor_boxes();
-
-// _route.reset ((Route*)0);
-// _pre_processor = 0;
-// _post_processor = 0;
-// track_input_label.set_text(_("NO TRACK"));
-// update_title();
-// }
-//}
-
void
RouteParams_UI::processors_changed ()
-
{
ENSURE_GUI_THREAD(mem_fun(*this, &RouteParams_UI::processors_changed));
-
-// pre_insert_list.freeze ();
-// pre_insert_list.clear ();
-// post_insert_list.freeze ();
-// post_insert_list.clear ();
-// if (_route) {
-// _route->foreach_redirect (this, &RouteParams_UI::add_redirect_to_display);
-// }
-// pre_insert_list.thaw ();
-// post_insert_list.thaw ();
-
cleanup_pre_view();
cleanup_post_view();
_pre_processor.reset ((Processor*) 0);
_post_processor.reset ((Processor*) 0);
+
//update_title();
}
-
-
void
RouteParams_UI::show_track_menu()
{
@@ -515,8 +547,6 @@ RouteParams_UI::show_track_menu()
track_menu->popup (1, gtk_get_current_event_time());
}
-
-
void
RouteParams_UI::redirect_selected (boost::shared_ptr<ARDOUR::Processor> insert, ARDOUR::Placement place)
{
@@ -658,7 +688,7 @@ RouteParams_UI::update_title ()
// }
title_label.set_text(_route->name());
-
+
title += _route->name();
set_title(title.get_string());
@@ -670,7 +700,6 @@ RouteParams_UI::update_title ()
}
}
-
void
RouteParams_UI::start_updating ()
{
diff --git a/gtk2_ardour/route_params_ui.h b/gtk2_ardour/route_params_ui.h
index 39305ae467..e9fca333ab 100644
--- a/gtk2_ardour/route_params_ui.h
+++ b/gtk2_ardour/route_params_ui.h
@@ -42,6 +42,7 @@
#include "ardour_dialog.h"
#include "processor_box.h"
#include "route_processor_selection.h"
+#include "latency_gui.h"
namespace ARDOUR {
class Route;
@@ -83,7 +84,7 @@ class RouteParams_UI : public ArdourDialog
Gtk::Frame output_frame;
Gtk::HPaned pre_redir_hpane;
Gtk::HPaned post_redir_hpane;
-
+
Gtk::Frame route_select_frame;
Gtk::HBox route_hpacker;
@@ -102,7 +103,18 @@ class RouteParams_UI : public ArdourDialog
Gtk::VBox choice_vpacker;
+ Gtk::Frame latency_frame;
+ Gtk::VBox latency_packer;
+ Gtk::HButtonBox latency_button_box;
+ Gtk::Button latency_apply_button;
+ LatencyGUI* latency_widget;
+ Gtk::Label delay_label;
+ sigc::connection latency_conn;
+ sigc::connection delay_conn;
+ sigc::connection latency_apply_conn;
+ void refresh_latency ();
+
Gtk::ToggleButton input_button;
Gtk::ToggleButton output_button;
Gtk::Label track_input_label;
@@ -168,8 +180,8 @@ class RouteParams_UI : public ArdourDialog
void cleanup_io_frames();
void cleanup_pre_view(bool stopupdate = true);
void cleanup_post_view(bool stopupdate = true);
-
-
+ void cleanup_latency_frame ();
+ void setup_latency_frame ();
void processors_changed ();
diff --git a/gtk2_ardour/route_ui.cc b/gtk2_ardour/route_ui.cc
index eb2eaeb115..95042af6ea 100644
--- a/gtk2_ardour/route_ui.cc
+++ b/gtk2_ardour/route_ui.cc
@@ -22,17 +22,21 @@
#include <gtkmm2ext/choice.h>
#include <gtkmm2ext/doi.h>
#include <gtkmm2ext/bindable_button.h>
+#include <gtkmm2ext/barcontroller.h>
#include <ardour/route_group.h>
#include <pbd/memento_command.h>
#include <pbd/stacktrace.h>
#include <pbd/shiva.h>
+#include <pbd/controllable.h>
#include "route_ui.h"
#include "keyboard.h"
#include "utils.h"
#include "prompter.h"
#include "gui_thread.h"
+#include "ardour_dialog.h"
+#include "latency_gui.h"
#include <ardour/route.h>
#include <ardour/session.h>
@@ -451,7 +455,7 @@ RouteUI::update_rec_display ()
rec_enable_button->set_active (model);
ignore_toggle = false;
}
-
+
/* now make sure its color state is correct */
if (model) {
@@ -1040,3 +1044,8 @@ RouteUI::map_frozen ()
}
}
+void
+RouteUI::adjust_latency ()
+{
+ LatencyDialog dialog (_route->name() + _("latency"), *(_route.get()), _session.frame_rate(), _session.engine().frames_per_cycle());
+}
diff --git a/gtk2_ardour/route_ui.h b/gtk2_ardour/route_ui.h
index 4a4fed5b75..730330372a 100644
--- a/gtk2_ardour/route_ui.h
+++ b/gtk2_ardour/route_ui.h
@@ -163,6 +163,8 @@ class RouteUI : public virtual AxisView
void reversibly_apply_route_boolean (string name, void (ARDOUR::Route::*func)(bool, void*), bool, void *);
void reversibly_apply_track_boolean (string name, void (ARDOUR::Track::*func)(bool, void*), bool, void *);
+
+ void adjust_latency ();
};
#endif /* __ardour_route_ui__ */