first pass at internal sends. this is a very tentative work in progress, and it is possible that major changes may follow in the near future. it is certainly not complete, but the fundamental changes to Port/Buffer operation merit a commit at this point

git-svn-id: svn://localhost/ardour2/branches/3.0@4464 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis 2009-01-30 07:40:13 +00:00
parent ee62ee07d3
commit 70b939da4f
48 changed files with 679 additions and 404 deletions

View file

@ -1273,7 +1273,7 @@ void
ARDOUR_UI::session_add_audio_route (bool track, int32_t input_channels, int32_t output_channels, ARDOUR::TrackMode mode, uint32_t how_many) ARDOUR_UI::session_add_audio_route (bool track, int32_t input_channels, int32_t output_channels, ARDOUR::TrackMode mode, uint32_t how_many)
{ {
list<boost::shared_ptr<AudioTrack> > tracks; list<boost::shared_ptr<AudioTrack> > tracks;
Session::RouteList routes; RouteList routes;
if (session == 0) { if (session == 0) {
warning << _("You cannot add a track or bus without a session already loaded.") << endmsg; warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;

View file

@ -595,7 +595,7 @@ class Editor : public PublicEditor
void add_item_with_sensitivity (Gtk::Menu_Helpers::MenuList&, Gtk::Menu_Helpers::MenuElem, bool) const; void add_item_with_sensitivity (Gtk::Menu_Helpers::MenuList&, Gtk::Menu_Helpers::MenuElem, bool) const;
void handle_new_route (ARDOUR::Session::RouteList&); void handle_new_route (ARDOUR::RouteList&);
void remove_route (TimeAxisView *); void remove_route (TimeAxisView *);
bool route_removal; bool route_removal;

View file

@ -48,7 +48,7 @@ using namespace Glib;
const char* _order_key = N_("editor"); const char* _order_key = N_("editor");
void void
Editor::handle_new_route (Session::RouteList& routes) Editor::handle_new_route (RouteList& routes)
{ {
ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::handle_new_route), routes)); ENSURE_GUI_THREAD(bind (mem_fun(*this, &Editor::handle_new_route), routes));
@ -60,7 +60,7 @@ Editor::handle_new_route (Session::RouteList& routes)
route_redisplay_does_not_sync_order_keys = true; route_redisplay_does_not_sync_order_keys = true;
no_route_list_redisplay = true; no_route_list_redisplay = true;
for (Session::RouteList::iterator x = routes.begin(); x != routes.end(); ++x) { for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
boost::shared_ptr<Route> route = (*x); boost::shared_ptr<Route> route = (*x);
if (route->is_hidden()) { if (route->is_hidden()) {
@ -592,8 +592,8 @@ struct EditorOrderRouteSorter {
void void
Editor::initial_route_list_display () Editor::initial_route_list_display ()
{ {
boost::shared_ptr<Session::RouteList> routes = session->get_routes(); boost::shared_ptr<RouteList> routes = session->get_routes();
Session::RouteList r (*routes); RouteList r (*routes);
EditorOrderRouteSorter sorter; EditorOrderRouteSorter sorter;
r.sort (sorter); r.sort (sorter);

View file

@ -105,14 +105,14 @@ void
PortExportChannelSelector::fill_route_list () PortExportChannelSelector::fill_route_list ()
{ {
channel_view.clear_routes (); channel_view.clear_routes ();
Session::RouteList routes = *session->get_routes(); RouteList routes = *session->get_routes();
/* Add master bus and then everything else */ /* Add master bus and then everything else */
ARDOUR::IO * master = session->master_out().get(); ARDOUR::IO * master = session->master_out().get();
channel_view.add_route (master); channel_view.add_route (master);
for (Session::RouteList::iterator it = routes.begin(); it != routes.end(); ++it) { for (RouteList::iterator it = routes.begin(); it != routes.end(); ++it) {
if (it->get() == master) { if (it->get() == master) {
continue; continue;
} }

View file

@ -35,6 +35,7 @@
#include <gtkmm2ext/gtk_ui.h> #include <gtkmm2ext/gtk_ui.h>
#include <midi++/manager.h> #include <midi++/manager.h>
#include <pbd/fastlog.h> #include <pbd/fastlog.h>
#include <pbd/stacktrace.h>
#include "ardour_ui.h" #include "ardour_ui.h"
#include "gain_meter.h" #include "gain_meter.h"
@ -160,6 +161,8 @@ GainMeterBase::~GainMeterBase ()
void void
GainMeterBase::set_io (boost::shared_ptr<IO> io) GainMeterBase::set_io (boost::shared_ptr<IO> io)
{ {
cerr << this << " Clear all connections\n";
connections.clear (); connections.clear ();
_io = io; _io = io;
@ -200,6 +203,8 @@ GainMeterBase::set_io (boost::shared_ptr<IO> io)
} }
} }
cerr << "Connect " << this << " to gain change for " << _io->name() << endl;
connections.push_back (_io->gain_control()->Changed.connect (mem_fun(*this, &GainMeterBase::gain_changed))); connections.push_back (_io->gain_control()->Changed.connect (mem_fun(*this, &GainMeterBase::gain_changed)));
gain_changed (); gain_changed ();
@ -371,8 +376,11 @@ GainMeterBase::show_gain ()
void void
GainMeterBase::gain_adjusted () GainMeterBase::gain_adjusted ()
{ {
cerr << this << " for " << _io->name() << " GAIN ADJUSTED\n";
if (!ignore_toggle) { if (!ignore_toggle) {
cerr << "Set GC\n";
_io->gain_control()->set_value (slider_position_to_gain (gain_adjustment.get_value())); _io->gain_control()->set_value (slider_position_to_gain (gain_adjustment.get_value()));
cerr << "Set GC OUT\n";
} }
show_gain (); show_gain ();
} }
@ -382,6 +390,9 @@ GainMeterBase::effective_gain_display ()
{ {
gfloat value = gain_to_slider_position (_io->effective_gain()); gfloat value = gain_to_slider_position (_io->effective_gain());
cerr << this << " for " << _io->name() << " EGAIN = " << value << " AGAIN = " << gain_adjustment.get_value () << endl;
// stacktrace (cerr, 20);
if (gain_adjustment.get_value() != value) { if (gain_adjustment.get_value() != value) {
ignore_toggle = true; ignore_toggle = true;
gain_adjustment.set_value (value); gain_adjustment.set_value (value);

View file

@ -297,7 +297,7 @@ Mixer_UI::hide_window (GdkEventAny *ev)
void void
Mixer_UI::add_strip (Session::RouteList& routes) Mixer_UI::add_strip (RouteList& routes)
{ {
ENSURE_GUI_THREAD(bind (mem_fun(*this, &Mixer_UI::add_strip), routes)); ENSURE_GUI_THREAD(bind (mem_fun(*this, &Mixer_UI::add_strip), routes));
@ -306,7 +306,7 @@ Mixer_UI::add_strip (Session::RouteList& routes)
no_track_list_redisplay = true; no_track_list_redisplay = true;
strip_redisplay_does_not_sync_order_keys = true; strip_redisplay_does_not_sync_order_keys = true;
for (Session::RouteList::iterator x = routes.begin(); x != routes.end(); ++x) { for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
boost::shared_ptr<Route> route = (*x); boost::shared_ptr<Route> route = (*x);
if (route->is_hidden()) { if (route->is_hidden()) {
@ -885,8 +885,8 @@ struct SignalOrderRouteSorter {
void void
Mixer_UI::initial_track_display () Mixer_UI::initial_track_display ()
{ {
boost::shared_ptr<Session::RouteList> routes = session->get_routes(); boost::shared_ptr<RouteList> routes = session->get_routes();
Session::RouteList copy (*routes); RouteList copy (*routes);
SignalOrderRouteSorter sorter; SignalOrderRouteSorter sorter;
copy.sort (sorter); copy.sort (sorter);

View file

@ -120,7 +120,7 @@ class Mixer_UI : public Gtk::Window
bool strip_scroller_button_release (GdkEventButton*); bool strip_scroller_button_release (GdkEventButton*);
void add_strip (ARDOUR::Session::RouteList&); void add_strip (ARDOUR::RouteList&);
void remove_strip (MixerStrip *); void remove_strip (MixerStrip *);
void hide_all_strips (bool with_select); void hide_all_strips (bool with_select);

View file

@ -429,7 +429,11 @@ PlugUIBase::bypass_toggled ()
bool x; bool x;
if ((x = bypass_button.get_active()) == insert->active()) { if ((x = bypass_button.get_active()) == insert->active()) {
insert->set_active (!x); if (x) {
insert->deactivate ();
} else {
insert->activate ();
}
} }
} }

View file

@ -142,9 +142,9 @@ PortGroupList::gather (ARDOUR::Session& session)
/* Find the bundles for routes. We take their bundles, copy them, /* Find the bundles for routes. We take their bundles, copy them,
and add ports from the route's processors */ and add ports from the route's processors */
boost::shared_ptr<ARDOUR::Session::RouteList> routes = session.get_routes (); boost::shared_ptr<ARDOUR::RouteList> routes = session.get_routes ();
for (ARDOUR::Session::RouteList::const_iterator i = routes->begin(); i != routes->end(); ++i) { for (ARDOUR::RouteList::const_iterator i = routes->begin(); i != routes->end(); ++i) {
/* Copy the appropriate bundle from the route */ /* Copy the appropriate bundle from the route */
boost::shared_ptr<ARDOUR::Bundle> bundle ( boost::shared_ptr<ARDOUR::Bundle> bundle (
new ARDOUR::Bundle ( new ARDOUR::Bundle (

View file

@ -89,8 +89,8 @@ PortMatrix::routes_changed ()
i->disconnect (); i->disconnect ();
} }
boost::shared_ptr<ARDOUR::Session::RouteList> routes = _session.get_routes (); boost::shared_ptr<ARDOUR::RouteList> routes = _session.get_routes ();
for (ARDOUR::Session::RouteList::iterator i = routes->begin(); i != routes->end(); ++i) { for (ARDOUR::RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
_route_connections.push_back ( _route_connections.push_back (
(*i)->processors_changed.connect (sigc::mem_fun (*this, &PortMatrix::setup)) (*i)->processors_changed.connect (sigc::mem_fun (*this, &PortMatrix::setup))
); );

View file

@ -342,7 +342,11 @@ ProcessorBox::processor_button_release_event (GdkEventButton *ev)
/* button2-click with no modifiers */ /* button2-click with no modifiers */
processor->set_active (!processor->active()); if (processor->active()) {
processor->deactivate ();
} else {
processor->activate ();
}
ret = true; ret = true;
} }
@ -396,7 +400,7 @@ ProcessorBox::use_plugins (const SelectedPlugins& plugins)
Route::ProcessorStreams err_streams; Route::ProcessorStreams err_streams;
if (Config->get_new_plugins_active()) { if (Config->get_new_plugins_active()) {
processor->set_active (true); processor->activate ();
} }
if (_route->add_processor (processor, &err_streams)) { if (_route->add_processor (processor, &err_streams)) {
@ -405,7 +409,7 @@ ProcessorBox::use_plugins (const SelectedPlugins& plugins)
} else { } else {
if (Profile->get_sae()) { if (Profile->get_sae()) {
processor->set_active (true); processor->activate ();
} }
processor->ActiveChanged.connect (bind (mem_fun (*this, &ProcessorBox::show_processor_active), boost::weak_ptr<Processor>(processor))); processor->ActiveChanged.connect (bind (mem_fun (*this, &ProcessorBox::show_processor_active), boost::weak_ptr<Processor>(processor)));
} }
@ -545,7 +549,7 @@ ProcessorBox::send_io_finished (IOSelector::Result r, boost::weak_ptr<Processor>
case IOSelector::Accepted: case IOSelector::Accepted:
_route->add_processor (processor); _route->add_processor (processor);
if (Profile->get_sae()) { if (Profile->get_sae()) {
processor->set_active (true); processor->activate ();
} }
break; break;
} }
@ -982,13 +986,13 @@ could not match the configuration of this track.");
void void
ProcessorBox::activate_processor (boost::shared_ptr<Processor> r) ProcessorBox::activate_processor (boost::shared_ptr<Processor> r)
{ {
r->set_active (true); r->activate ();
} }
void void
ProcessorBox::deactivate_processor (boost::shared_ptr<Processor> r) ProcessorBox::deactivate_processor (boost::shared_ptr<Processor> r)
{ {
r->set_active (false); r->deactivate ();
} }
void void

View file

@ -171,11 +171,11 @@ RouteParams_UI::~RouteParams_UI ()
} }
void void
RouteParams_UI::add_routes (Session::RouteList& routes) RouteParams_UI::add_routes (RouteList& routes)
{ {
ENSURE_GUI_THREAD(bind (mem_fun(*this, &RouteParams_UI::add_routes), routes)); ENSURE_GUI_THREAD(bind (mem_fun(*this, &RouteParams_UI::add_routes), routes));
for (Session::RouteList::iterator x = routes.begin(); x != routes.end(); ++x) { for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
boost::shared_ptr<Route> route = (*x); boost::shared_ptr<Route> route = (*x);
if (route->is_hidden()) { if (route->is_hidden()) {
@ -423,7 +423,7 @@ RouteParams_UI::set_session (Session *sess)
route_display_model->clear(); route_display_model->clear();
if (session) { if (session) {
boost::shared_ptr<Session::RouteList> r = session->get_routes(); boost::shared_ptr<RouteList> r = session->get_routes();
add_routes (*r); add_routes (*r);
session->GoingAway.connect (mem_fun(*this, &ArdourDialog::session_gone)); session->GoingAway.connect (mem_fun(*this, &ArdourDialog::session_gone));
session->RouteAdded.connect (mem_fun(*this, &RouteParams_UI::add_routes)); session->RouteAdded.connect (mem_fun(*this, &RouteParams_UI::add_routes));

View file

@ -167,7 +167,7 @@ class RouteParams_UI : public ArdourDialog
Glib::RefPtr<Gtk::ListStore> route_display_model; Glib::RefPtr<Gtk::ListStore> route_display_model;
void add_routes (ARDOUR::Session::RouteList&); void add_routes (ARDOUR::RouteList&);
void route_name_changed (boost::shared_ptr<ARDOUR::Route> route); void route_name_changed (boost::shared_ptr<ARDOUR::Route> route);
void route_removed (boost::shared_ptr<ARDOUR::Route> route); void route_removed (boost::shared_ptr<ARDOUR::Route> route);

View file

@ -92,6 +92,7 @@ gain.cc
gdither.cc gdither.cc
globals.cc globals.cc
import.cc import.cc
internal_send.cc
io.cc io.cc
io_processor.cc io_processor.cc
jack_slave.cc jack_slave.cc

View file

@ -42,9 +42,6 @@ namespace MIDI {
namespace ARDOUR { namespace ARDOUR {
class AudioEngine; class AudioEngine;
class OSC;
extern OSC* osc;
static const nframes_t max_frames = JACK_MAX_FRAMES; static const nframes_t max_frames = JACK_MAX_FRAMES;
extern sigc::signal<void,std::string> BootMessage; extern sigc::signal<void,std::string> BootMessage;

View file

@ -68,9 +68,14 @@ public:
/** Accumulate (add) @a len frames FROM THE START OF @a src into self at @a offset /** Accumulate (add) @a len frames FROM THE START OF @a src into self at @a offset
* scaling by @a gain_coeff */ * scaling by @a gain_coeff */
void accumulate_with_gain_from(const AudioBuffer& src, nframes_t len, nframes_t offset, gain_t gain_coeff) { void accumulate_with_gain_from(const AudioBuffer& src, nframes_t len, nframes_t offset, gain_t gain_coeff) {
assert(_capacity > 0); assert(_capacity > 0);
assert(offset + len <= _capacity); assert(offset + len <= _capacity);
if (src.silent()) {
return;
}
Sample* const dst_raw = _data + offset; Sample* const dst_raw = _data + offset;
const Sample* const src_raw = src.data(); const Sample* const src_raw = src.data();
@ -82,6 +87,7 @@ public:
/** Accumulate (add) @a len frames FROM THE START OF @a src into self at @a offset /** Accumulate (add) @a len frames FROM THE START OF @a src into self at @a offset
* scaling by @a gain_coeff */ * scaling by @a gain_coeff */
void accumulate_with_gain_from(const Sample* src_raw, nframes_t len, nframes_t offset, gain_t gain_coeff) { void accumulate_with_gain_from(const Sample* src_raw, nframes_t len, nframes_t offset, gain_t gain_coeff) {
assert(_capacity > 0); assert(_capacity > 0);
assert(offset + len <= _capacity); assert(offset + len <= _capacity);
@ -123,7 +129,22 @@ public:
Sample* data (nframes_t nframes, nframes_t offset) Sample* data (nframes_t nframes, nframes_t offset)
{ assert(offset + nframes <= _capacity); return _data + offset; } { assert(offset + nframes <= _capacity); return _data + offset; }
private: void replace_data (size_t nframes);
void drop_data () {
assert (_owns_data);
assert (_data);
free (_data);
_data = 0;
_size = 0;
_capacity = 0;
_silent = false;
}
void copy_to_internal (Sample* p, nframes_t cnt, nframes_t offset);
private:
bool _owns_data; bool _owns_data;
Sample* _data; ///< Actual buffer contents Sample* _data; ///< Actual buffer contents
}; };

View file

@ -51,12 +51,16 @@ class AudioPort : public Port
AudioPort (std::string const &, Flags, bool, nframes_t); AudioPort (std::string const &, Flags, bool, nframes_t);
bool using_internal_data() const;
void use_internal_data ();
void use_external_data ();
private: private:
void mixdown (nframes_t, nframes_t, bool); void mixdown (nframes_t, nframes_t, bool);
bool _has_been_mixed_down; bool _has_been_mixed_down;
AudioBuffer* _buffer; AudioBuffer* _buffer;
bool _own_buffer; bool _internal_buffer;
}; };
} // namespace ARDOUR } // namespace ARDOUR

View file

@ -73,6 +73,10 @@ class AudioTrack : public Track
int deprecated_use_diskstream_connections (); int deprecated_use_diskstream_connections ();
void set_state_part_two (); void set_state_part_two ();
void set_state_part_three (); void set_state_part_three ();
void catch_up_on_busses (ARDOUR::RouteList&);
void add_internal_send (boost::shared_ptr<ARDOUR::Route>);
}; };
} // namespace ARDOUR } // namespace ARDOUR

View file

@ -94,15 +94,16 @@ public:
Evoral::ControlSet& data() { return *this; } Evoral::ControlSet& data() { return *this; }
const Evoral::ControlSet& data() const { return *this; } const Evoral::ControlSet& data() const { return *this; }
protected: int set_automation_state (const XMLNode&, Evoral::Parameter default_param);
XMLNode& get_automation_state();
protected:
Session& _a_session; Session& _a_session;
void can_automate(Evoral::Parameter); void can_automate(Evoral::Parameter);
virtual void auto_state_changed (Evoral::Parameter which) {} virtual void auto_state_changed (Evoral::Parameter which) {}
int set_automation_state(const XMLNode&, Evoral::Parameter default_param);
XMLNode& get_automation_state();
int load_automation (const std::string& path); int load_automation (const std::string& path);
int old_set_automation_state(const XMLNode&); int old_set_automation_state(const XMLNode&);

View file

@ -68,7 +68,7 @@ public:
* passed to the constructor must have been non-zero. * passed to the constructor must have been non-zero.
*/ */
virtual void resize(size_t) = 0; virtual void resize(size_t) = 0;
/** Clear (eg zero, or empty) buffer starting at TIME @a offset */ /** Clear (eg zero, or empty) buffer starting at TIME @a offset */
virtual void silence(nframes_t len, nframes_t offset=0) = 0; virtual void silence(nframes_t len, nframes_t offset=0) = 0;
@ -77,9 +77,9 @@ public:
virtual void read_from(const Buffer& src, nframes_t offset, nframes_t len) = 0; virtual void read_from(const Buffer& src, nframes_t offset, nframes_t len) = 0;
protected: protected:
Buffer(DataType type, size_t capacity) Buffer(DataType type, size_t capacity)
: _type(type), _capacity(capacity), _size(0), _silent(true) : _type(type), _capacity(capacity), _size(0), _silent(true)
{} {}
DataType _type; DataType _type;

View file

@ -23,6 +23,7 @@
#include <vector> #include <vector>
#include <ardour/chan_count.h> #include <ardour/chan_count.h>
#include <ardour/data_type.h> #include <ardour/data_type.h>
#include <ardour/types.h>
namespace ARDOUR { namespace ARDOUR {
@ -53,7 +54,7 @@ public:
void clear(); void clear();
void attach_buffers(PortSet& ports); void attach_buffers(PortSet& ports, nframes_t nframes, nframes_t offset);
void ensure_buffers(const ChanCount& count, size_t buffer_capacity); void ensure_buffers(const ChanCount& count, size_t buffer_capacity);
void ensure_buffers(DataType type, size_t num_buffers, size_t buffer_capacity); void ensure_buffers(DataType type, size_t num_buffers, size_t buffer_capacity);

View file

@ -109,6 +109,8 @@ class IO : public SessionObject, public AutomatableControls, public Latent
void just_meter_input (nframes_t start_frame, nframes_t end_frame, void just_meter_input (nframes_t start_frame, nframes_t end_frame,
nframes_t nframes, nframes_t offset); nframes_t nframes, nframes_t offset);
BufferSet& output_buffers() { return *_output_buffers; }
gain_t gain () const { return _desired_gain; } gain_t gain () const { return _desired_gain; }
virtual gain_t effective_gain () const; virtual gain_t effective_gain () const;
@ -121,6 +123,7 @@ class IO : public SessionObject, public AutomatableControls, public Latent
Panner& panner() { return *_panner; } Panner& panner() { return *_panner; }
PeakMeter& peak_meter() { return *_meter; } PeakMeter& peak_meter() { return *_meter; }
const Panner& panner() const { return *_panner; } const Panner& panner() const { return *_panner; }
void reset_panner ();
int ensure_io (ChanCount in, ChanCount out, bool clear, void *src); int ensure_io (ChanCount in, ChanCount out, bool clear, void *src);
@ -196,15 +199,10 @@ class IO : public SessionObject, public AutomatableControls, public Latent
int set_state (const XMLNode&); int set_state (const XMLNode&);
static int disable_connecting (void); static int disable_connecting (void);
static int enable_connecting (void); static int enable_connecting (void);
static int disable_ports (void); static int disable_ports (void);
static int enable_ports (void); static int enable_ports (void);
static int disable_panners (void); static int disable_panners (void);
static int reset_panners (void); static int reset_panners (void);
static sigc::signal<int> PortsLegal; static sigc::signal<int> PortsLegal;
@ -214,16 +212,16 @@ class IO : public SessionObject, public AutomatableControls, public Latent
static sigc::signal<void,ChanCount> PortCountChanged; static sigc::signal<void,ChanCount> PortCountChanged;
static sigc::signal<int> PortsCreated; static sigc::signal<int> PortsCreated;
static void update_meters(); static void update_meters();
private: private:
static sigc::signal<void> Meter; static sigc::signal<void> Meter;
static Glib::StaticMutex m_meter_signal_lock; static Glib::StaticMutex m_meter_signal_lock;
sigc::connection m_meter_connection; sigc::connection m_meter_connection;
public: public:
/* automation */ /* automation */
struct GainControl : public AutomationControl { struct GainControl : public AutomationControl {
@ -292,8 +290,6 @@ class IO : public SessionObject, public AutomatableControls, public Latent
virtual void set_deferred_state() {} virtual void set_deferred_state() {}
void reset_panner ();
virtual uint32_t pans_required() const virtual uint32_t pans_required() const
{ return _inputs.count().n_audio(); } { return _inputs.count().n_audio(); }
@ -314,14 +310,11 @@ class IO : public SessionObject, public AutomatableControls, public Latent
static bool connecting_legal; static bool connecting_legal;
static bool ports_legal; static bool ports_legal;
BufferSet& output_buffers() { return *_output_buffers; }
private: private:
friend class Send;
static bool panners_legal; static bool panners_legal;
void copy_to_outputs (BufferSet& bufs, DataType type, nframes_t nframes, nframes_t offset);
int connecting_became_legal (); int connecting_became_legal ();
int panners_became_legal (); int panners_became_legal ();
sigc::connection connection_legal_c; sigc::connection connection_legal_c;

View file

@ -53,7 +53,9 @@ class IOProcessor : public Processor
{ {
public: public:
IOProcessor (Session&, const string& name, Placement, IOProcessor (Session&, const string& name, Placement,
int input_min = -1, int input_max = -1, int output_min = -1, int output_max = -1); int input_min = -1, int input_max = -1, int output_min = -1, int output_max = -1,
ARDOUR::DataType default_type = DataType::AUDIO,
bool public_ports = true);
IOProcessor (const IOProcessor&); IOProcessor (const IOProcessor&);
virtual ~IOProcessor (); virtual ~IOProcessor ();

View file

@ -71,6 +71,7 @@ public:
} }
bool connected () const; bool connected () const;
bool externally_connected () const;
int disconnect_all (); int disconnect_all ();
int get_connections (std::vector<std::string> &) const; int get_connections (std::vector<std::string> &) const;
@ -81,7 +82,7 @@ public:
/* connection by Port* */ /* connection by Port* */
bool connected_to (Port *) const; bool connected_to (Port *) const;
int connect (Port *); virtual int connect (Port *);
int disconnect (Port *); int disconnect (Port *);
void ensure_monitor_input (bool); void ensure_monitor_input (bool);
@ -113,6 +114,12 @@ protected:
std::set<Port*> _connections; ///< internal Ports that we are connected to std::set<Port*> _connections; ///< internal Ports that we are connected to
static AudioEngine* _engine; ///< the AudioEngine static AudioEngine* _engine; ///< the AudioEngine
virtual bool using_internal_data() const { return false; }
virtual void use_internal_data () {}
virtual void use_external_data () {}
void check_buffer_status ();
private: private:
friend class AudioEngine; friend class AudioEngine;
@ -130,6 +137,7 @@ private:
/// list of JACK ports that we are connected to; we only keep this around /// list of JACK ports that we are connected to; we only keep this around
/// so that we can implement ::reconnect () /// so that we can implement ::reconnect ()
std::set<std::string> _named_connections; std::set<std::string> _named_connections;
}; };
} }

View file

@ -39,6 +39,7 @@ class XMLNode;
namespace ARDOUR { namespace ARDOUR {
class Session; class Session;
class Route;
/* A mixer strip element - plugin, send, meter, etc. /* A mixer strip element - plugin, send, meter, etc.
*/ */
@ -60,7 +61,6 @@ class Processor : public SessionObject, public AutomatableControls, public Laten
void set_placement (Placement); void set_placement (Placement);
bool active () const { return _active; } bool active () const { return _active; }
void set_active (bool yn);
bool get_next_ab_is_active () const { return _next_ab_is_active; } 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; } void set_next_ab_is_active (bool yn) { _next_ab_is_active = yn; }
@ -77,8 +77,8 @@ class Processor : public SessionObject, public AutomatableControls, public Laten
virtual void silence (nframes_t nframes, nframes_t offset) {} virtual void silence (nframes_t nframes, nframes_t offset) {}
virtual void activate () { _active = true; ActiveChanged.emit(); } void activate () { _active = true; ActiveChanged(); }
virtual void deactivate () { _active = false; ActiveChanged.emit(); } void deactivate () { _active = false; ActiveChanged(); }
virtual bool configure_io (ChanCount in, ChanCount out); virtual bool configure_io (ChanCount in, ChanCount out);
@ -108,6 +108,7 @@ class Processor : public SessionObject, public AutomatableControls, public Laten
sigc::signal<void> PlacementChanged; sigc::signal<void> PlacementChanged;
protected: protected:
int _pending_active;
bool _active; bool _active;
bool _next_ab_is_active; bool _next_ab_is_active;
bool _configured; bool _configured;

View file

@ -306,7 +306,6 @@ class Session : public PBD::StatefulDestructible
uint32_t n_diskstreams() const; uint32_t n_diskstreams() const;
typedef std::list<boost::shared_ptr<Diskstream> > DiskstreamList; typedef std::list<boost::shared_ptr<Diskstream> > DiskstreamList;
typedef std::list<boost::shared_ptr<Route> > RouteList;
int load_routes (const XMLNode&); int load_routes (const XMLNode&);
boost::shared_ptr<RouteList> get_routes() const { boost::shared_ptr<RouteList> get_routes() const {

View file

@ -51,6 +51,7 @@ namespace ARDOUR {
class Source; class Source;
class AudioSource; class AudioSource;
class Route;
typedef jack_default_audio_sample_t Sample; typedef jack_default_audio_sample_t Sample;
typedef float pan_t; typedef float pan_t;
@ -419,9 +420,11 @@ namespace ARDOUR {
typedef std::list<nframes64_t> AnalysisFeatureList; typedef std::list<nframes64_t> AnalysisFeatureList;
typedef std::list<boost::shared_ptr<Route> > RouteList;
class Bundle; class Bundle;
typedef std::vector<boost::shared_ptr<Bundle> > BundleList; typedef std::vector<boost::shared_ptr<Bundle> > BundleList;
} // namespace ARDOUR } // namespace ARDOUR
std::istream& operator>>(std::istream& o, ARDOUR::SampleFormat& sf); std::istream& operator>>(std::istream& o, ARDOUR::SampleFormat& sf);

View file

@ -29,9 +29,7 @@ static const int CPU_CACHE_ALIGN = 16; /* arguably 32 on most arches, but it mat
#endif #endif
using namespace PBD; using namespace PBD;
using namespace ARDOUR;
namespace ARDOUR {
AudioBuffer::AudioBuffer(size_t capacity) AudioBuffer::AudioBuffer(size_t capacity)
: Buffer(DataType::AUDIO, capacity) : Buffer(DataType::AUDIO, capacity)
@ -41,6 +39,7 @@ AudioBuffer::AudioBuffer(size_t capacity)
if (_capacity > 0) { if (_capacity > 0) {
_owns_data = true; // prevent resize() from gagging _owns_data = true; // prevent resize() from gagging
resize (_capacity); resize (_capacity);
_silent = false; // force silence on the intial buffer state
silence (_capacity); silence (_capacity);
} }
} }
@ -51,10 +50,28 @@ AudioBuffer::~AudioBuffer()
free(_data); free(_data);
} }
/* called to replace a pointer to an external buffer (e.g. JACK) with
buffer-owned memory.
*/
void
AudioBuffer::replace_data (size_t capacity)
{
_owns_data = true;
_data = 0;
_capacity = 0; // force reallocation
resize (capacity);
}
void void
AudioBuffer::resize (size_t size) AudioBuffer::resize (size_t size)
{ {
if (!_owns_data || (size < _capacity)) { if (!_owns_data) {
return;
}
if (size < _capacity) {
_size = size;
return; return;
} }
@ -74,9 +91,12 @@ AudioBuffer::resize (size_t size)
CPU_CACHE_ALIGN, sizeof (Sample) * _capacity, strerror (errno)) << endmsg; CPU_CACHE_ALIGN, sizeof (Sample) * _capacity, strerror (errno)) << endmsg;
} }
#endif #endif
_owns_data = true;
} }
} // namespace ARDOUR void
AudioBuffer::copy_to_internal (Sample* p, nframes_t cnt, nframes_t offset)
{
memcpy (_data + offset, p, sizeof(Sample*) * cnt);
}

View file

@ -29,9 +29,10 @@ AudioPort::AudioPort (const std::string& name, Flags flags, bool ext, nframes_t
: Port (name, DataType::AUDIO, flags, ext) : Port (name, DataType::AUDIO, flags, ext)
, _has_been_mixed_down (false) , _has_been_mixed_down (false)
, _buffer (0) , _buffer (0)
, _internal_buffer (false)
{ {
assert (name.find_first_of (':') == string::npos); assert (name.find_first_of (':') == string::npos);
if (external ()) { if (external ()) {
/* external ports use the external port buffer */ /* external ports use the external port buffer */
@ -41,8 +42,9 @@ AudioPort::AudioPort (const std::string& name, Flags flags, bool ext, nframes_t
/* internal ports need their own buffers */ /* internal ports need their own buffers */
_buffer = new AudioBuffer (capacity); _buffer = new AudioBuffer (capacity);
} }
check_buffer_status ();
} }
@ -56,11 +58,22 @@ AudioPort::cycle_start (nframes_t nframes, nframes_t offset)
{ {
/* caller must hold process lock */ /* caller must hold process lock */
_has_been_mixed_down = false; /* For external (JACK) ports, get_buffer() must only be run
on outputs here in cycle_start().
if (external ()) { Inputs must be done in the correct processing order, which
/* external ports use JACK's memory */ requires interleaving with route processing. that will
_buffer->set_data ((Sample *) jack_port_get_buffer (_jack_port, nframes), nframes + offset); happen when Port::get_buffer() is called.
*/
if (!receives_input() && external ()) {
_buffer->set_data ((Sample *) jack_port_get_buffer (_jack_port, nframes) + offset, nframes);
}
if (receives_input()) {
_has_been_mixed_down = false;
} else {
_buffer->silence (nframes, offset);
} }
} }
@ -69,36 +82,21 @@ AudioPort::get_audio_buffer (nframes_t nframes, nframes_t offset)
{ {
/* caller must hold process lock */ /* caller must hold process lock */
if (_has_been_mixed_down) { if (receives_input () && !_has_been_mixed_down) {
return *_buffer;
}
if (receives_input ()) { /* external ports use JACK's memory unless otherwise noted */
/* INPUT */
/* If we're external (), we have some data in our buffer set up by JACK;
otherwise, we have an undefined buffer. In either case we mix down
our non-JACK inputs; either accumulating into the JACK data or
overwriting the undefined data */
mixdown (nframes, offset, !external ());
} else { if (external()) {
if (!using_internal_data()) {
/* OUTPUT */ _buffer->set_data ((Sample *) jack_port_get_buffer (_jack_port, nframes) + offset, nframes);
} else {
if (!external ()) { _buffer->silence (nframes, offset);
/* start internal output buffers with silence */ }
_buffer->silence (nframes, offset);
} }
}
if (nframes) {
_has_been_mixed_down = true;
}
mixdown (nframes, offset, !external ());
}
return *_buffer; return *_buffer;
} }
@ -111,22 +109,46 @@ AudioPort::cycle_end (nframes_t nframes, nframes_t offset)
void void
AudioPort::mixdown (nframes_t cnt, nframes_t offset, bool first_overwrite) AudioPort::mixdown (nframes_t cnt, nframes_t offset, bool first_overwrite)
{ {
/* note: this is only called for input ports */
if (_connections.empty()) { if (_connections.empty()) {
if (first_overwrite) {
/* no internal mixing to do, so for internal ports
just make sure the buffer is silent.
*/
if (!external()) {
_buffer->silence (cnt, offset); _buffer->silence (cnt, offset);
}
} else {
set<Port*>::const_iterator p = _connections.begin();
/* mix in internally-connected ports. if this is an external port
then it may already have data present from JACK. in that case, we
do not want to overwrite that data, so we skip the initial ::read_from()
call and do everything with accumulate_from()
*/
if (!external()) {
_buffer->read_from (dynamic_cast<AudioPort*>(*p)->get_audio_buffer (cnt, offset), cnt, offset);
++p;
} }
return;
}
set<Port*>::const_iterator p = _connections.begin();
if (first_overwrite) { for (; p != _connections.end (); ++p) {
_buffer->read_from (dynamic_cast<AudioPort*>(*p)->get_audio_buffer (cnt, offset), cnt, offset); _buffer->accumulate_from (dynamic_cast<AudioPort*>(*p)->get_audio_buffer (cnt, offset), cnt, offset);
++p;
}
} }
for (; p != _connections.end (); ++p) { /* XXX horrible heuristic designed to check that we worked the whole buffer.
_buffer->accumulate_from (dynamic_cast<AudioPort*>(*p)->get_audio_buffer (cnt, offset), cnt, offset); Needs fixing but its a hard problem.
*/
if (cnt && offset == 0) {
_has_been_mixed_down = true;
} }
} }
@ -140,3 +162,23 @@ AudioPort::reset ()
_buffer->clear (); _buffer->clear ();
} }
} }
bool
AudioPort::using_internal_data () const
{
return _internal_buffer;
}
void
AudioPort::use_internal_data ()
{
_buffer->replace_data (_buffer->capacity());
_internal_buffer = true;
}
void
AudioPort::use_external_data ()
{
_internal_buffer = false;
_buffer->drop_data ();
}

View file

@ -40,6 +40,7 @@
#include <ardour/utils.h> #include <ardour/utils.h>
#include <ardour/buffer_set.h> #include <ardour/buffer_set.h>
#include <ardour/audio_buffer.h> #include <ardour/audio_buffer.h>
#include <ardour/internal_send.h>
#include "i18n.h" #include "i18n.h"
using namespace std; using namespace std;
@ -65,6 +66,8 @@ AudioTrack::AudioTrack (Session& sess, string name, Route::Flag flag, TrackMode
_session.add_diskstream (ds); _session.add_diskstream (ds);
_session.RouteAdded.connect (mem_fun (*this, &AudioTrack::catch_up_on_busses));
set_diskstream (boost::dynamic_pointer_cast<AudioDiskstream> (ds), this); set_diskstream (boost::dynamic_pointer_cast<AudioDiskstream> (ds), this);
} }
@ -72,12 +75,47 @@ AudioTrack::AudioTrack (Session& sess, const XMLNode& node)
: Track (sess, node) : Track (sess, node)
{ {
_set_state (node, false); _set_state (node, false);
_session.RouteAdded.connect (mem_fun (*this, &AudioTrack::catch_up_on_busses));
} }
AudioTrack::~AudioTrack () AudioTrack::~AudioTrack ()
{ {
} }
void
AudioTrack::catch_up_on_busses (RouteList& added)
{
if (is_hidden()) {
return;
}
for (RouteList::iterator x = added.begin(); x != added.end(); ++x) {
if (boost::dynamic_pointer_cast<Track>(*x) == 0 && (*x)->default_type() == DataType::AUDIO) {
/* Audio bus */
if (!(*x)->is_master() && !(*x)->is_control()) {
add_internal_send (*x);
}
}
}
}
void
AudioTrack::add_internal_send (boost::shared_ptr<Route> r)
{
boost::shared_ptr<InternalSend> is (new InternalSend (_session, PreFader, r));
cerr << name() << " Adding processor\n";
add_processor (is, 0);
cerr << "After add, we have " << _processors.size() << endl;
/* note: if adding failed, the InternalSend will be cleaned up automatically when
the shared_ptr goes out of scope.
*/
}
int int
AudioTrack::set_mode (TrackMode m) AudioTrack::set_mode (TrackMode m)
{ {
@ -879,7 +917,7 @@ AudioTrack::freeze (InterThreadInfo& itt)
/* now deactivate the processor */ /* now deactivate the processor */
processor->set_active (false); processor->deactivate ();
_session.set_dirty (); _session.set_dirty ();
} }
} }

View file

@ -348,13 +348,6 @@ AudioEngine::process_callback (nframes_t nframes)
boost::shared_ptr<Ports> p = ports.reader(); boost::shared_ptr<Ports> p = ports.reader();
for (Ports::iterator i = p->begin(); i != p->end(); ++i) { for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
/* Only run cycle_start() on output ports, because
inputs must be done in the correct processing order,
which requires interleaving with route processing.
*/
/* XXX: we're running this on both inputs and outputs... */
(*i)->cycle_start (nframes, 0); (*i)->cycle_start (nframes, 0);
} }
@ -416,10 +409,8 @@ AudioEngine::process_callback (nframes_t nframes)
// Finalize ports (ie write data if necessary) // Finalize ports (ie write data if necessary)
for (Ports::iterator i = p->begin(); i != p->end(); ++i) { for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
(*i)->cycle_end (nframes, 0); (*i)->cycle_end (nframes, 0);
} }
_processed_frames = next_processed_frames; _processed_frames = next_processed_frames;
return 0; return 0;
} }

View file

@ -16,6 +16,7 @@
675 Mass Ave, Cambridge, MA 02139, USA. 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include <iostream>
#include <algorithm> #include <algorithm>
#include <ardour/buffer_set.h> #include <ardour/buffer_set.h>
#include <ardour/buffer.h> #include <ardour/buffer.h>
@ -61,7 +62,7 @@ BufferSet::clear()
/** Make this BufferSet a direct mirror of a PortSet's buffers. /** Make this BufferSet a direct mirror of a PortSet's buffers.
*/ */
void void
BufferSet::attach_buffers(PortSet& ports) BufferSet::attach_buffers(PortSet& ports, nframes_t nframes, nframes_t offset)
{ {
clear(); clear();
@ -71,9 +72,8 @@ BufferSet::attach_buffers(PortSet& ports)
for (PortSet::iterator p = ports.begin(*t); p != ports.end(*t); ++p) { for (PortSet::iterator p = ports.begin(*t); p != ports.end(*t); ++p) {
assert(p->type() == *t); assert(p->type() == *t);
v.push_back(&(p->get_buffer(0,0))); v.push_back(&(p->get_buffer(nframes, offset)));
} }
} }
_count = ports.count(); _count = ports.count();

View file

@ -153,9 +153,6 @@ IO::IO (Session& s, const string& name,
m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter)); m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
} }
// Connect to our own PortCountChanged signal to connect output buffers
IO::PortCountChanged.connect (mem_fun (*this, &IO::attach_buffers));
_session.add_controllable (_gain_control); _session.add_controllable (_gain_control);
create_bundles_for_inputs_and_outputs (); create_bundles_for_inputs_and_outputs ();
@ -195,9 +192,6 @@ IO::IO (Session& s, const XMLNode& node, DataType dt)
m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter)); m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter));
} }
// Connect to our own PortCountChanged signal to connect output buffers
IO::PortCountChanged.connect (mem_fun (*this, &IO::attach_buffers));
_session.add_controllable (_gain_control); _session.add_controllable (_gain_control);
create_bundles_for_inputs_and_outputs (); create_bundles_for_inputs_and_outputs ();
@ -222,7 +216,6 @@ IO::~IO ()
delete _meter; delete _meter;
delete _panner; delete _panner;
delete _output_buffers;
} }
void void
@ -266,48 +259,61 @@ IO::deliver_output (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame,
_gain = dg; _gain = dg;
} }
} }
/* do this so that any processing that comes after deliver_outputs()
can use the output buffers.
*/
output_buffers().attach_buffers (_outputs, nframes, offset);
// Use the panner to distribute audio to output port buffers // Use the panner to distribute audio to output port buffers
if( _panner && _panner->npanners() && !_panner->bypassed()) {
if (0 && _panner && _panner->npanners() && !_panner->bypassed()) {
/* blech .. we shouldn't be creating and tearing this down every process()
cycle. XXX fix me to not waste cycles and do memory allocation etc.
*/
_panner->run_out_of_place(bufs, output_buffers(), start_frame, end_frame, nframes, offset); _panner->run_out_of_place(bufs, output_buffers(), start_frame, end_frame, nframes, offset);
} else { } else {
const DataType type = DataType::AUDIO;
/* do a 1:1 copy of data to output ports */
// Copy any audio 1:1 to outputs
if (bufs.count().n_audio() > 0 && _outputs.count().n_audio () > 0) {
BufferSet::iterator o = output_buffers().begin(type); copy_to_outputs (bufs, DataType::AUDIO, nframes, offset);
BufferSet::iterator i = bufs.begin(type);
BufferSet::iterator prev = i;
while (i != bufs.end(type) && o != output_buffers().end (type)) {
o->read_from(*i, nframes, offset);
prev = i;
++i;
++o;
} }
if (bufs.count().n_midi() > 0 && _outputs.count().n_midi () > 0) {
/* extra outputs get a copy of the last buffer */ copy_to_outputs (bufs, DataType::MIDI, nframes, offset);
while (o != output_buffers().end(type)) {
o->read_from(*prev, nframes, offset);
++o;
} }
} }
}
/* ********** MIDI ********** */ void
IO::copy_to_outputs (BufferSet& bufs, DataType type, nframes_t nframes, nframes_t offset)
{
// Copy any buffers 1:1 to outputs
PortSet::iterator o = _outputs.begin(type);
BufferSet::iterator i = bufs.begin(type);
BufferSet::iterator prev = i;
while (i != bufs.end(type) && o != _outputs.end (type)) {
Buffer& port_buffer (o->get_buffer (nframes, offset));
port_buffer.read_from (*i, nframes, offset);
// No MIDI, we're done here prev = i;
if (bufs.count().n_midi() == 0 || output_buffers().count().n_midi () == 0) { ++i;
return; ++o;
} }
const DataType type = DataType::MIDI; /* extra outputs get a copy of the last buffer */
// Copy any MIDI 1:1 to outputs while (o != _outputs.end(type)) {
assert(bufs.count().n_midi() == output_buffers().count().n_midi()); Buffer& port_buffer (o->get_buffer (nframes, offset));
BufferSet::iterator o = output_buffers().begin(type); port_buffer.read_from(*prev, nframes, offset);
for (BufferSet::iterator i = bufs.begin(type); i != bufs.end(type); ++i, ++o) { ++o;
o->read_from(*i, nframes, offset);
} }
} }
@ -324,8 +330,10 @@ IO::collect_input (BufferSet& outs, nframes_t nframes, nframes_t offset)
for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) { for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
BufferSet::iterator o = outs.begin(*t); BufferSet::iterator o = outs.begin(*t);
for (PortSet::iterator i = _inputs.begin(*t); i != _inputs.end(*t); ++i, ++o) { PortSet::iterator e = _inputs.end (*t);
o->read_from(i->get_buffer(nframes,offset), nframes, offset); for (PortSet::iterator i = _inputs.begin(*t); i != e; ++i, ++o) {
Buffer& b (i->get_buffer (nframes,offset));
o->read_from (b, nframes, offset);
} }
} }
@ -879,16 +887,6 @@ IO::ensure_inputs_locked (ChanCount count, bool clear, void* src)
return changed; return changed;
} }
/** Attach output_buffers to port buffers.
*
* Connected to IO's own PortCountChanged signal.
*/
void
IO::attach_buffers(ChanCount ignored)
{
_output_buffers->attach_buffers(_outputs);
}
int int
IO::ensure_io (ChanCount in, ChanCount out, bool clear, void* src) IO::ensure_io (ChanCount in, ChanCount out, bool clear, void* src)
{ {
@ -2321,6 +2319,8 @@ IO::set_gain (gain_t val, void *src)
val = 1.99526231f; val = 1.99526231f;
} }
cerr << "set desired gain to " << val << " when curgain = " << _gain_control->get_value () << endl;
if (src != _gain_control.get()) { if (src != _gain_control.get()) {
_gain_control->set_value(val); _gain_control->set_value(val);
// bit twisty, this will come back and call us again // bit twisty, this will come back and call us again
@ -2741,3 +2741,5 @@ IO::bundle_channel_name (uint32_t c, uint32_t n) const
return ""; return "";
} }

View file

@ -43,10 +43,12 @@ using namespace ARDOUR;
using namespace PBD; using namespace PBD;
IOProcessor::IOProcessor (Session& s, const string& name, Placement p, IOProcessor::IOProcessor (Session& s, const string& name, Placement p,
int input_min, int input_max, int input_min, int input_max,
int output_min, int output_max) int output_min, int output_max,
DataType dtype,
bool public_ports)
: Processor(s, name, p) : Processor(s, name, p)
, _io(new IO(s, name, input_min, input_max, output_min, output_max)) , _io (new IO(s, name, input_min, input_max, output_min, output_max, dtype, public_ports))
{ {
_active = false; _active = false;
_sort_key = 0; _sort_key = 0;

View file

@ -25,19 +25,30 @@
#include "pbd/compose.h" #include "pbd/compose.h"
#include <stdexcept> #include <stdexcept>
ARDOUR::AudioEngine* ARDOUR::Port::_engine = 0; using namespace std;
using namespace ARDOUR;
AudioEngine* Port::_engine = 0;
/** @param n Port short name */ /** @param n Port short name */
ARDOUR::Port::Port (std::string const & n, DataType t, Flags f, bool e) : _jack_port (0), _last_monitor (false), _latency (0), _name (n), _flags (f) Port::Port (std::string const & n, DataType t, Flags f, bool e)
: _jack_port (0)
, _last_monitor (false)
, _latency (0)
, _name (n)
, _flags (f)
{ {
/* Unfortunately we have to pass the DataType into this constructor so that we can /* Unfortunately we have to pass the DataType into this constructor so that we can
create the right kind of JACK port; aside from this we'll use the virtual function type () create the right kind of JACK port; aside from this we'll use the virtual function type ()
to establish type. */ to establish type.
*/
assert (_name.find_first_of (':') == std::string::npos); assert (_name.find_first_of (':') == std::string::npos);
if (e) { if (e) {
try { try {
cerr << "NEW PORT " << _name << " ext = " << e << endl;
do_make_external (t); do_make_external (t);
} }
catch (...) { catch (...) {
@ -47,7 +58,7 @@ ARDOUR::Port::Port (std::string const & n, DataType t, Flags f, bool e) : _jack_
} }
/** Port destructor */ /** Port destructor */
ARDOUR::Port::~Port () Port::~Port ()
{ {
if (_jack_port) { if (_jack_port) {
jack_port_unregister (_engine->jack (), _jack_port); jack_port_unregister (_engine->jack (), _jack_port);
@ -58,28 +69,27 @@ ARDOUR::Port::~Port ()
* @param t Data type, so that we can call this method from the constructor. * @param t Data type, so that we can call this method from the constructor.
*/ */
void void
ARDOUR::Port::do_make_external (DataType t) Port::do_make_external (DataType t)
{ {
if (_jack_port) { if (_jack_port) {
/* already external */ /* already external */
return; return;
} }
_jack_port = jack_port_register (_engine->jack (), _name.c_str (), t.to_jack_type (), _flags, 0); if ((_jack_port = jack_port_register (_engine->jack (), _name.c_str (), t.to_jack_type (), _flags, 0)) == 0) {
if (_jack_port == 0) {
throw std::runtime_error ("Could not register JACK port"); throw std::runtime_error ("Could not register JACK port");
} }
} }
void void
ARDOUR::Port::make_external () Port::make_external ()
{ {
do_make_external (type ()); do_make_external (type ());
} }
/** @return true if this port is connected to anything */ /** @return true if this port is connected to anything */
bool bool
ARDOUR::Port::connected () const Port::connected () const
{ {
if (!_connections.empty ()) { if (!_connections.empty ()) {
/* connected to a Port* */ /* connected to a Port* */
@ -94,8 +104,20 @@ ARDOUR::Port::connected () const
return (jack_port_connected (_jack_port) != 0); return (jack_port_connected (_jack_port) != 0);
} }
/** @return true if this port is connected to anything via an external port */
bool
Port::externally_connected () const
{
if (_jack_port == 0) {
/* not using a JACK port, so can't be connected to anything else */
return false;
}
return (jack_port_connected (_jack_port) != 0);
}
int int
ARDOUR::Port::disconnect_all () Port::disconnect_all ()
{ {
/* Disconnect from Port* connections */ /* Disconnect from Port* connections */
for (std::set<Port*>::iterator i = _connections.begin (); i != _connections.end (); ++i) { for (std::set<Port*>::iterator i = _connections.begin (); i != _connections.end (); ++i) {
@ -108,6 +130,8 @@ ARDOUR::Port::disconnect_all ()
jack_port_disconnect (_engine->jack(), _jack_port); jack_port_disconnect (_engine->jack(), _jack_port);
_named_connections.clear (); _named_connections.clear ();
check_buffer_status ();
return 0; return 0;
} }
@ -115,7 +139,7 @@ ARDOUR::Port::disconnect_all ()
* @return true if this port is connected to o, otherwise false. * @return true if this port is connected to o, otherwise false.
*/ */
bool bool
ARDOUR::Port::connected_to (std::string const & o) const Port::connected_to (std::string const & o) const
{ {
std::string const full = _engine->make_port_name_non_relative (o); std::string const full = _engine->make_port_name_non_relative (o);
std::string const shrt = _engine->make_port_name_non_relative (o); std::string const shrt = _engine->make_port_name_non_relative (o);
@ -137,7 +161,7 @@ ARDOUR::Port::connected_to (std::string const & o) const
/** @param o Filled in with port full names of ports that we are connected to */ /** @param o Filled in with port full names of ports that we are connected to */
int int
ARDOUR::Port::get_connections (std::vector<std::string> & c) const Port::get_connections (std::vector<std::string> & c) const
{ {
int n = 0; int n = 0;
@ -163,7 +187,7 @@ ARDOUR::Port::get_connections (std::vector<std::string> & c) const
} }
int int
ARDOUR::Port::connect (std::string const & other) Port::connect (std::string const & other)
{ {
/* caller must hold process lock */ /* caller must hold process lock */
@ -197,11 +221,13 @@ ARDOUR::Port::connect (std::string const & other)
} }
} }
check_buffer_status ();
return r; return r;
} }
int int
ARDOUR::Port::disconnect (std::string const & other) Port::disconnect (std::string const & other)
{ {
/* caller must hold process lock */ /* caller must hold process lock */
@ -227,6 +253,8 @@ ARDOUR::Port::disconnect (std::string const & other)
if (r == 0) { if (r == 0) {
_named_connections.erase (other); _named_connections.erase (other);
} }
check_buffer_status ();
} }
return r; return r;
@ -234,13 +262,13 @@ ARDOUR::Port::disconnect (std::string const & other)
bool bool
ARDOUR::Port::connected_to (Port* o) const Port::connected_to (Port* o) const
{ {
return connected_to (o->name ()); return connected_to (o->name ());
} }
int int
ARDOUR::Port::connect (Port* o) Port::connect (Port* o)
{ {
/* caller must hold process lock */ /* caller must hold process lock */
@ -253,11 +281,14 @@ ARDOUR::Port::connect (Port* o)
_connections.insert (o); _connections.insert (o);
o->_connections.insert (this); o->_connections.insert (this);
check_buffer_status ();
o->check_buffer_status ();
return 0; return 0;
} }
int int
ARDOUR::Port::disconnect (Port* o) Port::disconnect (Port* o)
{ {
if (external () && o->external ()) { if (external () && o->external ()) {
/* we're both external; try disconnecting using name */ /* we're both external; try disconnecting using name */
@ -270,17 +301,20 @@ ARDOUR::Port::disconnect (Port* o)
_connections.erase (o); _connections.erase (o);
o->_connections.erase (this); o->_connections.erase (this);
check_buffer_status ();
o->check_buffer_status ();
return 0; return 0;
} }
void void
ARDOUR::Port::set_engine (AudioEngine* e) Port::set_engine (AudioEngine* e)
{ {
_engine = e; _engine = e;
} }
void void
ARDOUR::Port::ensure_monitor_input (bool yn) Port::ensure_monitor_input (bool yn)
{ {
if (_jack_port) { if (_jack_port) {
jack_port_ensure_monitor (_jack_port, yn); jack_port_ensure_monitor (_jack_port, yn);
@ -288,7 +322,7 @@ ARDOUR::Port::ensure_monitor_input (bool yn)
} }
bool bool
ARDOUR::Port::monitoring_input () const Port::monitoring_input () const
{ {
if (_jack_port) { if (_jack_port) {
return jack_port_monitoring_input (_jack_port); return jack_port_monitoring_input (_jack_port);
@ -298,7 +332,7 @@ ARDOUR::Port::monitoring_input () const
} }
void void
ARDOUR::Port::reset () Port::reset ()
{ {
_last_monitor = false; _last_monitor = false;
@ -308,7 +342,7 @@ ARDOUR::Port::reset ()
} }
void void
ARDOUR::Port::recompute_total_latency () const Port::recompute_total_latency () const
{ {
#ifdef HAVE_JACK_RECOMPUTE_LATENCY #ifdef HAVE_JACK_RECOMPUTE_LATENCY
if (_jack_port) { if (_jack_port) {
@ -318,7 +352,7 @@ ARDOUR::Port::recompute_total_latency () const
} }
nframes_t nframes_t
ARDOUR::Port::total_latency () const Port::total_latency () const
{ {
if (_jack_port) { if (_jack_port) {
return jack_port_get_total_latency (_engine->jack (), _jack_port); return jack_port_get_total_latency (_engine->jack (), _jack_port);
@ -328,7 +362,7 @@ ARDOUR::Port::total_latency () const
} }
int int
ARDOUR::Port::reestablish () Port::reestablish ()
{ {
if (!_jack_port) { if (!_jack_port) {
return 0; return 0;
@ -348,7 +382,7 @@ ARDOUR::Port::reestablish ()
int int
ARDOUR::Port::reconnect () Port::reconnect ()
{ {
/* caller must hold process lock; intended to be used only after reestablish() */ /* caller must hold process lock; intended to be used only after reestablish() */
@ -367,7 +401,7 @@ ARDOUR::Port::reconnect ()
/** @param n Short name */ /** @param n Short name */
int int
ARDOUR::Port::set_name (std::string const & n) Port::set_name (std::string const & n)
{ {
assert (_name.find_first_of (':') == std::string::npos); assert (_name.find_first_of (':') == std::string::npos);
@ -386,15 +420,48 @@ ARDOUR::Port::set_name (std::string const & n)
} }
void void
ARDOUR::Port::set_latency (nframes_t n) Port::set_latency (nframes_t n)
{ {
_latency = n; _latency = n;
} }
void void
ARDOUR::Port::request_monitor_input (bool yn) Port::request_monitor_input (bool yn)
{ {
if (_jack_port) { if (_jack_port) {
jack_port_request_monitor (_jack_port, yn); jack_port_request_monitor (_jack_port, yn);
} }
} }
void
Port::check_buffer_status ()
{
if (external() && receives_input()) {
if (!externally_connected()) {
if (!_connections.empty()) {
/* There are no external connections, so the
external port buffer will be the silent buffer. We cannot write into it.
But we have to write somewhere because there is at least one internal
connection that is supplying us with data.
*/
if (!using_internal_data()) {
use_internal_data ();
}
} else {
/* There are no external connections and no internal ones
either, so we can revert to use the externally supplied
buffer which will be silent (whatever the semantics of
that are for a particular data type.
*/
if (using_internal_data()) {
use_external_data ();
}
}
}
}
}

View file

@ -105,13 +105,6 @@ Processor::set_placement (Placement p)
} }
} }
void
Processor::set_active (bool yn)
{
_active = yn;
ActiveChanged ();
}
XMLNode& XMLNode&
Processor::get_state (void) Processor::get_state (void)
{ {

View file

@ -35,6 +35,7 @@
#include <ardour/plugin_insert.h> #include <ardour/plugin_insert.h>
#include <ardour/port_insert.h> #include <ardour/port_insert.h>
#include <ardour/send.h> #include <ardour/send.h>
#include <ardour/internal_send.h>
#include <ardour/session.h> #include <ardour/session.h>
#include <ardour/utils.h> #include <ardour/utils.h>
#include <ardour/configuration.h> #include <ardour/configuration.h>
@ -1229,6 +1230,11 @@ Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorStreams*
int int
Route::add_processors (const ProcessorList& others, ProcessorStreams* err) Route::add_processors (const ProcessorList& others, ProcessorStreams* err)
{ {
/* NOTE: this is intended to be used ONLY when copying
processors from another Route. Hence the subtle
differences between this and ::add_processor()
*/
ChanCount old_pmo = processor_max_outs; ChanCount old_pmo = processor_max_outs;
if (!_session.engine().connected()) { if (!_session.engine().connected()) {
@ -1292,7 +1298,7 @@ Route::disable_processors (Placement p)
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
if ((*i)->placement() == p) { if ((*i)->placement() == p) {
(*i)->set_active (false); (*i)->deactivate ();
} }
} }
@ -1308,7 +1314,7 @@ Route::disable_processors ()
Glib::RWLock::ReaderLock lm (_processor_lock); Glib::RWLock::ReaderLock lm (_processor_lock);
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
(*i)->set_active (false); (*i)->deactivate ();
} }
_session.set_dirty (); _session.set_dirty ();
@ -1325,7 +1331,7 @@ Route::disable_plugins (Placement p)
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
if (boost::dynamic_pointer_cast<PluginInsert> (*i) && (*i)->placement() == p) { if (boost::dynamic_pointer_cast<PluginInsert> (*i) && (*i)->placement() == p) {
(*i)->set_active (false); (*i)->deactivate ();
} }
} }
@ -1342,7 +1348,7 @@ Route::disable_plugins ()
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
if (boost::dynamic_pointer_cast<PluginInsert> (*i)) { if (boost::dynamic_pointer_cast<PluginInsert> (*i)) {
(*i)->set_active (false); (*i)->deactivate ();
} }
} }
@ -1367,7 +1373,7 @@ Route::ab_plugins (bool forward)
} }
if ((*i)->active()) { if ((*i)->active()) {
(*i)->set_active (false); (*i)->deactivate ();
(*i)->set_next_ab_is_active (true); (*i)->set_next_ab_is_active (true);
} else { } else {
(*i)->set_next_ab_is_active (false); (*i)->set_next_ab_is_active (false);
@ -1385,9 +1391,9 @@ Route::ab_plugins (bool forward)
} }
if ((*i)->get_next_ab_is_active()) { if ((*i)->get_next_ab_is_active()) {
(*i)->set_active (true); (*i)->activate ();
} else { } else {
(*i)->set_active (false); (*i)->deactivate ();
} }
} }
} }
@ -1602,9 +1608,11 @@ Route::_reset_processor_counts (ProcessorStreams* err)
} else if (boost::dynamic_pointer_cast<Send> (*r) != 0) { } else if (boost::dynamic_pointer_cast<Send> (*r) != 0) {
++send_cnt; ++send_cnt;
} else if (boost::dynamic_pointer_cast<InternalSend> (*r) != 0) {
++send_cnt;
} }
} }
if (insert_cnt == 0) { if (insert_cnt == 0) {
if (send_cnt) { if (send_cnt) {
goto recompute; goto recompute;
@ -1665,20 +1673,32 @@ Route::_reset_processor_counts (ProcessorStreams* err)
for (r = _processors.begin(); r != _processors.end(); prev = r, ++r) { for (r = _processors.begin(); r != _processors.end(); prev = r, ++r) {
boost::shared_ptr<Send> s; boost::shared_ptr<Send> s;
boost::shared_ptr<InternalSend> is;
if ((s = boost::dynamic_pointer_cast<Send> (*r)) != 0) { if ((s = boost::dynamic_pointer_cast<Send> (*r)) != 0) {
/* don't pay any attention to send output configuration, since it doesn't
affect the route.
*/
if (r == _processors.begin()) { if (r == _processors.begin()) {
s->expect_inputs (n_inputs()); s->expect_inputs (n_inputs());
} else { } else {
s->expect_inputs ((*prev)->output_streams()); s->expect_inputs ((*prev)->output_streams());
} }
} else if ((is = boost::dynamic_pointer_cast<InternalSend> (*r)) != 0) {
/* XXX ditto, but clean this inheritance pattern up someday soon */
if (r == _processors.begin()) {
is->expect_inputs (n_inputs());
} else {
is->expect_inputs ((*prev)->output_streams());
}
} else { } else {
/* don't pay any attention to send output configuration, since it doesn't
affect the route.
*/
max_audio = max ((*r)->output_streams ().n_audio(), max_audio); max_audio = max ((*r)->output_streams ().n_audio(), max_audio);
max_midi = max ((*r)->output_streams ().n_midi(), max_midi); max_midi = max ((*r)->output_streams ().n_midi(), max_midi);
} }
@ -1711,8 +1731,6 @@ Route::apply_some_processor_counts (list<ProcessorCount>& iclist)
ProcessorCount& pc (*i); ProcessorCount& pc (*i);
cerr << "now applying for " << (*i).processor->name() << " in = " << pc.in.n_audio() << " out = " << pc.out.n_audio() << endl;
if (pc.processor->configure_io (pc.in, pc.out)) { if (pc.processor->configure_io (pc.in, pc.out)) {
return -1; return -1;
} }
@ -1743,8 +1761,6 @@ Route::check_some_processor_counts (list<ProcessorCount>& iclist, ChanCount requ
for (i = iclist.begin(); i != iclist.end(); ++i, ++index) { for (i = iclist.begin(); i != iclist.end(); ++i, ++index) {
cerr << "Checking whether " << (*i).processor->name() << " can support " << required_inputs.n_audio() << " inputs\n";
if (!(*i).processor->can_support_io_configuration (required_inputs, (*i).out)) { if (!(*i).processor->can_support_io_configuration (required_inputs, (*i).out)) {
if (err) { if (err) {
err->index = index; err->index = index;
@ -1853,7 +1869,11 @@ Route::all_processors_flip ()
bool first_is_on = _processors.front()->active(); bool first_is_on = _processors.front()->active();
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
(*i)->set_active (!first_is_on); if (first_is_on) {
(*i)->deactivate ();
} else {
(*i)->activate ();
}
} }
_session.set_dirty (); _session.set_dirty ();
@ -1874,7 +1894,11 @@ Route::all_processors_active (Placement p, bool state)
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
if ((*i)->placement() == p) { if ((*i)->placement() == p) {
(*i)->set_active (state); if (state) {
(*i)->activate ();
} else {
(*i)->deactivate ();
}
} }
} }

View file

@ -140,7 +140,7 @@ Send::set_state(const XMLNode& node)
if ((*niter)->name() == "IOProcessor") { if ((*niter)->name() == "IOProcessor") {
insert_node = *niter; insert_node = *niter;
} else if ((*niter)->name() == X_("Automation")) { } else if ((*niter)->name() == X_("Automation")) {
_io->set_automation_state (*(*niter), Evoral::Parameter(GainAutomation)); // _io->set_automation_state (*(*niter), Evoral::Parameter(GainAutomation));
} }
} }
@ -165,10 +165,10 @@ Send::run_in_place (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame,
_io->deliver_output (sendbufs, start_frame, end_frame, nframes, offset); _io->deliver_output (sendbufs, start_frame, end_frame, nframes, offset);
if (_metering) { if (_metering) {
if (_io->_gain == 0) { if (_io->effective_gain() == 0) {
_io->_meter->reset(); _io->peak_meter().reset();
} else { } else {
_io->_meter->run_in_place(_io->output_buffers(), start_frame, end_frame, nframes, offset); _io->peak_meter().run_in_place(_io->output_buffers(), start_frame, end_frame, nframes, offset);
} }
} }
@ -176,7 +176,7 @@ Send::run_in_place (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame,
_io->silence (nframes, offset); _io->silence (nframes, offset);
if (_metering) { if (_metering) {
_io->_meter->reset(); _io->peak_meter().reset();
} }
} }
} }

View file

@ -72,6 +72,7 @@
#include <ardour/named_selection.h> #include <ardour/named_selection.h>
#include <ardour/crossfade.h> #include <ardour/crossfade.h>
#include <ardour/playlist.h> #include <ardour/playlist.h>
#include <ardour/internal_send.h>
#include <ardour/click.h> #include <ardour/click.h>
#include <ardour/data_type.h> #include <ardour/data_type.h>
#include <ardour/buffer_set.h> #include <ardour/buffer_set.h>
@ -1822,7 +1823,7 @@ Session::set_remote_control_ids ()
} }
Session::RouteList RouteList
Session::new_audio_route (int input_channels, int output_channels, uint32_t how_many) Session::new_audio_route (int input_channels, int output_channels, uint32_t how_many)
{ {
char bus_name[32]; char bus_name[32];
@ -3685,6 +3686,8 @@ Session::add_processor (Processor* processor)
_plugin_inserts.insert (_plugin_inserts.begin(), plugin_insert); _plugin_inserts.insert (_plugin_inserts.begin(), plugin_insert);
} else if ((send = dynamic_cast<Send *> (processor)) != 0) { } else if ((send = dynamic_cast<Send *> (processor)) != 0) {
_sends.insert (_sends.begin(), send); _sends.insert (_sends.begin(), send);
} else if (dynamic_cast<InternalSend *> (processor) != 0) {
/* relax */
} else { } else {
fatal << _("programming error: unknown type of Insert created!") << endmsg; fatal << _("programming error: unknown type of Insert created!") << endmsg;
/*NOTREACHED*/ /*NOTREACHED*/
@ -3710,6 +3713,8 @@ Session::remove_processor (Processor* processor)
} }
} else if ((plugin_insert = dynamic_cast<PluginInsert *> (processor)) != 0) { } else if ((plugin_insert = dynamic_cast<PluginInsert *> (processor)) != 0) {
_plugin_inserts.remove (plugin_insert); _plugin_inserts.remove (plugin_insert);
} else if (dynamic_cast<InternalSend *> (processor) != 0) {
/* relax */
} else if ((send = dynamic_cast<Send *> (processor)) != 0) { } else if ((send = dynamic_cast<Send *> (processor)) != 0) {
list<Send*>::iterator x = find (_sends.begin(), _sends.end(), send); list<Send*>::iterator x = find (_sends.begin(), _sends.end(), send);
if (x != _sends.end()) { if (x != _sends.end()) {

View file

@ -151,14 +151,22 @@ PixFader::on_button_release_event (GdkEventButton* ev)
/* no motion - just a click */ /* no motion - just a click */
if (ev->state & Gdk::SHIFT_MASK) { if (ev->state & Gdk::SHIFT_MASK) {
cerr << "SV A\n";
adjustment.set_value (default_value); adjustment.set_value (default_value);
cerr << "SV A OUT\n";
} else if (ev->state & fine_scale_modifier) { } else if (ev->state & fine_scale_modifier) {
cerr << "SV B\n";
adjustment.set_value (adjustment.get_lower()); adjustment.set_value (adjustment.get_lower());
cerr << "SV B OUT\n";
} else if ((_orien == VERT && ev_pos < span - display_span()) || (_orien == HORIZ && ev_pos > span - display_span())) { } else if ((_orien == VERT && ev_pos < span - display_span()) || (_orien == HORIZ && ev_pos > span - display_span())) {
/* above the current display height, remember X Window coords */ /* above the current display height, remember X Window coords */
cerr << "SV C\n";
adjustment.set_value (adjustment.get_value() + adjustment.get_step_increment()); adjustment.set_value (adjustment.get_value() + adjustment.get_step_increment());
cerr << "SV C OUT\n";
} else { } else {
cerr << "SV D\n";
adjustment.set_value (adjustment.get_value() - adjustment.get_step_increment()); adjustment.set_value (adjustment.get_value() - adjustment.get_step_increment());
cerr << "SV D OUT\n";
} }
} }

View file

@ -54,6 +54,8 @@ xml++.cc
conf = Configure(pbd) conf = Configure(pbd)
if conf.CheckFunc('getmntent'): if conf.CheckFunc('getmntent'):
conf.env.Append(CCFLAGS="-DHAVE_GETMNTENT") conf.env.Append(CCFLAGS="-DHAVE_GETMNTENT")
if conf.CheckCHeader('execinfo.h'):
conf.env.Append(CXXFLAGS="-DHAVE_EXECINFO")
pbd = conf.Finish() pbd = conf.Finish()
pbd.Merge ([ libraries['sigc2'], pbd.Merge ([ libraries['sigc2'],

View file

@ -30,7 +30,6 @@ PBD::trace_twb ()
#ifdef HAVE_EXECINFO #ifdef HAVE_EXECINFO
#include <execinfo.h> #include <execinfo.h>
#include <cstdlib>
void void
PBD::stacktrace (std::ostream& out, int levels) PBD::stacktrace (std::ostream& out, int levels)

View file

@ -218,7 +218,7 @@ MackieControlProtocol::Sorted MackieControlProtocol::get_sorted_routes()
Sorted sorted; Sorted sorted;
// fetch all routes // fetch all routes
boost::shared_ptr<Session::RouteList> routes = session->get_routes(); boost::shared_ptr<RouteList> routes = session->get_routes();
set<uint32_t> remote_ids; set<uint32_t> remote_ids;
// routes with remote_id 0 should never be added // routes with remote_id 0 should never be added
@ -227,7 +227,7 @@ MackieControlProtocol::Sorted MackieControlProtocol::get_sorted_routes()
// sort in remote_id order, and exclude master, control and hidden routes // sort in remote_id order, and exclude master, control and hidden routes
// and any routes that are already set. // and any routes that are already set.
for ( Session::RouteList::iterator it = routes->begin(); it != routes->end(); ++it ) for (RouteList::iterator it = routes->begin(); it != routes->end(); ++it )
{ {
Route & route = **it; Route & route = **it;
if ( if (
@ -1460,7 +1460,7 @@ void MackieControlProtocol::notify_parameter_changed( const char * name_str )
} }
// RouteList is the set of routes that have just been added // RouteList is the set of routes that have just been added
void MackieControlProtocol::notify_route_added( ARDOUR::Session::RouteList & rl ) void MackieControlProtocol::notify_route_added( ARDOUR::RouteList & rl )
{ {
// currently assigned banks are less than the full set of // currently assigned banks are less than the full set of
// strips, so activate the new strip now. // strips, so activate the new strip now.
@ -1471,7 +1471,7 @@ void MackieControlProtocol::notify_route_added( ARDOUR::Session::RouteList & rl
// otherwise route added, but current bank needs no updating // otherwise route added, but current bank needs no updating
// make sure remote id changes in the new route are handled // make sure remote id changes in the new route are handled
typedef ARDOUR::Session::RouteList ARS; typedef ARDOUR::RouteList ARS;
for ( ARS::iterator it = rl.begin(); it != rl.end(); ++it ) for ( ARS::iterator it = rl.begin(); it != rl.end(); ++it )
{ {
connections_back = (*it)->RemoteControlIDChanged.connect( ( mem_fun (*this, &MackieControlProtocol::notify_remote_id_changed) ) ); connections_back = (*it)->RemoteControlIDChanged.connect( ( mem_fun (*this, &MackieControlProtocol::notify_remote_id_changed) ) );

View file

@ -102,7 +102,7 @@ class MackieControlProtocol
/// Signal handler from Panner::Change /// Signal handler from Panner::Change
void notify_panner_changed( Mackie::RouteSignal *, bool force_update = true ); void notify_panner_changed( Mackie::RouteSignal *, bool force_update = true );
/// Signal handler for new routes added /// Signal handler for new routes added
void notify_route_added( ARDOUR::Session::RouteList & ); void notify_route_added( ARDOUR::RouteList & );
/// Signal handler for Route::active_changed /// Signal handler for Route::active_changed
void notify_active_changed( Mackie::RouteSignal * ); void notify_active_changed( Mackie::RouteSignal * );

View file

@ -43,6 +43,7 @@
#include <ardour/filesystem_paths.h> #include <ardour/filesystem_paths.h>
#include "osc.h" #include "osc.h"
#include "osc_controllable.h"
#include "i18n.h" #include "i18n.h"
using namespace ARDOUR; using namespace ARDOUR;
@ -74,7 +75,7 @@ OSC::OSC (Session& s, uint32_t port)
/* catch up with existing routes */ /* catch up with existing routes */
boost::shared_ptr<Session::RouteList> rl = session->get_routes (); boost::shared_ptr<RouteList> rl = session->get_routes ();
route_added (*(rl.get())); route_added (*(rl.get()));
// session->RouteAdded.connect (mem_fun (*this, &OSC::route_added)); // session->RouteAdded.connect (mem_fun (*this, &OSC::route_added));
@ -562,29 +563,23 @@ OSC::catchall (const char *path, const char *types, lo_arg **argv, int argc, lo_
lo_message reply = lo_message_new (); lo_message reply = lo_message_new ();
if (argc > 0) { if (argc <= 0) {
int id = argv[0]->i;
boost::shared_ptr<Route> r = session->route_by_remote_id (id);
if (!r) {
lo_message_add_string (reply, "not found");
cerr << "no such route\n";
} else {
ListenerPair listener;
listener.first = r.get();
listener.second = lo_message_get_source (msg);
cerr << "add listener\n";
listen_to_route (listener);
lo_message_add_string (reply, "0");
}
} else {
lo_message_add_string (reply, "syntax error"); lo_message_add_string (reply, "syntax error");
} else {
for (int n = 0; n < argc; ++n) {
boost::shared_ptr<Route> r = session->route_by_remote_id (argv[n]->i);
if (!r) {
lo_message_add_string (reply, "not found");
cerr << "no such route\n";
break;
} else {
cerr << "add listener\n";
listen_to_route (r, lo_message_get_source (msg));
lo_message_add_int32 (reply, argv[n]->i);
}
}
} }
lo_send_message (lo_message_get_source (msg), "#reply", reply); lo_send_message (lo_message_get_source (msg), "#reply", reply);
@ -592,17 +587,12 @@ OSC::catchall (const char *path, const char *types, lo_arg **argv, int argc, lo_
} else if (strcmp (path, "/routes/ignore") == 0) { } else if (strcmp (path, "/routes/ignore") == 0) {
if (argc > 0) { for (int n = 0; n < argc; ++n) {
int id = argv[0]->i;
boost::shared_ptr<Route> r = session->route_by_remote_id (id); boost::shared_ptr<Route> r = session->route_by_remote_id (argv[n]->i);
if (r) { if (r) {
ListenerPair listener; end_listen (r, lo_message_get_source (msg));
listener.first = r.get();
listener.second = lo_message_get_source (msg);
drop_listener_pair (listener);
} }
} }
} }
@ -611,55 +601,86 @@ OSC::catchall (const char *path, const char *types, lo_arg **argv, int argc, lo_
} }
void void
OSC::route_added (Session::RouteList& rl) OSC::route_added (RouteList& rl)
{ {
} }
void void
OSC::listen_to_route (const ListenerPair& lp) OSC::listen_to_route (boost::shared_ptr<Route> route, lo_address addr)
{ {
Listeners::iterator x; Controllables::iterator x;
bool route_exists = false; bool route_exists = false;
cerr << "listen to route\n"; cerr << "listen to route\n";
/* check existing listener pairs to avoid duplicate listens */ /* avoid duplicate listens */
for (x = controllables.begin(); x != controllables.end(); ++x) {
OSCRouteControllable* rc;
for (x = listeners.begin(); x != listeners.end(); ++x) { if ((rc = dynamic_cast<OSCRouteControllable*>(*x)) != 0) {
if ((*x)->route == lp.first) { if (rc->route() == route) {
route_exists = true; route_exists = true;
if ((*x)->addr == lp.second ) { /* XXX NEED lo_address_equal() */
return;
if (rc->address() == addr) {
return;
}
} }
} }
} }
Listener* l = new Listener (lp.first, lp.second);
cerr << "listener binding to signals\n"; cerr << "listener binding to signals\n";
l->connections.push_back (lp.first->solo_changed.connect (bind (mem_fun (*this, &OSC::route_changed), RouteSolo, lp.first, lp.second))); OSCControllable* c;
l->connections.push_back (lp.first->mute_changed.connect (bind (mem_fun (*this, &OSC::route_changed), RouteMute, lp.first, lp.second))); string path;
l->connections.push_back (lp.first->gain_control()->Changed.connect (bind (mem_fun (*this, &OSC::route_changed_deux), RouteGain, lp.first, lp.second)));
path = X_("/route/solo");
c = new OSCRouteControllable (addr, path, route->solo_control(), route);
controllables.push_back (c);
path = X_("/route/mute");
c = new OSCRouteControllable (addr, path, route->mute_control(), route);
controllables.push_back (c);
path = X_("/route/gain");
c = new OSCRouteControllable (addr, path, route->gain_control(), route);
controllables.push_back (c);
cerr << "Now have " << controllables.size() << " controllables\n";
/* if there is no existing controllable related to this route, make sure we clean up
if it is ever deleted.
*/
if (!route_exists) { if (!route_exists) {
l->route->GoingAway.connect (bind (mem_fun (*this, &OSC::drop_listeners_by_route), l->route)); route->GoingAway.connect (bind (mem_fun (*this, &OSC::drop_route), boost::weak_ptr<Route> (route)));
} }
listeners.push_back (l);
} }
void void
OSC::drop_listeners_by_route (Route* r) OSC::drop_route (boost::weak_ptr<Route> wr)
{ {
Listeners::iterator x; boost::shared_ptr<Route> r = wr.lock ();
for (x = listeners.begin(); x != listeners.end();) { if (!r) {
if ((*x)->route == r) { return;
delete *x; }
x = listeners.erase (x);
for (Controllables::iterator x = controllables.begin(); x != controllables.end();) {
OSCRouteControllable* rc;
if ((rc = dynamic_cast<OSCRouteControllable*>(*x)) != 0) {
if (rc->route() == r) {
delete *x;
x = controllables.erase (x);
} else {
++x;
}
} else { } else {
++x; ++x;
} }
@ -667,14 +688,22 @@ OSC::drop_listeners_by_route (Route* r)
} }
void void
OSC::drop_listener_pair (const ListenerPair& lp) OSC::end_listen (boost::shared_ptr<Route> r, lo_address addr)
{ {
Listeners::iterator x; Controllables::iterator x;
for (x = listeners.begin(); x != listeners.end(); ++x) { for (x = controllables.begin(); x != controllables.end(); ++x) {
if ((*x)->route == lp.first && (*x)->addr == lp.second) {
listeners.erase (x); OSCRouteControllable* rc;
return;
if ((rc = dynamic_cast<OSCRouteControllable*>(*x)) != 0) {
/* XXX NEED lo_address_equal () */
if (rc->route() == r && rc->address() == addr) {
controllables.erase (x);
return;
}
} }
} }
} }
@ -692,61 +721,6 @@ OSC::session_exported( std::string path, std::string name ) {
lo_send( listener, "/session/exported", "ss", path.c_str(), name.c_str() ); lo_send( listener, "/session/exported", "ss", path.c_str(), name.c_str() );
} }
void
OSC::set_send_route_changes (bool yn)
{
_send_route_changes = yn;
}
void
OSC::route_changed (void* src, RouteChangeType what, Route* r, lo_address addr)
{
route_changed_deux (what, r, addr);
}
void
OSC::route_changed_deux (RouteChangeType what, Route* r, lo_address addr)
{
if (!_send_route_changes) {
return;
}
string prefix = _namespace_root;
int ret;
switch (what) {
case OSC::RouteSolo:
prefix += "/changed/route/solo";
ret = lo_send (addr, prefix.c_str(), "ii", r->remote_control_id(), (int) r->soloed());
break;
case OSC::RouteMute:
prefix += "/changed/route/mute";
ret = lo_send (addr, prefix.c_str(), "ii", r->remote_control_id(), (int) r->muted());
break;
case OSC::RouteGain:
prefix += "/changed/route/gain";
ret = lo_send (addr, prefix.c_str(), "if", r->remote_control_id(), r->effective_gain());
default:
error << "OSC: unhandled route change\n";
return;
}
if (ret < 0) {
ListenerPair lp;
lp.first = r;
lp.second = addr;
cerr << "Error sending to listener ... dropping\n";
drop_listener_pair (lp);
}
}
// end "Application Hook" Handlers // // end "Application Hook" Handlers //
/* path callbacks */ /* path callbacks */

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2006 Paul Davis * Copyright (C) 2006-2009 Paul Davis
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -25,6 +25,8 @@
#include <sys/time.h> #include <sys/time.h>
#include <pthread.h> #include <pthread.h>
#include <boost/shared_ptr.hpp>
#include <lo/lo.h> #include <lo/lo.h>
#include <sigc++/sigc++.h> #include <sigc++/sigc++.h>
@ -33,15 +35,17 @@
#include <ardour/session.h> #include <ardour/session.h>
#include <control_protocol/control_protocol.h> #include <control_protocol/control_protocol.h>
namespace ARDOUR { class OSCControllable;
namespace ARDOUR {
class Session; class Session;
class Route; class Route;
}
class OSC : public ControlProtocol class OSC : public ARDOUR::ControlProtocol
{ {
public: public:
OSC (Session&, uint32_t port); OSC (ARDOUR::Session&, uint32_t port);
virtual ~OSC(); virtual ~OSC();
XMLNode& get_state (); XMLNode& get_state ();
@ -53,8 +57,6 @@ class OSC : public ControlProtocol
bool get_feedback () const; bool get_feedback () const;
void set_namespace_root (std::string); void set_namespace_root (std::string);
bool send_route_changes () const { return _send_route_changes; }
void set_send_route_changes (bool yn);
int start (); int start ();
int stop (); int stop ();
@ -82,21 +84,12 @@ class OSC : public ControlProtocol
void register_callbacks (); void register_callbacks ();
void route_added (ARDOUR::Session::RouteList&); void route_added (ARDOUR::RouteList&);
// Handlers for "Application Hook" signals // Handlers for "Application Hook" signals
void session_loaded (ARDOUR::Session&); void session_loaded (ARDOUR::Session&);
void session_exported (std::string, std::string); void session_exported (std::string, std::string);
enum RouteChangeType {
RouteSolo,
RouteMute,
RouteGain
};
void route_changed (void* ignored, RouteChangeType, ARDOUR::Route*, lo_address);
void route_changed_deux (RouteChangeType, ARDOUR::Route*, lo_address);
// end "Application Hook" handles // end "Application Hook" handles
std::string get_server_url (); std::string get_server_url ();
@ -173,24 +166,13 @@ class OSC : public ControlProtocol
int route_set_gain_abs (int rid, float level); int route_set_gain_abs (int rid, float level);
int route_set_gain_dB (int rid, float dB); int route_set_gain_dB (int rid, float dB);
struct Listener { void listen_to_route (boost::shared_ptr<ARDOUR::Route>, lo_address);
Route* route; void end_listen (boost::shared_ptr<ARDOUR::Route>, lo_address);
lo_address addr; void drop_route (boost::weak_ptr<ARDOUR::Route>);
std::vector<sigc::connection> connections;
Listener (Route* r, lo_address a) : route (r), addr (a) {} typedef std::list<OSCControllable*> Controllables;
};
typedef std::pair<Route*, lo_address> ListenerPair; Controllables controllables;
typedef std::list<Listener*> Listeners;
Listeners listeners;
void listen_to_route (const ListenerPair&);
void drop_listener_pair (const ListenerPair&);
void drop_listeners_by_route (Route*);
}; };
}
#endif // ardour_osc_h #endif // ardour_osc_h

View file

@ -22,16 +22,20 @@
#include <pbd/error.h> #include <pbd/error.h>
#include <pbd/xml++.h> #include <pbd/xml++.h>
#include <ardour/route.h>
#include "osc_controllable.h" #include "osc_controllable.h"
using namespace sigc; using namespace sigc;
using namespace PBD; using namespace PBD;
using namespace ARDOUR; using namespace ARDOUR;
OSCControllable::OSCControllable (lo_address a, Controllable& c) OSCControllable::OSCControllable (lo_address a, const string& p, boost::shared_ptr<Controllable> c)
: controllable (c) : controllable (c)
, addr (a) , addr (a)
, path (p)
{ {
c->Changed.connect (mem_fun (*this, &OSCControllable::send_change));
} }
OSCControllable::~OSCControllable () OSCControllable::~OSCControllable ()
@ -42,7 +46,7 @@ OSCControllable::~OSCControllable ()
XMLNode& XMLNode&
OSCControllable::get_state () OSCControllable::get_state ()
{ {
XMLNode& root (controllable.get_state()); XMLNode& root (controllable->get_state());
return root; return root;
} }
@ -52,3 +56,43 @@ OSCControllable::set_state (const XMLNode& node)
return 0; return 0;
} }
void
OSCControllable::send_change ()
{
lo_message msg = lo_message_new ();
lo_message_add_float (msg, (float) controllable->get_value());
/* XXX thread issues */
lo_send_message (addr, path.c_str(), msg);
lo_message_free (msg);
}
/*------------------------------------------------------------*/
OSCRouteControllable::OSCRouteControllable (lo_address a, const string& p,
boost::shared_ptr<Controllable> c, boost::shared_ptr<Route> r)
: OSCControllable (a, p, c)
, _route (r)
{
}
OSCRouteControllable::~OSCRouteControllable ()
{
}
void
OSCRouteControllable::send_change ()
{
lo_message msg = lo_message_new ();
lo_message_add_int32 (msg, _route->remote_control_id());
lo_message_add_float (msg, (float) controllable->get_value());
/* XXX thread issues */
cerr << "ORC: send " << path << " = " << controllable->get_value() << endl;
lo_send_message (addr, path.c_str(), msg);
lo_message_free (msg);
}

View file

@ -1,5 +1,5 @@
/* /*
Copyright (C) 1998-2006 Paul Davis Copyright (C) 2009 Paul Davis
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -21,7 +21,7 @@
#define __osc_osccontrollable_h__ #define __osc_osccontrollable_h__
#include <string> #include <string>
#include <boost/shared_ptr.hpp>
#include <sigc++/sigc++.h> #include <sigc++/sigc++.h>
#include <lo/lo.h> #include <lo/lo.h>
@ -29,18 +29,46 @@
#include <pbd/stateful.h> #include <pbd/stateful.h>
#include <ardour/types.h> #include <ardour/types.h>
namespace ARDOUR {
class Route;
}
class OSCControllable : public PBD::Stateful class OSCControllable : public PBD::Stateful
{ {
public: public:
OSCControllable (lo_address addr, PBD::Controllable&); OSCControllable (lo_address addr, const string& path, boost::shared_ptr<PBD::Controllable>);
virtual ~OSCControllable (); virtual ~OSCControllable ();
lo_address address() const { return addr; }
XMLNode& get_state (); XMLNode& get_state ();
int set_state (const XMLNode& node); int set_state (const XMLNode& node);
private: protected:
PBD::Controllable& controllable; boost::shared_ptr<PBD::Controllable> controllable;
lo_address addr; lo_address addr;
string path;
virtual void send_change ();
};
class OSCRouteControllable : public OSCControllable
{
public:
OSCRouteControllable (lo_address addr, const string& path,
boost::shared_ptr<PBD::Controllable>,
boost::shared_ptr<ARDOUR::Route>);
~OSCRouteControllable ();
boost::shared_ptr<ARDOUR::Route> route() const { return _route; }
private:
boost::shared_ptr<ARDOUR::Route> _route;
void send_change ();
}; };
#endif /* __osc_osccontrollable_h__ */ #endif /* __osc_osccontrollable_h__ */