From 61cade6d59118288e90a405e0f4fbc24d0108814 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Thu, 10 Dec 2009 03:25:32 +0000 Subject: drastic, deep and wide changes to make RouteGroup use boost::shared_ptr and boost::shared_ptr to better fit into emerging framework for "RT operations" ; torben's changes to MTC slaving code (sorry for bundling) git-svn-id: svn://localhost/ardour2/branches/3.0@6334 d708f5d6-7413-0410-9779-e7cbd77b26cf --- libs/ardour/ardour/pi_controller.h | 31 +++++ libs/ardour/ardour/route.h | 9 +- libs/ardour/ardour/route_group.h | 33 ++--- libs/ardour/ardour/route_group_member.h | 51 ++++++++ libs/ardour/ardour/route_group_specialized.h | 12 +- libs/ardour/ardour/slave.h | 4 +- libs/ardour/mtc_slave.cc | 36 +++++- libs/ardour/pi_controller.cc | 133 ++++++++++++++++++++- libs/ardour/route.cc | 61 +--------- libs/ardour/route_group.cc | 96 +++++++++++---- libs/ardour/route_group_member.cc | 43 +++++++ libs/ardour/session.cc | 8 +- libs/ardour/session_process.cc | 3 + libs/ardour/session_state.cc | 33 +++-- libs/ardour/wscript | 1 + libs/surfaces/control_protocol/basic_ui.cc | 1 + .../control_protocol/control_protocol/basic_ui.h | 1 + 17 files changed, 416 insertions(+), 140 deletions(-) create mode 100644 libs/ardour/ardour/route_group_member.h create mode 100644 libs/ardour/route_group_member.cc (limited to 'libs') diff --git a/libs/ardour/ardour/pi_controller.h b/libs/ardour/ardour/pi_controller.h index f992e6a18c..d3cd0eb6bf 100644 --- a/libs/ardour/ardour/pi_controller.h +++ b/libs/ardour/ardour/pi_controller.h @@ -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__ */ diff --git a/libs/ardour/ardour/route.h b/libs/ardour/ardour/route.h index 8b08dded99..8e63a2d523 100644 --- a/libs/ardour/ardour/route.h +++ b/libs/ardour/ardour/route.h @@ -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 processors_changed; sigc::signal record_enable_changed; - sigc::signal route_group_changed; /** the metering point has changed */ sigc::signal meter_change; sigc::signal signal_latency_changed; @@ -369,7 +365,6 @@ class Route : public SessionObject, public AutomatableControls boost::shared_ptr _mute_master; MuteMaster::MutePoint _mute_points; - RouteGroup* _route_group; std::string _comment; bool _have_internal_generator; bool _solo_safe; diff --git a/libs/ardour/ardour/route_group.h b/libs/ardour/ardour/route_group.h index 0f71093377..996e8fee2f 100644 --- a/libs/ardour/ardour/route_group.h +++ b/libs/ardour/ardour/route_group.h @@ -25,6 +25,7 @@ #include #include #include + #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); + int remove (boost::shared_ptr); void apply (void (Route::*func)(void *), void *src) { - for (std::list::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 void apply (void (Route::*func)(T, void *), T val, void *src) { - for (std::list::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 void foreach_route (T *obj, void (T::*func)(Route&)) { - for (std::list::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& at_set); + void audio_track_group (std::set >& at_set); void clear () { - routes.clear (); + routes->clear (); changed(); } void make_subgroup (); void destroy_subgroup (); - const std::list& route_list() { return routes; } + boost::shared_ptr route_list() { return routes; } + boost::shared_ptr route_list (Property forProperty); sigc::signal changed; sigc::signal FlagsChanged; @@ -135,13 +136,13 @@ public: private: Session& _session; - std::list routes; + boost::shared_ptr routes; boost::shared_ptr subgroup_bus; std::string _name; Flag _flags; Property _properties; - void remove_when_going_away (Route*); + void remove_when_going_away (boost::weak_ptr); 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 index 0000000000..4b577121a6 --- /dev/null +++ b/libs/ardour/ardour/route_group_member.h @@ -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 + +namespace ARDOUR { + +class RouteGroup; + +class RouteGroupMember +{ + public: + RouteGroupMember () : _route_group (0) {} + virtual ~RouteGroupMember() {} + + RouteGroup* route_group () const { return _route_group; } + + sigc::signal 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__ */ diff --git a/libs/ardour/ardour/route_group_specialized.h b/libs/ardour/ardour/route_group_specialized.h index c9d06a93c9..242a16c43e 100644 --- a/libs/ardour/ardour/route_group_specialized.h +++ b/libs/ardour/ardour/route_group_specialized.h @@ -26,12 +26,13 @@ namespace ARDOUR { template 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::iterator i = routes.begin(); i != routes.end(); i++) { - Track *at; - if ((at = dynamic_cast(*i)) != 0) { - (at->*func)(val, this); + for (RouteList::iterator i = routes->begin(); i != routes->end(); i++) { + boost::shared_ptr at; + + if ((at = boost::dynamic_pointer_cast(*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__ */ + diff --git a/libs/ardour/ardour/slave.h b/libs/ardour/ardour/slave.h index b01722e306..1125e920a0 100644 --- a/libs/ardour/ardour/slave.h +++ b/libs/ardour/ardour/slave.h @@ -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 connections; bool can_notify_on_unknown_rate; - PIController* pic; + PIChaser* pic; static const int frame_tolerance; diff --git a/libs/ardour/mtc_slave.cc b/libs/ardour/mtc_slave.cc index 41aaaccbcf..95fa4d984a 100644 --- a/libs/ardour/mtc_slave.cc +++ b/libs/ardour/mtc_slave.cc @@ -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 diff --git a/libs/ardour/pi_controller.cc b/libs/ardour/pi_controller.cc index 5aee7f2301..1db36355fe 100644 --- a/libs/ardour/pi_controller.cc +++ b/libs/ardour/pi_controller.cc @@ -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; ireset(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; } diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index 768df38698..f04de4c242 100644 --- a/libs/ardour/route.cc +++ b/libs/ardour/route.cc @@ -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) } } -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) { diff --git a/libs/ardour/route_group.cc b/libs/ardour/route_group.cc index f33a7f1f40..d7ac672f9a 100644 --- a/libs/ardour/route_group.cc +++ b/libs/ardour/route_group.cc @@ -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 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 (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 wr) { - remove (r); + boost::shared_ptr r (wr.lock()); + + if (r) { + remove (r); + } } int -RouteGroup::remove (Route *r) +RouteGroup::remove (boost::shared_ptr r) { - list::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::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::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 ids; + split (str.str(), ids, ' '); + + for (vector::iterator i = ids.begin(); i != ids.end(); ++i) { + PBD::ID id (*i); + boost::shared_ptr 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& ats) +RouteGroup::audio_track_group (set >& ats) { - for (list::iterator i = routes.begin(); i != routes.end(); ++i) { - AudioTrack* at = dynamic_cast(*i); + for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) { + boost::shared_ptr at = boost::dynamic_pointer_cast(*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::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::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 = subgroup_bus->input()->bundle (); - for (list::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::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 index 0000000000..e4075df689 --- /dev/null +++ b/libs/ardour/route_group_member.cc @@ -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 */ +} + diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index 9c3b28049f..0bf161bb5d 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -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); diff --git a/libs/ardour/session_process.cc b/libs/ardour/session_process.cc index 882694cccf..568017c064 100644 --- a/libs/ardour/session_process.cc +++ b/libs/ardour/session_process.cc @@ -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 } } diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index f1bfa5ea92..db3d9e94ae 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -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::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) { diff --git a/libs/ardour/wscript b/libs/ardour/wscript index 3e5f763461..9f056d9223 100644 --- a/libs/ardour/wscript +++ b/libs/ardour/wscript @@ -153,6 +153,7 @@ libardour_sources = [ 'reverse.cc', 'route.cc', 'route_group.cc', + 'route_group_member.cc', 'rb_effect.cc', 'send.cc', 'session.cc', diff --git a/libs/surfaces/control_protocol/basic_ui.cc b/libs/surfaces/control_protocol/basic_ui.cc index d53c44b0a8..f2a99296a1 100644 --- a/libs/surfaces/control_protocol/basic_ui.cc +++ b/libs/surfaces/control_protocol/basic_ui.cc @@ -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); } + diff --git a/libs/surfaces/control_protocol/control_protocol/basic_ui.h b/libs/surfaces/control_protocol/control_protocol/basic_ui.h index d702b1a3a2..3456838041 100644 --- a/libs/surfaces/control_protocol/control_protocol/basic_ui.h +++ b/libs/surfaces/control_protocol/control_protocol/basic_ui.h @@ -30,6 +30,7 @@ namespace ARDOUR { class Session; + class SessionEvent; } class BasicUI { -- cgit v1.2.3