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

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 handle_new_route (ARDOUR::Session::RouteList&);
void handle_new_route (ARDOUR::RouteList&);
void remove_route (TimeAxisView *);
bool route_removal;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 (

View File

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

View File

@ -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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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

View File

@ -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

View File

@ -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&);

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

@ -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 {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 "";
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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()) {

View File

@ -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";
}
}

View File

@ -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'],

View File

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

View File

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

View File

@ -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 * );

View File

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

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
* 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

View File

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

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