the big Route structure refactor. !!!! THIS WILL ***NOT LOAD*** PRIOR 3.0 or 2.X...
authorPaul Davis <paul@linuxaudiosystems.com>
Tue, 9 Jun 2009 20:21:19 +0000 (20:21 +0000)
committerPaul Davis <paul@linuxaudiosystems.com>
Tue, 9 Jun 2009 20:21:19 +0000 (20:21 +0000)
git-svn-id: svn://localhost/ardour2/branches/3.0@5137 d708f5d6-7413-0410-9779-e7cbd77b26cf

77 files changed:
gtk2_ardour/actions.cc
gtk2_ardour/ardour_ui.cc
gtk2_ardour/ardour_ui.h
gtk2_ardour/audio_time_axis.cc
gtk2_ardour/automation_time_axis.cc
gtk2_ardour/editor_route_list.cc
gtk2_ardour/export_channel_selector.cc
gtk2_ardour/gain_meter.cc
gtk2_ardour/gain_meter.h
gtk2_ardour/io_selector.cc
gtk2_ardour/io_selector.h
gtk2_ardour/midi_time_axis.cc
gtk2_ardour/mixer_strip.cc
gtk2_ardour/mixer_strip.h
gtk2_ardour/panner_ui.cc
gtk2_ardour/panner_ui.h
gtk2_ardour/port_group.cc
gtk2_ardour/port_group.h
gtk2_ardour/processor_box.cc
gtk2_ardour/processor_box.h
gtk2_ardour/return_ui.cc
gtk2_ardour/route_params_ui.cc
gtk2_ardour/route_time_axis.cc
gtk2_ardour/route_ui.cc
gtk2_ardour/route_ui.h
gtk2_ardour/send_ui.cc
gtk2_ardour/session_option_editor.cc
gtk2_ardour/sfdb_ui.cc
libs/ardour/SConscript
libs/ardour/amp.cc
libs/ardour/ardour/amp.h
libs/ardour/ardour/automatable.h
libs/ardour/ardour/click.h
libs/ardour/ardour/delivery.h
libs/ardour/ardour/io.h
libs/ardour/ardour/io_processor.h
libs/ardour/ardour/meter.h
libs/ardour/ardour/mute_master.h [new file with mode: 0644]
libs/ardour/ardour/panner.h
libs/ardour/ardour/port_insert.h
libs/ardour/ardour/processor.h
libs/ardour/ardour/rc_configuration_vars.h
libs/ardour/ardour/return.h
libs/ardour/ardour/route.h
libs/ardour/ardour/send.h
libs/ardour/ardour/session.h
libs/ardour/audio_diskstream.cc
libs/ardour/audio_track.cc
libs/ardour/audioengine.cc
libs/ardour/auditioner.cc
libs/ardour/automatable.cc
libs/ardour/delivery.cc
libs/ardour/diskstream.cc
libs/ardour/enums.cc
libs/ardour/io.cc
libs/ardour/io_processor.cc
libs/ardour/meter.cc
libs/ardour/midi_diskstream.cc
libs/ardour/midi_track.cc
libs/ardour/mute_master.cc [new file with mode: 0644]
libs/ardour/panner.cc
libs/ardour/port_insert.cc
libs/ardour/processor.cc
libs/ardour/return.cc
libs/ardour/route.cc
libs/ardour/route_group.cc
libs/ardour/send.cc
libs/ardour/session.cc
libs/ardour/session_click.cc
libs/ardour/session_state.cc
libs/ardour/session_transport.cc
libs/ardour/track.cc
libs/ardour/wscript
libs/gtkmm2ext/gtkmm2ext/barcontroller.h
libs/midi++2/midi.cc
libs/surfaces/control_protocol/control_protocol.cc
wscript

index 74daa23a9a1495cf9dac5a07a39122e9a6856e79..a39283c977390fe3eaa98a7eecb2586a21836a0a 100644 (file)
@@ -324,7 +324,7 @@ ActionManager::set_sensitive (vector<RefPtr<Action> >& actions, bool state)
 void
 ActionManager::uncheck_toggleaction (const char * name)
 {
-       char *last_slash = strrchr (name, '/');
+       const char *last_slash = strrchr (name, '/');
 
        if (last_slash == 0) {
                fatal << string_compose (_("programmer error: %1 %2"), X_("illegal toggle action name"), name) << endmsg;
@@ -339,7 +339,7 @@ ActionManager::uncheck_toggleaction (const char * name)
        memcpy (group_name, name + 10, len);
        group_name[len] = '\0';
 
-       char* action_name = last_slash + 1;
+       const char* action_name = last_slash + 1;
 
         RefPtr<Action> act = get_action (group_name, action_name);
        if (act) {
index 0af0a88e11a7703c157b95ff35a46dae2fac27b0..0b9b9f1f746c1f5ec2c806b32706fe56ac5fa501 100644 (file)
@@ -1835,44 +1835,6 @@ ARDOUR_UI::stop_blinking ()
        }
 }
 
-void
-ARDOUR_UI::name_io_setup (AudioEngine& engine, 
-                         string& buf,
-                         IO& io,
-                         bool in)
-{
-       vector<string> connections;
-
-       if (in) {
-               if (io.n_inputs().n_total() == 0) {
-                       buf = _("none");
-                       return;
-               }
-               
-               /* XXX we're not handling multiple ports yet. */
-
-               if (io.input(0)->get_connections(connections) == 0) {
-                       buf = _("off");
-               } else {
-                       buf = connections.front();
-               }
-
-       } else {
-
-               if (io.n_outputs().n_total() == 0) {
-                       buf = _("none");
-                       return;
-               }
-               
-               /* XXX we're not handling multiple ports yet. */
-
-               if (io.output(0)->get_connections(connections) == 0) {
-                       buf = _("off");
-               } else {
-                       buf = connections.front();
-               }
-       }
-}
 
 /** Ask the user for the name of a new shapshot and then take it.
  */
index 2c840324e02a5194c215d96cde3f0093fc8567f6..aae644dbec5477f9ecb76db2c272b275aa572a1a 100644 (file)
@@ -176,8 +176,6 @@ class ARDOUR_UI : public Gtkmm2ext::UI
        static sigc::signal<void>      SuperRapidScreenUpdate;
        static sigc::signal<void,nframes_t, bool, nframes_t> Clock;
 
-       void name_io_setup (ARDOUR::AudioEngine&, std::string&, ARDOUR::IO& io, bool in);
-
        XMLNode* editor_settings() const;
        XMLNode* mixer_settings () const;
        XMLNode* keyboard_settings () const;
index 6ce54f788210119078c3041ccb3def1e3d0723f4..8f0c25bdb00464bd94349f2a45672258ec64cda8 100644 (file)
@@ -37,6 +37,7 @@
 #include <gtkmm2ext/bindable_button.h>
 #include <gtkmm2ext/utils.h>
 
+#include "ardour/amp.h"
 #include "ardour/audio_diskstream.h"
 #include "ardour/audioplaylist.h"
 #include "ardour/event_type_map.h"
@@ -347,13 +348,14 @@ AudioTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool
                        return;
                }
 
-               boost::shared_ptr<AutomationTimeAxisView> gain_track(new AutomationTimeAxisView (_session,
-                               _route, _route, c,
-                               _editor,
-                               *this,
-                               false,
-                               parent_canvas,
-                               _route->describe_parameter(param)));
+               boost::shared_ptr<AutomationTimeAxisView> 
+                       gain_track(new AutomationTimeAxisView (_session,
+                                                              _route, _route->amp(), c,
+                                                              _editor,
+                                                              *this,
+                                                              false,
+                                                              parent_canvas,
+                                                              _route->amp()->describe_parameter(param)));
 
                add_automation_child(Evoral::Parameter(GainAutomation), gain_track, show);
 
@@ -396,11 +398,11 @@ AudioTimeAxisView::ensure_pan_views (bool show)
 
                        /* we don't already have an AutomationTimeAxisView for this parameter */
 
-                       std::string const name = _route->describe_parameter (pan_control->parameter ());
+                       std::string const name = _route->panner()->describe_parameter (pan_control->parameter ());
 
                        boost::shared_ptr<AutomationTimeAxisView> pan_track (
                                new AutomationTimeAxisView (_session,
-                                                           _route, _route, pan_control, 
+                                                           _route, _route->panner(), pan_control, 
                                                            _editor,
                                                            *this,
                                                            false,
index 78faf66944652dde94376979067c903a0269f686..e72c5add00d7d1dac68598d709aaa9fea7e9ed4e 100644 (file)
@@ -255,15 +255,20 @@ void
 AutomationTimeAxisView::set_automation_state (AutoState state)
 {
        if (!ignore_state_request) {
+               _automatable->set_parameter_automation_state (_control->parameter(), state);
+#if 0
                if (_route == _automatable) { // This is a time axis for route (not region) automation
                        _route->set_parameter_automation_state (_control->parameter(), state);
                }
 
                if (_control->list())
                        _control->alist()->set_automation_state(state);
+#endif
        }
-       if (_view)
+
+       if (_view) {
                _view->set_automation_state (state);
+       }
 }
 
 void
index 00b4a3656d400327a2f6f1b03e8a8701bfa2f9f8..964ee38712bad9ea4cd642dcb7213d9366da56f5 100644 (file)
@@ -67,10 +67,12 @@ Editor::handle_new_route (RouteList& routes)
                if (route->is_hidden()) {
                        continue;
                }
-               
-               if (route->default_type() == ARDOUR::DataType::AUDIO)
+
+               DataType dt = route->input()->default_type();
+
+               if (dt == ARDOUR::DataType::AUDIO)
                        tv = new AudioTimeAxisView (*this, *session, route, *track_canvas);
-               else if (route->default_type() == ARDOUR::DataType::MIDI)
+               else if (dt == ARDOUR::DataType::MIDI)
                        tv = new MidiTimeAxisView (*this, *session, route, *track_canvas);
                else
                        throw unknown_type();
index 2f66e58fe5fd0ac694d2899856b5994def0712c3..7b665a6087e709aef21a9baed4c785e4d23adfd9 100644 (file)
@@ -112,14 +112,14 @@ PortExportChannelSelector::fill_route_list ()
 
        /* Add master bus and then everything else */
        
-       ARDOUR::IO * master = session->master_out().get();
+       ARDOUR::IO* master = session->master_out()->output().get();
        channel_view.add_route (master);
        
        for (RouteList::iterator it = routes.begin(); it != routes.end(); ++it) {
-               if (it->get() == master) {
+               if ((*it)->output().get() == master) {
                        continue;
                }
-               channel_view.add_route (it->get());
+               channel_view.add_route ((*it)->output().get());
        }
        
        update_channel_count ();
@@ -261,27 +261,27 @@ PortExportChannelSelector::ChannelTreeView::set_config (ChannelConfigPtr c)
 }
 
 void
-PortExportChannelSelector::ChannelTreeView::add_route (ARDOUR::IO * route)
+PortExportChannelSelector::ChannelTreeView::add_route (ARDOUR::IO * io)
 {
        Gtk::TreeModel::iterator iter = route_list->append();
        Gtk::TreeModel::Row row = *iter;
 
        row[route_cols.selected] = false;
-       row[route_cols.name] = route->name();
-       row[route_cols.io] = route;
+       row[route_cols.name] = io->name();
+       row[route_cols.io] = io;
        
        /* Initialize port list */
        
        Glib::RefPtr<Gtk::ListStore> port_list = Gtk::ListStore::create (route_cols.port_cols);
        row[route_cols.port_list_col] = port_list;
        
-       uint32_t outs = route->n_outputs().n_audio();
+       uint32_t outs = io->n_ports().n_audio();
        for (uint32_t i = 0; i < outs; ++i) {
                iter = port_list->append();
                row = *iter;
                
                row[route_cols.port_cols.selected] = false;
-               row[route_cols.port_cols.port] = route->audio_output (i);
+               row[route_cols.port_cols.port] = io->audio (i);
                
                std::ostringstream oss;
                oss << "Out-" << (i + 1);
index 85e591a8ccbfab96b91861d96e4cb89f7f355dc0..045c93173e1da29aeaa52e243b6ea57315c596d6 100644 (file)
@@ -160,57 +160,58 @@ GainMeterBase::~GainMeterBase ()
 }
 
 void
-GainMeterBase::set_io (boost::shared_ptr<IO> io)
+GainMeterBase::set_controls (boost::shared_ptr<Route> r,
+                            boost::shared_ptr<PeakMeter> pm, 
+                            boost::shared_ptr<AutomationControl> gc,
+                            boost::shared_ptr<Automatable> gc_owner)
 {
        connections.clear ();
        
-       _io = io;
-       
-       if (!_io) {
+       if (!pm && !gc) {
                level_meter->set_meter (0);
                gain_slider->set_controllable (boost::shared_ptr<PBD::Controllable>());
+               _meter.reset ();
+               _gain_control.reset ();
+               _route.reset ();
                return;
        } 
 
-       level_meter->set_meter (&_io->peak_meter());
-       gain_slider->set_controllable (_io->gain_control());
-
-       boost::shared_ptr<Route> r;
-
-       if ((r = boost::dynamic_pointer_cast<Route> (_io)) != 0) {
+       _meter = pm;
+       _gain_control = gc;
+       _route = r;
 
-               if (!r->is_hidden()) {
-
-                       using namespace Menu_Helpers;
+       level_meter->set_meter (pm.get());
+       gain_slider->set_controllable (gc);
        
-                       gain_astate_menu.items().clear ();
-
-                       gain_astate_menu.items().push_back (MenuElem (_("Manual"), 
-                                                                     bind (mem_fun (*_io, &IO::set_parameter_automation_state),
-                                                                           Evoral::Parameter(GainAutomation), (AutoState) Off)));
-                       gain_astate_menu.items().push_back (MenuElem (_("Play"),
-                                                                     bind (mem_fun (*_io, &IO::set_parameter_automation_state),
-                                                                           Evoral::Parameter(GainAutomation), (AutoState) Play)));
-                       gain_astate_menu.items().push_back (MenuElem (_("Write"),
-                                                                     bind (mem_fun (*_io, &IO::set_parameter_automation_state),
-                                                                           Evoral::Parameter(GainAutomation), (AutoState) Write)));
-                       gain_astate_menu.items().push_back (MenuElem (_("Touch"),
-                                                                     bind (mem_fun (*_io, &IO::set_parameter_automation_state),
-                                                                           Evoral::Parameter(GainAutomation), (AutoState) Touch)));
-                       
-                       connections.push_back (gain_automation_style_button.signal_button_press_event().connect (mem_fun(*this, &GainMeterBase::gain_automation_style_button_event), false));
-                       connections.push_back (gain_automation_state_button.signal_button_press_event().connect (mem_fun(*this, &GainMeterBase::gain_automation_state_button_event), false));
-                       
-                       connections.push_back (r->gain_control()->alist()->automation_state_changed.connect (mem_fun(*this, &GainMeter::gain_automation_state_changed)));
-                       connections.push_back (r->gain_control()->alist()->automation_style_changed.connect (mem_fun(*this, &GainMeter::gain_automation_style_changed)));
-
-                       gain_automation_state_changed ();
-               }
+       if (!_route || !_route->is_hidden()) {
+               
+               using namespace Menu_Helpers;
+               
+               gain_astate_menu.items().clear ();
+               
+               gain_astate_menu.items().push_back (MenuElem (_("Manual"), 
+                                                             bind (mem_fun (*(gc_owner.get()), &Automatable::set_parameter_automation_state),
+                                                                   Evoral::Parameter(GainAutomation), (AutoState) Off)));
+               gain_astate_menu.items().push_back (MenuElem (_("Play"),
+                                                             bind (mem_fun (*(gc_owner.get()), &Automatable::set_parameter_automation_state),
+                                                                   Evoral::Parameter(GainAutomation), (AutoState) Play)));
+               gain_astate_menu.items().push_back (MenuElem (_("Write"),
+                                                             bind (mem_fun (*(gc_owner.get()), &Automatable::set_parameter_automation_state),
+                                                                   Evoral::Parameter(GainAutomation), (AutoState) Write)));
+               gain_astate_menu.items().push_back (MenuElem (_("Touch"),
+                                                             bind (mem_fun (*(gc_owner.get()), &Automatable::set_parameter_automation_state),
+                                                                   Evoral::Parameter(GainAutomation), (AutoState) Touch)));
+               
+               connections.push_back (gain_automation_style_button.signal_button_press_event().connect (mem_fun(*this, &GainMeterBase::gain_automation_style_button_event), false));
+               connections.push_back (gain_automation_state_button.signal_button_press_event().connect (mem_fun(*this, &GainMeterBase::gain_automation_state_button_event), false));
+               
+               connections.push_back (gc->alist()->automation_state_changed.connect (mem_fun(*this, &GainMeter::gain_automation_state_changed)));
+               connections.push_back (gc->alist()->automation_style_changed.connect (mem_fun(*this, &GainMeter::gain_automation_style_changed)));
+               
+               gain_automation_state_changed ();
        }
 
-       //cerr << "Connect " << this << " to gain change for " << _io->name() << endl;
-
-       connections.push_back (_io->gain_control()->Changed.connect (mem_fun(*this, &GainMeterBase::gain_changed)));
+       connections.push_back (gc->Changed.connect (mem_fun (*this, &GainMeterBase::gain_changed)));
 
        gain_changed ();
        show_gain ();
@@ -272,10 +273,8 @@ GainMeterBase::peak_button_release (GdkEventButton* ev)
        if (ev->button == 1 && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier|Keyboard::TertiaryModifier)) {
                ResetAllPeakDisplays ();
        } else if (ev->button == 1 && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
-               boost::shared_ptr<Route> r;
-
-               if ((r = boost::dynamic_pointer_cast<Route> (_io)) != 0) {
-                       ResetGroupPeakDisplays (r->mix_group());
+               if (_route) {
+                       ResetGroupPeakDisplays (_route->mix_group());
                }
        } else {
                reset_peak_display ();
@@ -287,12 +286,7 @@ GainMeterBase::peak_button_release (GdkEventButton* ev)
 void
 GainMeterBase::reset_peak_display ()
 {
-       boost::shared_ptr<Route> r;
-
-       if ((r = boost::dynamic_pointer_cast<Route> (_io)) != 0) {
-               r->peak_meter().reset_max();
-       }
-
+       _meter->reset_max();
        level_meter->clear_meters();
        max_peak = -INFINITY;
        peak_display.set_label (_("-Inf"));
@@ -302,13 +296,9 @@ GainMeterBase::reset_peak_display ()
 void
 GainMeterBase::reset_group_peak_display (RouteGroup* group)
 {
-       boost::shared_ptr<Route> r;
-       
-       if ((r = boost::dynamic_pointer_cast<Route> (_io)) != 0) {
-               if (group == r->mix_group()) {
-                       reset_peak_display ();
+       if (_route && group == _route->mix_group()) {
+               reset_peak_display ();
                }
-       }
 }
 
 void
@@ -354,7 +344,7 @@ GainMeterBase::gain_activated ()
 
                f = min (f, 6.0f);
 
-               _io->gain_control()->set_value (dB_to_coefficient(f));
+               _gain_control->set_value (dB_to_coefficient(f));
 
                if (gain_display.has_focus()) {
                        PublicEditor::instance().reset_focus();
@@ -384,7 +374,7 @@ GainMeterBase::gain_adjusted ()
        //cerr << this << " for " << _io->name() << " GAIN ADJUSTED\n";
        if (!ignore_toggle) {
                //cerr << "Set GC\n";
-               _io->gain_control()->set_value (slider_position_to_gain (gain_adjustment.get_value()));
+               _gain_control->set_value (slider_position_to_gain (gain_adjustment.get_value()));
                //cerr << "Set GC OUT\n";
        }
        show_gain ();
@@ -393,7 +383,7 @@ GainMeterBase::gain_adjusted ()
 void
 GainMeterBase::effective_gain_display ()
 {
-       gfloat value = gain_to_slider_position (_io->effective_gain());
+       gfloat value = gain_to_slider_position (_gain_control->get_value());
        
        //cerr << this << " for " << _io->name() << " EGAIN = " << value
        //              << " AGAIN = " << gain_adjustment.get_value () << endl;
@@ -428,7 +418,7 @@ void
 GainMeterBase::update_gain_sensitive ()
 {
        static_cast<Gtkmm2ext::SliderController*>(gain_slider)->set_sensitive (
-                       !(_io->gain_control()->alist()->automation_state() & Play));
+                       !(_gain_control->alist()->automation_state() & Play));
 }
 
 
@@ -459,7 +449,7 @@ GainMeterBase::meter_press(GdkEventButton* ev)
 
        wait_for_release = false;
        
-       if ((_route = boost::dynamic_pointer_cast<Route>(_io)) == 0) {
+       if (!_route) {
                return FALSE;
        }
 
@@ -482,10 +472,10 @@ GainMeterBase::meter_press(GdkEventButton* ev)
                                }
                        }
 
-                       if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
+                       if (_route && (ev->button == 1 || Keyboard::is_button2_event (ev))) {
 
                                if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
-
+                                       
                                        /* Primary+Tertiary-click applies change to all routes */
 
                                        _session.begin_reversible_command (_("meter point change"));
@@ -534,10 +524,8 @@ GainMeterBase::meter_release(GdkEventButton* ev)
                if (wait_for_release){
                        wait_for_release = false;
                        
-                       boost::shared_ptr<Route> r;
-                       
-                       if ((r = boost::dynamic_pointer_cast<Route>(_io)) != 0) {
-                               set_meter_point (*r, old_meter_point);
+                       if (_route) {
+                               set_meter_point (*_route, old_meter_point);
                        }
                }
        }
@@ -566,9 +554,7 @@ GainMeterBase::set_mix_group_meter_point (Route& route, MeterPoint mp)
 void
 GainMeterBase::meter_point_clicked ()
 {
-       boost::shared_ptr<Route> r;
-
-       if ((r = boost::dynamic_pointer_cast<Route> (_io)) != 0) {
+       if (_route) {
                /* WHAT? */
        }
 }
@@ -576,14 +562,14 @@ GainMeterBase::meter_point_clicked ()
 gint
 GainMeterBase::start_gain_touch (GdkEventButton* ev)
 {
-       _io->gain_control()->start_touch ();
+       _gain_control->start_touch ();
        return FALSE;
 }
 
 gint
 GainMeterBase::end_gain_touch (GdkEventButton* ev)
 {
-       _io->gain_control()->stop_touch ();
+       _gain_control->stop_touch ();
        return FALSE;
 }
 
@@ -686,10 +672,10 @@ GainMeterBase::gain_automation_style_changed ()
 {
        switch (_width) {
        case Wide:
-               gain_automation_style_button.set_label (astyle_string(_io->gain_control()->alist()->automation_style()));
+               gain_automation_style_button.set_label (astyle_string(_gain_control->alist()->automation_style()));
                break;
        case Narrow:
-               gain_automation_style_button.set_label  (short_astyle_string(_io->gain_control()->alist()->automation_style()));
+               gain_automation_style_button.set_label  (short_astyle_string(_gain_control->alist()->automation_style()));
                break;
        }
 }
@@ -703,14 +689,14 @@ GainMeterBase::gain_automation_state_changed ()
 
        switch (_width) {
        case Wide:
-               gain_automation_state_button.set_label (astate_string(_io->gain_control()->alist()->automation_state()));
+               gain_automation_state_button.set_label (astate_string(_gain_control->alist()->automation_state()));
                break;
        case Narrow:
-               gain_automation_state_button.set_label (short_astate_string(_io->gain_control()->alist()->automation_state()));
+               gain_automation_state_button.set_label (short_astate_string(_gain_control->alist()->automation_state()));
                break;
        }
 
-       x = (_io->gain_control()->alist()->automation_state() != Off);
+       x = (_gain_control->alist()->automation_state() != Off);
        
        if (gain_automation_state_button.get_active() != x) {
                ignore_toggle = true;
@@ -811,8 +797,11 @@ GainMeter::GainMeter (Session& s)
        meter_metric_area.signal_expose_event().connect (mem_fun(*this, &GainMeter::meter_metrics_expose));
 }
 
-void
-GainMeter::set_io (boost::shared_ptr<IO> io)
+void 
+GainMeter::set_controls (boost::shared_ptr<Route> r,
+                        boost::shared_ptr<PeakMeter> meter,
+                        boost::shared_ptr<AutomationControl> gain_control,
+                        boost::shared_ptr<Automatable> gc_owner)
 {
        if (level_meter->get_parent()) {
                hbox.remove (*level_meter);
@@ -826,30 +815,17 @@ GainMeter::set_io (boost::shared_ptr<IO> io)
                fader_vbox->remove (gain_automation_state_button);
        }
 
-       GainMeterBase::set_io (io);
+       GainMeterBase::set_controls (r, meter, gain_control, gc_owner);
 
-       boost::shared_ptr<Route> r;
-
-       if ((r = boost::dynamic_pointer_cast<Route> (_io)) != 0) {
-               
-               /* 
-                  if we have a non-hidden route (ie. we're not the click or the auditioner), 
-                  pack some route-dependent stuff.
-               */
-
-               gain_display_box.pack_end (peak_display, true, true);
-               hbox.pack_end (*level_meter, true, true);
-
-               if (!r->is_hidden()) {
-                       fader_vbox->pack_start (gain_automation_state_button, false, false, 0);
-               }
-
-       } else {
-
-               /* we're managing a non-Route IO (e.g. Send) */
-
-               gain_display_box.pack_end (peak_display, true, true);
-               hbox.pack_end (*level_meter, true, true);
+       /* 
+          if we have a non-hidden route (ie. we're not the click or the auditioner), 
+          pack some route-dependent stuff.
+       */
+       
+       gain_display_box.pack_end (peak_display, true, true);
+       hbox.pack_end (*level_meter, true, true);
+       
+       if (!r->is_hidden()) {
                fader_vbox->pack_start (gain_automation_state_button, false, false, 0);
        }
 }
@@ -941,7 +917,7 @@ GainMeter::meter_metrics_expose (GdkEventExpose *ev)
 boost::shared_ptr<PBD::Controllable>
 GainMeterBase::get_controllable()
 {
-       return _io->gain_control();
+       return _gain_control;
 }
 
 
index ea817bcae2f21b8df22ba3f5aca678c4577f3fda..7feaf5c0e4192e150262b4452ede5f85d32ce36d 100644 (file)
@@ -46,6 +46,8 @@ namespace ARDOUR {
        class Session;
        class Route;
        class RouteGroup;
+       class PeakMeter;
+       class Automatable;
 }
 namespace Gtkmm2ext {
        class FastMeter;
@@ -62,8 +64,10 @@ class GainMeterBase : virtual public sigc::trackable
                       bool horizontal);
        virtual ~GainMeterBase ();
 
-       virtual void set_io (boost::shared_ptr<ARDOUR::IO>);
-       boost::shared_ptr<ARDOUR::IO> io() const { return _io; }
+       virtual void set_controls (boost::shared_ptr<ARDOUR::Route> route,
+                                  boost::shared_ptr<ARDOUR::PeakMeter> meter,
+                                  boost::shared_ptr<ARDOUR::AutomationControl> gain_control,
+                                  boost::shared_ptr<ARDOUR::Automatable> gc_owner);
 
        void update_gain_sensitive ();
        void update_meters ();
@@ -83,7 +87,9 @@ class GainMeterBase : virtual public sigc::trackable
   protected:
 
        friend class MixerStrip;
-       boost::shared_ptr<ARDOUR::IO> _io;
+       boost::shared_ptr<ARDOUR::Route> _route;
+       boost::shared_ptr<ARDOUR::PeakMeter> _meter;
+       boost::shared_ptr<ARDOUR::AutomationControl> _gain_control;
        ARDOUR::Session& _session;
        std::vector<sigc::connection> connections;
 
@@ -176,7 +182,10 @@ class GainMeter : public GainMeterBase, public Gtk::VBox
        GainMeter (ARDOUR::Session&);
        ~GainMeter () {}
 
-       void set_io (boost::shared_ptr<ARDOUR::IO>);
+       virtual void set_controls (boost::shared_ptr<ARDOUR::Route> route,
+                                  boost::shared_ptr<ARDOUR::PeakMeter> meter,
+                                  boost::shared_ptr<ARDOUR::AutomationControl> gain_control,
+                                  boost::shared_ptr<ARDOUR::Automatable> gc_owner);
 
        int get_gm_width ();
        void setup_meters (int len=0);
index fb7d946f7d75f6df25967b6fbbf70acb296d18a0..4333efd8ead27cd17d381550b8bfc935e211bdbf 100644 (file)
 using namespace ARDOUR;
 using namespace Gtk;
 
-IOSelector::IOSelector (ARDOUR::Session& session, boost::shared_ptr<ARDOUR::IO> io, bool in)
+IOSelector::IOSelector (ARDOUR::Session& session, boost::shared_ptr<ARDOUR::IO> io)
        : PortMatrix (session, io->default_type())
        , _io (io)
-       , _find_inputs_for_io_outputs (in)
 {
        /* signal flow from 0 to 1 */
+
+       _find_inputs_for_io_outputs = (_io->direction() == IO::Output);
+
        if (_find_inputs_for_io_outputs) {
                _other = 1;
                _ours = 0;
@@ -73,9 +75,7 @@ IOSelector::setup_ports (int dim)
        } else {
 
                _port_group->clear ();
-               _port_group->add_bundle (
-                       _find_inputs_for_io_outputs ? _io->bundle_for_outputs() : _io->bundle_for_inputs()
-                       );
+               _port_group->add_bundle (_io->bundle ());
        }
 
        _ports[dim].resume_signals ();
@@ -96,17 +96,9 @@ IOSelector::set_state (ARDOUR::BundleChannel c[2], bool s)
                        }
 
                        if (s) {
-                               if (!_find_inputs_for_io_outputs) {
-                                       _io->connect_input (f, *j, 0);
-                               } else {
-                                       _io->connect_output (f, *j, 0);
-                               }
+                               _io->connect (f, *j, 0);
                        } else {
-                               if (!_find_inputs_for_io_outputs) {
-                                       _io->disconnect_input (f, *j, 0);
-                               } else {
-                                       _io->disconnect_output (f, *j, 0);
-                               }
+                               _io->disconnect (f, *j, 0);
                        }
                }
        }
@@ -147,9 +139,9 @@ uint32_t
 IOSelector::n_io_ports () const
 {
        if (!_find_inputs_for_io_outputs) {
-               return _io->inputs().num_ports (_io->default_type());
+               return _io->n_ports().get (_io->default_type());
        } else {
-               return _io->outputs().num_ports (_io->default_type());
+               return _io->n_ports().get (_io->default_type());
        }
 }
 
@@ -161,27 +153,13 @@ IOSelector::add_channel (boost::shared_ptr<ARDOUR::Bundle> b)
        // The IO selector only works for single typed IOs
        const ARDOUR::DataType t = _io->default_type ();
 
-       if (!_find_inputs_for_io_outputs) {
-
-               try {
-                       _io->add_input_port ("", this);
-               }
-
-               catch (AudioEngine::PortRegistrationFailure& err) {
-                       MessageDialog msg (_("There are no more JACK ports available."));
-                       msg.run ();
-               }
-
-       } else {
-
-               try {
-                       _io->add_output_port ("", this);
-               }
-
-               catch (AudioEngine::PortRegistrationFailure& err) {
-                       MessageDialog msg (_("There are no more JACK ports available."));
-                       msg.run ();
-               }
+       try {
+               _io->add_port ("", this);
+       }
+       
+       catch (AudioEngine::PortRegistrationFailure& err) {
+               MessageDialog msg (_("There are no more JACK ports available."));
+               msg.run ();
        }
 }
 
@@ -193,11 +171,7 @@ IOSelector::remove_channel (ARDOUR::BundleChannel bc)
                return;
        }
        
-       if (_find_inputs_for_io_outputs) {
-               _io->remove_output_port (f, this);
-       } else {
-               _io->remove_input_port (f, this);
-       }
+       _io->remove_port (f, this);
 }
 
 bool
@@ -206,9 +180,9 @@ IOSelector::list_is_global (int dim) const
        return (dim == _other);
 }
 
-IOSelectorWindow::IOSelectorWindow (ARDOUR::Session& session, boost::shared_ptr<ARDOUR::IO> io, bool for_input, bool can_cancel)
+IOSelectorWindow::IOSelectorWindow (ARDOUR::Session& session, boost::shared_ptr<ARDOUR::IO> io, bool can_cancel)
        : ArdourDialog ("I/O selector")
-       , _selector (session, io, !for_input)
+       , _selector (session, io)
        , add_button (_("Add Port"))
        , disconnect_button (_("Disconnect All"))
        , ok_button (can_cancel ? _("OK"): _("Close"))
@@ -327,8 +301,8 @@ IOSelectorWindow::io_name_changed (void* src)
 }
 
 PortInsertUI::PortInsertUI (ARDOUR::Session& sess, boost::shared_ptr<ARDOUR::PortInsert> pi)
-       : input_selector (sess, pi->io(), true),
-         output_selector (sess, pi->io(), false)
+       : input_selector (sess, pi->input())
+       , output_selector (sess, pi->output())
 {
        output_selector.set_min_height_divisor (2);
        input_selector.set_min_height_divisor (2);
index 872fd5d7d65b4446be971584afb3117483f9f587..d6b00254be66378a4d97755ca2b7b94cb4b2a192 100644 (file)
@@ -30,7 +30,7 @@ namespace ARDOUR {
 class IOSelector : public PortMatrix
 {
   public:
-       IOSelector (ARDOUR::Session&, boost::shared_ptr<ARDOUR::IO>, bool);
+       IOSelector (ARDOUR::Session&, boost::shared_ptr<ARDOUR::IO>);
 
        void set_state (ARDOUR::BundleChannel c[2], bool);
        PortMatrixNode::State get_state (ARDOUR::BundleChannel c[2]) const;
@@ -74,7 +74,7 @@ class IOSelector : public PortMatrix
 class IOSelectorWindow : public ArdourDialog
 {
   public:
-       IOSelectorWindow (ARDOUR::Session&, boost::shared_ptr<ARDOUR::IO>, bool for_input, bool can_cancel = false);
+       IOSelectorWindow (ARDOUR::Session&, boost::shared_ptr<ARDOUR::IO>, bool can_cancel = false);
 
        IOSelector& selector() { return _selector; }
 
index 18786fe54a971a8dc506e47c4126cd0afb86ea82..c8cd5fe46466930c82018098c40f115607b7eff3 100644 (file)
@@ -506,13 +506,7 @@ MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool
        if (existing != _automation_tracks.end())
                return;
 
-       boost::shared_ptr<AutomationControl> c
-               = boost::dynamic_pointer_cast<AutomationControl>(_route->data().control(param));
-
-       if (!c) {
-               c = boost::dynamic_pointer_cast<AutomationControl>(_route->control_factory(param));
-               _route->add_control(c);
-       }
+       boost::shared_ptr<AutomationControl> c = _route->get_control (param);
        
        assert(c);
 
index fdc1e2f39bda81795326dce5219d7f850cee2898..13e077c12f73da95de849e04c4b3706ef8ecee11 100644 (file)
@@ -34,6 +34,7 @@
 #include <gtkmm2ext/bindable_button.h>
 
 #include "ardour/ardour.h"
+#include "ardour/amp.h"
 #include "ardour/session.h"
 #include "ardour/audioengine.h"
 #include "ardour/route.h"
@@ -71,20 +72,6 @@ sigc::signal<void,boost::shared_ptr<Route> > MixerStrip::SwitchIO;
 
 int MixerStrip::scrollbar_height = 0;
 
-#ifdef VARISPEED_IN_MIXER_STRIP
-static void 
-speed_printer (char buf[32], Gtk::Adjustment& adj, void* arg)
-{
-       float val = adj.get_value ();
-
-       if (val == 1.0) {
-               strcpy (buf, "1");
-       } else {
-               snprintf (buf, 32, "%.3f", val);
-       }
-}
-#endif 
-
 MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, bool in_mixer)
        : AxisView(sess)
        , RouteUI (sess, _("Mute"), _("Solo"), _("Record"))
@@ -99,8 +86,6 @@ MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, bool in_mixer)
        , bottom_button_table (1, 2)
        , meter_point_label (_("pre"))
        , comment_button (_("Comments"))
-       , speed_adjustment (1.0, 0.001, 4.0, 0.001, 0.1)
-       , speed_spinner (&speed_adjustment, "MixerStripSpeedBase", true)
                         
 {
        init ();
@@ -128,8 +113,6 @@ MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, boost::shared_ptr<Route> rt
        , bottom_button_table (1, 2)
        , meter_point_label (_("pre"))
        , comment_button (_("Comments"))
-       , speed_adjustment (1.0, 0.001, 4.0, 0.001, 0.1)
-       , speed_spinner (&speed_adjustment, "MixerStripSpeedBase", true)
                         
 {
        init ();
@@ -146,7 +129,6 @@ MixerStrip::init ()
        route_ops_menu = 0;
        ignore_comment_edit = false;
        ignore_toggle = false;
-       ignore_speed_adjustment = false;
        comment_window = 0;
        comment_area = 0;
        _width_owner = 0;
@@ -340,12 +322,6 @@ MixerStrip::set_route (boost::shared_ptr<Route> rt)
                button_table.remove (*show_sends_button);
        }
 
-#ifdef VARISPEED_IN_MIXER_STRIP
-       if (speed_frame->get_parent()) {
-               button_table.remove (*speed_frame);
-       }
-#endif
-
        RouteUI::set_route (rt);
 
        delete input_selector;
@@ -354,14 +330,16 @@ MixerStrip::set_route (boost::shared_ptr<Route> rt)
        delete output_selector;
        output_selector = 0;
 
-       if (_current_send) {
-               _current_send->set_metering (false);
+       boost::shared_ptr<Send> send;
+
+       if (_current_delivery && (send = boost::dynamic_pointer_cast<Send>(_current_delivery))) {
+               send->set_metering (false);
        }
 
-       _current_send.reset ();
+       _current_delivery = _route->main_outs ();
 
-       panners.set_io (rt);
-       gpm.set_io (rt);
+       panners.set_panner (rt->main_outs()->panner());
+       gpm.set_controls (rt, rt->shared_peak_meter(), rt->gain_control(), rt->amp());
        pre_processor_box.set_route (rt);
        post_processor_box.set_route (rt);
 
@@ -388,20 +366,6 @@ MixerStrip::set_route (boost::shared_ptr<Route> rt)
 
                connections.push_back (at->FreezeChange.connect (mem_fun(*this, &MixerStrip::map_frozen)));
 
-#ifdef VARISPEED_IN_MIXER_STRIP
-               speed_adjustment.signal_value_changed().connect (mem_fun(*this, &MixerStrip::speed_adjustment_changed));
-               
-               speed_frame.set_name ("BaseFrame");
-               speed_frame.set_shadow_type (Gtk::SHADOW_IN);
-               speed_frame.add (speed_spinner);
-               
-               speed_spinner.set_print_func (speed_printer, 0);
-
-               ARDOUR_UI::instance()->tooltips().set_tip (speed_spinner, _("Varispeed"));
-
-               button_table.attach (speed_frame, 0, 2, 5, 6);
-#endif /* VARISPEED_IN_MIXER_STRIP */
-
                button_table.attach (*rec_enable_button, 0, 2, 2, 3);
                rec_enable_button->show();
 
@@ -443,9 +407,9 @@ MixerStrip::set_route (boost::shared_ptr<Route> rt)
 
        connections.push_back (_route->meter_change.connect (
                        mem_fun(*this, &MixerStrip::meter_changed)));
-       connections.push_back (_route->input_changed.connect (
+       connections.push_back (_route->input()->changed.connect (
                        mem_fun(*this, &MixerStrip::input_changed)));
-       connections.push_back (_route->output_changed.connect (
+       connections.push_back (_route->output()->changed.connect (
                        mem_fun(*this, &MixerStrip::output_changed)));
        connections.push_back (_route->mix_group_changed.connect (
                        mem_fun(*this, &MixerStrip::mix_group_changed)));
@@ -458,8 +422,6 @@ MixerStrip::set_route (boost::shared_ptr<Route> rt)
        if (is_audio_track()) {
                connections.push_back (audio_track()->DiskstreamChanged.connect (
                        mem_fun(*this, &MixerStrip::diskstream_changed)));
-               connections.push_back (get_diskstream()->SpeedChanged.connect (
-                       mem_fun(*this, &MixerStrip::speed_changed)));
        }
 
        connections.push_back (_route->NameChanged.connect (
@@ -485,10 +447,6 @@ MixerStrip::set_route (boost::shared_ptr<Route> rt)
 
        panners.setup_pan ();
 
-       if (is_audio_track()) {
-               speed_changed ();
-       }
-
        update_diskstream_display ();
        update_input_display ();
        update_output_display ();
@@ -530,9 +488,6 @@ MixerStrip::set_route (boost::shared_ptr<Route> rt)
        comment_button.show();
        group_button.show();
        group_label.show();
-       speed_spinner.show();
-       speed_label.show();
-       speed_frame.show();
 
        show ();
 }
@@ -703,7 +658,7 @@ MixerStrip::output_press (GdkEventButton *ev)
                citems.push_back (MenuElem (_("Disconnect"), mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_output)));
                citems.push_back (SeparatorElem());
 
-               ARDOUR::BundleList current = _route->bundles_connected_to_outputs ();
+               ARDOUR::BundleList current = _route->output()->bundles_connected ();
 
                boost::shared_ptr<ARDOUR::BundleList> b = _session.bundles ();
                for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
@@ -712,7 +667,7 @@ MixerStrip::output_press (GdkEventButton *ev)
 
                boost::shared_ptr<ARDOUR::RouteList> routes = _session.get_routes ();
                for (ARDOUR::RouteList::const_iterator i = routes->begin(); i != routes->end(); ++i) {
-                       maybe_add_bundle_to_output_menu ((*i)->bundle_for_inputs(), current);
+                       maybe_add_bundle_to_output_menu ((*i)->input()->bundle(), current);
                }
 
                if (citems.size() == 2) {
@@ -734,7 +689,7 @@ void
 MixerStrip::edit_output_configuration ()
 {
        if (output_selector == 0) {
-               output_selector = new IOSelectorWindow (_session, _route, false);
+               output_selector = new IOSelectorWindow (_session, _route->output());
        } 
 
        if (output_selector->is_visible()) {
@@ -748,7 +703,7 @@ void
 MixerStrip::edit_input_configuration ()
 {
        if (input_selector == 0) {
-               input_selector = new IOSelectorWindow (_session, _route, true);
+               input_selector = new IOSelectorWindow (_session, _route->input());
        } 
 
        if (input_selector->is_visible()) {
@@ -784,7 +739,7 @@ MixerStrip::input_press (GdkEventButton *ev)
                citems.push_back (MenuElem (_("Disconnect"), mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_input)));
                citems.push_back (SeparatorElem());
 
-               ARDOUR::BundleList current = _route->bundles_connected_to_inputs ();
+               ARDOUR::BundleList current = _route->input()->bundles_connected ();
 
                boost::shared_ptr<ARDOUR::BundleList> b = _session.bundles ();
                for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
@@ -793,7 +748,7 @@ MixerStrip::input_press (GdkEventButton *ev)
 
                boost::shared_ptr<ARDOUR::RouteList> routes = _session.get_routes ();
                for (ARDOUR::RouteList::const_iterator i = routes->begin(); i != routes->end(); ++i) {
-                       maybe_add_bundle_to_input_menu ((*i)->bundle_for_outputs(), current);
+                       maybe_add_bundle_to_input_menu ((*i)->output()->bundle(), current);
                }
 
                if (citems.size() == 2) {
@@ -817,12 +772,12 @@ MixerStrip::bundle_input_toggled (boost::shared_ptr<ARDOUR::Bundle> c)
                return;
        }
 
-       ARDOUR::BundleList current = _route->bundles_connected_to_inputs ();
+       ARDOUR::BundleList current = _route->input()->bundles_connected ();
 
        if (std::find (current.begin(), current.end(), c) == current.end()) {
-               _route->connect_input_ports_to_bundle (c, this);
+               _route->input()->connect_ports_to_bundle (c, this);
        } else {
-               _route->disconnect_input_ports_from_bundle (c, this);
+               _route->input()->disconnect_ports_from_bundle (c, this);
        }
 }
 
@@ -833,12 +788,12 @@ MixerStrip::bundle_output_toggled (boost::shared_ptr<ARDOUR::Bundle> c)
                return;
        }
 
-       ARDOUR::BundleList current = _route->bundles_connected_to_outputs ();
+       ARDOUR::BundleList current = _route->output()->bundles_connected ();
 
        if (std::find (current.begin(), current.end(), c) == current.end()) {
-               _route->connect_output_ports_to_bundle (c, this);
+               _route->output()->connect_ports_to_bundle (c, this);
        } else {
-               _route->disconnect_output_ports_from_bundle (c, this);
+               _route->output()->disconnect_ports_from_bundle (c, this);
        }
 }
 
@@ -848,7 +803,7 @@ MixerStrip::maybe_add_bundle_to_input_menu (boost::shared_ptr<Bundle> b, ARDOUR:
        using namespace Menu_Helpers;
 
        if (b->ports_are_outputs() == false ||
-           route()->default_type() != b->type() ||
+           route()->input()->default_type() != b->type() ||
            b->nchannels() != _route->n_inputs().get (b->type ())) {
                
                return;
@@ -874,7 +829,7 @@ MixerStrip::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR
        using namespace Menu_Helpers;
 
        if (b->ports_are_inputs() == false ||
-           route()->default_type() != b->type() ||
+           route()->output()->default_type() != b->type() ||
            b->nchannels() != _route->n_outputs().get (b->type ())) {
                
                return;
@@ -938,7 +893,7 @@ MixerStrip::connect_to_pan ()
 void
 MixerStrip::update_input_display ()
 {
-       ARDOUR::BundleList const c = _route->bundles_connected_to_inputs ();
+       ARDOUR::BundleList const c = _route->input()->bundles_connected();
 
        if (c.size() > 1) {
                input_label.set_text (_("Inputs"));
@@ -960,7 +915,7 @@ MixerStrip::update_input_display ()
 void
 MixerStrip::update_output_display ()
 {
-       ARDOUR::BundleList const c = _route->bundles_connected_to_outputs ();
+       ARDOUR::BundleList const c = _route->output()->bundles_connected ();
 
        /* XXX: how do we represent >1 connected bundle? */
        if (c.size() > 1) {
@@ -1269,43 +1224,6 @@ MixerStrip::list_route_operations ()
        refresh_remote_control_menu();
 }
 
-
-void
-MixerStrip::speed_adjustment_changed ()
-{
-       /* since there is a usable speed adjustment, there has to be a diskstream */
-       if (!ignore_speed_adjustment) {
-               get_diskstream()->set_speed (speed_adjustment.get_value());
-       }
-}
-
-void
-MixerStrip::speed_changed ()
-{
-       Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &MixerStrip::update_speed_display));
-}
-
-void
-MixerStrip::update_speed_display ()
-{
-       float val;
-       
-       val = get_diskstream()->speed();
-
-       if (val != 1.0) {
-               speed_spinner.set_name ("MixerStripSpeedBaseNotOne");
-       } else {
-               speed_spinner.set_name ("MixerStripSpeedBase");
-       }
-
-       if (speed_adjustment.get_value() != val) {
-               ignore_speed_adjustment = true;
-               speed_adjustment.set_value (val);
-               ignore_speed_adjustment = false;
-       }
-}                      
-
-
 void
 MixerStrip::set_selected (bool yn)
 {
@@ -1383,12 +1301,10 @@ MixerStrip::map_frozen ()
                case AudioTrack::Frozen:
                        pre_processor_box.set_sensitive (false);
                        post_processor_box.set_sensitive (false);
-                       speed_spinner.set_sensitive (false);
                        break;
                default:
                        pre_processor_box.set_sensitive (true);
                        post_processor_box.set_sensitive (true);
-                       speed_spinner.set_sensitive (true);
                        // XXX need some way, maybe, to retoggle redirect editors
                        break;
                }
@@ -1499,8 +1415,6 @@ MixerStrip::meter_changed (void *src)
 void
 MixerStrip::switch_io (boost::shared_ptr<Route> target)
 {
-       boost::shared_ptr<IO> to_display;
-
        if (_route == target || _route->is_master()) {
                /* don't change the display for the target or the master bus */
                return;
@@ -1519,22 +1433,28 @@ MixerStrip::switch_io (boost::shared_ptr<Route> target)
                return;
        }
        
-       if (_current_send) {
-               _current_send->set_metering (false);
+       boost::shared_ptr<Send> send;
+
+       if (_current_delivery && (send = boost::dynamic_pointer_cast<Send>(_current_delivery))) {
+               send->set_metering (false);
        }
        
-       _current_send = _route->send_for (target);
+       _current_delivery = _route->send_for (target->input());
 
-       if (_current_send) {
-               to_display = _current_send->io();
+       if (_current_delivery) {
+               send = boost::dynamic_pointer_cast<Send>(_current_delivery);
+               send->set_metering (true);
+               _current_delivery->GoingAway.connect (mem_fun (*this, &MixerStrip::revert_to_default_display));
+               gain_meter().set_controls (_route, send->meter(), send->amp()->gain_control(), send->amp());
+               panner_ui().set_panner (_current_delivery->panner());
 
-               _current_send->set_metering (true);
-               _current_send->GoingAway.connect (mem_fun (*this, &MixerStrip::revert_to_default_display));
+       } else {
+               _current_delivery = _route->main_outs ();
+               gain_meter().set_controls (_route, _route->shared_peak_meter(), _route->gain_control(), _route->amp());
+               panner_ui().set_panner (_route->main_outs()->panner());
        }
        
-       gain_meter().set_io (to_display);
        gain_meter().setup_meters ();
-       panner_ui().set_io (to_display);
        panner_ui().setup_pan ();
 }
 
@@ -1544,14 +1464,17 @@ MixerStrip::revert_to_default_display ()
 {
        show_sends_button->set_active (false);
        
-       if (_current_send) {
-               _current_send->set_metering (false);
-               _current_send.reset();
+       boost::shared_ptr<Send> send;
+
+       if (_current_delivery && (send = boost::dynamic_pointer_cast<Send>(_current_delivery))) {
+               send->set_metering (false);
        }
+       
+       _current_delivery = _route->main_outs();
 
-       gain_meter().set_io (_route);
+       gain_meter().set_controls (_route, _route->shared_peak_meter(), _route->gain_control(), _route->amp());
        gain_meter().setup_meters ();
-       panner_ui().set_io (_route);
+       panner_ui().set_panner (_route->main_outs()->panner());
        panner_ui().setup_pan ();
 }
 
index f0cc4c67c67d5b94cc822c327c853c420c82b74d..43c2e197fd4ed4012d5154e2053a193e1c21d92e 100644 (file)
@@ -242,15 +242,6 @@ class MixerStrip : public RouteUI, public Gtk::EventBox
 
        void route_active_changed ();
 
-       /* speed control (for tracks only) */
-
-       Gtk::Adjustment    speed_adjustment;
-       Gtkmm2ext::ClickBox speed_spinner;
-       Gtk::Label         speed_label;
-       Gtk::Frame         speed_frame;
-
-       void speed_adjustment_changed ();
-       void speed_changed ();
        void name_changed ();
        void update_speed_display ();
        void map_frozen ();
@@ -263,7 +254,7 @@ class MixerStrip : public RouteUI, public Gtk::EventBox
        void engine_stopped();
 
        void switch_io (boost::shared_ptr<ARDOUR::Route>);
-       boost::shared_ptr<ARDOUR::Send> _current_send;
+       boost::shared_ptr<ARDOUR::Delivery> _current_delivery;
        void revert_to_default_display ();
 
        static int scrollbar_height;
index b35ebe5f22875d4d62fb2b928fcbb30550528afd..29c991a995a8e6c6141c6a952e29326c727cc732 100644 (file)
@@ -25,6 +25,7 @@
 #include <gtkmm2ext/barcontroller.h>
 #include "midi++/manager.h"
 #include "pbd/fastlog.h"
+#include "pbd/stacktrace.h"
 
 #include "ardour_ui.h"
 #include "panner_ui.h"
@@ -33,6 +34,7 @@
 #include "panner.h"
 #include "gui_thread.h"
 
+#include "ardour/delivery.h"
 #include "ardour/session.h"
 #include "ardour/panner.h"
 #include "ardour/route.h"
@@ -131,13 +133,8 @@ PannerUI::PannerUI (Session& s)
 }
   
 void
-PannerUI::set_io (boost::shared_ptr<IO> io)
+PannerUI::set_panner (boost::shared_ptr<Panner> p)
 {
-       if (io && !io->panner()) {
-               cerr << "PannerUI::set_io IO has no panners" << endl;
-               return;
-       }
-
        connections.clear ();
        
        delete pan_astyle_menu;
@@ -146,18 +143,18 @@ PannerUI::set_io (boost::shared_ptr<IO> io)
        delete pan_astate_menu;
        pan_astate_menu = 0;
                        
-       _io = io;
+       _panner = p;
+
        delete panner;
        panner = 0;
 
-       if (!_io) {
+       if (!_panner) {
                return;
        }
  
-       connections.push_back (_io->panner()->Changed.connect (mem_fun(*this, &PannerUI::panner_changed)));
-       connections.push_back (_io->panner()->LinkStateChanged.connect (mem_fun(*this, &PannerUI::update_pan_linkage)));
-       connections.push_back (_io->panner()->StateChanged.connect (mem_fun(*this, &PannerUI::update_pan_state)));
+       connections.push_back (_panner->Changed.connect (mem_fun(*this, &PannerUI::panner_changed)));
+       connections.push_back (_panner->LinkStateChanged.connect (mem_fun(*this, &PannerUI::update_pan_linkage)));
+       connections.push_back (_panner->StateChanged.connect (mem_fun(*this, &PannerUI::update_pan_state)));
  
        setup_pan ();
 
@@ -196,16 +193,16 @@ PannerUI::build_astate_menu ()
        }
 
        pan_astate_menu->items().push_back (MenuElem (_("Manual"), bind (
-                       mem_fun (_io->panner().get(), &Panner::set_automation_state),
+                       mem_fun (_panner.get(), &Panner::set_automation_state),
                        (AutoState) Off)));
        pan_astate_menu->items().push_back (MenuElem (_("Play"), bind (
-                       mem_fun (_io->panner().get(), &Panner::set_automation_state),
+                       mem_fun (_panner.get(), &Panner::set_automation_state),
                        (AutoState) Play)));
        pan_astate_menu->items().push_back (MenuElem (_("Write"), bind (
-                       mem_fun (_io->panner().get(), &Panner::set_automation_state),
+                       mem_fun (_panner.get(), &Panner::set_automation_state),
                        (AutoState) Write)));
        pan_astate_menu->items().push_back (MenuElem (_("Touch"), bind (
-                       mem_fun (_io->panner().get(), &Panner::set_automation_state),
+                       mem_fun (_panner.get(), &Panner::set_automation_state),
                        (AutoState) Touch)));
 
 }
@@ -242,7 +239,7 @@ bool
 PannerUI::panning_link_button_release (GdkEventButton* ev)
 {
        if (!ignore_toggle) {
-               _io->panner()->set_linked (!_io->panner()->linked());
+               _panner->set_linked (!_panner->linked());
        }
        return true;
 }
@@ -250,12 +247,12 @@ PannerUI::panning_link_button_release (GdkEventButton* ev)
 void
 PannerUI::panning_link_direction_clicked()
 {
-       switch (_io->panner()->link_direction()) {
+       switch (_panner->link_direction()) {
        case Panner::SameDirection:
-               _io->panner()->set_link_direction (Panner::OppositeDirection);
+               _panner->set_link_direction (Panner::OppositeDirection);
                break;
        default:
-               _io->panner()->set_link_direction (Panner::SameDirection);
+               _panner->set_link_direction (Panner::SameDirection);
                break;
        }
 }
@@ -265,7 +262,7 @@ PannerUI::update_pan_linkage ()
 {
        ENSURE_GUI_THREAD(mem_fun(*this, &PannerUI::update_pan_linkage));
        
-       bool x = _io->panner()->linked();
+       bool x = _panner->linked();
        bool bx = panning_link_button.get_active();
 
        if (x != bx) {
@@ -277,7 +274,7 @@ PannerUI::update_pan_linkage ()
 
        panning_link_direction_button.set_sensitive (x);
 
-       switch (_io->panner()->link_direction()) {
+       switch (_panner->link_direction()) {
        case Panner::SameDirection:
                panning_link_direction_button.set_image (*(manage (new Image (get_xpm ("forwardblarrow.xpm")))));
                break;
@@ -339,11 +336,16 @@ PannerUI::update_pan_state ()
 void
 PannerUI::setup_pan ()
 {
-       if (!_io || !_io->panner()) {
+       cerr << "Setup pan for " << _panner->name() << endl;
+       // PBD::stacktrace (cerr, 5);
+
+       if (!_panner) {
                return;
        }
 
-       uint32_t nouts = _io->n_outputs ().n_audio();
+       uint32_t nouts = _panner->nouts();
+
+       cerr << "\tnouts = " << nouts << endl;
 
        if (nouts == 0 || nouts == 1) {
 
@@ -364,7 +366,7 @@ PannerUI::setup_pan ()
        } else if (nouts == 2) {
 
                vector<Adjustment*>::size_type asz;
-               uint32_t npans = _io->panner()->npanners();
+               uint32_t npans = _panner->npanners();
 
                while (!pan_adjustments.empty()) {
                        delete pan_bars.back();
@@ -381,7 +383,7 @@ PannerUI::setup_pan ()
                        /* initialize adjustment with 0.0 (L) or 1.0 (R) for the first and second panners,
                           which serves as a default, otherwise use current value */
 
-                       rx = _io->panner()->pan_control( asz)->get_value();
+                       rx = _panner->pan_control( asz)->get_value();
 
                        if (npans == 1) {
                                x = 0.5;
@@ -395,20 +397,24 @@ PannerUI::setup_pan ()
 
                        pan_adjustments.push_back (new Adjustment (x, 0, 1.0, 0.005, 0.05));
                        bc = new PannerBar (*pan_adjustments[asz],
-                               boost::static_pointer_cast<PBD::Controllable>( _io->panner()->pan_control( asz )) );
+                               boost::static_pointer_cast<PBD::Controllable>( _panner->pan_control( asz )) );
 
                        /* now set adjustment with current value of panner, then connect the signals */
                        pan_adjustments.back()->set_value(rx);
                        pan_adjustments.back()->signal_value_changed().connect (bind (mem_fun(*this, &PannerUI::pan_adjustment_changed), (uint32_t) asz));
 
-                       _io->panner()->pan_control( asz )->Changed.connect (bind (mem_fun(*this, &PannerUI::pan_value_changed), (uint32_t) asz));
+                       _panner->pan_control( asz )->Changed.connect (bind (mem_fun(*this, &PannerUI::pan_value_changed), (uint32_t) asz));
 
                        
                        bc->set_name ("PanSlider");
                        bc->set_shadow_type (Gtk::SHADOW_NONE);
-
-                       bc->StartGesture.connect (bind (mem_fun (*_io, &IO::start_pan_touch), (uint32_t) asz));
-                       bc->StopGesture.connect (bind (mem_fun (*_io, &IO::end_pan_touch), (uint32_t) asz));
+                       
+                       boost::shared_ptr<AutomationControl> ac = _panner->pan_control (asz);
+                       
+                       if (asz) {
+                               bc->StartGesture.connect (mem_fun (*ac, &AutomationControl::start_touch));
+                               bc->StopGesture.connect (mem_fun (*ac, &AutomationControl::stop_touch));
+                       }
 
                        char buf[64];
                        snprintf (buf, sizeof (buf), _("panner for channel %zu"), asz + 1);
@@ -437,7 +443,7 @@ PannerUI::setup_pan ()
        } else {
 
                if (!panner) {
-                       panner = new Panner2d (_io->panner(), 61);
+                       panner = new Panner2d (_panner, 61);
                        panner->set_name ("MixerPanZone");
                        panner->show ();
  
@@ -446,9 +452,9 @@ PannerUI::setup_pan ()
                }
                
                update_pan_sensitive ();
-               panner->reset (_io->n_inputs().n_audio());
+               panner->reset (nouts);
                if (big_window) {
-                       big_window->reset (_io->n_inputs().n_audio());
+                       big_window->reset (_panner->npanners());
                }
                panner->set_size_request (-1, 61);
 
@@ -467,7 +473,7 @@ PannerUI::pan_button_event (GdkEventButton* ev, uint32_t which)
        case 1:
                if (panner && ev->type == GDK_2BUTTON_PRESS) {
                        if (!big_window) {
-                               big_window = new Panner2dWindow (panner->get_panner(), 400, _io->n_inputs().n_audio());
+                               big_window = new Panner2dWindow (_panner, 400, _panner->npanners());
                        }
                        big_window->show ();
                        return true;
@@ -502,7 +508,7 @@ PannerUI::build_pan_menu (uint32_t which)
        
        /* set state first, connect second */
 
-       (dynamic_cast<CheckMenuItem*> (&items.back()))->set_active (_io->panner()->streampanner(which).muted());
+       (dynamic_cast<CheckMenuItem*> (&items.back()))->set_active (_panner->streampanner(which).muted());
        (dynamic_cast<CheckMenuItem*> (&items.back()))->signal_toggled().connect
                (bind (mem_fun(*this, &PannerUI::pan_mute), which));
 
@@ -511,7 +517,7 @@ PannerUI::build_pan_menu (uint32_t which)
 
        /* set state first, connect second */
 
-       bypass_menu_item->set_active (_io->panner()->bypassed());
+       bypass_menu_item->set_active (_panner->bypassed());
        bypass_menu_item->signal_toggled().connect (mem_fun(*this, &PannerUI::pan_bypass_toggle));
 
        items.push_back (MenuElem (_("Reset"), bind (mem_fun (*this, &PannerUI::pan_reset), which)));
@@ -522,38 +528,38 @@ PannerUI::build_pan_menu (uint32_t which)
 void
 PannerUI::pan_mute (uint32_t which)
 {
-       StreamPanner& sp = _io->panner()->streampanner(which);
+       StreamPanner& sp = _panner->streampanner(which);
        sp.set_muted (!sp.muted());
 }
 
 void
 PannerUI::pan_bypass_toggle ()
 {
-       if (bypass_menu_item && (_io->panner()->bypassed() != bypass_menu_item->get_active())) {
-               _io->panner()->set_bypassed (!_io->panner()->bypassed());
+       if (bypass_menu_item && (_panner->bypassed() != bypass_menu_item->get_active())) {
+               _panner->set_bypassed (!_panner->bypassed());
        }
 }
 
 void
 PannerUI::pan_reset (uint32_t which)
 {
-       _io->panner()->reset_streampanner (which);
+       _panner->reset_streampanner (which);
 }
 
 void
 PannerUI::pan_reset_all ()
 {
-       _io->panner()->reset_to_default ();
+       _panner->reset_to_default ();
 }
 
 void
 PannerUI::effective_pan_display ()
 {
-       if (_io->panner()->empty()) {
+       if (_panner->empty()) {
                return;
        }
 
-       switch (_io->n_outputs().n_audio()) {
+       switch (_panner->nouts()) {
        case 0: 
        case 1:
                /* relax */
@@ -576,7 +582,7 @@ PannerUI::pan_changed (void *src)
                return;
        }
 
-       switch (_io->panner()->npanners()) {
+       switch (_panner->npanners()) {
        case 0:
                panning_link_direction_button.set_sensitive (false);
                panning_link_button.set_sensitive (false);
@@ -590,7 +596,7 @@ PannerUI::pan_changed (void *src)
                panning_link_button.set_sensitive (true);
        }
 
-       uint32_t nouts = _io->n_outputs().n_audio();
+       uint32_t nouts = _panner->nouts();
 
        switch (nouts) {
        case 0:
@@ -612,11 +618,11 @@ PannerUI::pan_changed (void *src)
 void
 PannerUI::pan_adjustment_changed (uint32_t which)
 {
-       if (!in_pan_update && which < _io->panner()->npanners()) {
+       if (!in_pan_update && which < _panner->npanners()) {
 
                float xpos;
                float val = pan_adjustments[which]->get_value ();
-               xpos = _io->panner()->pan_control( which )->get_value();
+               xpos = _panner->pan_control( which )->get_value();
 
                /* add a kinda-sorta detent for the middle */
                
@@ -633,7 +639,7 @@ PannerUI::pan_adjustment_changed (uint32_t which)
                
                if (!Panner::equivalent (val, xpos)) {
 
-                       _io->panner()->streampanner(which).set_position (val);
+                       _panner->streampanner(which).set_position (val);
                        /* XXX 
                           the panner objects have no access to the session,
                           so do this here. ick.
@@ -648,11 +654,11 @@ PannerUI::pan_value_changed (uint32_t which)
 {
        ENSURE_GUI_THREAD (bind (mem_fun(*this, &PannerUI::pan_value_changed), which));
                                                           
-       if (_io->n_outputs().n_audio() > 1 && which < _io->panner()->npanners()) {
+       if (_panner->npanners() > 1 && which < _panner->npanners()) {
                float xpos;
                float val = pan_adjustments[which]->get_value ();
 
-               _io->panner()->streampanner(which).get_position (xpos);
+               _panner->streampanner(which).get_position (xpos);
 
                if (!Panner::equivalent (val, xpos)) {
                        in_pan_update = true;
@@ -678,14 +684,14 @@ PannerUI::update_pan_bars (bool only_if_aplay)
                float xpos, val;
 
                if (only_if_aplay) {
-                       boost::shared_ptr<AutomationList> alist (_io->panner()->streampanner(n).pan_control()->alist());
+                       boost::shared_ptr<AutomationList> alist (_panner->streampanner(n).pan_control()->alist());
                        
                        if (!alist->automation_playback()) {
                                continue;
                        }
                }
 
-               _io->panner()->streampanner(n).get_effective_position (xpos);
+               _panner->streampanner(n).get_effective_position (xpos);
                val = (*i)->get_value ();
                
                if (!Panner::equivalent (val, xpos)) {
@@ -699,9 +705,9 @@ PannerUI::update_pan_bars (bool only_if_aplay)
 void
 PannerUI::update_pan_sensitive () 
 {
-       bool sensitive = !(_io->panner()->automation_state() & Play);
+       bool sensitive = !(_panner->automation_state() & Play);
 
-       switch (_io->n_outputs().n_audio()) {
+       switch (_panner->nouts()) {
        case 0:
        case 1:
                break;
@@ -771,10 +777,10 @@ PannerUI::pan_automation_style_changed ()
        
        switch (_width) {
        case Wide:
-               pan_automation_style_button.set_label (astyle_string(_io->panner()->automation_style()));
+               pan_automation_style_button.set_label (astyle_string(_panner->automation_style()));
                break;
        case Narrow:
-               pan_automation_style_button.set_label (short_astyle_string(_io->panner()->automation_style()));
+               pan_automation_style_button.set_label (short_astyle_string(_panner->automation_style()));
                break;
        }
 }
@@ -788,10 +794,10 @@ PannerUI::pan_automation_state_changed ()
 
        switch (_width) {
        case Wide:
-         pan_automation_state_button.set_label (astate_string(_io->panner()->automation_state()));
+         pan_automation_state_button.set_label (astate_string(_panner->automation_state()));
                break;
        case Narrow:
-         pan_automation_state_button.set_label (short_astate_string(_io->panner()->automation_state()));
+         pan_automation_state_button.set_label (short_astate_string(_panner->automation_state()));
                break;
        }
 
@@ -800,11 +806,11 @@ PannerUI::pan_automation_state_changed ()
           here.
        */
 
-       if (_io->panner()->empty()) {
+       if (_panner->empty()) {
                return;
        }
 
-       x = (_io->panner()->streampanner(0).pan_control()->alist()->automation_state() != Off);
+       x = (_panner->streampanner(0).pan_control()->alist()->automation_state() != Off);
 
        if (pan_automation_state_button.get_active() != x) {
        ignore_toggle = true;
index 602164d7a941041f5c8050833523dbc9922f8168..95e1e6c688e565dbfbcf1a30657151c5ffa845f0 100644 (file)
@@ -40,8 +40,9 @@ class PannerBar;
 class Panner2dWindow;
 
 namespace ARDOUR {
-       class IO;
        class Session;
+       class Panner;
+       class Delivery;
 }
 namespace Gtkmm2ext {
        class FastMeter;
@@ -58,7 +59,7 @@ class PannerUI : public Gtk::HBox
        PannerUI (ARDOUR::Session&);
        ~PannerUI ();
 
-       virtual void set_io (boost::shared_ptr<ARDOUR::IO>);
+       virtual void set_panner (boost::shared_ptr<ARDOUR::Panner>);
 
        void pan_changed (void *);
 
@@ -76,7 +77,7 @@ class PannerUI : public Gtk::HBox
   private:
        friend class MixerStrip;
 
-       boost::shared_ptr<ARDOUR::IO> _io;
+       boost::shared_ptr<ARDOUR::Panner> _panner;
        ARDOUR::Session& _session;
        std::vector<sigc::connection> connections;
 
index 3ff074f9d701a04cc62955324a70355b23bcefff..99c4861f792a6ce9171d157304e5e47c6fe446e8 100644 (file)
@@ -36,6 +36,7 @@
 
 using namespace std;
 using namespace Gtk;
+using namespace ARDOUR;
 
 /** PortGroup constructor.
  * @param n Name.
@@ -50,7 +51,7 @@ PortGroup::PortGroup (std::string const & n)
  *  @param b Bundle.
  */
 void
-PortGroup::add_bundle (boost::shared_ptr<ARDOUR::Bundle> b)
+PortGroup::add_bundle (boost::shared_ptr<Bundle> b)
 {
        assert (b.get());
        _bundles.push_back (b);
@@ -62,11 +63,11 @@ PortGroup::add_bundle (boost::shared_ptr<ARDOUR::Bundle> b)
 }
 
 void
-PortGroup::remove_bundle (boost::shared_ptr<ARDOUR::Bundle> b)
+PortGroup::remove_bundle (boost::shared_ptr<Bundle> b)
 {
        assert (b.get());
 
-       ARDOUR::BundleList::iterator i = std::find (_bundles.begin(), _bundles.end(), b);
+       BundleList::iterator i = std::find (_bundles.begin(), _bundles.end(), b);
        if (i == _bundles.end()) {
                return;
        }
@@ -78,7 +79,7 @@ PortGroup::remove_bundle (boost::shared_ptr<ARDOUR::Bundle> b)
 }
 
 void
-PortGroup::bundle_changed (ARDOUR::Bundle::Change c)
+PortGroup::bundle_changed (Bundle::Change c)
 {
        BundleChanged (c);
 }
@@ -103,7 +104,7 @@ PortGroup::clear ()
 bool
 PortGroup::has_port (std::string const& p) const
 {
-       for (ARDOUR::BundleList::const_iterator i = _bundles.begin(); i != _bundles.end(); ++i) {
+       for (BundleList::const_iterator i = _bundles.begin(); i != _bundles.end(); ++i) {
                if ((*i)->offers_port_alone (p)) {
                        return true;
                }
@@ -112,7 +113,7 @@ PortGroup::has_port (std::string const& p) const
        return false;
 }
 
-boost::shared_ptr<ARDOUR::Bundle>
+boost::shared_ptr<Bundle>
 PortGroup::only_bundle ()
 {
        assert (_bundles.size() == 1);
@@ -124,7 +125,7 @@ uint32_t
 PortGroup::total_channels () const
 {
        uint32_t n = 0;
-       for (ARDOUR::BundleList::const_iterator i = _bundles.begin(); i != _bundles.end(); ++i) {
+       for (BundleList::const_iterator i = _bundles.begin(); i != _bundles.end(); ++i) {
                n += (*i)->nchannels ();
        }
 
@@ -135,21 +136,49 @@ PortGroup::total_channels () const
 /** PortGroupList constructor.
  */
 PortGroupList::PortGroupList ()
-       : _type (ARDOUR::DataType::AUDIO), _signals_suspended (false), _pending_change (false)
+       : _type (DataType::AUDIO), _signals_suspended (false), _pending_change (false)
 {
        
 }
 
 void
-PortGroupList::set_type (ARDOUR::DataType t)
+PortGroupList::set_type (DataType t)
 {
        _type = t;
        clear ();
 }
 
+void
+PortGroupList::maybe_add_processor_to_bundle (boost::weak_ptr<Processor> wp, boost::shared_ptr<RouteBundle> rb, bool inputs)
+{
+       boost::shared_ptr<Processor> p (wp.lock());
+
+       if (!p) {
+               return;
+       }
+
+       boost::shared_ptr<IOProcessor> iop = boost::dynamic_pointer_cast<IOProcessor> (p);
+       
+       if (iop) {
+               
+               if (inputs) {
+                       if (!iop->output()) {
+                               return;
+                       }
+               } else {
+                       if (!iop->input()) {
+                               return;
+                       }
+               }
+               
+               rb->add_processor_bundle (inputs ? iop->output()->bundle() : iop->input()->bundle());
+       }
+}
+
+
 /** Gather bundles from around the system and put them in this PortGroupList */
 void
-PortGroupList::gather (ARDOUR::Session& session, bool inputs)
+PortGroupList::gather (Session& session, bool inputs)
 {
        clear ();
 
@@ -162,49 +191,28 @@ PortGroupList::gather (ARDOUR::Session& session, bool inputs)
           the route's IO bundles and processor bundles together so that they
           are presented as one bundle in the matrix. */
 
-       boost::shared_ptr<ARDOUR::RouteList> routes = session.get_routes ();
-
-       for (ARDOUR::RouteList::const_iterator i = routes->begin(); i != routes->end(); ++i) {
+       boost::shared_ptr<RouteList> routes = session.get_routes ();
 
-               boost::shared_ptr<RouteBundle> rb (
-                       new RouteBundle (
-                               inputs ? (*i)->bundle_for_inputs() : (*i)->bundle_for_outputs()
-                               )
-                       );
+       for (RouteList::const_iterator i = routes->begin(); i != routes->end(); ++i) {
 
-               uint32_t n = 0;
-               while (1) {
-                       boost::shared_ptr<ARDOUR::Processor> p = (*i)->nth_processor (n);
-                       if (p == 0) {
-                               break;
-                       }
+               boost::shared_ptr<RouteBundle> rb (new RouteBundle (inputs ? (*i)->output()->bundle() : (*i)->input()->bundle()));
 
-                       boost::shared_ptr<ARDOUR::IOProcessor> iop = boost::dynamic_pointer_cast<ARDOUR::IOProcessor> (p);
+               (*i)->foreach_processor (bind (mem_fun (*this, &PortGroupList::maybe_add_processor_to_bundle), rb, inputs));
 
-                       if (iop) {
-                               rb->add_processor_bundle (
-                                       inputs ? iop->io()->bundle_for_inputs() : iop->io()->bundle_for_outputs()
-                                       );
-                                       
-                       }
-
-                       ++n;
-               }
-                       
                /* Work out which group to put this bundle in */
                boost::shared_ptr<PortGroup> g;
-               if (_type == ARDOUR::DataType::AUDIO) {
+               if (_type == DataType::AUDIO) {
 
-                       if (boost::dynamic_pointer_cast<ARDOUR::AudioTrack> (*i)) {
+                       if (boost::dynamic_pointer_cast<AudioTrack> (*i)) {
                                g = track;
-                       } else if (!boost::dynamic_pointer_cast<ARDOUR::MidiTrack>(*i)) {
+                       } else if (!boost::dynamic_pointer_cast<MidiTrack>(*i)) {
                                g = bus;
                        } 
 
 
-               } else if (_type == ARDOUR::DataType::MIDI) {
+               } else if (_type == DataType::MIDI) {
 
-                       if (boost::dynamic_pointer_cast<ARDOUR::MidiTrack> (*i)) {
+                       if (boost::dynamic_pointer_cast<MidiTrack> (*i)) {
                                g = track;
                        }
 
@@ -219,11 +227,11 @@ PortGroupList::gather (ARDOUR::Session& session, bool inputs)
        /* Bundles owned by the session.  We only add the mono ones and the User ones
           otherwise there is duplication of the same ports within the matrix */
        
-       boost::shared_ptr<ARDOUR::BundleList> b = session.bundles ();
-       for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
+       boost::shared_ptr<BundleList> b = session.bundles ();
+       for (BundleList::iterator i = b->begin(); i != b->end(); ++i) {
                if ((*i)->ports_are_inputs() == inputs && (*i)->type() == _type) {
 
-                       if ((*i)->nchannels() == 1 || boost::dynamic_pointer_cast<ARDOUR::UserBundle> (*i)) {
+                       if ((*i)->nchannels() == 1 || boost::dynamic_pointer_cast<UserBundle> (*i)) {
                                system->add_bundle (*i);
                        }
                
@@ -282,10 +290,10 @@ PortGroupList::gather (ARDOUR::Session& session, bool inputs)
        emit_changed ();
 }
 
-boost::shared_ptr<ARDOUR::Bundle>
+boost::shared_ptr<Bundle>
 PortGroupList::make_bundle_from_ports (std::vector<std::string> const & p, bool inputs) const
 {
-       boost::shared_ptr<ARDOUR::Bundle> b (new ARDOUR::Bundle ("", _type, inputs));
+       boost::shared_ptr<Bundle> b (new Bundle ("", _type, inputs));
 
        std::string const pre = common_prefix (p);
        if (!pre.empty()) {
@@ -366,7 +374,7 @@ PortGroupList::clear ()
 }
 
 
-ARDOUR::BundleList const &
+BundleList const &
 PortGroupList::bundles () const
 {
        _bundles.clear ();
@@ -410,7 +418,7 @@ PortGroupList::add_group (boost::shared_ptr<PortGroup> g)
 }
 
 void
-PortGroupList::remove_bundle (boost::shared_ptr<ARDOUR::Bundle> b)
+PortGroupList::remove_bundle (boost::shared_ptr<Bundle> b)
 {
        for (List::iterator i = _groups.begin(); i != _groups.end(); ++i) {
                (*i)->remove_bundle (b);
@@ -446,7 +454,7 @@ PortGroupList::resume_signals ()
        _signals_suspended = false;
 }
 
-RouteBundle::RouteBundle (boost::shared_ptr<ARDOUR::Bundle> r)
+RouteBundle::RouteBundle (boost::shared_ptr<Bundle> r)
        : _route (r)
 {
        _route->Changed.connect (sigc::hide (sigc::mem_fun (*this, &RouteBundle::reread_component_bundles)));
@@ -470,7 +478,7 @@ RouteBundle::reread_component_bundles ()
                }
        }
                
-       for (std::vector<boost::shared_ptr<ARDOUR::Bundle> >::iterator i = _processor.begin(); i != _processor.end(); ++i) {
+       for (std::vector<boost::shared_ptr<Bundle> >::iterator i = _processor.begin(); i != _processor.end(); ++i) {
                add_channels_from_bundle (*i);
        }
 
@@ -478,7 +486,7 @@ RouteBundle::reread_component_bundles ()
 }
 
 void
-RouteBundle::add_processor_bundle (boost::shared_ptr<ARDOUR::Bundle> p)
+RouteBundle::add_processor_bundle (boost::shared_ptr<Bundle> p)
 {
        p->Changed.connect (sigc::hide (sigc::mem_fun (*this, &RouteBundle::reread_component_bundles)));
        _processor.push_back (p);
index 02dd965e1ddeb86ea12ed81443962d7be81db635..707cc0496693e17f86eee1739e83ecfe448c6789 100644 (file)
 namespace ARDOUR {
        class Session;
        class Bundle;
+       class Processor;
 }
 
 class PortMatrix;
+class RouteBundle;
 
 /** A list of bundles and ports, grouped by some aspect of their
  *  type e.g. busses, tracks, system.  Each group has 0 or more bundles
@@ -119,7 +121,8 @@ class PortGroupList : public sigc::trackable
        std::string common_prefix_before (std::vector<std::string> const &, std::string const &) const;
        void emit_changed ();
        boost::shared_ptr<ARDOUR::Bundle> make_bundle_from_ports (std::vector<std::string> const &, bool) const;
-       
+       void maybe_add_processor_to_bundle (boost::weak_ptr<ARDOUR::Processor>, boost::shared_ptr<RouteBundle>, bool);
+
        ARDOUR::DataType _type;
        mutable ARDOUR::BundleList _bundles;
        List _groups;
index f850582fec62ec9df1e4b2f34a3546d325dba93a..f8ea758549d4acb3a8eb0691eebdf6bd1f4f4e36 100644 (file)
@@ -452,7 +452,7 @@ ProcessorBox::use_plugins (const SelectedPlugins& plugins)
                }
 
                if (_route->add_processor (processor, _placement, &err_streams)) {
-                       weird_plugin_dialog (**p, err_streams, _route);
+                       weird_plugin_dialog (**p, err_streams);
                        // XXX SHAREDPTR delete plugin here .. do we even need to care?
                } else {
 
@@ -467,7 +467,7 @@ ProcessorBox::use_plugins (const SelectedPlugins& plugins)
 }
 
 void
-ProcessorBox::weird_plugin_dialog (Plugin& p, Route::ProcessorStreams streams, boost::shared_ptr<IO> io)
+ProcessorBox::weird_plugin_dialog (Plugin& p, Route::ProcessorStreams streams)
 {
        ArdourDialog dialog (_("ardour: weird plugin dialog"));
        Label label;
@@ -511,7 +511,7 @@ ProcessorBox::weird_plugin_dialog (Plugin& p, Route::ProcessorStreams streams, b
 void
 ProcessorBox::choose_insert ()
 {
-       boost::shared_ptr<Processor> processor (new PortInsert (_session));
+       boost::shared_ptr<Processor> processor (new PortInsert (_session, _route->mute_master()));
        processor->ActiveChanged.connect (bind (
                        mem_fun(*this, &ProcessorBox::show_processor_active),
                        boost::weak_ptr<Processor>(processor)));
@@ -522,7 +522,7 @@ ProcessorBox::choose_insert ()
 void
 ProcessorBox::choose_send ()
 {
-       boost::shared_ptr<Send> send (new Send (_session));
+       boost::shared_ptr<Send> send (new Send (_session, _route->mute_master()));
 
        /* make an educated guess at the initial number of outputs for the send */
        ChanCount outs = (_session.master_out())
@@ -531,14 +531,14 @@ ProcessorBox::choose_send ()
 
        /* XXX need processor lock on route */
        try {
-               send->io()->ensure_io (ChanCount::ZERO, outs, false, this);
+               send->output()->ensure_io (outs, false, this);
        } catch (AudioEngine::PortRegistrationFailure& err) {
                error << string_compose (_("Cannot set up new send: %1"), err.what()) << endmsg;
                return;
        }
 
        /* let the user adjust the IO setup before creation */
-       IOSelectorWindow *ios = new IOSelectorWindow (_session, send->io(), false, true);
+       IOSelectorWindow *ios = new IOSelectorWindow (_session, send->output(), true);
        ios->show_all ();
 
        /* keep a reference to the send so it doesn't get deleted while
@@ -588,14 +588,14 @@ ProcessorBox::choose_return ()
 
        /* XXX need processor lock on route */
        try {
-               retrn->io()->ensure_io (ins, ChanCount::ZERO, false, this);
+               retrn->input()->ensure_io (ins, false, this);
        } catch (AudioEngine::PortRegistrationFailure& err) {
                error << string_compose (_("Cannot set up new return: %1"), err.what()) << endmsg;
                return;
        }
 
        /* let the user adjust the IO setup before creation */
-       IOSelectorWindow *ios = new IOSelectorWindow (_session, retrn->io(), true, true);
+       IOSelectorWindow *ios = new IOSelectorWindow (_session, retrn->output(), true);
        ios->show_all ();
 
        /* keep a reference to the send so it doesn't get deleted while
@@ -1050,7 +1050,7 @@ ProcessorBox::paste_processor_state (const XMLNodeList& nlist)
                        if (type->value() == "send") {
                                XMLNode n (**niter);
                                Send::make_unique (n, _session);
-                               p.reset (new Send (_session, n));
+                               p.reset (new Send (_session, _route->mute_master(), n));
 
                        } else if (type->value() == "meter") {
                                p = _route->shared_peak_meter();
@@ -1064,7 +1064,7 @@ ProcessorBox::paste_processor_state (const XMLNodeList& nlist)
                                continue;
 
                        } else if (type->value() == "listen") {
-                               p.reset (new Delivery (_session, **niter));
+                               p.reset (new Delivery (_session, _route->mute_master(), **niter));
                                
                        } else {
                                p.reset (new PluginInsert (_session, **niter));
@@ -1214,8 +1214,8 @@ ProcessorBox::edit_processor (boost::shared_ptr<Processor> processor)
                gidget = send_ui;
 #else
                if (_parent_strip) {
-                       _parent_strip->gain_meter().set_io (send->io());
-                       _parent_strip->panner_ui().set_io (send->io());
+                       _parent_strip->gain_meter().set_controls (_route, send->meter(), send->amp()->gain_control(), send->amp());
+                       _parent_strip->panner_ui().set_panner (send->panner());
                }
 #endif
        
index d53d05fe2328695c2f371f4e267951efcfa16603..985c8a1177c053a89b406fc526337bbae5ab81bb 100644 (file)
@@ -205,7 +205,7 @@ class ProcessorBox : public Gtk::HBox, public PluginInterestedObject
 
        gint idle_delete_processor (boost::weak_ptr<ARDOUR::Processor>);
 
-       void weird_plugin_dialog (ARDOUR::Plugin& p, ARDOUR::Route::ProcessorStreams streams, boost::shared_ptr<ARDOUR::IO> io);
+       void weird_plugin_dialog (ARDOUR::Plugin& p, ARDOUR::Route::ProcessorStreams streams);
 
        static ProcessorBox* _current_processor_box;
        static bool enter_box (GdkEventCrossing*, ProcessorBox*);
index ac06529d38aea4812f8647defc1723b45905714e..155a1095c1ef4b9c5be6ca1ad92f826e6cc2dde2 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <gtkmm2ext/doi.h>
 
+#include "ardour/amp.h"
 #include "ardour/io.h"
 #include "ardour/return.h"
 
@@ -37,7 +38,7 @@ ReturnUI::ReturnUI (boost::shared_ptr<Return> r, Session& se)
        , _session (se)
        , _gpm (se)
 {
-       _gpm.set_io (r->io());
+       _gpm.set_controls (boost::shared_ptr<Route>(), r->meter(), r->amp()->gain_control(), r->amp());
 
        _hbox.pack_start (_gpm, true, true);
        set_name ("ReturnUIFrame");
@@ -47,7 +48,7 @@ ReturnUI::ReturnUI (boost::shared_ptr<Return> r, Session& se)
 
        _vbox.pack_start (_hbox, false, false, false);
 
-       io = manage (new IOSelector (se, r->io(), true));
+       io = manage (new IOSelector (se, r->output()));
        
        pack_start (_vbox, false, false);
 
@@ -55,21 +56,19 @@ ReturnUI::ReturnUI (boost::shared_ptr<Return> r, Session& se)
 
        show_all ();
 
-       //_return->set_metering (true);
-
-       _return->io()->input_changed.connect (mem_fun (*this, &ReturnUI::ins_changed));
-       //_return->io()->output_changed.connect (mem_fun (*this, &ReturnUI::outs_changed));
+       _return->set_metering (true);
+       _return->input()->changed.connect (mem_fun (*this, &ReturnUI::ins_changed));
        
        _gpm.setup_meters ();
        _gpm.set_fader_name ("ReturnUIFrame");
-
+       
        // screen_update_connection = ARDOUR_UI::instance()->RapidScreenUpdate.connect (mem_fun (*this, &ReturnUI::update));
        fast_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (mem_fun (*this, &ReturnUI::fast_update));
 }
 
 ReturnUI::~ReturnUI ()
 {
-       //_return->set_metering (false);
+       _return->set_metering (false);
 
        /* XXX not clear that we need to do this */
 
@@ -111,12 +110,8 @@ ReturnUIWindow::ReturnUIWindow (boost::shared_ptr<Return> s, Session& ss)
 
        set_name ("ReturnUIWindow");
        
-       going_away_connection = s->GoingAway.connect (
-                       mem_fun (*this, &ReturnUIWindow::return_going_away));
-
-       signal_delete_event().connect (bind (
-                                              sigc::ptr_fun (just_hide_it),
-                                              reinterpret_cast<Window *> (this)));
+       going_away_connection = s->GoingAway.connect (mem_fun (*this, &ReturnUIWindow::return_going_away));
+       signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it), reinterpret_cast<Window *> (this)));
 }
 
 ReturnUIWindow::~ReturnUIWindow ()
index 5c709d80bfebeb9ab944042d8cfb89be1bf1b816..d2fc106c429620c6d87e48020594feec692bec72 100644 (file)
@@ -298,7 +298,7 @@ RouteParams_UI::cleanup_latency_frame ()
 void
 RouteParams_UI::setup_latency_frame ()
 {
-       latency_widget = new LatencyGUI (*(_route.get()), session->frame_rate(), session->engine().frames_per_cycle());
+       latency_widget = new LatencyGUI (*(_route->output()), session->frame_rate(), session->engine().frames_per_cycle());
 
        char buf[128];
        snprintf (buf, sizeof (buf), _("Playback delay: %u samples"), _route->initial_delay());
@@ -322,13 +322,13 @@ RouteParams_UI::setup_io_frames()
        cleanup_io_frames();
        
        // input
-       _input_iosel = new IOSelector (*session, _route, false);
+       _input_iosel = new IOSelector (*session, _route->input());
        _input_iosel->setup ();
        input_frame.add (*_input_iosel);
        input_frame.show_all();
        
        // output
-       _output_iosel = new IOSelector (*session, _route, true);
+       _output_iosel = new IOSelector (*session, _route->output());
        _output_iosel->setup ();
        output_frame.add (*_output_iosel);
        output_frame.show_all();
index df85cf69a42718abd3444f4836ca4ac691a357e9..715a70b1d3e445086a644866f7385fcf1f7195f4 100644 (file)
@@ -40,6 +40,7 @@
 #include <gtkmm2ext/bindable_button.h>
 #include <gtkmm2ext/utils.h>
 
+#include "ardour/amp.h"
 #include "ardour/audioplaylist.h"
 #include "ardour/diskstream.h"
 #include "ardour/event_type_map.h"
@@ -110,7 +111,7 @@ RouteTimeAxisView::RouteTimeAxisView (PublicEditor& ed, Session& sess, boost::sh
          visual_button (_("v")),
          gm (sess, slider, true)
 {
-       gm.set_io (rt);
+       gm.set_controls (_route, _route->shared_peak_meter(), _route->gain_control(), _route->amp());
        gm.get_level_meter().set_no_show_all();
        gm.get_level_meter().setup_meters(50);
 
@@ -187,8 +188,8 @@ RouteTimeAxisView::RouteTimeAxisView (PublicEditor& ed, Session& sess, boost::sh
 
        controls_hbox.pack_start(gm.get_level_meter(), false, false);
        _route->meter_change.connect (mem_fun(*this, &RouteTimeAxisView::meter_changed));
-       _route->input_changed.connect (mem_fun(*this, &RouteTimeAxisView::io_changed));
-       _route->output_changed.connect (mem_fun(*this, &RouteTimeAxisView::io_changed));
+       _route->input()->changed.connect (mem_fun(*this, &RouteTimeAxisView::io_changed));
+       _route->output()->changed.connect (mem_fun(*this, &RouteTimeAxisView::io_changed));
 
        controls_table.attach (*mute_button, 6, 7, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0);
        controls_table.attach (*solo_button, 7, 8, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0);
@@ -231,7 +232,7 @@ RouteTimeAxisView::RouteTimeAxisView (PublicEditor& ed, Session& sess, boost::sh
        _route->solo_changed.connect (mem_fun(*this, &RouteUI::solo_changed));
        _route->processors_changed.connect (mem_fun(*this, &RouteTimeAxisView::processors_changed));
        _route->NameChanged.connect (mem_fun(*this, &RouteTimeAxisView::route_name_changed));
-       _route->solo_safe_changed.connect (mem_fun(*this, &RouteUI::solo_changed));
+       _route->solo_isolated_changed.connect (mem_fun(*this, &RouteUI::solo_changed));
 
 
        if (is_track()) {
index 393ab011f3a1c54de3d41a05f6455017d37b432e..b62229a70cdacb59a75f523286ec40477270452f 100644 (file)
@@ -101,7 +101,6 @@ RouteUI::init ()
        ignore_toggle = false;
        wait_for_release = false;
        route_active_menu_item = 0;
-       was_solo_safe = false;
        polarity_menu_item = 0;
        denormal_menu_item = 0;
        multiple_mute_change = false;
@@ -192,7 +191,7 @@ RouteUI::set_route (boost::shared_ptr<Route> rp)
        connections.push_back (_route->active_changed.connect (mem_fun (*this, &RouteUI::route_active_changed)));
        connections.push_back (_route->mute_changed.connect (mem_fun(*this, &RouteUI::mute_changed)));
        connections.push_back (_route->solo_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
-       connections.push_back (_route->solo_safe_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
+       connections.push_back (_route->solo_isolated_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
   
        if (is_track()) {
                boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
@@ -396,7 +395,7 @@ RouteUI::solo_press(GdkEventButton* ev)
                                                        Config->set_solo_latched (false);
                                                }
                                        } else {
-                                               _route->set_solo_safe (!_route->solo_safe(), this);
+                                               _route->set_solo_isolated (!_route->solo_isolated(), this);
                                                wait_for_release = false;
                                        }
 
@@ -621,7 +620,7 @@ RouteUI::update_solo_display ()
                ignore_toggle = false;
        } 
        
-       if (_route->solo_safe()) {
+       if (_route->solo_isolated()) {
                solo_button->set_visual_state (2);
        } else if (_route->soloed()) {
                solo_button->set_visual_state (1);
@@ -663,8 +662,7 @@ RouteUI::update_mute_display ()
        if (Config->get_show_solo_mutes()) {
                if (_route->muted()) {
                        mute_button->set_visual_state (2);
-               } else if (!_route->soloed() && _route->solo_muted()) {
-                       
+               } else if (!_route->soloed() && _session.soloing()) {
                        mute_button->set_visual_state (1);
                } else {
                        mute_button->set_visual_state (0);
@@ -804,10 +802,10 @@ RouteUI::build_solo_menu (void)
        MenuList& items = solo_menu->items();
        CheckMenuItem* check;
 
-       check = new CheckMenuItem(_("Solo Lock"));
-       check->set_active (_route->solo_safe());
-       check->signal_toggled().connect (bind (mem_fun (*this, &RouteUI::toggle_solo_safe), check));
-       _route->solo_safe_changed.connect(bind (mem_fun (*this, &RouteUI::solo_safe_toggle), check));
+       check = new CheckMenuItem(_("Solo Isolate"));
+       check->set_active (_route->solo_isolated());
+       check->signal_toggled().connect (bind (mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
+       _route->solo_isolated_changed.connect(bind (mem_fun (*this, &RouteUI::solo_isolated_toggle), check));
        items.push_back (CheckMenuElem(*check));
        check->show_all();
 
@@ -823,9 +821,11 @@ RouteUI::build_mute_menu(void)
        
        mute_menu = new Menu;
        mute_menu->set_name ("ArdourContextMenu");
+
+#if FIX_ME_IN_3_0      
        MenuList& items = mute_menu->items();
        CheckMenuItem* check;
-       
+
        check = new CheckMenuItem(_("Pre Fader"));
        init_mute_menu(PRE_FADER, check);
        check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), PRE_FADER, check));
@@ -853,29 +853,27 @@ RouteUI::build_mute_menu(void)
        _route->main_outs_changed.connect(bind (mem_fun (*this, &RouteUI::main_outs_toggle), check));
        items.push_back (CheckMenuElem(*check));
        check->show_all();
-
+#endif
        //items.push_back (SeparatorElem());
        // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
 }
 
 void
-RouteUI::init_mute_menu(mute_type type, CheckMenuItem* check)
+RouteUI::init_mute_menu(MuteMaster::MutePoint mp, CheckMenuItem* check)
 {
-       if (_route->get_mute_config (type)) {
-               check->set_active (true);
-       }
+       check->set_active (_route->mute_master()->muted_at (mp));
 }
 
 void
-RouteUI::toggle_mute_menu(mute_type type, Gtk::CheckMenuItem* check)
+RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
 {
-       _route->set_mute_config(type, check->get_active(), this);
+       // _route->set_mute_config(type, check->get_active(), this);
 }
 
 void
-RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
+RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
 {
-       _route->set_solo_safe (check->get_active(), this);
+       _route->set_solo_isolated (check->get_active(), this);
 }
 
 void
@@ -1166,16 +1164,17 @@ RouteUI::denormal_protection_changed ()
        /* no signal for this yet */
 }
 
-
 void
-RouteUI::solo_safe_toggle(void* src, Gtk::CheckMenuItem* check)
+RouteUI::solo_isolated_toggle(void* src, Gtk::CheckMenuItem* check)
 {
-       bool yn = _route->solo_safe ();
+       bool yn = _route->solo_isolated ();
 
        if (check->get_active() != yn) {
                check->set_active (yn);
        }
 }
+
+#ifdef FIX_THIS_FOR_3_0
 void
 RouteUI::pre_fader_toggle(void* src, Gtk::CheckMenuItem* check)
 {
@@ -1219,17 +1218,18 @@ RouteUI::main_outs_toggle(void* src, Gtk::CheckMenuItem* check)
                check->set_active (yn);
        }
 }
+#endif
 
 void
 RouteUI::disconnect_input ()
 {
-       _route->disconnect_inputs (this);
+       _route->input()->disconnect (this);
 }
 
 void
 RouteUI::disconnect_output ()
 {
-       _route->disconnect_outputs (this);
+       _route->output()->disconnect (this);
 }
 
 bool
@@ -1308,7 +1308,7 @@ RouteUI::map_frozen ()
 void
 RouteUI::adjust_latency ()
 {
-       LatencyDialog dialog (_route->name() + _("latency"), *(_route.get()), _session.frame_rate(), _session.engine().frames_per_cycle());
+       LatencyDialog dialog (_route->name() + _("latency"), *(_route->output()), _session.frame_rate(), _session.engine().frames_per_cycle());
 }
 
 void
index de8d7ea30c27d779ac8ea4626a5d18560ebb8a1b..fc6ef87f57ed44d3cd240acd172955290d3da0fe 100644 (file)
@@ -24,6 +24,7 @@
 
 #include "pbd/xml++.h"
 #include "ardour/ardour.h"
+#include "ardour/mute_master.h"
 #include "ardour/route.h"
 #include "ardour/track.h"
 
@@ -125,17 +126,17 @@ class RouteUI : public virtual AxisView
        void build_remote_control_menu (void);
        void refresh_remote_control_menu ();
 
-       void solo_safe_toggle (void*, Gtk::CheckMenuItem*);
-       void toggle_solo_safe (Gtk::CheckMenuItem*);
+       void solo_isolated_toggle (void*, Gtk::CheckMenuItem*);
+       void toggle_solo_isolated (Gtk::CheckMenuItem*);
 
-       void toggle_mute_menu(ARDOUR::mute_type, Gtk::CheckMenuItem*);
+       void toggle_mute_menu(ARDOUR::MuteMaster::MutePoint, Gtk::CheckMenuItem*);
        void pre_fader_toggle(void*, Gtk::CheckMenuItem*);
        void post_fader_toggle(void*, Gtk::CheckMenuItem*);
        void control_outs_toggle(void*, Gtk::CheckMenuItem*);
        void main_outs_toggle(void*, Gtk::CheckMenuItem*);
 
        void build_mute_menu(void);
-       void init_mute_menu(ARDOUR::mute_type, Gtk::CheckMenuItem*);
+       void init_mute_menu(ARDOUR::MuteMaster::MutePoint, Gtk::CheckMenuItem*);
        
        void set_mix_group_solo(boost::shared_ptr<ARDOUR::Route>, bool);
        void set_mix_group_mute(boost::shared_ptr<ARDOUR::Route>, bool);
@@ -169,7 +170,6 @@ class RouteUI : public virtual AxisView
        virtual void update_rec_display ();
        void update_mute_display ();
 
-       bool was_solo_safe;
        void update_solo_display ();
 
        virtual void map_frozen ();
index 672d5f3d20b7142fdf3e6b06e8680b7ab84d0bd7..19baaa7f9319716796acd2edd191598b6b04fc24 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <gtkmm2ext/doi.h>
 
+#include "ardour/amp.h"
 #include "ardour/io.h"
 #include "ardour/send.h"
 
@@ -38,8 +39,8 @@ SendUI::SendUI (boost::shared_ptr<Send> s, Session& se)
        , _gpm (se)
        , _panners (se)
 {
-       _panners.set_io (s->io());
-       _gpm.set_io (s->io());
+       _panners.set_panner (s->panner());
+       _gpm.set_controls (boost::shared_ptr<Route>(), s->meter(), s->amp()->gain_control(), s->amp());
 
        _hbox.pack_start (_gpm, true, true);
        set_name ("SendUIFrame");
@@ -50,7 +51,7 @@ SendUI::SendUI (boost::shared_ptr<Send> s, Session& se)
        _vbox.pack_start (_hbox, false, false, false);
        _vbox.pack_start (_panners, false,false);
 
-       io = manage (new IOSelector (se, s->io(), true));
+       io = manage (new IOSelector (se, s->output()));
        
        pack_start (_vbox, false, false);
 
@@ -60,8 +61,8 @@ SendUI::SendUI (boost::shared_ptr<Send> s, Session& se)
 
        _send->set_metering (true);
 
-       _send->io()->input_changed.connect (mem_fun (*this, &SendUI::ins_changed));
-       _send->io()->output_changed.connect (mem_fun (*this, &SendUI::outs_changed));
+       _send->input()->changed.connect (mem_fun (*this, &SendUI::ins_changed));
+       _send->output()->changed.connect (mem_fun (*this, &SendUI::outs_changed));
        
        _panners.set_width (Wide);
        _panners.setup_pan ();
index 76c8a85b88d3523a86c8748d5c42448c4ef2f2b8..09138f428ecbb5d281ee4773383238e04f5d036e 100644 (file)
@@ -25,12 +25,12 @@ public:
 
        void setup_ports (int dim)
        {
-               cerr << _session.the_auditioner()->outputs().num_ports() << "\n";
+               cerr << _session.the_auditioner()->output()->n_ports() << "\n";
                
                if (dim == OURS) {
                        _port_group->clear ();
-                       _port_group->add_bundle (_session.click_io()->bundle_for_outputs());
-                       _port_group->add_bundle (_session.the_auditioner()->bundle_for_outputs());
+                       _port_group->add_bundle (_session.click_io()->bundle());
+                       _port_group->add_bundle (_session.the_auditioner()->output()->bundle());
                } else {
                        _ports[OTHER].gather (_session, true);
                }
@@ -41,7 +41,7 @@ public:
                Bundle::PortList const & our_ports = c[OURS].bundle->channel_ports (c[OURS].channel);
                Bundle::PortList const & other_ports = c[OTHER].bundle->channel_ports (c[OTHER].channel);
                
-               if (c[OURS].bundle == _session.click_io()->bundle_for_outputs()) {
+               if (c[OURS].bundle == _session.click_io()->bundle()) {
 
                        for (ARDOUR::Bundle::PortList::const_iterator i = our_ports.begin(); i != our_ports.end(); ++i) {
                                for (ARDOUR::Bundle::PortList::const_iterator j = other_ports.begin(); j != other_ports.end(); ++j) {
@@ -50,9 +50,9 @@ public:
                                        assert (f);
                                        
                                        if (s) {
-                                               _session.click_io()->connect_output (f, *j, 0);
+                                               _session.click_io()->connect (f, *j, 0);
                                        } else {
-                                               _session.click_io()->disconnect_output (f, *j, 0);
+                                               _session.click_io()->disconnect (f, *j, 0);
                                        }
                                }
                        }
@@ -64,7 +64,7 @@ public:
                Bundle::PortList const & our_ports = c[OURS].bundle->channel_ports (c[OURS].channel);
                Bundle::PortList const & other_ports = c[OTHER].bundle->channel_ports (c[OTHER].channel);
                
-               if (c[OURS].bundle == _session.click_io()->bundle_for_outputs()) {
+               if (c[OURS].bundle == _session.click_io()->bundle()) {
                        
                        for (ARDOUR::Bundle::PortList::const_iterator i = our_ports.begin(); i != our_ports.end(); ++i) {
                                for (ARDOUR::Bundle::PortList::const_iterator j = other_ports.begin(); j != other_ports.end(); ++j) {
index 98dd328f55f1e1dd75fafee7dd0566de9677edff..cc9d09b65408620b4c8ac300e9e9b744be6abc35 100644 (file)
@@ -39,6 +39,7 @@
 
 #include "evoral/SMF.hpp"
 
+#include "ardour/amp.h"
 #include "ardour/audio_library.h"
 #include "ardour/auditioner.h"
 #include "ardour/audioregion.h"
@@ -594,7 +595,10 @@ SoundFileBrowser::add_gain_meter ()
        delete gm;
 
        gm = new GainMeter (*session);
-       gm->set_io (session->the_auditioner());
+
+       boost::shared_ptr<Route> r = session->the_auditioner ();
+
+       gm->set_controls (r, r->shared_peak_meter(), r->gain_control(), r->amp());
 
        meter_packer.set_border_width (12);
        meter_packer.pack_start (*gm, false, true);
index edba74d1179e6d529fe89cbb5c679de96c154d79..eb45aad25d6d064d88a752ea44ceb4fcc57ab976 100644 (file)
@@ -118,6 +118,7 @@ midi_stretch.cc
 midi_track.cc
 mix.cc
 mtc_slave.cc
+mute_master.cc
 named_selection.cc
 onset_detector.cc
 panner.cc
index 591fcd85690cba868f482df6cfccb8176040cb43..755dc8b8212d7f197a7a86b9ea22517b92ed5ae9 100644 (file)
 #include <cstring>
 #include <cmath>
 #include <algorithm>
+
+#include "evoral/Curve.hpp"
+
 #include "ardour/amp.h"
 #include "ardour/audio_buffer.h"
 #include "ardour/buffer_set.h"
 #include "ardour/configuration.h"
 #include "ardour/io.h"
+#include "ardour/mute_master.h"
 #include "ardour/session.h"
 
-namespace ARDOUR {
+#include "i18n.h"
+
+using namespace ARDOUR;
 
-Amp::Amp(Session& s, IO& io)
+Amp::Amp(Session& s, boost::shared_ptr<MuteMaster> mm)
        : Processor(s, "Amp")
-       , _io(io)
-       , _mute(false)
        , _apply_gain(true)
        , _apply_gain_automation(false)
        , _current_gain(1.0)
-       , _desired_gain(1.0)
+       , _mute_master (mm)
 {
+       boost::shared_ptr<AutomationList> gl(new AutomationList(Evoral::Parameter(GainAutomation)));
+       _gain_control = boost::shared_ptr<GainControl>( new GainControl(X_("gaincontrol"), s, this, Evoral::Parameter(GainAutomation), gl ));
+       add_control(_gain_control);
 }
 
 bool
@@ -59,64 +66,92 @@ Amp::configure_io (ChanCount in, ChanCount out)
 void
 Amp::run_in_place (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes)
 {
-       gain_t* gab = _session.gain_automation_buffer();
+       gain_t mute_gain;
 
-       if (_mute && !bufs.is_silent()) {
-               Amp::apply_gain (bufs, nframes, _current_mute_gain, _desired_mute_gain, false);
-               if (_desired_mute_gain == 0.0f) {
-                       bufs.is_silent(true);
-               }
+       if (_mute_master) {
+               mute_gain = _mute_master->mute_gain_at (MuteMaster::PreFader);
+       } else {
+               mute_gain = 1.0;
        }
 
        if (_apply_gain) {
                
                if (_apply_gain_automation) {
                        
-                       if (_io.phase_invert()) {
+                       gain_t* gab = _session.gain_automation_buffer ();
+
+                       if (mute_gain == 0.0) {
+                               
+                               /* absolute mute */
+
+                               if (_current_gain == 0.0) {
+                                       
+                                       /* already silent */
+
+                                       for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i) {
+                                               i->clear ();
+                                       }
+                               } else {
+                                       
+                                       /* cut to silence */
+
+                                       Amp::apply_gain (bufs, nframes, _current_gain, 0.0);
+                                       _current_gain = 0.0;
+                               }
+                                       
+
+                       } else if (mute_gain != 1.0) {
+
+                               /* mute dimming */
+
                                for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i) {
                                        Sample* const sp = i->data();
                                        for (nframes_t nx = 0; nx < nframes; ++nx) {
-                                               sp[nx] *= -gab[nx];
+                                               sp[nx] *= gab[nx] * mute_gain;
                                        }
                                }
+
+                               _current_gain = gab[nframes-1] * mute_gain;
+
                        } else {
+
+                               /* no mute */
+
                                for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i) {
                                        Sample* const sp = i->data();
                                        for (nframes_t nx = 0; nx < nframes; ++nx) {
                                                sp[nx] *= gab[nx];
                                        }
                                }
+
+                               _current_gain = gab[nframes-1];
                        }
+                               
                        
                } else { /* manual (scalar) gain */
+
+                       gain_t dg = _gain_control->user_float() * mute_gain;
                        
-                       if (_current_gain != _desired_gain) {
+                       if (_current_gain != dg) {
                                
-                               Amp::apply_gain (bufs, nframes, _current_gain, _desired_gain, _io.phase_invert());
-                               _current_gain = _desired_gain;
+                               Amp::apply_gain (bufs, nframes, _current_gain, dg);
+                               _current_gain = dg;
                                
-                       } else if (_current_gain != 0.0f && (_io.phase_invert() || _current_gain != 1.0f)) {
+                       } else if ((_current_gain != 0.0f) && (_current_gain != 1.0f)) {
                                
-                               /* no need to interpolate current gain value,
-                                  but its non-unity, so apply it. if the gain
-                                  is zero, do nothing because we'll ship silence
-                                  below.
+                               /* gain has not changed, but its non-unity, so apply it unless
+                                  its zero.
                                */
 
-                               gain_t this_gain;
-                               
-                               if (_io.phase_invert()) {
-                                       this_gain = -_current_gain;
-                               } else {
-                                       this_gain = _current_gain;
-                               }
-                               
                                for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i) {
                                        Sample* const sp = i->data();
-                                       apply_gain_to_buffer(sp, nframes, this_gain);
+                                       apply_gain_to_buffer(sp, nframes, _current_gain);
                                }
 
                        } else if (_current_gain == 0.0f) {
+                               
+                               /* silence! */
+
                                for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i) {
                                        i->clear();
                                }
@@ -125,30 +160,19 @@ Amp::run_in_place (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame,
        }
 }
 
-/** Apply a declicked gain to the audio buffers of @a bufs */
 void
-Amp::apply_gain (BufferSet& bufs, nframes_t nframes,
-               gain_t initial, gain_t target, bool invert_polarity)
+Amp::apply_gain (BufferSet& bufs, nframes_t nframes, gain_t initial, gain_t target)
 {
-       if (nframes == 0) {
-               return;
-       }
-
-       if (bufs.count().n_audio() == 0) {
+        /** Apply a (potentially) declicked gain to the audio buffers of @a bufs 
+        */
+       
+       if (nframes == 0 || bufs.count().n_audio() == 0) {
                return;
        }
 
        // if we don't need to declick, defer to apply_simple_gain
        if (initial == target) {
-               if (target == 0.0) {
-                       for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i) {
-                               memset (i->data(), 0, sizeof (Sample) * nframes);
-                       }
-               } else if (target != 1.0) {
-                       for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i) {
-                               apply_gain_to_buffer (i->data(), nframes, target);
-                       }
-               }
+               apply_simple_gain (bufs, nframes, target);
                return;
        }
 
@@ -156,7 +180,7 @@ Amp::apply_gain (BufferSet& bufs, nframes_t nframes,
        gain_t         delta;
        double         fractional_shift = -1.0/declick;
        double         fractional_pos;
-       gain_t         polscale = invert_polarity ? -1.0f : 1.0f;
+       gain_t         polscale = 1.0f;
 
        if (target < initial) {
                /* fade out: remove more and more of delta from initial */
@@ -180,10 +204,6 @@ Amp::apply_gain (BufferSet& bufs, nframes_t nframes,
                
                if (declick != nframes) {
 
-                       if (invert_polarity) {
-                               target = -target;
-                       }
-
                        if (target == 0.0) {
                                memset (&buffer[declick], 0, sizeof (Sample) * (nframes - declick));
                        } else if (target != 1.0) {
@@ -196,6 +216,62 @@ Amp::apply_gain (BufferSet& bufs, nframes_t nframes,
 void
 Amp::apply_simple_gain (BufferSet& bufs, nframes_t nframes, gain_t target)
 {
+       if (target == 0.0) {
+               for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i) {
+                       memset (i->data(), 0, sizeof (Sample) * nframes);
+               }
+       } else if (target != 1.0) {
+               for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i) {
+                       apply_gain_to_buffer (i->data(), nframes, target);
+               }
+       }
+}
+
+void
+Amp::inc_gain (gain_t factor, void *src)
+{
+       float desired_gain = _gain_control->user_float();
+       if (desired_gain == 0.0f) {
+               set_gain (0.000001f + (0.000001f * factor), src);
+       } else {
+               set_gain (desired_gain + (desired_gain * factor), src);
+       }
+}
+
+void
+Amp::set_gain (gain_t val, void *src)
+{
+       // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
+       if (val > 1.99526231f) {
+               val = 1.99526231f;
+       }
+
+       //cerr << "set desired gain to " << val << " when curgain = " << _gain_control->get_value () << endl;
+
+       if (src != _gain_control.get()) {
+               _gain_control->set_value(val);
+               // bit twisty, this will come back and call us again
+               // (this keeps control in sync with reality)
+               return;
+       }
+
+       {
+               // Glib::Mutex::Lock dm (declick_lock);
+               _gain_control->set_float(val, false);
+       }
+
+       if (_session.transport_stopped()) {
+               // _gain = val;
+       }
+       
+       /*
+       if (_session.transport_stopped() && src != 0 && src != this && _gain_control->automation_write()) {
+               _gain_control->list()->add (_session.transport_frame(), val);
+               
+       }
+       */
+
+       _session.set_dirty();
 }
 
 XMLNode&
@@ -206,4 +282,33 @@ Amp::state (bool full_state)
        return node;
 }
 
-} // namespace ARDOUR
+void
+Amp::GainControl::set_value (float val)
+{
+       // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
+       if (val > 1.99526231f)
+               val = 1.99526231f;
+
+       _amp->set_gain (val, this);
+       
+       AutomationControl::set_value(val);
+}
+
+float
+Amp::GainControl::get_value (void) const
+{
+       return AutomationControl::get_value();
+}
+
+void
+Amp::setup_gain_automation (sframes_t start_frame, sframes_t end_frame, nframes_t nframes)
+{
+       Glib::Mutex::Lock am (data().control_lock(), Glib::TRY_LOCK);
+
+       if (am.locked() && _session.transport_rolling() && _gain_control->automation_playback()) {
+               _apply_gain_automation = _gain_control->list()->curve().rt_safe_get_vector (
+                       start_frame, end_frame, _session.gain_automation_buffer(), nframes);
+       } else {
+               _apply_gain_automation = false;
+       }
+}
index 152b89a4310da4fe0a93e1bdac51816ac756ad38..03cc3d02f7fd187470e64fe76b63ccf1de9a9139 100644 (file)
 #include "ardour/types.h"
 #include "ardour/chan_count.h"
 #include "ardour/processor.h"
+#include "ardour/automation_control.h"
 
 namespace ARDOUR {
 
 class BufferSet;
 class IO;
-
+class MuteMaster;
 
 /** Applies a declick operation to all audio inputs, passing the same number of
  * audio outputs, and passing through any other types unchanged.
  */
 class Amp : public Processor {
 public:
-       Amp(Session& s, IO& io);
+       Amp(Session& s, boost::shared_ptr<MuteMaster> m);
 
        bool can_support_io_configuration (const ChanCount& in, ChanCount& out) const;
        bool configure_io (ChanCount in, ChanCount out);
@@ -44,38 +45,54 @@ public:
        bool apply_gain() const  { return _apply_gain; }
        void apply_gain(bool yn) { _apply_gain = yn; }
 
+       void setup_gain_automation (sframes_t start_frame, sframes_t end_frame, nframes_t nframes);
+
        bool apply_gain_automation() const  { return _apply_gain_automation; }
        void apply_gain_automation(bool yn) { _apply_gain_automation = yn; }
 
-       void muute(bool yn) { _mute = yn; }
+       XMLNode& state (bool full);
 
-       void set_gain(float current, float desired) {
-               _current_gain = current;
-               _desired_gain = desired;
-       }
-       
-       void apply_mute(bool yn, float current=1.0, float desired=0.0) {
-               _mute = yn;
-               _current_mute_gain = current;
-               _desired_mute_gain = desired;
-       }
+       static void apply_gain (BufferSet& bufs, nframes_t nframes, gain_t initial, gain_t target);
+       static void apply_simple_gain(BufferSet& bufs, nframes_t nframes, gain_t target);
 
-       XMLNode& state (bool full);
+       gain_t         gain () const { return _gain_control->user_float(); }
 
-       static void apply_gain (BufferSet& bufs, nframes_t nframes,
-                       gain_t initial, gain_t target, bool invert_polarity);
+       virtual void   set_gain (gain_t g, void *src);
+       void           inc_gain (gain_t delta, void *src);
 
-       static void apply_simple_gain(BufferSet& bufs, nframes_t nframes, gain_t target);
+       static void update_meters();
+
+       /* automation */
+
+       struct GainControl : public AutomationControl {
+               GainControl (std::string name, Session& session, Amp* a, const Evoral::Parameter &param,
+                            boost::shared_ptr<AutomationList> al = boost::shared_ptr<AutomationList>() )
+                       : AutomationControl (session, param, al, name )
+                       , _amp (a)
+               {}
+        
+           void set_value (float val);
+           float get_value (void) const;
+   
+           Amp* _amp;
+       };
+
+       boost::shared_ptr<GainControl> gain_control() {
+               return _gain_control;
+       }
+
+       boost::shared_ptr<const GainControl> gain_control() const {
+               return _gain_control;
+       }
 
 private:
-       IO&   _io;
-       bool  _mute;
-       bool  _apply_gain;
-       bool  _apply_gain_automation;
-       float _current_gain;
-       float _desired_gain;
-       float _current_mute_gain;
-       float _desired_mute_gain;
+       bool   _denormal_protection;
+       bool   _apply_gain;
+       bool   _apply_gain_automation;
+       float  _current_gain;
+
+       boost::shared_ptr<GainControl> _gain_control;   
+       boost::shared_ptr<MuteMaster>  _mute_master;
 };
 
 
index 5eacfa14b211749d5b29f6955e4c004368651dd6..ed98e8d8ba00f407c82e825aa15951a2298b85ee 100644 (file)
@@ -58,7 +58,7 @@ public:
        virtual void add_control(boost::shared_ptr<Evoral::Control>);
        
        virtual void automation_snapshot(nframes_t now, bool force);
-       virtual void transport_stopped(nframes_t now);
+       virtual void transport_stopped (sframes_t now);
 
        virtual std::string describe_parameter(Evoral::Parameter param);
        
index 8488df47a66a7cb6f64655bbb5ac89e206a509f5..2f174ab4721df6bae021394e69863ed4fdec317e 100644 (file)
@@ -27,7 +27,7 @@ namespace ARDOUR {
 class ClickIO : public IO
 {
 public:
-       ClickIO (Session& s, const std::string& name) : IO (s, name) {}
+       ClickIO (Session& s, const std::string& name) : IO (s, name, IO::Output) {}
        ~ClickIO() {}
 
 protected:
index 8d083695b18c057bc1750d0c29ee9697dfad055f..645b601251b03cf216af71f89cf16cf7963c7a14 100644 (file)
@@ -28,48 +28,91 @@ namespace ARDOUR {
 
 class BufferSet;
 class IO;
+class MuteMaster;
+class Panner;
 
 class Delivery : public IOProcessor {
 public:
        enum Role {
-               Send   = 0x1,
-               Solo   = 0x2,
+               Insert = 0x1,
+               Send   = 0x2,
                Listen = 0x4,
                Main   = 0x8
        };
 
-       Delivery (Session& s, IO* io, const std::string& name, Role);
-       Delivery (Session& s, const std::string& name, Role);
-       Delivery (Session&, const XMLNode&);
+       Delivery (Session& s, boost::shared_ptr<IO> io, boost::shared_ptr<MuteMaster> mm, const std::string& name, Role);
+       Delivery (Session& s, boost::shared_ptr<MuteMaster> mm, const std::string& name, Role);
+       Delivery (Session&, boost::shared_ptr<MuteMaster> mm, const XMLNode&);
 
+       bool set_name (const std::string& name);
        bool visible() const;
-
        Role role() const { return _role; }
-
        bool can_support_io_configuration (const ChanCount& in, ChanCount& out) const;
        bool configure_io (ChanCount in, ChanCount out);
 
        void run_in_place (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes);
 
-       void set_metering (bool yn);
-       
-       bool muted_by_self() const { return _muted_by_self; }
-       bool muted_by_others() const { return _muted_by_others; }
+       /* supplemental method use with MIDI */
+
+       void flush (nframes_t nframes);
+
+       void no_outs_cuz_we_no_monitor(bool);
+
+       void mod_solo_level (int32_t);
+       uint32_t solo_level() const { return _solo_level; }
+       bool soloed () const { return (bool) _solo_level; }
+
+       bool solo_isolated() const { return _solo_isolated; }
+       void set_solo_isolated (bool);
+
+       void cycle_start (nframes_t);
+       void increment_output_offset (nframes_t);
+       void transport_stopped (sframes_t frame);
+
+       BufferSet& output_buffers() { return *_output_buffers; }
+
+       sigc::signal<void> MuteChange;
 
-       void set_self_mute (bool);
-       void set_nonself_mute (bool);
-       
-       sigc::signal<void> SelfMuteChange;
-       sigc::signal<void> OtherMuteChange;
+       static sigc::signal<void,nframes_t> CycleStart;
 
        XMLNode& state (bool full);
        int set_state (const XMLNode&);
 
-private:
-       Role _role;
-       bool _metering;
-       bool _muted_by_self;
-       bool _muted_by_others;
+       /* Panning */
+
+       static int  disable_panners (void);
+       static int  reset_panners (void);
+
+       boost::shared_ptr<Panner> panner() const { return _panner; }
+
+       void reset_panner ();
+       void defer_pan_reset ();
+       void allow_pan_reset ();
+
+       uint32_t pans_required() const { return _configured_input.n_audio(); }
+       void start_pan_touch (uint32_t which);
+       void end_pan_touch (uint32_t which);
+
+  protected:
+       Role        _role;
+       BufferSet*  _output_buffers;
+       gain_t      _current_gain;
+       nframes_t   _output_offset;
+       bool        _no_outs_cuz_we_no_monitor;
+       uint32_t    _solo_level;
+       bool        _solo_isolated;
+       boost::shared_ptr<MuteMaster> _mute_master;
+       bool         no_panner_reset;
+       boost::shared_ptr<Panner> _panner;
+
+       static bool panners_legal;
+       static sigc::signal<int>            PannersLegal;
+
+       int panners_became_legal ();
+       sigc::connection panner_legal_c;
+       void output_changed (IOChange, void*);
+
+       gain_t target_gain ();
 };
 
 
index 23e4f576df14554d8cc8229cafec1c1c0b9829f8..3f222c6aa1709782b66d2c88d9e652b615cb0210 100644 (file)
@@ -55,134 +55,83 @@ class AudioPort;
 class BufferSet;
 class Bundle;
 class MidiPort;
-class Panner;
 class PeakMeter;
 class Port;
+class Processor;
 class Session;
 class UserBundle;
 
-/** A collection of input and output ports with connections.
+/** A collection of ports (all input or all output) with connections.
  *
  * An IO can contain ports of varying types, making routes/inserts/etc with
  * varied combinations of types (eg MIDI and audio) possible.
  */
-class IO : public SessionObject, public AutomatableControls, public Latent
+class IO : public SessionObject, public Latent
 {
   public:
        static const std::string state_node_name;
 
-       IO (Session&, const std::string& name, DataType default_type = DataType::AUDIO);
+       enum Direction {
+               Input,
+               Output
+       };
+
+       IO (Session&, const std::string& name, Direction, DataType default_type = DataType::AUDIO);
        IO (Session&, const XMLNode&, DataType default_type = DataType::AUDIO);
        
        virtual ~IO();
 
-       bool active() const { return _active; }
-       void set_active (bool yn);
-       
+       Direction direction() const { return _direction; }
+
        DataType default_type() const         { return _default_type; }
        void     set_default_type(DataType t) { _default_type = t; }
+
+       bool active() const { return _active; }
+       void set_active(bool yn) { _active = yn; }
        
        bool set_name (const std::string& str);
 
        virtual void silence  (nframes_t);
 
-       void collect_input  (BufferSet& bufs, nframes_t nframes, ChanCount offset=ChanCount::ZERO);
-       void deliver_output (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes);
-       void just_meter_input (sframes_t start_frame, sframes_t end_frame, nframes_t nframes);
-
-       BufferSet& output_buffers() { return *_output_buffers; }
-
-       gain_t         gain () const { return _gain_control->user_float(); }
-       virtual gain_t effective_gain () const;
-       
-       void set_denormal_protection (bool yn, void *src);
-       bool denormal_protection() const { return _denormal_protection; }
-       
-       void set_phase_invert (bool yn, void *src);
-       bool phase_invert() const { return _phase_invert; }
-
-       void reset_panner ();
-       
-       boost::shared_ptr<Amp> amp() const { return _amp; }
-
-       PeakMeter&       peak_meter()       { return *_meter.get(); }
-       const PeakMeter& peak_meter() const { return *_meter.get(); }
-       boost::shared_ptr<PeakMeter> shared_peak_meter() const { return _meter; }
-
-       boost::shared_ptr<Panner> panner() const { return _panner; }
-       
-       int ensure_io (ChanCount in, ChanCount out, bool clear, void *src);
+       int ensure_io (ChanCount cnt, bool clear, void *src);
 
-       int connect_input_ports_to_bundle (boost::shared_ptr<Bundle>, void *);
-       int disconnect_input_ports_from_bundle (boost::shared_ptr<Bundle>, void *);
-       int connect_output_ports_to_bundle (boost::shared_ptr<Bundle>, void *);
-       int disconnect_output_ports_from_bundle (boost::shared_ptr<Bundle>, void *);
+       int connect_ports_to_bundle (boost::shared_ptr<Bundle>, void *);
+       int disconnect_ports_from_bundle (boost::shared_ptr<Bundle>, void *);
 
-       BundleList bundles_connected_to_inputs ();
-       BundleList bundles_connected_to_outputs ();
+       BundleList bundles_connected ();
 
-       boost::shared_ptr<Bundle> bundle_for_inputs () { return _bundle_for_inputs; }
-       boost::shared_ptr<Bundle> bundle_for_outputs () { return _bundle_for_outputs; }
+       boost::shared_ptr<Bundle> bundle () { return _bundle; }
        
-       int add_input_port (std::string source, void *src, DataType type = DataType::NIL);
-       int add_output_port (std::string destination, void *src, DataType type = DataType::NIL);
-
-       int remove_input_port (Port *, void *src);
-       int remove_output_port (Port *, void *src);
-
-       int set_input (Port *, void *src);
-
-       int connect_input (Port *our_port, std::string other_port, void *src);
-       int connect_output (Port *our_port, std::string other_port, void *src);
-
-       int disconnect_input (Port *our_port, std::string other_port, void *src);
-       int disconnect_output (Port *our_port, std::string other_port, void *src);
-
-       int disconnect_inputs (void *src);
-       int disconnect_outputs (void *src);
-
+       int add_port (std::string connection, void *src, DataType type = DataType::NIL);
+       int remove_port (Port *, void *src);
+       int connect (Port *our_port, std::string other_port, void *src);
+       int disconnect (Port *our_port, std::string other_port, void *src);
+       int disconnect (void *src);
        bool connected_to (boost::shared_ptr<const IO>) const;
 
        nframes_t signal_latency() const { return _own_latency; }
-       nframes_t output_latency() const;
-       nframes_t input_latency() const;
+       nframes_t latency() const;
        void      set_port_latency (nframes_t);
 
        void update_port_total_latencies ();
 
-       const PortSet& inputs()  const { return _inputs; }
-       const PortSet& outputs() const { return _outputs; }
+       PortSet& ports() { return _ports; }
+       const PortSet& ports() const { return _ports; }
 
-       Port *output (uint32_t n) const {
-               if (n < _outputs.num_ports()) {
-                       return _outputs.port(n);
+       Port *nth (uint32_t n) const {
+               if (n < _ports.num_ports()) {
+                       return _ports.port(n);
                } else {
                        return 0;
                }
        }
 
-       Port *input (uint32_t n) const {
-               if (n < _inputs.num_ports()) {
-                       return _inputs.port(n);
-               } else {
-                       return 0;
-               }
-       }
+       AudioPort* audio(uint32_t n) const;
+       MidiPort*  midi(uint32_t n) const;
 
-       AudioPort* audio_input(uint32_t n) const;
-       AudioPort* audio_output(uint32_t n) const;
-       MidiPort*  midi_input(uint32_t n) const;
-       MidiPort*  midi_output(uint32_t n) const;
+       const ChanCount& n_ports ()  const { return _ports.count(); }
 
-       const ChanCount& n_inputs ()  const { return _inputs.count(); }
-       const ChanCount& n_outputs () const { return _outputs.count(); }
-
-       void attach_buffers(ChanCount ignored);
-       
-       sigc::signal<void>                active_changed;
-
-       sigc::signal<void,IOChange,void*> input_changed;
-       sigc::signal<void,IOChange,void*> output_changed;
+       sigc::signal<void,IOChange,void*> changed;
 
        virtual XMLNode& state (bool full);
        XMLNode& get_state (void);
@@ -192,130 +141,45 @@ class IO : public SessionObject, public AutomatableControls, public Latent
        static int  enable_connecting (void);
        static int  disable_ports (void);
        static int  enable_ports (void);
-       static int  disable_panners (void);
-       static int  reset_panners (void);
        
-       static sigc::signal<int>            PortsLegal;
-       static sigc::signal<int>            PannersLegal;
-       static sigc::signal<int>            ConnectingLegal;
-       /// raised when the number of input or output ports changes
-       static sigc::signal<void,ChanCount> PortCountChanged;
-       static sigc::signal<void,nframes_t> CycleStart;
-
-       static void update_meters();
+       static sigc::signal<void,ChanCount> PortCountChanged; // emitted when the number of ports changes
+
        static std::string name_from_state (const XMLNode&);
        static void set_name_in_state (XMLNode&, const std::string&);
 
-  private: 
-       
-       static sigc::signal<void>   Meter;
-       static Glib::StaticMutex    m_meter_signal_lock;
-       sigc::connection            m_meter_connection;
-
-  public:
-    
-       /* automation */
-
-       struct GainControl : public AutomationControl {
-           GainControl (std::string name, IO* i, const Evoral::Parameter &param,
-                   boost::shared_ptr<AutomationList> al = boost::shared_ptr<AutomationList>() )
-                       : AutomationControl (i->_session, param, al, name )
-                       , _io (i)
-               {}
-        
-           void set_value (float val);
-           float get_value (void) const;
-   
-           IO* _io;
-       };
+       /* we have to defer/order port connection. this is how we do it.
+       */
 
-       boost::shared_ptr<GainControl> gain_control() {
-               return _gain_control;
-       }
-       boost::shared_ptr<const GainControl> gain_control() const {
-               return _gain_control;
-       }
+       static sigc::signal<int> ConnectingLegal;
+       static bool              connecting_legal;
 
-       void clear_automation ();
+       XMLNode *pending_state_node;
        
-       void set_parameter_automation_state (Evoral::Parameter, AutoState);
+       /* three utility functions - this just seems to be simplest place to put them */
 
-       virtual void transport_stopped (nframes_t now);
-       virtual void automation_snapshot (nframes_t now, bool force);
+       void collect_input (BufferSet& bufs, nframes_t nframes, ChanCount offset);
+       void process_input (boost::shared_ptr<Processor>, sframes_t start_frame, sframes_t end_frame, nframes_t nframes);
+       void copy_to_outputs (BufferSet& bufs, DataType type, nframes_t nframes, nframes_t offset);
 
-       void start_pan_touch (uint32_t which);
-       void end_pan_touch (uint32_t which);
-
-       void defer_pan_reset ();
-       void allow_pan_reset ();
+       /* AudioTrack::deprecated_use_diskstream_connections() needs these */
 
-       /* the session calls this for master outs before
-          anyone else. controls outs too, at some point.
-       */
-
-       XMLNode *pending_state_node;
-       int ports_became_legal ();
+       int set_ports (const std::string& str);
 
   private:
        mutable Glib::Mutex io_lock;
 
   protected:
-       BufferSet*          _output_buffers; //< Set directly to output port buffers
-       bool                _active;
-       gain_t              _gain;
-       Glib::Mutex          declick_lock;
-       PortSet             _outputs;
-       PortSet             _inputs;
-       bool                 no_panner_reset;
-       bool                _phase_invert;
-       bool                _denormal_protection;
-       XMLNode*             deferred_state;
-       DataType            _default_type;
-       nframes_t           _output_offset;
-       
-       boost::shared_ptr<Amp>       _amp;
-       boost::shared_ptr<PeakMeter> _meter;
-       boost::shared_ptr<Panner>    _panner;
-
-       virtual void prepare_inputs (nframes_t nframes);
-       virtual void flush_outputs (nframes_t nframes);
-
-       virtual void set_deferred_state() {}
-
-       virtual uint32_t pans_required() const
-               { return _inputs.count().n_audio(); }
-
-       boost::shared_ptr<GainControl> _gain_control;
-
-       virtual void   set_gain (gain_t g, void *src);
-       void           inc_gain (gain_t delta, void *src);
-
-       virtual int load_automation (std::string path);
-
-       /* AudioTrack::deprecated_use_diskstream_connections() needs these */
-
-       int set_inputs (const std::string& str);
-       int set_outputs (const std::string& str);
-
-       void increment_output_offset (nframes_t);
-       void cycle_start (nframes_t);
-
-       static bool connecting_legal;
-       static bool ports_legal;
-
+       PortSet   _ports;
+       Direction _direction;
+       DataType _default_type;
+       bool     _active;
+            
   private:
-       static bool panners_legal;
-
-       void copy_to_outputs (BufferSet& bufs, DataType type, nframes_t nframes);
 
        int connecting_became_legal ();
-       int panners_became_legal ();
        sigc::connection connection_legal_c;
-       sigc::connection port_legal_c;
-       sigc::connection panner_legal_c;
 
-       boost::shared_ptr<Bundle> _bundle_for_inputs; ///< a bundle representing our inputs
-       boost::shared_ptr<Bundle> _bundle_for_outputs; ///< a bundle representing our outputs
+       boost::shared_ptr<Bundle> _bundle; ///< a bundle representing our ports
 
        struct UserBundleInfo {
                UserBundleInfo (IO*, boost::shared_ptr<UserBundle> b);
@@ -324,45 +188,31 @@ class IO : public SessionObject, public AutomatableControls, public Latent
                sigc::connection changed;
        };
        
-       std::vector<UserBundleInfo> _bundles_connected_to_outputs; ///< user bundles connected to our outputs
-       std::vector<UserBundleInfo> _bundles_connected_to_inputs; ///< user bundles connected to our inputs
+       std::vector<UserBundleInfo> _bundles_connected; ///< user bundles connected to our ports
 
        static int parse_io_string (const std::string&, std::vector<std::string>& chns);
-
        static int parse_gain_string (const std::string&, std::vector<std::string>& chns);
        
-       int set_sources (std::vector<std::string>&, void *src, bool add);
-       int set_destinations (std::vector<std::string>&, void *src, bool add);
-
-       int ensure_inputs (ChanCount, bool clear, bool lockit, void *src);
-       int ensure_outputs (ChanCount, bool clear, bool lockit, void *src);
+       int ensure_ports (ChanCount, bool clear, bool lockit, void *src);
 
-       void check_bundles_connected_to_inputs ();
-       void check_bundles_connected_to_outputs ();
+       void check_bundles_connected ();
        void check_bundles (std::vector<UserBundleInfo>&, const PortSet&);
 
        void bundle_changed (Bundle::Change);
 
 
-       int get_port_counts (const XMLNode& node, ChanCount& in, ChanCount& out,
-                            boost::shared_ptr<Bundle>& ic, boost::shared_ptr<Bundle>& oc);
+       int get_port_counts (const XMLNode& node, ChanCount& n, boost::shared_ptr<Bundle>& c);
        int create_ports (const XMLNode&);
        int make_connections (const XMLNode&);
-       boost::shared_ptr<Bundle> find_possible_bundle (const std::string &desired_name, const std::string &default_name, const std::string &connection_type_name);
 
-       virtual void setup_peak_meters ();
-       void meter ();
+       boost::shared_ptr<Bundle> find_possible_bundle (const std::string &desired_name);
 
-       bool ensure_inputs_locked (ChanCount, bool clear, void *src);
-       bool ensure_outputs_locked (ChanCount, bool clear, void *src);
+       bool ensure_ports_locked (ChanCount, bool clear, void *src);
 
-       std::string build_legal_port_name (DataType type, bool for_input);
-       int32_t find_input_port_hole (const char* base);
-       int32_t find_output_port_hole (const char* base);
+       std::string build_legal_port_name (DataType type);
+       int32_t find_port_hole (const char* base);
 
-       void setup_bundles_for_inputs_and_outputs ();
-       void setup_bundle_for_inputs ();
-       void setup_bundle_for_outputs ();
+       void setup_bundles ();
        std::string bundle_channel_name (uint32_t, uint32_t) const;
 };
 
index 896de52a3b939584145c42302f72aa8dd9d226ac..72be2c0743a3a80e2aa1fa3a296507b36ee5602b 100644 (file)
@@ -38,15 +38,16 @@ namespace ARDOUR {
 class Session;
 class IO;
 
-/** A mixer strip element (Processor) with Jack ports (IO).
+/** A mixer strip element (Processor) with 1 or 2 IO elements.
  */
 class IOProcessor : public Processor
 {
   public:
-       IOProcessor (Session&, const std::string& proc_name, const std::string io_name="",
-                    ARDOUR::DataType default_type = DataType::AUDIO);
-       IOProcessor (Session&, IO* io, const std::string& proc_name,
+       IOProcessor (Session&, bool with_input, bool with_output,
+                    const std::string& proc_name, const std::string io_name="",
                     ARDOUR::DataType default_type = DataType::AUDIO);
+       IOProcessor (Session&, boost::shared_ptr<IO> input, boost::shared_ptr<IO> output,
+                    const std::string& proc_name, ARDOUR::DataType default_type = DataType::AUDIO);
        virtual ~IOProcessor ();
        
        bool set_name (const std::string& str);
@@ -56,13 +57,14 @@ class IOProcessor : public Processor
        virtual ChanCount natural_output_streams() const;
        virtual ChanCount natural_input_streams () const;
 
-       boost::shared_ptr<IO>       io()       { return _io; }
-       boost::shared_ptr<const IO> io() const { return _io; }
-       void set_io (boost::shared_ptr<IO>);
+       boost::shared_ptr<IO>       input()       { return _input; }
+       boost::shared_ptr<const IO> input() const { return _input; }
+       boost::shared_ptr<IO>       output()       { return _output; }
+       boost::shared_ptr<const IO> output() const { return _output; }
+       void set_input (boost::shared_ptr<IO>);
+       void set_output (boost::shared_ptr<IO>);
        
-       virtual void automation_snapshot (nframes_t now, bool force);
-
-       virtual void run_in_place (BufferSet& in, sframes_t start, sframes_t end, nframes_t nframes) = 0;
+       void run_in_place (BufferSet& in, sframes_t start, sframes_t end, nframes_t nframes) = 0;
        void silence (nframes_t nframes);
 
        sigc::signal<void,IOProcessor*,bool>     AutomationPlaybackChanged;
@@ -72,12 +74,14 @@ class IOProcessor : public Processor
        int set_state (const XMLNode&);
        
   protected:
-       boost::shared_ptr<IO> _io;
+       boost::shared_ptr<IO> _input;
+       boost::shared_ptr<IO> _output;
 
   private:
        /* disallow copy construction */
        IOProcessor (const IOProcessor&);
-       bool _own_io;
+       bool _own_input;
+       bool _own_output;
 
 };
 
index 250fb3111eeafd2d4ddfc8bb02c8004a0c5117e8..43df5e936cf4e02ad9c38ffd0ae5d2380e21eea0 100644 (file)
@@ -20,6 +20,7 @@
 #define __ardour_meter_h__
 
 #include <vector>
+#include <sigc++/slot.h>
 #include "ardour/types.h"
 #include "ardour/processor.h"
 #include "pbd/fastlog.h"
@@ -30,6 +31,20 @@ class BufferSet;
 class ChanCount;
 class Session;
 
+class Metering {
+  public:
+       static void               update_meters ();
+       static sigc::signal<void> Meter;
+
+       static sigc::connection   connect (sigc::slot<void> the_slot);
+       static void               disconnect (sigc::connection& c);
+
+  private:
+       /* this object is not meant to be instantiated */
+       virtual void foo() = 0;
+
+       static Glib::StaticMutex    m_meter_signal_lock;
+};
 
 /** Meters peaks on the input and stores them for access.
  */
@@ -37,6 +52,8 @@ class PeakMeter : public Processor {
 public:
        PeakMeter(Session& s) : Processor(s, "Meter") {}
 
+       void meter();
+
        void reset ();
        void reset_max ();
        
@@ -66,7 +83,6 @@ public:
 
 private:
        friend class IO;
-       void meter();
 
        std::vector<float> _peak_power;
        std::vector<float> _visible_peak_power;
diff --git a/libs/ardour/ardour/mute_master.h b/libs/ardour/ardour/mute_master.h
new file mode 100644 (file)
index 0000000..d55de0c
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+    Copyright (C) 2009 Paul Davis 
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __ardour_mute_master_h__
+#define __ardour_mute_master_h__
+
+#include "evoral/Parameter.hpp"
+#include "ardour/automation_control.h"
+#include "ardour/automation_list.h"
+
+namespace ARDOUR {
+
+class Session;
+
+class MuteMaster : public AutomationControl
+{
+  public:
+       enum MutePoint {
+               PreFader  = 0x1,
+               PostFader = 0x2,
+               Listen    = 0x4,
+               Main      = 0x8
+       };
+       
+       MuteMaster (Session& s, const std::string& name);
+       ~MuteMaster() {}
+
+       bool muted_pre_fader() const  { return _mute_point & PreFader; }
+       bool muted_post_fader() const { return _mute_point & PostFader; }
+       bool muted_listen() const     { return _mute_point & Listen; }
+       bool muted_main () const      { return _mute_point & Main; }
+
+       bool muted_at (MutePoint mp) const { return _mute_point & mp; }
+       bool muted() const { return _mute_point != MutePoint (0) && get_value() != 0.0; }
+       
+       gain_t mute_gain_at (MutePoint) const;
+
+       void clear_mute ();
+       void mute_at (MutePoint);
+       void unmute_at (MutePoint);
+
+       void mute (bool yn);
+
+       /* Controllable interface */
+
+       void set_value (float); /* note: float is used as a bitfield of MutePoints */
+       float get_value () const;
+
+       sigc::signal<void> MutePointChanged;
+
+       XMLNode& get_state();
+       int set_state(const XMLNode& node);
+
+  private:
+       AutomationList* _automation;
+       MutePoint _mute_point;
+};
+
+} // namespace ARDOUR
+
+#endif /*__ardour_mute_master_h__ */
index 9bc1817af0a8925dedce6ecbfc1117f00577e733..3c66046ad1b4d1a4dd9482f2f21905584984b0d2 100644 (file)
@@ -183,7 +183,7 @@ class Multi2dPanner : public StreamPanner
 };
 
 
-class Panner : public Processor
+class Panner : public SessionObject, public AutomatableControls
 {
   public:
        struct Output {
@@ -204,18 +204,16 @@ class Panner : public Processor
        void clear_panners ();
        bool empty() const { return _streampanners.empty(); }
 
-       /// The fundamental Panner function
        void set_automation_state (AutoState);
        AutoState automation_state() const;
        void set_automation_style (AutoStyle);
        AutoStyle automation_style() const;
        bool touching() const;
 
-       bool is_in_place () const { return false; }
-       bool is_out_of_place () const { return true; }
        bool can_support_io_configuration (const ChanCount& in, ChanCount& out) const { return true; };
 
-       void run_out_of_place(BufferSet& src, BufferSet& dest, sframes_t start_frame, sframes_t end_frames, nframes_t nframes);
+       /// The fundamental Panner function
+       void run (BufferSet& src, BufferSet& dest, sframes_t start_frame, sframes_t end_frames, nframes_t nframes);
 
        //void* get_inline_gui() const = 0;
        //void* get_full_gui() const = 0;
index 56aa43c6c5f5717fed777383cae94c06ad884d51..fa9c31efe6a45aacc9c302465917f69061ca966f 100644 (file)
@@ -34,25 +34,28 @@ class XMLNode;
 namespace ARDOUR {
 
 class Session;
+class IO;
+class Delivery;
+class MuteMaster;
 
 /** Port inserts: send output to a Jack port, pick up input at a Jack port
  */
 class PortInsert : public IOProcessor
 {
   public:
-       PortInsert (Session&);
-       PortInsert (Session&, const XMLNode&);
+       PortInsert (Session&, boost::shared_ptr<MuteMaster> mm);
+       PortInsert (Session&, boost::shared_ptr<MuteMaster> mm, const XMLNode&);
        ~PortInsert ();
 
        XMLNode& state(bool full);
        XMLNode& get_state(void);
        int set_state(const XMLNode&);
 
-       void init ();
-       
        void run_in_place (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes);
 
        nframes_t signal_latency() const;
+
+       bool set_name (const std::string& name);
        
        bool can_support_io_configuration (const ChanCount& in, ChanCount& out) const;
        bool configure_io (ChanCount in, ChanCount out);
@@ -62,6 +65,8 @@ class PortInsert : public IOProcessor
   private:
        /* disallow copy construction */
        PortInsert (const PortInsert&);
+
+       boost::shared_ptr<Delivery> _out;
        
        uint32_t bitslot;
 };
index 73a93b31d93377be9ea6e57e1ce5975108469282..61a266e9c5e333226fe032165f8ce7988361b332 100644 (file)
@@ -53,24 +53,26 @@ class Processor : public SessionObject, public AutomatableControls, public Laten
        
        virtual ~Processor() { }
        
-       /** Configuration of a processor on a bus
-        * (i.e. how to apply to a BufferSet)
-        */
-       struct Mapping {
-           ChanCount in;
-           ChanCount out;
-       };
-
        virtual bool visible() const { return true; }
        
        bool active () const { return _active; }
+
+       /* we keep loose tabs on the "placement" of a Processor. Ultimately,
+          they are all executed as a single list, but there are some
+          semantics that require knowing whether a Processor is before
+          or after the fader, or panner etc. See Route::reorder_processors()
+          to see where this gets set.
+       */
+
+       Placement placement() const { return _placement; }
+       void set_placement (Placement p) { _placement = p; }
        
        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; }
        
        virtual nframes_t signal_latency() const { return 0; }
        
-       virtual void transport_stopped (nframes_t frame) {}
+       virtual void transport_stopped (sframes_t frame) {}
        
        virtual void set_block_size (nframes_t nframes) {}
 
@@ -127,7 +129,7 @@ protected:
        ChanCount _configured_input;
        ChanCount _configured_output;
        void*     _gui;  /* generic, we don't know or care what this is */
-       Mapping   _mapping;
+       Placement _placement;
 };
 
 } // namespace ARDOUR
index 99ac9026293a32f708bc44408c48140d977fbbb3..1a4c49fe64323b6e254d3fcef9aaff51e0cf86cc 100644 (file)
@@ -84,6 +84,7 @@ CONFIG_VARIABLE (bool, all_safe, "all-safe", false)
 CONFIG_VARIABLE (bool, show_solo_mutes, "show-solo-mutes", false)
 CONFIG_VARIABLE (bool, solo_mute_override, "solo-mute-override", false)
 CONFIG_VARIABLE (bool, tape_machine_mode, "tape-machine-mode", false)
+CONFIG_VARIABLE (gain_t, solo_mute_gain, "solo_mute-gain", 0.0)
 
 /* click */
 
index 2b6cd0b69eaea82781723faa4bc3aa1cfa0dee29..5c2a82e3aa6cf48f0b1565dbd682f616e1878020 100644 (file)
@@ -32,6 +32,9 @@
 
 namespace ARDOUR {
 
+class Amp;
+class PeakMeter;
+
 class Return : public IOProcessor 
 {
 public:        
@@ -43,9 +46,12 @@ public:
 
        void run_in_place (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes);
        
-       void activate() {}
-       void deactivate () {}
+       boost::shared_ptr<Amp> amp() const { return _amp; }
+       boost::shared_ptr<PeakMeter> meter() const { return _meter; }
 
+       bool metering() const { return _metering; }
+       void set_metering (bool yn) { _metering = yn; }
+       
        XMLNode& state(bool full);
        XMLNode& get_state(void);
        int      set_state(const XMLNode& node);
@@ -55,14 +61,22 @@ public:
        bool can_support_io_configuration (const ChanCount& in, ChanCount& out) const;
        bool configure_io (ChanCount in, ChanCount out);
 
-       static uint32_t how_many_sends();
+       static uint32_t how_many_returns();
        static void make_unique (XMLNode &, Session &);
 
+  protected:
+       bool _metering;
+       boost::shared_ptr<Amp> _amp;
+       boost::shared_ptr<PeakMeter> _meter;
+
 private:
        /* disallow copy construction */
        Return (const Return&);
        
        uint32_t  _bitslot;
+
+       void collect_input  (BufferSet& bufs, nframes_t nframes, ChanCount offset=ChanCount::ZERO);
+       void just_meter_input (sframes_t start_frame, sframes_t end_frame, nframes_t nframes);
 };
 
 } // namespace ARDOUR
index 8de82bb2199460c907093f817a033f55d0e9bc17..a2ad7165921fa8826b544d40c23a6d183a4f3c92 100644 (file)
 #include "ardour/ardour.h"
 #include "ardour/io.h"
 #include "ardour/types.h"
+#include "ardour/mute_master.h"
 
 namespace ARDOUR {
 
 class Amp;
 class Delivery;
 class IOProcessor;
+class Panner;
 class Processor;
 class RouteGroup;
 class Send;
 
-enum mute_type {
-    PRE_FADER =    0x1,
-    POST_FADER =   0x2,
-    CONTROL_OUTS = 0x4,
-    MAIN_OUTS =    0x8
-};
-
-class Route : public IO
+class Route : public SessionObject, public AutomatableControls
 {
   public:
 
@@ -75,6 +70,16 @@ class Route : public IO
        Route (Session&, const XMLNode&, DataType default_type = DataType::AUDIO);
        virtual ~Route();
 
+       boost::shared_ptr<IO> input() const { return _input; }
+       boost::shared_ptr<IO> output() const { return _output; }
+
+       ChanCount n_inputs() const { return _input->n_ports(); }
+       ChanCount n_outputs() const { return _output->n_ports(); }
+
+       bool active() const { return _active; }
+       void set_active (bool yn);
+
+
        static std::string ensure_track_or_route_name(std::string, Session &);
 
        std::string comment() { return _comment; }
@@ -102,6 +107,7 @@ class Route : public IO
 
        virtual void toggle_monitor_input ();
        virtual bool can_record() { return false; }
+
        virtual void set_record_enable (bool yn, void *src) {}
        virtual bool record_enabled() const { return false; }
        virtual void handle_transport_stopped (bool abort, bool did_locate, bool flush_processors);
@@ -110,38 +116,44 @@ class Route : public IO
        /* end of vfunc-based API */
 
        void shift (nframes64_t, nframes64_t);
-
-       /* override IO::set_gain() to provide group control */
-
+       
        void set_gain (gain_t val, void *src);
        void inc_gain (gain_t delta, void *src);
-       
+
+       void set_mute (bool yn, void* src);
+       bool muted () const;
+
        void set_solo (bool yn, void *src);
-       bool soloed() const { return _soloed; }
+       bool soloed() const;
 
-       void set_solo_safe (bool yn, void *src);
-       bool solo_safe() const { return _solo_safe; }
+       void set_solo_isolated (bool yn, void *src);
+       bool solo_isolated() const;
        
-       void set_mute (bool yn, void *src);
-       bool muted() const { return _muted; }
-       bool solo_muted() const { return desired_solo_gain == 0.0; }
+       void set_phase_invert (bool yn, void* src);
+       bool phase_invert() const;
 
-       void set_mute_config (mute_type, bool, void *src);
-       bool get_mute_config (mute_type);
+       void set_denormal_protection (bool yn, void* src);
+       bool denormal_protection() const;
 
        void       set_edit_group (RouteGroup *, void *);
        void       drop_edit_group (void *);
-       RouteGroup *edit_group () { return _edit_group; }
+       RouteGroup *edit_group () const { return _edit_group; }
 
        void       set_mix_group (RouteGroup *, void *);
        void       drop_mix_group (void *);
-       RouteGroup *mix_group () { return _mix_group; }
+       RouteGroup *mix_group () const { return _mix_group; }
 
        virtual void set_meter_point (MeterPoint, void *src);
        MeterPoint   meter_point() const { return _meter_point; }
+       void         meter ();
 
        /* Processors */
 
+       boost::shared_ptr<Amp> amp() const  { return _amp; }
+       PeakMeter&       peak_meter()       { return *_meter.get(); }
+       const PeakMeter& peak_meter() const { return *_meter.get(); }
+       boost::shared_ptr<PeakMeter> shared_peak_meter() const { return _meter; }
+
        void flush_processors ();
 
        void foreach_processor (sigc::slot<void, boost::weak_ptr<Processor> > method) {
@@ -180,7 +192,7 @@ class Route : public IO
 
        boost::shared_ptr<Delivery> control_outs() const { return _control_outs; }
        boost::shared_ptr<Delivery> main_outs() const { return _main_outs; }
-
+       
        boost::shared_ptr<Send> send_for (boost::shared_ptr<const IO> target) const;
        
        /** A record of the stream configuration at some point in the processor list.
@@ -213,8 +225,10 @@ class Route : public IO
        void set_user_latency (nframes_t);
        nframes_t initial_delay() const { return _initial_delay; }
 
+       sigc::signal<void>       active_changed;
        sigc::signal<void,void*> solo_changed;
        sigc::signal<void,void*> solo_safe_changed;
+       sigc::signal<void,void*> solo_isolated_changed;
        sigc::signal<void,void*> comment_changed;
        sigc::signal<void,void*> mute_changed;
        sigc::signal<void,void*> pre_fader_changed;
@@ -240,8 +254,8 @@ class Route : public IO
        virtual XMLNode& get_template();
 
        XMLNode& get_processor_state ();
-       int set_processor_state (const XMLNode&);
-
+       virtual void set_processor_state (const XMLNode&);
+       
        int save_as_template (const std::string& path, const std::string& name);
 
        sigc::signal<void,void*> SelectedChanged;
@@ -252,28 +266,38 @@ class Route : public IO
        bool feeds (boost::shared_ptr<IO>);
        std::set<boost::shared_ptr<Route> > fed_by;
 
-       struct ToggleControllable : public PBD::Controllable {
-           enum ToggleType {
-                   MuteControl = 0,
-                   SoloControl
-           };
-           
-           ToggleControllable (std::string name, Route&, ToggleType);
-           void set_value (float);
-           float get_value (void) const;
-
-           Route& route;
-           ToggleType type;
+       /* Controls (not all directly owned by the Route */
+
+       boost::shared_ptr<AutomationControl> get_control (const Evoral::Parameter& param);
+
+       struct SoloControllable : public AutomationControl {
+               SoloControllable (std::string name, Route&);
+               void set_value (float);
+               float get_value (void) const;
+               
+               Route& route;
        };
 
-       boost::shared_ptr<PBD::Controllable> solo_control() {
+       boost::shared_ptr<AutomationControl> solo_control() const {
                return _solo_control;
        }
 
-       boost::shared_ptr<PBD::Controllable> mute_control() {
-               return _mute_control;
+       boost::shared_ptr<AutomationControl> mute_control() const {
+               return _mute_master;
        }
-       
+
+       boost::shared_ptr<MuteMaster> mute_master() const { 
+               return _mute_master; 
+       }
+
+       /* Route doesn't own these items, but sub-objects that it does own have them
+          and to make UI code a bit simpler, we provide direct access to them
+          here.
+       */
+
+       boost::shared_ptr<Panner> panner() const;
+       boost::shared_ptr<AutomationControl> gain_control() const;
+
        void automation_snapshot (nframes_t now, bool force=false);
        void protect_automation ();
        
@@ -288,10 +312,11 @@ class Route : public IO
        friend class Session;
 
        void catch_up_on_solo_mute_override ();
-       void set_solo_mute (bool yn);
+       void mod_solo_level (int32_t);
        void set_block_size (nframes_t nframes);
        bool has_external_redirects() const;
        void curve_reallocate ();
+       void just_meter_input (sframes_t start_frame, sframes_t end_frame, nframes_t nframes);
 
   protected:
        nframes_t check_initial_delay (nframes_t, nframes_t&);
@@ -303,44 +328,38 @@ class Route : public IO
                                             sframes_t start_frame, sframes_t end_frame,
                                             nframes_t nframes, bool with_processors, int declick);
        
-       Flag           _flags;
-       int            _pending_declick;
-       MeterPoint     _meter_point;
+       boost::shared_ptr<IO> _input;
+       boost::shared_ptr<IO> _output;
 
-       gain_t          solo_gain;
-       gain_t          mute_gain;
-       gain_t          desired_solo_gain;
-       gain_t          desired_mute_gain;
-       
+       bool           _active;
        nframes_t      _initial_delay;
        nframes_t      _roll_delay;
+
        ProcessorList  _processors;
        mutable Glib::RWLock   _processor_lock;
        boost::shared_ptr<Delivery> _main_outs;
        boost::shared_ptr<Delivery> _control_outs; // XXX to be removed/generalized by listen points
-       RouteGroup    *_edit_group;
-       RouteGroup    *_mix_group;
-       std::string    _comment;
-       bool           _have_internal_generator;
-       
-       boost::shared_ptr<ToggleControllable> _solo_control;
-       boost::shared_ptr<ToggleControllable> _mute_control;
-
-       /* tight cache-line access here is more important than sheer speed of access.
-          keep these after things that should be aligned
-       */
 
-       bool _muted : 1;
-       bool _soloed : 1;
-       bool _solo_safe : 1;
+       Flag           _flags;
+       int            _pending_declick;
+       MeterPoint     _meter_point;
+       uint32_t       _phase_invert;
+       bool           _denormal_protection;
+       
        bool _recordable : 1;
-       bool _mute_affects_pre_fader : 1;
-       bool _mute_affects_post_fader : 1;
-       bool _mute_affects_control_outs : 1;
-       bool _mute_affects_main_outs : 1;
        bool _silent : 1;
        bool _declickable : 1;
 
+       boost::shared_ptr<SoloControllable> _solo_control;
+       boost::shared_ptr<MuteMaster> _mute_master;
+
+       RouteGroup*    _edit_group;
+       RouteGroup*    _mix_group;
+       std::string    _comment;
+       bool           _have_internal_generator;
+       bool           _solo_safe;
+       DataType       _default_type;
+
   protected:
 
        virtual XMLNode& state(bool);
@@ -358,13 +377,14 @@ class Route : public IO
        uint32_t pans_required() const;
        ChanCount n_process_buffers ();
        
-       void setup_peak_meters ();
-
        virtual int  _set_state (const XMLNode&, bool call_base);
-       virtual void _set_processor_states (const XMLNodeList&);
 
        boost::shared_ptr<Delivery> add_listener (boost::shared_ptr<IO>, const std::string&);
 
+       boost::shared_ptr<Amp>       _amp;
+       boost::shared_ptr<PeakMeter> _meter;
+       sigc::connection _meter_connection;
+
   private:
        void init ();
 
@@ -386,8 +406,7 @@ class Route : public IO
 
        int configure_processors (ProcessorStreams*);
        int configure_processors_unlocked (ProcessorStreams*);
-       
-       void set_deferred_state ();
+
        bool add_processor_from_xml (const XMLNode&, Placement);
        bool add_processor_from_xml (const XMLNode&, ProcessorList::iterator iter);     
 
index b47263b547e87083add5567876382194a2ab21f9..302f512c9c71926f712fb4d8de4d2e2d54d2ddf5 100644 (file)
 #include <sigc++/signal.h>
 #include <string>
 
-
 #include "pbd/stateful.h" 
+
 #include "ardour/ardour.h"
 #include "ardour/audioengine.h"
 #include "ardour/delivery.h"
 
 namespace ARDOUR {
 
+class PeakMeter;
+class Amp;
+
 class Send : public Delivery
 {
   public:      
-       Send (Session&);
-       Send (Session&, const XMLNode&);
+       Send (Session&, boost::shared_ptr<MuteMaster>);
+       Send (Session&, boost::shared_ptr<MuteMaster>, const XMLNode&);
        virtual ~Send ();
 
        uint32_t bit_slot() const { return _bitslot; }
-       
-       void activate() {}
-       void deactivate () {}
 
+       boost::shared_ptr<Amp> amp() const { return _amp; }
+       boost::shared_ptr<PeakMeter> meter() const { return _meter; }
+
+       bool metering() const { return _metering; }
+       void set_metering (bool yn) { _metering = yn; }
+       
        XMLNode& state(bool full);
        XMLNode& get_state(void);
        int set_state(const XMLNode& node);
 
        uint32_t pans_required() const { return _configured_input.n_audio(); }
 
+       void run_in_place (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes);
+
        bool can_support_io_configuration (const ChanCount& in, ChanCount& out) const;
-       bool configure_io (ChanCount in, ChanCount out);
 
        bool set_name (const std::string& str);
 
        static uint32_t how_many_sends();
        static void make_unique (XMLNode &, Session &);
 
+  protected:
+       bool _metering;
+       boost::shared_ptr<Amp> _amp;
+       boost::shared_ptr<PeakMeter> _meter;
+
   private:
        /* disallow copy construction */
        Send (const Send&);
index 3d85c8d200de6338255e6563f49fb435fe0fd53e..d476a958d84c11730c366cc1349373d7f1dbd7a1 100644 (file)
@@ -730,8 +730,8 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable
 
        /* session-wide solo/mute/rec-enable */
 
-       bool soloing() const { return currently_soloing; }
-
+       bool soloing() const { return _non_soloed_outs_muted; }
+       
        void set_all_solo (bool);
        void set_all_mute (bool);
 
@@ -743,8 +743,8 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable
 
        /* control/master out */
 
-       boost::shared_ptr<IO> control_out() const { return _control_out; }
-       boost::shared_ptr<IO> master_out() const { return _master_out; }
+       boost::shared_ptr<Route> control_out() const { return _control_out; }
+       boost::shared_ptr<Route> master_out() const { return _master_out; }
 
        /* insert/send management */
 
@@ -1040,6 +1040,7 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable
        bool                    _have_captured;
        float                   _meter_hold;
        float                   _meter_falloff;
+       bool                    _non_soloed_outs_muted;
 
        void set_worst_io_latencies ();
        void set_worst_io_latencies_x (IOChange asifwecare, void *ignored) {
@@ -1688,8 +1689,8 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable
        /* main outs */
        uint32_t main_outs;
 
-       boost::shared_ptr<IO> _master_out;
-       boost::shared_ptr<IO> _control_out;
+       boost::shared_ptr<Route> _master_out;
+       boost::shared_ptr<Route> _control_out;
 
        gain_t* _gain_automation_buffer;
        pan_t** _pan_automation_buffer;
index 910239f6305e1ca59fa64cb61c8258b871281af8..4e8e2bf12d9b1975bc6305e8d988d7e446ccce03 100644 (file)
@@ -160,6 +160,8 @@ AudioDiskstream::free_working_buffers()
 void
 AudioDiskstream::non_realtime_input_change ()
 {
+       cerr << "AD::NRIC ... " << name() << endl;
+
        {
                Glib::Mutex::Lock lm (state_lock);
 
@@ -173,10 +175,10 @@ AudioDiskstream::non_realtime_input_change ()
                        
                        _n_channels.set(DataType::AUDIO, c->size());
                        
-                       if (_io->n_inputs().n_audio() > _n_channels.n_audio()) {
-                               add_channel_to (c, _io->n_inputs().n_audio() - _n_channels.n_audio());
-                       } else if (_io->n_inputs().n_audio() < _n_channels.n_audio()) {
-                               remove_channel_from (c, _n_channels.n_audio() - _io->n_inputs().n_audio());
+                       if (_io->n_ports().n_audio() > _n_channels.n_audio()) {
+                               add_channel_to (c, _io->n_ports().n_audio() - _n_channels.n_audio());
+                       } else if (_io->n_ports().n_audio() < _n_channels.n_audio()) {
+                               remove_channel_from (c, _n_channels.n_audio() - _io->n_ports().n_audio());
                        }
                }
                
@@ -227,14 +229,14 @@ AudioDiskstream::get_input_sources ()
 
        uint32_t n;
        ChannelList::iterator chan;
-       uint32_t ni = _io->n_inputs().n_audio();
+       uint32_t ni = _io->n_ports().n_audio();
        vector<string> connections;
 
        for (n = 0, chan = c->begin(); chan != c->end() && n < ni; ++chan, ++n) {
                
                connections.clear ();
 
-               if (_io->input(n)->get_connections (connections) == 0) {
+               if (_io->nth (n)->get_connections (connections) == 0) {
                
                        if ((*chan)->source) {
                                // _source->disable_metering ();
@@ -633,7 +635,7 @@ AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can
 
        if (nominally_recording || rec_nframes) {
 
-               uint32_t limit = _io->n_inputs ().n_audio();
+               uint32_t limit = _io->n_ports ().n_audio();
 
                /* one or more ports could already have been removed from _io, but our
                   channel setup hasn't yet been updated. prevent us from trying to
@@ -656,7 +658,7 @@ AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can
                                   for recording, and use rec_offset
                                */
 
-                               AudioPort* const ap = _io->audio_input(n);
+                               AudioPort* const ap = _io->audio (n);
                                assert(ap);
                                assert(rec_nframes <= ap->get_audio_buffer(nframes).capacity());
                                memcpy (chaninfo->current_capture_buffer, ap->get_audio_buffer (rec_nframes).data(rec_offset), sizeof (Sample) * rec_nframes);
@@ -671,7 +673,7 @@ AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can
                                        goto out;
                                }
 
-                               AudioPort* const ap = _io->audio_input(n);
+                               AudioPort* const ap = _io->audio (n);
                                assert(ap);
 
                                Sample* buf = ap->get_audio_buffer(nframes).data();
@@ -1822,7 +1824,7 @@ AudioDiskstream::finish_capture (bool rec_monitors_input, boost::shared_ptr<Chan
 void
 AudioDiskstream::set_record_enabled (bool yn)
 {
-       if (!recordable() || !_session.record_enabling_legal() || _io->n_inputs().n_audio() == 0) {
+       if (!recordable() || !_session.record_enabling_legal() || _io->n_ports().n_audio() == 0) {
                return;
        }
 
@@ -2110,6 +2112,8 @@ AudioDiskstream::reset_write_sources (bool mark_write_complete, bool force)
        boost::shared_ptr<ChannelList> c = channels.reader();
        uint32_t n;
 
+       cerr << _name << " RWS!!!\n";
+
        if (!recordable()) {
                return;
        }
index 70e317c880ab99fcec4e6afe5adb0a1a799f46d2..a41fdbe6b6d0a93b08d37f25f325d611c97dc898 100644 (file)
@@ -36,6 +36,7 @@
 #include "ardour/buffer_set.h"
 #include "ardour/io_processor.h"
 #include "ardour/panner.h"
+#include "ardour/meter.h"
 #include "ardour/playlist_factory.h"
 #include "ardour/plugin_insert.h"
 #include "ardour/processor.h"
@@ -140,8 +141,7 @@ AudioTrack::deprecated_use_diskstream_connections ()
        diskstream->deprecated_io_node = 0;
 
        if ((prop = node.property ("gain")) != 0) {
-               set_gain (atof (prop->value().c_str()), this);
-               _gain = _gain_control->user_float();
+               _amp->set_gain (atof (prop->value().c_str()), this);
        }
 
        if ((prop = node.property ("input-connection")) != 0) {
@@ -160,10 +160,10 @@ AudioTrack::deprecated_use_diskstream_connections ()
                        }
                }
 
-               connect_input_ports_to_bundle (c, this);
+               _input->connect_ports_to_bundle (c, this);
 
        } else if ((prop = node.property ("inputs")) != 0) {
-               if (set_inputs (prop->value())) {
+               if (_input->set_ports (prop->value())) {
                        error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg;
                        return -1;
                }
@@ -176,14 +176,14 @@ int
 AudioTrack::set_diskstream (boost::shared_ptr<AudioDiskstream> ds, void *src)
 {
        _diskstream = ds;
-       _diskstream->set_io (*this);
+       _diskstream->set_io (*(_input.get()));
        _diskstream->set_destructive (_mode == Destructive);
        _diskstream->set_non_layered (_mode == NonLayered);
 
        if (audio_diskstream()->deprecated_io_node) {
 
-               if (!connecting_legal) {
-                       ConnectingLegal.connect (mem_fun (*this, &AudioTrack::deprecated_use_diskstream_connections));
+               if (!IO::connecting_legal) {
+                       IO::ConnectingLegal.connect (mem_fun (*this, &AudioTrack::deprecated_use_diskstream_connections));
                } else {
                        deprecated_use_diskstream_connections ();
                }
@@ -193,7 +193,7 @@ AudioTrack::set_diskstream (boost::shared_ptr<AudioDiskstream> ds, void *src)
        _diskstream->monitor_input (false);
 
        ic_connection.disconnect();
-       ic_connection = input_changed.connect (mem_fun (*_diskstream, &Diskstream::handle_input_change));
+       ic_connection = _input->changed.connect (mem_fun (*_diskstream, &Diskstream::handle_input_change));
 
        DiskstreamChanged (); /* EMIT SIGNAL */
 
@@ -479,8 +479,6 @@ AudioTrack::roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame,
 
        transport_frame = _session.transport_frame();
 
-       prepare_inputs (nframes);
-
        if ((nframes = check_initial_delay (nframes, transport_frame)) == 0) {
 
                /* need to do this so that the diskstream sets its
@@ -501,7 +499,7 @@ AudioTrack::roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame,
        /* special condition applies */
        
        if (_meter_point == MeterInput) {
-               just_meter_input (start_frame, end_frame, nframes);
+               _input->process_input (_meter, start_frame, end_frame, nframes);
        }
 
        if (diskstream->record_enabled() && !can_record && !_session.config.get_auto_input()) {
@@ -599,6 +597,7 @@ AudioTrack::roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame,
                /* don't waste time with automation if we're recording or we've just stopped (yes it can happen) */
 
                if (!diskstream->record_enabled() && _session.transport_rolling()) {
+#ifdef XXX_MOVE_THIS_TO_AMP
                        Glib::Mutex::Lock am (data().control_lock(), Glib::TRY_LOCK);
                        
                        if (am.locked() && gain_control()->automation_playback()) {
@@ -606,6 +605,7 @@ AudioTrack::roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame,
                                                gain_control()->list()->curve().rt_safe_get_vector (
                                                        start_frame, end_frame, _session.gain_automation_buffer(), nframes));
                        }
+#endif
                }
 
                process_output_buffers (bufs, start_frame, end_frame, nframes, (!_session.get_record_enabled() || !Config->get_do_not_record_plugins()), declick);
@@ -759,9 +759,9 @@ AudioTrack::freeze (InterThreadInfo& itt)
 
        new_playlist = PlaylistFactory::create (DataType::AUDIO, _session, new_playlist_name, false);
 
-       _freeze_record.gain = _gain;
-       _freeze_record.gain_automation_state = _gain_control->automation_state();
-       _freeze_record.pan_automation_state = _panner->automation_state();
+       _freeze_record.gain = _amp->gain();
+       _freeze_record.gain_automation_state = _amp->gain_control()->automation_state();
+       /* XXX need main outs automation state _freeze_record.pan_automation_state = _mainpanner->automation_state(); */
 
        region_name = new_playlist_name;
 
@@ -784,8 +784,8 @@ AudioTrack::freeze (InterThreadInfo& itt)
        /* reset stuff that has already been accounted for in the freeze process */
        
        set_gain (1.0, this);
-       _gain_control->set_automation_state (Off);
-       _panner->set_automation_state (Off);
+       _amp->gain_control()->set_automation_state (Off);
+       /* XXX need to use _main_outs _panner->set_automation_state (Off); */
 
        _freeze_record.state = Frozen;
        FreezeChange(); /* EMIT SIGNAL */
@@ -811,8 +811,8 @@ AudioTrack::unfreeze ()
                
                _freeze_record.playlist.reset ();
                set_gain (_freeze_record.gain, this);
-               _gain_control->set_automation_state (_freeze_record.gain_automation_state);
-               _panner->set_automation_state (_freeze_record.pan_automation_state);
+               _amp->gain_control()->set_automation_state (_freeze_record.gain_automation_state);
+               /* XXX need to use _main_outs _panner->set_automation_state (_freeze_record.pan_automation_state); */
        }
 
        _freeze_record.state = UnFrozen;
index fe9c064efaf49275bc7f11e58a727f2ff343ef83..b563537cb39b4913f0ba7cf2898a095e8f9dc3f2 100644 (file)
 
 #include "ardour/audioengine.h"
 #include "ardour/buffer.h"
+#include "ardour/delivery.h"
 #include "ardour/port.h"
 #include "ardour/audio_port.h"
 #include "ardour/midi_port.h"
+#include "ardour/meter.h"
 #include "ardour/session.h"
 #include "ardour/cycle_timer.h"
 #include "ardour/utils.h"
@@ -358,9 +360,9 @@ AudioEngine::process_callback (nframes_t nframes)
                return 0;
        }
 
-       /* tell all IO objects that we're starting a new cycle */
+       /* tell all relevant objects that we're starting a new cycle */
 
-       IO::CycleStart (nframes);
+       Delivery::CycleStart (nframes);
        Port::set_port_offset (0);
 
        /* tell all Ports that we're starting a new cycle */
@@ -519,7 +521,7 @@ AudioEngine::meter_thread ()
                if (g_atomic_int_get(&m_meter_exit)) {
                        break;
                }
-               IO::update_meters ();
+               Metering::update_meters ();
        }
 }
 
index b62d0f340665a7912a63463e78596832a45a992d..35a1b70137456fc1e201aecda0fbb8ad82bc8a96 100644 (file)
@@ -24,6 +24,7 @@
 #include "ardour/audio_diskstream.h"
 #include "ardour/audioregion.h"
 #include "ardour/audioengine.h"
+#include "ardour/delivery.h"
 #include "ardour/route.h"
 #include "ardour/session.h"
 #include "ardour/auditioner.h"
@@ -57,22 +58,21 @@ Auditioner::Auditioner (Session& s)
                return;
        }
 
-       defer_pan_reset ();
+       _main_outs->defer_pan_reset ();
 
        if (left.length()) {
-               add_output_port (left, this, DataType::AUDIO);
+               _output->add_port (left, this, DataType::AUDIO);
        }
 
        if (right.length()) {
                audio_diskstream()->add_channel (1);
-               add_output_port (right, this, DataType::AUDIO);
+               _output->add_port (right, this, DataType::AUDIO);
        }
-
-       allow_pan_reset ();
        
-       reset_panner ();
+       _main_outs->allow_pan_reset ();
+       _main_outs->reset_panner ();
 
-       IO::output_changed.connect (mem_fun (*this, &Auditioner::output_changed));
+       _output->changed.connect (mem_fun (*this, &Auditioner::output_changed));
 
        the_region.reset ((AudioRegion*) 0);
        g_atomic_int_set (&_active, 0);
@@ -110,7 +110,7 @@ Auditioner::audition_current_playlist ()
 
        /* force a panner reset now that we have all channels */
 
-       _panner->reset (n_outputs().n_audio(), _diskstream->n_channels().n_audio());
+       _main_outs->panner()->reset (n_outputs().n_audio(), _diskstream->n_channels().n_audio());
 
        g_atomic_int_set (&_active, 1);
 }
@@ -148,7 +148,7 @@ Auditioner::audition_region (boost::shared_ptr<Region> region)
 
        /* force a panner reset now that we have all channels */
 
-       reset_panner();
+       _main_outs->reset_panner();
 
        length = the_region->length();
 
@@ -206,7 +206,7 @@ Auditioner::output_changed (IOChange change, void* src)
 
        if (change & ConnectionsChanged) {
                vector<string> connections;
-               if (output (0)->get_connections (connections)) {
+               if (_output->nth (0)->get_connections (connections)) {
                        phys = _session.engine().get_nth_physical_output (DataType::AUDIO, 0);
                        if (phys != connections[0]) {
                                _session.config.set_auditioner_output_left (connections[0]);
@@ -219,7 +219,7 @@ Auditioner::output_changed (IOChange change, void* src)
                
                connections.clear ();
 
-               if (output (1)->get_connections (connections)) {
+               if (_output->nth (1)->get_connections (connections)) {
                        phys = _session.engine().get_nth_physical_output (DataType::AUDIO, 1);
                        if (phys != connections[0]) {
                                _session.config.set_auditioner_output_right (connections[0]);
index 0fa4e9c67afb81122482cd63fe5125a775a0a593..bf08a4026cf5423b400eaec70a8c70c75bc3ad03 100644 (file)
 #include <errno.h>
 #include "pbd/error.h"
 #include "pbd/enumwriter.h"
+
 #include "midi++/names.h"
+
 #include "ardour/automatable.h"
+#include "ardour/amp.h"
 #include "ardour/event_type_map.h"
 #include "ardour/midi_track.h"
 #include "ardour/panner.h"
@@ -382,7 +385,7 @@ Automatable::automation_snapshot (nframes_t now, bool force)
 }
 
 void
-Automatable::transport_stopped (nframes_t now)
+Automatable::transport_stopped (sframes_t now)
 {
        for (Controls::iterator li = controls().begin(); li != controls().end(); ++li) {
                
@@ -409,7 +412,7 @@ Automatable::control_factory(const Evoral::Parameter& param)
        } else if (param.type() == PluginAutomation) {
                control = new PluginInsert::PluginControl((PluginInsert*)this, param);
        } else if (param.type() == GainAutomation) {
-               control = new IO::GainControl( X_("gaincontrol"), (IO*)this, param);
+               control = new Amp::GainControl( X_("gaincontrol"), _a_session, (Amp*)this, param);
        } else if (param.type() == PanAutomation) {
                Panner* me = dynamic_cast<Panner*>(this);
                if (me) {
index bf152420940a86a30ec2be40ae39edc2778fb0ea..75b026618b6d1a27c5115881572ed73e5d05c33f 100644 (file)
 #include <algorithm>
 
 #include "pbd/enumwriter.h"
+#include "pbd/convert.h"
+
 #include "ardour/delivery.h"
 #include "ardour/audio_buffer.h"
+#include "ardour/amp.h"
 #include "ardour/buffer_set.h"
 #include "ardour/configuration.h"
 #include "ardour/io.h"
 #include "ardour/meter.h"
+#include "ardour/mute_master.h"
+#include "ardour/panner.h"
+#include "ardour/port.h"
 #include "ardour/session.h"
 
+#include "i18n.h"
+
 using namespace std;
+using namespace PBD;
 using namespace ARDOUR;
 
+sigc::signal<void,nframes_t> Delivery::CycleStart;
+sigc::signal<int>            Delivery::PannersLegal;
+bool                         Delivery::panners_legal = false;
+
 /* deliver to an existing IO object */
 
-Delivery::Delivery (Session& s, IO* io, const string& name, Role r)
-       : IOProcessor(s, io, name)
+Delivery::Delivery (Session& s, boost::shared_ptr<IO> io, boost::shared_ptr<MuteMaster> mm, const string& name, Role r)
+       : IOProcessor(s, boost::shared_ptr<IO>(), io, name)
        , _role (r)
-       , _metering (false)
-       , _muted_by_self (false)
-       , _muted_by_others (false)
+       , _output_buffers (new BufferSet())
+       , _solo_level (0)
+       , _solo_isolated (false)
+       , _mute_master (mm)
 {
+       _output_offset = 0;
+       _current_gain = 1.0;
+       _panner = boost::shared_ptr<Panner>(new Panner (_name, _session));
+       
+       _output->changed.connect (mem_fun (*this, &Delivery::output_changed));
 }
 
 /* deliver to a new IO object */
 
-Delivery::Delivery (Session& s, const string& name, Role r)
-       : IOProcessor(s, name)
+Delivery::Delivery (Session& s, boost::shared_ptr<MuteMaster> mm, const string& name, Role r)
+       : IOProcessor(s, false, true, name)
        , _role (r)
-       , _metering (false)
-       , _muted_by_self (false)
-       , _muted_by_others (false)
+       , _output_buffers (new BufferSet())
+       , _solo_level (0)
+       , _solo_isolated (false)
+       , _mute_master (mm)
 {
+       _output_offset = 0;
+       _current_gain = 1.0;
+       _panner = boost::shared_ptr<Panner>(new Panner (_name, _session));
+
+       _output->changed.connect (mem_fun (*this, &Delivery::output_changed));
 }
 
-/* reconstruct from XML */
+/* deliver to a new IO object, reconstruct from XML */
 
-Delivery::Delivery (Session& s, const XMLNode& node)
-       : IOProcessor (s, "reset")
+Delivery::Delivery (Session& s, boost::shared_ptr<MuteMaster> mm, const XMLNode& node)
+       : IOProcessor (s, false, true, "reset")
        , _role (Role (0))
-       , _metering (false)
-       , _muted_by_self (false)
-       , _muted_by_others (false)
+       , _output_buffers (new BufferSet())
+       , _solo_level (0)
+       , _solo_isolated (false)
+       , _mute_master (mm)
 {
+       _output_offset = 0;
+       _current_gain = 1.0;
+       _panner = boost::shared_ptr<Panner>(new Panner (_name, _session));
+
        if (set_state (node)) {
                throw failed_constructor ();
        }
+
+       _output->changed.connect (mem_fun (*this, &Delivery::output_changed));
+}
+
+void
+Delivery::cycle_start (nframes_t nframes)
+{
+       _output_offset = 0;
+       _no_outs_cuz_we_no_monitor = false;
 }
 
+void
+Delivery::increment_output_offset (nframes_t n)
+{
+       _output_offset += n;
+}
 
 bool
 Delivery::visible () const
 {
-       if (_role & (Main|Solo)) {
+       if (_role & Main) {
                return false;
        }
 
@@ -91,6 +135,8 @@ Delivery::configure_io (ChanCount in, ChanCount out)
        if (out != in) { // always 1:1
                return false;
        }
+
+       reset_panner ();
        
        return Processor::configure_io (in, out);
 }
@@ -98,64 +144,46 @@ Delivery::configure_io (ChanCount in, ChanCount out)
 void
 Delivery::run_in_place (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes)
 {
-       if (_io->n_outputs().get (_io->default_type()) == 0) {
+       if (_output->n_ports ().get (_output->default_type()) == 0) {
                return;
        }
 
-       if (!active() || _muted_by_self || _muted_by_others) {
-               silence (nframes);
-               if (_metering) {
-                       _io->peak_meter().reset();
-               }
-       } else {
+       // this Delivery processor is not a derived type, and thus we assume
+       // we really can modify the buffers passed in (it is almost certainly
+       // the main output stage of a Route). Contrast with Send::run_in_place()
+       // which cannot do this.
 
-               // we have to copy the input, because IO::deliver_output may alter the buffers
-               // in-place, which a send must never do.
+       gain_t tgain = target_gain ();
+       
+       if (tgain != _current_gain) {
+               Amp::apply_gain (bufs, nframes, _current_gain, tgain);
+               _current_gain = tgain;
+       }
 
-               BufferSet& sendbufs = _session.get_mix_buffers (bufs.count());
+       // Attach output buffers to port buffers
 
-               sendbufs.read_from(bufs, nframes);
-               assert(sendbufs.count() == bufs.count());
+       PortSet& ports (_output->ports());
+       output_buffers().attach_buffers (ports, nframes, _output_offset);
 
-               _io->deliver_output (sendbufs, start_frame, end_frame, nframes);
-               
-               if (_metering) {
-                       if (_io->effective_gain() == 0) {
-                               _io->peak_meter().reset();
-                       } else {
-                               _io->peak_meter().run_in_place(_io->output_buffers(), start_frame, end_frame, nframes);
-                       }
+       if (_panner && _panner->npanners() && !_panner->bypassed()) {
+
+               // Use the panner to distribute audio to output port buffers
+
+               _panner->run (bufs, output_buffers(), start_frame, end_frame, nframes);
+
+       } else {
+               // Do a 1:1 copy of data to output ports
+
+               if (bufs.count().n_audio() > 0 && ports.count().n_audio () > 0) {
+                       _output->copy_to_outputs (bufs, DataType::AUDIO, nframes, _output_offset);
                }
-       }
-}
 
-void
-Delivery::set_metering (bool yn)
-{
-       _metering = yn;
-       
-       if (!_metering) {
-               /* XXX possible thread hazard here */
-               _io->peak_meter().reset();
-       }
-}
-void
-Delivery::set_self_mute (bool yn)
-{
-       if (yn != _muted_by_self) {
-               _muted_by_self = yn;
-               SelfMuteChange (); // emit signal
+               if (bufs.count().n_midi() > 0 && ports.count().n_midi () > 0) {
+                       _output->copy_to_outputs (bufs, DataType::MIDI, nframes, _output_offset);
+               }
        }
 }
 
-void
-Delivery::set_nonself_mute (bool yn)
-{
-       if (yn != _muted_by_others) {
-               _muted_by_others = yn;
-               OtherMuteChange (); // emit signal
-       }
-}
 
 XMLNode&
 Delivery::state (bool full_state)
@@ -170,10 +198,8 @@ Delivery::state (bool full_state)
                node.add_property("type", "delivery");
        }
 
-       node.add_property("metering", (_metering ? "yes" : "no"));
-       node.add_property("self-muted", (_muted_by_self ? "yes" : "no"));
-       node.add_property("other-muted", (_muted_by_others ? "yes" : "no"));
        node.add_property("role", enum_2_string(_role));
+       node.add_child_nocopy (_panner->state (full_state));
 
        return node;
 }
@@ -182,22 +208,236 @@ int
 Delivery::set_state (const XMLNode& node)
 {
        const XMLProperty* prop;
+
+       if (IOProcessor::set_state (node)) {
+               return -1;
+       }
        
        if ((prop = node.property ("role")) != 0) {
                _role = Role (string_2_enum (prop->value(), _role));
        }
 
-       if ((prop = node.property ("metering")) != 0) {
-               set_metering (prop->value() == "yes");
+       if ((prop = node.property ("solo_level")) != 0) {
+               _solo_level = 0; // needed for the reset to work
+               mod_solo_level (atoi (prop->value()));
        }
 
-       if ((prop = node.property ("self-muted")) != 0) {
-               set_self_mute (prop->value() == "yes");
+       if ((prop = node.property ("solo-isolated")) != 0) {
+               set_solo_isolated (prop->value() == "yes");
        }
 
-       if ((prop = node.property ("other-muted")) != 0) {
-               set_nonself_mute (prop->value() == "yes");
+       XMLNode* pan_node = node.child (X_("Panner"));
+       
+       if (pan_node) {
+               cerr << _name << " reset pan state from XML\n";
+               _panner->set_state (*pan_node);
+       } 
+
+       reset_panner ();
+
+       return 0;
+}
+
+void
+Delivery::reset_panner ()
+{
+       cerr << _name << " reset panner - plegal ? " << panners_legal << endl;
+
+       if (panners_legal) {
+               if (!no_panner_reset) {
+                       cerr << "\treset panner with " << _output->name() << " = " << _output->n_ports()
+                            << " vs. " << pans_required () << endl;
+                       _panner->reset (_output->n_ports().n_audio(), pans_required());
+               }
+       } else {
+               cerr << "\tdefer pan reset till later\n";
+               panner_legal_c.disconnect ();
+               panner_legal_c = PannersLegal.connect (mem_fun (*this, &Delivery::panners_became_legal));
        }
+}
 
+int
+Delivery::panners_became_legal ()
+{
+       cerr << _name << " panners now legal, outputs @ " << _output << " on " << _output->name()
+            << " = " << _output->n_ports() << " vs. " << pans_required() << endl;
+       _panner->reset (_output->n_ports().n_audio(), pans_required());
+       _panner->load (); // automation
+       panner_legal_c.disconnect ();
        return 0;
 }
+
+void
+Delivery::defer_pan_reset ()
+{
+       no_panner_reset = true;
+}
+
+void
+Delivery::allow_pan_reset ()
+{
+       no_panner_reset = false;
+       reset_panner ();
+}
+
+
+int
+Delivery::disable_panners (void)
+{
+       panners_legal = false;
+       return 0;
+}
+
+int
+Delivery::reset_panners ()
+{
+       panners_legal = true;
+       return PannersLegal ();
+}
+
+
+void
+Delivery::start_pan_touch (uint32_t which)
+{
+       if (which < _panner->npanners()) {
+               _panner->pan_control(which)->start_touch();
+       }
+}
+
+void
+Delivery::end_pan_touch (uint32_t which)
+{
+       if (which < _panner->npanners()) {
+               _panner->pan_control(which)->stop_touch();
+       }
+
+}
+
+void
+Delivery::transport_stopped (sframes_t frame)
+{
+       _panner->transport_stopped (frame);
+}
+
+void
+Delivery::flush (nframes_t nframes)
+{
+       /* io_lock, not taken: function must be called from Session::process() calltree */
+       
+       PortSet& ports (_output->ports());
+
+       for (PortSet::iterator i = ports.begin(); i != ports.end(); ++i) {
+               (*i).flush_buffers (nframes, _output_offset);
+       }
+}
+
+gain_t
+Delivery::target_gain ()
+{
+       /* if we've been told not to output because its a monitoring situation and
+          we're not monitoring, then be quiet.
+       */
+
+       if (_no_outs_cuz_we_no_monitor) {
+               return 0.0;
+       }
+
+       gain_t desired_gain;
+       MuteMaster::MutePoint mp;
+
+       if (_solo_level) {
+               desired_gain = 1.0;
+       } else {
+               if (_solo_isolated) {
+
+                       switch (_role) {
+                       case Main:
+                               mp = MuteMaster::Main;
+                               break;
+                       case Listen:
+                               mp = MuteMaster::Listen;
+                               break;
+                       case Send:
+                       case Insert:
+                               if (_placement == PreFader) {
+                                       mp = MuteMaster::PreFader;
+                               } else {
+                                       mp = MuteMaster::PostFader;
+                               }
+                               break;
+                       }
+
+                       desired_gain = _mute_master->mute_gain_at (mp);
+               } else if (_session.soloing()) {
+
+                       switch (_role) {
+                       case Main:
+                               mp = MuteMaster::Main;
+                               break;
+                       case Listen:
+                               mp = MuteMaster::Listen;
+                               break;
+                       case Send:
+                       case Insert:
+                               if (_placement == PreFader) {
+                                       mp = MuteMaster::PreFader;
+                               } else {
+                                       mp = MuteMaster::PostFader;
+                               }
+                               break;
+                       }
+
+                       desired_gain = min (Config->get_solo_mute_gain(), _mute_master->mute_gain_at (mp));
+               } else {
+                       desired_gain = 1.0;
+               }
+       }
+
+       return desired_gain;
+}
+
+void
+Delivery::mod_solo_level (int32_t delta)
+{
+       if (delta < 0) {
+               if (_solo_level >= (uint32_t) delta) {
+                       _solo_level += delta;
+               } else {
+                       _solo_level = 0;
+               }
+       } else {
+               _solo_level += delta;
+       }
+}
+
+void
+Delivery::set_solo_isolated (bool yn)
+{
+       _solo_isolated = yn;
+}
+
+void
+Delivery::no_outs_cuz_we_no_monitor (bool yn)
+{
+       _no_outs_cuz_we_no_monitor = yn;
+}
+
+bool
+Delivery::set_name (const std::string& name)
+{
+       bool ret = IOProcessor::set_name (name);
+
+       if (ret) {
+               ret = _panner->set_name (name);
+       }
+
+       return ret;
+}
+
+void
+Delivery::output_changed (IOChange change, void* src)
+{
+       if (change & ARDOUR::ConfigurationChanged) {
+               reset_panner ();
+       }
+}
index bca3c74241ca9768307f736ae6763677ba9d76dd..27a1c18ff4a46c2994618e52e2dff67cf662d7bf 100644 (file)
@@ -138,6 +138,8 @@ void
 Diskstream::set_io (IO& io)
 {
        _io = &io;
+       input_change_pending = ConfigurationChanged;
+       non_realtime_input_change ();
        set_align_style_from_io ();
 }
 
@@ -233,7 +235,7 @@ Diskstream::set_capture_offset ()
                return;
        }
 
-       _capture_offset = _io->input_latency();
+       _capture_offset = _io->latency();
 }
 
 void
@@ -420,6 +422,11 @@ Diskstream::remove_region_from_last_capture (boost::weak_ptr<Region> wregion)
 void
 Diskstream::playlist_ranges_moved (list< Evoral::RangeMove<nframes_t> > const & movements_frames)
 {
+#if 0
+       
+       XXX THIS HAS TO BE FIXED FOR 3.0
+
+
        if (Config->get_automation_follows_regions () == false) {
                return;
        }
@@ -431,7 +438,7 @@ Diskstream::playlist_ranges_moved (list< Evoral::RangeMove<nframes_t> > const &
        }
        
        /* move gain automation */
-       boost::shared_ptr<AutomationList> gain_alist = _io->gain_control()->alist();
+       boost::shared_ptr<AutomationList> gain_alist = _io->gain_control()->list();
        XMLNode & before = gain_alist->get_state ();
        gain_alist->move_ranges (movements);
        _session.add_command (
@@ -458,11 +465,12 @@ Diskstream::playlist_ranges_moved (list< Evoral::RangeMove<nframes_t> > const &
        if (route) {
                route->foreach_processor (sigc::bind (sigc::mem_fun (*this, &Diskstream::move_processor_automation), movements_frames));
        }
+#endif
 }
 
 void
 Diskstream::move_processor_automation (boost::weak_ptr<Processor> p,
-               list< Evoral::RangeMove<nframes_t> > const & movements_frames)
+                                      list< Evoral::RangeMove<nframes_t> > const & movements_frames)
 {
        boost::shared_ptr<Processor> processor (p.lock ());
        if (!processor) {
index 7767381499d6b73c4f7e40e949581dd5e5d34c59..60d2b5177ed303ae6087b203297a2a6cbb057470 100644 (file)
 
 #include "pbd/enumwriter.h"
 
-#include "ardour/types.h"
-#include "ardour/delivery.h"
-#include "ardour/session.h"
-#include "ardour/location.h"
 #include "ardour/audiofilesource.h"
-#include "ardour/diskstream.h"
 #include "ardour/audioregion.h"
-#include "ardour/route_group.h"
-#include "ardour/panner.h"
-#include "ardour/track.h"
-#include "ardour/midi_track.h"
+#include "ardour/delivery.h"
+#include "ardour/diskstream.h"
 #include "ardour/export_filename.h"
 #include "ardour/export_format_base.h"
 #include "ardour/export_profile_manager.h"
+#include "ardour/io.h"
+#include "ardour/location.h"
+#include "ardour/midi_track.h"
+#include "ardour/panner.h"
+#include "ardour/route_group.h"
+#include "ardour/session.h"
+#include "ardour/track.h"
+#include "ardour/types.h"
 
 using namespace std;
 using namespace PBD;
@@ -70,7 +71,6 @@ setup_enum_writer ()
        SlaveSource _SlaveSource;
        ShuttleBehaviour _ShuttleBehaviour;
        ShuttleUnits _ShuttleUnits;
-       mute_type _mute_type;
        Session::RecordState _Session_RecordState;
        Session::Event::Type _Session_Event_Type;
        SmpteFormat _Session_SmpteFormat;
@@ -105,6 +105,7 @@ setup_enum_writer ()
        ExportFormatBase::SRCQuality _ExportFormatBase_SRCQuality;
        ExportProfileManager::TimeFormat _ExportProfileManager_TimeFormat;
        Delivery::Role _Delivery_Role;
+       IO::Direction _IO_Direction;
 
 #define REGISTER(e) enum_writer->register_distinct (typeid(e).name(), i, s); i.clear(); s.clear()
 #define REGISTER_BITS(e) enum_writer->register_bits (typeid(e).name(), i, s); i.clear(); s.clear()
@@ -328,12 +329,6 @@ setup_enum_writer ()
        REGISTER_CLASS_ENUM (Session, pullup_Minus4Minus1);
        REGISTER (_Session_PullupFormat);
 
-       REGISTER_ENUM (PRE_FADER);
-       REGISTER_ENUM (POST_FADER);
-       REGISTER_ENUM (CONTROL_OUTS);
-       REGISTER_ENUM (MAIN_OUTS);
-       REGISTER (_mute_type);
-
        REGISTER_CLASS_ENUM (Route, Hidden);
        REGISTER_CLASS_ENUM (Route, MasterOut);
        REGISTER_CLASS_ENUM (Route, ControlOut);
@@ -502,9 +497,13 @@ setup_enum_writer ()
        REGISTER_CLASS_ENUM (ExportProfileManager, Off);
        REGISTER (_ExportProfileManager_TimeFormat);
 
-       REGISTER_CLASS_ENUM (Delivery, Solo);
+       REGISTER_CLASS_ENUM (Delivery, Insert);
        REGISTER_CLASS_ENUM (Delivery, Send);
        REGISTER_CLASS_ENUM (Delivery, Listen);
        REGISTER_CLASS_ENUM (Delivery, Main);
        REGISTER_BITS (_Delivery_Role);
+
+       REGISTER_CLASS_ENUM (IO, Input);
+       REGISTER_CLASS_ENUM (IO, Output);
+       REGISTER (_IO_Direction);
 }
index ba3d70c18461a5a2afbad1587c0aa5d9fe3019ea..a5d4e639e34e4bf5391c70d277d209c2bbf7b207 100644 (file)
 #include "pbd/xml++.h"
 #include "pbd/replace_all.h"
 #include "pbd/unknown_type.h"
+#include "pbd/enumwriter.h"
 
 #include "ardour/audioengine.h"
+#include "ardour/buffer.h"
 #include "ardour/io.h"
 #include "ardour/route.h"
 #include "ardour/port.h"
@@ -67,131 +69,46 @@ using namespace PBD;
 
 const string                 IO::state_node_name = "IO";
 bool                         IO::connecting_legal = false;
-bool                         IO::ports_legal = false;
-bool                         IO::panners_legal = false;
-sigc::signal<void>           IO::Meter;
 sigc::signal<int>            IO::ConnectingLegal;
-sigc::signal<int>            IO::PortsLegal;
-sigc::signal<int>            IO::PannersLegal;
 sigc::signal<void,ChanCount> IO::PortCountChanged;
-sigc::signal<void,nframes_t> IO::CycleStart;
-
-Glib::StaticMutex IO::m_meter_signal_lock = GLIBMM_STATIC_MUTEX_INIT;
-
-/* this is a default mapper of [0 .. 1.0] control values to a gain coefficient.
-   others can be imagined. 
-*/
-
-#if 0
-static gain_t direct_control_to_gain (double fract) { 
-       /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
-       /* this maxes at +6dB */
-       return pow (2.0,(sqrt(sqrt(sqrt(fract)))*198.0-192.0)/6.0);
-}
-
-static double direct_gain_to_control (gain_t gain) { 
-       /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */
-       if (gain == 0) return 0.0;
-       
-       return pow((6.0*log(gain)/log(2.0)+192.0)/198.0, 8.0);
-}
-#endif
 
 /** @param default_type The type of port that will be created by ensure_io
  * and friends if no type is explicitly requested (to avoid breakage).
  */
-IO::IO (Session& s, const string& name, DataType default_type)
+IO::IO (Session& s, const string& name, Direction dir, DataType default_type)
        : SessionObject (s, name)
-       , AutomatableControls (s)
-       , _output_buffers (new BufferSet())
-       , _active (true)
+       , _direction (dir)
        , _default_type (default_type)
-       , _amp (new Amp(s, *this))
-       , _meter (new PeakMeter(s))
-       , _panner (new Panner(name, s))
 {
-       _gain = 1.0;
+       _active = true;
        pending_state_node = 0;
-       no_panner_reset = false;
-       _phase_invert = false;
-       deferred_state = 0;
-
-       boost::shared_ptr<AutomationList> gl(
-                       new AutomationList(Evoral::Parameter(GainAutomation)));
-
-       _gain_control = boost::shared_ptr<GainControl>( new GainControl( X_("gaincontrol"), this, Evoral::Parameter(GainAutomation), gl ));
-
-       add_control(_gain_control);
-       
-       {
-               // IO::Meter is emitted from another thread so the
-               // Meter signal must be protected.
-               Glib::Mutex::Lock guard (m_meter_signal_lock);
-               m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
-       }
-       
-       _output_offset = 0;
-       CycleStart.connect (mem_fun (*this, &IO::cycle_start));
-
-       _session.add_controllable (_gain_control);
-
-       setup_bundles_for_inputs_and_outputs ();
+       setup_bundles ();
+       cerr << "+++ IO created with name = " << _name << endl;
 }
 
 IO::IO (Session& s, const XMLNode& node, DataType dt)
        : SessionObject(s, "unnamed io")
-       , AutomatableControls (s)
-       , _output_buffers (new BufferSet())
-       , _active(true)
+       , _direction (Input)
        , _default_type (dt)
-       , _amp (new Amp(s, *this))
-       , _meter(new PeakMeter (_session))
 {
-       deferred_state = 0;
-       no_panner_reset = false;
-       _gain = 1.0;
-
-       boost::shared_ptr<AutomationList> gl(
-                       new AutomationList(Evoral::Parameter(GainAutomation)));
-
-       _gain_control = boost::shared_ptr<GainControl>(
-                       new GainControl( X_("gaincontrol"), this, Evoral::Parameter(GainAutomation), gl));
-
-       add_control(_gain_control);
+       _active = true;
+       pending_state_node = 0;
 
        set_state (node);
 
-       {
-               // IO::Meter is emitted from another thread so the
-               // Meter signal must be protected.
-               Glib::Mutex::Lock guard (m_meter_signal_lock);
-               m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
-       }
-       
-       _output_offset = 0;
-       CycleStart.connect (mem_fun (*this, &IO::cycle_start));
-
-       _session.add_controllable (_gain_control);
-
-       setup_bundles_for_inputs_and_outputs ();
+       setup_bundles ();
+       cerr << "+++ IO created from XML with name = " << _name << endl;
 }
 
 IO::~IO ()
 {
-       Glib::Mutex::Lock guard (m_meter_signal_lock);
        Glib::Mutex::Lock lm (io_lock);
 
        BLOCK_PROCESS_CALLBACK ();
 
-       for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
-               _session.engine().unregister_port (*i);
-       }
-
-       for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
+       for (PortSet::iterator i = _ports.begin(); i != _ports.end(); ++i) {
                _session.engine().unregister_port (*i);
        }
-
-       m_meter_connection.disconnect();
 }
 
 void
@@ -199,131 +116,15 @@ IO::silence (nframes_t nframes)
 {
        /* io_lock, not taken: function must be called from Session::process() calltree */
 
-       for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
+       for (PortSet::iterator i = _ports.begin(); i != _ports.end(); ++i) {
                i->get_buffer(nframes).silence (nframes);
        }
 }
 
-/** Deliver bufs to the IO's output ports
- *
- * This function should automatically do whatever it necessary to correctly deliver bufs
- * to the outputs, eg applying gain or pan or whatever else needs to be done.
- */
-void
-IO::deliver_output (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes)
-{
-       // Attach output buffers to port buffers
-       output_buffers().attach_buffers (_outputs, nframes, _output_offset);
-
-       // Use the panner to distribute audio to output port buffers
-       if (_panner && _panner->npanners() && !_panner->bypassed()) {
-
-               _panner->run_out_of_place(bufs, output_buffers(), start_frame, end_frame, nframes);
-
-       // Do a 1:1 copy of data to output ports
-       } else {
-               if (bufs.count().n_audio() > 0 && _outputs.count().n_audio () > 0) {
-                       copy_to_outputs (bufs, DataType::AUDIO, nframes);
-               }
-               if (bufs.count().n_midi() > 0 && _outputs.count().n_midi () > 0) {
-                       copy_to_outputs (bufs, DataType::MIDI, nframes);
-               }
-       }
-       
-       // Apply gain to output buffers if gain automation isn't playing
-       if ( ! _amp->apply_gain_automation()) {
-               
-               gain_t dg = _gain; // desired gain
-
-               {
-                       Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
-
-                       if (dm.locked()) {
-                               dg = _gain_control->user_float();
-                       }
-
-               }
-
-               if (dg != _gain || dg != 1.0) {
-                       Amp::apply_gain(output_buffers(), nframes, _gain, dg, _phase_invert);
-                       _gain = dg;
-               }
-       }
-       
-}
-
-void
-IO::copy_to_outputs (BufferSet& bufs, DataType type, nframes_t nframes)
-{
-       // Copy any buffers 1:1 to outputs
-       
-       PortSet::iterator o = _outputs.begin(type);
-       BufferSet::iterator i = bufs.begin(type);
-       BufferSet::iterator prev = i;
-
-       while (i != bufs.end(type) && o != _outputs.end (type)) {
-               Buffer& port_buffer (o->get_buffer (nframes));
-               port_buffer.read_from (*i, nframes, _output_offset);
-               prev = i;
-               ++i;
-               ++o;
-       }
-       
-       // Copy last buffer to any extra outputs
-       while (o != _outputs.end(type)) {
-               Buffer& port_buffer (o->get_buffer (nframes));
-               port_buffer.read_from (*prev, nframes, _output_offset);
-               ++o;
-       }
-}
-
-void
-IO::collect_input (BufferSet& outs, nframes_t nframes, ChanCount offset)
-{
-       assert(outs.available() >= n_inputs());
-       
-       if (n_inputs() == ChanCount::ZERO) {
-               return;
-       }
-
-       outs.set_count(n_inputs());
-
-       for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
-               PortSet::iterator   i = _inputs.begin(*t);
-               BufferSet::iterator o = outs.begin(*t);
-
-               for (uint32_t off = 0; off < offset.get(*t); ++off, ++o) {
-                       if (o == outs.end(*t)) {
-                               continue;
-                       }
-               }
-
-               for ( ; i != _inputs.end(*t); ++i, ++o) {
-                       Buffer& b (i->get_buffer (nframes));
-                       o->read_from (b, nframes);
-               }
-       }
-}
-
-void
-IO::just_meter_input (sframes_t start_frame, sframes_t end_frame, nframes_t nframes)
-{
-       BufferSet& bufs = _session.get_scratch_buffers (n_inputs());
-       collect_input (bufs, nframes);
-       _meter->run_in_place (bufs, start_frame, end_frame, nframes);
-}
-
-
-void
-IO::check_bundles_connected_to_inputs ()
-{
-       check_bundles (_bundles_connected_to_inputs, inputs());
-}
-
 void
-IO::check_bundles_connected_to_outputs ()
+IO::check_bundles_connected ()
 {
-       check_bundles (_bundles_connected_to_outputs, outputs());
+       check_bundles (_bundles_connected, ports());
 }
 
 void
@@ -335,7 +136,7 @@ IO::check_bundles (std::vector<UserBundleInfo>& list, const PortSet& ports)
 
                uint32_t const N = i->bundle->nchannels ();
 
-               if (ports.num_ports (default_type()) < N) {
+               if (_ports.num_ports (default_type()) < N) {
                        continue;
                }
 
@@ -368,7 +169,7 @@ IO::check_bundles (std::vector<UserBundleInfo>& list, const PortSet& ports)
 
 
 int
-IO::disconnect_input (Port* our_port, string other_port, void* src)
+IO::disconnect (Port* our_port, string other_port, void* src)
 {
        if (other_port.length() == 0 || our_port == 0) {
                return 0;
@@ -382,29 +183,29 @@ IO::disconnect_input (Port* our_port, string other_port, void* src)
                        
                        /* check that our_port is really one of ours */
                        
-                       if ( ! _inputs.contains(our_port)) {
+                       if ( ! _ports.contains(our_port)) {
                                return -1;
                        }
                        
                        /* disconnect it from the source */
                        
                        if (our_port->disconnect (other_port)) {
-                               error << string_compose(_("IO: cannot disconnect input port %1 from %2"), our_port->name(), other_port) << endmsg;
+                               error << string_compose(_("IO: cannot disconnect port %1 from %2"), our_port->name(), other_port) << endmsg;
                                return -1;
                        }
 
-                       check_bundles_connected_to_inputs ();
+                       check_bundles_connected ();
                }
        }
 
-       input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
+       changed (ConnectionsChanged, src); /* EMIT SIGNAL */
        _session.set_dirty ();
 
        return 0;
 }
 
 int
-IO::connect_input (Port* our_port, string other_port, void* src)
+IO::connect (Port* our_port, string other_port, void* src)
 {
        if (other_port.length() == 0 || our_port == 0) {
                return 0;
@@ -418,7 +219,7 @@ IO::connect_input (Port* our_port, string other_port, void* src)
                        
                        /* check that our_port is really one of ours */
                        
-                       if ( ! _inputs.contains(our_port) ) {
+                       if ( ! _ports.contains(our_port) ) {
                                return -1;
                        }
                        
@@ -430,99 +231,13 @@ IO::connect_input (Port* our_port, string other_port, void* src)
                }
        }
 
-       input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
-       _session.set_dirty ();
-       return 0;
-}
-
-int
-IO::disconnect_output (Port* our_port, string other_port, void* src)
-{
-       if (other_port.length() == 0 || our_port == 0) {
-               return 0;
-       }
-
-       {
-               BLOCK_PROCESS_CALLBACK ();
-               
-               {
-                       Glib::Mutex::Lock lm (io_lock);
-                       
-                       /* check that our_port is really one of ours */
-                       
-                       if ( ! _outputs.contains(our_port) ) {
-                               return -1;
-                       }
-                       
-                       /* disconnect it from the destination */
-                       
-                       if (our_port->disconnect (other_port)) {
-                               error << string_compose(_("IO: cannot disconnect output port %1 from %2"), our_port->name(), other_port) << endmsg;
-                               return -1;
-                       }
-
-                       check_bundles_connected_to_outputs ();
-               }
-       }
-
-       output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
-       _session.set_dirty ();
-       return 0;
-}
-
-int
-IO::connect_output (Port* our_port, string other_port, void* src)
-{
-       if (other_port.length() == 0 || our_port == 0) {
-               return 0;
-       }
-
-       {
-               BLOCK_PROCESS_CALLBACK ();
-
-               
-               {
-                       Glib::Mutex::Lock lm (io_lock);
-                       
-                       /* check that our_port is really one of ours */
-                       
-                       if ( ! _outputs.contains(our_port) ) {
-                               return -1;
-                       }
-                       
-                       /* connect it to the destination */
-                       
-                       if (our_port->connect (other_port)) {
-                               return -1;
-                       }
-               }
-       }
-
-       output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
+       changed (ConnectionsChanged, src); /* EMIT SIGNAL */
        _session.set_dirty ();
        return 0;
 }
 
 int
-IO::set_input (Port* other_port, void* src)
-{
-       /* this removes all but one ports, and connects that one port
-          to the specified source.
-       */
-
-       if (!other_port) {
-               return -1;
-       }
-
-       if (ensure_inputs (ChanCount(other_port->type(), 1), true, true, src)) {
-               return -1;
-       }
-
-       return connect_input (_inputs.port(0), other_port->name(), src);
-}
-
-int
-IO::remove_output_port (Port* port, void* src)
+IO::remove_port (Port* port, void* src)
 {
        IOChange change (NoChange);
 
@@ -533,7 +248,7 @@ IO::remove_output_port (Port* port, void* src)
                {
                        Glib::Mutex::Lock lm (io_lock);
 
-                       if (_outputs.remove(port)) {
+                       if (_ports.remove(port)) {
                                change = IOChange (change|ConfigurationChanged);
 
                                if (port->connected()) {
@@ -541,22 +256,19 @@ IO::remove_output_port (Port* port, void* src)
                                } 
 
                                _session.engine().unregister_port (*port);
-                               check_bundles_connected_to_outputs ();
-                               
-                               setup_peak_meters ();
-                               reset_panner ();
+                               check_bundles_connected ();
                        }
                }
 
-               PortCountChanged (n_outputs()); /* EMIT SIGNAL */
+               PortCountChanged (n_ports()); /* EMIT SIGNAL */
        }
 
        if (change == ConfigurationChanged) {
-               setup_bundle_for_outputs ();
+               setup_bundles ();
        }
 
        if (change != NoChange) {
-               output_changed (change, src);
+               changed (change, src);
                _session.set_dirty ();
                return 0;
        }
@@ -571,12 +283,13 @@ IO::remove_output_port (Port* port, void* src)
  * @param type Data type of port.  Default value (NIL) will use this IO's default type.
  */
 int
-IO::add_output_port (string destination, void* src, DataType type)
+IO::add_port (string destination, void* src, DataType type)
 {
        Port* our_port;
 
-       if (type == DataType::NIL)
+       if (type == DataType::NIL) {
                type = _default_type;
+       }
 
        {
                BLOCK_PROCESS_CALLBACK ();
@@ -587,19 +300,24 @@ IO::add_output_port (string destination, void* src, DataType type)
                        
                        /* Create a new output port */
                        
-                       string portname = build_legal_port_name (type, false);
-                       
-                       if ((our_port = _session.engine().register_output_port (type, portname)) == 0) {
-                               error << string_compose(_("IO: cannot register output port %1"), portname) << endmsg;
-                               return -1;
+                       string portname = build_legal_port_name (type);
+
+                       if (_direction == Input) {
+                               if ((our_port = _session.engine().register_input_port (type, portname)) == 0) {
+                                       error << string_compose(_("IO: cannot register input port %1"), portname) << endmsg;
+                                       return -1;
+                               }
+                       } else {
+                               if ((our_port = _session.engine().register_output_port (type, portname)) == 0) {
+                                       error << string_compose(_("IO: cannot register output port %1"), portname) << endmsg;
+                                       return -1;
+                               }
                        }
-                       
-                       _outputs.add (our_port);
-                       setup_peak_meters ();
-                       reset_panner ();
+
+                       _ports.add (our_port);
                }
 
-               PortCountChanged (n_outputs()); /* EMIT SIGNAL */
+               PortCountChanged (n_ports()); /* EMIT SIGNAL */
        }
 
        if (destination.length()) {
@@ -609,433 +327,95 @@ IO::add_output_port (string destination, void* src, DataType type)
        }
        
        // pan_changed (src); /* EMIT SIGNAL */
-       output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
-       setup_bundle_for_outputs ();
+       changed (ConfigurationChanged, src); /* EMIT SIGNAL */
+       setup_bundles ();
        _session.set_dirty ();
 
        return 0;
 }
 
 int
-IO::remove_input_port (Port* port, void* src)
+IO::disconnect (void* src)
 {
-       IOChange change (NoChange);
-
-       {
+       { 
                BLOCK_PROCESS_CALLBACK ();
-
                
                {
                        Glib::Mutex::Lock lm (io_lock);
-
-                       if (_inputs.remove(port)) {
-                               change = IOChange (change|ConfigurationChanged);
-
-                               if (port->connected()) {
-                                       change = IOChange (change|ConnectionsChanged);
-                               } 
-
-                               _session.engine().unregister_port (*port);
-                               check_bundles_connected_to_inputs ();
-                               
-                               setup_peak_meters ();
-                               reset_panner ();
+                       
+                       for (PortSet::iterator i = _ports.begin(); i != _ports.end(); ++i) {
+                               i->disconnect_all ();
                        }
-               }
-               
-               PortCountChanged (n_inputs ()); /* EMIT SIGNAL */
-       }
 
-       if (change == ConfigurationChanged) {
-               setup_bundle_for_inputs ();
+                       check_bundles_connected ();
+               }
        }
-
-       if (change != NoChange) {
-               input_changed (change, src);
-               _session.set_dirty ();
-               return 0;
-       } 
        
-       return -1;
+       changed (ConnectionsChanged, src); /* EMIT SIGNAL */
+       
+       return 0;
 }
 
-
-/** Add an input port.
- *
- * @param type Data type of port.  The appropriate port type, and @ref Port will be created.
- * @param destination Name of input port to connect new port to.
- * @param src Source for emitted ConfigurationChanged signal.
- */
-int
-IO::add_input_port (string source, void* src, DataType type)
+bool
+IO::ensure_ports_locked (ChanCount count, bool clear, void* src)
 {
-       Port* our_port;
+       Port* port = 0;
+       bool  changed    = false;
        
-       if (type == DataType::NIL)
-               type = _default_type;
-
-       {
-               BLOCK_PROCESS_CALLBACK ();
+       for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
                
-               { 
-                       Glib::Mutex::Lock lm (io_lock);
-
-                       /* Create a new input port */
+               const size_t n = count.get(*t);
+       
+               /* remove unused ports */
+               for (size_t i = n_ports().get(*t); i > n; --i) {
+                       port = _ports.port(*t, i-1);
                        
-                       string portname = build_legal_port_name (type, true);
-
-                       if ((our_port = _session.engine().register_input_port (type, portname)) == 0) {
-                               error << string_compose(_("IO: cannot register input port %1"), portname) << endmsg;
-                               return -1;
-                       }
+                       assert(port);
+                       _ports.remove(port);
+                       _session.engine().unregister_port (*port);
 
-                       _inputs.add (our_port);
-                       setup_peak_meters ();
-                       reset_panner ();
+                       changed = true;
                }
 
-               PortCountChanged (n_inputs()); /* EMIT SIGNAL */
-       }
-
-       if (source.length()) {
+               /* create any necessary new ports */
+               while (n_ports().get(*t) < n) {
 
-               if (our_port->connect (source)) {
-                       return -1;
-               }
-       } 
+                       string portname = build_legal_port_name (*t);
 
-       // pan_changed (src); /* EMIT SIGNAL */
-       input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
-       setup_bundle_for_inputs ();
-       _session.set_dirty ();
-       
-       return 0;
-}
+                       try {
 
-int
-IO::disconnect_inputs (void* src)
-{
-       { 
-               BLOCK_PROCESS_CALLBACK ();
-               
-               {
-                       Glib::Mutex::Lock lm (io_lock);
-                       
-                       for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
-                               i->disconnect_all ();
-                       }
-
-                       check_bundles_connected_to_inputs ();
-               }
-       }
-       
-       input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
-       
-       return 0;
-}
-
-int
-IO::disconnect_outputs (void* src)
-{
-       {
-               BLOCK_PROCESS_CALLBACK ();
-               
-               {
-                       Glib::Mutex::Lock lm (io_lock);
-                       
-                       for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
-                               i->disconnect_all ();
-                       }
-
-                       check_bundles_connected_to_outputs ();
-               }
-       }
-
-       output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */
-       _session.set_dirty ();
-       
-       return 0;
-}
-
-bool
-IO::ensure_inputs_locked (ChanCount count, bool clear, void* src)
-{
-       Port* input_port = 0;
-       bool  changed    = false;
-       
-       for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
-               
-               const size_t n = count.get(*t);
-       
-               /* remove unused ports */
-               for (size_t i = n_inputs().get(*t); i > n; --i) {
-                       input_port = _inputs.port(*t, i-1);
-
-                       assert(input_port);
-                       _inputs.remove(input_port);
-                       _session.engine().unregister_port (*input_port);
-
-                       changed = true;
-               }
-
-               /* create any necessary new ports */
-               while (n_inputs().get(*t) < n) {
-
-                       string portname = build_legal_port_name (*t, true);
-
-                       try {
-
-                               if ((input_port = _session.engine().register_input_port (*t, portname)) == 0) {
-                                       error << string_compose(_("IO: cannot register input port %1"), portname) << endmsg;
-                                       return -1;
-                               }
-                       }
-
-                       catch (AudioEngine::PortRegistrationFailure& err) {
-                               setup_peak_meters ();
-                               reset_panner ();
-                               /* pass it on */
-                               throw AudioEngine::PortRegistrationFailure();
-                       }
-
-                       _inputs.add (input_port);
-                       changed = true;
-               }
-       }
-       
-       if (changed) {
-               check_bundles_connected_to_inputs ();
-               setup_peak_meters ();
-               reset_panner ();
-               PortCountChanged (n_inputs()); /* EMIT SIGNAL */
-               _session.set_dirty ();
-       }
-       
-       if (clear) {
-               /* disconnect all existing ports so that we get a fresh start */
-               for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
-                       i->disconnect_all ();
-               }
-       }
-
-       return changed;
-}
-
-int
-IO::ensure_io (ChanCount in, ChanCount out, bool clear, void* src)
-{
-       bool in_changed     = false;
-       bool out_changed    = false;
-
-       assert(in != ChanCount::INFINITE);
-       assert(out != ChanCount::INFINITE);
-
-       if (in == n_inputs() && out == n_outputs() && !clear) {
-               return 0;
-       }
-
-       {
-               BLOCK_PROCESS_CALLBACK ();
-               Glib::Mutex::Lock lm (io_lock);
-
-               Port* port;
-               
-               for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
-
-                       const size_t nin = in.get(*t);
-                       const size_t nout = out.get(*t);
-
-                       Port* output_port = 0;
-                       Port* input_port = 0;
-
-                       /* remove unused output ports */
-                       for (size_t i = n_outputs().get(*t); i > nout; --i) {
-                               output_port = _outputs.port(*t, i-1);
-
-                               assert(output_port);
-                               _outputs.remove(output_port);
-                               _session.engine().unregister_port (*output_port);
-
-                               out_changed = true;
-                       }
-
-                       /* remove unused input ports */
-                       for (size_t i = n_inputs().get(*t); i > nin; --i) {
-                               input_port = _inputs.port(*t, i-1);
-
-                               assert(input_port);
-                               _inputs.remove(input_port);
-                               _session.engine().unregister_port (*input_port);
-
-                               in_changed = true;
-                       }
-
-                       /* create any necessary new input ports */
-                       while (n_inputs().get(*t) < nin) {
-                               string portname = build_legal_port_name (*t, true);
-
-                               try {
+                               if (_direction == Input) {
                                        if ((port = _session.engine().register_input_port (*t, portname)) == 0) {
                                                error << string_compose(_("IO: cannot register input port %1"), portname) << endmsg;
                                                return -1;
                                        }
-                               }
-                               
-                               catch (AudioEngine::PortRegistrationFailure& err) {
-                                       setup_peak_meters ();
-                                       reset_panner ();
-                                       /* pass it on */
-                                       throw err;
-                               }
-
-                               _inputs.add (port);
-                               in_changed = true;
-                       }
-
-                       /* create any necessary new output ports */
-
-                       while (n_outputs().get(*t) < nout) {
-
-                               string portname = build_legal_port_name (*t, false);
-                               
-                               try { 
+                               } else {
                                        if ((port = _session.engine().register_output_port (*t, portname)) == 0) {
                                                error << string_compose(_("IO: cannot register output port %1"), portname) << endmsg;
                                                return -1;
                                        }
                                }
-
-                               catch (AudioEngine::PortRegistrationFailure& err) {
-                                       setup_peak_meters ();
-                                       reset_panner ();
-                                       /* pass it on */
-                                       throw err;
-                               }
-
-                               _outputs.add (port);
-                               out_changed = true;
-                       }
-               }
-               
-               if (clear) {
-                       
-                       /* disconnect all existing ports so that we get a fresh start */
-                       
-                       for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
-                               i->disconnect_all ();
                        }
-                       
-                       for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
-                               i->disconnect_all ();
-                       }
-               }
-               
-               if (in_changed || out_changed) {
-                       setup_peak_meters ();
-                       reset_panner ();
-               }
-       }
-
-       if (out_changed) {
-               check_bundles_connected_to_outputs ();
-               output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
-               setup_bundle_for_outputs ();
-       }
-       
-       if (in_changed) {
-               check_bundles_connected_to_inputs ();
-               input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
-               setup_bundle_for_inputs ();
-       }
-
-       if (in_changed || out_changed) {
-               PortCountChanged (max (n_outputs(), n_inputs())); /* EMIT SIGNAL */
-               _session.set_dirty ();
-       }
-
-       return 0;
-}
-
-int
-IO::ensure_inputs (ChanCount count, bool clear, bool lockit, void* src)
-{
-       bool changed = false;
-
-       if (count == n_inputs() && !clear) {
-               return 0;
-       }
 
-       if (lockit) {
-               BLOCK_PROCESS_CALLBACK ();
-               Glib::Mutex::Lock im (io_lock);
-               changed = ensure_inputs_locked (count, clear, src);
-       } else {
-               changed = ensure_inputs_locked (count, clear, src);
-       }
-
-       if (changed) {
-               input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
-               setup_bundle_for_inputs ();
-               _session.set_dirty ();
-       }
-       return 0;
-}
-
-bool
-IO::ensure_outputs_locked (ChanCount count, bool clear, void* src)
-{
-       Port* output_port    = 0;
-       bool  changed        = false;
-       bool  need_pan_reset = false;
-       
-       if (n_outputs() != count) {
-               need_pan_reset = true;
-       }
-       
-       for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
-
-               const size_t n = count.get(*t);
-
-               /* remove unused ports */
-               for (size_t i = n_outputs().get(*t); i > n; --i) {
-                       output_port = _outputs.port(*t, i-1);
-
-                       assert(output_port);
-                       _outputs.remove(output_port);
-                       _session.engine().unregister_port (*output_port);
-
-                       changed = true;
-               }
-
-               /* create any necessary new ports */
-               while (n_outputs().get(*t) < n) {
-
-                       string portname = build_legal_port_name (*t, false);
-
-                       if ((output_port = _session.engine().register_output_port (*t, portname)) == 0) {
-                               error << string_compose(_("IO: cannot register output port %1"), portname) << endmsg;
-                               return -1;
+                       catch (AudioEngine::PortRegistrationFailure& err) {
+                               /* pass it on */
+                               throw AudioEngine::PortRegistrationFailure();
                        }
 
-                       _outputs.add (output_port);
+                       _ports.add (port);
                        changed = true;
-                       setup_peak_meters ();
-
-                       if (need_pan_reset) {
-                               reset_panner ();
-                       }
                }
        }
        
        if (changed) {
-               check_bundles_connected_to_outputs ();
-               PortCountChanged (n_outputs()); /* EMIT SIGNAL */
+               check_bundles_connected ();
+               PortCountChanged (n_ports()); /* EMIT SIGNAL */
                _session.set_dirty ();
        }
        
        if (clear) {
                /* disconnect all existing ports so that we get a fresh start */
-               for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
+               for (PortSet::iterator i = _ports.begin(); i != _ports.end(); ++i) {
                        i->disconnect_all ();
                }
        }
@@ -1043,71 +423,45 @@ IO::ensure_outputs_locked (ChanCount count, bool clear, void* src)
        return changed;
 }
 
+
 int
-IO::ensure_outputs (ChanCount count, bool clear, bool lockit, void* src)
+IO::ensure_ports (ChanCount count, bool clear, bool lockit, void* src)
 {
        bool changed = false;
 
-       /* XXX caller should hold io_lock, but generally doesn't */
+       cerr << "Ensure that IO " << _name << '/' << (_direction == Input ? "input" : "output") 
+            << " has " << count << endl;
+
+       if (count == n_ports() && !clear) {
+               cerr << "\talready has " << n_ports() << endl;
+               return 0;
+       }
 
        if (lockit) {
                BLOCK_PROCESS_CALLBACK ();
                Glib::Mutex::Lock im (io_lock);
-               changed = ensure_outputs_locked (count, clear, src);
+               changed = ensure_ports_locked (count, clear, src);
        } else {
-               changed = ensure_outputs_locked (count, clear, src);
+               changed = ensure_ports_locked (count, clear, src);
        }
 
        if (changed) {
-                output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */
-                setup_bundle_for_outputs ();
+               this->changed (ConfigurationChanged, src); /* EMIT SIGNAL */
+               setup_bundles ();
+               _session.set_dirty ();
        }
 
+       cerr << "\t@" << this << "  established with " << n_ports() << endl;
+       
        return 0;
 }
 
-gain_t
-IO::effective_gain () const
-{
-       return _gain_control->get_value();
-}
-
-void
-IO::reset_panner ()
-{
-       if (panners_legal) {
-               if (!no_panner_reset) {
-                       _panner->reset (n_outputs().n_audio(), pans_required());
-               }
-       } else {
-               panner_legal_c.disconnect ();
-               panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
-       }
-}
-
 int
-IO::panners_became_legal ()
-{
-       _panner->reset (n_outputs().n_audio(), pans_required());
-       _panner->load (); // automation
-       panner_legal_c.disconnect ();
-       return 0;
-}
-
-void
-IO::defer_pan_reset ()
-{
-       no_panner_reset = true;
-}
-
-void
-IO::allow_pan_reset ()
+IO::ensure_io (ChanCount count, bool clear, void* src)
 {
-       no_panner_reset = false;
-       reset_panner ();
+       return ensure_ports (count, clear, true, src);
 }
 
-
 XMLNode&
 IO::get_state (void)
 {
@@ -1128,44 +482,26 @@ IO::state (bool full_state)
        node->add_property("name", _name);
        id().print (buf, sizeof (buf));
        node->add_property("id", buf);
+       node->add_property ("direction", enum_2_string (_direction));
+       node->add_property ("default-type", _default_type.to_string());
 
-       for (
-         std::vector<UserBundleInfo>::iterator i = _bundles_connected_to_inputs.begin();
-         i != _bundles_connected_to_inputs.end();
-         ++i
-         )
-       {
-               XMLNode* n = new XMLNode ("InputBundle");
-               n->add_property ("name", i->bundle->name ());
-               node->add_child_nocopy (*n);
-       }
-
-       for (
-         std::vector<UserBundleInfo>::iterator i = _bundles_connected_to_outputs.begin();
-         i != _bundles_connected_to_outputs.end();
-         ++i
-         )
-       {
-               XMLNode* n = new XMLNode ("OutputBundle");
+       for (std::vector<UserBundleInfo>::iterator i = _bundles_connected.begin(); i != _bundles_connected.end(); ++i) {
+               XMLNode* n = new XMLNode ("Bundle");
                n->add_property ("name", i->bundle->name ());
                node->add_child_nocopy (*n);
        }
-       
-       str = "";
 
-       for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
-                       
+       for (PortSet::iterator i = _ports.begin(); i != _ports.end(); ++i) {
+               
                vector<string> connections;
 
+               XMLNode* pnode = new XMLNode (X_("port"));
+               pnode->add_property (X_("type"), i->type().to_string());
+
                if (i->get_connections (connections)) {
 
-                       str += '{';
-                       
                        for (n = 0, ci = connections.begin(); ci != connections.end(); ++ci, ++n) {
-                               if (n) {
-                                       str += ',';
-                               }
-                               
+
                                /* if its a connection to our own port,
                                   return only the port name, not the
                                   whole thing. this allows connections
@@ -1173,60 +509,12 @@ IO::state (bool full_state)
                                   client name is different.
                                */
                                
-                               str += _session.engine().make_port_name_relative (*ci);
+                               pnode->add_property (X_("connection"), _session.engine().make_port_name_relative (*ci));
                        }       
-                       
-                       str += '}';
-
-               } else {
-                       str += "{}";
                }
-       }
-       
-       node->add_property ("inputs", str);
-
-       str = "";
-       
-       for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
                
-               vector<string> connections;
-
-               if (i->get_connections (connections)) {
-                       
-                       str += '{';
-                       
-                       for (n = 0, ci = connections.begin(); ci != connections.end(); ++ci, ++n) {
-                               if (n) {
-                                       str += ',';
-                               }
-                               
-                               str += _session.engine().make_port_name_relative (*ci);
-                       }
-                       
-                       str += '}';
-
-               } else {
-                       str += "{}";
-               }
+               node->add_child_nocopy (*pnode);
        }
-       
-       node->add_property ("outputs", str);
-
-       node->add_child_nocopy (_panner->state (full_state));
-       node->add_child_nocopy (_gain_control->get_state ());
-
-       snprintf (buf, sizeof(buf), "%2.12f", gain());
-       node->add_property ("gain", buf);
-
-       /* port counts */
-
-       node->add_child_nocopy(*n_inputs().state("Inputs"));
-       node->add_child_nocopy(*n_outputs().state("Outputs"));
-
-       /* automation */
-       
-       if (full_state)
-               node->add_child_nocopy (get_automation_state());
 
        return *node;
 }
@@ -1246,79 +534,34 @@ IO::set_state (const XMLNode& node)
                error << string_compose(_("incorrect XML node \"%1\" passed to IO object"), node.name()) << endmsg;
                return -1;
        }
-
+       
        if ((prop = node.property ("name")) != 0) {
-               _name = prop->value();
-               /* used to set panner name with this, but no more */
+               set_name (prop->value());
        }
 
-       if ((prop = node.property ("id")) != 0) {
-               _id = prop->value ();
-       }
-
-       if ((prop = node.property ("gain")) != 0) {
-               set_gain (atof (prop->value().c_str()), this);
-               _gain = _gain_control->user_float();
-       }
-
-       if ((prop = node.property ("automation-state")) != 0 || (prop = node.property ("automation-style")) != 0) {
-               /* old school automation handling */
+       if ((prop = node.property (X_("default-type"))) != 0) {
+               _default_type = DataType(prop->value());
+               assert(_default_type != DataType::NIL);
        }
 
-       for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
-
-               // Old school Panner.
-               if ((*iter)->name() == "Panner") {
-                       if (!_panner) {
-                               _panner = boost::shared_ptr<Panner>(new Panner (_name, _session));
-                       }
-                       _panner->set_state (**iter);
-               }
-
-               if ((*iter)->name() == "Processor") {
-                       if ((*iter)->property ("type") && ((*iter)->property ("type")->value() == "panner" ) ) {
-                               if (!_panner) {
-                                       _panner = boost::shared_ptr<Panner>(new Panner (_name, _session));
-                               }
-                               _panner->set_state (**iter);
-                       }
-               }
-
-               if ((*iter)->name() == X_("Automation")) {
-
-                       set_automation_state (*(*iter), Evoral::Parameter(GainAutomation));
-               }
-
-               if ((*iter)->name() == X_("Controllable")) {
-                       if ((prop = (*iter)->property("name")) != 0 && prop->value() == "gaincontrol") {
-                               _gain_control->set_state (**iter);
-                       }
-               }
+       if ((prop = node.property ("id")) != 0) {
+               _id = prop->value ();
        }
 
-       if (ports_legal) {
-
-               if (create_ports (node)) {
-                       return -1;
-               }
-
-       } else {
-
-               port_legal_c = PortsLegal.connect (mem_fun (*this, &IO::ports_became_legal));
+       if ((prop = node.property ("direction")) != 0) {
+               _direction = (Direction) string_2_enum (prop->value(), _direction);
        }
 
-       if (!_panner) {
-               _panner = boost::shared_ptr<Panner>(new Panner (_name, _session));
-       }
+       if (!connecting_legal) {
+               pending_state_node = new XMLNode (node);
+       } 
 
-       if (panners_legal) {
-               reset_panner ();
-       } else {
-               panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal));
+       if (create_ports (node)) {
+               return -1;
        }
 
        if (connecting_legal) {
-
+               
                if (make_connections (node)) {
                        return -1;
                }
@@ -1328,83 +571,6 @@ IO::set_state (const XMLNode& node)
                connection_legal_c = ConnectingLegal.connect (mem_fun (*this, &IO::connecting_became_legal));
        }
 
-       if (!ports_legal || !connecting_legal) {
-               pending_state_node = new XMLNode (node);
-       }
-
-       return 0;
-}
-
-int
-IO::load_automation (string path)
-{
-       string fullpath;
-       ifstream in;
-       char line[128];
-       uint32_t linecnt = 0;
-       float version;
-       LocaleGuard lg (X_("POSIX"));
-
-       fullpath = Glib::build_filename(_session.automation_dir(), path);
-
-       in.open (fullpath.c_str());
-
-       if (!in) {
-               fullpath = Glib::build_filename(_session.automation_dir(), _session.snap_name() + '-' + path);
-
-               in.open (fullpath.c_str());
-
-               if (!in) {
-                       error << string_compose(_("%1: cannot open automation event file \"%2\""), _name, fullpath) << endmsg;
-                       return -1;
-               }
-       }
-
-       clear_automation ();
-
-       while (in.getline (line, sizeof(line), '\n')) {
-               char type;
-               nframes_t when;
-               double value;
-
-               if (++linecnt == 1) {
-                       if (memcmp (line, "version", 7) == 0) {
-                               if (sscanf (line, "version %f", &version) != 1) {
-                                       error << string_compose(_("badly formed version number in automation event file \"%1\""), path) << endmsg;
-                                       return -1;
-                               }
-                       } else {
-                               error << string_compose(_("no version information in automation event file \"%1\""), path) << endmsg;
-                               return -1;
-                       }
-
-                       continue;
-               }
-
-               if (sscanf (line, "%c %" PRIu32 " %lf", &type, &when, &value) != 3) {
-                       warning << string_compose(_("badly formatted automation event record at line %1 of %2 (ignored)"), linecnt, path) << endmsg;
-                       continue;
-               }
-
-               switch (type) {
-               case 'g':
-                       _gain_control->list()->fast_simple_add (when, value);
-                       break;
-
-               case 's':
-                       break;
-
-               case 'm':
-                       break;
-
-               case 'p':
-                       /* older (pre-1.0) versions of ardour used this */
-                       break;
-
-               default:
-                       warning << _("dubious automation event found (and ignored)") << endmsg;
-               }
-       }
 
        return 0;
 }
@@ -1414,51 +580,25 @@ IO::connecting_became_legal ()
 {
        int ret;
 
-       if (pending_state_node == 0) {
-               fatal << _("IO::connecting_became_legal() called without a pending state node") << endmsg;
-               /*NOTREACHED*/
-               return -1;
-       }
+       assert (pending_state_node);
 
        connection_legal_c.disconnect ();
 
        ret = make_connections (*pending_state_node);
-
-       if (ports_legal) {
-               delete pending_state_node;
-               pending_state_node = 0;
-       }
-
-       return ret;
-}
-int
-IO::ports_became_legal ()
-{
-       int ret;
-
-       if (pending_state_node == 0) {
-               fatal << _("IO::ports_became_legal() called without a pending state node") << endmsg;
-               /*NOTREACHED*/
-               return -1;
-       }
-
-       port_legal_c.disconnect ();
-
-       ret = create_ports (*pending_state_node);
-
-       if (connecting_legal) {
-               delete pending_state_node;
-               pending_state_node = 0;
-       }
+       
+       delete pending_state_node;
+       pending_state_node = 0;
 
        return ret;
 }
 
 boost::shared_ptr<Bundle>
-IO::find_possible_bundle (const string &desired_name, const string &default_name, const string &bundle_type_name) 
+IO::find_possible_bundle (const string &desired_name)
 {
        static const string digits = "0123456789";
-
+       const string &default_name = (_direction == Input ? _("in") : _("out"));
+       const string &bundle_type_name = (_direction == Input ? _("input") : _("output"));
+       
        boost::shared_ptr<Bundle> c = _session.bundle_by_name (desired_name);
 
        if (!c) {
@@ -1547,77 +687,71 @@ IO::find_possible_bundle (const string &desired_name, const string &default_name
 }
 
 int
-IO::get_port_counts (const XMLNode& node, ChanCount& in, ChanCount& out,
-                    boost::shared_ptr<Bundle>& ic, boost::shared_ptr<Bundle>& oc)
+IO::get_port_counts (const XMLNode& node, ChanCount& n, boost::shared_ptr<Bundle>& c)
 {
        XMLProperty const * prop;
        XMLNodeConstIterator iter;
+       uint32_t n_audio = 0;
+       uint32_t n_midi = 0;
+       ChanCount cnt;
 
-       in = n_inputs();
-       out = n_outputs();
+       n = n_ports();
 
-       for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
-               if ((*iter)->name() == X_("Inputs")) {
-                       in = ChanCount::max(in, ChanCount(**iter));
-               } else if ((*iter)->name() == X_("Outputs")) {
-                       out = ChanCount::max(out, ChanCount(**iter));
+       if ((prop = node.property ("connection")) != 0) {
+
+               if ((c = find_possible_bundle (prop->value())) != 0) {
+                       n = ChanCount::max (n, ChanCount(c->type(), c->nchannels()));
                }
+               return 0;
        }
+       
+       for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
 
-       if ((prop = node.property ("input-connection")) != 0) {
-
-               ic = find_possible_bundle (prop->value(), _("in"), _("input"));
-               if (ic) {
-                       in = ChanCount::max(in, ChanCount(ic->type(), ic->nchannels()));
+               if ((*iter)->name() == X_("Bundle")) {
+                       if ((c = find_possible_bundle (prop->value())) != 0) {
+                               n = ChanCount::max (n, ChanCount(c->type(), c->nchannels()));
+                               return 0;
+                       } else {
+                               return -1;
+                       }
                }
 
-       } else if ((prop = node.property ("inputs")) != 0) {
+               if ((*iter)->name() == X_("port")) {
+                       prop = (*iter)->property (X_("type"));
 
-               in = ChanCount::max(in, ChanCount(_default_type,
-                                                 count (prop->value().begin(), prop->value().end(), '{')));
-       }
-       
-       if ((prop = node.property ("output-connection")) != 0) {
-               
-               oc = find_possible_bundle (prop->value(), _("out"), _("output"));
-               if (oc) {
-                       out = ChanCount::max(out, ChanCount(oc->type(), oc->nchannels()));
+                       if (!prop) {
+                               continue;
+                       }
+
+                       if (prop->value() == X_("audio")) {
+                               cnt.set_audio (++n_audio);
+                       } else if (prop->value() == X_("midi")) {
+                               cnt.set_midi (++n_midi);
+                       }
                }
-               
-       } else if ((prop = node.property ("outputs")) != 0) {
-               
-               out = ChanCount::max(out, ChanCount(_default_type,
-                                                   count (prop->value().begin(), prop->value().end(), '{')));
        }
        
+       n = ChanCount::max (n, cnt);
        return 0;
 }
 
 int
 IO::create_ports (const XMLNode& node)
 {
-       if (pending_state_node) {
+       ChanCount n;
+       boost::shared_ptr<Bundle> c;
+       
+       get_port_counts (node, n, c);
+       
+       cerr << _name << " got " << n << " from XML node" << endl;
 
-               ChanCount in;
-               ChanCount out;
-               boost::shared_ptr<Bundle> ic;
-               boost::shared_ptr<Bundle> oc;
-               
-               no_panner_reset = true;
-               
-               get_port_counts (*pending_state_node, in, out, ic, oc);
-               
-               if (ensure_io (in, out, true, this)) {
-                       error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
-                       return -1;
-               }
-               
-               /* XXX use ic and oc if relevant */
-               
-               no_panner_reset = false;
+       if (ensure_ports (n, true, true, this)) {
+               error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
+               return -1;
        }
 
-       set_deferred_state ();
+       /* XXX use c */
+
        return 0;
 }
 
@@ -1626,60 +760,41 @@ IO::make_connections (const XMLNode& node)
 {
        const XMLProperty* prop;
 
-       if ((prop = node.property ("input-connection")) != 0) {
-               boost::shared_ptr<Bundle> c = find_possible_bundle (prop->value(), _("in"), _("input"));
+       if ((prop = node.property ("connection")) != 0) {
+               boost::shared_ptr<Bundle> c = find_possible_bundle (prop->value());
                
                if (!c) {
                        return -1;
                }
 
-               if (n_inputs().get(c->type()) == c->nchannels() && c->ports_are_outputs()) {
-                       connect_input_ports_to_bundle (c, this);
-               }
-
-       } else if ((prop = node.property ("inputs")) != 0) {
-               if (set_inputs (prop->value())) {
-                       error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg;
-                       return -1;
+               if (n_ports().get(c->type()) == c->nchannels() && c->ports_are_outputs()) {
+                       connect_ports_to_bundle (c, this);
                }
-       }
 
-       if ((prop = node.property ("output-connection")) != 0) {
-               boost::shared_ptr<Bundle> c = find_possible_bundle (prop->value(), _("out"), _("output"));
-               
-               if (!c) {
-                       return -1;
-               } 
-               
-               if (n_outputs().get(c->type()) == c->nchannels() && c->ports_are_inputs()) {
-                       connect_output_ports_to_bundle (c, this);
-               }
+               return 0;
+       } 
 
-       } else if ((prop = node.property ("outputs")) != 0) {
-               if (set_outputs (prop->value())) {
-                       error << string_compose(_("improper output channel list in XML node (%1)"), prop->value()) << endmsg;
-                       return -1;
-               }
-       }
+       uint32_t n = 0;
 
        for (XMLNodeConstIterator i = node.children().begin(); i != node.children().end(); ++i) {
 
-               if ((*i)->name() == "InputBundle") {
+               if ((*i)->name() == "Bundle") {
                        XMLProperty const * prop = (*i)->property ("name");
                        if (prop) {
-                               boost::shared_ptr<Bundle> b = find_possible_bundle (prop->value(), _("in"), _("input"));
+                               boost::shared_ptr<Bundle> b = find_possible_bundle (prop->value());
                                if (b) {
-                                       connect_input_ports_to_bundle (b, this);
+                                       connect_ports_to_bundle (b, this);
                                }
                        }
-                       
-               } else if ((*i)->name() == "OutputBundle") {
-                       XMLProperty const * prop = (*i)->property ("name");
-                       if (prop) {
-                               boost::shared_ptr<Bundle> b = find_possible_bundle (prop->value(), _("out"), _("output"));
-                               if (b) {
-                                       connect_output_ports_to_bundle (b, this);
-                               } 
+
+                       return 0;
+               }
+
+               if ((*i)->name() == "port") {
+                       Port* p = nth (n++);
+                       XMLProperty* prop = (*i)->property ("connection");
+                       if (p && prop) {
+                               p->connect (prop->value());
                        }
                }
        }
@@ -1688,7 +803,7 @@ IO::make_connections (const XMLNode& node)
 }
 
 int
-IO::set_inputs (const string& str)
+IO::set_ports (const string& str)
 {
        vector<string> ports;
        int i;
@@ -1700,7 +815,7 @@ IO::set_inputs (const string& str)
        }
 
        // FIXME: audio-only
-       if (ensure_inputs (ChanCount(DataType::AUDIO, nports), true, true, this)) {
+       if (ensure_ports (ChanCount(DataType::AUDIO, nports), true, true, this)) {
                return -1;
        }
 
@@ -1727,58 +842,7 @@ IO::set_inputs (const string& str)
                } else if (n > 0) {
 
                        for (int x = 0; x < n; ++x) {
-                               connect_input (input (i), ports[x], this);
-                       }
-               }
-
-               ostart = end+1;
-               i++;
-       }
-
-       return 0;
-}
-
-int
-IO::set_outputs (const string& str)
-{
-       vector<string> ports;
-       int i;
-       int n;
-       uint32_t nports;
-       
-       if ((nports = count (str.begin(), str.end(), '{')) == 0) {
-               return 0;
-       }
-
-       // FIXME: audio-only - need a way to identify port types from XML/string
-       if (ensure_outputs (ChanCount(DataType::AUDIO, nports), true, true, this)) {
-               return -1;
-       }
-
-       string::size_type start, end, ostart;
-
-       ostart = 0;
-       start = 0;
-       end = 0;
-       i = 0;
-
-       while ((start = str.find_first_of ('{', ostart)) != string::npos) {
-               start += 1;
-
-               if ((end = str.find_first_of ('}', start)) == string::npos) {
-                       error << string_compose(_("IO: badly formed string in XML node for outputs \"%1\""), str) << endmsg;
-                       return -1;
-               }
-
-               if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) {
-                       error << string_compose(_("IO: bad output string in XML node \"%1\""), str) << endmsg;
-
-                       return -1;
-                       
-               } else if (n > 0) {
-
-                       for (int x = 0; x < n; ++x) {
-                               connect_output (output (i), ports[x], this);
+                               connect (nth (i), ports[x], this);
                        }
                }
 
@@ -1858,13 +922,7 @@ IO::set_name (const string& requested_name)
                warning << _("you cannot use colons to name objects with I/O connections") << endmsg;
        }
 
-       for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
-               string current_name = i->name();
-               current_name.replace (current_name.find (_name), _name.length(), name);
-               i->set_name (current_name);
-       }
-
-       for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
+       for (PortSet::iterator i = _ports.begin(); i != _ports.end(); ++i) {
                string current_name = i->name();
                current_name.replace (current_name.find (_name), _name.length(), name);
                i->set_name (current_name);
@@ -1872,7 +930,7 @@ IO::set_name (const string& requested_name)
 
        bool const r = SessionObject::set_name(name);
 
-       setup_bundles_for_inputs_and_outputs ();
+       setup_bundles ();
 
        return r;
 }
@@ -1882,32 +940,13 @@ IO::set_port_latency (nframes_t nframes)
 {
        Glib::Mutex::Lock lm (io_lock);
 
-       for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
+       for (PortSet::iterator i = _ports.begin(); i != _ports.end(); ++i) {
                i->set_latency (nframes);
        }
 }
 
 nframes_t
-IO::output_latency () const
-{
-       nframes_t max_latency;
-       nframes_t latency;
-
-       max_latency = 0;
-
-       /* io lock not taken - must be protected by other means */
-
-       for (PortSet::const_iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
-               if ((latency = i->total_latency ()) > max_latency) {
-                       max_latency = latency;
-               }
-       }
-
-       return max_latency;
-}
-
-nframes_t
-IO::input_latency () const
+IO::latency () const
 {
        nframes_t max_latency;
        nframes_t latency;
@@ -1916,7 +955,7 @@ IO::input_latency () const
 
        /* io lock not taken - must be protected by other means */
 
-       for (PortSet::const_iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
+       for (PortSet::const_iterator i = _ports.begin(); i != _ports.end(); ++i) {
                if ((latency = i->total_latency ()) > max_latency) {
                        max_latency = latency;
                } 
@@ -1925,371 +964,101 @@ IO::input_latency () const
        return max_latency;
 }
 
-int
-IO::connect_input_ports_to_bundle (boost::shared_ptr<Bundle> c, void* src)
-{
-       {
-               BLOCK_PROCESS_CALLBACK ();
-               Glib::Mutex::Lock lm2 (io_lock);
-
-               c->connect (_bundle_for_inputs, _session.engine());
-
-               /* If this is a UserBundle, make a note of what we've done */
-
-               boost::shared_ptr<UserBundle> ub = boost::dynamic_pointer_cast<UserBundle> (c);
-               if (ub) {
-
-                       /* See if we already know about this one */
-                       std::vector<UserBundleInfo>::iterator i = _bundles_connected_to_inputs.begin();
-                       while (i != _bundles_connected_to_inputs.end() && i->bundle != ub) {
-                               ++i;
-                       }
-
-                       if (i == _bundles_connected_to_inputs.end()) {
-                               /* We don't, so make a note */
-                               _bundles_connected_to_inputs.push_back (UserBundleInfo (this, ub));
-                       }
-               }
-       }
-
-       input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */
-       return 0;
-}
-
-int
-IO::disconnect_input_ports_from_bundle (boost::shared_ptr<Bundle> c, void* src)
-{
-       {
-               BLOCK_PROCESS_CALLBACK ();
-               Glib::Mutex::Lock lm2 (io_lock);
-
-               c->disconnect (_bundle_for_inputs, _session.engine());
-                       
-               /* If this is a UserBundle, make a note of what we've done */
-
-               boost::shared_ptr<UserBundle> ub = boost::dynamic_pointer_cast<UserBundle> (c);
-               if (ub) {
-
-                       std::vector<UserBundleInfo>::iterator i = _bundles_connected_to_inputs.begin();
-                       while (i != _bundles_connected_to_inputs.end() && i->bundle != ub) {
-                               ++i;
-                       }
-
-                       if (i != _bundles_connected_to_inputs.end()) {
-                               _bundles_connected_to_inputs.erase (i);
-                       }
-               }
-       }
-
-       input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */
-       return 0;
-}
-
-int
-IO::connect_output_ports_to_bundle (boost::shared_ptr<Bundle> c, void* src)
-{
-       {
-               BLOCK_PROCESS_CALLBACK ();
-               Glib::Mutex::Lock lm2 (io_lock);
-
-               c->connect (_bundle_for_outputs, _session.engine());
-
-               /* If this is a UserBundle, make a note of what we've done */
-
-               boost::shared_ptr<UserBundle> ub = boost::dynamic_pointer_cast<UserBundle> (c);
-               if (ub) {
-
-                       /* See if we already know about this one */
-                       std::vector<UserBundleInfo>::iterator i = _bundles_connected_to_outputs.begin();
-                       while (i != _bundles_connected_to_outputs.end() && i->bundle != ub) {
-                               ++i;
-                       }
-
-                       if (i == _bundles_connected_to_outputs.end()) {
-                               /* We don't, so make a note */
-                               _bundles_connected_to_outputs.push_back (UserBundleInfo (this, ub));
-                       }
-               }
-       }
-
-       output_changed (IOChange (ConnectionsChanged|ConfigurationChanged), src); /* EMIT SIGNAL */
-
-       return 0;
-}
-
-int
-IO::disconnect_output_ports_from_bundle (boost::shared_ptr<Bundle> c, void* src)
-{
-       {
-               BLOCK_PROCESS_CALLBACK ();
-               Glib::Mutex::Lock lm2 (io_lock);
-
-               c->disconnect (_bundle_for_outputs, _session.engine());
-                       
-               /* If this is a UserBundle, make a note of what we've done */
-
-               boost::shared_ptr<UserBundle> ub = boost::dynamic_pointer_cast<UserBundle> (c);
-               if (ub) {
-
-                       std::vector<UserBundleInfo>::iterator i = _bundles_connected_to_outputs.begin();
-                       while (i != _bundles_connected_to_outputs.end() && i->bundle != ub) {
-                               ++i;
-                       }
-
-                       if (i != _bundles_connected_to_outputs.end()) {
-                               _bundles_connected_to_outputs.erase (i);
-                       }
-               }
-       }
-
-       output_changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */
-       return 0;
-}
-
-
-int
-IO::disable_connecting ()
-{
-       connecting_legal = false;
-       return 0;
-}
-
-int
-IO::enable_connecting ()
-{
-       connecting_legal = true;
-       return ConnectingLegal ();
-}
-
-int
-IO::disable_ports ()
-{
-       ports_legal = false;
-       return 0;
-}
-
-int
-IO::enable_ports ()
-{
-       ports_legal = true;
-       return PortsLegal ();
-}
-
-int
-IO::disable_panners (void)
-{
-       panners_legal = false;
-       return 0;
-}
-
-int
-IO::reset_panners ()
-{
-       panners_legal = true;
-       return PannersLegal ();
-}
-
-void
-IO::bundle_changed (Bundle::Change c)
-{
-       //XXX
-//     connect_input_ports_to_bundle (_input_bundle, this);
-}
-
 void
-IO::GainControl::set_value (float val)
-{
-       // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
-       if (val > 1.99526231f)
-               val = 1.99526231f;
-
-       _io->set_gain (val, this);
-       
-       AutomationControl::set_value(val);
-}
-
-float
-IO::GainControl::get_value (void) const
-{
-       return AutomationControl::get_value();
-}
-
-void
-IO::setup_peak_meters()
-{
-       ChanCount max_streams = std::max (_inputs.count(), _outputs.count());
-       _meter->configure_io (max_streams, max_streams);
-}
-
-/**
-    Update the peak meters.
-
-    The meter signal lock is taken to prevent modification of the 
-    Meter signal while updating the meters, taking the meter signal
-    lock prior to taking the io_lock ensures that all IO will remain 
-    valid while metering.
-*/   
-void
-IO::update_meters()
-{
-       Glib::Mutex::Lock guard (m_meter_signal_lock);
-       Meter(); /* EMIT SIGNAL */
-}
-
-void
-IO::meter ()
-{
-       // FIXME: Ugly.  Meter should manage the lock, if it's necessary
-       
-       Glib::Mutex::Lock lm (io_lock); // READER: meter thread.
-       _meter->meter();
-}
-
-void
-IO::clear_automation ()
-{
-       data().clear_controls (); // clears gain automation
-       _panner->data().clear_controls ();
-}
-
-void
-IO::set_parameter_automation_state (Evoral::Parameter param, AutoState state)
+IO::update_port_total_latencies ()
 {
-       // XXX: would be nice to get rid of this special hack
+       /* io_lock, not taken: function must be called from Session::process() calltree */
 
-       if (param.type() == GainAutomation) {
+       for (PortSet::iterator i = _ports.begin(); i != _ports.end(); ++i) {
+               _session.engine().update_total_latency (*i);
+       }
+}
 
-               bool changed = false;
+int
+IO::connect_ports_to_bundle (boost::shared_ptr<Bundle> c, void* src)
+{
+       {
+               BLOCK_PROCESS_CALLBACK ();
+               Glib::Mutex::Lock lm2 (io_lock);
 
-               { 
-                       Glib::Mutex::Lock lm (control_lock());
+               c->connect (_bundle, _session.engine());
 
-                       boost::shared_ptr<AutomationList> gain_auto
-                               = boost::dynamic_pointer_cast<AutomationList>(_gain_control->list());
+               /* If this is a UserBundle, make a note of what we've done */
 
-                       if (state != gain_auto->automation_state()) {
-                               changed = true;
-                               _last_automation_snapshot = 0;
-                               gain_auto->set_automation_state (state);
+               boost::shared_ptr<UserBundle> ub = boost::dynamic_pointer_cast<UserBundle> (c);
+               if (ub) {
 
-                               if (state != Off) {
-                                       // FIXME: shouldn't this use Curve?
-                                       set_gain (gain_auto->eval (_session.transport_frame()), this);
-                               }
+                       /* See if we already know about this one */
+                       std::vector<UserBundleInfo>::iterator i = _bundles_connected.begin();
+                       while (i != _bundles_connected.end() && i->bundle != ub) {
+                               ++i;
                        }
-               }
 
-               if (changed) {
-                       _session.set_dirty ();
+                       if (i == _bundles_connected.end()) {
+                               /* We don't, so make a note */
+                               _bundles_connected.push_back (UserBundleInfo (this, ub));
+                       }
                }
-
-       } else {
-               AutomatableControls::set_parameter_automation_state(param, state);
        }
-}
 
-void
-IO::inc_gain (gain_t factor, void *src)
-{
-       float desired_gain = _gain_control->user_float();
-       if (desired_gain == 0.0f) {
-               set_gain (0.000001f + (0.000001f * factor), src);
-       } else {
-               set_gain (desired_gain + (desired_gain * factor), src);
-       }
+       changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */
+       return 0;
 }
 
-void
-IO::set_gain (gain_t val, void *src)
+int
+IO::disconnect_ports_from_bundle (boost::shared_ptr<Bundle> c, void* src)
 {
-       // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
-       if (val > 1.99526231f) {
-               val = 1.99526231f;
-       }
+       {
+               BLOCK_PROCESS_CALLBACK ();
+               Glib::Mutex::Lock lm2 (io_lock);
 
-       //cerr << "set desired gain to " << val << " when curgain = " << _gain_control->get_value () << endl;
+               c->disconnect (_bundle, _session.engine());
+                       
+               /* If this is a UserBundle, make a note of what we've done */
 
-       if (src != _gain_control.get()) {
-               _gain_control->set_value(val);
-               // bit twisty, this will come back and call us again
-               // (this keeps control in sync with reality)
-               return;
-       }
+               boost::shared_ptr<UserBundle> ub = boost::dynamic_pointer_cast<UserBundle> (c);
+               if (ub) {
 
-       {
-               Glib::Mutex::Lock dm (declick_lock);
-               _gain_control->set_float(val, false);
-       }
+                       std::vector<UserBundleInfo>::iterator i = _bundles_connected.begin();
+                       while (i != _bundles_connected.end() && i->bundle != ub) {
+                               ++i;
+                       }
 
-       if (_session.transport_stopped()) {
-               // _gain = val;
-       }
-       
-       /*
-       if (_session.transport_stopped() && src != 0 && src != this && _gain_control->automation_write()) {
-               _gain_control->list()->add (_session.transport_frame(), val);
-               
+                       if (i != _bundles_connected.end()) {
+                               _bundles_connected.erase (i);
+                       }
+               }
        }
-       */
 
-       _session.set_dirty();
+       changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */
+       return 0;
 }
 
-void
-IO::start_pan_touch (uint32_t which)
-{
-       if (which < _panner->npanners()) {
-               (*_panner).pan_control(which)->start_touch();
-       }
-}
 
-void
-IO::end_pan_touch (uint32_t which)
+int
+IO::disable_connecting ()
 {
-       if (which < _panner->npanners()) {
-               (*_panner).pan_control(which)->stop_touch();
-       }
-
+       connecting_legal = false;
+       return 0;
 }
 
-void
-IO::automation_snapshot (nframes_t now, bool force)
+int
+IO::enable_connecting ()
 {
-       AutomatableControls::automation_snapshot (now, force);
-       // XXX: This seems to be wrong. 
-       // drobilla: shouldnt automation_snapshot for panner be called
-       //           "automagically" because its an Automatable now ?
-       //
-       //           we could dump this whole method then. <3
-
-       if (_last_automation_snapshot > now || (now - _last_automation_snapshot) > _automation_interval) {
-               _panner->automation_snapshot (now, force);
-       }
-       
-       _panner->automation_snapshot (now, force);
-       _last_automation_snapshot = now;
+       connecting_legal = true;
+       return ConnectingLegal ();
 }
 
 void
-IO::transport_stopped (nframes_t frame)
+IO::bundle_changed (Bundle::Change c)
 {
-       _gain_control->list()->reposition_for_rt_add (frame);
-
-       if (_gain_control->automation_state() != Off) {
-               
-               /* the src=0 condition is a special signal to not propagate 
-                  automation gain changes into the mix group when locating.
-               */
-
-               // FIXME: shouldn't this use Curve?
-               set_gain (_gain_control->list()->eval (frame), 0);
-       }
-
-       _panner->transport_stopped (frame);
+       //XXX
+//     connect_input_ports_to_bundle (_input_bundle, this);
 }
 
+
 string
-IO::build_legal_port_name (DataType type, bool in)
+IO::build_legal_port_name (DataType type)
 {
        const int name_size = jack_port_name_size();
        int limit;
@@ -2303,7 +1072,7 @@ IO::build_legal_port_name (DataType type, bool in)
                throw unknown_type();
        }
        
-       if (in) {
+       if (_direction == Input) {
                suffix += _("_in");
        } else {
                suffix += _("_out");
@@ -2318,60 +1087,20 @@ IO::build_legal_port_name (DataType type, bool in)
        
        snprintf (buf1, name_size+1, ("%.*s/%s"), limit, _name.c_str(), suffix.c_str());
        
-       int port_number;
-       
-       if (in) {
-               port_number = find_input_port_hole (buf1);
-       } else {
-               port_number = find_output_port_hole (buf1);
-       }
-       
+       int port_number = find_port_hole (buf1);
        snprintf (buf2, name_size+1, "%s %d", buf1, port_number);
 
        return string (buf2);
 }
 
 int32_t
-IO::find_input_port_hole (const char* base)
-{
-       /* CALLER MUST HOLD IO LOCK */
-
-       uint32_t n;
-
-       if (_inputs.empty()) {
-               return 1;
-       }
-
-       /* we only allow up to 4 characters for the port number
-        */
-
-       for (n = 1; n < 9999; ++n) {
-               char buf[jack_port_name_size()];
-               PortSet::iterator i = _inputs.begin();
-
-               snprintf (buf, jack_port_name_size(), _("%s %u"), base, n);
-
-               for ( ; i != _inputs.end(); ++i) {
-                       if (i->name() == buf) {
-                               break;
-                       }
-               }
-
-               if (i == _inputs.end()) {
-                       break;
-               }
-       }
-       return n;
-}
-
-int32_t
-IO::find_output_port_hole (const char* base)
+IO::find_port_hole (const char* base)
 {
        /* CALLER MUST HOLD IO LOCK */
 
        uint32_t n;
 
-       if (_outputs.empty()) {
+       if (_ports.empty()) {
                return 1;
        }
 
@@ -2380,213 +1109,109 @@ IO::find_output_port_hole (const char* base)
 
        for (n = 1; n < 9999; ++n) {
                char buf[jack_port_name_size()];
-               PortSet::iterator i = _outputs.begin();
+               PortSet::iterator i = _ports.begin();
 
                snprintf (buf, jack_port_name_size(), _("%s %u"), base, n);
 
-               for ( ; i != _outputs.end(); ++i) {
+               for ( ; i != _ports.end(); ++i) {
                        if (i->name() == buf) {
                                break;
                        }
                }
 
-               if (i == _outputs.end()) {
+               if (i == _ports.end()) {
                        break;
                }
        }
-       
        return n;
 }
 
-void
-IO::set_active (bool yn)
-{
-       _active = yn; 
-        active_changed(); /* EMIT SIGNAL */
-}
-
-AudioPort*
-IO::audio_input(uint32_t n) const
-{
-       return dynamic_cast<AudioPort*>(input(n));
-}
 
 AudioPort*
-IO::audio_output(uint32_t n) const
+IO::audio(uint32_t n) const
 {
-       return dynamic_cast<AudioPort*>(output(n));
-}
+       return _ports.nth_audio_port (n);
 
-MidiPort*
-IO::midi_input(uint32_t n) const
-{
-       return dynamic_cast<MidiPort*>(input(n));
 }
 
 MidiPort*
-IO::midi_output(uint32_t n) const
-{
-       return dynamic_cast<MidiPort*>(output(n));
-}
-
-void
-IO::set_phase_invert (bool yn, void *src)
-{
-       if (_phase_invert != yn) {
-               _phase_invert = yn;
-               //  phase_invert_changed (src); /* EMIT SIGNAL */
-       }
-}
-
-void
-IO::set_denormal_protection (bool yn, void *src)
-{
-       if (_denormal_protection != yn) {
-               _denormal_protection = yn;
-               //  denormal_protection_changed (src); /* EMIT SIGNAL */
-       }
-}
-
-void
-IO::update_port_total_latencies ()
+IO::midi(uint32_t n) const
 {
-       /* 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);
-       }
+       return _ports.nth_midi_port (n);
 }
 
-
 /**
  *  Setup bundles that describe our inputs and outputs. Also creates bundles if necessary.
  */
 
 void
-IO::setup_bundles_for_inputs_and_outputs ()
-{
-       setup_bundle_for_inputs ();
-       setup_bundle_for_outputs ();
-}
-
-
-void
-IO::setup_bundle_for_inputs ()
+IO::setup_bundles ()
 {
         char buf[32];
 
-       if (!_bundle_for_inputs) {
-               _bundle_for_inputs.reset (new Bundle (true));
-       }
-
-       _bundle_for_inputs->suspend_signals ();
-
-       _bundle_for_inputs->set_type (default_type ());
-
-       _bundle_for_inputs->remove_channels ();
-
-        snprintf(buf, sizeof (buf), _("%s in"), _name.c_str());
-        _bundle_for_inputs->set_name (buf);
-       uint32_t const ni = inputs().num_ports();
-       for (uint32_t i = 0; i < ni; ++i) {
-               _bundle_for_inputs->add_channel (bundle_channel_name (i, ni));
-               _bundle_for_inputs->set_port (i, _session.engine().make_port_name_non_relative (inputs().port(i)->name()));
+       if (!_bundle) {
+               _bundle.reset (new Bundle (true));
        }
 
-       _bundle_for_inputs->resume_signals ();
-}
+       _bundle->suspend_signals ();
 
+       _bundle->set_type (default_type ());
 
-void
-IO::setup_bundle_for_outputs ()
-{
-        char buf[32];
+       _bundle->remove_channels ();
 
-       if (!_bundle_for_outputs) {
-               _bundle_for_outputs.reset (new Bundle (false));
+       if (_direction == Input) {
+               snprintf(buf, sizeof (buf), _("%s in"), _name.c_str());
+       } else {
+               snprintf(buf, sizeof (buf), _("%s out"), _name.c_str());
        }
-
-       _bundle_for_outputs->suspend_signals ();
-
-       _bundle_for_outputs->set_type (default_type ());
-
-       _bundle_for_outputs->remove_channels ();
-
-        snprintf(buf, sizeof (buf), _("%s out"), _name.c_str());
-        _bundle_for_outputs->set_name (buf);
-       uint32_t const no = outputs().num_ports();
-       for (uint32_t i = 0; i < no; ++i) {
-               _bundle_for_outputs->add_channel (bundle_channel_name (i, no));
-               _bundle_for_outputs->set_port (i, _session.engine().make_port_name_non_relative (outputs().port(i)->name()));
+        _bundle->set_name (buf);
+       uint32_t const ni = _ports.num_ports();
+       for (uint32_t i = 0; i < ni; ++i) {
+               _bundle->add_channel (bundle_channel_name (i, ni));
+               _bundle->set_port (i, _session.engine().make_port_name_non_relative (_ports.port(i)->name()));
        }
 
-       _bundle_for_outputs->resume_signals ();
+       _bundle->resume_signals ();
 }
 
-
-/** @return Bundles connected to our inputs */
+/** @return Bundles connected to our ports */
 BundleList
-IO::bundles_connected_to_inputs ()
+IO::bundles_connected ()
 {
        BundleList bundles;
        
        /* User bundles */
-       for (std::vector<UserBundleInfo>::iterator i = _bundles_connected_to_inputs.begin(); i != _bundles_connected_to_inputs.end(); ++i) {
+       for (std::vector<UserBundleInfo>::iterator i = _bundles_connected.begin(); i != _bundles_connected.end(); ++i) {
                bundles.push_back (i->bundle);
        }
 
        /* Session bundles */
        boost::shared_ptr<ARDOUR::BundleList> b = _session.bundles ();
        for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
-               if ((*i)->connected_to (_bundle_for_inputs, _session.engine())) {
+               if ((*i)->connected_to (_bundle, _session.engine())) {
                        bundles.push_back (*i);
                }
        }
 
        /* Route bundles */
-       boost::shared_ptr<ARDOUR::RouteList> r = _session.get_routes ();
-       for (ARDOUR::RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-               if ((*i)->bundle_for_outputs()->connected_to (_bundle_for_inputs, _session.engine())) {
-                       bundles.push_back ((*i)->bundle_for_outputs());
-               }
-       }
-         
-       return bundles;
-}
-
-
-/* @return Bundles connected to our outputs */
-BundleList
-IO::bundles_connected_to_outputs ()
-{
-       BundleList bundles;
 
-       /* User bundles */
-       for (std::vector<UserBundleInfo>::iterator i = _bundles_connected_to_outputs.begin(); i != _bundles_connected_to_outputs.end(); ++i) {
-               bundles.push_back (i->bundle);
-       }
+       boost::shared_ptr<ARDOUR::RouteList> r = _session.get_routes ();
 
-       /* Session bundles */
-       boost::shared_ptr<ARDOUR::BundleList> b = _session.bundles ();
-       for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
-               if ((*i)->connected_to (_bundle_for_outputs, _session.engine())) {
-                       bundles.push_back (*i);
+       if (_direction == Input) {
+               for (ARDOUR::RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+                       if ((*i)->output()->bundle()->connected_to (_bundle, _session.engine())) {
+                               bundles.push_back ((*i)->output()->bundle());
+                       }
                }
-       }
-
-       /* Route bundles */
-       boost::shared_ptr<ARDOUR::RouteList> r = _session.get_routes ();
-       for (ARDOUR::RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-               if ((*i)->bundle_for_inputs()->connected_to (_bundle_for_outputs, _session.engine())) {
-                       bundles.push_back ((*i)->bundle_for_inputs());
+       } else {
+               for (ARDOUR::RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+                       if ((*i)->input()->bundle()->connected_to (_bundle, _session.engine())) {
+                               bundles.push_back ((*i)->input()->bundle());
+                       }
                }
        }
-
-       return bundles; 
+         
+       return bundles;
 }
 
 
@@ -2598,22 +1223,6 @@ IO::UserBundleInfo::UserBundleInfo (IO* io, boost::shared_ptr<UserBundle> b)
                );
 }
 
-void
-IO::prepare_inputs (nframes_t nframes)
-{
-       /* io_lock, not taken: function must be called from Session::process() calltree */
-}
-
-void
-IO::flush_outputs (nframes_t nframes)
-{
-       /* io_lock, not taken: function must be called from Session::process() calltree */
-
-       for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
-               (*i).flush_buffers (nframes, _output_offset);
-       }
-}
-
 std::string
 IO::bundle_channel_name (uint32_t c, uint32_t n) const
 {
@@ -2654,29 +1263,18 @@ IO::set_name_in_state (XMLNode& node, const string& new_name)
        } 
 }
 
-void
-IO::cycle_start (nframes_t nframes)
-{
-       _output_offset = 0;
-}
-
-void
-IO::increment_output_offset (nframes_t n)
-{
-       _output_offset += n;
-}
-
 bool
 IO::connected_to (boost::shared_ptr<const IO> other) const
 {
+       assert (_direction != other->direction());
+
        uint32_t i, j;
-       
-       uint32_t no = n_outputs().n_total();
-       uint32_t ni = other->n_inputs ().n_total();
+       uint32_t no = n_ports().n_total();
+       uint32_t ni = other->n_ports ().n_total();
        
        for (i = 0; i < no; ++i) {
                for (j = 0; j < ni; ++j) {
-                       if (output(i)->connected_to (other->input(j)->name())) {
+                       if (nth(i)->connected_to (other->nth(j)->name())) {
                                return true;
                        }
                }
@@ -2685,3 +1283,67 @@ IO::connected_to (boost::shared_ptr<const IO> other) const
        return false;
 }
 
+void
+IO::process_input (boost::shared_ptr<Processor> proc, sframes_t start_frame, sframes_t end_frame, nframes_t nframes)
+{
+       BufferSet bufs;
+
+       /* don't read the data into new buffers - just use the port buffers directly */
+
+       bufs.attach_buffers (_ports, nframes, 0);
+       proc->run_in_place (bufs, start_frame, end_frame, nframes);
+}
+
+void
+IO::collect_input (BufferSet& bufs, nframes_t nframes, ChanCount offset)
+{
+       assert(bufs.available() >= _ports.count());
+       
+       if (_ports.count() == ChanCount::ZERO) {
+               return;
+       }
+
+       bufs.set_count (_ports.count());
+
+       for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
+               PortSet::iterator   i = _ports.begin(*t);
+               BufferSet::iterator b = bufs.begin(*t);
+
+               for (uint32_t off = 0; off < offset.get(*t); ++off, ++b) {
+                       if (b == bufs.end(*t)) {
+                               continue;
+                       }
+               }
+
+               for ( ; i != _ports.end(*t); ++i, ++b) {
+                       Buffer& bb (i->get_buffer (nframes));
+                       b->read_from (bb, nframes);
+               }
+       }
+}
+
+void
+IO::copy_to_outputs (BufferSet& bufs, DataType type, nframes_t nframes, nframes_t offset)
+{
+       // Copy any buffers 1:1 to outputs
+       
+       PortSet::iterator o = _ports.begin(type);
+       BufferSet::iterator i = bufs.begin(type);
+       BufferSet::iterator prev = i;
+
+       while (i != bufs.end(type) && o != _ports.end (type)) {
+               Buffer& port_buffer (o->get_buffer (nframes));
+               port_buffer.read_from (*i, nframes, offset);
+               prev = i;
+               ++i;
+               ++o;
+       }
+       
+       // Copy last buffer to any extra outputs
+
+       while (o != _ports.end(type)) {
+               Buffer& port_buffer (o->get_buffer (nframes));
+               port_buffer.read_from (*prev, nframes, offset);
+               ++o;
+       }
+}
index 2eac9dc88b586547af53d2e1180241413ff92b60..7e0d4a771cb04a739040e09d7f2cf6b700d65f25 100644 (file)
@@ -46,20 +46,36 @@ using namespace PBD;
 
 /* create an IOProcessor that proxies to a new IO object */
 
-IOProcessor::IOProcessor (Session& s, const string& proc_name, const string io_name, DataType dtype)
+IOProcessor::IOProcessor (Session& s, bool with_input, bool with_output,
+                         const string& proc_name, const string io_name, DataType dtype)
        : Processor(s, proc_name)
-       , _io (new IO(s, io_name.empty() ? proc_name : io_name, dtype))
 {
-       _own_io = true;
+       /* these are true in this constructor whether we actually create the associated
+          IO objects or not.
+       */
+
+       _own_input = true;
+       _own_output = true;
+
+       if (with_input) {
+               _input.reset (new IO(s, io_name.empty() ? proc_name : io_name, IO::Input, dtype));
+       }
+
+       if (with_output) {
+               _output.reset (new IO(s, io_name.empty() ? proc_name : io_name, IO::Output, dtype));
+       }
 }
 
 /* create an IOProcessor that proxies to an existing IO object */
 
-IOProcessor::IOProcessor (Session& s, IO* io, const string& proc_name, DataType dtype)
+IOProcessor::IOProcessor (Session& s, boost::shared_ptr<IO> in, boost::shared_ptr<IO> out, 
+                         const string& proc_name, DataType dtype)
        : Processor(s, proc_name)
-       , _io (io)
+       , _input (in)
+       , _output (out)
 {
-       _own_io = false;
+       _own_input = false;
+       _own_output = false;
 }
 
 IOProcessor::~IOProcessor ()
@@ -68,12 +84,21 @@ IOProcessor::~IOProcessor ()
 }
 
 void
-IOProcessor::set_io (boost::shared_ptr<IO> io)
+IOProcessor::set_input (boost::shared_ptr<IO> io)
+{
+       /* CALLER MUST HOLD PROCESS LOCK */
+
+       _input = io;
+       _own_input = false;
+}
+
+void
+IOProcessor::set_output (boost::shared_ptr<IO> io)
 {
        /* CALLER MUST HOLD PROCESS LOCK */
 
-       _io = io;
-       _own_io = false;
+       _output = io;
+       _own_output = false;
 }
 
 XMLNode&
@@ -81,12 +106,28 @@ IOProcessor::state (bool full_state)
 {
        XMLNode& node (Processor::state (full_state));
        
-       if (_own_io) {
-               node.add_child_nocopy (_io->state (full_state));
-               node.add_property ("own-io", "yes");
+       if (_own_input) {
+               XMLNode& i (_input->state (full_state));
+               // i.name() = X_("output");
+               node.add_child_nocopy (i);
+               node.add_property ("own-input", "yes");
+       } else {
+               node.add_property ("own-input", "no");
+               if (_input) {
+                       node.add_property ("input", _input->name());
+               }
+       }
+       
+       if (_own_output) {
+               XMLNode& o (_output->state (full_state));
+               // o.name() = X_("output");
+               node.add_child_nocopy (o);
+               node.add_property ("own-output", "yes");
        } else {
-               node.add_property ("own-io", "no");
-               node.add_property ("io", _io->name());
+               node.add_property ("own-output", "no");
+               if (_output) {
+                       node.add_property ("output", _output->name());
+               }
        }
 
        return node;
@@ -100,67 +141,59 @@ IOProcessor::set_state (const XMLNode& node)
 
        Processor::set_state(node);
 
-       if ((prop = node.property ("own-io")) != 0) {
-               _own_io = prop->value() == "yes";
+       if ((prop = node.property ("own-input")) != 0) {
+               _own_input = (prop->value() == "yes");
        }
 
-       /* don't attempt to set state for a proxied IO that we don't own */
-
-       if (!_own_io) {
-
-               /* look up the IO object we're supposed to proxy to */
-
-               if ((prop = node.property ("io")) == 0) {
-                       fatal << "IOProcessor has no named IO object" << endmsg;
-                       /*NOTREACHED*/
-               }
-
-               boost::shared_ptr<Route> r = _session.route_by_name (prop->value());
-
-               if (!r) {
-                       fatal << string_compose ("IOProcessor uses an unknown IO object called %1", prop->value()) << endmsg;
-                       /*NOTREACHED*/
-               }
-
-               /* gotcha */
-
-               _io = boost::static_pointer_cast<IO> (r);
-
-               return 0;
+       if ((prop = node.property ("own-output")) != 0) {
+               _own_output = (prop->value() == "yes");
        }
 
+       cerr << _name << " own input = " << _own_input << " output = " << _own_output << endl;
+       
+       /* don't attempt to set state for a proxied IO that we don't own */
+
        XMLNodeList nlist = node.children();
        XMLNodeIterator niter;
-
-       for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
-               if ((*niter)->name() == IO::state_node_name) {
-                       io_node = (*niter);
-                       break;
-               } else if ((*niter)->name() == "Redirect") {
-                       XMLNodeList rlist = (*niter)->children();
-                       XMLNodeIterator riter;
-
-                       for (riter = rlist.begin(); riter != rlist.end(); ++riter) {
-                               if ( (*riter)->name() == IO::state_node_name) {
-                                       warning << _("Found legacy IO in a redirect") << endmsg;
-                                       io_node = (*riter);
-                                       break;
-                               }
+       
+       if (_own_input) {
+               for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
+                       if ((*niter)->name() == "input") {
+                               io_node = (*niter);
+                               break;
+                       }
+               }
+               
+               if (io_node) {
+                       _input->set_state(*io_node);
+                       
+                       // legacy sessions: use IO name
+                       if ((prop = node.property ("name")) == 0) {
+                               set_name (_input->name());
                        }
+                       
+               } else {
+                       error << _("XML node describing an IOProcessor is missing an IO node") << endmsg;
+                       return -1;
                }
        }
-
-       if (io_node) {
-               _io->set_state(*io_node);
-
-               // legacy sessions: use IO name
-               if ((prop = node.property ("name")) == 0) {
-                       set_name (_io->name());
+       
+       if (_own_output) {
+               for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
+                       if ((*niter)->name() == "output") {
+                               io_node = (*niter);
+                               break;
+                       }
                }
-
-       } else {
-               error << _("XML node describing a redirect is missing an IO node") << endmsg;
-               return -1;
+               
+               if (io_node) {
+                       _output->set_state(*io_node);
+                       
+                       // legacy sessions: use IO name
+                       if ((prop = node.property ("name")) == 0) {
+                               set_name (_output->name());
+                       }
+               } 
        }
 
        return 0;
@@ -169,41 +202,33 @@ IOProcessor::set_state (const XMLNode& node)
 void
 IOProcessor::silence (nframes_t nframes)
 {
-       if (_own_io) {
-               _io->silence (nframes);
+       if (_own_output && _output) {
+               _output->silence (nframes);
        }
 }
 
 ChanCount
 IOProcessor::output_streams() const
 {
-       return _io->n_outputs();
+       return _output ? _output->n_ports() : ChanCount::ZERO;
 }
 
 ChanCount
 IOProcessor::input_streams () const
 {
-       return _io->n_inputs();
+       return _input ? _input->n_ports() : ChanCount::ZERO;
 }
 
 ChanCount
 IOProcessor::natural_output_streams() const
 {
-       return _io->n_outputs();
+       return _output ? _output->n_ports() : ChanCount::ZERO;
 }
 
 ChanCount
 IOProcessor::natural_input_streams () const
 {
-       return _io->n_inputs();
-}
-
-void
-IOProcessor::automation_snapshot (nframes_t now, bool force)
-{
-       if (_own_io) {
-               _io->automation_snapshot(now, force);
-       }
+       return _input ? _input->n_ports() : ChanCount::ZERO;
 }
 
 bool
@@ -211,8 +236,12 @@ IOProcessor::set_name (const std::string& name)
 {
        bool ret = SessionObject::set_name (name);
 
-       if (ret && _own_io) {
-               ret = _io->set_name (name);
+       if (ret && _own_input && _input) {
+               ret = _input->set_name (name);
+       }
+
+       if (ret && _own_output && _output) {
+               ret = _output->set_name (name);
        }
 
        return ret;
index 371e0c5a90bbef7dffaa34dda1f4030eb3c6e691..ed50479c743de4aadb753a981e591ece8b1c6860 100644 (file)
 
 using namespace std;
 
-namespace ARDOUR {
+using namespace ARDOUR;
 
+sigc::signal<void> Metering::Meter;
+Glib::StaticMutex  Metering::m_meter_signal_lock;
+
+sigc::connection
+Metering::connect (sigc::slot<void> the_slot)
+{
+       // SignalProcessor::Meter is emitted from another thread so the
+       // Meter signal must be protected.
+       Glib::Mutex::Lock guard (m_meter_signal_lock);
+       return Meter.connect (the_slot);
+}
+
+void
+Metering::disconnect (sigc::connection& c)
+{
+       Glib::Mutex::Lock guard (m_meter_signal_lock);
+       c.disconnect ();
+}
+
+/**
+    Update the meters.
+
+    The meter signal lock is taken to prevent modification of the 
+    Meter signal while updating the meters, taking the meter signal
+    lock prior to taking the io_lock ensures that all IO will remain 
+    valid while metering.
+*/   
+void
+Metering::update_meters()
+{
+       Glib::Mutex::Lock guard (m_meter_signal_lock);
+       Meter(); /* EMIT SIGNAL */
+}
 
 /** Get peaks from @a bufs
  * Input acceptance is lenient - the first n buffers from @a bufs will
@@ -128,8 +161,10 @@ PeakMeter::configure_io (ChanCount in, ChanCount out)
 }
 
 /** To be driven by the Meter signal from IO.
- * Caller MUST hold io_lock!
+ * Caller MUST hold its own processor_lock to prevent reconfiguration
+ * of meter size during this call.
  */
+
 void
 PeakMeter::meter ()
 {
@@ -139,12 +174,10 @@ PeakMeter::meter ()
 
        for (size_t n = 0; n < limit; ++n) {
 
-               /* XXX we should use atomic exchange here */
-
                /* grab peak since last read */
 
-               float new_peak = _peak_power[n];
-               _peak_power[n] = 0;
+               float new_peak = _peak_power[n]; /* XXX we should use atomic exchange from here ... */
+               _peak_power[n] = 0;              /* ... to here */
                
                /* compute new visible value using falloff */
 
@@ -176,4 +209,3 @@ PeakMeter::state (bool full_state)
        return node;
 }
 
-} // namespace ARDOUR
index 30b1542974531dd99ca623466051af411ad6f259..e0921d89160ce3fd5f92867124313147875f97ea 100644 (file)
@@ -159,8 +159,8 @@ MidiDiskstream::non_realtime_input_change ()
                }
 
                if (input_change_pending & ConfigurationChanged) {
-                       if (_io->n_inputs().n_midi() != _n_channels.n_midi()) {
-                               error << "Can not feed IO " << _io->n_inputs()
+                       if (_io->n_ports().n_midi() != _n_channels.n_midi()) {
+                               error << "Can not feed IO " << _io->n_ports()
                                        << " with diskstream " << _n_channels << endl;
                        }
                } 
@@ -199,7 +199,7 @@ MidiDiskstream::non_realtime_input_change ()
 void
 MidiDiskstream::get_input_sources ()
 {
-       uint32_t ni = _io->n_inputs().n_midi();
+       uint32_t ni = _io->n_ports().n_midi();
 
        if (ni == 0) {
                return;
@@ -208,7 +208,7 @@ MidiDiskstream::get_input_sources ()
        // This is all we do for now at least
        assert(ni == 1);
 
-       _source_port = _io->midi_input(0);
+       _source_port = _io->midi(0);
 
        // do... stuff?
 }              
@@ -421,6 +421,7 @@ MidiDiskstream::check_record_status (nframes_t transport_frame, nframes_t nframe
        last_possibly_recording = possibly_recording;
 }
 
+#if 0
 static void
 trace_midi (ostream& o, MIDI::byte *msg, size_t len)
 {
@@ -587,6 +588,7 @@ trace_midi (ostream& o, MIDI::byte *msg, size_t len)
                break;
        }
 }
+#endif
 
 int
 MidiDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can_record, bool rec_monitors_input)
index c993b17cedb5c730a8271ae9f4a53102ee95722d..a6ff1b93f42fa6d1c4696c3b7cc912563d2c4ac6 100644 (file)
@@ -27,6 +27,7 @@
 
 #include "ardour/amp.h"
 #include "ardour/buffer_set.h"
+#include "ardour/delivery.h"
 #include "ardour/io_processor.h"
 #include "ardour/meter.h"
 #include "ardour/midi_diskstream.h"
@@ -94,14 +95,14 @@ int
 MidiTrack::set_diskstream (boost::shared_ptr<MidiDiskstream> ds)
 {
        _diskstream = ds;
-       _diskstream->set_io (*this);
+       _diskstream->set_io (*(_input.get()));
        _diskstream->set_destructive (_mode == Destructive);
 
        _diskstream->set_record_enabled (false);
        //_diskstream->monitor_input (false);
 
        ic_connection.disconnect();
-       ic_connection = input_changed.connect (mem_fun (*_diskstream, &MidiDiskstream::handle_input_change));
+       ic_connection = _input->changed.connect (mem_fun (*_diskstream, &MidiDiskstream::handle_input_change));
 
        DiskstreamChanged (); /* EMIT SIGNAL */
 
@@ -113,11 +114,14 @@ MidiTrack::use_diskstream (string name)
 {
        boost::shared_ptr<MidiDiskstream> dstream;
 
+       cerr << "\n\n\nMIDI use diskstream\n";
+
        if ((dstream = boost::dynamic_pointer_cast<MidiDiskstream>(_session.diskstream_by_name (name))) == 0) {
                error << string_compose(_("MidiTrack: midi diskstream \"%1\" not known by session"), name) << endmsg;
                return -1;
        }
        
+       cerr << "\n\n\nMIDI found DS\n";
        return set_diskstream (dstream);
 }
 
@@ -191,6 +195,8 @@ MidiTrack::_set_state (const XMLNode& node, bool call_base)
                   that means "you should create a new diskstream here, not look for
                   an old one.
                */
+
+               cerr << "\n\n\n\n MIDI track " << name() << " found DS id " << id << endl;
                
                if (id == zero) {
                        use_new_diskstream ();
@@ -363,8 +369,6 @@ MidiTrack::roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame,
        int dret;
        boost::shared_ptr<MidiDiskstream> diskstream = midi_diskstream();
        
-       prepare_inputs (nframes);
-
        {
                Glib::RWLock::ReaderLock lm (_processor_lock, Glib::TRY_LOCK);
                if (lm.locked()) {
@@ -405,7 +409,7 @@ MidiTrack::roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame,
        /* special condition applies */
 
        if (_meter_point == MeterInput) {
-               just_meter_input (start_frame, end_frame, nframes);
+               _input->process_input (_meter, start_frame, end_frame, nframes);
        }
 
        if (diskstream->record_enabled() && !can_record && !_session.config.get_auto_input()) {
@@ -438,7 +442,7 @@ MidiTrack::roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame,
        
        }
 
-       flush_outputs (nframes);
+       _main_outs->flush (nframes);
 
        return 0;
 }
diff --git a/libs/ardour/mute_master.cc b/libs/ardour/mute_master.cc
new file mode 100644 (file)
index 0000000..ca64fb0
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+
+    Copyright (C) 2009 Paul Davis 
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "ardour/mute_master.h"
+#include "ardour/rc_configuration.h"
+
+#include "i18n.h"
+
+using namespace ARDOUR;
+
+MuteMaster::MuteMaster (Session& s, const std::string& name)
+       : AutomationControl (s, Evoral::Parameter (MuteAutomation), boost::shared_ptr<AutomationList>(), name)
+       , _mute_point (MutePoint (0))
+{
+       // default range for parameter is fine
+
+       _automation = new AutomationList (MuteAutomation);
+       set_list (boost::shared_ptr<AutomationList>(_automation));
+}
+
+void
+MuteMaster::clear_mute ()
+{
+       if (_mute_point != MutePoint (0)) {
+               _mute_point = MutePoint (0);
+               MutePointChanged (); // EMIT SIGNAL
+       }
+}
+
+void
+MuteMaster::mute_at (MutePoint mp)
+{
+       if ((_mute_point & mp) != mp) {
+               _mute_point = MutePoint (_mute_point | mp);
+               MutePointChanged (); // EMIT SIGNAL
+       }
+}
+
+void
+MuteMaster::unmute_at (MutePoint mp)
+{
+       if ((_mute_point & mp) == mp) {
+               _mute_point = MutePoint (_mute_point & ~mp);
+               MutePointChanged (); // EMIT SIGNAL
+       }
+}
+
+void
+MuteMaster::mute (bool yn)
+{
+       /* convenience wrapper around AutomationControl method */
+
+       if (yn) {
+               set_value (1.0f);
+       } else {
+               set_value (0.0f);
+       }
+}
+
+gain_t
+MuteMaster::mute_gain_at (MutePoint mp) const
+{
+       if (_mute_point & mp) {
+               return Config->get_solo_mute_gain ();
+       } else {
+               return 1.0;
+       }
+}
+
+void
+MuteMaster::set_value (float f)
+{
+       mute_at ((MutePoint) ((int) rint (f)));
+}
+
+float
+MuteMaster::get_value () const
+{
+       return (float) _mute_point;
+}
+
+int
+MuteMaster::set_state (const XMLNode& node)
+{
+       return 0;
+}
+
+XMLNode&
+MuteMaster::get_state()
+{
+       return *(new XMLNode (X_("MuteMaster")));
+}
index 73326e12a4537cd82214eb7ce13a40dd57731535..3b700631cbb20294a31e443e571387e8e0b69fb4 100644 (file)
@@ -703,7 +703,8 @@ Multi2dPanner::set_state (const XMLNode& node)
 /*---------------------------------------------------------------------- */
 
 Panner::Panner (string name, Session& s)
-       : Processor(s, name)
+       : SessionObject (s, name)
+       , AutomatableControls (s)
 {
        //set_name_old_auto (name);
        set_name (name);
@@ -829,6 +830,8 @@ Panner::reset (uint32_t nouts, uint32_t npans)
        bool changed = false;
        bool do_not_and_did_not_need_panning = ((nouts < 2) && (outputs.size() < 2));
 
+       cerr << "panner " << _name << " reset to " << nouts << " / " << npans << endl;
+
        /* if new and old config don't need panning, or if 
           the config hasn't changed, we're done.
        */
@@ -1058,15 +1061,13 @@ Panner::get_state (void)
 XMLNode&
 Panner::state (bool full)
 {
-       XMLNode& node = Processor::state(full);
-
-       node.add_property ("type", "panner");
+       XMLNode* node = new XMLNode ("Panner");
 
        char buf[32];
 
-       node.add_property (X_("linked"), (_linked ? "yes" : "no"));
-       node.add_property (X_("link_direction"), enum_2_string (_link_direction));
-       node.add_property (X_("bypassed"), (bypassed() ? "yes" : "no"));
+       node->add_property (X_("linked"), (_linked ? "yes" : "no"));
+       node->add_property (X_("link_direction"), enum_2_string (_link_direction));
+       node->add_property (X_("bypassed"), (bypassed() ? "yes" : "no"));
 
        for (vector<Panner::Output>::iterator o = outputs.begin(); o != outputs.end(); ++o) {
                XMLNode* onode = new XMLNode (X_("Output"));
@@ -1074,15 +1075,15 @@ Panner::state (bool full)
                onode->add_property (X_("x"), buf);
                snprintf (buf, sizeof (buf), "%.12g", (*o).y);
                onode->add_property (X_("y"), buf);
-               node.add_child_nocopy (*onode);
+               node->add_child_nocopy (*onode);
        }
-
+       
        for (vector<StreamPanner*>::const_iterator i = _streampanners.begin(); i != _streampanners.end(); ++i) {
-               node.add_child_nocopy ((*i)->state (full));
+               node->add_child_nocopy ((*i)->state (full));
        }
 
 
-       return node;
+       return *node;
 }
 
 int
@@ -1098,8 +1099,6 @@ Panner::set_state (const XMLNode& node)
 
        clear_panners ();
 
-       Processor::set_state(node);
-
        ChanCount ins = ChanCount::ZERO;
        ChanCount outs = ChanCount::ZERO;
 
@@ -1419,7 +1418,7 @@ Panner::distribute_no_automation (BufferSet& inbufs, BufferSet& outbufs, nframes
 }
 
 void
-Panner::run_out_of_place (BufferSet& inbufs, BufferSet& outbufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes)
+Panner::run (BufferSet& inbufs, BufferSet& outbufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes)
 {      
        if (outbufs.count().n_audio() == 0) {
                // Failing to deliver audio we were asked to deliver is a bug
@@ -1432,16 +1431,16 @@ Panner::run_out_of_place (BufferSet& inbufs, BufferSet& outbufs, sframes_t start
        assert(!empty());
 
        // If we shouldn't play automation defer to distribute_no_automation
-       if ( !( automation_state() & Play ||
-                        ((automation_state() & Touch) && !touching()) ) ) {
+       if (!(automation_state() & Play || ((automation_state() & Touch) && !touching()))) {
 
                // Speed quietning
                gain_t gain_coeff = 1.0;
+
                if (fabsf(_session.transport_speed()) > 1.5f) {
                        gain_coeff = speed_quietning;
                }
 
-               distribute_no_automation(inbufs, outbufs, nframes, gain_coeff);
+               distribute_no_automation (inbufs, outbufs, nframes, gain_coeff);
                return;
        }
 
index 9d0d65ccd511abe4947622924c4e463538a499e5..8ff26337715fb0a43f84b509c17e538260c03563 100644 (file)
@@ -24,6 +24,7 @@
 #include "pbd/failed_constructor.h"
 #include "pbd/xml++.h"
 
+#include "ardour/delivery.h"
 #include "ardour/port_insert.h"
 #include "ardour/plugin.h"
 #include "ardour/port.h"
@@ -40,15 +41,17 @@ using namespace std;
 using namespace ARDOUR;
 using namespace PBD;
 
-PortInsert::PortInsert (Session& s)
-       : IOProcessor (s, string_compose (_("insert %1"), (bitslot = s.next_insert_id()) + 1), "")
+PortInsert::PortInsert (Session& s, boost::shared_ptr<MuteMaster> mm)
+       : IOProcessor (s, true, true, string_compose (_("insert %1"), (bitslot = s.next_insert_id()) + 1), "")
+       , _out (new Delivery (s, _output, mm, _name, Delivery::Insert))
 {
-       init ();
        ProcessorCreated (this); /* EMIT SIGNAL */
 }
 
-PortInsert::PortInsert (Session& s, const XMLNode& node)
-       : IOProcessor (s, "unnamed port insert")
+PortInsert::PortInsert (Session& s, boost::shared_ptr<MuteMaster> mm, const XMLNode& node)
+       : IOProcessor (s, true, true, "unnamed port insert")
+       , _out (new Delivery (s, _output, mm, _name, Delivery::Insert))
+
 {
        if (set_state (node)) {
                throw failed_constructor();
@@ -62,30 +65,21 @@ PortInsert::~PortInsert ()
        GoingAway ();
 }
 
-void
-PortInsert::init ()
-{
-       if (_io->ensure_io(output_streams(), input_streams(), false, this)) { // sic
-               error << _("PortInsert: cannot create ports") << endmsg;
-               throw failed_constructor();
-       }
-}
-
 void
 PortInsert::run_in_place (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes)
 {
-       if (_io->n_outputs().n_total() == 0) {
+       if (_output->n_ports().n_total() == 0) {
                return;
        }
 
        if (!active()) {
                /* deliver silence */
-               _io->silence (nframes);
+               silence (nframes);
                return;
        }
 
-       _io->deliver_output (bufs, start_frame, end_frame, nframes);
-       _io->collect_input (bufs, nframes);
+       _out->run_in_place (bufs, start_frame, end_frame, nframes);
+       _input->collect_input (bufs, nframes, ChanCount::ZERO);
 }
 
 XMLNode&
@@ -97,7 +91,7 @@ PortInsert::get_state(void)
 XMLNode&
 PortInsert::state (bool full)
 {
-       XMLNode& node = IOProcessor::state(full);
+       XMLNode& node = Processor::state(full);
        char buf[32];
        node.add_property ("type", "port");
        snprintf (buf, sizeof (buf), "%" PRIu32, bitslot);
@@ -141,7 +135,7 @@ PortInsert::set_state(const XMLNode& node)
                }
        }
        
-       IOProcessor::set_state (*insert_node);
+       Processor::set_state (*insert_node);
 
        return 0;
 }
@@ -156,7 +150,7 @@ PortInsert::signal_latency() const
           need to take that into account too.
        */
 
-       return _session.engine().frames_per_cycle() + _io->input_latency();
+       return _session.engine().frames_per_cycle() + _input->signal_latency();
 }
 
 bool
@@ -164,7 +158,11 @@ PortInsert::configure_io (ChanCount in, ChanCount out)
 {
        /* for an insert, processor input corresponds to IO output, and vice versa */
 
-       if (_io->ensure_io (out, in, false, this) != 0) {
+       if (_input->ensure_io (in, false, this) != 0) {
+               return false;
+       }
+
+       if (_output->ensure_io (out, false, this) != 0) {
                return false;
        }
 
@@ -178,3 +176,12 @@ PortInsert::can_support_io_configuration (const ChanCount& in, ChanCount& out) c
        return true;
 }
 
+bool
+PortInsert::set_name (const std::string& name)
+{
+       bool ret = Processor::set_name (name);
+
+       ret = (_input->set_name (name) || _output->set_name (name));
+
+       return ret;
+}
index 3fc9fcaee27a6aa9765a9810432b13d33e88014e..2e39c52d674e668ed8dd90e9bc86f98450146d12 100644 (file)
@@ -211,7 +211,8 @@ Processor::configure_io (ChanCount in, ChanCount out)
 {
        /* This class assumes 1:1 input:output.static output stream count.
           Derived classes must override and set _configured_output appropriately
-          if this is not the case */
+          if this is not the case 
+       */
 
        _configured_input = in; 
        _configured_output = out; 
index 1f228d01ca816d0c7f1075642f6f27b91e3b50c0..4942f9023b02bf2bc72688d368b743afcc7f926c 100644 (file)
 
 #include "pbd/xml++.h"
 
-#include "ardour/return.h"
-#include "ardour/session.h"
-#include "ardour/port.h"
+#include "ardour/amp.h"
 #include "ardour/audio_port.h"
 #include "ardour/buffer_set.h"
+#include "ardour/io.h"
 #include "ardour/meter.h"
 #include "ardour/panner.h"
-#include "ardour/io.h"
+#include "ardour/port.h"
+#include "ardour/return.h"
+#include "ardour/session.h"
 
 #include "i18n.h"
 
@@ -36,14 +37,26 @@ using namespace ARDOUR;
 using namespace PBD;
 
 Return::Return (Session& s)
-       : IOProcessor (s, string_compose (_("return %1"), (_bitslot = s.next_return_id()) + 1))
+       : IOProcessor (s, true, false, string_compose (_("return %1"), (_bitslot = s.next_return_id()) + 1))
+       , _metering (false)
 {
+       /* never muted */
+
+       _amp.reset (new Amp (_session, boost::shared_ptr<MuteMaster>()));
+       _meter.reset (new PeakMeter (_session));
+
        ProcessorCreated (this); /* EMIT SIGNAL */
 }
 
 Return::Return (Session& s, const XMLNode& node)
-       : IOProcessor (s, "return")
+       : IOProcessor (s, true, false, "return")
+       , _metering (false)
 {
+       /* never muted */
+
+       _amp.reset (new Amp (_session, boost::shared_ptr<MuteMaster>()));
+       _meter.reset (new PeakMeter (_session));
+
        if (set_state (node)) {
                throw failed_constructor();
        }
@@ -108,23 +121,38 @@ Return::set_state(const XMLNode& node)
 void
 Return::run_in_place (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes)
 {
-       if (active()) {
-               _io->collect_input (bufs, nframes, _configured_input);
-               bufs.set_count(_configured_output);
+       if (!active() || _input->n_ports() == ChanCount::ZERO) {
+               return;
+       }
+       
+       _input->collect_input (bufs, nframes, _configured_input);
+       bufs.set_count(_configured_output);
+
+       // Can't automate gain for sends or returns yet because we need different buffers
+       // so that we don't overwrite the main automation data for the route amp
+       // _amp->setup_gain_automation (start_frame, end_frame, nframes);
+       _amp->run_in_place (bufs, start_frame, end_frame, nframes);
+       
+       if (_metering) {
+               if (_amp->gain_control()->get_value() == 0) {
+                       _meter->reset();
+               } else {
+                       _meter->run_in_place (bufs, start_frame, end_frame, nframes);
+               }
        }
 }
 
 bool
 Return::can_support_io_configuration (const ChanCount& in, ChanCount& out) const
 {
-       out = in + _io->n_inputs();
+       out = in + _input->n_ports();
        return true;
 }
 
 bool
 Return::configure_io (ChanCount in, ChanCount out)
 {
-       if (out != in + _io->n_inputs()) {
+       if (out != in + _input->n_ports()) {
                return false;
        }
 
@@ -162,3 +190,4 @@ Return::make_unique (XMLNode &state, Session &session)
        }
 }
 
+
index ccdd5236543a2423a079ae79f53e745d595f3c07..edd38eb80cbf7bf8effb11ebdf6b968ee72b04cd 100644 (file)
@@ -64,19 +64,23 @@ uint32_t Route::order_key_cnt = 0;
 sigc::signal<void,const char*> Route::SyncOrderKeys;
 
 Route::Route (Session& sess, string name, Flag flg, DataType default_type)
-       : IO (sess, name, default_type)
+       : SessionObject (sess, name)
+       , AutomatableControls (sess)
        , _flags (flg)
-       , _solo_control (new ToggleControllable (X_("solo"), *this, ToggleControllable::SoloControl))
-       , _mute_control (new ToggleControllable (X_("mute"), *this, ToggleControllable::MuteControl))
+       , _solo_control (new SoloControllable (X_("solo"), *this))
+       , _mute_master (new MuteMaster (sess, name))
+       , _default_type (default_type)
+         
 {
        init ();
-
 }
 
 Route::Route (Session& sess, const XMLNode& node, DataType default_type)
-       : IO (sess, *node.child ("IO"), default_type)
-       , _solo_control (new ToggleControllable (X_("solo"), *this, ToggleControllable::SoloControl))
-       , _mute_control (new ToggleControllable (X_("mute"), *this, ToggleControllable::MuteControl))
+       : SessionObject (sess, "toBeReset")
+       , AutomatableControls (sess)
+       , _solo_control (new SoloControllable (X_("solo"), *this))
+       , _mute_master (new MuteMaster (sess, "toBeReset"))
+       , _default_type (default_type)
 {
        init ();
        _set_state (node, false);
@@ -85,21 +89,15 @@ Route::Route (Session& sess, const XMLNode& node, DataType default_type)
 void
 Route::init ()
 {
+       _active = true;
        processor_max_streams.reset();
-       _muted = false;
-       _soloed = false;
        _solo_safe = false;
        _recordable = true;
-       _active = true;
-       _phase_invert = false;
-       _denormal_protection = false;
        order_keys[strdup (N_("signal"))] = order_key_cnt++;
        _silent = false;
        _meter_point = MeterPostFader;
        _initial_delay = 0;
        _roll_delay = 0;
-       _own_latency = 0;
-       _user_latency = 0;
        _have_internal_generator = false;
        _declickable = false;
        _pending_declick = true;
@@ -109,32 +107,42 @@ Route::init ()
        _edit_group = 0;
        _mix_group = 0;
 
-       _mute_affects_pre_fader = Config->get_mute_affects_pre_fader();
-       _mute_affects_post_fader = Config->get_mute_affects_post_fader();
-       _mute_affects_control_outs = Config->get_mute_affects_control_outs();
-       _mute_affects_main_outs = Config->get_mute_affects_main_outs();
-       
-       solo_gain = 1.0;
-       desired_solo_gain = 1.0;
-       mute_gain = 1.0;
-       desired_mute_gain = 1.0;
+       _phase_invert = 0;
+       _denormal_protection = false;
+
+       /* add standard controls */
 
-       input_changed.connect (mem_fun (this, &Route::input_change_handler));
-       output_changed.connect (mem_fun (this, &Route::output_change_handler));
+       add_control (_solo_control);
+       add_control (_mute_master);
        
-       /* add standard processors: amp, meter, main outs */
+       /* input and output objects */
 
-       /* amp & meter belong to IO but need to be added to our processor list */
+       _input.reset (new IO (_session, _name, IO::Input, _default_type));
+       _output.reset (new IO (_session, _name, IO::Output, _default_type));
 
+       _input->changed.connect (mem_fun (this, &Route::input_change_handler));
+       _output->changed.connect (mem_fun (this, &Route::output_change_handler));
+
+       /* add standard processors */
+
+       _amp.reset (new Amp (_session, _mute_master));
        add_processor (_amp, PostFader);
+
+       _meter.reset (new PeakMeter (_session));
        add_processor (_meter, PreFader);
        
-       _main_outs.reset (new Delivery (_session, this, _name, Delivery::Main));
+       _main_outs.reset (new Delivery (_session, _output, _mute_master, _name, Delivery::Main));
        add_processor (_main_outs, PostFader);
+
+       /* now we can meter */
+       
+       _meter_connection = Metering::connect (mem_fun (*this, &Route::meter));
 }
 
 Route::~Route ()
 {
+       Metering::disconnect (_meter_connection);
+
        clear_processors (PreFader);
        clear_processors (PostFader);
 
@@ -224,10 +232,11 @@ Route::ensure_track_or_route_name(string name, Session &session)
        return newname;
 }
 
+
 void
 Route::inc_gain (gain_t fraction, void *src)
 {
-       IO::inc_gain (fraction, src);
+       _amp->inc_gain (fraction, src);
 }
 
 void
@@ -237,7 +246,7 @@ Route::set_gain (gain_t val, void *src)
                
                if (_mix_group->is_relative()) {
                        
-                       gain_t usable_gain = gain();
+                       gain_t usable_gain = _amp->gain();
                        if (usable_gain < 0.000001f) {
                                usable_gain = 0.000001f;
                        }
@@ -257,13 +266,13 @@ Route::set_gain (gain_t val, void *src)
                        if (factor > 0.0f) {
                                factor = _mix_group->get_max_factor(factor);
                                if (factor == 0.0f) {
-                                       _gain_control->Changed(); /* EMIT SIGNAL */
+                                       _amp->gain_control()->Changed(); /* EMIT SIGNAL */
                                        return;
                                }
                        } else {
                                factor = _mix_group->get_min_factor(factor);
                                if (factor == 0.0f) {
-                                       _gain_control->Changed(); /* EMIT SIGNAL */
+                                       _amp->gain_control()->Changed(); /* EMIT SIGNAL */
                                        return;
                                }
                        }
@@ -278,11 +287,11 @@ Route::set_gain (gain_t val, void *src)
                return;
        } 
 
-       if (val == gain()) {
+       if (val == _amp->gain()) {
                return;
        }
 
-       IO::set_gain (val, src);
+       _amp->set_gain (val, src);
 }
 
 /** Process this route for one (sub) cycle (process thread)
@@ -300,132 +309,78 @@ Route::process_output_buffers (BufferSet& bufs,
                               sframes_t start_frame, sframes_t end_frame, nframes_t nframes,
                               bool with_processors, int declick)
 {
-       ProcessorList::iterator i;
-       bool mute_declick_applied = false;
-       gain_t dmg, dsg, dg;
-       bool no_monitor;
+       bool monitor;
 
-       bufs.is_silent(false);
+       bufs.is_silent (false);
 
        switch (Config->get_monitoring_model()) {
        case HardwareMonitoring:
        case ExternalMonitoring:
-               no_monitor = true;
+               monitor = record_enabled() && (_session.config.get_auto_input() || _session.actively_recording());
                break;
        default:
-               no_monitor = false;
-       }
-
-       declick = _pending_declick;
-       
-       const bool recording_without_monitoring = no_monitor && record_enabled()
-                       && (!_session.config.get_auto_input() || _session.actively_recording());
-       
-
-       /* -------------------------------------------------------------------------------------------
-          SET UP GAIN (FADER)
-          ----------------------------------------------------------------------------------------- */
-
-       { 
-               Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
-               
-               if (dm.locked()) {
-                       dmg = desired_mute_gain;
-                       dsg = desired_solo_gain;
-                       dg = _gain_control->user_float();
-               } else {
-                       dmg = mute_gain;
-                       dsg = solo_gain;
-                       dg = _gain;
-               }
+               monitor = true;
        }
-       
-       // apply gain at the amp if...
-       _amp->apply_gain(
-                       // we're not recording
-                       !(record_enabled() && _session.actively_recording())
-                       // or (we are recording, and) software monitoring is required
-                       || Config->get_monitoring_model() == SoftwareMonitoring);
-       
-       // mute at the amp if...
-       _amp->apply_mute (!_soloed && (mute_gain != dmg) && !mute_declick_applied && _mute_affects_post_fader,
-                         mute_gain, dmg);
 
-       _amp->set_gain (_gain, dg);
-       
-
-       /* -------------------------------------------------------------------------------------------
-          SET UP CONTROL OUTPUTS
-          ----------------------------------------------------------------------------------------- */
-
-       boost::shared_ptr<Delivery> co = _control_outs;
-       if (co) {
-               // deliver control outputs unless we're ...
-               bool self_mute = ((dmg == 0 && _mute_affects_control_outs) || // or muted by mute of this track
-                                 !recording_without_monitoring); // or rec-enabled w/o s/w monitoring 
-               bool other_mute = (dsg == 0); // muted by solo of another track
-               
-               co->set_self_mute (self_mute);
-               co->set_nonself_mute (other_mute);
+       if (!declick) {
+               declick = _pending_declick;
        }
 
-       /* -------------------------------------------------------------------------------------------
-          SET UP MAIN OUTPUT STAGE
-          ----------------------------------------------------------------------------------------- */
+       /* figure out if we're going to use gain automation */
 
-       bool solo_audible = dsg > 0;
-       bool mute_audible = dmg > 0 || !_mute_affects_main_outs;
+       _amp->setup_gain_automation (start_frame, end_frame, nframes);
+       
+       /* tell main outs what to do about monitoring */
 
-       bool silent_anyway = (_gain == 0 && !_amp->apply_gain_automation());
-       bool muted_by_other_solo = (!solo_audible && (Config->get_solo_model() != SoloBus));
-       bool muted_by_self = !mute_audible;
+       _main_outs->no_outs_cuz_we_no_monitor (!monitor);
 
-       _main_outs->set_nonself_mute (recording_without_monitoring || muted_by_other_solo || silent_anyway);
-       _main_outs->set_self_mute (muted_by_self);
-       
        /* -------------------------------------------------------------------------------------------
           GLOBAL DECLICK (for transport changes etc.)
           ----------------------------------------------------------------------------------------- */
 
        if (declick > 0) {
-               Amp::apply_gain (bufs, nframes, 0.0, 1.0, false);
-               _pending_declick = 0;
+               Amp::apply_gain (bufs, nframes, 0.0, 1.0);
        } else if (declick < 0) {
-               Amp::apply_gain (bufs, nframes, 1.0, 0.0, false);
-               _pending_declick = 0;
-       } else { // no global declick
-               if (solo_gain != dsg) {
-                       Amp::apply_gain (bufs, nframes, solo_gain, dsg, false);
-                       solo_gain = dsg;
-               }
-       }
-
+               Amp::apply_gain (bufs, nframes, 1.0, 0.0);
+       } 
 
+       _pending_declick = 0;
+               
        /* -------------------------------------------------------------------------------------------
-          PRE-FADER MUTING
+          DENORMAL CONTROL/PHASE INVERT
           ----------------------------------------------------------------------------------------- */
 
-       if (!_soloed && _mute_affects_pre_fader && (mute_gain != dmg)) {
-               Amp::apply_gain (bufs, nframes, mute_gain, dmg, false);
-               mute_gain = dmg;
-               mute_declick_applied = true;
-       }
-       if (mute_gain == 0.0f && dmg == 0.0f) {
-               bufs.is_silent(true);
-       }
+       if (_phase_invert) {
+               
+               int chn = 0;
 
+               if (_denormal_protection || Config->get_denormal_protection()) {
+                       
+                       for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i, ++chn) {
+                               Sample* const sp = i->data();
 
-       /* -------------------------------------------------------------------------------------------
-          DENORMAL CONTROL
-          ----------------------------------------------------------------------------------------- */
+                               if (_phase_invert & chn) {
+                                       for (nframes_t nx = 0; nx < nframes; ++nx) {
+                                               sp[nx]  = -sp[nx];
+                                               sp[nx] += 1.0e-27f;
+                                       }
+                               } else {
+                                       for (nframes_t nx = 0; nx < nframes; ++nx) {
+                                               sp[nx] += 1.0e-27f;
+                                       }
+                               }
+                       }
 
-       if (_denormal_protection || Config->get_denormal_protection()) {
+               } else {
 
-               for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i) {
-                       Sample* const sp = i->data();
-                       
-                       for (nframes_t nx = 0; nx < nframes; ++nx) {
-                               sp[nx] += 1.0e-27f;
+                       for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i, ++chn) {
+                               Sample* const sp = i->data();
+                               
+                               if (_phase_invert & chn) {
+                                       for (nframes_t nx = 0; nx < nframes; ++nx) {
+                                               sp[nx] = -sp[nx];
+                                       }
+                               } 
                        }
                }
        }
@@ -437,57 +392,48 @@ Route::process_output_buffers (BufferSet& bufs,
        Glib::RWLock::ReaderLock rm (_processor_lock, Glib::TRY_LOCK);
 
        if (rm.locked()) {
-               for (i = _processors.begin(); i != _processors.end(); ++i) {
-                       bufs.set_count(ChanCount::max(bufs.count(), (*i)->input_streams()));
+               for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
+                       bufs.set_count (ChanCount::max(bufs.count(), (*i)->input_streams()));
                        (*i)->run_in_place (bufs, start_frame, end_frame, nframes);
-                       bufs.set_count(ChanCount::max(bufs.count(), (*i)->output_streams()));
+                       bufs.set_count (ChanCount::max(bufs.count(), (*i)->output_streams()));
                }
 
                if (!_processors.empty()) {
-                       bufs.set_count(ChanCount::max(bufs.count(), _processors.back()->output_streams()));
+                       bufs.set_count (ChanCount::max (bufs.count(), _processors.back()->output_streams()));
                }
        }
-
-       /* -------------------------------------------------------------------------------------------
-          POST-FADER MUTING
-          ----------------------------------------------------------------------------------------- */
-
-       if (!_soloed && (mute_gain != dmg) && !mute_declick_applied && _mute_affects_main_outs) {
-               Amp::apply_gain (bufs, nframes, mute_gain, dmg, false);
-               mute_gain = dmg;
-               mute_declick_applied = true;
-       }
-
-       if (mute_gain == 0.0f && dmg == 0.0f) {
-               bufs.is_silent(true);
-       }
-       
-       // at this point we've reached the desired mute gain regardless
-       mute_gain = dmg;
 }
 
 ChanCount
 Route::n_process_buffers ()
 {
-       return max (n_inputs(), processor_max_streams);
-}
-
-void
-Route::setup_peak_meters()
-{
-       ChanCount max_streams = std::max (_inputs.count(), _outputs.count());
-       max_streams = std::max (max_streams, processor_max_streams);
-       _meter->configure_io (max_streams, max_streams);
+       return max (_input->n_ports(), processor_max_streams);
 }
 
 void
 Route::passthru (sframes_t start_frame, sframes_t end_frame, nframes_t nframes, int declick)
 {
-       BufferSet& bufs = _session.get_scratch_buffers(n_process_buffers());
+       BufferSet& bufs = _session.get_scratch_buffers (n_process_buffers());
 
        _silent = false;
 
-       collect_input (bufs, nframes);
+       assert (bufs.available() >= _input->n_ports());
+       
+       if (_input->n_ports() == ChanCount::ZERO) {
+               silence (nframes);
+       }
+       
+       bufs.set_count (_input->n_ports());
+       
+       for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
+               
+               BufferSet::iterator o = bufs.begin(*t);
+               PortSet& ports (_input->ports());
+
+               for (PortSet::iterator i = ports.begin(*t); i != ports.end(*t); ++i, ++o) {
+                       o->read_from (i->get_buffer(nframes), nframes);
+               }
+       }
 
        process_output_buffers (bufs, start_frame, end_frame, nframes, true, declick);
 }
@@ -510,82 +456,58 @@ Route::set_solo (bool yn, void *src)
                return;
        }
 
-       if (_soloed != yn) {
-               _soloed = yn;
+       if (_main_outs->soloed() != yn) {
+               _main_outs->mod_solo_level (yn ? 1 : -1);
                solo_changed (src); /* EMIT SIGNAL */
                _solo_control->Changed (); /* EMIT SIGNAL */
        }       
-       
-       catch_up_on_solo_mute_override ();
 }
 
-void
-Route::catch_up_on_solo_mute_override ()
+bool
+Route::soloed() const
 {
-       if (Config->get_solo_model() != InverseMute) {
-               return;
-       }
-       
-       {
-               Glib::Mutex::Lock lm (declick_lock);
-               
-               if (_muted) {
-                       if (Config->get_solo_mute_override()) {
-                               desired_mute_gain = (_soloed?1.0:0.0);
-                       } else {
-                               desired_mute_gain = 0.0;
-                       }
-               } else {
-                       desired_mute_gain = 1.0;
-               }
-       }
+       return _main_outs->soloed ();
 }
 
 void
-Route::set_solo_mute (bool yn)
+Route::set_solo_isolated (bool yn, void *src)
 {
-       Glib::Mutex::Lock lm (declick_lock);
+       if (_mix_group && src != _mix_group && _mix_group->is_active()) {
+               _mix_group->apply (&Route::set_solo_isolated, yn, _mix_group);
+               return;
+       }
 
-       /* Called by Session in response to another Route being soloed.
-        */
-          
-       desired_solo_gain = (yn?0.0:1.0);
+       _main_outs->set_solo_isolated (yn);
+       solo_isolated_changed (src);
 }
 
-void
-Route::set_solo_safe (bool yn, void *src)
+bool
+Route::solo_isolated () const 
 {
-       if (_solo_safe != yn) {
-               _solo_safe = yn;
-                solo_safe_changed (src); /* EMIT SIGNAL */
-       }
+       return _main_outs->solo_isolated();
 }
 
 void
 Route::set_mute (bool yn, void *src)
-
 {
        if (_mix_group && src != _mix_group && _mix_group->is_active()) {
                _mix_group->apply (&Route::set_mute, yn, _mix_group);
                return;
        }
 
-       if (_muted != yn) {
-               _muted = yn;
-               mute_changed (src); /* EMIT SIGNAL */
-               
-               _mute_control->Changed (); /* EMIT SIGNAL */
-               
-               Glib::Mutex::Lock lm (declick_lock);
-               
-               if (_soloed && Config->get_solo_mute_override()) {
-                       desired_mute_gain = 1.0f;
-               } else {
-                       desired_mute_gain = (yn?0.0f:1.0f);
-               }
+       if (muted() != yn) {
+               _mute_master->mute (yn);
+               mute_changed (src);
        }
+}      
+
+bool
+Route::muted() const 
+{
+       return _mute_master->muted ();
 }
 
+#if DEFINE_IF_YOU_NEED_THIS
 static void
 dump_processors(const string& name, const list<boost::shared_ptr<Processor> >& procs)
 {
@@ -596,6 +518,7 @@ dump_processors(const string& name, const list<boost::shared_ptr<Processor> >& p
        }
        cerr << "}" << endl;
 }
+#endif
 
 Route::ProcessorList::iterator
 Route::prefader_iterator() 
@@ -702,22 +625,19 @@ Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorList::ite
                        
                }
                
-               // Ensure peak vector sizes before the plugin is activated
-               ChanCount potential_max_streams = ChanCount::max (processor->input_streams(), processor->output_streams());
-
-               _meter->configure_io (potential_max_streams, potential_max_streams);
+               if (_meter) {
+                       // Ensure peak vector sizes before the plugin is activated
+                       ChanCount potential_max_streams = ChanCount::max (processor->input_streams(), processor->output_streams());
+                       _meter->configure_io (potential_max_streams, potential_max_streams);
+               }
 
                // XXX: do we want to emit the signal here ? change call order.
                processor->activate ();
                processor->ActiveChanged.connect (bind (mem_fun (_session, &Session::update_latency_compensation), false, false));
 
-               _user_latency = 0;
+               _output->set_user_latency (0);
        }
        
-       if (processor_max_streams != old_pms || old_pms == ChanCount::ZERO) {
-               reset_panner ();
-       }
-
        processors_changed (); /* EMIT SIGNAL */
        
        return 0;
@@ -747,7 +667,7 @@ Route::add_processor_from_xml (const XMLNode& node, ProcessorList::iterator iter
        if (node.name() == "Send") {
        
                try {
-                       boost::shared_ptr<Send> send (new Send (_session, node));
+                       boost::shared_ptr<Send> send (new Send (_session, _mute_master, node));
                        add_processor (send, iter); 
                        return true;
                } 
@@ -762,6 +682,9 @@ Route::add_processor_from_xml (const XMLNode& node, ProcessorList::iterator iter
                try {
                        if ((prop = node.property ("type")) != 0) {
 
+
+                               cerr << _name << " : got processor type " << prop->value() << endl;
+
                                boost::shared_ptr<Processor> processor;
                                bool have_insert = false;
 
@@ -775,31 +698,35 @@ Route::add_processor_from_xml (const XMLNode& node, ProcessorList::iterator iter
                                        
                                } else if (prop->value() == "port") {
 
-                                       processor.reset (new PortInsert (_session, node));
+                                       processor.reset (new PortInsert (_session, _mute_master, node));
                                
                                } else if (prop->value() == "send") {
 
-                                       processor.reset (new Send (_session, node));
+                                       processor.reset (new Send (_session, _mute_master, node));
                                        have_insert = true;
                                
                                } else if (prop->value() == "meter") {
 
                                        processor = _meter;
+                                       processor->set_state (node);
                                
                                } else if (prop->value() == "amp") {
                                        
                                        processor = _amp;
+                                       processor->set_state (node);
                                        
                                } else if (prop->value() == "listen" || prop->value() == "deliver") {
 
                                        /* XXX need to generalize */
 
                                        processor = _control_outs;
+                                       processor->set_state (node);
                                        
                                } else if (prop->value() == "main-outs") {
                                        
                                        processor = _main_outs;
-                                       
+                                       processor->set_state (node);
+
                                } else {
 
                                        error << string_compose(_("unknown Processor type \"%1\"; ignored"), prop->value()) << endmsg;
@@ -884,7 +811,7 @@ Route::add_processors (const ProcessorList& others, ProcessorList::iterator iter
                ProcessorList::iterator existing_end = _processors.end();
                --existing_end;
 
-               ChanCount potential_max_streams = ChanCount::max (n_inputs(), n_outputs());
+               ChanCount potential_max_streams = ChanCount::max (_input->n_ports(), _output->n_ports());
 
                for (ProcessorList::const_iterator i = others.begin(); i != others.end(); ++i) {
                        
@@ -921,11 +848,7 @@ Route::add_processors (const ProcessorList& others, ProcessorList::iterator iter
                        (*i)->ActiveChanged.connect (bind (mem_fun (_session, &Session::update_latency_compensation), false, false));
                }
 
-               _user_latency = 0;
-       }
-       
-       if (processor_max_streams != old_pms || old_pms == ChanCount::ZERO) {
-               reset_panner ();
+               _output->set_user_latency (0);
        }
        
        processors_changed (); /* EMIT SIGNAL */
@@ -1081,7 +1004,7 @@ Route::pre_fader_streams() const
        if (processor) {
                return processor->output_streams();
        } else {
-               return n_inputs ();
+               return _input->n_ports ();
        }
 }
 
@@ -1134,10 +1057,6 @@ Route::clear_processors (Placement p)
                configure_processors_unlocked (&err); // this can't fail
        }
 
-       if (processor_max_streams != old_pms) {
-               reset_panner ();
-       }
-       
        processor_max_streams.reset();
        _have_internal_generator = false;
        processors_changed (); /* EMIT SIGNAL */
@@ -1173,7 +1092,7 @@ Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStream
                        if (*i == processor) {
 
                                /* move along, see failure case for configure_processors()
-                                  where we may need to reprocessor the processor.
+                                  where we may need to reconfigure the processor.
                                */
 
                                /* stop redirects that send signals to JACK ports
@@ -1181,13 +1100,17 @@ Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStream
                                   run.
                                */
 
-                               boost::shared_ptr<IOProcessor> redirect;
-                               
-                               if ((redirect = boost::dynamic_pointer_cast<IOProcessor> (*i)) != 0) {
-                                       redirect->io()->disconnect_inputs (this);
-                                       redirect->io()->disconnect_outputs (this);
+                               boost::shared_ptr<IOProcessor> iop;
+
+                               if ((iop = boost::dynamic_pointer_cast<IOProcessor> (*i)) != 0) {
+                                       if (iop->input()) {
+                                               iop->input()->disconnect (this);
+                                       }
+                                       if (iop->output()) {
+                                               iop->output()->disconnect (this);
+                                       }
                                }
-                               
+
                                i = _processors.erase (i);
                                removed = true;
                                break;
@@ -1196,7 +1119,7 @@ Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStream
                                ++i;
                        }
 
-                       _user_latency = 0;
+                       _output->set_user_latency (0);
                }
 
                if (!removed) {
@@ -1226,10 +1149,6 @@ Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStream
                }
        }
 
-       if (old_pms != processor_max_streams) {
-               reset_panner ();
-       }
-
        processor->drop_references ();
        processors_changed (); /* EMIT SIGNAL */
 
@@ -1259,7 +1178,7 @@ Route::configure_processors_unlocked (ProcessorStreams* err)
        _in_configure_processors = true;
 
        // Check each processor in order to see if we can configure as requested
-       ChanCount in = n_inputs();
+       ChanCount in = _input->n_ports ();
        ChanCount out;
        list< pair<ChanCount,ChanCount> > configuration;
        uint32_t index = 0;
@@ -1288,8 +1207,8 @@ Route::configure_processors_unlocked (ProcessorStreams* err)
        }
 
        // Ensure route outputs match last processor's outputs
-       if (out != n_outputs()) {
-               ensure_io (n_inputs(), out, false, this);
+       if (out != _output->n_ports ()) {
+               _output->ensure_io (out, false, this);
        }
 
        _in_configure_processors = false;
@@ -1354,6 +1273,12 @@ Route::all_processors_active (Placement p, bool state)
 int
 Route::reorder_processors (const ProcessorList& new_order, Placement placement, ProcessorStreams* err)
 {
+       /* "new_order" is an ordered list of processors to be positioned according to "placement".
+          NOTE: all processors in "new_order" MUST be marked as visible. There maybe additional
+          processors in the current actual processor list that are hidden. Any visible processors
+          in the current list but not in "new_order" will be assumed to be deleted.
+       */
+
        {
                Glib::RWLock::WriterLock lm (_processor_lock);
                ChanCount old_pms = processor_max_streams;
@@ -1384,6 +1309,10 @@ Route::reorder_processors (const ProcessorList& new_order, Placement placement,
                                */
 
                                as_it_will_be.insert (as_it_will_be.end(), niter, new_order.end());
+                               while (niter != new_order.end()) {
+                                       (*niter)->set_placement (placement);
+                                       ++niter;
+                               }
                                break;
 
                        } else {
@@ -1391,16 +1320,18 @@ Route::reorder_processors (const ProcessorList& new_order, Placement placement,
                                if (!(*oiter)->visible()) {
 
                                        as_it_will_be.push_back (*oiter);
+                                       (*oiter)->set_placement (placement);
 
                                } else {
 
                                        /* visible processor: check that its in the new order */
 
                                        if (find (new_order.begin(), new_order.end(), (*oiter)) == new_order.end()) {
-                                               /* deleted: do nothing */
+                                               /* deleted: do nothing, shared_ptr<> will clean up */
                                        } else {
                                                /* ignore this one, and add the next item from the new order instead */
                                                as_it_will_be.push_back (*niter);
+                                               (*niter)->set_placement (placement);
                                                ++niter;
                                        }
                                }
@@ -1420,8 +1351,6 @@ Route::reorder_processors (const ProcessorList& new_order, Placement placement,
                } 
        } 
 
-       /* do we really need to do this every time? */
-       reset_panner ();
        processors_changed (); /* EMIT SIGNAL */
 
        return 0;
@@ -1446,21 +1375,16 @@ Route::state(bool full_state)
        ProcessorList::iterator i;
        char buf[32];
 
+       node->add_property ("name", _name);
+       node->add_property("default-type", _default_type.to_string());
+
        if (_flags) {
                node->add_property("flags", enum_2_string (_flags));
        }
-       
-       node->add_property("default-type", _default_type.to_string());
 
        node->add_property("active", _active?"yes":"no");
-       node->add_property("muted", _muted?"yes":"no");
-       node->add_property("soloed", _soloed?"yes":"no");
        node->add_property("phase-invert", _phase_invert?"yes":"no");
        node->add_property("denormal-protection", _denormal_protection?"yes":"no");
-       node->add_property("mute-affects-pre-fader", _mute_affects_pre_fader?"yes":"no"); 
-       node->add_property("mute-affects-post-fader", _mute_affects_post_fader?"yes":"no"); 
-       node->add_property("mute-affects-control-outs", _mute_affects_control_outs?"yes":"no"); 
-       node->add_property("mute-affects-main-outs", _mute_affects_main_outs?"yes":"no");
        node->add_property("meter-point", enum_2_string (_meter_point));
 
        if (_edit_group) {
@@ -1489,9 +1413,10 @@ Route::state(bool full_state)
        }
        node->add_property ("order-keys", order_string);
 
-       node->add_child_nocopy (IO::state (full_state));
+       node->add_child_nocopy (_input->state (full_state));
+       node->add_child_nocopy (_output->state (full_state));
        node->add_child_nocopy (_solo_control->get_state ());
-       node->add_child_nocopy (_mute_control->get_state ());
+       node->add_child_nocopy (_mute_master->get_state ());
 
        XMLNode* remote_control_node = new XMLNode (X_("RemoteControl"));
        snprintf (buf, sizeof (buf), "%d", _remote_control_id);
@@ -1514,92 +1439,6 @@ Route::state(bool full_state)
        return *node;
 }
 
-XMLNode&
-Route::get_processor_state ()
-{
-       XMLNode* root = new XMLNode (X_("redirects"));
-       for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
-               root->add_child_nocopy ((*i)->state (true));
-       }
-
-       return *root;
-}
-
-int
-Route::set_processor_state (const XMLNode& root)
-{
-       if (root.name() != X_("redirects")) {
-               return -1;
-       }
-
-       XMLNodeList nlist;
-       XMLNodeList nnlist;
-       XMLNodeConstIterator iter;
-       XMLNodeConstIterator niter;
-       Glib::RWLock::ReaderLock lm (_processor_lock);
-
-       nlist = root.children();
-       
-       for (iter = nlist.begin(); iter != nlist.end(); ++iter){
-
-               /* iter now points to a IOProcessor state node */
-               
-               nnlist = (*iter)->children ();
-
-               for (niter = nnlist.begin(); niter != nnlist.end(); ++niter) {
-
-                       /* find the IO child node, since it contains the ID we need */
-
-                       /* XXX OOP encapsulation violation, ugh */
-
-                       if ((*niter)->name() == IO::state_node_name) {
-
-                               XMLProperty* prop = (*niter)->property (X_("id"));
-                               
-                               if (!prop) {
-                                       warning << _("IOProcessor node has no ID, ignored") << endmsg;
-                                       break;
-                               }
-
-                               ID id = prop->value ();
-
-                               /* now look for a processor with that ID */
-       
-                               for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
-                                       if ((*i)->id() == id) {
-                                               (*i)->set_state (**iter);
-                                               break;
-                                       }
-                               }
-                               
-                               break;
-                               
-                       }
-               }
-
-       }
-
-       return 0;
-}
-
-void
-Route::set_deferred_state ()
-{
-       XMLNodeList nlist;
-       XMLNodeConstIterator niter;
-
-       if (!deferred_state) {
-               return;
-       }
-
-       nlist = deferred_state->children();
-
-       _set_processor_states (nlist);
-
-       delete deferred_state;
-       deferred_state = 0;
-}
-
 int
 Route::set_state (const XMLNode& node)
 {
@@ -1609,6 +1448,7 @@ Route::set_state (const XMLNode& node)
 int
 Route::_set_state (const XMLNode& node, bool call_base)
 {
+
        XMLNodeList nlist;
        XMLNodeConstIterator niter;
        XMLNode *child;
@@ -1620,17 +1460,16 @@ Route::_set_state (const XMLNode& node, bool call_base)
                return -1;
        }
 
+       if ((prop = node.property (X_("name"))) != 0) {
+               Route::set_name (prop->value());
+       } 
+
        if ((prop = node.property (X_("flags"))) != 0) {
                _flags = Flag (string_2_enum (prop->value(), _flags));
        } else {
                _flags = Flag (0);
        }
        
-       if ((prop = node.property (X_("default-type"))) != 0) {
-               _default_type = DataType(prop->value());
-               assert(_default_type != DataType::NIL);
-       }
-
        if ((prop = node.property (X_("phase-invert"))) != 0) {
                set_phase_invert (prop->value()=="yes"?true:false, this);
        }
@@ -1639,45 +1478,18 @@ Route::_set_state (const XMLNode& node, bool call_base)
                set_denormal_protection (prop->value()=="yes"?true:false, this);
        }
        
-       _active = true;
        if ((prop = node.property (X_("active"))) != 0) {
-               set_active (prop->value() == "yes");
-       }
-
-       if ((prop = node.property (X_("muted"))) != 0) {
-               bool yn = prop->value()=="yes"?true:false; 
-
-               /* force reset of mute status */
-
-               _muted = !yn;
-               set_mute(yn, this);
-               mute_gain = desired_mute_gain;
+               bool yn = (prop->value() == "yes");
+               _active = !yn; // force switch
+               set_active (yn);
        }
 
        if ((prop = node.property (X_("soloed"))) != 0) {
-               bool yn = prop->value()=="yes"?true:false; 
+               bool yn = (prop->value()=="yes");
 
-               /* force reset of solo status */
+               /* XXX force reset of solo status */
 
-               _soloed = !yn;
                set_solo (yn, this);
-               solo_gain = desired_solo_gain;
-       }
-
-       if ((prop = node.property (X_("mute-affects-pre-fader"))) != 0) {
-               _mute_affects_pre_fader = (prop->value()=="yes")?true:false;
-       }
-
-       if ((prop = node.property (X_("mute-affects-post-fader"))) != 0) {
-               _mute_affects_post_fader = (prop->value()=="yes")?true:false;
-       }
-
-       if ((prop = node.property (X_("mute-affects-control-outs"))) != 0) {
-               _mute_affects_control_outs = (prop->value()=="yes")?true:false;
-       }
-
-       if ((prop = node.property (X_("mute-affects-main-outs"))) != 0) {
-               _mute_affects_main_outs = (prop->value()=="yes")?true:false;
        }
 
        if ((prop = node.property (X_("meter-point"))) != 0) {
@@ -1725,51 +1537,35 @@ Route::_set_state (const XMLNode& node, bool call_base)
        }
 
        nlist = node.children();
-
-       delete deferred_state;
-       deferred_state = new XMLNode(X_("deferred state"));
-
-       /* set parent class properties before anything else */
+       XMLNode processor_state (X_("processor_state"));
 
        for (niter = nlist.begin(); niter != nlist.end(); ++niter){
-
+               
                child = *niter;
 
-               if (child->name() == IO::state_node_name && call_base) {
-                       IO::set_state (*child);
-                       break;
+               if (child->name() == IO::state_node_name) {
+                       if ((prop = child->property (X_("direction"))) == 0) {
+                               continue;
+                       }
+                       
+                       if (prop->value() == "Input") {
+                               _input->set_state (*child);
+                       } else if (prop->value() == "Output") {
+                               _output->set_state (*child);
+                       }
                }
-       }
-
-       for (niter = nlist.begin(); niter != nlist.end(); ++niter){
-               
-               child = *niter;
                        
-               if (child->name() == X_("Send") || child->name() == X_("Processor")) {
-                       deferred_state->add_child_copy (*child);
+               if (child->name() == X_("Processor")) {
+                       processor_state.add_child_copy (*child);
                }
        }
 
-       if (ports_legal) {
-               _set_processor_states (deferred_state->children());
-               delete deferred_state;
-               deferred_state = 0;
-       }
-
+       set_processor_state (processor_state);
+       
        for (niter = nlist.begin(); niter != nlist.end(); ++niter){
                child = *niter;
 
-               if (child->name() == X_("Automation")) {
-                       
-                       if ((prop = child->property (X_("path"))) != 0)  {
-                               load_automation (prop->value());
-                       }
-
-               } else if (child->name() == X_("ControlOuts")) {
-
-                       /* ignore this - deprecated */
-
-               } else if (child->name() == X_("Comment")) {
+               if (child->name() == X_("Comment")) {
 
                        /* XXX this is a terrible API design in libxml++ */
 
@@ -1785,17 +1581,15 @@ Route::_set_state (const XMLNode& node, bool call_base)
                        if (prop->value() == "solo") {
                                _solo_control->set_state (*child);
                                _session.add_controllable (_solo_control);
-                       } else if (prop->value() == "mute") {
-                               _mute_control->set_state (*child);
-                               _session.add_controllable (_mute_control);
-                       }
+                       } 
+
                } else if (child->name() == X_("RemoteControl")) {
                        if ((prop = child->property (X_("id"))) != 0) {
                                int32_t x;
                                sscanf (prop->value().c_str(), "%d", &x);
                                set_remote_control_id (x);
                        }
-               }
+               } 
        }
 
        if ((prop = node.property (X_("mix-group"))) != 0) {
@@ -1810,13 +1604,27 @@ Route::_set_state (const XMLNode& node, bool call_base)
        return 0;
 }
 
+XMLNode&
+Route::get_processor_state ()
+{
+       XMLNode* root = new XMLNode (X_("redirects"));
+       for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
+               root->add_child_nocopy ((*i)->state (true));
+       }
+
+       return *root;
+}
+
 void
-Route::_set_processor_states(const XMLNodeList &nlist)
+Route::set_processor_state (const XMLNode& node)
 {
+       const XMLNodeList &nlist = node.children();
        XMLNodeConstIterator niter;
        bool has_meter_processor = false; // legacy sessions don't
        ProcessorList::iterator i, o;
 
+       cerr << _name << " _set_processor_states\n";
+
        // Iterate through existing processors, remove those which are not in the state list
        for (i = _processors.begin(); i != _processors.end(); ) {
                ProcessorList::iterator tmp = i;
@@ -1852,6 +1660,8 @@ Route::_set_processor_states(const XMLNodeList &nlist)
                        has_meter_processor = true;
                }
 
+               cerr << _name << " setting up proc state for " << prop->value() << endl;
+
                o = i;
 
                if (prop->value() != "meter" && prop->value() != "amp" && prop->value() != "main-outs") {
@@ -1872,6 +1682,8 @@ Route::_set_processor_states(const XMLNodeList &nlist)
                // create it and move it to the correct location
                if (o == _processors.end()) {
 
+                       cerr << "\tproc not in list\n";
+
                        if (add_processor_from_xml (**niter, i)) {
                                --i; // move iterator to the newly inserted processor
                        } else {
@@ -1882,6 +1694,8 @@ Route::_set_processor_states(const XMLNodeList &nlist)
                // ensure it is at the location provided in the XML state
                } else {
 
+                       cerr << "\tproc in wrong place in list\n";
+                       
                        if (i != o) {
                                boost::shared_ptr<Processor> tmp = (*o);
                                _processors.erase (o); // remove the old copy
@@ -1889,6 +1703,7 @@ Route::_set_processor_states(const XMLNodeList &nlist)
                                --i; // move iterator to the correct processor
                        }
 
+                       cerr << "\tnow reset proc " << (*i)->name() << endl;
                        (*i)->set_state (**niter);
                }
        }
@@ -1902,9 +1717,6 @@ Route::_set_processor_states(const XMLNodeList &nlist)
        }
 
        processors_changed ();
-
-       
-
 }
 
 void
@@ -1919,7 +1731,7 @@ Route::silence (nframes_t nframes)
 {
        if (!_silent) {
 
-               IO::silence (nframes);
+               _output->silence (nframes);
                
                { 
                        Glib::RWLock::ReaderLock lm (_processor_lock, Glib::TRY_LOCK);
@@ -1953,7 +1765,7 @@ Route::add_listener (boost::shared_ptr<IO> io, const string& listen_name)
        name += listen_name;
        name += ']';
        
-       boost::shared_ptr<Delivery> listener (new Delivery (_session, name, Delivery::Listen)); 
+       boost::shared_ptr<Delivery> listener (new Delivery (_session, _mute_master, name, Delivery::Listen)); 
 
        /* As an IO, our control outs need as many IO outputs as we have outputs
         *   (we track the changes in ::output_change_handler()).
@@ -1961,7 +1773,7 @@ Route::add_listener (boost::shared_ptr<IO> io, const string& listen_name)
         *   (i.e. it does not modify its input buffers whatsoever)
         */
 
-       if (listener->io()->ensure_io (ChanCount::ZERO, n_outputs(), true, this)) {
+       if (listener->output()->ensure_io (n_outputs(), true, this)) {
                return boost::shared_ptr<Delivery>();
        }
        
@@ -1982,17 +1794,17 @@ Route::listen_via (boost::shared_ptr<IO> io, const string& listen_name)
                for (ProcessorList::const_iterator x = _processors.begin(); x != _processors.end(); ++x) {
                        boost::shared_ptr<const Delivery> d = boost::dynamic_pointer_cast<const Delivery>(*x);
 
-                       if (d && d->io() == io) {
+                       if (d && d->output() == io) {
                                /* already listening via the specified IO: do nothing */
                                return 0;
                        }
                }
        }
 
-       uint32_t ni = io->n_inputs().n_total();
+       uint32_t ni = io->n_ports().n_total();
 
        for (uint32_t n = 0; n < ni; ++n) {
-               ports.push_back (io->input(n)->name());
+               ports.push_back (io->nth (n)->name());
        }
 
        if (ports.empty()) {
@@ -2007,13 +1819,13 @@ Route::listen_via (boost::shared_ptr<IO> io, const string& listen_name)
 
        /* now connect to the named ports */
        
-       ni = listen_point->io()->n_outputs().n_total();
+       ni = listen_point->output()->n_ports().n_total();
        size_t psize = ports.size();
 
        for (size_t n = 0; n < ni; ++n) {
-               if (listen_point->io()->connect_output (listen_point->io()->output (n), ports[n % psize], this)) {
+               if (listen_point->output()->connect (listen_point->output()->nth (n), ports[n % psize], this)) {
                        error << string_compose (_("could not connect %1 to %2"),
-                                                listen_point->io()->output(n)->name(), ports[n % psize]) << endmsg;
+                                                listen_point->output()->nth (n)->name(), ports[n % psize]) << endmsg;
                        return -1;
                }
        }
@@ -2037,7 +1849,7 @@ Route::drop_listen (boost::shared_ptr<IO> io)
                
                boost::shared_ptr<Delivery> d = boost::dynamic_pointer_cast<Delivery>(*x);
                
-               if (d && d->io() == io) {
+               if (d && d->output() == io) {
                        /* already listening via the specified IO: do nothing */
                        remove_processor (*x, &err);
                        
@@ -2114,7 +1926,7 @@ Route::set_comment (string cmt, void *src)
 bool
 Route::feeds (boost::shared_ptr<IO> other)
 {
-       if (connected_to (other)) {
+       if (_output->connected_to (other)) {
                return true;
        }
 
@@ -2122,10 +1934,10 @@ Route::feeds (boost::shared_ptr<IO> other)
 
        for (ProcessorList::iterator r = _processors.begin(); r != _processors.end(); r++) {
 
-               boost::shared_ptr<IOProcessor> proc;
-
-               if ((proc = boost::dynamic_pointer_cast<IOProcessor>(*r)) != 0) {
-                       if (proc->io()->connected_to (other)) {
+               boost::shared_ptr<IOProcessor> iop;
+               
+               if ((iop = boost::dynamic_pointer_cast<IOProcessor>(*r)) != 0) {
+                       if (iop->output() && iop->output()->connected_to (other)) {
                                return true;
                        }
                }
@@ -2134,55 +1946,6 @@ Route::feeds (boost::shared_ptr<IO> other)
        return false;
 }
 
-void
-Route::set_mute_config (mute_type t, bool onoff, void *src)
-{
-       switch (t) {
-       case PRE_FADER:
-               _mute_affects_pre_fader = onoff;
-               pre_fader_changed(src); /* EMIT SIGNAL */
-               break;
-
-       case POST_FADER:
-               _mute_affects_post_fader = onoff;
-               post_fader_changed(src); /* EMIT SIGNAL */
-               break;
-
-       case CONTROL_OUTS:
-               _mute_affects_control_outs = onoff;
-               control_outs_changed(src); /* EMIT SIGNAL */
-               break;
-
-       case MAIN_OUTS:
-               _mute_affects_main_outs = onoff;
-               main_outs_changed(src); /* EMIT SIGNAL */
-               break;
-       }
-}
-
-bool
-Route::get_mute_config (mute_type t)
-{
-       bool onoff = false;
-       
-       switch (t){
-       case PRE_FADER:
-               onoff = _mute_affects_pre_fader; 
-               break;
-       case POST_FADER:
-               onoff = _mute_affects_post_fader;
-               break;
-       case CONTROL_OUTS:
-               onoff = _mute_affects_control_outs;
-               break;
-       case MAIN_OUTS:
-               onoff = _mute_affects_main_outs;
-               break;
-       }
-       
-       return onoff;
-}
-
 void
 Route::handle_transport_stopped (bool abort_ignored, bool did_locate, bool can_flush_processors)
 {
@@ -2206,8 +1969,6 @@ Route::handle_transport_stopped (bool abort_ignored, bool did_locate, bool can_f
                }
        }
 
-       IO::transport_stopped (now);
        _roll_delay = _initial_delay;
 }
 
@@ -2223,11 +1984,10 @@ void
 Route::output_change_handler (IOChange change, void *src)
 {
        if ((change & ConfigurationChanged)) {
-               if (_control_outs) {
-                       _control_outs->io()->ensure_io (ChanCount::ZERO, n_outputs(), true, this);
-               }
                
-               configure_processors (0);
+               /* XXX resize all listeners to match _main_outs? */
+               
+               // configure_processors (0);
        }
 }
 
@@ -2249,18 +2009,13 @@ Route::no_roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame,
                return 0;
        }
 
-       if (session_state_changing || !_active)  {
+       if (session_state_changing || !_active || n_inputs() == ChanCount::ZERO)  {
                silence (nframes);
                return 0;
        }
 
-       _amp->apply_gain_automation(false);
-       
-       if (n_inputs() != ChanCount::ZERO) {
-               passthru (start_frame, end_frame, nframes, 0);
-       } else {
-               silence (nframes);
-       }
+       _amp->apply_gain_automation (false);
+       passthru (start_frame, end_frame, nframes, 0);
 
        return 0;
 }
@@ -2283,7 +2038,7 @@ Route::check_initial_delay (nframes_t nframes, nframes_t& transport_frame)
                   output ports, so make a note of that for
                   future reference.
                */
-               increment_output_offset (_roll_delay);
+               _main_outs->increment_output_offset (_roll_delay);
                transport_frame += _roll_delay;
 
                _roll_delay = 0;
@@ -2297,15 +2052,20 @@ Route::roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame, int
             bool can_record, bool rec_monitors_input)
 {
        {
+               // automation snapshot can also be called from the non-rt context
+               // and it uses the processor list, so we try to acquire the lock here
                Glib::RWLock::ReaderLock lm (_processor_lock, Glib::TRY_LOCK);
+
                if (lm.locked()) {
-                       // automation snapshot can also be called from the non-rt context
-                       // and it uses the processor list, so we take the lock out here
                        automation_snapshot (_session.transport_frame(), false);
                }
        }
 
-       if ((n_outputs().n_total() == 0 && _processors.empty()) || n_inputs().n_total() == 0 || !_active) {
+       if (n_outputs().n_total() == 0) {
+               return 0;
+       }
+
+       if (!_active || n_inputs().n_total() == 0) {
                silence (nframes);
                return 0;
        }
@@ -2318,21 +2078,6 @@ Route::roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame, int
 
        _silent = false;
 
-       _amp->apply_gain_automation(false);
-
-       { 
-               Glib::Mutex::Lock am (data().control_lock(), Glib::TRY_LOCK);
-               
-               if (am.locked() && _session.transport_rolling()) {
-                       
-                       if (_gain_control->automation_playback()) {
-                               _amp->apply_gain_automation(
-                                               _gain_control->list()->curve().rt_safe_get_vector (
-                                                       start_frame, end_frame, _session.gain_automation_buffer(), nframes));
-                       }
-               }
-       }
-
        passthru (start_frame, end_frame, nframes, declick);
 
        return 0;
@@ -2349,7 +2094,7 @@ Route::silent_roll (nframes_t nframes, sframes_t start_frame, sframes_t end_fram
 void
 Route::toggle_monitor_input ()
 {
-       for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
+       for (PortSet::iterator i = _input->ports().begin(); i != _input->ports().end(); ++i) {
                i->ensure_monitor_input( ! i->monitoring_input());
        }
 }
@@ -2357,15 +2102,15 @@ Route::toggle_monitor_input ()
 bool
 Route::has_external_redirects () const
 {
-       // FIXME: what about sends?
+       // FIXME: what about sends? - they don't return a signal back to ardour?
 
        boost::shared_ptr<const PortInsert> pi;
        
        for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) {
+
                if ((pi = boost::dynamic_pointer_cast<const PortInsert>(*i)) != 0) {
 
-                       for (PortSet::const_iterator port = pi->io()->outputs().begin();
-                                       port != pi->io()->outputs().end(); ++port) {
+                       for (PortSet::const_iterator port = pi->output()->ports().begin(); port != pi->output()->ports().end(); ++port) {
                                
                                string port_name = port->name();
                                string client_name = port_name.substr (0, port_name.find(':'));
@@ -2428,55 +2173,51 @@ Route::set_meter_point (MeterPoint p, void *src)
 nframes_t
 Route::update_total_latency ()
 {
-       nframes_t old = _own_latency;
-
-       if (_user_latency) {
-               _own_latency = _user_latency;
-       } else {
-               _own_latency = 0;
+       nframes_t old = _output->effective_latency();
+       nframes_t own_latency = _output->user_latency();
 
-               for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
-                       if ((*i)->active ()) {
-                               _own_latency += (*i)->signal_latency ();
-                       }
+       for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
+               if ((*i)->active ()) {
+                       own_latency += (*i)->signal_latency ();
                }
        }
 
 #undef DEBUG_LATENCY
 #ifdef DEBUG_LATENCY
-       cerr << _name << ": internal redirect latency = " << _own_latency << endl;
+       cerr << _name << ": internal redirect latency = " << own_latency << endl;
 #endif
 
-       set_port_latency (_own_latency);
+       _output->set_port_latency (own_latency);
        
-       if (!_user_latency) {
+       if (_output->user_latency() == 0) {
+
                /* 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->signal_latency ();
        }
 
-       if (old != _own_latency) {
+       if (old != own_latency) {
+               _output->set_latency_delay (own_latency);
                signal_latency_changed (); /* EMIT SIGNAL */
        }
        
 #ifdef DEBUG_LATENCY
-       cerr << _name << ": input latency = " << input_latency() << " total = "
-            << _own_latency << endl;
+       cerr << _name << ": input latency = " << _input->signal_latency() << " total = "
+            << own_latency << endl;
 #endif
 
-       return _own_latency;
+       return _output->effective_latency ();
 }
 
 void
 Route::set_user_latency (nframes_t nframes)
 {
-       Latent::set_user_latency (nframes);
+       _output->set_user_latency (nframes);
        _session.update_latency_compensation (false, false);
 }
 
@@ -2485,8 +2226,8 @@ Route::set_latency_delay (nframes_t longest_session_latency)
 {
        nframes_t old = _initial_delay;
 
-       if (_own_latency < longest_session_latency) {
-               _initial_delay = longest_session_latency - _own_latency;
+       if (_output->effective_latency() < longest_session_latency) {
+               _initial_delay = longest_session_latency - _output->effective_latency();
        } else {
                _initial_delay = 0;
        }
@@ -2503,57 +2244,32 @@ Route::set_latency_delay (nframes_t longest_session_latency)
 void
 Route::automation_snapshot (nframes_t now, bool force)
 {
-       if (!force && !should_snapshot(now)) {
-               return;
-       }
-
-       IO::automation_snapshot (now, force);
-
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
                (*i)->automation_snapshot (now, force);
        }
 }
 
-Route::ToggleControllable::ToggleControllable (std::string name, Route& s, ToggleType tp)
-       : Controllable (name), route (s), type(tp)
+Route::SoloControllable::SoloControllable (std::string name, Route& r)
+       : AutomationControl (r.session(), Evoral::Parameter (SoloAutomation), 
+                            boost::shared_ptr<AutomationList>(), name)
+       , route (r)
 {
-       
+       boost::shared_ptr<AutomationList> gl(new AutomationList(Evoral::Parameter(SoloAutomation)));
+       set_list (gl);
 }
 
 void
-Route::ToggleControllable::set_value (float val)
+Route::SoloControllable::set_value (float val)
 {
        bool bval = ((val >= 0.5f) ? true: false);
        
-       switch (type) {
-       case MuteControl:
-               route.set_mute (bval, this);
-               break;
-       case SoloControl:
-               route.set_solo (bval, this);
-               break;
-       default:
-               break;
-       }
+       route.set_solo (bval, this);
 }
 
 float
-Route::ToggleControllable::get_value (void) const
+Route::SoloControllable::get_value (void) const
 {
-       float val = 0.0f;
-       
-       switch (type) {
-       case MuteControl:
-               val = route.muted() ? 1.0f : 0.0f;
-               break;
-       case SoloControl:
-               val = route.soloed() ? 1.0f : 0.0f;
-               break;
-       default:
-               break;
-       }
-
-       return val;
+       return route.soloed() ? 1.0f : 0.0f;
 }
 
 void 
@@ -2568,8 +2284,6 @@ Route::set_block_size (nframes_t nframes)
 void
 Route::protect_automation ()
 {
-       Automatable::protect_automation();
-       
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i)
                (*i)->protect_automation();
 }
@@ -2656,23 +2370,28 @@ Route::set_name (const string& str)
 {
        bool ret;
        string ioproc_name;
+       
+       SessionObject::set_name (str);
+       
+       ret = (_input->set_name(str) && _output->set_name(str));
 
-       if ((ret = IO::set_name (str)) == true) {
+       if (ret) {
+               
                Glib::RWLock::ReaderLock lm (_processor_lock);
                
                for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
                        
-                       /* rename all delivery objects to reflect our new name */
+                       /* rename all processors with outputs to reflect our new name */
 
-                       boost::shared_ptr<Delivery> dp = boost::dynamic_pointer_cast<Delivery> (*i);
+                       boost::shared_ptr<IOProcessor> iop = boost::dynamic_pointer_cast<IOProcessor> (*i);
 
-                       if (dp) {
-                               string dp_name = str;
-                               dp_name += '[';
-                               dp_name += "XXX FIX ME XXX";
-                               dp_name += ']';
+                       if (iop) {
+                               string iop_name = str;
+                               iop_name += '[';
+                               iop_name += "XXX FIX ME XXX";
+                               iop_name += ']';
                                
-                               if (!dp->set_name (dp_name)) {
+                               if (!iop->set_name (iop_name)) {
                                        ret = false;
                                }
                        }
@@ -2692,7 +2411,7 @@ Route::send_for (boost::shared_ptr<const IO> target) const
                boost::shared_ptr<Send> send;
                
                if ((send = boost::dynamic_pointer_cast<Send>(*i)) != 0) {
-                       if (send->io()->connected_to (target)) {
+                       if (send->output()->connected_to (target)) {
                                return send;
                        }
                }
@@ -2700,3 +2419,95 @@ Route::send_for (boost::shared_ptr<const IO> target) const
        
        return boost::shared_ptr<Send>();
 }
+
+void
+Route::set_phase_invert (bool yn, void *src)
+{
+       if (_phase_invert != yn) {
+               _phase_invert = yn;
+               //  phase_invert_changed (src); /* EMIT SIGNAL */
+       }
+}
+
+bool
+Route::phase_invert () const
+{
+       return _phase_invert != 0;
+}
+
+void
+Route::set_denormal_protection (bool yn, void *src)
+{
+       if (_denormal_protection != yn) {
+               _denormal_protection = yn;
+               //  denormal_protection_changed (src); /* EMIT SIGNAL */
+       }
+}
+
+bool
+Route::denormal_protection () const
+{
+       return _denormal_protection;
+}
+
+void
+Route::set_active (bool yn)
+{
+       if (_active != yn) {
+               _active = yn;
+               _input->set_active (yn);
+               _output->set_active (yn);
+               active_changed (); // EMIT SIGNAL
+       }
+}
+
+void
+Route::meter ()
+{
+       Glib::RWLock::ReaderLock rm (_processor_lock, Glib::TRY_LOCK);
+       _meter->meter ();
+}
+
+boost::shared_ptr<Panner>
+Route::panner() const
+{
+
+       return _main_outs->panner();
+}
+
+boost::shared_ptr<AutomationControl>
+Route::gain_control() const
+{
+
+       return _amp->gain_control();
+}
+
+boost::shared_ptr<AutomationControl>
+Route::get_control (const Evoral::Parameter& param)
+{
+       /* either we own the control or .... */
+
+       boost::shared_ptr<AutomationControl> c = boost::dynamic_pointer_cast<AutomationControl>(data().control (param));
+
+       if (!c) {
+
+               /* maybe one of our processors does or ... */
+               
+               Glib::RWLock::ReaderLock rm (_processor_lock, Glib::TRY_LOCK);
+               for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
+                       if ((c = boost::dynamic_pointer_cast<AutomationControl>((*i)->data().control (param))) != 0) {
+                               break;
+                       }
+               }
+       }
+               
+       if (!c) {
+
+               /* nobody does so we'll make a new one */
+
+               c = boost::dynamic_pointer_cast<AutomationControl>(control_factory(param));
+               add_control(c);
+       }
+
+       return c;
+}
index 527597548d69830b18d57364e7fa96e0eb68899e..438d0395d01c8ecf007947bd919d0843ff395abd 100644 (file)
@@ -27,6 +27,7 @@
 #include "pbd/error.h"
 #include "pbd/enumwriter.h"
 
+#include "ardour/amp.h"
 #include "ardour/route_group.h"
 #include "ardour/audio_track.h"
 #include "ardour/audio_diskstream.h"
@@ -87,7 +88,7 @@ RouteGroup::get_min_factor(gain_t factor)
        gain_t g;
        
        for (list<Route *>::iterator i = routes.begin(); i != routes.end(); i++) {
-               g = (*i)->gain();
+               g = (*i)->amp()->gain();
 
                if ( (g+g*factor) >= 0.0f)
                        continue;
@@ -106,7 +107,7 @@ RouteGroup::get_max_factor(gain_t factor)
        gain_t g;
        
        for (list<Route *>::iterator i = routes.begin(); i != routes.end(); i++) {
-               g = (*i)->gain();
+               g = (*i)->amp()->gain();
                
                // if the current factor woulnd't raise this route above maximum
                if ( (g+g*factor) <= 1.99526231f) 
index 5874b91cf6bada9398c2e836e080ea70a8580687..61c235e60ae395ce9afc7d5885b33d43d1722b0e 100644 (file)
@@ -21,6 +21,7 @@
 
 #include "pbd/xml++.h"
 
+#include "ardour/amp.h"
 #include "ardour/send.h"
 #include "ardour/session.h"
 #include "ardour/port.h"
 using namespace ARDOUR;
 using namespace PBD;
 
-Send::Send (Session& s)
-       : Delivery (s, string_compose (_("send %1"), (_bitslot = s.next_send_id()) + 1), Delivery::Send)
+Send::Send (Session& s, boost::shared_ptr<MuteMaster> mm)
+       : Delivery (s, mm, string_compose (_("send %1"), (_bitslot = s.next_send_id()) + 1), Delivery::Send)
+       , _metering (false)
 {
+       _amp.reset (new Amp (_session, _mute_master));
+       _meter.reset (new PeakMeter (_session));
+
        ProcessorCreated (this); /* EMIT SIGNAL */
 }
 
-Send::Send (Session& s, const XMLNode& node)
-       : Delivery (s, "send", Delivery::Send)
+Send::Send (Session& s, boost::shared_ptr<MuteMaster> mm, const XMLNode& node)
+       : Delivery (s, mm, "send", Delivery::Send)
+       , _metering (false)
 {
+       _amp.reset (new Amp (_session, _mute_master));
+       _meter.reset (new PeakMeter (_session));
+
        if (set_state (node)) {
                throw failed_constructor();
        }
@@ -56,6 +65,43 @@ Send::~Send ()
        GoingAway ();
 }
 
+void
+Send::run_in_place (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes)
+{
+       if (!_active || _output->n_ports() == ChanCount::ZERO) {
+               _meter->reset ();
+               return;
+       }
+
+       // we have to copy the input, because deliver_output() may alter the buffers
+       // in-place, which a send must never do.
+       
+       BufferSet& sendbufs = _session.get_mix_buffers (bufs.count());
+       sendbufs.read_from (bufs, nframes);
+       assert(sendbufs.count() == bufs.count());
+
+       /* gain control */
+
+       // Can't automate gain for sends or returns yet because we need different buffers
+       // so that we don't overwrite the main automation data for the route amp
+       // _amp->setup_gain_automation (start_frame, end_frame, nframes);
+       _amp->run_in_place (sendbufs, start_frame, end_frame, nframes);
+
+       /* deliver to outputs */
+
+       Delivery::run_in_place (sendbufs, start_frame, end_frame, nframes);
+
+       /* consider metering */
+       
+       if (_metering) {
+               if (_amp->gain_control()->get_value() == 0) {
+                       _meter->reset();
+               } else {
+                       _meter->run_in_place (*_output_buffers, start_frame, end_frame, nframes);
+               }
+       }
+}
+
 XMLNode&
 Send::get_state(void)
 {
@@ -90,17 +136,9 @@ Send::set_state(const XMLNode& node)
 
        const XMLNode* insert_node = &node;
 
-       /* Send has regular IO automation (gain, pan) */
-
-       for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
-               if ((*niter)->name() == IOProcessor::state_node_name) {
-                       insert_node = *niter;
-               } else if ((*niter)->name() == X_("Automation")) {
-                       // _io->set_automation_state (*(*niter), Evoral::Parameter(GainAutomation));
-               }
-       }
+       /* XXX need to load automation state & data for amp */
        
-       IOProcessor::set_state (*insert_node);
+       Delivery::set_state (*insert_node);
 
        return 0;
 }
@@ -108,7 +146,7 @@ Send::set_state(const XMLNode& node)
 bool
 Send::can_support_io_configuration (const ChanCount& in, ChanCount& out) const
 {
-       if (_io->n_inputs() == ChanCount::ZERO && _io->n_outputs() == ChanCount::ZERO) {
+       if (_output->n_ports() == ChanCount::ZERO) {
 
                /* not configured yet, we can support anything */
 
@@ -126,25 +164,6 @@ Send::can_support_io_configuration (const ChanCount& in, ChanCount& out) const
        return false;
 }
 
-bool
-Send::configure_io (ChanCount in, ChanCount out)
-{
-       /* we're transparent no matter what.  fight the power. */
-
-       if (out != in) {
-               return false;
-       }
-
-       if (_io->ensure_io (ChanCount::ZERO, in, false, this) != 0) {
-               return false;
-       }
-
-       Processor::configure_io(in, out);
-       _io->reset_panner();
-
-       return true;
-}
-
 /** Set up the XML description of a send so that its name is unique.
  *  @param state XML send state.
  *  @param session Session.
index db6063e7f4f180df41f8ac3531d6c7193b3bfbc9..25f3f6a3680e3a1d0a9966e6fd8b42b8a1ac4812 100644 (file)
@@ -272,7 +272,8 @@ Session::Session (AudioEngine &eng,
                if (control_out_channels) {
                        ChanCount count(DataType::AUDIO, control_out_channels);
                        shared_ptr<Route> r (new Route (*this, _("monitor"), Route::ControlOut, DataType::AUDIO));
-                       r->ensure_io (count, count, false, this);
+                       r->input()->ensure_io (count, false, this);
+                       r->output()->ensure_io (count, false, this);
                        r->set_remote_control_id (control_id++);
 
                        rl.push_back (r);
@@ -280,9 +281,9 @@ Session::Session (AudioEngine &eng,
 
                if (master_out_channels) {
                        ChanCount count(DataType::AUDIO, master_out_channels);
-                       cerr << "new MO with " << count << endl;
                        shared_ptr<Route> r (new Route (*this, _("master"), Route::MasterOut, DataType::AUDIO));
-                       r->ensure_io (count, count, false, this);
+                       r->input()->ensure_io (count, false, this);
+                       r->output()->ensure_io (count, false, this);
                        r->set_remote_control_id (control_id);
 
                        rl.push_back (r);
@@ -516,8 +517,8 @@ Session::set_worst_io_latencies ()
        boost::shared_ptr<RouteList> r = routes.reader ();
 
        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-               _worst_output_latency = max (_worst_output_latency, (*i)->output_latency());
-               _worst_input_latency = max (_worst_input_latency, (*i)->input_latency());
+               _worst_output_latency = max (_worst_output_latency, (*i)->output()->latency());
+               _worst_input_latency = max (_worst_input_latency, (*i)->input()->latency());
        }
 }
 
@@ -574,15 +575,15 @@ Session::when_engine_running ()
 
                        for (int physport = 0; physport < 2; ++physport) {
                                string physical_output = _engine.get_nth_physical_output (DataType::AUDIO, physport);
-
+                              
                                if (physical_output.length()) {
-                                       if (_click_io->add_output_port (physical_output, this)) {
+                                       if (_click_io->add_port (physical_output, this)) {
                                                // relax, even though its an error
                                       }
                               }
                       }
                       
-                       if (_click_io->n_outputs () > ChanCount::ZERO) {
+                       if (_click_io->n_ports () > ChanCount::ZERO) {
                                _clicking = Config->get_clicking ();
                        }
                }
@@ -665,12 +666,6 @@ Session::when_engine_running ()
        
        if (_master_out) {
 
-               /* force the master to ignore any later call to this 
-                */
-               if (_master_out->pending_state_node) {
-                       _master_out->ports_became_legal();
-               }
-               
                /* if requested auto-connect the outputs to the first N physical ports.
                */
 
@@ -678,11 +673,11 @@ Session::when_engine_running ()
                        uint32_t limit = _master_out->n_outputs().n_total();
 
                        for (uint32_t n = 0; n < limit; ++n) {
-                               Port* p = _master_out->output (n);
+                               Port* p = _master_out->output()->nth (n);
                                string connect_to = _engine.get_nth_physical_output (DataType (p->type()), n);
 
                                if (!connect_to.empty()) {
-                                       if (_master_out->connect_output (p, connect_to, this)) {
+                                       if (_master_out->output()->connect (p, connect_to, this)) {
                                                error << string_compose (_("cannot connect master output %1 to %2"), n, connect_to) 
                                                      << endmsg;
                                                break;
@@ -760,10 +755,6 @@ Session::hookup_io ()
                }
        }
 
-       /* Tell all IO objects to create their ports */
-
-       IO::enable_ports ();
-
        /* Connect track to listen/solo etc. busses XXX generalize this beyond control_out */
 
        if (_control_out) {
@@ -777,7 +768,7 @@ Session::hookup_io ()
                        boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*x);
 
                        if (t) {
-                               t->listen_via (_control_out, X_("listen"));
+                               t->listen_via (_control_out->input(), X_("listen"));
                        }
                }
        }
@@ -794,7 +785,7 @@ Session::hookup_io ()
 
        /* Now reset all panners */
 
-       IO::reset_panners ();
+       Delivery::reset_panners ();
 
        /* Anyone who cares about input state, wake up and do something */
 
@@ -1468,7 +1459,7 @@ Session::resort_routes_using (shared_ptr<RouteList> r)
                                continue;
                        }
 
-                       if ((*j)->feeds (*i)) {
+                       if ((*j)->feeds ((*i)->input())) {
                                (*i)->fed_by.insert (*j);
                        }
                }
@@ -1553,7 +1544,13 @@ Session::new_midi_track (TrackMode mode, uint32_t how_many)
                try {
                        track = boost::shared_ptr<MidiTrack>((new MidiTrack (*this, track_name, Route::Flag (0), mode)));
 
-                       if (track->ensure_io (ChanCount(DataType::MIDI, 1), ChanCount(DataType::AUDIO, 1), false, this)) {
+                       if (track->input()->ensure_io (ChanCount(DataType::MIDI, 1), false, this)) {
+                               error << "cannot configure 1 in/1 out configuration for new midi track" << endmsg;
+                               goto failed;
+                       }
+
+
+                       if (track->output()->ensure_io (ChanCount(DataType::AUDIO, 1), false, this)) {
                                error << "cannot configure 1 in/1 out configuration for new midi track" << endmsg;
                                goto failed;
                        }
@@ -1711,7 +1708,14 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
                try {
                        track = boost::shared_ptr<AudioTrack>((new AudioTrack (*this, track_name, Route::Flag (0), mode)));
 
-                       if (track->ensure_io (ChanCount(DataType::AUDIO, input_channels), ChanCount(DataType::AUDIO, output_channels), false, this)) {
+                       if (track->input()->ensure_io (ChanCount(DataType::AUDIO, input_channels), false, this)) {
+                               error << string_compose (_("cannot configure %1 in/%2 out configuration for new audio track"),
+                                                        input_channels, output_channels)
+                                     << endmsg;
+                               goto failed;
+                       }
+                       
+                       if (track->output()->ensure_io (ChanCount(DataType::AUDIO, output_channels), false, this)) {
                                error << string_compose (_("cannot configure %1 in/%2 out configuration for new audio track"),
                                                         input_channels, output_channels)
                                      << endmsg;
@@ -1729,7 +1733,7 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
                                                port = physinputs[(channels_used+x)%nphysical_in];
                                        }
 
-                                       if (port.length() && track->connect_input (track->input (x), port, this)) {
+                                       if (port.length() && track->input()->connect (track->input()->nth(x), port, this)) {
                                                break;
                                        }
                                }
@@ -1745,11 +1749,11 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
                                                port = physoutputs[(channels_used+x)%nphysical_out];
                                        } else if (Config->get_output_auto_connect() & AutoConnectMaster) {
                                                if (_master_out && _master_out->n_inputs().n_audio() > 0) {
-                                                       port = _master_out->input (x % _master_out->n_inputs().n_audio())->name();
+                                                       port = _master_out->input()->nth (x % _master_out->input()->n_ports().n_audio())->name();
                                                }
                                        }
                                        
-                                       if (port.length() && track->connect_output (track->output (x), port, this)) {
+                                       if (port.length() && track->output()->connect (track->output()->nth(x), port, this)) {
                                                break;
                                        }
                                }
@@ -1889,7 +1893,15 @@ Session::new_audio_route (int input_channels, int output_channels, uint32_t how_
                try {
                        shared_ptr<Route> bus (new Route (*this, bus_name, Route::Flag(0), DataType::AUDIO));
 
-                       if (bus->ensure_io (ChanCount(DataType::AUDIO, input_channels), ChanCount(DataType::AUDIO, output_channels), false, this)) {
+                       if (bus->output()->ensure_io (ChanCount(DataType::AUDIO, input_channels), false, this)) {
+                               error << string_compose (_("cannot configure %1 in/%2 out configuration for new audio track"),
+                                                        input_channels, output_channels)
+                                     << endmsg;
+                               goto failure;
+                       }
+
+
+                       if (bus->output()->ensure_io (ChanCount(DataType::AUDIO, output_channels), false, this)) {
                                error << string_compose (_("cannot configure %1 in/%2 out configuration for new audio track"),
                                                         input_channels, output_channels)
                                      << endmsg;
@@ -1920,11 +1932,11 @@ Session::new_audio_route (int input_channels, int output_channels, uint32_t how_
                                        port = physoutputs[((n+x)%n_physical_outputs)];
                                } else if (Config->get_output_auto_connect() & AutoConnectMaster) {
                                        if (_master_out) {
-                                               port = _master_out->input (x%_master_out->n_inputs().n_audio())->name();
+                                               port = _master_out->input()->nth (x%_master_out->input()->n_ports().n_audio())->name();
                                        }
                                }
 
-                               if (port.length() && bus->connect_output (bus->output (x), port, this)) {
+                               if (port.length() && bus->output()->connect (bus->output()->nth(x), port, this)) {
                                        break;
                                }
                        }
@@ -2023,8 +2035,8 @@ Session::new_route_from_template (uint32_t how_many, const std::string& template
                                   picks up the configuration of the route. During session
                                   loading this normally happens in a different way.
                                */
-                               route->input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), this);
-                               route->output_changed (IOChange (ConfigurationChanged|ConnectionsChanged), this);
+                               route->input()->changed (IOChange (ConfigurationChanged|ConnectionsChanged), this);
+                               route->output()->changed (IOChange (ConfigurationChanged|ConnectionsChanged), this);
                        }
                        
                        route->set_remote_control_id (control_id);
@@ -2070,7 +2082,7 @@ Session::add_routes (RouteList& new_routes, bool save)
 
                (*x)->solo_changed.connect (sigc::bind (mem_fun (*this, &Session::route_solo_changed), wpr));
                (*x)->mute_changed.connect (mem_fun (*this, &Session::route_mute_changed));
-               (*x)->output_changed.connect (mem_fun (*this, &Session::set_worst_io_latencies_x));
+               (*x)->output()->changed.connect (mem_fun (*this, &Session::set_worst_io_latencies_x));
                (*x)->processors_changed.connect (bind (mem_fun (*this, &Session::update_latency_compensation), false, false));
 
                if ((*x)->is_master()) {
@@ -2085,7 +2097,7 @@ Session::add_routes (RouteList& new_routes, bool save)
        if (_control_out && IO::connecting_legal) {
 
                for (RouteList::iterator x = new_routes.begin(); x != new_routes.end(); ++x) {
-                       (*x)->listen_via (_control_out, "control");
+                       (*x)->listen_via (_control_out->input(), "control");
                }
        }
 
@@ -2145,7 +2157,7 @@ Session::remove_route (shared_ptr<Route> route)
                        /* cancel control outs for all routes */
 
                        for (RouteList::iterator r = rs->begin(); r != rs->end(); ++r) {
-                               (*r)->drop_listen (_control_out);
+                               (*r)->drop_listen (_control_out->input());
                        }
 
                        _control_out = shared_ptr<Route> ();
@@ -2176,8 +2188,8 @@ Session::remove_route (shared_ptr<Route> route)
 
        // We need to disconnect the routes inputs and outputs
 
-       route->disconnect_inputs (0);
-       route->disconnect_outputs (0);
+       route->input()->disconnect (0);
+       route->output()->disconnect (0);
 
        update_latency_compensation (false, false);
        set_dirty();
@@ -2215,7 +2227,6 @@ Session::route_solo_changed (void* src, boost::weak_ptr<Route> wpr)
                return;
        }
 
-       bool is_track;
        boost::shared_ptr<Route> route = wpr.lock ();
 
        if (!route) {
@@ -2224,86 +2235,39 @@ Session::route_solo_changed (void* src, boost::weak_ptr<Route> wpr)
                return;
        }
 
-       is_track = (boost::dynamic_pointer_cast<AudioTrack>(route) != 0);
-
        shared_ptr<RouteList> r = routes.reader ();
+       int32_t delta;
 
-       for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-
-               /* soloing a track mutes all other tracks, soloing a bus mutes all other busses */
-
-               if (is_track) {
-
-                       /* don't mess with busses */
-
-                       if (boost::dynamic_pointer_cast<Track>(*i) == 0) {
-                               continue;
-                       }
-
-               } else {
-
-                       /* don't mess with tracks */
-
-                       if (boost::dynamic_pointer_cast<Track>(*i) != 0) {
-                               continue;
-                       }
-               }
-
-               if ((*i) != route &&
-                   ((*i)->mix_group () == 0 ||
-                    (*i)->mix_group () != route->mix_group () ||
-                    !route->mix_group ()->is_active())) {
-
-                       if ((*i)->soloed()) {
-
-                               /* if its already soloed, and solo latching is enabled,
-                                  then leave it as it is.
-                               */
-
-                               if (Config->get_solo_latched()) {
-                                       continue;
-                               }
-                       }
+       if (route->soloed()) {
+               delta = 1;
+       } else {
+               delta = -1;
+       }
 
+       for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+               if ((*i)->feeds (route->input())) {
                        /* do it */
-
+                       
                        solo_update_disabled = true;
-                       (*i)->set_solo (false, src);
+                       (*i)->main_outs()->mod_solo_level (delta);
                        solo_update_disabled = false;
                }
        }
 
+       /* now figure out if anything is soloed */
+
        bool something_soloed = false;
-       bool same_thing_soloed = false;
-       bool signal = false;
 
-        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+       for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
                if ((*i)->soloed()) {
                        something_soloed = true;
-                       if (boost::dynamic_pointer_cast<Track>(*i)) {
-                               if (is_track) {
-                                       same_thing_soloed = true;
-                                       break;
-                               }
-                       } else {
-                               if (!is_track) {
-                                       same_thing_soloed = true;
-                                       break;
-                               }
-                       }
                        break;
                }
        }
 
-       if (something_soloed != currently_soloing) {
-               signal = true;
-               currently_soloing = something_soloed;
-       }
-
-       modify_solo_mute (is_track, same_thing_soloed);
-
-       if (signal) {
-               SoloActive (currently_soloing); /* EMIT SIGNAL */
+       if (something_soloed != _non_soloed_outs_muted) {
+               _non_soloed_outs_muted = something_soloed;
+               SoloActive (_non_soloed_outs_muted); /* EMIT SIGNAL */
        }
 
        SoloChanged (); /* EMIT SIGNAL */
@@ -2343,70 +2307,18 @@ Session::update_route_solo_state ()
 
                /* nothing is soloed */
 
-               for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-                       (*i)->set_solo_mute (false);
-               }
-
                if (signal) {
                        SoloActive (false);
                }
 
                return;
        }
-
-       modify_solo_mute (is_track, mute);
-
+       
        if (signal) {
                SoloActive (currently_soloing);
        }
 }
 
-void
-Session::modify_solo_mute (bool is_track, bool mute)
-{
-       shared_ptr<RouteList> r = routes.reader ();
-
-        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-
-               if (is_track) {
-
-                       /* only alter track solo mute */
-
-                       if (boost::dynamic_pointer_cast<Track>(*i)) {
-                               if ((*i)->soloed()) {
-                                       (*i)->set_solo_mute (!mute);
-                               } else {
-                                       (*i)->set_solo_mute (mute);
-                               }
-                       }
-
-               } else {
-
-                       /* only alter bus solo mute */
-
-                       if (!boost::dynamic_pointer_cast<Track>(*i)) {
-
-                               if ((*i)->soloed()) {
-
-                                       (*i)->set_solo_mute (false);
-
-                               } else {
-
-                                       /* don't mute master or control outs
-                                          in response to another bus solo
-                                       */
-
-                                       if ((*i) != _master_out &&
-                                           (*i) != _control_out) {
-                                               (*i)->set_solo_mute (mute);
-                                       }
-                               }
-                       }
-
-               }
-       }
-}
-
 
 void
 Session::catch_up_on_solo ()
@@ -2432,7 +2344,7 @@ Session::catch_up_on_solo_mute_override ()
        shared_ptr<RouteList> r = routes.reader ();
 
        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-               (*i)->catch_up_on_solo_mute_override ();
+               // (*i)->catch_up_on_solo_mute_override ();
        }
 }      
 
index cbe085b82dfdddc2417b439d99c646f264a49623..dfbd599c4c4423ca1c0a9f02fc166270e17cc87a 100644 (file)
@@ -127,7 +127,7 @@ Session::click (nframes_t start, nframes_t nframes)
                i = next;
        }
        
-       _click_io->deliver_output (bufs, start, end, nframes);
+       _click_io->copy_to_outputs (bufs, DataType::AUDIO, nframes, 0);
 }
 
 void
index 4d07a6c6e26db883651860a941ef68e0e61456e4..0391e1f962b9bd4856b4b2135e87fb5d94060cff 100644 (file)
@@ -151,7 +151,7 @@ Session::first_stage_init (string fullpath, string snapshot_name)
        _tempo_map->StateChanged.connect (mem_fun (*this, &Session::tempo_map_changed));
 
 
-
+       _non_soloed_outs_muted = false;
        g_atomic_int_set (&processing_prohibited, 0);
        insert_cnt = 0;
        _transport_speed = 0;
@@ -272,8 +272,7 @@ Session::first_stage_init (string fullpath, string snapshot_name)
 
        /* stop IO objects from doing stuff until we're ready for them */
 
-       IO::disable_panners ();
-       IO::disable_ports ();
+       Delivery::disable_panners ();
        IO::disable_connecting ();
 }
 
@@ -1155,7 +1154,6 @@ Session::set_state (const XMLNode& node)
        }
 
        
-       IO::disable_ports ();
        IO::disable_connecting ();
 
        /* Object loading order:
@@ -3215,7 +3213,7 @@ Session::config_changed (std::string p, bool ours)
                        // deliver_midi (_mmc_port, buf, 2);
                }
        } else if (p == "solo-mute-override") {
-               catch_up_on_solo_mute_override ();
+               // catch_up_on_solo_mute_override ();
        }
 
        set_dirty ();
index b3fa34419a62c5e2d4a925bcec098d7123ab78b7..31dc52a11b78f9aaaf35542346b01c0449dc9aaf 100644 (file)
@@ -1335,11 +1335,12 @@ Session::update_latency_compensation (bool with_stop, bool abort)
                                                        (!(post_transport_work & PostTransportLocate) || pending_locate_flush));
                }
 
-               nframes_t old_latency = (*i)->signal_latency ();
+               nframes_t old_latency = (*i)->output()->signal_latency ();
                nframes_t track_latency = (*i)->update_total_latency ();
 
                if (old_latency != track_latency) {
-                       (*i)->update_port_total_latencies ();
+                       (*i)->input()->update_port_total_latencies ();
+                       (*i)->output()->update_port_total_latencies ();
                        update_jack = true;
                }
 
index fa3193cba36c9183452d0bedd6d48bd973b38287..96d44de5551cc63e30f342160f48c3779b47452f 100644 (file)
@@ -26,7 +26,7 @@
 #include "ardour/audiosource.h"
 #include "ardour/diskstream.h"
 #include "ardour/io_processor.h"
-#include "ardour/panner.h"
+#include "ardour/meter.h"
 #include "ardour/port.h"
 #include "ardour/processor.h"
 #include "ardour/route_group_specialized.h"
@@ -84,7 +84,7 @@ Track::get_template ()
 void
 Track::toggle_monitor_input ()
 {
-       for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) {
+       for (PortSet::iterator i = _input->ports().begin(); i != _input->ports().end(); ++i) {
                i->ensure_monitor_input(!i->monitoring_input());
        }
 }
@@ -92,32 +92,28 @@ Track::toggle_monitor_input ()
 ARDOUR::nframes_t
 Track::update_total_latency ()
 {
-       nframes_t old = _own_latency;
-
-       if (_user_latency) {
-               _own_latency = _user_latency;
-       } else {
-               _own_latency = 0;
-
-               for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
-                       if ((*i)->active ()) {
-                               _own_latency += (*i)->signal_latency ();
-                       }
+       nframes_t old = _output->effective_latency();
+       nframes_t own_latency = _output->user_latency();
+       
+       for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
+               if ((*i)->active ()) {
+                       own_latency += (*i)->signal_latency ();
                }
        }
 
 #undef DEBUG_LATENCY
 #ifdef DEBUG_LATENCY
-       cerr << _name << ": internal redirect (final) latency = " << _own_latency << endl;
+       cerr << _name << ": internal redirect (final) latency = " << own_latency << endl;
 #endif
 
-       set_port_latency (_own_latency);
-
-       if (old != _own_latency) {
+       _output->set_port_latency (own_latency);
+       
+       if (old != own_latency) {
+               _output->set_latency_delay (own_latency);
                signal_latency_changed (); /* EMIT SIGNAL */
        }
 
-       return _own_latency;
+       return _output->effective_latency();
 }
 
 Track::FreezeRecord::~FreezeRecord ()
@@ -155,14 +151,14 @@ Track::RecEnableControllable::get_value (void) const
 bool
 Track::record_enabled () const
 {
-       return _diskstream->record_enabled ();
+       return _diskstream && _diskstream->record_enabled ();
 }
 
 bool
 Track::can_record()
 {
        bool will_record = true;
-       for (PortSet::iterator i = _inputs.begin(); i != _inputs.end() && will_record; ++i) {
+       for (PortSet::iterator i = _input->ports().begin(); i != _input->ports().end() && will_record; ++i) {
                if (!i->connected())
                        will_record = false;
        }
@@ -307,7 +303,7 @@ Track::no_roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame,
                        passthru_silence (start_frame, end_frame, nframes, 0);
                } else {
                        if (_meter_point == MeterInput) {
-                               just_meter_input (start_frame, end_frame, nframes);
+                               _input->process_input (_meter, start_frame, end_frame, nframes);
                        }
                        passthru_silence (start_frame, end_frame, nframes, 0);
                }
index 7079a64a0832ecfa232694097a98f1fb73136e73..98bc7106f3a044700be8b641dc21af56f57e9716 100644 (file)
@@ -135,7 +135,7 @@ def build(bld):
                gdither.cc
                globals.cc
                import.cc
-               io.cc
+                io.cc
                io_processor.cc
                jack_slave.cc
                ladspa_plugin.cc
@@ -157,6 +157,7 @@ def build(bld):
                midi_track.cc
                mix.cc
                mtc_slave.cc
+                mute_master.cc
                named_selection.cc
                onset_detector.cc
                panner.cc
@@ -178,7 +179,7 @@ def build(bld):
                resampled_source.cc
                return.cc
                reverse.cc
-               route.cc
+                route.cc
                route_group.cc
                send.cc
                session.cc
index 0b074a0f90166ae172c7b0fbb8d484213665873f..5970fe2d5fffc5cf7dd79257ac61c99cb922f77e 100644 (file)
@@ -23,9 +23,6 @@
 #include <gtkmm/drawingarea.h>
 #include <gtkmm2ext/binding_proxy.h>
 
-namespace ARDOUR {
-       class Controllable;
-}
 
 namespace Gtkmm2ext {
 
index eacd85bf28c4af4d74f3fe08b5e2cebb522f9e01..6b5bca8a98bc870d2f92e6772e2e76bef00cd797 100644 (file)
@@ -158,7 +158,7 @@ MIDI::byte
 MIDI::decode_controller_name (const char *name)
 
 {
-       char *lparen;
+       const char *lparen;
        size_t len;
 
        if ((lparen = strrchr (name, '(')) != 0) {
index f95aadb2b87abca702c17c691f3abc35778d7ef8..2d59912dc8b9c35dcc504ba95b844420fd1c4061 100644 (file)
 
 */
 
-#include <ardour/session.h>
-#include <ardour/route.h>
-#include <ardour/audio_track.h>
-#include <ardour/meter.h>
-#include <control_protocol/control_protocol.h>
+#include "ardour/session.h"
+#include "ardour/route.h"
+#include "ardour/audio_track.h"
+#include "ardour/meter.h"
+#include "ardour/amp.h"
+#include "control_protocol/control_protocol.h"
 
 using namespace ARDOUR;
 using namespace std;
@@ -212,7 +213,7 @@ ControlProtocol::route_get_gain (uint32_t table_index)
                return 0.0f;
        }
 
-       return r->gain ();
+       return r->amp()->gain ();
 }
 
 void
@@ -242,7 +243,7 @@ ControlProtocol::route_get_effective_gain (uint32_t table_index)
                return 0.0f;
        }
 
-       return r->effective_gain ();
+       return r->amp()->gain_control()->get_value();
 }
 
 
diff --git a/wscript b/wscript
index 471ed1f0bf7bed12e3c9d9bc3d43d66f9da90afb..051d97d07c77e8d6816ca91926026b55568e1847 100644 (file)
--- a/wscript
+++ b/wscript
@@ -95,7 +95,7 @@ def set_options(opt):
                        help='Compile with support for LV2 (if slv2 is available)')
        opt.add_option('--nls', action='store_true', default=True, dest='nls',
                        help='Enable i18n (native language support)')
-       opt.add_option('--surfaces', action='store_true', default=True, dest='surfaces',
+       opt.add_option('--surfaces', action='store_true', default=False, dest='surfaces',
                        help='Build support for control surfaces')
        opt.add_option('--syslibs', action='store_true', default=True, dest='syslibs',
                        help='Use existing system versions of various libraries instead of internal ones')