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:
parent
f18bcf0cc8
commit
61cade6d59
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 ());
|
||||
|
@ -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;
|
||||
|
@ -73,7 +73,6 @@ RouteGroupMenu::set_group (RouteGroup* g)
|
||||
GroupSelected (g);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
RouteGroupMenu::new_group ()
|
||||
{
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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__ */
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
|
51
libs/ardour/ardour/route_group_member.h
Normal file
51
libs/ardour/ardour/route_group_member.h
Normal 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__ */
|
@ -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__ */
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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 */
|
||||
}
|
||||
|
43
libs/ardour/route_group_member.cc
Normal file
43
libs/ardour/route_group_member.cc
Normal 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 */
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -153,6 +153,7 @@ libardour_sources = [
|
||||
'reverse.cc',
|
||||
'route.cc',
|
||||
'route_group.cc',
|
||||
'route_group_member.cc',
|
||||
'rb_effect.cc',
|
||||
'send.cc',
|
||||
'session.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);
|
||||
}
|
||||
|
||||
|
@ -30,6 +30,7 @@
|
||||
|
||||
namespace ARDOUR {
|
||||
class Session;
|
||||
class SessionEvent;
|
||||
}
|
||||
|
||||
class BasicUI {
|
||||
|
Loading…
Reference in New Issue
Block a user