Insert/Redirect refactoring, towards better MIDI support in mixer strip, and

http://ardour.org/node/1043 style things.


git-svn-id: svn://localhost/ardour2/trunk@2027 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
David Robillard 2007-06-23 20:13:13 +00:00
parent 05184ed52f
commit 49ee64ada7
77 changed files with 2052 additions and 1948 deletions

View file

@ -74,6 +74,7 @@ gain.cc
gdither.cc
globals.cc
import.cc
automatable.cc
insert.cc
plugin_insert.cc
port_insert.cc

View file

@ -28,6 +28,8 @@ class BufferSet;
/** Applies a declick operation to all audio inputs, passing the same number of
* audio outputs, and passing through any other types unchanged.
*
* FIXME: make this an insert.
*/
class Amp {
public:

View file

@ -56,7 +56,8 @@ class AudioFileSource : public AudioSource {
virtual ~AudioFileSource ();
int set_name (Glib::ustring newname, bool destructive);
bool set_name (const std::string& newname) { return (set_source_name(newname, destructive()) == 0); }
int set_source_name (Glib::ustring newname, bool destructive);
Glib::ustring path() const { return _path; }
Glib::ustring peak_path (Glib::ustring audio_path);

View file

@ -0,0 +1,78 @@
/*
Copyright (C) 2000,2007 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 __ardour_automatable_h__
#define __ardour_automatable_h__
#include <set>
#include <map>
#include <ardour/session_object.h>
#include <ardour/automation_event.h>
namespace ARDOUR {
class Session;
class Automatable : public SessionObject
{
public:
Automatable(Session&, const std::string& name);
virtual ~Automatable() {}
virtual AutomationList& automation_list(uint32_t n);
virtual void automation_snapshot (nframes_t now) {};
virtual bool find_next_event(nframes_t start, nframes_t end, ControlEvent& ev) const;
virtual string describe_parameter(uint32_t which);
virtual float default_parameter_value(uint32_t which) { return 1.0f; }
void what_has_automation(std::set<uint32_t>&) const;
void what_has_visible_automation(std::set<uint32_t>&) const;
const std::set<uint32_t>& what_can_be_automated() const { return _can_automate_list; }
void mark_automation_visible(uint32_t, bool);
protected:
void can_automate(uint32_t);
virtual void automation_list_creation_callback(uint32_t, AutomationList&) {}
int set_automation_state(const XMLNode&);
XMLNode& get_automation_state();
int load_automation (const std::string& path);
int old_set_automation_state(const XMLNode&);
mutable Glib::Mutex _automation_lock;
// FIXME: map with int keys is a bit silly. this could be O(1)
std::map<uint32_t,AutomationList*> _parameter_automation;
std::set<uint32_t> _visible_parameter_automation;
std::set<uint32_t> _can_automate_list;
nframes_t _last_automation_snapshot;
};
} // namespace ARDOUR
#endif /* __ardour_automatable_h__ */

View file

@ -114,10 +114,10 @@ class AutomationList : public PBD::StatefulDestructible
AutoStyle automation_style() const { return _style; }
sigc::signal<void> automation_state_changed;
bool automation_playback() {
bool automation_playback() const {
return (_state & Play) || ((_state & Touch) && !_touching);
}
bool automation_write () {
bool automation_write () const {
return (_state & Write) || ((_state & Touch) && _touching);
}

View file

@ -60,7 +60,7 @@ class Curve : public AutomationList
void solve ();
static sigc::signal<void, Curve*> CurveCreated;
static sigc::signal<void, Curve*> CurveCreated;
protected:
ControlEvent* point_factory (double,double) const;

View file

@ -53,7 +53,7 @@ class Session;
class Playlist;
class IO;
class Diskstream : public PBD::StatefulDestructible
class Diskstream : public SessionObject
{
public:
enum Flag {
@ -65,9 +65,8 @@ class Diskstream : public PBD::StatefulDestructible
Diskstream (Session &, const string& name, Flag f = Recordable);
Diskstream (Session &, const XMLNode&);
virtual ~Diskstream();
string name () const { return _name; }
virtual int set_name (string str);
bool set_name (const string& str);
ARDOUR::IO* io() const { return _io; }
void set_io (ARDOUR::IO& io);
@ -238,8 +237,6 @@ class Diskstream : public PBD::StatefulDestructible
uint32_t i_am_the_modifier;
string _name;
ARDOUR::Session& _session;
ARDOUR::IO* _io;
ChanCount _n_channels;

View file

@ -24,11 +24,16 @@
#include <string>
#include <exception>
#include <pbd/statefuldestructible.h>
#include <sigc++/signal.h>
#include <ardour/ardour.h>
#include <ardour/redirect.h>
#include <ardour/plugin_state.h>
#include <ardour/types.h>
#include <ardour/ardour.h>
#include <ardour/plugin_state.h>
#include <ardour/buffer_set.h>
#include <ardour/automatable.h>
class XMLNode;
@ -36,26 +41,71 @@ namespace ARDOUR {
class Session;
class Insert : public Redirect
/* A mixer strip element - plugin, send, meter, etc.
*/
class Insert : public Automatable
{
public:
Insert(Session& s, std::string name, Placement p);
Insert(Session& s, std::string name, Placement p, int imin, int imax, int omin, int omax);
static const string state_node_name;
Insert(Session&, const string& name, Placement p); // TODO: remove placement in favour of sort key
virtual ~Insert() { }
static boost::shared_ptr<Insert> clone (boost::shared_ptr<const Insert>);
uint32_t sort_key() const { return _sort_key; }
void set_sort_key (uint32_t key);
Placement placement() const { return _placement; }
void set_placement (Placement);
bool active () const { return _active; }
void set_active (bool yn);
bool get_next_ab_is_active () const { return _next_ab_is_active; }
void set_next_ab_is_active (bool yn) { _next_ab_is_active = yn; }
virtual nframes_t latency() { return 0; }
virtual void transport_stopped (nframes_t frame) {}
virtual void set_block_size (nframes_t nframes) {}
virtual void run (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes, nframes_t offset) = 0;
virtual void silence (nframes_t nframes, nframes_t offset) {}
virtual void activate () {}
virtual void deactivate () {}
virtual void activate () { _active = true; ActiveChanged.emit(); }
virtual void deactivate () { _active = false; ActiveChanged.emit(); }
virtual bool configure_io (ChanCount in, ChanCount out) { _configured_input = in; return (_configured = true); }
virtual bool can_support_input_configuration (ChanCount in) const = 0;
virtual ChanCount output_for_input_configuration (ChanCount in) const = 0;
virtual bool configure_io (ChanCount in, ChanCount out) = 0;
/* Act as a pass through, if not overridden */
virtual bool can_support_input_configuration (ChanCount in) const { return true; }
virtual ChanCount output_for_input_configuration (ChanCount in) const { return in; }
virtual ChanCount output_streams() const { return _configured_input; }
virtual ChanCount input_streams () const { return _configured_input; }
virtual XMLNode& state (bool full);
virtual XMLNode& get_state (void);
virtual int set_state (const XMLNode&);
void *get_gui () const { return _gui; }
void set_gui (void *p) { _gui = p; }
static sigc::signal<void,Insert*> InsertCreated;
sigc::signal<void> ActiveChanged;
sigc::signal<void> PlacementChanged;
protected:
bool _active;
bool _next_ab_is_active;
bool _configured;
ChanCount _configured_input;
Placement _placement;
uint32_t _sort_key;
void* _gui; /* generic, we don't know or care what this is */
};
} // namespace ARDOUR

View file

@ -34,6 +34,7 @@
#include <pbd/controllable.h>
#include <ardour/ardour.h>
#include <ardour/session_object.h>
#include <ardour/utils.h>
#include <ardour/curve.h>
#include <ardour/types.h>
@ -63,13 +64,13 @@ class BufferSet;
* An IO can contain ports of varying types, making routes/inserts/etc with
* varied combinations of types (eg MIDI and audio) possible.
*/
class IO : public PBD::StatefulDestructible
class IO : public SessionObject
{
public:
static const string state_node_name;
IO (Session&, string name,
IO (Session&, const string& name,
int input_min = -1, int input_max = -1,
int output_min = -1, int output_max = -1,
DataType default_type = DataType::AUDIO);
@ -90,10 +91,9 @@ class IO : public PBD::StatefulDestructible
DataType default_type() const { return _default_type; }
void set_default_type(DataType t) { _default_type = t; }
const string& name() const { return _name; }
virtual int set_name (string str, void *src);
bool set_name (const string& str);
virtual void silence (nframes_t, nframes_t offset);
void collect_input (BufferSet& bufs, nframes_t nframes, nframes_t offset);
@ -179,7 +179,6 @@ class IO : public PBD::StatefulDestructible
sigc::signal<void,IOChange,void*> output_changed;
sigc::signal<void,void*> gain_changed;
sigc::signal<void,void*> name_changed;
virtual XMLNode& state (bool full);
XMLNode& get_state (void);
@ -229,26 +228,16 @@ class IO : public PBD::StatefulDestructible
void clear_automation ();
bool gain_automation_recording() const {
return (_gain_automation_curve.automation_state() & (Write|Touch));
}
bool gain_automation_playback() const {
return (_gain_automation_curve.automation_state() & Play) ||
((_gain_automation_curve.automation_state() & Touch) &&
!_gain_automation_curve.touching());
}
virtual void set_gain_automation_state (AutoState);
AutoState gain_automation_state() const { return _gain_automation_curve.automation_state(); }
sigc::signal<void> gain_automation_state_changed;
//sigc::signal<void> gain_automation_state_changed;
virtual void set_gain_automation_style (AutoStyle);
AutoStyle gain_automation_style () const { return _gain_automation_curve.automation_style(); }
sigc::signal<void> gain_automation_style_changed;
//sigc::signal<void> gain_automation_style_changed;
virtual void transport_stopped (nframes_t now);
void automation_snapshot (nframes_t now);
virtual void transport_stopped (nframes_t now); // interface: matches Insert
void automation_snapshot (nframes_t now); // interface: matches Automatable
ARDOUR::Curve& gain_automation_curve () { return _gain_automation_curve; }
@ -272,7 +261,6 @@ class IO : public PBD::StatefulDestructible
mutable Glib::Mutex io_lock;
protected:
Session& _session;
Panner* _panner;
BufferSet* _output_buffers; //< Set directly to output port buffers
gain_t _gain;
@ -282,7 +270,6 @@ class IO : public PBD::StatefulDestructible
PortSet _outputs;
PortSet _inputs;
PeakMeter* _meter;
string _name;
Bundle* _input_bundle;
Bundle* _output_bundle;
bool no_panner_reset;
@ -336,6 +323,8 @@ class IO : public PBD::StatefulDestructible
private:
friend class Send;
/* are these the best variable names ever, or what? */
sigc::connection input_bundle_configuration_connection;

View file

@ -21,6 +21,7 @@
#include <vector>
#include <ardour/types.h>
#include <ardour/insert.h>
#include <pbd/fastlog.h>
namespace ARDOUR {
@ -32,16 +33,17 @@ class Session;
/** Meters peaks on the input and stores them for access.
*/
class PeakMeter {
class PeakMeter : public Insert {
public:
PeakMeter(Session& s) : _session(s) {}
PeakMeter(Session& s) : Insert(s, "meter", PreFader) {}
void setup (const ChanCount& in);
void reset ();
void reset_max ();
bool configure_io (ChanCount in, ChanCount out);
/** Compute peaks */
void run (BufferSet& bufs, nframes_t nframes, nframes_t offset=0);
void run (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes, nframes_t offset);
float peak_power (uint32_t n) {
if (n < _visible_peak_power.size()) {
@ -64,7 +66,6 @@ private:
friend class IO;
void meter();
Session& _session;
std::vector<float> _peak_power;
std::vector<float> _visible_peak_power;
std::vector<float> _max_peak_power;

View file

@ -37,8 +37,6 @@ public:
MidiTrack (Session&, const XMLNode&);
~MidiTrack ();
int set_name (string str, void *src);
int roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame,
nframes_t offset, int declick, bool can_record, bool rec_monitors_input);

View file

@ -38,6 +38,7 @@
#include <pbd/statefuldestructible.h>
#include <ardour/ardour.h>
#include <ardour/session_object.h>
#include <ardour/crossfade_compare.h>
#include <ardour/location.h>
#include <ardour/data_type.h>
@ -47,7 +48,7 @@ namespace ARDOUR {
class Session;
class Region;
class Playlist : public PBD::StatefulDestructible, public boost::enable_shared_from_this<Playlist> {
class Playlist : public SessionObject, public boost::enable_shared_from_this<Playlist> {
public:
typedef list<boost::shared_ptr<Region> > RegionList;
@ -67,8 +68,7 @@ class Playlist : public PBD::StatefulDestructible, public boost::enable_shared_f
void release();
bool used () const { return _refcnt != 0; }
std::string name() const { return _name; }
void set_name (std::string str);
bool set_name (const string& str);
const DataType& data_type() const { return _type; }
@ -130,8 +130,6 @@ class Playlist : public PBD::StatefulDestructible, public boost::enable_shared_f
uint32_t read_data_count() const { return _read_data_count; }
Session& session() { return _session; }
const PBD::ID& get_orig_diskstream_id () const { return _orig_diskstream_id; }
void set_orig_diskstream_id (const PBD::ID& did) { _orig_diskstream_id = did; }
@ -170,8 +168,6 @@ class Playlist : public PBD::StatefulDestructible, public boost::enable_shared_f
RegionList regions; /* the current list of regions in the playlist */
std::set<boost::shared_ptr<Region> > all_regions; /* all regions ever added to this playlist */
string _name;
Session& _session;
DataType _type;
mutable gint block_notifications;
mutable gint ignore_state_changes;

View file

@ -22,13 +22,13 @@
#include <vector>
#include <string>
#include <exception>
#include <sigc++/signal.h>
#include <ardour/ardour.h>
#include <ardour/plugin_state.h>
#include <ardour/types.h>
#include <ardour/insert.h>
#include <ardour/automation_event.h>
class XMLNode;
@ -105,7 +105,7 @@ class PluginInsert : public Insert
void parameter_changed (uint32_t, float);
vector<boost::shared_ptr<Plugin> > _plugins;
std::vector<boost::shared_ptr<Plugin> > _plugins;
void automation_run (BufferSet& bufs, nframes_t nframes, nframes_t offset);
void connect_and_run (BufferSet& bufs, nframes_t nframes, nframes_t offset, bool with_auto, nframes_t now = 0);

View file

@ -26,7 +26,7 @@
#include <sigc++/signal.h>
#include <ardour/ardour.h>
#include <ardour/insert.h>
#include <ardour/redirect.h>
#include <ardour/plugin_state.h>
#include <ardour/types.h>
@ -37,8 +37,10 @@ namespace ARDOUR {
class Session;
/** Port inserts: send output to a Jack port, pick up input at a Jack port
*
* PortInsert IS-A Redirect IS-A Insert, IO
*/
class PortInsert : public Insert
class PortInsert : public Redirect
{
public:
PortInsert (Session&, Placement);

View file

@ -32,6 +32,7 @@
#include <pbd/undo.h>
#include <ardour/ardour.h>
#include <ardour/insert.h>
#include <ardour/io.h>
#include <ardour/automation_event.h>
@ -46,97 +47,37 @@ namespace ARDOUR {
class Session;
class Redirect : public IO
/** A mixer strip element (Insert) with Jack ports (IO).
*/
class Redirect : public Insert
{
public:
static const string state_node_name;
Redirect (Session&, const string& name, Placement,
int input_min = -1, int input_max = -1, int output_min = -1, int output_max = -1);
Redirect (const Redirect&);
virtual ~Redirect ();
virtual ChanCount output_streams() const { return _io->n_outputs(); }
virtual ChanCount input_streams () const { return _io->n_inputs(); }
virtual ChanCount natural_output_streams() const { return _io->n_outputs(); }
virtual ChanCount natural_input_streams () const { return _io->n_inputs(); }
static boost::shared_ptr<Redirect> clone (boost::shared_ptr<const Redirect>);
bool active () const { return _active; }
void set_active (bool yn, void *src);
virtual ChanCount output_streams() const { return n_outputs(); }
virtual ChanCount input_streams () const { return n_inputs(); }
virtual ChanCount natural_output_streams() const { return n_outputs(); }
virtual ChanCount natural_input_streams () const { return n_inputs(); }
uint32_t sort_key() const { return _sort_key; }
void set_sort_key (uint32_t key);
Placement placement() const { return _placement; }
void set_placement (Placement, void *src);
boost::shared_ptr<IO> io() { return _io; }
boost::shared_ptr<const IO> io() const { return _io; }
virtual void automation_snapshot (nframes_t now) { _io->automation_snapshot(now); }
virtual void run (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes, nframes_t offset) = 0;
virtual void activate () = 0;
virtual void deactivate () = 0;
virtual nframes_t latency() { return 0; }
void silence (nframes_t nframes, nframes_t offset);
virtual void set_block_size (nframes_t nframes) {}
sigc::signal<void,Redirect*,void*> active_changed;
sigc::signal<void,Redirect*,void*> placement_changed;
sigc::signal<void,Redirect*,bool> AutomationPlaybackChanged;
sigc::signal<void,Redirect*,bool> AutomationPlaybackChanged;
sigc::signal<void,Redirect*,uint32_t> AutomationChanged;
static sigc::signal<void,Redirect*> RedirectCreated;
XMLNode& state (bool full);
XMLNode& get_state (void);
XMLNode& state (bool full_state);
int set_state (const XMLNode&);
void *get_gui () const { return _gui; }
void set_gui (void *p) { _gui = p; }
virtual string describe_parameter (uint32_t which);
virtual float default_parameter_value (uint32_t which) {
return 1.0f;
}
void what_has_automation (set<uint32_t>&) const;
void what_has_visible_automation (set<uint32_t>&) const;
const set<uint32_t>& what_can_be_automated () const { return can_automate_list; }
void mark_automation_visible (uint32_t, bool);
AutomationList& automation_list (uint32_t);
bool find_next_event (nframes_t, nframes_t, ControlEvent&) const;
virtual void transport_stopped (nframes_t frame) {};
bool get_next_ab_is_active () const { return _next_ab_is_active; }
void set_next_ab_is_active (bool yn);
protected:
/* children may use this stuff as they see fit */
map<uint32_t,AutomationList*> parameter_automation;
set<uint32_t> visible_parameter_automation;
mutable Glib::Mutex _automation_lock;
void can_automate (uint32_t);
set<uint32_t> can_automate_list;
virtual void automation_list_creation_callback (uint32_t, AutomationList&) {}
int set_automation_state (const XMLNode&);
XMLNode& get_automation_state ();
private:
bool _active;
bool _next_ab_is_active;
Placement _placement;
uint32_t _sort_key;
void* _gui; /* generic, we don't know or care what this is */
int old_set_automation_state (const XMLNode&);
int load_automation (std::string path);
boost::shared_ptr<IO> _io;
};
} // namespace ARDOUR

View file

@ -59,7 +59,8 @@ class Route : public IO
{
protected:
typedef list<boost::shared_ptr<Redirect> > RedirectList;
typedef list<boost::shared_ptr<Insert> > InsertList;
public:
enum Flag {
@ -99,7 +100,7 @@ class Route : public IO
virtual bool can_record() { return false; }
virtual void set_record_enable (bool yn, void *src) {}
virtual bool record_enabled() const { return false; }
virtual void handle_transport_stopped (bool abort, bool did_locate, bool flush_redirects);
virtual void handle_transport_stopped (bool abort, bool did_locate, bool flush_inserts);
virtual void set_pending_declick (int);
/* end of vfunc-based API */
@ -136,54 +137,54 @@ class Route : public IO
virtual void set_meter_point (MeterPoint, void *src);
MeterPoint meter_point() const { return _meter_point; }
/* Redirects */
/* Inserts */
void flush_redirects ();
void flush_inserts ();
template<class T> void foreach_redirect (T *obj, void (T::*func)(boost::shared_ptr<Redirect>)) {
Glib::RWLock::ReaderLock lm (redirect_lock);
for (RedirectList::iterator i = _redirects.begin(); i != _redirects.end(); ++i) {
template<class T> void foreach_insert (T *obj, void (T::*func)(boost::shared_ptr<Insert>)) {
Glib::RWLock::ReaderLock lm (insert_lock);
for (InsertList::iterator i = _inserts.begin(); i != _inserts.end(); ++i) {
(obj->*func) (*i);
}
}
boost::shared_ptr<Redirect> nth_redirect (uint32_t n) {
Glib::RWLock::ReaderLock lm (redirect_lock);
RedirectList::iterator i;
for (i = _redirects.begin(); i != _redirects.end() && n; ++i, --n);
if (i == _redirects.end()) {
boost::shared_ptr<Insert> nth_insert (uint32_t n) {
Glib::RWLock::ReaderLock lm (insert_lock);
InsertList::iterator i;
for (i = _inserts.begin(); i != _inserts.end() && n; ++i, --n);
if (i == _inserts.end()) {
return boost::shared_ptr<Redirect> ();
} else {
return *i;
}
}
ChanCount max_redirect_outs () const { return redirect_max_outs; }
ChanCount max_insert_outs () const { return insert_max_outs; }
ChanCount pre_fader_streams() const;
/** A record of the stream configuration at some point in the redirect list.
* Used to return where and why a redirect list configuration request failed.
/** A record of the stream configuration at some point in the insert list.
* Used to return where and why an insert list configuration request failed.
*/
struct InsertStreams {
InsertStreams(size_t i=0, ChanCount c=ChanCount()) : index(i), count(c) {}
size_t index; ///< Index of redirect where configuration failed
ChanCount count; ///< Input requested of redirect
size_t index; ///< Index of insert where configuration failed
ChanCount count; ///< Input requested of insert
};
int add_redirect (boost::shared_ptr<Redirect>, void *src, InsertStreams* err = 0);
int add_redirects (const RedirectList&, void *src, InsertStreams* err = 0);
int remove_redirect (boost::shared_ptr<Redirect>, void *src, InsertStreams* err = 0);
int copy_redirects (const Route&, Placement, InsertStreams* err = 0);
int sort_redirects (InsertStreams* err = 0);
void disable_redirects (Placement);
void disable_redirects ();
int add_insert (boost::shared_ptr<Insert>, InsertStreams* err = 0);
int add_inserts (const InsertList&, InsertStreams* err = 0);
int remove_insert (boost::shared_ptr<Insert>, InsertStreams* err = 0);
int copy_inserts (const Route&, Placement, InsertStreams* err = 0);
int sort_inserts (InsertStreams* err = 0);
void disable_inserts (Placement);
void disable_inserts ();
void disable_plugins (Placement);
void disable_plugins ();
void ab_plugins (bool forward);
void clear_redirects (Placement, void *src);
void all_redirects_flip();
void all_redirects_active (Placement, bool state);
void clear_inserts (Placement);
void all_inserts_flip();
void all_inserts_active (Placement, bool state);
virtual nframes_t update_total_latency();
nframes_t signal_latency() const { return _own_latency; }
@ -197,7 +198,7 @@ class Route : public IO
sigc::signal<void,void*> post_fader_changed;
sigc::signal<void,void*> control_outs_changed;
sigc::signal<void,void*> main_outs_changed;
sigc::signal<void,void*> redirects_changed;
sigc::signal<void> inserts_changed;
sigc::signal<void,void*> record_enable_changed;
sigc::signal<void,void*> edit_group_changed;
sigc::signal<void,void*> mix_group_changed;
@ -214,8 +215,8 @@ class Route : public IO
int set_state(const XMLNode& node);
virtual XMLNode& get_template();
XMLNode& get_redirect_state ();
int set_redirect_state (const XMLNode&);
XMLNode& get_insert_state ();
int set_insert_state (const XMLNode&);
sigc::signal<void,void*> SelectedChanged;
@ -294,8 +295,8 @@ class Route : public IO
nframes_t _initial_delay;
nframes_t _roll_delay;
nframes_t _own_latency;
RedirectList _redirects;
Glib::RWLock redirect_lock;
InsertList _inserts;
Glib::RWLock insert_lock;
IO *_control_outs;
Glib::Mutex control_outs_lock;
RouteGroup *_edit_group;
@ -311,7 +312,7 @@ class Route : public IO
virtual void process_output_buffers (BufferSet& bufs,
nframes_t start_frame, nframes_t end_frame,
nframes_t nframes, nframes_t offset, bool with_redirects, int declick,
nframes_t nframes, nframes_t offset, bool with_inserts, int declick,
bool meter);
protected:
@ -326,14 +327,14 @@ class Route : public IO
sigc::connection input_signal_connection;
ChanCount redirect_max_outs;
ChanCount insert_max_outs;
uint32_t _remote_control_id;
uint32_t pans_required() const;
ChanCount n_process_buffers ();
virtual int _set_state (const XMLNode&, bool call_base);
virtual void _set_redirect_states (const XMLNodeList&);
virtual void _set_insert_states (const XMLNodeList&);
private:
void init ();
@ -354,7 +355,6 @@ class Route : public IO
void input_change_handler (IOChange, void *src);
void output_change_handler (IOChange, void *src);
bool legal_redirect (Redirect&);
int reset_plugin_counts (InsertStreams*); /* locked */
int _reset_plugin_counts (InsertStreams*); /* unlocked */
@ -372,8 +372,7 @@ class Route : public IO
bool check_some_plugin_counts (std::list<InsertCount>& iclist, ChanCount required_inputs, InsertStreams* err_streams);
void set_deferred_state ();
void add_redirect_from_xml (const XMLNode&);
void redirect_active_proxy (Redirect*, void*);
void add_insert_from_xml (const XMLNode&);
};
} // namespace ARDOUR

View file

@ -42,6 +42,9 @@ class Send : public Redirect
uint32_t bit_slot() const { return bitslot; }
ChanCount output_streams() const;
ChanCount input_streams () const;
void run (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes, nframes_t offset);
void activate() {}
@ -54,7 +57,10 @@ class Send : public Redirect
int set_state(const XMLNode& node);
uint32_t pans_required() const { return _expected_inputs.n_audio(); }
void expect_inputs (const ChanCount&);
virtual bool can_support_input_configuration (ChanCount in) const;
virtual ChanCount output_for_input_configuration (ChanCount in) const;
virtual bool configure_io (ChanCount in, ChanCount out);
static uint32_t how_many_sends();

View file

@ -1374,7 +1374,7 @@ class Session : public PBD::StatefulDestructible
void set_play_loop (bool yn);
void overwrite_some_buffers (Diskstream*);
void flush_all_redirects ();
void flush_all_inserts ();
void locate (nframes_t, bool with_roll, bool with_flush, bool with_loop=false);
void start_locate (nframes_t, bool with_roll, bool with_flush, bool with_loop=false);
void force_locate (nframes_t frame, bool with_roll = false);
@ -1521,8 +1521,8 @@ class Session : public PBD::StatefulDestructible
uint32_t insert_cnt;
void add_redirect (Redirect *);
void remove_redirect (Redirect *);
void add_insert (Insert *);
void remove_insert (Insert *);
/* S/W RAID */

View file

@ -61,7 +61,8 @@ class SMFSource : public MidiSource {
virtual void mark_capture_end () {}
virtual void clear_capture_marks() {}
int set_name (string newname, bool destructive);
bool set_name (const std::string& newname) { return (set_source_name(newname, false) == 0); }
int set_source_name (string newname, bool destructive);
string path() const { return _path; }

View file

@ -28,6 +28,7 @@
#include <pbd/statefuldestructible.h>
#include <ardour/ardour.h>
#include <ardour/session_object.h>
#include <ardour/data_type.h>
namespace ARDOUR {
@ -35,17 +36,14 @@ namespace ARDOUR {
class Session;
class Playlist;
class Source : public PBD::StatefulDestructible
class Source : public SessionObject
{
public:
Source (Session&, std::string name, DataType type);
Source (Session&, const std::string& name, DataType type);
Source (Session&, const XMLNode&);
virtual ~Source ();
std::string name() const { return _name; }
int set_name (std::string str, bool destructive);
DataType type() { return _type; }
time_t timestamp() const { return _timestamp; }
@ -76,8 +74,6 @@ class Source : public PBD::StatefulDestructible
protected:
void update_length (nframes_t pos, nframes_t cnt);
Session& _session;
string _name;
DataType _type;
time_t _timestamp;
nframes_t _length;

View file

@ -37,7 +37,7 @@ class Track : public Route
virtual ~Track ();
int set_name (string str, void *src);
bool set_name (const std::string& str);
TrackMode mode () const { return _mode; }
virtual int set_mode (TrackMode m) { return false; }

View file

@ -2024,7 +2024,7 @@ AudioDiskstream::rename_write_sources ()
for (chan = c->begin(), n = 0; chan != c->end(); ++chan, ++n) {
if ((*chan)->write_source != 0) {
(*chan)->write_source->set_name (_name, destructive());
(*chan)->write_source->set_source_name (_name, destructive());
/* XXX what to do if one of them fails ? */
}
}

View file

@ -515,7 +515,7 @@ AudioTrack::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame,
boost::shared_ptr<AudioDiskstream> diskstream = audio_diskstream();
{
Glib::RWLock::ReaderLock lm (redirect_lock, Glib::TRY_LOCK);
Glib::RWLock::ReaderLock lm (insert_lock, Glib::TRY_LOCK);
if (lm.locked()) {
// automation snapshot can also be called from the non-rt context
// and it uses the redirect list, so we take the lock out here
@ -524,7 +524,7 @@ AudioTrack::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame,
}
if (n_outputs().n_total() == 0 && _redirects.empty()) {
if (n_outputs().n_total() == 0 && _inserts.empty()) {
return 0;
}
@ -601,7 +601,7 @@ AudioTrack::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame,
if (!diskstream->record_enabled() && _session.transport_rolling()) {
Glib::Mutex::Lock am (automation_lock, Glib::TRY_LOCK);
if (am.locked() && gain_automation_playback()) {
if (am.locked() && _gain_automation_curve.automation_playback()) {
apply_gain_automation = _gain_automation_curve.rt_safe_get_vector (start_frame, end_frame, _session.gain_automation_buffer(), nframes);
}
}
@ -620,7 +620,7 @@ int
AudioTrack::silent_roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, nframes_t offset,
bool can_record, bool rec_monitors_input)
{
if (n_outputs().n_total() == 0 && _redirects.empty()) {
if (n_outputs().n_total() == 0 && _inserts.empty()) {
return 0;
}
@ -643,12 +643,12 @@ AudioTrack::export_stuff (BufferSet& buffers, nframes_t start, nframes_t nframes
gain_t gain_automation[nframes];
gain_t gain_buffer[nframes];
float mix_buffer[nframes];
RedirectList::iterator i;
InsertList::iterator i;
bool post_fader_work = false;
gain_t this_gain = _gain;
boost::shared_ptr<AudioDiskstream> diskstream = audio_diskstream();
Glib::RWLock::ReaderLock rlock (redirect_lock);
Glib::RWLock::ReaderLock rlock (insert_lock);
boost::shared_ptr<AudioPlaylist> apl = boost::dynamic_pointer_cast<AudioPlaylist>(diskstream->playlist());
assert(apl);
@ -681,7 +681,7 @@ AudioTrack::export_stuff (BufferSet& buffers, nframes_t start, nframes_t nframes
will already have checked that there are no external port inserts.
*/
for (i = _redirects.begin(); i != _redirects.end(); ++i) {
for (i = _inserts.begin(); i != _inserts.end(); ++i) {
boost::shared_ptr<Insert> insert;
if ((insert = boost::dynamic_pointer_cast<Insert>(*i)) != 0) {
@ -719,7 +719,7 @@ AudioTrack::export_stuff (BufferSet& buffers, nframes_t start, nframes_t nframes
if (post_fader_work) {
for (i = _redirects.begin(); i != _redirects.end(); ++i) {
for (i = _inserts.begin(); i != _inserts.end(); ++i) {
boost::shared_ptr<PluginInsert> insert;
if ((insert = boost::dynamic_pointer_cast<PluginInsert>(*i)) != 0) {
@ -800,9 +800,9 @@ AudioTrack::freeze (InterThreadInfo& itt)
_freeze_record.have_mementos = true;
{
Glib::RWLock::ReaderLock lm (redirect_lock);
Glib::RWLock::ReaderLock lm (insert_lock);
for (RedirectList::iterator r = _redirects.begin(); r != _redirects.end(); ++r) {
for (InsertList::iterator r = _inserts.begin(); r != _inserts.end(); ++r) {
boost::shared_ptr<Insert> insert;
@ -816,7 +816,8 @@ AudioTrack::freeze (InterThreadInfo& itt)
/* now deactivate the insert */
insert->set_active (false, this);
insert->set_active (false);
_session.set_dirty ();
}
}
}
@ -857,8 +858,8 @@ AudioTrack::unfreeze ()
} else {
Glib::RWLock::ReaderLock lm (redirect_lock); // should this be a write lock? jlc
for (RedirectList::iterator i = _redirects.begin(); i != _redirects.end(); ++i) {
Glib::RWLock::ReaderLock lm (insert_lock); // should this be a write lock? jlc
for (InsertList::iterator i = _inserts.begin(); i != _inserts.end(); ++i) {
for (vector<FreezeRecordInsertInfo*>::iterator ii = _freeze_record.insert_info.begin(); ii != _freeze_record.insert_info.end(); ++ii) {
if ((*ii)->id == (*i)->id()) {
(*i)->set_state (((*ii)->state));

View file

@ -573,7 +573,7 @@ AudioFileSource::set_allow_remove_if_empty (bool yn)
}
int
AudioFileSource::set_name (ustring newname, bool destructive)
AudioFileSource::set_source_name (ustring newname, bool destructive)
{
Glib::Mutex::Lock lm (_lock);
ustring oldpath = _path;

267
libs/ardour/automatable.cc Normal file
View file

@ -0,0 +1,267 @@
/*
Copyright (C) 2001,2007 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/ardour.h>
#include <fstream>
#include <inttypes.h>
#include <cstdio>
#include <errno.h>
#include <pbd/error.h>
#include <pbd/enumwriter.h>
#include <ardour/session.h>
#include <ardour/automatable.h>
#include "i18n.h"
using namespace std;
using namespace ARDOUR;
using namespace PBD;
Automatable::Automatable(Session& _session, const string& name)
: SessionObject(_session, name)
, _last_automation_snapshot(0)
{}
int
Automatable::old_set_automation_state (const XMLNode& node)
{
const XMLProperty *prop;
if ((prop = node.property ("path")) != 0) {
load_automation (prop->value());
} else {
warning << string_compose(_("%1: Automation node has no path property"), _name) << endmsg;
}
if ((prop = node.property ("visible")) != 0) {
uint32_t what;
stringstream sstr;
_visible_parameter_automation.clear ();
sstr << prop->value();
while (1) {
sstr >> what;
if (sstr.fail()) {
break;
}
mark_automation_visible (what, true);
}
}
return 0;
}
int
Automatable::load_automation (const string& path)
{
string fullpath;
if (path[0] == '/') { // legacy
fullpath = path;
} else {
fullpath = _session.automation_dir();
fullpath += path;
}
ifstream in (fullpath.c_str());
if (!in) {
warning << string_compose(_("%1: cannot open %2 to load automation data (%3)"), _name, fullpath, strerror (errno)) << endmsg;
return 1;
}
Glib::Mutex::Lock lm (_automation_lock);
set<uint32_t> tosave;
_parameter_automation.clear ();
while (in) {
double when;
double value;
uint32_t port;
in >> port; if (!in) break;
in >> when; if (!in) goto bad;
in >> value; if (!in) goto bad;
AutomationList& al = automation_list (port);
al.add (when, value);
tosave.insert (port);
}
return 0;
bad:
error << string_compose(_("%1: cannot load automation data from %2"), _name, fullpath) << endmsg;
_parameter_automation.clear ();
return -1;
}
void
Automatable::what_has_automation (set<uint32_t>& s) const
{
Glib::Mutex::Lock lm (_automation_lock);
map<uint32_t,AutomationList*>::const_iterator li;
for (li = _parameter_automation.begin(); li != _parameter_automation.end(); ++li) {
s.insert ((*li).first);
}
}
void
Automatable::what_has_visible_automation (set<uint32_t>& s) const
{
Glib::Mutex::Lock lm (_automation_lock);
set<uint32_t>::const_iterator li;
for (li = _visible_parameter_automation.begin(); li != _visible_parameter_automation.end(); ++li) {
s.insert (*li);
}
}
AutomationList&
Automatable::automation_list (uint32_t parameter)
{
AutomationList* al = _parameter_automation[parameter];
if (al == 0) {
al = _parameter_automation[parameter] = new AutomationList (default_parameter_value (parameter));
/* let derived classes do whatever they need with this */
automation_list_creation_callback (parameter, *al);
}
return *al;
}
string
Automatable::describe_parameter (uint32_t which)
{
/* derived classes will override this */
return "";
}
void
Automatable::can_automate (uint32_t what)
{
_can_automate_list.insert (what);
}
void
Automatable::mark_automation_visible (uint32_t what, bool yn)
{
if (yn) {
_visible_parameter_automation.insert (what);
} else {
set<uint32_t>::iterator i;
if ((i = _visible_parameter_automation.find (what)) != _visible_parameter_automation.end()) {
_visible_parameter_automation.erase (i);
}
}
}
bool
Automatable::find_next_event (nframes_t now, nframes_t end, ControlEvent& next_event) const
{
map<uint32_t,AutomationList*>::const_iterator li;
AutomationList::TimeComparator cmp;
next_event.when = max_frames;
for (li = _parameter_automation.begin(); li != _parameter_automation.end(); ++li) {
AutomationList::const_iterator i;
const AutomationList& alist (*((*li).second));
ControlEvent cp (now, 0.0f);
for (i = lower_bound (alist.const_begin(), alist.const_end(), &cp, cmp); i != alist.const_end() && (*i)->when < end; ++i) {
if ((*i)->when > now) {
break;
}
}
if (i != alist.const_end() && (*i)->when < end) {
if ((*i)->when < next_event.when) {
next_event.when = (*i)->when;
}
}
}
return next_event.when != max_frames;
}
int
Automatable::set_automation_state (const XMLNode& node)
{
Glib::Mutex::Lock lm (_automation_lock);
_parameter_automation.clear ();
XMLNodeList nlist = node.children();
XMLNodeIterator niter;
for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
uint32_t param;
if (sscanf ((*niter)->name().c_str(), "parameter-%" PRIu32, &param) != 1) {
error << string_compose (_("%2: badly formatted node name in XML automation state, ignored"), _name) << endmsg;
continue;
}
AutomationList& al = automation_list (param);
if (al.set_state (*(*niter)->children().front())) {
goto bad;
}
}
return 0;
bad:
error << string_compose(_("%1: cannot load automation data from XML"), _name) << endmsg;
_parameter_automation.clear ();
return -1;
}
XMLNode&
Automatable::get_automation_state ()
{
Glib::Mutex::Lock lm (_automation_lock);
XMLNode* node = new XMLNode (X_("Automation"));
string fullpath;
if (_parameter_automation.empty()) {
return *node;
}
map<uint32_t,AutomationList*>::iterator li;
for (li = _parameter_automation.begin(); li != _parameter_automation.end(); ++li) {
XMLNode* child;
char buf[64];
stringstream str;
snprintf (buf, sizeof (buf), "parameter-%" PRIu32, li->first);
child = new XMLNode (buf);
child->add_child_nocopy (li->second->get_state ());
}
return *node;
}

View file

@ -67,14 +67,13 @@ sigc::signal<void> Diskstream::DiskOverrun;
sigc::signal<void> Diskstream::DiskUnderrun;
Diskstream::Diskstream (Session &sess, const string &name, Flag flag)
: _name (name)
, _session (sess)
: SessionObject(sess, name)
{
init (flag);
}
Diskstream::Diskstream (Session& sess, const XMLNode& node)
: _session (sess)
: SessionObject(sess, "unnamed diskstream")
{
init (Recordable);
}
@ -377,23 +376,24 @@ Diskstream::playlist_deleted (boost::weak_ptr<Playlist> wpl)
}
}
int
Diskstream::set_name (string str)
bool
Diskstream::set_name (const string& str)
{
if (str != _name) {
assert(playlist());
playlist()->set_name (str);
_name = str;
SessionObject::set_name(str);
if (!in_set_state && recordable()) {
/* rename existing capture files so that they have the correct name */
return rename_write_sources ();
} else {
return -1;
return false;
}
}
return 0;
return true;
}
void

View file

@ -22,6 +22,7 @@
#include <sigc++/bind.h>
#include <pbd/failed_constructor.h>
#include <pbd/enumwriter.h>
#include <pbd/xml++.h>
#include <ardour/insert.h>
@ -30,6 +31,9 @@
#include <ardour/route.h>
#include <ardour/ladspa_plugin.h>
#include <ardour/buffer_set.h>
#include <ardour/send.h>
#include <ardour/port_insert.h>
#include <ardour/plugin_insert.h>
#ifdef VST_SUPPORT
#include <ardour/vst_plugin.h>
@ -49,17 +53,214 @@ using namespace std;
using namespace ARDOUR;
using namespace PBD;
Insert::Insert(Session& s, string name, Placement p)
: Redirect (s, name, p)
sigc::signal<void,Insert*> Insert::InsertCreated;
// Always saved as Insert, but may be Redirect in legacy sessions
const string Insert::state_node_name = "Insert";
Insert::Insert(Session& session, const string& name, Placement p)
: Automatable(session, name)
, _active(false)
, _next_ab_is_active(false)
, _configured(false)
, _placement(p)
, _gui(0)
{
// FIXME: default type?
}
Insert::Insert(Session& s, string name, Placement p, int imin, int imax, int omin, int omax)
: Redirect (s, name, p, imin, imax, omin, omax)
, _configured(false)
boost::shared_ptr<Insert>
Insert::clone (boost::shared_ptr<const Insert> other)
{
// FIXME: default type?
boost::shared_ptr<const Send> send;
boost::shared_ptr<const PortInsert> port_insert;
boost::shared_ptr<const PluginInsert> plugin_insert;
if ((send = boost::dynamic_pointer_cast<const Send>(other)) != 0) {
return boost::shared_ptr<Insert> (new Send (*send));
} else if ((port_insert = boost::dynamic_pointer_cast<const PortInsert>(other)) != 0) {
return boost::shared_ptr<Insert> (new PortInsert (*port_insert));
} else if ((plugin_insert = boost::dynamic_pointer_cast<const PluginInsert>(other)) != 0) {
return boost::shared_ptr<Insert> (new PluginInsert (*plugin_insert));
} else {
fatal << _("programming error: unknown Insert type in Insert::Clone!\n")
<< endmsg;
/*NOTREACHED*/
}
return boost::shared_ptr<Insert>();
}
void
Insert::set_sort_key (uint32_t key)
{
_sort_key = key;
}
void
Insert::set_placement (Placement p)
{
if (_placement != p) {
_placement = p;
PlacementChanged (); /* EMIT SIGNAL */
}
}
void
Insert::set_active (bool yn)
{
_active = yn;
ActiveChanged ();
}
XMLNode&
Insert::get_state (void)
{
return state (true);
}
/* NODE STRUCTURE
<Automation [optionally with visible="...." ]>
<parameter-N>
<AutomationList id=N>
<events>
X1 Y1
X2 Y2
....
</events>
</parameter-N>
<Automation>
*/
XMLNode&
Insert::state (bool full_state)
{
XMLNode* node = new XMLNode (state_node_name);
stringstream sstr;
// FIXME: This conflicts with "id" used by plugin for name in legacy sessions (ugh).
// Do we need to serialize this?
/*
char buf[64];
id().print (buf, sizeof (buf));
node->add_property("id", buf);
*/
node->add_property("name", _name);
node->add_property("active", active() ? "yes" : "no");
node->add_property("placement", enum_2_string (_placement));
if (_extra_xml){
node->add_child_copy (*_extra_xml);
}
if (full_state) {
XMLNode& automation = Automatable::get_automation_state();
for (set<uint32_t>::iterator x = _visible_parameter_automation.begin(); x != _visible_parameter_automation.end(); ++x) {
if (x != _visible_parameter_automation.begin()) {
sstr << ' ';
}
sstr << *x;
}
automation.add_property ("visible", sstr.str());
node->add_child_nocopy (automation);
}
return *node;
}
int
Insert::set_state (const XMLNode& node)
{
const XMLProperty *prop;
if (node.name() != state_node_name) {
error << string_compose(_("incorrect XML node \"%1\" passed to Redirect object"), node.name()) << endmsg;
return -1;
}
if ((prop = node.property ("name")) == 0) {
warning << _("XML node describing an insert is missing the `name' field") << endmsg;
} else {
set_name(prop->value());
}
XMLNodeList nlist = node.children();
XMLNodeIterator niter;
bool have_io = false;
for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
if ((*niter)->name() == X_("Automation")) {
XMLProperty *prop;
if ((prop = (*niter)->property ("path")) != 0) {
old_set_automation_state (*(*niter));
} else {
Automatable::set_automation_state (*(*niter));
}
if ((prop = (*niter)->property ("visible")) != 0) {
uint32_t what;
stringstream sstr;
_visible_parameter_automation.clear ();
sstr << prop->value();
while (1) {
sstr >> what;
if (sstr.fail()) {
break;
}
mark_automation_visible (what, true);
}
}
} else if ((*niter)->name() == "extra") {
_extra_xml = new XMLNode (*(*niter));
}
}
if (!have_io && dynamic_cast<IO*>(this)) {
error << _("XML node describing a redirect is missing an IO node") << endmsg;
return -1;
}
if ((prop = node.property ("active")) == 0) {
error << _("XML node describing an insert is missing the `active' field") << endmsg;
return -1;
}
if (_active != (prop->value() == "yes")) {
_active = !_active;
ActiveChanged (); /* EMIT_SIGNAL */
}
if ((prop = node.property ("placement")) == 0) {
error << _("XML node describing an insert is missing the `placement' field") << endmsg;
return -1;
}
/* hack to handle older sessions before we only used EnumWriter */
string pstr;
if (prop->value() == "pre") {
pstr = "PreFader";
} else if (prop->value() == "post") {
pstr = "PostFader";
} else {
pstr = prop->value();
}
Placement p = Placement (string_2_enum (pstr, p));
set_placement (p);
return 0;
}

View file

@ -98,12 +98,11 @@ static double direct_gain_to_control (gain_t gain) {
/** @param default_type The type of port that will be created by ensure_io
* and friends if no type is explicitly requested (to avoid breakage).
*/
IO::IO (Session& s, string name,
IO::IO (Session& s, const string& name,
int input_min, int input_max, int output_min, int output_max,
DataType default_type)
: _session (s),
: SessionObject(s, name),
_output_buffers(new BufferSet()),
_name (name),
_default_type(default_type),
_gain_control (X_("gaincontrol"), *this),
_gain_automation_curve (0.0, 2.0, 1.0),
@ -158,7 +157,7 @@ IO::IO (Session& s, string name,
}
IO::IO (Session& s, const XMLNode& node, DataType dt)
: _session (s),
: SessionObject(s, "unnamed io"),
_output_buffers(new BufferSet()),
_default_type (dt),
_gain_control (X_("gaincontrol"), *this),
@ -324,7 +323,7 @@ IO::just_meter_input (nframes_t start_frame, nframes_t end_frame,
collect_input (bufs, nframes, offset);
_meter->run(bufs, nframes);
_meter->run(bufs, start_frame, end_frame, nframes, offset);
}
void
@ -1130,7 +1129,7 @@ IO::ensure_outputs (ChanCount count, bool clear, bool lockit, void* src)
gain_t
IO::effective_gain () const
{
if (gain_automation_playback()) {
if (_gain_automation_curve.automation_playback()) {
return _effective_gain;
} else {
return _desired_gain;
@ -1826,14 +1825,15 @@ IO::parse_gain_string (const string& str, vector<string>& ports)
return ports.size();
}
int
IO::set_name (string name, void* src)
bool
IO::set_name (const string& str)
{
if (name == _name) {
return 0;
if (str == _name) {
return true;
}
/* replace all colons in the name. i wish we didn't have to do this */
string name = str;
if (replace_all (name, ":", "-")) {
warning << _("you cannot use colons to name objects with I/O connections") << endmsg;
@ -1851,10 +1851,7 @@ IO::set_name (string name, void* src)
i->set_name (current_name);
}
_name = name;
name_changed (src); /* EMIT SIGNAL */
return 0;
return SessionObject::set_name(name);
}
void
@ -2169,7 +2166,8 @@ IO::GainControllable::get_value (void) const
void
IO::setup_peak_meters()
{
_meter->setup(std::max(_inputs.count(), _outputs.count()));
ChanCount max_streams = std::max(_inputs.count(), _outputs.count());
_meter->configure_io(max_streams, max_streams);
}
/**
@ -2226,28 +2224,17 @@ IO::set_gain_automation_state (AutoState state)
if (changed) {
_session.set_dirty ();
gain_automation_state_changed (); /* EMIT SIGNAL */
//gain_automation_state_changed (); /* EMIT SIGNAL */
}
}
void
IO::set_gain_automation_style (AutoStyle style)
{
bool changed = false;
{
Glib::Mutex::Lock lm (automation_lock);
if (style != _gain_automation_curve.automation_style()) {
changed = true;
_gain_automation_curve.set_automation_style (style);
}
}
if (changed) {
gain_automation_style_changed (); /* EMIT SIGNAL */
}
Glib::Mutex::Lock lm (automation_lock);
_gain_automation_curve.set_automation_style (style);
}
void
IO::inc_gain (gain_t factor, void *src)
{
@ -2276,7 +2263,7 @@ IO::set_gain (gain_t val, void *src)
gain_changed (src);
_gain_control.Changed (); /* EMIT SIGNAL */
if (_session.transport_stopped() && src != 0 && src != this && gain_automation_recording()) {
if (_session.transport_stopped() && src != 0 && src != this && _gain_automation_curve.automation_write()) {
_gain_automation_curve.add (_session.transport_frame(), val);
}
@ -2318,7 +2305,7 @@ IO::automation_snapshot (nframes_t now)
{
if (last_automation_snapshot > now || (now - last_automation_snapshot) > _automation_interval) {
if (gain_automation_recording()) {
if (_gain_automation_curve.automation_write()) {
_gain_automation_curve.rt_add (now, gain());
}

View file

@ -34,7 +34,7 @@ namespace ARDOUR {
* be set to 0.
*/
void
PeakMeter::run (BufferSet& bufs, nframes_t nframes, nframes_t offset)
PeakMeter::run (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes, nframes_t offset)
{
size_t meterable = std::min(bufs.count().n_total(), _peak_power.size());
@ -93,9 +93,13 @@ PeakMeter::reset_max ()
}
}
void
PeakMeter::setup (const ChanCount& in)
bool
PeakMeter::configure_io (ChanCount in, ChanCount out)
{
/* we're transparent no matter what. fight the power. */
if (out != in)
return false;
uint32_t limit = in.n_total();
while (_peak_power.size() > limit) {
@ -113,6 +117,10 @@ PeakMeter::setup (const ChanCount& in)
assert(_peak_power.size() == limit);
assert(_visible_peak_power.size() == limit);
assert(_max_peak_power.size() == limit);
Insert::configure_io(in, out);
return true;
}
/** To be driven by the Meter signal from IO.

View file

@ -1391,7 +1391,7 @@ int
MidiDiskstream::rename_write_sources ()
{
if (_write_source != 0) {
_write_source->set_name (_name, destructive());
_write_source->set_source_name (_name, destructive());
/* XXX what to do if this fails ? */
}
return 0;

View file

@ -427,7 +427,7 @@ MidiTrack::roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame,
int dret;
boost::shared_ptr<MidiDiskstream> diskstream = midi_diskstream();
if (n_outputs().n_total() == 0 && _redirects.empty()) {
if (n_outputs().n_total() == 0 && _inserts.empty()) {
return 0;
}
@ -498,7 +498,7 @@ int
MidiTrack::silent_roll (nframes_t nframes, nframes_t start_frame, nframes_t end_frame, nframes_t offset,
bool can_record, bool rec_monitors_input)
{
if (n_outputs().n_midi() == 0 && _redirects.empty()) {
if (n_outputs().n_midi() == 0 && _inserts.empty()) {
return 0;
}
@ -518,29 +518,29 @@ MidiTrack::silent_roll (nframes_t nframes, nframes_t start_frame, nframes_t end_
void
MidiTrack::process_output_buffers (BufferSet& bufs,
nframes_t start_frame, nframes_t end_frame,
nframes_t nframes, nframes_t offset, bool with_redirects, int declick,
nframes_t nframes, nframes_t offset, bool with_inserts, int declick,
bool meter)
{
/* There's no such thing as a MIDI bus for the time being, to avoid diverging from trunk
* too much until the SoC settles down. We'll do all the MIDI route work here for now,
* but the long-term goal is to have Route::process_output_buffers handle everything */
/* There's no such thing as a MIDI bus for the time being.
* We'll do all the MIDI route work here for now, but the long-term goal is to have
* Route::process_output_buffers handle everything */
if (meter && (_meter_point == MeterInput || _meter_point == MeterPreFader)) {
_meter->run(bufs, nframes);
_meter->run(bufs, start_frame, end_frame, nframes, offset);
}
// Run all redirects
if (with_redirects) {
Glib::RWLock::ReaderLock rm (redirect_lock, Glib::TRY_LOCK);
// Run all inserts
if (with_inserts) {
Glib::RWLock::ReaderLock rm (insert_lock, Glib::TRY_LOCK);
if (rm.locked()) {
for (RedirectList::iterator i = _redirects.begin(); i != _redirects.end(); ++i) {
for (InsertList::iterator i = _inserts.begin(); i != _inserts.end(); ++i) {
(*i)->run (bufs, start_frame, end_frame, nframes, offset);
}
}
}
if (meter && (_meter_point == MeterPostFader)) {
_meter->run(bufs, nframes);
_meter->run(bufs, start_frame, end_frame, nframes, offset);
}
// Main output stage
@ -551,28 +551,6 @@ MidiTrack::process_output_buffers (BufferSet& bufs,
}
}
int
MidiTrack::set_name (string str, void *src)
{
int ret;
if (record_enabled() && _session.actively_recording()) {
/* this messes things up if done while recording */
return -1;
}
if (_diskstream->set_name (str)) {
return -1;
}
/* save state so that the statefile fully reflects any filename changes */
if ((ret = IO::set_name (str, src)) == 0) {
_session.save_state ("");
}
return ret;
}
int
MidiTrack::export_stuff (BufferSet& bufs, nframes_t nframes, nframes_t end_frame)
{

View file

@ -71,7 +71,7 @@ struct RegionSortByLastLayerOp {
};
Playlist::Playlist (Session& sess, string nom, DataType type, bool hide)
: _session (sess)
: SessionObject(sess, nom)
, _type(type)
{
init (hide);
@ -81,7 +81,7 @@ Playlist::Playlist (Session& sess, string nom, DataType type, bool hide)
}
Playlist::Playlist (Session& sess, const XMLNode& node, DataType type, bool hide)
: _session (sess)
: SessionObject(sess, "unnamed playlist")
, _type(type)
{
const XMLProperty* prop = node.property("type");
@ -94,7 +94,7 @@ Playlist::Playlist (Session& sess, const XMLNode& node, DataType type, bool hide
}
Playlist::Playlist (boost::shared_ptr<const Playlist> other, string namestr, bool hide)
: _name (namestr), _session (other->_session), _type(other->_type), _orig_diskstream_id(other->_orig_diskstream_id)
: SessionObject(other->_session, namestr), _type(other->_type), _orig_diskstream_id(other->_orig_diskstream_id)
{
init (hide);
@ -126,7 +126,7 @@ Playlist::Playlist (boost::shared_ptr<const Playlist> other, string namestr, boo
}
Playlist::Playlist (boost::shared_ptr<const Playlist> other, nframes_t start, nframes_t cnt, string str, bool hide)
: _name (str), _session (other->_session), _type(other->_type), _orig_diskstream_id(other->_orig_diskstream_id)
: SessionObject(other->_session, str), _type(other->_type), _orig_diskstream_id(other->_orig_diskstream_id)
{
RegionLock rlock2 (const_cast<Playlist*> (other.get()));
@ -247,14 +247,14 @@ Playlist::init (bool hide)
}
Playlist::Playlist (const Playlist& pl)
: _session (pl._session)
: SessionObject(pl._session, pl._name)
, _type(pl.data_type())
{
fatal << _("playlist const copy constructor called") << endmsg;
}
Playlist::Playlist (Playlist& pl)
: _session (pl._session)
: SessionObject(pl._session, pl._name)
, _type(pl.data_type())
{
fatal << _("playlist non-const copy constructor called") << endmsg;
@ -273,8 +273,8 @@ Playlist::~Playlist ()
/* GoingAway must be emitted by derived classes */
}
void
Playlist::set_name (string str)
bool
Playlist::set_name (const string& str)
{
/* in a typical situation, a playlist is being used
by one diskstream and also is referenced by the
@ -283,11 +283,10 @@ Playlist::set_name (string str)
*/
if (_refcnt > 2) {
return;
return false;
} else {
return SessionObject::set_name(str);
}
_name = str;
NameChanged(); /* EMIT SIGNAL */
}
/***********************************************************************

View file

@ -30,6 +30,7 @@
#include <ardour/route.h>
#include <ardour/ladspa_plugin.h>
#include <ardour/buffer_set.h>
#include <ardour/automation_event.h>
#ifdef VST_SUPPORT
#include <ardour/vst_plugin.h>
@ -67,11 +68,11 @@ PluginInsert::PluginInsert (Session& s, boost::shared_ptr<Plugin> plug, Placemen
IO::MoreChannels (max(input_streams(), output_streams()));
}
RedirectCreated (this); /* EMIT SIGNAL */
InsertCreated (this); /* EMIT SIGNAL */
}
PluginInsert::PluginInsert (Session& s, const XMLNode& node)
: Insert (s, "will change", PreFader)
: Insert (s, "unnamed plugin insert", PreFader)
{
if (set_state (node)) {
throw failed_constructor();
@ -88,7 +89,7 @@ PluginInsert::PluginInsert (Session& s, const XMLNode& node)
}
PluginInsert::PluginInsert (const PluginInsert& other)
: Insert (other._session, other.plugin()->name(), other.placement())
: Insert (other._session, other._name, other.placement())
{
uint32_t count = other._plugins.size();
@ -102,7 +103,7 @@ PluginInsert::PluginInsert (const PluginInsert& other)
init ();
RedirectCreated (this); /* EMIT SIGNAL */
InsertCreated (this); /* EMIT SIGNAL */
}
bool
@ -272,7 +273,7 @@ PluginInsert::connect_and_run (BufferSet& bufs, nframes_t nframes, nframes_t off
map<uint32_t,AutomationList*>::iterator li;
uint32_t n;
for (n = 0, li = parameter_automation.begin(); li != parameter_automation.end(); ++li, ++n) {
for (n = 0, li = _parameter_automation.begin(); li != _parameter_automation.end(); ++li, ++n) {
AutomationList& alist (*((*li).second));
@ -302,14 +303,14 @@ PluginInsert::automation_snapshot (nframes_t now)
{
map<uint32_t,AutomationList*>::iterator li;
for (li = parameter_automation.begin(); li != parameter_automation.end(); ++li) {
for (li =_parameter_automation.begin(); li !=_parameter_automation.end(); ++li) {
AutomationList *alist = ((*li).second);
if (alist != 0 && alist->automation_write ()) {
float val = _plugins[0]->get_parameter ((*li).first);
alist->rt_add (now, val);
last_automation_snapshot = now;
_last_automation_snapshot = now;
}
}
}
@ -319,7 +320,7 @@ PluginInsert::transport_stopped (nframes_t now)
{
map<uint32_t,AutomationList*>::iterator li;
for (li = parameter_automation.begin(); li != parameter_automation.end(); ++li) {
for (li =_parameter_automation.begin(); li !=_parameter_automation.end(); ++li) {
AutomationList& alist (*(li->second));
alist.reposition_for_rt_add (now);
@ -353,6 +354,9 @@ PluginInsert::run (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame,
connect_and_run (bufs, nframes, offset, false);
}
} else {
/* FIXME: type, audio only */
uint32_t in = _plugins[0]->get_info()->n_inputs.n_audio();
uint32_t out = _plugins[0]->get_info()->n_outputs.n_audio();
@ -365,7 +369,7 @@ PluginInsert::run (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame,
}
}
bufs.count().set(_default_type, out);
bufs.count().set_audio(out);
}
}
@ -526,26 +530,41 @@ PluginInsert::configure_io (ChanCount in, ChanCount out)
return false;
} else {
bool success = set_count (count_for_configuration(in, out));
if (success) {
_configured = true;
_configured_input = in;
}
if (success)
Insert::configure_io(in, out);
return success;
}
}
bool
PluginInsert::can_support_input_configuration (ChanCount in_count) const
PluginInsert::can_support_input_configuration (ChanCount in) const
{
int32_t outputs = _plugins[0]->get_info()->n_outputs.get(_default_type);
int32_t inputs = _plugins[0]->get_info()->n_inputs.get(_default_type);
int32_t in = in_count.get(_default_type);
ChanCount outputs = _plugins[0]->get_info()->n_outputs;
ChanCount inputs = _plugins[0]->get_info()->n_inputs;
/* see output_for_input_configuration below */
if ((inputs == 0)
|| (outputs == 1 && inputs == 1)
|| (inputs == in)
|| ((inputs < in) && (inputs % in == 0))) {
if ((inputs.n_total() == 0)
|| (inputs.n_total() == 1 && outputs == inputs)
|| (inputs.n_total() == 1 && outputs == inputs
&& ((inputs.n_audio() == 0 && in.n_audio() == 0)
|| (inputs.n_midi() == 0 && in.n_midi() == 0)))
|| (inputs == in)) {
return true;
}
bool can_replicate = true;
/* if number of inputs is a factor of the requested input
configuration for every type, we can replicate.
*/
for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
if (inputs.get(*t) >= in.get(*t) || (inputs.get(*t) % in.get(*t) != 0)) {
can_replicate = false;
break;
}
}
if (can_replicate && (in.n_total() % inputs.n_total() == 0)) {
return true;
} else {
return false;
@ -563,7 +582,9 @@ PluginInsert::output_for_input_configuration (ChanCount in) const
return outputs;
}
if (inputs.n_total() == 1 && outputs == inputs) {
if (inputs.n_total() == 1 && outputs == inputs
&& ((inputs.n_audio() == 0 && in.n_audio() == 0)
|| (inputs.n_midi() == 0 && in.n_midi() == 0))) {
/* mono plugin, replicate as needed to match in */
return in;
}
@ -573,17 +594,26 @@ PluginInsert::output_for_input_configuration (ChanCount in) const
return outputs;
}
// FIXME: single type plugins only. can we do this for instruments?
if ((inputs.n_total() == inputs.get(_default_type))
&& ((in.n_total() == in.get(_default_type))
&& (inputs.n_total() < in.n_total())
&& (inputs.n_total() % in.n_total() == 0))) {
bool can_replicate = true;
/* number of inputs is a factor of the requested input
configuration, so we can replicate.
*/
/* if number of inputs is a factor of the requested input
configuration for every type, we can replicate.
*/
for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
if (inputs.get(*t) >= in.get(*t) || (in.get(*t) % inputs.get(*t) != 0)) {
can_replicate = false;
break;
}
}
return ChanCount(_default_type, in.n_total() / inputs.n_total());
if (can_replicate && (inputs.n_total() % in.n_total() == 0)) {
ChanCount output;
for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
output.set(*t, outputs.get(*t) * (in.get(*t) / inputs.get(*t)));
}
return output;
}
/* sorry */
@ -606,7 +636,9 @@ PluginInsert::count_for_configuration (ChanCount in, ChanCount out) const
return 1;
}
if (inputs.n_total() == 1 && outputs == inputs) {
if (inputs.n_total() == 1 && outputs == inputs
&& ((inputs.n_audio() == 0 && in.n_audio() == 0)
|| (inputs.n_midi() == 0 && in.n_midi() == 0))) {
/* mono plugin, replicate as needed to match in */
return in.n_total();
}
@ -616,20 +648,14 @@ PluginInsert::count_for_configuration (ChanCount in, ChanCount out) const
return 1;
}
// FIXME: single type plugins only. can we do this for instruments?
if ((inputs.n_total() == inputs.get(_default_type))
&& ((in.n_total() == in.get(_default_type))
&& (inputs.n_total() < in.n_total())
&& (inputs.n_total() % in.n_total() == 0))) {
/* number of inputs is a factor of the requested input
configuration, so we can replicate.
*/
// assumes in is valid, so we must be replicating
if (inputs.n_total() < in.n_total()
&& (in.n_total() % inputs.n_total() == 0)) {
return in.n_total() / inputs.n_total();
}
/* sorry */
/* err... */
return 0;
}
@ -643,20 +669,18 @@ XMLNode&
PluginInsert::state (bool full)
{
char buf[256];
XMLNode *node = new XMLNode("Insert");
XMLNode& node = Insert::state (full);
node->add_child_nocopy (Redirect::state (full));
node->add_property ("type", _plugins[0]->state_node_name());
node.add_property ("type", _plugins[0]->state_node_name());
snprintf(buf, sizeof(buf), "%s", _plugins[0]->name());
node->add_property("id", string(buf));
node.add_property("id", string(buf));
if (_plugins[0]->state_node_name() == "ladspa") {
char buf[32];
snprintf (buf, sizeof (buf), "%ld", _plugins[0]->get_info()->unique_id);
node->add_property("unique-id", string(buf));
node.add_property("unique-id", string(buf));
}
node->add_property("count", string_compose("%1", _plugins.size()));
node->add_child_nocopy (_plugins[0]->get_state());
node.add_property("count", string_compose("%1", _plugins.size()));
node.add_child_nocopy (_plugins[0]->get_state());
/* add port automation state */
XMLNode *autonode = new XMLNode(port_automation_node_name);
@ -672,9 +696,9 @@ PluginInsert::state (bool full)
autonode->add_child_nocopy (*child);
}
node->add_child_nocopy (*autonode);
node.add_child_nocopy (*autonode);
return *node;
return node;
}
int
@ -752,23 +776,18 @@ PluginInsert::set_state(const XMLNode& node)
}
}
const XMLNode* insert_node = &node;
// legacy sessions: search for child Redirect node
for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
if ((*niter)->name() == Redirect::state_node_name) {
Redirect::set_state (**niter);
if ((*niter)->name() == "Redirect") {
insert_node = *niter;
break;
}
}
if (niter == nlist.end()) {
error << _("XML node describing insert is missing a Redirect node") << endmsg;
return -1;
}
if (niter == nlist.end()) {
error << string_compose(_("XML node describing a plugin insert is missing the `%1' information"), plugin->state_node_name()) << endmsg;
return -1;
}
Insert::set_state (*insert_node);
/* look for port automation node */
for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
@ -835,7 +854,7 @@ PluginInsert::set_state(const XMLNode& node)
}
// The name of the PluginInsert comes from the plugin, nothing else
set_name(plugin->get_info()->name,this);
_name = plugin->get_info()->name;
return 0;
}

View file

@ -41,41 +41,41 @@ using namespace ARDOUR;
using namespace PBD;
PortInsert::PortInsert (Session& s, Placement p)
: Insert (s, string_compose (_("insert %1"), (bitslot = s.next_insert_id()) + 1), p, 1, -1, 1, -1)
: Redirect (s, string_compose (_("insert %1"), (bitslot = s.next_insert_id()) + 1), p, 1, -1, 1, -1)
{
init ();
RedirectCreated (this); /* EMIT SIGNAL */
InsertCreated (this); /* EMIT SIGNAL */
}
PortInsert::PortInsert (const PortInsert& other)
: Insert (other._session, string_compose (_("insert %1"), (bitslot = other._session.next_insert_id()) + 1), other.placement(), 1, -1, 1, -1)
: Redirect (other._session, string_compose (_("insert %1"), (bitslot = other._session.next_insert_id()) + 1), other.placement(), 1, -1, 1, -1)
{
init ();
RedirectCreated (this); /* EMIT SIGNAL */
InsertCreated (this); /* EMIT SIGNAL */
}
void
PortInsert::init ()
{
if (add_input_port ("", this)) {
if (_io->add_input_port ("", this)) {
error << _("PortInsert: cannot add input port") << endmsg;
throw failed_constructor();
}
if (add_output_port ("", this)) {
if (_io->add_output_port ("", this)) {
error << _("PortInsert: cannot add output port") << endmsg;
throw failed_constructor();
}
}
PortInsert::PortInsert (Session& s, const XMLNode& node)
: Insert (s, "will change", PreFader)
: Redirect (s, "unnamed port insert", PreFader)
{
if (set_state (node)) {
throw failed_constructor();
}
RedirectCreated (this); /* EMIT SIGNAL */
InsertCreated (this); /* EMIT SIGNAL */
}
PortInsert::~PortInsert ()
@ -86,19 +86,19 @@ PortInsert::~PortInsert ()
void
PortInsert::run (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes, nframes_t offset)
{
if (n_outputs().get(_default_type) == 0) {
if (_io->n_outputs().n_total() == 0) {
return;
}
if (!active()) {
/* deliver silence */
silence (nframes, offset);
_io->silence (nframes, offset);
return;
}
deliver_output(bufs, start_frame, end_frame, nframes, offset);
_io->deliver_output(bufs, start_frame, end_frame, nframes, offset);
collect_input(bufs, nframes, offset);
_io->collect_input(bufs, nframes, offset);
}
XMLNode&
@ -110,14 +110,13 @@ PortInsert::get_state(void)
XMLNode&
PortInsert::state (bool full)
{
XMLNode *node = new XMLNode("Insert");
XMLNode& node = Redirect::state(full);
char buf[32];
node->add_child_nocopy (Redirect::state(full));
node->add_property ("type", "port");
node.add_property ("type", "port");
snprintf (buf, sizeof (buf), "%" PRIu32, bitslot);
node->add_property ("bitslot", buf);
node.add_property ("bitslot", buf);
return *node;
return node;
}
int
@ -145,17 +144,17 @@ PortInsert::set_state(const XMLNode& node)
_session.mark_insert_id (bitslot);
}
const XMLNode* insert_node = &node;
// legacy sessions: search for child Redirect node
for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
if ((*niter)->name() == Redirect::state_node_name) {
Redirect::set_state (**niter);
if ((*niter)->name() == "Redirect") {
insert_node = *niter;
break;
}
}
if (niter == nlist.end()) {
error << _("XML node describing insert is missing a Redirect node") << endmsg;
return -1;
}
Redirect::set_state (*insert_node);
return 0;
}
@ -170,13 +169,13 @@ PortInsert::latency()
need to take that into account too.
*/
return _session.engine().frames_per_cycle() + input_latency();
return _session.engine().frames_per_cycle() + _io->input_latency();
}
bool
PortInsert::can_support_input_configuration (ChanCount in) const
{
if (input_maximum() == ChanCount::INFINITE && output_maximum() == ChanCount::INFINITE) {
if (_io->input_maximum() == ChanCount::INFINITE && _io->output_maximum() == ChanCount::INFINITE) {
/* not configured yet */
@ -188,7 +187,7 @@ PortInsert::can_support_input_configuration (ChanCount in) const
many output ports it will have.
*/
if (output_maximum() == in) {
if (_io->output_maximum() == in) {
return true;
}
@ -220,23 +219,28 @@ PortInsert::configure_io (ChanCount in, ChanCount out)
to the number of input ports we need.
*/
set_output_maximum (in);
set_output_minimum (in);
set_input_maximum (out);
set_input_minimum (out);
_io->set_output_maximum (in);
_io->set_output_minimum (in);
_io->set_input_maximum (out);
_io->set_input_minimum (out);
return (ensure_io (out, in, false, this) == 0);
bool success = (_io->ensure_io (out, in, false, this) == 0);
if (success)
return Insert::configure_io(in, out);
else
return false;
}
ChanCount
PortInsert::output_streams() const
{
return n_inputs ();
return _io->n_inputs ();
}
ChanCount
PortInsert::input_streams() const
{
return n_outputs ();
return _io->n_outputs ();
}

View file

@ -42,17 +42,13 @@ using namespace std;
using namespace ARDOUR;
using namespace PBD;
const string Redirect::state_node_name = "Redirect";
sigc::signal<void,Redirect*> Redirect::RedirectCreated;
Redirect::Redirect (Session& s, const string& name, Placement p,
int input_min, int input_max,
int output_min, int output_max)
: IO (s, name, input_min, input_max, output_min, output_max)
: Insert(s, name, p)
, _io(new IO(s, name, input_min, input_max, output_min, output_max))
{
_placement = p;
_active = false;
_next_ab_is_active = false;
_sort_key = 0;
_gui = 0;
_extra_xml = 0;
@ -63,161 +59,22 @@ Redirect::~Redirect ()
notify_callbacks ();
}
boost::shared_ptr<Redirect>
Redirect::clone (boost::shared_ptr<const Redirect> other)
{
boost::shared_ptr<const Send> send;
boost::shared_ptr<const PortInsert> port_insert;
boost::shared_ptr<const PluginInsert> plugin_insert;
if ((send = boost::dynamic_pointer_cast<const Send>(other)) != 0) {
return boost::shared_ptr<Redirect> (new Send (*send));
} else if ((port_insert = boost::dynamic_pointer_cast<const PortInsert>(other)) != 0) {
return boost::shared_ptr<Redirect> (new PortInsert (*port_insert));
} else if ((plugin_insert = boost::dynamic_pointer_cast<const PluginInsert>(other)) != 0) {
return boost::shared_ptr<Redirect> (new PluginInsert (*plugin_insert));
} else {
fatal << _("programming error: unknown Redirect type in Redirect::Clone!\n")
<< endmsg;
/*NOTREACHED*/
}
return boost::shared_ptr<Redirect>();
}
void
Redirect::set_sort_key (uint32_t key)
{
_sort_key = key;
}
void
Redirect::set_placement (Placement p, void *src)
{
if (_placement != p) {
_placement = p;
placement_changed (this, src); /* EMIT SIGNAL */
}
}
/* NODE STRUCTURE
<Automation [optionally with visible="...." ]>
<parameter-N>
<AutomationList id=N>
<events>
X1 Y1
X2 Y2
....
</events>
</parameter-N>
<Automation>
*/
int
Redirect::set_automation_state (const XMLNode& node)
{
Glib::Mutex::Lock lm (_automation_lock);
parameter_automation.clear ();
XMLNodeList nlist = node.children();
XMLNodeIterator niter;
for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
uint32_t param;
if (sscanf ((*niter)->name().c_str(), "parameter-%" PRIu32, &param) != 1) {
error << string_compose (_("%2: badly formatted node name in XML automation state, ignored"), _name) << endmsg;
continue;
}
AutomationList& al = automation_list (param);
if (al.set_state (*(*niter)->children().front())) {
goto bad;
}
}
return 0;
bad:
error << string_compose(_("%1: cannot load automation data from XML"), _name) << endmsg;
parameter_automation.clear ();
return -1;
}
XMLNode&
Redirect::get_automation_state ()
{
Glib::Mutex::Lock lm (_automation_lock);
XMLNode* node = new XMLNode (X_("Automation"));
string fullpath;
if (parameter_automation.empty()) {
return *node;
}
map<uint32_t,AutomationList*>::iterator li;
for (li = parameter_automation.begin(); li != parameter_automation.end(); ++li) {
XMLNode* child;
char buf[64];
stringstream str;
snprintf (buf, sizeof (buf), "parameter-%" PRIu32, li->first);
child = new XMLNode (buf);
child->add_child_nocopy (li->second->get_state ());
}
return *node;
}
XMLNode&
Redirect::get_state (void)
{
return state (true);
}
XMLNode&
Redirect::state (bool full_state)
{
XMLNode* node = new XMLNode (state_node_name);
stringstream sstr;
node->add_property("active", active() ? "yes" : "no");
node->add_property("placement", enum_2_string (_placement));
node->add_child_nocopy (IO::state (full_state));
if (_extra_xml){
node->add_child_copy (*_extra_xml);
}
XMLNode& node = Insert::state(full_state);
if (full_state) {
node.add_child_nocopy (_io->state (full_state));
XMLNode& automation = get_automation_state();
for (set<uint32_t>::iterator x = visible_parameter_automation.begin(); x != visible_parameter_automation.end(); ++x) {
if (x != visible_parameter_automation.begin()) {
sstr << ' ';
}
sstr << *x;
}
automation.add_property ("visible", sstr.str());
node->add_child_nocopy (automation);
}
return *node;
return node;
}
int
Redirect::set_state (const XMLNode& node)
{
const XMLProperty *prop;
Insert::set_state(node);
if (node.name() != state_node_name) {
if (node.name() != "Insert" && node.name() != "Redirect") {
error << string_compose(_("incorrect XML node \"%1\" passed to Redirect object"), node.name()) << endmsg;
return -1;
}
@ -227,260 +84,22 @@ Redirect::set_state (const XMLNode& node)
bool have_io = false;
for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
if ((*niter)->name() == IO::state_node_name) {
IO::set_state (**niter);
have_io = true;
} else if ((*niter)->name() == X_("Automation")) {
XMLProperty *prop;
if ((prop = (*niter)->property ("path")) != 0) {
old_set_automation_state (*(*niter));
} else {
set_automation_state (*(*niter));
}
if ((prop = (*niter)->property ("visible")) != 0) {
uint32_t what;
stringstream sstr;
visible_parameter_automation.clear ();
sstr << prop->value();
while (1) {
sstr >> what;
if (sstr.fail()) {
break;
}
mark_automation_visible (what, true);
}
}
} else if ((*niter)->name() == "extra") {
_extra_xml = new XMLNode (*(*niter));
_io->set_state(**niter);
}
}
if (!have_io) {
error << _("XML node describing an IO is missing an IO node") << endmsg;
error << _("XML node describing a redirect is missing an IO node") << endmsg;
return -1;
}
if ((prop = node.property ("active")) == 0) {
error << _("XML node describing a redirect is missing the `active' field") << endmsg;
return -1;
}
if (_active != (prop->value() == "yes")) {
_active = !_active;
active_changed (this, this); /* EMIT_SIGNAL */
}
if ((prop = node.property ("placement")) == 0) {
error << _("XML node describing a redirect is missing the `placement' field") << endmsg;
return -1;
}
/* hack to handle older sessions before we only used EnumWriter */
string pstr;
if (prop->value() == "pre") {
pstr = "PreFader";
} else if (prop->value() == "post") {
pstr = "PostFader";
} else {
pstr = prop->value();
}
Placement p = Placement (string_2_enum (pstr, p));
set_placement (p, this);
return 0;
}
int
Redirect::old_set_automation_state (const XMLNode& node)
{
const XMLProperty *prop;
if ((prop = node.property ("path")) != 0) {
load_automation (prop->value());
} else {
warning << string_compose(_("%1: Automation node has no path property"), _name) << endmsg;
}
if ((prop = node.property ("visible")) != 0) {
uint32_t what;
stringstream sstr;
visible_parameter_automation.clear ();
sstr << prop->value();
while (1) {
sstr >> what;
if (sstr.fail()) {
break;
}
mark_automation_visible (what, true);
}
}
return 0;
}
int
Redirect::load_automation (string path)
{
string fullpath;
if (path[0] == '/') { // legacy
fullpath = path;
} else {
fullpath = _session.automation_dir();
fullpath += path;
}
ifstream in (fullpath.c_str());
if (!in) {
warning << string_compose(_("%1: cannot open %2 to load automation data (%3)"), _name, fullpath, strerror (errno)) << endmsg;
return 1;
}
Glib::Mutex::Lock lm (_automation_lock);
set<uint32_t> tosave;
parameter_automation.clear ();
while (in) {
double when;
double value;
uint32_t port;
in >> port; if (!in) break;
in >> when; if (!in) goto bad;
in >> value; if (!in) goto bad;
AutomationList& al = automation_list (port);
al.add (when, value);
tosave.insert (port);
}
return 0;
bad:
error << string_compose(_("%1: cannot load automation data from %2"), _name, fullpath) << endmsg;
parameter_automation.clear ();
return -1;
}
void
Redirect::what_has_automation (set<uint32_t>& s) const
Redirect::silence (nframes_t nframes, nframes_t offset)
{
Glib::Mutex::Lock lm (_automation_lock);
map<uint32_t,AutomationList*>::const_iterator li;
for (li = parameter_automation.begin(); li != parameter_automation.end(); ++li) {
s.insert ((*li).first);
}
}
void
Redirect::what_has_visible_automation (set<uint32_t>& s) const
{
Glib::Mutex::Lock lm (_automation_lock);
set<uint32_t>::const_iterator li;
for (li = visible_parameter_automation.begin(); li != visible_parameter_automation.end(); ++li) {
s.insert (*li);
}
}
AutomationList&
Redirect::automation_list (uint32_t parameter)
{
AutomationList* al = parameter_automation[parameter];
if (al == 0) {
al = parameter_automation[parameter] = new AutomationList (default_parameter_value (parameter));
/* let derived classes do whatever they need with this */
automation_list_creation_callback (parameter, *al);
}
return *al;
}
string
Redirect::describe_parameter (uint32_t which)
{
/* derived classes will override this */
return "";
}
void
Redirect::can_automate (uint32_t what)
{
can_automate_list.insert (what);
}
void
Redirect::mark_automation_visible (uint32_t what, bool yn)
{
if (yn) {
visible_parameter_automation.insert (what);
} else {
set<uint32_t>::iterator i;
if ((i = visible_parameter_automation.find (what)) != visible_parameter_automation.end()) {
visible_parameter_automation.erase (i);
}
}
}
bool
Redirect::find_next_event (nframes_t now, nframes_t end, ControlEvent& next_event) const
{
map<uint32_t,AutomationList*>::const_iterator li;
AutomationList::TimeComparator cmp;
next_event.when = max_frames;
for (li = parameter_automation.begin(); li != parameter_automation.end(); ++li) {
AutomationList::const_iterator i;
const AutomationList& alist (*((*li).second));
ControlEvent cp (now, 0.0f);
for (i = lower_bound (alist.const_begin(), alist.const_end(), &cp, cmp); i != alist.const_end() && (*i)->when < end; ++i) {
if ((*i)->when > now) {
break;
}
}
if (i != alist.const_end() && (*i)->when < end) {
if ((*i)->when < next_event.when) {
next_event.when = (*i)->when;
}
}
}
return next_event.when != max_frames;
}
void
Redirect::set_active (bool yn, void* src)
{
_active = yn;
active_changed (this, src);
_session.set_dirty ();
}
void
Redirect::set_next_ab_is_active (bool yn)
{
_next_ab_is_active = yn;
_io->silence(nframes, offset);
}

File diff suppressed because it is too large Load diff

View file

@ -149,7 +149,6 @@ RouteGroup::set_state (const XMLNode& node)
void
RouteGroup::set_active (bool yn, void *src)
{
if (is_active() == yn) {
return;

View file

@ -36,7 +36,7 @@ Send::Send (Session& s, Placement p)
: Redirect (s, string_compose (_("send %1"), (bitslot = s.next_send_id()) + 1), p)
{
_metering = false;
RedirectCreated (this); /* EMIT SIGNAL */
InsertCreated (this); /* EMIT SIGNAL */
}
Send::Send (Session& s, const XMLNode& node)
@ -48,14 +48,14 @@ Send::Send (Session& s, const XMLNode& node)
throw failed_constructor();
}
RedirectCreated (this); /* EMIT SIGNAL */
InsertCreated (this); /* EMIT SIGNAL */
}
Send::Send (const Send& other)
: Redirect (other._session, string_compose (_("send %1"), (bitslot = other._session.next_send_id()) + 1), other.placement())
{
_metering = false;
RedirectCreated (this); /* EMIT SIGNAL */
InsertCreated (this); /* EMIT SIGNAL */
}
Send::~Send ()
@ -72,12 +72,13 @@ Send::get_state(void)
XMLNode&
Send::state(bool full)
{
XMLNode *node = new XMLNode("Send");
XMLNode& node = Redirect::state(full);
char buf[32];
node->add_child_nocopy (Redirect::state (full));
node.add_property ("type", "send");
snprintf (buf, sizeof (buf), "%" PRIu32, bitslot);
node->add_property ("bitslot", buf);
return *node;
node.add_property ("bitslot", buf);
return node;
}
int
@ -94,16 +95,19 @@ Send::set_state(const XMLNode& node)
_session.mark_send_id (bitslot);
}
const XMLNode* insert_node = &node;
/* Send has regular IO automation (gain, pan) */
for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
if ((*niter)->name() == Redirect::state_node_name) {
Redirect::set_state (**niter);
break;
if ((*niter)->name() == "Redirect") {
insert_node = *niter;
} else if ((*niter)->name() == X_("Automation")) {
IO::set_automation_state (*(*niter));
_io->set_automation_state (*(*niter));
}
}
Redirect::set_state (*insert_node);
if (niter == nlist.end()) {
error << _("XML node describing a send is missing a Redirect node") << endmsg;
@ -126,21 +130,21 @@ Send::run (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_
sendbufs.read_from(bufs, nframes);
assert(sendbufs.count() == bufs.count());
IO::deliver_output (sendbufs, start_frame, end_frame, nframes, offset);
_io->deliver_output (sendbufs, start_frame, end_frame, nframes, offset);
if (_metering) {
if (_gain == 0) {
_meter->reset();
if (_io->_gain == 0) {
_io->_meter->reset();
} else {
_meter->run(output_buffers(), nframes, offset);
_io->_meter->run(_io->output_buffers(), start_frame, end_frame, nframes, offset);
}
}
} else {
silence (nframes, offset);
_io->silence (nframes, offset);
if (_metering) {
_meter->reset();
_io->_meter->reset();
}
}
}
@ -152,15 +156,72 @@ Send::set_metering (bool yn)
if (!_metering) {
/* XXX possible thread hazard here */
peak_meter().reset();
_io->peak_meter().reset();
}
}
void
Send::expect_inputs (const ChanCount& expected)
bool
Send::can_support_input_configuration (ChanCount in) const
{
if (expected != _expected_inputs) {
_expected_inputs = expected;
reset_panner ();
if (_io->input_maximum() == ChanCount::INFINITE && _io->output_maximum() == ChanCount::INFINITE) {
/* not configured yet */
return true; /* we can support anything the first time we're asked */
} else {
/* the "input" config for a port insert corresponds to how
many output ports it will have.
*/
if (_io->output_maximum() == in) {
return true;
}
}
return false;
}
ChanCount
Send::output_for_input_configuration (ChanCount in) const
{
// from the internal (Insert) perspective a Send does not modify its input whatsoever
return in;
}
bool
Send::configure_io (ChanCount in, ChanCount out)
{
/* we're transparent no matter what. fight the power. */
if (out != in)
return false;
_io->set_output_maximum (in);
_io->set_output_minimum (in);
_io->set_input_maximum (ChanCount::ZERO);
_io->set_input_minimum (ChanCount::ZERO);
bool success = _io->ensure_io (ChanCount::ZERO, in, false, this) == 0;
if (success) {
Insert::configure_io(in, out);
_io->reset_panner();
return true;
} else {
return false;
}
}
ChanCount
Send::output_streams() const
{
return _io->n_outputs ();
}
ChanCount
Send::input_streams() const
{
return _io->n_outputs (); // (sic)
}

View file

@ -1887,7 +1887,7 @@ Session::add_routes (RouteList& new_routes, bool save)
(*x)->solo_changed.connect (sigc::bind (mem_fun (*this, &Session::route_solo_changed), wpr));
(*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)->redirects_changed.connect (mem_fun (*this, &Session::update_latency_compensation_proxy));
(*x)->inserts_changed.connect (bind (mem_fun (*this, &Session::update_latency_compensation), false, false));
if ((*x)->master()) {
_master_out = (*x);
@ -3529,65 +3529,51 @@ Session::record_enable_change_all (bool yn)
}
void
Session::add_redirect (Redirect* redirect)
Session::add_insert (Insert* insert)
{
Send* send;
Insert* insert;
PortInsert* port_insert;
PluginInsert* plugin_insert;
if ((insert = dynamic_cast<Insert *> (redirect)) != 0) {
if ((port_insert = dynamic_cast<PortInsert *> (insert)) != 0) {
_port_inserts.insert (_port_inserts.begin(), port_insert);
} else if ((plugin_insert = dynamic_cast<PluginInsert *> (insert)) != 0) {
_plugin_inserts.insert (_plugin_inserts.begin(), plugin_insert);
} else {
fatal << _("programming error: unknown type of Insert created!") << endmsg;
/*NOTREACHED*/
}
} else if ((send = dynamic_cast<Send *> (redirect)) != 0) {
if ((port_insert = dynamic_cast<PortInsert *> (insert)) != 0) {
_port_inserts.insert (_port_inserts.begin(), port_insert);
} else if ((plugin_insert = dynamic_cast<PluginInsert *> (insert)) != 0) {
_plugin_inserts.insert (_plugin_inserts.begin(), plugin_insert);
} else if ((send = dynamic_cast<Send *> (insert)) != 0) {
_sends.insert (_sends.begin(), send);
} else {
fatal << _("programming error: unknown type of Redirect created!") << endmsg;
fatal << _("programming error: unknown type of Insert created!") << endmsg;
/*NOTREACHED*/
}
redirect->GoingAway.connect (sigc::bind (mem_fun (*this, &Session::remove_redirect), redirect));
insert->GoingAway.connect (sigc::bind (mem_fun (*this, &Session::remove_insert), insert));
set_dirty();
}
void
Session::remove_redirect (Redirect* redirect)
Session::remove_insert (Insert* insert)
{
Send* send;
Insert* insert;
PortInsert* port_insert;
PluginInsert* plugin_insert;
if ((insert = dynamic_cast<Insert *> (redirect)) != 0) {
if ((port_insert = dynamic_cast<PortInsert *> (insert)) != 0) {
list<PortInsert*>::iterator x = find (_port_inserts.begin(), _port_inserts.end(), port_insert);
if (x != _port_inserts.end()) {
insert_bitset[port_insert->bit_slot()] = false;
_port_inserts.erase (x);
}
} else if ((plugin_insert = dynamic_cast<PluginInsert *> (insert)) != 0) {
_plugin_inserts.remove (plugin_insert);
} else {
fatal << string_compose (_("programming error: %1"),
X_("unknown type of Insert deleted!"))
<< endmsg;
/*NOTREACHED*/
if ((port_insert = dynamic_cast<PortInsert *> (insert)) != 0) {
list<PortInsert*>::iterator x = find (_port_inserts.begin(), _port_inserts.end(), port_insert);
if (x != _port_inserts.end()) {
insert_bitset[port_insert->bit_slot()] = false;
_port_inserts.erase (x);
}
} else if ((send = dynamic_cast<Send *> (redirect)) != 0) {
} else if ((plugin_insert = dynamic_cast<PluginInsert *> (insert)) != 0) {
_plugin_inserts.remove (plugin_insert);
} else if ((send = dynamic_cast<Send *> (insert)) != 0) {
list<Send*>::iterator x = find (_sends.begin(), _sends.end(), send);
if (x != _sends.end()) {
send_bitset[send->bit_slot()] = false;
_sends.erase (x);
}
} else {
fatal << _("programming error: unknown type of Redirect deleted!") << endmsg;
fatal << _("programming error: unknown type of Insert deleted!") << endmsg;
/*NOTREACHED*/
}

View file

@ -261,7 +261,7 @@ Session::first_stage_init (string fullpath, string snapshot_name)
RegionFactory::CheckNewRegion.connect (mem_fun (*this, &Session::add_region));
SourceFactory::SourceCreated.connect (mem_fun (*this, &Session::add_source));
PlaylistFactory::PlaylistCreated.connect (mem_fun (*this, &Session::add_playlist));
Redirect::RedirectCreated.connect (mem_fun (*this, &Session::add_redirect));
Insert::InsertCreated.connect (mem_fun (*this, &Session::add_insert));
NamedSelection::NamedSelectionCreated.connect (mem_fun (*this, &Session::add_named_selection));
AutomationList::AutomationListCreated.connect (mem_fun (*this, &Session::add_automation_list));

View file

@ -379,7 +379,7 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished)
if ((Config->get_slave_source() == None && Config->get_auto_return()) || (post_transport_work & PostTransportLocate) || synced_to_jack()) {
if (pending_locate_flush) {
flush_all_redirects ();
flush_all_inserts ();
}
if (((Config->get_slave_source() == None && Config->get_auto_return()) || synced_to_jack()) && !(post_transport_work & PostTransportLocate)) {
@ -573,12 +573,12 @@ Session::set_play_loop (bool yn)
}
void
Session::flush_all_redirects ()
Session::flush_all_inserts ()
{
boost::shared_ptr<RouteList> r = routes.reader ();
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
(*i)->flush_redirects ();
(*i)->flush_inserts ();
}
}
@ -1266,12 +1266,6 @@ Session::update_latency_compensation (bool with_stop, bool abort)
}
}
void
Session::update_latency_compensation_proxy (void* ignored)
{
update_latency_compensation (false, false);
}
void
Session::allow_auto_play (bool yn)
{

View file

@ -679,7 +679,7 @@ SMFSource::set_allow_remove_if_empty (bool yn)
}
int
SMFSource::set_name (string newname, bool destructive)
SMFSource::set_source_name (string newname, bool destructive)
{
//Glib::Mutex::Lock lm (_lock); FIXME
string oldpath = _path;

View file

@ -42,20 +42,20 @@ using std::max;
using namespace ARDOUR;
Source::Source (Session& s, string name, DataType type)
: _session (s)
Source::Source (Session& s, const string& name, DataType type)
: SessionObject(s, name)
, _type(type)
{
assert(_name.find("/") == string::npos);
// not true.. is this supposed to be an assertion?
//assert(_name.find("/") == string::npos);
_name = name;
_timestamp = 0;
_length = 0;
_in_use = 0;
}
Source::Source (Session& s, const XMLNode& node)
: _session (s)
: SessionObject(s, "unnamed source")
, _type(DataType::AUDIO)
{
_timestamp = 0;

View file

@ -40,7 +40,7 @@ using namespace PBD;
Track::Track (Session& sess, string name, Route::Flag flag, TrackMode mode, DataType default_type)
: Route (sess, name, 1, -1, -1, -1, flag, default_type)
, _rec_enable_control (*this)
, _rec_enable_control (*this)
{
_declickable = true;
_freeze_record.state = NoFreeze;
@ -49,8 +49,8 @@ Track::Track (Session& sess, string name, Route::Flag flag, TrackMode mode, Data
}
Track::Track (Session& sess, const XMLNode& node, DataType default_type)
: Route (sess, node),
_rec_enable_control (*this)
: Route (sess, node)
, _rec_enable_control (*this)
{
_freeze_record.state = NoFreeze;
_declickable = true;
@ -92,7 +92,7 @@ Track::update_total_latency ()
{
_own_latency = 0;
for (RedirectList::iterator i = _redirects.begin(); i != _redirects.end(); ++i) {
for (InsertList::iterator i = _inserts.begin(); i != _inserts.end(); ++i) {
if ((*i)->active ()) {
_own_latency += (*i)->latency ();
}
@ -182,25 +182,27 @@ Track::set_record_enable (bool yn, void *src)
_rec_enable_control.Changed ();
}
int
Track::set_name (string str, void *src)
bool
Track::set_name (const string& str)
{
int ret;
bool ret;
if (record_enabled() && _session.actively_recording()) {
/* this messes things up if done while recording */
return -1;
return false;
}
if (_diskstream->set_name (str)) {
return -1;
return false;
}
/* save state so that the statefile fully reflects any filename changes */
if ((ret = IO::set_name (str, src)) == 0) {
if ((ret = IO::set_name (str)) == 0) {
_session.save_state ("");
}
return ret;
}

View file

@ -980,7 +980,7 @@ void MackieControlProtocol::notify_gain_changed( RouteSignal * route_signal )
}
}
void MackieControlProtocol::notify_name_changed( void *, RouteSignal * route_signal )
void MackieControlProtocol::notify_name_changed( RouteSignal * route_signal )
{
try
{

View file

@ -95,7 +95,7 @@ class MackieControlProtocol
/// Signal handler for Route::gain_changed ( from IO )
void notify_gain_changed( Mackie::RouteSignal * );
/// Signal handler for Route::name_change
void notify_name_changed( void *, Mackie::RouteSignal * );
void notify_name_changed( Mackie::RouteSignal * );
/// Signal handler from Panner::Change
void notify_panner_changed( Mackie::RouteSignal * );
/// Signal handler for new routes added

View file

@ -38,7 +38,7 @@ void RouteSignal::connect()
if ( _strip.has_gain() )
_gain_changed_connection = _route.gain_control().Changed.connect( sigc::bind ( mem_fun ( _mcp, &MackieControlProtocol::notify_gain_changed ), this ) );
_name_changed_connection = _route.name_changed.connect( sigc::bind ( mem_fun ( _mcp, &MackieControlProtocol::notify_name_changed ), this ) );
_name_changed_connection = _route.NameChanged.connect( sigc::bind ( mem_fun ( _mcp, &MackieControlProtocol::notify_name_changed ), this ) );
if ( _route.panner().size() == 1 )
{
@ -85,7 +85,7 @@ void RouteSignal::notify_all()
if ( _strip.has_gain() )
_mcp.notify_gain_changed( this );
_mcp.notify_name_changed( &_route, this );
_mcp.notify_name_changed( this );
if ( _strip.has_vpot() )
_mcp.notify_panner_changed( this );