the big Route structure refactor. !!!! THIS WILL ***NOT LOAD*** PRIOR 3.0 or 2.X SESSIONS !!!! BREAKAGE IS EXPECTED !!!! IF YOU HAVE AND NEED A WORKING 3.0 DO **NOT** UPDATE. !!!! otherwise, update and enjoy the steadily emerging joys of this major reworking of ardour internals

git-svn-id: svn://localhost/ardour2/branches/3.0@5137 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis 2009-06-09 20:21:19 +00:00
parent 9bd274bfde
commit e6eb059576
77 changed files with 2688 additions and 3801 deletions

View file

@ -324,7 +324,7 @@ ActionManager::set_sensitive (vector<RefPtr<Action> >& actions, bool state)
void void
ActionManager::uncheck_toggleaction (const char * name) ActionManager::uncheck_toggleaction (const char * name)
{ {
char *last_slash = strrchr (name, '/'); const char *last_slash = strrchr (name, '/');
if (last_slash == 0) { if (last_slash == 0) {
fatal << string_compose (_("programmer error: %1 %2"), X_("illegal toggle action name"), name) << endmsg; fatal << string_compose (_("programmer error: %1 %2"), X_("illegal toggle action name"), name) << endmsg;
@ -339,7 +339,7 @@ ActionManager::uncheck_toggleaction (const char * name)
memcpy (group_name, name + 10, len); memcpy (group_name, name + 10, len);
group_name[len] = '\0'; group_name[len] = '\0';
char* action_name = last_slash + 1; const char* action_name = last_slash + 1;
RefPtr<Action> act = get_action (group_name, action_name); RefPtr<Action> act = get_action (group_name, action_name);
if (act) { if (act) {

View file

@ -1835,44 +1835,6 @@ ARDOUR_UI::stop_blinking ()
} }
} }
void
ARDOUR_UI::name_io_setup (AudioEngine& engine,
string& buf,
IO& io,
bool in)
{
vector<string> connections;
if (in) {
if (io.n_inputs().n_total() == 0) {
buf = _("none");
return;
}
/* XXX we're not handling multiple ports yet. */
if (io.input(0)->get_connections(connections) == 0) {
buf = _("off");
} else {
buf = connections.front();
}
} else {
if (io.n_outputs().n_total() == 0) {
buf = _("none");
return;
}
/* XXX we're not handling multiple ports yet. */
if (io.output(0)->get_connections(connections) == 0) {
buf = _("off");
} else {
buf = connections.front();
}
}
}
/** Ask the user for the name of a new shapshot and then take it. /** Ask the user for the name of a new shapshot and then take it.
*/ */

View file

@ -176,8 +176,6 @@ class ARDOUR_UI : public Gtkmm2ext::UI
static sigc::signal<void> SuperRapidScreenUpdate; static sigc::signal<void> SuperRapidScreenUpdate;
static sigc::signal<void,nframes_t, bool, nframes_t> Clock; static sigc::signal<void,nframes_t, bool, nframes_t> Clock;
void name_io_setup (ARDOUR::AudioEngine&, std::string&, ARDOUR::IO& io, bool in);
XMLNode* editor_settings() const; XMLNode* editor_settings() const;
XMLNode* mixer_settings () const; XMLNode* mixer_settings () const;
XMLNode* keyboard_settings () const; XMLNode* keyboard_settings () const;

View file

@ -37,6 +37,7 @@
#include <gtkmm2ext/bindable_button.h> #include <gtkmm2ext/bindable_button.h>
#include <gtkmm2ext/utils.h> #include <gtkmm2ext/utils.h>
#include "ardour/amp.h"
#include "ardour/audio_diskstream.h" #include "ardour/audio_diskstream.h"
#include "ardour/audioplaylist.h" #include "ardour/audioplaylist.h"
#include "ardour/event_type_map.h" #include "ardour/event_type_map.h"
@ -347,13 +348,14 @@ AudioTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool
return; return;
} }
boost::shared_ptr<AutomationTimeAxisView> gain_track(new AutomationTimeAxisView (_session, boost::shared_ptr<AutomationTimeAxisView>
_route, _route, c, gain_track(new AutomationTimeAxisView (_session,
_editor, _route, _route->amp(), c,
*this, _editor,
false, *this,
parent_canvas, false,
_route->describe_parameter(param))); parent_canvas,
_route->amp()->describe_parameter(param)));
add_automation_child(Evoral::Parameter(GainAutomation), gain_track, show); add_automation_child(Evoral::Parameter(GainAutomation), gain_track, show);
@ -396,11 +398,11 @@ AudioTimeAxisView::ensure_pan_views (bool show)
/* we don't already have an AutomationTimeAxisView for this parameter */ /* we don't already have an AutomationTimeAxisView for this parameter */
std::string const name = _route->describe_parameter (pan_control->parameter ()); std::string const name = _route->panner()->describe_parameter (pan_control->parameter ());
boost::shared_ptr<AutomationTimeAxisView> pan_track ( boost::shared_ptr<AutomationTimeAxisView> pan_track (
new AutomationTimeAxisView (_session, new AutomationTimeAxisView (_session,
_route, _route, pan_control, _route, _route->panner(), pan_control,
_editor, _editor,
*this, *this,
false, false,

View file

@ -255,15 +255,20 @@ void
AutomationTimeAxisView::set_automation_state (AutoState state) AutomationTimeAxisView::set_automation_state (AutoState state)
{ {
if (!ignore_state_request) { if (!ignore_state_request) {
_automatable->set_parameter_automation_state (_control->parameter(), state);
#if 0
if (_route == _automatable) { // This is a time axis for route (not region) automation if (_route == _automatable) { // This is a time axis for route (not region) automation
_route->set_parameter_automation_state (_control->parameter(), state); _route->set_parameter_automation_state (_control->parameter(), state);
} }
if (_control->list()) if (_control->list())
_control->alist()->set_automation_state(state); _control->alist()->set_automation_state(state);
#endif
} }
if (_view)
if (_view) {
_view->set_automation_state (state); _view->set_automation_state (state);
}
} }
void void

View file

@ -68,9 +68,11 @@ Editor::handle_new_route (RouteList& routes)
continue; continue;
} }
if (route->default_type() == ARDOUR::DataType::AUDIO) DataType dt = route->input()->default_type();
if (dt == ARDOUR::DataType::AUDIO)
tv = new AudioTimeAxisView (*this, *session, route, *track_canvas); tv = new AudioTimeAxisView (*this, *session, route, *track_canvas);
else if (route->default_type() == ARDOUR::DataType::MIDI) else if (dt == ARDOUR::DataType::MIDI)
tv = new MidiTimeAxisView (*this, *session, route, *track_canvas); tv = new MidiTimeAxisView (*this, *session, route, *track_canvas);
else else
throw unknown_type(); throw unknown_type();

View file

@ -112,14 +112,14 @@ PortExportChannelSelector::fill_route_list ()
/* Add master bus and then everything else */ /* Add master bus and then everything else */
ARDOUR::IO * master = session->master_out().get(); ARDOUR::IO* master = session->master_out()->output().get();
channel_view.add_route (master); channel_view.add_route (master);
for (RouteList::iterator it = routes.begin(); it != routes.end(); ++it) { for (RouteList::iterator it = routes.begin(); it != routes.end(); ++it) {
if (it->get() == master) { if ((*it)->output().get() == master) {
continue; continue;
} }
channel_view.add_route (it->get()); channel_view.add_route ((*it)->output().get());
} }
update_channel_count (); update_channel_count ();
@ -261,27 +261,27 @@ PortExportChannelSelector::ChannelTreeView::set_config (ChannelConfigPtr c)
} }
void void
PortExportChannelSelector::ChannelTreeView::add_route (ARDOUR::IO * route) PortExportChannelSelector::ChannelTreeView::add_route (ARDOUR::IO * io)
{ {
Gtk::TreeModel::iterator iter = route_list->append(); Gtk::TreeModel::iterator iter = route_list->append();
Gtk::TreeModel::Row row = *iter; Gtk::TreeModel::Row row = *iter;
row[route_cols.selected] = false; row[route_cols.selected] = false;
row[route_cols.name] = route->name(); row[route_cols.name] = io->name();
row[route_cols.io] = route; row[route_cols.io] = io;
/* Initialize port list */ /* Initialize port list */
Glib::RefPtr<Gtk::ListStore> port_list = Gtk::ListStore::create (route_cols.port_cols); Glib::RefPtr<Gtk::ListStore> port_list = Gtk::ListStore::create (route_cols.port_cols);
row[route_cols.port_list_col] = port_list; row[route_cols.port_list_col] = port_list;
uint32_t outs = route->n_outputs().n_audio(); uint32_t outs = io->n_ports().n_audio();
for (uint32_t i = 0; i < outs; ++i) { for (uint32_t i = 0; i < outs; ++i) {
iter = port_list->append(); iter = port_list->append();
row = *iter; row = *iter;
row[route_cols.port_cols.selected] = false; row[route_cols.port_cols.selected] = false;
row[route_cols.port_cols.port] = route->audio_output (i); row[route_cols.port_cols.port] = io->audio (i);
std::ostringstream oss; std::ostringstream oss;
oss << "Out-" << (i + 1); oss << "Out-" << (i + 1);

View file

@ -160,57 +160,58 @@ GainMeterBase::~GainMeterBase ()
} }
void void
GainMeterBase::set_io (boost::shared_ptr<IO> io) GainMeterBase::set_controls (boost::shared_ptr<Route> r,
boost::shared_ptr<PeakMeter> pm,
boost::shared_ptr<AutomationControl> gc,
boost::shared_ptr<Automatable> gc_owner)
{ {
connections.clear (); connections.clear ();
_io = io; if (!pm && !gc) {
if (!_io) {
level_meter->set_meter (0); level_meter->set_meter (0);
gain_slider->set_controllable (boost::shared_ptr<PBD::Controllable>()); gain_slider->set_controllable (boost::shared_ptr<PBD::Controllable>());
_meter.reset ();
_gain_control.reset ();
_route.reset ();
return; return;
} }
level_meter->set_meter (&_io->peak_meter()); _meter = pm;
gain_slider->set_controllable (_io->gain_control()); _gain_control = gc;
_route = r;
boost::shared_ptr<Route> r; level_meter->set_meter (pm.get());
gain_slider->set_controllable (gc);
if ((r = boost::dynamic_pointer_cast<Route> (_io)) != 0) { if (!_route || !_route->is_hidden()) {
if (!r->is_hidden()) { using namespace Menu_Helpers;
using namespace Menu_Helpers; gain_astate_menu.items().clear ();
gain_astate_menu.items().clear (); gain_astate_menu.items().push_back (MenuElem (_("Manual"),
bind (mem_fun (*(gc_owner.get()), &Automatable::set_parameter_automation_state),
Evoral::Parameter(GainAutomation), (AutoState) Off)));
gain_astate_menu.items().push_back (MenuElem (_("Play"),
bind (mem_fun (*(gc_owner.get()), &Automatable::set_parameter_automation_state),
Evoral::Parameter(GainAutomation), (AutoState) Play)));
gain_astate_menu.items().push_back (MenuElem (_("Write"),
bind (mem_fun (*(gc_owner.get()), &Automatable::set_parameter_automation_state),
Evoral::Parameter(GainAutomation), (AutoState) Write)));
gain_astate_menu.items().push_back (MenuElem (_("Touch"),
bind (mem_fun (*(gc_owner.get()), &Automatable::set_parameter_automation_state),
Evoral::Parameter(GainAutomation), (AutoState) Touch)));
gain_astate_menu.items().push_back (MenuElem (_("Manual"), connections.push_back (gain_automation_style_button.signal_button_press_event().connect (mem_fun(*this, &GainMeterBase::gain_automation_style_button_event), false));
bind (mem_fun (*_io, &IO::set_parameter_automation_state), connections.push_back (gain_automation_state_button.signal_button_press_event().connect (mem_fun(*this, &GainMeterBase::gain_automation_state_button_event), false));
Evoral::Parameter(GainAutomation), (AutoState) Off)));
gain_astate_menu.items().push_back (MenuElem (_("Play"),
bind (mem_fun (*_io, &IO::set_parameter_automation_state),
Evoral::Parameter(GainAutomation), (AutoState) Play)));
gain_astate_menu.items().push_back (MenuElem (_("Write"),
bind (mem_fun (*_io, &IO::set_parameter_automation_state),
Evoral::Parameter(GainAutomation), (AutoState) Write)));
gain_astate_menu.items().push_back (MenuElem (_("Touch"),
bind (mem_fun (*_io, &IO::set_parameter_automation_state),
Evoral::Parameter(GainAutomation), (AutoState) Touch)));
connections.push_back (gain_automation_style_button.signal_button_press_event().connect (mem_fun(*this, &GainMeterBase::gain_automation_style_button_event), false)); connections.push_back (gc->alist()->automation_state_changed.connect (mem_fun(*this, &GainMeter::gain_automation_state_changed)));
connections.push_back (gain_automation_state_button.signal_button_press_event().connect (mem_fun(*this, &GainMeterBase::gain_automation_state_button_event), false)); connections.push_back (gc->alist()->automation_style_changed.connect (mem_fun(*this, &GainMeter::gain_automation_style_changed)));
connections.push_back (r->gain_control()->alist()->automation_state_changed.connect (mem_fun(*this, &GainMeter::gain_automation_state_changed))); gain_automation_state_changed ();
connections.push_back (r->gain_control()->alist()->automation_style_changed.connect (mem_fun(*this, &GainMeter::gain_automation_style_changed)));
gain_automation_state_changed ();
}
} }
//cerr << "Connect " << this << " to gain change for " << _io->name() << endl; connections.push_back (gc->Changed.connect (mem_fun (*this, &GainMeterBase::gain_changed)));
connections.push_back (_io->gain_control()->Changed.connect (mem_fun(*this, &GainMeterBase::gain_changed)));
gain_changed (); gain_changed ();
show_gain (); show_gain ();
@ -272,10 +273,8 @@ GainMeterBase::peak_button_release (GdkEventButton* ev)
if (ev->button == 1 && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier|Keyboard::TertiaryModifier)) { if (ev->button == 1 && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier|Keyboard::TertiaryModifier)) {
ResetAllPeakDisplays (); ResetAllPeakDisplays ();
} else if (ev->button == 1 && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) { } else if (ev->button == 1 && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
boost::shared_ptr<Route> r; if (_route) {
ResetGroupPeakDisplays (_route->mix_group());
if ((r = boost::dynamic_pointer_cast<Route> (_io)) != 0) {
ResetGroupPeakDisplays (r->mix_group());
} }
} else { } else {
reset_peak_display (); reset_peak_display ();
@ -287,12 +286,7 @@ GainMeterBase::peak_button_release (GdkEventButton* ev)
void void
GainMeterBase::reset_peak_display () GainMeterBase::reset_peak_display ()
{ {
boost::shared_ptr<Route> r; _meter->reset_max();
if ((r = boost::dynamic_pointer_cast<Route> (_io)) != 0) {
r->peak_meter().reset_max();
}
level_meter->clear_meters(); level_meter->clear_meters();
max_peak = -INFINITY; max_peak = -INFINITY;
peak_display.set_label (_("-Inf")); peak_display.set_label (_("-Inf"));
@ -302,13 +296,9 @@ GainMeterBase::reset_peak_display ()
void void
GainMeterBase::reset_group_peak_display (RouteGroup* group) GainMeterBase::reset_group_peak_display (RouteGroup* group)
{ {
boost::shared_ptr<Route> r; if (_route && group == _route->mix_group()) {
reset_peak_display ();
if ((r = boost::dynamic_pointer_cast<Route> (_io)) != 0) {
if (group == r->mix_group()) {
reset_peak_display ();
} }
}
} }
void void
@ -354,7 +344,7 @@ GainMeterBase::gain_activated ()
f = min (f, 6.0f); f = min (f, 6.0f);
_io->gain_control()->set_value (dB_to_coefficient(f)); _gain_control->set_value (dB_to_coefficient(f));
if (gain_display.has_focus()) { if (gain_display.has_focus()) {
PublicEditor::instance().reset_focus(); PublicEditor::instance().reset_focus();
@ -384,7 +374,7 @@ GainMeterBase::gain_adjusted ()
//cerr << this << " for " << _io->name() << " GAIN ADJUSTED\n"; //cerr << this << " for " << _io->name() << " GAIN ADJUSTED\n";
if (!ignore_toggle) { if (!ignore_toggle) {
//cerr << "Set GC\n"; //cerr << "Set GC\n";
_io->gain_control()->set_value (slider_position_to_gain (gain_adjustment.get_value())); _gain_control->set_value (slider_position_to_gain (gain_adjustment.get_value()));
//cerr << "Set GC OUT\n"; //cerr << "Set GC OUT\n";
} }
show_gain (); show_gain ();
@ -393,7 +383,7 @@ GainMeterBase::gain_adjusted ()
void void
GainMeterBase::effective_gain_display () GainMeterBase::effective_gain_display ()
{ {
gfloat value = gain_to_slider_position (_io->effective_gain()); gfloat value = gain_to_slider_position (_gain_control->get_value());
//cerr << this << " for " << _io->name() << " EGAIN = " << value //cerr << this << " for " << _io->name() << " EGAIN = " << value
// << " AGAIN = " << gain_adjustment.get_value () << endl; // << " AGAIN = " << gain_adjustment.get_value () << endl;
@ -428,7 +418,7 @@ void
GainMeterBase::update_gain_sensitive () GainMeterBase::update_gain_sensitive ()
{ {
static_cast<Gtkmm2ext::SliderController*>(gain_slider)->set_sensitive ( static_cast<Gtkmm2ext::SliderController*>(gain_slider)->set_sensitive (
!(_io->gain_control()->alist()->automation_state() & Play)); !(_gain_control->alist()->automation_state() & Play));
} }
@ -459,7 +449,7 @@ GainMeterBase::meter_press(GdkEventButton* ev)
wait_for_release = false; wait_for_release = false;
if ((_route = boost::dynamic_pointer_cast<Route>(_io)) == 0) { if (!_route) {
return FALSE; return FALSE;
} }
@ -482,7 +472,7 @@ GainMeterBase::meter_press(GdkEventButton* ev)
} }
} }
if (ev->button == 1 || Keyboard::is_button2_event (ev)) { if (_route && (ev->button == 1 || Keyboard::is_button2_event (ev))) {
if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) { if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
@ -534,10 +524,8 @@ GainMeterBase::meter_release(GdkEventButton* ev)
if (wait_for_release){ if (wait_for_release){
wait_for_release = false; wait_for_release = false;
boost::shared_ptr<Route> r; if (_route) {
set_meter_point (*_route, old_meter_point);
if ((r = boost::dynamic_pointer_cast<Route>(_io)) != 0) {
set_meter_point (*r, old_meter_point);
} }
} }
} }
@ -566,9 +554,7 @@ GainMeterBase::set_mix_group_meter_point (Route& route, MeterPoint mp)
void void
GainMeterBase::meter_point_clicked () GainMeterBase::meter_point_clicked ()
{ {
boost::shared_ptr<Route> r; if (_route) {
if ((r = boost::dynamic_pointer_cast<Route> (_io)) != 0) {
/* WHAT? */ /* WHAT? */
} }
} }
@ -576,14 +562,14 @@ GainMeterBase::meter_point_clicked ()
gint gint
GainMeterBase::start_gain_touch (GdkEventButton* ev) GainMeterBase::start_gain_touch (GdkEventButton* ev)
{ {
_io->gain_control()->start_touch (); _gain_control->start_touch ();
return FALSE; return FALSE;
} }
gint gint
GainMeterBase::end_gain_touch (GdkEventButton* ev) GainMeterBase::end_gain_touch (GdkEventButton* ev)
{ {
_io->gain_control()->stop_touch (); _gain_control->stop_touch ();
return FALSE; return FALSE;
} }
@ -686,10 +672,10 @@ GainMeterBase::gain_automation_style_changed ()
{ {
switch (_width) { switch (_width) {
case Wide: case Wide:
gain_automation_style_button.set_label (astyle_string(_io->gain_control()->alist()->automation_style())); gain_automation_style_button.set_label (astyle_string(_gain_control->alist()->automation_style()));
break; break;
case Narrow: case Narrow:
gain_automation_style_button.set_label (short_astyle_string(_io->gain_control()->alist()->automation_style())); gain_automation_style_button.set_label (short_astyle_string(_gain_control->alist()->automation_style()));
break; break;
} }
} }
@ -703,14 +689,14 @@ GainMeterBase::gain_automation_state_changed ()
switch (_width) { switch (_width) {
case Wide: case Wide:
gain_automation_state_button.set_label (astate_string(_io->gain_control()->alist()->automation_state())); gain_automation_state_button.set_label (astate_string(_gain_control->alist()->automation_state()));
break; break;
case Narrow: case Narrow:
gain_automation_state_button.set_label (short_astate_string(_io->gain_control()->alist()->automation_state())); gain_automation_state_button.set_label (short_astate_string(_gain_control->alist()->automation_state()));
break; break;
} }
x = (_io->gain_control()->alist()->automation_state() != Off); x = (_gain_control->alist()->automation_state() != Off);
if (gain_automation_state_button.get_active() != x) { if (gain_automation_state_button.get_active() != x) {
ignore_toggle = true; ignore_toggle = true;
@ -812,7 +798,10 @@ GainMeter::GainMeter (Session& s)
} }
void void
GainMeter::set_io (boost::shared_ptr<IO> io) GainMeter::set_controls (boost::shared_ptr<Route> r,
boost::shared_ptr<PeakMeter> meter,
boost::shared_ptr<AutomationControl> gain_control,
boost::shared_ptr<Automatable> gc_owner)
{ {
if (level_meter->get_parent()) { if (level_meter->get_parent()) {
hbox.remove (*level_meter); hbox.remove (*level_meter);
@ -826,30 +815,17 @@ GainMeter::set_io (boost::shared_ptr<IO> io)
fader_vbox->remove (gain_automation_state_button); fader_vbox->remove (gain_automation_state_button);
} }
GainMeterBase::set_io (io); GainMeterBase::set_controls (r, meter, gain_control, gc_owner);
boost::shared_ptr<Route> r; /*
if we have a non-hidden route (ie. we're not the click or the auditioner),
pack some route-dependent stuff.
*/
if ((r = boost::dynamic_pointer_cast<Route> (_io)) != 0) { gain_display_box.pack_end (peak_display, true, true);
hbox.pack_end (*level_meter, true, true);
/* if (!r->is_hidden()) {
if we have a non-hidden route (ie. we're not the click or the auditioner),
pack some route-dependent stuff.
*/
gain_display_box.pack_end (peak_display, true, true);
hbox.pack_end (*level_meter, true, true);
if (!r->is_hidden()) {
fader_vbox->pack_start (gain_automation_state_button, false, false, 0);
}
} else {
/* we're managing a non-Route IO (e.g. Send) */
gain_display_box.pack_end (peak_display, true, true);
hbox.pack_end (*level_meter, true, true);
fader_vbox->pack_start (gain_automation_state_button, false, false, 0); fader_vbox->pack_start (gain_automation_state_button, false, false, 0);
} }
} }
@ -941,7 +917,7 @@ GainMeter::meter_metrics_expose (GdkEventExpose *ev)
boost::shared_ptr<PBD::Controllable> boost::shared_ptr<PBD::Controllable>
GainMeterBase::get_controllable() GainMeterBase::get_controllable()
{ {
return _io->gain_control(); return _gain_control;
} }

View file

@ -46,6 +46,8 @@ namespace ARDOUR {
class Session; class Session;
class Route; class Route;
class RouteGroup; class RouteGroup;
class PeakMeter;
class Automatable;
} }
namespace Gtkmm2ext { namespace Gtkmm2ext {
class FastMeter; class FastMeter;
@ -62,8 +64,10 @@ class GainMeterBase : virtual public sigc::trackable
bool horizontal); bool horizontal);
virtual ~GainMeterBase (); virtual ~GainMeterBase ();
virtual void set_io (boost::shared_ptr<ARDOUR::IO>); virtual void set_controls (boost::shared_ptr<ARDOUR::Route> route,
boost::shared_ptr<ARDOUR::IO> io() const { return _io; } boost::shared_ptr<ARDOUR::PeakMeter> meter,
boost::shared_ptr<ARDOUR::AutomationControl> gain_control,
boost::shared_ptr<ARDOUR::Automatable> gc_owner);
void update_gain_sensitive (); void update_gain_sensitive ();
void update_meters (); void update_meters ();
@ -83,7 +87,9 @@ class GainMeterBase : virtual public sigc::trackable
protected: protected:
friend class MixerStrip; friend class MixerStrip;
boost::shared_ptr<ARDOUR::IO> _io; boost::shared_ptr<ARDOUR::Route> _route;
boost::shared_ptr<ARDOUR::PeakMeter> _meter;
boost::shared_ptr<ARDOUR::AutomationControl> _gain_control;
ARDOUR::Session& _session; ARDOUR::Session& _session;
std::vector<sigc::connection> connections; std::vector<sigc::connection> connections;
@ -176,7 +182,10 @@ class GainMeter : public GainMeterBase, public Gtk::VBox
GainMeter (ARDOUR::Session&); GainMeter (ARDOUR::Session&);
~GainMeter () {} ~GainMeter () {}
void set_io (boost::shared_ptr<ARDOUR::IO>); virtual void set_controls (boost::shared_ptr<ARDOUR::Route> route,
boost::shared_ptr<ARDOUR::PeakMeter> meter,
boost::shared_ptr<ARDOUR::AutomationControl> gain_control,
boost::shared_ptr<ARDOUR::Automatable> gc_owner);
int get_gm_width (); int get_gm_width ();
void setup_meters (int len=0); void setup_meters (int len=0);

View file

@ -41,12 +41,14 @@
using namespace ARDOUR; using namespace ARDOUR;
using namespace Gtk; using namespace Gtk;
IOSelector::IOSelector (ARDOUR::Session& session, boost::shared_ptr<ARDOUR::IO> io, bool in) IOSelector::IOSelector (ARDOUR::Session& session, boost::shared_ptr<ARDOUR::IO> io)
: PortMatrix (session, io->default_type()) : PortMatrix (session, io->default_type())
, _io (io) , _io (io)
, _find_inputs_for_io_outputs (in)
{ {
/* signal flow from 0 to 1 */ /* signal flow from 0 to 1 */
_find_inputs_for_io_outputs = (_io->direction() == IO::Output);
if (_find_inputs_for_io_outputs) { if (_find_inputs_for_io_outputs) {
_other = 1; _other = 1;
_ours = 0; _ours = 0;
@ -73,9 +75,7 @@ IOSelector::setup_ports (int dim)
} else { } else {
_port_group->clear (); _port_group->clear ();
_port_group->add_bundle ( _port_group->add_bundle (_io->bundle ());
_find_inputs_for_io_outputs ? _io->bundle_for_outputs() : _io->bundle_for_inputs()
);
} }
_ports[dim].resume_signals (); _ports[dim].resume_signals ();
@ -96,17 +96,9 @@ IOSelector::set_state (ARDOUR::BundleChannel c[2], bool s)
} }
if (s) { if (s) {
if (!_find_inputs_for_io_outputs) { _io->connect (f, *j, 0);
_io->connect_input (f, *j, 0);
} else {
_io->connect_output (f, *j, 0);
}
} else { } else {
if (!_find_inputs_for_io_outputs) { _io->disconnect (f, *j, 0);
_io->disconnect_input (f, *j, 0);
} else {
_io->disconnect_output (f, *j, 0);
}
} }
} }
} }
@ -147,9 +139,9 @@ uint32_t
IOSelector::n_io_ports () const IOSelector::n_io_ports () const
{ {
if (!_find_inputs_for_io_outputs) { if (!_find_inputs_for_io_outputs) {
return _io->inputs().num_ports (_io->default_type()); return _io->n_ports().get (_io->default_type());
} else { } else {
return _io->outputs().num_ports (_io->default_type()); return _io->n_ports().get (_io->default_type());
} }
} }
@ -161,27 +153,13 @@ IOSelector::add_channel (boost::shared_ptr<ARDOUR::Bundle> b)
// The IO selector only works for single typed IOs // The IO selector only works for single typed IOs
const ARDOUR::DataType t = _io->default_type (); const ARDOUR::DataType t = _io->default_type ();
if (!_find_inputs_for_io_outputs) { try {
_io->add_port ("", this);
}
try { catch (AudioEngine::PortRegistrationFailure& err) {
_io->add_input_port ("", this); MessageDialog msg (_("There are no more JACK ports available."));
} msg.run ();
catch (AudioEngine::PortRegistrationFailure& err) {
MessageDialog msg (_("There are no more JACK ports available."));
msg.run ();
}
} else {
try {
_io->add_output_port ("", this);
}
catch (AudioEngine::PortRegistrationFailure& err) {
MessageDialog msg (_("There are no more JACK ports available."));
msg.run ();
}
} }
} }
@ -193,11 +171,7 @@ IOSelector::remove_channel (ARDOUR::BundleChannel bc)
return; return;
} }
if (_find_inputs_for_io_outputs) { _io->remove_port (f, this);
_io->remove_output_port (f, this);
} else {
_io->remove_input_port (f, this);
}
} }
bool bool
@ -206,9 +180,9 @@ IOSelector::list_is_global (int dim) const
return (dim == _other); return (dim == _other);
} }
IOSelectorWindow::IOSelectorWindow (ARDOUR::Session& session, boost::shared_ptr<ARDOUR::IO> io, bool for_input, bool can_cancel) IOSelectorWindow::IOSelectorWindow (ARDOUR::Session& session, boost::shared_ptr<ARDOUR::IO> io, bool can_cancel)
: ArdourDialog ("I/O selector") : ArdourDialog ("I/O selector")
, _selector (session, io, !for_input) , _selector (session, io)
, add_button (_("Add Port")) , add_button (_("Add Port"))
, disconnect_button (_("Disconnect All")) , disconnect_button (_("Disconnect All"))
, ok_button (can_cancel ? _("OK"): _("Close")) , ok_button (can_cancel ? _("OK"): _("Close"))
@ -327,8 +301,8 @@ IOSelectorWindow::io_name_changed (void* src)
} }
PortInsertUI::PortInsertUI (ARDOUR::Session& sess, boost::shared_ptr<ARDOUR::PortInsert> pi) PortInsertUI::PortInsertUI (ARDOUR::Session& sess, boost::shared_ptr<ARDOUR::PortInsert> pi)
: input_selector (sess, pi->io(), true), : input_selector (sess, pi->input())
output_selector (sess, pi->io(), false) , output_selector (sess, pi->output())
{ {
output_selector.set_min_height_divisor (2); output_selector.set_min_height_divisor (2);
input_selector.set_min_height_divisor (2); input_selector.set_min_height_divisor (2);

View file

@ -30,7 +30,7 @@ namespace ARDOUR {
class IOSelector : public PortMatrix class IOSelector : public PortMatrix
{ {
public: public:
IOSelector (ARDOUR::Session&, boost::shared_ptr<ARDOUR::IO>, bool); IOSelector (ARDOUR::Session&, boost::shared_ptr<ARDOUR::IO>);
void set_state (ARDOUR::BundleChannel c[2], bool); void set_state (ARDOUR::BundleChannel c[2], bool);
PortMatrixNode::State get_state (ARDOUR::BundleChannel c[2]) const; PortMatrixNode::State get_state (ARDOUR::BundleChannel c[2]) const;
@ -74,7 +74,7 @@ class IOSelector : public PortMatrix
class IOSelectorWindow : public ArdourDialog class IOSelectorWindow : public ArdourDialog
{ {
public: public:
IOSelectorWindow (ARDOUR::Session&, boost::shared_ptr<ARDOUR::IO>, bool for_input, bool can_cancel = false); IOSelectorWindow (ARDOUR::Session&, boost::shared_ptr<ARDOUR::IO>, bool can_cancel = false);
IOSelector& selector() { return _selector; } IOSelector& selector() { return _selector; }

View file

@ -506,13 +506,7 @@ MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool
if (existing != _automation_tracks.end()) if (existing != _automation_tracks.end())
return; return;
boost::shared_ptr<AutomationControl> c boost::shared_ptr<AutomationControl> c = _route->get_control (param);
= boost::dynamic_pointer_cast<AutomationControl>(_route->data().control(param));
if (!c) {
c = boost::dynamic_pointer_cast<AutomationControl>(_route->control_factory(param));
_route->add_control(c);
}
assert(c); assert(c);

View file

@ -34,6 +34,7 @@
#include <gtkmm2ext/bindable_button.h> #include <gtkmm2ext/bindable_button.h>
#include "ardour/ardour.h" #include "ardour/ardour.h"
#include "ardour/amp.h"
#include "ardour/session.h" #include "ardour/session.h"
#include "ardour/audioengine.h" #include "ardour/audioengine.h"
#include "ardour/route.h" #include "ardour/route.h"
@ -71,20 +72,6 @@ sigc::signal<void,boost::shared_ptr<Route> > MixerStrip::SwitchIO;
int MixerStrip::scrollbar_height = 0; int MixerStrip::scrollbar_height = 0;
#ifdef VARISPEED_IN_MIXER_STRIP
static void
speed_printer (char buf[32], Gtk::Adjustment& adj, void* arg)
{
float val = adj.get_value ();
if (val == 1.0) {
strcpy (buf, "1");
} else {
snprintf (buf, 32, "%.3f", val);
}
}
#endif
MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, bool in_mixer) MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, bool in_mixer)
: AxisView(sess) : AxisView(sess)
, RouteUI (sess, _("Mute"), _("Solo"), _("Record")) , RouteUI (sess, _("Mute"), _("Solo"), _("Record"))
@ -99,8 +86,6 @@ MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, bool in_mixer)
, bottom_button_table (1, 2) , bottom_button_table (1, 2)
, meter_point_label (_("pre")) , meter_point_label (_("pre"))
, comment_button (_("Comments")) , comment_button (_("Comments"))
, speed_adjustment (1.0, 0.001, 4.0, 0.001, 0.1)
, speed_spinner (&speed_adjustment, "MixerStripSpeedBase", true)
{ {
init (); init ();
@ -128,8 +113,6 @@ MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, boost::shared_ptr<Route> rt
, bottom_button_table (1, 2) , bottom_button_table (1, 2)
, meter_point_label (_("pre")) , meter_point_label (_("pre"))
, comment_button (_("Comments")) , comment_button (_("Comments"))
, speed_adjustment (1.0, 0.001, 4.0, 0.001, 0.1)
, speed_spinner (&speed_adjustment, "MixerStripSpeedBase", true)
{ {
init (); init ();
@ -146,7 +129,6 @@ MixerStrip::init ()
route_ops_menu = 0; route_ops_menu = 0;
ignore_comment_edit = false; ignore_comment_edit = false;
ignore_toggle = false; ignore_toggle = false;
ignore_speed_adjustment = false;
comment_window = 0; comment_window = 0;
comment_area = 0; comment_area = 0;
_width_owner = 0; _width_owner = 0;
@ -340,12 +322,6 @@ MixerStrip::set_route (boost::shared_ptr<Route> rt)
button_table.remove (*show_sends_button); button_table.remove (*show_sends_button);
} }
#ifdef VARISPEED_IN_MIXER_STRIP
if (speed_frame->get_parent()) {
button_table.remove (*speed_frame);
}
#endif
RouteUI::set_route (rt); RouteUI::set_route (rt);
delete input_selector; delete input_selector;
@ -354,14 +330,16 @@ MixerStrip::set_route (boost::shared_ptr<Route> rt)
delete output_selector; delete output_selector;
output_selector = 0; output_selector = 0;
if (_current_send) { boost::shared_ptr<Send> send;
_current_send->set_metering (false);
if (_current_delivery && (send = boost::dynamic_pointer_cast<Send>(_current_delivery))) {
send->set_metering (false);
} }
_current_send.reset (); _current_delivery = _route->main_outs ();
panners.set_io (rt); panners.set_panner (rt->main_outs()->panner());
gpm.set_io (rt); gpm.set_controls (rt, rt->shared_peak_meter(), rt->gain_control(), rt->amp());
pre_processor_box.set_route (rt); pre_processor_box.set_route (rt);
post_processor_box.set_route (rt); post_processor_box.set_route (rt);
@ -388,20 +366,6 @@ MixerStrip::set_route (boost::shared_ptr<Route> rt)
connections.push_back (at->FreezeChange.connect (mem_fun(*this, &MixerStrip::map_frozen))); connections.push_back (at->FreezeChange.connect (mem_fun(*this, &MixerStrip::map_frozen)));
#ifdef VARISPEED_IN_MIXER_STRIP
speed_adjustment.signal_value_changed().connect (mem_fun(*this, &MixerStrip::speed_adjustment_changed));
speed_frame.set_name ("BaseFrame");
speed_frame.set_shadow_type (Gtk::SHADOW_IN);
speed_frame.add (speed_spinner);
speed_spinner.set_print_func (speed_printer, 0);
ARDOUR_UI::instance()->tooltips().set_tip (speed_spinner, _("Varispeed"));
button_table.attach (speed_frame, 0, 2, 5, 6);
#endif /* VARISPEED_IN_MIXER_STRIP */
button_table.attach (*rec_enable_button, 0, 2, 2, 3); button_table.attach (*rec_enable_button, 0, 2, 2, 3);
rec_enable_button->show(); rec_enable_button->show();
@ -443,9 +407,9 @@ MixerStrip::set_route (boost::shared_ptr<Route> rt)
connections.push_back (_route->meter_change.connect ( connections.push_back (_route->meter_change.connect (
mem_fun(*this, &MixerStrip::meter_changed))); mem_fun(*this, &MixerStrip::meter_changed)));
connections.push_back (_route->input_changed.connect ( connections.push_back (_route->input()->changed.connect (
mem_fun(*this, &MixerStrip::input_changed))); mem_fun(*this, &MixerStrip::input_changed)));
connections.push_back (_route->output_changed.connect ( connections.push_back (_route->output()->changed.connect (
mem_fun(*this, &MixerStrip::output_changed))); mem_fun(*this, &MixerStrip::output_changed)));
connections.push_back (_route->mix_group_changed.connect ( connections.push_back (_route->mix_group_changed.connect (
mem_fun(*this, &MixerStrip::mix_group_changed))); mem_fun(*this, &MixerStrip::mix_group_changed)));
@ -458,8 +422,6 @@ MixerStrip::set_route (boost::shared_ptr<Route> rt)
if (is_audio_track()) { if (is_audio_track()) {
connections.push_back (audio_track()->DiskstreamChanged.connect ( connections.push_back (audio_track()->DiskstreamChanged.connect (
mem_fun(*this, &MixerStrip::diskstream_changed))); mem_fun(*this, &MixerStrip::diskstream_changed)));
connections.push_back (get_diskstream()->SpeedChanged.connect (
mem_fun(*this, &MixerStrip::speed_changed)));
} }
connections.push_back (_route->NameChanged.connect ( connections.push_back (_route->NameChanged.connect (
@ -485,10 +447,6 @@ MixerStrip::set_route (boost::shared_ptr<Route> rt)
panners.setup_pan (); panners.setup_pan ();
if (is_audio_track()) {
speed_changed ();
}
update_diskstream_display (); update_diskstream_display ();
update_input_display (); update_input_display ();
update_output_display (); update_output_display ();
@ -530,9 +488,6 @@ MixerStrip::set_route (boost::shared_ptr<Route> rt)
comment_button.show(); comment_button.show();
group_button.show(); group_button.show();
group_label.show(); group_label.show();
speed_spinner.show();
speed_label.show();
speed_frame.show();
show (); show ();
} }
@ -703,7 +658,7 @@ MixerStrip::output_press (GdkEventButton *ev)
citems.push_back (MenuElem (_("Disconnect"), mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_output))); citems.push_back (MenuElem (_("Disconnect"), mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_output)));
citems.push_back (SeparatorElem()); citems.push_back (SeparatorElem());
ARDOUR::BundleList current = _route->bundles_connected_to_outputs (); ARDOUR::BundleList current = _route->output()->bundles_connected ();
boost::shared_ptr<ARDOUR::BundleList> b = _session.bundles (); boost::shared_ptr<ARDOUR::BundleList> b = _session.bundles ();
for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) { for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
@ -712,7 +667,7 @@ MixerStrip::output_press (GdkEventButton *ev)
boost::shared_ptr<ARDOUR::RouteList> routes = _session.get_routes (); boost::shared_ptr<ARDOUR::RouteList> routes = _session.get_routes ();
for (ARDOUR::RouteList::const_iterator i = routes->begin(); i != routes->end(); ++i) { for (ARDOUR::RouteList::const_iterator i = routes->begin(); i != routes->end(); ++i) {
maybe_add_bundle_to_output_menu ((*i)->bundle_for_inputs(), current); maybe_add_bundle_to_output_menu ((*i)->input()->bundle(), current);
} }
if (citems.size() == 2) { if (citems.size() == 2) {
@ -734,7 +689,7 @@ void
MixerStrip::edit_output_configuration () MixerStrip::edit_output_configuration ()
{ {
if (output_selector == 0) { if (output_selector == 0) {
output_selector = new IOSelectorWindow (_session, _route, false); output_selector = new IOSelectorWindow (_session, _route->output());
} }
if (output_selector->is_visible()) { if (output_selector->is_visible()) {
@ -748,7 +703,7 @@ void
MixerStrip::edit_input_configuration () MixerStrip::edit_input_configuration ()
{ {
if (input_selector == 0) { if (input_selector == 0) {
input_selector = new IOSelectorWindow (_session, _route, true); input_selector = new IOSelectorWindow (_session, _route->input());
} }
if (input_selector->is_visible()) { if (input_selector->is_visible()) {
@ -784,7 +739,7 @@ MixerStrip::input_press (GdkEventButton *ev)
citems.push_back (MenuElem (_("Disconnect"), mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_input))); citems.push_back (MenuElem (_("Disconnect"), mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_input)));
citems.push_back (SeparatorElem()); citems.push_back (SeparatorElem());
ARDOUR::BundleList current = _route->bundles_connected_to_inputs (); ARDOUR::BundleList current = _route->input()->bundles_connected ();
boost::shared_ptr<ARDOUR::BundleList> b = _session.bundles (); boost::shared_ptr<ARDOUR::BundleList> b = _session.bundles ();
for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) { for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
@ -793,7 +748,7 @@ MixerStrip::input_press (GdkEventButton *ev)
boost::shared_ptr<ARDOUR::RouteList> routes = _session.get_routes (); boost::shared_ptr<ARDOUR::RouteList> routes = _session.get_routes ();
for (ARDOUR::RouteList::const_iterator i = routes->begin(); i != routes->end(); ++i) { for (ARDOUR::RouteList::const_iterator i = routes->begin(); i != routes->end(); ++i) {
maybe_add_bundle_to_input_menu ((*i)->bundle_for_outputs(), current); maybe_add_bundle_to_input_menu ((*i)->output()->bundle(), current);
} }
if (citems.size() == 2) { if (citems.size() == 2) {
@ -817,12 +772,12 @@ MixerStrip::bundle_input_toggled (boost::shared_ptr<ARDOUR::Bundle> c)
return; return;
} }
ARDOUR::BundleList current = _route->bundles_connected_to_inputs (); ARDOUR::BundleList current = _route->input()->bundles_connected ();
if (std::find (current.begin(), current.end(), c) == current.end()) { if (std::find (current.begin(), current.end(), c) == current.end()) {
_route->connect_input_ports_to_bundle (c, this); _route->input()->connect_ports_to_bundle (c, this);
} else { } else {
_route->disconnect_input_ports_from_bundle (c, this); _route->input()->disconnect_ports_from_bundle (c, this);
} }
} }
@ -833,12 +788,12 @@ MixerStrip::bundle_output_toggled (boost::shared_ptr<ARDOUR::Bundle> c)
return; return;
} }
ARDOUR::BundleList current = _route->bundles_connected_to_outputs (); ARDOUR::BundleList current = _route->output()->bundles_connected ();
if (std::find (current.begin(), current.end(), c) == current.end()) { if (std::find (current.begin(), current.end(), c) == current.end()) {
_route->connect_output_ports_to_bundle (c, this); _route->output()->connect_ports_to_bundle (c, this);
} else { } else {
_route->disconnect_output_ports_from_bundle (c, this); _route->output()->disconnect_ports_from_bundle (c, this);
} }
} }
@ -848,7 +803,7 @@ MixerStrip::maybe_add_bundle_to_input_menu (boost::shared_ptr<Bundle> b, ARDOUR:
using namespace Menu_Helpers; using namespace Menu_Helpers;
if (b->ports_are_outputs() == false || if (b->ports_are_outputs() == false ||
route()->default_type() != b->type() || route()->input()->default_type() != b->type() ||
b->nchannels() != _route->n_inputs().get (b->type ())) { b->nchannels() != _route->n_inputs().get (b->type ())) {
return; return;
@ -874,7 +829,7 @@ MixerStrip::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR
using namespace Menu_Helpers; using namespace Menu_Helpers;
if (b->ports_are_inputs() == false || if (b->ports_are_inputs() == false ||
route()->default_type() != b->type() || route()->output()->default_type() != b->type() ||
b->nchannels() != _route->n_outputs().get (b->type ())) { b->nchannels() != _route->n_outputs().get (b->type ())) {
return; return;
@ -938,7 +893,7 @@ MixerStrip::connect_to_pan ()
void void
MixerStrip::update_input_display () MixerStrip::update_input_display ()
{ {
ARDOUR::BundleList const c = _route->bundles_connected_to_inputs (); ARDOUR::BundleList const c = _route->input()->bundles_connected();
if (c.size() > 1) { if (c.size() > 1) {
input_label.set_text (_("Inputs")); input_label.set_text (_("Inputs"));
@ -960,7 +915,7 @@ MixerStrip::update_input_display ()
void void
MixerStrip::update_output_display () MixerStrip::update_output_display ()
{ {
ARDOUR::BundleList const c = _route->bundles_connected_to_outputs (); ARDOUR::BundleList const c = _route->output()->bundles_connected ();
/* XXX: how do we represent >1 connected bundle? */ /* XXX: how do we represent >1 connected bundle? */
if (c.size() > 1) { if (c.size() > 1) {
@ -1269,43 +1224,6 @@ MixerStrip::list_route_operations ()
refresh_remote_control_menu(); refresh_remote_control_menu();
} }
void
MixerStrip::speed_adjustment_changed ()
{
/* since there is a usable speed adjustment, there has to be a diskstream */
if (!ignore_speed_adjustment) {
get_diskstream()->set_speed (speed_adjustment.get_value());
}
}
void
MixerStrip::speed_changed ()
{
Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &MixerStrip::update_speed_display));
}
void
MixerStrip::update_speed_display ()
{
float val;
val = get_diskstream()->speed();
if (val != 1.0) {
speed_spinner.set_name ("MixerStripSpeedBaseNotOne");
} else {
speed_spinner.set_name ("MixerStripSpeedBase");
}
if (speed_adjustment.get_value() != val) {
ignore_speed_adjustment = true;
speed_adjustment.set_value (val);
ignore_speed_adjustment = false;
}
}
void void
MixerStrip::set_selected (bool yn) MixerStrip::set_selected (bool yn)
{ {
@ -1383,12 +1301,10 @@ MixerStrip::map_frozen ()
case AudioTrack::Frozen: case AudioTrack::Frozen:
pre_processor_box.set_sensitive (false); pre_processor_box.set_sensitive (false);
post_processor_box.set_sensitive (false); post_processor_box.set_sensitive (false);
speed_spinner.set_sensitive (false);
break; break;
default: default:
pre_processor_box.set_sensitive (true); pre_processor_box.set_sensitive (true);
post_processor_box.set_sensitive (true); post_processor_box.set_sensitive (true);
speed_spinner.set_sensitive (true);
// XXX need some way, maybe, to retoggle redirect editors // XXX need some way, maybe, to retoggle redirect editors
break; break;
} }
@ -1499,8 +1415,6 @@ MixerStrip::meter_changed (void *src)
void void
MixerStrip::switch_io (boost::shared_ptr<Route> target) MixerStrip::switch_io (boost::shared_ptr<Route> target)
{ {
boost::shared_ptr<IO> to_display;
if (_route == target || _route->is_master()) { if (_route == target || _route->is_master()) {
/* don't change the display for the target or the master bus */ /* don't change the display for the target or the master bus */
return; return;
@ -1519,22 +1433,28 @@ MixerStrip::switch_io (boost::shared_ptr<Route> target)
return; return;
} }
if (_current_send) { boost::shared_ptr<Send> send;
_current_send->set_metering (false);
if (_current_delivery && (send = boost::dynamic_pointer_cast<Send>(_current_delivery))) {
send->set_metering (false);
} }
_current_send = _route->send_for (target); _current_delivery = _route->send_for (target->input());
if (_current_send) { if (_current_delivery) {
to_display = _current_send->io(); send = boost::dynamic_pointer_cast<Send>(_current_delivery);
send->set_metering (true);
_current_delivery->GoingAway.connect (mem_fun (*this, &MixerStrip::revert_to_default_display));
gain_meter().set_controls (_route, send->meter(), send->amp()->gain_control(), send->amp());
panner_ui().set_panner (_current_delivery->panner());
_current_send->set_metering (true); } else {
_current_send->GoingAway.connect (mem_fun (*this, &MixerStrip::revert_to_default_display)); _current_delivery = _route->main_outs ();
gain_meter().set_controls (_route, _route->shared_peak_meter(), _route->gain_control(), _route->amp());
panner_ui().set_panner (_route->main_outs()->panner());
} }
gain_meter().set_io (to_display);
gain_meter().setup_meters (); gain_meter().setup_meters ();
panner_ui().set_io (to_display);
panner_ui().setup_pan (); panner_ui().setup_pan ();
} }
@ -1544,14 +1464,17 @@ MixerStrip::revert_to_default_display ()
{ {
show_sends_button->set_active (false); show_sends_button->set_active (false);
if (_current_send) { boost::shared_ptr<Send> send;
_current_send->set_metering (false);
_current_send.reset(); if (_current_delivery && (send = boost::dynamic_pointer_cast<Send>(_current_delivery))) {
send->set_metering (false);
} }
gain_meter().set_io (_route); _current_delivery = _route->main_outs();
gain_meter().set_controls (_route, _route->shared_peak_meter(), _route->gain_control(), _route->amp());
gain_meter().setup_meters (); gain_meter().setup_meters ();
panner_ui().set_io (_route); panner_ui().set_panner (_route->main_outs()->panner());
panner_ui().setup_pan (); panner_ui().setup_pan ();
} }

View file

@ -242,15 +242,6 @@ class MixerStrip : public RouteUI, public Gtk::EventBox
void route_active_changed (); void route_active_changed ();
/* speed control (for tracks only) */
Gtk::Adjustment speed_adjustment;
Gtkmm2ext::ClickBox speed_spinner;
Gtk::Label speed_label;
Gtk::Frame speed_frame;
void speed_adjustment_changed ();
void speed_changed ();
void name_changed (); void name_changed ();
void update_speed_display (); void update_speed_display ();
void map_frozen (); void map_frozen ();
@ -263,7 +254,7 @@ class MixerStrip : public RouteUI, public Gtk::EventBox
void engine_stopped(); void engine_stopped();
void switch_io (boost::shared_ptr<ARDOUR::Route>); void switch_io (boost::shared_ptr<ARDOUR::Route>);
boost::shared_ptr<ARDOUR::Send> _current_send; boost::shared_ptr<ARDOUR::Delivery> _current_delivery;
void revert_to_default_display (); void revert_to_default_display ();
static int scrollbar_height; static int scrollbar_height;

View file

@ -25,6 +25,7 @@
#include <gtkmm2ext/barcontroller.h> #include <gtkmm2ext/barcontroller.h>
#include "midi++/manager.h" #include "midi++/manager.h"
#include "pbd/fastlog.h" #include "pbd/fastlog.h"
#include "pbd/stacktrace.h"
#include "ardour_ui.h" #include "ardour_ui.h"
#include "panner_ui.h" #include "panner_ui.h"
@ -33,6 +34,7 @@
#include "panner.h" #include "panner.h"
#include "gui_thread.h" #include "gui_thread.h"
#include "ardour/delivery.h"
#include "ardour/session.h" #include "ardour/session.h"
#include "ardour/panner.h" #include "ardour/panner.h"
#include "ardour/route.h" #include "ardour/route.h"
@ -131,13 +133,8 @@ PannerUI::PannerUI (Session& s)
} }
void void
PannerUI::set_io (boost::shared_ptr<IO> io) PannerUI::set_panner (boost::shared_ptr<Panner> p)
{ {
if (io && !io->panner()) {
cerr << "PannerUI::set_io IO has no panners" << endl;
return;
}
connections.clear (); connections.clear ();
delete pan_astyle_menu; delete pan_astyle_menu;
@ -146,18 +143,18 @@ PannerUI::set_io (boost::shared_ptr<IO> io)
delete pan_astate_menu; delete pan_astate_menu;
pan_astate_menu = 0; pan_astate_menu = 0;
_io = io; _panner = p;
delete panner; delete panner;
panner = 0; panner = 0;
if (!_io) { if (!_panner) {
return; return;
} }
connections.push_back (_io->panner()->Changed.connect (mem_fun(*this, &PannerUI::panner_changed))); connections.push_back (_panner->Changed.connect (mem_fun(*this, &PannerUI::panner_changed)));
connections.push_back (_io->panner()->LinkStateChanged.connect (mem_fun(*this, &PannerUI::update_pan_linkage))); connections.push_back (_panner->LinkStateChanged.connect (mem_fun(*this, &PannerUI::update_pan_linkage)));
connections.push_back (_io->panner()->StateChanged.connect (mem_fun(*this, &PannerUI::update_pan_state))); connections.push_back (_panner->StateChanged.connect (mem_fun(*this, &PannerUI::update_pan_state)));
setup_pan (); setup_pan ();
@ -196,16 +193,16 @@ PannerUI::build_astate_menu ()
} }
pan_astate_menu->items().push_back (MenuElem (_("Manual"), bind ( pan_astate_menu->items().push_back (MenuElem (_("Manual"), bind (
mem_fun (_io->panner().get(), &Panner::set_automation_state), mem_fun (_panner.get(), &Panner::set_automation_state),
(AutoState) Off))); (AutoState) Off)));
pan_astate_menu->items().push_back (MenuElem (_("Play"), bind ( pan_astate_menu->items().push_back (MenuElem (_("Play"), bind (
mem_fun (_io->panner().get(), &Panner::set_automation_state), mem_fun (_panner.get(), &Panner::set_automation_state),
(AutoState) Play))); (AutoState) Play)));
pan_astate_menu->items().push_back (MenuElem (_("Write"), bind ( pan_astate_menu->items().push_back (MenuElem (_("Write"), bind (
mem_fun (_io->panner().get(), &Panner::set_automation_state), mem_fun (_panner.get(), &Panner::set_automation_state),
(AutoState) Write))); (AutoState) Write)));
pan_astate_menu->items().push_back (MenuElem (_("Touch"), bind ( pan_astate_menu->items().push_back (MenuElem (_("Touch"), bind (
mem_fun (_io->panner().get(), &Panner::set_automation_state), mem_fun (_panner.get(), &Panner::set_automation_state),
(AutoState) Touch))); (AutoState) Touch)));
} }
@ -242,7 +239,7 @@ bool
PannerUI::panning_link_button_release (GdkEventButton* ev) PannerUI::panning_link_button_release (GdkEventButton* ev)
{ {
if (!ignore_toggle) { if (!ignore_toggle) {
_io->panner()->set_linked (!_io->panner()->linked()); _panner->set_linked (!_panner->linked());
} }
return true; return true;
} }
@ -250,12 +247,12 @@ PannerUI::panning_link_button_release (GdkEventButton* ev)
void void
PannerUI::panning_link_direction_clicked() PannerUI::panning_link_direction_clicked()
{ {
switch (_io->panner()->link_direction()) { switch (_panner->link_direction()) {
case Panner::SameDirection: case Panner::SameDirection:
_io->panner()->set_link_direction (Panner::OppositeDirection); _panner->set_link_direction (Panner::OppositeDirection);
break; break;
default: default:
_io->panner()->set_link_direction (Panner::SameDirection); _panner->set_link_direction (Panner::SameDirection);
break; break;
} }
} }
@ -265,7 +262,7 @@ PannerUI::update_pan_linkage ()
{ {
ENSURE_GUI_THREAD(mem_fun(*this, &PannerUI::update_pan_linkage)); ENSURE_GUI_THREAD(mem_fun(*this, &PannerUI::update_pan_linkage));
bool x = _io->panner()->linked(); bool x = _panner->linked();
bool bx = panning_link_button.get_active(); bool bx = panning_link_button.get_active();
if (x != bx) { if (x != bx) {
@ -277,7 +274,7 @@ PannerUI::update_pan_linkage ()
panning_link_direction_button.set_sensitive (x); panning_link_direction_button.set_sensitive (x);
switch (_io->panner()->link_direction()) { switch (_panner->link_direction()) {
case Panner::SameDirection: case Panner::SameDirection:
panning_link_direction_button.set_image (*(manage (new Image (get_xpm ("forwardblarrow.xpm"))))); panning_link_direction_button.set_image (*(manage (new Image (get_xpm ("forwardblarrow.xpm")))));
break; break;
@ -339,11 +336,16 @@ PannerUI::update_pan_state ()
void void
PannerUI::setup_pan () PannerUI::setup_pan ()
{ {
if (!_io || !_io->panner()) { cerr << "Setup pan for " << _panner->name() << endl;
// PBD::stacktrace (cerr, 5);
if (!_panner) {
return; return;
} }
uint32_t nouts = _io->n_outputs ().n_audio(); uint32_t nouts = _panner->nouts();
cerr << "\tnouts = " << nouts << endl;
if (nouts == 0 || nouts == 1) { if (nouts == 0 || nouts == 1) {
@ -364,7 +366,7 @@ PannerUI::setup_pan ()
} else if (nouts == 2) { } else if (nouts == 2) {
vector<Adjustment*>::size_type asz; vector<Adjustment*>::size_type asz;
uint32_t npans = _io->panner()->npanners(); uint32_t npans = _panner->npanners();
while (!pan_adjustments.empty()) { while (!pan_adjustments.empty()) {
delete pan_bars.back(); delete pan_bars.back();
@ -381,7 +383,7 @@ PannerUI::setup_pan ()
/* initialize adjustment with 0.0 (L) or 1.0 (R) for the first and second panners, /* initialize adjustment with 0.0 (L) or 1.0 (R) for the first and second panners,
which serves as a default, otherwise use current value */ which serves as a default, otherwise use current value */
rx = _io->panner()->pan_control( asz)->get_value(); rx = _panner->pan_control( asz)->get_value();
if (npans == 1) { if (npans == 1) {
x = 0.5; x = 0.5;
@ -395,20 +397,24 @@ PannerUI::setup_pan ()
pan_adjustments.push_back (new Adjustment (x, 0, 1.0, 0.005, 0.05)); pan_adjustments.push_back (new Adjustment (x, 0, 1.0, 0.005, 0.05));
bc = new PannerBar (*pan_adjustments[asz], bc = new PannerBar (*pan_adjustments[asz],
boost::static_pointer_cast<PBD::Controllable>( _io->panner()->pan_control( asz )) ); boost::static_pointer_cast<PBD::Controllable>( _panner->pan_control( asz )) );
/* now set adjustment with current value of panner, then connect the signals */ /* now set adjustment with current value of panner, then connect the signals */
pan_adjustments.back()->set_value(rx); pan_adjustments.back()->set_value(rx);
pan_adjustments.back()->signal_value_changed().connect (bind (mem_fun(*this, &PannerUI::pan_adjustment_changed), (uint32_t) asz)); pan_adjustments.back()->signal_value_changed().connect (bind (mem_fun(*this, &PannerUI::pan_adjustment_changed), (uint32_t) asz));
_io->panner()->pan_control( asz )->Changed.connect (bind (mem_fun(*this, &PannerUI::pan_value_changed), (uint32_t) asz)); _panner->pan_control( asz )->Changed.connect (bind (mem_fun(*this, &PannerUI::pan_value_changed), (uint32_t) asz));
bc->set_name ("PanSlider"); bc->set_name ("PanSlider");
bc->set_shadow_type (Gtk::SHADOW_NONE); bc->set_shadow_type (Gtk::SHADOW_NONE);
bc->StartGesture.connect (bind (mem_fun (*_io, &IO::start_pan_touch), (uint32_t) asz)); boost::shared_ptr<AutomationControl> ac = _panner->pan_control (asz);
bc->StopGesture.connect (bind (mem_fun (*_io, &IO::end_pan_touch), (uint32_t) asz));
if (asz) {
bc->StartGesture.connect (mem_fun (*ac, &AutomationControl::start_touch));
bc->StopGesture.connect (mem_fun (*ac, &AutomationControl::stop_touch));
}
char buf[64]; char buf[64];
snprintf (buf, sizeof (buf), _("panner for channel %zu"), asz + 1); snprintf (buf, sizeof (buf), _("panner for channel %zu"), asz + 1);
@ -437,7 +443,7 @@ PannerUI::setup_pan ()
} else { } else {
if (!panner) { if (!panner) {
panner = new Panner2d (_io->panner(), 61); panner = new Panner2d (_panner, 61);
panner->set_name ("MixerPanZone"); panner->set_name ("MixerPanZone");
panner->show (); panner->show ();
@ -446,9 +452,9 @@ PannerUI::setup_pan ()
} }
update_pan_sensitive (); update_pan_sensitive ();
panner->reset (_io->n_inputs().n_audio()); panner->reset (nouts);
if (big_window) { if (big_window) {
big_window->reset (_io->n_inputs().n_audio()); big_window->reset (_panner->npanners());
} }
panner->set_size_request (-1, 61); panner->set_size_request (-1, 61);
@ -467,7 +473,7 @@ PannerUI::pan_button_event (GdkEventButton* ev, uint32_t which)
case 1: case 1:
if (panner && ev->type == GDK_2BUTTON_PRESS) { if (panner && ev->type == GDK_2BUTTON_PRESS) {
if (!big_window) { if (!big_window) {
big_window = new Panner2dWindow (panner->get_panner(), 400, _io->n_inputs().n_audio()); big_window = new Panner2dWindow (_panner, 400, _panner->npanners());
} }
big_window->show (); big_window->show ();
return true; return true;
@ -502,7 +508,7 @@ PannerUI::build_pan_menu (uint32_t which)
/* set state first, connect second */ /* set state first, connect second */
(dynamic_cast<CheckMenuItem*> (&items.back()))->set_active (_io->panner()->streampanner(which).muted()); (dynamic_cast<CheckMenuItem*> (&items.back()))->set_active (_panner->streampanner(which).muted());
(dynamic_cast<CheckMenuItem*> (&items.back()))->signal_toggled().connect (dynamic_cast<CheckMenuItem*> (&items.back()))->signal_toggled().connect
(bind (mem_fun(*this, &PannerUI::pan_mute), which)); (bind (mem_fun(*this, &PannerUI::pan_mute), which));
@ -511,7 +517,7 @@ PannerUI::build_pan_menu (uint32_t which)
/* set state first, connect second */ /* set state first, connect second */
bypass_menu_item->set_active (_io->panner()->bypassed()); bypass_menu_item->set_active (_panner->bypassed());
bypass_menu_item->signal_toggled().connect (mem_fun(*this, &PannerUI::pan_bypass_toggle)); bypass_menu_item->signal_toggled().connect (mem_fun(*this, &PannerUI::pan_bypass_toggle));
items.push_back (MenuElem (_("Reset"), bind (mem_fun (*this, &PannerUI::pan_reset), which))); items.push_back (MenuElem (_("Reset"), bind (mem_fun (*this, &PannerUI::pan_reset), which)));
@ -522,38 +528,38 @@ PannerUI::build_pan_menu (uint32_t which)
void void
PannerUI::pan_mute (uint32_t which) PannerUI::pan_mute (uint32_t which)
{ {
StreamPanner& sp = _io->panner()->streampanner(which); StreamPanner& sp = _panner->streampanner(which);
sp.set_muted (!sp.muted()); sp.set_muted (!sp.muted());
} }
void void
PannerUI::pan_bypass_toggle () PannerUI::pan_bypass_toggle ()
{ {
if (bypass_menu_item && (_io->panner()->bypassed() != bypass_menu_item->get_active())) { if (bypass_menu_item && (_panner->bypassed() != bypass_menu_item->get_active())) {
_io->panner()->set_bypassed (!_io->panner()->bypassed()); _panner->set_bypassed (!_panner->bypassed());
} }
} }
void void
PannerUI::pan_reset (uint32_t which) PannerUI::pan_reset (uint32_t which)
{ {
_io->panner()->reset_streampanner (which); _panner->reset_streampanner (which);
} }
void void
PannerUI::pan_reset_all () PannerUI::pan_reset_all ()
{ {
_io->panner()->reset_to_default (); _panner->reset_to_default ();
} }
void void
PannerUI::effective_pan_display () PannerUI::effective_pan_display ()
{ {
if (_io->panner()->empty()) { if (_panner->empty()) {
return; return;
} }
switch (_io->n_outputs().n_audio()) { switch (_panner->nouts()) {
case 0: case 0:
case 1: case 1:
/* relax */ /* relax */
@ -576,7 +582,7 @@ PannerUI::pan_changed (void *src)
return; return;
} }
switch (_io->panner()->npanners()) { switch (_panner->npanners()) {
case 0: case 0:
panning_link_direction_button.set_sensitive (false); panning_link_direction_button.set_sensitive (false);
panning_link_button.set_sensitive (false); panning_link_button.set_sensitive (false);
@ -590,7 +596,7 @@ PannerUI::pan_changed (void *src)
panning_link_button.set_sensitive (true); panning_link_button.set_sensitive (true);
} }
uint32_t nouts = _io->n_outputs().n_audio(); uint32_t nouts = _panner->nouts();
switch (nouts) { switch (nouts) {
case 0: case 0:
@ -612,11 +618,11 @@ PannerUI::pan_changed (void *src)
void void
PannerUI::pan_adjustment_changed (uint32_t which) PannerUI::pan_adjustment_changed (uint32_t which)
{ {
if (!in_pan_update && which < _io->panner()->npanners()) { if (!in_pan_update && which < _panner->npanners()) {
float xpos; float xpos;
float val = pan_adjustments[which]->get_value (); float val = pan_adjustments[which]->get_value ();
xpos = _io->panner()->pan_control( which )->get_value(); xpos = _panner->pan_control( which )->get_value();
/* add a kinda-sorta detent for the middle */ /* add a kinda-sorta detent for the middle */
@ -633,7 +639,7 @@ PannerUI::pan_adjustment_changed (uint32_t which)
if (!Panner::equivalent (val, xpos)) { if (!Panner::equivalent (val, xpos)) {
_io->panner()->streampanner(which).set_position (val); _panner->streampanner(which).set_position (val);
/* XXX /* XXX
the panner objects have no access to the session, the panner objects have no access to the session,
so do this here. ick. so do this here. ick.
@ -648,11 +654,11 @@ PannerUI::pan_value_changed (uint32_t which)
{ {
ENSURE_GUI_THREAD (bind (mem_fun(*this, &PannerUI::pan_value_changed), which)); ENSURE_GUI_THREAD (bind (mem_fun(*this, &PannerUI::pan_value_changed), which));
if (_io->n_outputs().n_audio() > 1 && which < _io->panner()->npanners()) { if (_panner->npanners() > 1 && which < _panner->npanners()) {
float xpos; float xpos;
float val = pan_adjustments[which]->get_value (); float val = pan_adjustments[which]->get_value ();
_io->panner()->streampanner(which).get_position (xpos); _panner->streampanner(which).get_position (xpos);
if (!Panner::equivalent (val, xpos)) { if (!Panner::equivalent (val, xpos)) {
in_pan_update = true; in_pan_update = true;
@ -678,14 +684,14 @@ PannerUI::update_pan_bars (bool only_if_aplay)
float xpos, val; float xpos, val;
if (only_if_aplay) { if (only_if_aplay) {
boost::shared_ptr<AutomationList> alist (_io->panner()->streampanner(n).pan_control()->alist()); boost::shared_ptr<AutomationList> alist (_panner->streampanner(n).pan_control()->alist());
if (!alist->automation_playback()) { if (!alist->automation_playback()) {
continue; continue;
} }
} }
_io->panner()->streampanner(n).get_effective_position (xpos); _panner->streampanner(n).get_effective_position (xpos);
val = (*i)->get_value (); val = (*i)->get_value ();
if (!Panner::equivalent (val, xpos)) { if (!Panner::equivalent (val, xpos)) {
@ -699,9 +705,9 @@ PannerUI::update_pan_bars (bool only_if_aplay)
void void
PannerUI::update_pan_sensitive () PannerUI::update_pan_sensitive ()
{ {
bool sensitive = !(_io->panner()->automation_state() & Play); bool sensitive = !(_panner->automation_state() & Play);
switch (_io->n_outputs().n_audio()) { switch (_panner->nouts()) {
case 0: case 0:
case 1: case 1:
break; break;
@ -771,10 +777,10 @@ PannerUI::pan_automation_style_changed ()
switch (_width) { switch (_width) {
case Wide: case Wide:
pan_automation_style_button.set_label (astyle_string(_io->panner()->automation_style())); pan_automation_style_button.set_label (astyle_string(_panner->automation_style()));
break; break;
case Narrow: case Narrow:
pan_automation_style_button.set_label (short_astyle_string(_io->panner()->automation_style())); pan_automation_style_button.set_label (short_astyle_string(_panner->automation_style()));
break; break;
} }
} }
@ -788,10 +794,10 @@ PannerUI::pan_automation_state_changed ()
switch (_width) { switch (_width) {
case Wide: case Wide:
pan_automation_state_button.set_label (astate_string(_io->panner()->automation_state())); pan_automation_state_button.set_label (astate_string(_panner->automation_state()));
break; break;
case Narrow: case Narrow:
pan_automation_state_button.set_label (short_astate_string(_io->panner()->automation_state())); pan_automation_state_button.set_label (short_astate_string(_panner->automation_state()));
break; break;
} }
@ -800,11 +806,11 @@ PannerUI::pan_automation_state_changed ()
here. here.
*/ */
if (_io->panner()->empty()) { if (_panner->empty()) {
return; return;
} }
x = (_io->panner()->streampanner(0).pan_control()->alist()->automation_state() != Off); x = (_panner->streampanner(0).pan_control()->alist()->automation_state() != Off);
if (pan_automation_state_button.get_active() != x) { if (pan_automation_state_button.get_active() != x) {
ignore_toggle = true; ignore_toggle = true;

View file

@ -40,8 +40,9 @@ class PannerBar;
class Panner2dWindow; class Panner2dWindow;
namespace ARDOUR { namespace ARDOUR {
class IO;
class Session; class Session;
class Panner;
class Delivery;
} }
namespace Gtkmm2ext { namespace Gtkmm2ext {
class FastMeter; class FastMeter;
@ -58,7 +59,7 @@ class PannerUI : public Gtk::HBox
PannerUI (ARDOUR::Session&); PannerUI (ARDOUR::Session&);
~PannerUI (); ~PannerUI ();
virtual void set_io (boost::shared_ptr<ARDOUR::IO>); virtual void set_panner (boost::shared_ptr<ARDOUR::Panner>);
void pan_changed (void *); void pan_changed (void *);
@ -76,7 +77,7 @@ class PannerUI : public Gtk::HBox
private: private:
friend class MixerStrip; friend class MixerStrip;
boost::shared_ptr<ARDOUR::IO> _io; boost::shared_ptr<ARDOUR::Panner> _panner;
ARDOUR::Session& _session; ARDOUR::Session& _session;
std::vector<sigc::connection> connections; std::vector<sigc::connection> connections;

View file

@ -36,6 +36,7 @@
using namespace std; using namespace std;
using namespace Gtk; using namespace Gtk;
using namespace ARDOUR;
/** PortGroup constructor. /** PortGroup constructor.
* @param n Name. * @param n Name.
@ -50,7 +51,7 @@ PortGroup::PortGroup (std::string const & n)
* @param b Bundle. * @param b Bundle.
*/ */
void void
PortGroup::add_bundle (boost::shared_ptr<ARDOUR::Bundle> b) PortGroup::add_bundle (boost::shared_ptr<Bundle> b)
{ {
assert (b.get()); assert (b.get());
_bundles.push_back (b); _bundles.push_back (b);
@ -62,11 +63,11 @@ PortGroup::add_bundle (boost::shared_ptr<ARDOUR::Bundle> b)
} }
void void
PortGroup::remove_bundle (boost::shared_ptr<ARDOUR::Bundle> b) PortGroup::remove_bundle (boost::shared_ptr<Bundle> b)
{ {
assert (b.get()); assert (b.get());
ARDOUR::BundleList::iterator i = std::find (_bundles.begin(), _bundles.end(), b); BundleList::iterator i = std::find (_bundles.begin(), _bundles.end(), b);
if (i == _bundles.end()) { if (i == _bundles.end()) {
return; return;
} }
@ -78,7 +79,7 @@ PortGroup::remove_bundle (boost::shared_ptr<ARDOUR::Bundle> b)
} }
void void
PortGroup::bundle_changed (ARDOUR::Bundle::Change c) PortGroup::bundle_changed (Bundle::Change c)
{ {
BundleChanged (c); BundleChanged (c);
} }
@ -103,7 +104,7 @@ PortGroup::clear ()
bool bool
PortGroup::has_port (std::string const& p) const PortGroup::has_port (std::string const& p) const
{ {
for (ARDOUR::BundleList::const_iterator i = _bundles.begin(); i != _bundles.end(); ++i) { for (BundleList::const_iterator i = _bundles.begin(); i != _bundles.end(); ++i) {
if ((*i)->offers_port_alone (p)) { if ((*i)->offers_port_alone (p)) {
return true; return true;
} }
@ -112,7 +113,7 @@ PortGroup::has_port (std::string const& p) const
return false; return false;
} }
boost::shared_ptr<ARDOUR::Bundle> boost::shared_ptr<Bundle>
PortGroup::only_bundle () PortGroup::only_bundle ()
{ {
assert (_bundles.size() == 1); assert (_bundles.size() == 1);
@ -124,7 +125,7 @@ uint32_t
PortGroup::total_channels () const PortGroup::total_channels () const
{ {
uint32_t n = 0; uint32_t n = 0;
for (ARDOUR::BundleList::const_iterator i = _bundles.begin(); i != _bundles.end(); ++i) { for (BundleList::const_iterator i = _bundles.begin(); i != _bundles.end(); ++i) {
n += (*i)->nchannels (); n += (*i)->nchannels ();
} }
@ -135,21 +136,49 @@ PortGroup::total_channels () const
/** PortGroupList constructor. /** PortGroupList constructor.
*/ */
PortGroupList::PortGroupList () PortGroupList::PortGroupList ()
: _type (ARDOUR::DataType::AUDIO), _signals_suspended (false), _pending_change (false) : _type (DataType::AUDIO), _signals_suspended (false), _pending_change (false)
{ {
} }
void void
PortGroupList::set_type (ARDOUR::DataType t) PortGroupList::set_type (DataType t)
{ {
_type = t; _type = t;
clear (); clear ();
} }
void
PortGroupList::maybe_add_processor_to_bundle (boost::weak_ptr<Processor> wp, boost::shared_ptr<RouteBundle> rb, bool inputs)
{
boost::shared_ptr<Processor> p (wp.lock());
if (!p) {
return;
}
boost::shared_ptr<IOProcessor> iop = boost::dynamic_pointer_cast<IOProcessor> (p);
if (iop) {
if (inputs) {
if (!iop->output()) {
return;
}
} else {
if (!iop->input()) {
return;
}
}
rb->add_processor_bundle (inputs ? iop->output()->bundle() : iop->input()->bundle());
}
}
/** Gather bundles from around the system and put them in this PortGroupList */ /** Gather bundles from around the system and put them in this PortGroupList */
void void
PortGroupList::gather (ARDOUR::Session& session, bool inputs) PortGroupList::gather (Session& session, bool inputs)
{ {
clear (); clear ();
@ -162,49 +191,28 @@ PortGroupList::gather (ARDOUR::Session& session, bool inputs)
the route's IO bundles and processor bundles together so that they the route's IO bundles and processor bundles together so that they
are presented as one bundle in the matrix. */ are presented as one bundle in the matrix. */
boost::shared_ptr<ARDOUR::RouteList> routes = session.get_routes (); boost::shared_ptr<RouteList> routes = session.get_routes ();
for (ARDOUR::RouteList::const_iterator i = routes->begin(); i != routes->end(); ++i) { for (RouteList::const_iterator i = routes->begin(); i != routes->end(); ++i) {
boost::shared_ptr<RouteBundle> rb ( boost::shared_ptr<RouteBundle> rb (new RouteBundle (inputs ? (*i)->output()->bundle() : (*i)->input()->bundle()));
new RouteBundle (
inputs ? (*i)->bundle_for_inputs() : (*i)->bundle_for_outputs()
)
);
uint32_t n = 0; (*i)->foreach_processor (bind (mem_fun (*this, &PortGroupList::maybe_add_processor_to_bundle), rb, inputs));
while (1) {
boost::shared_ptr<ARDOUR::Processor> p = (*i)->nth_processor (n);
if (p == 0) {
break;
}
boost::shared_ptr<ARDOUR::IOProcessor> iop = boost::dynamic_pointer_cast<ARDOUR::IOProcessor> (p);
if (iop) {
rb->add_processor_bundle (
inputs ? iop->io()->bundle_for_inputs() : iop->io()->bundle_for_outputs()
);
}
++n;
}
/* Work out which group to put this bundle in */ /* Work out which group to put this bundle in */
boost::shared_ptr<PortGroup> g; boost::shared_ptr<PortGroup> g;
if (_type == ARDOUR::DataType::AUDIO) { if (_type == DataType::AUDIO) {
if (boost::dynamic_pointer_cast<ARDOUR::AudioTrack> (*i)) { if (boost::dynamic_pointer_cast<AudioTrack> (*i)) {
g = track; g = track;
} else if (!boost::dynamic_pointer_cast<ARDOUR::MidiTrack>(*i)) { } else if (!boost::dynamic_pointer_cast<MidiTrack>(*i)) {
g = bus; g = bus;
} }
} else if (_type == ARDOUR::DataType::MIDI) { } else if (_type == DataType::MIDI) {
if (boost::dynamic_pointer_cast<ARDOUR::MidiTrack> (*i)) { if (boost::dynamic_pointer_cast<MidiTrack> (*i)) {
g = track; g = track;
} }
@ -219,11 +227,11 @@ PortGroupList::gather (ARDOUR::Session& session, bool inputs)
/* Bundles owned by the session. We only add the mono ones and the User ones /* Bundles owned by the session. We only add the mono ones and the User ones
otherwise there is duplication of the same ports within the matrix */ otherwise there is duplication of the same ports within the matrix */
boost::shared_ptr<ARDOUR::BundleList> b = session.bundles (); boost::shared_ptr<BundleList> b = session.bundles ();
for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) { for (BundleList::iterator i = b->begin(); i != b->end(); ++i) {
if ((*i)->ports_are_inputs() == inputs && (*i)->type() == _type) { if ((*i)->ports_are_inputs() == inputs && (*i)->type() == _type) {
if ((*i)->nchannels() == 1 || boost::dynamic_pointer_cast<ARDOUR::UserBundle> (*i)) { if ((*i)->nchannels() == 1 || boost::dynamic_pointer_cast<UserBundle> (*i)) {
system->add_bundle (*i); system->add_bundle (*i);
} }
@ -282,10 +290,10 @@ PortGroupList::gather (ARDOUR::Session& session, bool inputs)
emit_changed (); emit_changed ();
} }
boost::shared_ptr<ARDOUR::Bundle> boost::shared_ptr<Bundle>
PortGroupList::make_bundle_from_ports (std::vector<std::string> const & p, bool inputs) const PortGroupList::make_bundle_from_ports (std::vector<std::string> const & p, bool inputs) const
{ {
boost::shared_ptr<ARDOUR::Bundle> b (new ARDOUR::Bundle ("", _type, inputs)); boost::shared_ptr<Bundle> b (new Bundle ("", _type, inputs));
std::string const pre = common_prefix (p); std::string const pre = common_prefix (p);
if (!pre.empty()) { if (!pre.empty()) {
@ -366,7 +374,7 @@ PortGroupList::clear ()
} }
ARDOUR::BundleList const & BundleList const &
PortGroupList::bundles () const PortGroupList::bundles () const
{ {
_bundles.clear (); _bundles.clear ();
@ -410,7 +418,7 @@ PortGroupList::add_group (boost::shared_ptr<PortGroup> g)
} }
void void
PortGroupList::remove_bundle (boost::shared_ptr<ARDOUR::Bundle> b) PortGroupList::remove_bundle (boost::shared_ptr<Bundle> b)
{ {
for (List::iterator i = _groups.begin(); i != _groups.end(); ++i) { for (List::iterator i = _groups.begin(); i != _groups.end(); ++i) {
(*i)->remove_bundle (b); (*i)->remove_bundle (b);
@ -446,7 +454,7 @@ PortGroupList::resume_signals ()
_signals_suspended = false; _signals_suspended = false;
} }
RouteBundle::RouteBundle (boost::shared_ptr<ARDOUR::Bundle> r) RouteBundle::RouteBundle (boost::shared_ptr<Bundle> r)
: _route (r) : _route (r)
{ {
_route->Changed.connect (sigc::hide (sigc::mem_fun (*this, &RouteBundle::reread_component_bundles))); _route->Changed.connect (sigc::hide (sigc::mem_fun (*this, &RouteBundle::reread_component_bundles)));
@ -470,7 +478,7 @@ RouteBundle::reread_component_bundles ()
} }
} }
for (std::vector<boost::shared_ptr<ARDOUR::Bundle> >::iterator i = _processor.begin(); i != _processor.end(); ++i) { for (std::vector<boost::shared_ptr<Bundle> >::iterator i = _processor.begin(); i != _processor.end(); ++i) {
add_channels_from_bundle (*i); add_channels_from_bundle (*i);
} }
@ -478,7 +486,7 @@ RouteBundle::reread_component_bundles ()
} }
void void
RouteBundle::add_processor_bundle (boost::shared_ptr<ARDOUR::Bundle> p) RouteBundle::add_processor_bundle (boost::shared_ptr<Bundle> p)
{ {
p->Changed.connect (sigc::hide (sigc::mem_fun (*this, &RouteBundle::reread_component_bundles))); p->Changed.connect (sigc::hide (sigc::mem_fun (*this, &RouteBundle::reread_component_bundles)));
_processor.push_back (p); _processor.push_back (p);

View file

@ -31,9 +31,11 @@
namespace ARDOUR { namespace ARDOUR {
class Session; class Session;
class Bundle; class Bundle;
class Processor;
} }
class PortMatrix; class PortMatrix;
class RouteBundle;
/** A list of bundles and ports, grouped by some aspect of their /** A list of bundles and ports, grouped by some aspect of their
* type e.g. busses, tracks, system. Each group has 0 or more bundles * type e.g. busses, tracks, system. Each group has 0 or more bundles
@ -119,6 +121,7 @@ class PortGroupList : public sigc::trackable
std::string common_prefix_before (std::vector<std::string> const &, std::string const &) const; std::string common_prefix_before (std::vector<std::string> const &, std::string const &) const;
void emit_changed (); void emit_changed ();
boost::shared_ptr<ARDOUR::Bundle> make_bundle_from_ports (std::vector<std::string> const &, bool) const; boost::shared_ptr<ARDOUR::Bundle> make_bundle_from_ports (std::vector<std::string> const &, bool) const;
void maybe_add_processor_to_bundle (boost::weak_ptr<ARDOUR::Processor>, boost::shared_ptr<RouteBundle>, bool);
ARDOUR::DataType _type; ARDOUR::DataType _type;
mutable ARDOUR::BundleList _bundles; mutable ARDOUR::BundleList _bundles;

View file

@ -452,7 +452,7 @@ ProcessorBox::use_plugins (const SelectedPlugins& plugins)
} }
if (_route->add_processor (processor, _placement, &err_streams)) { if (_route->add_processor (processor, _placement, &err_streams)) {
weird_plugin_dialog (**p, err_streams, _route); weird_plugin_dialog (**p, err_streams);
// XXX SHAREDPTR delete plugin here .. do we even need to care? // XXX SHAREDPTR delete plugin here .. do we even need to care?
} else { } else {
@ -467,7 +467,7 @@ ProcessorBox::use_plugins (const SelectedPlugins& plugins)
} }
void void
ProcessorBox::weird_plugin_dialog (Plugin& p, Route::ProcessorStreams streams, boost::shared_ptr<IO> io) ProcessorBox::weird_plugin_dialog (Plugin& p, Route::ProcessorStreams streams)
{ {
ArdourDialog dialog (_("ardour: weird plugin dialog")); ArdourDialog dialog (_("ardour: weird plugin dialog"));
Label label; Label label;
@ -511,7 +511,7 @@ ProcessorBox::weird_plugin_dialog (Plugin& p, Route::ProcessorStreams streams, b
void void
ProcessorBox::choose_insert () ProcessorBox::choose_insert ()
{ {
boost::shared_ptr<Processor> processor (new PortInsert (_session)); boost::shared_ptr<Processor> processor (new PortInsert (_session, _route->mute_master()));
processor->ActiveChanged.connect (bind ( processor->ActiveChanged.connect (bind (
mem_fun(*this, &ProcessorBox::show_processor_active), mem_fun(*this, &ProcessorBox::show_processor_active),
boost::weak_ptr<Processor>(processor))); boost::weak_ptr<Processor>(processor)));
@ -522,7 +522,7 @@ ProcessorBox::choose_insert ()
void void
ProcessorBox::choose_send () ProcessorBox::choose_send ()
{ {
boost::shared_ptr<Send> send (new Send (_session)); boost::shared_ptr<Send> send (new Send (_session, _route->mute_master()));
/* make an educated guess at the initial number of outputs for the send */ /* make an educated guess at the initial number of outputs for the send */
ChanCount outs = (_session.master_out()) ChanCount outs = (_session.master_out())
@ -531,14 +531,14 @@ ProcessorBox::choose_send ()
/* XXX need processor lock on route */ /* XXX need processor lock on route */
try { try {
send->io()->ensure_io (ChanCount::ZERO, outs, false, this); send->output()->ensure_io (outs, false, this);
} catch (AudioEngine::PortRegistrationFailure& err) { } catch (AudioEngine::PortRegistrationFailure& err) {
error << string_compose (_("Cannot set up new send: %1"), err.what()) << endmsg; error << string_compose (_("Cannot set up new send: %1"), err.what()) << endmsg;
return; return;
} }
/* let the user adjust the IO setup before creation */ /* let the user adjust the IO setup before creation */
IOSelectorWindow *ios = new IOSelectorWindow (_session, send->io(), false, true); IOSelectorWindow *ios = new IOSelectorWindow (_session, send->output(), true);
ios->show_all (); ios->show_all ();
/* keep a reference to the send so it doesn't get deleted while /* keep a reference to the send so it doesn't get deleted while
@ -588,14 +588,14 @@ ProcessorBox::choose_return ()
/* XXX need processor lock on route */ /* XXX need processor lock on route */
try { try {
retrn->io()->ensure_io (ins, ChanCount::ZERO, false, this); retrn->input()->ensure_io (ins, false, this);
} catch (AudioEngine::PortRegistrationFailure& err) { } catch (AudioEngine::PortRegistrationFailure& err) {
error << string_compose (_("Cannot set up new return: %1"), err.what()) << endmsg; error << string_compose (_("Cannot set up new return: %1"), err.what()) << endmsg;
return; return;
} }
/* let the user adjust the IO setup before creation */ /* let the user adjust the IO setup before creation */
IOSelectorWindow *ios = new IOSelectorWindow (_session, retrn->io(), true, true); IOSelectorWindow *ios = new IOSelectorWindow (_session, retrn->output(), true);
ios->show_all (); ios->show_all ();
/* keep a reference to the send so it doesn't get deleted while /* keep a reference to the send so it doesn't get deleted while
@ -1050,7 +1050,7 @@ ProcessorBox::paste_processor_state (const XMLNodeList& nlist)
if (type->value() == "send") { if (type->value() == "send") {
XMLNode n (**niter); XMLNode n (**niter);
Send::make_unique (n, _session); Send::make_unique (n, _session);
p.reset (new Send (_session, n)); p.reset (new Send (_session, _route->mute_master(), n));
} else if (type->value() == "meter") { } else if (type->value() == "meter") {
p = _route->shared_peak_meter(); p = _route->shared_peak_meter();
@ -1064,7 +1064,7 @@ ProcessorBox::paste_processor_state (const XMLNodeList& nlist)
continue; continue;
} else if (type->value() == "listen") { } else if (type->value() == "listen") {
p.reset (new Delivery (_session, **niter)); p.reset (new Delivery (_session, _route->mute_master(), **niter));
} else { } else {
p.reset (new PluginInsert (_session, **niter)); p.reset (new PluginInsert (_session, **niter));
@ -1214,8 +1214,8 @@ ProcessorBox::edit_processor (boost::shared_ptr<Processor> processor)
gidget = send_ui; gidget = send_ui;
#else #else
if (_parent_strip) { if (_parent_strip) {
_parent_strip->gain_meter().set_io (send->io()); _parent_strip->gain_meter().set_controls (_route, send->meter(), send->amp()->gain_control(), send->amp());
_parent_strip->panner_ui().set_io (send->io()); _parent_strip->panner_ui().set_panner (send->panner());
} }
#endif #endif

View file

@ -205,7 +205,7 @@ class ProcessorBox : public Gtk::HBox, public PluginInterestedObject
gint idle_delete_processor (boost::weak_ptr<ARDOUR::Processor>); gint idle_delete_processor (boost::weak_ptr<ARDOUR::Processor>);
void weird_plugin_dialog (ARDOUR::Plugin& p, ARDOUR::Route::ProcessorStreams streams, boost::shared_ptr<ARDOUR::IO> io); void weird_plugin_dialog (ARDOUR::Plugin& p, ARDOUR::Route::ProcessorStreams streams);
static ProcessorBox* _current_processor_box; static ProcessorBox* _current_processor_box;
static bool enter_box (GdkEventCrossing*, ProcessorBox*); static bool enter_box (GdkEventCrossing*, ProcessorBox*);

View file

@ -19,6 +19,7 @@
#include <gtkmm2ext/doi.h> #include <gtkmm2ext/doi.h>
#include "ardour/amp.h"
#include "ardour/io.h" #include "ardour/io.h"
#include "ardour/return.h" #include "ardour/return.h"
@ -37,7 +38,7 @@ ReturnUI::ReturnUI (boost::shared_ptr<Return> r, Session& se)
, _session (se) , _session (se)
, _gpm (se) , _gpm (se)
{ {
_gpm.set_io (r->io()); _gpm.set_controls (boost::shared_ptr<Route>(), r->meter(), r->amp()->gain_control(), r->amp());
_hbox.pack_start (_gpm, true, true); _hbox.pack_start (_gpm, true, true);
set_name ("ReturnUIFrame"); set_name ("ReturnUIFrame");
@ -47,7 +48,7 @@ ReturnUI::ReturnUI (boost::shared_ptr<Return> r, Session& se)
_vbox.pack_start (_hbox, false, false, false); _vbox.pack_start (_hbox, false, false, false);
io = manage (new IOSelector (se, r->io(), true)); io = manage (new IOSelector (se, r->output()));
pack_start (_vbox, false, false); pack_start (_vbox, false, false);
@ -55,10 +56,8 @@ ReturnUI::ReturnUI (boost::shared_ptr<Return> r, Session& se)
show_all (); show_all ();
//_return->set_metering (true); _return->set_metering (true);
_return->input()->changed.connect (mem_fun (*this, &ReturnUI::ins_changed));
_return->io()->input_changed.connect (mem_fun (*this, &ReturnUI::ins_changed));
//_return->io()->output_changed.connect (mem_fun (*this, &ReturnUI::outs_changed));
_gpm.setup_meters (); _gpm.setup_meters ();
_gpm.set_fader_name ("ReturnUIFrame"); _gpm.set_fader_name ("ReturnUIFrame");
@ -69,7 +68,7 @@ ReturnUI::ReturnUI (boost::shared_ptr<Return> r, Session& se)
ReturnUI::~ReturnUI () ReturnUI::~ReturnUI ()
{ {
//_return->set_metering (false); _return->set_metering (false);
/* XXX not clear that we need to do this */ /* XXX not clear that we need to do this */
@ -111,12 +110,8 @@ ReturnUIWindow::ReturnUIWindow (boost::shared_ptr<Return> s, Session& ss)
set_name ("ReturnUIWindow"); set_name ("ReturnUIWindow");
going_away_connection = s->GoingAway.connect ( going_away_connection = s->GoingAway.connect (mem_fun (*this, &ReturnUIWindow::return_going_away));
mem_fun (*this, &ReturnUIWindow::return_going_away)); signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it), reinterpret_cast<Window *> (this)));
signal_delete_event().connect (bind (
sigc::ptr_fun (just_hide_it),
reinterpret_cast<Window *> (this)));
} }
ReturnUIWindow::~ReturnUIWindow () ReturnUIWindow::~ReturnUIWindow ()

View file

@ -298,7 +298,7 @@ RouteParams_UI::cleanup_latency_frame ()
void void
RouteParams_UI::setup_latency_frame () RouteParams_UI::setup_latency_frame ()
{ {
latency_widget = new LatencyGUI (*(_route.get()), session->frame_rate(), session->engine().frames_per_cycle()); latency_widget = new LatencyGUI (*(_route->output()), session->frame_rate(), session->engine().frames_per_cycle());
char buf[128]; char buf[128];
snprintf (buf, sizeof (buf), _("Playback delay: %u samples"), _route->initial_delay()); snprintf (buf, sizeof (buf), _("Playback delay: %u samples"), _route->initial_delay());
@ -322,13 +322,13 @@ RouteParams_UI::setup_io_frames()
cleanup_io_frames(); cleanup_io_frames();
// input // input
_input_iosel = new IOSelector (*session, _route, false); _input_iosel = new IOSelector (*session, _route->input());
_input_iosel->setup (); _input_iosel->setup ();
input_frame.add (*_input_iosel); input_frame.add (*_input_iosel);
input_frame.show_all(); input_frame.show_all();
// output // output
_output_iosel = new IOSelector (*session, _route, true); _output_iosel = new IOSelector (*session, _route->output());
_output_iosel->setup (); _output_iosel->setup ();
output_frame.add (*_output_iosel); output_frame.add (*_output_iosel);
output_frame.show_all(); output_frame.show_all();

View file

@ -40,6 +40,7 @@
#include <gtkmm2ext/bindable_button.h> #include <gtkmm2ext/bindable_button.h>
#include <gtkmm2ext/utils.h> #include <gtkmm2ext/utils.h>
#include "ardour/amp.h"
#include "ardour/audioplaylist.h" #include "ardour/audioplaylist.h"
#include "ardour/diskstream.h" #include "ardour/diskstream.h"
#include "ardour/event_type_map.h" #include "ardour/event_type_map.h"
@ -110,7 +111,7 @@ RouteTimeAxisView::RouteTimeAxisView (PublicEditor& ed, Session& sess, boost::sh
visual_button (_("v")), visual_button (_("v")),
gm (sess, slider, true) gm (sess, slider, true)
{ {
gm.set_io (rt); gm.set_controls (_route, _route->shared_peak_meter(), _route->gain_control(), _route->amp());
gm.get_level_meter().set_no_show_all(); gm.get_level_meter().set_no_show_all();
gm.get_level_meter().setup_meters(50); gm.get_level_meter().setup_meters(50);
@ -187,8 +188,8 @@ RouteTimeAxisView::RouteTimeAxisView (PublicEditor& ed, Session& sess, boost::sh
controls_hbox.pack_start(gm.get_level_meter(), false, false); controls_hbox.pack_start(gm.get_level_meter(), false, false);
_route->meter_change.connect (mem_fun(*this, &RouteTimeAxisView::meter_changed)); _route->meter_change.connect (mem_fun(*this, &RouteTimeAxisView::meter_changed));
_route->input_changed.connect (mem_fun(*this, &RouteTimeAxisView::io_changed)); _route->input()->changed.connect (mem_fun(*this, &RouteTimeAxisView::io_changed));
_route->output_changed.connect (mem_fun(*this, &RouteTimeAxisView::io_changed)); _route->output()->changed.connect (mem_fun(*this, &RouteTimeAxisView::io_changed));
controls_table.attach (*mute_button, 6, 7, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0); controls_table.attach (*mute_button, 6, 7, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0);
controls_table.attach (*solo_button, 7, 8, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0); controls_table.attach (*solo_button, 7, 8, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0);
@ -231,7 +232,7 @@ RouteTimeAxisView::RouteTimeAxisView (PublicEditor& ed, Session& sess, boost::sh
_route->solo_changed.connect (mem_fun(*this, &RouteUI::solo_changed)); _route->solo_changed.connect (mem_fun(*this, &RouteUI::solo_changed));
_route->processors_changed.connect (mem_fun(*this, &RouteTimeAxisView::processors_changed)); _route->processors_changed.connect (mem_fun(*this, &RouteTimeAxisView::processors_changed));
_route->NameChanged.connect (mem_fun(*this, &RouteTimeAxisView::route_name_changed)); _route->NameChanged.connect (mem_fun(*this, &RouteTimeAxisView::route_name_changed));
_route->solo_safe_changed.connect (mem_fun(*this, &RouteUI::solo_changed)); _route->solo_isolated_changed.connect (mem_fun(*this, &RouteUI::solo_changed));
if (is_track()) { if (is_track()) {

View file

@ -101,7 +101,6 @@ RouteUI::init ()
ignore_toggle = false; ignore_toggle = false;
wait_for_release = false; wait_for_release = false;
route_active_menu_item = 0; route_active_menu_item = 0;
was_solo_safe = false;
polarity_menu_item = 0; polarity_menu_item = 0;
denormal_menu_item = 0; denormal_menu_item = 0;
multiple_mute_change = false; multiple_mute_change = false;
@ -192,7 +191,7 @@ RouteUI::set_route (boost::shared_ptr<Route> rp)
connections.push_back (_route->active_changed.connect (mem_fun (*this, &RouteUI::route_active_changed))); connections.push_back (_route->active_changed.connect (mem_fun (*this, &RouteUI::route_active_changed)));
connections.push_back (_route->mute_changed.connect (mem_fun(*this, &RouteUI::mute_changed))); connections.push_back (_route->mute_changed.connect (mem_fun(*this, &RouteUI::mute_changed)));
connections.push_back (_route->solo_changed.connect (mem_fun(*this, &RouteUI::solo_changed))); connections.push_back (_route->solo_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
connections.push_back (_route->solo_safe_changed.connect (mem_fun(*this, &RouteUI::solo_changed))); connections.push_back (_route->solo_isolated_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
if (is_track()) { if (is_track()) {
boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route); boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
@ -396,7 +395,7 @@ RouteUI::solo_press(GdkEventButton* ev)
Config->set_solo_latched (false); Config->set_solo_latched (false);
} }
} else { } else {
_route->set_solo_safe (!_route->solo_safe(), this); _route->set_solo_isolated (!_route->solo_isolated(), this);
wait_for_release = false; wait_for_release = false;
} }
@ -621,7 +620,7 @@ RouteUI::update_solo_display ()
ignore_toggle = false; ignore_toggle = false;
} }
if (_route->solo_safe()) { if (_route->solo_isolated()) {
solo_button->set_visual_state (2); solo_button->set_visual_state (2);
} else if (_route->soloed()) { } else if (_route->soloed()) {
solo_button->set_visual_state (1); solo_button->set_visual_state (1);
@ -663,8 +662,7 @@ RouteUI::update_mute_display ()
if (Config->get_show_solo_mutes()) { if (Config->get_show_solo_mutes()) {
if (_route->muted()) { if (_route->muted()) {
mute_button->set_visual_state (2); mute_button->set_visual_state (2);
} else if (!_route->soloed() && _route->solo_muted()) { } else if (!_route->soloed() && _session.soloing()) {
mute_button->set_visual_state (1); mute_button->set_visual_state (1);
} else { } else {
mute_button->set_visual_state (0); mute_button->set_visual_state (0);
@ -804,10 +802,10 @@ RouteUI::build_solo_menu (void)
MenuList& items = solo_menu->items(); MenuList& items = solo_menu->items();
CheckMenuItem* check; CheckMenuItem* check;
check = new CheckMenuItem(_("Solo Lock")); check = new CheckMenuItem(_("Solo Isolate"));
check->set_active (_route->solo_safe()); check->set_active (_route->solo_isolated());
check->signal_toggled().connect (bind (mem_fun (*this, &RouteUI::toggle_solo_safe), check)); check->signal_toggled().connect (bind (mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
_route->solo_safe_changed.connect(bind (mem_fun (*this, &RouteUI::solo_safe_toggle), check)); _route->solo_isolated_changed.connect(bind (mem_fun (*this, &RouteUI::solo_isolated_toggle), check));
items.push_back (CheckMenuElem(*check)); items.push_back (CheckMenuElem(*check));
check->show_all(); check->show_all();
@ -823,6 +821,8 @@ RouteUI::build_mute_menu(void)
mute_menu = new Menu; mute_menu = new Menu;
mute_menu->set_name ("ArdourContextMenu"); mute_menu->set_name ("ArdourContextMenu");
#if FIX_ME_IN_3_0
MenuList& items = mute_menu->items(); MenuList& items = mute_menu->items();
CheckMenuItem* check; CheckMenuItem* check;
@ -853,29 +853,27 @@ RouteUI::build_mute_menu(void)
_route->main_outs_changed.connect(bind (mem_fun (*this, &RouteUI::main_outs_toggle), check)); _route->main_outs_changed.connect(bind (mem_fun (*this, &RouteUI::main_outs_toggle), check));
items.push_back (CheckMenuElem(*check)); items.push_back (CheckMenuElem(*check));
check->show_all(); check->show_all();
#endif
//items.push_back (SeparatorElem()); //items.push_back (SeparatorElem());
// items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn))); // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
} }
void void
RouteUI::init_mute_menu(mute_type type, CheckMenuItem* check) RouteUI::init_mute_menu(MuteMaster::MutePoint mp, CheckMenuItem* check)
{ {
if (_route->get_mute_config (type)) { check->set_active (_route->mute_master()->muted_at (mp));
check->set_active (true);
}
} }
void void
RouteUI::toggle_mute_menu(mute_type type, Gtk::CheckMenuItem* check) RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
{ {
_route->set_mute_config(type, check->get_active(), this); // _route->set_mute_config(type, check->get_active(), this);
} }
void void
RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check) RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
{ {
_route->set_solo_safe (check->get_active(), this); _route->set_solo_isolated (check->get_active(), this);
} }
void void
@ -1166,16 +1164,17 @@ RouteUI::denormal_protection_changed ()
/* no signal for this yet */ /* no signal for this yet */
} }
void void
RouteUI::solo_safe_toggle(void* src, Gtk::CheckMenuItem* check) RouteUI::solo_isolated_toggle(void* src, Gtk::CheckMenuItem* check)
{ {
bool yn = _route->solo_safe (); bool yn = _route->solo_isolated ();
if (check->get_active() != yn) { if (check->get_active() != yn) {
check->set_active (yn); check->set_active (yn);
} }
} }
#ifdef FIX_THIS_FOR_3_0
void void
RouteUI::pre_fader_toggle(void* src, Gtk::CheckMenuItem* check) RouteUI::pre_fader_toggle(void* src, Gtk::CheckMenuItem* check)
{ {
@ -1219,17 +1218,18 @@ RouteUI::main_outs_toggle(void* src, Gtk::CheckMenuItem* check)
check->set_active (yn); check->set_active (yn);
} }
} }
#endif
void void
RouteUI::disconnect_input () RouteUI::disconnect_input ()
{ {
_route->disconnect_inputs (this); _route->input()->disconnect (this);
} }
void void
RouteUI::disconnect_output () RouteUI::disconnect_output ()
{ {
_route->disconnect_outputs (this); _route->output()->disconnect (this);
} }
bool bool
@ -1308,7 +1308,7 @@ RouteUI::map_frozen ()
void void
RouteUI::adjust_latency () RouteUI::adjust_latency ()
{ {
LatencyDialog dialog (_route->name() + _("latency"), *(_route.get()), _session.frame_rate(), _session.engine().frames_per_cycle()); LatencyDialog dialog (_route->name() + _("latency"), *(_route->output()), _session.frame_rate(), _session.engine().frames_per_cycle());
} }
void void

View file

@ -24,6 +24,7 @@
#include "pbd/xml++.h" #include "pbd/xml++.h"
#include "ardour/ardour.h" #include "ardour/ardour.h"
#include "ardour/mute_master.h"
#include "ardour/route.h" #include "ardour/route.h"
#include "ardour/track.h" #include "ardour/track.h"
@ -125,17 +126,17 @@ class RouteUI : public virtual AxisView
void build_remote_control_menu (void); void build_remote_control_menu (void);
void refresh_remote_control_menu (); void refresh_remote_control_menu ();
void solo_safe_toggle (void*, Gtk::CheckMenuItem*); void solo_isolated_toggle (void*, Gtk::CheckMenuItem*);
void toggle_solo_safe (Gtk::CheckMenuItem*); void toggle_solo_isolated (Gtk::CheckMenuItem*);
void toggle_mute_menu(ARDOUR::mute_type, Gtk::CheckMenuItem*); void toggle_mute_menu(ARDOUR::MuteMaster::MutePoint, Gtk::CheckMenuItem*);
void pre_fader_toggle(void*, Gtk::CheckMenuItem*); void pre_fader_toggle(void*, Gtk::CheckMenuItem*);
void post_fader_toggle(void*, Gtk::CheckMenuItem*); void post_fader_toggle(void*, Gtk::CheckMenuItem*);
void control_outs_toggle(void*, Gtk::CheckMenuItem*); void control_outs_toggle(void*, Gtk::CheckMenuItem*);
void main_outs_toggle(void*, Gtk::CheckMenuItem*); void main_outs_toggle(void*, Gtk::CheckMenuItem*);
void build_mute_menu(void); void build_mute_menu(void);
void init_mute_menu(ARDOUR::mute_type, Gtk::CheckMenuItem*); void init_mute_menu(ARDOUR::MuteMaster::MutePoint, Gtk::CheckMenuItem*);
void set_mix_group_solo(boost::shared_ptr<ARDOUR::Route>, bool); void set_mix_group_solo(boost::shared_ptr<ARDOUR::Route>, bool);
void set_mix_group_mute(boost::shared_ptr<ARDOUR::Route>, bool); void set_mix_group_mute(boost::shared_ptr<ARDOUR::Route>, bool);
@ -169,7 +170,6 @@ class RouteUI : public virtual AxisView
virtual void update_rec_display (); virtual void update_rec_display ();
void update_mute_display (); void update_mute_display ();
bool was_solo_safe;
void update_solo_display (); void update_solo_display ();
virtual void map_frozen (); virtual void map_frozen ();

View file

@ -19,6 +19,7 @@
#include <gtkmm2ext/doi.h> #include <gtkmm2ext/doi.h>
#include "ardour/amp.h"
#include "ardour/io.h" #include "ardour/io.h"
#include "ardour/send.h" #include "ardour/send.h"
@ -38,8 +39,8 @@ SendUI::SendUI (boost::shared_ptr<Send> s, Session& se)
, _gpm (se) , _gpm (se)
, _panners (se) , _panners (se)
{ {
_panners.set_io (s->io()); _panners.set_panner (s->panner());
_gpm.set_io (s->io()); _gpm.set_controls (boost::shared_ptr<Route>(), s->meter(), s->amp()->gain_control(), s->amp());
_hbox.pack_start (_gpm, true, true); _hbox.pack_start (_gpm, true, true);
set_name ("SendUIFrame"); set_name ("SendUIFrame");
@ -50,7 +51,7 @@ SendUI::SendUI (boost::shared_ptr<Send> s, Session& se)
_vbox.pack_start (_hbox, false, false, false); _vbox.pack_start (_hbox, false, false, false);
_vbox.pack_start (_panners, false,false); _vbox.pack_start (_panners, false,false);
io = manage (new IOSelector (se, s->io(), true)); io = manage (new IOSelector (se, s->output()));
pack_start (_vbox, false, false); pack_start (_vbox, false, false);
@ -60,8 +61,8 @@ SendUI::SendUI (boost::shared_ptr<Send> s, Session& se)
_send->set_metering (true); _send->set_metering (true);
_send->io()->input_changed.connect (mem_fun (*this, &SendUI::ins_changed)); _send->input()->changed.connect (mem_fun (*this, &SendUI::ins_changed));
_send->io()->output_changed.connect (mem_fun (*this, &SendUI::outs_changed)); _send->output()->changed.connect (mem_fun (*this, &SendUI::outs_changed));
_panners.set_width (Wide); _panners.set_width (Wide);
_panners.setup_pan (); _panners.setup_pan ();

View file

@ -25,12 +25,12 @@ public:
void setup_ports (int dim) void setup_ports (int dim)
{ {
cerr << _session.the_auditioner()->outputs().num_ports() << "\n"; cerr << _session.the_auditioner()->output()->n_ports() << "\n";
if (dim == OURS) { if (dim == OURS) {
_port_group->clear (); _port_group->clear ();
_port_group->add_bundle (_session.click_io()->bundle_for_outputs()); _port_group->add_bundle (_session.click_io()->bundle());
_port_group->add_bundle (_session.the_auditioner()->bundle_for_outputs()); _port_group->add_bundle (_session.the_auditioner()->output()->bundle());
} else { } else {
_ports[OTHER].gather (_session, true); _ports[OTHER].gather (_session, true);
} }
@ -41,7 +41,7 @@ public:
Bundle::PortList const & our_ports = c[OURS].bundle->channel_ports (c[OURS].channel); Bundle::PortList const & our_ports = c[OURS].bundle->channel_ports (c[OURS].channel);
Bundle::PortList const & other_ports = c[OTHER].bundle->channel_ports (c[OTHER].channel); Bundle::PortList const & other_ports = c[OTHER].bundle->channel_ports (c[OTHER].channel);
if (c[OURS].bundle == _session.click_io()->bundle_for_outputs()) { if (c[OURS].bundle == _session.click_io()->bundle()) {
for (ARDOUR::Bundle::PortList::const_iterator i = our_ports.begin(); i != our_ports.end(); ++i) { for (ARDOUR::Bundle::PortList::const_iterator i = our_ports.begin(); i != our_ports.end(); ++i) {
for (ARDOUR::Bundle::PortList::const_iterator j = other_ports.begin(); j != other_ports.end(); ++j) { for (ARDOUR::Bundle::PortList::const_iterator j = other_ports.begin(); j != other_ports.end(); ++j) {
@ -50,9 +50,9 @@ public:
assert (f); assert (f);
if (s) { if (s) {
_session.click_io()->connect_output (f, *j, 0); _session.click_io()->connect (f, *j, 0);
} else { } else {
_session.click_io()->disconnect_output (f, *j, 0); _session.click_io()->disconnect (f, *j, 0);
} }
} }
} }
@ -64,7 +64,7 @@ public:
Bundle::PortList const & our_ports = c[OURS].bundle->channel_ports (c[OURS].channel); Bundle::PortList const & our_ports = c[OURS].bundle->channel_ports (c[OURS].channel);
Bundle::PortList const & other_ports = c[OTHER].bundle->channel_ports (c[OTHER].channel); Bundle::PortList const & other_ports = c[OTHER].bundle->channel_ports (c[OTHER].channel);
if (c[OURS].bundle == _session.click_io()->bundle_for_outputs()) { if (c[OURS].bundle == _session.click_io()->bundle()) {
for (ARDOUR::Bundle::PortList::const_iterator i = our_ports.begin(); i != our_ports.end(); ++i) { for (ARDOUR::Bundle::PortList::const_iterator i = our_ports.begin(); i != our_ports.end(); ++i) {
for (ARDOUR::Bundle::PortList::const_iterator j = other_ports.begin(); j != other_ports.end(); ++j) { for (ARDOUR::Bundle::PortList::const_iterator j = other_ports.begin(); j != other_ports.end(); ++j) {

View file

@ -39,6 +39,7 @@
#include "evoral/SMF.hpp" #include "evoral/SMF.hpp"
#include "ardour/amp.h"
#include "ardour/audio_library.h" #include "ardour/audio_library.h"
#include "ardour/auditioner.h" #include "ardour/auditioner.h"
#include "ardour/audioregion.h" #include "ardour/audioregion.h"
@ -594,7 +595,10 @@ SoundFileBrowser::add_gain_meter ()
delete gm; delete gm;
gm = new GainMeter (*session); gm = new GainMeter (*session);
gm->set_io (session->the_auditioner());
boost::shared_ptr<Route> r = session->the_auditioner ();
gm->set_controls (r, r->shared_peak_meter(), r->gain_control(), r->amp());
meter_packer.set_border_width (12); meter_packer.set_border_width (12);
meter_packer.pack_start (*gm, false, true); meter_packer.pack_start (*gm, false, true);

View file

@ -118,6 +118,7 @@ midi_stretch.cc
midi_track.cc midi_track.cc
mix.cc mix.cc
mtc_slave.cc mtc_slave.cc
mute_master.cc
named_selection.cc named_selection.cc
onset_detector.cc onset_detector.cc
panner.cc panner.cc

View file

@ -19,24 +19,31 @@
#include <cstring> #include <cstring>
#include <cmath> #include <cmath>
#include <algorithm> #include <algorithm>
#include "evoral/Curve.hpp"
#include "ardour/amp.h" #include "ardour/amp.h"
#include "ardour/audio_buffer.h" #include "ardour/audio_buffer.h"
#include "ardour/buffer_set.h" #include "ardour/buffer_set.h"
#include "ardour/configuration.h" #include "ardour/configuration.h"
#include "ardour/io.h" #include "ardour/io.h"
#include "ardour/mute_master.h"
#include "ardour/session.h" #include "ardour/session.h"
namespace ARDOUR { #include "i18n.h"
Amp::Amp(Session& s, IO& io) using namespace ARDOUR;
Amp::Amp(Session& s, boost::shared_ptr<MuteMaster> mm)
: Processor(s, "Amp") : Processor(s, "Amp")
, _io(io)
, _mute(false)
, _apply_gain(true) , _apply_gain(true)
, _apply_gain_automation(false) , _apply_gain_automation(false)
, _current_gain(1.0) , _current_gain(1.0)
, _desired_gain(1.0) , _mute_master (mm)
{ {
boost::shared_ptr<AutomationList> gl(new AutomationList(Evoral::Parameter(GainAutomation)));
_gain_control = boost::shared_ptr<GainControl>( new GainControl(X_("gaincontrol"), s, this, Evoral::Parameter(GainAutomation), gl ));
add_control(_gain_control);
} }
bool bool
@ -59,64 +66,92 @@ Amp::configure_io (ChanCount in, ChanCount out)
void void
Amp::run_in_place (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes) Amp::run_in_place (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes)
{ {
gain_t* gab = _session.gain_automation_buffer(); gain_t mute_gain;
if (_mute && !bufs.is_silent()) { if (_mute_master) {
Amp::apply_gain (bufs, nframes, _current_mute_gain, _desired_mute_gain, false); mute_gain = _mute_master->mute_gain_at (MuteMaster::PreFader);
if (_desired_mute_gain == 0.0f) { } else {
bufs.is_silent(true); mute_gain = 1.0;
}
} }
if (_apply_gain) { if (_apply_gain) {
if (_apply_gain_automation) { if (_apply_gain_automation) {
if (_io.phase_invert()) { gain_t* gab = _session.gain_automation_buffer ();
if (mute_gain == 0.0) {
/* absolute mute */
if (_current_gain == 0.0) {
/* already silent */
for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i) {
i->clear ();
}
} else {
/* cut to silence */
Amp::apply_gain (bufs, nframes, _current_gain, 0.0);
_current_gain = 0.0;
}
} else if (mute_gain != 1.0) {
/* mute dimming */
for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i) { for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i) {
Sample* const sp = i->data(); Sample* const sp = i->data();
for (nframes_t nx = 0; nx < nframes; ++nx) { for (nframes_t nx = 0; nx < nframes; ++nx) {
sp[nx] *= -gab[nx]; sp[nx] *= gab[nx] * mute_gain;
} }
} }
_current_gain = gab[nframes-1] * mute_gain;
} else { } else {
/* no mute */
for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i) { for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i) {
Sample* const sp = i->data(); Sample* const sp = i->data();
for (nframes_t nx = 0; nx < nframes; ++nx) { for (nframes_t nx = 0; nx < nframes; ++nx) {
sp[nx] *= gab[nx]; sp[nx] *= gab[nx];
} }
} }
_current_gain = gab[nframes-1];
} }
} else { /* manual (scalar) gain */ } else { /* manual (scalar) gain */
if (_current_gain != _desired_gain) { gain_t dg = _gain_control->user_float() * mute_gain;
Amp::apply_gain (bufs, nframes, _current_gain, _desired_gain, _io.phase_invert()); if (_current_gain != dg) {
_current_gain = _desired_gain;
} else if (_current_gain != 0.0f && (_io.phase_invert() || _current_gain != 1.0f)) { Amp::apply_gain (bufs, nframes, _current_gain, dg);
_current_gain = dg;
/* no need to interpolate current gain value, } else if ((_current_gain != 0.0f) && (_current_gain != 1.0f)) {
but its non-unity, so apply it. if the gain
is zero, do nothing because we'll ship silence /* gain has not changed, but its non-unity, so apply it unless
below. its zero.
*/ */
gain_t this_gain;
if (_io.phase_invert()) {
this_gain = -_current_gain;
} else {
this_gain = _current_gain;
}
for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i) { for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i) {
Sample* const sp = i->data(); Sample* const sp = i->data();
apply_gain_to_buffer(sp, nframes, this_gain); apply_gain_to_buffer(sp, nframes, _current_gain);
} }
} else if (_current_gain == 0.0f) { } else if (_current_gain == 0.0f) {
/* silence! */
for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i) { for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i) {
i->clear(); i->clear();
} }
@ -125,30 +160,19 @@ Amp::run_in_place (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame,
} }
} }
/** Apply a declicked gain to the audio buffers of @a bufs */
void void
Amp::apply_gain (BufferSet& bufs, nframes_t nframes, Amp::apply_gain (BufferSet& bufs, nframes_t nframes, gain_t initial, gain_t target)
gain_t initial, gain_t target, bool invert_polarity)
{ {
if (nframes == 0) { /** Apply a (potentially) declicked gain to the audio buffers of @a bufs
return; */
}
if (bufs.count().n_audio() == 0) { if (nframes == 0 || bufs.count().n_audio() == 0) {
return; return;
} }
// if we don't need to declick, defer to apply_simple_gain // if we don't need to declick, defer to apply_simple_gain
if (initial == target) { if (initial == target) {
if (target == 0.0) { apply_simple_gain (bufs, nframes, target);
for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i) {
memset (i->data(), 0, sizeof (Sample) * nframes);
}
} else if (target != 1.0) {
for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i) {
apply_gain_to_buffer (i->data(), nframes, target);
}
}
return; return;
} }
@ -156,7 +180,7 @@ Amp::apply_gain (BufferSet& bufs, nframes_t nframes,
gain_t delta; gain_t delta;
double fractional_shift = -1.0/declick; double fractional_shift = -1.0/declick;
double fractional_pos; double fractional_pos;
gain_t polscale = invert_polarity ? -1.0f : 1.0f; gain_t polscale = 1.0f;
if (target < initial) { if (target < initial) {
/* fade out: remove more and more of delta from initial */ /* fade out: remove more and more of delta from initial */
@ -180,10 +204,6 @@ Amp::apply_gain (BufferSet& bufs, nframes_t nframes,
if (declick != nframes) { if (declick != nframes) {
if (invert_polarity) {
target = -target;
}
if (target == 0.0) { if (target == 0.0) {
memset (&buffer[declick], 0, sizeof (Sample) * (nframes - declick)); memset (&buffer[declick], 0, sizeof (Sample) * (nframes - declick));
} else if (target != 1.0) { } else if (target != 1.0) {
@ -196,6 +216,62 @@ Amp::apply_gain (BufferSet& bufs, nframes_t nframes,
void void
Amp::apply_simple_gain (BufferSet& bufs, nframes_t nframes, gain_t target) Amp::apply_simple_gain (BufferSet& bufs, nframes_t nframes, gain_t target)
{ {
if (target == 0.0) {
for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i) {
memset (i->data(), 0, sizeof (Sample) * nframes);
}
} else if (target != 1.0) {
for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i) {
apply_gain_to_buffer (i->data(), nframes, target);
}
}
}
void
Amp::inc_gain (gain_t factor, void *src)
{
float desired_gain = _gain_control->user_float();
if (desired_gain == 0.0f) {
set_gain (0.000001f + (0.000001f * factor), src);
} else {
set_gain (desired_gain + (desired_gain * factor), src);
}
}
void
Amp::set_gain (gain_t val, void *src)
{
// max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
if (val > 1.99526231f) {
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
// (this keeps control in sync with reality)
return;
}
{
// Glib::Mutex::Lock dm (declick_lock);
_gain_control->set_float(val, false);
}
if (_session.transport_stopped()) {
// _gain = val;
}
/*
if (_session.transport_stopped() && src != 0 && src != this && _gain_control->automation_write()) {
_gain_control->list()->add (_session.transport_frame(), val);
}
*/
_session.set_dirty();
} }
XMLNode& XMLNode&
@ -206,4 +282,33 @@ Amp::state (bool full_state)
return node; return node;
} }
} // namespace ARDOUR void
Amp::GainControl::set_value (float val)
{
// max gain at about +6dB (10.0 ^ ( 6 dB * 0.05))
if (val > 1.99526231f)
val = 1.99526231f;
_amp->set_gain (val, this);
AutomationControl::set_value(val);
}
float
Amp::GainControl::get_value (void) const
{
return AutomationControl::get_value();
}
void
Amp::setup_gain_automation (sframes_t start_frame, sframes_t end_frame, nframes_t nframes)
{
Glib::Mutex::Lock am (data().control_lock(), Glib::TRY_LOCK);
if (am.locked() && _session.transport_rolling() && _gain_control->automation_playback()) {
_apply_gain_automation = _gain_control->list()->curve().rt_safe_get_vector (
start_frame, end_frame, _session.gain_automation_buffer(), nframes);
} else {
_apply_gain_automation = false;
}
}

View file

@ -22,19 +22,20 @@
#include "ardour/types.h" #include "ardour/types.h"
#include "ardour/chan_count.h" #include "ardour/chan_count.h"
#include "ardour/processor.h" #include "ardour/processor.h"
#include "ardour/automation_control.h"
namespace ARDOUR { namespace ARDOUR {
class BufferSet; class BufferSet;
class IO; class IO;
class MuteMaster;
/** Applies a declick operation to all audio inputs, passing the same number of /** Applies a declick operation to all audio inputs, passing the same number of
* audio outputs, and passing through any other types unchanged. * audio outputs, and passing through any other types unchanged.
*/ */
class Amp : public Processor { class Amp : public Processor {
public: public:
Amp(Session& s, IO& io); Amp(Session& s, boost::shared_ptr<MuteMaster> m);
bool can_support_io_configuration (const ChanCount& in, ChanCount& out) const; bool can_support_io_configuration (const ChanCount& in, ChanCount& out) const;
bool configure_io (ChanCount in, ChanCount out); bool configure_io (ChanCount in, ChanCount out);
@ -44,38 +45,54 @@ public:
bool apply_gain() const { return _apply_gain; } bool apply_gain() const { return _apply_gain; }
void apply_gain(bool yn) { _apply_gain = yn; } void apply_gain(bool yn) { _apply_gain = yn; }
void setup_gain_automation (sframes_t start_frame, sframes_t end_frame, nframes_t nframes);
bool apply_gain_automation() const { return _apply_gain_automation; } bool apply_gain_automation() const { return _apply_gain_automation; }
void apply_gain_automation(bool yn) { _apply_gain_automation = yn; } void apply_gain_automation(bool yn) { _apply_gain_automation = yn; }
void muute(bool yn) { _mute = yn; }
void set_gain(float current, float desired) {
_current_gain = current;
_desired_gain = desired;
}
void apply_mute(bool yn, float current=1.0, float desired=0.0) {
_mute = yn;
_current_mute_gain = current;
_desired_mute_gain = desired;
}
XMLNode& state (bool full); XMLNode& state (bool full);
static void apply_gain (BufferSet& bufs, nframes_t nframes, static void apply_gain (BufferSet& bufs, nframes_t nframes, gain_t initial, gain_t target);
gain_t initial, gain_t target, bool invert_polarity);
static void apply_simple_gain(BufferSet& bufs, nframes_t nframes, gain_t target); static void apply_simple_gain(BufferSet& bufs, nframes_t nframes, gain_t target);
gain_t gain () const { return _gain_control->user_float(); }
virtual void set_gain (gain_t g, void *src);
void inc_gain (gain_t delta, void *src);
static void update_meters();
/* automation */
struct GainControl : public AutomationControl {
GainControl (std::string name, Session& session, Amp* a, const Evoral::Parameter &param,
boost::shared_ptr<AutomationList> al = boost::shared_ptr<AutomationList>() )
: AutomationControl (session, param, al, name )
, _amp (a)
{}
void set_value (float val);
float get_value (void) const;
Amp* _amp;
};
boost::shared_ptr<GainControl> gain_control() {
return _gain_control;
}
boost::shared_ptr<const GainControl> gain_control() const {
return _gain_control;
}
private: private:
IO& _io; bool _denormal_protection;
bool _mute; bool _apply_gain;
bool _apply_gain; bool _apply_gain_automation;
bool _apply_gain_automation; float _current_gain;
float _current_gain;
float _desired_gain; boost::shared_ptr<GainControl> _gain_control;
float _current_mute_gain; boost::shared_ptr<MuteMaster> _mute_master;
float _desired_mute_gain;
}; };

View file

@ -58,7 +58,7 @@ public:
virtual void add_control(boost::shared_ptr<Evoral::Control>); virtual void add_control(boost::shared_ptr<Evoral::Control>);
virtual void automation_snapshot(nframes_t now, bool force); virtual void automation_snapshot(nframes_t now, bool force);
virtual void transport_stopped(nframes_t now); virtual void transport_stopped (sframes_t now);
virtual std::string describe_parameter(Evoral::Parameter param); virtual std::string describe_parameter(Evoral::Parameter param);

View file

@ -27,7 +27,7 @@ namespace ARDOUR {
class ClickIO : public IO class ClickIO : public IO
{ {
public: public:
ClickIO (Session& s, const std::string& name) : IO (s, name) {} ClickIO (Session& s, const std::string& name) : IO (s, name, IO::Output) {}
~ClickIO() {} ~ClickIO() {}
protected: protected:

View file

@ -28,48 +28,91 @@ namespace ARDOUR {
class BufferSet; class BufferSet;
class IO; class IO;
class MuteMaster;
class Panner;
class Delivery : public IOProcessor { class Delivery : public IOProcessor {
public: public:
enum Role { enum Role {
Send = 0x1, Insert = 0x1,
Solo = 0x2, Send = 0x2,
Listen = 0x4, Listen = 0x4,
Main = 0x8 Main = 0x8
}; };
Delivery (Session& s, IO* io, const std::string& name, Role); Delivery (Session& s, boost::shared_ptr<IO> io, boost::shared_ptr<MuteMaster> mm, const std::string& name, Role);
Delivery (Session& s, const std::string& name, Role); Delivery (Session& s, boost::shared_ptr<MuteMaster> mm, const std::string& name, Role);
Delivery (Session&, const XMLNode&); Delivery (Session&, boost::shared_ptr<MuteMaster> mm, const XMLNode&);
bool set_name (const std::string& name);
bool visible() const; bool visible() const;
Role role() const { return _role; } Role role() const { return _role; }
bool can_support_io_configuration (const ChanCount& in, ChanCount& out) const; bool can_support_io_configuration (const ChanCount& in, ChanCount& out) const;
bool configure_io (ChanCount in, ChanCount out); bool configure_io (ChanCount in, ChanCount out);
void run_in_place (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes); void run_in_place (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes);
void set_metering (bool yn); /* supplemental method use with MIDI */
bool muted_by_self() const { return _muted_by_self; } void flush (nframes_t nframes);
bool muted_by_others() const { return _muted_by_others; }
void set_self_mute (bool); void no_outs_cuz_we_no_monitor(bool);
void set_nonself_mute (bool);
sigc::signal<void> SelfMuteChange; void mod_solo_level (int32_t);
sigc::signal<void> OtherMuteChange; uint32_t solo_level() const { return _solo_level; }
bool soloed () const { return (bool) _solo_level; }
bool solo_isolated() const { return _solo_isolated; }
void set_solo_isolated (bool);
void cycle_start (nframes_t);
void increment_output_offset (nframes_t);
void transport_stopped (sframes_t frame);
BufferSet& output_buffers() { return *_output_buffers; }
sigc::signal<void> MuteChange;
static sigc::signal<void,nframes_t> CycleStart;
XMLNode& state (bool full); XMLNode& state (bool full);
int set_state (const XMLNode&); int set_state (const XMLNode&);
private: /* Panning */
Role _role;
bool _metering; static int disable_panners (void);
bool _muted_by_self; static int reset_panners (void);
bool _muted_by_others;
boost::shared_ptr<Panner> panner() const { return _panner; }
void reset_panner ();
void defer_pan_reset ();
void allow_pan_reset ();
uint32_t pans_required() const { return _configured_input.n_audio(); }
void start_pan_touch (uint32_t which);
void end_pan_touch (uint32_t which);
protected:
Role _role;
BufferSet* _output_buffers;
gain_t _current_gain;
nframes_t _output_offset;
bool _no_outs_cuz_we_no_monitor;
uint32_t _solo_level;
bool _solo_isolated;
boost::shared_ptr<MuteMaster> _mute_master;
bool no_panner_reset;
boost::shared_ptr<Panner> _panner;
static bool panners_legal;
static sigc::signal<int> PannersLegal;
int panners_became_legal ();
sigc::connection panner_legal_c;
void output_changed (IOChange, void*);
gain_t target_gain ();
}; };

View file

@ -55,134 +55,83 @@ class AudioPort;
class BufferSet; class BufferSet;
class Bundle; class Bundle;
class MidiPort; class MidiPort;
class Panner;
class PeakMeter; class PeakMeter;
class Port; class Port;
class Processor;
class Session; class Session;
class UserBundle; class UserBundle;
/** A collection of input and output ports with connections. /** A collection of ports (all input or all output) with connections.
* *
* An IO can contain ports of varying types, making routes/inserts/etc with * An IO can contain ports of varying types, making routes/inserts/etc with
* varied combinations of types (eg MIDI and audio) possible. * varied combinations of types (eg MIDI and audio) possible.
*/ */
class IO : public SessionObject, public AutomatableControls, public Latent class IO : public SessionObject, public Latent
{ {
public: public:
static const std::string state_node_name; static const std::string state_node_name;
IO (Session&, const std::string& name, DataType default_type = DataType::AUDIO); enum Direction {
Input,
Output
};
IO (Session&, const std::string& name, Direction, DataType default_type = DataType::AUDIO);
IO (Session&, const XMLNode&, DataType default_type = DataType::AUDIO); IO (Session&, const XMLNode&, DataType default_type = DataType::AUDIO);
virtual ~IO(); virtual ~IO();
bool active() const { return _active; } Direction direction() const { return _direction; }
void set_active (bool yn);
DataType default_type() const { return _default_type; } DataType default_type() const { return _default_type; }
void set_default_type(DataType t) { _default_type = t; } void set_default_type(DataType t) { _default_type = t; }
bool active() const { return _active; }
void set_active(bool yn) { _active = yn; }
bool set_name (const std::string& str); bool set_name (const std::string& str);
virtual void silence (nframes_t); virtual void silence (nframes_t);
void collect_input (BufferSet& bufs, nframes_t nframes, ChanCount offset=ChanCount::ZERO); int ensure_io (ChanCount cnt, bool clear, void *src);
void deliver_output (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes);
void just_meter_input (sframes_t start_frame, sframes_t end_frame, nframes_t nframes);
BufferSet& output_buffers() { return *_output_buffers; } int connect_ports_to_bundle (boost::shared_ptr<Bundle>, void *);
int disconnect_ports_from_bundle (boost::shared_ptr<Bundle>, void *);
gain_t gain () const { return _gain_control->user_float(); } BundleList bundles_connected ();
virtual gain_t effective_gain () const;
void set_denormal_protection (bool yn, void *src); boost::shared_ptr<Bundle> bundle () { return _bundle; }
bool denormal_protection() const { return _denormal_protection; }
void set_phase_invert (bool yn, void *src);
bool phase_invert() const { return _phase_invert; }
void reset_panner ();
boost::shared_ptr<Amp> amp() const { return _amp; }
PeakMeter& peak_meter() { return *_meter.get(); }
const PeakMeter& peak_meter() const { return *_meter.get(); }
boost::shared_ptr<PeakMeter> shared_peak_meter() const { return _meter; }
boost::shared_ptr<Panner> panner() const { return _panner; }
int ensure_io (ChanCount in, ChanCount out, bool clear, void *src);
int connect_input_ports_to_bundle (boost::shared_ptr<Bundle>, void *);
int disconnect_input_ports_from_bundle (boost::shared_ptr<Bundle>, void *);
int connect_output_ports_to_bundle (boost::shared_ptr<Bundle>, void *);
int disconnect_output_ports_from_bundle (boost::shared_ptr<Bundle>, void *);
BundleList bundles_connected_to_inputs ();
BundleList bundles_connected_to_outputs ();
boost::shared_ptr<Bundle> bundle_for_inputs () { return _bundle_for_inputs; }
boost::shared_ptr<Bundle> bundle_for_outputs () { return _bundle_for_outputs; }
int add_input_port (std::string source, void *src, DataType type = DataType::NIL);
int add_output_port (std::string destination, void *src, DataType type = DataType::NIL);
int remove_input_port (Port *, void *src);
int remove_output_port (Port *, void *src);
int set_input (Port *, void *src);
int connect_input (Port *our_port, std::string other_port, void *src);
int connect_output (Port *our_port, std::string other_port, void *src);
int disconnect_input (Port *our_port, std::string other_port, void *src);
int disconnect_output (Port *our_port, std::string other_port, void *src);
int disconnect_inputs (void *src);
int disconnect_outputs (void *src);
int add_port (std::string connection, void *src, DataType type = DataType::NIL);
int remove_port (Port *, void *src);
int connect (Port *our_port, std::string other_port, void *src);
int disconnect (Port *our_port, std::string other_port, void *src);
int disconnect (void *src);
bool connected_to (boost::shared_ptr<const IO>) const; bool connected_to (boost::shared_ptr<const IO>) const;
nframes_t signal_latency() const { return _own_latency; } nframes_t signal_latency() const { return _own_latency; }
nframes_t output_latency() const; nframes_t latency() const;
nframes_t input_latency() const;
void set_port_latency (nframes_t); void set_port_latency (nframes_t);
void update_port_total_latencies (); void update_port_total_latencies ();
const PortSet& inputs() const { return _inputs; } PortSet& ports() { return _ports; }
const PortSet& outputs() const { return _outputs; } const PortSet& ports() const { return _ports; }
Port *output (uint32_t n) const { Port *nth (uint32_t n) const {
if (n < _outputs.num_ports()) { if (n < _ports.num_ports()) {
return _outputs.port(n); return _ports.port(n);
} else { } else {
return 0; return 0;
} }
} }
Port *input (uint32_t n) const { AudioPort* audio(uint32_t n) const;
if (n < _inputs.num_ports()) { MidiPort* midi(uint32_t n) const;
return _inputs.port(n);
} else {
return 0;
}
}
AudioPort* audio_input(uint32_t n) const; const ChanCount& n_ports () const { return _ports.count(); }
AudioPort* audio_output(uint32_t n) const;
MidiPort* midi_input(uint32_t n) const;
MidiPort* midi_output(uint32_t n) const;
const ChanCount& n_inputs () const { return _inputs.count(); } sigc::signal<void,IOChange,void*> changed;
const ChanCount& n_outputs () const { return _outputs.count(); }
void attach_buffers(ChanCount ignored);
sigc::signal<void> active_changed;
sigc::signal<void,IOChange,void*> input_changed;
sigc::signal<void,IOChange,void*> output_changed;
virtual XMLNode& state (bool full); virtual XMLNode& state (bool full);
XMLNode& get_state (void); XMLNode& get_state (void);
@ -192,130 +141,45 @@ class IO : public SessionObject, public AutomatableControls, public Latent
static int enable_connecting (void); static int enable_connecting (void);
static int disable_ports (void); static int disable_ports (void);
static int enable_ports (void); static int enable_ports (void);
static int disable_panners (void);
static int reset_panners (void);
static sigc::signal<int> PortsLegal; static sigc::signal<void,ChanCount> PortCountChanged; // emitted when the number of ports changes
static sigc::signal<int> PannersLegal;
static sigc::signal<int> ConnectingLegal;
/// raised when the number of input or output ports changes
static sigc::signal<void,ChanCount> PortCountChanged;
static sigc::signal<void,nframes_t> CycleStart;
static void update_meters();
static std::string name_from_state (const XMLNode&); static std::string name_from_state (const XMLNode&);
static void set_name_in_state (XMLNode&, const std::string&); static void set_name_in_state (XMLNode&, const std::string&);
private: /* we have to defer/order port connection. this is how we do it.
static sigc::signal<void> Meter;
static Glib::StaticMutex m_meter_signal_lock;
sigc::connection m_meter_connection;
public:
/* automation */
struct GainControl : public AutomationControl {
GainControl (std::string name, IO* i, const Evoral::Parameter &param,
boost::shared_ptr<AutomationList> al = boost::shared_ptr<AutomationList>() )
: AutomationControl (i->_session, param, al, name )
, _io (i)
{}
void set_value (float val);
float get_value (void) const;
IO* _io;
};
boost::shared_ptr<GainControl> gain_control() {
return _gain_control;
}
boost::shared_ptr<const GainControl> gain_control() const {
return _gain_control;
}
void clear_automation ();
void set_parameter_automation_state (Evoral::Parameter, AutoState);
virtual void transport_stopped (nframes_t now);
virtual void automation_snapshot (nframes_t now, bool force);
void start_pan_touch (uint32_t which);
void end_pan_touch (uint32_t which);
void defer_pan_reset ();
void allow_pan_reset ();
/* the session calls this for master outs before
anyone else. controls outs too, at some point.
*/ */
static sigc::signal<int> ConnectingLegal;
static bool connecting_legal;
XMLNode *pending_state_node; XMLNode *pending_state_node;
int ports_became_legal ();
/* three utility functions - this just seems to be simplest place to put them */
void collect_input (BufferSet& bufs, nframes_t nframes, ChanCount offset);
void process_input (boost::shared_ptr<Processor>, sframes_t start_frame, sframes_t end_frame, nframes_t nframes);
void copy_to_outputs (BufferSet& bufs, DataType type, nframes_t nframes, nframes_t offset);
/* AudioTrack::deprecated_use_diskstream_connections() needs these */
int set_ports (const std::string& str);
private: private:
mutable Glib::Mutex io_lock; mutable Glib::Mutex io_lock;
protected: protected:
BufferSet* _output_buffers; //< Set directly to output port buffers PortSet _ports;
bool _active; Direction _direction;
gain_t _gain; DataType _default_type;
Glib::Mutex declick_lock; bool _active;
PortSet _outputs;
PortSet _inputs;
bool no_panner_reset;
bool _phase_invert;
bool _denormal_protection;
XMLNode* deferred_state;
DataType _default_type;
nframes_t _output_offset;
boost::shared_ptr<Amp> _amp;
boost::shared_ptr<PeakMeter> _meter;
boost::shared_ptr<Panner> _panner;
virtual void prepare_inputs (nframes_t nframes);
virtual void flush_outputs (nframes_t nframes);
virtual void set_deferred_state() {}
virtual uint32_t pans_required() const
{ return _inputs.count().n_audio(); }
boost::shared_ptr<GainControl> _gain_control;
virtual void set_gain (gain_t g, void *src);
void inc_gain (gain_t delta, void *src);
virtual int load_automation (std::string path);
/* AudioTrack::deprecated_use_diskstream_connections() needs these */
int set_inputs (const std::string& str);
int set_outputs (const std::string& str);
void increment_output_offset (nframes_t);
void cycle_start (nframes_t);
static bool connecting_legal;
static bool ports_legal;
private: private:
static bool panners_legal;
void copy_to_outputs (BufferSet& bufs, DataType type, nframes_t nframes);
int connecting_became_legal (); int connecting_became_legal ();
int panners_became_legal ();
sigc::connection connection_legal_c; sigc::connection connection_legal_c;
sigc::connection port_legal_c;
sigc::connection panner_legal_c;
boost::shared_ptr<Bundle> _bundle_for_inputs; ///< a bundle representing our inputs boost::shared_ptr<Bundle> _bundle; ///< a bundle representing our ports
boost::shared_ptr<Bundle> _bundle_for_outputs; ///< a bundle representing our outputs
struct UserBundleInfo { struct UserBundleInfo {
UserBundleInfo (IO*, boost::shared_ptr<UserBundle> b); UserBundleInfo (IO*, boost::shared_ptr<UserBundle> b);
@ -324,45 +188,31 @@ class IO : public SessionObject, public AutomatableControls, public Latent
sigc::connection changed; sigc::connection changed;
}; };
std::vector<UserBundleInfo> _bundles_connected_to_outputs; ///< user bundles connected to our outputs std::vector<UserBundleInfo> _bundles_connected; ///< user bundles connected to our ports
std::vector<UserBundleInfo> _bundles_connected_to_inputs; ///< user bundles connected to our inputs
static int parse_io_string (const std::string&, std::vector<std::string>& chns); static int parse_io_string (const std::string&, std::vector<std::string>& chns);
static int parse_gain_string (const std::string&, std::vector<std::string>& chns); static int parse_gain_string (const std::string&, std::vector<std::string>& chns);
int set_sources (std::vector<std::string>&, void *src, bool add); int ensure_ports (ChanCount, bool clear, bool lockit, void *src);
int set_destinations (std::vector<std::string>&, void *src, bool add);
int ensure_inputs (ChanCount, bool clear, bool lockit, void *src); void check_bundles_connected ();
int ensure_outputs (ChanCount, bool clear, bool lockit, void *src);
void check_bundles_connected_to_inputs ();
void check_bundles_connected_to_outputs ();
void check_bundles (std::vector<UserBundleInfo>&, const PortSet&); void check_bundles (std::vector<UserBundleInfo>&, const PortSet&);
void bundle_changed (Bundle::Change); void bundle_changed (Bundle::Change);
int get_port_counts (const XMLNode& node, ChanCount& in, ChanCount& out, int get_port_counts (const XMLNode& node, ChanCount& n, boost::shared_ptr<Bundle>& c);
boost::shared_ptr<Bundle>& ic, boost::shared_ptr<Bundle>& oc);
int create_ports (const XMLNode&); int create_ports (const XMLNode&);
int make_connections (const XMLNode&); int make_connections (const XMLNode&);
boost::shared_ptr<Bundle> find_possible_bundle (const std::string &desired_name, const std::string &default_name, const std::string &connection_type_name);
virtual void setup_peak_meters (); boost::shared_ptr<Bundle> find_possible_bundle (const std::string &desired_name);
void meter ();
bool ensure_inputs_locked (ChanCount, bool clear, void *src); bool ensure_ports_locked (ChanCount, bool clear, void *src);
bool ensure_outputs_locked (ChanCount, bool clear, void *src);
std::string build_legal_port_name (DataType type, bool for_input); std::string build_legal_port_name (DataType type);
int32_t find_input_port_hole (const char* base); int32_t find_port_hole (const char* base);
int32_t find_output_port_hole (const char* base);
void setup_bundles_for_inputs_and_outputs (); void setup_bundles ();
void setup_bundle_for_inputs ();
void setup_bundle_for_outputs ();
std::string bundle_channel_name (uint32_t, uint32_t) const; std::string bundle_channel_name (uint32_t, uint32_t) const;
}; };

View file

@ -38,15 +38,16 @@ namespace ARDOUR {
class Session; class Session;
class IO; class IO;
/** A mixer strip element (Processor) with Jack ports (IO). /** A mixer strip element (Processor) with 1 or 2 IO elements.
*/ */
class IOProcessor : public Processor class IOProcessor : public Processor
{ {
public: public:
IOProcessor (Session&, const std::string& proc_name, const std::string io_name="", IOProcessor (Session&, bool with_input, bool with_output,
ARDOUR::DataType default_type = DataType::AUDIO); const std::string& proc_name, const std::string io_name="",
IOProcessor (Session&, IO* io, const std::string& proc_name,
ARDOUR::DataType default_type = DataType::AUDIO); ARDOUR::DataType default_type = DataType::AUDIO);
IOProcessor (Session&, boost::shared_ptr<IO> input, boost::shared_ptr<IO> output,
const std::string& proc_name, ARDOUR::DataType default_type = DataType::AUDIO);
virtual ~IOProcessor (); virtual ~IOProcessor ();
bool set_name (const std::string& str); bool set_name (const std::string& str);
@ -56,13 +57,14 @@ class IOProcessor : public Processor
virtual ChanCount natural_output_streams() const; virtual ChanCount natural_output_streams() const;
virtual ChanCount natural_input_streams () const; virtual ChanCount natural_input_streams () const;
boost::shared_ptr<IO> io() { return _io; } boost::shared_ptr<IO> input() { return _input; }
boost::shared_ptr<const IO> io() const { return _io; } boost::shared_ptr<const IO> input() const { return _input; }
void set_io (boost::shared_ptr<IO>); boost::shared_ptr<IO> output() { return _output; }
boost::shared_ptr<const IO> output() const { return _output; }
void set_input (boost::shared_ptr<IO>);
void set_output (boost::shared_ptr<IO>);
virtual void automation_snapshot (nframes_t now, bool force); void run_in_place (BufferSet& in, sframes_t start, sframes_t end, nframes_t nframes) = 0;
virtual void run_in_place (BufferSet& in, sframes_t start, sframes_t end, nframes_t nframes) = 0;
void silence (nframes_t nframes); void silence (nframes_t nframes);
sigc::signal<void,IOProcessor*,bool> AutomationPlaybackChanged; sigc::signal<void,IOProcessor*,bool> AutomationPlaybackChanged;
@ -72,12 +74,14 @@ class IOProcessor : public Processor
int set_state (const XMLNode&); int set_state (const XMLNode&);
protected: protected:
boost::shared_ptr<IO> _io; boost::shared_ptr<IO> _input;
boost::shared_ptr<IO> _output;
private: private:
/* disallow copy construction */ /* disallow copy construction */
IOProcessor (const IOProcessor&); IOProcessor (const IOProcessor&);
bool _own_io; bool _own_input;
bool _own_output;
}; };

View file

@ -20,6 +20,7 @@
#define __ardour_meter_h__ #define __ardour_meter_h__
#include <vector> #include <vector>
#include <sigc++/slot.h>
#include "ardour/types.h" #include "ardour/types.h"
#include "ardour/processor.h" #include "ardour/processor.h"
#include "pbd/fastlog.h" #include "pbd/fastlog.h"
@ -30,6 +31,20 @@ class BufferSet;
class ChanCount; class ChanCount;
class Session; class Session;
class Metering {
public:
static void update_meters ();
static sigc::signal<void> Meter;
static sigc::connection connect (sigc::slot<void> the_slot);
static void disconnect (sigc::connection& c);
private:
/* this object is not meant to be instantiated */
virtual void foo() = 0;
static Glib::StaticMutex m_meter_signal_lock;
};
/** Meters peaks on the input and stores them for access. /** Meters peaks on the input and stores them for access.
*/ */
@ -37,6 +52,8 @@ class PeakMeter : public Processor {
public: public:
PeakMeter(Session& s) : Processor(s, "Meter") {} PeakMeter(Session& s) : Processor(s, "Meter") {}
void meter();
void reset (); void reset ();
void reset_max (); void reset_max ();
@ -66,7 +83,6 @@ public:
private: private:
friend class IO; friend class IO;
void meter();
std::vector<float> _peak_power; std::vector<float> _peak_power;
std::vector<float> _visible_peak_power; std::vector<float> _visible_peak_power;

View file

@ -0,0 +1,77 @@
/*
Copyright (C) 2009 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __ardour_mute_master_h__
#define __ardour_mute_master_h__
#include "evoral/Parameter.hpp"
#include "ardour/automation_control.h"
#include "ardour/automation_list.h"
namespace ARDOUR {
class Session;
class MuteMaster : public AutomationControl
{
public:
enum MutePoint {
PreFader = 0x1,
PostFader = 0x2,
Listen = 0x4,
Main = 0x8
};
MuteMaster (Session& s, const std::string& name);
~MuteMaster() {}
bool muted_pre_fader() const { return _mute_point & PreFader; }
bool muted_post_fader() const { return _mute_point & PostFader; }
bool muted_listen() const { return _mute_point & Listen; }
bool muted_main () const { return _mute_point & Main; }
bool muted_at (MutePoint mp) const { return _mute_point & mp; }
bool muted() const { return _mute_point != MutePoint (0) && get_value() != 0.0; }
gain_t mute_gain_at (MutePoint) const;
void clear_mute ();
void mute_at (MutePoint);
void unmute_at (MutePoint);
void mute (bool yn);
/* Controllable interface */
void set_value (float); /* note: float is used as a bitfield of MutePoints */
float get_value () const;
sigc::signal<void> MutePointChanged;
XMLNode& get_state();
int set_state(const XMLNode& node);
private:
AutomationList* _automation;
MutePoint _mute_point;
};
} // namespace ARDOUR
#endif /*__ardour_mute_master_h__ */

View file

@ -183,7 +183,7 @@ class Multi2dPanner : public StreamPanner
}; };
class Panner : public Processor class Panner : public SessionObject, public AutomatableControls
{ {
public: public:
struct Output { struct Output {
@ -204,18 +204,16 @@ class Panner : public Processor
void clear_panners (); void clear_panners ();
bool empty() const { return _streampanners.empty(); } bool empty() const { return _streampanners.empty(); }
/// The fundamental Panner function
void set_automation_state (AutoState); void set_automation_state (AutoState);
AutoState automation_state() const; AutoState automation_state() const;
void set_automation_style (AutoStyle); void set_automation_style (AutoStyle);
AutoStyle automation_style() const; AutoStyle automation_style() const;
bool touching() const; bool touching() const;
bool is_in_place () const { return false; }
bool is_out_of_place () const { return true; }
bool can_support_io_configuration (const ChanCount& in, ChanCount& out) const { return true; }; bool can_support_io_configuration (const ChanCount& in, ChanCount& out) const { return true; };
void run_out_of_place(BufferSet& src, BufferSet& dest, sframes_t start_frame, sframes_t end_frames, nframes_t nframes); /// The fundamental Panner function
void run (BufferSet& src, BufferSet& dest, sframes_t start_frame, sframes_t end_frames, nframes_t nframes);
//void* get_inline_gui() const = 0; //void* get_inline_gui() const = 0;
//void* get_full_gui() const = 0; //void* get_full_gui() const = 0;

View file

@ -34,26 +34,29 @@ class XMLNode;
namespace ARDOUR { namespace ARDOUR {
class Session; class Session;
class IO;
class Delivery;
class MuteMaster;
/** Port inserts: send output to a Jack port, pick up input at a Jack port /** Port inserts: send output to a Jack port, pick up input at a Jack port
*/ */
class PortInsert : public IOProcessor class PortInsert : public IOProcessor
{ {
public: public:
PortInsert (Session&); PortInsert (Session&, boost::shared_ptr<MuteMaster> mm);
PortInsert (Session&, const XMLNode&); PortInsert (Session&, boost::shared_ptr<MuteMaster> mm, const XMLNode&);
~PortInsert (); ~PortInsert ();
XMLNode& state(bool full); XMLNode& state(bool full);
XMLNode& get_state(void); XMLNode& get_state(void);
int set_state(const XMLNode&); int set_state(const XMLNode&);
void init ();
void run_in_place (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes); void run_in_place (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes);
nframes_t signal_latency() const; nframes_t signal_latency() const;
bool set_name (const std::string& name);
bool can_support_io_configuration (const ChanCount& in, ChanCount& out) const; bool can_support_io_configuration (const ChanCount& in, ChanCount& out) const;
bool configure_io (ChanCount in, ChanCount out); bool configure_io (ChanCount in, ChanCount out);
@ -63,6 +66,8 @@ class PortInsert : public IOProcessor
/* disallow copy construction */ /* disallow copy construction */
PortInsert (const PortInsert&); PortInsert (const PortInsert&);
boost::shared_ptr<Delivery> _out;
uint32_t bitslot; uint32_t bitslot;
}; };

View file

@ -53,24 +53,26 @@ class Processor : public SessionObject, public AutomatableControls, public Laten
virtual ~Processor() { } virtual ~Processor() { }
/** Configuration of a processor on a bus
* (i.e. how to apply to a BufferSet)
*/
struct Mapping {
ChanCount in;
ChanCount out;
};
virtual bool visible() const { return true; } virtual bool visible() const { return true; }
bool active () const { return _active; } bool active () const { return _active; }
/* we keep loose tabs on the "placement" of a Processor. Ultimately,
they are all executed as a single list, but there are some
semantics that require knowing whether a Processor is before
or after the fader, or panner etc. See Route::reorder_processors()
to see where this gets set.
*/
Placement placement() const { return _placement; }
void set_placement (Placement p) { _placement = p; }
bool get_next_ab_is_active () const { return _next_ab_is_active; } bool get_next_ab_is_active () const { return _next_ab_is_active; }
void set_next_ab_is_active (bool yn) { _next_ab_is_active = yn; } void set_next_ab_is_active (bool yn) { _next_ab_is_active = yn; }
virtual nframes_t signal_latency() const { return 0; } virtual nframes_t signal_latency() const { return 0; }
virtual void transport_stopped (nframes_t frame) {} virtual void transport_stopped (sframes_t frame) {}
virtual void set_block_size (nframes_t nframes) {} virtual void set_block_size (nframes_t nframes) {}
@ -127,7 +129,7 @@ protected:
ChanCount _configured_input; ChanCount _configured_input;
ChanCount _configured_output; ChanCount _configured_output;
void* _gui; /* generic, we don't know or care what this is */ void* _gui; /* generic, we don't know or care what this is */
Mapping _mapping; Placement _placement;
}; };
} // namespace ARDOUR } // namespace ARDOUR

View file

@ -84,6 +84,7 @@ CONFIG_VARIABLE (bool, all_safe, "all-safe", false)
CONFIG_VARIABLE (bool, show_solo_mutes, "show-solo-mutes", false) CONFIG_VARIABLE (bool, show_solo_mutes, "show-solo-mutes", false)
CONFIG_VARIABLE (bool, solo_mute_override, "solo-mute-override", false) CONFIG_VARIABLE (bool, solo_mute_override, "solo-mute-override", false)
CONFIG_VARIABLE (bool, tape_machine_mode, "tape-machine-mode", false) CONFIG_VARIABLE (bool, tape_machine_mode, "tape-machine-mode", false)
CONFIG_VARIABLE (gain_t, solo_mute_gain, "solo_mute-gain", 0.0)
/* click */ /* click */

View file

@ -32,6 +32,9 @@
namespace ARDOUR { namespace ARDOUR {
class Amp;
class PeakMeter;
class Return : public IOProcessor class Return : public IOProcessor
{ {
public: public:
@ -43,8 +46,11 @@ public:
void run_in_place (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes); void run_in_place (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes);
void activate() {} boost::shared_ptr<Amp> amp() const { return _amp; }
void deactivate () {} boost::shared_ptr<PeakMeter> meter() const { return _meter; }
bool metering() const { return _metering; }
void set_metering (bool yn) { _metering = yn; }
XMLNode& state(bool full); XMLNode& state(bool full);
XMLNode& get_state(void); XMLNode& get_state(void);
@ -55,14 +61,22 @@ public:
bool can_support_io_configuration (const ChanCount& in, ChanCount& out) const; bool can_support_io_configuration (const ChanCount& in, ChanCount& out) const;
bool configure_io (ChanCount in, ChanCount out); bool configure_io (ChanCount in, ChanCount out);
static uint32_t how_many_sends(); static uint32_t how_many_returns();
static void make_unique (XMLNode &, Session &); static void make_unique (XMLNode &, Session &);
protected:
bool _metering;
boost::shared_ptr<Amp> _amp;
boost::shared_ptr<PeakMeter> _meter;
private: private:
/* disallow copy construction */ /* disallow copy construction */
Return (const Return&); Return (const Return&);
uint32_t _bitslot; uint32_t _bitslot;
void collect_input (BufferSet& bufs, nframes_t nframes, ChanCount offset=ChanCount::ZERO);
void just_meter_input (sframes_t start_frame, sframes_t end_frame, nframes_t nframes);
}; };
} // namespace ARDOUR } // namespace ARDOUR

View file

@ -41,24 +41,19 @@
#include "ardour/ardour.h" #include "ardour/ardour.h"
#include "ardour/io.h" #include "ardour/io.h"
#include "ardour/types.h" #include "ardour/types.h"
#include "ardour/mute_master.h"
namespace ARDOUR { namespace ARDOUR {
class Amp; class Amp;
class Delivery; class Delivery;
class IOProcessor; class IOProcessor;
class Panner;
class Processor; class Processor;
class RouteGroup; class RouteGroup;
class Send; class Send;
enum mute_type { class Route : public SessionObject, public AutomatableControls
PRE_FADER = 0x1,
POST_FADER = 0x2,
CONTROL_OUTS = 0x4,
MAIN_OUTS = 0x8
};
class Route : public IO
{ {
public: public:
@ -75,6 +70,16 @@ class Route : public IO
Route (Session&, const XMLNode&, DataType default_type = DataType::AUDIO); Route (Session&, const XMLNode&, DataType default_type = DataType::AUDIO);
virtual ~Route(); virtual ~Route();
boost::shared_ptr<IO> input() const { return _input; }
boost::shared_ptr<IO> output() const { return _output; }
ChanCount n_inputs() const { return _input->n_ports(); }
ChanCount n_outputs() const { return _output->n_ports(); }
bool active() const { return _active; }
void set_active (bool yn);
static std::string ensure_track_or_route_name(std::string, Session &); static std::string ensure_track_or_route_name(std::string, Session &);
std::string comment() { return _comment; } std::string comment() { return _comment; }
@ -102,6 +107,7 @@ class Route : public IO
virtual void toggle_monitor_input (); virtual void toggle_monitor_input ();
virtual bool can_record() { return false; } virtual bool can_record() { return false; }
virtual void set_record_enable (bool yn, void *src) {} virtual void set_record_enable (bool yn, void *src) {}
virtual bool record_enabled() const { return false; } virtual bool record_enabled() const { return false; }
virtual void handle_transport_stopped (bool abort, bool did_locate, bool flush_processors); virtual void handle_transport_stopped (bool abort, bool did_locate, bool flush_processors);
@ -111,37 +117,43 @@ class Route : public IO
void shift (nframes64_t, nframes64_t); void shift (nframes64_t, nframes64_t);
/* override IO::set_gain() to provide group control */
void set_gain (gain_t val, void *src); void set_gain (gain_t val, void *src);
void inc_gain (gain_t delta, void *src); void inc_gain (gain_t delta, void *src);
void set_mute (bool yn, void* src);
bool muted () const;
void set_solo (bool yn, void *src); void set_solo (bool yn, void *src);
bool soloed() const { return _soloed; } bool soloed() const;
void set_solo_safe (bool yn, void *src); void set_solo_isolated (bool yn, void *src);
bool solo_safe() const { return _solo_safe; } bool solo_isolated() const;
void set_mute (bool yn, void *src); void set_phase_invert (bool yn, void* src);
bool muted() const { return _muted; } bool phase_invert() const;
bool solo_muted() const { return desired_solo_gain == 0.0; }
void set_mute_config (mute_type, bool, void *src); void set_denormal_protection (bool yn, void* src);
bool get_mute_config (mute_type); bool denormal_protection() const;
void set_edit_group (RouteGroup *, void *); void set_edit_group (RouteGroup *, void *);
void drop_edit_group (void *); void drop_edit_group (void *);
RouteGroup *edit_group () { return _edit_group; } RouteGroup *edit_group () const { return _edit_group; }
void set_mix_group (RouteGroup *, void *); void set_mix_group (RouteGroup *, void *);
void drop_mix_group (void *); void drop_mix_group (void *);
RouteGroup *mix_group () { return _mix_group; } RouteGroup *mix_group () const { return _mix_group; }
virtual void set_meter_point (MeterPoint, void *src); virtual void set_meter_point (MeterPoint, void *src);
MeterPoint meter_point() const { return _meter_point; } MeterPoint meter_point() const { return _meter_point; }
void meter ();
/* Processors */ /* Processors */
boost::shared_ptr<Amp> amp() const { return _amp; }
PeakMeter& peak_meter() { return *_meter.get(); }
const PeakMeter& peak_meter() const { return *_meter.get(); }
boost::shared_ptr<PeakMeter> shared_peak_meter() const { return _meter; }
void flush_processors (); void flush_processors ();
void foreach_processor (sigc::slot<void, boost::weak_ptr<Processor> > method) { void foreach_processor (sigc::slot<void, boost::weak_ptr<Processor> > method) {
@ -213,8 +225,10 @@ class Route : public IO
void set_user_latency (nframes_t); void set_user_latency (nframes_t);
nframes_t initial_delay() const { return _initial_delay; } nframes_t initial_delay() const { return _initial_delay; }
sigc::signal<void> active_changed;
sigc::signal<void,void*> solo_changed; sigc::signal<void,void*> solo_changed;
sigc::signal<void,void*> solo_safe_changed; sigc::signal<void,void*> solo_safe_changed;
sigc::signal<void,void*> solo_isolated_changed;
sigc::signal<void,void*> comment_changed; sigc::signal<void,void*> comment_changed;
sigc::signal<void,void*> mute_changed; sigc::signal<void,void*> mute_changed;
sigc::signal<void,void*> pre_fader_changed; sigc::signal<void,void*> pre_fader_changed;
@ -240,7 +254,7 @@ class Route : public IO
virtual XMLNode& get_template(); virtual XMLNode& get_template();
XMLNode& get_processor_state (); XMLNode& get_processor_state ();
int set_processor_state (const XMLNode&); virtual void set_processor_state (const XMLNode&);
int save_as_template (const std::string& path, const std::string& name); int save_as_template (const std::string& path, const std::string& name);
@ -252,28 +266,38 @@ class Route : public IO
bool feeds (boost::shared_ptr<IO>); bool feeds (boost::shared_ptr<IO>);
std::set<boost::shared_ptr<Route> > fed_by; std::set<boost::shared_ptr<Route> > fed_by;
struct ToggleControllable : public PBD::Controllable { /* Controls (not all directly owned by the Route */
enum ToggleType {
MuteControl = 0,
SoloControl
};
ToggleControllable (std::string name, Route&, ToggleType); boost::shared_ptr<AutomationControl> get_control (const Evoral::Parameter& param);
void set_value (float);
float get_value (void) const;
Route& route; struct SoloControllable : public AutomationControl {
ToggleType type; SoloControllable (std::string name, Route&);
void set_value (float);
float get_value (void) const;
Route& route;
}; };
boost::shared_ptr<PBD::Controllable> solo_control() { boost::shared_ptr<AutomationControl> solo_control() const {
return _solo_control; return _solo_control;
} }
boost::shared_ptr<PBD::Controllable> mute_control() { boost::shared_ptr<AutomationControl> mute_control() const {
return _mute_control; return _mute_master;
} }
boost::shared_ptr<MuteMaster> mute_master() const {
return _mute_master;
}
/* Route doesn't own these items, but sub-objects that it does own have them
and to make UI code a bit simpler, we provide direct access to them
here.
*/
boost::shared_ptr<Panner> panner() const;
boost::shared_ptr<AutomationControl> gain_control() const;
void automation_snapshot (nframes_t now, bool force=false); void automation_snapshot (nframes_t now, bool force=false);
void protect_automation (); void protect_automation ();
@ -288,10 +312,11 @@ class Route : public IO
friend class Session; friend class Session;
void catch_up_on_solo_mute_override (); void catch_up_on_solo_mute_override ();
void set_solo_mute (bool yn); void mod_solo_level (int32_t);
void set_block_size (nframes_t nframes); void set_block_size (nframes_t nframes);
bool has_external_redirects() const; bool has_external_redirects() const;
void curve_reallocate (); void curve_reallocate ();
void just_meter_input (sframes_t start_frame, sframes_t end_frame, nframes_t nframes);
protected: protected:
nframes_t check_initial_delay (nframes_t, nframes_t&); nframes_t check_initial_delay (nframes_t, nframes_t&);
@ -303,44 +328,38 @@ class Route : public IO
sframes_t start_frame, sframes_t end_frame, sframes_t start_frame, sframes_t end_frame,
nframes_t nframes, bool with_processors, int declick); nframes_t nframes, bool with_processors, int declick);
Flag _flags; boost::shared_ptr<IO> _input;
int _pending_declick; boost::shared_ptr<IO> _output;
MeterPoint _meter_point;
gain_t solo_gain;
gain_t mute_gain;
gain_t desired_solo_gain;
gain_t desired_mute_gain;
bool _active;
nframes_t _initial_delay; nframes_t _initial_delay;
nframes_t _roll_delay; nframes_t _roll_delay;
ProcessorList _processors; ProcessorList _processors;
mutable Glib::RWLock _processor_lock; mutable Glib::RWLock _processor_lock;
boost::shared_ptr<Delivery> _main_outs; boost::shared_ptr<Delivery> _main_outs;
boost::shared_ptr<Delivery> _control_outs; // XXX to be removed/generalized by listen points boost::shared_ptr<Delivery> _control_outs; // XXX to be removed/generalized by listen points
RouteGroup *_edit_group;
RouteGroup *_mix_group;
std::string _comment;
bool _have_internal_generator;
boost::shared_ptr<ToggleControllable> _solo_control; Flag _flags;
boost::shared_ptr<ToggleControllable> _mute_control; int _pending_declick;
MeterPoint _meter_point;
uint32_t _phase_invert;
bool _denormal_protection;
/* tight cache-line access here is more important than sheer speed of access.
keep these after things that should be aligned
*/
bool _muted : 1;
bool _soloed : 1;
bool _solo_safe : 1;
bool _recordable : 1; bool _recordable : 1;
bool _mute_affects_pre_fader : 1;
bool _mute_affects_post_fader : 1;
bool _mute_affects_control_outs : 1;
bool _mute_affects_main_outs : 1;
bool _silent : 1; bool _silent : 1;
bool _declickable : 1; bool _declickable : 1;
boost::shared_ptr<SoloControllable> _solo_control;
boost::shared_ptr<MuteMaster> _mute_master;
RouteGroup* _edit_group;
RouteGroup* _mix_group;
std::string _comment;
bool _have_internal_generator;
bool _solo_safe;
DataType _default_type;
protected: protected:
virtual XMLNode& state(bool); virtual XMLNode& state(bool);
@ -358,13 +377,14 @@ class Route : public IO
uint32_t pans_required() const; uint32_t pans_required() const;
ChanCount n_process_buffers (); ChanCount n_process_buffers ();
void setup_peak_meters ();
virtual int _set_state (const XMLNode&, bool call_base); virtual int _set_state (const XMLNode&, bool call_base);
virtual void _set_processor_states (const XMLNodeList&);
boost::shared_ptr<Delivery> add_listener (boost::shared_ptr<IO>, const std::string&); boost::shared_ptr<Delivery> add_listener (boost::shared_ptr<IO>, const std::string&);
boost::shared_ptr<Amp> _amp;
boost::shared_ptr<PeakMeter> _meter;
sigc::connection _meter_connection;
private: private:
void init (); void init ();
@ -387,7 +407,6 @@ class Route : public IO
int configure_processors (ProcessorStreams*); int configure_processors (ProcessorStreams*);
int configure_processors_unlocked (ProcessorStreams*); int configure_processors_unlocked (ProcessorStreams*);
void set_deferred_state ();
bool add_processor_from_xml (const XMLNode&, Placement); bool add_processor_from_xml (const XMLNode&, Placement);
bool add_processor_from_xml (const XMLNode&, ProcessorList::iterator iter); bool add_processor_from_xml (const XMLNode&, ProcessorList::iterator iter);

View file

@ -23,25 +23,31 @@
#include <sigc++/signal.h> #include <sigc++/signal.h>
#include <string> #include <string>
#include "pbd/stateful.h" #include "pbd/stateful.h"
#include "ardour/ardour.h" #include "ardour/ardour.h"
#include "ardour/audioengine.h" #include "ardour/audioengine.h"
#include "ardour/delivery.h" #include "ardour/delivery.h"
namespace ARDOUR { namespace ARDOUR {
class PeakMeter;
class Amp;
class Send : public Delivery class Send : public Delivery
{ {
public: public:
Send (Session&); Send (Session&, boost::shared_ptr<MuteMaster>);
Send (Session&, const XMLNode&); Send (Session&, boost::shared_ptr<MuteMaster>, const XMLNode&);
virtual ~Send (); virtual ~Send ();
uint32_t bit_slot() const { return _bitslot; } uint32_t bit_slot() const { return _bitslot; }
void activate() {} boost::shared_ptr<Amp> amp() const { return _amp; }
void deactivate () {} boost::shared_ptr<PeakMeter> meter() const { return _meter; }
bool metering() const { return _metering; }
void set_metering (bool yn) { _metering = yn; }
XMLNode& state(bool full); XMLNode& state(bool full);
XMLNode& get_state(void); XMLNode& get_state(void);
@ -49,14 +55,20 @@ class Send : public Delivery
uint32_t pans_required() const { return _configured_input.n_audio(); } uint32_t pans_required() const { return _configured_input.n_audio(); }
void run_in_place (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes);
bool can_support_io_configuration (const ChanCount& in, ChanCount& out) const; bool can_support_io_configuration (const ChanCount& in, ChanCount& out) const;
bool configure_io (ChanCount in, ChanCount out);
bool set_name (const std::string& str); bool set_name (const std::string& str);
static uint32_t how_many_sends(); static uint32_t how_many_sends();
static void make_unique (XMLNode &, Session &); static void make_unique (XMLNode &, Session &);
protected:
bool _metering;
boost::shared_ptr<Amp> _amp;
boost::shared_ptr<PeakMeter> _meter;
private: private:
/* disallow copy construction */ /* disallow copy construction */
Send (const Send&); Send (const Send&);

View file

@ -730,7 +730,7 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable
/* session-wide solo/mute/rec-enable */ /* session-wide solo/mute/rec-enable */
bool soloing() const { return currently_soloing; } bool soloing() const { return _non_soloed_outs_muted; }
void set_all_solo (bool); void set_all_solo (bool);
void set_all_mute (bool); void set_all_mute (bool);
@ -743,8 +743,8 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable
/* control/master out */ /* control/master out */
boost::shared_ptr<IO> control_out() const { return _control_out; } boost::shared_ptr<Route> control_out() const { return _control_out; }
boost::shared_ptr<IO> master_out() const { return _master_out; } boost::shared_ptr<Route> master_out() const { return _master_out; }
/* insert/send management */ /* insert/send management */
@ -1040,6 +1040,7 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable
bool _have_captured; bool _have_captured;
float _meter_hold; float _meter_hold;
float _meter_falloff; float _meter_falloff;
bool _non_soloed_outs_muted;
void set_worst_io_latencies (); void set_worst_io_latencies ();
void set_worst_io_latencies_x (IOChange asifwecare, void *ignored) { void set_worst_io_latencies_x (IOChange asifwecare, void *ignored) {
@ -1688,8 +1689,8 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable
/* main outs */ /* main outs */
uint32_t main_outs; uint32_t main_outs;
boost::shared_ptr<IO> _master_out; boost::shared_ptr<Route> _master_out;
boost::shared_ptr<IO> _control_out; boost::shared_ptr<Route> _control_out;
gain_t* _gain_automation_buffer; gain_t* _gain_automation_buffer;
pan_t** _pan_automation_buffer; pan_t** _pan_automation_buffer;

View file

@ -160,6 +160,8 @@ AudioDiskstream::free_working_buffers()
void void
AudioDiskstream::non_realtime_input_change () AudioDiskstream::non_realtime_input_change ()
{ {
cerr << "AD::NRIC ... " << name() << endl;
{ {
Glib::Mutex::Lock lm (state_lock); Glib::Mutex::Lock lm (state_lock);
@ -173,10 +175,10 @@ AudioDiskstream::non_realtime_input_change ()
_n_channels.set(DataType::AUDIO, c->size()); _n_channels.set(DataType::AUDIO, c->size());
if (_io->n_inputs().n_audio() > _n_channels.n_audio()) { if (_io->n_ports().n_audio() > _n_channels.n_audio()) {
add_channel_to (c, _io->n_inputs().n_audio() - _n_channels.n_audio()); add_channel_to (c, _io->n_ports().n_audio() - _n_channels.n_audio());
} else if (_io->n_inputs().n_audio() < _n_channels.n_audio()) { } else if (_io->n_ports().n_audio() < _n_channels.n_audio()) {
remove_channel_from (c, _n_channels.n_audio() - _io->n_inputs().n_audio()); remove_channel_from (c, _n_channels.n_audio() - _io->n_ports().n_audio());
} }
} }
@ -227,14 +229,14 @@ AudioDiskstream::get_input_sources ()
uint32_t n; uint32_t n;
ChannelList::iterator chan; ChannelList::iterator chan;
uint32_t ni = _io->n_inputs().n_audio(); uint32_t ni = _io->n_ports().n_audio();
vector<string> connections; vector<string> connections;
for (n = 0, chan = c->begin(); chan != c->end() && n < ni; ++chan, ++n) { for (n = 0, chan = c->begin(); chan != c->end() && n < ni; ++chan, ++n) {
connections.clear (); connections.clear ();
if (_io->input(n)->get_connections (connections) == 0) { if (_io->nth (n)->get_connections (connections) == 0) {
if ((*chan)->source) { if ((*chan)->source) {
// _source->disable_metering (); // _source->disable_metering ();
@ -633,7 +635,7 @@ AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can
if (nominally_recording || rec_nframes) { if (nominally_recording || rec_nframes) {
uint32_t limit = _io->n_inputs ().n_audio(); uint32_t limit = _io->n_ports ().n_audio();
/* one or more ports could already have been removed from _io, but our /* one or more ports could already have been removed from _io, but our
channel setup hasn't yet been updated. prevent us from trying to channel setup hasn't yet been updated. prevent us from trying to
@ -656,7 +658,7 @@ AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can
for recording, and use rec_offset for recording, and use rec_offset
*/ */
AudioPort* const ap = _io->audio_input(n); AudioPort* const ap = _io->audio (n);
assert(ap); assert(ap);
assert(rec_nframes <= ap->get_audio_buffer(nframes).capacity()); assert(rec_nframes <= ap->get_audio_buffer(nframes).capacity());
memcpy (chaninfo->current_capture_buffer, ap->get_audio_buffer (rec_nframes).data(rec_offset), sizeof (Sample) * rec_nframes); memcpy (chaninfo->current_capture_buffer, ap->get_audio_buffer (rec_nframes).data(rec_offset), sizeof (Sample) * rec_nframes);
@ -671,7 +673,7 @@ AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can
goto out; goto out;
} }
AudioPort* const ap = _io->audio_input(n); AudioPort* const ap = _io->audio (n);
assert(ap); assert(ap);
Sample* buf = ap->get_audio_buffer(nframes).data(); Sample* buf = ap->get_audio_buffer(nframes).data();
@ -1822,7 +1824,7 @@ AudioDiskstream::finish_capture (bool rec_monitors_input, boost::shared_ptr<Chan
void void
AudioDiskstream::set_record_enabled (bool yn) AudioDiskstream::set_record_enabled (bool yn)
{ {
if (!recordable() || !_session.record_enabling_legal() || _io->n_inputs().n_audio() == 0) { if (!recordable() || !_session.record_enabling_legal() || _io->n_ports().n_audio() == 0) {
return; return;
} }
@ -2110,6 +2112,8 @@ AudioDiskstream::reset_write_sources (bool mark_write_complete, bool force)
boost::shared_ptr<ChannelList> c = channels.reader(); boost::shared_ptr<ChannelList> c = channels.reader();
uint32_t n; uint32_t n;
cerr << _name << " RWS!!!\n";
if (!recordable()) { if (!recordable()) {
return; return;
} }

View file

@ -36,6 +36,7 @@
#include "ardour/buffer_set.h" #include "ardour/buffer_set.h"
#include "ardour/io_processor.h" #include "ardour/io_processor.h"
#include "ardour/panner.h" #include "ardour/panner.h"
#include "ardour/meter.h"
#include "ardour/playlist_factory.h" #include "ardour/playlist_factory.h"
#include "ardour/plugin_insert.h" #include "ardour/plugin_insert.h"
#include "ardour/processor.h" #include "ardour/processor.h"
@ -140,8 +141,7 @@ AudioTrack::deprecated_use_diskstream_connections ()
diskstream->deprecated_io_node = 0; diskstream->deprecated_io_node = 0;
if ((prop = node.property ("gain")) != 0) { if ((prop = node.property ("gain")) != 0) {
set_gain (atof (prop->value().c_str()), this); _amp->set_gain (atof (prop->value().c_str()), this);
_gain = _gain_control->user_float();
} }
if ((prop = node.property ("input-connection")) != 0) { if ((prop = node.property ("input-connection")) != 0) {
@ -160,10 +160,10 @@ AudioTrack::deprecated_use_diskstream_connections ()
} }
} }
connect_input_ports_to_bundle (c, this); _input->connect_ports_to_bundle (c, this);
} else if ((prop = node.property ("inputs")) != 0) { } else if ((prop = node.property ("inputs")) != 0) {
if (set_inputs (prop->value())) { if (_input->set_ports (prop->value())) {
error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg; error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg;
return -1; return -1;
} }
@ -176,14 +176,14 @@ int
AudioTrack::set_diskstream (boost::shared_ptr<AudioDiskstream> ds, void *src) AudioTrack::set_diskstream (boost::shared_ptr<AudioDiskstream> ds, void *src)
{ {
_diskstream = ds; _diskstream = ds;
_diskstream->set_io (*this); _diskstream->set_io (*(_input.get()));
_diskstream->set_destructive (_mode == Destructive); _diskstream->set_destructive (_mode == Destructive);
_diskstream->set_non_layered (_mode == NonLayered); _diskstream->set_non_layered (_mode == NonLayered);
if (audio_diskstream()->deprecated_io_node) { if (audio_diskstream()->deprecated_io_node) {
if (!connecting_legal) { if (!IO::connecting_legal) {
ConnectingLegal.connect (mem_fun (*this, &AudioTrack::deprecated_use_diskstream_connections)); IO::ConnectingLegal.connect (mem_fun (*this, &AudioTrack::deprecated_use_diskstream_connections));
} else { } else {
deprecated_use_diskstream_connections (); deprecated_use_diskstream_connections ();
} }
@ -193,7 +193,7 @@ AudioTrack::set_diskstream (boost::shared_ptr<AudioDiskstream> ds, void *src)
_diskstream->monitor_input (false); _diskstream->monitor_input (false);
ic_connection.disconnect(); ic_connection.disconnect();
ic_connection = input_changed.connect (mem_fun (*_diskstream, &Diskstream::handle_input_change)); ic_connection = _input->changed.connect (mem_fun (*_diskstream, &Diskstream::handle_input_change));
DiskstreamChanged (); /* EMIT SIGNAL */ DiskstreamChanged (); /* EMIT SIGNAL */
@ -479,8 +479,6 @@ AudioTrack::roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame,
transport_frame = _session.transport_frame(); transport_frame = _session.transport_frame();
prepare_inputs (nframes);
if ((nframes = check_initial_delay (nframes, transport_frame)) == 0) { if ((nframes = check_initial_delay (nframes, transport_frame)) == 0) {
/* need to do this so that the diskstream sets its /* need to do this so that the diskstream sets its
@ -501,7 +499,7 @@ AudioTrack::roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame,
/* special condition applies */ /* special condition applies */
if (_meter_point == MeterInput) { if (_meter_point == MeterInput) {
just_meter_input (start_frame, end_frame, nframes); _input->process_input (_meter, start_frame, end_frame, nframes);
} }
if (diskstream->record_enabled() && !can_record && !_session.config.get_auto_input()) { if (diskstream->record_enabled() && !can_record && !_session.config.get_auto_input()) {
@ -599,6 +597,7 @@ AudioTrack::roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame,
/* don't waste time with automation if we're recording or we've just stopped (yes it can happen) */ /* don't waste time with automation if we're recording or we've just stopped (yes it can happen) */
if (!diskstream->record_enabled() && _session.transport_rolling()) { if (!diskstream->record_enabled() && _session.transport_rolling()) {
#ifdef XXX_MOVE_THIS_TO_AMP
Glib::Mutex::Lock am (data().control_lock(), Glib::TRY_LOCK); Glib::Mutex::Lock am (data().control_lock(), Glib::TRY_LOCK);
if (am.locked() && gain_control()->automation_playback()) { if (am.locked() && gain_control()->automation_playback()) {
@ -606,6 +605,7 @@ AudioTrack::roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame,
gain_control()->list()->curve().rt_safe_get_vector ( gain_control()->list()->curve().rt_safe_get_vector (
start_frame, end_frame, _session.gain_automation_buffer(), nframes)); start_frame, end_frame, _session.gain_automation_buffer(), nframes));
} }
#endif
} }
process_output_buffers (bufs, start_frame, end_frame, nframes, (!_session.get_record_enabled() || !Config->get_do_not_record_plugins()), declick); process_output_buffers (bufs, start_frame, end_frame, nframes, (!_session.get_record_enabled() || !Config->get_do_not_record_plugins()), declick);
@ -759,9 +759,9 @@ AudioTrack::freeze (InterThreadInfo& itt)
new_playlist = PlaylistFactory::create (DataType::AUDIO, _session, new_playlist_name, false); new_playlist = PlaylistFactory::create (DataType::AUDIO, _session, new_playlist_name, false);
_freeze_record.gain = _gain; _freeze_record.gain = _amp->gain();
_freeze_record.gain_automation_state = _gain_control->automation_state(); _freeze_record.gain_automation_state = _amp->gain_control()->automation_state();
_freeze_record.pan_automation_state = _panner->automation_state(); /* XXX need main outs automation state _freeze_record.pan_automation_state = _mainpanner->automation_state(); */
region_name = new_playlist_name; region_name = new_playlist_name;
@ -784,8 +784,8 @@ AudioTrack::freeze (InterThreadInfo& itt)
/* reset stuff that has already been accounted for in the freeze process */ /* reset stuff that has already been accounted for in the freeze process */
set_gain (1.0, this); set_gain (1.0, this);
_gain_control->set_automation_state (Off); _amp->gain_control()->set_automation_state (Off);
_panner->set_automation_state (Off); /* XXX need to use _main_outs _panner->set_automation_state (Off); */
_freeze_record.state = Frozen; _freeze_record.state = Frozen;
FreezeChange(); /* EMIT SIGNAL */ FreezeChange(); /* EMIT SIGNAL */
@ -811,8 +811,8 @@ AudioTrack::unfreeze ()
_freeze_record.playlist.reset (); _freeze_record.playlist.reset ();
set_gain (_freeze_record.gain, this); set_gain (_freeze_record.gain, this);
_gain_control->set_automation_state (_freeze_record.gain_automation_state); _amp->gain_control()->set_automation_state (_freeze_record.gain_automation_state);
_panner->set_automation_state (_freeze_record.pan_automation_state); /* XXX need to use _main_outs _panner->set_automation_state (_freeze_record.pan_automation_state); */
} }
_freeze_record.state = UnFrozen; _freeze_record.state = UnFrozen;

View file

@ -33,9 +33,11 @@
#include "ardour/audioengine.h" #include "ardour/audioengine.h"
#include "ardour/buffer.h" #include "ardour/buffer.h"
#include "ardour/delivery.h"
#include "ardour/port.h" #include "ardour/port.h"
#include "ardour/audio_port.h" #include "ardour/audio_port.h"
#include "ardour/midi_port.h" #include "ardour/midi_port.h"
#include "ardour/meter.h"
#include "ardour/session.h" #include "ardour/session.h"
#include "ardour/cycle_timer.h" #include "ardour/cycle_timer.h"
#include "ardour/utils.h" #include "ardour/utils.h"
@ -358,9 +360,9 @@ AudioEngine::process_callback (nframes_t nframes)
return 0; return 0;
} }
/* tell all IO objects that we're starting a new cycle */ /* tell all relevant objects that we're starting a new cycle */
IO::CycleStart (nframes); Delivery::CycleStart (nframes);
Port::set_port_offset (0); Port::set_port_offset (0);
/* tell all Ports that we're starting a new cycle */ /* tell all Ports that we're starting a new cycle */
@ -519,7 +521,7 @@ AudioEngine::meter_thread ()
if (g_atomic_int_get(&m_meter_exit)) { if (g_atomic_int_get(&m_meter_exit)) {
break; break;
} }
IO::update_meters (); Metering::update_meters ();
} }
} }

View file

@ -24,6 +24,7 @@
#include "ardour/audio_diskstream.h" #include "ardour/audio_diskstream.h"
#include "ardour/audioregion.h" #include "ardour/audioregion.h"
#include "ardour/audioengine.h" #include "ardour/audioengine.h"
#include "ardour/delivery.h"
#include "ardour/route.h" #include "ardour/route.h"
#include "ardour/session.h" #include "ardour/session.h"
#include "ardour/auditioner.h" #include "ardour/auditioner.h"
@ -57,22 +58,21 @@ Auditioner::Auditioner (Session& s)
return; return;
} }
defer_pan_reset (); _main_outs->defer_pan_reset ();
if (left.length()) { if (left.length()) {
add_output_port (left, this, DataType::AUDIO); _output->add_port (left, this, DataType::AUDIO);
} }
if (right.length()) { if (right.length()) {
audio_diskstream()->add_channel (1); audio_diskstream()->add_channel (1);
add_output_port (right, this, DataType::AUDIO); _output->add_port (right, this, DataType::AUDIO);
} }
allow_pan_reset (); _main_outs->allow_pan_reset ();
_main_outs->reset_panner ();
reset_panner (); _output->changed.connect (mem_fun (*this, &Auditioner::output_changed));
IO::output_changed.connect (mem_fun (*this, &Auditioner::output_changed));
the_region.reset ((AudioRegion*) 0); the_region.reset ((AudioRegion*) 0);
g_atomic_int_set (&_active, 0); g_atomic_int_set (&_active, 0);
@ -110,7 +110,7 @@ Auditioner::audition_current_playlist ()
/* force a panner reset now that we have all channels */ /* force a panner reset now that we have all channels */
_panner->reset (n_outputs().n_audio(), _diskstream->n_channels().n_audio()); _main_outs->panner()->reset (n_outputs().n_audio(), _diskstream->n_channels().n_audio());
g_atomic_int_set (&_active, 1); g_atomic_int_set (&_active, 1);
} }
@ -148,7 +148,7 @@ Auditioner::audition_region (boost::shared_ptr<Region> region)
/* force a panner reset now that we have all channels */ /* force a panner reset now that we have all channels */
reset_panner(); _main_outs->reset_panner();
length = the_region->length(); length = the_region->length();
@ -206,7 +206,7 @@ Auditioner::output_changed (IOChange change, void* src)
if (change & ConnectionsChanged) { if (change & ConnectionsChanged) {
vector<string> connections; vector<string> connections;
if (output (0)->get_connections (connections)) { if (_output->nth (0)->get_connections (connections)) {
phys = _session.engine().get_nth_physical_output (DataType::AUDIO, 0); phys = _session.engine().get_nth_physical_output (DataType::AUDIO, 0);
if (phys != connections[0]) { if (phys != connections[0]) {
_session.config.set_auditioner_output_left (connections[0]); _session.config.set_auditioner_output_left (connections[0]);
@ -219,7 +219,7 @@ Auditioner::output_changed (IOChange change, void* src)
connections.clear (); connections.clear ();
if (output (1)->get_connections (connections)) { if (_output->nth (1)->get_connections (connections)) {
phys = _session.engine().get_nth_physical_output (DataType::AUDIO, 1); phys = _session.engine().get_nth_physical_output (DataType::AUDIO, 1);
if (phys != connections[0]) { if (phys != connections[0]) {
_session.config.set_auditioner_output_right (connections[0]); _session.config.set_auditioner_output_right (connections[0]);

View file

@ -24,8 +24,11 @@
#include <errno.h> #include <errno.h>
#include "pbd/error.h" #include "pbd/error.h"
#include "pbd/enumwriter.h" #include "pbd/enumwriter.h"
#include "midi++/names.h" #include "midi++/names.h"
#include "ardour/automatable.h" #include "ardour/automatable.h"
#include "ardour/amp.h"
#include "ardour/event_type_map.h" #include "ardour/event_type_map.h"
#include "ardour/midi_track.h" #include "ardour/midi_track.h"
#include "ardour/panner.h" #include "ardour/panner.h"
@ -382,7 +385,7 @@ Automatable::automation_snapshot (nframes_t now, bool force)
} }
void void
Automatable::transport_stopped (nframes_t now) Automatable::transport_stopped (sframes_t now)
{ {
for (Controls::iterator li = controls().begin(); li != controls().end(); ++li) { for (Controls::iterator li = controls().begin(); li != controls().end(); ++li) {
@ -409,7 +412,7 @@ Automatable::control_factory(const Evoral::Parameter& param)
} else if (param.type() == PluginAutomation) { } else if (param.type() == PluginAutomation) {
control = new PluginInsert::PluginControl((PluginInsert*)this, param); control = new PluginInsert::PluginControl((PluginInsert*)this, param);
} else if (param.type() == GainAutomation) { } else if (param.type() == GainAutomation) {
control = new IO::GainControl( X_("gaincontrol"), (IO*)this, param); control = new Amp::GainControl( X_("gaincontrol"), _a_session, (Amp*)this, param);
} else if (param.type() == PanAutomation) { } else if (param.type() == PanAutomation) {
Panner* me = dynamic_cast<Panner*>(this); Panner* me = dynamic_cast<Panner*>(this);
if (me) { if (me) {

View file

@ -20,58 +20,102 @@
#include <algorithm> #include <algorithm>
#include "pbd/enumwriter.h" #include "pbd/enumwriter.h"
#include "pbd/convert.h"
#include "ardour/delivery.h" #include "ardour/delivery.h"
#include "ardour/audio_buffer.h" #include "ardour/audio_buffer.h"
#include "ardour/amp.h"
#include "ardour/buffer_set.h" #include "ardour/buffer_set.h"
#include "ardour/configuration.h" #include "ardour/configuration.h"
#include "ardour/io.h" #include "ardour/io.h"
#include "ardour/meter.h" #include "ardour/meter.h"
#include "ardour/mute_master.h"
#include "ardour/panner.h"
#include "ardour/port.h"
#include "ardour/session.h" #include "ardour/session.h"
#include "i18n.h"
using namespace std; using namespace std;
using namespace PBD;
using namespace ARDOUR; using namespace ARDOUR;
sigc::signal<void,nframes_t> Delivery::CycleStart;
sigc::signal<int> Delivery::PannersLegal;
bool Delivery::panners_legal = false;
/* deliver to an existing IO object */ /* deliver to an existing IO object */
Delivery::Delivery (Session& s, IO* io, const string& name, Role r) Delivery::Delivery (Session& s, boost::shared_ptr<IO> io, boost::shared_ptr<MuteMaster> mm, const string& name, Role r)
: IOProcessor(s, io, name) : IOProcessor(s, boost::shared_ptr<IO>(), io, name)
, _role (r) , _role (r)
, _metering (false) , _output_buffers (new BufferSet())
, _muted_by_self (false) , _solo_level (0)
, _muted_by_others (false) , _solo_isolated (false)
, _mute_master (mm)
{ {
_output_offset = 0;
_current_gain = 1.0;
_panner = boost::shared_ptr<Panner>(new Panner (_name, _session));
_output->changed.connect (mem_fun (*this, &Delivery::output_changed));
} }
/* deliver to a new IO object */ /* deliver to a new IO object */
Delivery::Delivery (Session& s, const string& name, Role r) Delivery::Delivery (Session& s, boost::shared_ptr<MuteMaster> mm, const string& name, Role r)
: IOProcessor(s, name) : IOProcessor(s, false, true, name)
, _role (r) , _role (r)
, _metering (false) , _output_buffers (new BufferSet())
, _muted_by_self (false) , _solo_level (0)
, _muted_by_others (false) , _solo_isolated (false)
, _mute_master (mm)
{ {
_output_offset = 0;
_current_gain = 1.0;
_panner = boost::shared_ptr<Panner>(new Panner (_name, _session));
_output->changed.connect (mem_fun (*this, &Delivery::output_changed));
} }
/* reconstruct from XML */ /* deliver to a new IO object, reconstruct from XML */
Delivery::Delivery (Session& s, const XMLNode& node) Delivery::Delivery (Session& s, boost::shared_ptr<MuteMaster> mm, const XMLNode& node)
: IOProcessor (s, "reset") : IOProcessor (s, false, true, "reset")
, _role (Role (0)) , _role (Role (0))
, _metering (false) , _output_buffers (new BufferSet())
, _muted_by_self (false) , _solo_level (0)
, _muted_by_others (false) , _solo_isolated (false)
, _mute_master (mm)
{ {
_output_offset = 0;
_current_gain = 1.0;
_panner = boost::shared_ptr<Panner>(new Panner (_name, _session));
if (set_state (node)) { if (set_state (node)) {
throw failed_constructor (); throw failed_constructor ();
} }
_output->changed.connect (mem_fun (*this, &Delivery::output_changed));
} }
void
Delivery::cycle_start (nframes_t nframes)
{
_output_offset = 0;
_no_outs_cuz_we_no_monitor = false;
}
void
Delivery::increment_output_offset (nframes_t n)
{
_output_offset += n;
}
bool bool
Delivery::visible () const Delivery::visible () const
{ {
if (_role & (Main|Solo)) { if (_role & Main) {
return false; return false;
} }
@ -92,70 +136,54 @@ Delivery::configure_io (ChanCount in, ChanCount out)
return false; return false;
} }
reset_panner ();
return Processor::configure_io (in, out); return Processor::configure_io (in, out);
} }
void void
Delivery::run_in_place (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes) Delivery::run_in_place (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes)
{ {
if (_io->n_outputs().get (_io->default_type()) == 0) { if (_output->n_ports ().get (_output->default_type()) == 0) {
return; return;
} }
if (!active() || _muted_by_self || _muted_by_others) { // this Delivery processor is not a derived type, and thus we assume
silence (nframes); // we really can modify the buffers passed in (it is almost certainly
if (_metering) { // the main output stage of a Route). Contrast with Send::run_in_place()
_io->peak_meter().reset(); // which cannot do this.
}
gain_t tgain = target_gain ();
if (tgain != _current_gain) {
Amp::apply_gain (bufs, nframes, _current_gain, tgain);
_current_gain = tgain;
}
// Attach output buffers to port buffers
PortSet& ports (_output->ports());
output_buffers().attach_buffers (ports, nframes, _output_offset);
if (_panner && _panner->npanners() && !_panner->bypassed()) {
// Use the panner to distribute audio to output port buffers
_panner->run (bufs, output_buffers(), start_frame, end_frame, nframes);
} else { } else {
// Do a 1:1 copy of data to output ports
// we have to copy the input, because IO::deliver_output may alter the buffers if (bufs.count().n_audio() > 0 && ports.count().n_audio () > 0) {
// in-place, which a send must never do. _output->copy_to_outputs (bufs, DataType::AUDIO, nframes, _output_offset);
}
BufferSet& sendbufs = _session.get_mix_buffers (bufs.count()); if (bufs.count().n_midi() > 0 && ports.count().n_midi () > 0) {
_output->copy_to_outputs (bufs, DataType::MIDI, nframes, _output_offset);
sendbufs.read_from(bufs, nframes);
assert(sendbufs.count() == bufs.count());
_io->deliver_output (sendbufs, start_frame, end_frame, nframes);
if (_metering) {
if (_io->effective_gain() == 0) {
_io->peak_meter().reset();
} else {
_io->peak_meter().run_in_place(_io->output_buffers(), start_frame, end_frame, nframes);
}
} }
} }
} }
void
Delivery::set_metering (bool yn)
{
_metering = yn;
if (!_metering) {
/* XXX possible thread hazard here */
_io->peak_meter().reset();
}
}
void
Delivery::set_self_mute (bool yn)
{
if (yn != _muted_by_self) {
_muted_by_self = yn;
SelfMuteChange (); // emit signal
}
}
void
Delivery::set_nonself_mute (bool yn)
{
if (yn != _muted_by_others) {
_muted_by_others = yn;
OtherMuteChange (); // emit signal
}
}
XMLNode& XMLNode&
Delivery::state (bool full_state) Delivery::state (bool full_state)
@ -170,10 +198,8 @@ Delivery::state (bool full_state)
node.add_property("type", "delivery"); node.add_property("type", "delivery");
} }
node.add_property("metering", (_metering ? "yes" : "no"));
node.add_property("self-muted", (_muted_by_self ? "yes" : "no"));
node.add_property("other-muted", (_muted_by_others ? "yes" : "no"));
node.add_property("role", enum_2_string(_role)); node.add_property("role", enum_2_string(_role));
node.add_child_nocopy (_panner->state (full_state));
return node; return node;
} }
@ -183,21 +209,235 @@ Delivery::set_state (const XMLNode& node)
{ {
const XMLProperty* prop; const XMLProperty* prop;
if (IOProcessor::set_state (node)) {
return -1;
}
if ((prop = node.property ("role")) != 0) { if ((prop = node.property ("role")) != 0) {
_role = Role (string_2_enum (prop->value(), _role)); _role = Role (string_2_enum (prop->value(), _role));
} }
if ((prop = node.property ("metering")) != 0) { if ((prop = node.property ("solo_level")) != 0) {
set_metering (prop->value() == "yes"); _solo_level = 0; // needed for the reset to work
mod_solo_level (atoi (prop->value()));
} }
if ((prop = node.property ("self-muted")) != 0) { if ((prop = node.property ("solo-isolated")) != 0) {
set_self_mute (prop->value() == "yes"); set_solo_isolated (prop->value() == "yes");
} }
if ((prop = node.property ("other-muted")) != 0) { XMLNode* pan_node = node.child (X_("Panner"));
set_nonself_mute (prop->value() == "yes");
if (pan_node) {
cerr << _name << " reset pan state from XML\n";
_panner->set_state (*pan_node);
} }
reset_panner ();
return 0; return 0;
} }
void
Delivery::reset_panner ()
{
cerr << _name << " reset panner - plegal ? " << panners_legal << endl;
if (panners_legal) {
if (!no_panner_reset) {
cerr << "\treset panner with " << _output->name() << " = " << _output->n_ports()
<< " vs. " << pans_required () << endl;
_panner->reset (_output->n_ports().n_audio(), pans_required());
}
} else {
cerr << "\tdefer pan reset till later\n";
panner_legal_c.disconnect ();
panner_legal_c = PannersLegal.connect (mem_fun (*this, &Delivery::panners_became_legal));
}
}
int
Delivery::panners_became_legal ()
{
cerr << _name << " panners now legal, outputs @ " << _output << " on " << _output->name()
<< " = " << _output->n_ports() << " vs. " << pans_required() << endl;
_panner->reset (_output->n_ports().n_audio(), pans_required());
_panner->load (); // automation
panner_legal_c.disconnect ();
return 0;
}
void
Delivery::defer_pan_reset ()
{
no_panner_reset = true;
}
void
Delivery::allow_pan_reset ()
{
no_panner_reset = false;
reset_panner ();
}
int
Delivery::disable_panners (void)
{
panners_legal = false;
return 0;
}
int
Delivery::reset_panners ()
{
panners_legal = true;
return PannersLegal ();
}
void
Delivery::start_pan_touch (uint32_t which)
{
if (which < _panner->npanners()) {
_panner->pan_control(which)->start_touch();
}
}
void
Delivery::end_pan_touch (uint32_t which)
{
if (which < _panner->npanners()) {
_panner->pan_control(which)->stop_touch();
}
}
void
Delivery::transport_stopped (sframes_t frame)
{
_panner->transport_stopped (frame);
}
void
Delivery::flush (nframes_t nframes)
{
/* io_lock, not taken: function must be called from Session::process() calltree */
PortSet& ports (_output->ports());
for (PortSet::iterator i = ports.begin(); i != ports.end(); ++i) {
(*i).flush_buffers (nframes, _output_offset);
}
}
gain_t
Delivery::target_gain ()
{
/* if we've been told not to output because its a monitoring situation and
we're not monitoring, then be quiet.
*/
if (_no_outs_cuz_we_no_monitor) {
return 0.0;
}
gain_t desired_gain;
MuteMaster::MutePoint mp;
if (_solo_level) {
desired_gain = 1.0;
} else {
if (_solo_isolated) {
switch (_role) {
case Main:
mp = MuteMaster::Main;
break;
case Listen:
mp = MuteMaster::Listen;
break;
case Send:
case Insert:
if (_placement == PreFader) {
mp = MuteMaster::PreFader;
} else {
mp = MuteMaster::PostFader;
}
break;
}
desired_gain = _mute_master->mute_gain_at (mp);
} else if (_session.soloing()) {
switch (_role) {
case Main:
mp = MuteMaster::Main;
break;
case Listen:
mp = MuteMaster::Listen;
break;
case Send:
case Insert:
if (_placement == PreFader) {
mp = MuteMaster::PreFader;
} else {
mp = MuteMaster::PostFader;
}
break;
}
desired_gain = min (Config->get_solo_mute_gain(), _mute_master->mute_gain_at (mp));
} else {
desired_gain = 1.0;
}
}
return desired_gain;
}
void
Delivery::mod_solo_level (int32_t delta)
{
if (delta < 0) {
if (_solo_level >= (uint32_t) delta) {
_solo_level += delta;
} else {
_solo_level = 0;
}
} else {
_solo_level += delta;
}
}
void
Delivery::set_solo_isolated (bool yn)
{
_solo_isolated = yn;
}
void
Delivery::no_outs_cuz_we_no_monitor (bool yn)
{
_no_outs_cuz_we_no_monitor = yn;
}
bool
Delivery::set_name (const std::string& name)
{
bool ret = IOProcessor::set_name (name);
if (ret) {
ret = _panner->set_name (name);
}
return ret;
}
void
Delivery::output_changed (IOChange change, void* src)
{
if (change & ARDOUR::ConfigurationChanged) {
reset_panner ();
}
}

View file

@ -138,6 +138,8 @@ void
Diskstream::set_io (IO& io) Diskstream::set_io (IO& io)
{ {
_io = &io; _io = &io;
input_change_pending = ConfigurationChanged;
non_realtime_input_change ();
set_align_style_from_io (); set_align_style_from_io ();
} }
@ -233,7 +235,7 @@ Diskstream::set_capture_offset ()
return; return;
} }
_capture_offset = _io->input_latency(); _capture_offset = _io->latency();
} }
void void
@ -420,6 +422,11 @@ Diskstream::remove_region_from_last_capture (boost::weak_ptr<Region> wregion)
void void
Diskstream::playlist_ranges_moved (list< Evoral::RangeMove<nframes_t> > const & movements_frames) Diskstream::playlist_ranges_moved (list< Evoral::RangeMove<nframes_t> > const & movements_frames)
{ {
#if 0
XXX THIS HAS TO BE FIXED FOR 3.0
if (Config->get_automation_follows_regions () == false) { if (Config->get_automation_follows_regions () == false) {
return; return;
} }
@ -431,7 +438,7 @@ Diskstream::playlist_ranges_moved (list< Evoral::RangeMove<nframes_t> > const &
} }
/* move gain automation */ /* move gain automation */
boost::shared_ptr<AutomationList> gain_alist = _io->gain_control()->alist(); boost::shared_ptr<AutomationList> gain_alist = _io->gain_control()->list();
XMLNode & before = gain_alist->get_state (); XMLNode & before = gain_alist->get_state ();
gain_alist->move_ranges (movements); gain_alist->move_ranges (movements);
_session.add_command ( _session.add_command (
@ -458,11 +465,12 @@ Diskstream::playlist_ranges_moved (list< Evoral::RangeMove<nframes_t> > const &
if (route) { if (route) {
route->foreach_processor (sigc::bind (sigc::mem_fun (*this, &Diskstream::move_processor_automation), movements_frames)); route->foreach_processor (sigc::bind (sigc::mem_fun (*this, &Diskstream::move_processor_automation), movements_frames));
} }
#endif
} }
void void
Diskstream::move_processor_automation (boost::weak_ptr<Processor> p, Diskstream::move_processor_automation (boost::weak_ptr<Processor> p,
list< Evoral::RangeMove<nframes_t> > const & movements_frames) list< Evoral::RangeMove<nframes_t> > const & movements_frames)
{ {
boost::shared_ptr<Processor> processor (p.lock ()); boost::shared_ptr<Processor> processor (p.lock ());
if (!processor) { if (!processor) {

View file

@ -19,20 +19,21 @@
#include "pbd/enumwriter.h" #include "pbd/enumwriter.h"
#include "ardour/types.h"
#include "ardour/delivery.h"
#include "ardour/session.h"
#include "ardour/location.h"
#include "ardour/audiofilesource.h" #include "ardour/audiofilesource.h"
#include "ardour/diskstream.h"
#include "ardour/audioregion.h" #include "ardour/audioregion.h"
#include "ardour/route_group.h" #include "ardour/delivery.h"
#include "ardour/panner.h" #include "ardour/diskstream.h"
#include "ardour/track.h"
#include "ardour/midi_track.h"
#include "ardour/export_filename.h" #include "ardour/export_filename.h"
#include "ardour/export_format_base.h" #include "ardour/export_format_base.h"
#include "ardour/export_profile_manager.h" #include "ardour/export_profile_manager.h"
#include "ardour/io.h"
#include "ardour/location.h"
#include "ardour/midi_track.h"
#include "ardour/panner.h"
#include "ardour/route_group.h"
#include "ardour/session.h"
#include "ardour/track.h"
#include "ardour/types.h"
using namespace std; using namespace std;
using namespace PBD; using namespace PBD;
@ -70,7 +71,6 @@ setup_enum_writer ()
SlaveSource _SlaveSource; SlaveSource _SlaveSource;
ShuttleBehaviour _ShuttleBehaviour; ShuttleBehaviour _ShuttleBehaviour;
ShuttleUnits _ShuttleUnits; ShuttleUnits _ShuttleUnits;
mute_type _mute_type;
Session::RecordState _Session_RecordState; Session::RecordState _Session_RecordState;
Session::Event::Type _Session_Event_Type; Session::Event::Type _Session_Event_Type;
SmpteFormat _Session_SmpteFormat; SmpteFormat _Session_SmpteFormat;
@ -105,6 +105,7 @@ setup_enum_writer ()
ExportFormatBase::SRCQuality _ExportFormatBase_SRCQuality; ExportFormatBase::SRCQuality _ExportFormatBase_SRCQuality;
ExportProfileManager::TimeFormat _ExportProfileManager_TimeFormat; ExportProfileManager::TimeFormat _ExportProfileManager_TimeFormat;
Delivery::Role _Delivery_Role; Delivery::Role _Delivery_Role;
IO::Direction _IO_Direction;
#define REGISTER(e) enum_writer->register_distinct (typeid(e).name(), i, s); i.clear(); s.clear() #define REGISTER(e) enum_writer->register_distinct (typeid(e).name(), i, s); i.clear(); s.clear()
#define REGISTER_BITS(e) enum_writer->register_bits (typeid(e).name(), i, s); i.clear(); s.clear() #define REGISTER_BITS(e) enum_writer->register_bits (typeid(e).name(), i, s); i.clear(); s.clear()
@ -328,12 +329,6 @@ setup_enum_writer ()
REGISTER_CLASS_ENUM (Session, pullup_Minus4Minus1); REGISTER_CLASS_ENUM (Session, pullup_Minus4Minus1);
REGISTER (_Session_PullupFormat); REGISTER (_Session_PullupFormat);
REGISTER_ENUM (PRE_FADER);
REGISTER_ENUM (POST_FADER);
REGISTER_ENUM (CONTROL_OUTS);
REGISTER_ENUM (MAIN_OUTS);
REGISTER (_mute_type);
REGISTER_CLASS_ENUM (Route, Hidden); REGISTER_CLASS_ENUM (Route, Hidden);
REGISTER_CLASS_ENUM (Route, MasterOut); REGISTER_CLASS_ENUM (Route, MasterOut);
REGISTER_CLASS_ENUM (Route, ControlOut); REGISTER_CLASS_ENUM (Route, ControlOut);
@ -502,9 +497,13 @@ setup_enum_writer ()
REGISTER_CLASS_ENUM (ExportProfileManager, Off); REGISTER_CLASS_ENUM (ExportProfileManager, Off);
REGISTER (_ExportProfileManager_TimeFormat); REGISTER (_ExportProfileManager_TimeFormat);
REGISTER_CLASS_ENUM (Delivery, Solo); REGISTER_CLASS_ENUM (Delivery, Insert);
REGISTER_CLASS_ENUM (Delivery, Send); REGISTER_CLASS_ENUM (Delivery, Send);
REGISTER_CLASS_ENUM (Delivery, Listen); REGISTER_CLASS_ENUM (Delivery, Listen);
REGISTER_CLASS_ENUM (Delivery, Main); REGISTER_CLASS_ENUM (Delivery, Main);
REGISTER_BITS (_Delivery_Role); REGISTER_BITS (_Delivery_Role);
REGISTER_CLASS_ENUM (IO, Input);
REGISTER_CLASS_ENUM (IO, Output);
REGISTER (_IO_Direction);
} }

File diff suppressed because it is too large Load diff

View file

@ -46,20 +46,36 @@ using namespace PBD;
/* create an IOProcessor that proxies to a new IO object */ /* create an IOProcessor that proxies to a new IO object */
IOProcessor::IOProcessor (Session& s, const string& proc_name, const string io_name, DataType dtype) IOProcessor::IOProcessor (Session& s, bool with_input, bool with_output,
const string& proc_name, const string io_name, DataType dtype)
: Processor(s, proc_name) : Processor(s, proc_name)
, _io (new IO(s, io_name.empty() ? proc_name : io_name, dtype))
{ {
_own_io = true; /* these are true in this constructor whether we actually create the associated
IO objects or not.
*/
_own_input = true;
_own_output = true;
if (with_input) {
_input.reset (new IO(s, io_name.empty() ? proc_name : io_name, IO::Input, dtype));
}
if (with_output) {
_output.reset (new IO(s, io_name.empty() ? proc_name : io_name, IO::Output, dtype));
}
} }
/* create an IOProcessor that proxies to an existing IO object */ /* create an IOProcessor that proxies to an existing IO object */
IOProcessor::IOProcessor (Session& s, IO* io, const string& proc_name, DataType dtype) IOProcessor::IOProcessor (Session& s, boost::shared_ptr<IO> in, boost::shared_ptr<IO> out,
const string& proc_name, DataType dtype)
: Processor(s, proc_name) : Processor(s, proc_name)
, _io (io) , _input (in)
, _output (out)
{ {
_own_io = false; _own_input = false;
_own_output = false;
} }
IOProcessor::~IOProcessor () IOProcessor::~IOProcessor ()
@ -68,12 +84,21 @@ IOProcessor::~IOProcessor ()
} }
void void
IOProcessor::set_io (boost::shared_ptr<IO> io) IOProcessor::set_input (boost::shared_ptr<IO> io)
{ {
/* CALLER MUST HOLD PROCESS LOCK */ /* CALLER MUST HOLD PROCESS LOCK */
_io = io; _input = io;
_own_io = false; _own_input = false;
}
void
IOProcessor::set_output (boost::shared_ptr<IO> io)
{
/* CALLER MUST HOLD PROCESS LOCK */
_output = io;
_own_output = false;
} }
XMLNode& XMLNode&
@ -81,12 +106,28 @@ IOProcessor::state (bool full_state)
{ {
XMLNode& node (Processor::state (full_state)); XMLNode& node (Processor::state (full_state));
if (_own_io) { if (_own_input) {
node.add_child_nocopy (_io->state (full_state)); XMLNode& i (_input->state (full_state));
node.add_property ("own-io", "yes"); // i.name() = X_("output");
node.add_child_nocopy (i);
node.add_property ("own-input", "yes");
} else { } else {
node.add_property ("own-io", "no"); node.add_property ("own-input", "no");
node.add_property ("io", _io->name()); if (_input) {
node.add_property ("input", _input->name());
}
}
if (_own_output) {
XMLNode& o (_output->state (full_state));
// o.name() = X_("output");
node.add_child_nocopy (o);
node.add_property ("own-output", "yes");
} else {
node.add_property ("own-output", "no");
if (_output) {
node.add_property ("output", _output->name());
}
} }
return node; return node;
@ -100,67 +141,59 @@ IOProcessor::set_state (const XMLNode& node)
Processor::set_state(node); Processor::set_state(node);
if ((prop = node.property ("own-io")) != 0) { if ((prop = node.property ("own-input")) != 0) {
_own_io = prop->value() == "yes"; _own_input = (prop->value() == "yes");
} }
if ((prop = node.property ("own-output")) != 0) {
_own_output = (prop->value() == "yes");
}
cerr << _name << " own input = " << _own_input << " output = " << _own_output << endl;
/* don't attempt to set state for a proxied IO that we don't own */ /* don't attempt to set state for a proxied IO that we don't own */
if (!_own_io) {
/* look up the IO object we're supposed to proxy to */
if ((prop = node.property ("io")) == 0) {
fatal << "IOProcessor has no named IO object" << endmsg;
/*NOTREACHED*/
}
boost::shared_ptr<Route> r = _session.route_by_name (prop->value());
if (!r) {
fatal << string_compose ("IOProcessor uses an unknown IO object called %1", prop->value()) << endmsg;
/*NOTREACHED*/
}
/* gotcha */
_io = boost::static_pointer_cast<IO> (r);
return 0;
}
XMLNodeList nlist = node.children(); XMLNodeList nlist = node.children();
XMLNodeIterator niter; XMLNodeIterator niter;
for (niter = nlist.begin(); niter != nlist.end(); ++niter) { if (_own_input) {
if ((*niter)->name() == IO::state_node_name) { for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
io_node = (*niter); if ((*niter)->name() == "input") {
break; io_node = (*niter);
} else if ((*niter)->name() == "Redirect") { break;
XMLNodeList rlist = (*niter)->children();
XMLNodeIterator riter;
for (riter = rlist.begin(); riter != rlist.end(); ++riter) {
if ( (*riter)->name() == IO::state_node_name) {
warning << _("Found legacy IO in a redirect") << endmsg;
io_node = (*riter);
break;
}
} }
} }
if (io_node) {
_input->set_state(*io_node);
// legacy sessions: use IO name
if ((prop = node.property ("name")) == 0) {
set_name (_input->name());
}
} else {
error << _("XML node describing an IOProcessor is missing an IO node") << endmsg;
return -1;
}
} }
if (io_node) { if (_own_output) {
_io->set_state(*io_node); for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
if ((*niter)->name() == "output") {
// legacy sessions: use IO name io_node = (*niter);
if ((prop = node.property ("name")) == 0) { break;
set_name (_io->name()); }
} }
} else { if (io_node) {
error << _("XML node describing a redirect is missing an IO node") << endmsg; _output->set_state(*io_node);
return -1;
// legacy sessions: use IO name
if ((prop = node.property ("name")) == 0) {
set_name (_output->name());
}
}
} }
return 0; return 0;
@ -169,41 +202,33 @@ IOProcessor::set_state (const XMLNode& node)
void void
IOProcessor::silence (nframes_t nframes) IOProcessor::silence (nframes_t nframes)
{ {
if (_own_io) { if (_own_output && _output) {
_io->silence (nframes); _output->silence (nframes);
} }
} }
ChanCount ChanCount
IOProcessor::output_streams() const IOProcessor::output_streams() const
{ {
return _io->n_outputs(); return _output ? _output->n_ports() : ChanCount::ZERO;
} }
ChanCount ChanCount
IOProcessor::input_streams () const IOProcessor::input_streams () const
{ {
return _io->n_inputs(); return _input ? _input->n_ports() : ChanCount::ZERO;
} }
ChanCount ChanCount
IOProcessor::natural_output_streams() const IOProcessor::natural_output_streams() const
{ {
return _io->n_outputs(); return _output ? _output->n_ports() : ChanCount::ZERO;
} }
ChanCount ChanCount
IOProcessor::natural_input_streams () const IOProcessor::natural_input_streams () const
{ {
return _io->n_inputs(); return _input ? _input->n_ports() : ChanCount::ZERO;
}
void
IOProcessor::automation_snapshot (nframes_t now, bool force)
{
if (_own_io) {
_io->automation_snapshot(now, force);
}
} }
bool bool
@ -211,8 +236,12 @@ IOProcessor::set_name (const std::string& name)
{ {
bool ret = SessionObject::set_name (name); bool ret = SessionObject::set_name (name);
if (ret && _own_io) { if (ret && _own_input && _input) {
ret = _io->set_name (name); ret = _input->set_name (name);
}
if (ret && _own_output && _output) {
ret = _output->set_name (name);
} }
return ret; return ret;

View file

@ -29,8 +29,41 @@
using namespace std; using namespace std;
namespace ARDOUR { using namespace ARDOUR;
sigc::signal<void> Metering::Meter;
Glib::StaticMutex Metering::m_meter_signal_lock;
sigc::connection
Metering::connect (sigc::slot<void> the_slot)
{
// SignalProcessor::Meter is emitted from another thread so the
// Meter signal must be protected.
Glib::Mutex::Lock guard (m_meter_signal_lock);
return Meter.connect (the_slot);
}
void
Metering::disconnect (sigc::connection& c)
{
Glib::Mutex::Lock guard (m_meter_signal_lock);
c.disconnect ();
}
/**
Update the meters.
The meter signal lock is taken to prevent modification of the
Meter signal while updating the meters, taking the meter signal
lock prior to taking the io_lock ensures that all IO will remain
valid while metering.
*/
void
Metering::update_meters()
{
Glib::Mutex::Lock guard (m_meter_signal_lock);
Meter(); /* EMIT SIGNAL */
}
/** Get peaks from @a bufs /** Get peaks from @a bufs
* Input acceptance is lenient - the first n buffers from @a bufs will * Input acceptance is lenient - the first n buffers from @a bufs will
@ -128,8 +161,10 @@ PeakMeter::configure_io (ChanCount in, ChanCount out)
} }
/** To be driven by the Meter signal from IO. /** To be driven by the Meter signal from IO.
* Caller MUST hold io_lock! * Caller MUST hold its own processor_lock to prevent reconfiguration
* of meter size during this call.
*/ */
void void
PeakMeter::meter () PeakMeter::meter ()
{ {
@ -139,12 +174,10 @@ PeakMeter::meter ()
for (size_t n = 0; n < limit; ++n) { for (size_t n = 0; n < limit; ++n) {
/* XXX we should use atomic exchange here */
/* grab peak since last read */ /* grab peak since last read */
float new_peak = _peak_power[n]; float new_peak = _peak_power[n]; /* XXX we should use atomic exchange from here ... */
_peak_power[n] = 0; _peak_power[n] = 0; /* ... to here */
/* compute new visible value using falloff */ /* compute new visible value using falloff */
@ -176,4 +209,3 @@ PeakMeter::state (bool full_state)
return node; return node;
} }
} // namespace ARDOUR

View file

@ -159,8 +159,8 @@ MidiDiskstream::non_realtime_input_change ()
} }
if (input_change_pending & ConfigurationChanged) { if (input_change_pending & ConfigurationChanged) {
if (_io->n_inputs().n_midi() != _n_channels.n_midi()) { if (_io->n_ports().n_midi() != _n_channels.n_midi()) {
error << "Can not feed IO " << _io->n_inputs() error << "Can not feed IO " << _io->n_ports()
<< " with diskstream " << _n_channels << endl; << " with diskstream " << _n_channels << endl;
} }
} }
@ -199,7 +199,7 @@ MidiDiskstream::non_realtime_input_change ()
void void
MidiDiskstream::get_input_sources () MidiDiskstream::get_input_sources ()
{ {
uint32_t ni = _io->n_inputs().n_midi(); uint32_t ni = _io->n_ports().n_midi();
if (ni == 0) { if (ni == 0) {
return; return;
@ -208,7 +208,7 @@ MidiDiskstream::get_input_sources ()
// This is all we do for now at least // This is all we do for now at least
assert(ni == 1); assert(ni == 1);
_source_port = _io->midi_input(0); _source_port = _io->midi(0);
// do... stuff? // do... stuff?
} }
@ -421,6 +421,7 @@ MidiDiskstream::check_record_status (nframes_t transport_frame, nframes_t nframe
last_possibly_recording = possibly_recording; last_possibly_recording = possibly_recording;
} }
#if 0
static void static void
trace_midi (ostream& o, MIDI::byte *msg, size_t len) trace_midi (ostream& o, MIDI::byte *msg, size_t len)
{ {
@ -587,6 +588,7 @@ trace_midi (ostream& o, MIDI::byte *msg, size_t len)
break; break;
} }
} }
#endif
int int
MidiDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can_record, bool rec_monitors_input) MidiDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can_record, bool rec_monitors_input)

View file

@ -27,6 +27,7 @@
#include "ardour/amp.h" #include "ardour/amp.h"
#include "ardour/buffer_set.h" #include "ardour/buffer_set.h"
#include "ardour/delivery.h"
#include "ardour/io_processor.h" #include "ardour/io_processor.h"
#include "ardour/meter.h" #include "ardour/meter.h"
#include "ardour/midi_diskstream.h" #include "ardour/midi_diskstream.h"
@ -94,14 +95,14 @@ int
MidiTrack::set_diskstream (boost::shared_ptr<MidiDiskstream> ds) MidiTrack::set_diskstream (boost::shared_ptr<MidiDiskstream> ds)
{ {
_diskstream = ds; _diskstream = ds;
_diskstream->set_io (*this); _diskstream->set_io (*(_input.get()));
_diskstream->set_destructive (_mode == Destructive); _diskstream->set_destructive (_mode == Destructive);
_diskstream->set_record_enabled (false); _diskstream->set_record_enabled (false);
//_diskstream->monitor_input (false); //_diskstream->monitor_input (false);
ic_connection.disconnect(); ic_connection.disconnect();
ic_connection = input_changed.connect (mem_fun (*_diskstream, &MidiDiskstream::handle_input_change)); ic_connection = _input->changed.connect (mem_fun (*_diskstream, &MidiDiskstream::handle_input_change));
DiskstreamChanged (); /* EMIT SIGNAL */ DiskstreamChanged (); /* EMIT SIGNAL */
@ -113,11 +114,14 @@ MidiTrack::use_diskstream (string name)
{ {
boost::shared_ptr<MidiDiskstream> dstream; boost::shared_ptr<MidiDiskstream> dstream;
cerr << "\n\n\nMIDI use diskstream\n";
if ((dstream = boost::dynamic_pointer_cast<MidiDiskstream>(_session.diskstream_by_name (name))) == 0) { if ((dstream = boost::dynamic_pointer_cast<MidiDiskstream>(_session.diskstream_by_name (name))) == 0) {
error << string_compose(_("MidiTrack: midi diskstream \"%1\" not known by session"), name) << endmsg; error << string_compose(_("MidiTrack: midi diskstream \"%1\" not known by session"), name) << endmsg;
return -1; return -1;
} }
cerr << "\n\n\nMIDI found DS\n";
return set_diskstream (dstream); return set_diskstream (dstream);
} }
@ -192,6 +196,8 @@ MidiTrack::_set_state (const XMLNode& node, bool call_base)
an old one. an old one.
*/ */
cerr << "\n\n\n\n MIDI track " << name() << " found DS id " << id << endl;
if (id == zero) { if (id == zero) {
use_new_diskstream (); use_new_diskstream ();
} else if (use_diskstream (id)) { } else if (use_diskstream (id)) {
@ -363,8 +369,6 @@ MidiTrack::roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame,
int dret; int dret;
boost::shared_ptr<MidiDiskstream> diskstream = midi_diskstream(); boost::shared_ptr<MidiDiskstream> diskstream = midi_diskstream();
prepare_inputs (nframes);
{ {
Glib::RWLock::ReaderLock lm (_processor_lock, Glib::TRY_LOCK); Glib::RWLock::ReaderLock lm (_processor_lock, Glib::TRY_LOCK);
if (lm.locked()) { if (lm.locked()) {
@ -405,7 +409,7 @@ MidiTrack::roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame,
/* special condition applies */ /* special condition applies */
if (_meter_point == MeterInput) { if (_meter_point == MeterInput) {
just_meter_input (start_frame, end_frame, nframes); _input->process_input (_meter, start_frame, end_frame, nframes);
} }
if (diskstream->record_enabled() && !can_record && !_session.config.get_auto_input()) { if (diskstream->record_enabled() && !can_record && !_session.config.get_auto_input()) {
@ -438,7 +442,7 @@ MidiTrack::roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame,
} }
flush_outputs (nframes); _main_outs->flush (nframes);
return 0; return 0;
} }

109
libs/ardour/mute_master.cc Normal file
View file

@ -0,0 +1,109 @@
/*
Copyright (C) 2009 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "ardour/mute_master.h"
#include "ardour/rc_configuration.h"
#include "i18n.h"
using namespace ARDOUR;
MuteMaster::MuteMaster (Session& s, const std::string& name)
: AutomationControl (s, Evoral::Parameter (MuteAutomation), boost::shared_ptr<AutomationList>(), name)
, _mute_point (MutePoint (0))
{
// default range for parameter is fine
_automation = new AutomationList (MuteAutomation);
set_list (boost::shared_ptr<AutomationList>(_automation));
}
void
MuteMaster::clear_mute ()
{
if (_mute_point != MutePoint (0)) {
_mute_point = MutePoint (0);
MutePointChanged (); // EMIT SIGNAL
}
}
void
MuteMaster::mute_at (MutePoint mp)
{
if ((_mute_point & mp) != mp) {
_mute_point = MutePoint (_mute_point | mp);
MutePointChanged (); // EMIT SIGNAL
}
}
void
MuteMaster::unmute_at (MutePoint mp)
{
if ((_mute_point & mp) == mp) {
_mute_point = MutePoint (_mute_point & ~mp);
MutePointChanged (); // EMIT SIGNAL
}
}
void
MuteMaster::mute (bool yn)
{
/* convenience wrapper around AutomationControl method */
if (yn) {
set_value (1.0f);
} else {
set_value (0.0f);
}
}
gain_t
MuteMaster::mute_gain_at (MutePoint mp) const
{
if (_mute_point & mp) {
return Config->get_solo_mute_gain ();
} else {
return 1.0;
}
}
void
MuteMaster::set_value (float f)
{
mute_at ((MutePoint) ((int) rint (f)));
}
float
MuteMaster::get_value () const
{
return (float) _mute_point;
}
int
MuteMaster::set_state (const XMLNode& node)
{
return 0;
}
XMLNode&
MuteMaster::get_state()
{
return *(new XMLNode (X_("MuteMaster")));
}

View file

@ -703,7 +703,8 @@ Multi2dPanner::set_state (const XMLNode& node)
/*---------------------------------------------------------------------- */ /*---------------------------------------------------------------------- */
Panner::Panner (string name, Session& s) Panner::Panner (string name, Session& s)
: Processor(s, name) : SessionObject (s, name)
, AutomatableControls (s)
{ {
//set_name_old_auto (name); //set_name_old_auto (name);
set_name (name); set_name (name);
@ -829,6 +830,8 @@ Panner::reset (uint32_t nouts, uint32_t npans)
bool changed = false; bool changed = false;
bool do_not_and_did_not_need_panning = ((nouts < 2) && (outputs.size() < 2)); bool do_not_and_did_not_need_panning = ((nouts < 2) && (outputs.size() < 2));
cerr << "panner " << _name << " reset to " << nouts << " / " << npans << endl;
/* if new and old config don't need panning, or if /* if new and old config don't need panning, or if
the config hasn't changed, we're done. the config hasn't changed, we're done.
*/ */
@ -1058,15 +1061,13 @@ Panner::get_state (void)
XMLNode& XMLNode&
Panner::state (bool full) Panner::state (bool full)
{ {
XMLNode& node = Processor::state(full); XMLNode* node = new XMLNode ("Panner");
node.add_property ("type", "panner");
char buf[32]; char buf[32];
node.add_property (X_("linked"), (_linked ? "yes" : "no")); node->add_property (X_("linked"), (_linked ? "yes" : "no"));
node.add_property (X_("link_direction"), enum_2_string (_link_direction)); node->add_property (X_("link_direction"), enum_2_string (_link_direction));
node.add_property (X_("bypassed"), (bypassed() ? "yes" : "no")); node->add_property (X_("bypassed"), (bypassed() ? "yes" : "no"));
for (vector<Panner::Output>::iterator o = outputs.begin(); o != outputs.end(); ++o) { for (vector<Panner::Output>::iterator o = outputs.begin(); o != outputs.end(); ++o) {
XMLNode* onode = new XMLNode (X_("Output")); XMLNode* onode = new XMLNode (X_("Output"));
@ -1074,15 +1075,15 @@ Panner::state (bool full)
onode->add_property (X_("x"), buf); onode->add_property (X_("x"), buf);
snprintf (buf, sizeof (buf), "%.12g", (*o).y); snprintf (buf, sizeof (buf), "%.12g", (*o).y);
onode->add_property (X_("y"), buf); onode->add_property (X_("y"), buf);
node.add_child_nocopy (*onode); node->add_child_nocopy (*onode);
} }
for (vector<StreamPanner*>::const_iterator i = _streampanners.begin(); i != _streampanners.end(); ++i) { for (vector<StreamPanner*>::const_iterator i = _streampanners.begin(); i != _streampanners.end(); ++i) {
node.add_child_nocopy ((*i)->state (full)); node->add_child_nocopy ((*i)->state (full));
} }
return node; return *node;
} }
int int
@ -1098,8 +1099,6 @@ Panner::set_state (const XMLNode& node)
clear_panners (); clear_panners ();
Processor::set_state(node);
ChanCount ins = ChanCount::ZERO; ChanCount ins = ChanCount::ZERO;
ChanCount outs = ChanCount::ZERO; ChanCount outs = ChanCount::ZERO;
@ -1419,7 +1418,7 @@ Panner::distribute_no_automation (BufferSet& inbufs, BufferSet& outbufs, nframes
} }
void void
Panner::run_out_of_place (BufferSet& inbufs, BufferSet& outbufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes) Panner::run (BufferSet& inbufs, BufferSet& outbufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes)
{ {
if (outbufs.count().n_audio() == 0) { if (outbufs.count().n_audio() == 0) {
// Failing to deliver audio we were asked to deliver is a bug // Failing to deliver audio we were asked to deliver is a bug
@ -1432,16 +1431,16 @@ Panner::run_out_of_place (BufferSet& inbufs, BufferSet& outbufs, sframes_t start
assert(!empty()); assert(!empty());
// If we shouldn't play automation defer to distribute_no_automation // If we shouldn't play automation defer to distribute_no_automation
if ( !( automation_state() & Play || if (!(automation_state() & Play || ((automation_state() & Touch) && !touching()))) {
((automation_state() & Touch) && !touching()) ) ) {
// Speed quietning // Speed quietning
gain_t gain_coeff = 1.0; gain_t gain_coeff = 1.0;
if (fabsf(_session.transport_speed()) > 1.5f) { if (fabsf(_session.transport_speed()) > 1.5f) {
gain_coeff = speed_quietning; gain_coeff = speed_quietning;
} }
distribute_no_automation(inbufs, outbufs, nframes, gain_coeff); distribute_no_automation (inbufs, outbufs, nframes, gain_coeff);
return; return;
} }

View file

@ -24,6 +24,7 @@
#include "pbd/failed_constructor.h" #include "pbd/failed_constructor.h"
#include "pbd/xml++.h" #include "pbd/xml++.h"
#include "ardour/delivery.h"
#include "ardour/port_insert.h" #include "ardour/port_insert.h"
#include "ardour/plugin.h" #include "ardour/plugin.h"
#include "ardour/port.h" #include "ardour/port.h"
@ -40,15 +41,17 @@ using namespace std;
using namespace ARDOUR; using namespace ARDOUR;
using namespace PBD; using namespace PBD;
PortInsert::PortInsert (Session& s) PortInsert::PortInsert (Session& s, boost::shared_ptr<MuteMaster> mm)
: IOProcessor (s, string_compose (_("insert %1"), (bitslot = s.next_insert_id()) + 1), "") : IOProcessor (s, true, true, string_compose (_("insert %1"), (bitslot = s.next_insert_id()) + 1), "")
, _out (new Delivery (s, _output, mm, _name, Delivery::Insert))
{ {
init ();
ProcessorCreated (this); /* EMIT SIGNAL */ ProcessorCreated (this); /* EMIT SIGNAL */
} }
PortInsert::PortInsert (Session& s, const XMLNode& node) PortInsert::PortInsert (Session& s, boost::shared_ptr<MuteMaster> mm, const XMLNode& node)
: IOProcessor (s, "unnamed port insert") : IOProcessor (s, true, true, "unnamed port insert")
, _out (new Delivery (s, _output, mm, _name, Delivery::Insert))
{ {
if (set_state (node)) { if (set_state (node)) {
throw failed_constructor(); throw failed_constructor();
@ -62,30 +65,21 @@ PortInsert::~PortInsert ()
GoingAway (); GoingAway ();
} }
void
PortInsert::init ()
{
if (_io->ensure_io(output_streams(), input_streams(), false, this)) { // sic
error << _("PortInsert: cannot create ports") << endmsg;
throw failed_constructor();
}
}
void void
PortInsert::run_in_place (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes) PortInsert::run_in_place (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes)
{ {
if (_io->n_outputs().n_total() == 0) { if (_output->n_ports().n_total() == 0) {
return; return;
} }
if (!active()) { if (!active()) {
/* deliver silence */ /* deliver silence */
_io->silence (nframes); silence (nframes);
return; return;
} }
_io->deliver_output (bufs, start_frame, end_frame, nframes); _out->run_in_place (bufs, start_frame, end_frame, nframes);
_io->collect_input (bufs, nframes); _input->collect_input (bufs, nframes, ChanCount::ZERO);
} }
XMLNode& XMLNode&
@ -97,7 +91,7 @@ PortInsert::get_state(void)
XMLNode& XMLNode&
PortInsert::state (bool full) PortInsert::state (bool full)
{ {
XMLNode& node = IOProcessor::state(full); XMLNode& node = Processor::state(full);
char buf[32]; char buf[32];
node.add_property ("type", "port"); node.add_property ("type", "port");
snprintf (buf, sizeof (buf), "%" PRIu32, bitslot); snprintf (buf, sizeof (buf), "%" PRIu32, bitslot);
@ -141,7 +135,7 @@ PortInsert::set_state(const XMLNode& node)
} }
} }
IOProcessor::set_state (*insert_node); Processor::set_state (*insert_node);
return 0; return 0;
} }
@ -156,7 +150,7 @@ PortInsert::signal_latency() const
need to take that into account too. need to take that into account too.
*/ */
return _session.engine().frames_per_cycle() + _io->input_latency(); return _session.engine().frames_per_cycle() + _input->signal_latency();
} }
bool bool
@ -164,7 +158,11 @@ PortInsert::configure_io (ChanCount in, ChanCount out)
{ {
/* for an insert, processor input corresponds to IO output, and vice versa */ /* for an insert, processor input corresponds to IO output, and vice versa */
if (_io->ensure_io (out, in, false, this) != 0) { if (_input->ensure_io (in, false, this) != 0) {
return false;
}
if (_output->ensure_io (out, false, this) != 0) {
return false; return false;
} }
@ -178,3 +176,12 @@ PortInsert::can_support_io_configuration (const ChanCount& in, ChanCount& out) c
return true; return true;
} }
bool
PortInsert::set_name (const std::string& name)
{
bool ret = Processor::set_name (name);
ret = (_input->set_name (name) || _output->set_name (name));
return ret;
}

View file

@ -211,7 +211,8 @@ Processor::configure_io (ChanCount in, ChanCount out)
{ {
/* This class assumes 1:1 input:output.static output stream count. /* This class assumes 1:1 input:output.static output stream count.
Derived classes must override and set _configured_output appropriately Derived classes must override and set _configured_output appropriately
if this is not the case */ if this is not the case
*/
_configured_input = in; _configured_input = in;
_configured_output = out; _configured_output = out;

View file

@ -21,14 +21,15 @@
#include "pbd/xml++.h" #include "pbd/xml++.h"
#include "ardour/return.h" #include "ardour/amp.h"
#include "ardour/session.h"
#include "ardour/port.h"
#include "ardour/audio_port.h" #include "ardour/audio_port.h"
#include "ardour/buffer_set.h" #include "ardour/buffer_set.h"
#include "ardour/io.h"
#include "ardour/meter.h" #include "ardour/meter.h"
#include "ardour/panner.h" #include "ardour/panner.h"
#include "ardour/io.h" #include "ardour/port.h"
#include "ardour/return.h"
#include "ardour/session.h"
#include "i18n.h" #include "i18n.h"
@ -36,14 +37,26 @@ using namespace ARDOUR;
using namespace PBD; using namespace PBD;
Return::Return (Session& s) Return::Return (Session& s)
: IOProcessor (s, string_compose (_("return %1"), (_bitslot = s.next_return_id()) + 1)) : IOProcessor (s, true, false, string_compose (_("return %1"), (_bitslot = s.next_return_id()) + 1))
, _metering (false)
{ {
/* never muted */
_amp.reset (new Amp (_session, boost::shared_ptr<MuteMaster>()));
_meter.reset (new PeakMeter (_session));
ProcessorCreated (this); /* EMIT SIGNAL */ ProcessorCreated (this); /* EMIT SIGNAL */
} }
Return::Return (Session& s, const XMLNode& node) Return::Return (Session& s, const XMLNode& node)
: IOProcessor (s, "return") : IOProcessor (s, true, false, "return")
, _metering (false)
{ {
/* never muted */
_amp.reset (new Amp (_session, boost::shared_ptr<MuteMaster>()));
_meter.reset (new PeakMeter (_session));
if (set_state (node)) { if (set_state (node)) {
throw failed_constructor(); throw failed_constructor();
} }
@ -108,23 +121,38 @@ Return::set_state(const XMLNode& node)
void void
Return::run_in_place (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes) Return::run_in_place (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes)
{ {
if (active()) { if (!active() || _input->n_ports() == ChanCount::ZERO) {
_io->collect_input (bufs, nframes, _configured_input); return;
bufs.set_count(_configured_output); }
_input->collect_input (bufs, nframes, _configured_input);
bufs.set_count(_configured_output);
// Can't automate gain for sends or returns yet because we need different buffers
// so that we don't overwrite the main automation data for the route amp
// _amp->setup_gain_automation (start_frame, end_frame, nframes);
_amp->run_in_place (bufs, start_frame, end_frame, nframes);
if (_metering) {
if (_amp->gain_control()->get_value() == 0) {
_meter->reset();
} else {
_meter->run_in_place (bufs, start_frame, end_frame, nframes);
}
} }
} }
bool bool
Return::can_support_io_configuration (const ChanCount& in, ChanCount& out) const Return::can_support_io_configuration (const ChanCount& in, ChanCount& out) const
{ {
out = in + _io->n_inputs(); out = in + _input->n_ports();
return true; return true;
} }
bool bool
Return::configure_io (ChanCount in, ChanCount out) Return::configure_io (ChanCount in, ChanCount out)
{ {
if (out != in + _io->n_inputs()) { if (out != in + _input->n_ports()) {
return false; return false;
} }
@ -162,3 +190,4 @@ Return::make_unique (XMLNode &state, Session &session)
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -27,6 +27,7 @@
#include "pbd/error.h" #include "pbd/error.h"
#include "pbd/enumwriter.h" #include "pbd/enumwriter.h"
#include "ardour/amp.h"
#include "ardour/route_group.h" #include "ardour/route_group.h"
#include "ardour/audio_track.h" #include "ardour/audio_track.h"
#include "ardour/audio_diskstream.h" #include "ardour/audio_diskstream.h"
@ -87,7 +88,7 @@ RouteGroup::get_min_factor(gain_t factor)
gain_t g; gain_t g;
for (list<Route *>::iterator i = routes.begin(); i != routes.end(); i++) { for (list<Route *>::iterator i = routes.begin(); i != routes.end(); i++) {
g = (*i)->gain(); g = (*i)->amp()->gain();
if ( (g+g*factor) >= 0.0f) if ( (g+g*factor) >= 0.0f)
continue; continue;
@ -106,7 +107,7 @@ RouteGroup::get_max_factor(gain_t factor)
gain_t g; gain_t g;
for (list<Route *>::iterator i = routes.begin(); i != routes.end(); i++) { for (list<Route *>::iterator i = routes.begin(); i != routes.end(); i++) {
g = (*i)->gain(); g = (*i)->amp()->gain();
// if the current factor woulnd't raise this route above maximum // if the current factor woulnd't raise this route above maximum
if ( (g+g*factor) <= 1.99526231f) if ( (g+g*factor) <= 1.99526231f)

View file

@ -21,6 +21,7 @@
#include "pbd/xml++.h" #include "pbd/xml++.h"
#include "ardour/amp.h"
#include "ardour/send.h" #include "ardour/send.h"
#include "ardour/session.h" #include "ardour/session.h"
#include "ardour/port.h" #include "ardour/port.h"
@ -35,15 +36,23 @@
using namespace ARDOUR; using namespace ARDOUR;
using namespace PBD; using namespace PBD;
Send::Send (Session& s) Send::Send (Session& s, boost::shared_ptr<MuteMaster> mm)
: Delivery (s, string_compose (_("send %1"), (_bitslot = s.next_send_id()) + 1), Delivery::Send) : Delivery (s, mm, string_compose (_("send %1"), (_bitslot = s.next_send_id()) + 1), Delivery::Send)
, _metering (false)
{ {
_amp.reset (new Amp (_session, _mute_master));
_meter.reset (new PeakMeter (_session));
ProcessorCreated (this); /* EMIT SIGNAL */ ProcessorCreated (this); /* EMIT SIGNAL */
} }
Send::Send (Session& s, const XMLNode& node) Send::Send (Session& s, boost::shared_ptr<MuteMaster> mm, const XMLNode& node)
: Delivery (s, "send", Delivery::Send) : Delivery (s, mm, "send", Delivery::Send)
, _metering (false)
{ {
_amp.reset (new Amp (_session, _mute_master));
_meter.reset (new PeakMeter (_session));
if (set_state (node)) { if (set_state (node)) {
throw failed_constructor(); throw failed_constructor();
} }
@ -56,6 +65,43 @@ Send::~Send ()
GoingAway (); GoingAway ();
} }
void
Send::run_in_place (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes)
{
if (!_active || _output->n_ports() == ChanCount::ZERO) {
_meter->reset ();
return;
}
// we have to copy the input, because deliver_output() may alter the buffers
// in-place, which a send must never do.
BufferSet& sendbufs = _session.get_mix_buffers (bufs.count());
sendbufs.read_from (bufs, nframes);
assert(sendbufs.count() == bufs.count());
/* gain control */
// Can't automate gain for sends or returns yet because we need different buffers
// so that we don't overwrite the main automation data for the route amp
// _amp->setup_gain_automation (start_frame, end_frame, nframes);
_amp->run_in_place (sendbufs, start_frame, end_frame, nframes);
/* deliver to outputs */
Delivery::run_in_place (sendbufs, start_frame, end_frame, nframes);
/* consider metering */
if (_metering) {
if (_amp->gain_control()->get_value() == 0) {
_meter->reset();
} else {
_meter->run_in_place (*_output_buffers, start_frame, end_frame, nframes);
}
}
}
XMLNode& XMLNode&
Send::get_state(void) Send::get_state(void)
{ {
@ -90,17 +136,9 @@ Send::set_state(const XMLNode& node)
const XMLNode* insert_node = &node; const XMLNode* insert_node = &node;
/* Send has regular IO automation (gain, pan) */ /* XXX need to load automation state & data for amp */
for (niter = nlist.begin(); niter != nlist.end(); ++niter) { Delivery::set_state (*insert_node);
if ((*niter)->name() == IOProcessor::state_node_name) {
insert_node = *niter;
} else if ((*niter)->name() == X_("Automation")) {
// _io->set_automation_state (*(*niter), Evoral::Parameter(GainAutomation));
}
}
IOProcessor::set_state (*insert_node);
return 0; return 0;
} }
@ -108,7 +146,7 @@ Send::set_state(const XMLNode& node)
bool bool
Send::can_support_io_configuration (const ChanCount& in, ChanCount& out) const Send::can_support_io_configuration (const ChanCount& in, ChanCount& out) const
{ {
if (_io->n_inputs() == ChanCount::ZERO && _io->n_outputs() == ChanCount::ZERO) { if (_output->n_ports() == ChanCount::ZERO) {
/* not configured yet, we can support anything */ /* not configured yet, we can support anything */
@ -126,25 +164,6 @@ Send::can_support_io_configuration (const ChanCount& in, ChanCount& out) const
return false; return false;
} }
bool
Send::configure_io (ChanCount in, ChanCount out)
{
/* we're transparent no matter what. fight the power. */
if (out != in) {
return false;
}
if (_io->ensure_io (ChanCount::ZERO, in, false, this) != 0) {
return false;
}
Processor::configure_io(in, out);
_io->reset_panner();
return true;
}
/** Set up the XML description of a send so that its name is unique. /** Set up the XML description of a send so that its name is unique.
* @param state XML send state. * @param state XML send state.
* @param session Session. * @param session Session.

View file

@ -272,7 +272,8 @@ Session::Session (AudioEngine &eng,
if (control_out_channels) { if (control_out_channels) {
ChanCount count(DataType::AUDIO, control_out_channels); ChanCount count(DataType::AUDIO, control_out_channels);
shared_ptr<Route> r (new Route (*this, _("monitor"), Route::ControlOut, DataType::AUDIO)); shared_ptr<Route> r (new Route (*this, _("monitor"), Route::ControlOut, DataType::AUDIO));
r->ensure_io (count, count, false, this); r->input()->ensure_io (count, false, this);
r->output()->ensure_io (count, false, this);
r->set_remote_control_id (control_id++); r->set_remote_control_id (control_id++);
rl.push_back (r); rl.push_back (r);
@ -280,9 +281,9 @@ Session::Session (AudioEngine &eng,
if (master_out_channels) { if (master_out_channels) {
ChanCount count(DataType::AUDIO, master_out_channels); ChanCount count(DataType::AUDIO, master_out_channels);
cerr << "new MO with " << count << endl;
shared_ptr<Route> r (new Route (*this, _("master"), Route::MasterOut, DataType::AUDIO)); shared_ptr<Route> r (new Route (*this, _("master"), Route::MasterOut, DataType::AUDIO));
r->ensure_io (count, count, false, this); r->input()->ensure_io (count, false, this);
r->output()->ensure_io (count, false, this);
r->set_remote_control_id (control_id); r->set_remote_control_id (control_id);
rl.push_back (r); rl.push_back (r);
@ -516,8 +517,8 @@ Session::set_worst_io_latencies ()
boost::shared_ptr<RouteList> r = routes.reader (); boost::shared_ptr<RouteList> r = routes.reader ();
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
_worst_output_latency = max (_worst_output_latency, (*i)->output_latency()); _worst_output_latency = max (_worst_output_latency, (*i)->output()->latency());
_worst_input_latency = max (_worst_input_latency, (*i)->input_latency()); _worst_input_latency = max (_worst_input_latency, (*i)->input()->latency());
} }
} }
@ -576,13 +577,13 @@ Session::when_engine_running ()
string physical_output = _engine.get_nth_physical_output (DataType::AUDIO, physport); string physical_output = _engine.get_nth_physical_output (DataType::AUDIO, physport);
if (physical_output.length()) { if (physical_output.length()) {
if (_click_io->add_output_port (physical_output, this)) { if (_click_io->add_port (physical_output, this)) {
// relax, even though its an error // relax, even though its an error
} }
} }
} }
if (_click_io->n_outputs () > ChanCount::ZERO) { if (_click_io->n_ports () > ChanCount::ZERO) {
_clicking = Config->get_clicking (); _clicking = Config->get_clicking ();
} }
} }
@ -665,12 +666,6 @@ Session::when_engine_running ()
if (_master_out) { if (_master_out) {
/* force the master to ignore any later call to this
*/
if (_master_out->pending_state_node) {
_master_out->ports_became_legal();
}
/* if requested auto-connect the outputs to the first N physical ports. /* if requested auto-connect the outputs to the first N physical ports.
*/ */
@ -678,11 +673,11 @@ Session::when_engine_running ()
uint32_t limit = _master_out->n_outputs().n_total(); uint32_t limit = _master_out->n_outputs().n_total();
for (uint32_t n = 0; n < limit; ++n) { for (uint32_t n = 0; n < limit; ++n) {
Port* p = _master_out->output (n); Port* p = _master_out->output()->nth (n);
string connect_to = _engine.get_nth_physical_output (DataType (p->type()), n); string connect_to = _engine.get_nth_physical_output (DataType (p->type()), n);
if (!connect_to.empty()) { if (!connect_to.empty()) {
if (_master_out->connect_output (p, connect_to, this)) { if (_master_out->output()->connect (p, connect_to, this)) {
error << string_compose (_("cannot connect master output %1 to %2"), n, connect_to) error << string_compose (_("cannot connect master output %1 to %2"), n, connect_to)
<< endmsg; << endmsg;
break; break;
@ -760,10 +755,6 @@ Session::hookup_io ()
} }
} }
/* Tell all IO objects to create their ports */
IO::enable_ports ();
/* Connect track to listen/solo etc. busses XXX generalize this beyond control_out */ /* Connect track to listen/solo etc. busses XXX generalize this beyond control_out */
if (_control_out) { if (_control_out) {
@ -777,7 +768,7 @@ Session::hookup_io ()
boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*x); boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*x);
if (t) { if (t) {
t->listen_via (_control_out, X_("listen")); t->listen_via (_control_out->input(), X_("listen"));
} }
} }
} }
@ -794,7 +785,7 @@ Session::hookup_io ()
/* Now reset all panners */ /* Now reset all panners */
IO::reset_panners (); Delivery::reset_panners ();
/* Anyone who cares about input state, wake up and do something */ /* Anyone who cares about input state, wake up and do something */
@ -1468,7 +1459,7 @@ Session::resort_routes_using (shared_ptr<RouteList> r)
continue; continue;
} }
if ((*j)->feeds (*i)) { if ((*j)->feeds ((*i)->input())) {
(*i)->fed_by.insert (*j); (*i)->fed_by.insert (*j);
} }
} }
@ -1553,7 +1544,13 @@ Session::new_midi_track (TrackMode mode, uint32_t how_many)
try { try {
track = boost::shared_ptr<MidiTrack>((new MidiTrack (*this, track_name, Route::Flag (0), mode))); track = boost::shared_ptr<MidiTrack>((new MidiTrack (*this, track_name, Route::Flag (0), mode)));
if (track->ensure_io (ChanCount(DataType::MIDI, 1), ChanCount(DataType::AUDIO, 1), false, this)) { if (track->input()->ensure_io (ChanCount(DataType::MIDI, 1), false, this)) {
error << "cannot configure 1 in/1 out configuration for new midi track" << endmsg;
goto failed;
}
if (track->output()->ensure_io (ChanCount(DataType::AUDIO, 1), false, this)) {
error << "cannot configure 1 in/1 out configuration for new midi track" << endmsg; error << "cannot configure 1 in/1 out configuration for new midi track" << endmsg;
goto failed; goto failed;
} }
@ -1711,7 +1708,14 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
try { try {
track = boost::shared_ptr<AudioTrack>((new AudioTrack (*this, track_name, Route::Flag (0), mode))); track = boost::shared_ptr<AudioTrack>((new AudioTrack (*this, track_name, Route::Flag (0), mode)));
if (track->ensure_io (ChanCount(DataType::AUDIO, input_channels), ChanCount(DataType::AUDIO, output_channels), false, this)) { if (track->input()->ensure_io (ChanCount(DataType::AUDIO, input_channels), false, this)) {
error << string_compose (_("cannot configure %1 in/%2 out configuration for new audio track"),
input_channels, output_channels)
<< endmsg;
goto failed;
}
if (track->output()->ensure_io (ChanCount(DataType::AUDIO, output_channels), false, this)) {
error << string_compose (_("cannot configure %1 in/%2 out configuration for new audio track"), error << string_compose (_("cannot configure %1 in/%2 out configuration for new audio track"),
input_channels, output_channels) input_channels, output_channels)
<< endmsg; << endmsg;
@ -1729,7 +1733,7 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
port = physinputs[(channels_used+x)%nphysical_in]; port = physinputs[(channels_used+x)%nphysical_in];
} }
if (port.length() && track->connect_input (track->input (x), port, this)) { if (port.length() && track->input()->connect (track->input()->nth(x), port, this)) {
break; break;
} }
} }
@ -1745,11 +1749,11 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
port = physoutputs[(channels_used+x)%nphysical_out]; port = physoutputs[(channels_used+x)%nphysical_out];
} else if (Config->get_output_auto_connect() & AutoConnectMaster) { } else if (Config->get_output_auto_connect() & AutoConnectMaster) {
if (_master_out && _master_out->n_inputs().n_audio() > 0) { if (_master_out && _master_out->n_inputs().n_audio() > 0) {
port = _master_out->input (x % _master_out->n_inputs().n_audio())->name(); port = _master_out->input()->nth (x % _master_out->input()->n_ports().n_audio())->name();
} }
} }
if (port.length() && track->connect_output (track->output (x), port, this)) { if (port.length() && track->output()->connect (track->output()->nth(x), port, this)) {
break; break;
} }
} }
@ -1889,7 +1893,15 @@ Session::new_audio_route (int input_channels, int output_channels, uint32_t how_
try { try {
shared_ptr<Route> bus (new Route (*this, bus_name, Route::Flag(0), DataType::AUDIO)); shared_ptr<Route> bus (new Route (*this, bus_name, Route::Flag(0), DataType::AUDIO));
if (bus->ensure_io (ChanCount(DataType::AUDIO, input_channels), ChanCount(DataType::AUDIO, output_channels), false, this)) { if (bus->output()->ensure_io (ChanCount(DataType::AUDIO, input_channels), false, this)) {
error << string_compose (_("cannot configure %1 in/%2 out configuration for new audio track"),
input_channels, output_channels)
<< endmsg;
goto failure;
}
if (bus->output()->ensure_io (ChanCount(DataType::AUDIO, output_channels), false, this)) {
error << string_compose (_("cannot configure %1 in/%2 out configuration for new audio track"), error << string_compose (_("cannot configure %1 in/%2 out configuration for new audio track"),
input_channels, output_channels) input_channels, output_channels)
<< endmsg; << endmsg;
@ -1920,11 +1932,11 @@ Session::new_audio_route (int input_channels, int output_channels, uint32_t how_
port = physoutputs[((n+x)%n_physical_outputs)]; port = physoutputs[((n+x)%n_physical_outputs)];
} else if (Config->get_output_auto_connect() & AutoConnectMaster) { } else if (Config->get_output_auto_connect() & AutoConnectMaster) {
if (_master_out) { if (_master_out) {
port = _master_out->input (x%_master_out->n_inputs().n_audio())->name(); port = _master_out->input()->nth (x%_master_out->input()->n_ports().n_audio())->name();
} }
} }
if (port.length() && bus->connect_output (bus->output (x), port, this)) { if (port.length() && bus->output()->connect (bus->output()->nth(x), port, this)) {
break; break;
} }
} }
@ -2023,8 +2035,8 @@ Session::new_route_from_template (uint32_t how_many, const std::string& template
picks up the configuration of the route. During session picks up the configuration of the route. During session
loading this normally happens in a different way. loading this normally happens in a different way.
*/ */
route->input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), this); route->input()->changed (IOChange (ConfigurationChanged|ConnectionsChanged), this);
route->output_changed (IOChange (ConfigurationChanged|ConnectionsChanged), this); route->output()->changed (IOChange (ConfigurationChanged|ConnectionsChanged), this);
} }
route->set_remote_control_id (control_id); route->set_remote_control_id (control_id);
@ -2070,7 +2082,7 @@ Session::add_routes (RouteList& new_routes, bool save)
(*x)->solo_changed.connect (sigc::bind (mem_fun (*this, &Session::route_solo_changed), wpr)); (*x)->solo_changed.connect (sigc::bind (mem_fun (*this, &Session::route_solo_changed), wpr));
(*x)->mute_changed.connect (mem_fun (*this, &Session::route_mute_changed)); (*x)->mute_changed.connect (mem_fun (*this, &Session::route_mute_changed));
(*x)->output_changed.connect (mem_fun (*this, &Session::set_worst_io_latencies_x)); (*x)->output()->changed.connect (mem_fun (*this, &Session::set_worst_io_latencies_x));
(*x)->processors_changed.connect (bind (mem_fun (*this, &Session::update_latency_compensation), false, false)); (*x)->processors_changed.connect (bind (mem_fun (*this, &Session::update_latency_compensation), false, false));
if ((*x)->is_master()) { if ((*x)->is_master()) {
@ -2085,7 +2097,7 @@ Session::add_routes (RouteList& new_routes, bool save)
if (_control_out && IO::connecting_legal) { if (_control_out && IO::connecting_legal) {
for (RouteList::iterator x = new_routes.begin(); x != new_routes.end(); ++x) { for (RouteList::iterator x = new_routes.begin(); x != new_routes.end(); ++x) {
(*x)->listen_via (_control_out, "control"); (*x)->listen_via (_control_out->input(), "control");
} }
} }
@ -2145,7 +2157,7 @@ Session::remove_route (shared_ptr<Route> route)
/* cancel control outs for all routes */ /* cancel control outs for all routes */
for (RouteList::iterator r = rs->begin(); r != rs->end(); ++r) { for (RouteList::iterator r = rs->begin(); r != rs->end(); ++r) {
(*r)->drop_listen (_control_out); (*r)->drop_listen (_control_out->input());
} }
_control_out = shared_ptr<Route> (); _control_out = shared_ptr<Route> ();
@ -2176,8 +2188,8 @@ Session::remove_route (shared_ptr<Route> route)
// We need to disconnect the routes inputs and outputs // We need to disconnect the routes inputs and outputs
route->disconnect_inputs (0); route->input()->disconnect (0);
route->disconnect_outputs (0); route->output()->disconnect (0);
update_latency_compensation (false, false); update_latency_compensation (false, false);
set_dirty(); set_dirty();
@ -2215,7 +2227,6 @@ Session::route_solo_changed (void* src, boost::weak_ptr<Route> wpr)
return; return;
} }
bool is_track;
boost::shared_ptr<Route> route = wpr.lock (); boost::shared_ptr<Route> route = wpr.lock ();
if (!route) { if (!route) {
@ -2224,86 +2235,39 @@ Session::route_solo_changed (void* src, boost::weak_ptr<Route> wpr)
return; return;
} }
is_track = (boost::dynamic_pointer_cast<AudioTrack>(route) != 0);
shared_ptr<RouteList> r = routes.reader (); shared_ptr<RouteList> r = routes.reader ();
int32_t delta;
if (route->soloed()) {
delta = 1;
} else {
delta = -1;
}
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
if ((*i)->feeds (route->input())) {
/* soloing a track mutes all other tracks, soloing a bus mutes all other busses */
if (is_track) {
/* don't mess with busses */
if (boost::dynamic_pointer_cast<Track>(*i) == 0) {
continue;
}
} else {
/* don't mess with tracks */
if (boost::dynamic_pointer_cast<Track>(*i) != 0) {
continue;
}
}
if ((*i) != route &&
((*i)->mix_group () == 0 ||
(*i)->mix_group () != route->mix_group () ||
!route->mix_group ()->is_active())) {
if ((*i)->soloed()) {
/* if its already soloed, and solo latching is enabled,
then leave it as it is.
*/
if (Config->get_solo_latched()) {
continue;
}
}
/* do it */ /* do it */
solo_update_disabled = true; solo_update_disabled = true;
(*i)->set_solo (false, src); (*i)->main_outs()->mod_solo_level (delta);
solo_update_disabled = false; solo_update_disabled = false;
} }
} }
bool something_soloed = false; /* now figure out if anything is soloed */
bool same_thing_soloed = false;
bool signal = false;
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { bool something_soloed = false;
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
if ((*i)->soloed()) { if ((*i)->soloed()) {
something_soloed = true; something_soloed = true;
if (boost::dynamic_pointer_cast<Track>(*i)) {
if (is_track) {
same_thing_soloed = true;
break;
}
} else {
if (!is_track) {
same_thing_soloed = true;
break;
}
}
break; break;
} }
} }
if (something_soloed != currently_soloing) { if (something_soloed != _non_soloed_outs_muted) {
signal = true; _non_soloed_outs_muted = something_soloed;
currently_soloing = something_soloed; SoloActive (_non_soloed_outs_muted); /* EMIT SIGNAL */
}
modify_solo_mute (is_track, same_thing_soloed);
if (signal) {
SoloActive (currently_soloing); /* EMIT SIGNAL */
} }
SoloChanged (); /* EMIT SIGNAL */ SoloChanged (); /* EMIT SIGNAL */
@ -2343,10 +2307,6 @@ Session::update_route_solo_state ()
/* nothing is soloed */ /* nothing is soloed */
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
(*i)->set_solo_mute (false);
}
if (signal) { if (signal) {
SoloActive (false); SoloActive (false);
} }
@ -2354,59 +2314,11 @@ Session::update_route_solo_state ()
return; return;
} }
modify_solo_mute (is_track, mute);
if (signal) { if (signal) {
SoloActive (currently_soloing); SoloActive (currently_soloing);
} }
} }
void
Session::modify_solo_mute (bool is_track, bool mute)
{
shared_ptr<RouteList> r = routes.reader ();
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
if (is_track) {
/* only alter track solo mute */
if (boost::dynamic_pointer_cast<Track>(*i)) {
if ((*i)->soloed()) {
(*i)->set_solo_mute (!mute);
} else {
(*i)->set_solo_mute (mute);
}
}
} else {
/* only alter bus solo mute */
if (!boost::dynamic_pointer_cast<Track>(*i)) {
if ((*i)->soloed()) {
(*i)->set_solo_mute (false);
} else {
/* don't mute master or control outs
in response to another bus solo
*/
if ((*i) != _master_out &&
(*i) != _control_out) {
(*i)->set_solo_mute (mute);
}
}
}
}
}
}
void void
Session::catch_up_on_solo () Session::catch_up_on_solo ()
@ -2432,7 +2344,7 @@ Session::catch_up_on_solo_mute_override ()
shared_ptr<RouteList> r = routes.reader (); shared_ptr<RouteList> r = routes.reader ();
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
(*i)->catch_up_on_solo_mute_override (); // (*i)->catch_up_on_solo_mute_override ();
} }
} }

View file

@ -127,7 +127,7 @@ Session::click (nframes_t start, nframes_t nframes)
i = next; i = next;
} }
_click_io->deliver_output (bufs, start, end, nframes); _click_io->copy_to_outputs (bufs, DataType::AUDIO, nframes, 0);
} }
void void

View file

@ -151,7 +151,7 @@ Session::first_stage_init (string fullpath, string snapshot_name)
_tempo_map->StateChanged.connect (mem_fun (*this, &Session::tempo_map_changed)); _tempo_map->StateChanged.connect (mem_fun (*this, &Session::tempo_map_changed));
_non_soloed_outs_muted = false;
g_atomic_int_set (&processing_prohibited, 0); g_atomic_int_set (&processing_prohibited, 0);
insert_cnt = 0; insert_cnt = 0;
_transport_speed = 0; _transport_speed = 0;
@ -272,8 +272,7 @@ Session::first_stage_init (string fullpath, string snapshot_name)
/* stop IO objects from doing stuff until we're ready for them */ /* stop IO objects from doing stuff until we're ready for them */
IO::disable_panners (); Delivery::disable_panners ();
IO::disable_ports ();
IO::disable_connecting (); IO::disable_connecting ();
} }
@ -1155,7 +1154,6 @@ Session::set_state (const XMLNode& node)
} }
IO::disable_ports ();
IO::disable_connecting (); IO::disable_connecting ();
/* Object loading order: /* Object loading order:
@ -3215,7 +3213,7 @@ Session::config_changed (std::string p, bool ours)
// deliver_midi (_mmc_port, buf, 2); // deliver_midi (_mmc_port, buf, 2);
} }
} else if (p == "solo-mute-override") { } else if (p == "solo-mute-override") {
catch_up_on_solo_mute_override (); // catch_up_on_solo_mute_override ();
} }
set_dirty (); set_dirty ();

View file

@ -1335,11 +1335,12 @@ Session::update_latency_compensation (bool with_stop, bool abort)
(!(post_transport_work & PostTransportLocate) || pending_locate_flush)); (!(post_transport_work & PostTransportLocate) || pending_locate_flush));
} }
nframes_t old_latency = (*i)->signal_latency (); nframes_t old_latency = (*i)->output()->signal_latency ();
nframes_t track_latency = (*i)->update_total_latency (); nframes_t track_latency = (*i)->update_total_latency ();
if (old_latency != track_latency) { if (old_latency != track_latency) {
(*i)->update_port_total_latencies (); (*i)->input()->update_port_total_latencies ();
(*i)->output()->update_port_total_latencies ();
update_jack = true; update_jack = true;
} }

View file

@ -26,7 +26,7 @@
#include "ardour/audiosource.h" #include "ardour/audiosource.h"
#include "ardour/diskstream.h" #include "ardour/diskstream.h"
#include "ardour/io_processor.h" #include "ardour/io_processor.h"
#include "ardour/panner.h" #include "ardour/meter.h"
#include "ardour/port.h" #include "ardour/port.h"
#include "ardour/processor.h" #include "ardour/processor.h"
#include "ardour/route_group_specialized.h" #include "ardour/route_group_specialized.h"
@ -84,7 +84,7 @@ Track::get_template ()
void void
Track::toggle_monitor_input () Track::toggle_monitor_input ()
{ {
for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) { for (PortSet::iterator i = _input->ports().begin(); i != _input->ports().end(); ++i) {
i->ensure_monitor_input(!i->monitoring_input()); i->ensure_monitor_input(!i->monitoring_input());
} }
} }
@ -92,32 +92,28 @@ Track::toggle_monitor_input ()
ARDOUR::nframes_t ARDOUR::nframes_t
Track::update_total_latency () Track::update_total_latency ()
{ {
nframes_t old = _own_latency; nframes_t old = _output->effective_latency();
nframes_t own_latency = _output->user_latency();
if (_user_latency) { for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
_own_latency = _user_latency; if ((*i)->active ()) {
} else { own_latency += (*i)->signal_latency ();
_own_latency = 0;
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
if ((*i)->active ()) {
_own_latency += (*i)->signal_latency ();
}
} }
} }
#undef DEBUG_LATENCY #undef DEBUG_LATENCY
#ifdef DEBUG_LATENCY #ifdef DEBUG_LATENCY
cerr << _name << ": internal redirect (final) latency = " << _own_latency << endl; cerr << _name << ": internal redirect (final) latency = " << own_latency << endl;
#endif #endif
set_port_latency (_own_latency); _output->set_port_latency (own_latency);
if (old != _own_latency) { if (old != own_latency) {
_output->set_latency_delay (own_latency);
signal_latency_changed (); /* EMIT SIGNAL */ signal_latency_changed (); /* EMIT SIGNAL */
} }
return _own_latency; return _output->effective_latency();
} }
Track::FreezeRecord::~FreezeRecord () Track::FreezeRecord::~FreezeRecord ()
@ -155,14 +151,14 @@ Track::RecEnableControllable::get_value (void) const
bool bool
Track::record_enabled () const Track::record_enabled () const
{ {
return _diskstream->record_enabled (); return _diskstream && _diskstream->record_enabled ();
} }
bool bool
Track::can_record() Track::can_record()
{ {
bool will_record = true; bool will_record = true;
for (PortSet::iterator i = _inputs.begin(); i != _inputs.end() && will_record; ++i) { for (PortSet::iterator i = _input->ports().begin(); i != _input->ports().end() && will_record; ++i) {
if (!i->connected()) if (!i->connected())
will_record = false; will_record = false;
} }
@ -307,7 +303,7 @@ Track::no_roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame,
passthru_silence (start_frame, end_frame, nframes, 0); passthru_silence (start_frame, end_frame, nframes, 0);
} else { } else {
if (_meter_point == MeterInput) { if (_meter_point == MeterInput) {
just_meter_input (start_frame, end_frame, nframes); _input->process_input (_meter, start_frame, end_frame, nframes);
} }
passthru_silence (start_frame, end_frame, nframes, 0); passthru_silence (start_frame, end_frame, nframes, 0);
} }

View file

@ -135,7 +135,7 @@ def build(bld):
gdither.cc gdither.cc
globals.cc globals.cc
import.cc import.cc
io.cc io.cc
io_processor.cc io_processor.cc
jack_slave.cc jack_slave.cc
ladspa_plugin.cc ladspa_plugin.cc
@ -157,6 +157,7 @@ def build(bld):
midi_track.cc midi_track.cc
mix.cc mix.cc
mtc_slave.cc mtc_slave.cc
mute_master.cc
named_selection.cc named_selection.cc
onset_detector.cc onset_detector.cc
panner.cc panner.cc
@ -178,7 +179,7 @@ def build(bld):
resampled_source.cc resampled_source.cc
return.cc return.cc
reverse.cc reverse.cc
route.cc route.cc
route_group.cc route_group.cc
send.cc send.cc
session.cc session.cc

View file

@ -23,9 +23,6 @@
#include <gtkmm/drawingarea.h> #include <gtkmm/drawingarea.h>
#include <gtkmm2ext/binding_proxy.h> #include <gtkmm2ext/binding_proxy.h>
namespace ARDOUR {
class Controllable;
}
namespace Gtkmm2ext { namespace Gtkmm2ext {

View file

@ -158,7 +158,7 @@ MIDI::byte
MIDI::decode_controller_name (const char *name) MIDI::decode_controller_name (const char *name)
{ {
char *lparen; const char *lparen;
size_t len; size_t len;
if ((lparen = strrchr (name, '(')) != 0) { if ((lparen = strrchr (name, '(')) != 0) {

View file

@ -18,11 +18,12 @@
*/ */
#include <ardour/session.h> #include "ardour/session.h"
#include <ardour/route.h> #include "ardour/route.h"
#include <ardour/audio_track.h> #include "ardour/audio_track.h"
#include <ardour/meter.h> #include "ardour/meter.h"
#include <control_protocol/control_protocol.h> #include "ardour/amp.h"
#include "control_protocol/control_protocol.h"
using namespace ARDOUR; using namespace ARDOUR;
using namespace std; using namespace std;
@ -212,7 +213,7 @@ ControlProtocol::route_get_gain (uint32_t table_index)
return 0.0f; return 0.0f;
} }
return r->gain (); return r->amp()->gain ();
} }
void void
@ -242,7 +243,7 @@ ControlProtocol::route_get_effective_gain (uint32_t table_index)
return 0.0f; return 0.0f;
} }
return r->effective_gain (); return r->amp()->gain_control()->get_value();
} }

View file

@ -95,7 +95,7 @@ def set_options(opt):
help='Compile with support for LV2 (if slv2 is available)') help='Compile with support for LV2 (if slv2 is available)')
opt.add_option('--nls', action='store_true', default=True, dest='nls', opt.add_option('--nls', action='store_true', default=True, dest='nls',
help='Enable i18n (native language support)') help='Enable i18n (native language support)')
opt.add_option('--surfaces', action='store_true', default=True, dest='surfaces', opt.add_option('--surfaces', action='store_true', default=False, dest='surfaces',
help='Build support for control surfaces') help='Build support for control surfaces')
opt.add_option('--syslibs', action='store_true', default=True, dest='syslibs', opt.add_option('--syslibs', action='store_true', default=True, dest='syslibs',
help='Use existing system versions of various libraries instead of internal ones') help='Use existing system versions of various libraries instead of internal ones')