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
This commit is contained in:
Paul Davis 2009-12-10 03:25:32 +00:00
parent f18bcf0cc8
commit 61cade6d59
30 changed files with 472 additions and 191 deletions

View 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);

View 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;

View 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;

View 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);
}

View 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);
}
}
}

View 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();

View 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;

View 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();
}
}

View 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 ());

View 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;

View File

@ -73,7 +73,6 @@ RouteGroupMenu::set_group (RouteGroup* g)
GroupSelected (g);
}
void
RouteGroupMenu::new_group ()
{

View 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
}
}
}

View 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
}
}

View 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__ */

View 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;

View 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);
};

View File

@ -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__ */

View File

@ -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__ */

View 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;

View 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

View 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;
}

View 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)
{

View 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 */
}

View File

@ -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 */
}

View 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);

View 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
}
}

View 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)
{

View 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',

View 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);
}

View File

@ -30,6 +30,7 @@
namespace ARDOUR {
class Session;
class SessionEvent;
}
class BasicUI {