X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Fprocessor_box.cc;h=064e7358fdd25ee8ec38db750b6f660231f01aa8;hb=b502bbc61895d61c39bf240b47e8a3664be2c541;hp=25bd4a79ffddbf2e1ed3f62fba4ef84d07bc6951;hpb=e1d194cf48069b310eb6740b6029d974d38de94a;p=ardour.git diff --git a/gtk2_ardour/processor_box.cc b/gtk2_ardour/processor_box.cc index 25bd4a79ff..064e7358fd 100644 --- a/gtk2_ardour/processor_box.cc +++ b/gtk2_ardour/processor_box.cc @@ -44,6 +44,7 @@ #include "ardour/audio_track.h" #include "ardour/audioengine.h" #include "ardour/internal_send.h" +#include "ardour/internal_return.h" #include "ardour/ladspa_plugin.h" #include "ardour/meter.h" #include "ardour/plugin_insert.h" @@ -53,6 +54,7 @@ #include "ardour/route.h" #include "ardour/send.h" #include "ardour/session.h" +#include "ardour/dB.h" #include "actions.h" #include "ardour_dialog.h" @@ -93,20 +95,40 @@ RefPtr ProcessorBox::edit_action; Glib::RefPtr SendProcessorEntry::_slider; ProcessorEntry::ProcessorEntry (boost::shared_ptr p, Width w) - : _processor (p) + : _position (PreFader) + , _processor (p) , _width (w) + , _visual_state (Gtk::STATE_NORMAL) { _hbox.pack_start (_active, false, false); _event_box.add (_name); _hbox.pack_start (_event_box, true, true); _vbox.pack_start (_hbox); + _frame.add (_vbox); + + /* without this, the border is mis-drawn on some systems */ + _vbox.set_border_width (1); _name.set_alignment (0, 0.5); _name.set_text (name ()); _name.set_padding (2, 2); - + + if (boost::dynamic_pointer_cast (p)) { + /* Fader processor gets a special look */ + _event_box.set_name ("ProcessorFader"); + _frame.set_name ("ProcessorFaderFrame"); + _name.set_padding (2, 4); + } + _active.set_active (_processor->active ()); _active.signal_toggled().connect (sigc::mem_fun (*this, &ProcessorEntry::active_toggled)); + + _frame.show (); + _vbox.show (); + _hbox.show (); + _event_box.show (); + _name.show (); + _active.show (); _processor->ActiveChanged.connect (active_connection, invalidator (*this), boost::bind (&ProcessorEntry::processor_active_changed, this), gui_context()); _processor->PropertyChanged.connect (name_connection, invalidator (*this), ui_bind (&ProcessorEntry::processor_property_changed, this, _1), gui_context()); @@ -121,7 +143,7 @@ ProcessorEntry::action_widget () Gtk::Widget& ProcessorEntry::widget () { - return _vbox; + return _frame; } string @@ -130,6 +152,66 @@ ProcessorEntry::drag_text () const return name (); } +void +ProcessorEntry::set_visual_state (Gtk::StateType t) +{ + _visual_state = t; + setup_visuals (); +} + +void +ProcessorEntry::set_position (Position p) +{ + _position = p; + setup_visuals (); +} + +void +ProcessorEntry::setup_visuals () +{ + switch (_position) { + case PreFader: + _event_box.set_name ("ProcessorPreFader"); + if (_visual_state == Gtk::STATE_NORMAL) { + _frame.set_name ("ProcessorPreFaderFrame"); + } + break; + + case Fader: + _event_box.set_name ("ProcessorFader"); + if (_visual_state == Gtk::STATE_NORMAL) { + _frame.set_name ("ProcessorFaderFrame"); + } + break; + + case PostFader: + _event_box.set_name ("ProcessorPostFader"); + if (_visual_state == Gtk::STATE_NORMAL) { + _frame.set_name ("ProcessorPostFaderFrame"); + } + break; + } + + switch (_visual_state) { + case Gtk::STATE_NORMAL: + /* _frame has been set up above */ + _event_box.set_state (Gtk::STATE_NORMAL); + break; + case Gtk::STATE_SELECTED: + _frame.set_name ("ProcessorFrameSelected"); + /* don't change the background of the box when it is selected */ + _event_box.set_state (Gtk::STATE_NORMAL); + break; + case Gtk::STATE_ACTIVE: + _frame.set_name ("ProcessorFrameActiveSend"); + _event_box.set_state (Gtk::STATE_ACTIVE); + break; + default: + break; + } +} + + boost::shared_ptr ProcessorEntry::processor () const { @@ -217,13 +299,17 @@ ProcessorEntry::name () const SendProcessorEntry::SendProcessorEntry (boost::shared_ptr s, Width w) : ProcessorEntry (s, w), _send (s), - _adjustment (0, 0, 1, 0.01, 0.1), + /* set the adjustment to a gain of 0dB so that the fader's default value is right */ + _adjustment (0.781787, 0, 1, 0.01, 0.1), _fader (_slider, &_adjustment, 0, false), _ignore_gain_change (false) { + _fader.set_name ("SendFader"); _fader.set_controllable (_send->amp()->gain_control ()); _vbox.pack_start (_fader); + _fader.show (); + _adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &SendProcessorEntry::gain_adjusted)); _send->amp()->gain_control()->Changed.connect (send_gain_connection, invalidator (*this), boost::bind (&SendProcessorEntry::show_gain, this), gui_context()); show_gain (); @@ -247,6 +333,12 @@ SendProcessorEntry::show_gain () _ignore_gain_change = true; _adjustment.set_value (value); _ignore_gain_change = false; + + stringstream s; + s.precision (1); + s.setf (ios::fixed, ios::floatfield); + s << accurate_coefficient_to_dB (_send->amp()->gain ()) << _("dB"); + _fader.set_tooltip_text (s.str ()); } } @@ -266,6 +358,88 @@ SendProcessorEntry::set_pixel_width (int p) _fader.set_fader_length (p); } +PluginInsertProcessorEntry::PluginInsertProcessorEntry (boost::shared_ptr p, Width w) + : ProcessorEntry (p, w) + , _plugin_insert (p) +{ + p->SplittingChanged.connect ( + _splitting_connection, invalidator (*this), ui_bind (&PluginInsertProcessorEntry::plugin_insert_splitting_changed, this), gui_context() + ); + + _splitting_icon.set_size_request (-1, 12); + + _vbox.pack_start (_splitting_icon); + _vbox.reorder_child (_splitting_icon, 0); + + plugin_insert_splitting_changed (); +} + +void +PluginInsertProcessorEntry::plugin_insert_splitting_changed () +{ + if (_plugin_insert->splitting ()) { + _splitting_icon.show (); + } else { + _splitting_icon.hide (); + } +} + +void +PluginInsertProcessorEntry::hide_things () +{ + plugin_insert_splitting_changed (); +} + +void +PluginInsertProcessorEntry::setup_visuals () +{ + switch (_position) { + case PreFader: + _splitting_icon.set_name ("ProcessorPreFader"); + break; + + case Fader: + _splitting_icon.set_name ("ProcessorFader"); + break; + + case PostFader: + _splitting_icon.set_name ("ProcessorPostFader"); + break; + } + + ProcessorEntry::setup_visuals (); +} + +bool +PluginInsertProcessorEntry::SplittingIcon::on_expose_event (GdkEventExpose* ev) +{ + cairo_t* cr = gdk_cairo_create (get_window()->gobj()); + + cairo_set_line_width (cr, 1); + + double const width = ev->area.width; + double const height = ev->area.height; + + Gdk::Color const bg = get_style()->get_bg (STATE_NORMAL); + cairo_set_source_rgb (cr, bg.get_red_p (), bg.get_green_p (), bg.get_blue_p ()); + + cairo_rectangle (cr, 0, 0, width, height); + cairo_fill (cr); + + Gdk::Color const fg = get_style()->get_fg (STATE_NORMAL); + cairo_set_source_rgb (cr, fg.get_red_p (), fg.get_green_p (), fg.get_blue_p ()); + + cairo_move_to (cr, width * 0.3, height); + cairo_line_to (cr, width * 0.3, height * 0.5); + cairo_line_to (cr, width * 0.7, height * 0.5); + cairo_line_to (cr, width * 0.7, height); + cairo_move_to (cr, width * 0.5, height * 0.5); + cairo_line_to (cr, width * 0.5, 0); + cairo_stroke (cr); + + return true; +} + ProcessorBox::ProcessorBox (ARDOUR::Session* sess, boost::function get_plugin_selector, RouteRedirectSelection& rsel, MixerStrip* parent, bool owner_is_mixer) : _parent_strip (parent) @@ -287,9 +461,10 @@ ProcessorBox::ProcessorBox (ARDOUR::Session* sess, boost::functionDeliveryChanged.connect ( + _mixer_strip_connections, invalidator (*this), ui_bind (&ProcessorBox::mixer_strip_delivery_changed, this, _1), gui_context () + ); + } } ProcessorBox::~ProcessorBox () @@ -316,15 +500,23 @@ ProcessorBox::set_route (boost::shared_ptr r) return; } - connections.drop_connections(); + _route_connections.drop_connections(); /* new route: any existing block on processor redisplay must be meaningless */ no_processor_redisplay = false; _route = r; - _route->processors_changed.connect (connections, invalidator (*this), ui_bind (&ProcessorBox::route_processors_changed, this, _1), gui_context()); - _route->DropReferences.connect (connections, invalidator (*this), boost::bind (&ProcessorBox::route_going_away, this), gui_context()); - _route->PropertyChanged.connect (connections, invalidator (*this), ui_bind (&ProcessorBox::route_property_changed, this, _1), gui_context()); + _route->processors_changed.connect ( + _route_connections, invalidator (*this), ui_bind (&ProcessorBox::route_processors_changed, this, _1), gui_context() + ); + + _route->DropReferences.connect ( + _route_connections, invalidator (*this), boost::bind (&ProcessorBox::route_going_away, this), gui_context() + ); + + _route->PropertyChanged.connect ( + _route_connections, invalidator (*this), ui_bind (&ProcessorBox::route_property_changed, this, _1), gui_context() + ); redisplay_processors (); } @@ -446,13 +638,13 @@ ProcessorBox::show_processor_menu (gint arg) processor_menu = build_processor_menu (); } - Gtk::MenuItem* plugin_menu_item = dynamic_cast(ActionManager::get_widget("/processormenu/newplugin")); + Gtk::MenuItem* plugin_menu_item = dynamic_cast(ActionManager::get_widget("/ProcessorMenu/newplugin")); if (plugin_menu_item) { plugin_menu_item->set_submenu (*_get_plugin_selector()->plugin_menu()); } - Gtk::MenuItem* aux_menu_item = dynamic_cast(ActionManager::get_widget("/processormenu/newaux")); + Gtk::MenuItem* aux_menu_item = dynamic_cast(ActionManager::get_widget("/ProcessorMenu/newaux")); if (aux_menu_item) { Menu* m = build_possible_aux_menu(); @@ -515,7 +707,7 @@ ProcessorBox::processor_key_release_event (GdkEventKey *ev) int x, y; processor_display.get_pointer (x, y); - pair const pointer = processor_display.get_child_at_position (x, y); + pair const pointer = processor_display.get_child_at_position (y); if (pointer.first) { targets.push_back (pointer.first->processor ()); @@ -606,7 +798,7 @@ ProcessorBox::processor_button_press_event (GdkEventButton *ev, ProcessorEntry* if (_session->engine().connected()) { /* XXX giving an error message here is hard, because we may be in the midst of a button press */ - edit_processor (processor); + toggle_edit_processor (processor); } ret = true; @@ -683,11 +875,8 @@ ProcessorBox::processor_button_release_event (GdkEventButton *ev, ProcessorEntry Menu * ProcessorBox::build_processor_menu () { - processor_menu = dynamic_cast(ActionManager::get_widget("/processormenu") ); + processor_menu = dynamic_cast(ActionManager::get_widget("/ProcessorMenu") ); processor_menu->set_name ("ArdourContextMenu"); - - show_all_children(); - return processor_menu; } @@ -765,18 +954,22 @@ ProcessorBox::weird_plugin_dialog (Plugin& p, Route::ProcessorStreams streams) text += _("\nThis plugin has:\n"); if (has_midi) { - text += string_compose("\t%1 ", p.get_info()->n_inputs.n_midi()) + _("MIDI input(s)\n"); + uint32_t const n = p.get_info()->n_inputs.n_midi (); + text += string_compose (ngettext ("\t%1 MIDI input\n", "\t%1 MIDI inputs\n", n), n); } if (has_audio) { - text += string_compose("\t%1 ", p.get_info()->n_inputs.n_audio()) + _("audio input(s)\n"); + uint32_t const n = p.get_info()->n_inputs.n_audio (); + text += string_compose (ngettext ("\t%1 audio input\n", "\t%1 audio inputs\n", n), n); } - text += _("\nBut at the insertion point, there are:\n"); + text += _("\nbut at the insertion point, there are:\n"); if (has_midi) { - text += string_compose("\t%1 ", streams.count.n_midi()) + _("MIDI channel(s)\n"); + uint32_t const n = streams.count.n_midi (); + text += string_compose (ngettext ("\t%1 MIDI channel\n", "\t%1 MIDI channels\n", n), n); } if (has_audio) { - text += string_compose("\t%1 ", streams.count.n_audio()) + _("audio channel(s)\n"); + uint32_t const n = streams.count.n_audio (); + text += string_compose (ngettext ("\t%1 audio channel\n", "\t%1 audio channels\n", n), n); } text += string_compose (_("\n%1 is unable to insert this plugin here.\n"), PROGRAM_NAME); @@ -796,14 +989,15 @@ ProcessorBox::weird_plugin_dialog (Plugin& p, Route::ProcessorStreams streams) void ProcessorBox::choose_insert () { - boost::shared_ptr processor (new PortInsert (*_session, _route->mute_master())); + boost::shared_ptr processor (new PortInsert (*_session, _route->pannable(), _route->mute_master())); _route->add_processor (processor, _placement); } +/* Caller must not hold process lock */ void ProcessorBox::choose_send () { - boost::shared_ptr send (new Send (*_session, _route->mute_master())); + boost::shared_ptr send (new Send (*_session, _route->pannable(), _route->mute_master())); /* make an educated guess at the initial number of outputs for the send */ ChanCount outs = (_session->master_out()) @@ -812,6 +1006,7 @@ ProcessorBox::choose_send () /* XXX need processor lock on route */ try { + Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock()); send->output()->ensure_io (outs, false, this); } catch (AudioEngine::PortRegistrationFailure& err) { error << string_compose (_("Cannot set up new send: %1"), err.what()) << endmsg; @@ -826,7 +1021,7 @@ ProcessorBox::choose_send () */ IOSelectorWindow *ios = new IOSelectorWindow (_session, send->output(), true); - ios->show_all (); + ios->show (); /* keep a reference to the send so it doesn't get deleted while the IOSelectorWindow is doing its stuff @@ -938,8 +1133,6 @@ ProcessorBox::redisplay_processors () _route->foreach_processor (sigc::mem_fun (*this, &ProcessorBox::add_processor_to_display)); - build_processor_tooltip (processor_eventbox, _("Inserts, sends & plugins:")); - for (list::iterator i = _processor_window_proxies.begin(); i != _processor_window_proxies.end(); ++i) { (*i)->marked = false; } @@ -955,12 +1148,14 @@ ProcessorBox::redisplay_processors () if (!(*i)->marked) { ARDOUR_UI::instance()->remove_window_proxy (*i); - _processor_window_proxies.erase (i); delete *i; + _processor_window_proxies.erase (i); } i = j; } + + setup_entry_positions (); } /** Add a ProcessorWindowProxy for a processor to our list, if that processor does @@ -1008,6 +1203,17 @@ ProcessorBox::maybe_add_processor_to_ui_list (boost::weak_ptr w) w); wp->marked = true; + + /* if the processor already has an existing UI, + note that so that we don't recreate it + */ + + void* existing_ui = p->get_ui (); + + if (existing_ui) { + wp->set (static_cast(existing_ui)); + } + _processor_window_proxies.push_back (wp); ARDOUR_UI::instance()->add_window_proxy (wp); } @@ -1022,12 +1228,16 @@ ProcessorBox::add_processor_to_display (boost::weak_ptr p) } boost::shared_ptr send = boost::dynamic_pointer_cast (processor); + boost::shared_ptr plugin_insert = boost::dynamic_pointer_cast (processor); ProcessorEntry* e = 0; if (send) { e = new SendProcessorEntry (send, _width); + } else if (plugin_insert) { + e = new PluginInsertProcessorEntry (plugin_insert, _width); } else { e = new ProcessorEntry (processor, _width); } + e->set_pixel_width (get_allocation().get_width()); processor_display.add_child (e); } @@ -1051,6 +1261,27 @@ void ProcessorBox::reordered () { compute_processor_sort_keys (); + setup_entry_positions (); +} + +void +ProcessorBox::setup_entry_positions () +{ + list children = processor_display.children (); + bool pre_fader = true; + + for (list::iterator i = children.begin(); i != children.end(); ++i) { + if (boost::dynamic_pointer_cast((*i)->processor())) { + pre_fader = false; + (*i)->set_position (ProcessorEntry::Fader); + } else { + if (pre_fader) { + (*i)->set_position (ProcessorEntry::PreFader); + } else { + (*i)->set_position (ProcessorEntry::PostFader); + } + } + } } void @@ -1064,32 +1295,42 @@ ProcessorBox::compute_processor_sort_keys () } if (_route->reorder_processors (our_processors)) { + /* Reorder failed, so report this to the user. As far as I can see this must be done + in an idle handler: it seems that the redisplay_processors() that happens below destroys + widgets that were involved in the drag-and-drop on the processor list, which causes problems + when the drag is torn down after this handler function is finished. + */ + Glib::signal_idle().connect_once (sigc::mem_fun (*this, &ProcessorBox::report_failed_reorder)); + } +} - /* reorder failed, so redisplay */ - - redisplay_processors (); - - /* now tell them about the problem */ - - ArdourDialog dialog (_("Plugin Incompatibility")); - Label label; - - label.set_text (_("\ +void +ProcessorBox::report_failed_reorder () +{ + /* reorder failed, so redisplay */ + + redisplay_processors (); + + /* now tell them about the problem */ + + ArdourDialog dialog (_("Plugin Incompatibility")); + Label label; + + label.set_text (_("\ You cannot reorder these plugins/sends/inserts\n\ in that way because the inputs and\n\ outputs will not work correctly.")); - dialog.get_vbox()->set_border_width (12); - dialog.get_vbox()->pack_start (label); - dialog.add_button (Stock::OK, RESPONSE_ACCEPT); - - dialog.set_name (X_("PluginIODialog")); - dialog.set_position (Gtk::WIN_POS_MOUSE); - dialog.set_modal (true); - dialog.show_all (); - - dialog.run (); - } + dialog.get_vbox()->set_border_width (12); + dialog.get_vbox()->pack_start (label); + dialog.add_button (Stock::OK, RESPONSE_ACCEPT); + + dialog.set_name (X_("PluginIODialog")); + dialog.set_position (Gtk::WIN_POS_MOUSE); + dialog.set_modal (true); + dialog.show_all (); + + dialog.run (); } void @@ -1373,7 +1614,7 @@ ProcessorBox::paste_processor_state (const XMLNodeList& nlist, boost::shared_ptr XMLNode n (**niter); Send::make_unique (n, *_session); - Send* s = new Send (*_session, _route->mute_master()); + Send* s = new Send (*_session, _route->pannable(), _route->mute_master()); if (s->set_state (n, Stateful::loading_state_version)) { delete s; return; @@ -1395,6 +1636,14 @@ ProcessorBox::paste_processor_state (const XMLNodeList& nlist, boost::shared_ptr p.reset (r); + } else if (type->value() == "port") { + + XMLNode n (**niter); + p.reset (new PortInsert (*_session, _route->pannable (), _route->mute_master ())); + if (p->set_state (n, Stateful::loading_state_version)) { + return; + } + } else { /* XXX its a bit limiting to assume that everything else is a plugin. @@ -1548,9 +1797,10 @@ ProcessorBox::one_processor_can_be_edited () } void -ProcessorBox::edit_processor (boost::shared_ptr processor) +ProcessorBox::toggle_edit_processor (boost::shared_ptr processor) { boost::shared_ptr send; + boost::shared_ptr internal_send; boost::shared_ptr retrn; boost::shared_ptr plugin_insert; boost::shared_ptr port_insert; @@ -1563,34 +1813,40 @@ ProcessorBox::edit_processor (boost::shared_ptr processor) } } - if ((send = boost::dynamic_pointer_cast (processor)) != 0) { + if (boost::dynamic_pointer_cast (processor)) { + + _parent_strip->revert_to_default_display (); + + } else if ((internal_send = boost::dynamic_pointer_cast (processor)) != 0) { if (!_session->engine().connected()) { return; } -#ifdef OLD_SEND_EDITING - SendUIWindow *send_ui; + if (_parent_strip) { + if (boost::dynamic_pointer_cast (_parent_strip->current_delivery()) == internal_send) { + _parent_strip->revert_to_default_display (); + } else { + _parent_strip->show_send (internal_send); + } + } - Window* w = get_processor_ui (send); - if (w == 0) { - send_ui = new SendUIWindow (send, _session); - send_ui->set_title (send->name()); - set_processor_ui (send, send_ui); + } else if ((send = boost::dynamic_pointer_cast (processor)) != 0) { - } else { - send_ui = dynamic_cast (w); + if (!_session->engine().connected()) { + return; } - gidget = send_ui; -#else - if (_parent_strip) { - _parent_strip->show_send (send); - } -#endif + SendUIWindow* w = new SendUIWindow (send, _session); + w->show (); } else if ((retrn = boost::dynamic_pointer_cast (processor)) != 0) { + if (boost::dynamic_pointer_cast (retrn)) { + /* no GUI for these */ + return; + } + if (!_session->engine().connected()) { return; } @@ -1661,7 +1917,7 @@ ProcessorBox::edit_processor (boost::shared_ptr processor) if (gidget) { if (gidget->is_visible()) { - gidget->get_window()->raise (); + gidget->hide (); } else { gidget->show_all (); gidget->present (); @@ -1672,7 +1928,7 @@ ProcessorBox::edit_processor (boost::shared_ptr processor) void ProcessorBox::register_actions () { - Glib::RefPtr popup_act_grp = Gtk::ActionGroup::create(X_("processormenu")); + Glib::RefPtr popup_act_grp = Gtk::ActionGroup::create(X_("ProcessorMenu")); Glib::RefPtr act; /* new stuff */ @@ -1905,7 +2161,7 @@ ProcessorBox::rb_edit () return; } - _current_processor_box->for_selected_processors (&ProcessorBox::edit_processor); + _current_processor_box->for_selected_processors (&ProcessorBox::toggle_edit_processor); } void @@ -2003,6 +2259,9 @@ void ProcessorBox::set_processor_ui (boost::shared_ptr p, Gtk::Window* w) { list::iterator i = _processor_window_proxies.begin (); + + p->set_ui (w); + while (i != _processor_window_proxies.end()) { boost::shared_ptr t = (*i)->processor().lock (); if (t && t == p) { @@ -2019,6 +2278,36 @@ ProcessorBox::set_processor_ui (boost::shared_ptr p, Gtk::Window* w) assert (false); } +void +ProcessorBox::mixer_strip_delivery_changed (boost::weak_ptr w) +{ + boost::shared_ptr d = w.lock (); + if (!d) { + return; + } + + list children = processor_display.children (); + list::const_iterator i = children.begin(); + while (i != children.end() && (*i)->processor() != d) { + ++i; + } + + if (i == children.end()) { + processor_display.set_active (0); + } else { + processor_display.set_active (*i); + } +} + +void +ProcessorBox::hide_things () +{ + list c = processor_display.children (); + for (list::iterator i = c.begin(); i != c.end(); ++i) { + (*i)->hide_things (); + } +} + ProcessorWindowProxy::ProcessorWindowProxy ( string const & name, XMLNode const * node, @@ -2042,5 +2331,6 @@ ProcessorWindowProxy::show () return; } - _processor_box->edit_processor (p); + _processor_box->toggle_edit_processor (p); } +