diff options
author | Paul Davis <paul@linuxaudiosystems.com> | 2007-06-27 22:06:35 +0000 |
---|---|---|
committer | Paul Davis <paul@linuxaudiosystems.com> | 2007-06-27 22:06:35 +0000 |
commit | b5af3bb8e313e13166cc54c60a14e5492e674065 (patch) | |
tree | d27e045a17bae47e63cde89173a53fb30ffa298b /gtk2_ardour | |
parent | 34be8c21198441a4f8ceac35da12250cafa2d1c2 (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/SConscript | 1 | ||||
-rw-r--r-- | gtk2_ardour/latency_gui.cc | 167 | ||||
-rw-r--r-- | gtk2_ardour/latency_gui.h | 61 | ||||
-rw-r--r-- | gtk2_ardour/mixer_strip.cc | 5 | ||||
-rw-r--r-- | gtk2_ardour/route_params_ui.cc | 113 | ||||
-rw-r--r-- | gtk2_ardour/route_params_ui.h | 18 | ||||
-rw-r--r-- | gtk2_ardour/route_ui.cc | 11 | ||||
-rw-r--r-- | gtk2_ardour/route_ui.h | 2 |
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__ */ |