The great audio processing overhaul.
authorDavid Robillard <d@drobilla.net>
Thu, 7 May 2009 06:30:50 +0000 (06:30 +0000)
committerDavid Robillard <d@drobilla.net>
Thu, 7 May 2009 06:30:50 +0000 (06:30 +0000)
The vast majority of Route signal processing is now simply in the list of
processors.  There are definitely regressions here, but there's also
a lot of things fixed.  It's far too much work to let diverge anymore
regardless, so here it is.

The basic model is: A route has a fixed set of input channels (matching
its JACK input ports and diskstream).  The first processor takes this
as input.  The next processor is configured using the first processor's
output as input, and is allowed to choose whatever output it wants
given that input... and so on, and so on.  Finally, the last processor's
requested output is used to set up the panner and create whatever Jack
ports are needed to output the data.

All 'special' internal processors (meter, fader, amp, insert, send) are
currently transparent: they read any input, and return the same set
of channels back (unmodified, except for amp).

User visible changes:
 * LV2 Instrument support (tracks with both MIDI and audio channels)
 * MIDI in/out plugin support
 * Generic plugin replication (for MIDI plugins, MIDI/audio plugins)
 * Movable meter point

Known Bugs:
 * Things seem to get weird on loaded sessions
 * Output delivery is sketchy
 * 2.0 session loading was probably already broken...
   but it's definitely broken now :)

Please test this and file bugs if you have any time...

git-svn-id: svn://localhost/ardour2/branches/3.0@5055 d708f5d6-7413-0410-9779-e7cbd77b26cf

85 files changed:
gtk2_ardour/audio_time_axis.cc
gtk2_ardour/keyboard.cc
gtk2_ardour/main.cc
gtk2_ardour/mixer_strip.cc
gtk2_ardour/panner2d.cc
gtk2_ardour/panner2d.h
gtk2_ardour/panner_ui.cc
gtk2_ardour/po/de_DE.po
gtk2_ardour/po/el_GR.po
gtk2_ardour/po/es_ES.po
gtk2_ardour/po/fr_FR.po
gtk2_ardour/po/it_IT.po
gtk2_ardour/po/pl_PL.po
gtk2_ardour/po/pt_BR.po
gtk2_ardour/po/pt_PT.po
gtk2_ardour/po/ru_RU.po
gtk2_ardour/po/sv_SE.po
gtk2_ardour/processor_box.cc
gtk2_ardour/processor_box.h
gtk2_ardour/time_axis_view.cc
gtk2_ardour/ui_config.cc
libs/ardour/amp.cc
libs/ardour/ardour/amp.h
libs/ardour/ardour/audio_track.h
libs/ardour/ardour/buffer_set.h
libs/ardour/ardour/chan_count.h
libs/ardour/ardour/chan_mapping.h
libs/ardour/ardour/click.h
libs/ardour/ardour/control_outputs.h [new file with mode: 0644]
libs/ardour/ardour/io.h
libs/ardour/ardour/io_processor.h
libs/ardour/ardour/meter.h
libs/ardour/ardour/midi_track.h
libs/ardour/ardour/panner.h
libs/ardour/ardour/plugin_insert.h
libs/ardour/ardour/port_insert.h
libs/ardour/ardour/processor.h
libs/ardour/ardour/route.h
libs/ardour/ardour/send.h
libs/ardour/ardour/session.h
libs/ardour/ardour/track.h
libs/ardour/audio_diskstream.cc
libs/ardour/audio_track.cc
libs/ardour/audioengine.cc
libs/ardour/automatable.cc
libs/ardour/buffer_set.cc
libs/ardour/chan_count.cc
libs/ardour/configuration.cc
libs/ardour/control_outputs.cc [new file with mode: 0644]
libs/ardour/diskstream.cc
libs/ardour/globals.cc
libs/ardour/import.cc
libs/ardour/io.cc
libs/ardour/io_processor.cc
libs/ardour/lv2_event_buffer.cc
libs/ardour/lv2_plugin.cc
libs/ardour/meter.cc
libs/ardour/midi_diskstream.cc
libs/ardour/midi_patch_manager.cc
libs/ardour/midi_source.cc
libs/ardour/midi_track.cc
libs/ardour/panner.cc
libs/ardour/plugin_insert.cc
libs/ardour/plugin_manager.cc
libs/ardour/po/el_GR.po
libs/ardour/po/it_IT.po
libs/ardour/po/pl_PL.po
libs/ardour/po/ru_RU.po
libs/ardour/po/sv_SE.po
libs/ardour/port.cc
libs/ardour/port_insert.cc
libs/ardour/processor.cc
libs/ardour/route.cc
libs/ardour/send.cc
libs/ardour/session.cc
libs/ardour/session_state.cc
libs/ardour/smf_source.cc
libs/ardour/template_utils.cc
libs/ardour/track.cc
libs/ardour/wscript
libs/evoral/evoral/Control.hpp
libs/evoral/evoral/ControlSet.hpp
libs/evoral/evoral/Sequence.hpp
libs/evoral/src/Control.cpp
libs/evoral/src/ControlSet.cpp

index b774182a88d4d5edc33cc8e35c242c7f6aac03f3..6f8acc9651763572c4dba4c0b67075d35456b3d7 100644 (file)
@@ -106,7 +106,11 @@ AudioTimeAxisView::AudioTimeAxisView (PublicEditor& ed, Session& sess, boost::sh
                create_automation_child (GainAutomation, false);
        }
        
-       _route->panner().Changed.connect (bind (mem_fun(*this, &AudioTimeAxisView::ensure_pan_views), false));
+       if (_route->panner()) {
+               _route->panner()->Changed.connect (bind (
+                               mem_fun(*this, &AudioTimeAxisView::ensure_pan_views),
+                               false));
+       }
 
        /* map current state of the route */
 
@@ -370,13 +374,17 @@ AudioTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool
 void
 AudioTimeAxisView::ensure_pan_views (bool show)
 {
-       const set<Evoral::Parameter>& params = _route->panner().what_can_be_automated();
+       if (!_route->panner()) {
+               return;
+       }
+
+       const set<Evoral::Parameter>& params = _route->panner()->what_can_be_automated();
        set<Evoral::Parameter>::iterator p;
 
        for (p = params.begin(); p != params.end(); ++p) {
                boost::shared_ptr<ARDOUR::AutomationControl> pan_control
                        = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
-                               _route->panner().data().control(*p));
+                               _route->panner()->data().control(*p));
                
                if (pan_control->parameter().type() == NullAutomation) {
                        error << "Pan control has NULL automation type!" << endmsg;
index ad8b02ab53b3d5e5658fabe0f3d86014c98f229c..2e29c9c1c541b83716e6bc9a5b62fb6d4e0e2fe7 100644 (file)
@@ -617,7 +617,7 @@ bool
 Keyboard::load_keybindings (string path)
 {
        try {
-               cerr << "loading bindings from " << path << endl;
+               cerr << "Loading bindings from " << path << endl;
 
                Gtk::AccelMap::load (path);
 
index 32454d69d561c655582b17e3c37fb89b2b4a0616..0a95b9a94b6074e707b6369a7c044febced0c427 100644 (file)
@@ -344,7 +344,7 @@ int main (int argc, char *argv[])
        
        cout << _("Ardour/GTK ") 
             << VERSIONSTRING
-            << _("\n   (built using ")
+            << _(" (built using ")
             << svn_revision
 #ifdef __GNUC__
             << _(" and GCC version ") << __VERSION__ 
index fc358b8f7bf200b2a94f8b3d2f527e6812757f88..8a00eb88a28a2f8675bb934b27d0f3a653ff2204 100644 (file)
@@ -413,20 +413,33 @@ MixerStrip::set_route (boost::shared_ptr<Route> rt)
                                                   _("Click to Add/Edit Comments"):
                                                   _route->comment());
 
-       connections.push_back (_route->meter_change.connect (mem_fun(*this, &MixerStrip::meter_changed)));
-       connections.push_back (_route->input_changed.connect (mem_fun(*this, &MixerStrip::input_changed)));
-       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)));
-       connections.push_back (_route->panner().Changed.connect (mem_fun(*this, &MixerStrip::connect_to_pan)));
+       connections.push_back (_route->meter_change.connect (
+                       mem_fun(*this, &MixerStrip::meter_changed)));
+       connections.push_back (_route->input_changed.connect (
+                       mem_fun(*this, &MixerStrip::input_changed)));
+       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)));
+
+       if (_route->panner()) {
+               connections.push_back (_route->panner()->Changed.connect (
+                       mem_fun(*this, &MixerStrip::connect_to_pan)));
+       }
 
        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 (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 (mem_fun(*this, &RouteUI::name_changed)));
-       connections.push_back (_route->comment_changed.connect (mem_fun(*this, &MixerStrip::comment_changed)));
-       connections.push_back (_route->gui_changed.connect (mem_fun(*this, &MixerStrip::route_gui_changed)));
+       connections.push_back (_route->NameChanged.connect (
+                       mem_fun(*this, &RouteUI::name_changed)));
+       connections.push_back (_route->comment_changed.connect (
+                       mem_fun(*this, &MixerStrip::comment_changed)));
+       connections.push_back (_route->gui_changed.connect (
+                       mem_fun(*this, &MixerStrip::route_gui_changed)));
 
        set_stuff_from_route ();
 
@@ -553,17 +566,25 @@ MixerStrip::set_width (Width w, void* owner)
                ((Gtk::Label*)solo_button->get_child())->set_text (_("Solo"));
 
                if (_route->comment() == "") {
-                      comment_button.unset_bg (STATE_NORMAL);
-                      ((Gtk::Label*)comment_button.get_child())->set_text (_("Comments"));
+                       comment_button.unset_bg (STATE_NORMAL);
+                       ((Gtk::Label*)comment_button.get_child())->set_text (_("Comments"));
                } else {
-                      comment_button.modify_bg (STATE_NORMAL, color());
-                      ((Gtk::Label*)comment_button.get_child())->set_text (_("*Comments*"));
+                       comment_button.modify_bg (STATE_NORMAL, color());
+                       ((Gtk::Label*)comment_button.get_child())->set_text (_("*Comments*"));
+               }
+
+               ((Gtk::Label*)gpm.gain_automation_style_button.get_child())->set_text (
+                               gpm.astyle_string(gain_automation->automation_style()));
+               ((Gtk::Label*)gpm.gain_automation_state_button.get_child())->set_text (
+                               gpm.astate_string(gain_automation->automation_state()));
+
+               if (_route->panner()) {
+                       ((Gtk::Label*)panners.pan_automation_style_button.get_child())->set_text (
+                                       panners.astyle_string(_route->panner()->automation_style()));
+                       ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
+                                       panners.astate_string(_route->panner()->automation_state()));
                }
 
-               ((Gtk::Label*)gpm.gain_automation_style_button.get_child())->set_text (gpm.astyle_string(gain_automation->automation_style()));
-               ((Gtk::Label*)gpm.gain_automation_state_button.get_child())->set_text (gpm.astate_string(gain_automation->automation_state()));
-               ((Gtk::Label*)panners.pan_automation_style_button.get_child())->set_text (panners.astyle_string(_route->panner().automation_style()));
-               ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (panners.astate_string(_route->panner().automation_state()));
                Gtkmm2ext::set_size_request_to_display_given_text (name_button, "long", 2, 2);
                set_size_request (-1, -1);
                break;
@@ -583,10 +604,18 @@ MixerStrip::set_width (Width w, void* owner)
                       ((Gtk::Label*)comment_button.get_child())->set_text (_("*Cmt*"));
                }
 
-               ((Gtk::Label*)gpm.gain_automation_style_button.get_child())->set_text (gpm.short_astyle_string(gain_automation->automation_style()));
-               ((Gtk::Label*)gpm.gain_automation_state_button.get_child())->set_text (gpm.short_astate_string(gain_automation->automation_state()));
-               ((Gtk::Label*)panners.pan_automation_style_button.get_child())->set_text (panners.short_astyle_string(_route->panner().automation_style()));
-               ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (panners.short_astate_string(_route->panner().automation_state()));
+               ((Gtk::Label*)gpm.gain_automation_style_button.get_child())->set_text (
+                               gpm.short_astyle_string(gain_automation->automation_style()));
+               ((Gtk::Label*)gpm.gain_automation_state_button.get_child())->set_text (
+                               gpm.short_astate_string(gain_automation->automation_state()));
+               
+               if (_route->panner()) {
+                       ((Gtk::Label*)panners.pan_automation_style_button.get_child())->set_text (
+                       panners.short_astyle_string(_route->panner()->automation_style()));
+                       ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
+                       panners.short_astate_string(_route->panner()->automation_state()));
+               }
+
                Gtkmm2ext::set_size_request_to_display_given_text (name_button, "longest label", 2, 2);
                set_size_request (max (50, gpm.get_gm_width()), -1);
                break;
@@ -856,9 +885,13 @@ MixerStrip::connect_to_pan ()
        panstate_connection.disconnect ();
        panstyle_connection.disconnect ();
 
-               boost::shared_ptr<ARDOUR::AutomationControl> pan_control
-                       = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
-                               _route->panner().data().control(Evoral::Parameter( PanAutomation ) ));
+       if (!_route->panner()) {
+               return;
+       }
+
+       boost::shared_ptr<ARDOUR::AutomationControl> pan_control
+               = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
+                               _route->panner()->data().control(Evoral::Parameter(PanAutomation)));
 
        if (pan_control) {
                panstate_connection = pan_control->alist()->automation_state_changed.connect (mem_fun(panners, &PannerUI::pan_automation_state_changed));
@@ -1407,7 +1440,6 @@ MixerStrip::engine_running ()
 void
 MixerStrip::meter_changed (void *src)
 {
-
        ENSURE_GUI_THREAD (bind (mem_fun(*this, &MixerStrip::meter_changed), src));
 
        switch (_route->meter_point()) {
index 0216e76c2771269062fdf369c1873a5b609c2fd7..b6c601cdefb827a9cd2176315a85f791fe606ce7 100644 (file)
@@ -65,15 +65,15 @@ Panner2d::Target::set_text (const char* txt)
        text = strdup (txt);
 }
 
-Panner2d::Panner2d (Panner& p, int32_t h)
+Panner2d::Panner2d (boost::shared_ptr<Panner> p, int32_t h)
        : panner (p), width (0), height (h)
 {
        allow_x = false;
        allow_y = false;
        allow_target = false;
 
-       panner.StateChanged.connect (mem_fun(*this, &Panner2d::handle_state_change));
-       panner.Changed.connect (mem_fun(*this, &Panner2d::handle_position_change));
+       panner->StateChanged.connect (mem_fun(*this, &Panner2d::handle_state_change));
+       panner->Changed.connect (mem_fun(*this, &Panner2d::handle_position_change));
        
        drag_target = 0;
        set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
@@ -135,7 +135,7 @@ Panner2d::reset (uint32_t n_inputs)
                        
                        if (existing_pucks < i) {
                                float x, y;
-                               panner.streampanner (i).get_position (x, y);
+                               panner->streampanner (i).get_position (x, y);
                                pucks[i]->x.set_value (x);
                                pucks[i]->y.set_value (y);
                        }
@@ -147,11 +147,11 @@ Panner2d::reset (uint32_t n_inputs)
        
        /* add all outputs */
        
-       while (targets.size() < panner.nouts()) {
+       while (targets.size() < panner->nouts()) {
                add_target (0.0, 0.0);
        }
        
-       while (targets.size() > panner.nouts()) {
+       while (targets.size() > panner->nouts()) {
                targets.erase (targets.begin());
        }
 
@@ -159,13 +159,13 @@ Panner2d::reset (uint32_t n_inputs)
                (*x).second->visible = false;
        }
 
-       for (uint32_t n = 0; n < panner.nouts(); ++n) {
+       for (uint32_t n = 0; n < panner->nouts(); ++n) {
                char buf[16];
 
                snprintf (buf, sizeof (buf), "%d", n+1);
                targets[n]->set_text (buf);
-               targets[n]->x.set_value (panner.output(n).x);
-               targets[n]->y.set_value (panner.output(n).y);
+               targets[n]->x.set_value (panner->output(n).x);
+               targets[n]->y.set_value (panner->output(n).y);
                targets[n]->visible = true;
        }
        
@@ -275,14 +275,14 @@ Panner2d::handle_position_change ()
 
        for (n = 0; n < pucks.size(); ++n) {
                float x, y;
-               panner.streampanner(n).get_position (x, y);
+               panner->streampanner(n).get_position (x, y);
                pucks[n]->x.set_value (x);
                pucks[n]->y.set_value (y);
        }
 
        for (n = 0; n < targets.size(); ++n) {
-               targets[n]->x.set_value (panner.output(n).x);
-               targets[n]->y.set_value (panner.output(n).y);
+               targets[n]->x.set_value (panner->output(n).x);
+               targets[n]->y.set_value (panner->output(n).y);
        }
 
        queue_draw ();
@@ -454,7 +454,7 @@ Panner2d::on_expose_event (GdkEventExpose *event)
        cairo_set_line_width (cr, 1.0);
 
        cairo_rectangle (cr, event->area.x, event->area.y, event->area.width, event->area.height);
-       if (!panner.bypassed()) {
+       if (!panner->bypassed()) {
                cairo_set_source_rgba (cr, 0.1, 0.1, 0.1, 1.0);
        } else {
                cairo_set_source_rgba (cr, 0.1, 0.1, 0.1, 0.2);
@@ -478,7 +478,7 @@ Panner2d::on_expose_event (GdkEventExpose *event)
        cairo_arc (cr, height/2, height/2, height/2, 0, 2.0 * M_PI);
        cairo_stroke (cr);
 
-       if (!panner.bypassed()) {
+       if (!panner->bypassed()) {
                float arc_radius;
 
                cairo_select_font_face (cr, "sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
@@ -715,7 +715,8 @@ Panner2d::handle_motion (gint evx, gint evy, GdkModifierType state)
                        
                        if (drag_is_puck) {
                                
-                               panner.streampanner(drag_index).set_position (drag_target->x.get_value(), drag_target->y.get_value(), false);
+                               panner->streampanner(drag_index).set_position (
+                                               drag_target->x.get_value(), drag_target->y.get_value(), false);
                                
                        } else {
                                
@@ -745,7 +746,7 @@ Panner2d::handle_motion (gint evx, gint evy, GdkModifierType state)
 void
 Panner2d::toggle_bypass ()
 {
-       panner.set_bypassed (!panner.bypassed());
+       panner->set_bypassed (!panner->bypassed());
 }
 
 void
@@ -766,7 +767,7 @@ Panner2d::allow_y_motion (bool yn)
        allow_y = yn;
 }
 
-Panner2dWindow::Panner2dWindow (Panner&p, int32_t h, uint32_t inputs)
+Panner2dWindow::Panner2dWindow (boost::shared_ptr<Panner> p, int32_t h, uint32_t inputs)
        : widget (p, h)
        , reset_button (_("Reset"))
        , bypass_button (_("Bypass"))
index 2bf57f26277a2e94990d2d528c844f26b161f3e6..1abac7fe5a6cc72b2b4ca12ef3db50e61444b66f 100644 (file)
@@ -54,7 +54,7 @@ class Panner2dWindow;
 class Panner2d : public Gtk::DrawingArea
 {
   public:
-       Panner2d (ARDOUR::Panner&, int32_t height);
+       Panner2d (boost::shared_ptr<ARDOUR::Panner>, int32_t height);
        ~Panner2d ();
        
        void allow_x_motion(bool);
@@ -76,7 +76,7 @@ class Panner2d : public Gtk::DrawingArea
 
        Gtk::Adjustment& azimuth (uint32_t which);
 
-       ARDOUR::Panner& get_panner() const { return panner; }
+       boost::shared_ptr<ARDOUR::Panner> get_panner() const { return panner; }
        
        sigc::signal<void,int> PuckMoved;
        sigc::signal<void,int> TargetMoved;
@@ -102,7 +102,7 @@ class Panner2d : public Gtk::DrawingArea
            void set_text (const char*);
        };
 
-       ARDOUR::Panner& panner;
+       boost::shared_ptr<ARDOUR::Panner> panner;
        Glib::RefPtr<Pango::Layout> layout;
 
        typedef std::map<int,Target *> Targets;
@@ -137,7 +137,7 @@ class Panner2d : public Gtk::DrawingArea
 class Panner2dWindow : public Gtk::Window
 {
   public:
-       Panner2dWindow (ARDOUR::Panner&, int32_t height, uint32_t inputs);
+       Panner2dWindow (boost::shared_ptr<ARDOUR::Panner>, int32_t height, uint32_t inputs);
        
        void reset (uint32_t n_inputs);
 
index 2df79d2c397f0475d4a671cc5ce80be6c1100994..4777c82479f77a6ef5bbdb7ffa5126866eec1fa0 100644 (file)
@@ -132,6 +132,11 @@ PannerUI::PannerUI (Session& s)
 void
 PannerUI::set_io (boost::shared_ptr<IO> io)
 {
+       if (!io->panner()) {
+               cerr << "PannerUI::set_io IO has no panners" << endl;
+               return;
+       }
+
        connections.clear ();
        
        delete pan_astyle_menu;
@@ -142,9 +147,12 @@ PannerUI::set_io (boost::shared_ptr<IO> io)
                        
        _io = io;
  
-       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 (_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)));
  
        delete panner;
        panner = 0;
@@ -185,14 +193,18 @@ PannerUI::build_astate_menu ()
                pan_astate_menu->items().clear ();
        }
 
-       pan_astate_menu->items().push_back (MenuElem (_("Manual"), 
-                                                    bind (mem_fun (_io->panner(), &Panner::set_automation_state), (AutoState) Off)));
-       pan_astate_menu->items().push_back (MenuElem (_("Play"),
-                                                    bind (mem_fun (_io->panner(), &Panner::set_automation_state), (AutoState) Play)));
-       pan_astate_menu->items().push_back (MenuElem (_("Write"),
-                                                    bind (mem_fun (_io->panner(), &Panner::set_automation_state), (AutoState) Write)));
-       pan_astate_menu->items().push_back (MenuElem (_("Touch"),
-                                                    bind (mem_fun (_io->panner(), &Panner::set_automation_state), (AutoState) Touch)));
+       pan_astate_menu->items().push_back (MenuElem (_("Manual"), bind (
+                       mem_fun (_io->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),
+                       (AutoState) Play)));
+       pan_astate_menu->items().push_back (MenuElem (_("Write"), bind (
+                       mem_fun (_io->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),
+                       (AutoState) Touch)));
 
 }
 
@@ -228,7 +240,7 @@ bool
 PannerUI::panning_link_button_release (GdkEventButton* ev)
 {
        if (!ignore_toggle) {
-               _io->panner().set_linked (!_io->panner().linked());
+               _io->panner()->set_linked (!_io->panner()->linked());
        }
        return true;
 }
@@ -236,12 +248,12 @@ PannerUI::panning_link_button_release (GdkEventButton* ev)
 void
 PannerUI::panning_link_direction_clicked()
 {
-       switch (_io->panner().link_direction()) {
+       switch (_io->panner()->link_direction()) {
        case Panner::SameDirection:
-               _io->panner().set_link_direction (Panner::OppositeDirection);
+               _io->panner()->set_link_direction (Panner::OppositeDirection);
                break;
        default:
-               _io->panner().set_link_direction (Panner::SameDirection);
+               _io->panner()->set_link_direction (Panner::SameDirection);
                break;
        }
 }
@@ -251,7 +263,7 @@ PannerUI::update_pan_linkage ()
 {
        ENSURE_GUI_THREAD(mem_fun(*this, &PannerUI::update_pan_linkage));
        
-       bool x = _io->panner().linked();
+       bool x = _io->panner()->linked();
        bool bx = panning_link_button.get_active();
 
        if (x != bx) {
@@ -263,7 +275,7 @@ PannerUI::update_pan_linkage ()
 
        panning_link_direction_button.set_sensitive (x);
 
-       switch (_io->panner().link_direction()) {
+       switch (_io->panner()->link_direction()) {
        case Panner::SameDirection:
                panning_link_direction_button.set_image (*(manage (new Image (get_xpm ("forwardblarrow.xpm")))));
                break;
@@ -325,6 +337,10 @@ PannerUI::update_pan_state ()
 void
 PannerUI::setup_pan ()
 {
+       if (!_io->panner()) {
+               return;
+       }
+
        uint32_t nouts = _io->n_outputs ().n_audio();
 
        if (nouts == 0 || nouts == 1) {
@@ -346,7 +362,7 @@ PannerUI::setup_pan ()
        } else if (nouts == 2) {
 
                vector<Adjustment*>::size_type asz;
-               uint32_t npans = _io->panner().npanners();
+               uint32_t npans = _io->panner()->npanners();
 
                while (!pan_adjustments.empty()) {
                        delete pan_bars.back();
@@ -363,7 +379,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 = _io->panner()->pan_control( asz)->get_value();
 
                        if (npans == 1) {
                                x = 0.5;
@@ -377,13 +393,13 @@ PannerUI::setup_pan ()
 
                        pan_adjustments.push_back (new Adjustment (x, 0, 1.0, 0.05, 0.1));
                        bc = new PannerBar (*pan_adjustments[asz],
-                               boost::static_pointer_cast<PBD::Controllable>( _io->panner().pan_control( asz )) );
+                               boost::static_pointer_cast<PBD::Controllable>( _io->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));
+                       _io->panner()->pan_control( asz )->Changed.connect (bind (mem_fun(*this, &PannerUI::pan_value_changed), (uint32_t) asz));
 
                        
                        bc->set_name ("PanSlider");
@@ -418,11 +434,10 @@ PannerUI::setup_pan ()
 
        } else {
 
-               if (panner == 0) {
+               if (!panner) {
                        panner = new Panner2d (_io->panner(), 61);
                        panner->set_name ("MixerPanZone");
                        panner->show ();
-
  
                        panner->signal_button_press_event().connect
                                (bind (mem_fun(*this, &PannerUI::pan_button_event), (uint32_t) 0), false);
@@ -485,7 +500,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 (_io->panner()->streampanner(which).muted());
        (dynamic_cast<CheckMenuItem*> (&items.back()))->signal_toggled().connect
                (bind (mem_fun(*this, &PannerUI::pan_mute), which));
 
@@ -494,7 +509,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 (_io->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)));
@@ -505,34 +520,34 @@ PannerUI::build_pan_menu (uint32_t which)
 void
 PannerUI::pan_mute (uint32_t which)
 {
-       StreamPanner& sp = _io->panner().streampanner(which);
+       StreamPanner& sp = _io->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 && (_io->panner()->bypassed() != bypass_menu_item->get_active())) {
+               _io->panner()->set_bypassed (!_io->panner()->bypassed());
        }
 }
 
 void
 PannerUI::pan_reset (uint32_t which)
 {
-       _io->panner().reset_streampanner (which);
+       _io->panner()->reset_streampanner (which);
 }
 
 void
 PannerUI::pan_reset_all ()
 {
-       _io->panner().reset_to_default ();
+       _io->panner()->reset_to_default ();
 }
 
 void
 PannerUI::effective_pan_display ()
 {
-       if (_io->panner().empty()) {
+       if (_io->panner()->empty()) {
                return;
        }
 
@@ -559,7 +574,7 @@ PannerUI::pan_changed (void *src)
                return;
        }
 
-       switch (_io->panner().npanners()) {
+       switch (_io->panner()->npanners()) {
        case 0:
                panning_link_direction_button.set_sensitive (false);
                panning_link_button.set_sensitive (false);
@@ -595,11 +610,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 < _io->panner()->npanners()) {
 
                float xpos;
                float val = pan_adjustments[which]->get_value ();
-               xpos = _io->panner().pan_control( which )->get_value();
+               xpos = _io->panner()->pan_control( which )->get_value();
 
                /* add a kinda-sorta detent for the middle */
                
@@ -616,7 +631,7 @@ PannerUI::pan_adjustment_changed (uint32_t which)
                
                if (!Panner::equivalent (val, xpos)) {
 
-                       _io->panner().streampanner(which).set_position (val);
+                       _io->panner()->streampanner(which).set_position (val);
                        /* XXX 
                           the panner objects have no access to the session,
                           so do this here. ick.
@@ -631,11 +646,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 (_io->n_outputs().n_audio() > 1 && which < _io->panner()->npanners()) {
                float xpos;
                float val = pan_adjustments[which]->get_value ();
 
-               _io->panner().streampanner(which).get_position (xpos);
+               _io->panner()->streampanner(which).get_position (xpos);
 
                if (!Panner::equivalent (val, xpos)) {
                        in_pan_update = true;
@@ -661,14 +676,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 (_io->panner()->streampanner(n).pan_control()->alist());
                        
                        if (!alist->automation_playback()) {
                                continue;
                        }
                }
 
-               _io->panner().streampanner(n).get_effective_position (xpos);
+               _io->panner()->streampanner(n).get_effective_position (xpos);
                val = (*i)->get_value ();
                
                if (!Panner::equivalent (val, xpos)) {
@@ -699,7 +714,7 @@ PannerUI::pan_printer (char *buf, uint32_t len, Adjustment* adj)
 void
 PannerUI::update_pan_sensitive () 
 {
-       bool sensitive = !(_io->panner().automation_state() & Play);
+       bool sensitive = !(_io->panner()->automation_state() & Play);
 
        switch (_io->n_outputs().n_audio()) {
        case 0:
@@ -771,10 +786,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(_io->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(_io->panner()->automation_style()));
                break;
        }
 }
@@ -788,10 +803,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(_io->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(_io->panner()->automation_state()));
                break;
        }
 
@@ -800,11 +815,11 @@ PannerUI::pan_automation_state_changed ()
           here.
        */
 
-       if (_io->panner().empty()) {
+       if (_io->panner()->empty()) {
                return;
        }
 
-       x = (_io->panner().streampanner(0).pan_control()->alist()->automation_state() != Off);
+       x = (_io->panner()->streampanner(0).pan_control()->alist()->automation_state() != Off);
 
        if (pan_automation_state_button.get_active() != x) {
        ignore_toggle = true;
index 7087f0c278320257470c260a94f46bba3ea4a670..4fc76bc7daca58bebc06820150017b094e7f27d7 100644 (file)
@@ -7312,8 +7312,7 @@ msgstr "Ardour/GTK "
 
 #: gtk2_ardour/main.cc:294
 msgid ""
-"\n"
-"   (built using "
+" (built using "
 msgstr ""
 "\n"
 "   (kompiliert mit Version "
@@ -7355,7 +7354,7 @@ msgid "could not create ARDOUR GUI"
 msgstr "konnte das grafische Ardour User Interface nicht erstellen"
 
 #: gtk2_ardour/ui_config.cc:78
-msgid "loading default ui configuration file %1"
+msgid "Loading default ui configuration file %1"
 msgstr "lade voreingestellte UI-Konfigurationsdatei %1"
 
 #: gtk2_ardour/ui_config.cc:81
@@ -7367,8 +7366,8 @@ msgid "Ardour: default ui configuration file \"%1\" not loaded successfully."
 msgstr "Ardour: Die voreingestellte UI-Konfigurationsdatei \"%1\" konnte nicht geladen werden."
 
 #: gtk2_ardour/ui_config.cc:104
-msgid "loading user ui configuration file %1"
-msgstr "lade benutzerdefinierte UI-Konfigurationsdatei %1"
+msgid "Loading user ui configuration file %1"
+msgstr "Lade benutzerdefinierte UI-Konfigurationsdatei %1"
 
 #: gtk2_ardour/ui_config.cc:107
 msgid "Ardour: cannot read ui configuration file \"%1\""
index fdbe8f0673e842ffb0d0f54d227b374d7b514c25..c34906e607b06e43119daa6d8e905dd1a2d30bec 100644 (file)
@@ -4931,8 +4931,7 @@ msgstr "Ardour/GTK "
 
 #: main.cc:401
 msgid ""
-"\n"
-"   (built using "
+" (built using "
 msgstr ""
 
 #: main.cc:405
index c6c0c7415ee0ac319308385f939cb9a43ff95337..682e85199bbba723c6827dc9422bcfd8db087691 100644 (file)
@@ -4900,8 +4900,7 @@ msgstr ""
 
 #: main.cc:401
 msgid ""
-"\n"
-"   (built using "
+" (built using "
 msgstr ""
 
 #: main.cc:405
index 100e2dbedf99680676990e4152508d1ace84858f..7ae67b2df72dd52431f8b3f3dafd7c23821b9c0c 100644 (file)
@@ -5528,8 +5528,7 @@ msgstr "Ardour/GTK"
 
 #: gtk2_ardour/main.cc:314
 msgid ""
-"\n"
-"   (built using "
+" (built using "
 msgstr ""
 "\n"
 "   (construit avec "
@@ -7004,7 +7003,7 @@ msgid "programming error: request for non-existent audio range (%1)!"
 msgstr "programming error: request for non-existent audio range (%1)!"
 
 #: gtk2_ardour/ui_config.cc:67
-msgid "loading default ui configuration file %1"
+msgid "Loading default ui configuration file %1"
 msgstr ""
 "Chargement du fichier de style par défaut (%1) pour l'interface graphique"
 
@@ -7021,9 +7020,9 @@ msgstr ""
 "graphique n'a pas pu être chargé correctement."
 
 #: gtk2_ardour/ui_config.cc:93
-msgid "loading user ui configuration file %1"
+msgid "Loading user ui configuration file %1"
 msgstr ""
-"chargement du fichier utilisateur (%1) pour la configuration de l'interface "
+"Chargement du fichier utilisateur (%1) pour la configuration de l'interface "
 "graphique"
 
 #: gtk2_ardour/ui_config.cc:96
index 018bce6576e41a843582ceb232c3cf9e3d3ece56..c550eb5132b201c8bc3551422f5fe2832f547867 100644 (file)
@@ -4790,8 +4790,7 @@ msgstr ""
 
 #: main.cc:401
 msgid ""
-"\n"
-"   (built using "
+" (built using "
 msgstr ""
 
 #: main.cc:405
index b01253b6e5efd17a54b1bba84e6547e7071c262a..2e19de45d2918507caa4d6f04c7bf81a3e0d9aaf 100644 (file)
@@ -6147,8 +6147,7 @@ msgstr "Ardour/GTK "
 
 #: gtk2_ardour/main.cc:272
 msgid ""
-"\n"
-"   (built using "
+" (built using "
 msgstr ""
 "\n"
 "   (skompilowany przy użyciu "
@@ -7636,7 +7635,7 @@ msgid "programming error: request for non-existent audio range (%1)!"
 msgstr ""
 
 #: gtk2_ardour/ui_config.cc:76
-msgid "loading default ui configuration file %1"
+msgid "Loading default ui configuration file %1"
 msgstr ""
 
 #: gtk2_ardour/ui_config.cc:79
@@ -7648,7 +7647,7 @@ msgid "Ardour: default ui configuration file \"%1\" not loaded successfully."
 msgstr ""
 
 #: gtk2_ardour/ui_config.cc:102
-msgid "loading user ui configuration file %1"
+msgid "Loading user ui configuration file %1"
 msgstr ""
 
 #: gtk2_ardour/ui_config.cc:105
index e327dd1549435909a2679a0b3ab276f8d35bc23d..4de77b1748beb6662a5aed8dbf3083685987bfa7 100644 (file)
@@ -4852,8 +4852,7 @@ msgstr ""
 
 #: main.cc:401
 msgid ""
-"\n"
-"   (built using "
+" (built using "
 msgstr ""
 
 #: main.cc:405
index 7af0a5925463a51939f8c7b9f86d1ff1cd4872f1..253628e405a56dfe861e5ef807838d78a3d83600 100644 (file)
@@ -4529,8 +4529,7 @@ msgstr ""
 
 #: main.cc:401
 msgid ""
-"\n"
-"   (built using "
+" (built using "
 msgstr ""
 "\n"
 "   (compilado "
index 6ef4bf587857df1d634963ad376b8c7228bd67a8..dc97ef025e8f03ffb22189e19d984b60f0e6db37 100644 (file)
@@ -4761,8 +4761,7 @@ msgstr "Ardour/GTK "
 
 #: gtk2_ardour/main.cc:388
 msgid ""
-"\n"
-"   (built using "
+" (built using "
 msgstr ""
 "\n"
 "   (собран с использованием "
index 66edd56dcc4cac33d8aac7022116f5d1a433c103..dba2d071346e79f9aa94cd64691508f1e3c60fa5 100644 (file)
@@ -4797,8 +4797,7 @@ msgstr ""
 
 #: ../main.cc:397
 msgid ""
-"\n"
-"   (built using "
+" (built using "
 msgstr ""
 "\n"
 "   (kompilerat med "
index 75d9281a948cff432d553f56b6ce92b8110ca070..2bf988aad9b6cb7de9ff9bdfd70e6edf85b11de2 100644 (file)
 #include <gtkmm2ext/doi.h>
 #include <gtkmm2ext/window_title.h>
 
+#include "ardour/amp.h"
 #include "ardour/ardour.h"
-#include "ardour/session.h"
-#include "ardour/audioengine.h"
-#include "ardour/route.h"
-#include "ardour/audio_track.h"
 #include "ardour/audio_diskstream.h"
-#include "ardour/send.h"
+#include "ardour/audio_track.h"
+#include "ardour/audioengine.h"
+#include "ardour/ladspa_plugin.h"
+#include "ardour/meter.h"
 #include "ardour/plugin_insert.h"
 #include "ardour/port_insert.h"
-#include "ardour/ladspa_plugin.h"
 #include "ardour/profile.h"
+#include "ardour/route.h"
+#include "ardour/send.h"
+#include "ardour/session.h"
 
 #include "ardour_ui.h"
 #include "ardour_dialog.h"
@@ -82,19 +84,21 @@ bool ProcessorBox::get_colors = true;
 Gdk::Color* ProcessorBox::active_processor_color;
 Gdk::Color* ProcessorBox::inactive_processor_color;
 
-ProcessorBox::ProcessorBox (Placement pcmnt, Session& sess, PluginSelector &plugsel, 
+ProcessorBox::ProcessorBox (Placement pcmnt, Session& sess, PluginSelector &plugsel,
                            RouteRedirectSelection & rsel, bool owner_is_mixer)
-       : _session(sess)
-         _owner_is_mixer (owner_is_mixer), 
-         _placement(pcmnt), 
-         _plugin_selector(plugsel),
-         _rr_selection(rsel)
+       : _session(sess)
+       , _owner_is_mixer (owner_is_mixer)
+       , _placement(pcmnt)
+       , _plugin_selector(plugsel)
+       , _rr_selection(rsel)
 {
        if (get_colors) {
                active_processor_color = new Gdk::Color;
                inactive_processor_color = new Gdk::Color;
-               set_color (*active_processor_color, rgba_from_style ("ProcessorSelector", 0xff, 0, 0, 0, "fg", Gtk::STATE_ACTIVE, false ));
-               set_color (*inactive_processor_color, rgba_from_style ("ProcessorSelector", 0xff, 0, 0, 0, "fg", Gtk::STATE_NORMAL, false ));
+               set_color (*active_processor_color, rgba_from_style (
+                               "ProcessorSelector", 0xff, 0, 0, 0, "fg", Gtk::STATE_ACTIVE, false ));
+               set_color (*inactive_processor_color, rgba_from_style (
+                               "ProcessorSelector", 0xff, 0, 0, 0, "fg", Gtk::STATE_NORMAL, false ));
                get_colors = false;
        }
 
@@ -123,24 +127,29 @@ ProcessorBox::ProcessorBox (Placement pcmnt, Session& sess, PluginSelector &plug
        processor_display.signal_drop.connect (mem_fun (*this, &ProcessorBox::object_drop));
 
        TreeViewColumn* name_col = processor_display.get_column(0);
-       CellRendererText* renderer = dynamic_cast<CellRendererText*>(processor_display.get_column_cell_renderer (0));
+       CellRendererText* renderer = dynamic_cast<CellRendererText*>(
+                       processor_display.get_column_cell_renderer (0));
        name_col->add_attribute(renderer->property_foreground_gdk(), columns.color);
 
        processor_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
-       
+
        model->signal_row_deleted().connect (mem_fun (*this, &ProcessorBox::row_deleted));
 
        processor_scroller.add (processor_display);
        processor_eventbox.add (processor_scroller);
-       
+
        processor_scroller.set_size_request (-1, 40);
 
        pack_start (processor_eventbox, true, true);
 
-       processor_eventbox.signal_enter_notify_event().connect (bind (sigc::ptr_fun (ProcessorBox::enter_box), this));
+       processor_eventbox.signal_enter_notify_event().connect (bind (
+                       sigc::ptr_fun (ProcessorBox::enter_box),
+                       this));
 
-       processor_display.signal_button_press_event().connect (mem_fun(*this, &ProcessorBox::processor_button_press_event), false);
-       processor_display.signal_button_release_event().connect (mem_fun(*this, &ProcessorBox::processor_button_release_event));
+       processor_display.signal_button_press_event().connect (
+                       mem_fun(*this, &ProcessorBox::processor_button_press_event), false);
+       processor_display.signal_button_release_event().connect (
+                       mem_fun(*this, &ProcessorBox::processor_button_release_event));
 }
 
 ProcessorBox::~ProcessorBox ()
@@ -154,9 +163,12 @@ ProcessorBox::set_route (boost::shared_ptr<Route> r)
 
        _route = r;
 
-       connections.push_back (_route->processors_changed.connect (mem_fun(*this, &ProcessorBox::redisplay_processors)));
-       connections.push_back (_route->GoingAway.connect (mem_fun (*this, &ProcessorBox::route_going_away)));
-       connections.push_back (_route->NameChanged.connect (mem_fun(*this, &ProcessorBox::route_name_changed)));
+       connections.push_back (_route->processors_changed.connect (
+                       mem_fun(*this, &ProcessorBox::redisplay_processors)));
+       connections.push_back (_route->GoingAway.connect (
+                       mem_fun (*this, &ProcessorBox::route_going_away)));
+       connections.push_back (_route->NameChanged.connect (
+                       mem_fun(*this, &ProcessorBox::route_name_changed)));
 
        redisplay_processors ();
 }
@@ -172,8 +184,8 @@ ProcessorBox::route_going_away ()
 void
 ProcessorBox::object_drop (const list<boost::shared_ptr<Processor> >& procs)
 {
-       for (std::list<boost::shared_ptr<Processor> >::const_iterator i = procs.begin(); i != procs.end(); ++i) {
-
+       for (std::list<boost::shared_ptr<Processor> >::const_iterator i = procs.begin();
+                       i != procs.end(); ++i) {
                XMLNode& state = (*i)->get_state ();
                XMLNodeList nlist;
                nlist.push_back (&state);
@@ -207,11 +219,9 @@ ProcessorBox::remove_processor_gui (boost::shared_ptr<Processor> processor)
        boost::shared_ptr<PortInsert> port_insert;
 
        if ((port_insert = boost::dynamic_pointer_cast<PortInsert> (processor)) != 0) {
-
                PortInsertUI *io_selector = reinterpret_cast<PortInsertUI *> (port_insert->get_gui());
                port_insert->set_gui (0);
                delete io_selector;
-
        } else if ((send = boost::dynamic_pointer_cast<Send> (processor)) != 0) {
                SendUIWindow *sui = reinterpret_cast<SendUIWindow*> (send->get_gui());
                send->set_gui (0);
@@ -219,9 +229,8 @@ ProcessorBox::remove_processor_gui (boost::shared_ptr<Processor> processor)
        }
 }
 
-void 
+void
 ProcessorBox::build_send_action_menu ()
-
 {
        using namespace Menu_Helpers;
 
@@ -235,13 +244,11 @@ ProcessorBox::build_send_action_menu ()
 
 void
 ProcessorBox::show_send_controls ()
-
 {
 }
 
 void
 ProcessorBox::new_send ()
-
 {
 }
 
@@ -292,17 +299,17 @@ ProcessorBox::processor_button_press_event (GdkEventButton *ev)
                        processor = (*iter)[columns.processor];
                        selected = processor_display.get_selection()->is_selected (iter);
                }
-               
+
        }
 
        if (processor && (Keyboard::is_edit_event (ev) || (ev->button == 1 && ev->type == GDK_2BUTTON_PRESS))) {
-               
+
                if (_session.engine().connected()) {
                        /* XXX giving an error message here is hard, because we may be in the midst of a button press */
                        edit_processor (processor);
                }
                ret = true;
-               
+
        } else if (processor && ev->button == 1 && selected) {
 
                // this is purely informational but necessary
@@ -314,7 +321,7 @@ ProcessorBox::processor_button_press_event (GdkEventButton *ev)
                _plugin_selector.show_manager ();
        }
 
-       
+
        return ret;
 }
 
@@ -337,10 +344,12 @@ ProcessorBox::processor_button_release_event (GdkEventButton *ev)
        }
 
        if (processor && Keyboard::is_delete_event (ev)) {
-               
-               Glib::signal_idle().connect (bind (mem_fun(*this, &ProcessorBox::idle_delete_processor), boost::weak_ptr<Processor>(processor)));
+
+               Glib::signal_idle().connect (bind (
+                               mem_fun(*this, &ProcessorBox::idle_delete_processor),
+                               boost::weak_ptr<Processor>(processor)));
                ret = true;
-               
+
        } else if (Keyboard::is_context_menu_event (ev)) {
 
                show_processor_menu(ev->time);
@@ -350,7 +359,7 @@ ProcessorBox::processor_button_release_event (GdkEventButton *ev)
 #ifndef GTKOSX
                   && (Keyboard::no_modifier_keys_pressed (ev) && ((ev->state & Gdk::BUTTON2_MASK) == Gdk::BUTTON2_MASK))
 #endif
-               ) {             
+               ) {
 
                /* button2-click with no/appropriate modifiers */
 
@@ -361,7 +370,7 @@ ProcessorBox::processor_button_release_event (GdkEventButton *ev)
                }
                ret = true;
 
-       } 
+       }
 
        return ret;
 }
@@ -407,23 +416,25 @@ ProcessorBox::use_plugins (const SelectedPlugins& plugins)
 {
        for (SelectedPlugins::const_iterator p = plugins.begin(); p != plugins.end(); ++p) {
 
-               boost::shared_ptr<Processor> processor (new PluginInsert (_session, *p, _placement));
+               boost::shared_ptr<Processor> processor (new PluginInsert (_session, *p));
 
                Route::ProcessorStreams err_streams;
 
                if (Config->get_new_plugins_active()) {
                        processor->activate ();
                }
-               
-               if (_route->add_processor (processor, &err_streams)) {
+
+               if (_route->add_processor (processor, &err_streams, 0, _placement)) {
                        weird_plugin_dialog (**p, err_streams, _route);
-                       // XXX SHAREDPTR delete plugin here .. do we even need to care? 
+                       // XXX SHAREDPTR delete plugin here .. do we even need to care?
                } else {
-                       
+
                        if (Profile->get_sae()) {
                                processor->activate ();
                        }
-                       processor->ActiveChanged.connect (bind (mem_fun (*this, &ProcessorBox::show_processor_active), boost::weak_ptr<Processor>(processor)));
+                       processor->ActiveChanged.connect (bind (
+                                       mem_fun (*this, &ProcessorBox::show_processor_active),
+                                       boost::weak_ptr<Processor>(processor)));
                }
        }
 }
@@ -448,7 +459,7 @@ ProcessorBox::weird_plugin_dialog (Plugin& p, Route::ProcessorStreams streams, b
                text += string_compose("\t%1 ", p.get_info()->n_inputs.n_audio()) + _("audio input(s)\n");
        }
 
-       text += "\nBut at the insertion point, there are:\n";
+       text += _("\nBut at the insertion point, there are:\n");
        if (has_midi) {
                text += string_compose("\t%1 ", streams.count.n_midi()) + _("MIDI channel(s)\n");
        }
@@ -456,7 +467,7 @@ ProcessorBox::weird_plugin_dialog (Plugin& p, Route::ProcessorStreams streams, b
                text += string_compose("\t%1 ", streams.count.n_audio()) + _("audio channel(s)\n");
        }
 
-       text += "\nArdour is unable to insert this plugin here.\n";
+       text += _("\nArdour is unable to insert this plugin here.\n");
        label.set_text(text);
 
        dialog.get_vbox()->pack_start (label);
@@ -473,15 +484,17 @@ ProcessorBox::weird_plugin_dialog (Plugin& p, Route::ProcessorStreams streams, b
 void
 ProcessorBox::choose_insert ()
 {
-       boost::shared_ptr<Processor> processor (new PortInsert (_session, _placement));
-       processor->ActiveChanged.connect (bind (mem_fun(*this, &ProcessorBox::show_processor_active), boost::weak_ptr<Processor>(processor)));
-       _route->add_processor (processor);
+       boost::shared_ptr<Processor> processor (new PortInsert (_session));
+       processor->ActiveChanged.connect (bind (
+                       mem_fun(*this, &ProcessorBox::show_processor_active),
+                       boost::weak_ptr<Processor>(processor)));
+       _route->add_processor (processor, 0, 0, _placement);
 }
 
 void
 ProcessorBox::choose_send ()
 {
-       boost::shared_ptr<Send> send (new Send (_session, _placement));
+       boost::shared_ptr<Send> send (new Send (_session));
        //send->set_default_type(_route->default_type());
 
        ChanCount outs;
@@ -502,11 +515,11 @@ ProcessorBox::choose_send ()
                error << string_compose (_("Cannot set up new send: %1"), err.what()) << endmsg;
                return;
        }
-       
+
        /* let the user adjust the output setup (number and connections) before passing
           it along to the Route
        */
-       
+
        IOSelectorWindow *ios = new IOSelectorWindow (_session, send->io(), false, true);
 
        ios->show_all ();
@@ -516,8 +529,10 @@ ProcessorBox::choose_send ()
        _send_being_created = send;
 
        boost::shared_ptr<Processor> r = boost::static_pointer_cast<Processor>(send);
-       
-       ios->selector().Finished.connect (bind (mem_fun(*this, &ProcessorBox::send_io_finished), boost::weak_ptr<Processor>(r), ios));
+
+       ios->selector().Finished.connect (bind (
+                       mem_fun(*this, &ProcessorBox::send_io_finished),
+                       boost::weak_ptr<Processor>(r), ios));
 }
 
 void
@@ -538,7 +553,7 @@ ProcessorBox::send_io_finished (IOSelector::Result r, boost::weak_ptr<Processor>
                break;
 
        case IOSelector::Accepted:
-               _route->add_processor (processor);
+               _route->add_processor (processor, 0, 0, _placement);
                if (Profile->get_sae()) {
                        processor->activate ();
                }
@@ -556,7 +571,7 @@ ProcessorBox::redisplay_processors ()
        if (no_processor_redisplay) {
                return;
        }
-       
+
        ignore_delete = true;
        model->clear ();
        ignore_delete = false;
@@ -564,7 +579,7 @@ ProcessorBox::redisplay_processors ()
        processor_active_connections.clear ();
        processor_name_connections.clear ();
 
-       _route->foreach_processor (mem_fun (*this, &ProcessorBox::add_processor_to_display));
+       _route->foreach_processor (_placement, mem_fun (*this, &ProcessorBox::add_processor_to_display));
 
        switch (_placement) {
        case PreFader:
@@ -583,19 +598,23 @@ ProcessorBox::add_processor_to_display (boost::weak_ptr<Processor> p)
        if (!processor) {
                return;
        }
-       
-       if (processor->placement() != _placement) {
+
+       if (processor == _route->amp()) {
                return;
        }
-       
+
        Gtk::TreeModel::Row row = *(model->append());
        row[columns.text] = processor_name (processor);
        row[columns.processor] = processor;
 
        show_processor_active (processor);
 
-       processor_active_connections.push_back (processor->ActiveChanged.connect (bind (mem_fun(*this, &ProcessorBox::show_processor_active), boost::weak_ptr<Processor>(processor))));
-       processor_name_connections.push_back (processor->NameChanged.connect (bind (mem_fun(*this, &ProcessorBox::show_processor_name), boost::weak_ptr<Processor>(processor))));
+       processor_active_connections.push_back (processor->ActiveChanged.connect (bind (
+                       mem_fun(*this, &ProcessorBox::show_processor_active),
+                       boost::weak_ptr<Processor>(processor))));
+       processor_name_connections.push_back (processor->NameChanged.connect (bind (
+                       mem_fun(*this, &ProcessorBox::show_processor_name),
+                       boost::weak_ptr<Processor>(processor))));
 }
 
 string
@@ -678,13 +697,13 @@ void
 ProcessorBox::show_processor_active (boost::weak_ptr<Processor> weak_processor)
 {
        boost::shared_ptr<Processor> processor (weak_processor.lock());
-       
+
        if (!processor) {
                return;
        }
 
        ENSURE_GUI_THREAD(bind (mem_fun(*this, &ProcessorBox::show_processor_active), weak_processor));
-       
+
        Gtk::TreeModel::Children children = model->children();
        Gtk::TreeModel::Children::iterator iter = children.begin();
 
@@ -694,7 +713,7 @@ ProcessorBox::show_processor_active (boost::weak_ptr<Processor> weak_processor)
 
                if (r == processor) {
                        (*iter)[columns.text] = processor_name (r);
-                       
+
                        if (processor->active()) {
                                (*iter)[columns.color] = *active_processor_color;
                        } else {
@@ -756,15 +775,15 @@ outputs do not work correctly."));
 void
 ProcessorBox::rename_processors ()
 {
-       vector<boost::shared_ptr<Processor> > to_be_renamed;
-       
+       ProcSelection to_be_renamed;
+
        get_selected_processors (to_be_renamed);
 
        if (to_be_renamed.empty()) {
                return;
        }
 
-       for (vector<boost::shared_ptr<Processor> >::iterator i = to_be_renamed.begin(); i != to_be_renamed.end(); ++i) {
+       for (ProcSelection::iterator i = to_be_renamed.begin(); i != to_be_renamed.end(); ++i) {
                rename_processor (*i);
        }
 }
@@ -772,7 +791,7 @@ ProcessorBox::rename_processors ()
 void
 ProcessorBox::cut_processors ()
 {
-       vector<boost::shared_ptr<Processor> > to_be_removed;
+       ProcSelection to_be_removed;
        XMLNode* node = new XMLNode (X_("cut"));
 
        get_selected_processors (to_be_removed);
@@ -782,17 +801,17 @@ ProcessorBox::cut_processors ()
        }
 
        no_processor_redisplay = true;
-       for (vector<boost::shared_ptr<Processor> >::iterator i = to_be_removed.begin(); i != to_be_removed.end(); ++i) {
+       for (ProcSelection::iterator i = to_be_removed.begin(); i != to_be_removed.end(); ++i) {
                // Do not cut inserts
                if (boost::dynamic_pointer_cast<PluginInsert>((*i)) != 0 ||
                    (boost::dynamic_pointer_cast<Send>((*i)) != 0)) {
 
                        void* gui = (*i)->get_gui ();
-               
+
                        if (gui) {
                                static_cast<Gtk::Widget*>(gui)->hide ();
                        }
-                       
+
                        XMLNode& child ((*i)->get_state());
 
                        if (_route->remove_processor (*i) == 0) {
@@ -801,7 +820,7 @@ ProcessorBox::cut_processors ()
                        } else {
                                delete &child;
                        }
-               } 
+               }
        }
 
        _rr_selection.set (node);
@@ -813,7 +832,7 @@ ProcessorBox::cut_processors ()
 void
 ProcessorBox::copy_processors ()
 {
-       vector<boost::shared_ptr<Processor> > to_be_copied;
+       ProcSelection to_be_copied;
        XMLNode* node = new XMLNode (X_("copy"));
 
        get_selected_processors (to_be_copied);
@@ -822,7 +841,7 @@ ProcessorBox::copy_processors ()
                return;
        }
 
-       for (vector<boost::shared_ptr<Processor> >::iterator i = to_be_copied.begin(); i != to_be_copied.end(); ++i) {
+       for (ProcSelection::iterator i = to_be_copied.begin(); i != to_be_copied.end(); ++i) {
                // Do not copy inserts
                if (boost::dynamic_pointer_cast<PluginInsert>((*i)) != 0 ||
                    (boost::dynamic_pointer_cast<Send>((*i)) != 0)) {
@@ -836,18 +855,18 @@ ProcessorBox::copy_processors ()
 void
 ProcessorBox::delete_processors ()
 {
-       vector<boost::shared_ptr<Processor> > to_be_deleted;
-       
+       ProcSelection to_be_deleted;
+
        get_selected_processors (to_be_deleted);
 
        if (to_be_deleted.empty()) {
                return;
        }
 
-       for (vector<boost::shared_ptr<Processor> >::iterator i = to_be_deleted.begin(); i != to_be_deleted.end(); ++i) {
-               
+       for (ProcSelection::iterator i = to_be_deleted.begin(); i != to_be_deleted.end(); ++i) {
+
                void* gui = (*i)->get_gui ();
-               
+
                if (gui) {
                        static_cast<Gtk::Widget*>(gui)->hide ();
                }
@@ -895,7 +914,7 @@ ProcessorBox::rename_processor (boost::shared_ptr<Processor> processor)
         name_prompter.get_result (result);
         if (result.length()) {
                        processor->set_name (result);
-               }       
+               }
                break;
        }
 
@@ -937,12 +956,14 @@ ProcessorBox::paste_processor_state (const XMLNodeList& nlist)
                                XMLNode n (**niter);
                                Send::make_unique (n, _session);
                                p.reset (new Send (_session, n));
-                               
+
+                       } else if (type->value() == "meter") {
+                               p = _route->shared_peak_meter();
+
                        } else {
                                p.reset (new PluginInsert (_session, **niter));
                        }
 
-                       p->set_placement (_placement);
                        copies.push_back (p);
                }
                catch (...) {
@@ -950,7 +971,7 @@ ProcessorBox::paste_processor_state (const XMLNodeList& nlist)
                }
        }
 
-       if (_route->add_processors (copies)) {
+       if (_route->add_processors (copies, 0, _placement)) {
 
                string msg = _(
                        "Copying the set of processors on the clipboard failed,\n\
@@ -974,10 +995,10 @@ ProcessorBox::deactivate_processor (boost::shared_ptr<Processor> r)
 }
 
 void
-ProcessorBox::get_selected_processors (vector<boost::shared_ptr<Processor> >& processors)
+ProcessorBox::get_selected_processors (ProcSelection& processors)
 {
     vector<Gtk::TreeModel::Path> pathlist = processor_display.get_selection()->get_selected_rows();
+
     for (vector<Gtk::TreeModel::Path>::iterator iter = pathlist.begin(); iter != pathlist.end(); ++iter) {
            processors.push_back ((*(model->get_iter(*iter)))[columns.processor]);
     }
@@ -1056,19 +1077,19 @@ ProcessorBox::edit_processor (boost::shared_ptr<Processor> processor)
                        return;
                }
        }
-       
+
        if ((send = boost::dynamic_pointer_cast<Send> (processor)) != 0) {
-               
+
                if (!_session.engine().connected()) {
                        return;
                }
 
                boost::shared_ptr<Send> send = boost::dynamic_pointer_cast<Send> (processor);
-               
+
                SendUIWindow *send_ui;
-               
+
                if (send->get_gui() == 0) {
-                       
+
                        send_ui = new SendUIWindow (send, _session);
 
                        WindowTitle title(Glib::get_application_name());
@@ -1076,57 +1097,57 @@ ProcessorBox::edit_processor (boost::shared_ptr<Processor> processor)
                        send_ui->set_title (title.get_string());
 
                        send->set_gui (send_ui);
-                       
+
                } else {
                        send_ui = reinterpret_cast<SendUIWindow *> (send->get_gui());
                }
-               
+
                gidget = send_ui;
-               
+
        } else if ((plugin_insert = boost::dynamic_pointer_cast<PluginInsert> (processor)) != 0) {
-               
+
                PluginUIWindow *plugin_ui;
-               
+
                /* these are both allowed to be null */
-               
+
                Container* toplevel = get_toplevel();
                Window* win = dynamic_cast<Gtk::Window*>(toplevel);
-               
+
                if (plugin_insert->get_gui() == 0) {
-                       
+
                        plugin_ui = new PluginUIWindow (win, plugin_insert);
-                       
+
                        WindowTitle title(Glib::get_application_name());
                        title += generate_processor_title (plugin_insert);
                        plugin_ui->set_title (title.get_string());
-                       
+
                        plugin_insert->set_gui (plugin_ui);
-                       
+
                } else {
                        plugin_ui = reinterpret_cast<PluginUIWindow *> (plugin_insert->get_gui());
                        plugin_ui->set_parent (win);
                }
-               
+
                gidget = plugin_ui;
-               
+
        } else if ((port_insert = boost::dynamic_pointer_cast<PortInsert> (processor)) != 0) {
-               
+
                if (!_session.engine().connected()) {
                        MessageDialog msg ( _("Not connected to JACK - no I/O changes are possible"));
                        msg.run ();
                        return;
                }
-               
+
                PortInsertWindow *io_selector;
-               
+
                if (port_insert->get_gui() == 0) {
                        io_selector = new PortInsertWindow (_session, port_insert);
                        port_insert->set_gui (io_selector);
-                       
+
                } else {
                        io_selector = reinterpret_cast<PortInsertWindow *> (port_insert->get_gui());
                }
-               
+
                gidget = io_selector;
        }
 
@@ -1164,45 +1185,59 @@ ProcessorBox::register_actions ()
        Glib::RefPtr<Action> act;
 
        /* new stuff */
-       ActionManager::register_action (popup_act_grp, X_("newplugin"), _("New Plugin"),  sigc::ptr_fun (ProcessorBox::rb_choose_plugin));
+       ActionManager::register_action (popup_act_grp, X_("newplugin"), _("New Plugin"),
+                       sigc::ptr_fun (ProcessorBox::rb_choose_plugin));
 
-       act = ActionManager::register_action (popup_act_grp, X_("newinsert"), _("New Insert"),  sigc::ptr_fun (ProcessorBox::rb_choose_insert));
+       act = ActionManager::register_action (popup_act_grp, X_("newinsert"), _("New Insert"),
+                       sigc::ptr_fun (ProcessorBox::rb_choose_insert));
        ActionManager::jack_sensitive_actions.push_back (act);
-       act = ActionManager::register_action (popup_act_grp, X_("newsend"), _("New Send ..."),  sigc::ptr_fun (ProcessorBox::rb_choose_send));
+       act = ActionManager::register_action (popup_act_grp, X_("newsend"), _("New Send ..."),
+                       sigc::ptr_fun (ProcessorBox::rb_choose_send));
        ActionManager::jack_sensitive_actions.push_back (act);
 
-       ActionManager::register_action (popup_act_grp, X_("clear"), _("Clear"),  sigc::ptr_fun (ProcessorBox::rb_clear));
+       ActionManager::register_action (popup_act_grp, X_("clear"), _("Clear"),
+                       sigc::ptr_fun (ProcessorBox::rb_clear));
 
        /* standard editing stuff */
-       act = ActionManager::register_action (popup_act_grp, X_("cut"), _("Cut"),  sigc::ptr_fun (ProcessorBox::rb_cut));
+       act = ActionManager::register_action (popup_act_grp, X_("cut"), _("Cut"),
+                       sigc::ptr_fun (ProcessorBox::rb_cut));
        ActionManager::plugin_selection_sensitive_actions.push_back(act);
-       act = ActionManager::register_action (popup_act_grp, X_("copy"), _("Copy"),  sigc::ptr_fun (ProcessorBox::rb_copy));
+       act = ActionManager::register_action (popup_act_grp, X_("copy"), _("Copy"),
+                       sigc::ptr_fun (ProcessorBox::rb_copy));
        ActionManager::plugin_selection_sensitive_actions.push_back(act);
 
-       act = ActionManager::register_action (popup_act_grp, X_("delete"), _("Delete"),  sigc::ptr_fun (ProcessorBox::rb_delete));
+       act = ActionManager::register_action (popup_act_grp, X_("delete"), _("Delete"),
+                       sigc::ptr_fun (ProcessorBox::rb_delete));
        ActionManager::plugin_selection_sensitive_actions.push_back(act); // ??
 
-       paste_action = ActionManager::register_action (popup_act_grp, X_("paste"), _("Paste"),  sigc::ptr_fun (ProcessorBox::rb_paste));
-       act = ActionManager::register_action (popup_act_grp, X_("rename"), _("Rename"),  sigc::ptr_fun (ProcessorBox::rb_rename));
+       paste_action = ActionManager::register_action (popup_act_grp, X_("paste"), _("Paste"),
+                       sigc::ptr_fun (ProcessorBox::rb_paste));
+       act = ActionManager::register_action (popup_act_grp, X_("rename"), _("Rename"),
+                       sigc::ptr_fun (ProcessorBox::rb_rename));
        ActionManager::plugin_selection_sensitive_actions.push_back(act);
-       ActionManager::register_action (popup_act_grp, X_("selectall"), _("Select All"),  sigc::ptr_fun (ProcessorBox::rb_select_all));
-       ActionManager::register_action (popup_act_grp, X_("deselectall"), _("Deselect All"),  sigc::ptr_fun (ProcessorBox::rb_deselect_all));
-               
+       ActionManager::register_action (popup_act_grp, X_("selectall"), _("Select All"),
+                       sigc::ptr_fun (ProcessorBox::rb_select_all));
+       ActionManager::register_action (popup_act_grp, X_("deselectall"), _("Deselect All"),
+                       sigc::ptr_fun (ProcessorBox::rb_deselect_all));
+
        /* activation */
-       act = ActionManager::register_action (popup_act_grp, X_("activate"), _("Activate"),  sigc::ptr_fun (ProcessorBox::rb_activate));
+       act = ActionManager::register_action (popup_act_grp, X_("activate"), _("Activate"),
+                       sigc::ptr_fun (ProcessorBox::rb_activate));
        ActionManager::plugin_selection_sensitive_actions.push_back(act);
-       act = ActionManager::register_action (popup_act_grp, X_("deactivate"), _("Deactivate"),  sigc::ptr_fun (ProcessorBox::rb_deactivate));
+       act = ActionManager::register_action (popup_act_grp, X_("deactivate"), _("Deactivate"),
+                       sigc::ptr_fun (ProcessorBox::rb_deactivate));
        ActionManager::plugin_selection_sensitive_actions.push_back(act);
-       ActionManager::register_action (popup_act_grp, X_("activate_all"), _("Activate all"),  sigc::ptr_fun (ProcessorBox::rb_activate_all));
-       ActionManager::register_action (popup_act_grp, X_("deactivate_all"), _("Deactivate all"),  sigc::ptr_fun (ProcessorBox::rb_deactivate_all));
+       ActionManager::register_action (popup_act_grp, X_("activate_all"), _("Activate all"),
+                       sigc::ptr_fun (ProcessorBox::rb_activate_all));
+       ActionManager::register_action (popup_act_grp, X_("deactivate_all"), _("Deactivate all"),
+                       sigc::ptr_fun (ProcessorBox::rb_deactivate_all));
 
        /* show editors */
-       act = ActionManager::register_action (popup_act_grp, X_("edit"), _("Edit"),  sigc::ptr_fun (ProcessorBox::rb_edit));
+       act = ActionManager::register_action (popup_act_grp, X_("edit"), _("Edit"),
+                       sigc::ptr_fun (ProcessorBox::rb_edit));
        ActionManager::plugin_selection_sensitive_actions.push_back(act);
 
        ActionManager::add_action_group (popup_act_grp);
-
-
 }
 
 void
@@ -1373,7 +1408,7 @@ ProcessorBox::route_name_changed ()
                Gtk::TreeModel::Row row = *iter;
 
                processor= row[columns.processor];
-               
+
                void* gui = processor->get_gui();
 
                if (!gui) {
@@ -1383,7 +1418,7 @@ ProcessorBox::route_name_changed ()
                /* rename editor windows for sends and plugins */
 
                WindowTitle title (Glib::get_application_name());
-               
+
                if ((send = boost::dynamic_pointer_cast<Send> (processor)) != 0) {
                        title += send->name();
                        static_cast<Window*>(gui)->set_title (title.get_string());
@@ -1394,7 +1429,7 @@ ProcessorBox::route_name_changed ()
        }
 }
 
-string 
+string
 ProcessorBox::generate_processor_title (boost::shared_ptr<PluginInsert> pi)
 {
        string maker = pi->plugin()->maker() ? pi->plugin()->maker() : "";
@@ -1409,6 +1444,6 @@ ProcessorBox::generate_processor_title (boost::shared_ptr<PluginInsert> pi)
                maker += " ...";
        }
 
-       return string_compose(_("%1: %2 (by %3)"), _route->name(), pi->name(), maker);  
+       return string_compose(_("%1: %2 (by %3)"), _route->name(), pi->name(), maker);
 }
 
index 60836ac1f6676b342a4fbd23e6ade438650eeb1f..ea908133e34f9f890bc96ba49f73d49ad4b356ec 100644 (file)
@@ -184,8 +184,10 @@ class ProcessorBox : public Gtk::HBox, public PluginInterestedObject
        void clear_processors ();
        void rename_processors ();
 
+       typedef vector<boost::shared_ptr<ARDOUR::Processor> > ProcSelection;
+
        void for_selected_processors (void (ProcessorBox::*pmf)(boost::shared_ptr<ARDOUR::Processor>));
-       void get_selected_processors (vector<boost::shared_ptr<ARDOUR::Processor> >&);
+       void get_selected_processors (ProcSelection&);
 
        static Glib::RefPtr<Gtk::Action> paste_action;
        void paste_processor_state (const XMLNodeList&);
index 056135e70c1313b6858aa2180e95e707cffa09c4..f62895c6f75edbbc70593353ea7748eb511459b5 100644 (file)
@@ -1104,8 +1104,6 @@ TimeAxisView::compute_controls_size_info ()
        two_row_table.show_all ();
        req = two_row_table.size_request ();
 
-       cerr << "Normal height is " << req.height << " + " << extra_height << endl;
-
        // height required to show all normal buttons 
 
        hNormal = /*req.height*/ 48 + extra_height;
index c6dd70c992f53594ba841a23e29bfb3d7bd3e76d..f52ad14277e62e56139680e2a53a86011a874b44 100644 (file)
@@ -79,7 +79,7 @@ UIConfiguration::load_defaults ()
 
                string rcfile = default_ui_rc_file.to_string();
 
-               cerr << string_compose (_("loading default ui configuration file %1"), rcfile) << endl;
+               cerr << string_compose (_("Loading default ui configuration file %1"), rcfile) << endl;
                
                if (!tree.read (rcfile.c_str())) {
                        error << string_compose(_("Ardour: cannot read default ui configuration file \"%1\""), rcfile) << endmsg;
@@ -109,7 +109,7 @@ UIConfiguration::load_state ()
 
                string rcfile = default_ui_rc_file.to_string();
 
-               cerr << string_compose (_("loading default ui configuration file %1"), rcfile) << endl;
+               cerr << string_compose (_("Loading default ui configuration file %1"), rcfile) << endl;
                
                if (!tree.read (rcfile.c_str())) {
                        error << string_compose(_("Ardour: cannot read default ui configuration file \"%1\""), rcfile) << endmsg;
@@ -132,7 +132,7 @@ UIConfiguration::load_state ()
        
                string rcfile = user_ui_rc_file.to_string();
 
-               cerr << string_compose (_("loading user ui configuration file %1"), rcfile) << endl;
+               cerr << string_compose (_("Loading user ui configuration file %1"), rcfile) << endl;
 
                if (!tree.read (rcfile)) {
                        error << string_compose(_("Ardour: cannot read ui configuration file \"%1\""), rcfile) << endmsg;
index 263ce82086b05c7ac6434876a80eb96abb8b624a..aa20f3e389da23a677262ff76a4806bb915a9c71 100644 (file)
 #include <cmath>
 #include <algorithm>
 #include "ardour/amp.h"
-#include "ardour/buffer_set.h"
 #include "ardour/audio_buffer.h"
+#include "ardour/buffer_set.h"
+#include "ardour/configuration.h"
+#include "ardour/io.h"
+#include "ardour/session.h"
 
 namespace ARDOUR {
 
+Amp::Amp(Session& s, IO& io)
+       : Processor(s, "Amp")
+       , _io(io)
+       , _mute(false)
+       , _apply_gain(true)
+       , _apply_gain_automation(false)
+       , _current_gain(1.0)
+       , _desired_gain(1.0)
+{
+}
+
+bool
+Amp::can_support_io_configuration (const ChanCount& in, ChanCount& out) const
+{
+       out = in;
+       return true;
+}
+
+bool
+Amp::configure_io (ChanCount in, ChanCount out)
+{
+       if (out != in) { // always 1:1
+               return false;
+       }
+       
+       return Processor::configure_io (in, out);
+}
+
+void
+Amp::run_in_place (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes)
+{
+       gain_t* gab = _session.gain_automation_buffer();
+
+       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 (_apply_gain) {
+               
+               if (_apply_gain_automation) {
+                       
+                       if (_io.phase_invert()) {
+                               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];
+                                       }
+                               }
+                       } 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] *= gab[nx];
+                                       }
+                               }
+                       }
+                       
+               } else { /* manual (scalar) gain */
+                       
+                       if (_current_gain != _desired_gain) {
+                               
+                               Amp::apply_gain (bufs, nframes, _current_gain, _desired_gain, _io.phase_invert());
+                               _current_gain = _desired_gain;
+                               
+                       } else if (_current_gain != 0.0f && (_io.phase_invert() || _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_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);
+                               }
+
+                       } else if (_current_gain == 0.0f) {
+                               for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i) {
+                                       i->clear();
+                               }
+                       }
+               }
+       }
+}
 
 /** Apply a declicked gain to the audio buffers of @a bufs */
 void
-Amp::run_in_place (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, bool invert_polarity)
 {
-       if (nframes == 0)
+       if (nframes == 0) {
                return;
+       }
 
-       if (bufs.count().n_audio() == 0)
+       if (bufs.count().n_audio() == 0) {
                return;
-
-       // assert(bufs.buffer_capacity(DataType::AUDIO) >= nframes);
+       }
 
        // if we don't need to declick, defer to apply_simple_gain
        if (initial == target) {
@@ -98,5 +198,18 @@ Amp::apply_simple_gain (BufferSet& bufs, nframes_t nframes, gain_t target)
 {
 }
 
+XMLNode&
+Amp::state (bool full_state)
+{
+       return get_state();
+}
+
+XMLNode&
+Amp::get_state()
+{
+       XMLNode* node = new XMLNode(state_node_name);
+       node->add_property("type", "amp");
+       return *node;
+}
 
 } // namespace ARDOUR
index 402a29542df0e071d872eeafd1f0d59788a4e7bf..fa9de724adf47e08ce0c616f10611b2bf27908a2 100644 (file)
 #define __ardour_amp_h__
 
 #include "ardour/types.h"
+#include "ardour/chan_count.h"
+#include "ardour/processor.h"
 
 namespace ARDOUR {
 
 class BufferSet;
+class IO;
 
 
 /** Applies a declick operation to all audio inputs, passing the same number of
  * audio outputs, and passing through any other types unchanged.
- *
- * FIXME: make this a Processor.
  */
-class Amp {
+class Amp : public Processor {
 public:
-       static void run_in_place (BufferSet& bufs, nframes_t nframes, gain_t initial, gain_t target, bool invert_polarity);
+       Amp(Session& s, IO& io);
+
+       bool can_support_io_configuration (const ChanCount& in, ChanCount& out) const;
+       bool configure_io (ChanCount in, ChanCount out);
+       
+       void run_in_place (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes);
+
+       bool apply_gain() const  { return _apply_gain; }
+       void apply_gain(bool yn) { _apply_gain = yn; }
+
+       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; }
+
+       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;
+       }
+
+       XMLNode& state (bool full);
+       XMLNode& get_state();
+
+       static void apply_gain (BufferSet& bufs, nframes_t nframes,
+                       gain_t initial, gain_t target, bool invert_polarity);
 
        static void apply_simple_gain(BufferSet& bufs, nframes_t nframes, gain_t target);
+
+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;
 };
 
 
index 22092b5e1baa3986a46320ad4fbd8fc63b5fabdc..484887e0b77f2c58b59e7a489fc9311497cc0594 100644 (file)
@@ -41,12 +41,6 @@ class AudioTrack : public Track
 
        int roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, 
                  int declick, bool can_record, bool rec_monitors_input);
-       
-       int no_roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, 
-                    bool state_changing, bool can_record, bool rec_monitors_input);
-       
-       int silent_roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, 
-                        bool can_record, bool rec_monitors_input);
 
        boost::shared_ptr<AudioDiskstream> audio_diskstream() const;
 
index 9d7ba6d6aee3161c5d5725fc6ae7769b778f6226..3f10929fe8ea5bba6d911db69cf9ca3557e0c1e2 100644 (file)
@@ -66,7 +66,10 @@ public:
        const ChanCount& count() const { return _count; }
        ChanCount&       count()       { return _count; }
 
-       void set_count(const ChanCount& count) { _count = count; }
+       void is_silent(bool yn) { _is_silent = yn; }
+       bool is_silent() const  { return _is_silent; }
+
+       void set_count(const ChanCount& count) { assert(count <= _available); _count = count; }
        
        size_t buffer_capacity(DataType type) const;
 
@@ -161,6 +164,9 @@ private:
 
        /// Whether we (don't) 'own' the contained buffers (otherwise we mirror a PortSet)
        bool _is_mirror;
+
+       /// Whether the buffer set should be considered silent
+       bool _is_silent;
 };
 
 
index fb4b1999cad1c0d4e5ae64fdb1c0b4afdcf1aa04..c9b543c4ba3f42272631fab2e15b243f256745ff 100644 (file)
@@ -23,6 +23,7 @@
 #include <cassert>
 #include <ostream>
 
+#include "pbd/xml++.h"
 #include "ardour/data_type.h"
 
 namespace ARDOUR {
@@ -35,6 +36,7 @@ namespace ARDOUR {
  */
 class ChanCount {
 public:
+       ChanCount(const XMLNode& node);
        ChanCount() { reset(); }
        
        // Convenience constructor for making single-typed streams (stereo, mono, etc)
@@ -104,6 +106,14 @@ public:
                return ( (*this > other) || (*this == other) );
        }
        
+       static ChanCount min(const ChanCount& a, const ChanCount& b) {
+               ChanCount ret;
+               for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
+                       ret.set(*t, std::min(a.get(*t), b.get(*t)));
+               }
+               return ret;
+       }
+       
        static ChanCount max(const ChanCount& a, const ChanCount& b) {
                ChanCount ret;
                for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
@@ -111,6 +121,8 @@ public:
                }
                return ret;
        }
+       
+       XMLNode* state(const std::string& name) const;
 
        static const ChanCount INFINITE;
        static const ChanCount ZERO;
index 1dae20e34aa439c9c40dc9402b0d0c7536c85888..5f948a77b09d1f3e76d9807e74f4e6a56558fcce 100644 (file)
@@ -26,6 +26,7 @@
 #include <utility>
 
 #include "ardour/data_type.h"
+#include "ardour/chan_count.h"
 
 namespace ARDOUR {
 
@@ -36,47 +37,26 @@ namespace ARDOUR {
 class ChanMapping {
 public:
        ChanMapping() {}
-       ChanMapping(ChanCount identity) {
-               for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
-                       for (size_t i = 0; i <= identity.get(*t); ++i)
-                               set(*t, i, i);
-               }
-       }
-
-       uint32_t get(DataType t, uint32_t from) {
-               Mappings::iterator tm = _mappings.find(t);
-               assert(tm != _mappings.end());
-               TypeMapping::iterator m = tm->second.find(from);
-               assert(m != tm->second.end());
-               return m->second;
-       }
+       ChanMapping(ARDOUR::ChanCount identity);
+       
+       uint32_t get(DataType t, uint32_t from);
+       void     set(DataType t, uint32_t from, uint32_t to);
+       void     offset_from(DataType t, int32_t delta);
+       void     offset_to(DataType t, int32_t delta);
        
-       void set(DataType t, uint32_t from, uint32_t to) {
-               Mappings::iterator tm = _mappings.find(t);
-               if (tm == _mappings.end()) {
-                       tm = _mappings.insert(std::make_pair(t, TypeMapping())).first;
-               }
-               tm->second.insert(std::make_pair(from, to));
-       }
-
-       /** Increase the 'to' field of every mapping for type @a t by @a delta */
-       void offset(DataType t, uint32_t delta) {
-               Mappings::iterator tm = _mappings.find(t);
-               if (tm != _mappings.end()) {
-                       for (TypeMapping::iterator m = tm->second.begin(); m != tm->second.end(); ++m) {
-                               m->second += delta;
-                       }
-               }
-       }
-
-private:
        typedef std::map<uint32_t, uint32_t>    TypeMapping;
        typedef std::map<DataType, TypeMapping> Mappings;
        
+       Mappings       mappings()       { return _mappings; }
+       const Mappings mappings() const { return _mappings; }
+
+private:
        Mappings _mappings;
 };
 
 } // namespace ARDOUR
 
+std::ostream& operator<<(std::ostream& o, const ARDOUR::ChanMapping& m);
+
 #endif // __ardour_chan_mapping_h__
 
index e50e0a29cbc6e8d079a34a8c38ef0de8045e99f7..ae744478f1a4ee6974307559854b1134c505ede7 100644 (file)
@@ -26,17 +26,11 @@ namespace ARDOUR {
 
 class ClickIO : public IO
 {
-  public:
-       ClickIO (Session& s, const string& name, 
-
-              int input_min = -1, int input_max = -1, 
-
-              int output_min = -1, int output_max = -1)
-       : IO (s, name, input_min, input_max, output_min, output_max) {}
-
+public:
+       ClickIO (Session& s, const string& name) : IO (s, name) {}
        ~ClickIO() {}
 
-  protected:
+protected:
        uint32_t pans_required () const { return 1; }
 };
 
diff --git a/libs/ardour/ardour/control_outputs.h b/libs/ardour/ardour/control_outputs.h
new file mode 100644 (file)
index 0000000..72d9534
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+    Copyright (C) 2006 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_control_outputs_h__
+#define __ardour_control_outputs_h__
+
+#include <string>
+#include "ardour/types.h"
+#include "ardour/chan_count.h"
+#include "ardour/io_processor.h"
+
+namespace ARDOUR {
+
+class BufferSet;
+class IO;
+
+class ControlOutputs : public IOProcessor {
+public:
+       ControlOutputs(Session& s, IO* io);
+
+       bool can_support_io_configuration (const ChanCount& in, ChanCount& out) const;
+       bool configure_io (ChanCount in, ChanCount out);
+
+       void run_in_place (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes);
+       
+       bool deliver() const  { return _deliver; }
+       void deliver(bool yn) { _deliver = yn; }
+
+       XMLNode& state (bool full);
+       XMLNode& get_state();
+
+private:
+       bool _deliver;
+};
+
+
+} // namespace ARDOUR
+
+#endif // __ardour_control_outputs_h__
+
index 84576687565ada0fdb5ec0f6438219911cc9e6f7..3e36d10be382f011ff1af0e62368d06b917427d3 100644 (file)
@@ -52,32 +52,31 @@ class XMLNode;
 
 namespace ARDOUR {
 
-class Session;
+class Amp;
 class AudioEngine;
-class UserBundle;
+class AudioPort;
+class BufferSet;
 class Bundle;
+class MidiPort;
 class Panner;
 class PeakMeter;
 class Port;
-class AudioPort;
-class MidiPort;
-class BufferSet;
+class Session;
+class UserBundle;
 
 /** A collection of input and output ports 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
 {
   public:
        static const string state_node_name;
 
-       IO (Session&, const string& name, 
-           int input_min = -1, int input_max = -1, 
-           int output_min = -1, int output_max = -1,
-           DataType default_type = DataType::AUDIO);
+       IO (Session&, const string& name, DataType default_type = DataType::AUDIO,
+               ChanCount in_min=ChanCount::ZERO, ChanCount in_max=ChanCount::INFINITE,
+               ChanCount out_min=ChanCount::ZERO, ChanCount out_max=ChanCount::INFINITE);
        
        IO (Session&, const XMLNode&, DataType default_type = DataType::AUDIO);
        
@@ -109,7 +108,7 @@ class IO : public SessionObject, public AutomatableControls, public Latent
 
        BufferSet& output_buffers() { return *_output_buffers; }
 
-       gain_t         gain () const { return _desired_gain; }
+       gain_t         gain () const { return _gain_control->user_float(); }
        virtual gain_t effective_gain () const;
        
        void set_denormal_protection (bool yn, void *src);
@@ -118,11 +117,16 @@ class IO : public SessionObject, public AutomatableControls, public Latent
        void set_phase_invert (bool yn, void *src);
        bool phase_invert() const { return _phase_invert; }
 
-       Panner& panner()        { return *_panner; }
-       PeakMeter& peak_meter() { return *_meter; }
-       const Panner& panner() const { return *_panner; }
        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 connect_input_ports_to_bundle (boost::shared_ptr<Bundle>, void *);
@@ -133,8 +137,8 @@ class IO : public SessionObject, public AutomatableControls, public Latent
        BundleList bundles_connected_to_inputs ();
        BundleList bundles_connected_to_outputs ();
 
-        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_for_inputs () { return _bundle_for_inputs; }
+       boost::shared_ptr<Bundle> bundle_for_outputs () { return _bundle_for_outputs; }
        
        int add_input_port (string source, void *src, DataType type = DataType::NIL);
        int add_output_port (string destination, void *src, DataType type = DataType::NIL);
@@ -271,22 +275,24 @@ class IO : public SessionObject, public AutomatableControls, public Latent
        mutable Glib::Mutex io_lock;
 
   protected:
-       Panner*             _panner;
        BufferSet*          _output_buffers; //< Set directly to output port buffers
        bool                _active;
        gain_t              _gain;
-       gain_t              _effective_gain;
-       gain_t              _desired_gain;
        Glib::Mutex          declick_lock;
        PortSet             _outputs;
        PortSet             _inputs;
-       PeakMeter*          _meter;
        bool                 no_panner_reset;
        bool                _phase_invert;
        bool                _denormal_protection;
        XMLNode*             deferred_state;
        DataType            _default_type;
        nframes_t           _output_offset;
+       ChanCount           _configured_inputs;
+       ChanCount           _configured_outputs;
+       
+       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);
@@ -301,8 +307,6 @@ class IO : public SessionObject, public AutomatableControls, public Latent
        virtual void   set_gain (gain_t g, void *src);
        void           inc_gain (gain_t delta, void *src);
 
-       bool apply_gain_automation;
-       
        virtual int load_automation (std::string path);
 
        /* AudioTrack::deprecated_use_diskstream_connections() needs these */
@@ -361,6 +365,7 @@ class IO : public SessionObject, public AutomatableControls, public Latent
 
        void bundle_changed (Bundle::Change);
 
+       int get_port_counts (const XMLNode& node);
        int create_ports (const XMLNode&);
        int make_connections (const XMLNode&);
        boost::shared_ptr<Bundle> find_possible_bundle (const string &desired_name, const string &default_name, const string &connection_type_name);
index 1a12a3271e87d5e1280c8f28eec0f8cb336ef992..e7dffb3138139f30b9e1149ba92061b4a0348e56 100644 (file)
@@ -45,8 +45,9 @@ class IO;
 class IOProcessor : public Processor
 {
   public:
-       IOProcessor (Session&, const string& name, Placement,
-                    int input_min = -1, int input_max = -1, int output_min = -1, int output_max = -1,
+       IOProcessor (Session&, const string& proc_name, const string io_name="",
+                    ARDOUR::DataType default_type = DataType::AUDIO);
+       IOProcessor (Session&, IO* io, const string& proc_name,
                     ARDOUR::DataType default_type = DataType::AUDIO);
        virtual ~IOProcessor ();
        
index 972e1b676089aabcdd6b74a0040eaac000caf64c..0a49ddf99f41d18df960c8c0357d96f24eb437c9 100644 (file)
@@ -35,12 +35,12 @@ class Session;
  */
 class PeakMeter : public Processor {
 public:
-       PeakMeter(Session& s) : Processor(s, "meter", PreFader) {}
+       PeakMeter(Session& s) : Processor(s, "Meter") {}
 
        void reset ();
        void reset_max ();
        
-       bool can_support_io_configuration (const ChanCount& in, ChanCount& out) const { return true; }
+       bool can_support_io_configuration (const ChanCount& in, ChanCount& out) const;
        bool configure_io (ChanCount in, ChanCount out);
        
        /** Compute peaks */
@@ -61,11 +61,11 @@ public:
                        return minus_infinity();
                }
        }
+       
+       XMLNode& state (bool full);
+       XMLNode& get_state();
 
 private:
-       /* disallow copy construction */
-       PeakMeter (PeakMeter const &);
-       
        friend class IO;
        void meter();
 
index 424b9d2c924d21084904762e28ee3ec96e50764a..fe8290d5d97ab0f3e661a1df543e1bc26fc0d79c 100644 (file)
@@ -41,17 +41,6 @@ public:
        int roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, 
                  int declick, bool can_record, bool rec_monitors_input);
        
-       int no_roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, 
-                    bool state_changing, bool can_record, bool rec_monitors_input);
-       
-       int silent_roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, 
-                        bool can_record, bool rec_monitors_input);
-
-       void process_output_buffers (BufferSet& bufs,
-                                    nframes_t start_frame, nframes_t end_frame,
-                                    nframes_t nframes, bool with_redirects, int declick,
-                                    bool meter);
-
        boost::shared_ptr<MidiDiskstream> midi_diskstream() const;
 
        int use_diskstream (string name);
index 9e5469604879ea4330fafb08fc784ebe97792554..dcb34c8a04a6690dfa7946b966e8e35489cf8a39 100644 (file)
@@ -205,7 +205,7 @@ class Panner : public Processor
        virtual ~Panner ();
 
        void clear_panners ();
-
+       bool empty() const { return _streampanners.empty(); }
 
        /// The fundamental Panner function
        void set_automation_state (AutoState);
index 99bd492ab5dd0201fbfc1a95d577bbce3a1959f6..89512df40cb2582cff27352339ec2d470536e99f 100644 (file)
@@ -44,7 +44,7 @@ class Plugin;
 class PluginInsert : public Processor
 {
   public:
-       PluginInsert (Session&, boost::shared_ptr<Plugin>, Placement);
+       PluginInsert (Session&, boost::shared_ptr<Plugin>);
        PluginInsert (Session&, const XMLNode&);
        ~PluginInsert ();
 
index 27d251cc45f4b0f91f8af9e066164c0fcb2f6fb8..076e4af9d1cf335f8403b417d0d57cb6d9807683 100644 (file)
@@ -40,7 +40,7 @@ class Session;
 class PortInsert : public IOProcessor
 {
   public:
-       PortInsert (Session&, Placement);
+       PortInsert (Session&);
        PortInsert (Session&, const XMLNode&);
        ~PortInsert ();
 
index 1167930d61a2789b790d2135c156a227a61608c1..547cc87f88c670f386a00e1c96b9fc0a494d5b9c 100644 (file)
@@ -49,16 +49,21 @@ class Processor : public SessionObject, public AutomatableControls, public Laten
   public:
        static const string state_node_name;
 
-       Processor(Session&, const string& name, Placement p); // TODO: remove placement (use sort key)
+       Processor(Session&, const string& name);
        
        virtual ~Processor() { }
        
+       /** Configuration of a processor on a bus
+        * (i.e. how to apply to a BufferSet)
+        */
+       struct Mapping {
+           ChanCount in;
+           ChanCount out;
+       };
+       
        uint32_t sort_key() const { return _sort_key; }
        void set_sort_key (uint32_t key);
 
-       Placement placement() const { return _placement; }
-       void set_placement (Placement);
-       
        bool active () const { return _active; }
        
        bool get_next_ab_is_active () const { return _next_ab_is_active; }
@@ -108,7 +113,6 @@ class Processor : public SessionObject, public AutomatableControls, public Laten
        static sigc::signal<void,Processor*> ProcessorCreated;
 
        sigc::signal<void>                     ActiveChanged;
-       sigc::signal<void>                     PlacementChanged;
        sigc::signal<void,ChanCount,ChanCount> ConfigurationChanged;
 
 protected:
@@ -118,9 +122,9 @@ protected:
        bool      _configured;
        ChanCount _configured_input;
        ChanCount _configured_output;
-       Placement _placement;
        uint32_t  _sort_key;
        void*     _gui;  /* generic, we don't know or care what this is */
+       Mapping   _mapping;
 };
 
 } // namespace ARDOUR
index 6926dbd0366e346d12ccad87f9029b8ea3242ddb..2b54810577db3699e084eaa13cacd7ed65c20ce2 100644 (file)
 
 namespace ARDOUR {
 
-class Processor;
+class Amp;
+class ControlOutputs;
 class IOProcessor;
-class Send;
+class Processor;
 class RouteGroup;
+class Send;
 
 enum mute_type {
     PRE_FADER =    0x1,
@@ -70,8 +72,10 @@ class Route : public IO
                ControlOut = 0x4
        };
 
-       Route (Session&, std::string name, int input_min, int input_max, int output_min, int output_max,
-              Flag flags = Flag(0), DataType default_type = DataType::AUDIO);
+       Route (Session&, std::string name, Flag flags = Flag(0),
+                       DataType default_type = DataType::AUDIO,
+                       ChanCount in=ChanCount::ZERO, ChanCount out=ChanCount::ZERO);
+
        Route (Session&, const XMLNode&, DataType default_type = DataType::AUDIO);
        virtual ~Route();
 
@@ -149,6 +153,15 @@ class Route : public IO
                        method (boost::weak_ptr<Processor> (*i));
                }
        }
+       
+       void foreach_processor (Placement p, sigc::slot<void, boost::weak_ptr<Processor> > method) {
+               Glib::RWLock::ReaderLock lm (_processor_lock);
+               ProcessorList::iterator start, end;
+               placement_range(p, start, end);
+               for (ProcessorList::iterator i = start; i != end; ++i) {
+                       method (boost::weak_ptr<Processor> (*i));
+               }
+       }
 
        boost::shared_ptr<Processor> nth_processor (uint32_t n) {
                Glib::RWLock::ReaderLock lm (_processor_lock);
@@ -170,12 +183,12 @@ class Route : public IO
        struct ProcessorStreams {
                ProcessorStreams(size_t i=0, ChanCount c=ChanCount()) : index(i), count(c) {}
 
-               size_t    index; ///< Index of processor where configuration failed
+               uint32_t  index; ///< Index of processor where configuration failed
                ChanCount count; ///< Input requested of processor
        };
 
-       int add_processor (boost::shared_ptr<Processor>, ProcessorStreams* err = 0);
-       int add_processors (const ProcessorList&, ProcessorStreams* err = 0);
+       int add_processor (boost::shared_ptr<Processor>, ProcessorStreams* err = 0, ProcessorList::iterator* iter=0, Placement=PreFader);
+       int add_processors (const ProcessorList&, ProcessorStreams* err = 0, Placement placement=PreFader);
        int remove_processor (boost::shared_ptr<Processor>, ProcessorStreams* err = 0);
        int sort_processors (ProcessorStreams* err = 0);
        void disable_processors (Placement);
@@ -226,7 +239,7 @@ class Route : public IO
        sigc::signal<void,void*> SelectedChanged;
 
        int set_control_outs (const vector<std::string>& ports);
-       IO* control_outs() { return _control_outs; }
+       boost::shared_ptr<ControlOutputs> control_outs() { return _control_outs; }
 
        bool feeds (boost::shared_ptr<Route>);
        std::set<boost::shared_ptr<Route> > fed_by;
@@ -276,12 +289,11 @@ class Route : public IO
        nframes_t check_initial_delay (nframes_t, nframes_t&);
        
        void passthru (nframes_t start_frame, nframes_t end_frame,
-                       nframes_t nframes, int declick, bool meter_inputs);
+                       nframes_t nframes, int declick);
 
        virtual void process_output_buffers (BufferSet& bufs,
                                             nframes_t start_frame, nframes_t end_frame,
-                                            nframes_t nframes, bool with_processors, int declick,
-                                            bool meter);
+                                            nframes_t nframes, bool with_processors, int declick);
        
        Flag           _flags;
        int            _pending_declick;
@@ -296,8 +308,7 @@ class Route : public IO
        nframes_t      _roll_delay;
        ProcessorList  _processors;
        Glib::RWLock   _processor_lock;
-       IO            *_control_outs;
-       Glib::Mutex    _control_outs_lock;
+       boost::shared_ptr<ControlOutputs> _control_outs;
        RouteGroup    *_edit_group;
        RouteGroup    *_mix_group;
        std::string    _comment;
@@ -326,8 +337,7 @@ class Route : public IO
        virtual XMLNode& state(bool);
 
        void passthru_silence (nframes_t start_frame, nframes_t end_frame,
-                              nframes_t nframes, int declick,
-                              bool meter);
+                              nframes_t nframes, int declick);
        
        void silence (nframes_t nframes);
        
@@ -361,24 +371,18 @@ class Route : public IO
        void input_change_handler (IOChange, void *src);
        void output_change_handler (IOChange, void *src);
 
-       int reset_processor_counts (ProcessorStreams*); /* locked */
-       int _reset_processor_counts (ProcessorStreams*); /* unlocked */
-
-       /** processor I/O channels and plugin count handling */
-       struct ProcessorCount {
-           boost::shared_ptr<ARDOUR::Processor> processor;
-           ChanCount in;
-           ChanCount out;
+       bool _in_configure_processors;
 
-           ProcessorCount (boost::shared_ptr<ARDOUR::Processor> ins) : processor(ins) {}
-       };
+       int configure_processors (ProcessorStreams*);
+       int configure_processors_unlocked (ProcessorStreams*);
        
-       int32_t apply_some_processor_counts (std::list<ProcessorCount>& iclist);
-       bool    check_some_processor_counts (std::list<ProcessorCount>& iclist,
-                               ChanCount required_inputs, ProcessorStreams* err_streams);
-
        void set_deferred_state ();
-       void add_processor_from_xml (const XMLNode&);
+       bool add_processor_from_xml (const XMLNode&, ProcessorList::iterator* iter=0);  
+
+       void placement_range(
+                       Placement                p,
+                       ProcessorList::iterator& start,
+                       ProcessorList::iterator& end);
 };
 
 } // namespace ARDOUR
index 2e7d2c239c584bea63486aabb7993b7e4fe08466..77bb6d901710a9cb1b39d648e7f4ba5348d5914e 100644 (file)
@@ -34,7 +34,7 @@ namespace ARDOUR {
 class Send : public IOProcessor 
 {
   public:      
-       Send (Session&, Placement);
+       Send (Session&);
        Send (Session&, const XMLNode&);
        virtual ~Send ();
 
index 8bef24a7e259c000f971e6062035bd32cf3d9eee..1e3855c3088243273b816bf0b749c9e40c2b0f1c 100644 (file)
@@ -255,6 +255,7 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable
        void set_clean ();
        bool dirty() const { return _state_of_the_state & Dirty; }
        void set_deletion_in_progress ();
+       void clear_deletion_in_progress ();
        bool deletion_in_progress() const { return _state_of_the_state & Deletion; }
        sigc::signal<void> DirtyChanged;
 
index 29a4aa8e2596ce330028f08cdd92d87fb160cc88..96826e3eaaa9880bc994703de24cd665e7841197 100644 (file)
@@ -44,16 +44,16 @@ class Track : public Route
        virtual int set_mode (TrackMode m) { return false; }
        virtual bool can_use_mode (TrackMode m, bool& bounce_required) { return false; }
        sigc::signal<void> TrackModeChanged;
+       
+       int no_roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, 
+                            bool state_changing, bool can_record, bool rec_monitors_input);
+       
+       int silent_roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, 
+                       bool can_record, bool rec_monitors_input);
 
        virtual int roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, 
                          int declick, bool can_record, bool rec_monitors_input) = 0;
        
-       virtual int no_roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, 
-                            bool state_changing, bool can_record, bool rec_monitors_input) = 0;
-       
-       virtual int silent_roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, 
-                                bool can_record, bool rec_monitors_input) = 0;
-
        void toggle_monitor_input ();
 
        bool can_record();
index 5c73d826bfd8015c9d7c71f1d1f5ebf214bc6f22..bb74d5fc1689dd0b03e8aa1f88352f23db2c6793 100644 (file)
@@ -2172,7 +2172,8 @@ AudioDiskstream::set_block_size (nframes_t nframes)
                boost::shared_ptr<ChannelList> c = channels.reader();
 
                for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
-                       if ((*chan)->speed_buffer) delete [] (*chan)->speed_buffer;
+                       if ((*chan)->speed_buffer)
+                               delete [] (*chan)->speed_buffer;
                        (*chan)->speed_buffer = new Sample[speed_buffer_size];
                }
        }
@@ -2195,9 +2196,11 @@ AudioDiskstream::allocate_temporary_buffers ()
                boost::shared_ptr<ChannelList> c = channels.reader();
 
                for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
-                       if ((*chan)->playback_wrap_buffer) delete [] (*chan)->playback_wrap_buffer;
+                       if ((*chan)->playback_wrap_buffer)
+                               delete [] (*chan)->playback_wrap_buffer;
                        (*chan)->playback_wrap_buffer = new Sample[required_wrap_size]; 
-                       if ((*chan)->capture_wrap_buffer) delete [] (*chan)->capture_wrap_buffer;
+                       if ((*chan)->capture_wrap_buffer)
+                               delete [] (*chan)->capture_wrap_buffer;
                        (*chan)->capture_wrap_buffer = new Sample[required_wrap_size];  
                }
 
@@ -2270,7 +2273,7 @@ int
 AudioDiskstream::remove_channel_from (boost::shared_ptr<ChannelList> c, uint32_t how_many)
 {
        while (how_many-- && !c->empty()) {
-               delete c->back();
+               //delete c->back(); // FIXME: crash (thread safe with RCU?)
                c->pop_back();
        }
 
index d814709798a08192e637499de726c83688003ab5..79b1240ab040d4866232333be44470d2f98fde9d 100644 (file)
 
 #include "evoral/Curve.hpp"
 
-#include "ardour/audio_track.h"
+#include "ardour/amp.h"
+#include "ardour/audio_buffer.h"
 #include "ardour/audio_diskstream.h"
-#include "ardour/session.h"
-#include "ardour/io_processor.h"
+#include "ardour/audio_track.h"
+#include "ardour/audioplaylist.h"
 #include "ardour/audioregion.h"
 #include "ardour/audiosource.h"
+#include "ardour/buffer_set.h"
+#include "ardour/io_processor.h"
+#include "ardour/panner.h"
+#include "ardour/playlist_factory.h"
+#include "ardour/plugin_insert.h"
+#include "ardour/processor.h"
 #include "ardour/region_factory.h"
 #include "ardour/route_group_specialized.h"
-#include "ardour/processor.h"
-#include "ardour/plugin_insert.h"
-#include "ardour/audioplaylist.h"
-#include "ardour/playlist_factory.h"
-#include "ardour/panner.h"
+#include "ardour/session.h"
 #include "ardour/utils.h"
-#include "ardour/buffer_set.h"
-#include "ardour/audio_buffer.h"
 #include "i18n.h"
 
 using namespace std;
@@ -145,7 +146,7 @@ AudioTrack::deprecated_use_diskstream_connections ()
        
        if ((prop = node.property ("gain")) != 0) {
                set_gain (atof (prop->value().c_str()), this);
-               _gain = _desired_gain;
+               _gain = _gain_control->user_float();
        }
 
        if ((prop = node.property ("input-connection")) != 0) {
@@ -452,91 +453,6 @@ AudioTrack::set_state_part_two ()
        return;
 }      
 
-int 
-AudioTrack::no_roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, 
-                    bool session_state_changing, bool can_record, bool rec_monitors_input)
-{
-       if (n_outputs().n_total() == 0) {
-               return 0;
-       }
-
-       if (!_active) {
-               silence (nframes);
-               return 0;
-       }
-
-       if (session_state_changing) {
-
-               /* XXX is this safe to do against transport state changes? */
-
-               passthru_silence (start_frame, end_frame, nframes, 0, false);
-               return 0;
-       }
-
-       audio_diskstream()->check_record_status (start_frame, nframes, can_record);
-
-       bool send_silence;
-       
-       if (_have_internal_generator) {
-               /* since the instrument has no input streams,
-                  there is no reason to send any signal
-                  into the route.
-               */
-               send_silence = true;
-       } else {
-
-               if (!Config->get_tape_machine_mode()) {
-                       /* 
-                          ADATs work in a strange way.. 
-                          they monitor input always when stopped.and auto-input is engaged. 
-                       */
-                       if ((Config->get_monitoring_model() == SoftwareMonitoring) && (Config->get_auto_input () || _diskstream->record_enabled())) {
-                               send_silence = false;
-                       } else {
-                               send_silence = true;
-                       }
-               } else {
-                       /* 
-                          Other machines switch to input on stop if the track is record enabled,
-                          regardless of the auto input setting (auto input only changes the 
-                          monitoring state when the transport is rolling) 
-                       */
-                       if ((Config->get_monitoring_model() == SoftwareMonitoring) && _diskstream->record_enabled()) {
-                               send_silence = false;
-                       } else {
-                               send_silence = true;
-                       }
-               }
-       }
-
-       apply_gain_automation = false;
-
-       if (send_silence) {
-               
-               /* if we're sending silence, but we want the meters to show levels for the signal,
-                  meter right here.
-               */
-               
-               if (_have_internal_generator) {
-                       passthru_silence (start_frame, end_frame, nframes, 0, true);
-               } else {
-                       if (_meter_point == MeterInput) {
-                               just_meter_input (start_frame, end_frame, nframes);
-                       }
-                       passthru_silence (start_frame, end_frame, nframes, 0, false);
-               }
-
-       } else {
-       
-               /* we're sending signal, but we may still want to meter the input. 
-                */
-
-               passthru (start_frame, end_frame, nframes, 0, (_meter_point == MeterInput));
-       }
-
-       return 0;
-}
-
 int
 AudioTrack::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, int declick,
                  bool can_record, bool rec_monitors_input)
@@ -580,7 +496,7 @@ AudioTrack::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame,
        } 
 
        _silent = false;
-       apply_gain_automation = false;
+       _amp->apply_gain_automation(false);
 
        if ((dret = diskstream->process (transport_frame, nframes, can_record, rec_monitors_input)) != 0) {
                silence (nframes);
@@ -599,7 +515,7 @@ AudioTrack::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame,
                   at least potentially (depending on monitoring options)
                 */
 
-               passthru (start_frame, end_frame, nframes, 0, true);
+               passthru (start_frame, end_frame, nframes, false);
 
        } else if ((b = diskstream->playback_buffer(0)) != 0) {
 
@@ -691,11 +607,13 @@ AudioTrack::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame,
                        Glib::Mutex::Lock am (data().control_lock(), Glib::TRY_LOCK);
                        
                        if (am.locked() && gain_control()->automation_playback()) {
-                               apply_gain_automation = gain_control()->list()->curve().rt_safe_get_vector (start_frame, end_frame, _session.gain_automation_buffer(), nframes);
+                               _amp->apply_gain_automation(
+                                               gain_control()->list()->curve().rt_safe_get_vector (
+                                                       start_frame, end_frame, _session.gain_automation_buffer(), nframes));
                        }
                }
 
-               process_output_buffers (bufs, start_frame, end_frame, nframes, (!_session.get_record_enabled() || !Config->get_do_not_record_plugins()), declick, (_meter_point != MeterInput));
+               process_output_buffers (bufs, start_frame, end_frame, nframes, (!_session.get_record_enabled() || !Config->get_do_not_record_plugins()), declick);
                
        } else {
                /* problem with the diskstream; just be quiet for a bit */
@@ -705,36 +623,12 @@ AudioTrack::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame,
        return 0;
 }
 
-int
-AudioTrack::silent_roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame,  
-                        bool can_record, bool rec_monitors_input)
-{
-       if (n_outputs().n_total() == 0 && _processors.empty()) {
-               return 0;
-       }
-
-       if (!_active) {
-               silence (nframes);
-               return 0;
-       }
-
-       _silent = true;
-       apply_gain_automation = false;
-
-       silence (nframes);
-
-       return audio_diskstream()->process (_session.transport_frame(), nframes, can_record, rec_monitors_input);
-}
-
 int
 AudioTrack::export_stuff (BufferSet& buffers, nframes_t start, nframes_t nframes, bool enable_processing)
 {
-       gain_t  gain_automation[nframes];
        gain_t  gain_buffer[nframes];
        float   mix_buffer[nframes];
        ProcessorList::iterator i;
-       bool post_fader_work = false;
-       gain_t this_gain = _gain;
        boost::shared_ptr<AudioDiskstream> diskstream = audio_diskstream();
        
        Glib::RWLock::ReaderLock rlock (_processor_lock);
@@ -767,8 +661,9 @@ AudioTrack::export_stuff (BufferSet& buffers, nframes_t start, nframes_t nframes
        }
 
        // If no processing is required, there's no need to go any further.
-       if (!enable_processing)
+       if (!enable_processing) {
                return 0;
+       }
 
        /* note: only run processors during export. other layers in the machinery
           will already have checked that there are no external port processors.
@@ -776,57 +671,11 @@ AudioTrack::export_stuff (BufferSet& buffers, nframes_t start, nframes_t nframes
        
        for (i = _processors.begin(); i != _processors.end(); ++i) {
                boost::shared_ptr<Processor> processor;
-               
                if ((processor = boost::dynamic_pointer_cast<Processor>(*i)) != 0) {
-                       switch (processor->placement()) {
-                       case PreFader:
-                               processor->run_in_place (buffers, start, start+nframes, nframes);
-                               break;
-                       case PostFader:
-                               post_fader_work = true;
-                               break;
-                       }
+                       processor->run_in_place (buffers, start, start+nframes, nframes);
                }
        }
        
-       if (gain_control()->automation_state() == Play) {
-               
-               gain_control()->list()->curve().get_vector (start, start + nframes, gain_automation, nframes);
-
-               for (BufferSet::audio_iterator bi = buffers.audio_begin(); bi != buffers.audio_end(); ++bi) {
-                       Sample *b = bi->data();
-                       for (nframes_t n = 0; n < nframes; ++n) {
-                               b[n] *= gain_automation[n];
-                       }
-               }
-
-       } else {
-
-               for (BufferSet::audio_iterator bi = buffers.audio_begin(); bi != buffers.audio_end(); ++bi) {
-                       Sample *b = bi->data();
-                       for (nframes_t n = 0; n < nframes; ++n) {
-                               b[n] *= this_gain;
-                       }
-               }
-       }
-
-       if (post_fader_work) {
-
-               for (i = _processors.begin(); i != _processors.end(); ++i) {
-                       boost::shared_ptr<PluginInsert> processor;
-                       
-                       if ((processor = boost::dynamic_pointer_cast<PluginInsert>(*i)) != 0) {
-                               switch ((*i)->placement()) {
-                               case PreFader:
-                                       break;
-                               case PostFader:
-                                       processor->run_in_place (buffers, start, start+nframes, nframes);
-                                       break;
-                               }
-                       }
-               }
-       } 
-
        return 0;
 }
 
index 51a6ae71fbb15bca4ecbc90cd677dad5f3dbb78a..91cea6ba71d3a35212692f6641be797945bc95f4 100644 (file)
@@ -469,6 +469,8 @@ AudioEngine::jack_bufsize_callback (nframes_t nframes)
 {
        _buffer_size = nframes;
        _raw_buffer_sizes[DataType::AUDIO] = nframes * sizeof(float);
+       cout << "FIXME: Assuming maximum MIDI buffer size " << nframes * 4 << "bytes" << endl;
+       _raw_buffer_sizes[DataType::MIDI] = nframes * 4;
        _usecs_per_cycle = (int) floor ((((double) nframes / frame_rate())) * 1000000.0);
        last_monitor_check = 0;
 
@@ -604,13 +606,14 @@ AudioEngine::register_port (DataType dtype, const string& portname, bool input)
                } else if (dtype == DataType::MIDI) {
                        newport = new MidiPort (portname, (input ? Port::IsInput : Port::IsOutput));
                } else {
-                       throw unknown_type();
+                       throw PortRegistrationFailure("unable to create port (unknown type)");
                }
                
                size_t& old_buffer_size  = _raw_buffer_sizes[newport->type()];
                size_t  port_buffer_size = newport->raw_buffer_size(0);
-               if (port_buffer_size > old_buffer_size)
+               if (port_buffer_size > old_buffer_size) {
                        old_buffer_size = port_buffer_size;
+               }
 
                RCUWriter<Ports> writer (ports);
                boost::shared_ptr<Ports> ps = writer.get_copy ();
@@ -621,8 +624,13 @@ AudioEngine::register_port (DataType dtype, const string& portname, bool input)
                return newport;
        }
 
-       catch (...) {
-               throw PortRegistrationFailure("unable to create port (unknown type?)");
+       catch (PortRegistrationFailure& err) {
+               throw err;
+       } catch (std::exception& e) {
+               throw PortRegistrationFailure(string_compose(
+                               _("unable to create port: %1"), e.what()).c_str());
+       } catch (...) {
+               throw PortRegistrationFailure("unable to create port (unknown error)");
        }
 }
 
@@ -1256,6 +1264,10 @@ AudioEngine::reconnect_to_jack ()
                nframes_t blocksize = jack_get_buffer_size (_jack);
                session->set_block_size (blocksize);
                session->set_frame_rate (jack_get_sample_rate (_jack));
+               
+               _raw_buffer_sizes[DataType::AUDIO] = blocksize * sizeof(float);
+               cout << "FIXME: Assuming maximum MIDI buffer size " << blocksize * 4 << "bytes" << endl;
+               _raw_buffer_sizes[DataType::MIDI] = blocksize * 4;
        }
 
        last_monitor_check = 0;
index c43623b35886c6adf75e1960d400b3fe3e58b3df..0fa4e9c67afb81122482cd63fe5125a775a0a593 100644 (file)
@@ -242,7 +242,6 @@ Automatable::set_automation_state (const XMLNode& node, Evoral::Parameter legacy
                            boost::shared_ptr<Evoral::Control> newcontrol = control_factory(param);
                                add_control(newcontrol);
                                newcontrol->set_list(al);
-                               warning << "Control did not exist";
                        }
 
                } else {
@@ -268,7 +267,9 @@ Automatable::get_automation_state ()
        for (Controls::iterator li = controls().begin(); li != controls().end(); ++li) {
                boost::shared_ptr<AutomationList> l
                                = boost::dynamic_pointer_cast<AutomationList>(li->second->list());
-               node->add_child_nocopy (l->get_state ());
+               if (!l->empty()) {
+                       node->add_child_nocopy (l->get_state ());
+               }
        }
 
        return *node;
@@ -410,7 +411,12 @@ Automatable::control_factory(const Evoral::Parameter& param)
        } else if (param.type() == GainAutomation) {
                control = new IO::GainControl( X_("gaincontrol"), (IO*)this, param);
        } else if (param.type() == PanAutomation) {
-               control = new Panner::PanControllable( ((Panner *)this)->session(), X_("panner"), *(Panner *)this, param);
+               Panner* me = dynamic_cast<Panner*>(this);
+               if (me) {
+                       control = new Panner::PanControllable(me->session(), X_("panner"), *me, param);
+               } else {
+                       cerr << "ERROR: PanAutomation for non-Panner" << endl;
+               }
        } else {
                control = new AutomationControl(_a_session, param);
        }
index 545d9801784e535650e9018a8c3118c9e15a00ae..005a4dae65c0f49b57293c7d3a4137b6f89eae77 100644 (file)
@@ -34,6 +34,7 @@ namespace ARDOUR {
 /** Create a new, empty BufferSet */
 BufferSet::BufferSet()
        : _is_mirror(false)
+       , _is_silent(false)
 {
        for (size_t i=0; i < DataType::num_types; ++i) {
                _buffers.push_back(BufferVec());
@@ -84,6 +85,7 @@ BufferSet::attach_buffers(PortSet& ports, nframes_t nframes, nframes_t offset)
        }
        
        _count = ports.count();
+       _available = ports.count();
 
        _is_mirror = true;
 }
@@ -97,8 +99,9 @@ BufferSet::ensure_buffers(DataType type, size_t num_buffers, size_t buffer_capac
        assert(type != DataType::NIL);
        assert(type < _buffers.size());
 
-       if (num_buffers == 0)
+       if (num_buffers == 0) {
                return;
+       }
 
        // The vector of buffers of the type we care about
        BufferVec& bufs = _buffers[type];
@@ -132,7 +135,7 @@ BufferSet::ensure_buffers(DataType type, size_t num_buffers, size_t buffer_capac
 #ifdef HAVE_SLV2
        // Ensure enough low level MIDI format buffers are available for conversion
        // in both directions (input & output, out-of-place)
-       if (type == DataType::MIDI && _lv2_buffers.size() < _buffers[type].size() * 2) {
+       if (type == DataType::MIDI && _lv2_buffers.size() < _buffers[type].size() * 2 + 1) {
                while (_lv2_buffers.size() < _buffers[type].size() * 2) {
                        _lv2_buffers.push_back(std::make_pair(false, new LV2EventBuffer(buffer_capacity)));
                }
@@ -160,7 +163,7 @@ BufferSet::buffer_capacity(DataType type) const
 Buffer&
 BufferSet::get(DataType type, size_t i)
 {
-       assert(i <= _count.get(type));
+       assert(i < _available.get(type));
        return *_buffers[type][i];
 }
 
index 1c892c1a87feeaf909dd6c8b68282f55fb9a6dee..e60104dad8d2c42e622fbc5b8fc84edd67b3e1ca 100644 (file)
 #include <stdint.h>
 #include "ardour/chan_count.h"
 
+#include "i18n.h"
+
+static const char* state_node_name = "Channels";
+
 namespace ARDOUR {
 
 // infinite/zero chan count stuff, for setting minimums and maximums, etc.
 // FIXME: implement this in a less fugly way
 
+ChanCount::ChanCount(const XMLNode& node)
+{
+       reset();
+       XMLNodeConstIterator iter = node.children().begin();
+       for ( ; iter != node.children().end(); ++iter) {
+               if ((*iter)->name() == X_(state_node_name)) {
+                       const string& type_str  = (*iter)->property("type")->value();
+                       const string& count_str = (*iter)->property("count")->value();
+                       set(DataType(type_str), atol(count_str.c_str()));
+               }
+       }
+}
+
 ChanCount
 infinity_factory()
 {
@@ -39,6 +56,21 @@ infinity_factory()
        return ret;
 }
 
+XMLNode*
+ChanCount::state(const std::string& name) const
+{
+       XMLNode* node = new XMLNode (name);
+       for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
+               uint32_t count = get(*t);
+               if (count > 0) {
+                       XMLNode* n = new XMLNode(X_(state_node_name));
+                       n->add_property("type", (*t).to_string());
+                       n->add_property("count", count);
+                       node->add_child_nocopy(*n);
+               }
+       }
+       return node;
+}
 
 // Statics
 const ChanCount ChanCount::INFINITE = infinity_factory();
index 611ebddb59b7a006db5574681879d5fb8c63959f..bff9fb16d63fd3b560a255ae790e9072f9bec6b6 100644 (file)
@@ -103,7 +103,7 @@ Configuration::load_state ()
                }
 
                if (statbuf.st_size != 0) {
-                       cerr << string_compose (_("loading system configuration file %1"), rcfile) << endl;
+                       cerr << string_compose (_("Loading system configuration file %1"), rcfile) << endl;
                        
                        if (!tree.read (rcfile.c_str())) {
                                error << string_compose(_("Ardour: cannot read system configuration file \"%1\""), rcfile) << endmsg;
@@ -140,7 +140,7 @@ Configuration::load_state ()
                }
 
                if (statbuf.st_size != 0) {
-                       cerr << string_compose (_("loading user configuration file %1"), rcfile) << endl;
+                       cerr << string_compose (_("Loading user configuration file %1"), rcfile) << endl;
                        
                        if (!tree.read (rcfile)) {
                                error << string_compose(_("Ardour: cannot read configuration file \"%1\""), rcfile) << endmsg;
diff --git a/libs/ardour/control_outputs.cc b/libs/ardour/control_outputs.cc
new file mode 100644 (file)
index 0000000..2acd3c6
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+    Copyright (C) 2006 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 <cmath>
+#include <algorithm>
+#include "ardour/control_outputs.h"
+#include "ardour/audio_buffer.h"
+#include "ardour/buffer_set.h"
+#include "ardour/configuration.h"
+#include "ardour/io.h"
+#include "ardour/session.h"
+
+using namespace std;
+
+namespace ARDOUR {
+
+ControlOutputs::ControlOutputs(Session& s, IO* io)
+       : IOProcessor(s, io, "Control Outs")
+       , _deliver(true)
+{
+}
+
+bool
+ControlOutputs::can_support_io_configuration (const ChanCount& in, ChanCount& out) const
+{
+       out = in;
+       return true;
+}
+
+bool
+ControlOutputs::configure_io (ChanCount in, ChanCount out)
+{
+       if (out != in) { // always 1:1
+               return false;
+       }
+       
+       return Processor::configure_io (in, out);
+}
+
+void
+ControlOutputs::run_in_place (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes)
+{
+       if (_deliver) {
+               _io->deliver_output (bufs, start_frame, end_frame, nframes);
+       } else {
+               _io->silence (nframes);
+       }
+}
+
+XMLNode&
+ControlOutputs::state (bool full_state)
+{
+       return get_state();
+}
+
+XMLNode&
+ControlOutputs::get_state()
+{
+       XMLNode* node = new XMLNode(state_node_name);
+       node->add_property("type", "control-outputs");
+       return *node;
+}
+
+} // namespace ARDOUR
index 4cce7d4dc31be3a1f2849ef634ca54eba3aba383..bca3c74241ca9768307f736ae6763677ba9d76dd 100644 (file)
@@ -441,17 +441,15 @@ Diskstream::playlist_ranges_moved (list< Evoral::RangeMove<nframes_t> > const &
                );
        
        /* move panner automation */
-       Panner & p = _io->panner ();
-       for (uint32_t i = 0; i < p.npanners (); ++i) {
-
-               boost::shared_ptr<AutomationList> pan_alist = p.streampanner(i).pan_control()->alist();
-               XMLNode & before = pan_alist->get_state ();
-               pan_alist->move_ranges (movements);
-               _session.add_command (
-                       new MementoCommand<AutomationList> (
-                               *pan_alist.get(), &before, &pan_alist->get_state ()
-                               )
-                       );
+       boost::shared_ptr<Panner> p = _io->panner ();
+       if (p) {
+               for (uint32_t i = 0; i < p->npanners (); ++i) {
+                       boost::shared_ptr<AutomationList> pan_alist = p->streampanner(i).pan_control()->alist();
+                       XMLNode & before = pan_alist->get_state ();
+                       pan_alist->move_ranges (movements);
+                       _session.add_command (new MementoCommand<AutomationList> (
+                                       *pan_alist.get(), &before, &pan_alist->get_state ()));
+               }
        }
 
        /* move processor automation */
index 1c354a5db01e3fa6f5c8f5f00872de0a85374678..722c0fad49cc0f071625eb3d554604d794169b39 100644 (file)
@@ -107,7 +107,7 @@ int
 ARDOUR::setup_midi ()
 {
        if (Config->midi_ports.size() == 0) {
-               warning << _("no MIDI ports specified: no MMC or MTC control possible") << endmsg;
+               //warning << _("no MIDI ports specified: no MMC or MTC control possible") << endmsg;
                return 0;
        }
 
index 410d0851426d1440131cf9a1288ce078e5d1dec5..ef9605f467ad14a876e7b2dac90ec8a877519ca3 100644 (file)
@@ -449,7 +449,7 @@ Session::import_audiofiles (ImportStatus& status)
                                                                    frame_rate(), cnt, status.total);
                        write_audio_data_to_new_files (source.get(), status, newfiles);
                } else if (smf_reader.get()) { // midi
-                       status.doing_what = string_compose(_("loading MIDI file %1"), *p);
+                       status.doing_what = string_compose(_("Loading MIDI file %1"), *p);
                        write_midi_data_to_new_files (smf_reader.get(), status, newfiles);
                }
        }
index 7e77996d3904896f273867698c1192d4219ed69d..3e5b138fb7d6f24cb1f4a76cff74a085c8db417c 100644 (file)
@@ -102,36 +102,27 @@ static double direct_gain_to_control (gain_t gain) {
  * and friends if no type is explicitly requested (to avoid breakage).
  */
 IO::IO (Session& s, const string& name,
-       int input_min, int input_max, int output_min, int output_max,
-       DataType default_type)
-       : SessionObject(s, name),
-         AutomatableControls (s),
-         _output_buffers (new BufferSet()),
-         _active(true),
-         _default_type (default_type),
-         _input_minimum (ChanCount::ZERO),
-         _input_maximum (ChanCount::INFINITE),
-         _output_minimum (ChanCount::ZERO),
-         _output_maximum (ChanCount::INFINITE)
-{
-       _panner = new Panner (name, _session);
-       _meter = new PeakMeter (_session);
-
-       if (input_min > 0) {
-               _input_minimum = ChanCount(_default_type, input_min);
-       }
-       if (input_max >= 0) {
-               _input_maximum = ChanCount(_default_type, input_max);
-       }
-       if (output_min > 0) {
-               _output_minimum = ChanCount(_default_type, output_min);
-       }
-       if (output_max >= 0) {
-               _output_maximum = ChanCount(_default_type, output_max);
-       }
+               DataType default_type,
+               ChanCount in_min, ChanCount in_max, ChanCount out_min, ChanCount out_max)
+       : SessionObject (s, name)
+       , AutomatableControls (s)
+       , _output_buffers (new BufferSet())
+       , _active (true)
+       , _default_type (default_type)
+       , _amp (new Amp(s, *this))
+       , _meter (new PeakMeter(s))
+       , _panner (new Panner(name, s))
+       , _input_minimum (ChanCount::ZERO)
+       , _input_maximum (ChanCount::INFINITE)
+       , _output_minimum (ChanCount::ZERO)
+       , _output_maximum (ChanCount::INFINITE)
+{
+       _input_minimum  = in_min;
+       _output_minimum = out_min;
+       _input_maximum  = in_max;
+       _output_maximum = out_max;
 
        _gain = 1.0;
-       _desired_gain = 1.0;
        pending_state_node = 0;
        no_panner_reset = false;
        _phase_invert = false;
@@ -143,8 +134,6 @@ IO::IO (Session& s, const string& name,
        _gain_control = boost::shared_ptr<GainControl>( new GainControl( X_("gaincontrol"), this, Evoral::Parameter(GainAutomation), gl ));
 
        add_control(_gain_control);
-
-       apply_gain_automation = false;
        
        {
                // IO::Meter is emitted from another thread so the
@@ -162,21 +151,18 @@ IO::IO (Session& s, const string& name,
 }
 
 IO::IO (Session& s, const XMLNode& node, DataType dt)
-       : SessionObject(s, "unnamed io"),
-         AutomatableControls (s),
-         _output_buffers (new BufferSet()),
-         _active(true),
-         _default_type (dt)
-{
-       _meter = new PeakMeter (_session);
-       _panner = 0;
+       : SessionObject(s, "unnamed io")
+       , AutomatableControls (s)
+       , _output_buffers (new BufferSet())
+       , _active(true)
+       , _default_type (dt)
+       , _amp (new Amp(s, *this))
+       , _meter(new PeakMeter (_session))
+{
        deferred_state = 0;
        no_panner_reset = false;
-       _desired_gain = 1.0;
        _gain = 1.0;
 
-       apply_gain_automation = false;
-       
        boost::shared_ptr<AutomationList> gl(
                        new AutomationList(Evoral::Parameter(GainAutomation)));
 
@@ -218,9 +204,6 @@ IO::~IO ()
        }
 
        m_meter_connection.disconnect();
-
-       delete _meter;
-       delete _panner;
 }
 
 void
@@ -241,12 +224,26 @@ IO::silence (nframes_t nframes)
 void
 IO::deliver_output (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes)
 {
-       // FIXME: type specific code doesn't actually need to be here, it will go away in time
+       // Attach output buffers to port buffers
+       output_buffers().attach_buffers (_outputs, nframes, _output_offset);
 
-       /* ********** AUDIO ********** */
+       // 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);
 
-       // Apply gain if gain automation isn't playing
-       if ( ! apply_gain_automation) {
+       // 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
 
@@ -254,44 +251,17 @@ IO::deliver_output (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame,
                        Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
 
                        if (dm.locked()) {
-                               dg = _desired_gain;
+                               dg = _gain_control->user_float();
                        }
 
                }
 
                if (dg != _gain || dg != 1.0) {
-                       Amp::run_in_place(bufs, nframes, _gain, dg, _phase_invert);
+                       Amp::apply_gain(output_buffers(), nframes, _gain, dg, _phase_invert);
                        _gain = dg;
                }
        }
        
-       /* do this so that any processing that comes after deliver_outputs()
-          can use the output buffers.
-       */
-
-       output_buffers().attach_buffers (_outputs, nframes, _output_offset);
-
-       // Use the panner to distribute audio to output port buffers
-
-       if (0 && _panner && _panner->npanners() && !_panner->bypassed()) {
-
-               /* blech .. we shouldn't be creating and tearing this down every process()
-                  cycle. XXX fix me to not waste cycles and do memory allocation etc.
-               */
-               
-               _panner->run_out_of_place(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 && _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);
-               }
-       }
 }
 
 void
@@ -302,9 +272,8 @@ IO::copy_to_outputs (BufferSet& bufs, DataType type, nframes_t nframes)
        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;
@@ -312,8 +281,7 @@ IO::copy_to_outputs (BufferSet& bufs, DataType type, nframes_t nframes)
                ++o;
        }
        
-       /* extra outputs get a copy of the last buffer */
-       
+       // 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);
@@ -894,14 +862,19 @@ IO::ensure_io (ChanCount in, ChanCount out, bool clear, void* src)
        bool out_changed    = false;
        bool need_pan_reset = false;
 
-       in = min (_input_maximum, in);
+       assert(in != ChanCount::INFINITE);
+       assert(out != ChanCount::INFINITE);
 
-       out = min (_output_maximum, out);
+       in = ChanCount::min (_input_maximum, in);
+       out = ChanCount::min (_output_maximum, out);
 
        if (in == n_inputs() && out == n_outputs() && !clear) {
                return 0;
        }
 
+       _configured_inputs = in;
+       _configured_outputs = out;
+
        {
                BLOCK_PROCESS_CALLBACK ();
                Glib::Mutex::Lock lm (io_lock);
@@ -943,9 +916,7 @@ IO::ensure_io (ChanCount in, ChanCount out, bool clear, void* src)
                        }
 
                        /* create any necessary new input ports */
-
                        while (n_inputs().get(*t) < nin) {
-
                                string portname = build_legal_port_name (*t, true);
 
                                try {
@@ -959,7 +930,7 @@ IO::ensure_io (ChanCount in, ChanCount out, bool clear, void* src)
                                        setup_peak_meters ();
                                        reset_panner ();
                                        /* pass it on */
-                                       throw AudioEngine::PortRegistrationFailure();
+                                       throw err;
                                }
 
                                _inputs.add (port);
@@ -983,7 +954,7 @@ IO::ensure_io (ChanCount in, ChanCount out, bool clear, void* src)
                                        setup_peak_meters ();
                                        reset_panner ();
                                        /* pass it on */
-                                       throw AudioEngine::PortRegistrationFailure ();
+                                       throw err;
                                }
 
                                _outputs.add (port);
@@ -1124,7 +1095,7 @@ IO::ensure_outputs (ChanCount count, bool clear, bool lockit, void* src)
 {
        bool changed = false;
 
-       if (_output_maximum < ChanCount::INFINITE) {
+       if (_output_maximum != ChanCount::INFINITE) {
                count = min (_output_maximum, count);
                if (count == n_outputs() && !clear) {
                        return 0;
@@ -1152,11 +1123,7 @@ IO::ensure_outputs (ChanCount count, bool clear, bool lockit, void* src)
 gain_t
 IO::effective_gain () const
 {
-       if (_gain_control->automation_playback()) {
-               return _gain_control->get_value();
-       } else {
-               return _desired_gain;
-       }
+       return _gain_control->get_value();
 }
 
 void
@@ -1305,16 +1272,10 @@ IO::state (bool full_state)
        snprintf (buf, sizeof(buf), "%2.12f", gain());
        node->add_property ("gain", buf);
 
-       /* To make backwards compatibility a bit easier, write ChanCount::INFINITE to the session file
-          as -1.
-       */
-
-       int const in_max = _input_maximum == ChanCount::INFINITE ? -1 : _input_maximum.get(_default_type);
-       int const out_max = _output_maximum == ChanCount::INFINITE ? -1 : _output_maximum.get(_default_type);
-
-       snprintf (buf, sizeof(buf)-1, "%d,%d,%d,%d", _input_minimum.get(_default_type), in_max, _output_minimum.get(_default_type), out_max);
-
-       node->add_property ("iolimits", buf);
+       /* port counts */
+       
+       node->add_child_nocopy(*n_inputs().state("Inputs"));
+       node->add_child_nocopy(*n_outputs().state("Outputs"));
 
        /* automation */
        
@@ -1358,9 +1319,9 @@ IO::set_state (const XMLNode& node)
                sscanf (prop->value().c_str(), "%d,%d,%d,%d",
                        &in_min, &in_max, &out_min, &out_max);
 
-               /* Correct for the difference between the way we write things to session files and the
-                  way things are described by ChanCount; see comments in io.h about what the different
-                  ChanCount values mean. */
+               // Legacy numbers:
+               // minimum == -1  =>  minimum == 0
+               // maximum == -1  =>  maximum == infinity
 
                if (in_min < 0) {
                        _input_minimum = ChanCount::ZERO;
@@ -1389,7 +1350,7 @@ IO::set_state (const XMLNode& node)
        
        if ((prop = node.property ("gain")) != 0) {
                set_gain (atof (prop->value().c_str()), this);
-               _gain = _desired_gain;
+               _gain = _gain_control->user_float();
        }
 
        if ((prop = node.property ("automation-state")) != 0 || (prop = node.property ("automation-style")) != 0) {
@@ -1400,16 +1361,16 @@ IO::set_state (const XMLNode& node)
 
                // Old school Panner.
                if ((*iter)->name() == "Panner") {
-                       if (_panner == 0) {
-                               _panner = new Panner (_name, _session);
+                       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 == 0) {
-                                       _panner = new Panner (_name, _session);
+                               if (!_panner) {
+                                       _panner = boost::shared_ptr<Panner>(new Panner (_name, _session));
                                }
                                _panner->set_state (**iter);
                        }
@@ -1427,6 +1388,8 @@ IO::set_state (const XMLNode& node)
                }
        }
 
+       get_port_counts (node);
+
        if (ports_legal) {
 
                if (create_ports (node)) {
@@ -1438,8 +1401,10 @@ IO::set_state (const XMLNode& node)
                port_legal_c = PortsLegal.connect (mem_fun (*this, &IO::ports_became_legal));
        }
 
-       if( !_panner )
-           _panner = new Panner( _name, _session );
+       if (!_panner) {
+               _panner = boost::shared_ptr<Panner>(new Panner (_name, _session));
+       }
+
        if (panners_legal) {
                reset_panner ();
        } else {
@@ -1573,6 +1538,7 @@ IO::ports_became_legal ()
 
        port_legal_c.disconnect ();
 
+       get_port_counts (*pending_state_node);
        ret = create_ports (*pending_state_node);
 
        if (connecting_legal) {
@@ -1676,48 +1642,64 @@ IO::find_possible_bundle (const string &desired_name, const string &default_name
 }
 
 int
-IO::create_ports (const XMLNode& node)
+IO::get_port_counts (const XMLNode& node)
 {
        XMLProperty const * prop;
-       uint32_t num_inputs = 0;
-       uint32_t num_outputs = 0;
+       XMLNodeConstIterator iter;
+       ChanCount num_inputs = n_inputs();
+       ChanCount num_outputs = n_outputs();
+
+       for (iter = node.children().begin(); iter != node.children().end(); ++iter) {
+               if ((*iter)->name() == X_("Inputs")) {
+                       num_inputs = ChanCount::max(num_inputs, ChanCount(**iter));
+               } else if ((*iter)->name() == X_("Outputs")) {
+                       num_outputs = ChanCount::max(num_inputs, ChanCount(**iter));
+               }
+       }
 
        if ((prop = node.property ("input-connection")) != 0) {
 
                boost::shared_ptr<Bundle> c = find_possible_bundle (prop->value(), _("in"), _("input"));
-       
                if (c) {
-                       num_inputs = c->nchannels ();
-               } else {
-                       num_inputs = 0;
+                       num_inputs = ChanCount::max(num_inputs, ChanCount(c->type(), c->nchannels()));
                }
 
        } else if ((prop = node.property ("inputs")) != 0) {
 
-               num_inputs = count (prop->value().begin(), prop->value().end(), '{');
+               num_inputs = ChanCount::max(num_inputs, ChanCount(_default_type,
+                               count (prop->value().begin(), prop->value().end(), '{')));
        }
        
        if ((prop = node.property ("output-connection")) != 0) {
 
-               boost::shared_ptr<Bundle> c = find_possible_bundle(prop->value(), _("out"), _("output"));
-
+               boost::shared_ptr<Bundle> c = find_possible_bundle (prop->value(), _("out"), _("output"));
                if (c) {
-                       num_outputs = c->nchannels ();
-               } else {
-                       num_outputs = 0;
+                       num_outputs = ChanCount::max(num_outputs, ChanCount(c->type(), c->nchannels()));
                }
                
        } else if ((prop = node.property ("outputs")) != 0) {
 
-               num_outputs = count (prop->value().begin(), prop->value().end(), '{');
+               num_outputs = ChanCount::max(num_outputs, ChanCount(_default_type,
+                               count (prop->value().begin(), prop->value().end(), '{')));
        }
+       
+       _configured_inputs = num_inputs;
+       _configured_outputs = num_outputs;
 
+       _input_minimum = ChanCount::min(_input_minimum, num_inputs);
+       _input_maximum = ChanCount::max(_input_maximum, num_inputs);
+       _output_minimum = ChanCount::min(_output_minimum, num_outputs);
+       _output_maximum = ChanCount::max(_output_maximum, num_outputs);
+       
+       return 0;
+}
+
+int
+IO::create_ports (const XMLNode& node)
+{
        no_panner_reset = true;
 
-       if (ensure_io (ChanCount (_default_type, num_inputs),
-                      ChanCount (_default_type, num_outputs),
-                      true, this)) {
-               
+       if (ensure_io (_input_minimum, _output_minimum, true, this)) {
                error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
                return -1;
        }
@@ -1730,7 +1712,6 @@ IO::create_ports (const XMLNode& node)
        return 0;
 }
 
-
 int
 IO::make_connections (const XMLNode& node)
 {
@@ -2282,8 +2263,8 @@ IO::meter ()
 void
 IO::clear_automation ()
 {
-       data().clear (); // clears gain automation
-       _panner->data().clear();
+       data().clear_controls (); // clears gain automation
+       _panner->data().clear_controls ();
 }
 
 void
@@ -2325,10 +2306,12 @@ IO::set_parameter_automation_state (Evoral::Parameter param, AutoState state)
 void
 IO::inc_gain (gain_t factor, void *src)
 {
-       if (_desired_gain == 0.0f)
+       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);
+       } else {
+               set_gain (desired_gain + (desired_gain * factor), src);
+       }
 }
 
 void
@@ -2350,7 +2333,7 @@ IO::set_gain (gain_t val, void *src)
 
        {
                Glib::Mutex::Lock dm (declick_lock);
-               _desired_gain = val;
+               _gain_control->set_float(val, false);
        }
 
        if (_session.transport_stopped()) {
@@ -2470,7 +2453,7 @@ IO::build_legal_port_name (DataType type, bool in)
        }
        
        snprintf (buf2, name_size+1, "%s %d", buf1, port_number);
-       
+
        return string (buf2);
 }
 
index 53ad91b9bfa94459de9612596c26b1b12cc58ec5..53fbda24c7fda7fd58277ecd2956db617a08149e 100644 (file)
@@ -43,12 +43,19 @@ using namespace std;
 using namespace ARDOUR;
 using namespace PBD;
 
-IOProcessor::IOProcessor (Session& s, const string& name, Placement p,
-                         int input_min, int input_max,
-                         int output_min, int output_max, 
-                         DataType dtype)
-       : Processor(s, name, p)
-       , _io (new IO(s, name, input_min, input_max, output_min, output_max, dtype))
+IOProcessor::IOProcessor (Session& s, const string& proc_name, const string io_name, DataType dtype)
+       : Processor(s, proc_name)
+       , _io (new IO(s, io_name != "" ? io_name : proc_name, dtype))
+{
+       _active = false;
+       _sort_key = 0;
+       _gui = 0;
+       _extra_xml = 0;
+}
+
+IOProcessor::IOProcessor (Session& s, IO* io, const string& proc_name, DataType dtype)
+       : Processor(s, proc_name)
+       , _io (io)
 {
        _active = false;
        _sort_key = 0;
index dd4a925877ee820dd976193696ee43f192024154..6afd395a56580ae2e3eea99aef2edd0f87d0d744 100644 (file)
@@ -41,6 +41,11 @@ LV2EventBuffer::LV2EventBuffer(size_t capacity)
                throw std::bad_alloc();
        }
 
+       if (capacity == 0) {
+               cerr << "ERROR: LV2 event buffer of size 0 created." << endl;
+               capacity = 1024;
+       }
+
 #ifdef NO_POSIX_MEMALIGN
        _data = (LV2_Event_Buffer*)malloc(sizeof(LV2_Event_Buffer) + capacity);
        int ret = (_data != NULL) ? 0 : -1;
@@ -139,7 +144,8 @@ LV2EventBuffer::append(uint32_t       frames,
 #endif
 
        /*cout << "Appending event type " << type << ", size " << size
-               << " @ " << frames << "." << subframes << endl;*/
+               << " @ " << frames << "." << subframes << endl;
+       cout << "Buffer capacity " << _data->capacity << ", size " << _data->size << endl;*/
 
        if (!lv2_event_write(&_iter, frames, subframes, type, size, data)) {
                cerr << "ERROR: Failed to write event." << endl;
index 5b4696b48c88cdf205d02b318db8e0249790053e..8000bd8e44e3487de6c1524d8fbd1b6ca2dda193 100644 (file)
@@ -268,8 +268,8 @@ LV2Plugin::get_state()
 
                if (parameter_is_input(i) && parameter_is_control(i)) {
                        child = new XMLNode("Port");
-                       snprintf(buf, sizeof(buf), "%u", i);
-                       child->add_property("number", string(buf));
+                       /*snprintf(buf, sizeof(buf), "%u", i);
+                       child->add_property("number", string(buf));*/
                        child->add_property("symbol", port_symbol(i));
                        snprintf(buf, sizeof(buf), "%+f", _shadow_data[i]);
                        child->add_property("value", string(buf));
@@ -343,8 +343,8 @@ LV2Plugin::set_state(const XMLNode& node)
        XMLProperty *prop;
        XMLNodeConstIterator iter;
        XMLNode *child;
-       const char *port;
-       const char *data;
+       const char *sym;
+       const char *value;
        uint32_t port_id;
        LocaleGuard lg (X_("POSIX"));
 
@@ -359,22 +359,29 @@ LV2Plugin::set_state(const XMLNode& node)
 
                child = *iter;
 
-               if ((prop = child->property("number")) != 0) {
-                       port = prop->value().c_str();
+               if ((prop = child->property("symbol")) != 0) {
+                       sym = prop->value().c_str();
                } else {
-                       warning << _("LV2: no lv2 port number") << endmsg;
+                       warning << _("LV2: port has no symbol, ignored") << endmsg;
+                       continue;
+               }
+
+               map<string,uint32_t>::iterator i = _port_indices.find(sym);
+               if (i != _port_indices.end()) {
+                       port_id = i->second;
+               } else {
+                       warning << _("LV2: port has unknown index, ignored") << endmsg;
                        continue;
                }
 
                if ((prop = child->property("value")) != 0) {
-                       data = prop->value().c_str();
+                       value = prop->value().c_str();
                } else {
-                       warning << _("LV2: no lv2 port data") << endmsg;
+                       warning << _("LV2: port has no value, ignored") << endmsg;
                        continue;
                }
 
-               sscanf (port, "%" PRIu32, &port_id);
-               set_parameter (port_id, atof(data));
+               set_parameter (port_id, atof(value));
        }
        
        latency_compute_run ();
@@ -462,9 +469,7 @@ LV2Plugin::connect_and_run (BufferSet& bufs,
                ChanMapping in_map, ChanMapping out_map,
                nframes_t nframes, nframes_t offset)
 {
-       cycles_t then, now;
-
-       then = get_cycles ();
+       cycles_t then = get_cycles ();
 
        uint32_t audio_in_index  = 0;
        uint32_t audio_out_index = 0;
@@ -474,25 +479,29 @@ LV2Plugin::connect_and_run (BufferSet& bufs,
                if (parameter_is_audio(port_index)) {
                        if (parameter_is_input(port_index)) {
                                const uint32_t buf_index = in_map.get(DataType::AUDIO, audio_in_index++);
+                               //cerr << port_index << " : " << " AUDIO IN " << buf_index << endl;
                                slv2_instance_connect_port(_instance, port_index,
                                                bufs.get_audio(buf_index).data(offset));
                        } else if (parameter_is_output(port_index)) {
                                const uint32_t buf_index = out_map.get(DataType::AUDIO, audio_out_index++);
+                               //cerr << port_index << " : " << " AUDIO OUT " << buf_index << endl;
                                slv2_instance_connect_port(_instance, port_index,
                                                bufs.get_audio(buf_index).data(offset));
                        }
                } else if (parameter_is_midi(port_index)) {
                        if (parameter_is_input(port_index)) {
                                const uint32_t buf_index = in_map.get(DataType::MIDI, midi_in_index++);
+                               //cerr << port_index << " : " << " MIDI IN " << buf_index << endl;
                                slv2_instance_connect_port(_instance, port_index,
                                                bufs.get_lv2_midi(true, buf_index).data());
                        } else if (parameter_is_output(port_index)) {
                                const uint32_t buf_index = out_map.get(DataType::MIDI, midi_out_index++);
+                               //cerr << port_index << " : " << " MIDI OUT " << buf_index << endl;
                                slv2_instance_connect_port(_instance, port_index,
                                                bufs.get_lv2_midi(false, buf_index).data());
                        }
                } else if (!parameter_is_control(port_index)) {
-                       std::cerr << "WARNING: Unknown LV2 port type, ignored" << endl;
+                       // Optional port (it'd better be if we've made it this far...)
                        slv2_instance_connect_port(_instance, port_index, NULL);
                }
        }
@@ -507,7 +516,7 @@ LV2Plugin::connect_and_run (BufferSet& bufs,
                }
        }
        
-       now = get_cycles ();
+       cycles_t now = get_cycles ();
        set_cycles ((uint32_t) (now - then));
 
        return 0;
@@ -683,7 +692,7 @@ LV2PluginInfo::discover (void* lv2_world)
        LV2World* world = (LV2World*)lv2_world;
        SLV2Plugins plugins = slv2_world_get_all_plugins(world->world);
 
-       cerr << "Discovered " << slv2_plugins_size (plugins) << " Lv2 plugins\n";
+       cerr << "LV2: Discovered " << slv2_plugins_size (plugins) << " plugins\n";
 
        for (unsigned i=0; i < slv2_plugins_size(plugins); ++i) {
                SLV2Plugin p = slv2_plugins_get_at(plugins, i);
index 30d4d1a1d889439178df169bfb3903808f5b5851..d8fee1ac475e2e663aa792be17b6acdfe9c3d59e 100644 (file)
@@ -27,6 +27,8 @@
 #include "ardour/audio_buffer.h"
 #include "ardour/runtime_functions.h"
 
+using namespace std;
+
 namespace ARDOUR {
 
 
@@ -38,44 +40,39 @@ namespace ARDOUR {
 void
 PeakMeter::run_in_place (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes)
 {
+       const uint32_t n_audio = min(_configured_input.n_audio(), bufs.count().n_audio());
+       const uint32_t n_midi  = min(_configured_input.n_midi(), bufs.count().n_midi());
+       
        uint32_t n = 0;
-       uint32_t meterable = std::min(bufs.count().n_total(), (uint32_t)_peak_power.size());
-       uint32_t limit = std::min (meterable, (uint32_t)bufs.count().n_midi());
-
-       // Meter what we have (midi)
-       for ( ; n < limit; ++n) {
-               float val = 0;
-               
-               // GUI needs a better MIDI meter, not much information can be
-               // expressed through peaks alone
-               for (MidiBuffer::iterator i = bufs.get_midi(n).begin(); i != bufs.get_midi(n).end(); ++i) {
-                       const Evoral::MIDIEvent<nframes_t> ev(*i, false);
+       
+       // Meter MIDI in to the first n_midi peaks
+       for (uint32_t i = 0; i < n_midi; ++i, ++n) {
+               float val = 0.0f;
+               for (MidiBuffer::iterator e = bufs.get_midi(i).begin(); e != bufs.get_midi(i).end(); ++e) {
+                       const Evoral::MIDIEvent<nframes_t> ev(*e, false);
                        if (ev.is_note_on()) {
                                const float this_vel = log(ev.buffer()[2] / 127.0 * (M_E*M_E-M_E) + M_E) - 1.0;
-                               //printf("V %d -> %f\n", (int)((Byte)ev.buffer[2]), this_vel);
-                               if (this_vel > val)
+                               if (this_vel > val) {
                                        val = this_vel;
+                               }
                        } else {
                                val += 1.0 / bufs.get_midi(n).capacity();
-                               if (val > 1.0)
+                               if (val > 1.0) {
                                        val = 1.0;
+                               }
                        }
                }
-                       
                _peak_power[n] = val;
-
        }
-       
-       limit = std::min (meterable, bufs.count().n_audio());
 
-       // Meter what we have (audio)
-       for ( ; n < limit; ++n) {
-               _peak_power[n] = compute_peak (bufs.get_audio(n).data(), nframes, _peak_power[n]); 
+       // Meter audio in to the rest of the peaks
+       for (uint32_t i = 0; i < n_audio; ++i, ++n) {
+               _peak_power[n] = compute_peak (bufs.get_audio(i).data(), nframes, _peak_power[n]); 
        }
 
        // Zero any excess peaks
-       for (size_t n = meterable; n < _peak_power.size(); ++n) {
-               _peak_power[n] = 0;
+       for (uint32_t i = n; i < _peak_power.size(); ++i) {
+               _peak_power[i] = 0.0f;
        }
 }
 
@@ -83,7 +80,7 @@ void
 PeakMeter::reset ()
 {
        for (size_t i = 0; i < _peak_power.size(); ++i) {
-               _peak_power[i] = 0;
+               _peak_power[i] = 0.0f;
        }
 }
 
@@ -95,14 +92,20 @@ PeakMeter::reset_max ()
        }
 }
 
+bool
+PeakMeter::can_support_io_configuration (const ChanCount& in, ChanCount& out) const
+{
+       out = in;
+       return true;
+}
+
 bool
 PeakMeter::configure_io (ChanCount in, ChanCount out)
 {
-       /* we're transparent no matter what.  fight the power. */
-       if (out != in) {
+       if (out != in) { // always 1:1
                return false;
        }
-
+       
        uint32_t limit = in.n_total();
        
        while (_peak_power.size() > limit) {
@@ -165,4 +168,18 @@ PeakMeter::meter ()
        }
 }
 
+XMLNode&
+PeakMeter::state (bool full_state)
+{
+       return get_state();
+}
+
+XMLNode&
+PeakMeter::get_state()
+{
+       XMLNode* node = new XMLNode(state_node_name);
+       node->add_property("type", "meter");
+       return *node;
+}
+
 } // namespace ARDOUR
index a0ef073c3ae431f5739150835a16c60468037f9b..f8d9f1eb580f903e8e626f7ff04127ca01939244 100644 (file)
@@ -139,8 +139,9 @@ MidiDiskstream::~MidiDiskstream ()
 void
 MidiDiskstream::non_realtime_locate (nframes_t position)
 {
-       assert(_write_source);
-       _write_source->set_timeline_position (position);
+       if (_write_source) {
+               _write_source->set_timeline_position (position);
+       }
        seek(position, false);
 }
 
@@ -156,7 +157,10 @@ MidiDiskstream::non_realtime_input_change ()
                }
 
                if (input_change_pending & ConfigurationChanged) {
-                       assert(_io->n_inputs() == _n_channels);
+                       if (_io->n_inputs().n_midi() != _n_channels.n_midi()) {
+                               error << "Can not feed IO " << _io->n_inputs()
+                                       << " with diskstream " << _n_channels << endl;
+                       }
                } 
 
                get_input_sources ();
@@ -547,8 +551,6 @@ MidiDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can_
 
        } else if (nominally_recording) {
 
-               cerr << "B" << endl;
-
                /* can't do actual capture yet - waiting for latency effects to finish before we start*/
 
                playback_distance = nframes;
index 39a5be9b5a1850279958ab997bdf2227e8b3c84f..b555c12934497c50302d071c2b24cc570292a87a 100644 (file)
 #include <sigc++/sigc++.h>
 #include <boost/shared_ptr.hpp>
 
+#include "pbd/compose.h"
 #include "pbd/file_utils.h"
+#include "pbd/error.h"
 
 #include "ardour/session.h"
 #include "ardour/session_directory.h"
 #include "ardour/midi_patch_manager.h"
 
+#include "i18n.h"
+
 using namespace std;
 using namespace sigc;
 using namespace ARDOUR;
@@ -55,12 +59,11 @@ MidiPatchManager::refresh()
        
        path path_to_patches = _session->session_directory().midi_patch_path();
        
-       cerr << "Path to patches: " << path_to_patches.to_string() << endl;
+       info << string_compose(_("looking for MIDI patches in %1"), path_to_patches.to_string()) << endmsg;
        
-       if(!exists(path_to_patches)) {
+       if (!exists(path_to_patches)) {
                return;
        }
-       cerr << "Path to patches: " << path_to_patches.to_string() << " exists" << endl;
        
        assert(is_directory(path_to_patches));
        
@@ -69,17 +72,15 @@ MidiPatchManager::refresh()
        
        find_matching_files_in_directory(path_to_patches, pattern, result);
 
-       cerr << "patchfiles result contains " << result.size() << " elements" << endl;
+       cerr << "Loading " << result.size() << " MIDI patches from " << path_to_patches.to_string() << endl;
        
-       for(vector<path>::iterator i = result.begin(); i != result.end(); ++i) {
-               cerr << "processing patchfile " << i->to_string() << endl;      
-               
+       for (vector<path>::iterator i = result.begin(); i != result.end(); ++i) {
                boost::shared_ptr<MIDINameDocument> document(new MIDINameDocument(i->to_string()));
-               for(MIDINameDocument::MasterDeviceNamesList::const_iterator device = 
-                         document->master_device_names_by_model().begin();
-                   device != document->master_device_names_by_model().end();
-                   ++device) {
-                       cerr << "got model " << device->first << endl;
+               for (MIDINameDocument::MasterDeviceNamesList::const_iterator device = 
+                                       document->master_device_names_by_model().begin();
+                               device != document->master_device_names_by_model().end();
+                               ++device) {
+                       //cerr << "got model " << device->first << endl;
                        // have access to the documents by model name
                        _documents[device->first] = document;
                        // build a list of all master devices from all documents
index b66d6c6b13545fa1d0ed79135e9502678bd7c4c5..59c19981a50c515b44846a559e7b712143449841 100644 (file)
@@ -139,7 +139,7 @@ MidiSource::midi_read (MidiRingBuffer<nframes_t>& dst, sframes_t source_start,
                Evoral::Sequence<double>::const_iterator& i = _model_iter;
                
                if (_last_read_end == 0 || start != _last_read_end) { // || !i.valid()) {
-                       cerr << "MidiSource seeking to " << start << " from " << _last_read_end << endl;
+                       //cerr << "MidiSource seeking to " << start << " from " << _last_read_end << endl;
                        for (i = _model->begin(); i != _model->end(); ++i) {
                                if (BEATS_TO_FRAMES(i->time()) >= start) {
                                        break;
index 1fe15a16bfc11caadc7260eb5d6f34f0391772fd..030e8ff905a8eea0cebbebed9372187178b7dfe7 100644 (file)
 #include "midi++/events.h"
 #include "evoral/midi_util.h"
 
-#include "ardour/midi_track.h"
-#include "ardour/midi_diskstream.h"
-#include "ardour/session.h"
+#include "ardour/amp.h"
+#include "ardour/buffer_set.h"
 #include "ardour/io_processor.h"
+#include "ardour/meter.h"
+#include "ardour/midi_diskstream.h"
+#include "ardour/midi_playlist.h"
 #include "ardour/midi_region.h"
 #include "ardour/midi_source.h"
-#include "ardour/route_group_specialized.h"
-#include "ardour/processor.h"
-#include "ardour/midi_playlist.h"
+#include "ardour/midi_track.h"
 #include "ardour/panner.h"
+#include "ardour/processor.h"
+#include "ardour/route_group_specialized.h"
+#include "ardour/session.h"
 #include "ardour/utils.h"
-#include "ardour/buffer_set.h"
-#include "ardour/meter.h"
-
 
 #include "i18n.h"
 
@@ -60,10 +60,6 @@ MidiTrack::MidiTrack (Session& sess, string name, Route::Flag flag, TrackMode mo
 
        set_input_minimum(ChanCount(DataType::MIDI, 1));
        set_input_maximum(ChanCount(DataType::MIDI, 1));
-       set_output_minimum(ChanCount(DataType::MIDI, 1));
-       set_output_maximum(ChanCount(DataType::MIDI, 1));
-
-       PortCountChanged(ChanCount(DataType::MIDI, 2)); /* EMIT SIGNAL */
 }
 
 MidiTrack::MidiTrack (Session& sess, const XMLNode& node)
@@ -75,10 +71,6 @@ MidiTrack::MidiTrack (Session& sess, const XMLNode& node)
        
        set_input_minimum(ChanCount(DataType::MIDI, 1));
        set_input_maximum(ChanCount(DataType::MIDI, 1));
-       set_output_minimum(ChanCount(DataType::MIDI, 1));
-       set_output_maximum(ChanCount(DataType::MIDI, 1));
-       
-       PortCountChanged(ChanCount(DataType::MIDI, 2)); /* EMIT SIGNAL */
 }
 
 MidiTrack::~MidiTrack ()
@@ -370,87 +362,6 @@ MidiTrack::set_state_part_two ()
        return;
 }      
 
-int 
-MidiTrack::no_roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, 
-                   bool session_state_changing, bool can_record, bool rec_monitors_input)
-{
-       if (n_outputs().n_midi() == 0) {
-               return 0;
-       }
-
-       if (!_active) {
-               silence (nframes);
-       }
-
-       if (session_state_changing) {
-
-               /* XXX is this safe to do against transport state changes? */
-
-               passthru_silence (start_frame, end_frame, nframes, 0, false);
-               return 0;
-       }
-
-       midi_diskstream()->check_record_status (start_frame, nframes, can_record);
-
-       bool send_silence;
-       
-       if (_have_internal_generator) {
-               /* since the instrument has no input streams,
-                  there is no reason to send any signal
-                  into the route.
-               */
-               send_silence = true;
-       } else {
-
-               if (Config->get_auto_input()) {
-                       if (Config->get_monitoring_model() == SoftwareMonitoring) {
-                               send_silence = false;
-                       } else {
-                               send_silence = true;
-                       }
-               } else {
-                       if (_diskstream->record_enabled()) {
-                               if (Config->get_monitoring_model() == SoftwareMonitoring) {
-                                       send_silence = false;
-                               } else {
-                                       send_silence = true;
-                               }
-                       } else {
-                               send_silence = true;
-                       }
-               }
-       }
-
-       apply_gain_automation = false;
-
-       if (send_silence) {
-               
-               /* if we're sending silence, but we want the meters to show levels for the signal,
-                  meter right here.
-               */
-               
-               if (_have_internal_generator) {
-                       passthru_silence (start_frame, end_frame, nframes, 0, true);
-               } else {
-                       if (_meter_point == MeterInput) {
-                               just_meter_input (start_frame, end_frame, nframes);
-                       }
-                       passthru_silence (start_frame, end_frame, nframes, 0, false);
-               }
-
-       } else {
-       
-               /* we're sending signal, but we may still want to meter the input. 
-                */
-
-               passthru (start_frame, end_frame, nframes, 0, (_meter_point == MeterInput));
-       }
-       
-       flush_outputs (nframes);
-
-       return 0;
-}
-
 int
 MidiTrack::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, int declick,
                 bool can_record, bool rec_monitors_input)
@@ -509,7 +420,7 @@ MidiTrack::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame,
                   at least potentially (depending on monitoring options)
                   */
 
-               passthru (start_frame, end_frame, nframes, 0, true);
+               passthru (start_frame, end_frame, nframes, 0);
 
        } else {
                /*
@@ -529,7 +440,7 @@ MidiTrack::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame,
                diskstream->get_playback(bufs.get_midi(0), start_frame, end_frame);
 
                process_output_buffers (bufs, start_frame, end_frame, nframes,
-                                       (!_session.get_record_enabled() || !Config->get_do_not_record_plugins()), declick, (_meter_point != MeterInput));
+                               (!_session.get_record_enabled() || !Config->get_do_not_record_plugins()), declick);
        
        }
 
@@ -538,68 +449,6 @@ MidiTrack::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame,
        return 0;
 }
 
-int
-MidiTrack::silent_roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame,  
-                       bool can_record, bool rec_monitors_input)
-{
-       if (n_outputs().n_midi() == 0 && _processors.empty()) {
-               return 0;
-       }
-
-       if (!_active) {
-               silence (nframes);
-               return 0;
-       }
-
-       _silent = true;
-       apply_gain_automation = false;
-
-       silence (nframes);
-
-       return midi_diskstream()->process (_session.transport_frame(), nframes, can_record, rec_monitors_input);
-}
-
-void
-MidiTrack::process_output_buffers (BufferSet& bufs,
-                                  nframes_t start_frame, nframes_t end_frame, 
-                                  nframes_t nframes, bool with_processors, int declick,
-                                  bool meter)
-{
-       /* There's no such thing as a MIDI bus for the time being.
-        * We'll do all the MIDI route work here for now, but the long-term goal is to have
-        * Route::process_output_buffers handle everything */
-       
-       if (meter && (_meter_point == MeterInput || _meter_point == MeterPreFader)) {
-               _meter->run_in_place(bufs, start_frame, end_frame, nframes);
-       }
-
-       // Run all processors
-       if (with_processors) {
-               Glib::RWLock::ReaderLock rm (_processor_lock, Glib::TRY_LOCK);
-               if (rm.locked()) {
-                       for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
-                               bufs.set_count(ChanCount::max(bufs.count(), (*i)->output_streams()));
-                               (*i)->run_in_place (bufs, start_frame, end_frame, nframes);
-                       }
-               } 
-       }
-       
-       if (meter && (_meter_point == MeterPostFader)) {
-               _meter->run_in_place(bufs, start_frame, end_frame, nframes);
-       }
-       
-       // Main output stage
-       if (muted()) {
-               IO::silence (nframes);
-       } else {
-
-               // Write 'automation' controllers (e.g. CC events from a UI slider)
-               write_controller_messages(bufs.get_midi(0), start_frame, end_frame, nframes);
-               
-               deliver_output(bufs, start_frame, end_frame, nframes);
-       }
-}
-
 void
 MidiTrack::write_controller_messages(MidiBuffer& output_buf, nframes_t start, nframes_t end, nframes_t nframes)
 {
index 23c87f0a2e84f33e88214ee80eb1a7901a7e20c8..83923a44d653db55a456c2ff9183623f8cd2d75c 100644 (file)
@@ -703,7 +703,7 @@ Multi2dPanner::set_state (const XMLNode& node)
 /*---------------------------------------------------------------------- */
 
 Panner::Panner (string name, Session& s)
-       : Processor(s, name, PostFader)
+       : Processor(s, name)
 {
        //set_name_old_auto (name);
        set_name (name);
@@ -1012,23 +1012,30 @@ Panner::set_automation_state (AutoState state)
 AutoState
 Panner::automation_state () const
 {
+       boost::shared_ptr<AutomationList> l;
        if (!empty()) {
-               return ((AutomationList*)_streampanners.front()->pan_control()->list().get())->automation_state ();
-       } else {
-               return Off;
+               boost::shared_ptr<AutomationControl> control = _streampanners.front()->pan_control();
+               if (control) {
+                       l = boost::dynamic_pointer_cast<AutomationList>(control->list());
+               }
        }
+
+       return l ? l->automation_state() : Off;
 }
 
 AutoStyle
 Panner::automation_style () const
 {
+       boost::shared_ptr<AutomationList> l;
        if (!empty()) {
-               return ((AutomationList*)_streampanners.front()->pan_control()->list().get())->automation_style ();
-       } else {
-               return Absolute;
+               boost::shared_ptr<AutomationControl> control = _streampanners.front()->pan_control();
+               if (control) {
+                       l = boost::dynamic_pointer_cast<AutomationList>(control->list());
+               }
        }
-}
 
+       return l ? l->automation_style() : Absolute;
+}
 
 struct PanPlugins {
     string name;
index bf67e33493157a7c473a8156cd35f7adf43e9586..41c65ba4fe387772b2485030ff941ff52cf7c3cb 100644 (file)
@@ -58,10 +58,10 @@ using namespace PBD;
 
 const string PluginInsert::port_automation_node_name = "PortAutomation";
 
-PluginInsert::PluginInsert (Session& s, boost::shared_ptr<Plugin> plug, Placement placement)
-       : Processor (s, plug->name(), placement),
-          _signal_analysis_collected_nframes(0),
-          _signal_analysis_collect_nframes_max(0)
+PluginInsert::PluginInsert (Session& s, boost::shared_ptr<Plugin> plug)
+       : Processor (s, plug->name())
+       , _signal_analysis_collected_nframes(0)
+       , _signal_analysis_collect_nframes_max(0)
 {
        /* the first is the master */
 
@@ -78,7 +78,7 @@ PluginInsert::PluginInsert (Session& s, boost::shared_ptr<Plugin> plug, Placemen
 }
 
 PluginInsert::PluginInsert (Session& s, const XMLNode& node)
-       : Processor (s, "unnamed plugin insert", PreFader),
+       : Processor (s, "unnamed plugin insert"),
           _signal_analysis_collected_nframes(0),
           _signal_analysis_collect_nframes_max(0)
 {
@@ -160,14 +160,10 @@ PluginInsert::output_streams() const
        ChanCount out = _plugins.front()->get_info()->n_outputs;
 
        if (out == ChanCount::INFINITE) {
-
                return _plugins.front()->output_streams ();
-
        } else {
-
                out.set_audio (out.n_audio() * _plugins.size());
                out.set_midi (out.n_midi() * _plugins.size());
-
                return out;
        }
 }
@@ -182,7 +178,6 @@ PluginInsert::input_streams() const
        } else {
                in.set_audio (in.n_audio() * _plugins.size());
                in.set_midi (in.n_midi() * _plugins.size());
-
                return in;
        }
 }
@@ -323,10 +318,10 @@ PluginInsert::connect_and_run (BufferSet& bufs, nframes_t nframes, nframes_t off
        }
 
        for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
-               (*i)->connect_and_run (bufs, in_map, out_map, nframes, offset);
+               (*i)->connect_and_run(bufs, in_map, out_map, nframes, offset);
                for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
-                       in_map.offset(*t, input_streams().get(*t));
-                       out_map.offset(*t, output_streams().get(*t));
+                       in_map.offset_to(*t, natural_input_streams().get(*t));
+                       out_map.offset_to(*t, natural_output_streams().get(*t));
                }
        }
 
@@ -562,61 +557,60 @@ PluginInsert::configure_io (ChanCount in, ChanCount out)
 bool
 PluginInsert::can_support_io_configuration (const ChanCount& in, ChanCount& out) const
 {
+       // Plugin has flexible I/O, so delegate to it
        if (_plugins.front()->reconfigurable_io()) {
-               /* plugin has flexible I/O, so delegate to it */
                return _plugins.front()->can_support_io_configuration (in, out);
        }
 
+       ChanCount inputs  = _plugins[0]->get_info()->n_inputs;
        ChanCount outputs = _plugins[0]->get_info()->n_outputs;
-       ChanCount inputs = _plugins[0]->get_info()->n_inputs;
 
-       if ((inputs.n_total() == 0)
-                       || (inputs.n_total() == 1 && outputs == inputs)
-                       || (inputs.n_total() == 1 && outputs == inputs
-                               && ((inputs.n_audio() == 0 && in.n_audio() == 0)
-                                       || (inputs.n_midi() == 0 && in.n_midi() == 0)))
-                       || (inputs == in)) {
+       // Plugin inputs match requested inputs exactly
+       if (inputs == in) {
                out = outputs;
                return true;
        }
 
-       bool can_replicate = true;
-
-       /* if number of inputs is a factor of the requested input
-          configuration for every type, we can replicate.
-       */
+       // See if replication is possible
+       // We can replicate if there exists a single factor f such that, for every type,
+       // the number of plugin inputs * f = the requested number of inputs
+       uint32_t f             = 0;
+       bool     can_replicate = true;
        for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
-               if (inputs.get(*t) >= in.get(*t) || (inputs.get(*t) % in.get(*t) != 0)) {
+               // No inputs of this type
+               if (inputs.get(*t) == 0 && in.get(*t) == 0) {
+                       continue;
+
+               // Plugin has more inputs than requested, can not replicate
+               } else if (inputs.get(*t) >= in.get(*t)) {
                        can_replicate = false;
                        break;
+               
+               // Plugin inputs is not a factor of requested inputs, can not replicate
+               } else if (inputs.get(*t) == 0 || in.get(*t) % inputs.get(*t) != 0) {
+                       can_replicate = false;
+                       break;
+               
+               // Potential factor not set yet
+               } else if (f == 0) {
+                       f = in.get(*t) / inputs.get(*t);;
                }
-       }
 
-       if (!can_replicate || (in.n_total() % inputs.n_total() != 0)) {
-               return false;
+               // Factor for this type does not match another type, can not replicate
+               if (f != (in.get(*t) / inputs.get(*t))) {
+                       can_replicate = false;
+                       break;
+               }
        }
 
-       if (inputs.n_total() == 0) {
-               /* instrument plugin, always legal, but throws away any existing streams */
-               out = outputs;
-       } else if (inputs.n_total() == 1 && outputs == inputs
-                       && ((inputs.n_audio() == 0 && in.n_audio() == 0)
-                           || (inputs.n_midi() == 0 && in.n_midi() == 0))) {
-               /* mono, single-typed plugin, replicate as needed to match in */
-               out = in;
-       } else if (inputs == in) {
-               /* exact match */
-               out = outputs;
-       } else {
-               /* replicate - note that we've already verified that
-                  the replication count is constant across all data types.
-               */
+       if (can_replicate) {
                for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
-                       out.set (*t, outputs.get(*t) * (in.get(*t) / inputs.get(*t)));
+                       out.set (*t, outputs.get(*t) * f);
                }
+               return true;
+       } else {
+               return false;
        }
-               
-       return true;
 }
 
 /* Number of plugin instances required to support a given channel configuration.
@@ -798,7 +792,7 @@ PluginInsert::set_state(const XMLNode& node)
                
                cnodes = (*niter)->children ("Port");
                
-               for(iter = cnodes.begin(); iter != cnodes.end(); ++iter){
+               for (iter = cnodes.begin(); iter != cnodes.end(); ++iter) {
                        
                        child = *iter;
                        
index ce7a94a517249cfb0fffe47579e50aeb1a4fa942..0b5b9276f1364aaf759f4378aa6fda9d9239cf45 100644 (file)
@@ -127,7 +127,7 @@ PluginManager::PluginManager ()
        } 
 
 #ifdef HAVE_SLV2
-       cerr << "Creating a new lv2 world\n";
+       cerr << "LV2: Creating world" << endl;
        _lv2_world = new LV2World();
 #endif
 
index 9ddd3e7188179c57c4d6d170c332ca9ac5435f22..fb1856dbdd10293ec867cef3c0205a60e9e576d2 100644 (file)
@@ -446,7 +446,7 @@ msgid "automation list: no y-coordinate stored for control point (point ignored)
 msgstr "λίστα αυτοματισμού: καμία y-συντεταγμένη αποθηκευμένη για σημείο ελέγχου (το σημείο αγνοήθηκε)"
 
 #: libs/ardour/configuration.cc:80
-msgid "loading system configuration file %1"
+msgid "Loading system configuration file %1"
 msgstr "Ανάκληση αρχείου ρυθμίσεων συστήματος %1"
 
 #: libs/ardour/configuration.cc:83
@@ -458,7 +458,7 @@ msgid "Ardour: system configuration file \"%1\" not loaded successfully."
 msgstr "Ardour: το αρχείο διαρρυθμίσεως του συστήματος \"%1\" δεν φορτώθηκε επιτυχώς."
 
 #: libs/ardour/configuration.cc:105
-msgid "loading user configuration file %1"
+msgid "Loading user configuration file %1"
 msgstr "Ανάκληση αρχείου ρυθμίσεων χρήστη %1"
 
 #: libs/ardour/configuration.cc:108
index 2ce02827bd83eab31ae68f1dcda71e4a2bbcc03d..61ec7853edff2de105135b907af5b2a3b4e7f359 100644 (file)
@@ -467,7 +467,7 @@ msgstr ""
 
 #: libs/ardour/configuration.cc:80
 #, fuzzy
-msgid "loading system configuration file %1"
+msgid "Loading system configuration file %1"
 msgstr ""
 "Ardour: impossibile leggere il file di configurazione di sistema \"%1\""
 
@@ -484,7 +484,7 @@ msgstr ""
 
 #: libs/ardour/configuration.cc:105
 #, fuzzy
-msgid "loading user configuration file %1"
+msgid "Loading user configuration file %1"
 msgstr "Ardour: impossibile la lettura del file di configurazione \"%1\""
 
 #: libs/ardour/configuration.cc:108
index f2bdc8d91a2e1da171069bcaf3ca4208324c7434..c189796689260360cf424acc52dd051c6b7fdf82 100644 (file)
@@ -365,7 +365,7 @@ msgid "AutomationList: passed XML node called %1, not \"AutomationList\" - ignor
 msgstr ""
 
 #: libs/ardour/configuration.cc:97
-msgid "loading system configuration file %1"
+msgid "Loading system configuration file %1"
 msgstr ""
 
 #: libs/ardour/configuration.cc:100
@@ -381,7 +381,7 @@ msgid "your system Ardour configuration file is empty. This probably means that
 msgstr ""
 
 #: libs/ardour/configuration.cc:131
-msgid "loading user configuration file %1"
+msgid "Loading user configuration file %1"
 msgstr ""
 
 #: libs/ardour/configuration.cc:134
index aeeb1bf547783c740797c217463d328a7df7e859..c1c4850ce27d0a05f10485cd441825d43cdde8be 100644 (file)
@@ -430,7 +430,7 @@ msgstr ""
 
 #: libs/ardour/configuration.cc:80
 #, fuzzy
-msgid "loading system configuration file %1"
+msgid "Loading system configuration file %1"
 msgstr "Ardour: �� ������� ��������� ���� ������������ ��������� \"%1\""
 
 #: libs/ardour/configuration.cc:83
@@ -443,7 +443,7 @@ msgstr "Ardour: 
 
 #: libs/ardour/configuration.cc:105
 #, fuzzy
-msgid "loading user configuration file %1"
+msgid "Loading user configuration file %1"
 msgstr "Ardour: �� ������� ��������� ���� ������������ ������������ \"%1\""
 
 #: libs/ardour/configuration.cc:108
index 58be548f8e667cb473604edb6c3c399f743a8828..19fe623de9576d14cb78dc9e4bf8486af0809048 100644 (file)
@@ -423,7 +423,7 @@ msgid ""
 msgstr ""
 
 #: libs/ardour/configuration.cc:87
-msgid "loading system configuration file %1"
+msgid "Loading system configuration file %1"
 msgstr ""
 
 #: libs/ardour/configuration.cc:90
@@ -435,7 +435,7 @@ msgid "Ardour: system configuration file \"%1\" not loaded successfully."
 msgstr ""
 
 #: libs/ardour/configuration.cc:111
-msgid "loading user configuration file %1"
+msgid "Loading user configuration file %1"
 msgstr ""
 
 #: libs/ardour/configuration.cc:114
index d5021026de593cbaa11d378059f20c96ee7eb92e..ebe31a1fde32a3dd808150284b96442ef5ed5dc3 100644 (file)
@@ -210,6 +210,7 @@ Port::total_latency () const
 int
 Port::reestablish ()
 {
+       cerr << "RE-REGISTER: " << _name.c_str() << endl;
        _jack_port = jack_port_register (_engine->jack(), _name.c_str(), type().to_jack_type(), _flags, 0);
 
        if (_jack_port == 0) {
index 8f53be853447aa94b39b7e6a7ee242472089bde9..606b055dab8e61413cbc6abd0ee3fb23f04ad783 100644 (file)
@@ -40,29 +40,15 @@ using namespace std;
 using namespace ARDOUR;
 using namespace PBD;
 
-PortInsert::PortInsert (Session& s, Placement p)
-       : IOProcessor (s, string_compose (_("insert %1"), (bitslot = s.next_insert_id()) + 1), p, 1, -1, 1, -1)
+PortInsert::PortInsert (Session& s)
+       : IOProcessor (s, string_compose (_("insert %1"), (bitslot = s.next_insert_id()) + 1), "")
 {
        init ();
        ProcessorCreated (this); /* EMIT SIGNAL */
 }
 
-void
-PortInsert::init ()
-{
-       if (_io->add_input_port ("", this)) {
-               error << _("PortInsert: cannot add input port") << endmsg;
-               throw failed_constructor();
-       }
-       
-       if (_io->add_output_port ("", this)) {
-               error << _("PortInsert: cannot add output port") << endmsg;
-               throw failed_constructor();
-       }
-}
-
 PortInsert::PortInsert (Session& s, const XMLNode& node)
-       : IOProcessor (s, "unnamed port insert", PreFader)
+       : IOProcessor (s, "unnamed port insert")
 {
        if (set_state (node)) {
                throw failed_constructor();
@@ -76,6 +62,15 @@ 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, nframes_t start_frame, nframes_t end_frame, nframes_t nframes)
 {
@@ -180,10 +175,10 @@ PortInsert::configure_io (ChanCount in, ChanCount out)
           to the number of input ports we need.
        */
 
-       _io->set_output_maximum (in);
+       /*_io->set_output_maximum (in);
        _io->set_output_minimum (in);
        _io->set_input_maximum (out);
-       _io->set_input_minimum (out);
+       _io->set_input_minimum (out);*/
 
        if (_io->ensure_io (out, in, false, this) != 0) {
                return false;
index 63848e8c407fbd2ac952293d505fa275c2e4727a..b48b0aebb0d6eeb797dcb5023a8a94611b39648e 100644 (file)
@@ -58,13 +58,12 @@ sigc::signal<void,Processor*> Processor::ProcessorCreated;
 // Always saved as Processor, but may be IOProcessor or Send in legacy sessions
 const string Processor::state_node_name = "Processor";
 
-Processor::Processor(Session& session, const string& name, Placement p)
+Processor::Processor(Session& session, const string& name)
        : SessionObject(session, name)
        , AutomatableControls(session)
        , _active(false)
        , _next_ab_is_active(false)
        , _configured(false)
-       , _placement(p)
        , _gui(0)
 {
 }
@@ -75,15 +74,6 @@ Processor::set_sort_key (uint32_t key)
        _sort_key = key;
 }
        
-void
-Processor::set_placement (Placement p)
-{
-       if (_placement != p) {
-               _placement = p;
-                PlacementChanged (); /* EMIT SIGNAL */
-       }
-}
-
 XMLNode&
 Processor::get_state (void)
 {
@@ -120,26 +110,28 @@ Processor::state (bool full_state)
 
        node->add_property("name", _name);
        node->add_property("active", active() ? "yes" : "no");  
-       node->add_property("placement", enum_2_string (_placement));
 
        if (_extra_xml){
                node->add_child_copy (*_extra_xml);
        }
        
        if (full_state) {
-
                XMLNode& automation = Automatable::get_automation_state(); 
-               
-               for (set<Evoral::Parameter>::iterator x = _visible_controls.begin(); x != _visible_controls.end(); ++x) {
-                       if (x != _visible_controls.begin()) {
-                               sstr << ' ';
+               if (!automation.children().empty()
+                               || !automation.properties().empty()
+                               || !_visible_controls.empty()) {
+
+                       for (set<Evoral::Parameter>::iterator x = _visible_controls.begin();
+                                       x != _visible_controls.end(); ++x) {
+                               if (x != _visible_controls.begin()) {
+                                       sstr << ' ';
+                               }
+                               sstr << *x;
                        }
-                       sstr << *x;
-               }
-
-               automation.add_property ("visible", sstr.str());
 
-               node->add_child_nocopy (automation);
+                       automation.add_property ("visible", sstr.str());
+                       node->add_child_nocopy (automation);
+               }
        }
 
        return *node;
@@ -164,7 +156,6 @@ Processor::set_state (const XMLNode& node)
 
                if ((*niter)->name() == X_("Automation")) {
 
-
                        XMLProperty *prop;
                        
                        if ((prop = (*niter)->property ("path")) != 0) {
@@ -203,7 +194,8 @@ Processor::set_state (const XMLNode& node)
        }
 
        if ((prop = node.property ("active")) == 0) {
-               warning << _("XML node describing a processor is missing the `active' field, trying legacy active flag from child node") << endmsg;
+               warning << _("XML node describing a processor is missing the `active' field,"
+                          "trying legacy active flag from child node") << endmsg;
                if (legacy_active) {
                        prop = legacy_active;
                } else {
@@ -217,31 +209,6 @@ Processor::set_state (const XMLNode& node)
                ActiveChanged (); /* EMIT_SIGNAL */
        }       
 
-       if ((prop = node.property ("placement")) == 0) {
-               warning << _("XML node describing a processor is missing the `placement' field, trying legacy placement flag from child node") << endmsg;
-               if (legacy_placement) {
-                       prop = legacy_placement; 
-               } else {
-                       error << _("No child node with placement property") << endmsg;
-                       return -1;
-               }
-       }
-
-       /* hack to handle older sessions before we only used EnumWriter */
-
-       string pstr;
-
-       if (prop->value() == "pre") {
-               pstr = "PreFader";
-       } else if (prop->value() == "post") {
-               pstr = "PostFader";
-       } else {
-               pstr = prop->value();
-       }
-
-       Placement p = Placement (string_2_enum (pstr, p));
-       set_placement (p);
-
        return 0;
 }
 
index 6179af502868bdc4d3429afd0f1034a98a639cdf..931ae9a99625a42bb2fc4097e0e57d7a4b5f4872 100644 (file)
 
 #include "evoral/Curve.hpp"
 
-#include "ardour/timestamps.h"
+#include "ardour/amp.h"
+#include "ardour/audio_port.h"
 #include "ardour/audioengine.h"
-#include "ardour/route.h"
 #include "ardour/buffer.h"
-#include "ardour/processor.h"
-#include "ardour/plugin_insert.h"
-#include "ardour/port_insert.h"
-#include "ardour/send.h"
-#include "ardour/session.h"
-#include "ardour/utils.h"
+#include "ardour/buffer_set.h"
 #include "ardour/configuration.h"
+#include "ardour/control_outputs.h"
 #include "ardour/cycle_timer.h"
-#include "ardour/route_group.h"
-#include "ardour/port.h"
-#include "ardour/audio_port.h"
-#include "ardour/ladspa_plugin.h"
-#include "ardour/panner.h"
 #include "ardour/dB.h"
-#include "ardour/amp.h"
+#include "ardour/ladspa_plugin.h"
 #include "ardour/meter.h"
-#include "ardour/buffer_set.h"
 #include "ardour/mix.h"
+#include "ardour/panner.h"
+#include "ardour/plugin_insert.h"
+#include "ardour/port.h"
+#include "ardour/port_insert.h"
+#include "ardour/processor.h"
 #include "ardour/profile.h"
+#include "ardour/route.h"
+#include "ardour/route_group.h"
+#include "ardour/send.h"
+#include "ardour/session.h"
+#include "ardour/timestamps.h"
+#include "ardour/utils.h"
 
 #include "i18n.h"
 
@@ -62,21 +63,22 @@ using namespace PBD;
 uint32_t Route::order_key_cnt = 0;
 sigc::signal<void,const char*> Route::SyncOrderKeys;
 
-Route::Route (Session& sess, string name,
-               int in_min, int in_max, int out_min, int out_max,
-               Flag flg, DataType default_type)
-       : IO (sess, name, in_min, in_max, out_min, out_max, default_type)
+Route::Route (Session& sess, string name, Flag flg,
+               DataType default_type, ChanCount in, ChanCount out)
+       : IO (sess, name, default_type, in, ChanCount::INFINITE, out, ChanCount::INFINITE)
        , _flags (flg)
        , _solo_control (new ToggleControllable (X_("solo"), *this, ToggleControllable::SoloControl))
        , _mute_control (new ToggleControllable (X_("mute"), *this, ToggleControllable::MuteControl))
 {
+       _configured_inputs = in;
+       _configured_outputs = out;
        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))
+       , _solo_control (new ToggleControllable (X_("solo"), *this, ToggleControllable::SoloControl))
+       , _mute_control (new ToggleControllable (X_("mute"), *this, ToggleControllable::MuteControl))
 {
        init ();
        _set_state (node, false);
@@ -104,6 +106,7 @@ Route::init ()
        _declickable = false;
        _pending_declick = true;
        _remote_control_id = 0;
+       _in_configure_processors = false;
        
        _edit_group = 0;
        _mix_group = 0;
@@ -118,10 +121,13 @@ Route::init ()
        mute_gain = 1.0;
        desired_mute_gain = 1.0;
 
-       _control_outs = 0;
-
        input_changed.connect (mem_fun (this, &Route::input_change_handler));
        output_changed.connect (mem_fun (this, &Route::output_change_handler));
+
+       _amp->set_sort_key (0);
+       _meter->set_sort_key (1);
+       add_processor (_amp, NULL);
+       add_processor (_meter, NULL);
 }
 
 Route::~Route ()
@@ -132,8 +138,6 @@ Route::~Route ()
        for (OrderKeys::iterator i = order_keys.begin(); i != order_keys.end(); ++i) {
                free ((void*)(i->first));
        }
-
-       delete _control_outs;
 }
 
 void
@@ -217,7 +221,6 @@ Route::ensure_track_or_route_name(string name, Session &session)
        return newname;
 }
 
-
 void
 Route::inc_gain (gain_t fraction, void *src)
 {
@@ -291,21 +294,15 @@ Route::set_gain (gain_t val, void *src)
  */
 void
 Route::process_output_buffers (BufferSet& bufs,
-                              nframes_t start_frame, nframes_t end_frame, nframes_t nframes,
-                              bool with_processors, int declick, bool meter)
+               nframes_t start_frame, nframes_t end_frame, nframes_t nframes,
+               bool with_processors, int declick)
 {
-       // This is definitely very audio-only for now
-       assert(_default_type == DataType::AUDIO);
-       
        ProcessorList::iterator i;
-       bool post_fader_work = false;
        bool mute_declick_applied = false;
        gain_t dmg, dsg, dg;
-       IO *co;
-       bool mute_audible;
-       bool solo_audible;
        bool no_monitor;
-       gain_t* gab = _session.gain_automation_buffer();
+
+       bufs.is_silent(false);
 
        switch (Config->get_monitoring_model()) {
        case HardwareMonitoring:
@@ -317,96 +314,89 @@ Route::process_output_buffers (BufferSet& bufs,
        }
 
        declick = _pending_declick;
-
-       {
-               Glib::Mutex::Lock cm (_control_outs_lock, Glib::TRY_LOCK);
-               
-               if (cm.locked()) {
-                       co = _control_outs;
-               } else {
-                       co = 0;
-               }
-       }
        
+       const bool recording_without_monitoring = no_monitor && record_enabled()
+                       && (!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 = _desired_gain;
+                       dg = _gain_control->user_float();
                } else {
                        dmg = mute_gain;
                        dsg = solo_gain;
                        dg = _gain;
                }
        }
+       
+       // 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<ControlOutputs> co = _control_outs;
+       if (co) {
+               // deliver control outputs unless we're ...
+               co->deliver (!(
+                               dsg == 0 || // muted by solo of another track
+                               (dmg == 0 && _mute_affects_control_outs) || // or muted by mute of this track
+                               !recording_without_monitoring )); // or rec-enabled w/o s/w monitoring 
+       }
+       
 
        /* -------------------------------------------------------------------------------------------
           GLOBAL DECLICK (for transport changes etc.)
           ----------------------------------------------------------------------------------------- */
 
        if (declick > 0) {
-               Amp::run_in_place (bufs, nframes, 0.0, 1.0, false);
+               Amp::apply_gain (bufs, nframes, 0.0, 1.0, false);
                _pending_declick = 0;
        } else if (declick < 0) {
-               Amp::run_in_place (bufs, nframes, 1.0, 0.0, false);
+               Amp::apply_gain (bufs, nframes, 1.0, 0.0, false);
                _pending_declick = 0;
-       } else {
-
-               /* no global declick */
-
+       } else { // no global declick
                if (solo_gain != dsg) {
-                       Amp::run_in_place (bufs, nframes, solo_gain, dsg, false);
+                       Amp::apply_gain (bufs, nframes, solo_gain, dsg, false);
                        solo_gain = dsg;
                }
        }
 
 
        /* -------------------------------------------------------------------------------------------
-          INPUT METERING & MONITORING
+          PRE-FADER MUTING
           ----------------------------------------------------------------------------------------- */
 
-       if (meter && (_meter_point == MeterInput)) {
-               _meter->run_in_place(bufs, start_frame, end_frame, nframes);
-       }
-
        if (!_soloed && _mute_affects_pre_fader && (mute_gain != dmg)) {
-               Amp::run_in_place (bufs, nframes, mute_gain, dmg, false);
+               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 ((_meter_point == MeterInput) && co) {
-               
-               solo_audible = dsg > 0;
-               mute_audible = dmg > 0;// || !_mute_affects_pre_fader;
-               
-               if (    // muted by solo of another track
-                       
-                       !solo_audible || 
-                       
-                       // muted by mute of this track 
-                       
-                       !mute_audible ||
-                       
-                       // rec-enabled but not s/w monitoring 
-                       
-                       // TODO: this is probably wrong
-
-                       ( no_monitor && record_enabled()
-                               && (!Config->get_auto_input() || _session.actively_recording()) )
-
-                       ) {
-                       
-                       co->silence (nframes);
-                       
-               } else {
-
-                       co->deliver_output (bufs, start_frame, end_frame, nframes);
-                       
-               } 
-       } 
 
        /* -------------------------------------------------------------------------------------------
           DENORMAL CONTROL
@@ -423,616 +413,78 @@ Route::process_output_buffers (BufferSet& bufs,
                }
        }
 
-       /* -------------------------------------------------------------------------------------------
-          PRE-FADER REDIRECTS
-          ----------------------------------------------------------------------------------------- */
-
-       if (with_processors) {
-               Glib::RWLock::ReaderLock rm (_processor_lock, Glib::TRY_LOCK);
-               if (rm.locked()) {
-                       if (mute_gain > 0 || !_mute_affects_pre_fader) {
-                               for (i = _processors.begin(); i != _processors.end(); ++i) {
-                                       switch ((*i)->placement()) {
-                                       case PreFader:
-                                               (*i)->run_in_place (bufs, start_frame, end_frame, nframes);
-                                               break;
-                                       case PostFader:
-                                               post_fader_work = true;
-                                               break;
-                                       }
-                               }
-                       } else {
-                               for (i = _processors.begin(); i != _processors.end(); ++i) {
-                                       switch ((*i)->placement()) {
-                                       case PreFader:
-                                               (*i)->silence (nframes);
-                                               break;
-                                       case PostFader:
-                                               post_fader_work = true;
-                                               break;
-                                       }
-                               }
-                       }
-               } 
-       }
-
-       /* When we entered this method, the number of bufs was set by n_process_buffers(), so
-        * it may be larger than required.  Consider e.g a mono track with two redirects A and B.
-        * If A has one input and three outputs, and B three inputs and one output, n_process_buffers()
-        * will be 3.  In this case, now we've done pre-fader redirects, we can reset the number of bufs.
-        */
-       bufs.set_count (pre_fader_streams());
-       
-       if (!_soloed && (mute_gain != dmg) && !mute_declick_applied && _mute_affects_post_fader) {
-               Amp::run_in_place (bufs, nframes, mute_gain, dmg, false);
-               mute_gain = dmg;
-               mute_declick_applied = true;
-       }
 
        /* -------------------------------------------------------------------------------------------
-          PRE-FADER METERING & MONITORING
+          PROCESSORS (including Amp (fader) and Meter)
           ----------------------------------------------------------------------------------------- */
 
-       if (meter && (_meter_point == MeterPreFader)) {
-               _meter->run_in_place(bufs, start_frame, end_frame, nframes);
-       }
-
-       
-       if ((_meter_point == MeterPreFader) && co) {
-               
-               solo_audible = dsg > 0;
-               mute_audible = dmg > 0 || !_mute_affects_pre_fader;
-               
-               if ( // muted by solo of another track
-                       
-                       !solo_audible || 
-                       
-                       // muted by mute of this track 
-                       
-                       !mute_audible ||
-                       
-                       // rec-enabled but not s/w monitoring 
-                       
-                       ( no_monitor && record_enabled()
-                               && (!Config->get_auto_input() || _session.actively_recording()) )
-
-                       ) {
-                       
-                       co->silence (nframes);
-                       
-               } else {
-
-                       co->deliver_output (bufs, start_frame, end_frame, nframes);
-               } 
-       } 
-       
-       /* -------------------------------------------------------------------------------------------
-          GAIN STAGE
-          ----------------------------------------------------------------------------------------- */
-
-       /* if not recording or recording and requiring any monitor signal, then apply gain */
-
-       if ( // not recording 
-
-               !(record_enabled() && _session.actively_recording()) || 
-               
-               // OR recording 
-               
-               // AND software monitoring required
-
-               Config->get_monitoring_model() == SoftwareMonitoring) { 
-               
-               if (apply_gain_automation) {
-                       
-                       if (_phase_invert) {
-                               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];
-                                       }
-                               }
-                       } 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] *= gab[nx];
-                                       }
-                               }
-                       }
-                       
-                       if (apply_gain_automation && _session.transport_rolling() && nframes > 0) {
-                               _effective_gain = gab[nframes-1];
-                       }
-                       
-               } else {
-                       
-                       /* manual (scalar) gain */
-                       
-                       if (_gain != dg) {
-                               
-                               Amp::run_in_place (bufs, nframes, _gain, dg, _phase_invert);
-                               _gain = dg;
-                               
-                       } else if (_gain != 0 && (_phase_invert || _gain != 1.0)) {
-                               
-                               /* 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_t this_gain;
-                               
-                               if (_phase_invert) {
-                                       this_gain = -_gain;
-                               } else {
-                                       this_gain = _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);
-                               }
-
-                       } else if (_gain == 0) {
-                               for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i) {
-                                       i->clear();
-                               }
-                       }
-               }
-
-       } else {
-
-               /* actively recording, no monitoring required; leave buffers as-is to save CPU cycles */
-
-       }
-
-       /* -------------------------------------------------------------------------------------------
-          POST-FADER REDIRECTS
-          ----------------------------------------------------------------------------------------- */
-
-       /* note that post_fader_work cannot be true unless with_processors was also true,
-          so don't test both
-       */
-
-       if (post_fader_work) {
-
+       if (with_processors) {
                Glib::RWLock::ReaderLock rm (_processor_lock, Glib::TRY_LOCK);
                if (rm.locked()) {
-                       if (mute_gain > 0 || !_mute_affects_post_fader) {
+                       //if (!bufs.is_silent()) {
                                for (i = _processors.begin(); i != _processors.end(); ++i) {
-                                       switch ((*i)->placement()) {
-                                       case PreFader:
-                                               break;
-                                       case PostFader:
-                                               (*i)->run_in_place (bufs, start_frame, end_frame, nframes);
-                                               break;
-                                       }
+                                       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()));
                                }
-                       } else {
+                       /*} else {
                                for (i = _processors.begin(); i != _processors.end(); ++i) {
-                                       switch ((*i)->placement()) {
-                                       case PreFader:
-                                               break;
-                                       case PostFader:
-                                               (*i)->silence (nframes);
-                                               break;
-                                       }
+                                       (*i)->silence (nframes);
+                                       bufs.set_count(ChanCount::max(bufs.count(), (*i)->output_streams()));
                                }
-                       }
-               } 
-       }
-
-       if (!_soloed && (mute_gain != dmg) && !mute_declick_applied && _mute_affects_control_outs) {
-               Amp::run_in_place (bufs, nframes, mute_gain, dmg, false);
-               mute_gain = dmg;
-               mute_declick_applied = true;
-       }
-
-       /* -------------------------------------------------------------------------------------------
-          CONTROL OUTPUT STAGE
-          ----------------------------------------------------------------------------------------- */
-
-       if ((_meter_point == MeterPostFader) && co) {
-               
-               solo_audible = solo_gain > 0;
-               mute_audible = dmg > 0 || !_mute_affects_control_outs;
-
-               if ( // silent anyway
-
-                       (_gain == 0 && !apply_gain_automation) ||
-
-                       // muted by solo of another track
-
-                       !solo_audible || 
-
-                       // muted by mute of this track 
-
-                       !mute_audible ||
-
-                       // recording but not s/w monitoring 
-                       
-                       ( no_monitor && record_enabled()
-                               && (!Config->get_auto_input() || _session.actively_recording()) )
-
-                       ) {
-                       
-                       co->silence (nframes);
-                       
-               } else {
-
-                       co->deliver_output (bufs, start_frame, end_frame, nframes);
+                       }*/
                } 
-       } 
-
-       /* -------------------------------------------------------------------------------------------
-          GLOBAL MUTE 
-          ----------------------------------------------------------------------------------------- */
-
-       if (!_soloed && (mute_gain != dmg) && !mute_declick_applied && _mute_affects_main_outs) {
-               Amp::run_in_place (bufs, nframes, mute_gain, dmg, false);
-               mute_gain = dmg;
-               mute_declick_applied = true;
-       }
-       
-       /* -------------------------------------------------------------------------------------------
-          MAIN OUTPUT STAGE
-          ----------------------------------------------------------------------------------------- */
-
-       solo_audible = dsg > 0;
-       mute_audible = dmg > 0 || !_mute_affects_main_outs;
-       
-       if (n_outputs().get(_default_type) == 0) {
-           
-           /* relax */
-
-       } else if (no_monitor && record_enabled()
-                       && (!Config->get_auto_input() || _session.actively_recording())) {
-               
-               IO::silence (nframes);
-               
-       } else {
-
-               if ( // silent anyway
-
-                       (_gain == 0 && !apply_gain_automation) ||
-                       
-                       // muted by solo of another track, but not using control outs for solo
-
-                       (!solo_audible && (Config->get_solo_model() != SoloBus)) ||
-                       
-                       // muted by mute of this track
-
-                       !mute_audible
-
-                       ) {
-
-                       /* don't use Route::silence() here, because that causes
-                          all outputs (sends, port processors, etc. to be silent).
-                       */
-                       
-                       if (_meter_point == MeterPostFader) {
-                               peak_meter().reset();
-                       }
-
-                       IO::silence (nframes);
-                       
-               } else {
-                       
-                       deliver_output(bufs, start_frame, end_frame, nframes);
-
-               }
-
-       }
-
-       /* -------------------------------------------------------------------------------------------
-          POST-FADER METERING
-          ----------------------------------------------------------------------------------------- */
-
-       if (meter && (_meter_point == MeterPostFader)) {
-               if ((_gain == 0 && !apply_gain_automation) || dmg == 0) {
-                       _meter->reset();
-               } else {
-                       _meter->run_in_place(output_buffers(), start_frame, end_frame, nframes);
-               }
-       }
-}
-
-#ifdef NEW_POB
-/** Process this route for one (sub) cycle (process thread)
- *
- * @param bufs Scratch buffers to use for the signal path
- * @param start_frame Initial transport frame 
- * @param end_frame Final transport frame
- * @param nframes Number of frames to output (to ports)
- *
- * Note that (end_frame - start_frame) may not be equal to nframes when the
- * transport speed isn't 1.0 (eg varispeed).
- */
-void
-Route::process_output_buffers (BufferSet& bufs,
-                              nframes_t start_frame, nframes_t end_frame, nframes_t nframes,
-                              bool with_processors, int declick, bool meter)
-{
-       // This is definitely very audio-only for now
-       assert(_default_type == DataType::AUDIO);
-       
-       ProcessorList::iterator i;
-       bool post_fader_work = false;
-       bool mute_declick_applied = false;
-       gain_t dmg, dsg, dg;
-       IO *co;
-       bool mute_audible;
-       bool solo_audible;
-       bool no_monitor;
-       gain_t* gab = _session.gain_automation_buffer();
-
-       switch (Config->get_monitoring_model()) {
-       case HardwareMonitoring:
-       case ExternalMonitoring:
-               no_monitor = true;
-               break;
-       default:
-               no_monitor = false;
-       }
-
-       declick = _pending_declick;
 
-       {
-               Glib::Mutex::Lock cm (_control_outs_lock, Glib::TRY_LOCK);
-               
-               if (cm.locked()) {
-                       co = _control_outs;
-               } else {
-                       co = 0;
+               if (!_processors.empty()) {
+                       bufs.set_count(ChanCount::max(bufs.count(), _processors.back()->output_streams()));
                }
        }
        
-       { 
-               Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK);
-               
-               if (dm.locked()) {
-                       dmg = desired_mute_gain;
-                       dsg = desired_solo_gain;
-                       dg = _desired_gain;
-               } else {
-                       dmg = mute_gain;
-                       dsg = solo_gain;
-                       dg = _gain;
-               }
-       }
-
-       /* -------------------------------------------------------------------------------------------
-          GLOBAL DECLICK (for transport changes etc.)
-          input metering & monitoring (control outs)
-          denormal control
-          pre-fader redirects
-          pre-fader metering & monitoring (control outs)
-          gain stage
-          post-fader redirects
-          global mute
-          main output
-          post-fader metering & monitoring (control outs)
-          ----------------------------------------------------------------------------------------- */
-
-       {
-               Glib::RWLock::ReaderLock rm (_processor_lock, Glib::TRY_LOCK);
-               for (i = processors.begin(); i != processors.end(); ++i) {
-                       (*i)->run_in_place (bufs, start_frame, end_frame, nframes);
-               }
-       }
-
-       
-       /* -------------------------------------------------------------------------------------------
-          INPUT METERING & MONITORING
-          ----------------------------------------------------------------------------------------- */
-
-       if (meter && (_meter_point == MeterInput)) {
-               _meter->run_in_place(bufs, start_frame, end_frame, nframes);
-       }
-
-       if (!_soloed && _mute_affects_pre_fader && (mute_gain != dmg)) {
-               Amp::run_in_place (bufs, nframes, mute_gain, dmg, false);
-               mute_gain = dmg;
-               mute_declick_applied = true;
-       }
-
-       /* -------------------------------------------------------------------------------------------
-          PRE-FADER REDIRECTS
-          ----------------------------------------------------------------------------------------- */
-
-       // This really should already be true...
-       bufs.set_count(pre_fader_streams());
-       
-
-       if ((_meter_point == MeterPreFader) && co) {
-               
-               solo_audible = dsg > 0;
-               mute_audible = dmg > 0 || !_mute_affects_pre_fader;
-               
-               if ( // muted by solo of another track
-                       
-                       !solo_audible || 
-                       
-                       // muted by mute of this track 
-                       
-                       !mute_audible ||
-                       
-                       // rec-enabled but not s/w monitoring 
-                       
-                       ( no_monitor && record_enabled()
-                               && (!Config->get_auto_input() || _session.actively_recording()) )
-
-                       ) {
-                       
-                       co->silence (nframes);
-                       
-               } else {
-
-                       co->deliver_output (bufs, start_frame, end_frame, nframes);
-               } 
-       } 
-       
-       /* -------------------------------------------------------------------------------------------
-          GAIN STAGE
-          ----------------------------------------------------------------------------------------- */
-
-       /* if not recording or recording and requiring any monitor signal, then apply gain */
-
-       if ( // not recording 
-
-               !(record_enabled() && _session.actively_recording()) || 
-               
-               // OR recording 
-               
-               // AND software monitoring required
-
-               Config->get_monitoring_model() == SoftwareMonitoring) { 
-               
-               if (apply_gain_automation) {
-                       
-                       if (_phase_invert) {
-                               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];
-                                       }
-                               }
-                       } 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] *= gab[nx];
-                                       }
-                               }
-                       }
-                       
-                       if (apply_gain_automation && _session.transport_rolling() && nframes > 0) {
-                               _effective_gain = gab[nframes-1];
-                       }
-                       
-               } else {
-                       
-                       /* manual (scalar) gain */
-                       
-                       if (_gain != dg) {
-                               
-                               Amp::run_in_place (bufs, nframes, _gain, dg, _phase_invert);
-                               _gain = dg;
-                               
-                       } else if (_gain != 0 && (_phase_invert || _gain != 1.0)) {
-                               
-                               /* 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_t this_gain;
-                               
-                               if (_phase_invert) {
-                                       this_gain = -_gain;
-                               } else {
-                                       this_gain = _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);
-                               }
-
-                       } else if (_gain == 0) {
-                               for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i) {
-                                       i->clear();
-                               }
-                       }
-               }
-
-       } else {
-
-               /* actively recording, no monitoring required; leave buffers as-is to save CPU cycles */
-
-       }
 
        /* -------------------------------------------------------------------------------------------
-          CONTROL OUTPUT STAGE
+          POST-FADER MUTING
           ----------------------------------------------------------------------------------------- */
 
-       if ((_meter_point == MeterPostFader) && co) {
-               
-               solo_audible = solo_gain > 0;
-               mute_audible = dmg > 0 || !_mute_affects_control_outs;
-
-               if ( // silent anyway
-
-                       (_gain == 0 && !apply_gain_automation) || 
-
-                       // muted by solo of another track
-
-                       !solo_audible || 
-
-                       // muted by mute of this track 
-
-                       !mute_audible ||
-
-                       // recording but not s/w monitoring 
-
-                       (no_monitor && record_enabled() && (!Config->get_auto_input() || _session.actively_recording()))
-
-                       ) {
-                       
-                       co->silence (nframes);
-                       
-               } else {
-
-                       co->deliver_output (bufs, start_frame, end_frame, nframes);
-               } 
-       } 
+       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);
+       }
+       
 
        /* -------------------------------------------------------------------------------------------
           MAIN OUTPUT STAGE
           ----------------------------------------------------------------------------------------- */
 
-       solo_audible = dsg > 0;
-       mute_audible = dmg > 0 || !_mute_affects_main_outs;
+       bool solo_audible = dsg > 0;
+       bool mute_audible = dmg > 0 || !_mute_affects_main_outs;
        
        if (n_outputs().get(_default_type) == 0) {
            
            /* relax */
 
-       } else if (no_monitor && record_enabled()
-                       && (!Config->get_auto_input() || _session.actively_recording())) {
-               
-               IO::silence (nframes);
-               
-       } else {
-
-               if ( // silent anyway
+       } else if (recording_without_monitoring) {
 
-                       (_gain == 0 && !apply_gain_automation) ||
+               IO::silence (nframes);
 
-                       // muted by solo of another track, but not using control outs for solo
+       } else {
 
+               if ( // we're silent anyway
+                       (_gain == 0 && !_amp->apply_gain_automation()) ||
+                       
+                       // or muted by solo of another track, but not using control outs for solo
                        (!solo_audible && (Config->get_solo_model() != SoloBus)) ||
-
-                       // muted by mute of this track
-
+                       
+                       // or muted by mute of this track
                        !mute_audible
-
                        ) {
 
                        /* don't use Route::silence() here, because that causes
                           all outputs (sends, port processors, etc. to be silent).
                        */
-
-                       if (_meter_point == MeterPostFader) {
-                               peak_meter().reset();
-                       }
-
                        IO::silence (nframes);
                        
                } else {
@@ -1042,9 +494,23 @@ Route::process_output_buffers (BufferSet& bufs,
                }
 
        }
-}
 
-#endif /* NEW_POB */
+       /* -------------------------------------------------------------------------------------------
+          POST-FADER METERING
+          ----------------------------------------------------------------------------------------- */
+
+       /* TODO: Processor-list-ification needs to go further for this to be cleanly possible...
+       if (meter && (_meter_point == MeterPostFader)) {
+               if ((_gain == 0 && !apply_gain_automation) || dmg == 0) {
+                       _meter->reset();
+               } else {
+                       _meter->run_in_place(output_buffers(), start_frame, end_frame, nframes);
+               }
+       }*/
+
+       // at this point we've reached the desired mute gain regardless
+       mute_gain = dmg;
+}
 
 ChanCount
 Route::n_process_buffers ()
@@ -1061,7 +527,7 @@ Route::setup_peak_meters()
 }
 
 void
-Route::passthru (nframes_t start_frame, nframes_t end_frame, nframes_t nframes, int declick, bool meter_first)
+Route::passthru (nframes_t start_frame, nframes_t end_frame, nframes_t nframes, int declick)
 {
        BufferSet& bufs = _session.get_scratch_buffers(n_process_buffers());
 
@@ -1069,20 +535,13 @@ Route::passthru (nframes_t start_frame, nframes_t end_frame, nframes_t nframes,
 
        collect_input (bufs, nframes);
 
-       if (meter_first) {
-               _meter->run_in_place(bufs, start_frame, end_frame, nframes);
-               meter_first = false;
-        } else {
-               meter_first = true;
-        }
-               
-       process_output_buffers (bufs, start_frame, end_frame, nframes, true, declick, meter_first);
+       process_output_buffers (bufs, start_frame, end_frame, nframes, true, declick);
 }
 
 void
-Route::passthru_silence (nframes_t start_frame, nframes_t end_frame, nframes_t nframes, int declick, bool meter)
+Route::passthru_silence (nframes_t start_frame, nframes_t end_frame, nframes_t nframes, int declick)
 {
-       process_output_buffers (_session.get_silent_buffers (n_process_buffers()), start_frame, end_frame, nframes, true, declick, meter);
+       process_output_buffers (_session.get_silent_buffers (n_process_buffers()), start_frame, end_frame, nframes, true, declick);
 }
 
 void
@@ -1114,7 +573,6 @@ Route::catch_up_on_solo_mute_override ()
        }
        
        {
-
                Glib::Mutex::Lock lm (declick_lock);
                
                if (_muted) {
@@ -1166,7 +624,7 @@ Route::set_mute (bool yn, void *src)
                
                Glib::Mutex::Lock lm (declick_lock);
                
-               if (_soloed && Config->get_solo_mute_override()){
+               if (_soloed && Config->get_solo_mute_override()) {
                        desired_mute_gain = 1.0f;
                } else {
                        desired_mute_gain = (yn?0.0f:1.0f);
@@ -1174,8 +632,24 @@ Route::set_mute (bool yn, void *src)
        }
 }
 
+static void
+dump_processors(const string& name, const list<boost::shared_ptr<Processor> >& procs)
+{
+       cerr << name << " {" << endl;
+       for (list<boost::shared_ptr<Processor> >::const_iterator p = procs.begin();
+                       p != procs.end(); ++p) {
+               cerr << "\t" << (*p)->sort_key() << ": " << (*p)->name() << endl;
+       }
+       cerr << "}" << endl;
+}
+
+/** Add a processor to the route.
+ * If @a iter is not NULL, it must point to an iterator in _processors and the new
+ * processor will be inserted immediately before this location.  Otherwise,
+ * @a position is used.
+ */
 int
-Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorStreams* err)
+Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorStreams* err, ProcessorList::iterator* iter, Placement placement)
 {
        ChanCount old_pms = processor_max_streams;
 
@@ -1189,18 +663,66 @@ Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorStreams*
                boost::shared_ptr<PluginInsert> pi;
                boost::shared_ptr<PortInsert> porti;
 
-               //processor->set_default_type(_default_type);
+               ProcessorList::iterator loc = find(_processors.begin(), _processors.end(), processor);
+
+               if (processor == _amp || processor == _meter) {
+                       // Ensure only one amp and one meter are in the list at any time
+                       if (loc != _processors.end()) {
+                               if (iter) {
+                                       if (*iter == loc) { // Already in place, do nothing
+                                               return 0;
+                                       } else { // New position given, relocate
+                                               _processors.erase(loc);
+                                       }
+                               } else { // Insert at end
+                                       _processors.erase(loc);
+                                       loc = _processors.end();
+                               }
+                       }
+
+               } else {
+                       if (loc != _processors.end()) {
+                               cerr << "ERROR: Processor added to route twice!" << endl;
+                               return 1;
+                       }
+               }
+
+               // Use position given by user
+               if (iter) {
+                       loc = *iter;
+
+               // Insert immediately before the amp
+               } else if (placement == PreFader) {
+                       loc = find(_processors.begin(), _processors.end(), _amp);
+
+               // Insert at end
+               } else {
+                       loc = _processors.end();
+               }
+               
+               // Update sort keys
+               if (loc == _processors.end()) {
+                       processor->set_sort_key(_processors.size());
+               } else {
+                       processor->set_sort_key((*loc)->sort_key());
+                       for (ProcessorList::iterator p = loc; p != _processors.end(); ++p) {
+                               (*p)->set_sort_key((*p)->sort_key() + 1);
+                       }
+               }
 
-               _processors.push_back (processor);
+               _processors.insert(loc, processor);
 
                // Set up processor list channels.  This will set processor->[input|output]_streams(),
                // configure redirect ports properly, etc.
-               if (_reset_processor_counts (err)) {
-                       _processors.pop_back ();
-                       _reset_processor_counts (0); // it worked before we tried to add it ...
+               if (configure_processors_unlocked (err)) {
+                       dump_processors(_name, _processors);
+                       ProcessorList::iterator ploc = loc;
+                       --ploc;
+                       _processors.erase(ploc);
+                       configure_processors_unlocked (0); // it worked before we tried to add it ...
                        return -1;
                }
-
+       
                if ((pi = boost::dynamic_pointer_cast<PluginInsert>(processor)) != 0) {
                        
                        if (pi->natural_input_streams() == ChanCount::ZERO) {
@@ -1211,13 +733,8 @@ Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorStreams*
                }
                
                // Ensure peak vector sizes before the plugin is activated
-
-               ChanCount potential_max_streams;
-
-               potential_max_streams.set (DataType::AUDIO, max (processor->input_streams().n_audio(), 
-                                                                processor->output_streams().n_audio()));
-               potential_max_streams.set (DataType::MIDI, max (processor->input_streams().n_midi(), 
-                                                               processor->output_streams().n_midi()));
+               ChanCount potential_max_streams = ChanCount::max(
+                               processor->input_streams(), processor->output_streams());
 
                _meter->configure_io (potential_max_streams, potential_max_streams);
 
@@ -1232,13 +749,15 @@ Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorStreams*
                reset_panner ();
        }
 
+       dump_processors (_name, _processors);
        processors_changed (); /* EMIT SIGNAL */
+
        
        return 0;
 }
 
 int
-Route::add_processors (const ProcessorList& others, ProcessorStreams* err)
+Route::add_processors (const ProcessorList& others, ProcessorStreams* err, Placement placement)
 {
        /* NOTE: this is intended to be used ONLY when copying
           processors from another Route. Hence the subtle
@@ -1257,10 +776,18 @@ Route::add_processors (const ProcessorList& others, ProcessorStreams* err)
                ProcessorList::iterator existing_end = _processors.end();
                --existing_end;
 
-               ChanCount potential_max_streams;
+               ChanCount potential_max_streams = ChanCount::max(input_minimum(), output_minimum());
 
                for (ProcessorList::const_iterator i = others.begin(); i != others.end(); ++i) {
                        
+                       // Ensure meter only appears in the list once
+                       if (*i == _meter) {
+                               ProcessorList::iterator m = find(_processors.begin(), _processors.end(), *i);
+                               if (m != _processors.end()) {
+                                       _processors.erase(m);
+                               }
+                       }
+                       
                        boost::shared_ptr<PluginInsert> pi;
                        
                        if ((pi = boost::dynamic_pointer_cast<PluginInsert>(*i)) != 0) {
@@ -1274,12 +801,16 @@ Route::add_processors (const ProcessorList& others, ProcessorStreams* err)
                        // Ensure peak vector sizes before the plugin is activated
                        _meter->configure_io (potential_max_streams, potential_max_streams);
 
-                       _processors.push_back (*i);
+                       ProcessorList::iterator loc = (placement == PreFader)
+                                       ? find(_processors.begin(), _processors.end(), _amp)
+                                       : _processors.end();
+
+                       _processors.insert (loc, *i);
                        
-                       if (_reset_processor_counts (err)) {
+                       if (configure_processors_unlocked (err)) {
                                ++existing_end;
                                _processors.erase (existing_end, _processors.end());
-                               _reset_processor_counts (0); // it worked before we tried to add it ...
+                               configure_processors_unlocked (0); // it worked before we tried to add it ...
                                return -1;
                        }
                        
@@ -1292,11 +823,26 @@ Route::add_processors (const ProcessorList& others, ProcessorStreams* err)
        if (processor_max_streams != old_pms || old_pms == ChanCount::ZERO) {
                reset_panner ();
        }
-
+       
+       dump_processors (_name, _processors);
        processors_changed (); /* EMIT SIGNAL */
+
        return 0;
 }
 
+void
+Route::placement_range(Placement p, ProcessorList::iterator& start, ProcessorList::iterator& end)
+{
+       if (p == PreFader) {
+               start = _processors.begin();
+               end = find(_processors.begin(), _processors.end(), _amp);
+       } else {
+               start = find(_processors.begin(), _processors.end(), _amp);
+               ++start;
+               end = _processors.end();
+       }
+}
+
 /** Turn off all processors with a given placement
  * @param p Placement of processors to disable
  */
@@ -1305,10 +851,11 @@ Route::disable_processors (Placement p)
 {
        Glib::RWLock::ReaderLock lm (_processor_lock);
        
-       for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
-               if ((*i)->placement() == p) {
-                       (*i)->deactivate ();
-               }
+       ProcessorList::iterator start, end;
+       placement_range(p, start, end);
+       
+       for (ProcessorList::iterator i = start; i != end; ++i) {
+               (*i)->deactivate ();
        }
 
        _session.set_dirty ();
@@ -1336,8 +883,11 @@ Route::disable_plugins (Placement p)
 {
        Glib::RWLock::ReaderLock lm (_processor_lock);
        
-       for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
-               if (boost::dynamic_pointer_cast<PluginInsert> (*i) && (*i)->placement() == p) {
+       ProcessorList::iterator start, end;
+       placement_range(p, start, end);
+       
+       for (ProcessorList::iterator i = start; i != end; ++i) {
+               if (boost::dynamic_pointer_cast<PluginInsert> (*i)) {
                        (*i)->deactivate ();
                }
        }
@@ -1417,7 +967,10 @@ Route::pre_fader_streams() const
        /* Find the last pre-fader redirect that isn't a send; sends don't affect the number
         * of streams. */
        for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) {
-               if ((*i)->placement() == PreFader && boost::dynamic_pointer_cast<Send> (*i) == 0) {
+               if ((*i) == _amp) {
+                       break;
+               }
+               if (boost::dynamic_pointer_cast<Send> (*i) == 0) {
                        processor = *i;
                }
        }
@@ -1441,21 +994,38 @@ Route::clear_processors (Placement p)
        if (!_session.engine().connected()) {
                return;
        }
+       
+       bool already_deleting = _session.deletion_in_progress();
+       if (!already_deleting) {
+               _session.set_deletion_in_progress();
+       }
 
        {
                Glib::RWLock::WriterLock lm (_processor_lock);
                ProcessorList new_list;
                
-               for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
-                       if ((*i)->placement() == p) {
-                               /* it's the placement we want to get rid of */
+               ProcessorList::iterator amp_loc = find(_processors.begin(), _processors.end(), _amp);
+               if (p == PreFader) {
+                       // Get rid of PreFader processors
+                       for (ProcessorList::iterator i = _processors.begin(); i != amp_loc; ++i) {
                                (*i)->drop_references ();
-                       } else {
-                               /* it's a different placement, so keep it */
+                       }
+                       // Keep the rest
+                       for (ProcessorList::iterator i = amp_loc; i != _processors.end(); ++i) {
                                new_list.push_back (*i);
                        }
+               } else {
+                       // Keep PreFader processors
+                       for (ProcessorList::iterator i = _processors.begin(); i != amp_loc; ++i) {
+                               new_list.push_back (*i);
+                       }
+                       new_list.push_back (_amp);
+                       // Get rid of PostFader processors
+                       for (ProcessorList::iterator i = amp_loc; i != _processors.end(); ++i) {
+                               (*i)->drop_references ();
+                       }
                }
-               
+
                _processors = new_list;
        }
 
@@ -1467,11 +1037,19 @@ Route::clear_processors (Placement p)
        processor_max_streams.reset();
        _have_internal_generator = false;
        processors_changed (); /* EMIT SIGNAL */
+
+       if (!already_deleting) {
+               _session.clear_deletion_in_progress();
+       }
 }
 
 int
 Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStreams* err)
 {
+       if (processor == _amp || processor == _meter) {
+               return 0;
+       }
+
        ChanCount old_pms = processor_max_streams;
 
        if (!_session.engine().connected()) {
@@ -1490,7 +1068,7 @@ Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStream
 
                                ProcessorList::iterator tmp;
 
-                               /* move along, see failure case for reset_processor_counts()
+                               /* move along, see failure case for configure_processors()
                                   where we may need to reprocessor the processor.
                                */
 
@@ -1524,11 +1102,11 @@ Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStream
                        return 1;
                }
 
-               if (_reset_processor_counts (err)) {
+               if (configure_processors_unlocked (err)) {
                        /* get back to where we where */
                        _processors.insert (i, processor);
                        /* we know this will work, because it worked before :) */
-                       _reset_processor_counts (0);
+                       configure_processors_unlocked (0);
                        return -1;
                }
 
@@ -1551,224 +1129,72 @@ Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStream
        }
 
        processor->drop_references ();
-
+       
+       dump_processors (_name, _processors);
        processors_changed (); /* EMIT SIGNAL */
-       return 0;
-}
 
-int
-Route::reset_processor_counts (ProcessorStreams* err)
-{
-       Glib::RWLock::WriterLock lm (_processor_lock);
-       return _reset_processor_counts (err);
+       return 0;
 }
 
-
 int
-Route::_reset_processor_counts (ProcessorStreams* err)
-{
-       ProcessorList::iterator r;
-       uint32_t insert_cnt = 0;
-       uint32_t send_cnt = 0;
-       map<Placement,list<ProcessorCount> > proc_map;
-       ProcessorList::iterator prev;
-       ChanCount initial_streams = n_inputs ();
-       ChanCount previous_initial_streams = n_inputs ();
-       int ret = -1;
-       uint32_t max_audio = 0;
-       uint32_t max_midi = 0;
-
-       processor_max_streams.reset ();
-       
-       /* Step 1: build a map that links each insert to an in/out channel count 
-
-          Divide inserts up by placement so we get the signal flow
-          properly modelled. we need to do this because the _processors
-          list is not sorted by placement, and because other reasons may 
-          exist now or in the future for this separate treatment.
-       */
-
-       /* ... but it should/will be... */
-       
-       for (r = _processors.begin(); r != _processors.end(); ++r) {
-
-               boost::shared_ptr<PluginInsert> plugin_insert;
-               boost::shared_ptr<PortInsert> port_insert;
-
-               if ((plugin_insert = boost::dynamic_pointer_cast<PluginInsert>(*r)) != 0) {
-
-                       ++insert_cnt;
-                       proc_map[(*r)->placement()].push_back (ProcessorCount (*r));
-
-                       /* reset plugin counts back to one for now so
-                          that we have a predictable, controlled
-                          state to try to configure.
-                       */
-
-                       plugin_insert->set_count (1);
-
-               } else if ((port_insert = boost::dynamic_pointer_cast<PortInsert>(*r)) != 0) {
-
-                       ++insert_cnt;
-                       proc_map[(*r)->placement()].push_back (ProcessorCount (*r));
-
-               } else if (boost::dynamic_pointer_cast<Send> (*r) != 0) {
-                       ++send_cnt;
-               }
-       }
-
-       if (insert_cnt == 0) {
-               if (send_cnt) {
-                       goto recompute;
-               } else {
-                       ret = 0;
-                       goto streamcount;
-               }
-       }
-
-       /* Now process each placement in order, checking to see if we 
-          can really do what has been requested.
-       */
-
-       /* A: PreFader */
-       
-       if (check_some_processor_counts (proc_map[PreFader], n_inputs (), err)) {
-               goto streamcount;
-       }
-
-       if (!proc_map[PreFader].empty()) {
-               previous_initial_streams = n_inputs ();
-               for (list<ProcessorCount>::iterator i = proc_map[PreFader].begin(); i != proc_map[PreFader].end(); i++) {
-                       if (i->processor->can_support_io_configuration (previous_initial_streams, initial_streams) == false) {
-                               goto streamcount;
-                       }
-                       previous_initial_streams = initial_streams;
-               }
-       }
-
-       /* B: PostFader */
-
-       if (check_some_processor_counts (proc_map[PostFader], initial_streams, err)) {
-               goto streamcount;
-       }
-
-       if (!proc_map[PostFader].empty()) {
-               for (list<ProcessorCount>::iterator i = proc_map[PostFader].begin(); i != proc_map[PostFader].end(); i++) {
-                       if (i->processor->can_support_io_configuration (previous_initial_streams, initial_streams) == false) {
-                               goto streamcount;
-                       }
-                       previous_initial_streams = initial_streams;
-               }
-       }
-
-       /* OK, everything can be set up correctly, so lets do it */
-
-       apply_some_processor_counts (proc_map[PreFader]);
-       apply_some_processor_counts (proc_map[PostFader]);
-
-       /* recompute max outs of any processor */
-
-       ret = 0;
-
-  recompute:
-
-       processor_max_streams.reset ();
-       prev = _processors.end();
-
-       for (r = _processors.begin(); r != _processors.end(); prev = r, ++r) {
-               boost::shared_ptr<Send> s;
-
-               if ((s = boost::dynamic_pointer_cast<Send> (*r)) != 0) {
-
-                       /* don't pay any attention to send output configuration, since it doesn't
-                          affect the route.
-                        */
-
-                       if (r == _processors.begin()) {
-                               s->expect_inputs (n_inputs());
-                       } else {
-                               s->expect_inputs ((*prev)->output_streams());
-                       }
-
-               } else {
-                       
-                       max_audio = max ((*r)->input_streams ().n_audio(), max_audio);
-                       max_midi = max ((*r)->input_streams ().n_midi(), max_midi);
-                       max_audio = max ((*r)->output_streams ().n_audio(), max_audio);
-                       max_midi = max ((*r)->output_streams ().n_midi(), max_midi);
-               }
-       }
-
-       processor_max_streams.set (DataType::AUDIO, max_audio);
-       processor_max_streams.set (DataType::MIDI, max_midi);
-
-       /* we're done */
-       return 0;
-
-  streamcount:
-       for (r = _processors.begin(); r != _processors.end(); ++r) {
-               max_audio = max ((*r)->output_streams ().n_audio(), max_audio);
-               max_midi = max ((*r)->output_streams ().n_midi(), max_midi);
-       }
-
-       processor_max_streams.set (DataType::AUDIO, max_audio);
-       processor_max_streams.set (DataType::MIDI, max_midi);
-       
-       return ret;
-}                                 
-
-int32_t
-Route::apply_some_processor_counts (list<ProcessorCount>& iclist)
+Route::configure_processors (ProcessorStreams* err)
 {
-       list<ProcessorCount>::iterator i;
-       
-       for (i = iclist.begin(); i != iclist.end(); ++i) {
-
-               ProcessorCount& pc (*i);
-
-               if (pc.processor->configure_io (pc.in, pc.out)) {
-                       return -1;
-               }
-
-               /* make sure that however many we have, they are all active */
-
-               pc.processor->activate ();
+       if (!_in_configure_processors) {
+               Glib::RWLock::WriterLock lm (_processor_lock);
+               return configure_processors_unlocked (err);
        }
-
        return 0;
 }
 
-/** Returns whether \a iclist can be configured and run starting with
- * \a required_inputs at the first processor's inputs.
- * If false is returned, \a iclist can not be run with \a required_inputs, and \a err is set.
- * Otherwise, \a err is set to the output of the list.
+/** Configure the input/output configuration of each processor in the processors list.
+ * Return 0 on success, otherwise configuration is impossible.
  */
-bool
-Route::check_some_processor_counts (list<ProcessorCount>& iclist, ChanCount required_inputs, ProcessorStreams* err)
+int
+Route::configure_processors_unlocked (ProcessorStreams* err)
 {
-       list<ProcessorCount>::iterator i;
-       size_t index = 0;
-                       
-       if (err) {
-               err->index = 0;
-               err->count = required_inputs;
+       if (_in_configure_processors) {
+          return 0;
        }
 
-       for (i = iclist.begin(); i != iclist.end(); ++i, ++index) {
+       _in_configure_processors = true;
 
-               if (!(*i).processor->can_support_io_configuration (required_inputs, (*i).out)) {
+       // Check each processor in order to see if we can configure as requested
+       ChanCount in = _configured_inputs;
+       ChanCount out;
+       list< pair<ChanCount,ChanCount> > configuration;
+       uint32_t index = 0;
+       for (ProcessorList::iterator p = _processors.begin(); p != _processors.end(); ++p, ++index) {
+               (*p)->set_sort_key(index);
+               if ((*p)->can_support_io_configuration(in, out)) {
+                       configuration.push_back(make_pair(in, out));
+                       in = out;
+               } else {
                        if (err) {
                                err->index = index;
-                               err->count = required_inputs;
+                               err->count = in;
                        }
-                       return true;
+                       _in_configure_processors = false;
+                       return -1;
                }
-               
-               (*i).in = required_inputs;
-               required_inputs = (*i).out;
+       }
+       
+       // We can, so configure everything
+       list< pair<ChanCount,ChanCount> >::iterator c = configuration.begin();
+       for (ProcessorList::iterator p = _processors.begin(); p != _processors.end(); ++p, ++c) {
+               (*p)->configure_io(c->first, c->second);
+               (*p)->activate();
+               processor_max_streams = ChanCount::max(processor_max_streams, c->first);
+               processor_max_streams = ChanCount::max(processor_max_streams, c->second);
+               out = c->second;
        }
 
-       return false;
+       // Ensure route outputs match last processor's outputs
+       if (out != n_outputs()) {
+               ensure_io(_configured_inputs, out, false, this);
+       }
+
+       _in_configure_processors = false;
+       return 0;
 }
 
 void
@@ -1805,9 +1231,16 @@ Route::all_processors_active (Placement p, bool state)
        if (_processors.empty()) {
                return;
        }
+       ProcessorList::iterator start, end;
+       placement_range(p, start, end);
 
+       bool before_amp = true;
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
-               if ((*i)->placement() == p) {
+               if ((*i) == _amp) {
+                       before_amp = false;
+                       continue;
+               }
+               if (p == PreFader && before_amp) {
                        if (state) {
                                (*i)->activate ();
                        } else {
@@ -1839,7 +1272,7 @@ Route::sort_processors (ProcessorStreams* err)
 
                _processors.sort (comparator);
        
-               if (_reset_processor_counts (err)) {
+               if (configure_processors_unlocked (err)) {
                        _processors = as_it_was_before;
                        processor_max_streams = old_pms;
                        return -1;
@@ -1925,7 +1358,7 @@ Route::state(bool full_state)
 
        if (_control_outs) {
                XMLNode* cnode = new XMLNode (X_("ControlOuts"));
-               cnode->add_child_nocopy (_control_outs->state (full_state));
+               cnode->add_child_nocopy (_control_outs->io()->state (full_state));
                node->add_child_nocopy (*cnode);
        }
 
@@ -2033,8 +1466,8 @@ Route::set_deferred_state ()
        deferred_state = 0;
 }
 
-void
-Route::add_processor_from_xml (const XMLNode& node)
+bool
+Route::add_processor_from_xml (const XMLNode& node, ProcessorList::iterator* iter)
 {
        const XMLProperty *prop;
 
@@ -2043,15 +1476,15 @@ Route::add_processor_from_xml (const XMLNode& node)
        
                try {
                        boost::shared_ptr<Send> send (new Send (_session, node));
-                       add_processor (send);
+                       add_processor (send, 0, iter);
+                       return true;
                } 
                
                catch (failed_constructor &err) {
                        error << _("Send construction failed") << endmsg;
-                       return;
+                       return false;
                }
                
-       // use "Processor" in XML?
        } else if (node.name() == "Processor") {
                
                try {
@@ -2076,13 +1509,21 @@ Route::add_processor_from_xml (const XMLNode& node)
 
                                        processor.reset (new Send (_session, node));
                                        have_insert = true;
+                               
+                               } else if (prop->value() == "meter") {
+
+                                       processor = _meter;
+                               
+                               } else if (prop->value() == "amp") {
+                                       
+                                       processor = _amp;
 
                                } else {
 
                                        error << string_compose(_("unknown Processor type \"%1\"; ignored"), prop->value()) << endmsg;
                                }
                                
-                               add_processor (processor);
+                               return (add_processor (processor, 0, iter) == 0);
                                
                        } else {
                                error << _("Processor XML node has no type property") << endmsg;
@@ -2091,9 +1532,10 @@ Route::add_processor_from_xml (const XMLNode& node)
 
                catch (failed_constructor &err) {
                        warning << _("processor could not be created. Ignored.") << endmsg;
-                       return;
+                       return false;
                }
        }
+       return false;
 }
 
 int
@@ -2238,6 +1680,7 @@ Route::_set_state (const XMLNode& node, bool call_base)
        }
 
        XMLNodeList processor_nodes;
+       bool has_meter_processor = false; // legacy sessions don't
                        
        for (niter = nlist.begin(); niter != nlist.end(); ++niter){
 
@@ -2245,12 +1688,18 @@ Route::_set_state (const XMLNode& node, bool call_base)
                        
                if (child->name() == X_("Send") || child->name() == X_("Processor")) {
                        processor_nodes.push_back(child);
+                       if ((prop = child->property (X_("type"))) != 0 && prop->value() == "meter")  {
+                               has_meter_processor = true;
+                       }
                }
 
        }
 
        _set_processor_states(processor_nodes);
-
+       if (!has_meter_processor) {
+               set_meter_point(_meter_point, NULL);
+       }
+       processors_changed ();
 
        for (niter = nlist.begin(); niter != nlist.end(); ++niter){
                child = *niter;
@@ -2267,8 +1716,8 @@ Route::_set_state (const XMLNode& node, bool call_base)
                        string coutname = _name;
                        coutname += _("[control]");
 
-                       delete _control_outs;
-                       _control_outs = new IO (_session, coutname);
+                       _control_outs = boost::shared_ptr<ControlOutputs> (
+                                       new ControlOutputs (_session, new IO (_session, coutname)));
                        
                        /* fix up the control out name in the XML before setting it.
                           Otherwise track templates don't work because the control
@@ -2281,7 +1730,9 @@ Route::_set_state (const XMLNode& node, bool call_base)
                                prop->set_value (coutname);
                        }
                        
-                       _control_outs->set_state (**(child->children().begin()));
+                       _control_outs->io()->set_state (**(child->children().begin()));
+                       _control_outs->set_sort_key (_meter->sort_key() + 1);
+                       add_processor (_control_outs, 0);
 
                } else if (child->name() == X_("Comment")) {
 
@@ -2303,8 +1754,7 @@ Route::_set_state (const XMLNode& node, bool call_base)
                                _mute_control->set_state (*child);
                                _session.add_controllable (_mute_control);
                        }
-               }
-               else if (child->name() == X_("RemoteControl")) {
+               } else if (child->name() == X_("RemoteControl")) {
                        if ((prop = child->property (X_("id"))) != 0) {
                                int32_t x;
                                sscanf (prop->value().c_str(), "%d", &x);
@@ -2365,6 +1815,7 @@ Route::_set_processor_states(const XMLNodeList &nlist)
                i = tmp;
        }
 
+       Placement placement = PreFader;
 
        // Iterate through state list and make sure all processors are on the track and in the correct order,
        // set the state of existing processors according to the new state on the same go
@@ -2389,50 +1840,33 @@ Route::_set_processor_states(const XMLNodeList &nlist)
                        ++o;
                }
 
+               // If the processor (*niter) is not on the route,
+               // create it and move it to the correct location
                if (o == _processors.end()) {
-                       // If the processor (*niter) is not on the route, we need to create it
-                       // and move it to the correct location
-
-                       ProcessorList::iterator prev_last = _processors.end();
-                       --prev_last; // We need this to check whether adding succeeded
-                       
-                       add_processor_from_xml (**niter);
-
-                       ProcessorList::iterator last = _processors.end();
-                       --last;
+                       if (add_processor_from_xml (**niter, &i)) {
+                               --i; // move iterator to the newly inserted processor
+                       } else {
+                               cerr << "Error restoring route: unable to restore processor" << endl;
+                       }
 
-                       if (prev_last == last) {
-                               cerr << "Could not fully restore state as some processors were not possible to create" << endl;
-                               continue;
+               // Otherwise, we found the processor (*niter) on the route,
+               // ensure it is at the location provided in the XML state
+               } else {
 
+                       if (i != o) {
+                               boost::shared_ptr<Processor> tmp = (*o);
+                               _processors.erase(o); // remove the old copy
+                               _processors.insert(i, tmp); // insert the processor at the correct location
+                               --i; // move iterator to the correct processor
                        }
 
-                       boost::shared_ptr<Processor> tmp = (*last);
-                       // remove the processor from the wrong location
-                       _processors.erase(last);
-                       // processor the new processor at the current location
-                       _processors.insert(i, tmp);
-
-                       --i; // move pointer to the newly processored processor
-                       continue;
+                       (*i)->set_state((**niter));
                }
 
-               // We found the processor (*niter) on the route, first we must make sure the processor
-               // is at the location provided in the XML state
-               if (i != o) {
-                       boost::shared_ptr<Processor> tmp = (*o);
-                       // remove the old copy
-                       _processors.erase(o);
-                       // processor the processor at the correct location
-                       _processors.insert(i, tmp);
-
-                       --i; // move pointer so it points to the right processor
+               if (*i == _amp) {
+                       placement = PostFader;
                }
-
-               (*i)->set_state( (**niter) );
        }
-       
-       processors_changed ();
 }
 
 void
@@ -2450,7 +1884,7 @@ Route::silence (nframes_t nframes)
                IO::silence (nframes);
 
                if (_control_outs) {
-                       _control_outs->silence (nframes);
+                       _control_outs->io()->silence (nframes);
                }
 
                { 
@@ -2479,13 +1913,8 @@ Route::silence (nframes_t nframes)
 int
 Route::set_control_outs (const vector<string>& ports)
 {
-       Glib::Mutex::Lock lm (_control_outs_lock);
        vector<string>::const_iterator i;
-       size_t limit;
        
-       delete _control_outs;
-       _control_outs = 0;
-
        if (is_control() || is_master()) {
                /* no control outs for these two special busses */
                return 0;
@@ -2498,28 +1927,31 @@ Route::set_control_outs (const vector<string>& ports)
        string coutname = _name;
        coutname += _("[control]");
        
-       _control_outs = new IO (_session, coutname);
-
-       /* our control outs need as many outputs as we
-          have audio outputs. we track the changes in ::output_change_handler().
-       */
-       
-       // XXX its stupid that we have to get this value twice
+       IO* out_io = new IO (_session, coutname);
+       boost::shared_ptr<ControlOutputs> out_proc(new ControlOutputs (_session, out_io));
 
-       limit = n_outputs().n_audio();
-       
-       if (_control_outs->ensure_io (ChanCount::ZERO, ChanCount (DataType::AUDIO, n_outputs().get (DataType::AUDIO)), true, this)) {
+       /* As an IO, our control outs need as many IO outputs as we have outputs
+        *   (we track the changes in ::output_change_handler()).
+        * As a processor, the control outs is an identity processor
+        *   (i.e. it does not modify its input buffers whatsoever)
+        */
+       if (out_io->ensure_io (ChanCount::ZERO, n_outputs(), true, this)) {
                return -1;
        }
-       
+
        /* now connect to the named ports */
        
-       for (size_t n = 0; n < limit; ++n) {
-               if (_control_outs->connect_output (_control_outs->output (n), ports[n % ports.size()], this)) {
-                       error << string_compose (_("could not connect %1 to %2"), _control_outs->output(n)->name(), ports[n]) << endmsg;
+       for (size_t n = 0; n < n_outputs().n_total(); ++n) {
+               if (out_io->connect_output (out_io->output (n), ports[n % ports.size()], this)) {
+                       error << string_compose (_("could not connect %1 to %2"),
+                                       out_io->output(n)->name(), ports[n]) << endmsg;
                        return -1;
                }
        }
+
+       _control_outs = out_proc;
+       _control_outs->set_sort_key (_meter->sort_key() + 1);
+       add_processor (_control_outs, NULL);
  
        return 0;
 }      
@@ -2631,11 +2063,11 @@ Route::feeds (boost::shared_ptr<Route> other)
 
        if (_control_outs) {
 
-               no = _control_outs->n_outputs().n_total();
+               no = _control_outs->io()->n_outputs().n_total();
                
                for (i = 0; i < no; ++i) {
                        for (j = 0; j < ni; ++j) {
-                               if (_control_outs->output(i)->connected_to (other->input (j)->name())) {
+                               if (_control_outs->io()->output(i)->connected_to (other->input (j)->name())) {
                                        return true;
                                }
                        }
@@ -2651,22 +2083,22 @@ 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 */
+               pre_fader_changed(src); /* EMIT SIGNAL */
                break;
 
        case POST_FADER:
                _mute_affects_post_fader = onoff;
-                post_fader_changed(src); /* EMIT SIGNAL */
+               post_fader_changed(src); /* EMIT SIGNAL */
                break;
 
        case CONTROL_OUTS:
                _mute_affects_control_outs = onoff;
-                control_outs_changed(src); /* EMIT SIGNAL */
+               control_outs_changed(src); /* EMIT SIGNAL */
                break;
 
        case MAIN_OUTS:
                _mute_affects_main_outs = onoff;
-                main_outs_changed(src); /* EMIT SIGNAL */
+               main_outs_changed(src); /* EMIT SIGNAL */
                break;
        }
 }
@@ -2723,22 +2155,22 @@ Route::handle_transport_stopped (bool abort_ignored, bool did_locate, bool can_f
 }
 
 void
-Route::input_change_handler (IOChange change, void *ignored)
+Route::input_change_handler (IOChange change, void *src)
 {
-       if (change & ConfigurationChanged) {
-               reset_processor_counts (0);
+       if ((change & ConfigurationChanged)) {
+               configure_processors (0);
        }
 }
 
 void
-Route::output_change_handler (IOChange change, void *ignored)
+Route::output_change_handler (IOChange change, void *src)
 {
-       if (change & ConfigurationChanged) {
+       if ((change & ConfigurationChanged)) {
                if (_control_outs) {
-                       _control_outs->ensure_io (ChanCount::ZERO, ChanCount(DataType::AUDIO, n_outputs().n_audio()), true, this);
+                       _control_outs->io()->ensure_io (ChanCount::ZERO, n_outputs(), true, this);
                }
                
-               reset_processor_counts (0);
+               configure_processors (0);
        }
 }
 
@@ -2765,10 +2197,10 @@ Route::no_roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame,
                return 0;
        }
 
-       apply_gain_automation = false;
+       _amp->apply_gain_automation(false);
        
-       if (n_inputs().n_total()) {
-               passthru (start_frame, end_frame, nframes, 0, false);
+       if (n_inputs() != ChanCount::ZERO) {
+               passthru (start_frame, end_frame, nframes, 0);
        } else {
                silence (nframes);
        }
@@ -2829,7 +2261,7 @@ Route::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, int
 
        _silent = false;
 
-       apply_gain_automation = false;
+       _amp->apply_gain_automation(false);
 
        { 
                Glib::Mutex::Lock am (data().control_lock(), Glib::TRY_LOCK);
@@ -2837,13 +2269,14 @@ Route::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, int
                if (am.locked() && _session.transport_rolling()) {
                        
                        if (_gain_control->automation_playback()) {
-                               apply_gain_automation = _gain_control->list()->curve().rt_safe_get_vector (
-                                               start_frame, end_frame, _session.gain_automation_buffer(), nframes);
+                               _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, false);
+       passthru (start_frame, end_frame, nframes, declick);
 
        return 0;
 }
@@ -2912,7 +2345,35 @@ Route::set_meter_point (MeterPoint p, void *src)
 {
        if (_meter_point != p) {
                _meter_point = p;
+
+               // Move meter in the processors list
+               ProcessorList::iterator loc = find(_processors.begin(), _processors.end(), _meter);
+               _processors.erase(loc);
+               switch (p) {
+               case MeterInput:
+                       loc = _processors.begin();
+                       break;
+               case MeterPreFader:
+                       loc = find(_processors.begin(), _processors.end(), _amp);
+                       break;
+               case MeterPostFader:
+                       loc = _processors.end();
+                       break;
+               }
+               _processors.insert(loc, _meter);
+               
+               // Update sort key
+               if (loc == _processors.end()) {
+                       _meter->set_sort_key(_processors.size());
+               } else {
+                       _meter->set_sort_key((*loc)->sort_key());
+                       for (ProcessorList::iterator p = loc; p != _processors.end(); ++p) {
+                               (*p)->set_sort_key((*p)->sort_key() + 1);
+                       }
+               }
+
                 meter_change (src); /* EMIT SIGNAL */
+               processors_changed (); /* EMIT SIGNAL */
                _session.set_dirty ();
        }
 }
@@ -3054,6 +2515,7 @@ Route::set_block_size (nframes_t nframes)
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
                (*i)->set_block_size (nframes);
        }
+       _session.ensure_buffers(processor_max_streams);
 }
 
 void
index ef6f954dd2ea40c8afaebdc08fc2ff4486e2d2ca..9246db9458bf6f505b99ead82b5c701e77d00500 100644 (file)
 using namespace ARDOUR;
 using namespace PBD;
 
-Send::Send (Session& s, Placement p)
-       : IOProcessor (s, string_compose (_("send %1"), (bitslot = s.next_send_id()) + 1), p)
+Send::Send (Session& s)
+       : IOProcessor (s, string_compose (_("send %1"), (bitslot = s.next_send_id()) + 1))
 {
        _metering = false;
        ProcessorCreated (this); /* EMIT SIGNAL */
 }
 
 Send::Send (Session& s, const XMLNode& node)
-       : IOProcessor (s, "send", PreFader)
+       : IOProcessor (s, "send")
 {
        _metering = false;
 
@@ -183,10 +183,10 @@ Send::configure_io (ChanCount in, ChanCount out)
                return false;
        }
 
-       _io->set_output_maximum (in);
+       /*_io->set_output_maximum (in);
        _io->set_output_minimum (in);
        _io->set_input_maximum (ChanCount::ZERO);
-       _io->set_input_minimum (ChanCount::ZERO);
+       _io->set_input_minimum (ChanCount::ZERO);*/
 
        if (_io->ensure_io (ChanCount::ZERO, in, false, this) != 0) {
                return false;
index 0297aa76bbc7bdfb0934d2c0c7eb5fb6b76ae3d4..db66c2dc3079724f583f067e10a2e79609ad9540 100644 (file)
@@ -112,6 +112,9 @@ Session::Session (AudioEngine &eng,
                  string mix_template)
 
        : _engine (eng),
+         phi (0),
+         target_phi (0),
+         phase (0),
          _requested_return_frame (-1),
          _scratch_buffers(new BufferSet()),
          _silent_buffers(new BufferSet()),
@@ -196,6 +199,9 @@ Session::Session (AudioEngine &eng,
                  nframes_t initial_length)
 
        : _engine (eng),
+         phi (0),
+         target_phi (0),
+         phase (0),
          _requested_return_frame (-1),
          _scratch_buffers(new BufferSet()),
          _silent_buffers(new BufferSet()),
@@ -264,14 +270,18 @@ Session::Session (AudioEngine &eng,
                int control_id = 1;
 
                if (control_out_channels) {
-                       shared_ptr<Route> r (new Route (*this, _("monitor"), -1, control_out_channels, -1, control_out_channels, Route::ControlOut));
+                       ChanCount count(DataType::AUDIO, control_out_channels);
+                       shared_ptr<Route> r (new Route (*this, _("monitor"), Route::ControlOut,
+                                               DataType::AUDIO, count, count));
                        r->set_remote_control_id (control_id++);
 
                        rl.push_back (r);
                }
 
                if (master_out_channels) {
-                       shared_ptr<Route> r (new Route (*this, _("master"), -1, master_out_channels, -1, master_out_channels, Route::MasterOut));
+                       ChanCount count(DataType::AUDIO, master_out_channels);
+                       shared_ptr<Route> r (new Route (*this, _("master"), Route::MasterOut,
+                                               DataType::AUDIO, count, count));
                        r->set_remote_control_id (control_id);
 
                        rl.push_back (r);
@@ -543,7 +553,7 @@ Session::when_engine_running ()
        try {
                XMLNode* child = 0;
 
-               _click_io.reset (new ClickIO (*this, "click", 0, 0, -1, -1));
+               _click_io.reset (new ClickIO (*this, "click"));
 
                if (state_tree && (child = find_named_node (*state_tree->root(), "Click")) != 0) {
 
@@ -656,36 +666,20 @@ Session::when_engine_running ()
                /* create master/control ports */
 
                if (_master_out) {
-                       uint32_t n;
-
                        /* force the master to ignore any later call to this */
-
                        if (_master_out->pending_state_node) {
                                _master_out->ports_became_legal();
                        }
 
                        /* no panner resets till we are through */
-
                        _master_out->defer_pan_reset ();
 
-                       while (_master_out->n_inputs().n_audio()
-                                       < _master_out->input_maximum().n_audio()) {
-                               if (_master_out->add_input_port ("", this, DataType::AUDIO)) {
-                                       error << _("cannot setup master inputs")
-                                             << endmsg;
-                                       break;
-                               }
-                       }
-                       n = 0;
-                       while (_master_out->n_outputs().n_audio()
-                                       < _master_out->output_maximum().n_audio()) {
-                               if (_master_out->add_output_port (_engine.get_nth_physical_output (DataType::AUDIO, n), this, DataType::AUDIO)) {
-                                       error << _("cannot setup master outputs")
-                                             << endmsg;
-                                       break;
-                               }
-                               n++;
-                       }
+                       /* create ports */
+                       _master_out->set_input_minimum(ChanCount(DataType::AUDIO, n_physical_inputs));
+                       _master_out->set_output_minimum(ChanCount(DataType::AUDIO, n_physical_outputs));
+                       _master_out->ensure_io (
+                                       _master_out->input_minimum (), _master_out->output_minimum (),
+                                       true, this);
 
                        _master_out->allow_pan_reset ();
 
@@ -765,30 +759,15 @@ Session::hookup_io ()
        IO::enable_ports ();
 
        if (_control_out) {
-               uint32_t n;
                vector<string> cports;
 
-               while (_control_out->n_inputs().n_audio() < _control_out->input_maximum().n_audio()) {
-                       if (_control_out->add_input_port ("", this)) {
-                               error << _("cannot setup control inputs")
-                                     << endmsg;
-                               break;
-                       }
-               }
-               n = 0;
-               while (_control_out->n_outputs().n_audio() < _control_out->output_maximum().n_audio()) {
-                       if (_control_out->add_output_port (_engine.get_nth_physical_output (DataType::AUDIO, n), this)) {
-                               error << _("cannot set up master outputs")
-                                     << endmsg;
-                               break;
-                       }
-                       n++;
-               }
-
+               _control_out->ensure_io(
+                               _control_out->input_minimum(), _control_out->output_minimum(),
+                               false, this);
 
                uint32_t ni = _control_out->n_inputs().get (DataType::AUDIO);
 
-               for (n = 0; n < ni; ++n) {
+               for (uint32_t n = 0; n < ni; ++n) {
                        cports.push_back (_control_out->input(n)->name());
                }
 
@@ -1313,7 +1292,6 @@ Session::set_block_size (nframes_t nframes)
        */
 
        {
-
                current_block_size = nframes;
 
                ensure_buffers(_scratch_buffers->available());
@@ -1757,14 +1735,13 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
                                uint32_t nphysical_out = physoutputs.size();
 
                                for (uint32_t x = 0; x < track->n_outputs().n_audio(); ++x) {
-                                       
                                        port = "";
                                        
                                        if (Config->get_output_auto_connect() & AutoConnectPhysical) {
                                                port = physoutputs[(channels_used+x)%nphysical_out];
                                        } else if (Config->get_output_auto_connect() & AutoConnectMaster) {
-                                               if (_master_out) {
-                                                       port = _master_out->input (x%_master_out->n_inputs().n_audio())->name();
+                                               if (_master_out && _master_out->n_inputs().n_audio() > 0) {
+                                                       port = _master_out->input (x % _master_out->n_inputs().n_audio())->name();
                                                }
                                        }
                                        
@@ -1906,7 +1883,7 @@ Session::new_audio_route (int input_channels, int output_channels, uint32_t how_
                } while (bus_id < (UINT_MAX-1));
 
                try {
-                       shared_ptr<Route> bus (new Route (*this, bus_name, -1, -1, -1, -1, Route::Flag(0), DataType::AUDIO));
+                       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)) {
                                error << string_compose (_("cannot configure %1 in/%2 out configuration for new audio track"),
index 44e8bb0392ae582b6f0649ef02466f99f994f8d7..7d14035c93e1aeae30e71535756cd5a5c5edd95b 100644 (file)
@@ -339,8 +339,7 @@ Session::second_stage_init (bool new_session)
        /* handle this one in a different way than all others, so that its clear what happened */
        
        catch (AudioEngine::PortRegistrationFailure& err) {
-               error << _("Unable to create all required ports")
-                     << endmsg;
+               error << err.what() << endmsg;
                return -1;
        }
 
@@ -2831,7 +2830,12 @@ void
 Session::set_deletion_in_progress ()
 {
        _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
+}
 
+void
+Session::clear_deletion_in_progress ()
+{
+       _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
 }
 
 void
index ea9f30322b6be4b533bf8a1d3082009dd72017f3..40848dc9edfe5c21a13de406551eddec08fa88f4 100644 (file)
@@ -117,7 +117,7 @@ SMFSource::read_unlocked (MidiRingBuffer<nframes_t>& destination, sframes_t sour
        const uint64_t start_ticks = (uint64_t)(converter.from(start) * ppqn());
 
        if (_last_read_end == 0 || start != _last_read_end) {
-               cerr << "SMFSource::read_unlocked seeking to " << start << endl;
+               //cerr << "SMFSource::read_unlocked seeking to " << start << endl;
                Evoral::SMF::seek_to_start();
                while (time < start_ticks) {
                        ret = read_event(&ev_delta_t, &ev_size, &ev_buffer);
@@ -374,10 +374,10 @@ SMFSource::load_model (bool lock, bool force_reload)
 
        if (! _model) {
                _model = boost::shared_ptr<MidiModel>(new MidiModel(this));
-               cerr << _name << " loaded new model " << _model.get() << endl;
+               //cerr << _name << " loaded new model " << _model.get() << endl;
        } else {
-               cerr << _name << " reloading model " << _model.get()
-                       << " (" << _model->n_notes() << " notes)" <<endl;
+               /*cerr << _name << " reloading model " << _model.get()
+                       << " (" << _model->n_notes() << " notes)" << endl;*/
                _model->clear();
        }
 
index 22fc6f38df6e904dbced398b1444638bb53fa4e7..3f380c0fd6445f9d72201126ef51f2b510ff7659 100644 (file)
@@ -102,7 +102,7 @@ find_session_templates (vector<TemplateInfo>& template_names)
                template_names.push_back (rti);
        }
 
-       free (templates);
+       delete templates;
 }
 
 void
index 2ce73ce72721a0c8c02a995d123d0de95d9319f2..1e344403b1b8e549f03911aa677e82092b55f2a4 100644 (file)
 #include <sigc++/retype_return.h>
 #include <sigc++/bind.h>
 
-#include "ardour/track.h"
-#include "ardour/diskstream.h"
-#include "ardour/session.h"
-#include "ardour/io_processor.h"
+#include "ardour/amp.h"
+#include "ardour/audioplaylist.h"
 #include "ardour/audioregion.h"
 #include "ardour/audiosource.h"
-#include "ardour/route_group_specialized.h"
-#include "ardour/processor.h"
-#include "ardour/audioplaylist.h"
+#include "ardour/diskstream.h"
+#include "ardour/io_processor.h"
 #include "ardour/panner.h"
-#include "ardour/utils.h"
 #include "ardour/port.h"
+#include "ardour/processor.h"
+#include "ardour/route_group_specialized.h"
+#include "ardour/session.h"
+#include "ardour/track.h"
+#include "ardour/utils.h"
 
 #include "i18n.h"
 
@@ -40,7 +41,7 @@ using namespace ARDOUR;
 using namespace PBD;
 
 Track::Track (Session& sess, string name, Route::Flag flag, TrackMode mode, DataType default_type)
-       : Route (sess, name, 1, -1, -1, -1, flag, default_type)
+       : Route (sess, name, flag, default_type)
        , _rec_enable_control (new RecEnableControllable(*this))
 {
        _declickable = true;
@@ -231,7 +232,114 @@ Track::set_latency_delay (nframes_t longest_session_latency)
 void
 Track::zero_diskstream_id_in_xml (XMLNode& node)
 {
-       if (node.property ("diskstream-id")) {
-               node.add_property ("diskstream-id", "0");
-       }
+       if (node.property ("diskstream-id")) {
+               node.add_property ("diskstream-id", "0");
+       }
+}
+
+int 
+Track::no_roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, 
+                    bool session_state_changing, bool can_record, bool rec_monitors_input)
+{
+       if (n_outputs().n_total() == 0) {
+               return 0;
+       }
+
+       if (!_active) {
+               silence (nframes);
+               return 0;
+       }
+
+       if (session_state_changing) {
+
+               /* XXX is this safe to do against transport state changes? */
+
+               passthru_silence (start_frame, end_frame, nframes, 0);
+               return 0;
+       }
+
+       diskstream()->check_record_status (start_frame, nframes, can_record);
+
+       bool send_silence;
+       
+       if (_have_internal_generator) {
+               /* since the instrument has no input streams,
+                  there is no reason to send any signal
+                  into the route.
+               */
+               send_silence = true;
+       } else {
+               if (!Config->get_tape_machine_mode()) {
+                       /* 
+                          ADATs work in a strange way.. 
+                          they monitor input always when stopped.and auto-input is engaged. 
+                       */
+                       if ((Config->get_monitoring_model() == SoftwareMonitoring)
+                                       && (Config->get_auto_input () || _diskstream->record_enabled())) {
+                               send_silence = false;
+                       } else {
+                               send_silence = true;
+                       }
+               } else {
+                       /* 
+                          Other machines switch to input on stop if the track is record enabled,
+                          regardless of the auto input setting (auto input only changes the 
+                          monitoring state when the transport is rolling) 
+                       */
+                       if ((Config->get_monitoring_model() == SoftwareMonitoring)
+                                       && _diskstream->record_enabled()) {
+                               send_silence = false;
+                       } else {
+                               send_silence = true;
+                       }
+               }
+       }
+
+       _amp->apply_gain_automation(false);
+
+       if (send_silence) {
+               
+               /* if we're sending silence, but we want the meters to show levels for the signal,
+                  meter right here.
+               */
+               
+               if (_have_internal_generator) {
+                       passthru_silence (start_frame, end_frame, nframes, 0);
+               } else {
+                       if (_meter_point == MeterInput) {
+                               just_meter_input (start_frame, end_frame, nframes);
+                       }
+                       passthru_silence (start_frame, end_frame, nframes, 0);
+               }
+
+       } else {
+       
+               /* we're sending signal, but we may still want to meter the input. 
+                */
+
+               passthru (start_frame, end_frame, nframes, false);
+       }
+
+       return 0;
+}
+
+int
+Track::silent_roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame,  
+                bool can_record, bool rec_monitors_input)
+{
+       if (n_outputs().n_total() == 0 && _processors.empty()) {
+               return 0;
+       }
+
+       if (!_active) {
+               silence (nframes);
+               return 0;
+       }
+
+       _silent = true;
+       _amp->apply_gain_automation(false);
+
+       silence (nframes);
+
+       return diskstream()->process (_session.transport_frame(), nframes, can_record, rec_monitors_input);
 }
index dfc9cc0156586932a8002588b300eb970ec571a5..adcf3a5f0bf3c25f7d21949f2420ccd3e65f48c9 100644 (file)
@@ -97,7 +97,9 @@ def build(bld):
                buffer_set.cc
                bundle.cc
                chan_count.cc
+               chan_mapping.cc
                configuration.cc
+               control_outputs.cc
                control_protocol_manager.cc
                control_protocol_search_path.cc
                crossfade.cc
index 2f6e72be1e82fe3364cc1848602953fe9361ff09..806125d9736f33a2f5d607eb4318510108a68292 100644 (file)
@@ -38,7 +38,15 @@ public:
 
        virtual void  set_float(float val, bool to_list=false, FrameTime frame=0);
        virtual float get_float(bool from_list=false, FrameTime frame=0) const;
-       virtual float user_float() const;
+       
+
+       /** Get the latest user-set value
+        * (which may not equal get_value() when automation is playing back).
+        *
+        * Automation write/touch works by periodically sampling this value
+        * and adding it to the ControlList.
+        */
+       float user_float() const { return _user_value; }
 
        void set_list(boost::shared_ptr<ControlList>);
 
index 0172d0e0254bf4a23ddd91cd64bab7af2b8ebb6e..e03933292022b24c4b6b724f3f02880601d05181 100644 (file)
@@ -58,8 +58,8 @@ public:
 
        bool find_next_event(FrameTime start, FrameTime end, ControlEvent& ev) const;
        
-       virtual bool empty() const { return _controls.size() == 0; }
-       virtual void clear();
+       virtual bool controls_empty() const { return _controls.size() == 0; }
+       virtual void clear_controls();
 
        void what_has_data(std::set<Parameter>&) const;
        
index ee18af50dc4cb31db10ab091f5282f89c3f02804..6a1fe5ab87eaca82e42d8f448cec08f62e0ce730 100644 (file)
@@ -85,7 +85,7 @@ public:
        inline const boost::shared_ptr< Note<Time> >       note_at(size_t i)       { return _notes[i]; }
 
        inline size_t n_notes() const { return _notes.size(); }
-       inline bool   empty()   const { return _notes.size() == 0 && ControlSet::empty(); }
+       inline bool   empty()   const { return _notes.size() == 0 && ControlSet::controls_empty(); }
 
        inline static bool note_time_comparator(const boost::shared_ptr< const Note<Time> >& a,
                                                const boost::shared_ptr< const Note<Time> >& b) { 
index b1b492548b4fa77b5a3a770fbe2848caa0b6c47f..079bd2929efa449be9a1ae8475a5e10049013775 100644 (file)
@@ -54,19 +54,6 @@ Control::set_float(float value, bool to_list, FrameTime frame)
 }
 
 
-/** Get the latest user-set value, which may not equal get_value() when automation
- * is playing back, etc.
- *
- * Automation write/touch works by periodically sampling this value and adding it
- * to the AutomationList.
- */
-float
-Control::user_float() const
-{
-       return _user_value;
-}
-       
-
 void
 Control::set_list(boost::shared_ptr<ControlList> list)
 {
index 860419a187f6424fb7dee0aaf929c64b8ba8f797..4a583b5a55f26ad1b184ef90c07384c09ae92521 100644 (file)
@@ -99,7 +99,7 @@ ControlSet::find_next_event (FrameTime now, FrameTime end, ControlEvent& next_ev
 }
 
 void
-ControlSet::clear ()
+ControlSet::clear_controls ()
 {
        Glib::Mutex::Lock lm (_control_lock);