drastic, deep and wide changes to make RouteGroup use boost::shared_ptr<Route> and...
authorPaul Davis <paul@linuxaudiosystems.com>
Thu, 10 Dec 2009 03:25:32 +0000 (03:25 +0000)
committerPaul Davis <paul@linuxaudiosystems.com>
Thu, 10 Dec 2009 03:25:32 +0000 (03:25 +0000)
git-svn-id: svn://localhost/ardour2/branches/3.0@6334 d708f5d6-7413-0410-9779-e7cbd77b26cf

30 files changed:
gtk2_ardour/editor.cc
gtk2_ardour/editor.h
gtk2_ardour/editor_route_groups.cc
gtk2_ardour/editor_routes.cc
gtk2_ardour/group_tabs.cc
gtk2_ardour/mixer_strip.cc
gtk2_ardour/mixer_strip.h
gtk2_ardour/mixer_ui.cc
gtk2_ardour/port_group.cc
gtk2_ardour/public_editor.h
gtk2_ardour/route_group_menu.cc
gtk2_ardour/route_time_axis.cc
gtk2_ardour/route_ui.cc
libs/ardour/ardour/pi_controller.h
libs/ardour/ardour/route.h
libs/ardour/ardour/route_group.h
libs/ardour/ardour/route_group_member.h [new file with mode: 0644]
libs/ardour/ardour/route_group_specialized.h
libs/ardour/ardour/slave.h
libs/ardour/mtc_slave.cc
libs/ardour/pi_controller.cc
libs/ardour/route.cc
libs/ardour/route_group.cc
libs/ardour/route_group_member.cc [new file with mode: 0644]
libs/ardour/session.cc
libs/ardour/session_process.cc
libs/ardour/session_state.cc
libs/ardour/wscript
libs/surfaces/control_protocol/basic_ui.cc
libs/surfaces/control_protocol/control_protocol/basic_ui.h

index c21393247c532ac78710c84ced367940a1194243..5cbe2b7c6a5c7a362dd5b4a1edaeead56ae44664 100644 (file)
@@ -4805,12 +4805,12 @@ Editor::streamview_height_changed ()
 }
 
 TimeAxisView*
-Editor::axis_view_from_route (Route* r) const
+Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
 {
        TrackViewList::const_iterator j = track_views.begin ();
        while (j != track_views.end()) {
                RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
-               if (rtv && rtv->route().get() == r) {
+               if (rtv && rtv->route() == r) {
                        return rtv;
                }
                ++j;
@@ -4821,11 +4821,11 @@ Editor::axis_view_from_route (Route* r) const
 
 
 TrackSelection
-Editor::axis_views_from_routes (list<Route*> r) const
+Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
 {
        TrackSelection t;
 
-       for (list<Route*>::const_iterator i = r.begin(); i != r.end(); ++i) {
+       for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
                TimeAxisView* tv = axis_view_from_route (*i);
                if (tv) {
                        t.push_back (tv);
index 73a4649e949d100606eed6f20ea691f70c475ba1..49135f0f9e42a6e5e1e8251790d8378055095de5 100644 (file)
@@ -950,8 +950,8 @@ class Editor : public PublicEditor
        /* track views */
        TrackViewList track_views;
        std::pair<TimeAxisView*, ARDOUR::layer_t> trackview_by_y_position (double);
-       TimeAxisView* axis_view_from_route (ARDOUR::Route *) const;
-       TrackSelection axis_views_from_routes (std::list<ARDOUR::Route *>) const;
+       TimeAxisView* axis_view_from_route (boost::shared_ptr<ARDOUR::Route>) const;
+       TrackSelection axis_views_from_routes (boost::shared_ptr<ARDOUR::RouteList>) const;
 
        TrackSelection get_tracks_for_range_action () const;
 
index 79049e02bcb19e6f27ec923e5789b8e4f8a82043..bb094e2cc057a8f2dddf10e68136786760785df0 100644 (file)
@@ -271,7 +271,7 @@ EditorRouteGroups::run_new_group_dialog (const RouteList& rl)
        case Gtk::RESPONSE_ACCEPT:
                _session->add_route_group (g);
                for (RouteList::const_iterator i = rl.begin(); i != rl.end(); ++i) {
-                       (*i)->set_route_group (g, this);
+                       g->add (*i);
                }
                break;
        default:
@@ -673,7 +673,7 @@ EditorRouteGroups::connect_to_session (Session* s)
 }
 
 struct CollectSorter {
-       bool operator () (Route* a, Route* b) {
+    bool operator () (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
                return a->order_key (N_ ("editor")) < b->order_key (N_ ("editor"));
        }
 };
@@ -684,16 +684,16 @@ struct CollectSorter {
 void
 EditorRouteGroups::collect (RouteGroup* g)
 {
-       list<Route*> routes = g->route_list ();
-       routes.sort (CollectSorter ());
-       int const N = routes.size ();
+       boost::shared_ptr<RouteList> routes = g->route_list ();
+       routes->sort (CollectSorter ());
+       int const N = routes->size ();
 
-       list<Route*>::iterator i = routes.begin ();
+       RouteList::iterator i = routes->begin ();
        Editor::TrackViewList::const_iterator j = _editor->get_track_views().begin();
 
        int diff = 0;
        int coll = -1;
-       while (i != routes.end() && j != _editor->get_track_views().end()) {
+       while (i != routes->end() && j != _editor->get_track_views().end()) {
 
                RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
                if (rtv) {
@@ -701,7 +701,7 @@ EditorRouteGroups::collect (RouteGroup* g)
                        boost::shared_ptr<Route> r = rtv->route ();
                        int const k = r->order_key (N_ ("editor"));
 
-                       if (*i == r.get()) {
+                       if (*i == r) {
 
                                if (coll == -1) {
                                        coll = k;
index e92e0544262c8367502bc73c71e2e5cc2f701b7f..100c552be75e6a548a33a7615eeeb3991caf814e 100644 (file)
@@ -946,7 +946,7 @@ EditorRoutes::show_tracks_with_regions_at_playhead ()
 
        set<TimeAxisView*> show;
        for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
-               TimeAxisView* tav = _editor->axis_view_from_route (i->get ());
+               TimeAxisView* tav = _editor->axis_view_from_route (*i);
                if (tav) {
                        show.insert (tav);
                }
index b099c0d309f6a79f76b26e1a1125d3d7983b9663..571368fe93b6caddf5f2f220cdc19c3043df99e9 100644 (file)
@@ -183,7 +183,7 @@ GroupTabs::on_button_release_event (GdkEventButton* ev)
                                RouteGroup* g = new_route_group ();
                                if (g) {
                                        for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) {
-                                               (*i)->set_route_group (g, this);
+                                               g->add (*i);
                                        }
                                }
                        } else {
@@ -193,10 +193,10 @@ GroupTabs::on_button_release_event (GdkEventButton* ev)
                                        if (find (routes.begin(), routes.end(), *i) == routes.end()) {
                                                /* this route is not on the list of those that should be in _dragging's group */
                                                if ((*i)->route_group() == _dragging->group) {
-                                                       (*i)->drop_route_group (this);
+                                                       _dragging->group->remove (*i);
                                                }
                                        } else {
-                                               (*i)->set_route_group (_dragging->group, this);
+                                               _dragging->group->add (*i);
                                        }
                                }
                        }
index 8e67b4b52674df1950469dfc2a8da7faf2c3f94b..22b39c1a298dabe16c13ad386bcb2b203367e8e4 100644 (file)
@@ -447,7 +447,7 @@ MixerStrip::set_route (boost::shared_ptr<Route> rt)
        solo_changed (0);
        name_changed ();
        comment_changed (0);
-       route_group_changed (0);
+       route_group_changed ();
 
        connect_to_pan ();
 
@@ -608,7 +608,7 @@ MixerStrip::set_width_enum (Width w, void* owner)
        
        update_input_display ();
        update_output_display ();
-       route_group_changed (0);
+       route_group_changed ();
        name_changed ();
        WidthChanged ();
 }
@@ -1303,7 +1303,7 @@ MixerStrip::comment_changed (void *src)
 void
 MixerStrip::set_route_group (RouteGroup *rg)
 {
-       _route->set_route_group (rg, this);
+       rg->add (_route);
 }
 
 bool
@@ -1330,9 +1330,9 @@ MixerStrip::select_route_group (GdkEventButton *ev)
 }
 
 void
-MixerStrip::route_group_changed (void *ignored)
+MixerStrip::route_group_changed ()
 {
-       ENSURE_GUI_THREAD(bind (mem_fun(*this, &MixerStrip::route_group_changed), ignored));
+       ENSURE_GUI_THREAD (mem_fun(*this, &MixerStrip::route_group_changed));
 
        RouteGroup *rg = _route->route_group();
 
index 1f31b7cae56aa3ebcb4fb45b9a8e46d81d418fe3..d5b247019bb65af68658016a6ad91fca30bcb855 100644 (file)
@@ -238,7 +238,7 @@ class MixerStrip : public RouteUI, public Gtk::EventBox
 
        void set_route_group (ARDOUR::RouteGroup *);
        bool select_route_group (GdkEventButton *);
-       void route_group_changed (void *);
+       void route_group_changed ();
 
        IOSelectorWindow *input_selector;
        IOSelectorWindow *output_selector;
index 30e56620a0f74e38680ba7c3076b7adfef7c98d7..097c229cf09471fb5bfa67b3c6c8a258053832d9 100644 (file)
@@ -1152,7 +1152,7 @@ Mixer_UI::group_flags_changed (void* src, RouteGroup* group)
 
        for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
                if ((*i)->route_group() == group) {
-                       (*i)->route_group_changed(0);
+                       (*i)->route_group_changed();
                }
        }
 
index 25897222644e8f37f7108acd9aa93016fc855caa..c0d8db9cbaa09dd7c2480121de7aca192b40f176 100644 (file)
@@ -296,7 +296,7 @@ PortGroupList::gather (ARDOUR::Session* session, bool inputs, bool allow_dups)
 
                if (g) {
 
-                       TimeAxisView* tv = PublicEditor::instance().axis_view_from_route (i->get());
+                       TimeAxisView* tv = PublicEditor::instance().axis_view_from_route (*i);
                        for (list<boost::shared_ptr<Bundle> >::iterator i = route_bundles.begin(); i != route_bundles.end(); ++i) {
                                if (tv) {
                                        g->add_bundle (*i, io, tv->color ());
index 90d24dc8027bca1942b162cbb99a8ff38b98f8f8..e520e30a890bcfa1d412ccb00401c677ec25e3d3 100644 (file)
@@ -346,7 +346,7 @@ class PublicEditor : public Gtk::Window, public PBD::StatefulThingWithGoingAway
        virtual ArdourCanvas::Group* get_background_group () const = 0;
        virtual ArdourCanvas::Group* get_trackview_group () const = 0;
 
-       virtual TimeAxisView* axis_view_from_route (ARDOUR::Route *) const = 0;
+       virtual TimeAxisView* axis_view_from_route (boost::shared_ptr<ARDOUR::Route>) const = 0;
 
        virtual void show_verbose_canvas_cursor_with (const std::string& txt) = 0;
        virtual void hide_verbose_canvas_cursor() = 0;
index 6c3e9db73dea4edfb363b0ea4644f163fb3606c0..bd8bcc8a28679473104348a230e8aedb062984a2 100644 (file)
@@ -73,7 +73,6 @@ RouteGroupMenu::set_group (RouteGroup* g)
        GroupSelected (g);
 }
 
-
 void
 RouteGroupMenu::new_group ()
 {
index ef948307a2846ce85f36597009bf89a917edb2a0..4d828d4fd823c3420cc3f05acdf0c2e66bcc64b6 100644 (file)
@@ -311,20 +311,28 @@ gint
 RouteTimeAxisView::edit_click (GdkEventButton *ev)
 {
        if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
-               _route->set_route_group (0, this);
-               return FALSE;
+               if (_route->route_group()) {
+                       _route->route_group()->remove (_route);
+               }
+               return false;
        }
 
        route_group_menu->rebuild (_route->route_group ());
        route_group_menu->popup (ev->button, ev->time);
 
-       return FALSE;
+       return false;
 }
 
 void
 RouteTimeAxisView::set_route_group_from_menu (RouteGroup *eg)
 {
-       _route->set_route_group (eg, this);
+       if (eg) {
+               eg->add (_route);
+       } else {
+               if (_route->route_group()) {
+                       _route->route_group()->remove (_route);
+               }
+       }
 }
 
 void
@@ -1572,14 +1580,16 @@ RouteTimeAxisView::use_playlist (boost::weak_ptr<Playlist> wpl)
 
                        take_name = take_name.substr(idx + group_string.length()); // find the bit containing the take number / name
 
-                       for (list<Route*>::const_iterator i = route_group()->route_list().begin(); i != route_group()->route_list().end(); ++i) {
-                               if ( (*i) == this->route().get()) {
+                       boost::shared_ptr<RouteList> rl (route_group()->route_list());
+
+                       for (RouteList::const_iterator i = rl->begin(); i != rl->end(); ++i) {
+                               if ( (*i) == this->route()) {
                                        continue;
                                }
 
                                std::string playlist_name = (*i)->name()+group_string+take_name;
 
-                               Track *track = dynamic_cast<Track *>(*i);
+                               boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track>(*i);
                                if (!track) {
                                        std::cerr << "route " << (*i)->name() << " is not a Track" << std::endl;
                                        continue;
@@ -1593,8 +1603,6 @@ RouteTimeAxisView::use_playlist (boost::weak_ptr<Playlist> wpl)
                                } else {
                                        track->diskstream()->use_playlist(ipl);
                                }
-
-                               //(*i)->get_dis
                        }
                }
        }
index 9eb356ddd17d3c0742b92c4a6b28ddd3636450dc..821b82a0b607aa556aac902827e4976ab349b961 100644 (file)
@@ -543,35 +543,33 @@ RouteUI::rec_enable_press(GdkEventButton* ev)
 
                } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
 
-                       SessionEvent* ev = new SessionEvent (SessionEvent::RealTimeOperation, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0);
-                       ev->rt_slot =   bind (sigc::mem_fun (_session, &Session::set_record_enable), _session.get_routes(), !rec_enable_button->get_active());
-                       ev->rt_return = sigc::mem_fun (*this, &RouteUI::post_rtop_cleanup);
-                       
-                       _session.queue_event (ev);
+#if 0                  
+                       _session.set_record_enable (_session.get_route(), !rec_enable_button->get_active(), sigc::mem_fun (*this, &RouteUI::post_rtop_cleanup));
+#endif
 
                } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
 
                        /* Primary-button1 applies change to the route group (even if it is not active)
                           NOTE: Primary-button2 is MIDI learn.
                        */
-                       
-                       if (ev->button == 1) {
-                               queue_route_group_op (RouteGroup::RecEnable, &Session::set_record_enable, !rec_enable_button->get_active());
+#if 0                  
+                       if (ev->button == 1 && _route->route_group()) {
+                               _session.set_record_enable (_route->route_group(), !rec_enable_button->get_active(),
+                               queue_route_group_op (RouteGroup::RecEnable, &Session::set_record_enable, 
                        }
+#endif
 
                } else if (Keyboard::is_context_menu_event (ev)) {
 
                        /* do this on release */
 
                } else {
+
+#if 0
                        boost::shared_ptr<RouteList> rl (new RouteList);
                        rl->push_back (route());
-                       
-                       SessionEvent* ev = new SessionEvent (SessionEvent::RealTimeOperation, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0);
-                       ev->rt_slot =   bind (sigc::mem_fun (_session, &Session::set_record_enable), rl, !rec_enable_button->get_active());
-                       ev->rt_return = sigc::mem_fun (*this, &RouteUI::post_rtop_cleanup);
-
-                       _session.queue_event (ev);
+                       _session.set_record_enable (rl, !rec_enable_button->get_active(), sigc::mem_fun (*this, &RouteUI::post_rtop_cleanup));
+#endif
                }
        }
 
index f992e6a18c1924297c8a6b65c15c008d7e197f02..d3cd0eb6bff74a00ee513c22f38a234e65c32211 100644 (file)
@@ -19,6 +19,8 @@
 #ifndef __libardour_pi_controller__
 #define __libardour_pi_controller__
 
+#include "ardour/types.h"
+
 class PIController {
 
   public:
@@ -48,6 +50,35 @@ class PIController {
     int     smooth_size;
     double  smooth_offset;
     double  current_resample_factor;
+    bool    fir_empty;
 };
 
+#define ESTIMATOR_SIZE 16
+
+class PIChaser {
+  public:
+    PIChaser();
+    ~PIChaser();
+
+    double get_ratio( nframes64_t realtime, nframes64_t chasetime, nframes64_t slavetime, bool in_control );
+    void reset();
+    nframes64_t want_locate() { return want_locate_val; }
+
+  private:
+    PIController *pic;
+    nframes64_t realtime_stamps[ESTIMATOR_SIZE];
+    nframes64_t chasetime_stamps[ESTIMATOR_SIZE];
+    int array_index;
+    nframes64_t want_locate_val;
+
+    void feed_estimator( nframes64_t realtime, nframes64_t chasetime );
+    double get_estimate();
+
+    double speed;
+
+    double speed_threshold;
+    nframes64_t pos_threshold;
+};
+
+
 #endif /* __libardour_pi_controller__ */
index 8b08dded99f67543929bf306c3acf7d1d2b038ab..8e63a2d523386fda08161d9d5ce52a54d9706e86 100644 (file)
@@ -42,6 +42,7 @@
 #include "ardour/io.h"
 #include "ardour/types.h"
 #include "ardour/mute_master.h"
+#include "ardour/route_group_member.h"
 
 namespace ARDOUR {
 
@@ -54,7 +55,7 @@ class RouteGroup;
 class Send;
 class InternalReturn;
 
-class Route : public SessionObject, public AutomatableControls
+class Route : public SessionObject, public AutomatableControls, public RouteGroupMember
 {
   public:
 
@@ -149,10 +150,6 @@ class Route : public SessionObject, public AutomatableControls
        void set_denormal_protection (bool yn);
        bool denormal_protection() const;
 
-       void       set_route_group (RouteGroup *, void *);
-       void       drop_route_group (void *);
-       RouteGroup *route_group () const { return _route_group; }
-
        void         set_meter_point (MeterPoint, void *src);
        MeterPoint   meter_point() const { return _meter_point; }
        void         meter ();
@@ -244,7 +241,6 @@ class Route : public SessionObject, public AutomatableControls
        /** the processors have changed; the parameter indicates what changed */
        sigc::signal<void, RouteProcessorChange> processors_changed;
        sigc::signal<void,void*> record_enable_changed;
-       sigc::signal<void,void*> route_group_changed;
        /** the metering point has changed */
        sigc::signal<void,void*> meter_change; 
        sigc::signal<void>       signal_latency_changed;
@@ -369,7 +365,6 @@ class Route : public SessionObject, public AutomatableControls
        boost::shared_ptr<MuteMaster> _mute_master;
        MuteMaster::MutePoint _mute_points;
 
-       RouteGroup*    _route_group;
        std::string    _comment;
        bool           _have_internal_generator;
        bool           _solo_safe;
index 0f7109337798932d43c4ea1975e5b94cf616f2f1..996e8fee2f7671ccc919033be4d5c940d328cfd6 100644 (file)
@@ -25,6 +25,7 @@
 #include <string>
 #include <stdint.h>
 #include <sigc++/signal.h>
+
 #include "pbd/stateful.h"
 #include "ardour/types.h"
 
@@ -53,6 +54,7 @@ public:
        };
 
        RouteGroup (Session& s, const std::string &n, Flag f = Flag(0), Property p = Property(0));
+       ~RouteGroup ();
 
        const std::string& name() { return _name; }
        void set_name (std::string str);
@@ -60,13 +62,12 @@ public:
        bool is_active () const { return _flags & Active; }
        bool is_relative () const { return _flags & Relative; }
        bool is_hidden () const { return _flags & Hidden; }
-       bool empty() const {return routes.empty();}
+       bool empty() const {return routes->empty();}
+       size_t size() const { return routes->size();}
 
        gain_t get_max_factor(gain_t factor);
        gain_t get_min_factor(gain_t factor);
 
-       int size() { return routes.size();}
-
        void set_active (bool yn, void *src);
        void set_relative (bool yn, void *src);
        void set_hidden (bool yn, void *src);
@@ -86,24 +87,23 @@ public:
                }
        }
 
-       int add (Route *);
-
-       int remove (Route *);
+       int add (boost::shared_ptr<Route>);
+       int remove (boost::shared_ptr<Route>);
 
        void apply (void (Route::*func)(void *), void *src) {
-               for (std::list<Route *>::iterator i = routes.begin(); i != routes.end(); i++) {
-                       ((*i)->*func)(src);
+               for (RouteList::iterator i = routes->begin(); i != routes->end(); i++) {
+                       ((*i).get()->*func)(src);
                }
        }
 
        template<class T> void apply (void (Route::*func)(T, void *), T val, void *src) {
-               for (std::list<Route *>::iterator i = routes.begin(); i != routes.end(); i++) {
-                       ((*i)->*func)(val, src);
+               for (RouteList::iterator i = routes->begin(); i != routes->end(); i++) {
+                       ((*i).get()->*func)(val, src);
                }
        }
 
        template<class T> void foreach_route (T *obj, void (T::*func)(Route&)) {
-               for (std::list<Route *>::iterator i = routes.begin(); i != routes.end(); i++) {
+               for (RouteList::iterator i = routes->begin(); i != routes->end(); i++) {
                        (obj->*func)(**i);
                }
        }
@@ -114,17 +114,18 @@ public:
 
        /* fills at_set with all members of the group that are AudioTracks */
 
-       void audio_track_group (std::set<AudioTrack*>& at_set);
+       void audio_track_group (std::set<boost::shared_ptr<AudioTrack> >& at_set);
 
        void clear () {
-               routes.clear ();
+               routes->clear ();
                changed();
        }
 
        void make_subgroup ();
        void destroy_subgroup ();
 
-       const std::list<Route*>& route_list() { return routes; }
+       boost::shared_ptr<RouteList> route_list() { return routes; }
+       boost::shared_ptr<RouteList> route_list (Property forProperty);
 
        sigc::signal<void> changed;
        sigc::signal<void,void*> FlagsChanged;
@@ -135,13 +136,13 @@ public:
        
 private:
        Session& _session;
-       std::list<Route *> routes;
+       boost::shared_ptr<RouteList> routes;
        boost::shared_ptr<Route> subgroup_bus;
        std::string _name;
        Flag _flags;
        Property _properties;
 
-       void remove_when_going_away (Route*);
+       void remove_when_going_away (boost::weak_ptr<Route>);
        int set_state_2X (const XMLNode&, int);
 };
 
diff --git a/libs/ardour/ardour/route_group_member.h b/libs/ardour/ardour/route_group_member.h
new file mode 100644 (file)
index 0000000..4b57712
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+    Copyright (C) 2009 Paul Davis
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __libardour_route_group_member_h__
+#define __libardour_route_group_member_h__
+
+#include <sigc++/signal.h>
+
+namespace ARDOUR  {
+
+class RouteGroup;
+
+class RouteGroupMember 
+{
+  public:
+       RouteGroupMember () : _route_group (0) {}
+       virtual ~RouteGroupMember() {}
+
+       RouteGroup* route_group () const { return _route_group; }
+
+       sigc::signal<void> route_group_changed;
+
+  protected:
+       RouteGroup* _route_group;
+
+  private:
+       friend class RouteGroup;
+
+       void join_route_group (RouteGroup*);
+       void leave_route_group ();
+};
+
+}
+
+#endif /* __libardour_route_group_member_h__ */
index c9d06a93c9aeaa243235d8560be52656cac0be26..242a16c43e471ecc0d72548886d99d552ac72256 100644 (file)
 namespace ARDOUR {
 
 template<class T> void
-RouteGroup::apply (void (Track::*func)(T, void *), T val, void */*src*/)
+RouteGroup::apply (void (Track::*func)(T, void *), T val, void/*src*/)
 {
-       for (std::list<Route *>::iterator i = routes.begin(); i != routes.end(); i++) {
-               Track *at;
-               if ((at = dynamic_cast<Track*>(*i)) != 0) {
-                       (at->*func)(val, this);
+       for (RouteList::iterator i = routes->begin(); i != routes->end(); i++) {
+               boost::shared_ptr<Track> at;
+
+               if ((at = boost::dynamic_pointer_cast<Track>(*i)) != 0) {
+                       (at.get()->*func)(val, this);
                }
        }
 }
@@ -39,3 +40,4 @@ RouteGroup::apply (void (Track::*func)(T, void *), T val, void */*src*/)
 } /* namespace ARDOUR */
 
 #endif /* __ardour_route_group_specialized_h__ */
+
index b01722e306216b9ae8ba07fb8e2a71177ade7f10..1125e920a0d3a8f9e688950de267547466d8a684 100644 (file)
@@ -31,7 +31,7 @@
 #include "midi++/parser.h"
 #include "midi++/types.h"
 
-class PIController;
+class PIChaser;
 
 namespace MIDI {
        class Port;
@@ -242,7 +242,7 @@ class MTC_Slave : public Slave, public sigc::trackable {
        MIDI::Port* port;
        std::vector<sigc::connection> connections;
        bool        can_notify_on_unknown_rate;
-       PIController* pic;
+       PIChaser* pic;
 
        static const int frame_tolerance;
 
index 41aaaccbcf75a74417b442fdd648870fe02eebc8..95fa4d984aa32dd4444d6f48050e18d8a78bc95d 100644 (file)
@@ -57,7 +57,7 @@ MTC_Slave::MTC_Slave (Session& s, MIDI::Port& p)
        can_notify_on_unknown_rate = true;
        did_reset_tc_format = false;
 
-       pic = new PIController (1.0, 8);
+       pic = new PIChaser();
        
        last_mtc_fps_byte = session.get_mtc_timecode_bits ();
        mtc_frame = 0;
@@ -229,8 +229,18 @@ MTC_Slave::update_mtc_time (const byte *msg, bool was_full, nframes_t now)
                                         * 
                                         * its not the average, but we will assign it to current.speed below
                                         */
+
+                                   static nframes64_t last_seen_timestamp = 0; 
+                                   static nframes64_t last_seen_position = 0; 
+
+                                   if ((now - last_seen_timestamp) < 300) {
+                                       mtc_frame = (mtc_frame + last_seen_position)/2;
+                                   }
+
+                                   last_seen_timestamp = now;
+                                   last_seen_position = mtc_frame;
+
                                        
-                                       average_speed = pic->get_ratio (session.audible_frame() - mtc_frame);
                                        
                                } else {
 
@@ -412,6 +422,24 @@ MTC_Slave::speed_and_position (double& speed, nframes64_t& pos)
 
        DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::speed_and_position %1 %2\n", last.speed, last.position));
 
+       if (give_slave_full_control_over_transport_speed()) {
+           bool in_control = (session.slave_state() == Session::Running);
+           nframes64_t pic_want_locate = 0; 
+           //nframes64_t slave_pos = session.audible_frame();
+           nframes64_t slave_pos = session.transport_frame();
+           static double average_speed = 0;
+
+           average_speed = pic->get_ratio (last.timestamp, last.position, slave_pos, in_control );
+           pic_want_locate = pic->want_locate();
+
+           if (in_control && pic_want_locate) {
+               last.speed = average_speed + (double) (pic_want_locate - session.transport_frame()) / (double)session.get_block_size();
+               std::cout << "locate req " << pic_want_locate << " speed: " << average_speed << "\n"; 
+           } else {
+               last.speed = average_speed;
+           }
+       }
+
        if (last.speed == 0.0f) {
 
                elapsed = 0;
@@ -431,7 +459,7 @@ MTC_Slave::speed_and_position (double& speed, nframes64_t& pos)
 
        /* now add the most recent timecode value plus the estimated elapsed interval */
 
-       pos =  elapsed + last.position;
+       pos = last.position + elapsed; 
        speed = last.speed;
 
        DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::speed_and_position FINAL %1 %2\n", last.speed, pos));
@@ -486,7 +514,7 @@ MTC_Slave::reset ()
        have_first_speed_accumulator = false;
        speed_accumulator_cnt = 0;
 
-       pic->out_of_bounds();
+       pic->reset();
 }
 
 void
index 5aee7f23011933568b7f58fdb8126707bc0ba54c..1db36355fe50d509d2d89459bf903e8b1d4f56ff 100644 (file)
@@ -42,10 +42,11 @@ PIController::PIController (double resample_factor, int fir_size)
        }
        
        // These values could be configurable
-       catch_factor = 100000;
-       catch_factor2 = 10000;
-       pclamp = 15.0;
+       catch_factor = 20000;
+       catch_factor2 = 4000;
+       pclamp = 150.0;
        controlquant = 10000.0;
+       fir_empty = false;
 }
 
 PIController::~PIController ()
@@ -58,9 +59,18 @@ double
 PIController::get_ratio (int fill_level)
 {
        double offset = fill_level;
+       double this_catch_factor = catch_factor;
+
        
        // Save offset.
-       offset_array[(offset_differential_index++) % smooth_size] = offset;
+       if( fir_empty ) {
+           for (int i = 0; i < smooth_size; i++) {
+                   offset_array[i] = offset;
+           }
+           fir_empty = false;
+       } else {
+           offset_array[(offset_differential_index++) % smooth_size] = offset;
+       }
         
        // Build the mean of the windowed offset array basically fir lowpassing.
        smooth_offset = 0.0;
@@ -72,24 +82,29 @@ PIController::get_ratio (int fill_level)
        // This is the integral of the smoothed_offset
        offset_integral += smooth_offset;
 
+       std::cerr << smooth_offset << " ";
        
        // Clamp offset : the smooth offset still contains unwanted noise which would go straigth onto the resample coeff.
        // It only used in the P component and the I component is used for the fine tuning anyways.
+    
        if (fabs(smooth_offset) < pclamp)
                 smooth_offset = 0.0;
        
+       smooth_offset += (static_resample_factor - resample_mean) * this_catch_factor;
+       
        // Ok, now this is the PI controller. 
        // u(t) = K * (e(t) + 1/T \int e(t') dt')
        // Kp = 1/catch_factor and T = catch_factor2  Ki = Kp/T 
        current_resample_factor 
-                = static_resample_factor - smooth_offset / catch_factor - offset_integral / catch_factor / catch_factor2;
+                = static_resample_factor - smooth_offset / this_catch_factor - offset_integral / this_catch_factor / catch_factor2;
        
        // Now quantize this value around resample_mean, so that the noise which is in the integral component doesnt hurt.
        current_resample_factor = floor((current_resample_factor - resample_mean) * controlquant + 0.5) / controlquant + resample_mean;
        
        // Calculate resample_mean so we can init ourselves to saner values.
        // resample_mean = 0.9999 * resample_mean + 0.0001 * current_resample_factor;
-       resample_mean = 0.9 * resample_mean + 0.1 * current_resample_factor;
+       resample_mean = (1.0-0.01) * resample_mean + 0.01 * current_resample_factor;
+       std::cerr << fill_level << " " << smooth_offset << " " << offset_integral << " " << current_resample_factor << " " << resample_mean << "\n";
        return current_resample_factor;
 }
         
@@ -105,4 +120,110 @@ PIController::out_of_bounds()
        for (i = 0; i < smooth_size; i++) {
                 offset_array[i] = 0.0;
        }
+       fir_empty = false;
+}
+
+
+PIChaser::PIChaser() {
+       pic = new PIController( 1.0, 16 );
+       array_index = 0;
+       for( int i=0; i<ESTIMATOR_SIZE; i++ ) {
+           realtime_stamps[i] = 0;
+           chasetime_stamps[i] = 0;
+       }
+
+       speed_threshold = 0.2;
+       pos_threshold = 4000;
+       want_locate_val = 0;
+}
+
+void
+PIChaser::reset() {
+       array_index = 0;
+       for( int i=0; i<ESTIMATOR_SIZE; i++ ) {
+           realtime_stamps[i] = 0;
+           chasetime_stamps[i] = 0;
+       }
+       pic->reset(1.0);
+}
+PIChaser::~PIChaser() {
+       delete pic;
+}
+
+double
+PIChaser::get_ratio(nframes64_t realtime, nframes64_t chasetime, nframes64_t slavetime, bool in_control ) {
+
+       feed_estimator( realtime, chasetime );
+       std::cerr << (double)realtime/48000.0 << " " << chasetime << " " << slavetime << " ";
+       double crude = get_estimate();
+       double fine;  
+
+           fine = pic->get_ratio( slavetime - chasetime );
+       if (in_control) {
+           if (fabs(fine-crude) > crude*speed_threshold) {
+               std::cout << "reset to " << crude << " fine = " << fine << "\n";
+               pic->reset( crude );
+               speed = crude;
+           } else {
+               speed = fine;
+           }
+
+           if (abs(chasetime-slavetime) > pos_threshold) {
+               pic->reset( crude );
+               speed = crude;
+               want_locate_val = chasetime;
+               std::cout << "we are off by " << chasetime-slavetime << " want_locate:" << chasetime << "\n";
+           } else {
+               want_locate_val = 0;
+           }
+       } else {
+           std::cout << "not in control..." << crude << "\n";
+           speed = crude;
+           pic->reset( crude );
+       }
+       
+       return speed;
+}
+
+void
+PIChaser::feed_estimator( nframes64_t realtime, nframes64_t chasetime ) {
+       array_index += 1;
+       realtime_stamps [ array_index%ESTIMATOR_SIZE ] = realtime;
+       chasetime_stamps[ array_index%ESTIMATOR_SIZE ] = chasetime;
+}
+
+double
+PIChaser::get_estimate() {
+       double est = 0;
+       int num=0;
+       int i;
+       nframes64_t n1_realtime;
+       nframes64_t n1_chasetime;
+       for( i=(array_index + 1); i<=(array_index + ESTIMATOR_SIZE); i++ ) {
+           if( realtime_stamps[(i)%ESTIMATOR_SIZE] ) {
+               n1_realtime = realtime_stamps[(i)%ESTIMATOR_SIZE];
+               n1_chasetime = chasetime_stamps[(i)%ESTIMATOR_SIZE];
+               i+=1;
+               break;
+           }
+       }
+
+       for( ; i<=(array_index + ESTIMATOR_SIZE); i++ ) {
+           if( realtime_stamps[(i)%ESTIMATOR_SIZE] ) {
+               if( (realtime_stamps[(i)%ESTIMATOR_SIZE] - n1_realtime) > 200 ) {
+                   nframes64_t n_realtime = realtime_stamps[(i)%ESTIMATOR_SIZE];
+                   nframes64_t n_chasetime = chasetime_stamps[(i)%ESTIMATOR_SIZE];
+                   est += ((double)( n_chasetime - n1_chasetime ))
+                         / ((double)( n_realtime - n1_realtime ));
+                   n1_realtime = n_realtime;
+                   n1_chasetime = n_chasetime;
+                   num += 1;
+               }
+           }
+       }
+
+       if(num)
+           return est/(double)num;
+       else
+           return 0.0;
 }
index 768df386988b615f53fae63e46c063de2a5b5948..f04de4c24265999ec08f89ebb125f1fec352d9bc 100644 (file)
@@ -135,8 +135,6 @@ Route::init ()
        _in_configure_processors = false;
        _mute_points = MuteMaster::AllPoints;
 
-       _route_group = 0;
-
        _phase_invert = 0;
        _denormal_protection = false;
 
@@ -1836,15 +1834,6 @@ Route::_set_state (const XMLNode& node, int version, bool /*call_base*/)
                }
        }
 
-       if ((prop = node.property (X_("route-group"))) != 0) {
-               RouteGroup* route_group = _session.route_group_by_name(prop->value());
-               if (route_group == 0) {
-                       error << string_compose(_("Route %1: unknown route group \"%2 in saved state (ignored)"), _name, prop->value()) << endmsg;
-               } else {
-                       set_route_group (route_group, this);
-               }
-       }
-
        if ((prop = node.property (X_("order-keys"))) != 0) {
 
                long n;
@@ -2011,26 +2000,9 @@ Route::_set_state_2X (const XMLNode& node, int version)
                _meter_point = MeterPoint (string_2_enum (prop->value (), _meter_point));
        }
 
-       /* XXX: if the route was in both a mix group and an edit group, it'll end up
-          just in the edit group. */
-
-       if ((prop = node.property (X_("mix-group"))) != 0) {
-               RouteGroup* route_group = _session.route_group_by_name(prop->value());
-               if (route_group == 0) {
-                       error << string_compose(_("Route %1: unknown route group \"%2 in saved state (ignored)"), _name, prop->value()) << endmsg;
-               } else {
-                       set_route_group (route_group, this);
-               }
-       }
-
-       if ((prop = node.property (X_("edit-group"))) != 0) {
-               RouteGroup* route_group = _session.route_group_by_name(prop->value());
-               if (route_group == 0) {
-                       error << string_compose(_("Route %1: unknown route group \"%2 in saved state (ignored)"), _name, prop->value()) << endmsg;
-               } else {
-                       set_route_group (route_group, this);
-               }
-       }
+       /* do not carry over edit/mix groups from 2.X because (a) its hard (b) they
+          don't mean the same thing.
+       */
 
        if ((prop = node.property (X_("order-keys"))) != 0) {
 
@@ -2398,33 +2370,6 @@ Route::drop_listen (boost::shared_ptr<Route> route)
        }
 }
 
-void
-Route::set_route_group (RouteGroup *rg, void *src)
-{
-       if (rg == _route_group) {
-               return;
-       }
-
-       if (_route_group) {
-               _route_group->remove (this);
-       }
-
-       if ((_route_group = rg) != 0) {
-               _route_group->add (this);
-       }
-
-       _session.set_dirty ();
-       route_group_changed (src); /* EMIT SIGNAL */
-}
-
-void
-Route::drop_route_group (void *src)
-{
-       _route_group = 0;
-       _session.set_dirty ();
-       route_group_changed (src); /* EMIT SIGNAL */
-}
-
 void
 Route::set_comment (string cmt, void *src)
 {
index f33a7f1f408763ada05943ec91bb9cdd9ea3c046..d7ac672f9a54f3a8b5bac1da7c21fd17cc8526d4 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2000-2002 Paul Davis
+    Copyright (C) 2000-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
@@ -26,6 +26,7 @@
 
 #include "pbd/error.h"
 #include "pbd/enumwriter.h"
+#include "pbd/strsplit.h"
 
 #include "ardour/amp.h"
 #include "ardour/route_group.h"
@@ -41,10 +42,26 @@ using namespace sigc;
 using namespace std;
 
 RouteGroup::RouteGroup (Session& s, const string &n, Flag f, Property p)
-       : _session (s), _name (n), _flags (f), _properties (Property (p))
+       : _session (s)
+       , routes (new RouteList)
+       , _name (n)
+       , _flags (f)
+       , _properties (Property (p))
 {
 }
 
+RouteGroup::~RouteGroup ()
+{
+       for (RouteList::iterator i = routes->begin(); i != routes->end();) {
+               RouteList::iterator tmp = i;
+               ++tmp;
+
+               (*i)->leave_route_group ();
+               
+               i = tmp;
+       }
+}
+
 void
 RouteGroup::set_name (string str)
 {
@@ -54,32 +71,43 @@ RouteGroup::set_name (string str)
 }
 
 int
-RouteGroup::add (Route *r)
+RouteGroup::add (boost::shared_ptr<Route> r)
 {
-       routes.push_back (r);
-       r->GoingAway.connect (sigc::bind (mem_fun (*this, &RouteGroup::remove_when_going_away), r));
+       r->leave_route_group ();
+
+       routes->push_back (r);
+
+       r->join_route_group (this);
+       r->GoingAway.connect (sigc::bind (mem_fun (*this, &RouteGroup::remove_when_going_away), boost::weak_ptr<Route> (r)));
+       
        _session.set_dirty ();
        changed (); /* EMIT SIGNAL */
        return 0;
 }
 
 void
-RouteGroup::remove_when_going_away (Route *r)
+RouteGroup::remove_when_going_away (boost::weak_ptr<Route> wr)
 {
-       remove (r);
+       boost::shared_ptr<Route> r (wr.lock());
+
+       if (r) {
+               remove (r);
+       }
 }
 
 int
-RouteGroup::remove (Route *r)
+RouteGroup::remove (boost::shared_ptr<Route> r)
 {
-       list<Route *>::iterator i;
+       RouteList::iterator i;
 
-       if ((i = find (routes.begin(), routes.end(), r)) != routes.end()) {
-               routes.erase (i);
+       if ((i = find (routes->begin(), routes->end(), r)) != routes->end()) {
+               r->leave_route_group ();
+               routes->erase (i);
                _session.set_dirty ();
                changed (); /* EMIT SIGNAL */
                return 0;
        }
+
        return -1;
 }
 
@@ -89,7 +117,7 @@ RouteGroup::get_min_factor(gain_t factor)
 {
        gain_t g;
 
-       for (list<Route *>::iterator i = routes.begin(); i != routes.end(); i++) {
+       for (RouteList::iterator i = routes->begin(); i != routes->end(); i++) {
                g = (*i)->amp()->gain();
 
                if ( (g+g*factor) >= 0.0f)
@@ -108,7 +136,7 @@ RouteGroup::get_max_factor(gain_t factor)
 {
        gain_t g;
 
-       for (list<Route *>::iterator i = routes.begin(); i != routes.end(); i++) {
+       for (RouteList::iterator i = routes->begin(); i != routes->end(); i++) {
                g = (*i)->amp()->gain();
 
                // if the current factor woulnd't raise this route above maximum
@@ -133,6 +161,17 @@ RouteGroup::get_state (void)
        node->add_property ("name", _name);
        node->add_property ("flags", enum_2_string (_flags));
        node->add_property ("properties", enum_2_string (_properties));
+
+       if (!routes->empty()) {
+               stringstream str;
+               
+               for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
+                       str << (*i)->id () << ' ';
+               }
+
+               node->add_property ("routes", str.str());
+       }
+
        return *node;
 }
 
@@ -157,6 +196,21 @@ RouteGroup::set_state (const XMLNode& node, int version)
                _properties = Property (string_2_enum (prop->value(), _properties));
        }
 
+       if ((prop = node.property ("routes")) != 0) {
+               stringstream str (prop->value());
+               vector<string> ids;
+               split (str.str(), ids, ' ');
+               
+               for (vector<string>::iterator i = ids.begin(); i != ids.end(); ++i) {
+                       PBD::ID id (*i);
+                       boost::shared_ptr<Route> r = _session.route_by_id (id);
+                       
+                       if (r) {
+                               add (r);
+                       } 
+               }
+       }
+
        return 0;
 }
 
@@ -236,10 +290,10 @@ RouteGroup::set_hidden (bool yn, void *src)
 }
 
 void
-RouteGroup::audio_track_group (set<AudioTrack*>& ats)
+RouteGroup::audio_track_group (set<boost::shared_ptr<AudioTrack> >& ats)
 {
-       for (list<Route*>::iterator i = routes.begin(); i != routes.end(); ++i) {
-               AudioTrack* at = dynamic_cast<AudioTrack*>(*i);
+       for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
+               boost::shared_ptr<AudioTrack> at = boost::dynamic_pointer_cast<AudioTrack>(*i);
                if (at) {
                        ats.insert (at);
                }
@@ -254,14 +308,14 @@ RouteGroup::make_subgroup ()
 
        /* since we don't do MIDI Busses yet, check quickly ... */
 
-       for (list<Route*>::iterator i = routes.begin(); i != routes.end(); ++i) {
+       for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
                if ((*i)->output()->n_ports().n_midi() != 0) {
                        PBD::info << _("You cannot subgroup MIDI tracks at this time") << endmsg;
                        return;
                }
        }
 
-       for (list<Route*>::iterator i = routes.begin(); i != routes.end(); ++i) {
+       for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
                nin = max (nin, (*i)->output()->n_ports().n_audio());
        }
 
@@ -277,7 +331,7 @@ RouteGroup::make_subgroup ()
 
        boost::shared_ptr<Bundle> bundle = subgroup_bus->input()->bundle ();
 
-       for (list<Route*>::iterator i = routes.begin(); i != routes.end(); ++i) {
+       for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
                (*i)->output()->disconnect (this);
                (*i)->output()->connect_ports_to_bundle (bundle, this);
        }
@@ -289,8 +343,8 @@ RouteGroup::destroy_subgroup ()
        if (!subgroup_bus) {
                return;
        }
-
-       for (list<Route*>::iterator i = routes.begin(); i != routes.end(); ++i) {
+       
+       for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
                (*i)->output()->disconnect (this);
                /* XXX find a new bundle to connect to */
        }
diff --git a/libs/ardour/route_group_member.cc b/libs/ardour/route_group_member.cc
new file mode 100644 (file)
index 0000000..e4075df
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+    Copyright (C) 2009 Paul Davis
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+
+#include "ardour/route_group.h"
+#include "ardour/route_group_member.h"
+
+using namespace ARDOUR;
+
+void
+RouteGroupMember::join_route_group (RouteGroup *rg)
+{
+       if (rg == _route_group) {
+               return;
+       }
+
+       _route_group = rg;
+       route_group_changed (); /* EMIT SIGNAL */
+}
+
+void
+RouteGroupMember::leave_route_group ()
+{
+       _route_group = 0;
+       route_group_changed (); /* EMIT SIGNAL */
+}
+
index 9c3b28049f98a45cc8a43f849296ba38c5039b03..0bf161bb5daadaa360ed7a75c39e0536240a18cc 100644 (file)
@@ -1648,7 +1648,7 @@ Session::new_midi_track (TrackMode mode, RouteGroup* route_group, uint32_t how_m
                        */
 
                        track->midi_diskstream()->non_realtime_input_change();
-                       track->set_route_group (route_group, 0);
+                       route_group->add (track);
 
                        track->DiskstreamChanged.connect (mem_fun (this, &Session::resort_routes));
                        //track->set_remote_control_id (control_id);
@@ -1819,7 +1819,7 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
 
                        channels_used += track->n_inputs ().n_audio();
 
-                       track->set_route_group (route_group, 0);
+                       route_group->add (track);
 
                        track->audio_diskstream()->non_realtime_input_change();
 
@@ -1998,7 +1998,7 @@ Session::new_audio_route (bool aux, int input_channels, int output_channels, Rou
 
                        channels_used += bus->n_inputs ().n_audio();
 
-                       bus->set_route_group (route_group, 0);
+                       route_group->add (bus);
                        bus->set_remote_control_id (control_id);
                        ++control_id;
 
@@ -2151,7 +2151,7 @@ Session::add_routes (RouteList& new_routes, bool save)
                (*x)->mute_changed.connect (mem_fun (*this, &Session::route_mute_changed));
                (*x)->output()->changed.connect (mem_fun (*this, &Session::set_worst_io_latencies_x));
                (*x)->processors_changed.connect (mem_fun (*this, &Session::route_processors_changed));
-               (*x)->route_group_changed.connect (hide (mem_fun (*this, &Session::route_group_changed)));
+               (*x)->route_group_changed.connect (mem_fun (*this, &Session::route_group_changed));
 
                if ((*x)->is_master()) {
                        _master_out = (*x);
index 882694cccf5ead23a5181b93bbb76a8e3923236f..568017c064c86cf3fb829649b65ece25de4dea6d 100644 (file)
@@ -568,6 +568,7 @@ Session::follow_slave (nframes_t nframes)
                        
                        if (_slave->give_slave_full_control_over_transport_speed()) {
                                set_transport_speed (slave_speed, false, false);
+                               //std::cout << "set speed = " << slave_speed << "\n";
                        } else {
                                float adjusted_speed = slave_speed + (1.5 * (delta /  float(_current_frame_rate)));
                                request_transport_speed (adjusted_speed);
@@ -576,10 +577,12 @@ Session::follow_slave (nframes_t nframes)
                                                                           slave_speed));
                        }
                        
+#if 0
                        if (abs(average_slave_delta) > _slave->resolution()) {
                                cerr << "average slave delta greater than slave resolution (" << _slave->resolution() << "), going to silent motion\n";
                                goto silent_motion;
                        }
+#endif
                }
        }
 
index f1bfa5ea92b108482e44a04b1631f28a41383695..db3d9e94ae79e59b61a6e5aec806aef66aea56e0 100644 (file)
@@ -1281,6 +1281,20 @@ Session::set_state (const XMLNode& node, int version)
                }
        }
        
+       if ((child = find_named_node (node, "TempoMap")) == 0) {
+               error << _("Session: XML state has no Tempo Map section") << endmsg;
+               goto out;
+       } else if (_tempo_map->set_state (*child, version)) {
+               goto out;
+       }
+
+       if ((child = find_named_node (node, "Routes")) == 0) {
+               error << _("Session: XML state has no routes section") << endmsg;
+               goto out;
+       } else if (load_routes (*child, version)) {
+               goto out;
+       }
+
        if (version >= 3000) {
                
                if ((child = find_named_node (node, "RouteGroups")) == 0) {
@@ -1307,20 +1321,6 @@ Session::set_state (const XMLNode& node, int version)
                }
        }
 
-       if ((child = find_named_node (node, "TempoMap")) == 0) {
-               error << _("Session: XML state has no Tempo Map section") << endmsg;
-               goto out;
-       } else if (_tempo_map->set_state (*child, version)) {
-               goto out;
-       }
-
-       if ((child = find_named_node (node, "Routes")) == 0) {
-               error << _("Session: XML state has no routes section") << endmsg;
-               goto out;
-       } else if (load_routes (*child, version)) {
-               goto out;
-       }
-
        if ((child = find_named_node (node, "Click")) == 0) {
                warning << _("Session: XML state has no click section") << endmsg;
        } else if (_click_io) {
@@ -2103,15 +2103,14 @@ Session::remove_route_group (RouteGroup& rg)
        list<RouteGroup*>::iterator i;
 
        if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
-               (*i)->apply (&Route::drop_route_group, this);
                _route_groups.erase (i);
+               delete &rg;
+
                route_group_removed (); /* EMIT SIGNAL */
        }
 
-       delete &rg;
 }
 
-
 RouteGroup *
 Session::route_group_by_name (string name)
 {
index 3e5f763461f243acbe783f965244151a1eb224b5..9f056d9223403c6df7899f98e7543c6734de17bc 100644 (file)
@@ -153,6 +153,7 @@ libardour_sources = [
        'reverse.cc',
        'route.cc',
        'route_group.cc',
+       'route_group_member.cc',
        'rb_effect.cc',
        'send.cc',
        'session.cc',
index d53c44b0a87b9a800c21d942e4b8b883cd506386..f2a99296a1e7be82fff67c9255316e34f6640dd2 100644 (file)
@@ -295,3 +295,4 @@ BasicUI::sample_to_timecode (nframes_t sample, Timecode::Time& timecode, bool us
 {
        session->sample_to_timecode (sample, *((Timecode::Time*)&timecode), use_offset, use_subframes);
 }
+
index d702b1a3a22be685e652bc6d7aa107e86ea3ca58..3456838041fb103a14bf97e4c5d5410ff42b8e9e 100644 (file)
@@ -30,6 +30,7 @@
 
 namespace ARDOUR {
        class Session;
+       class SessionEvent;
 }
 
 class BasicUI {