first pass at internal sends. this is a very tentative work in progress, and it is...
authorPaul Davis <paul@linuxaudiosystems.com>
Fri, 30 Jan 2009 07:40:13 +0000 (07:40 +0000)
committerPaul Davis <paul@linuxaudiosystems.com>
Fri, 30 Jan 2009 07:40:13 +0000 (07:40 +0000)
git-svn-id: svn://localhost/ardour2/branches/3.0@4464 d708f5d6-7413-0410-9779-e7cbd77b26cf

48 files changed:
gtk2_ardour/ardour_ui.cc
gtk2_ardour/editor.h
gtk2_ardour/editor_route_list.cc
gtk2_ardour/export_channel_selector.cc
gtk2_ardour/gain_meter.cc
gtk2_ardour/mixer_ui.cc
gtk2_ardour/mixer_ui.h
gtk2_ardour/plugin_ui.cc
gtk2_ardour/port_group.cc
gtk2_ardour/port_matrix.cc
gtk2_ardour/processor_box.cc
gtk2_ardour/route_params_ui.cc
gtk2_ardour/route_params_ui.h
libs/ardour/SConscript
libs/ardour/ardour/ardour.h
libs/ardour/ardour/audio_buffer.h
libs/ardour/ardour/audio_port.h
libs/ardour/ardour/audio_track.h
libs/ardour/ardour/automatable.h
libs/ardour/ardour/buffer.h
libs/ardour/ardour/buffer_set.h
libs/ardour/ardour/io.h
libs/ardour/ardour/io_processor.h
libs/ardour/ardour/port.h
libs/ardour/ardour/processor.h
libs/ardour/ardour/session.h
libs/ardour/ardour/types.h
libs/ardour/audio_buffer.cc
libs/ardour/audio_port.cc
libs/ardour/audio_track.cc
libs/ardour/audioengine.cc
libs/ardour/buffer_set.cc
libs/ardour/io.cc
libs/ardour/io_processor.cc
libs/ardour/port.cc
libs/ardour/processor.cc
libs/ardour/route.cc
libs/ardour/send.cc
libs/ardour/session.cc
libs/gtkmm2ext/pixfader.cc
libs/pbd/SConscript
libs/pbd/stacktrace.cc
libs/surfaces/mackie/mackie_control_protocol.cc
libs/surfaces/mackie/mackie_control_protocol.h
libs/surfaces/osc/osc.cc
libs/surfaces/osc/osc.h
libs/surfaces/osc/osc_controllable.cc
libs/surfaces/osc/osc_controllable.h

index e51edbb6318c5ce336477216a6448d773aabc67b..9298353cab49442f993eb41cffce5c1d604f9e30 100644 (file)
@@ -1273,7 +1273,7 @@ void
 ARDOUR_UI::session_add_audio_route (bool track, int32_t input_channels, int32_t output_channels, ARDOUR::TrackMode mode, uint32_t how_many)
 {
        list<boost::shared_ptr<AudioTrack> > tracks;
-       Session::RouteList routes;
+       RouteList routes;
 
        if (session == 0) {
                warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
index aaaa7397e87c14740013193a0595145212376c58..379716ed368bd143beaa0ca32ef20408c66d4854 100644 (file)
@@ -595,7 +595,7 @@ class Editor : public PublicEditor
 
        void add_item_with_sensitivity (Gtk::Menu_Helpers::MenuList&, Gtk::Menu_Helpers::MenuElem, bool) const;
 
-       void handle_new_route (ARDOUR::Session::RouteList&);
+       void handle_new_route (ARDOUR::RouteList&);
        void remove_route (TimeAxisView *);
        bool route_removal;
 
index 52a1f622438a053b6b9c483da4daecb9815679f4..28474163974133c053c9b73b20a85793f6fff292 100644 (file)
@@ -48,7 +48,7 @@ using namespace Glib;
 const char* _order_key = N_("editor");
 
 void
-Editor::handle_new_route (Session::RouteList& routes)
+Editor::handle_new_route (RouteList& routes)
 {
        ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::handle_new_route), routes));
        
@@ -60,7 +60,7 @@ Editor::handle_new_route (Session::RouteList& routes)
        route_redisplay_does_not_sync_order_keys = true;
        no_route_list_redisplay = true;
 
-       for (Session::RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
+       for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
                boost::shared_ptr<Route> route = (*x);
 
                if (route->is_hidden()) {
@@ -592,8 +592,8 @@ struct EditorOrderRouteSorter {
 void
 Editor::initial_route_list_display ()
 {
-       boost::shared_ptr<Session::RouteList> routes = session->get_routes();
-       Session::RouteList r (*routes);
+       boost::shared_ptr<RouteList> routes = session->get_routes();
+       RouteList r (*routes);
        EditorOrderRouteSorter sorter;
 
        r.sort (sorter);
index f01a029c0cb8c88e8c868f501f67f5d57d7dc014..62380c1604c34910c2e98b5f5a8b4b0b4526ab10 100644 (file)
@@ -105,14 +105,14 @@ void
 PortExportChannelSelector::fill_route_list ()
 {
        channel_view.clear_routes ();
-       Session::RouteList routes = *session->get_routes();
+       RouteList routes = *session->get_routes();
 
        /* Add master bus and then everything else */
        
        ARDOUR::IO * master = session->master_out().get();
        channel_view.add_route (master);
        
-       for (Session::RouteList::iterator it = routes.begin(); it != routes.end(); ++it) {
+       for (RouteList::iterator it = routes.begin(); it != routes.end(); ++it) {
                if (it->get() == master) {
                        continue;
                }
index a74df66bc049351bbfca6a051ae3474ac40d3c8e..8438147746ad69f8c03bca8f106fccbe041c65cc 100644 (file)
@@ -35,6 +35,7 @@
 #include <gtkmm2ext/gtk_ui.h>
 #include <midi++/manager.h>
 #include <pbd/fastlog.h>
+#include <pbd/stacktrace.h>
 
 #include "ardour_ui.h"
 #include "gain_meter.h"
@@ -160,6 +161,8 @@ GainMeterBase::~GainMeterBase ()
 void
 GainMeterBase::set_io (boost::shared_ptr<IO> io)
 {
+       cerr << this << " Clear all connections\n";
+
        connections.clear ();
        
        _io = io;
@@ -200,6 +203,8 @@ GainMeterBase::set_io (boost::shared_ptr<IO> io)
                }
        }
 
+       cerr << "Connect " << this << " to gain change for " << _io->name() << endl;
+
        connections.push_back (_io->gain_control()->Changed.connect (mem_fun(*this, &GainMeterBase::gain_changed)));
 
        gain_changed ();
@@ -371,8 +376,11 @@ GainMeterBase::show_gain ()
 void
 GainMeterBase::gain_adjusted ()
 {
+       cerr << this << " for " << _io->name() << " GAIN ADJUSTED\n";
        if (!ignore_toggle) {
+               cerr << "Set GC\n";
                _io->gain_control()->set_value (slider_position_to_gain (gain_adjustment.get_value()));
+               cerr << "Set GC OUT\n";
        }
        show_gain ();
 }
@@ -382,6 +390,9 @@ GainMeterBase::effective_gain_display ()
 {
        gfloat value = gain_to_slider_position (_io->effective_gain());
        
+       cerr << this << " for " << _io->name() << " EGAIN = " << value << " AGAIN = " << gain_adjustment.get_value () << endl;
+       // stacktrace (cerr, 20);
+
        if (gain_adjustment.get_value() != value) {
                ignore_toggle = true; 
                gain_adjustment.set_value (value);
index 06b30c700c3e972ce5d89b979d691d64e85001a3..2c223f5bdab8323b8da3bdda1132aa38365c054f 100644 (file)
@@ -297,7 +297,7 @@ Mixer_UI::hide_window (GdkEventAny *ev)
 
 
 void
-Mixer_UI::add_strip (Session::RouteList& routes)
+Mixer_UI::add_strip (RouteList& routes)
 {
        ENSURE_GUI_THREAD(bind (mem_fun(*this, &Mixer_UI::add_strip), routes));
        
@@ -306,7 +306,7 @@ Mixer_UI::add_strip (Session::RouteList& routes)
        no_track_list_redisplay = true;
        strip_redisplay_does_not_sync_order_keys = true;
 
-       for (Session::RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
+       for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
                boost::shared_ptr<Route> route = (*x);
 
                if (route->is_hidden()) {
@@ -885,8 +885,8 @@ struct SignalOrderRouteSorter {
 void
 Mixer_UI::initial_track_display ()
 {
-       boost::shared_ptr<Session::RouteList> routes = session->get_routes();
-       Session::RouteList copy (*routes);
+       boost::shared_ptr<RouteList> routes = session->get_routes();
+       RouteList copy (*routes);
        SignalOrderRouteSorter sorter;
 
        copy.sort (sorter);
index 2b48ade6e0460784098d413c4edb014c184f2dea..f5e1ae211ddd8246f1259edea3c24a96b9f2eb45 100644 (file)
@@ -120,7 +120,7 @@ class Mixer_UI : public Gtk::Window
 
        bool strip_scroller_button_release (GdkEventButton*);
 
-       void add_strip (ARDOUR::Session::RouteList&);
+       void add_strip (ARDOUR::RouteList&);
        void remove_strip (MixerStrip *);
 
        void hide_all_strips (bool with_select);
index dbb5f3969e1c8e4faa98b57c66f8134fdd4d50aa..336b7ea3df2ed567194c675ff418734ab5de1368 100644 (file)
@@ -429,7 +429,11 @@ PlugUIBase::bypass_toggled ()
        bool x;
 
        if ((x = bypass_button.get_active()) == insert->active()) {
-               insert->set_active (!x);
+               if (x) {
+                       insert->deactivate ();
+               } else {
+                       insert->activate ();
+               }
        }
 }
 
index af2fd24bc5f4adf8095347279b8f41418f167650..e68c8364ec03df26a08cba9ece3f0c536b55bd45 100644 (file)
@@ -142,9 +142,9 @@ PortGroupList::gather (ARDOUR::Session& session)
        /* Find the bundles for routes.  We take their bundles, copy them,
           and add ports from the route's processors */
 
-       boost::shared_ptr<ARDOUR::Session::RouteList> routes = session.get_routes ();
+       boost::shared_ptr<ARDOUR::RouteList> routes = session.get_routes ();
 
-       for (ARDOUR::Session::RouteList::const_iterator i = routes->begin(); i != routes->end(); ++i) {
+       for (ARDOUR::RouteList::const_iterator i = routes->begin(); i != routes->end(); ++i) {
                /* Copy the appropriate bundle from the route */
                boost::shared_ptr<ARDOUR::Bundle> bundle (
                        new ARDOUR::Bundle (
index c080b3365d7e4ee250b0227b8334acaae9b8bfcf..55cd6a46b5c874020cf9a2f336feb2b8d2a9c867 100644 (file)
@@ -89,8 +89,8 @@ PortMatrix::routes_changed ()
                i->disconnect ();
        }
 
-       boost::shared_ptr<ARDOUR::Session::RouteList> routes = _session.get_routes ();
-       for (ARDOUR::Session::RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
+       boost::shared_ptr<ARDOUR::RouteList> routes = _session.get_routes ();
+       for (ARDOUR::RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
                _route_connections.push_back (
                        (*i)->processors_changed.connect (sigc::mem_fun (*this, &PortMatrix::setup))
                        );
index 0c97c59ae4477b46e71e6936c07fdb5f094ca6f8..567dc2985fbd67073ffe65f5572641c57c74479a 100644 (file)
@@ -342,7 +342,11 @@ ProcessorBox::processor_button_release_event (GdkEventButton *ev)
                
                /* button2-click with no modifiers */
 
-               processor->set_active (!processor->active());
+               if (processor->active()) {
+                       processor->deactivate ();
+               } else {
+                       processor->activate ();
+               }
                ret = true;
 
        } 
@@ -396,7 +400,7 @@ ProcessorBox::use_plugins (const SelectedPlugins& plugins)
                Route::ProcessorStreams err_streams;
 
                if (Config->get_new_plugins_active()) {
-                       processor->set_active (true);
+                       processor->activate ();
                }
                
                if (_route->add_processor (processor, &err_streams)) {
@@ -405,7 +409,7 @@ ProcessorBox::use_plugins (const SelectedPlugins& plugins)
                } else {
                        
                        if (Profile->get_sae()) {
-                               processor->set_active (true);
+                               processor->activate ();
                        }
                        processor->ActiveChanged.connect (bind (mem_fun (*this, &ProcessorBox::show_processor_active), boost::weak_ptr<Processor>(processor)));
                }
@@ -545,7 +549,7 @@ ProcessorBox::send_io_finished (IOSelector::Result r, boost::weak_ptr<Processor>
        case IOSelector::Accepted:
                _route->add_processor (processor);
                if (Profile->get_sae()) {
-                       processor->set_active (true);
+                       processor->activate ();
                }
                break;
        }
@@ -982,13 +986,13 @@ could not match the configuration of this track.");
 void
 ProcessorBox::activate_processor (boost::shared_ptr<Processor> r)
 {
-       r->set_active (true);
+       r->activate ();
 }
 
 void
 ProcessorBox::deactivate_processor (boost::shared_ptr<Processor> r)
 {
-       r->set_active (false);
+       r->deactivate ();
 }
 
 void
index 13807a15214ab21324963f7a2eacaa3375da4c76..30a939022e6786f7e45b081b1c5fd12c27504b9d 100644 (file)
@@ -171,11 +171,11 @@ RouteParams_UI::~RouteParams_UI ()
 }
 
 void
-RouteParams_UI::add_routes (Session::RouteList& routes)
+RouteParams_UI::add_routes (RouteList& routes)
 {
        ENSURE_GUI_THREAD(bind (mem_fun(*this, &RouteParams_UI::add_routes), routes));
        
-       for (Session::RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
+       for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
                boost::shared_ptr<Route> route = (*x);
 
                if (route->is_hidden()) {
@@ -423,7 +423,7 @@ RouteParams_UI::set_session (Session *sess)
        route_display_model->clear();
 
        if (session) {
-               boost::shared_ptr<Session::RouteList> r = session->get_routes();
+               boost::shared_ptr<RouteList> r = session->get_routes();
                add_routes (*r);
                session->GoingAway.connect (mem_fun(*this, &ArdourDialog::session_gone));
                session->RouteAdded.connect (mem_fun(*this, &RouteParams_UI::add_routes));
index e9fca333abe78f26a4ad68b15b954c113367109e..a41a0924409e7e6edda27c54b547c73b02ce1c90 100644 (file)
@@ -167,7 +167,7 @@ class RouteParams_UI : public ArdourDialog
        Glib::RefPtr<Gtk::ListStore> route_display_model;
 
        
-       void add_routes (ARDOUR::Session::RouteList&);
+       void add_routes (ARDOUR::RouteList&);
 
        void route_name_changed (boost::shared_ptr<ARDOUR::Route> route);
        void route_removed (boost::shared_ptr<ARDOUR::Route> route);
index f34dd9b078fdfb285d45b0eefde7879c1e8956eb..59ffd764bcc5332139d6b921db4ae7c99bf2e422 100644 (file)
@@ -92,6 +92,7 @@ gain.cc
 gdither.cc
 globals.cc
 import.cc
+internal_send.cc
 io.cc
 io_processor.cc
 jack_slave.cc
index 635e8a31cabe53978f6671045f98f0d24c3ef0ee..7321daf0971c6ce179ae0c14611c8eaa3ce21c58 100644 (file)
@@ -42,9 +42,6 @@ namespace MIDI {
 namespace ARDOUR {
 
        class AudioEngine;
-       class OSC;
-
-       extern OSC* osc;
 
        static const nframes_t max_frames = JACK_MAX_FRAMES;
        extern sigc::signal<void,std::string> BootMessage;
index 9a41e8e093f82ceb6de9dab2cd9aab6e05727421..829288a7afd0a1096c6fc1a613e212952c81eef3 100644 (file)
@@ -68,9 +68,14 @@ public:
        /** Accumulate (add) @a len frames FROM THE START OF @a src into self at @a offset
         * scaling by @a gain_coeff */
        void accumulate_with_gain_from(const AudioBuffer& src, nframes_t len, nframes_t offset, gain_t gain_coeff) {
+
                assert(_capacity > 0);
                assert(offset + len <= _capacity);
 
+               if (src.silent()) {
+                       return;
+               }
+
                Sample*       const dst_raw = _data + offset;
                const Sample* const src_raw = src.data();
 
@@ -82,6 +87,7 @@ public:
        /** Accumulate (add) @a len frames FROM THE START OF @a src into self at @a offset
         * scaling by @a gain_coeff */
        void accumulate_with_gain_from(const Sample* src_raw, nframes_t len, nframes_t offset, gain_t gain_coeff) {
+
                assert(_capacity > 0);
                assert(offset + len <= _capacity);
 
@@ -123,7 +129,22 @@ public:
        Sample* data (nframes_t nframes, nframes_t offset)
                { assert(offset + nframes <= _capacity); return _data + offset; }
 
-private:
+       void replace_data (size_t nframes);
+
+       void drop_data () {
+               assert (_owns_data);
+               assert (_data);
+
+               free (_data);
+               _data = 0;
+               _size = 0;
+               _capacity = 0;
+               _silent = false;
+       }
+
+       void copy_to_internal (Sample* p, nframes_t cnt, nframes_t offset);
+
+  private:
        bool    _owns_data;
        Sample* _data; ///< Actual buffer contents
 };
index 339165da0f71471c96e54ff4f267e0da36ebab0e..304902bccbeea81715dad487a8ca83f728a4e4cb 100644 (file)
@@ -51,12 +51,16 @@ class AudioPort : public Port
 
        AudioPort (std::string const &, Flags, bool, nframes_t);
   
+       bool using_internal_data() const;
+       void use_internal_data ();
+       void use_external_data (); 
+
   private:
        void mixdown (nframes_t, nframes_t, bool);
 
        bool _has_been_mixed_down;
        AudioBuffer* _buffer;
-       bool _own_buffer;
+       bool _internal_buffer;
 };
  
 } // namespace ARDOUR
index fe7dcb58ff8a8a9a58678d9b0d3e4518a9b40d8a..48609271d7bad6e670d2c74e5cba56f6a267ab45 100644 (file)
@@ -73,6 +73,10 @@ class AudioTrack : public Track
        int  deprecated_use_diskstream_connections ();
        void set_state_part_two ();
        void set_state_part_three ();
+
+       void catch_up_on_busses (ARDOUR::RouteList&);
+       void add_internal_send (boost::shared_ptr<ARDOUR::Route>);
+
 };
 
 } // namespace ARDOUR
index fc61e2200d563852f7c3872474e96945062e6059..d99960334d00a464224c505811db5df0bcc6d937 100644 (file)
@@ -94,15 +94,16 @@ public:
        Evoral::ControlSet&       data()       { return *this; }
        const Evoral::ControlSet& data() const { return *this; }
 
-protected:
+       int set_automation_state (const XMLNode&, Evoral::Parameter default_param);
+       XMLNode& get_automation_state();
+
+  protected:
        Session& _a_session;
 
        void can_automate(Evoral::Parameter);
 
        virtual void auto_state_changed (Evoral::Parameter which) {}
 
-       int set_automation_state(const XMLNode&, Evoral::Parameter default_param);
-       XMLNode& get_automation_state();
        
        int load_automation (const std::string& path);
        int old_set_automation_state(const XMLNode&);
index e03489568cf2024653b0401c9b2e29edbc997796..02d6975fad5f5b54ff470f3fa9744147c339af2d 100644 (file)
@@ -68,7 +68,7 @@ public:
         * passed to the constructor must have been non-zero.
         */
        virtual void resize(size_t) = 0;
-
+       
        /** Clear (eg zero, or empty) buffer starting at TIME @a offset */
        virtual void silence(nframes_t len, nframes_t offset=0) = 0;
        
@@ -77,9 +77,9 @@ public:
        
        virtual void read_from(const Buffer& src, nframes_t offset, nframes_t len) = 0;
 
-protected:
+  protected:
        Buffer(DataType type, size_t capacity)
-       : _type(type), _capacity(capacity), _size(0), _silent(true)
+               : _type(type), _capacity(capacity), _size(0), _silent(true)
        {}
 
        DataType _type;
index c75061579889cad47d855409d7e99b2a9920b9f9..3f7a6e7665b6db7f0a561ea7125dc3514c0f7272 100644 (file)
@@ -23,6 +23,7 @@
 #include <vector>
 #include <ardour/chan_count.h>
 #include <ardour/data_type.h>
+#include <ardour/types.h>
 
 namespace ARDOUR {
 
@@ -53,7 +54,7 @@ public:
 
        void clear();
        
-       void attach_buffers(PortSet& ports);
+       void attach_buffers(PortSet& ports, nframes_t nframes, nframes_t offset);
 
        void ensure_buffers(const ChanCount& count, size_t buffer_capacity);
        void ensure_buffers(DataType type, size_t num_buffers, size_t buffer_capacity);
index 2d5b55c50296c25f5adea9b6ad0d4eacf203efc7..32962fef0d0e75b7931df85cc9dc62e6f318255f 100644 (file)
@@ -109,6 +109,8 @@ class IO : public SessionObject, public AutomatableControls, public Latent
        void just_meter_input (nframes_t start_frame, nframes_t end_frame, 
                               nframes_t nframes, nframes_t offset);
 
+       BufferSet& output_buffers() { return *_output_buffers; }
+
        gain_t         gain () const { return _desired_gain; }
        virtual gain_t effective_gain () const;
        
@@ -121,6 +123,7 @@ class IO : public SessionObject, public AutomatableControls, public Latent
        Panner& panner()        { return *_panner; }
        PeakMeter& peak_meter() { return *_meter; }
        const Panner& panner() const { return *_panner; }
+       void reset_panner ();
        
        int ensure_io (ChanCount in, ChanCount out, bool clear, void *src);
 
@@ -196,15 +199,10 @@ class IO : public SessionObject, public AutomatableControls, public Latent
        int set_state (const XMLNode&);
 
        static int  disable_connecting (void);
-
        static int  enable_connecting (void);
-
        static int  disable_ports (void);
-
        static int  enable_ports (void);
-
        static int  disable_panners (void);
-
        static int  reset_panners (void);
        
        static sigc::signal<int>            PortsLegal;
@@ -214,16 +212,16 @@ class IO : public SessionObject, public AutomatableControls, public Latent
        static sigc::signal<void,ChanCount> PortCountChanged;
        static sigc::signal<int>            PortsCreated;
 
-    static void update_meters();
+       static void update_meters();
 
   private: 
-
-    static sigc::signal<void>   Meter;
-    static Glib::StaticMutex    m_meter_signal_lock;
-    sigc::connection            m_meter_connection;
+       
+       static sigc::signal<void>   Meter;
+       static Glib::StaticMutex    m_meter_signal_lock;
+       sigc::connection            m_meter_connection;
 
   public:
-
+    
        /* automation */
 
        struct GainControl : public AutomationControl {
@@ -292,8 +290,6 @@ class IO : public SessionObject, public AutomatableControls, public Latent
 
        virtual void set_deferred_state() {}
 
-       void reset_panner ();
-
        virtual uint32_t pans_required() const
                { return _inputs.count().n_audio(); }
 
@@ -314,14 +310,11 @@ class IO : public SessionObject, public AutomatableControls, public Latent
        static bool connecting_legal;
        static bool ports_legal;
 
-       BufferSet& output_buffers() { return *_output_buffers; }
-
   private:
+       static bool panners_legal;
 
-       friend class Send;
+       void copy_to_outputs (BufferSet& bufs, DataType type, nframes_t nframes, nframes_t offset);
 
-       static bool panners_legal;
-       
        int connecting_became_legal ();
        int panners_became_legal ();
        sigc::connection connection_legal_c;
index d2bd210516e375abc9b6fe81a150a0c59b554d40..3739c496c55a20eaf2cbdc2365fe6a4677724d90 100644 (file)
@@ -53,7 +53,9 @@ 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);
+                    int input_min = -1, int input_max = -1, int output_min = -1, int output_max = -1,
+                    ARDOUR::DataType default_type = DataType::AUDIO,
+                    bool public_ports = true);
        IOProcessor (const IOProcessor&);
        virtual ~IOProcessor ();
        
index 7539aac9d56ed8f594590c9d46b462954201663f..759d532e82e185f7ff424884a5e39cd25d37def9 100644 (file)
@@ -71,6 +71,7 @@ public:
        }
 
        bool connected () const;
+       bool externally_connected () const;
        int disconnect_all ();
        int get_connections (std::vector<std::string> &) const;
 
@@ -81,7 +82,7 @@ public:
 
        /* connection by Port* */
        bool connected_to (Port *) const;
-       int connect (Port *);
+       virtual int connect (Port *);
        int disconnect (Port *);
 
        void ensure_monitor_input (bool);
@@ -113,6 +114,12 @@ protected:
        std::set<Port*> _connections; ///< internal Ports that we are connected to
 
        static AudioEngine* _engine; ///< the AudioEngine
+
+       virtual bool using_internal_data() const { return false; }
+       virtual void use_internal_data () {}
+       virtual void use_external_data () {} 
+
+       void check_buffer_status ();
        
 private:
        friend class AudioEngine;
@@ -130,6 +137,7 @@ private:
        /// list of JACK ports that we are connected to; we only keep this around
        /// so that we can implement ::reconnect ()
        std::set<std::string> _named_connections;
+
 };
 
 }
index 4b236d159e1ee0f552bdb1bf59f0f5840d4fbbd2..da00c77dab6bb3f39dd926c542d73bd2e987b473 100644 (file)
@@ -39,6 +39,7 @@ class XMLNode;
 namespace ARDOUR {
 
 class Session;
+class Route;
 
 /* A mixer strip element - plugin, send, meter, etc.
  */
@@ -60,7 +61,6 @@ class Processor : public SessionObject, public AutomatableControls, public Laten
        void set_placement (Placement);
        
        bool active () const { return _active; }
-       void set_active (bool yn);
        
        bool get_next_ab_is_active () const { return _next_ab_is_active; }
        void set_next_ab_is_active (bool yn) { _next_ab_is_active = yn; }
@@ -77,8 +77,8 @@ class Processor : public SessionObject, public AutomatableControls, public Laten
        
        virtual void silence (nframes_t nframes, nframes_t offset) {}
        
-       virtual void activate () { _active = true; ActiveChanged.emit(); }
-       virtual void deactivate () { _active = false; ActiveChanged.emit(); }
+       void activate () { _active = true; ActiveChanged(); }
+       void deactivate () { _active = false; ActiveChanged(); }
        
        virtual bool configure_io (ChanCount in, ChanCount out);
 
@@ -108,6 +108,7 @@ class Processor : public SessionObject, public AutomatableControls, public Laten
        sigc::signal<void> PlacementChanged;
 
 protected:
+       int       _pending_active;
        bool      _active;
        bool      _next_ab_is_active;
        bool      _configured;
index 1a88882eb6ea4572e5bc90273e4d29e204816c16..7cdc11a05487deeafefcc10e405f6108ad9fdbff 100644 (file)
@@ -306,7 +306,6 @@ class Session : public PBD::StatefulDestructible
        uint32_t n_diskstreams() const;
 
        typedef std::list<boost::shared_ptr<Diskstream> > DiskstreamList;
-       typedef std::list<boost::shared_ptr<Route> >      RouteList;
 
        int load_routes (const XMLNode&);
        boost::shared_ptr<RouteList> get_routes() const {
index cb058254bf8c94390bc1a2536d1243e828acc737..125c8569a82d2407cff08d5fbb7ffeabb000f71f 100644 (file)
@@ -51,6 +51,7 @@ namespace ARDOUR {
 
        class Source;
        class AudioSource;
+       class Route;
 
        typedef jack_default_audio_sample_t Sample;
        typedef float                       pan_t;
@@ -419,9 +420,11 @@ namespace ARDOUR {
 
        typedef std::list<nframes64_t> AnalysisFeatureList;
 
+       typedef std::list<boost::shared_ptr<Route> >      RouteList;
+
        class Bundle;
        typedef std::vector<boost::shared_ptr<Bundle> > BundleList;
-  
+
 } // namespace ARDOUR
 
 std::istream& operator>>(std::istream& o, ARDOUR::SampleFormat& sf);
index 915fdeb948adc75ec1d988ca2638cd59891dc962..506b34eb04d8202378866f85cde01279c6fea1e4 100644 (file)
@@ -29,9 +29,7 @@ static const int CPU_CACHE_ALIGN = 16; /* arguably 32 on most arches, but it mat
 #endif
 
 using namespace PBD;
-
-namespace ARDOUR {
-
+using namespace ARDOUR;
 
 AudioBuffer::AudioBuffer(size_t capacity)
        : Buffer(DataType::AUDIO, capacity)
@@ -41,6 +39,7 @@ AudioBuffer::AudioBuffer(size_t capacity)
        if (_capacity > 0) {
                _owns_data = true; // prevent resize() from gagging
                resize (_capacity);
+               _silent = false; // force silence on the intial buffer state
                silence (_capacity);
        }
 }
@@ -51,10 +50,28 @@ AudioBuffer::~AudioBuffer()
                free(_data);
 }
 
+/* called to replace a pointer to an external buffer (e.g. JACK) with 
+   buffer-owned memory.
+*/
+
+void
+AudioBuffer::replace_data (size_t capacity)
+{
+       _owns_data = true;
+       _data = 0;
+       _capacity = 0; // force reallocation
+       resize (capacity);
+}
+
 void
 AudioBuffer::resize (size_t size)
 {
-       if (!_owns_data || (size < _capacity)) {
+       if (!_owns_data) {
+               return;
+       }
+
+       if (size < _capacity) {
+               _size = size;
                return;
        }
 
@@ -74,9 +91,12 @@ AudioBuffer::resize (size_t size)
                                CPU_CACHE_ALIGN, sizeof (Sample) * _capacity, strerror (errno)) << endmsg;
        }
 #endif 
-       
-       _owns_data = true;
+
 }
 
-} // namespace ARDOUR
+void
+AudioBuffer::copy_to_internal (Sample* p, nframes_t cnt, nframes_t offset)
+{
+       memcpy (_data + offset, p, sizeof(Sample*) * cnt);
+}
 
index 55d65d850d6a69ebf564998bb644ff136ae78282..0e48c2a69960200fb16f3b228f3dc63d17e7b892 100644 (file)
@@ -29,9 +29,10 @@ AudioPort::AudioPort (const std::string& name, Flags flags, bool ext, nframes_t
        : Port (name, DataType::AUDIO, flags, ext)
        , _has_been_mixed_down (false)
        , _buffer (0)
+       , _internal_buffer (false)
 {
        assert (name.find_first_of (':') == string::npos);
-       
+
        if (external ()) {
                
                /* external ports use the external port buffer */
@@ -41,8 +42,9 @@ AudioPort::AudioPort (const std::string& name, Flags flags, bool ext, nframes_t
 
                /* internal ports need their own buffers */
                _buffer = new AudioBuffer (capacity);
-               
        }
+
+       check_buffer_status ();
        
 }
 
@@ -56,11 +58,22 @@ AudioPort::cycle_start (nframes_t nframes, nframes_t offset)
 {
        /* caller must hold process lock */
 
-       _has_been_mixed_down = false;
+       /* For external (JACK) ports, get_buffer() must only be run 
+          on outputs here in cycle_start().
 
-       if (external ()) {
-               /* external ports use JACK's memory */
-               _buffer->set_data ((Sample *) jack_port_get_buffer (_jack_port, nframes), nframes + offset);
+          Inputs must be done in the correct processing order, which 
+          requires interleaving with route processing. that will 
+          happen when Port::get_buffer() is called.
+       */
+       
+       if (!receives_input() && external ()) {
+               _buffer->set_data ((Sample *) jack_port_get_buffer (_jack_port, nframes) + offset, nframes);
+       }
+
+       if (receives_input()) {
+               _has_been_mixed_down = false;
+       } else {
+               _buffer->silence (nframes, offset);
        }
 }
 
@@ -69,36 +82,21 @@ AudioPort::get_audio_buffer (nframes_t nframes, nframes_t offset)
 {
        /* caller must hold process lock */
 
-       if (_has_been_mixed_down) {
-               return *_buffer;
-       }
-
-       if (receives_input ()) {
-
-               /* INPUT */
+       if (receives_input () && !_has_been_mixed_down) {
 
-               /* If we're external (), we have some data in our buffer set up by JACK;
-                  otherwise, we have an undefined buffer.  In either case we mix down
-                  our non-JACK inputs; either accumulating into the JACK data or
-                  overwriting the undefined data */
-                  
-               mixdown (nframes, offset, !external ());
+               /* external ports use JACK's memory unless otherwise noted */
                
-       } else {
-
-               /* OUTPUT */
-
-               if (!external ()) {
-                       /* start internal output buffers with silence */
-                       _buffer->silence (nframes, offset);
+               if (external()) {
+                       if (!using_internal_data()) {
+                               _buffer->set_data ((Sample *) jack_port_get_buffer (_jack_port, nframes) + offset, nframes);
+                       } else {
+                               _buffer->silence (nframes, offset);
+                       }
                }
-               
-       }
-       
-       if (nframes) {
-               _has_been_mixed_down = true;
-       }
 
+               mixdown (nframes, offset, !external ());
+       } 
+       
        return *_buffer;
 }
 
@@ -111,22 +109,46 @@ AudioPort::cycle_end (nframes_t nframes, nframes_t offset)
 void
 AudioPort::mixdown (nframes_t cnt, nframes_t offset, bool first_overwrite)
 {
+       /* note: this is only called for input ports */
+
        if (_connections.empty()) {
-               if (first_overwrite) {
+
+               /* no internal mixing to do, so for internal ports
+                  just make sure the buffer is silent.
+               */
+               
+               if (!external()) {
                        _buffer->silence (cnt, offset);
+               } 
+
+       } else {
+
+               set<Port*>::const_iterator p = _connections.begin();
+
+               /* mix in internally-connected ports. if this is an external port
+                  then it may already have data present from JACK. in that case, we 
+                  do not want to overwrite that data, so we skip the initial ::read_from()
+                  call and do everything with accumulate_from()
+                */
+
+               if (!external()) {
+                       _buffer->read_from (dynamic_cast<AudioPort*>(*p)->get_audio_buffer (cnt, offset), cnt, offset);
+                       ++p;
+                       
                }
-               return;
-       }
-       
-       set<Port*>::const_iterator p = _connections.begin();
 
-       if (first_overwrite) {
-               _buffer->read_from (dynamic_cast<AudioPort*>(*p)->get_audio_buffer (cnt, offset), cnt, offset);
-               ++p;
+               for (; p != _connections.end (); ++p) {
+                       _buffer->accumulate_from (dynamic_cast<AudioPort*>(*p)->get_audio_buffer (cnt, offset), cnt, offset);
+
+               }
        }
 
-       for (; p != _connections.end (); ++p) {
-               _buffer->accumulate_from (dynamic_cast<AudioPort*>(*p)->get_audio_buffer (cnt, offset), cnt, offset);
+       /* XXX horrible heuristic designed to check that we worked the whole buffer.
+          Needs fixing but its a hard problem.
+       */
+
+       if (cnt && offset == 0) {
+               _has_been_mixed_down = true;
        }
 }
 
@@ -140,3 +162,23 @@ AudioPort::reset ()
                _buffer->clear ();
        }
 }
+
+bool
+AudioPort::using_internal_data () const
+{
+       return _internal_buffer;
+}
+
+void
+AudioPort::use_internal_data ()
+{
+       _buffer->replace_data (_buffer->capacity());
+       _internal_buffer = true;
+}
+
+void
+AudioPort::use_external_data ()
+{
+       _internal_buffer = false;
+       _buffer->drop_data ();
+}
index ada5a183dcf8e38ef8d492b4570f7421aaf43c86..5749afd265a06537ef80a49c006fb63cf109f8b7 100644 (file)
@@ -40,6 +40,7 @@
 #include <ardour/utils.h>
 #include <ardour/buffer_set.h>
 #include <ardour/audio_buffer.h>
+#include <ardour/internal_send.h>
 #include "i18n.h"
 
 using namespace std;
@@ -65,6 +66,8 @@ AudioTrack::AudioTrack (Session& sess, string name, Route::Flag flag, TrackMode
        
        _session.add_diskstream (ds);
 
+       _session.RouteAdded.connect (mem_fun (*this, &AudioTrack::catch_up_on_busses));
+
        set_diskstream (boost::dynamic_pointer_cast<AudioDiskstream> (ds), this);
 }
 
@@ -72,12 +75,47 @@ AudioTrack::AudioTrack (Session& sess, const XMLNode& node)
        : Track (sess, node)
 {
        _set_state (node, false);
+
+       _session.RouteAdded.connect (mem_fun (*this, &AudioTrack::catch_up_on_busses));
 }
 
 AudioTrack::~AudioTrack ()
 {
 }
 
+void
+AudioTrack::catch_up_on_busses (RouteList& added)
+{
+       if (is_hidden()) {
+               return;
+       }
+
+       for (RouteList::iterator x = added.begin(); x != added.end(); ++x) {
+               if (boost::dynamic_pointer_cast<Track>(*x) == 0 && (*x)->default_type() == DataType::AUDIO)  {
+                       /* Audio bus */
+                       if (!(*x)->is_master() && !(*x)->is_control()) {
+                               add_internal_send (*x);
+                       }
+               }
+       }
+}
+
+void
+AudioTrack::add_internal_send (boost::shared_ptr<Route> r)
+{
+       boost::shared_ptr<InternalSend> is (new InternalSend (_session, PreFader, r));
+
+       cerr << name() << " Adding processor\n";
+       
+       add_processor (is, 0);
+
+       cerr << "After add, we have " << _processors.size() << endl;
+               
+       /* note: if adding failed, the InternalSend will be cleaned up automatically when
+          the shared_ptr goes out of scope.
+       */
+}
+
 int
 AudioTrack::set_mode (TrackMode m)
 {
@@ -879,7 +917,7 @@ AudioTrack::freeze (InterThreadInfo& itt)
                                
                                /* now deactivate the processor */
                                
-                               processor->set_active (false);
+                               processor->deactivate ();
                                _session.set_dirty ();
                        }
                }
index 4d8f18423fd6160b94f9e59cf6850fd1641c56aa..27b5fcc5c5698f6c839ada24c5f7a323e246bd93 100644 (file)
@@ -348,13 +348,6 @@ AudioEngine::process_callback (nframes_t nframes)
        boost::shared_ptr<Ports> p = ports.reader();
 
        for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
-
-               /* Only run cycle_start() on output ports, because 
-                  inputs must be done in the correct processing order,
-                  which requires interleaving with route processing.
-               */
-
-               /* XXX: we're running this on both inputs and outputs... */
                (*i)->cycle_start (nframes, 0);
        }
 
@@ -416,10 +409,8 @@ AudioEngine::process_callback (nframes_t nframes)
        // Finalize ports (ie write data if necessary)
 
        for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
-
                (*i)->cycle_end (nframes, 0);
        }
-
        _processed_frames = next_processed_frames;
        return 0;
 }
index 5b6f0711503dd2891b2c96460f5983b0ab50f639..09fd8804515aecf2174022b2275d864e632aaa9f 100644 (file)
@@ -16,6 +16,7 @@
     675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
+#include <iostream>
 #include <algorithm>
 #include <ardour/buffer_set.h>
 #include <ardour/buffer.h>
@@ -61,7 +62,7 @@ BufferSet::clear()
 /** Make this BufferSet a direct mirror of a PortSet's buffers.
  */
 void
-BufferSet::attach_buffers(PortSet& ports)
+BufferSet::attach_buffers(PortSet& ports, nframes_t nframes, nframes_t offset)
 {
        clear();
 
@@ -71,9 +72,8 @@ BufferSet::attach_buffers(PortSet& ports)
 
                for (PortSet::iterator p = ports.begin(*t); p != ports.end(*t); ++p) {
                        assert(p->type() == *t);
-                       v.push_back(&(p->get_buffer(0,0)));
+                       v.push_back(&(p->get_buffer(nframes, offset)));
                }
-
        }
        
        _count = ports.count();
index a5a330cc3628006ee897cb4e7eea6f0017944240..dbe7b3c526b7f4addb8df38d86db9c4193d6c87e 100644 (file)
@@ -153,9 +153,6 @@ IO::IO (Session& s, const string& name,
                m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
        }
        
-       // Connect to our own PortCountChanged signal to connect output buffers
-       IO::PortCountChanged.connect (mem_fun (*this, &IO::attach_buffers));
-
        _session.add_controllable (_gain_control);
 
        create_bundles_for_inputs_and_outputs ();
@@ -195,9 +192,6 @@ IO::IO (Session& s, const XMLNode& node, DataType dt)
                m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
        }
        
-       // Connect to our own PortCountChanged signal to connect output buffers
-       IO::PortCountChanged.connect (mem_fun (*this, &IO::attach_buffers));
-
        _session.add_controllable (_gain_control);
 
        create_bundles_for_inputs_and_outputs ();
@@ -222,7 +216,6 @@ IO::~IO ()
 
        delete _meter;
        delete _panner;
-       delete _output_buffers;
 }
 
 void
@@ -266,48 +259,61 @@ IO::deliver_output (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame,
                        _gain = dg;
                }
        }
+       
+       /* do this so that any processing that comes after deliver_outputs()
+          can use the output buffers.
+       */
+
+       output_buffers().attach_buffers (_outputs, nframes, offset);
 
        // Use the panner to distribute audio to output port buffers
-       if( _panner && _panner->npanners() && !_panner->bypassed()) {
+
+       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, offset);
+
        } else {
-               const DataType type = DataType::AUDIO;
-               
-               // Copy any audio 1:1 to outputs
-               
-               BufferSet::iterator o = output_buffers().begin(type);
-               BufferSet::iterator i = bufs.begin(type);
-               BufferSet::iterator prev = i;
-               
-               while (i != bufs.end(type) && o != output_buffers().end (type)) {
-                       o->read_from(*i, nframes, offset);
-                       prev = i;
-                       ++i;
-                       ++o;
-               }
 
-               /* extra outputs get a copy of the last buffer */
+               /* do a 1:1 copy of data to output ports */
 
-               while (o != output_buffers().end(type)) {
-                       o->read_from(*prev, nframes, offset);
-                       ++o;
+               if (bufs.count().n_audio() > 0 && _outputs.count().n_audio () > 0) {
+                       copy_to_outputs (bufs, DataType::AUDIO, nframes, offset);
+               }
+               if (bufs.count().n_midi() > 0 && _outputs.count().n_midi () > 0) {
+                       copy_to_outputs (bufs, DataType::MIDI, nframes, offset);
                }
        }
+}
 
-       /* ********** MIDI ********** */
+void
+IO::copy_to_outputs (BufferSet& bufs, DataType type, nframes_t nframes, nframes_t offset)
+{
+       // Copy any buffers 1:1 to outputs
+       
+       PortSet::iterator o = _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, offset));
+               port_buffer.read_from (*i, nframes, offset);
 
-       // No MIDI, we're done here
-       if (bufs.count().n_midi() == 0 || output_buffers().count().n_midi () == 0) {
-               return;
+               prev = i;
+               ++i;
+               ++o;
        }
-
-       const DataType type = DataType::MIDI;
-
-       // Copy any MIDI 1:1 to outputs
-       assert(bufs.count().n_midi() == output_buffers().count().n_midi());
-       BufferSet::iterator o = output_buffers().begin(type);
-       for (BufferSet::iterator i = bufs.begin(type); i != bufs.end(type); ++i, ++o) {
-               o->read_from(*i, nframes, offset);
+       
+       /* extra outputs get a copy of the last buffer */
+       
+       while (o != _outputs.end(type)) {
+               Buffer& port_buffer (o->get_buffer (nframes, offset));
+               port_buffer.read_from(*prev, nframes, offset);
+               ++o;
        }
 }
 
@@ -324,8 +330,10 @@ IO::collect_input (BufferSet& outs, nframes_t nframes, nframes_t offset)
        for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
                
                BufferSet::iterator o = outs.begin(*t);
-               for (PortSet::iterator i = _inputs.begin(*t); i != _inputs.end(*t); ++i, ++o) {
-                       o->read_from(i->get_buffer(nframes,offset), nframes, offset);
+               PortSet::iterator e = _inputs.end (*t);
+               for (PortSet::iterator i = _inputs.begin(*t); i != e; ++i, ++o) {
+                       Buffer& b (i->get_buffer (nframes,offset));
+                       o->read_from (b, nframes, offset);
                }
 
        }
@@ -879,16 +887,6 @@ IO::ensure_inputs_locked (ChanCount count, bool clear, void* src)
        return changed;
 }
 
-/** Attach output_buffers to port buffers.
- * 
- * Connected to IO's own PortCountChanged signal.
- */
-void
-IO::attach_buffers(ChanCount ignored)
-{
-       _output_buffers->attach_buffers(_outputs);
-}
-
 int
 IO::ensure_io (ChanCount in, ChanCount out, bool clear, void* src)
 {
@@ -2321,6 +2319,8 @@ IO::set_gain (gain_t val, void *src)
                val = 1.99526231f;
        }
 
+       cerr << "set desired gain to " << val << " when curgain = " << _gain_control->get_value () << endl;
+
        if (src != _gain_control.get()) {
                _gain_control->set_value(val);
                // bit twisty, this will come back and call us again
@@ -2741,3 +2741,5 @@ IO::bundle_channel_name (uint32_t c, uint32_t n) const
 
        return "";
 }
+
+
index 08530b924ce8dfa8cca5ceabcc78ca7390f96ac6..fb27ba6f540d599c9dbc8299cc2b444591b5a79d 100644 (file)
@@ -43,10 +43,12 @@ 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)
+                         int input_min, int input_max,
+                         int output_min, int output_max, 
+                         DataType dtype,
+                         bool public_ports)
        : Processor(s, name, p)
-       , _io(new IO(s, name, input_min, input_max, output_min, output_max))
+       , _io (new IO(s, name, input_min, input_max, output_min, output_max, dtype, public_ports))
 {
        _active = false;
        _sort_key = 0;
index b200888508dc240729156e77936a87f9aaf50129..74de1922fee4143dadc9856406ba271b3869c1a3 100644 (file)
 #include "pbd/compose.h"
 #include <stdexcept>
 
-ARDOUR::AudioEngine* ARDOUR::Port::_engine = 0;
+using namespace std;
+using namespace ARDOUR;
+
+AudioEngine* Port::_engine = 0;
 
 /** @param n Port short name */
-ARDOUR::Port::Port (std::string const & n, DataType t, Flags f, bool e) : _jack_port (0), _last_monitor (false), _latency (0), _name (n), _flags (f)
+Port::Port (std::string const & n, DataType t, Flags f, bool e) 
+       : _jack_port (0)
+       , _last_monitor (false)
+       , _latency (0)
+       , _name (n)
+       , _flags (f)
 {
+
        /* Unfortunately we have to pass the DataType into this constructor so that we can
           create the right kind of JACK port; aside from this we'll use the virtual function type ()
-          to establish type. */
+          to establish type. 
+       */
 
        assert (_name.find_first_of (':') == std::string::npos);
        
        if (e) {
                try {
+                       cerr << "NEW PORT " << _name << " ext = " << e << endl;
                        do_make_external (t);
                }
                catch (...) {
@@ -47,7 +58,7 @@ ARDOUR::Port::Port (std::string const & n, DataType t, Flags f, bool e) : _jack_
 }
 
 /** Port destructor */
-ARDOUR::Port::~Port ()
+Port::~Port ()
 {
        if (_jack_port) {
                jack_port_unregister (_engine->jack (), _jack_port);
@@ -58,28 +69,27 @@ ARDOUR::Port::~Port ()
  * @param t Data type, so that we can call this method from the constructor.
  */
 void
-ARDOUR::Port::do_make_external (DataType t)
+Port::do_make_external (DataType t)
 {
        if (_jack_port) {
                /* already external */
                return;
        }
        
-       _jack_port = jack_port_register (_engine->jack (), _name.c_str (), t.to_jack_type (), _flags, 0);
-       if (_jack_port == 0) {
+       if ((_jack_port = jack_port_register (_engine->jack (), _name.c_str (), t.to_jack_type (), _flags, 0)) == 0) {
                throw std::runtime_error ("Could not register JACK port");
        }
 }
 
 void
-ARDOUR::Port::make_external ()
+Port::make_external ()
 {
        do_make_external (type ());
 }
 
 /** @return true if this port is connected to anything */
 bool
-ARDOUR::Port::connected () const
+Port::connected () const
 {
        if (!_connections.empty ()) {
                /* connected to a Port* */
@@ -94,8 +104,20 @@ ARDOUR::Port::connected () const
        return (jack_port_connected (_jack_port) != 0);
 }
 
+/** @return true if this port is connected to anything via an external port */
+bool
+Port::externally_connected () const
+{
+       if (_jack_port == 0) {
+               /* not using a JACK port, so can't be connected to anything else */
+               return false;
+       }
+       
+       return (jack_port_connected (_jack_port) != 0);
+}
+
 int
-ARDOUR::Port::disconnect_all ()
+Port::disconnect_all ()
 {
        /* Disconnect from Port* connections */
        for (std::set<Port*>::iterator i = _connections.begin (); i != _connections.end (); ++i) {
@@ -108,6 +130,8 @@ ARDOUR::Port::disconnect_all ()
        jack_port_disconnect (_engine->jack(), _jack_port);
        _named_connections.clear ();
 
+       check_buffer_status ();
+
        return 0;
 }
 
@@ -115,7 +139,7 @@ ARDOUR::Port::disconnect_all ()
  * @return true if this port is connected to o, otherwise false.
  */
 bool
-ARDOUR::Port::connected_to (std::string const & o) const
+Port::connected_to (std::string const & o) const
 {
        std::string const full = _engine->make_port_name_non_relative (o);
        std::string const shrt = _engine->make_port_name_non_relative (o);
@@ -137,7 +161,7 @@ ARDOUR::Port::connected_to (std::string const & o) const
 
 /** @param o Filled in with port full names of ports that we are connected to */
 int
-ARDOUR::Port::get_connections (std::vector<std::string> & c) const
+Port::get_connections (std::vector<std::string> & c) const
 {
        int n = 0;
 
@@ -163,7 +187,7 @@ ARDOUR::Port::get_connections (std::vector<std::string> & c) const
 }
 
 int
-ARDOUR::Port::connect (std::string const & other)
+Port::connect (std::string const & other)
 {
        /* caller must hold process lock */
 
@@ -197,11 +221,13 @@ ARDOUR::Port::connect (std::string const & other)
                }
        }
 
+       check_buffer_status ();
+
        return r;
 }
 
 int
-ARDOUR::Port::disconnect (std::string const & other)
+Port::disconnect (std::string const & other)
 {
        /* caller must hold process lock */
 
@@ -227,6 +253,8 @@ ARDOUR::Port::disconnect (std::string const & other)
                if (r == 0) {
                        _named_connections.erase (other);
                }
+
+               check_buffer_status ();
        }
 
        return r;
@@ -234,13 +262,13 @@ ARDOUR::Port::disconnect (std::string const & other)
 
 
 bool
-ARDOUR::Port::connected_to (Port* o) const
+Port::connected_to (Port* o) const
 {
        return connected_to (o->name ());
 }
 
 int
-ARDOUR::Port::connect (Port* o)
+Port::connect (Port* o)
 {
        /* caller must hold process lock */
 
@@ -253,11 +281,14 @@ ARDOUR::Port::connect (Port* o)
        _connections.insert (o);
        o->_connections.insert (this);
 
+       check_buffer_status ();
+       o->check_buffer_status ();
+
        return 0;
 }
 
 int
-ARDOUR::Port::disconnect (Port* o)
+Port::disconnect (Port* o)
 {
        if (external () && o->external ()) {
                /* we're both external; try disconnecting using name */
@@ -270,17 +301,20 @@ ARDOUR::Port::disconnect (Port* o)
        _connections.erase (o);
        o->_connections.erase (this);
 
+       check_buffer_status ();
+       o->check_buffer_status ();
+
        return 0;
 }
 
 void
-ARDOUR::Port::set_engine (AudioEngine* e)
+Port::set_engine (AudioEngine* e)
 {
        _engine = e;
 }
 
 void
-ARDOUR::Port::ensure_monitor_input (bool yn)
+Port::ensure_monitor_input (bool yn)
 {
        if (_jack_port) {
                jack_port_ensure_monitor (_jack_port, yn);
@@ -288,7 +322,7 @@ ARDOUR::Port::ensure_monitor_input (bool yn)
 }
 
 bool
-ARDOUR::Port::monitoring_input () const
+Port::monitoring_input () const
 {
        if (_jack_port) {
                return jack_port_monitoring_input (_jack_port);
@@ -298,7 +332,7 @@ ARDOUR::Port::monitoring_input () const
 }
 
 void
-ARDOUR::Port::reset ()
+Port::reset ()
 {
        _last_monitor = false;
 
@@ -308,7 +342,7 @@ ARDOUR::Port::reset ()
 }
 
 void
-ARDOUR::Port::recompute_total_latency () const
+Port::recompute_total_latency () const
 {
 #ifdef HAVE_JACK_RECOMPUTE_LATENCY     
        if (_jack_port) {
@@ -318,7 +352,7 @@ ARDOUR::Port::recompute_total_latency () const
 }
 
 nframes_t
-ARDOUR::Port::total_latency () const
+Port::total_latency () const
 {
        if (_jack_port) {
                return jack_port_get_total_latency (_engine->jack (), _jack_port);
@@ -328,7 +362,7 @@ ARDOUR::Port::total_latency () const
 }
 
 int
-ARDOUR::Port::reestablish ()
+Port::reestablish ()
 {
        if (!_jack_port) {
                return 0;
@@ -348,7 +382,7 @@ ARDOUR::Port::reestablish ()
 
 
 int
-ARDOUR::Port::reconnect ()
+Port::reconnect ()
 {
        /* caller must hold process lock; intended to be used only after reestablish() */
 
@@ -367,7 +401,7 @@ ARDOUR::Port::reconnect ()
 
 /** @param n Short name */
 int
-ARDOUR::Port::set_name (std::string const & n)
+Port::set_name (std::string const & n)
 {
        assert (_name.find_first_of (':') == std::string::npos);
 
@@ -386,15 +420,48 @@ ARDOUR::Port::set_name (std::string const & n)
 }
 
 void
-ARDOUR::Port::set_latency (nframes_t n)
+Port::set_latency (nframes_t n)
 {
        _latency = n;
 }
 
 void
-ARDOUR::Port::request_monitor_input (bool yn)
+Port::request_monitor_input (bool yn)
 {
        if (_jack_port) {
                jack_port_request_monitor (_jack_port, yn);
        }
 }
+
+void
+Port::check_buffer_status ()
+{
+       if (external() && receives_input()) {
+               if (!externally_connected()) {
+                       if (!_connections.empty()) {
+
+                               /* There are no external connections, so the
+                                  external port buffer will be the silent buffer. We cannot write into it.
+                                  But we have to write somewhere because there is at least one internal
+                                  connection that is supplying us with data.
+                               */
+
+                               if (!using_internal_data()) {
+                                       use_internal_data ();
+                               }
+
+                       } else {
+                               
+                               /* There are no external connections and no internal ones
+                                  either, so we can revert to use the externally supplied
+                                  buffer which will be silent (whatever the semantics of 
+                                  that are for a particular data type.
+                               */
+
+                               if (using_internal_data()) {
+                                       use_external_data ();
+                               }
+                       }
+               } 
+       }
+}
index a541ae0423d7e10e84e74c41779829c7bbf73d9c..a528a4587cc7a4e1d3d97ef297bb5cfdbca22a7d 100644 (file)
@@ -105,13 +105,6 @@ Processor::set_placement (Placement p)
        }
 }
 
-void
-Processor::set_active (bool yn)
-{
-       _active = yn; 
-       ActiveChanged (); 
-}
-
 XMLNode&
 Processor::get_state (void)
 {
index fab3c085dbf70ac5223a44cd8a64b209391983fc..14a8537068cbdd482ba68ff5346e9cb2a9b543f7 100644 (file)
@@ -35,6 +35,7 @@
 #include <ardour/plugin_insert.h>
 #include <ardour/port_insert.h>
 #include <ardour/send.h>
+#include <ardour/internal_send.h>
 #include <ardour/session.h>
 #include <ardour/utils.h>
 #include <ardour/configuration.h>
@@ -1229,6 +1230,11 @@ Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorStreams*
 int
 Route::add_processors (const ProcessorList& others, ProcessorStreams* err)
 {
+       /* NOTE: this is intended to be used ONLY when copying
+          processors from another Route. Hence the subtle
+          differences between this and ::add_processor()
+       */
+
        ChanCount old_pmo = processor_max_outs;
 
        if (!_session.engine().connected()) {
@@ -1292,7 +1298,7 @@ Route::disable_processors (Placement p)
        
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
                if ((*i)->placement() == p) {
-                       (*i)->set_active (false);
+                       (*i)->deactivate ();
                }
        }
 
@@ -1308,7 +1314,7 @@ Route::disable_processors ()
        Glib::RWLock::ReaderLock lm (_processor_lock);
        
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
-               (*i)->set_active (false);
+               (*i)->deactivate ();
        }
        
        _session.set_dirty ();
@@ -1325,7 +1331,7 @@ Route::disable_plugins (Placement p)
        
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
                if (boost::dynamic_pointer_cast<PluginInsert> (*i) && (*i)->placement() == p) {
-                       (*i)->set_active (false);
+                       (*i)->deactivate ();
                }
        }
        
@@ -1342,7 +1348,7 @@ Route::disable_plugins ()
        
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
                if (boost::dynamic_pointer_cast<PluginInsert> (*i)) {
-                       (*i)->set_active (false);
+                       (*i)->deactivate ();
                }
        }
        
@@ -1367,7 +1373,7 @@ Route::ab_plugins (bool forward)
                        }
 
                        if ((*i)->active()) {
-                               (*i)->set_active (false);
+                               (*i)->deactivate ();
                                (*i)->set_next_ab_is_active (true);
                        } else {
                                (*i)->set_next_ab_is_active (false);
@@ -1385,9 +1391,9 @@ Route::ab_plugins (bool forward)
                        }
 
                        if ((*i)->get_next_ab_is_active()) {
-                               (*i)->set_active (true);
+                               (*i)->activate ();
                        } else {
-                               (*i)->set_active (false);
+                               (*i)->deactivate ();
                        }
                }
        }
@@ -1602,9 +1608,11 @@ Route::_reset_processor_counts (ProcessorStreams* err)
 
                } else if (boost::dynamic_pointer_cast<Send> (*r) != 0) {
                        ++send_cnt;
+               } else if (boost::dynamic_pointer_cast<InternalSend> (*r) != 0) {
+                       ++send_cnt;
                }
        }
-       
+
        if (insert_cnt == 0) {
                if (send_cnt) {
                        goto recompute;
@@ -1665,20 +1673,32 @@ Route::_reset_processor_counts (ProcessorStreams* err)
 
        for (r = _processors.begin(); r != _processors.end(); prev = r, ++r) {
                boost::shared_ptr<Send> s;
+               boost::shared_ptr<InternalSend> is;
 
                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 if ((is = boost::dynamic_pointer_cast<InternalSend> (*r)) != 0) {
+
+                       /* XXX ditto, but clean this inheritance pattern up someday soon */
+
+                       if (r == _processors.begin()) {
+                               is->expect_inputs (n_inputs());
+                       } else {
+                               is->expect_inputs ((*prev)->output_streams());
+                       }
+
                } else {
                        
-                       /* don't pay any attention to send output configuration, since it doesn't
-                          affect the route.
-                        */
-                       
                        max_audio = max ((*r)->output_streams ().n_audio(), max_audio);
                        max_midi = max ((*r)->output_streams ().n_midi(), max_midi);
                }
@@ -1711,8 +1731,6 @@ Route::apply_some_processor_counts (list<ProcessorCount>& iclist)
 
                ProcessorCount& pc (*i);
 
-               cerr << "now applying for " << (*i).processor->name() << " in = " << pc.in.n_audio() << " out = " << pc.out.n_audio() << endl;
-
                if (pc.processor->configure_io (pc.in, pc.out)) {
                        return -1;
                }
@@ -1743,8 +1761,6 @@ Route::check_some_processor_counts (list<ProcessorCount>& iclist, ChanCount requ
 
        for (i = iclist.begin(); i != iclist.end(); ++i, ++index) {
 
-               cerr << "Checking whether " << (*i).processor->name() << " can support " << required_inputs.n_audio() << " inputs\n";
-
                if (!(*i).processor->can_support_io_configuration (required_inputs, (*i).out)) {
                        if (err) {
                                err->index = index;
@@ -1853,7 +1869,11 @@ Route::all_processors_flip ()
        bool first_is_on = _processors.front()->active();
        
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
-               (*i)->set_active (!first_is_on);
+               if (first_is_on) {
+                       (*i)->deactivate ();
+               } else {
+                       (*i)->activate ();
+               }
        }
        
        _session.set_dirty ();
@@ -1874,7 +1894,11 @@ Route::all_processors_active (Placement p, bool state)
 
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
                if ((*i)->placement() == p) {
-                       (*i)->set_active (state);
+                       if (state) {
+                               (*i)->activate ();
+                       } else {
+                               (*i)->deactivate ();
+                       }
                }
        }
        
index 58352a5dfe5be41dd0725a49389b3988fca6b61e..d562ddff3f2860dcdbde46dc5a5a4351b568921c 100644 (file)
@@ -140,7 +140,7 @@ Send::set_state(const XMLNode& node)
                if ((*niter)->name() == "IOProcessor") {
                        insert_node = *niter;
                } else if ((*niter)->name() == X_("Automation")) {
-                       _io->set_automation_state (*(*niter), Evoral::Parameter(GainAutomation));
+                       // _io->set_automation_state (*(*niter), Evoral::Parameter(GainAutomation));
                }
        }
        
@@ -165,10 +165,10 @@ Send::run_in_place (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame,
                _io->deliver_output (sendbufs, start_frame, end_frame, nframes, offset);
 
                if (_metering) {
-                       if (_io->_gain == 0) {
-                               _io->_meter->reset();
+                       if (_io->effective_gain() == 0) {
+                               _io->peak_meter().reset();
                        } else {
-                               _io->_meter->run_in_place(_io->output_buffers(), start_frame, end_frame, nframes, offset);
+                               _io->peak_meter().run_in_place(_io->output_buffers(), start_frame, end_frame, nframes, offset);
                        }
                }
 
@@ -176,7 +176,7 @@ Send::run_in_place (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame,
                _io->silence (nframes, offset);
                
                if (_metering) {
-                       _io->_meter->reset();
+                       _io->peak_meter().reset();
                }
        }
 }
index 59b873e87f22426f11f2259242ccc8d58bd45188..6e7fe3a0f6186daed5ef04a75af8ea5d727ba368 100644 (file)
@@ -72,6 +72,7 @@
 #include <ardour/named_selection.h>
 #include <ardour/crossfade.h>
 #include <ardour/playlist.h>
+#include <ardour/internal_send.h>
 #include <ardour/click.h>
 #include <ardour/data_type.h>
 #include <ardour/buffer_set.h>
@@ -1822,7 +1823,7 @@ Session::set_remote_control_ids ()
 }
 
 
-Session::RouteList
+RouteList
 Session::new_audio_route (int input_channels, int output_channels, uint32_t how_many)
 {
        char bus_name[32];
@@ -3685,6 +3686,8 @@ Session::add_processor (Processor* processor)
                _plugin_inserts.insert (_plugin_inserts.begin(), plugin_insert);
        } else if ((send = dynamic_cast<Send *> (processor)) != 0) {
                _sends.insert (_sends.begin(), send);
+       } else if (dynamic_cast<InternalSend *> (processor) != 0) {
+               /* relax */
        } else {
                fatal << _("programming error: unknown type of Insert created!") << endmsg;
                /*NOTREACHED*/
@@ -3710,6 +3713,8 @@ Session::remove_processor (Processor* processor)
                }
        } else if ((plugin_insert = dynamic_cast<PluginInsert *> (processor)) != 0) {
                _plugin_inserts.remove (plugin_insert);
+       } else if (dynamic_cast<InternalSend *> (processor) != 0) {
+               /* relax */
        } else if ((send = dynamic_cast<Send *> (processor)) != 0) {
                list<Send*>::iterator x = find (_sends.begin(), _sends.end(), send);
                if (x != _sends.end()) {
index 521a6cb9caf775f0e5ec65e1ead4904cb155a7f0..af2cef56784f4c4b3a0136d8d7c1ac7890012922 100644 (file)
@@ -151,14 +151,22 @@ PixFader::on_button_release_event (GdkEventButton* ev)
                                /* no motion - just a click */
 
                                if (ev->state & Gdk::SHIFT_MASK) {
+                                       cerr << "SV A\n";
                                        adjustment.set_value (default_value);
+                                       cerr << "SV A OUT\n";
                                } else if (ev->state & fine_scale_modifier) {
+                                       cerr << "SV B\n";
                                        adjustment.set_value (adjustment.get_lower());
+                                       cerr << "SV B OUT\n";
                                } else if ((_orien == VERT && ev_pos < span - display_span()) || (_orien == HORIZ && ev_pos > span - display_span())) {
                                        /* above the current display height, remember X Window coords */
+                                       cerr << "SV C\n";
                                        adjustment.set_value (adjustment.get_value() + adjustment.get_step_increment());
+                                       cerr << "SV C OUT\n";
                                } else {
+                                       cerr << "SV D\n";
                                        adjustment.set_value (adjustment.get_value() - adjustment.get_step_increment());
+                                       cerr << "SV D OUT\n";
                                }
                        }
 
index d7981be771376bf8cc808eb5698a7329d0b98f13..5a395641caeb8f34b6bf4159954b63fe99232071 100644 (file)
@@ -54,6 +54,8 @@ xml++.cc
 conf = Configure(pbd)
 if conf.CheckFunc('getmntent'):
     conf.env.Append(CCFLAGS="-DHAVE_GETMNTENT")
+if conf.CheckCHeader('execinfo.h'):
+    conf.env.Append(CXXFLAGS="-DHAVE_EXECINFO")
 pbd = conf.Finish()
 
 pbd.Merge ([ libraries['sigc2'],
index 39dd46be3d523c1399c321de692ed1c6f8c2970d..c517967fa22f5a1253cfe9368af78f0d4f66eb29 100644 (file)
@@ -30,7 +30,6 @@ PBD::trace_twb ()
 #ifdef HAVE_EXECINFO
 
 #include <execinfo.h>
-#include <cstdlib>
 
 void
 PBD::stacktrace (std::ostream& out, int levels)
index b29c26b0d37850d4bdd09d576f8e922dd5b0bb08..18dbd28c0e15a85cfd3801562def78afec2d80e9 100644 (file)
@@ -218,7 +218,7 @@ MackieControlProtocol::Sorted MackieControlProtocol::get_sorted_routes()
        Sorted sorted;
        
        // fetch all routes
-       boost::shared_ptr<Session::RouteList> routes = session->get_routes();
+       boost::shared_ptr<RouteList> routes = session->get_routes();
        set<uint32_t> remote_ids;
        
        // routes with remote_id 0 should never be added
@@ -227,7 +227,7 @@ MackieControlProtocol::Sorted MackieControlProtocol::get_sorted_routes()
        
        // sort in remote_id order, and exclude master, control and hidden routes
        // and any routes that are already set.
-       for ( Session::RouteList::iterator it = routes->begin(); it != routes->end(); ++it )
+       for (RouteList::iterator it = routes->begin(); it != routes->end(); ++it )
        {
                Route & route = **it;
                if (
@@ -1460,7 +1460,7 @@ void MackieControlProtocol::notify_parameter_changed( const char * name_str )
 }
 
 // RouteList is the set of routes that have just been added
-void MackieControlProtocol::notify_route_added( ARDOUR::Session::RouteList & rl )
+void MackieControlProtocol::notify_route_added( ARDOUR::RouteList & rl )
 {
        // currently assigned banks are less than the full set of
        // strips, so activate the new strip now.
@@ -1471,7 +1471,7 @@ void MackieControlProtocol::notify_route_added( ARDOUR::Session::RouteList & rl
        // otherwise route added, but current bank needs no updating
        
        // make sure remote id changes in the new route are handled
-       typedef ARDOUR::Session::RouteList ARS;
+       typedef ARDOUR::RouteList ARS;
        for ( ARS::iterator it = rl.begin(); it != rl.end(); ++it )
        {
                connections_back = (*it)->RemoteControlIDChanged.connect( ( mem_fun (*this, &MackieControlProtocol::notify_remote_id_changed) ) );
index 7d726e70ee937492778e7dd2bfcf11933f53b31c..456fb49485c3363a01b7580deaca9c347b35a7ad 100644 (file)
@@ -102,7 +102,7 @@ class MackieControlProtocol
        /// Signal handler from Panner::Change
        void notify_panner_changed( Mackie::RouteSignal *, bool force_update = true );
        /// Signal handler for new routes added
-       void notify_route_added( ARDOUR::Session::RouteList & );
+       void notify_route_added( ARDOUR::RouteList & );
        /// Signal handler for Route::active_changed
        void notify_active_changed( Mackie::RouteSignal * );
  
index 45039933604b8ce2d08ccc0d611d6440c80ca18b..d8ff311486e8fbda02e653efae5defebcdfeaa60 100644 (file)
@@ -43,6 +43,7 @@
 #include <ardour/filesystem_paths.h>
 
 #include "osc.h"
+#include "osc_controllable.h"
 #include "i18n.h"
 
 using namespace ARDOUR;
@@ -74,7 +75,7 @@ OSC::OSC (Session& s, uint32_t port)
 
        /* catch up with existing routes */
 
-       boost::shared_ptr<Session::RouteList> rl = session->get_routes ();
+       boost::shared_ptr<RouteList> rl = session->get_routes ();
        route_added (*(rl.get()));
 
        // session->RouteAdded.connect (mem_fun (*this, &OSC::route_added));
@@ -562,29 +563,23 @@ OSC::catchall (const char *path, const char *types, lo_arg **argv, int argc, lo_
 
                lo_message reply = lo_message_new ();
 
-               if (argc > 0) {
-                       int id = argv[0]->i;
-                       boost::shared_ptr<Route> r = session->route_by_remote_id (id);
-                       
-                       if (!r) {
-                               lo_message_add_string (reply, "not found");
-                               cerr << "no such route\n";
-                       } else {                        
-                               
-                               ListenerPair listener;
+               if (argc <= 0) {
+                       lo_message_add_string (reply, "syntax error");
+               } else {
+                       for (int n = 0; n < argc; ++n) {
 
-                               listener.first = r.get();
-                               listener.second = lo_message_get_source (msg);
-                               
-                               cerr << "add listener\n";
+                               boost::shared_ptr<Route> r = session->route_by_remote_id (argv[n]->i);
                                
-                               listen_to_route (listener);
-
-                               lo_message_add_string (reply, "0");
+                               if (!r) {
+                                       lo_message_add_string (reply, "not found");
+                                       cerr << "no such route\n";
+                                       break;
+                               } else {                        
+                                       cerr << "add listener\n";
+                                       listen_to_route (r, lo_message_get_source (msg));
+                                       lo_message_add_int32 (reply, argv[n]->i);
+                               }
                        }
-
-               } else {
-                       lo_message_add_string (reply, "syntax error");
                }
 
                lo_send_message (lo_message_get_source (msg), "#reply", reply);
@@ -592,17 +587,12 @@ OSC::catchall (const char *path, const char *types, lo_arg **argv, int argc, lo_
 
        } else if (strcmp (path, "/routes/ignore") == 0) {
 
-               if (argc > 0) {
-                       int id = argv[0]->i;
-                       boost::shared_ptr<Route> r = session->route_by_remote_id (id);
+               for (int n = 0; n < argc; ++n) {
+
+                       boost::shared_ptr<Route> r = session->route_by_remote_id (argv[n]->i);
                        
                        if (r) {
-                               ListenerPair listener;
-
-                               listener.first = r.get();
-                               listener.second = lo_message_get_source (msg);
-                               
-                               drop_listener_pair (listener);
+                               end_listen (r, lo_message_get_source (msg));
                        }
                }
        }
@@ -611,55 +601,86 @@ OSC::catchall (const char *path, const char *types, lo_arg **argv, int argc, lo_
 }
 
 void
-OSC::route_added (Session::RouteList& rl)
+OSC::route_added (RouteList& rl)
 {
 }
 
 void
-OSC::listen_to_route (const ListenerPair& lp)
+OSC::listen_to_route (boost::shared_ptr<Route> route, lo_address addr)
 {
-       Listeners::iterator x;
+       Controllables::iterator x;
        bool route_exists = false;
 
        cerr << "listen to route\n";
 
-       /* check existing listener pairs to avoid duplicate listens */
-
-       for (x = listeners.begin(); x != listeners.end(); ++x) {
-
-               if ((*x)->route == lp.first) {
-                       route_exists = true;
+       /* avoid duplicate listens */
+       
+       for (x = controllables.begin(); x != controllables.end(); ++x) {
+               
+               OSCRouteControllable* rc;
 
-                       if ((*x)->addr == lp.second ) {
-                               return;
+               if ((rc = dynamic_cast<OSCRouteControllable*>(*x)) != 0) {
+                       
+                       if (rc->route() == route) {
+                               route_exists = true;
+                               
+                               /* XXX NEED lo_address_equal() */
+                               
+                               if (rc->address() == addr) {
+                                       return;
+                               }
                        }
                }
        }
 
-       Listener* l = new Listener (lp.first, lp.second);
-
        cerr << "listener binding to signals\n";
 
-       l->connections.push_back (lp.first->solo_changed.connect (bind (mem_fun (*this, &OSC::route_changed), RouteSolo, lp.first, lp.second)));
-       l->connections.push_back (lp.first->mute_changed.connect (bind (mem_fun (*this, &OSC::route_changed), RouteMute, lp.first, lp.second)));
-       l->connections.push_back (lp.first->gain_control()->Changed.connect (bind (mem_fun (*this, &OSC::route_changed_deux), RouteGain, lp.first, lp.second)));
+       OSCControllable* c;
+       string path;
+
+       path = X_("/route/solo");
+       c = new OSCRouteControllable (addr, path, route->solo_control(), route);
+       controllables.push_back (c);
+
+       path = X_("/route/mute");
+       c = new OSCRouteControllable (addr, path, route->mute_control(), route);
+       controllables.push_back (c);
+
+       path = X_("/route/gain");
+       c = new OSCRouteControllable (addr, path, route->gain_control(), route);
+       controllables.push_back (c);
+
+       cerr << "Now have " << controllables.size() << " controllables\n";
+
+       /* if there is no existing controllable related to this route, make sure we clean up
+          if it is ever deleted.
+       */
        
        if (!route_exists) {
-               l->route->GoingAway.connect (bind (mem_fun (*this, &OSC::drop_listeners_by_route), l->route));
+               route->GoingAway.connect (bind (mem_fun (*this, &OSC::drop_route), boost::weak_ptr<Route> (route)));
        }
-
-       listeners.push_back (l);
 }
 
 void
-OSC::drop_listeners_by_route (Route* r)
+OSC::drop_route (boost::weak_ptr<Route> wr)
 {
-       Listeners::iterator x;
+       boost::shared_ptr<Route> r = wr.lock ();
+
+       if (!r) {
+               return;
+       }
+
+       for (Controllables::iterator x = controllables.begin(); x != controllables.end();) {
 
-       for (x = listeners.begin(); x != listeners.end();) {
-               if ((*x)->route == r) {
-                       delete *x;
-                       x = listeners.erase (x);
+               OSCRouteControllable* rc;
+               
+               if ((rc = dynamic_cast<OSCRouteControllable*>(*x)) != 0) {
+                       if (rc->route() == r) {
+                               delete *x;
+                               x = controllables.erase (x);
+                       } else {
+                               ++x;
+                       }
                } else {
                        ++x;
                }
@@ -667,14 +688,22 @@ OSC::drop_listeners_by_route (Route* r)
 }
 
 void
-OSC::drop_listener_pair (const ListenerPair& lp)
+OSC::end_listen (boost::shared_ptr<Route> r, lo_address addr)
 {
-       Listeners::iterator x;
+       Controllables::iterator x;
 
-       for (x = listeners.begin(); x != listeners.end(); ++x) {
-               if ((*x)->route == lp.first && (*x)->addr == lp.second) {
-                       listeners.erase (x);
-                       return;
+       for (x = controllables.begin(); x != controllables.end(); ++x) {
+
+               OSCRouteControllable* rc;
+               
+               if ((rc = dynamic_cast<OSCRouteControllable*>(*x)) != 0) {
+
+                       /* XXX NEED lo_address_equal () */
+
+                       if (rc->route() == r && rc->address() == addr) {
+                               controllables.erase (x);
+                               return;
+                       }
                }
        }
 }
@@ -692,61 +721,6 @@ OSC::session_exported( std::string path, std::string name ) {
        lo_send( listener, "/session/exported", "ss", path.c_str(), name.c_str() );
 }
 
-void
-OSC::set_send_route_changes (bool yn)
-{
-       _send_route_changes = yn;
-}
-
-void
-OSC::route_changed (void* src, RouteChangeType what, Route* r, lo_address addr)
-{
-       route_changed_deux (what, r, addr);
-}
-
-void
-OSC::route_changed_deux (RouteChangeType what, Route* r, lo_address addr)
-{
-       if (!_send_route_changes) {
-               return;
-       }
-
-       string prefix = _namespace_root;
-       int ret;
-
-       switch (what) {
-
-       case OSC::RouteSolo:
-               prefix += "/changed/route/solo";
-               ret = lo_send (addr, prefix.c_str(), "ii", r->remote_control_id(), (int) r->soloed());
-               break;
-
-       case OSC::RouteMute:
-               prefix += "/changed/route/mute";
-               ret = lo_send (addr, prefix.c_str(), "ii", r->remote_control_id(), (int) r->muted());
-               break;
-
-       case OSC::RouteGain:
-               prefix += "/changed/route/gain";
-               ret = lo_send (addr, prefix.c_str(), "if", r->remote_control_id(), r->effective_gain());
-
-       default:
-               error << "OSC: unhandled route change\n";
-               return;
-       }
-
-       if (ret < 0) {
-               ListenerPair lp;
-
-               lp.first = r;
-               lp.second = addr;
-
-               cerr << "Error sending to listener ... dropping\n";
-               drop_listener_pair (lp);
-       }
-
-}
-
 // end "Application Hook" Handlers //
 
 /* path callbacks */
index b2417474fc9c130edd4d1672582f1cb3f5ec7c20..4eebc906bb30e7224c4fe2be0498c9ae0f51dc56 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006 Paul Davis
+ * Copyright (C) 2006-2009 Paul Davis
  *  
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -25,6 +25,8 @@
 #include <sys/time.h>
 #include <pthread.h>
 
+#include <boost/shared_ptr.hpp>
+
 #include <lo/lo.h>
 
 #include <sigc++/sigc++.h>
 #include <ardour/session.h>
 #include <control_protocol/control_protocol.h>
 
-namespace ARDOUR {
+class OSCControllable;
 
+namespace ARDOUR {
 class Session;
 class Route;
+}
        
-class OSC : public ControlProtocol
+class OSC : public ARDOUR::ControlProtocol
 {
   public:
-       OSC (Session&, uint32_t port);
+       OSC (ARDOUR::Session&, uint32_t port);
        virtual ~OSC();
 
        XMLNode& get_state ();
@@ -53,8 +57,6 @@ class OSC : public ControlProtocol
        bool get_feedback () const;
 
        void set_namespace_root (std::string);
-       bool send_route_changes () const { return _send_route_changes; }
-       void set_send_route_changes (bool yn);
 
        int start ();
        int stop ();
@@ -82,21 +84,12 @@ class OSC : public ControlProtocol
 
        void register_callbacks ();
 
-       void route_added (ARDOUR::Session::RouteList&);
+       void route_added (ARDOUR::RouteList&);
                
        // Handlers for "Application Hook" signals
        void session_loaded (ARDOUR::Session&);
        void session_exported (std::string, std::string);
 
-       enum RouteChangeType {
-               RouteSolo,
-               RouteMute,
-               RouteGain
-       };
-
-       void route_changed (void* ignored, RouteChangeType, ARDOUR::Route*, lo_address);
-       void route_changed_deux (RouteChangeType, ARDOUR::Route*, lo_address);
-
        // end "Application Hook" handles
 
        std::string get_server_url ();
@@ -173,24 +166,13 @@ class OSC : public ControlProtocol
        int route_set_gain_abs (int rid, float level);
        int route_set_gain_dB (int rid, float dB);
 
-       struct Listener {
-           Route* route;
-           lo_address addr;
-           std::vector<sigc::connection> connections;
-
-           Listener (Route* r, lo_address a) : route (r), addr (a) {}
-       };
-
-       typedef std::pair<Route*, lo_address> ListenerPair;
-       typedef std::list<Listener*> Listeners;
+       void listen_to_route (boost::shared_ptr<ARDOUR::Route>, lo_address);
+       void end_listen (boost::shared_ptr<ARDOUR::Route>, lo_address);
+       void drop_route (boost::weak_ptr<ARDOUR::Route>);
 
-       Listeners listeners;
+       typedef std::list<OSCControllable*> Controllables;
 
-       void listen_to_route (const ListenerPair&);
-       void drop_listener_pair (const ListenerPair&);
-       void drop_listeners_by_route (Route*);
+       Controllables controllables;
 };
 
-}
-
 #endif // ardour_osc_h
index 12959652b8d789bcba8555fbcf1954e79b854d8d..66e70c7e7a5576c41d2414c8162880f34ef6b0e4 100644 (file)
 #include <pbd/error.h>
 #include <pbd/xml++.h>
 
+#include <ardour/route.h>
+
 #include "osc_controllable.h"
 
 using namespace sigc;
 using namespace PBD;
 using namespace ARDOUR;
 
-OSCControllable::OSCControllable (lo_address a, Controllable& c)
+OSCControllable::OSCControllable (lo_address a, const string& p, boost::shared_ptr<Controllable> c)
        : controllable (c)
        , addr (a)
+       , path (p)
 {
+       c->Changed.connect (mem_fun (*this, &OSCControllable::send_change));
 }
 
 OSCControllable::~OSCControllable ()
@@ -42,7 +46,7 @@ OSCControllable::~OSCControllable ()
 XMLNode&
 OSCControllable::get_state ()
 {
-       XMLNode& root (controllable.get_state());
+       XMLNode& root (controllable->get_state());
        return root;
 }
 
@@ -52,3 +56,43 @@ OSCControllable::set_state (const XMLNode& node)
        return 0;
 }
 
+void
+OSCControllable::send_change ()
+{
+       lo_message msg = lo_message_new ();
+       
+       lo_message_add_float (msg, (float) controllable->get_value());
+
+       /* XXX thread issues */
+
+       lo_send_message (addr, path.c_str(), msg);
+       lo_message_free (msg);
+}
+
+/*------------------------------------------------------------*/       
+
+OSCRouteControllable::OSCRouteControllable (lo_address a, const string& p, 
+                                           boost::shared_ptr<Controllable> c, boost::shared_ptr<Route> r)
+       : OSCControllable (a, p, c)
+       , _route (r)
+{
+}
+
+OSCRouteControllable::~OSCRouteControllable ()
+{
+}
+
+void
+OSCRouteControllable::send_change ()
+{
+       lo_message msg = lo_message_new ();
+
+       lo_message_add_int32 (msg, _route->remote_control_id());
+       lo_message_add_float (msg, (float) controllable->get_value());
+
+       /* XXX thread issues */
+
+       cerr << "ORC: send " << path << " = " << controllable->get_value() << endl;
+       lo_send_message (addr, path.c_str(), msg);
+       lo_message_free (msg);
+}
index 48183138ec4e17deb8cf724c876a61650389bbe3..61261a8f1c40bfdc750c295148b391e52ad528c7 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 1998-2006 Paul Davis
+    Copyright (C) 2009 Paul Davis
  
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -21,7 +21,7 @@
 #define __osc_osccontrollable_h__
 
 #include <string>
-
+#include <boost/shared_ptr.hpp>
 #include <sigc++/sigc++.h>
 #include <lo/lo.h>
 
 #include <pbd/stateful.h>
 #include <ardour/types.h>
 
+namespace ARDOUR {
+
+class Route;
+
+}
+
 class OSCControllable : public PBD::Stateful
 {
   public:
-       OSCControllable (lo_address addr, PBD::Controllable&);
+       OSCControllable (lo_address addr, const string& path, boost::shared_ptr<PBD::Controllable>);
        virtual ~OSCControllable ();
 
+       lo_address address() const { return addr; }
+
        XMLNode& get_state ();
        int set_state (const XMLNode& node);
 
-  private:
-       PBD::Controllable& controllable;
+  protected:
+       boost::shared_ptr<PBD::Controllable> controllable;
        lo_address addr;
+       string path;
+
+       virtual void send_change ();
+};
+
+class OSCRouteControllable : public OSCControllable
+{
+
+  public:
+       OSCRouteControllable (lo_address addr, const string& path, 
+                             boost::shared_ptr<PBD::Controllable>, 
+                             boost::shared_ptr<ARDOUR::Route>);
+       ~OSCRouteControllable ();
+
+       boost::shared_ptr<ARDOUR::Route> route() const { return _route; }
+
+  private:
+       boost::shared_ptr<ARDOUR::Route> _route;
+
+       void send_change ();
 };
 
 #endif /* __osc_osccontrollable_h__ */