summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2009-12-10 03:25:32 +0000
committerPaul Davis <paul@linuxaudiosystems.com>2009-12-10 03:25:32 +0000
commit61cade6d59118288e90a405e0f4fbc24d0108814 (patch)
treefe9083a4c005ac239bf5995c16252609dc547869 /libs
parentf18bcf0cc835ab401d8e28dcc18c72795977752a (diff)
drastic, deep and wide changes to make RouteGroup use boost::shared_ptr<Route> and boost::shared_ptr<RouteList> 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
Diffstat (limited to 'libs')
-rw-r--r--libs/ardour/ardour/pi_controller.h31
-rw-r--r--libs/ardour/ardour/route.h9
-rw-r--r--libs/ardour/ardour/route_group.h33
-rw-r--r--libs/ardour/ardour/route_group_member.h51
-rw-r--r--libs/ardour/ardour/route_group_specialized.h12
-rw-r--r--libs/ardour/ardour/slave.h4
-rw-r--r--libs/ardour/mtc_slave.cc36
-rw-r--r--libs/ardour/pi_controller.cc133
-rw-r--r--libs/ardour/route.cc61
-rw-r--r--libs/ardour/route_group.cc96
-rw-r--r--libs/ardour/route_group_member.cc43
-rw-r--r--libs/ardour/session.cc8
-rw-r--r--libs/ardour/session_process.cc3
-rw-r--r--libs/ardour/session_state.cc33
-rw-r--r--libs/ardour/wscript1
-rw-r--r--libs/surfaces/control_protocol/basic_ui.cc1
-rw-r--r--libs/surfaces/control_protocol/control_protocol/basic_ui.h1
17 files changed, 416 insertions, 140 deletions
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<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;
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 <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
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 <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__ */
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<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__ */
+
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<sigc::connection> 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; 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;
}
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) {
@@ -2399,33 +2371,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)
{
_comment = cmt;
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<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
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<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)
{
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 {