mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-07 15:25:01 +01:00
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
This commit is contained in:
parent
34be8c2119
commit
b5af3bb8e3
32 changed files with 553 additions and 99 deletions
|
|
@ -152,6 +152,7 @@ gtk-custom-ruler.c
|
||||||
io_selector.cc
|
io_selector.cc
|
||||||
keyboard.cc
|
keyboard.cc
|
||||||
ladspa_pluginui.cc
|
ladspa_pluginui.cc
|
||||||
|
latency_gui.cc
|
||||||
location_ui.cc
|
location_ui.cc
|
||||||
main.cc
|
main.cc
|
||||||
marker.cc
|
marker.cc
|
||||||
|
|
|
||||||
167
gtk2_ardour/latency_gui.cc
Normal file
167
gtk2_ardour/latency_gui.cc
Normal file
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
61
gtk2_ardour/latency_gui.h
Normal file
61
gtk2_ardour/latency_gui.h
Normal file
|
|
@ -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;
|
||||||
|
};
|
||||||
|
|
@ -984,6 +984,11 @@ MixerStrip::build_route_ops_menu ()
|
||||||
items.push_back (CheckMenuElem (_("Active"), mem_fun (*this, &RouteUI::toggle_route_active)));
|
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 = dynamic_cast<CheckMenuItem *> (&items.back());
|
||||||
route_active_menu_item->set_active (_route->active());
|
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 (SeparatorElem());
|
||||||
items.push_back (CheckMenuElem (_("Invert Polarity"), mem_fun (*this, &RouteUI::toggle_polarity)));
|
items.push_back (CheckMenuElem (_("Invert Polarity"), mem_fun (*this, &RouteUI::toggle_polarity)));
|
||||||
polarity_menu_item = dynamic_cast<CheckMenuItem *> (&items.back());
|
polarity_menu_item = dynamic_cast<CheckMenuItem *> (&items.back());
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#define __STDC_FORMAT_MACROS
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
#include <glibmm/thread.h>
|
#include <glibmm/thread.h>
|
||||||
#include <gtkmm2ext/utils.h>
|
#include <gtkmm2ext/utils.h>
|
||||||
|
|
@ -58,7 +60,9 @@ using namespace sigc;
|
||||||
|
|
||||||
RouteParams_UI::RouteParams_UI ()
|
RouteParams_UI::RouteParams_UI ()
|
||||||
: ArdourDialog ("track/bus inspector"),
|
: ArdourDialog ("track/bus inspector"),
|
||||||
|
latency_apply_button (Stock::APPLY),
|
||||||
track_menu(0)
|
track_menu(0)
|
||||||
|
|
||||||
{
|
{
|
||||||
pre_insert_box = 0;
|
pre_insert_box = 0;
|
||||||
post_insert_box = 0;
|
post_insert_box = 0;
|
||||||
|
|
@ -66,12 +70,14 @@ RouteParams_UI::RouteParams_UI ()
|
||||||
_output_iosel = 0;
|
_output_iosel = 0;
|
||||||
_active_pre_view = 0;
|
_active_pre_view = 0;
|
||||||
_active_post_view = 0;
|
_active_post_view = 0;
|
||||||
|
latency_widget = 0;
|
||||||
|
|
||||||
using namespace Notebook_Helpers;
|
using namespace Notebook_Helpers;
|
||||||
|
|
||||||
input_frame.set_shadow_type(Gtk::SHADOW_NONE);
|
input_frame.set_shadow_type(Gtk::SHADOW_NONE);
|
||||||
output_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_tabs (true);
|
||||||
notebook.set_show_border (true);
|
notebook.set_show_border (true);
|
||||||
notebook.set_name ("RouteParamNotebook");
|
notebook.set_name ("RouteParamNotebook");
|
||||||
|
|
@ -92,7 +98,6 @@ RouteParams_UI::RouteParams_UI ()
|
||||||
route_select_scroller.add(route_display);
|
route_select_scroller.add(route_display);
|
||||||
route_select_scroller.set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
|
route_select_scroller.set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
|
||||||
|
|
||||||
|
|
||||||
route_select_frame.set_name("RouteSelectBaseFrame");
|
route_select_frame.set_name("RouteSelectBaseFrame");
|
||||||
route_select_frame.set_shadow_type (Gtk::SHADOW_IN);
|
route_select_frame.set_shadow_type (Gtk::SHADOW_IN);
|
||||||
route_select_frame.add(route_select_scroller);
|
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 (output_frame, _("Outputs")));
|
||||||
notebook.pages().push_back (TabElem (pre_redir_hpane, _("Pre-fader Redirects")));
|
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 (post_redir_hpane, _("Post-fader Redirects")));
|
||||||
|
notebook.pages().push_back (TabElem (latency_frame, _("Latency")));
|
||||||
|
|
||||||
notebook.set_name ("InspectorNotebook");
|
notebook.set_name ("InspectorNotebook");
|
||||||
|
|
||||||
title_label.set_name ("RouteParamsTitleLabel");
|
title_label.set_name ("RouteParamsTitleLabel");
|
||||||
update_title();
|
update_title();
|
||||||
|
|
||||||
|
latency_packer.set_spacing (18);
|
||||||
|
latency_button_box.pack_start (latency_apply_button);
|
||||||
|
delay_label.set_alignment (0, 0.5);
|
||||||
|
|
||||||
// changeable area
|
// changeable area
|
||||||
route_param_frame.set_name("RouteParamsBaseFrame");
|
route_param_frame.set_name("RouteParamsBaseFrame");
|
||||||
route_param_frame.set_shadow_type (Gtk::SHADOW_IN);
|
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_hpacker.pack_start (notebook, true, true);
|
||||||
|
|
||||||
|
|
||||||
route_vpacker.pack_start (title_label, false, false);
|
route_vpacker.pack_start (title_label, false, false);
|
||||||
route_vpacker.pack_start (route_hpacker, true, true);
|
route_vpacker.pack_start (route_hpacker, true, true);
|
||||||
|
|
||||||
|
|
@ -142,6 +151,7 @@ RouteParams_UI::RouteParams_UI ()
|
||||||
title += _("Track/Bus Inspector");
|
title += _("Track/Bus Inspector");
|
||||||
set_title (title.get_string());
|
set_title (title.get_string());
|
||||||
|
|
||||||
|
|
||||||
// events
|
// events
|
||||||
route_display.get_selection()->signal_changed().connect(mem_fun(*this, &RouteParams_UI::route_selected));
|
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));
|
route_display.get_column(0)->signal_clicked().connect(mem_fun(*this, &RouteParams_UI::show_track_menu));
|
||||||
|
|
@ -252,6 +262,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
|
void
|
||||||
RouteParams_UI::setup_io_frames()
|
RouteParams_UI::setup_io_frames()
|
||||||
{
|
{
|
||||||
|
|
@ -387,6 +446,7 @@ RouteParams_UI::session_gone ()
|
||||||
cleanup_pre_view();
|
cleanup_pre_view();
|
||||||
cleanup_post_view();
|
cleanup_post_view();
|
||||||
cleanup_processor_boxes();
|
cleanup_processor_boxes();
|
||||||
|
cleanup_latency_frame ();
|
||||||
|
|
||||||
_route.reset ((Route*) 0);
|
_route.reset ((Route*) 0);
|
||||||
_pre_processor.reset ((Processor*) 0);
|
_pre_processor.reset ((Processor*) 0);
|
||||||
|
|
@ -402,6 +462,7 @@ RouteParams_UI::route_selected()
|
||||||
{
|
{
|
||||||
Glib::RefPtr<TreeSelection> selection = route_display.get_selection();
|
Glib::RefPtr<TreeSelection> selection = route_display.get_selection();
|
||||||
TreeModel::iterator iter = selection->get_selected(); // only used with Gtk::SELECTION_SINGLE
|
TreeModel::iterator iter = selection->get_selected(); // only used with Gtk::SELECTION_SINGLE
|
||||||
|
|
||||||
if(iter) {
|
if(iter) {
|
||||||
//If anything is selected
|
//If anything is selected
|
||||||
boost::shared_ptr<Route> route = (*iter)[route_display_columns.route] ;
|
boost::shared_ptr<Route> route = (*iter)[route_display_columns.route] ;
|
||||||
|
|
@ -419,6 +480,7 @@ RouteParams_UI::route_selected()
|
||||||
cleanup_pre_view();
|
cleanup_pre_view();
|
||||||
cleanup_post_view();
|
cleanup_post_view();
|
||||||
cleanup_io_frames();
|
cleanup_io_frames();
|
||||||
|
cleanup_latency_frame ();
|
||||||
}
|
}
|
||||||
|
|
||||||
// update the other panes with the correct info
|
// update the other panes with the correct info
|
||||||
|
|
@ -427,6 +489,7 @@ RouteParams_UI::route_selected()
|
||||||
|
|
||||||
setup_io_frames();
|
setup_io_frames();
|
||||||
setup_processor_boxes();
|
setup_processor_boxes();
|
||||||
|
setup_latency_frame ();
|
||||||
|
|
||||||
// bind to redirects changed event for this route
|
// bind to redirects changed event for this route
|
||||||
_route_conn = route->processors_changed.connect (mem_fun(*this, &RouteParams_UI::processors_changed));
|
_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());
|
track_input_label.set_text (_route->name());
|
||||||
|
|
||||||
update_title();
|
update_title();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// no selection
|
// no selection
|
||||||
if (_route) {
|
if (_route) {
|
||||||
|
|
@ -444,6 +508,7 @@ RouteParams_UI::route_selected()
|
||||||
cleanup_pre_view();
|
cleanup_pre_view();
|
||||||
cleanup_post_view();
|
cleanup_post_view();
|
||||||
cleanup_processor_boxes();
|
cleanup_processor_boxes();
|
||||||
|
cleanup_latency_frame ();
|
||||||
|
|
||||||
_route.reset ((Route*) 0);
|
_route.reset ((Route*) 0);
|
||||||
_pre_processor.reset ((Processor*) 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
|
void
|
||||||
RouteParams_UI::processors_changed ()
|
RouteParams_UI::processors_changed ()
|
||||||
|
|
||||||
{
|
{
|
||||||
ENSURE_GUI_THREAD(mem_fun(*this, &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_pre_view();
|
||||||
cleanup_post_view();
|
cleanup_post_view();
|
||||||
|
|
||||||
_pre_processor.reset ((Processor*) 0);
|
_pre_processor.reset ((Processor*) 0);
|
||||||
_post_processor.reset ((Processor*) 0);
|
_post_processor.reset ((Processor*) 0);
|
||||||
|
|
||||||
//update_title();
|
//update_title();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
RouteParams_UI::show_track_menu()
|
RouteParams_UI::show_track_menu()
|
||||||
{
|
{
|
||||||
|
|
@ -515,8 +547,6 @@ RouteParams_UI::show_track_menu()
|
||||||
track_menu->popup (1, gtk_get_current_event_time());
|
track_menu->popup (1, gtk_get_current_event_time());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
RouteParams_UI::redirect_selected (boost::shared_ptr<ARDOUR::Processor> insert, ARDOUR::Placement place)
|
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_label.set_text(_route->name());
|
||||||
|
|
||||||
title += _route->name();
|
title += _route->name();
|
||||||
|
|
||||||
set_title(title.get_string());
|
set_title(title.get_string());
|
||||||
|
|
@ -670,7 +700,6 @@ RouteParams_UI::update_title ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
RouteParams_UI::start_updating ()
|
RouteParams_UI::start_updating ()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@
|
||||||
#include "ardour_dialog.h"
|
#include "ardour_dialog.h"
|
||||||
#include "processor_box.h"
|
#include "processor_box.h"
|
||||||
#include "route_processor_selection.h"
|
#include "route_processor_selection.h"
|
||||||
|
#include "latency_gui.h"
|
||||||
|
|
||||||
namespace ARDOUR {
|
namespace ARDOUR {
|
||||||
class Route;
|
class Route;
|
||||||
|
|
@ -83,7 +84,7 @@ class RouteParams_UI : public ArdourDialog
|
||||||
Gtk::Frame output_frame;
|
Gtk::Frame output_frame;
|
||||||
Gtk::HPaned pre_redir_hpane;
|
Gtk::HPaned pre_redir_hpane;
|
||||||
Gtk::HPaned post_redir_hpane;
|
Gtk::HPaned post_redir_hpane;
|
||||||
|
|
||||||
Gtk::Frame route_select_frame;
|
Gtk::Frame route_select_frame;
|
||||||
|
|
||||||
Gtk::HBox route_hpacker;
|
Gtk::HBox route_hpacker;
|
||||||
|
|
@ -102,7 +103,18 @@ class RouteParams_UI : public ArdourDialog
|
||||||
|
|
||||||
Gtk::VBox choice_vpacker;
|
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 input_button;
|
||||||
Gtk::ToggleButton output_button;
|
Gtk::ToggleButton output_button;
|
||||||
Gtk::Label track_input_label;
|
Gtk::Label track_input_label;
|
||||||
|
|
@ -168,8 +180,8 @@ class RouteParams_UI : public ArdourDialog
|
||||||
void cleanup_io_frames();
|
void cleanup_io_frames();
|
||||||
void cleanup_pre_view(bool stopupdate = true);
|
void cleanup_pre_view(bool stopupdate = true);
|
||||||
void cleanup_post_view(bool stopupdate = true);
|
void cleanup_post_view(bool stopupdate = true);
|
||||||
|
void cleanup_latency_frame ();
|
||||||
|
void setup_latency_frame ();
|
||||||
|
|
||||||
void processors_changed ();
|
void processors_changed ();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,17 +22,21 @@
|
||||||
#include <gtkmm2ext/choice.h>
|
#include <gtkmm2ext/choice.h>
|
||||||
#include <gtkmm2ext/doi.h>
|
#include <gtkmm2ext/doi.h>
|
||||||
#include <gtkmm2ext/bindable_button.h>
|
#include <gtkmm2ext/bindable_button.h>
|
||||||
|
#include <gtkmm2ext/barcontroller.h>
|
||||||
|
|
||||||
#include <ardour/route_group.h>
|
#include <ardour/route_group.h>
|
||||||
#include <pbd/memento_command.h>
|
#include <pbd/memento_command.h>
|
||||||
#include <pbd/stacktrace.h>
|
#include <pbd/stacktrace.h>
|
||||||
#include <pbd/shiva.h>
|
#include <pbd/shiva.h>
|
||||||
|
#include <pbd/controllable.h>
|
||||||
|
|
||||||
#include "route_ui.h"
|
#include "route_ui.h"
|
||||||
#include "keyboard.h"
|
#include "keyboard.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "prompter.h"
|
#include "prompter.h"
|
||||||
#include "gui_thread.h"
|
#include "gui_thread.h"
|
||||||
|
#include "ardour_dialog.h"
|
||||||
|
#include "latency_gui.h"
|
||||||
|
|
||||||
#include <ardour/route.h>
|
#include <ardour/route.h>
|
||||||
#include <ardour/session.h>
|
#include <ardour/session.h>
|
||||||
|
|
@ -451,7 +455,7 @@ RouteUI::update_rec_display ()
|
||||||
rec_enable_button->set_active (model);
|
rec_enable_button->set_active (model);
|
||||||
ignore_toggle = false;
|
ignore_toggle = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* now make sure its color state is correct */
|
/* now make sure its color state is correct */
|
||||||
|
|
||||||
if (model) {
|
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());
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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_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 reversibly_apply_track_boolean (string name, void (ARDOUR::Track::*func)(bool, void*), bool, void *);
|
||||||
|
|
||||||
|
void adjust_latency ();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* __ardour_route_ui__ */
|
#endif /* __ardour_route_ui__ */
|
||||||
|
|
|
||||||
|
|
@ -199,6 +199,25 @@ def CheckJackVideoFrameOffset(context):
|
||||||
context.Result(result)
|
context.Result(result)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# See if JACK supports jack_recompute_total_latency() (single port version)
|
||||||
|
#
|
||||||
|
|
||||||
|
jack_port_latency_test = """
|
||||||
|
#include <jack/jack.h>
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
jack_recompute_total_latency ((jack_client_t*) 0, (jack_port_t*) 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
def CheckJackRecomputeLatency(context):
|
||||||
|
context.Message('Checking for jack_recompute_total_latency()...')
|
||||||
|
result = context.TryLink(jack_port_latency_test, '.c')
|
||||||
|
context.Result(result)
|
||||||
|
return result
|
||||||
|
|
||||||
#
|
#
|
||||||
# See if JACK supports jack_port_ensure_monitor_input()
|
# See if JACK supports jack_port_ensure_monitor_input()
|
||||||
#
|
#
|
||||||
|
|
@ -223,6 +242,7 @@ def CheckJackEnsureMonitorInput(context):
|
||||||
conf = Configure(ardour, custom_tests = {
|
conf = Configure(ardour, custom_tests = {
|
||||||
'CheckJackClientOpen' : CheckJackClientOpen,
|
'CheckJackClientOpen' : CheckJackClientOpen,
|
||||||
'CheckJackRecomputeLatencies' : CheckJackRecomputeLatencies,
|
'CheckJackRecomputeLatencies' : CheckJackRecomputeLatencies,
|
||||||
|
'CheckJackRecomputeLatency' : CheckJackRecomputeLatency,
|
||||||
'CheckJackVideoFrameOffset' : CheckJackVideoFrameOffset,
|
'CheckJackVideoFrameOffset' : CheckJackVideoFrameOffset,
|
||||||
'CheckJackEnsureMonitorInput' : CheckJackEnsureMonitorInput
|
'CheckJackEnsureMonitorInput' : CheckJackEnsureMonitorInput
|
||||||
})
|
})
|
||||||
|
|
@ -233,6 +253,9 @@ if conf.CheckJackClientOpen():
|
||||||
if conf.CheckJackRecomputeLatencies():
|
if conf.CheckJackRecomputeLatencies():
|
||||||
ardour.Append(CXXFLAGS="-DHAVE_JACK_RECOMPUTE_LATENCIES")
|
ardour.Append(CXXFLAGS="-DHAVE_JACK_RECOMPUTE_LATENCIES")
|
||||||
|
|
||||||
|
if conf.CheckJackRecomputeLatency():
|
||||||
|
ardour.Append(CXXFLAGS="-DHAVE_JACK_RECOMPUTE_LATENCY")
|
||||||
|
|
||||||
if conf.CheckJackVideoFrameOffset():
|
if conf.CheckJackVideoFrameOffset():
|
||||||
ardour.Append(CXXFLAGS="-DHAVE_JACK_VIDEO_SUPPORT")
|
ardour.Append(CXXFLAGS="-DHAVE_JACK_VIDEO_SUPPORT")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ class AUPlugin : public ARDOUR::Plugin
|
||||||
const char * maker () const;
|
const char * maker () const;
|
||||||
uint32_t parameter_count () const;
|
uint32_t parameter_count () const;
|
||||||
float default_value (uint32_t port);
|
float default_value (uint32_t port);
|
||||||
nframes_t latency () const;
|
nframes_t signal_latency () const;
|
||||||
void set_parameter (uint32_t which, float val);
|
void set_parameter (uint32_t which, float val);
|
||||||
float get_parameter (uint32_t which) const;
|
float get_parameter (uint32_t which) const;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -139,6 +139,7 @@ class AudioEngine : public sigc::trackable
|
||||||
|
|
||||||
nframes_t get_port_total_latency (const Port&);
|
nframes_t get_port_total_latency (const Port&);
|
||||||
void update_total_latencies ();
|
void update_total_latencies ();
|
||||||
|
void update_total_latency (const Port&);
|
||||||
|
|
||||||
/** Caller may not delete the object pointed to by the return value
|
/** Caller may not delete the object pointed to by the return value
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@
|
||||||
#include <ardour/data_type.h>
|
#include <ardour/data_type.h>
|
||||||
#include <ardour/port_set.h>
|
#include <ardour/port_set.h>
|
||||||
#include <ardour/chan_count.h>
|
#include <ardour/chan_count.h>
|
||||||
|
#include <ardour/latent.h>
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
using std::vector;
|
using std::vector;
|
||||||
|
|
@ -64,7 +65,8 @@ class BufferSet;
|
||||||
* An IO can contain ports of varying types, making routes/inserts/etc with
|
* An IO can contain ports of varying types, making routes/inserts/etc with
|
||||||
* varied combinations of types (eg MIDI and audio) possible.
|
* varied combinations of types (eg MIDI and audio) possible.
|
||||||
*/
|
*/
|
||||||
class IO : public Automatable
|
|
||||||
|
class IO : public Automatable, public Latent
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static const string state_node_name;
|
static const string state_node_name;
|
||||||
|
|
@ -141,9 +143,12 @@ class IO : public Automatable
|
||||||
int disconnect_inputs (void *src);
|
int disconnect_inputs (void *src);
|
||||||
int disconnect_outputs (void *src);
|
int disconnect_outputs (void *src);
|
||||||
|
|
||||||
|
nframes_t signal_latency() const { return _own_latency; }
|
||||||
nframes_t output_latency() const;
|
nframes_t output_latency() const;
|
||||||
nframes_t input_latency() const;
|
nframes_t input_latency() const;
|
||||||
void set_port_latency (nframes_t);
|
void set_port_latency (nframes_t);
|
||||||
|
|
||||||
|
void update_port_total_latencies ();
|
||||||
|
|
||||||
const PortSet& inputs() const { return _inputs; }
|
const PortSet& inputs() const { return _inputs; }
|
||||||
const PortSet& outputs() const { return _outputs; }
|
const PortSet& outputs() const { return _outputs; }
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ class LadspaPlugin : public ARDOUR::Plugin
|
||||||
const char * maker() const { return descriptor->Maker; }
|
const char * maker() const { return descriptor->Maker; }
|
||||||
uint32_t parameter_count() const { return descriptor->PortCount; }
|
uint32_t parameter_count() const { return descriptor->PortCount; }
|
||||||
float default_value (uint32_t port);
|
float default_value (uint32_t port);
|
||||||
nframes_t latency() const;
|
nframes_t signal_latency() const;
|
||||||
void set_parameter (uint32_t port, float val);
|
void set_parameter (uint32_t port, float val);
|
||||||
float get_parameter (uint32_t port) const;
|
float get_parameter (uint32_t port) const;
|
||||||
int get_parameter_descriptor (uint32_t which, ParameterDescriptor&) const;
|
int get_parameter_descriptor (uint32_t which, ParameterDescriptor&) const;
|
||||||
|
|
|
||||||
26
libs/ardour/ardour/latent.h
Normal file
26
libs/ardour/ardour/latent.h
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
#ifndef __ardour_latent_h__
|
||||||
|
#define __ardour_latent_h__
|
||||||
|
|
||||||
|
#include <ardour/types.h>
|
||||||
|
|
||||||
|
namespace ARDOUR {
|
||||||
|
|
||||||
|
class Latent {
|
||||||
|
public:
|
||||||
|
Latent() : _own_latency (0), _user_latency (0) {}
|
||||||
|
virtual ~Latent() {}
|
||||||
|
|
||||||
|
virtual nframes_t signal_latency() const = 0;
|
||||||
|
nframes_t user_latency () const { return _user_latency; }
|
||||||
|
|
||||||
|
virtual void set_latency_delay (nframes_t val) { _own_latency = val; }
|
||||||
|
virtual void set_user_latency (nframes_t val) { _user_latency = val; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
nframes_t _own_latency;
|
||||||
|
nframes_t _user_latency;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* __ardour_latent_h__*/
|
||||||
|
|
@ -31,6 +31,7 @@
|
||||||
#include <ardour/chan_count.h>
|
#include <ardour/chan_count.h>
|
||||||
#include <ardour/plugin_state.h>
|
#include <ardour/plugin_state.h>
|
||||||
#include <ardour/cycles.h>
|
#include <ardour/cycles.h>
|
||||||
|
#include <ardour/latent.h>
|
||||||
#include <ardour/param_id.h>
|
#include <ardour/param_id.h>
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
@ -79,7 +80,7 @@ class PluginInfo {
|
||||||
typedef boost::shared_ptr<PluginInfo> PluginInfoPtr;
|
typedef boost::shared_ptr<PluginInfo> PluginInfoPtr;
|
||||||
typedef std::list<PluginInfoPtr> PluginInfoList;
|
typedef std::list<PluginInfoPtr> PluginInfoList;
|
||||||
|
|
||||||
class Plugin : public PBD::StatefulDestructible
|
class Plugin : public PBD::StatefulDestructible, public Latent
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Plugin (ARDOUR::AudioEngine&, ARDOUR::Session&);
|
Plugin (ARDOUR::AudioEngine&, ARDOUR::Session&);
|
||||||
|
|
@ -110,7 +111,6 @@ class Plugin : public PBD::StatefulDestructible
|
||||||
virtual const char * maker() const = 0;
|
virtual const char * maker() const = 0;
|
||||||
virtual uint32_t parameter_count () const = 0;
|
virtual uint32_t parameter_count () const = 0;
|
||||||
virtual float default_value (uint32_t port) = 0;
|
virtual float default_value (uint32_t port) = 0;
|
||||||
virtual nframes_t latency() const = 0;
|
|
||||||
virtual void set_parameter (uint32_t which, float val) = 0;
|
virtual void set_parameter (uint32_t which, float val) = 0;
|
||||||
virtual float get_parameter(uint32_t which) const = 0;
|
virtual float get_parameter(uint32_t which) const = 0;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,7 @@ class PluginInsert : public Processor
|
||||||
|
|
||||||
string describe_parameter (ParamID param);
|
string describe_parameter (ParamID param);
|
||||||
|
|
||||||
nframes_t latency();
|
nframes_t signal_latency() const;
|
||||||
|
|
||||||
void transport_stopped (nframes_t now);
|
void transport_stopped (nframes_t now);
|
||||||
void automation_snapshot (nframes_t now);
|
void automation_snapshot (nframes_t now);
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ class PortInsert : public IOProcessor
|
||||||
|
|
||||||
void run (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes, nframes_t offset);
|
void run (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes, nframes_t offset);
|
||||||
|
|
||||||
nframes_t latency();
|
nframes_t signal_latency() const;
|
||||||
|
|
||||||
ChanCount output_streams() const;
|
ChanCount output_streams() const;
|
||||||
ChanCount input_streams() const;
|
ChanCount input_streams() const;
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@
|
||||||
#include <ardour/plugin_state.h>
|
#include <ardour/plugin_state.h>
|
||||||
#include <ardour/buffer_set.h>
|
#include <ardour/buffer_set.h>
|
||||||
#include <ardour/automatable.h>
|
#include <ardour/automatable.h>
|
||||||
|
#include <ardour/latent.h>
|
||||||
|
|
||||||
class XMLNode;
|
class XMLNode;
|
||||||
|
|
||||||
|
|
@ -43,7 +43,7 @@ class Session;
|
||||||
|
|
||||||
/* A mixer strip element - plugin, send, meter, etc.
|
/* A mixer strip element - plugin, send, meter, etc.
|
||||||
*/
|
*/
|
||||||
class Processor : public Automatable
|
class Processor : public Automatable, public Latent
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static const string state_node_name;
|
static const string state_node_name;
|
||||||
|
|
@ -66,7 +66,7 @@ class Processor : public Automatable
|
||||||
bool get_next_ab_is_active () const { return _next_ab_is_active; }
|
bool get_next_ab_is_active () const { return _next_ab_is_active; }
|
||||||
void set_next_ab_is_active (bool yn) { _next_ab_is_active = yn; }
|
void set_next_ab_is_active (bool yn) { _next_ab_is_active = yn; }
|
||||||
|
|
||||||
virtual nframes_t latency() { return 0; }
|
virtual nframes_t signal_latency() const { return 0; }
|
||||||
|
|
||||||
virtual void transport_stopped (nframes_t frame) {}
|
virtual void transport_stopped (nframes_t frame) {}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -187,8 +187,9 @@ class Route : public IO
|
||||||
void all_processors_active (Placement, bool state);
|
void all_processors_active (Placement, bool state);
|
||||||
|
|
||||||
virtual nframes_t update_total_latency();
|
virtual nframes_t update_total_latency();
|
||||||
nframes_t signal_latency() const { return _own_latency; }
|
void set_latency_delay (nframes_t);
|
||||||
virtual void set_latency_delay (nframes_t);
|
void set_user_latency (nframes_t);
|
||||||
|
nframes_t initial_delay() const { return _initial_delay; }
|
||||||
|
|
||||||
sigc::signal<void,void*> solo_changed;
|
sigc::signal<void,void*> solo_changed;
|
||||||
sigc::signal<void,void*> solo_safe_changed;
|
sigc::signal<void,void*> solo_safe_changed;
|
||||||
|
|
@ -204,6 +205,8 @@ class Route : public IO
|
||||||
sigc::signal<void,void*> mix_group_changed;
|
sigc::signal<void,void*> mix_group_changed;
|
||||||
sigc::signal<void> active_changed;
|
sigc::signal<void> active_changed;
|
||||||
sigc::signal<void,void*> meter_change;
|
sigc::signal<void,void*> meter_change;
|
||||||
|
sigc::signal<void> signal_latency_changed;
|
||||||
|
sigc::signal<void> initial_delay_changed;
|
||||||
|
|
||||||
/* gui's call this for their own purposes. */
|
/* gui's call this for their own purposes. */
|
||||||
|
|
||||||
|
|
@ -294,7 +297,6 @@ class Route : public IO
|
||||||
|
|
||||||
nframes_t _initial_delay;
|
nframes_t _initial_delay;
|
||||||
nframes_t _roll_delay;
|
nframes_t _roll_delay;
|
||||||
nframes_t _own_latency;
|
|
||||||
ProcessorList _processors;
|
ProcessorList _processors;
|
||||||
Glib::RWLock _processor_lock;
|
Glib::RWLock _processor_lock;
|
||||||
IO *_control_outs;
|
IO *_control_outs;
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ class VSTPlugin : public ARDOUR::Plugin
|
||||||
const char * maker() const;
|
const char * maker() const;
|
||||||
uint32_t parameter_count() const;
|
uint32_t parameter_count() const;
|
||||||
float default_value (uint32_t port);
|
float default_value (uint32_t port);
|
||||||
nframes_t latency() const;
|
nframes_t signal_latency() const;
|
||||||
void set_parameter (uint32_t port, float val);
|
void set_parameter (uint32_t port, float val);
|
||||||
float get_parameter (uint32_t port) const;
|
float get_parameter (uint32_t port) const;
|
||||||
int get_parameter_descriptor (uint32_t which, ParameterDescriptor&) const;
|
int get_parameter_descriptor (uint32_t which, ParameterDescriptor&) const;
|
||||||
|
|
|
||||||
|
|
@ -113,8 +113,12 @@ AUPlugin::default_value (uint32_t port)
|
||||||
}
|
}
|
||||||
|
|
||||||
nframes_t
|
nframes_t
|
||||||
AUPlugin::latency () const
|
AUPlugin::signal_latency () const
|
||||||
{
|
{
|
||||||
|
if (_user_latency) {
|
||||||
|
return _user_latency;
|
||||||
|
}
|
||||||
|
|
||||||
return unit->Latency ();
|
return unit->Latency ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -931,6 +931,27 @@ AudioEngine::get_port_total_latency (const Port& port)
|
||||||
return jack_port_get_total_latency (_jack, port._port);
|
return jack_port_get_total_latency (_jack, port._port);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
AudioEngine::update_total_latency (const Port& port)
|
||||||
|
{
|
||||||
|
if (!_jack) {
|
||||||
|
fatal << _("update_total_latency() called with no JACK client connection") << endmsg;
|
||||||
|
/*NOTREACHED*/
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_running) {
|
||||||
|
if (!_has_run) {
|
||||||
|
fatal << _("update_total_latency() called before engine was started") << endmsg;
|
||||||
|
/*NOTREACHED*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_JACK_RECOMPUTE_LATENCY
|
||||||
|
jack_recompute_total_latency (_jack, port._port);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
AudioEngine::transport_stop ()
|
AudioEngine::transport_stop ()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1899,7 +1899,7 @@ IO::input_latency () const
|
||||||
for (PortSet::const_iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
|
for (PortSet::const_iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
|
||||||
if ((latency = _session.engine().get_port_total_latency (*i)) > max_latency) {
|
if ((latency = _session.engine().get_port_total_latency (*i)) > max_latency) {
|
||||||
max_latency = latency;
|
max_latency = latency;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return max_latency;
|
return max_latency;
|
||||||
|
|
@ -2411,4 +2411,16 @@ IO::set_denormal_protection (bool yn, void *src)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
IO::update_port_total_latencies ()
|
||||||
|
{
|
||||||
|
/* io_lock, not taken: function must be called from Session::process() calltree */
|
||||||
|
|
||||||
|
for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
|
||||||
|
_session.engine().update_total_latency (*i);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
|
||||||
|
_session.engine().update_total_latency (*i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -491,7 +491,6 @@ LadspaPlugin::get_parameter_descriptor (uint32_t which, ParameterDescriptor& des
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
string
|
string
|
||||||
LadspaPlugin::describe_parameter (ParamID which)
|
LadspaPlugin::describe_parameter (ParamID which)
|
||||||
{
|
{
|
||||||
|
|
@ -503,8 +502,12 @@ LadspaPlugin::describe_parameter (ParamID which)
|
||||||
}
|
}
|
||||||
|
|
||||||
ARDOUR::nframes_t
|
ARDOUR::nframes_t
|
||||||
LadspaPlugin::latency () const
|
LadspaPlugin::signal_latency () const
|
||||||
{
|
{
|
||||||
|
if (_user_latency) {
|
||||||
|
return _user_latency;
|
||||||
|
}
|
||||||
|
|
||||||
if (latency_control_port) {
|
if (latency_control_port) {
|
||||||
return (nframes_t) floor (*latency_control_port);
|
return (nframes_t) floor (*latency_control_port);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -836,11 +836,15 @@ PluginInsert::describe_parameter (ParamID param)
|
||||||
}
|
}
|
||||||
|
|
||||||
ARDOUR::nframes_t
|
ARDOUR::nframes_t
|
||||||
PluginInsert::latency()
|
PluginInsert::signal_latency() const
|
||||||
{
|
{
|
||||||
return _plugins[0]->latency ();
|
if (_user_latency) {
|
||||||
|
return _user_latency;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _plugins[0]->signal_latency ();
|
||||||
}
|
}
|
||||||
|
|
||||||
ARDOUR::PluginType
|
ARDOUR::PluginType
|
||||||
PluginInsert::type ()
|
PluginInsert::type ()
|
||||||
{
|
{
|
||||||
|
|
@ -870,4 +874,3 @@ PluginInsert::type ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -160,7 +160,7 @@ PortInsert::set_state(const XMLNode& node)
|
||||||
}
|
}
|
||||||
|
|
||||||
ARDOUR::nframes_t
|
ARDOUR::nframes_t
|
||||||
PortInsert::latency()
|
PortInsert::signal_latency() const
|
||||||
{
|
{
|
||||||
/* because we deliver and collect within the same cycle,
|
/* because we deliver and collect within the same cycle,
|
||||||
all I/O is necessarily delayed by at least frames_per_cycle().
|
all I/O is necessarily delayed by at least frames_per_cycle().
|
||||||
|
|
|
||||||
|
|
@ -89,6 +89,7 @@ Route::init ()
|
||||||
_initial_delay = 0;
|
_initial_delay = 0;
|
||||||
_roll_delay = 0;
|
_roll_delay = 0;
|
||||||
_own_latency = 0;
|
_own_latency = 0;
|
||||||
|
_user_latency = 0;
|
||||||
_have_internal_generator = false;
|
_have_internal_generator = false;
|
||||||
_declickable = false;
|
_declickable = false;
|
||||||
_pending_declick = true;
|
_pending_declick = true;
|
||||||
|
|
@ -812,6 +813,8 @@ Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorStreams*
|
||||||
|
|
||||||
processor->activate ();
|
processor->activate ();
|
||||||
processor->ActiveChanged.connect (bind (mem_fun (_session, &Session::update_latency_compensation), false, false));
|
processor->ActiveChanged.connect (bind (mem_fun (_session, &Session::update_latency_compensation), false, false));
|
||||||
|
|
||||||
|
_user_latency = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (processor_max_outs != old_rmo || old_rmo == ChanCount::ZERO) {
|
if (processor_max_outs != old_rmo || old_rmo == ChanCount::ZERO) {
|
||||||
|
|
@ -867,6 +870,8 @@ Route::add_processors (const ProcessorList& others, ProcessorStreams* err)
|
||||||
(*i)->activate ();
|
(*i)->activate ();
|
||||||
(*i)->ActiveChanged.connect (bind (mem_fun (_session, &Session::update_latency_compensation), false, false));
|
(*i)->ActiveChanged.connect (bind (mem_fun (_session, &Session::update_latency_compensation), false, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_user_latency = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (processor_max_outs != old_rmo || old_rmo == ChanCount::ZERO) {
|
if (processor_max_outs != old_rmo || old_rmo == ChanCount::ZERO) {
|
||||||
|
|
@ -1098,6 +1103,8 @@ Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStream
|
||||||
removed = true;
|
removed = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_user_latency = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!removed) {
|
if (!removed) {
|
||||||
|
|
@ -1337,6 +1344,7 @@ Route::copy_processors (const Route& other, Placement placement, ProcessorStream
|
||||||
|
|
||||||
/* SUCCESSFUL COPY ATTEMPT: delete the processors we removed pre-copy */
|
/* SUCCESSFUL COPY ATTEMPT: delete the processors we removed pre-copy */
|
||||||
to_be_deleted.clear ();
|
to_be_deleted.clear ();
|
||||||
|
_user_latency = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2470,32 +2478,62 @@ Route::set_meter_point (MeterPoint p, void *src)
|
||||||
nframes_t
|
nframes_t
|
||||||
Route::update_total_latency ()
|
Route::update_total_latency ()
|
||||||
{
|
{
|
||||||
_own_latency = 0;
|
nframes_t old = _own_latency;
|
||||||
|
|
||||||
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
|
if (_user_latency) {
|
||||||
if ((*i)->active ()) {
|
_own_latency = _user_latency;
|
||||||
_own_latency += (*i)->latency ();
|
} else {
|
||||||
|
_own_latency = 0;
|
||||||
|
|
||||||
|
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
|
||||||
|
if ((*i)->active ()) {
|
||||||
|
_own_latency += (*i)->signal_latency ();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
set_port_latency (_own_latency);
|
set_port_latency (_own_latency);
|
||||||
|
|
||||||
|
if (!_user_latency) {
|
||||||
|
/* this (virtual) function is used for pure Routes,
|
||||||
|
not derived classes like AudioTrack. this means
|
||||||
|
that the data processed here comes from an input
|
||||||
|
port, not prerecorded material, and therefore we
|
||||||
|
have to take into account any input latency.
|
||||||
|
*/
|
||||||
|
|
||||||
/* this (virtual) function is used for pure Routes,
|
|
||||||
not derived classes like AudioTrack. this means
|
|
||||||
that the data processed here comes from an input
|
|
||||||
port, not prerecorded material, and therefore we
|
|
||||||
have to take into account any input latency.
|
|
||||||
*/
|
|
||||||
|
|
||||||
_own_latency += input_latency ();
|
_own_latency += input_latency ();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (old != _own_latency) {
|
||||||
|
signal_latency_changed (); /* EMIT SIGNAL */
|
||||||
|
}
|
||||||
|
|
||||||
return _own_latency;
|
return _own_latency;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Route::set_user_latency (nframes_t nframes)
|
||||||
|
{
|
||||||
|
Latent::set_user_latency (nframes);
|
||||||
|
_session.update_latency_compensation (false, false);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Route::set_latency_delay (nframes_t longest_session_latency)
|
Route::set_latency_delay (nframes_t longest_session_latency)
|
||||||
{
|
{
|
||||||
_initial_delay = longest_session_latency - _own_latency;
|
nframes_t old = _initial_delay;
|
||||||
|
|
||||||
|
if (_own_latency < longest_session_latency) {
|
||||||
|
_initial_delay = longest_session_latency - _own_latency;
|
||||||
|
} else {
|
||||||
|
_initial_delay = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_initial_delay != old) {
|
||||||
|
initial_delay_changed (); /* EMIT SIGNAL */
|
||||||
|
}
|
||||||
|
|
||||||
if (_session.transport_stopped()) {
|
if (_session.transport_stopped()) {
|
||||||
_roll_delay = _initial_delay;
|
_roll_delay = _initial_delay;
|
||||||
|
|
|
||||||
|
|
@ -1248,33 +1248,33 @@ Session::update_latency_compensation (bool with_stop, bool abort)
|
||||||
boost::shared_ptr<RouteList> r = routes.reader ();
|
boost::shared_ptr<RouteList> r = routes.reader ();
|
||||||
|
|
||||||
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
|
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
|
||||||
|
|
||||||
if (with_stop) {
|
if (with_stop) {
|
||||||
(*i)->handle_transport_stopped (abort, (post_transport_work & PostTransportLocate),
|
(*i)->handle_transport_stopped (abort, (post_transport_work & PostTransportLocate),
|
||||||
(!(post_transport_work & PostTransportLocate) || pending_locate_flush));
|
(!(post_transport_work & PostTransportLocate) || pending_locate_flush));
|
||||||
}
|
}
|
||||||
|
|
||||||
nframes_t old_latency = (*i)->signal_latency ();
|
nframes_t old_latency = (*i)->signal_latency ();
|
||||||
nframes_t track_latency = (*i)->update_total_latency ();
|
nframes_t track_latency = (*i)->update_total_latency ();
|
||||||
|
|
||||||
if (old_latency != track_latency) {
|
if (old_latency != track_latency) {
|
||||||
|
(*i)->update_port_total_latencies ();
|
||||||
update_jack = true;
|
update_jack = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(*i)->hidden() && ((*i)->active())) {
|
if (!(*i)->hidden() && ((*i)->active())) {
|
||||||
_worst_track_latency = max (_worst_track_latency, track_latency);
|
_worst_track_latency = max (_worst_track_latency, track_latency);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (update_jack) {
|
||||||
|
_engine.update_total_latencies ();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
|
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
|
||||||
(*i)->set_latency_delay (_worst_track_latency);
|
(*i)->set_latency_delay (_worst_track_latency);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* tell JACK to play catch up */
|
|
||||||
|
|
||||||
if (update_jack) {
|
|
||||||
_engine.update_total_latencies ();
|
|
||||||
}
|
|
||||||
|
|
||||||
set_worst_io_latencies ();
|
set_worst_io_latencies ();
|
||||||
|
|
||||||
/* reflect any changes in latencies into capture offsets
|
/* reflect any changes in latencies into capture offsets
|
||||||
|
|
|
||||||
|
|
@ -90,20 +90,29 @@ Track::toggle_monitor_input ()
|
||||||
ARDOUR::nframes_t
|
ARDOUR::nframes_t
|
||||||
Track::update_total_latency ()
|
Track::update_total_latency ()
|
||||||
{
|
{
|
||||||
_own_latency = 0;
|
nframes_t old = _own_latency;
|
||||||
|
|
||||||
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
|
if (_user_latency) {
|
||||||
if ((*i)->active ()) {
|
_own_latency = _user_latency;
|
||||||
_own_latency += (*i)->latency ();
|
} else {
|
||||||
|
_own_latency = 0;
|
||||||
|
|
||||||
|
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
|
||||||
|
if ((*i)->active ()) {
|
||||||
|
_own_latency += (*i)->signal_latency ();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
set_port_latency (_own_latency);
|
set_port_latency (_own_latency);
|
||||||
|
|
||||||
|
if (old != _own_latency) {
|
||||||
|
signal_latency_changed (); /* EMIT SIGNAL */
|
||||||
|
}
|
||||||
|
|
||||||
return _own_latency;
|
return _own_latency;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Track::FreezeRecord::~FreezeRecord ()
|
Track::FreezeRecord::~FreezeRecord ()
|
||||||
{
|
{
|
||||||
for (vector<FreezeRecordProcessorInfo*>::iterator i = processor_info.begin(); i != processor_info.end(); ++i) {
|
for (vector<FreezeRecordProcessorInfo*>::iterator i = processor_info.begin(); i != processor_info.end(); ++i) {
|
||||||
|
|
|
||||||
|
|
@ -351,8 +351,12 @@ VSTPlugin::describe_parameter (uint32_t param)
|
||||||
}
|
}
|
||||||
|
|
||||||
nframes_t
|
nframes_t
|
||||||
VSTPlugin::latency () const
|
VSTPlugin::signal_latency () const
|
||||||
{
|
{
|
||||||
|
if (_user_latency) {
|
||||||
|
return _user_latency;
|
||||||
|
}
|
||||||
|
|
||||||
return _plugin->initialDelay;
|
return _plugin->initialDelay;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ get_files_in_directory (const sys::path& directory_path, vector<string>& result)
|
||||||
}
|
}
|
||||||
catch (Glib::FileError& err)
|
catch (Glib::FileError& err)
|
||||||
{
|
{
|
||||||
warning << err.what();
|
warning << err.what() << endmsg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -113,6 +113,7 @@ find_file_in_search_path(const SearchPath& search_path,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
if (tmp.size() != 1)
|
if (tmp.size() != 1)
|
||||||
{
|
{
|
||||||
info << string_compose
|
info << string_compose
|
||||||
|
|
@ -123,6 +124,7 @@ find_file_in_search_path(const SearchPath& search_path,
|
||||||
)
|
)
|
||||||
<< endmsg;
|
<< endmsg;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
result = tmp.front();
|
result = tmp.front();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,21 @@ class Controllable : public PBD::StatefulDestructible {
|
||||||
static Controllables registry;
|
static Controllables registry;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* a utility class for the occasions when you need but do not have
|
||||||
|
a Controllable
|
||||||
|
*/
|
||||||
|
|
||||||
|
class IgnorableControllable : public Controllable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
IgnorableControllable () : PBD::Controllable ("ignoreMe") {}
|
||||||
|
~IgnorableControllable () {}
|
||||||
|
|
||||||
|
void set_value (float v){}
|
||||||
|
float get_value () const { return 0.0; }
|
||||||
|
bool can_send_feedback () const { return false; }
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* __pbd_controllable_h__ */
|
#endif /* __pbd_controllable_h__ */
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue