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:
parent
ee62ee07d3
commit
70b939da4f
|
@ -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)
|
||||
{
|
||||
list<boost::shared_ptr<AudioTrack> > tracks;
|
||||
Session::RouteList routes;
|
||||
RouteList routes;
|
||||
|
||||
if (session == 0) {
|
||||
warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
|
||||
|
|
|
@ -595,7 +595,7 @@ class Editor : public PublicEditor
|
|||
|
||||
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 *);
|
||||
bool route_removal;
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ using namespace Glib;
|
|||
const char* _order_key = N_("editor");
|
||||
|
||||
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));
|
||||
|
||||
|
@ -60,7 +60,7 @@ Editor::handle_new_route (Session::RouteList& routes)
|
|||
route_redisplay_does_not_sync_order_keys = 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);
|
||||
|
||||
if (route->is_hidden()) {
|
||||
|
@ -592,8 +592,8 @@ struct EditorOrderRouteSorter {
|
|||
void
|
||||
Editor::initial_route_list_display ()
|
||||
{
|
||||
boost::shared_ptr<Session::RouteList> routes = session->get_routes();
|
||||
Session::RouteList r (*routes);
|
||||
boost::shared_ptr<RouteList> routes = session->get_routes();
|
||||
RouteList r (*routes);
|
||||
EditorOrderRouteSorter sorter;
|
||||
|
||||
r.sort (sorter);
|
||||
|
|
|
@ -105,14 +105,14 @@ void
|
|||
PortExportChannelSelector::fill_route_list ()
|
||||
{
|
||||
channel_view.clear_routes ();
|
||||
Session::RouteList routes = *session->get_routes();
|
||||
RouteList routes = *session->get_routes();
|
||||
|
||||
/* Add master bus and then everything else */
|
||||
|
||||
ARDOUR::IO * master = session->master_out().get();
|
||||
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) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include <gtkmm2ext/gtk_ui.h>
|
||||
#include <midi++/manager.h>
|
||||
#include <pbd/fastlog.h>
|
||||
#include <pbd/stacktrace.h>
|
||||
|
||||
#include "ardour_ui.h"
|
||||
#include "gain_meter.h"
|
||||
|
@ -160,6 +161,8 @@ GainMeterBase::~GainMeterBase ()
|
|||
void
|
||||
GainMeterBase::set_io (boost::shared_ptr<IO> io)
|
||||
{
|
||||
cerr << this << " Clear all connections\n";
|
||||
|
||||
connections.clear ();
|
||||
|
||||
_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)));
|
||||
|
||||
gain_changed ();
|
||||
|
@ -371,8 +376,11 @@ GainMeterBase::show_gain ()
|
|||
void
|
||||
GainMeterBase::gain_adjusted ()
|
||||
{
|
||||
cerr << this << " for " << _io->name() << " GAIN ADJUSTED\n";
|
||||
if (!ignore_toggle) {
|
||||
cerr << "Set GC\n";
|
||||
_io->gain_control()->set_value (slider_position_to_gain (gain_adjustment.get_value()));
|
||||
cerr << "Set GC OUT\n";
|
||||
}
|
||||
show_gain ();
|
||||
}
|
||||
|
@ -382,6 +390,9 @@ GainMeterBase::effective_gain_display ()
|
|||
{
|
||||
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) {
|
||||
ignore_toggle = true;
|
||||
gain_adjustment.set_value (value);
|
||||
|
|
|
@ -297,7 +297,7 @@ Mixer_UI::hide_window (GdkEventAny *ev)
|
|||
|
||||
|
||||
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));
|
||||
|
||||
|
@ -306,7 +306,7 @@ Mixer_UI::add_strip (Session::RouteList& routes)
|
|||
no_track_list_redisplay = 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);
|
||||
|
||||
if (route->is_hidden()) {
|
||||
|
@ -885,8 +885,8 @@ struct SignalOrderRouteSorter {
|
|||
void
|
||||
Mixer_UI::initial_track_display ()
|
||||
{
|
||||
boost::shared_ptr<Session::RouteList> routes = session->get_routes();
|
||||
Session::RouteList copy (*routes);
|
||||
boost::shared_ptr<RouteList> routes = session->get_routes();
|
||||
RouteList copy (*routes);
|
||||
SignalOrderRouteSorter sorter;
|
||||
|
||||
copy.sort (sorter);
|
||||
|
|
|
@ -120,7 +120,7 @@ class Mixer_UI : public Gtk::Window
|
|||
|
||||
bool strip_scroller_button_release (GdkEventButton*);
|
||||
|
||||
void add_strip (ARDOUR::Session::RouteList&);
|
||||
void add_strip (ARDOUR::RouteList&);
|
||||
void remove_strip (MixerStrip *);
|
||||
|
||||
void hide_all_strips (bool with_select);
|
||||
|
|
|
@ -429,7 +429,11 @@ PlugUIBase::bypass_toggled ()
|
|||
bool x;
|
||||
|
||||
if ((x = bypass_button.get_active()) == insert->active()) {
|
||||
insert->set_active (!x);
|
||||
if (x) {
|
||||
insert->deactivate ();
|
||||
} else {
|
||||
insert->activate ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -142,9 +142,9 @@ PortGroupList::gather (ARDOUR::Session& session)
|
|||
/* Find the bundles for routes. We take their bundles, copy them,
|
||||
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 */
|
||||
boost::shared_ptr<ARDOUR::Bundle> bundle (
|
||||
new ARDOUR::Bundle (
|
||||
|
|
|
@ -89,8 +89,8 @@ PortMatrix::routes_changed ()
|
|||
i->disconnect ();
|
||||
}
|
||||
|
||||
boost::shared_ptr<ARDOUR::Session::RouteList> routes = _session.get_routes ();
|
||||
for (ARDOUR::Session::RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
|
||||
boost::shared_ptr<ARDOUR::RouteList> routes = _session.get_routes ();
|
||||
for (ARDOUR::RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
|
||||
_route_connections.push_back (
|
||||
(*i)->processors_changed.connect (sigc::mem_fun (*this, &PortMatrix::setup))
|
||||
);
|
||||
|
|
|
@ -342,7 +342,11 @@ ProcessorBox::processor_button_release_event (GdkEventButton *ev)
|
|||
|
||||
/* button2-click with no modifiers */
|
||||
|
||||
processor->set_active (!processor->active());
|
||||
if (processor->active()) {
|
||||
processor->deactivate ();
|
||||
} else {
|
||||
processor->activate ();
|
||||
}
|
||||
ret = true;
|
||||
|
||||
}
|
||||
|
@ -396,7 +400,7 @@ ProcessorBox::use_plugins (const SelectedPlugins& plugins)
|
|||
Route::ProcessorStreams err_streams;
|
||||
|
||||
if (Config->get_new_plugins_active()) {
|
||||
processor->set_active (true);
|
||||
processor->activate ();
|
||||
}
|
||||
|
||||
if (_route->add_processor (processor, &err_streams)) {
|
||||
|
@ -405,7 +409,7 @@ ProcessorBox::use_plugins (const SelectedPlugins& plugins)
|
|||
} else {
|
||||
|
||||
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)));
|
||||
}
|
||||
|
@ -545,7 +549,7 @@ ProcessorBox::send_io_finished (IOSelector::Result r, boost::weak_ptr<Processor>
|
|||
case IOSelector::Accepted:
|
||||
_route->add_processor (processor);
|
||||
if (Profile->get_sae()) {
|
||||
processor->set_active (true);
|
||||
processor->activate ();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -982,13 +986,13 @@ could not match the configuration of this track.");
|
|||
void
|
||||
ProcessorBox::activate_processor (boost::shared_ptr<Processor> r)
|
||||
{
|
||||
r->set_active (true);
|
||||
r->activate ();
|
||||
}
|
||||
|
||||
void
|
||||
ProcessorBox::deactivate_processor (boost::shared_ptr<Processor> r)
|
||||
{
|
||||
r->set_active (false);
|
||||
r->deactivate ();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -171,11 +171,11 @@ RouteParams_UI::~RouteParams_UI ()
|
|||
}
|
||||
|
||||
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));
|
||||
|
||||
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);
|
||||
|
||||
if (route->is_hidden()) {
|
||||
|
@ -423,7 +423,7 @@ RouteParams_UI::set_session (Session *sess)
|
|||
route_display_model->clear();
|
||||
|
||||
if (session) {
|
||||
boost::shared_ptr<Session::RouteList> r = session->get_routes();
|
||||
boost::shared_ptr<RouteList> r = session->get_routes();
|
||||
add_routes (*r);
|
||||
session->GoingAway.connect (mem_fun(*this, &ArdourDialog::session_gone));
|
||||
session->RouteAdded.connect (mem_fun(*this, &RouteParams_UI::add_routes));
|
||||
|
|
|
@ -167,7 +167,7 @@ class RouteParams_UI : public ArdourDialog
|
|||
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_removed (boost::shared_ptr<ARDOUR::Route> route);
|
||||
|
|
|
@ -92,6 +92,7 @@ gain.cc
|
|||
gdither.cc
|
||||
globals.cc
|
||||
import.cc
|
||||
internal_send.cc
|
||||
io.cc
|
||||
io_processor.cc
|
||||
jack_slave.cc
|
||||
|
|
|
@ -42,9 +42,6 @@ namespace MIDI {
|
|||
namespace ARDOUR {
|
||||
|
||||
class AudioEngine;
|
||||
class OSC;
|
||||
|
||||
extern OSC* osc;
|
||||
|
||||
static const nframes_t max_frames = JACK_MAX_FRAMES;
|
||||
extern sigc::signal<void,std::string> BootMessage;
|
||||
|
|
|
@ -68,9 +68,14 @@ public:
|
|||
/** Accumulate (add) @a len frames FROM THE START OF @a src into self at @a offset
|
||||
* scaling by @a gain_coeff */
|
||||
void accumulate_with_gain_from(const AudioBuffer& src, nframes_t len, nframes_t offset, gain_t gain_coeff) {
|
||||
|
||||
assert(_capacity > 0);
|
||||
assert(offset + len <= _capacity);
|
||||
|
||||
if (src.silent()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Sample* const dst_raw = _data + offset;
|
||||
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
|
||||
* scaling by @a 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(offset + len <= _capacity);
|
||||
|
||||
|
@ -123,7 +129,22 @@ public:
|
|||
Sample* data (nframes_t nframes, nframes_t 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;
|
||||
Sample* _data; ///< Actual buffer contents
|
||||
};
|
||||
|
|
|
@ -51,12 +51,16 @@ class AudioPort : public Port
|
|||
|
||||
AudioPort (std::string const &, Flags, bool, nframes_t);
|
||||
|
||||
bool using_internal_data() const;
|
||||
void use_internal_data ();
|
||||
void use_external_data ();
|
||||
|
||||
private:
|
||||
void mixdown (nframes_t, nframes_t, bool);
|
||||
|
||||
bool _has_been_mixed_down;
|
||||
AudioBuffer* _buffer;
|
||||
bool _own_buffer;
|
||||
bool _internal_buffer;
|
||||
};
|
||||
|
||||
} // namespace ARDOUR
|
||||
|
|
|
@ -73,6 +73,10 @@ class AudioTrack : public Track
|
|||
int deprecated_use_diskstream_connections ();
|
||||
void set_state_part_two ();
|
||||
void set_state_part_three ();
|
||||
|
||||
void catch_up_on_busses (ARDOUR::RouteList&);
|
||||
void add_internal_send (boost::shared_ptr<ARDOUR::Route>);
|
||||
|
||||
};
|
||||
|
||||
} // namespace ARDOUR
|
||||
|
|
|
@ -94,15 +94,16 @@ public:
|
|||
Evoral::ControlSet& data() { 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;
|
||||
|
||||
void can_automate(Evoral::Parameter);
|
||||
|
||||
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 old_set_automation_state(const XMLNode&);
|
||||
|
|
|
@ -68,7 +68,7 @@ public:
|
|||
* passed to the constructor must have been non-zero.
|
||||
*/
|
||||
virtual void resize(size_t) = 0;
|
||||
|
||||
|
||||
/** Clear (eg zero, or empty) buffer starting at TIME @a offset */
|
||||
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;
|
||||
|
||||
protected:
|
||||
protected:
|
||||
Buffer(DataType type, size_t capacity)
|
||||
: _type(type), _capacity(capacity), _size(0), _silent(true)
|
||||
: _type(type), _capacity(capacity), _size(0), _silent(true)
|
||||
{}
|
||||
|
||||
DataType _type;
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <vector>
|
||||
#include <ardour/chan_count.h>
|
||||
#include <ardour/data_type.h>
|
||||
#include <ardour/types.h>
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
|
@ -53,7 +54,7 @@ public:
|
|||
|
||||
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(DataType type, size_t num_buffers, size_t buffer_capacity);
|
||||
|
|
|
@ -109,6 +109,8 @@ class IO : public SessionObject, public AutomatableControls, public Latent
|
|||
void just_meter_input (nframes_t start_frame, nframes_t end_frame,
|
||||
nframes_t nframes, nframes_t offset);
|
||||
|
||||
BufferSet& output_buffers() { return *_output_buffers; }
|
||||
|
||||
gain_t gain () const { return _desired_gain; }
|
||||
virtual gain_t effective_gain () const;
|
||||
|
||||
|
@ -121,6 +123,7 @@ class IO : public SessionObject, public AutomatableControls, public Latent
|
|||
Panner& panner() { return *_panner; }
|
||||
PeakMeter& peak_meter() { return *_meter; }
|
||||
const Panner& panner() const { return *_panner; }
|
||||
void reset_panner ();
|
||||
|
||||
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&);
|
||||
|
||||
static int disable_connecting (void);
|
||||
|
||||
static int enable_connecting (void);
|
||||
|
||||
static int disable_ports (void);
|
||||
|
||||
static int enable_ports (void);
|
||||
|
||||
static int disable_panners (void);
|
||||
|
||||
static int reset_panners (void);
|
||||
|
||||
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<int> PortsCreated;
|
||||
|
||||
static void update_meters();
|
||||
static void update_meters();
|
||||
|
||||
private:
|
||||
|
||||
static sigc::signal<void> Meter;
|
||||
static Glib::StaticMutex m_meter_signal_lock;
|
||||
sigc::connection m_meter_connection;
|
||||
|
||||
static sigc::signal<void> Meter;
|
||||
static Glib::StaticMutex m_meter_signal_lock;
|
||||
sigc::connection m_meter_connection;
|
||||
|
||||
public:
|
||||
|
||||
|
||||
/* automation */
|
||||
|
||||
struct GainControl : public AutomationControl {
|
||||
|
@ -292,8 +290,6 @@ class IO : public SessionObject, public AutomatableControls, public Latent
|
|||
|
||||
virtual void set_deferred_state() {}
|
||||
|
||||
void reset_panner ();
|
||||
|
||||
virtual uint32_t pans_required() const
|
||||
{ return _inputs.count().n_audio(); }
|
||||
|
||||
|
@ -314,14 +310,11 @@ class IO : public SessionObject, public AutomatableControls, public Latent
|
|||
static bool connecting_legal;
|
||||
static bool ports_legal;
|
||||
|
||||
BufferSet& output_buffers() { return *_output_buffers; }
|
||||
|
||||
private:
|
||||
|
||||
friend class Send;
|
||||
|
||||
static bool panners_legal;
|
||||
|
||||
|
||||
void copy_to_outputs (BufferSet& bufs, DataType type, nframes_t nframes, nframes_t offset);
|
||||
|
||||
int connecting_became_legal ();
|
||||
int panners_became_legal ();
|
||||
sigc::connection connection_legal_c;
|
||||
|
|
|
@ -53,7 +53,9 @@ class IOProcessor : public Processor
|
|||
{
|
||||
public:
|
||||
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&);
|
||||
virtual ~IOProcessor ();
|
||||
|
||||
|
|
|
@ -71,6 +71,7 @@ public:
|
|||
}
|
||||
|
||||
bool connected () const;
|
||||
bool externally_connected () const;
|
||||
int disconnect_all ();
|
||||
int get_connections (std::vector<std::string> &) const;
|
||||
|
||||
|
@ -81,7 +82,7 @@ public:
|
|||
|
||||
/* connection by Port* */
|
||||
bool connected_to (Port *) const;
|
||||
int connect (Port *);
|
||||
virtual int connect (Port *);
|
||||
int disconnect (Port *);
|
||||
|
||||
void ensure_monitor_input (bool);
|
||||
|
@ -113,6 +114,12 @@ protected:
|
|||
std::set<Port*> _connections; ///< internal Ports that we are connected to
|
||||
|
||||
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:
|
||||
friend class AudioEngine;
|
||||
|
@ -130,6 +137,7 @@ private:
|
|||
/// list of JACK ports that we are connected to; we only keep this around
|
||||
/// so that we can implement ::reconnect ()
|
||||
std::set<std::string> _named_connections;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ class XMLNode;
|
|||
namespace ARDOUR {
|
||||
|
||||
class Session;
|
||||
class Route;
|
||||
|
||||
/* A mixer strip element - plugin, send, meter, etc.
|
||||
*/
|
||||
|
@ -60,7 +61,6 @@ class Processor : public SessionObject, public AutomatableControls, public Laten
|
|||
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; }
|
||||
|
@ -77,8 +77,8 @@ class Processor : public SessionObject, public AutomatableControls, public Laten
|
|||
|
||||
virtual void silence (nframes_t nframes, nframes_t offset) {}
|
||||
|
||||
virtual void activate () { _active = true; ActiveChanged.emit(); }
|
||||
virtual void deactivate () { _active = false; ActiveChanged.emit(); }
|
||||
void activate () { _active = true; ActiveChanged(); }
|
||||
void deactivate () { _active = false; ActiveChanged(); }
|
||||
|
||||
virtual bool configure_io (ChanCount in, ChanCount out);
|
||||
|
||||
|
@ -108,6 +108,7 @@ class Processor : public SessionObject, public AutomatableControls, public Laten
|
|||
sigc::signal<void> PlacementChanged;
|
||||
|
||||
protected:
|
||||
int _pending_active;
|
||||
bool _active;
|
||||
bool _next_ab_is_active;
|
||||
bool _configured;
|
||||
|
|
|
@ -306,7 +306,6 @@ class Session : public PBD::StatefulDestructible
|
|||
uint32_t n_diskstreams() const;
|
||||
|
||||
typedef std::list<boost::shared_ptr<Diskstream> > DiskstreamList;
|
||||
typedef std::list<boost::shared_ptr<Route> > RouteList;
|
||||
|
||||
int load_routes (const XMLNode&);
|
||||
boost::shared_ptr<RouteList> get_routes() const {
|
||||
|
|
|
@ -51,6 +51,7 @@ namespace ARDOUR {
|
|||
|
||||
class Source;
|
||||
class AudioSource;
|
||||
class Route;
|
||||
|
||||
typedef jack_default_audio_sample_t Sample;
|
||||
typedef float pan_t;
|
||||
|
@ -419,9 +420,11 @@ namespace ARDOUR {
|
|||
|
||||
typedef std::list<nframes64_t> AnalysisFeatureList;
|
||||
|
||||
typedef std::list<boost::shared_ptr<Route> > RouteList;
|
||||
|
||||
class Bundle;
|
||||
typedef std::vector<boost::shared_ptr<Bundle> > BundleList;
|
||||
|
||||
|
||||
} // namespace ARDOUR
|
||||
|
||||
std::istream& operator>>(std::istream& o, ARDOUR::SampleFormat& sf);
|
||||
|
|
|
@ -29,9 +29,7 @@ static const int CPU_CACHE_ALIGN = 16; /* arguably 32 on most arches, but it mat
|
|||
#endif
|
||||
|
||||
using namespace PBD;
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
using namespace ARDOUR;
|
||||
|
||||
AudioBuffer::AudioBuffer(size_t capacity)
|
||||
: Buffer(DataType::AUDIO, capacity)
|
||||
|
@ -41,6 +39,7 @@ AudioBuffer::AudioBuffer(size_t capacity)
|
|||
if (_capacity > 0) {
|
||||
_owns_data = true; // prevent resize() from gagging
|
||||
resize (_capacity);
|
||||
_silent = false; // force silence on the intial buffer state
|
||||
silence (_capacity);
|
||||
}
|
||||
}
|
||||
|
@ -51,10 +50,28 @@ AudioBuffer::~AudioBuffer()
|
|||
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
|
||||
AudioBuffer::resize (size_t size)
|
||||
{
|
||||
if (!_owns_data || (size < _capacity)) {
|
||||
if (!_owns_data) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (size < _capacity) {
|
||||
_size = size;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -74,9 +91,12 @@ AudioBuffer::resize (size_t size)
|
|||
CPU_CACHE_ALIGN, sizeof (Sample) * _capacity, strerror (errno)) << endmsg;
|
||||
}
|
||||
#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);
|
||||
}
|
||||
|
||||
|
|
|
@ -29,9 +29,10 @@ AudioPort::AudioPort (const std::string& name, Flags flags, bool ext, nframes_t
|
|||
: Port (name, DataType::AUDIO, flags, ext)
|
||||
, _has_been_mixed_down (false)
|
||||
, _buffer (0)
|
||||
, _internal_buffer (false)
|
||||
{
|
||||
assert (name.find_first_of (':') == string::npos);
|
||||
|
||||
|
||||
if (external ()) {
|
||||
|
||||
/* 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 */
|
||||
_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 */
|
||||
|
||||
_has_been_mixed_down = false;
|
||||
/* For external (JACK) ports, get_buffer() must only be run
|
||||
on outputs here in cycle_start().
|
||||
|
||||
if (external ()) {
|
||||
/* external ports use JACK's memory */
|
||||
_buffer->set_data ((Sample *) jack_port_get_buffer (_jack_port, nframes), nframes + offset);
|
||||
Inputs must be done in the correct processing order, which
|
||||
requires interleaving with route processing. that will
|
||||
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 */
|
||||
|
||||
if (_has_been_mixed_down) {
|
||||
return *_buffer;
|
||||
}
|
||||
if (receives_input () && !_has_been_mixed_down) {
|
||||
|
||||
if (receives_input ()) {
|
||||
|
||||
/* 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 ());
|
||||
/* external ports use JACK's memory unless otherwise noted */
|
||||
|
||||
} else {
|
||||
|
||||
/* OUTPUT */
|
||||
|
||||
if (!external ()) {
|
||||
/* start internal output buffers with silence */
|
||||
_buffer->silence (nframes, offset);
|
||||
if (external()) {
|
||||
if (!using_internal_data()) {
|
||||
_buffer->set_data ((Sample *) jack_port_get_buffer (_jack_port, nframes) + offset, nframes);
|
||||
} else {
|
||||
_buffer->silence (nframes, offset);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (nframes) {
|
||||
_has_been_mixed_down = true;
|
||||
}
|
||||
|
||||
mixdown (nframes, offset, !external ());
|
||||
}
|
||||
|
||||
return *_buffer;
|
||||
}
|
||||
|
||||
|
@ -111,22 +109,46 @@ AudioPort::cycle_end (nframes_t nframes, nframes_t offset)
|
|||
void
|
||||
AudioPort::mixdown (nframes_t cnt, nframes_t offset, bool first_overwrite)
|
||||
{
|
||||
/* note: this is only called for input ports */
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
} 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) {
|
||||
_buffer->read_from (dynamic_cast<AudioPort*>(*p)->get_audio_buffer (cnt, offset), cnt, offset);
|
||||
++p;
|
||||
for (; p != _connections.end (); ++p) {
|
||||
_buffer->accumulate_from (dynamic_cast<AudioPort*>(*p)->get_audio_buffer (cnt, offset), cnt, offset);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
for (; p != _connections.end (); ++p) {
|
||||
_buffer->accumulate_from (dynamic_cast<AudioPort*>(*p)->get_audio_buffer (cnt, offset), cnt, offset);
|
||||
/* XXX horrible heuristic designed to check that we worked the whole buffer.
|
||||
Needs fixing but its a hard problem.
|
||||
*/
|
||||
|
||||
if (cnt && offset == 0) {
|
||||
_has_been_mixed_down = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -140,3 +162,23 @@ AudioPort::reset ()
|
|||
_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 ();
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include <ardour/utils.h>
|
||||
#include <ardour/buffer_set.h>
|
||||
#include <ardour/audio_buffer.h>
|
||||
#include <ardour/internal_send.h>
|
||||
#include "i18n.h"
|
||||
|
||||
using namespace std;
|
||||
|
@ -65,6 +66,8 @@ AudioTrack::AudioTrack (Session& sess, string name, Route::Flag flag, TrackMode
|
|||
|
||||
_session.add_diskstream (ds);
|
||||
|
||||
_session.RouteAdded.connect (mem_fun (*this, &AudioTrack::catch_up_on_busses));
|
||||
|
||||
set_diskstream (boost::dynamic_pointer_cast<AudioDiskstream> (ds), this);
|
||||
}
|
||||
|
||||
|
@ -72,12 +75,47 @@ AudioTrack::AudioTrack (Session& sess, const XMLNode& node)
|
|||
: Track (sess, node)
|
||||
{
|
||||
_set_state (node, false);
|
||||
|
||||
_session.RouteAdded.connect (mem_fun (*this, &AudioTrack::catch_up_on_busses));
|
||||
}
|
||||
|
||||
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
|
||||
AudioTrack::set_mode (TrackMode m)
|
||||
{
|
||||
|
@ -879,7 +917,7 @@ AudioTrack::freeze (InterThreadInfo& itt)
|
|||
|
||||
/* now deactivate the processor */
|
||||
|
||||
processor->set_active (false);
|
||||
processor->deactivate ();
|
||||
_session.set_dirty ();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -348,13 +348,6 @@ AudioEngine::process_callback (nframes_t nframes)
|
|||
boost::shared_ptr<Ports> p = ports.reader();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -416,10 +409,8 @@ AudioEngine::process_callback (nframes_t nframes)
|
|||
// Finalize ports (ie write data if necessary)
|
||||
|
||||
for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
|
||||
|
||||
(*i)->cycle_end (nframes, 0);
|
||||
}
|
||||
|
||||
_processed_frames = next_processed_frames;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include <ardour/buffer_set.h>
|
||||
#include <ardour/buffer.h>
|
||||
|
@ -61,7 +62,7 @@ BufferSet::clear()
|
|||
/** Make this BufferSet a direct mirror of a PortSet's buffers.
|
||||
*/
|
||||
void
|
||||
BufferSet::attach_buffers(PortSet& ports)
|
||||
BufferSet::attach_buffers(PortSet& ports, nframes_t nframes, nframes_t offset)
|
||||
{
|
||||
clear();
|
||||
|
||||
|
@ -71,9 +72,8 @@ BufferSet::attach_buffers(PortSet& ports)
|
|||
|
||||
for (PortSet::iterator p = ports.begin(*t); p != ports.end(*t); ++p) {
|
||||
assert(p->type() == *t);
|
||||
v.push_back(&(p->get_buffer(0,0)));
|
||||
v.push_back(&(p->get_buffer(nframes, offset)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_count = ports.count();
|
||||
|
|
|
@ -153,9 +153,6 @@ IO::IO (Session& s, const string& name,
|
|||
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);
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
// Connect to our own PortCountChanged signal to connect output buffers
|
||||
IO::PortCountChanged.connect (mem_fun (*this, &IO::attach_buffers));
|
||||
|
||||
_session.add_controllable (_gain_control);
|
||||
|
||||
create_bundles_for_inputs_and_outputs ();
|
||||
|
@ -222,7 +216,6 @@ IO::~IO ()
|
|||
|
||||
delete _meter;
|
||||
delete _panner;
|
||||
delete _output_buffers;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -266,48 +259,61 @@ IO::deliver_output (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame,
|
|||
_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
|
||||
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);
|
||||
|
||||
} else {
|
||||
const DataType type = DataType::AUDIO;
|
||||
|
||||
// Copy any audio 1:1 to outputs
|
||||
|
||||
BufferSet::iterator o = output_buffers().begin(type);
|
||||
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;
|
||||
|
||||
/* do a 1:1 copy of data to output ports */
|
||||
|
||||
if (bufs.count().n_audio() > 0 && _outputs.count().n_audio () > 0) {
|
||||
copy_to_outputs (bufs, DataType::AUDIO, nframes, offset);
|
||||
}
|
||||
|
||||
/* extra outputs get a copy of the last buffer */
|
||||
|
||||
while (o != output_buffers().end(type)) {
|
||||
o->read_from(*prev, nframes, offset);
|
||||
++o;
|
||||
if (bufs.count().n_midi() > 0 && _outputs.count().n_midi () > 0) {
|
||||
copy_to_outputs (bufs, DataType::MIDI, nframes, offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ********** 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
|
||||
if (bufs.count().n_midi() == 0 || output_buffers().count().n_midi () == 0) {
|
||||
return;
|
||||
prev = i;
|
||||
++i;
|
||||
++o;
|
||||
}
|
||||
|
||||
const DataType type = DataType::MIDI;
|
||||
|
||||
// Copy any MIDI 1:1 to outputs
|
||||
assert(bufs.count().n_midi() == output_buffers().count().n_midi());
|
||||
BufferSet::iterator o = output_buffers().begin(type);
|
||||
for (BufferSet::iterator i = bufs.begin(type); i != bufs.end(type); ++i, ++o) {
|
||||
o->read_from(*i, nframes, offset);
|
||||
|
||||
/* extra outputs get a copy of the last buffer */
|
||||
|
||||
while (o != _outputs.end(type)) {
|
||||
Buffer& port_buffer (o->get_buffer (nframes, offset));
|
||||
port_buffer.read_from(*prev, nframes, offset);
|
||||
++o;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
||||
BufferSet::iterator o = outs.begin(*t);
|
||||
for (PortSet::iterator i = _inputs.begin(*t); i != _inputs.end(*t); ++i, ++o) {
|
||||
o->read_from(i->get_buffer(nframes,offset), nframes, offset);
|
||||
PortSet::iterator e = _inputs.end (*t);
|
||||
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;
|
||||
}
|
||||
|
||||
/** 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
|
||||
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;
|
||||
}
|
||||
|
||||
cerr << "set desired gain to " << val << " when curgain = " << _gain_control->get_value () << endl;
|
||||
|
||||
if (src != _gain_control.get()) {
|
||||
_gain_control->set_value(val);
|
||||
// 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 "";
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -43,10 +43,12 @@ using namespace ARDOUR;
|
|||
using namespace PBD;
|
||||
|
||||
IOProcessor::IOProcessor (Session& s, const string& name, Placement p,
|
||||
int input_min, int input_max,
|
||||
int output_min, int output_max)
|
||||
int input_min, int input_max,
|
||||
int output_min, int output_max,
|
||||
DataType dtype,
|
||||
bool public_ports)
|
||||
: 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;
|
||||
_sort_key = 0;
|
||||
|
|
|
@ -25,19 +25,30 @@
|
|||
#include "pbd/compose.h"
|
||||
#include <stdexcept>
|
||||
|
||||
ARDOUR::AudioEngine* ARDOUR::Port::_engine = 0;
|
||||
using namespace std;
|
||||
using namespace ARDOUR;
|
||||
|
||||
AudioEngine* Port::_engine = 0;
|
||||
|
||||
/** @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
|
||||
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);
|
||||
|
||||
if (e) {
|
||||
try {
|
||||
cerr << "NEW PORT " << _name << " ext = " << e << endl;
|
||||
do_make_external (t);
|
||||
}
|
||||
catch (...) {
|
||||
|
@ -47,7 +58,7 @@ ARDOUR::Port::Port (std::string const & n, DataType t, Flags f, bool e) : _jack_
|
|||
}
|
||||
|
||||
/** Port destructor */
|
||||
ARDOUR::Port::~Port ()
|
||||
Port::~Port ()
|
||||
{
|
||||
if (_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.
|
||||
*/
|
||||
void
|
||||
ARDOUR::Port::do_make_external (DataType t)
|
||||
Port::do_make_external (DataType t)
|
||||
{
|
||||
if (_jack_port) {
|
||||
/* already external */
|
||||
return;
|
||||
}
|
||||
|
||||
_jack_port = jack_port_register (_engine->jack (), _name.c_str (), t.to_jack_type (), _flags, 0);
|
||||
if (_jack_port == 0) {
|
||||
if ((_jack_port = jack_port_register (_engine->jack (), _name.c_str (), t.to_jack_type (), _flags, 0)) == 0) {
|
||||
throw std::runtime_error ("Could not register JACK port");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ARDOUR::Port::make_external ()
|
||||
Port::make_external ()
|
||||
{
|
||||
do_make_external (type ());
|
||||
}
|
||||
|
||||
/** @return true if this port is connected to anything */
|
||||
bool
|
||||
ARDOUR::Port::connected () const
|
||||
Port::connected () const
|
||||
{
|
||||
if (!_connections.empty ()) {
|
||||
/* connected to a Port* */
|
||||
|
@ -94,8 +104,20 @@ ARDOUR::Port::connected () const
|
|||
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
|
||||
ARDOUR::Port::disconnect_all ()
|
||||
Port::disconnect_all ()
|
||||
{
|
||||
/* Disconnect from Port* connections */
|
||||
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);
|
||||
_named_connections.clear ();
|
||||
|
||||
check_buffer_status ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -115,7 +139,7 @@ ARDOUR::Port::disconnect_all ()
|
|||
* @return true if this port is connected to o, otherwise false.
|
||||
*/
|
||||
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 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 */
|
||||
int
|
||||
ARDOUR::Port::get_connections (std::vector<std::string> & c) const
|
||||
Port::get_connections (std::vector<std::string> & c) const
|
||||
{
|
||||
int n = 0;
|
||||
|
||||
|
@ -163,7 +187,7 @@ ARDOUR::Port::get_connections (std::vector<std::string> & c) const
|
|||
}
|
||||
|
||||
int
|
||||
ARDOUR::Port::connect (std::string const & other)
|
||||
Port::connect (std::string const & other)
|
||||
{
|
||||
/* caller must hold process lock */
|
||||
|
||||
|
@ -197,11 +221,13 @@ ARDOUR::Port::connect (std::string const & other)
|
|||
}
|
||||
}
|
||||
|
||||
check_buffer_status ();
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
ARDOUR::Port::disconnect (std::string const & other)
|
||||
Port::disconnect (std::string const & other)
|
||||
{
|
||||
/* caller must hold process lock */
|
||||
|
||||
|
@ -227,6 +253,8 @@ ARDOUR::Port::disconnect (std::string const & other)
|
|||
if (r == 0) {
|
||||
_named_connections.erase (other);
|
||||
}
|
||||
|
||||
check_buffer_status ();
|
||||
}
|
||||
|
||||
return r;
|
||||
|
@ -234,13 +262,13 @@ ARDOUR::Port::disconnect (std::string const & other)
|
|||
|
||||
|
||||
bool
|
||||
ARDOUR::Port::connected_to (Port* o) const
|
||||
Port::connected_to (Port* o) const
|
||||
{
|
||||
return connected_to (o->name ());
|
||||
}
|
||||
|
||||
int
|
||||
ARDOUR::Port::connect (Port* o)
|
||||
Port::connect (Port* o)
|
||||
{
|
||||
/* caller must hold process lock */
|
||||
|
||||
|
@ -253,11 +281,14 @@ ARDOUR::Port::connect (Port* o)
|
|||
_connections.insert (o);
|
||||
o->_connections.insert (this);
|
||||
|
||||
check_buffer_status ();
|
||||
o->check_buffer_status ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
ARDOUR::Port::disconnect (Port* o)
|
||||
Port::disconnect (Port* o)
|
||||
{
|
||||
if (external () && o->external ()) {
|
||||
/* we're both external; try disconnecting using name */
|
||||
|
@ -270,17 +301,20 @@ ARDOUR::Port::disconnect (Port* o)
|
|||
_connections.erase (o);
|
||||
o->_connections.erase (this);
|
||||
|
||||
check_buffer_status ();
|
||||
o->check_buffer_status ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
ARDOUR::Port::set_engine (AudioEngine* e)
|
||||
Port::set_engine (AudioEngine* e)
|
||||
{
|
||||
_engine = e;
|
||||
}
|
||||
|
||||
void
|
||||
ARDOUR::Port::ensure_monitor_input (bool yn)
|
||||
Port::ensure_monitor_input (bool yn)
|
||||
{
|
||||
if (_jack_port) {
|
||||
jack_port_ensure_monitor (_jack_port, yn);
|
||||
|
@ -288,7 +322,7 @@ ARDOUR::Port::ensure_monitor_input (bool yn)
|
|||
}
|
||||
|
||||
bool
|
||||
ARDOUR::Port::monitoring_input () const
|
||||
Port::monitoring_input () const
|
||||
{
|
||||
if (_jack_port) {
|
||||
return jack_port_monitoring_input (_jack_port);
|
||||
|
@ -298,7 +332,7 @@ ARDOUR::Port::monitoring_input () const
|
|||
}
|
||||
|
||||
void
|
||||
ARDOUR::Port::reset ()
|
||||
Port::reset ()
|
||||
{
|
||||
_last_monitor = false;
|
||||
|
||||
|
@ -308,7 +342,7 @@ ARDOUR::Port::reset ()
|
|||
}
|
||||
|
||||
void
|
||||
ARDOUR::Port::recompute_total_latency () const
|
||||
Port::recompute_total_latency () const
|
||||
{
|
||||
#ifdef HAVE_JACK_RECOMPUTE_LATENCY
|
||||
if (_jack_port) {
|
||||
|
@ -318,7 +352,7 @@ ARDOUR::Port::recompute_total_latency () const
|
|||
}
|
||||
|
||||
nframes_t
|
||||
ARDOUR::Port::total_latency () const
|
||||
Port::total_latency () const
|
||||
{
|
||||
if (_jack_port) {
|
||||
return jack_port_get_total_latency (_engine->jack (), _jack_port);
|
||||
|
@ -328,7 +362,7 @@ ARDOUR::Port::total_latency () const
|
|||
}
|
||||
|
||||
int
|
||||
ARDOUR::Port::reestablish ()
|
||||
Port::reestablish ()
|
||||
{
|
||||
if (!_jack_port) {
|
||||
return 0;
|
||||
|
@ -348,7 +382,7 @@ ARDOUR::Port::reestablish ()
|
|||
|
||||
|
||||
int
|
||||
ARDOUR::Port::reconnect ()
|
||||
Port::reconnect ()
|
||||
{
|
||||
/* caller must hold process lock; intended to be used only after reestablish() */
|
||||
|
||||
|
@ -367,7 +401,7 @@ ARDOUR::Port::reconnect ()
|
|||
|
||||
/** @param n Short name */
|
||||
int
|
||||
ARDOUR::Port::set_name (std::string const & n)
|
||||
Port::set_name (std::string const & n)
|
||||
{
|
||||
assert (_name.find_first_of (':') == std::string::npos);
|
||||
|
||||
|
@ -386,15 +420,48 @@ ARDOUR::Port::set_name (std::string const & n)
|
|||
}
|
||||
|
||||
void
|
||||
ARDOUR::Port::set_latency (nframes_t n)
|
||||
Port::set_latency (nframes_t n)
|
||||
{
|
||||
_latency = n;
|
||||
}
|
||||
|
||||
void
|
||||
ARDOUR::Port::request_monitor_input (bool yn)
|
||||
Port::request_monitor_input (bool yn)
|
||||
{
|
||||
if (_jack_port) {
|
||||
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 ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -105,13 +105,6 @@ Processor::set_placement (Placement p)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
Processor::set_active (bool yn)
|
||||
{
|
||||
_active = yn;
|
||||
ActiveChanged ();
|
||||
}
|
||||
|
||||
XMLNode&
|
||||
Processor::get_state (void)
|
||||
{
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include <ardour/plugin_insert.h>
|
||||
#include <ardour/port_insert.h>
|
||||
#include <ardour/send.h>
|
||||
#include <ardour/internal_send.h>
|
||||
#include <ardour/session.h>
|
||||
#include <ardour/utils.h>
|
||||
#include <ardour/configuration.h>
|
||||
|
@ -1229,6 +1230,11 @@ Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorStreams*
|
|||
int
|
||||
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;
|
||||
|
||||
if (!_session.engine().connected()) {
|
||||
|
@ -1292,7 +1298,7 @@ Route::disable_processors (Placement p)
|
|||
|
||||
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
|
||||
if ((*i)->placement() == p) {
|
||||
(*i)->set_active (false);
|
||||
(*i)->deactivate ();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1308,7 +1314,7 @@ Route::disable_processors ()
|
|||
Glib::RWLock::ReaderLock lm (_processor_lock);
|
||||
|
||||
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
|
||||
(*i)->set_active (false);
|
||||
(*i)->deactivate ();
|
||||
}
|
||||
|
||||
_session.set_dirty ();
|
||||
|
@ -1325,7 +1331,7 @@ Route::disable_plugins (Placement p)
|
|||
|
||||
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
|
||||
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) {
|
||||
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()) {
|
||||
(*i)->set_active (false);
|
||||
(*i)->deactivate ();
|
||||
(*i)->set_next_ab_is_active (true);
|
||||
} else {
|
||||
(*i)->set_next_ab_is_active (false);
|
||||
|
@ -1385,9 +1391,9 @@ Route::ab_plugins (bool forward)
|
|||
}
|
||||
|
||||
if ((*i)->get_next_ab_is_active()) {
|
||||
(*i)->set_active (true);
|
||||
(*i)->activate ();
|
||||
} 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) {
|
||||
++send_cnt;
|
||||
} else if (boost::dynamic_pointer_cast<InternalSend> (*r) != 0) {
|
||||
++send_cnt;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (insert_cnt == 0) {
|
||||
if (send_cnt) {
|
||||
goto recompute;
|
||||
|
@ -1665,20 +1673,32 @@ Route::_reset_processor_counts (ProcessorStreams* err)
|
|||
|
||||
for (r = _processors.begin(); r != _processors.end(); prev = r, ++r) {
|
||||
boost::shared_ptr<Send> s;
|
||||
boost::shared_ptr<InternalSend> is;
|
||||
|
||||
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()) {
|
||||
s->expect_inputs (n_inputs());
|
||||
} else {
|
||||
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 {
|
||||
|
||||
/* 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_midi = max ((*r)->output_streams ().n_midi(), max_midi);
|
||||
}
|
||||
|
@ -1711,8 +1731,6 @@ Route::apply_some_processor_counts (list<ProcessorCount>& iclist)
|
|||
|
||||
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)) {
|
||||
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) {
|
||||
|
||||
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 (err) {
|
||||
err->index = index;
|
||||
|
@ -1853,7 +1869,11 @@ Route::all_processors_flip ()
|
|||
bool first_is_on = _processors.front()->active();
|
||||
|
||||
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 ();
|
||||
|
@ -1874,7 +1894,11 @@ Route::all_processors_active (Placement p, bool state)
|
|||
|
||||
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
|
||||
if ((*i)->placement() == p) {
|
||||
(*i)->set_active (state);
|
||||
if (state) {
|
||||
(*i)->activate ();
|
||||
} else {
|
||||
(*i)->deactivate ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -140,7 +140,7 @@ Send::set_state(const XMLNode& node)
|
|||
if ((*niter)->name() == "IOProcessor") {
|
||||
insert_node = *niter;
|
||||
} 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);
|
||||
|
||||
if (_metering) {
|
||||
if (_io->_gain == 0) {
|
||||
_io->_meter->reset();
|
||||
if (_io->effective_gain() == 0) {
|
||||
_io->peak_meter().reset();
|
||||
} 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);
|
||||
|
||||
if (_metering) {
|
||||
_io->_meter->reset();
|
||||
_io->peak_meter().reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,6 +72,7 @@
|
|||
#include <ardour/named_selection.h>
|
||||
#include <ardour/crossfade.h>
|
||||
#include <ardour/playlist.h>
|
||||
#include <ardour/internal_send.h>
|
||||
#include <ardour/click.h>
|
||||
#include <ardour/data_type.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)
|
||||
{
|
||||
char bus_name[32];
|
||||
|
@ -3685,6 +3686,8 @@ Session::add_processor (Processor* processor)
|
|||
_plugin_inserts.insert (_plugin_inserts.begin(), plugin_insert);
|
||||
} else if ((send = dynamic_cast<Send *> (processor)) != 0) {
|
||||
_sends.insert (_sends.begin(), send);
|
||||
} else if (dynamic_cast<InternalSend *> (processor) != 0) {
|
||||
/* relax */
|
||||
} else {
|
||||
fatal << _("programming error: unknown type of Insert created!") << endmsg;
|
||||
/*NOTREACHED*/
|
||||
|
@ -3710,6 +3713,8 @@ Session::remove_processor (Processor* processor)
|
|||
}
|
||||
} else if ((plugin_insert = dynamic_cast<PluginInsert *> (processor)) != 0) {
|
||||
_plugin_inserts.remove (plugin_insert);
|
||||
} else if (dynamic_cast<InternalSend *> (processor) != 0) {
|
||||
/* relax */
|
||||
} else if ((send = dynamic_cast<Send *> (processor)) != 0) {
|
||||
list<Send*>::iterator x = find (_sends.begin(), _sends.end(), send);
|
||||
if (x != _sends.end()) {
|
||||
|
|
|
@ -151,14 +151,22 @@ PixFader::on_button_release_event (GdkEventButton* ev)
|
|||
/* no motion - just a click */
|
||||
|
||||
if (ev->state & Gdk::SHIFT_MASK) {
|
||||
cerr << "SV A\n";
|
||||
adjustment.set_value (default_value);
|
||||
cerr << "SV A OUT\n";
|
||||
} else if (ev->state & fine_scale_modifier) {
|
||||
cerr << "SV B\n";
|
||||
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())) {
|
||||
/* above the current display height, remember X Window coords */
|
||||
cerr << "SV C\n";
|
||||
adjustment.set_value (adjustment.get_value() + adjustment.get_step_increment());
|
||||
cerr << "SV C OUT\n";
|
||||
} else {
|
||||
cerr << "SV D\n";
|
||||
adjustment.set_value (adjustment.get_value() - adjustment.get_step_increment());
|
||||
cerr << "SV D OUT\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -54,6 +54,8 @@ xml++.cc
|
|||
conf = Configure(pbd)
|
||||
if conf.CheckFunc('getmntent'):
|
||||
conf.env.Append(CCFLAGS="-DHAVE_GETMNTENT")
|
||||
if conf.CheckCHeader('execinfo.h'):
|
||||
conf.env.Append(CXXFLAGS="-DHAVE_EXECINFO")
|
||||
pbd = conf.Finish()
|
||||
|
||||
pbd.Merge ([ libraries['sigc2'],
|
||||
|
|
|
@ -30,7 +30,6 @@ PBD::trace_twb ()
|
|||
#ifdef HAVE_EXECINFO
|
||||
|
||||
#include <execinfo.h>
|
||||
#include <cstdlib>
|
||||
|
||||
void
|
||||
PBD::stacktrace (std::ostream& out, int levels)
|
||||
|
|
|
@ -218,7 +218,7 @@ MackieControlProtocol::Sorted MackieControlProtocol::get_sorted_routes()
|
|||
Sorted sorted;
|
||||
|
||||
// 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;
|
||||
|
||||
// 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
|
||||
// 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;
|
||||
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
|
||||
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
|
||||
// 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
|
||||
|
||||
// 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 )
|
||||
{
|
||||
connections_back = (*it)->RemoteControlIDChanged.connect( ( mem_fun (*this, &MackieControlProtocol::notify_remote_id_changed) ) );
|
||||
|
|
|
@ -102,7 +102,7 @@ class MackieControlProtocol
|
|||
/// Signal handler from Panner::Change
|
||||
void notify_panner_changed( Mackie::RouteSignal *, bool force_update = true );
|
||||
/// 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
|
||||
void notify_active_changed( Mackie::RouteSignal * );
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include <ardour/filesystem_paths.h>
|
||||
|
||||
#include "osc.h"
|
||||
#include "osc_controllable.h"
|
||||
#include "i18n.h"
|
||||
|
||||
using namespace ARDOUR;
|
||||
|
@ -74,7 +75,7 @@ OSC::OSC (Session& s, uint32_t port)
|
|||
|
||||
/* 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()));
|
||||
|
||||
// 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 ();
|
||||
|
||||
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 {
|
||||
if (argc <= 0) {
|
||||
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);
|
||||
|
@ -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) {
|
||||
|
||||
if (argc > 0) {
|
||||
int id = argv[0]->i;
|
||||
boost::shared_ptr<Route> r = session->route_by_remote_id (id);
|
||||
for (int n = 0; n < argc; ++n) {
|
||||
|
||||
boost::shared_ptr<Route> r = session->route_by_remote_id (argv[n]->i);
|
||||
|
||||
if (r) {
|
||||
ListenerPair listener;
|
||||
|
||||
listener.first = r.get();
|
||||
listener.second = lo_message_get_source (msg);
|
||||
|
||||
drop_listener_pair (listener);
|
||||
end_listen (r, lo_message_get_source (msg));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -611,55 +601,86 @@ OSC::catchall (const char *path, const char *types, lo_arg **argv, int argc, lo_
|
|||
}
|
||||
|
||||
void
|
||||
OSC::route_added (Session::RouteList& rl)
|
||||
OSC::route_added (RouteList& rl)
|
||||
{
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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 ((*x)->route == lp.first) {
|
||||
route_exists = true;
|
||||
|
||||
if ((*x)->addr == lp.second ) {
|
||||
return;
|
||||
if ((rc = dynamic_cast<OSCRouteControllable*>(*x)) != 0) {
|
||||
|
||||
if (rc->route() == route) {
|
||||
route_exists = true;
|
||||
|
||||
/* XXX NEED lo_address_equal() */
|
||||
|
||||
if (rc->address() == addr) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Listener* l = new Listener (lp.first, lp.second);
|
||||
|
||||
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)));
|
||||
l->connections.push_back (lp.first->mute_changed.connect (bind (mem_fun (*this, &OSC::route_changed), RouteMute, lp.first, lp.second)));
|
||||
l->connections.push_back (lp.first->gain_control()->Changed.connect (bind (mem_fun (*this, &OSC::route_changed_deux), RouteGain, lp.first, lp.second)));
|
||||
OSCControllable* c;
|
||||
string path;
|
||||
|
||||
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) {
|
||||
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
|
||||
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 ((*x)->route == r) {
|
||||
delete *x;
|
||||
x = listeners.erase (x);
|
||||
if (!r) {
|
||||
return;
|
||||
}
|
||||
|
||||
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 {
|
||||
++x;
|
||||
}
|
||||
|
@ -667,14 +688,22 @@ OSC::drop_listeners_by_route (Route* r)
|
|||
}
|
||||
|
||||
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) {
|
||||
if ((*x)->route == lp.first && (*x)->addr == lp.second) {
|
||||
listeners.erase (x);
|
||||
return;
|
||||
for (x = controllables.begin(); x != controllables.end(); ++x) {
|
||||
|
||||
OSCRouteControllable* rc;
|
||||
|
||||
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() );
|
||||
}
|
||||
|
||||
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 //
|
||||
|
||||
/* path callbacks */
|
||||
|
|
|
@ -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
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -25,6 +25,8 @@
|
|||
#include <sys/time.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include <lo/lo.h>
|
||||
|
||||
#include <sigc++/sigc++.h>
|
||||
|
@ -33,15 +35,17 @@
|
|||
#include <ardour/session.h>
|
||||
#include <control_protocol/control_protocol.h>
|
||||
|
||||
namespace ARDOUR {
|
||||
class OSCControllable;
|
||||
|
||||
namespace ARDOUR {
|
||||
class Session;
|
||||
class Route;
|
||||
}
|
||||
|
||||
class OSC : public ControlProtocol
|
||||
class OSC : public ARDOUR::ControlProtocol
|
||||
{
|
||||
public:
|
||||
OSC (Session&, uint32_t port);
|
||||
OSC (ARDOUR::Session&, uint32_t port);
|
||||
virtual ~OSC();
|
||||
|
||||
XMLNode& get_state ();
|
||||
|
@ -53,8 +57,6 @@ class OSC : public ControlProtocol
|
|||
bool get_feedback () const;
|
||||
|
||||
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 stop ();
|
||||
|
@ -82,21 +84,12 @@ class OSC : public ControlProtocol
|
|||
|
||||
void register_callbacks ();
|
||||
|
||||
void route_added (ARDOUR::Session::RouteList&);
|
||||
void route_added (ARDOUR::RouteList&);
|
||||
|
||||
// Handlers for "Application Hook" signals
|
||||
void session_loaded (ARDOUR::Session&);
|
||||
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
|
||||
|
||||
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_dB (int rid, float dB);
|
||||
|
||||
struct Listener {
|
||||
Route* route;
|
||||
lo_address addr;
|
||||
std::vector<sigc::connection> connections;
|
||||
void listen_to_route (boost::shared_ptr<ARDOUR::Route>, lo_address);
|
||||
void end_listen (boost::shared_ptr<ARDOUR::Route>, lo_address);
|
||||
void drop_route (boost::weak_ptr<ARDOUR::Route>);
|
||||
|
||||
Listener (Route* r, lo_address a) : route (r), addr (a) {}
|
||||
};
|
||||
typedef std::list<OSCControllable*> Controllables;
|
||||
|
||||
typedef std::pair<Route*, lo_address> ListenerPair;
|
||||
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*);
|
||||
Controllables controllables;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // ardour_osc_h
|
||||
|
|
|
@ -22,16 +22,20 @@
|
|||
#include <pbd/error.h>
|
||||
#include <pbd/xml++.h>
|
||||
|
||||
#include <ardour/route.h>
|
||||
|
||||
#include "osc_controllable.h"
|
||||
|
||||
using namespace sigc;
|
||||
using namespace PBD;
|
||||
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)
|
||||
, addr (a)
|
||||
, path (p)
|
||||
{
|
||||
c->Changed.connect (mem_fun (*this, &OSCControllable::send_change));
|
||||
}
|
||||
|
||||
OSCControllable::~OSCControllable ()
|
||||
|
@ -42,7 +46,7 @@ OSCControllable::~OSCControllable ()
|
|||
XMLNode&
|
||||
OSCControllable::get_state ()
|
||||
{
|
||||
XMLNode& root (controllable.get_state());
|
||||
XMLNode& root (controllable->get_state());
|
||||
return root;
|
||||
}
|
||||
|
||||
|
@ -52,3 +56,43 @@ OSCControllable::set_state (const XMLNode& node)
|
|||
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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -21,7 +21,7 @@
|
|||
#define __osc_osccontrollable_h__
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <sigc++/sigc++.h>
|
||||
#include <lo/lo.h>
|
||||
|
||||
|
@ -29,18 +29,46 @@
|
|||
#include <pbd/stateful.h>
|
||||
#include <ardour/types.h>
|
||||
|
||||
namespace ARDOUR {
|
||||
|
||||
class Route;
|
||||
|
||||
}
|
||||
|
||||
class OSCControllable : public PBD::Stateful
|
||||
{
|
||||
public:
|
||||
OSCControllable (lo_address addr, PBD::Controllable&);
|
||||
OSCControllable (lo_address addr, const string& path, boost::shared_ptr<PBD::Controllable>);
|
||||
virtual ~OSCControllable ();
|
||||
|
||||
lo_address address() const { return addr; }
|
||||
|
||||
XMLNode& get_state ();
|
||||
int set_state (const XMLNode& node);
|
||||
|
||||
private:
|
||||
PBD::Controllable& controllable;
|
||||
protected:
|
||||
boost::shared_ptr<PBD::Controllable> controllable;
|
||||
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__ */
|
||||
|
|
Loading…
Reference in New Issue