From e6eb059576eefd9a26c177627ae7dd3ba2feb727 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Tue, 9 Jun 2009 20:21:19 +0000 Subject: 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 --- gtk2_ardour/actions.cc | 4 +- gtk2_ardour/ardour_ui.cc | 38 - gtk2_ardour/ardour_ui.h | 2 - gtk2_ardour/audio_time_axis.cc | 20 +- gtk2_ardour/automation_time_axis.cc | 7 +- gtk2_ardour/editor_route_list.cc | 8 +- gtk2_ardour/export_channel_selector.cc | 16 +- gtk2_ardour/gain_meter.cc | 180 +- gtk2_ardour/gain_meter.h | 17 +- gtk2_ardour/io_selector.cc | 68 +- gtk2_ardour/io_selector.h | 4 +- gtk2_ardour/midi_time_axis.cc | 8 +- gtk2_ardour/mixer_strip.cc | 175 +- gtk2_ardour/mixer_strip.h | 11 +- gtk2_ardour/panner_ui.cc | 128 +- gtk2_ardour/panner_ui.h | 7 +- gtk2_ardour/port_group.cc | 108 +- gtk2_ardour/port_group.h | 5 +- gtk2_ardour/processor_box.cc | 24 +- gtk2_ardour/processor_box.h | 2 +- gtk2_ardour/return_ui.cc | 23 +- gtk2_ardour/route_params_ui.cc | 6 +- gtk2_ardour/route_time_axis.cc | 9 +- gtk2_ardour/route_ui.cc | 52 +- gtk2_ardour/route_ui.h | 10 +- gtk2_ardour/send_ui.cc | 11 +- gtk2_ardour/session_option_editor.cc | 14 +- gtk2_ardour/sfdb_ui.cc | 6 +- libs/ardour/SConscript | 1 + libs/ardour/amp.cc | 211 +- libs/ardour/ardour/amp.h | 67 +- libs/ardour/ardour/automatable.h | 2 +- libs/ardour/ardour/click.h | 2 +- libs/ardour/ardour/delivery.h | 85 +- libs/ardour/ardour/io.h | 274 +-- libs/ardour/ardour/io_processor.h | 28 +- libs/ardour/ardour/meter.h | 18 +- libs/ardour/ardour/mute_master.h | 77 + libs/ardour/ardour/panner.h | 8 +- libs/ardour/ardour/port_insert.h | 13 +- libs/ardour/ardour/processor.h | 22 +- libs/ardour/ardour/rc_configuration_vars.h | 1 + libs/ardour/ardour/return.h | 20 +- libs/ardour/ardour/route.h | 165 +- libs/ardour/ardour/send.h | 26 +- libs/ardour/ardour/session.h | 13 +- libs/ardour/audio_diskstream.cc | 24 +- libs/ardour/audio_track.cc | 36 +- libs/ardour/audioengine.cc | 8 +- libs/ardour/auditioner.cc | 22 +- libs/ardour/automatable.cc | 7 +- libs/ardour/delivery.cc | 384 +++- libs/ardour/diskstream.cc | 14 +- libs/ardour/enums.cc | 33 +- libs/ardour/io.cc | 2102 ++++---------------- libs/ardour/io_processor.cc | 191 +- libs/ardour/meter.cc | 46 +- libs/ardour/midi_diskstream.cc | 10 +- libs/ardour/midi_track.cc | 16 +- libs/ardour/mute_master.cc | 109 + libs/ardour/panner.cc | 33 +- libs/ardour/port_insert.cc | 51 +- libs/ardour/processor.cc | 3 +- libs/ardour/return.cc | 51 +- libs/ardour/route.cc | 1013 ++++------ libs/ardour/route_group.cc | 5 +- libs/ardour/send.cc | 87 +- libs/ardour/session.cc | 224 +-- libs/ardour/session_click.cc | 2 +- libs/ardour/session_state.cc | 8 +- libs/ardour/session_transport.cc | 5 +- libs/ardour/track.cc | 38 +- libs/ardour/wscript | 5 +- libs/gtkmm2ext/gtkmm2ext/barcontroller.h | 3 - libs/midi++2/midi.cc | 2 +- libs/surfaces/control_protocol/control_protocol.cc | 15 +- wscript | 2 +- 77 files changed, 2716 insertions(+), 3829 deletions(-) create mode 100644 libs/ardour/ardour/mute_master.h create mode 100644 libs/ardour/mute_master.cc diff --git a/gtk2_ardour/actions.cc b/gtk2_ardour/actions.cc index 74daa23a9a..a39283c977 100644 --- a/gtk2_ardour/actions.cc +++ b/gtk2_ardour/actions.cc @@ -324,7 +324,7 @@ ActionManager::set_sensitive (vector >& actions, bool state) void ActionManager::uncheck_toggleaction (const char * name) { - char *last_slash = strrchr (name, '/'); + const char *last_slash = strrchr (name, '/'); if (last_slash == 0) { 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); group_name[len] = '\0'; - char* action_name = last_slash + 1; + const char* action_name = last_slash + 1; RefPtr act = get_action (group_name, action_name); if (act) { diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc index 0af0a88e11..0b9b9f1f74 100644 --- a/gtk2_ardour/ardour_ui.cc +++ b/gtk2_ardour/ardour_ui.cc @@ -1835,44 +1835,6 @@ ARDOUR_UI::stop_blinking () } } -void -ARDOUR_UI::name_io_setup (AudioEngine& engine, - string& buf, - IO& io, - bool in) -{ - vector 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. */ diff --git a/gtk2_ardour/ardour_ui.h b/gtk2_ardour/ardour_ui.h index 2c840324e0..aae644dbec 100644 --- a/gtk2_ardour/ardour_ui.h +++ b/gtk2_ardour/ardour_ui.h @@ -176,8 +176,6 @@ class ARDOUR_UI : public Gtkmm2ext::UI static sigc::signal SuperRapidScreenUpdate; static sigc::signal Clock; - void name_io_setup (ARDOUR::AudioEngine&, std::string&, ARDOUR::IO& io, bool in); - XMLNode* editor_settings() const; XMLNode* mixer_settings () const; XMLNode* keyboard_settings () const; diff --git a/gtk2_ardour/audio_time_axis.cc b/gtk2_ardour/audio_time_axis.cc index 6ce54f7882..8f0c25bdb0 100644 --- a/gtk2_ardour/audio_time_axis.cc +++ b/gtk2_ardour/audio_time_axis.cc @@ -37,6 +37,7 @@ #include #include +#include "ardour/amp.h" #include "ardour/audio_diskstream.h" #include "ardour/audioplaylist.h" #include "ardour/event_type_map.h" @@ -347,13 +348,14 @@ AudioTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool return; } - boost::shared_ptr gain_track(new AutomationTimeAxisView (_session, - _route, _route, c, - _editor, - *this, - false, - parent_canvas, - _route->describe_parameter(param))); + boost::shared_ptr + gain_track(new AutomationTimeAxisView (_session, + _route, _route->amp(), c, + _editor, + *this, + false, + parent_canvas, + _route->amp()->describe_parameter(param))); 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 */ - std::string const name = _route->describe_parameter (pan_control->parameter ()); + std::string const name = _route->panner()->describe_parameter (pan_control->parameter ()); boost::shared_ptr pan_track ( new AutomationTimeAxisView (_session, - _route, _route, pan_control, + _route, _route->panner(), pan_control, _editor, *this, false, diff --git a/gtk2_ardour/automation_time_axis.cc b/gtk2_ardour/automation_time_axis.cc index 78faf66944..e72c5add00 100644 --- a/gtk2_ardour/automation_time_axis.cc +++ b/gtk2_ardour/automation_time_axis.cc @@ -255,15 +255,20 @@ void AutomationTimeAxisView::set_automation_state (AutoState state) { 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 _route->set_parameter_automation_state (_control->parameter(), state); } if (_control->list()) _control->alist()->set_automation_state(state); +#endif } - if (_view) + + if (_view) { _view->set_automation_state (state); + } } void diff --git a/gtk2_ardour/editor_route_list.cc b/gtk2_ardour/editor_route_list.cc index 00b4a3656d..964ee38712 100644 --- a/gtk2_ardour/editor_route_list.cc +++ b/gtk2_ardour/editor_route_list.cc @@ -67,10 +67,12 @@ Editor::handle_new_route (RouteList& routes) if (route->is_hidden()) { 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); - else if (route->default_type() == ARDOUR::DataType::MIDI) + else if (dt == ARDOUR::DataType::MIDI) tv = new MidiTimeAxisView (*this, *session, route, *track_canvas); else throw unknown_type(); diff --git a/gtk2_ardour/export_channel_selector.cc b/gtk2_ardour/export_channel_selector.cc index 2f66e58fe5..7b665a6087 100644 --- a/gtk2_ardour/export_channel_selector.cc +++ b/gtk2_ardour/export_channel_selector.cc @@ -112,14 +112,14 @@ PortExportChannelSelector::fill_route_list () /* 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); for (RouteList::iterator it = routes.begin(); it != routes.end(); ++it) { - if (it->get() == master) { + if ((*it)->output().get() == master) { continue; } - channel_view.add_route (it->get()); + channel_view.add_route ((*it)->output().get()); } update_channel_count (); @@ -261,27 +261,27 @@ PortExportChannelSelector::ChannelTreeView::set_config (ChannelConfigPtr c) } void -PortExportChannelSelector::ChannelTreeView::add_route (ARDOUR::IO * route) +PortExportChannelSelector::ChannelTreeView::add_route (ARDOUR::IO * io) { Gtk::TreeModel::iterator iter = route_list->append(); Gtk::TreeModel::Row row = *iter; row[route_cols.selected] = false; - row[route_cols.name] = route->name(); - row[route_cols.io] = route; + row[route_cols.name] = io->name(); + row[route_cols.io] = io; /* Initialize port list */ Glib::RefPtr port_list = Gtk::ListStore::create (route_cols.port_cols); 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) { iter = port_list->append(); row = *iter; 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; oss << "Out-" << (i + 1); diff --git a/gtk2_ardour/gain_meter.cc b/gtk2_ardour/gain_meter.cc index 85e591a8cc..045c93173e 100644 --- a/gtk2_ardour/gain_meter.cc +++ b/gtk2_ardour/gain_meter.cc @@ -160,57 +160,58 @@ GainMeterBase::~GainMeterBase () } void -GainMeterBase::set_io (boost::shared_ptr io) +GainMeterBase::set_controls (boost::shared_ptr r, + boost::shared_ptr pm, + boost::shared_ptr gc, + boost::shared_ptr gc_owner) { connections.clear (); - _io = io; - - if (!_io) { + if (!pm && !gc) { level_meter->set_meter (0); gain_slider->set_controllable (boost::shared_ptr()); + _meter.reset (); + _gain_control.reset (); + _route.reset (); return; } - level_meter->set_meter (&_io->peak_meter()); - gain_slider->set_controllable (_io->gain_control()); - - boost::shared_ptr r; - - if ((r = boost::dynamic_pointer_cast (_io)) != 0) { + _meter = pm; + _gain_control = gc; + _route = r; - if (!r->is_hidden()) { - - using namespace Menu_Helpers; + level_meter->set_meter (pm.get()); + gain_slider->set_controllable (gc); - gain_astate_menu.items().clear (); - - gain_astate_menu.items().push_back (MenuElem (_("Manual"), - bind (mem_fun (*_io, &IO::set_parameter_automation_state), - 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 (gain_automation_state_button.signal_button_press_event().connect (mem_fun(*this, &GainMeterBase::gain_automation_state_button_event), false)); - - connections.push_back (r->gain_control()->alist()->automation_state_changed.connect (mem_fun(*this, &GainMeter::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 (); - } + if (!_route || !_route->is_hidden()) { + + using namespace Menu_Helpers; + + 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))); + + 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 (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_state_changed.connect (mem_fun(*this, &GainMeter::gain_automation_state_changed))); + connections.push_back (gc->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 (_io->gain_control()->Changed.connect (mem_fun(*this, &GainMeterBase::gain_changed))); + connections.push_back (gc->Changed.connect (mem_fun (*this, &GainMeterBase::gain_changed))); gain_changed (); 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)) { ResetAllPeakDisplays (); } else if (ev->button == 1 && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) { - boost::shared_ptr r; - - if ((r = boost::dynamic_pointer_cast (_io)) != 0) { - ResetGroupPeakDisplays (r->mix_group()); + if (_route) { + ResetGroupPeakDisplays (_route->mix_group()); } } else { reset_peak_display (); @@ -287,12 +286,7 @@ GainMeterBase::peak_button_release (GdkEventButton* ev) void GainMeterBase::reset_peak_display () { - boost::shared_ptr r; - - if ((r = boost::dynamic_pointer_cast (_io)) != 0) { - r->peak_meter().reset_max(); - } - + _meter->reset_max(); level_meter->clear_meters(); max_peak = -INFINITY; peak_display.set_label (_("-Inf")); @@ -302,13 +296,9 @@ GainMeterBase::reset_peak_display () void GainMeterBase::reset_group_peak_display (RouteGroup* group) { - boost::shared_ptr r; - - if ((r = boost::dynamic_pointer_cast (_io)) != 0) { - if (group == r->mix_group()) { - reset_peak_display (); + if (_route && group == _route->mix_group()) { + reset_peak_display (); } - } } void @@ -354,7 +344,7 @@ GainMeterBase::gain_activated () 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()) { PublicEditor::instance().reset_focus(); @@ -384,7 +374,7 @@ GainMeterBase::gain_adjusted () //cerr << this << " for " << _io->name() << " GAIN ADJUSTED\n"; if (!ignore_toggle) { //cerr << "Set GC\n"; - _io->gain_control()->set_value (slider_position_to_gain (gain_adjustment.get_value())); + _gain_control->set_value (slider_position_to_gain (gain_adjustment.get_value())); //cerr << "Set GC OUT\n"; } show_gain (); @@ -393,7 +383,7 @@ GainMeterBase::gain_adjusted () void 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 // << " AGAIN = " << gain_adjustment.get_value () << endl; @@ -428,7 +418,7 @@ void GainMeterBase::update_gain_sensitive () { static_cast(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; - if ((_route = boost::dynamic_pointer_cast(_io)) == 0) { + if (!_route) { return FALSE; } @@ -482,10 +472,10 @@ 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))) { - + /* Primary+Tertiary-click applies change to all routes */ _session.begin_reversible_command (_("meter point change")); @@ -534,10 +524,8 @@ GainMeterBase::meter_release(GdkEventButton* ev) if (wait_for_release){ wait_for_release = false; - boost::shared_ptr r; - - if ((r = boost::dynamic_pointer_cast(_io)) != 0) { - set_meter_point (*r, old_meter_point); + if (_route) { + set_meter_point (*_route, old_meter_point); } } } @@ -566,9 +554,7 @@ GainMeterBase::set_mix_group_meter_point (Route& route, MeterPoint mp) void GainMeterBase::meter_point_clicked () { - boost::shared_ptr r; - - if ((r = boost::dynamic_pointer_cast (_io)) != 0) { + if (_route) { /* WHAT? */ } } @@ -576,14 +562,14 @@ GainMeterBase::meter_point_clicked () gint GainMeterBase::start_gain_touch (GdkEventButton* ev) { - _io->gain_control()->start_touch (); + _gain_control->start_touch (); return FALSE; } gint GainMeterBase::end_gain_touch (GdkEventButton* ev) { - _io->gain_control()->stop_touch (); + _gain_control->stop_touch (); return FALSE; } @@ -686,10 +672,10 @@ GainMeterBase::gain_automation_style_changed () { switch (_width) { 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; 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; } } @@ -703,14 +689,14 @@ GainMeterBase::gain_automation_state_changed () switch (_width) { 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; 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; } - x = (_io->gain_control()->alist()->automation_state() != Off); + x = (_gain_control->alist()->automation_state() != Off); if (gain_automation_state_button.get_active() != x) { ignore_toggle = true; @@ -811,8 +797,11 @@ GainMeter::GainMeter (Session& s) meter_metric_area.signal_expose_event().connect (mem_fun(*this, &GainMeter::meter_metrics_expose)); } -void -GainMeter::set_io (boost::shared_ptr io) +void +GainMeter::set_controls (boost::shared_ptr r, + boost::shared_ptr meter, + boost::shared_ptr gain_control, + boost::shared_ptr gc_owner) { if (level_meter->get_parent()) { hbox.remove (*level_meter); @@ -826,30 +815,17 @@ GainMeter::set_io (boost::shared_ptr io) fader_vbox->remove (gain_automation_state_button); } - GainMeterBase::set_io (io); + GainMeterBase::set_controls (r, meter, gain_control, gc_owner); - boost::shared_ptr r; - - if ((r = boost::dynamic_pointer_cast (_io)) != 0) { - - /* - 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); + /* + 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); } } @@ -941,7 +917,7 @@ GainMeter::meter_metrics_expose (GdkEventExpose *ev) boost::shared_ptr GainMeterBase::get_controllable() { - return _io->gain_control(); + return _gain_control; } diff --git a/gtk2_ardour/gain_meter.h b/gtk2_ardour/gain_meter.h index ea817bcae2..7feaf5c0e4 100644 --- a/gtk2_ardour/gain_meter.h +++ b/gtk2_ardour/gain_meter.h @@ -46,6 +46,8 @@ namespace ARDOUR { class Session; class Route; class RouteGroup; + class PeakMeter; + class Automatable; } namespace Gtkmm2ext { class FastMeter; @@ -62,8 +64,10 @@ class GainMeterBase : virtual public sigc::trackable bool horizontal); virtual ~GainMeterBase (); - virtual void set_io (boost::shared_ptr); - boost::shared_ptr io() const { return _io; } + virtual void set_controls (boost::shared_ptr route, + boost::shared_ptr meter, + boost::shared_ptr gain_control, + boost::shared_ptr gc_owner); void update_gain_sensitive (); void update_meters (); @@ -83,7 +87,9 @@ class GainMeterBase : virtual public sigc::trackable protected: friend class MixerStrip; - boost::shared_ptr _io; + boost::shared_ptr _route; + boost::shared_ptr _meter; + boost::shared_ptr _gain_control; ARDOUR::Session& _session; std::vector connections; @@ -176,7 +182,10 @@ class GainMeter : public GainMeterBase, public Gtk::VBox GainMeter (ARDOUR::Session&); ~GainMeter () {} - void set_io (boost::shared_ptr); + virtual void set_controls (boost::shared_ptr route, + boost::shared_ptr meter, + boost::shared_ptr gain_control, + boost::shared_ptr gc_owner); int get_gm_width (); void setup_meters (int len=0); diff --git a/gtk2_ardour/io_selector.cc b/gtk2_ardour/io_selector.cc index fb7d946f7d..4333efd8ea 100644 --- a/gtk2_ardour/io_selector.cc +++ b/gtk2_ardour/io_selector.cc @@ -41,12 +41,14 @@ using namespace ARDOUR; using namespace Gtk; -IOSelector::IOSelector (ARDOUR::Session& session, boost::shared_ptr io, bool in) +IOSelector::IOSelector (ARDOUR::Session& session, boost::shared_ptr io) : PortMatrix (session, io->default_type()) , _io (io) - , _find_inputs_for_io_outputs (in) { /* signal flow from 0 to 1 */ + + _find_inputs_for_io_outputs = (_io->direction() == IO::Output); + if (_find_inputs_for_io_outputs) { _other = 1; _ours = 0; @@ -73,9 +75,7 @@ IOSelector::setup_ports (int dim) } else { _port_group->clear (); - _port_group->add_bundle ( - _find_inputs_for_io_outputs ? _io->bundle_for_outputs() : _io->bundle_for_inputs() - ); + _port_group->add_bundle (_io->bundle ()); } _ports[dim].resume_signals (); @@ -96,17 +96,9 @@ IOSelector::set_state (ARDOUR::BundleChannel c[2], bool s) } if (s) { - if (!_find_inputs_for_io_outputs) { - _io->connect_input (f, *j, 0); - } else { - _io->connect_output (f, *j, 0); - } + _io->connect (f, *j, 0); } else { - if (!_find_inputs_for_io_outputs) { - _io->disconnect_input (f, *j, 0); - } else { - _io->disconnect_output (f, *j, 0); - } + _io->disconnect (f, *j, 0); } } } @@ -147,9 +139,9 @@ uint32_t IOSelector::n_io_ports () const { if (!_find_inputs_for_io_outputs) { - return _io->inputs().num_ports (_io->default_type()); + return _io->n_ports().get (_io->default_type()); } 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 b) // The IO selector only works for single typed IOs const ARDOUR::DataType t = _io->default_type (); - if (!_find_inputs_for_io_outputs) { - - try { - _io->add_input_port ("", this); - } - - 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 (); - } + try { + _io->add_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; } - if (_find_inputs_for_io_outputs) { - _io->remove_output_port (f, this); - } else { - _io->remove_input_port (f, this); - } + _io->remove_port (f, this); } bool @@ -206,9 +180,9 @@ IOSelector::list_is_global (int dim) const return (dim == _other); } -IOSelectorWindow::IOSelectorWindow (ARDOUR::Session& session, boost::shared_ptr io, bool for_input, bool can_cancel) +IOSelectorWindow::IOSelectorWindow (ARDOUR::Session& session, boost::shared_ptr io, bool can_cancel) : ArdourDialog ("I/O selector") - , _selector (session, io, !for_input) + , _selector (session, io) , add_button (_("Add Port")) , disconnect_button (_("Disconnect All")) , ok_button (can_cancel ? _("OK"): _("Close")) @@ -327,8 +301,8 @@ IOSelectorWindow::io_name_changed (void* src) } PortInsertUI::PortInsertUI (ARDOUR::Session& sess, boost::shared_ptr pi) - : input_selector (sess, pi->io(), true), - output_selector (sess, pi->io(), false) + : input_selector (sess, pi->input()) + , output_selector (sess, pi->output()) { output_selector.set_min_height_divisor (2); input_selector.set_min_height_divisor (2); diff --git a/gtk2_ardour/io_selector.h b/gtk2_ardour/io_selector.h index 872fd5d7d6..d6b00254be 100644 --- a/gtk2_ardour/io_selector.h +++ b/gtk2_ardour/io_selector.h @@ -30,7 +30,7 @@ namespace ARDOUR { class IOSelector : public PortMatrix { public: - IOSelector (ARDOUR::Session&, boost::shared_ptr, bool); + IOSelector (ARDOUR::Session&, boost::shared_ptr); void set_state (ARDOUR::BundleChannel c[2], bool); PortMatrixNode::State get_state (ARDOUR::BundleChannel c[2]) const; @@ -74,7 +74,7 @@ class IOSelector : public PortMatrix class IOSelectorWindow : public ArdourDialog { public: - IOSelectorWindow (ARDOUR::Session&, boost::shared_ptr, bool for_input, bool can_cancel = false); + IOSelectorWindow (ARDOUR::Session&, boost::shared_ptr, bool can_cancel = false); IOSelector& selector() { return _selector; } diff --git a/gtk2_ardour/midi_time_axis.cc b/gtk2_ardour/midi_time_axis.cc index 18786fe54a..c8cd5fe464 100644 --- a/gtk2_ardour/midi_time_axis.cc +++ b/gtk2_ardour/midi_time_axis.cc @@ -506,13 +506,7 @@ MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool if (existing != _automation_tracks.end()) return; - boost::shared_ptr c - = boost::dynamic_pointer_cast(_route->data().control(param)); - - if (!c) { - c = boost::dynamic_pointer_cast(_route->control_factory(param)); - _route->add_control(c); - } + boost::shared_ptr c = _route->get_control (param); assert(c); diff --git a/gtk2_ardour/mixer_strip.cc b/gtk2_ardour/mixer_strip.cc index fdc1e2f39b..13e077c12f 100644 --- a/gtk2_ardour/mixer_strip.cc +++ b/gtk2_ardour/mixer_strip.cc @@ -34,6 +34,7 @@ #include #include "ardour/ardour.h" +#include "ardour/amp.h" #include "ardour/session.h" #include "ardour/audioengine.h" #include "ardour/route.h" @@ -71,20 +72,6 @@ sigc::signal > MixerStrip::SwitchIO; 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) : AxisView(sess) , RouteUI (sess, _("Mute"), _("Solo"), _("Record")) @@ -99,8 +86,6 @@ MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, bool in_mixer) , bottom_button_table (1, 2) , meter_point_label (_("pre")) , comment_button (_("Comments")) - , speed_adjustment (1.0, 0.001, 4.0, 0.001, 0.1) - , speed_spinner (&speed_adjustment, "MixerStripSpeedBase", true) { init (); @@ -128,8 +113,6 @@ MixerStrip::MixerStrip (Mixer_UI& mx, Session& sess, boost::shared_ptr rt , bottom_button_table (1, 2) , meter_point_label (_("pre")) , comment_button (_("Comments")) - , speed_adjustment (1.0, 0.001, 4.0, 0.001, 0.1) - , speed_spinner (&speed_adjustment, "MixerStripSpeedBase", true) { init (); @@ -146,7 +129,6 @@ MixerStrip::init () route_ops_menu = 0; ignore_comment_edit = false; ignore_toggle = false; - ignore_speed_adjustment = false; comment_window = 0; comment_area = 0; _width_owner = 0; @@ -340,12 +322,6 @@ MixerStrip::set_route (boost::shared_ptr rt) 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); delete input_selector; @@ -354,14 +330,16 @@ MixerStrip::set_route (boost::shared_ptr rt) delete output_selector; output_selector = 0; - if (_current_send) { - _current_send->set_metering (false); + boost::shared_ptr send; + + if (_current_delivery && (send = boost::dynamic_pointer_cast(_current_delivery))) { + send->set_metering (false); } - _current_send.reset (); + _current_delivery = _route->main_outs (); - panners.set_io (rt); - gpm.set_io (rt); + panners.set_panner (rt->main_outs()->panner()); + gpm.set_controls (rt, rt->shared_peak_meter(), rt->gain_control(), rt->amp()); pre_processor_box.set_route (rt); post_processor_box.set_route (rt); @@ -388,20 +366,6 @@ MixerStrip::set_route (boost::shared_ptr rt) 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); rec_enable_button->show(); @@ -443,9 +407,9 @@ MixerStrip::set_route (boost::shared_ptr rt) connections.push_back (_route->meter_change.connect ( 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))); - connections.push_back (_route->output_changed.connect ( + connections.push_back (_route->output()->changed.connect ( mem_fun(*this, &MixerStrip::output_changed))); connections.push_back (_route->mix_group_changed.connect ( mem_fun(*this, &MixerStrip::mix_group_changed))); @@ -458,8 +422,6 @@ MixerStrip::set_route (boost::shared_ptr rt) if (is_audio_track()) { connections.push_back (audio_track()->DiskstreamChanged.connect ( 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 ( @@ -485,10 +447,6 @@ MixerStrip::set_route (boost::shared_ptr rt) panners.setup_pan (); - if (is_audio_track()) { - speed_changed (); - } - update_diskstream_display (); update_input_display (); update_output_display (); @@ -530,9 +488,6 @@ MixerStrip::set_route (boost::shared_ptr rt) comment_button.show(); group_button.show(); group_label.show(); - speed_spinner.show(); - speed_label.show(); - speed_frame.show(); show (); } @@ -703,7 +658,7 @@ MixerStrip::output_press (GdkEventButton *ev) citems.push_back (MenuElem (_("Disconnect"), mem_fun (*(static_cast(this)), &RouteUI::disconnect_output))); citems.push_back (SeparatorElem()); - ARDOUR::BundleList current = _route->bundles_connected_to_outputs (); + ARDOUR::BundleList current = _route->output()->bundles_connected (); boost::shared_ptr b = _session.bundles (); for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) { @@ -712,7 +667,7 @@ MixerStrip::output_press (GdkEventButton *ev) boost::shared_ptr routes = _session.get_routes (); 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) { @@ -734,7 +689,7 @@ void MixerStrip::edit_output_configuration () { if (output_selector == 0) { - output_selector = new IOSelectorWindow (_session, _route, false); + output_selector = new IOSelectorWindow (_session, _route->output()); } if (output_selector->is_visible()) { @@ -748,7 +703,7 @@ void MixerStrip::edit_input_configuration () { if (input_selector == 0) { - input_selector = new IOSelectorWindow (_session, _route, true); + input_selector = new IOSelectorWindow (_session, _route->input()); } if (input_selector->is_visible()) { @@ -784,7 +739,7 @@ MixerStrip::input_press (GdkEventButton *ev) citems.push_back (MenuElem (_("Disconnect"), mem_fun (*(static_cast(this)), &RouteUI::disconnect_input))); citems.push_back (SeparatorElem()); - ARDOUR::BundleList current = _route->bundles_connected_to_inputs (); + ARDOUR::BundleList current = _route->input()->bundles_connected (); boost::shared_ptr b = _session.bundles (); for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) { @@ -793,7 +748,7 @@ MixerStrip::input_press (GdkEventButton *ev) boost::shared_ptr routes = _session.get_routes (); 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) { @@ -817,12 +772,12 @@ MixerStrip::bundle_input_toggled (boost::shared_ptr c) 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()) { - _route->connect_input_ports_to_bundle (c, this); + _route->input()->connect_ports_to_bundle (c, this); } 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 c) 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()) { - _route->connect_output_ports_to_bundle (c, this); + _route->output()->connect_ports_to_bundle (c, this); } 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 b, ARDOUR: using namespace Menu_Helpers; 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 ())) { return; @@ -874,7 +829,7 @@ MixerStrip::maybe_add_bundle_to_output_menu (boost::shared_ptr b, ARDOUR using namespace Menu_Helpers; 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 ())) { return; @@ -938,7 +893,7 @@ MixerStrip::connect_to_pan () void 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) { input_label.set_text (_("Inputs")); @@ -960,7 +915,7 @@ MixerStrip::update_input_display () void 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? */ if (c.size() > 1) { @@ -1269,43 +1224,6 @@ MixerStrip::list_route_operations () 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 MixerStrip::set_selected (bool yn) { @@ -1383,12 +1301,10 @@ MixerStrip::map_frozen () case AudioTrack::Frozen: pre_processor_box.set_sensitive (false); post_processor_box.set_sensitive (false); - speed_spinner.set_sensitive (false); break; default: pre_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 break; } @@ -1499,8 +1415,6 @@ MixerStrip::meter_changed (void *src) void MixerStrip::switch_io (boost::shared_ptr target) { - boost::shared_ptr to_display; - if (_route == target || _route->is_master()) { /* don't change the display for the target or the master bus */ return; @@ -1519,22 +1433,28 @@ MixerStrip::switch_io (boost::shared_ptr target) return; } - if (_current_send) { - _current_send->set_metering (false); + boost::shared_ptr send; + + if (_current_delivery && (send = boost::dynamic_pointer_cast(_current_delivery))) { + send->set_metering (false); } - _current_send = _route->send_for (target); + _current_delivery = _route->send_for (target->input()); - if (_current_send) { - to_display = _current_send->io(); + if (_current_delivery) { + send = boost::dynamic_pointer_cast(_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); - _current_send->GoingAway.connect (mem_fun (*this, &MixerStrip::revert_to_default_display)); + } else { + _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 (); - panner_ui().set_io (to_display); panner_ui().setup_pan (); } @@ -1544,14 +1464,17 @@ MixerStrip::revert_to_default_display () { show_sends_button->set_active (false); - if (_current_send) { - _current_send->set_metering (false); - _current_send.reset(); + boost::shared_ptr send; + + if (_current_delivery && (send = boost::dynamic_pointer_cast(_current_delivery))) { + send->set_metering (false); } + + _current_delivery = _route->main_outs(); - gain_meter().set_io (_route); + gain_meter().set_controls (_route, _route->shared_peak_meter(), _route->gain_control(), _route->amp()); gain_meter().setup_meters (); - panner_ui().set_io (_route); + panner_ui().set_panner (_route->main_outs()->panner()); panner_ui().setup_pan (); } diff --git a/gtk2_ardour/mixer_strip.h b/gtk2_ardour/mixer_strip.h index f0cc4c67c6..43c2e197fd 100644 --- a/gtk2_ardour/mixer_strip.h +++ b/gtk2_ardour/mixer_strip.h @@ -242,15 +242,6 @@ class MixerStrip : public RouteUI, public Gtk::EventBox 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 update_speed_display (); void map_frozen (); @@ -263,7 +254,7 @@ class MixerStrip : public RouteUI, public Gtk::EventBox void engine_stopped(); void switch_io (boost::shared_ptr); - boost::shared_ptr _current_send; + boost::shared_ptr _current_delivery; void revert_to_default_display (); static int scrollbar_height; diff --git a/gtk2_ardour/panner_ui.cc b/gtk2_ardour/panner_ui.cc index b35ebe5f22..29c991a995 100644 --- a/gtk2_ardour/panner_ui.cc +++ b/gtk2_ardour/panner_ui.cc @@ -25,6 +25,7 @@ #include #include "midi++/manager.h" #include "pbd/fastlog.h" +#include "pbd/stacktrace.h" #include "ardour_ui.h" #include "panner_ui.h" @@ -33,6 +34,7 @@ #include "panner.h" #include "gui_thread.h" +#include "ardour/delivery.h" #include "ardour/session.h" #include "ardour/panner.h" #include "ardour/route.h" @@ -131,13 +133,8 @@ PannerUI::PannerUI (Session& s) } void -PannerUI::set_io (boost::shared_ptr io) +PannerUI::set_panner (boost::shared_ptr p) { - if (io && !io->panner()) { - cerr << "PannerUI::set_io IO has no panners" << endl; - return; - } - connections.clear (); delete pan_astyle_menu; @@ -146,18 +143,18 @@ PannerUI::set_io (boost::shared_ptr io) delete pan_astate_menu; pan_astate_menu = 0; - _io = io; - + _panner = p; + delete panner; panner = 0; - if (!_io) { + if (!_panner) { return; } - connections.push_back (_io->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 (_io->panner()->StateChanged.connect (mem_fun(*this, &PannerUI::update_pan_state))); + connections.push_back (_panner->Changed.connect (mem_fun(*this, &PannerUI::panner_changed))); + connections.push_back (_panner->LinkStateChanged.connect (mem_fun(*this, &PannerUI::update_pan_linkage))); + connections.push_back (_panner->StateChanged.connect (mem_fun(*this, &PannerUI::update_pan_state))); setup_pan (); @@ -196,16 +193,16 @@ PannerUI::build_astate_menu () } 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))); 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))); 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))); 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))); } @@ -242,7 +239,7 @@ bool PannerUI::panning_link_button_release (GdkEventButton* ev) { if (!ignore_toggle) { - _io->panner()->set_linked (!_io->panner()->linked()); + _panner->set_linked (!_panner->linked()); } return true; } @@ -250,12 +247,12 @@ PannerUI::panning_link_button_release (GdkEventButton* ev) void PannerUI::panning_link_direction_clicked() { - switch (_io->panner()->link_direction()) { + switch (_panner->link_direction()) { case Panner::SameDirection: - _io->panner()->set_link_direction (Panner::OppositeDirection); + _panner->set_link_direction (Panner::OppositeDirection); break; default: - _io->panner()->set_link_direction (Panner::SameDirection); + _panner->set_link_direction (Panner::SameDirection); break; } } @@ -265,7 +262,7 @@ 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(); if (x != bx) { @@ -277,7 +274,7 @@ PannerUI::update_pan_linkage () panning_link_direction_button.set_sensitive (x); - switch (_io->panner()->link_direction()) { + switch (_panner->link_direction()) { case Panner::SameDirection: panning_link_direction_button.set_image (*(manage (new Image (get_xpm ("forwardblarrow.xpm"))))); break; @@ -339,11 +336,16 @@ PannerUI::update_pan_state () void PannerUI::setup_pan () { - if (!_io || !_io->panner()) { + cerr << "Setup pan for " << _panner->name() << endl; + // PBD::stacktrace (cerr, 5); + + if (!_panner) { return; } - uint32_t nouts = _io->n_outputs ().n_audio(); + uint32_t nouts = _panner->nouts(); + + cerr << "\tnouts = " << nouts << endl; if (nouts == 0 || nouts == 1) { @@ -364,7 +366,7 @@ PannerUI::setup_pan () } else if (nouts == 2) { vector::size_type asz; - uint32_t npans = _io->panner()->npanners(); + uint32_t npans = _panner->npanners(); while (!pan_adjustments.empty()) { 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, 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) { x = 0.5; @@ -395,20 +397,24 @@ PannerUI::setup_pan () pan_adjustments.push_back (new Adjustment (x, 0, 1.0, 0.005, 0.05)); bc = new PannerBar (*pan_adjustments[asz], - boost::static_pointer_cast( _io->panner()->pan_control( asz )) ); + boost::static_pointer_cast( _panner->pan_control( asz )) ); /* now set adjustment with current value of panner, then connect the signals */ pan_adjustments.back()->set_value(rx); 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_shadow_type (Gtk::SHADOW_NONE); - - bc->StartGesture.connect (bind (mem_fun (*_io, &IO::start_pan_touch), (uint32_t) asz)); - bc->StopGesture.connect (bind (mem_fun (*_io, &IO::end_pan_touch), (uint32_t) asz)); + + boost::shared_ptr ac = _panner->pan_control (asz); + + if (asz) { + bc->StartGesture.connect (mem_fun (*ac, &AutomationControl::start_touch)); + bc->StopGesture.connect (mem_fun (*ac, &AutomationControl::stop_touch)); + } char buf[64]; snprintf (buf, sizeof (buf), _("panner for channel %zu"), asz + 1); @@ -437,7 +443,7 @@ PannerUI::setup_pan () } else { if (!panner) { - panner = new Panner2d (_io->panner(), 61); + panner = new Panner2d (_panner, 61); panner->set_name ("MixerPanZone"); panner->show (); @@ -446,9 +452,9 @@ PannerUI::setup_pan () } update_pan_sensitive (); - panner->reset (_io->n_inputs().n_audio()); + panner->reset (nouts); if (big_window) { - big_window->reset (_io->n_inputs().n_audio()); + big_window->reset (_panner->npanners()); } panner->set_size_request (-1, 61); @@ -467,7 +473,7 @@ PannerUI::pan_button_event (GdkEventButton* ev, uint32_t which) case 1: if (panner && ev->type == GDK_2BUTTON_PRESS) { 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 (); return true; @@ -502,7 +508,7 @@ PannerUI::build_pan_menu (uint32_t which) /* set state first, connect second */ - (dynamic_cast (&items.back()))->set_active (_io->panner()->streampanner(which).muted()); + (dynamic_cast (&items.back()))->set_active (_panner->streampanner(which).muted()); (dynamic_cast (&items.back()))->signal_toggled().connect (bind (mem_fun(*this, &PannerUI::pan_mute), which)); @@ -511,7 +517,7 @@ PannerUI::build_pan_menu (uint32_t which) /* 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)); 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 PannerUI::pan_mute (uint32_t which) { - StreamPanner& sp = _io->panner()->streampanner(which); + StreamPanner& sp = _panner->streampanner(which); sp.set_muted (!sp.muted()); } void PannerUI::pan_bypass_toggle () { - if (bypass_menu_item && (_io->panner()->bypassed() != bypass_menu_item->get_active())) { - _io->panner()->set_bypassed (!_io->panner()->bypassed()); + if (bypass_menu_item && (_panner->bypassed() != bypass_menu_item->get_active())) { + _panner->set_bypassed (!_panner->bypassed()); } } void PannerUI::pan_reset (uint32_t which) { - _io->panner()->reset_streampanner (which); + _panner->reset_streampanner (which); } void PannerUI::pan_reset_all () { - _io->panner()->reset_to_default (); + _panner->reset_to_default (); } void PannerUI::effective_pan_display () { - if (_io->panner()->empty()) { + if (_panner->empty()) { return; } - switch (_io->n_outputs().n_audio()) { + switch (_panner->nouts()) { case 0: case 1: /* relax */ @@ -576,7 +582,7 @@ PannerUI::pan_changed (void *src) return; } - switch (_io->panner()->npanners()) { + switch (_panner->npanners()) { case 0: panning_link_direction_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); } - uint32_t nouts = _io->n_outputs().n_audio(); + uint32_t nouts = _panner->nouts(); switch (nouts) { case 0: @@ -612,11 +618,11 @@ PannerUI::pan_changed (void *src) void 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 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 */ @@ -633,7 +639,7 @@ PannerUI::pan_adjustment_changed (uint32_t which) if (!Panner::equivalent (val, xpos)) { - _io->panner()->streampanner(which).set_position (val); + _panner->streampanner(which).set_position (val); /* XXX the panner objects have no access to the session, 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)); - if (_io->n_outputs().n_audio() > 1 && which < _io->panner()->npanners()) { + if (_panner->npanners() > 1 && which < _panner->npanners()) { float xpos; 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)) { in_pan_update = true; @@ -678,14 +684,14 @@ PannerUI::update_pan_bars (bool only_if_aplay) float xpos, val; if (only_if_aplay) { - boost::shared_ptr alist (_io->panner()->streampanner(n).pan_control()->alist()); + boost::shared_ptr alist (_panner->streampanner(n).pan_control()->alist()); if (!alist->automation_playback()) { continue; } } - _io->panner()->streampanner(n).get_effective_position (xpos); + _panner->streampanner(n).get_effective_position (xpos); val = (*i)->get_value (); if (!Panner::equivalent (val, xpos)) { @@ -699,9 +705,9 @@ PannerUI::update_pan_bars (bool only_if_aplay) void 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 1: break; @@ -771,10 +777,10 @@ PannerUI::pan_automation_style_changed () switch (_width) { 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; 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; } } @@ -788,10 +794,10 @@ PannerUI::pan_automation_state_changed () switch (_width) { 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; 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; } @@ -800,11 +806,11 @@ PannerUI::pan_automation_state_changed () here. */ - if (_io->panner()->empty()) { + if (_panner->empty()) { 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) { ignore_toggle = true; diff --git a/gtk2_ardour/panner_ui.h b/gtk2_ardour/panner_ui.h index 602164d7a9..95e1e6c688 100644 --- a/gtk2_ardour/panner_ui.h +++ b/gtk2_ardour/panner_ui.h @@ -40,8 +40,9 @@ class PannerBar; class Panner2dWindow; namespace ARDOUR { - class IO; class Session; + class Panner; + class Delivery; } namespace Gtkmm2ext { class FastMeter; @@ -58,7 +59,7 @@ class PannerUI : public Gtk::HBox PannerUI (ARDOUR::Session&); ~PannerUI (); - virtual void set_io (boost::shared_ptr); + virtual void set_panner (boost::shared_ptr); void pan_changed (void *); @@ -76,7 +77,7 @@ class PannerUI : public Gtk::HBox private: friend class MixerStrip; - boost::shared_ptr _io; + boost::shared_ptr _panner; ARDOUR::Session& _session; std::vector connections; diff --git a/gtk2_ardour/port_group.cc b/gtk2_ardour/port_group.cc index 3ff074f9d7..99c4861f79 100644 --- a/gtk2_ardour/port_group.cc +++ b/gtk2_ardour/port_group.cc @@ -36,6 +36,7 @@ using namespace std; using namespace Gtk; +using namespace ARDOUR; /** PortGroup constructor. * @param n Name. @@ -50,7 +51,7 @@ PortGroup::PortGroup (std::string const & n) * @param b Bundle. */ void -PortGroup::add_bundle (boost::shared_ptr b) +PortGroup::add_bundle (boost::shared_ptr b) { assert (b.get()); _bundles.push_back (b); @@ -62,11 +63,11 @@ PortGroup::add_bundle (boost::shared_ptr b) } void -PortGroup::remove_bundle (boost::shared_ptr b) +PortGroup::remove_bundle (boost::shared_ptr b) { 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()) { return; } @@ -78,7 +79,7 @@ PortGroup::remove_bundle (boost::shared_ptr b) } void -PortGroup::bundle_changed (ARDOUR::Bundle::Change c) +PortGroup::bundle_changed (Bundle::Change c) { BundleChanged (c); } @@ -103,7 +104,7 @@ PortGroup::clear () bool 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)) { return true; } @@ -112,7 +113,7 @@ PortGroup::has_port (std::string const& p) const return false; } -boost::shared_ptr +boost::shared_ptr PortGroup::only_bundle () { assert (_bundles.size() == 1); @@ -124,7 +125,7 @@ uint32_t PortGroup::total_channels () const { 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 (); } @@ -135,21 +136,49 @@ PortGroup::total_channels () const /** PortGroupList constructor. */ PortGroupList::PortGroupList () - : _type (ARDOUR::DataType::AUDIO), _signals_suspended (false), _pending_change (false) + : _type (DataType::AUDIO), _signals_suspended (false), _pending_change (false) { } void -PortGroupList::set_type (ARDOUR::DataType t) +PortGroupList::set_type (DataType t) { _type = t; clear (); } +void +PortGroupList::maybe_add_processor_to_bundle (boost::weak_ptr wp, boost::shared_ptr rb, bool inputs) +{ + boost::shared_ptr p (wp.lock()); + + if (!p) { + return; + } + + boost::shared_ptr iop = boost::dynamic_pointer_cast (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 */ void -PortGroupList::gather (ARDOUR::Session& session, bool inputs) +PortGroupList::gather (Session& session, bool inputs) { clear (); @@ -162,49 +191,28 @@ PortGroupList::gather (ARDOUR::Session& session, bool inputs) the route's IO bundles and processor bundles together so that they are presented as one bundle in the matrix. */ - boost::shared_ptr routes = session.get_routes (); - - for (ARDOUR::RouteList::const_iterator i = routes->begin(); i != routes->end(); ++i) { + boost::shared_ptr routes = session.get_routes (); - boost::shared_ptr rb ( - new RouteBundle ( - inputs ? (*i)->bundle_for_inputs() : (*i)->bundle_for_outputs() - ) - ); + for (RouteList::const_iterator i = routes->begin(); i != routes->end(); ++i) { - uint32_t n = 0; - while (1) { - boost::shared_ptr p = (*i)->nth_processor (n); - if (p == 0) { - break; - } + boost::shared_ptr rb (new RouteBundle (inputs ? (*i)->output()->bundle() : (*i)->input()->bundle())); - boost::shared_ptr iop = boost::dynamic_pointer_cast (p); + (*i)->foreach_processor (bind (mem_fun (*this, &PortGroupList::maybe_add_processor_to_bundle), rb, inputs)); - 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 */ boost::shared_ptr g; - if (_type == ARDOUR::DataType::AUDIO) { + if (_type == DataType::AUDIO) { - if (boost::dynamic_pointer_cast (*i)) { + if (boost::dynamic_pointer_cast (*i)) { g = track; - } else if (!boost::dynamic_pointer_cast(*i)) { + } else if (!boost::dynamic_pointer_cast(*i)) { g = bus; } - } else if (_type == ARDOUR::DataType::MIDI) { + } else if (_type == DataType::MIDI) { - if (boost::dynamic_pointer_cast (*i)) { + if (boost::dynamic_pointer_cast (*i)) { 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 otherwise there is duplication of the same ports within the matrix */ - boost::shared_ptr b = session.bundles (); - for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) { + boost::shared_ptr b = session.bundles (); + for (BundleList::iterator i = b->begin(); i != b->end(); ++i) { if ((*i)->ports_are_inputs() == inputs && (*i)->type() == _type) { - if ((*i)->nchannels() == 1 || boost::dynamic_pointer_cast (*i)) { + if ((*i)->nchannels() == 1 || boost::dynamic_pointer_cast (*i)) { system->add_bundle (*i); } @@ -282,10 +290,10 @@ PortGroupList::gather (ARDOUR::Session& session, bool inputs) emit_changed (); } -boost::shared_ptr +boost::shared_ptr PortGroupList::make_bundle_from_ports (std::vector const & p, bool inputs) const { - boost::shared_ptr b (new ARDOUR::Bundle ("", _type, inputs)); + boost::shared_ptr b (new Bundle ("", _type, inputs)); std::string const pre = common_prefix (p); if (!pre.empty()) { @@ -366,7 +374,7 @@ PortGroupList::clear () } -ARDOUR::BundleList const & +BundleList const & PortGroupList::bundles () const { _bundles.clear (); @@ -410,7 +418,7 @@ PortGroupList::add_group (boost::shared_ptr g) } void -PortGroupList::remove_bundle (boost::shared_ptr b) +PortGroupList::remove_bundle (boost::shared_ptr b) { for (List::iterator i = _groups.begin(); i != _groups.end(); ++i) { (*i)->remove_bundle (b); @@ -446,7 +454,7 @@ PortGroupList::resume_signals () _signals_suspended = false; } -RouteBundle::RouteBundle (boost::shared_ptr r) +RouteBundle::RouteBundle (boost::shared_ptr r) : _route (r) { _route->Changed.connect (sigc::hide (sigc::mem_fun (*this, &RouteBundle::reread_component_bundles))); @@ -470,7 +478,7 @@ RouteBundle::reread_component_bundles () } } - for (std::vector >::iterator i = _processor.begin(); i != _processor.end(); ++i) { + for (std::vector >::iterator i = _processor.begin(); i != _processor.end(); ++i) { add_channels_from_bundle (*i); } @@ -478,7 +486,7 @@ RouteBundle::reread_component_bundles () } void -RouteBundle::add_processor_bundle (boost::shared_ptr p) +RouteBundle::add_processor_bundle (boost::shared_ptr p) { p->Changed.connect (sigc::hide (sigc::mem_fun (*this, &RouteBundle::reread_component_bundles))); _processor.push_back (p); diff --git a/gtk2_ardour/port_group.h b/gtk2_ardour/port_group.h index 02dd965e1d..707cc04966 100644 --- a/gtk2_ardour/port_group.h +++ b/gtk2_ardour/port_group.h @@ -31,9 +31,11 @@ namespace ARDOUR { class Session; class Bundle; + class Processor; } class PortMatrix; +class RouteBundle; /** 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 @@ -119,7 +121,8 @@ class PortGroupList : public sigc::trackable std::string common_prefix_before (std::vector const &, std::string const &) const; void emit_changed (); boost::shared_ptr make_bundle_from_ports (std::vector const &, bool) const; - + void maybe_add_processor_to_bundle (boost::weak_ptr, boost::shared_ptr, bool); + ARDOUR::DataType _type; mutable ARDOUR::BundleList _bundles; List _groups; diff --git a/gtk2_ardour/processor_box.cc b/gtk2_ardour/processor_box.cc index f850582fec..f8ea758549 100644 --- a/gtk2_ardour/processor_box.cc +++ b/gtk2_ardour/processor_box.cc @@ -452,7 +452,7 @@ ProcessorBox::use_plugins (const SelectedPlugins& plugins) } 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? } else { @@ -467,7 +467,7 @@ ProcessorBox::use_plugins (const SelectedPlugins& plugins) } void -ProcessorBox::weird_plugin_dialog (Plugin& p, Route::ProcessorStreams streams, boost::shared_ptr io) +ProcessorBox::weird_plugin_dialog (Plugin& p, Route::ProcessorStreams streams) { ArdourDialog dialog (_("ardour: weird plugin dialog")); Label label; @@ -511,7 +511,7 @@ ProcessorBox::weird_plugin_dialog (Plugin& p, Route::ProcessorStreams streams, b void ProcessorBox::choose_insert () { - boost::shared_ptr processor (new PortInsert (_session)); + boost::shared_ptr processor (new PortInsert (_session, _route->mute_master())); processor->ActiveChanged.connect (bind ( mem_fun(*this, &ProcessorBox::show_processor_active), boost::weak_ptr(processor))); @@ -522,7 +522,7 @@ ProcessorBox::choose_insert () void ProcessorBox::choose_send () { - boost::shared_ptr send (new Send (_session)); + boost::shared_ptr send (new Send (_session, _route->mute_master())); /* make an educated guess at the initial number of outputs for the send */ ChanCount outs = (_session.master_out()) @@ -531,14 +531,14 @@ ProcessorBox::choose_send () /* XXX need processor lock on route */ try { - send->io()->ensure_io (ChanCount::ZERO, outs, false, this); + send->output()->ensure_io (outs, false, this); } catch (AudioEngine::PortRegistrationFailure& err) { error << string_compose (_("Cannot set up new send: %1"), err.what()) << endmsg; return; } /* 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 (); /* 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 */ try { - retrn->io()->ensure_io (ins, ChanCount::ZERO, false, this); + retrn->input()->ensure_io (ins, false, this); } catch (AudioEngine::PortRegistrationFailure& err) { error << string_compose (_("Cannot set up new return: %1"), err.what()) << endmsg; return; } /* 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 (); /* 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") { XMLNode n (**niter); 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") { p = _route->shared_peak_meter(); @@ -1064,7 +1064,7 @@ ProcessorBox::paste_processor_state (const XMLNodeList& nlist) continue; } else if (type->value() == "listen") { - p.reset (new Delivery (_session, **niter)); + p.reset (new Delivery (_session, _route->mute_master(), **niter)); } else { p.reset (new PluginInsert (_session, **niter)); @@ -1214,8 +1214,8 @@ ProcessorBox::edit_processor (boost::shared_ptr processor) gidget = send_ui; #else if (_parent_strip) { - _parent_strip->gain_meter().set_io (send->io()); - _parent_strip->panner_ui().set_io (send->io()); + _parent_strip->gain_meter().set_controls (_route, send->meter(), send->amp()->gain_control(), send->amp()); + _parent_strip->panner_ui().set_panner (send->panner()); } #endif diff --git a/gtk2_ardour/processor_box.h b/gtk2_ardour/processor_box.h index d53d05fe23..985c8a1177 100644 --- a/gtk2_ardour/processor_box.h +++ b/gtk2_ardour/processor_box.h @@ -205,7 +205,7 @@ class ProcessorBox : public Gtk::HBox, public PluginInterestedObject gint idle_delete_processor (boost::weak_ptr); - void weird_plugin_dialog (ARDOUR::Plugin& p, ARDOUR::Route::ProcessorStreams streams, boost::shared_ptr io); + void weird_plugin_dialog (ARDOUR::Plugin& p, ARDOUR::Route::ProcessorStreams streams); static ProcessorBox* _current_processor_box; static bool enter_box (GdkEventCrossing*, ProcessorBox*); diff --git a/gtk2_ardour/return_ui.cc b/gtk2_ardour/return_ui.cc index ac06529d38..155a1095c1 100644 --- a/gtk2_ardour/return_ui.cc +++ b/gtk2_ardour/return_ui.cc @@ -19,6 +19,7 @@ #include +#include "ardour/amp.h" #include "ardour/io.h" #include "ardour/return.h" @@ -37,7 +38,7 @@ ReturnUI::ReturnUI (boost::shared_ptr r, Session& se) , _session (se) , _gpm (se) { - _gpm.set_io (r->io()); + _gpm.set_controls (boost::shared_ptr(), r->meter(), r->amp()->gain_control(), r->amp()); _hbox.pack_start (_gpm, true, true); set_name ("ReturnUIFrame"); @@ -47,7 +48,7 @@ ReturnUI::ReturnUI (boost::shared_ptr r, Session& se) _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); @@ -55,21 +56,19 @@ ReturnUI::ReturnUI (boost::shared_ptr r, Session& se) show_all (); - //_return->set_metering (true); - - _return->io()->input_changed.connect (mem_fun (*this, &ReturnUI::ins_changed)); - //_return->io()->output_changed.connect (mem_fun (*this, &ReturnUI::outs_changed)); + _return->set_metering (true); + _return->input()->changed.connect (mem_fun (*this, &ReturnUI::ins_changed)); _gpm.setup_meters (); _gpm.set_fader_name ("ReturnUIFrame"); - + // screen_update_connection = ARDOUR_UI::instance()->RapidScreenUpdate.connect (mem_fun (*this, &ReturnUI::update)); fast_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (mem_fun (*this, &ReturnUI::fast_update)); } ReturnUI::~ReturnUI () { - //_return->set_metering (false); + _return->set_metering (false); /* XXX not clear that we need to do this */ @@ -111,12 +110,8 @@ ReturnUIWindow::ReturnUIWindow (boost::shared_ptr s, Session& ss) set_name ("ReturnUIWindow"); - going_away_connection = s->GoingAway.connect ( - mem_fun (*this, &ReturnUIWindow::return_going_away)); - - signal_delete_event().connect (bind ( - sigc::ptr_fun (just_hide_it), - reinterpret_cast (this))); + going_away_connection = s->GoingAway.connect (mem_fun (*this, &ReturnUIWindow::return_going_away)); + signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it), reinterpret_cast (this))); } ReturnUIWindow::~ReturnUIWindow () diff --git a/gtk2_ardour/route_params_ui.cc b/gtk2_ardour/route_params_ui.cc index 5c709d80bf..d2fc106c42 100644 --- a/gtk2_ardour/route_params_ui.cc +++ b/gtk2_ardour/route_params_ui.cc @@ -298,7 +298,7 @@ RouteParams_UI::cleanup_latency_frame () void 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]; snprintf (buf, sizeof (buf), _("Playback delay: %u samples"), _route->initial_delay()); @@ -322,13 +322,13 @@ RouteParams_UI::setup_io_frames() cleanup_io_frames(); // input - _input_iosel = new IOSelector (*session, _route, false); + _input_iosel = new IOSelector (*session, _route->input()); _input_iosel->setup (); input_frame.add (*_input_iosel); input_frame.show_all(); // output - _output_iosel = new IOSelector (*session, _route, true); + _output_iosel = new IOSelector (*session, _route->output()); _output_iosel->setup (); output_frame.add (*_output_iosel); output_frame.show_all(); diff --git a/gtk2_ardour/route_time_axis.cc b/gtk2_ardour/route_time_axis.cc index df85cf69a4..715a70b1d3 100644 --- a/gtk2_ardour/route_time_axis.cc +++ b/gtk2_ardour/route_time_axis.cc @@ -40,6 +40,7 @@ #include #include +#include "ardour/amp.h" #include "ardour/audioplaylist.h" #include "ardour/diskstream.h" #include "ardour/event_type_map.h" @@ -110,7 +111,7 @@ RouteTimeAxisView::RouteTimeAxisView (PublicEditor& ed, Session& sess, boost::sh visual_button (_("v")), 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().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); _route->meter_change.connect (mem_fun(*this, &RouteTimeAxisView::meter_changed)); - _route->input_changed.connect (mem_fun(*this, &RouteTimeAxisView::io_changed)); - _route->output_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)); 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); @@ -231,7 +232,7 @@ RouteTimeAxisView::RouteTimeAxisView (PublicEditor& ed, Session& sess, boost::sh _route->solo_changed.connect (mem_fun(*this, &RouteUI::solo_changed)); _route->processors_changed.connect (mem_fun(*this, &RouteTimeAxisView::processors_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()) { diff --git a/gtk2_ardour/route_ui.cc b/gtk2_ardour/route_ui.cc index 393ab011f3..b62229a70c 100644 --- a/gtk2_ardour/route_ui.cc +++ b/gtk2_ardour/route_ui.cc @@ -101,7 +101,6 @@ RouteUI::init () ignore_toggle = false; wait_for_release = false; route_active_menu_item = 0; - was_solo_safe = false; polarity_menu_item = 0; denormal_menu_item = 0; multiple_mute_change = false; @@ -192,7 +191,7 @@ RouteUI::set_route (boost::shared_ptr rp) 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->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()) { boost::shared_ptr t = boost::dynamic_pointer_cast(_route); @@ -396,7 +395,7 @@ RouteUI::solo_press(GdkEventButton* ev) Config->set_solo_latched (false); } } else { - _route->set_solo_safe (!_route->solo_safe(), this); + _route->set_solo_isolated (!_route->solo_isolated(), this); wait_for_release = false; } @@ -621,7 +620,7 @@ RouteUI::update_solo_display () ignore_toggle = false; } - if (_route->solo_safe()) { + if (_route->solo_isolated()) { solo_button->set_visual_state (2); } else if (_route->soloed()) { solo_button->set_visual_state (1); @@ -663,8 +662,7 @@ RouteUI::update_mute_display () if (Config->get_show_solo_mutes()) { if (_route->muted()) { 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); } else { mute_button->set_visual_state (0); @@ -804,10 +802,10 @@ RouteUI::build_solo_menu (void) MenuList& items = solo_menu->items(); CheckMenuItem* check; - check = new CheckMenuItem(_("Solo Lock")); - check->set_active (_route->solo_safe()); - check->signal_toggled().connect (bind (mem_fun (*this, &RouteUI::toggle_solo_safe), check)); - _route->solo_safe_changed.connect(bind (mem_fun (*this, &RouteUI::solo_safe_toggle), check)); + check = new CheckMenuItem(_("Solo Isolate")); + check->set_active (_route->solo_isolated()); + check->signal_toggled().connect (bind (mem_fun (*this, &RouteUI::toggle_solo_isolated), check)); + _route->solo_isolated_changed.connect(bind (mem_fun (*this, &RouteUI::solo_isolated_toggle), check)); items.push_back (CheckMenuElem(*check)); check->show_all(); @@ -823,9 +821,11 @@ RouteUI::build_mute_menu(void) mute_menu = new Menu; mute_menu->set_name ("ArdourContextMenu"); + +#if FIX_ME_IN_3_0 MenuList& items = mute_menu->items(); CheckMenuItem* check; - + check = new CheckMenuItem(_("Pre Fader")); init_mute_menu(PRE_FADER, check); check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), PRE_FADER, check)); @@ -853,29 +853,27 @@ RouteUI::build_mute_menu(void) _route->main_outs_changed.connect(bind (mem_fun (*this, &RouteUI::main_outs_toggle), check)); items.push_back (CheckMenuElem(*check)); check->show_all(); - +#endif //items.push_back (SeparatorElem()); // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn))); } 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 (true); - } + check->set_active (_route->mute_master()->muted_at (mp)); } 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 -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 @@ -1166,16 +1164,17 @@ RouteUI::denormal_protection_changed () /* no signal for this yet */ } - 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) { check->set_active (yn); } } + +#ifdef FIX_THIS_FOR_3_0 void 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); } } +#endif void RouteUI::disconnect_input () { - _route->disconnect_inputs (this); + _route->input()->disconnect (this); } void RouteUI::disconnect_output () { - _route->disconnect_outputs (this); + _route->output()->disconnect (this); } bool @@ -1308,7 +1308,7 @@ RouteUI::map_frozen () void 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 diff --git a/gtk2_ardour/route_ui.h b/gtk2_ardour/route_ui.h index de8d7ea30c..fc6ef87f57 100644 --- a/gtk2_ardour/route_ui.h +++ b/gtk2_ardour/route_ui.h @@ -24,6 +24,7 @@ #include "pbd/xml++.h" #include "ardour/ardour.h" +#include "ardour/mute_master.h" #include "ardour/route.h" #include "ardour/track.h" @@ -125,17 +126,17 @@ class RouteUI : public virtual AxisView void build_remote_control_menu (void); void refresh_remote_control_menu (); - void solo_safe_toggle (void*, Gtk::CheckMenuItem*); - void toggle_solo_safe (Gtk::CheckMenuItem*); + void solo_isolated_toggle (void*, 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 post_fader_toggle(void*, Gtk::CheckMenuItem*); void control_outs_toggle(void*, Gtk::CheckMenuItem*); void main_outs_toggle(void*, Gtk::CheckMenuItem*); 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, bool); void set_mix_group_mute(boost::shared_ptr, bool); @@ -169,7 +170,6 @@ class RouteUI : public virtual AxisView virtual void update_rec_display (); void update_mute_display (); - bool was_solo_safe; void update_solo_display (); virtual void map_frozen (); diff --git a/gtk2_ardour/send_ui.cc b/gtk2_ardour/send_ui.cc index 672d5f3d20..19baaa7f93 100644 --- a/gtk2_ardour/send_ui.cc +++ b/gtk2_ardour/send_ui.cc @@ -19,6 +19,7 @@ #include +#include "ardour/amp.h" #include "ardour/io.h" #include "ardour/send.h" @@ -38,8 +39,8 @@ SendUI::SendUI (boost::shared_ptr s, Session& se) , _gpm (se) , _panners (se) { - _panners.set_io (s->io()); - _gpm.set_io (s->io()); + _panners.set_panner (s->panner()); + _gpm.set_controls (boost::shared_ptr(), s->meter(), s->amp()->gain_control(), s->amp()); _hbox.pack_start (_gpm, true, true); set_name ("SendUIFrame"); @@ -50,7 +51,7 @@ SendUI::SendUI (boost::shared_ptr s, Session& se) _vbox.pack_start (_hbox, false, 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); @@ -60,8 +61,8 @@ SendUI::SendUI (boost::shared_ptr s, Session& se) _send->set_metering (true); - _send->io()->input_changed.connect (mem_fun (*this, &SendUI::ins_changed)); - _send->io()->output_changed.connect (mem_fun (*this, &SendUI::outs_changed)); + _send->input()->changed.connect (mem_fun (*this, &SendUI::ins_changed)); + _send->output()->changed.connect (mem_fun (*this, &SendUI::outs_changed)); _panners.set_width (Wide); _panners.setup_pan (); diff --git a/gtk2_ardour/session_option_editor.cc b/gtk2_ardour/session_option_editor.cc index 76c8a85b88..09138f428e 100644 --- a/gtk2_ardour/session_option_editor.cc +++ b/gtk2_ardour/session_option_editor.cc @@ -25,12 +25,12 @@ public: void setup_ports (int dim) { - cerr << _session.the_auditioner()->outputs().num_ports() << "\n"; + cerr << _session.the_auditioner()->output()->n_ports() << "\n"; if (dim == OURS) { _port_group->clear (); - _port_group->add_bundle (_session.click_io()->bundle_for_outputs()); - _port_group->add_bundle (_session.the_auditioner()->bundle_for_outputs()); + _port_group->add_bundle (_session.click_io()->bundle()); + _port_group->add_bundle (_session.the_auditioner()->output()->bundle()); } else { _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 & 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 j = other_ports.begin(); j != other_ports.end(); ++j) { @@ -50,9 +50,9 @@ public: assert (f); if (s) { - _session.click_io()->connect_output (f, *j, 0); + _session.click_io()->connect (f, *j, 0); } 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 & 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 j = other_ports.begin(); j != other_ports.end(); ++j) { diff --git a/gtk2_ardour/sfdb_ui.cc b/gtk2_ardour/sfdb_ui.cc index 98dd328f55..cc9d09b654 100644 --- a/gtk2_ardour/sfdb_ui.cc +++ b/gtk2_ardour/sfdb_ui.cc @@ -39,6 +39,7 @@ #include "evoral/SMF.hpp" +#include "ardour/amp.h" #include "ardour/audio_library.h" #include "ardour/auditioner.h" #include "ardour/audioregion.h" @@ -594,7 +595,10 @@ SoundFileBrowser::add_gain_meter () delete gm; gm = new GainMeter (*session); - gm->set_io (session->the_auditioner()); + + boost::shared_ptr 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.pack_start (*gm, false, true); diff --git a/libs/ardour/SConscript b/libs/ardour/SConscript index edba74d117..eb45aad25d 100644 --- a/libs/ardour/SConscript +++ b/libs/ardour/SConscript @@ -118,6 +118,7 @@ midi_stretch.cc midi_track.cc mix.cc mtc_slave.cc +mute_master.cc named_selection.cc onset_detector.cc panner.cc diff --git a/libs/ardour/amp.cc b/libs/ardour/amp.cc index 591fcd8569..755dc8b821 100644 --- a/libs/ardour/amp.cc +++ b/libs/ardour/amp.cc @@ -19,24 +19,31 @@ #include #include #include + +#include "evoral/Curve.hpp" + #include "ardour/amp.h" #include "ardour/audio_buffer.h" #include "ardour/buffer_set.h" #include "ardour/configuration.h" #include "ardour/io.h" +#include "ardour/mute_master.h" #include "ardour/session.h" -namespace ARDOUR { +#include "i18n.h" + +using namespace ARDOUR; -Amp::Amp(Session& s, IO& io) +Amp::Amp(Session& s, boost::shared_ptr mm) : Processor(s, "Amp") - , _io(io) - , _mute(false) , _apply_gain(true) , _apply_gain_automation(false) , _current_gain(1.0) - , _desired_gain(1.0) + , _mute_master (mm) { + boost::shared_ptr gl(new AutomationList(Evoral::Parameter(GainAutomation))); + _gain_control = boost::shared_ptr( new GainControl(X_("gaincontrol"), s, this, Evoral::Parameter(GainAutomation), gl )); + add_control(_gain_control); } bool @@ -59,64 +66,92 @@ Amp::configure_io (ChanCount in, ChanCount out) void 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()) { - Amp::apply_gain (bufs, nframes, _current_mute_gain, _desired_mute_gain, false); - if (_desired_mute_gain == 0.0f) { - bufs.is_silent(true); - } + if (_mute_master) { + mute_gain = _mute_master->mute_gain_at (MuteMaster::PreFader); + } else { + mute_gain = 1.0; } if (_apply_gain) { 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) { Sample* const sp = i->data(); 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 { + + /* no mute */ + for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i) { Sample* const sp = i->data(); for (nframes_t nx = 0; nx < nframes; ++nx) { sp[nx] *= gab[nx]; } } + + _current_gain = gab[nframes-1]; } + } else { /* manual (scalar) gain */ + + gain_t dg = _gain_control->user_float() * mute_gain; - if (_current_gain != _desired_gain) { + if (_current_gain != dg) { - Amp::apply_gain (bufs, nframes, _current_gain, _desired_gain, _io.phase_invert()); - _current_gain = _desired_gain; + Amp::apply_gain (bufs, nframes, _current_gain, dg); + _current_gain = dg; - } else if (_current_gain != 0.0f && (_io.phase_invert() || _current_gain != 1.0f)) { + } else if ((_current_gain != 0.0f) && (_current_gain != 1.0f)) { - /* no need to interpolate current gain value, - but its non-unity, so apply it. if the gain - is zero, do nothing because we'll ship silence - below. + /* gain has not changed, but its non-unity, so apply it unless + 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) { 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) { + + /* silence! */ + for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i) { 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 -Amp::apply_gain (BufferSet& bufs, nframes_t nframes, - gain_t initial, gain_t target, bool invert_polarity) +Amp::apply_gain (BufferSet& bufs, nframes_t nframes, gain_t initial, gain_t target) { - if (nframes == 0) { - return; - } - - if (bufs.count().n_audio() == 0) { + /** Apply a (potentially) declicked gain to the audio buffers of @a bufs + */ + + if (nframes == 0 || bufs.count().n_audio() == 0) { return; } // if we don't need to declick, defer to apply_simple_gain if (initial == 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); - } - } + apply_simple_gain (bufs, nframes, target); return; } @@ -156,7 +180,7 @@ Amp::apply_gain (BufferSet& bufs, nframes_t nframes, gain_t delta; double fractional_shift = -1.0/declick; double fractional_pos; - gain_t polscale = invert_polarity ? -1.0f : 1.0f; + gain_t polscale = 1.0f; if (target < 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 (invert_polarity) { - target = -target; - } - if (target == 0.0) { memset (&buffer[declick], 0, sizeof (Sample) * (nframes - declick)); } else if (target != 1.0) { @@ -196,6 +216,62 @@ Amp::apply_gain (BufferSet& bufs, nframes_t nframes, void 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& @@ -206,4 +282,33 @@ Amp::state (bool full_state) 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; + } +} diff --git a/libs/ardour/ardour/amp.h b/libs/ardour/ardour/amp.h index 152b89a431..03cc3d02f7 100644 --- a/libs/ardour/ardour/amp.h +++ b/libs/ardour/ardour/amp.h @@ -22,19 +22,20 @@ #include "ardour/types.h" #include "ardour/chan_count.h" #include "ardour/processor.h" +#include "ardour/automation_control.h" namespace ARDOUR { class BufferSet; class IO; - +class MuteMaster; /** Applies a declick operation to all audio inputs, passing the same number of * audio outputs, and passing through any other types unchanged. */ class Amp : public Processor { public: - Amp(Session& s, IO& io); + Amp(Session& s, boost::shared_ptr m); bool can_support_io_configuration (const ChanCount& in, ChanCount& out) const; bool configure_io (ChanCount in, ChanCount out); @@ -44,38 +45,54 @@ public: bool apply_gain() const { return _apply_gain; } 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; } void apply_gain_automation(bool yn) { _apply_gain_automation = yn; } - void muute(bool yn) { _mute = yn; } + XMLNode& state (bool full); - 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; - } + static void apply_gain (BufferSet& bufs, nframes_t nframes, gain_t initial, gain_t target); + static void apply_simple_gain(BufferSet& bufs, nframes_t nframes, gain_t target); - XMLNode& state (bool full); + gain_t gain () const { return _gain_control->user_float(); } - static void apply_gain (BufferSet& bufs, nframes_t nframes, - gain_t initial, gain_t target, bool invert_polarity); + virtual void set_gain (gain_t g, void *src); + void inc_gain (gain_t delta, void *src); - static void apply_simple_gain(BufferSet& bufs, nframes_t nframes, gain_t target); + static void update_meters(); + + /* automation */ + + struct GainControl : public AutomationControl { + GainControl (std::string name, Session& session, Amp* a, const Evoral::Parameter ¶m, + boost::shared_ptr al = boost::shared_ptr() ) + : AutomationControl (session, param, al, name ) + , _amp (a) + {} + + void set_value (float val); + float get_value (void) const; + + Amp* _amp; + }; + + boost::shared_ptr gain_control() { + return _gain_control; + } + + boost::shared_ptr gain_control() const { + return _gain_control; + } private: - IO& _io; - bool _mute; - bool _apply_gain; - bool _apply_gain_automation; - float _current_gain; - float _desired_gain; - float _current_mute_gain; - float _desired_mute_gain; + bool _denormal_protection; + bool _apply_gain; + bool _apply_gain_automation; + float _current_gain; + + boost::shared_ptr _gain_control; + boost::shared_ptr _mute_master; }; diff --git a/libs/ardour/ardour/automatable.h b/libs/ardour/ardour/automatable.h index 5eacfa14b2..ed98e8d8ba 100644 --- a/libs/ardour/ardour/automatable.h +++ b/libs/ardour/ardour/automatable.h @@ -58,7 +58,7 @@ public: virtual void add_control(boost::shared_ptr); 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); diff --git a/libs/ardour/ardour/click.h b/libs/ardour/ardour/click.h index 8488df47a6..2f174ab472 100644 --- a/libs/ardour/ardour/click.h +++ b/libs/ardour/ardour/click.h @@ -27,7 +27,7 @@ namespace ARDOUR { class ClickIO : public IO { public: - ClickIO (Session& s, const std::string& name) : IO (s, name) {} + ClickIO (Session& s, const std::string& name) : IO (s, name, IO::Output) {} ~ClickIO() {} protected: diff --git a/libs/ardour/ardour/delivery.h b/libs/ardour/ardour/delivery.h index 8d083695b1..645b601251 100644 --- a/libs/ardour/ardour/delivery.h +++ b/libs/ardour/ardour/delivery.h @@ -28,48 +28,91 @@ namespace ARDOUR { class BufferSet; class IO; +class MuteMaster; +class Panner; class Delivery : public IOProcessor { public: enum Role { - Send = 0x1, - Solo = 0x2, + Insert = 0x1, + Send = 0x2, Listen = 0x4, Main = 0x8 }; - Delivery (Session& s, IO* io, const std::string& name, Role); - Delivery (Session& s, const std::string& name, Role); - Delivery (Session&, const XMLNode&); + Delivery (Session& s, boost::shared_ptr io, boost::shared_ptr mm, const std::string& name, Role); + Delivery (Session& s, boost::shared_ptr mm, const std::string& name, Role); + Delivery (Session&, boost::shared_ptr mm, const XMLNode&); + bool set_name (const std::string& name); bool visible() const; - Role role() const { return _role; } - bool can_support_io_configuration (const ChanCount& in, ChanCount& out) const; 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 set_metering (bool yn); - - bool muted_by_self() const { return _muted_by_self; } - bool muted_by_others() const { return _muted_by_others; } + /* supplemental method use with MIDI */ + + void flush (nframes_t nframes); + + void no_outs_cuz_we_no_monitor(bool); + + void mod_solo_level (int32_t); + 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 MuteChange; - void set_self_mute (bool); - void set_nonself_mute (bool); - - sigc::signal SelfMuteChange; - sigc::signal OtherMuteChange; + static sigc::signal CycleStart; XMLNode& state (bool full); int set_state (const XMLNode&); -private: - Role _role; - bool _metering; - bool _muted_by_self; - bool _muted_by_others; + /* Panning */ + + static int disable_panners (void); + static int reset_panners (void); + + boost::shared_ptr 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 _mute_master; + bool no_panner_reset; + boost::shared_ptr _panner; + + static bool panners_legal; + static sigc::signal PannersLegal; + + int panners_became_legal (); + sigc::connection panner_legal_c; + void output_changed (IOChange, void*); + + gain_t target_gain (); }; diff --git a/libs/ardour/ardour/io.h b/libs/ardour/ardour/io.h index 23e4f576df..3f222c6aa1 100644 --- a/libs/ardour/ardour/io.h +++ b/libs/ardour/ardour/io.h @@ -55,134 +55,83 @@ class AudioPort; class BufferSet; class Bundle; class MidiPort; -class Panner; class PeakMeter; class Port; +class Processor; class Session; 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 * varied combinations of types (eg MIDI and audio) possible. */ -class IO : public SessionObject, public AutomatableControls, public Latent +class IO : public SessionObject, public Latent { public: 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); virtual ~IO(); - bool active() const { return _active; } - void set_active (bool yn); - + Direction direction() const { return _direction; } + DataType default_type() const { return _default_type; } 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); virtual void silence (nframes_t); - void collect_input (BufferSet& bufs, nframes_t nframes, ChanCount offset=ChanCount::ZERO); - 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; } - - gain_t gain () const { return _gain_control->user_float(); } - virtual gain_t effective_gain () const; - - void set_denormal_protection (bool yn, void *src); - 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() const { return _amp; } - - PeakMeter& peak_meter() { return *_meter.get(); } - const PeakMeter& peak_meter() const { return *_meter.get(); } - boost::shared_ptr shared_peak_meter() const { return _meter; } - - boost::shared_ptr panner() const { return _panner; } - - int ensure_io (ChanCount in, ChanCount out, bool clear, void *src); + int ensure_io (ChanCount cnt, bool clear, void *src); - int connect_input_ports_to_bundle (boost::shared_ptr, void *); - int disconnect_input_ports_from_bundle (boost::shared_ptr, void *); - int connect_output_ports_to_bundle (boost::shared_ptr, void *); - int disconnect_output_ports_from_bundle (boost::shared_ptr, void *); + int connect_ports_to_bundle (boost::shared_ptr, void *); + int disconnect_ports_from_bundle (boost::shared_ptr, void *); - BundleList bundles_connected_to_inputs (); - BundleList bundles_connected_to_outputs (); + BundleList bundles_connected (); - boost::shared_ptr bundle_for_inputs () { return _bundle_for_inputs; } - boost::shared_ptr bundle_for_outputs () { return _bundle_for_outputs; } + boost::shared_ptr bundle () { return _bundle; } - 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; nframes_t signal_latency() const { return _own_latency; } - nframes_t output_latency() const; - nframes_t input_latency() const; + nframes_t latency() const; void set_port_latency (nframes_t); void update_port_total_latencies (); - const PortSet& inputs() const { return _inputs; } - const PortSet& outputs() const { return _outputs; } + PortSet& ports() { return _ports; } + const PortSet& ports() const { return _ports; } - Port *output (uint32_t n) const { - if (n < _outputs.num_ports()) { - return _outputs.port(n); + Port *nth (uint32_t n) const { + if (n < _ports.num_ports()) { + return _ports.port(n); } else { return 0; } } - Port *input (uint32_t n) const { - if (n < _inputs.num_ports()) { - return _inputs.port(n); - } else { - return 0; - } - } + AudioPort* audio(uint32_t n) const; + MidiPort* midi(uint32_t n) const; - AudioPort* audio_input(uint32_t n) const; - AudioPort* audio_output(uint32_t n) const; - MidiPort* midi_input(uint32_t n) const; - MidiPort* midi_output(uint32_t n) const; + const ChanCount& n_ports () const { return _ports.count(); } - const ChanCount& n_inputs () const { return _inputs.count(); } - const ChanCount& n_outputs () const { return _outputs.count(); } - - void attach_buffers(ChanCount ignored); - - sigc::signal active_changed; - - sigc::signal input_changed; - sigc::signal output_changed; + sigc::signal changed; virtual XMLNode& state (bool full); XMLNode& get_state (void); @@ -192,130 +141,45 @@ class IO : public SessionObject, public AutomatableControls, public Latent static int enable_connecting (void); static int disable_ports (void); static int enable_ports (void); - static int disable_panners (void); - static int reset_panners (void); - static sigc::signal PortsLegal; - static sigc::signal PannersLegal; - static sigc::signal ConnectingLegal; - /// raised when the number of input or output ports changes - static sigc::signal PortCountChanged; - static sigc::signal CycleStart; - - static void update_meters(); + static sigc::signal PortCountChanged; // emitted when the number of ports changes + static std::string name_from_state (const XMLNode&); static void set_name_in_state (XMLNode&, const std::string&); - private: - - static sigc::signal 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 ¶m, - boost::shared_ptr al = boost::shared_ptr() ) - : AutomationControl (i->_session, param, al, name ) - , _io (i) - {} - - void set_value (float val); - float get_value (void) const; - - IO* _io; - }; + /* we have to defer/order port connection. this is how we do it. + */ - boost::shared_ptr gain_control() { - return _gain_control; - } - boost::shared_ptr gain_control() const { - return _gain_control; - } + static sigc::signal ConnectingLegal; + static bool connecting_legal; - void clear_automation (); + XMLNode *pending_state_node; - void set_parameter_automation_state (Evoral::Parameter, AutoState); + /* three utility functions - this just seems to be simplest place to put them */ - virtual void transport_stopped (nframes_t now); - virtual void automation_snapshot (nframes_t now, bool force); + void collect_input (BufferSet& bufs, nframes_t nframes, ChanCount offset); + void process_input (boost::shared_ptr, 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); - void start_pan_touch (uint32_t which); - void end_pan_touch (uint32_t which); - - void defer_pan_reset (); - void allow_pan_reset (); + /* AudioTrack::deprecated_use_diskstream_connections() needs these */ - /* the session calls this for master outs before - anyone else. controls outs too, at some point. - */ - - XMLNode *pending_state_node; - int ports_became_legal (); + int set_ports (const std::string& str); private: mutable Glib::Mutex io_lock; protected: - BufferSet* _output_buffers; //< Set directly to output port buffers - bool _active; - gain_t _gain; - Glib::Mutex declick_lock; - 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; - boost::shared_ptr _meter; - boost::shared_ptr _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 _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; - + PortSet _ports; + Direction _direction; + DataType _default_type; + bool _active; + private: - static bool panners_legal; - - void copy_to_outputs (BufferSet& bufs, DataType type, nframes_t nframes); int connecting_became_legal (); - int panners_became_legal (); sigc::connection connection_legal_c; - sigc::connection port_legal_c; - sigc::connection panner_legal_c; - boost::shared_ptr _bundle_for_inputs; ///< a bundle representing our inputs - boost::shared_ptr _bundle_for_outputs; ///< a bundle representing our outputs + boost::shared_ptr _bundle; ///< a bundle representing our ports struct UserBundleInfo { UserBundleInfo (IO*, boost::shared_ptr b); @@ -324,45 +188,31 @@ class IO : public SessionObject, public AutomatableControls, public Latent sigc::connection changed; }; - std::vector _bundles_connected_to_outputs; ///< user bundles connected to our outputs - std::vector _bundles_connected_to_inputs; ///< user bundles connected to our inputs + std::vector _bundles_connected; ///< user bundles connected to our ports static int parse_io_string (const std::string&, std::vector& chns); - static int parse_gain_string (const std::string&, std::vector& chns); - int set_sources (std::vector&, void *src, bool add); - int set_destinations (std::vector&, void *src, bool add); - - int ensure_inputs (ChanCount, bool clear, bool lockit, void *src); - int ensure_outputs (ChanCount, bool clear, bool lockit, void *src); + int ensure_ports (ChanCount, bool clear, bool lockit, void *src); - void check_bundles_connected_to_inputs (); - void check_bundles_connected_to_outputs (); + void check_bundles_connected (); void check_bundles (std::vector&, const PortSet&); void bundle_changed (Bundle::Change); - int get_port_counts (const XMLNode& node, ChanCount& in, ChanCount& out, - boost::shared_ptr& ic, boost::shared_ptr& oc); + int get_port_counts (const XMLNode& node, ChanCount& n, boost::shared_ptr& c); int create_ports (const XMLNode&); int make_connections (const XMLNode&); - boost::shared_ptr find_possible_bundle (const std::string &desired_name, const std::string &default_name, const std::string &connection_type_name); - virtual void setup_peak_meters (); - void meter (); + boost::shared_ptr find_possible_bundle (const std::string &desired_name); - bool ensure_inputs_locked (ChanCount, bool clear, void *src); - bool ensure_outputs_locked (ChanCount, bool clear, void *src); + bool ensure_ports_locked (ChanCount, bool clear, void *src); - std::string build_legal_port_name (DataType type, bool for_input); - int32_t find_input_port_hole (const char* base); - int32_t find_output_port_hole (const char* base); + std::string build_legal_port_name (DataType type); + int32_t find_port_hole (const char* base); - void setup_bundles_for_inputs_and_outputs (); - void setup_bundle_for_inputs (); - void setup_bundle_for_outputs (); + void setup_bundles (); std::string bundle_channel_name (uint32_t, uint32_t) const; }; diff --git a/libs/ardour/ardour/io_processor.h b/libs/ardour/ardour/io_processor.h index 896de52a3b..72be2c0743 100644 --- a/libs/ardour/ardour/io_processor.h +++ b/libs/ardour/ardour/io_processor.h @@ -38,15 +38,16 @@ namespace ARDOUR { class Session; 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 { public: - IOProcessor (Session&, const std::string& proc_name, const std::string io_name="", - ARDOUR::DataType default_type = DataType::AUDIO); - IOProcessor (Session&, IO* io, const std::string& proc_name, + IOProcessor (Session&, bool with_input, bool with_output, + const std::string& proc_name, const std::string io_name="", ARDOUR::DataType default_type = DataType::AUDIO); + IOProcessor (Session&, boost::shared_ptr input, boost::shared_ptr output, + const std::string& proc_name, ARDOUR::DataType default_type = DataType::AUDIO); virtual ~IOProcessor (); bool set_name (const std::string& str); @@ -56,13 +57,14 @@ class IOProcessor : public Processor virtual ChanCount natural_output_streams() const; virtual ChanCount natural_input_streams () const; - boost::shared_ptr io() { return _io; } - boost::shared_ptr io() const { return _io; } - void set_io (boost::shared_ptr); + boost::shared_ptr input() { return _input; } + boost::shared_ptr input() const { return _input; } + boost::shared_ptr output() { return _output; } + boost::shared_ptr output() const { return _output; } + void set_input (boost::shared_ptr); + void set_output (boost::shared_ptr); - virtual void automation_snapshot (nframes_t now, bool force); - - virtual void run_in_place (BufferSet& in, sframes_t start, sframes_t end, nframes_t nframes) = 0; + void run_in_place (BufferSet& in, sframes_t start, sframes_t end, nframes_t nframes) = 0; void silence (nframes_t nframes); sigc::signal AutomationPlaybackChanged; @@ -72,12 +74,14 @@ class IOProcessor : public Processor int set_state (const XMLNode&); protected: - boost::shared_ptr _io; + boost::shared_ptr _input; + boost::shared_ptr _output; private: /* disallow copy construction */ IOProcessor (const IOProcessor&); - bool _own_io; + bool _own_input; + bool _own_output; }; diff --git a/libs/ardour/ardour/meter.h b/libs/ardour/ardour/meter.h index 250fb3111e..43df5e936c 100644 --- a/libs/ardour/ardour/meter.h +++ b/libs/ardour/ardour/meter.h @@ -20,6 +20,7 @@ #define __ardour_meter_h__ #include +#include #include "ardour/types.h" #include "ardour/processor.h" #include "pbd/fastlog.h" @@ -30,6 +31,20 @@ class BufferSet; class ChanCount; class Session; +class Metering { + public: + static void update_meters (); + static sigc::signal Meter; + + static sigc::connection connect (sigc::slot 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. */ @@ -37,6 +52,8 @@ class PeakMeter : public Processor { public: PeakMeter(Session& s) : Processor(s, "Meter") {} + void meter(); + void reset (); void reset_max (); @@ -66,7 +83,6 @@ public: private: friend class IO; - void meter(); std::vector _peak_power; std::vector _visible_peak_power; diff --git a/libs/ardour/ardour/mute_master.h b/libs/ardour/ardour/mute_master.h new file mode 100644 index 0000000000..d55de0c856 --- /dev/null +++ b/libs/ardour/ardour/mute_master.h @@ -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 MutePointChanged; + + XMLNode& get_state(); + int set_state(const XMLNode& node); + + private: + AutomationList* _automation; + MutePoint _mute_point; +}; + +} // namespace ARDOUR + +#endif /*__ardour_mute_master_h__ */ diff --git a/libs/ardour/ardour/panner.h b/libs/ardour/ardour/panner.h index 9bc1817af0..3c66046ad1 100644 --- a/libs/ardour/ardour/panner.h +++ b/libs/ardour/ardour/panner.h @@ -183,7 +183,7 @@ class Multi2dPanner : public StreamPanner }; -class Panner : public Processor +class Panner : public SessionObject, public AutomatableControls { public: struct Output { @@ -204,18 +204,16 @@ class Panner : public Processor void clear_panners (); bool empty() const { return _streampanners.empty(); } - /// The fundamental Panner function void set_automation_state (AutoState); AutoState automation_state() const; void set_automation_style (AutoStyle); AutoStyle automation_style() 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; }; - 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_full_gui() const = 0; diff --git a/libs/ardour/ardour/port_insert.h b/libs/ardour/ardour/port_insert.h index 56aa43c6c5..fa9c31efe6 100644 --- a/libs/ardour/ardour/port_insert.h +++ b/libs/ardour/ardour/port_insert.h @@ -34,25 +34,28 @@ class XMLNode; namespace ARDOUR { class Session; +class IO; +class Delivery; +class MuteMaster; /** Port inserts: send output to a Jack port, pick up input at a Jack port */ class PortInsert : public IOProcessor { public: - PortInsert (Session&); - PortInsert (Session&, const XMLNode&); + PortInsert (Session&, boost::shared_ptr mm); + PortInsert (Session&, boost::shared_ptr mm, const XMLNode&); ~PortInsert (); XMLNode& state(bool full); XMLNode& get_state(void); int set_state(const XMLNode&); - void init (); - void run_in_place (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes); nframes_t signal_latency() const; + + bool set_name (const std::string& name); bool can_support_io_configuration (const ChanCount& in, ChanCount& out) const; bool configure_io (ChanCount in, ChanCount out); @@ -62,6 +65,8 @@ class PortInsert : public IOProcessor private: /* disallow copy construction */ PortInsert (const PortInsert&); + + boost::shared_ptr _out; uint32_t bitslot; }; diff --git a/libs/ardour/ardour/processor.h b/libs/ardour/ardour/processor.h index 73a93b31d9..61a266e9c5 100644 --- a/libs/ardour/ardour/processor.h +++ b/libs/ardour/ardour/processor.h @@ -53,24 +53,26 @@ class Processor : public SessionObject, public AutomatableControls, public Laten 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; } 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; } void set_next_ab_is_active (bool yn) { _next_ab_is_active = yn; } 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) {} @@ -127,7 +129,7 @@ protected: ChanCount _configured_input; ChanCount _configured_output; void* _gui; /* generic, we don't know or care what this is */ - Mapping _mapping; + Placement _placement; }; } // namespace ARDOUR diff --git a/libs/ardour/ardour/rc_configuration_vars.h b/libs/ardour/ardour/rc_configuration_vars.h index 99ac902629..1a4c49fe64 100644 --- a/libs/ardour/ardour/rc_configuration_vars.h +++ b/libs/ardour/ardour/rc_configuration_vars.h @@ -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, solo_mute_override, "solo-mute-override", false) CONFIG_VARIABLE (bool, tape_machine_mode, "tape-machine-mode", false) +CONFIG_VARIABLE (gain_t, solo_mute_gain, "solo_mute-gain", 0.0) /* click */ diff --git a/libs/ardour/ardour/return.h b/libs/ardour/ardour/return.h index 2b6cd0b69e..5c2a82e3aa 100644 --- a/libs/ardour/ardour/return.h +++ b/libs/ardour/ardour/return.h @@ -32,6 +32,9 @@ namespace ARDOUR { +class Amp; +class PeakMeter; + class Return : public IOProcessor { public: @@ -43,9 +46,12 @@ public: void run_in_place (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes); - void activate() {} - void deactivate () {} + boost::shared_ptr amp() const { return _amp; } + boost::shared_ptr meter() const { return _meter; } + bool metering() const { return _metering; } + void set_metering (bool yn) { _metering = yn; } + XMLNode& state(bool full); XMLNode& get_state(void); int set_state(const XMLNode& node); @@ -55,14 +61,22 @@ public: bool can_support_io_configuration (const ChanCount& in, ChanCount& out) const; 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 &); + protected: + bool _metering; + boost::shared_ptr _amp; + boost::shared_ptr _meter; + private: /* disallow copy construction */ Return (const Return&); 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 diff --git a/libs/ardour/ardour/route.h b/libs/ardour/ardour/route.h index 8de82bb219..a2ad716592 100644 --- a/libs/ardour/ardour/route.h +++ b/libs/ardour/ardour/route.h @@ -41,24 +41,19 @@ #include "ardour/ardour.h" #include "ardour/io.h" #include "ardour/types.h" +#include "ardour/mute_master.h" namespace ARDOUR { class Amp; class Delivery; class IOProcessor; +class Panner; class Processor; class RouteGroup; class Send; -enum mute_type { - PRE_FADER = 0x1, - POST_FADER = 0x2, - CONTROL_OUTS = 0x4, - MAIN_OUTS = 0x8 -}; - -class Route : public IO +class Route : public SessionObject, public AutomatableControls { public: @@ -75,6 +70,16 @@ class Route : public IO Route (Session&, const XMLNode&, DataType default_type = DataType::AUDIO); virtual ~Route(); + boost::shared_ptr input() const { return _input; } + boost::shared_ptr 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 &); std::string comment() { return _comment; } @@ -102,6 +107,7 @@ class Route : public IO virtual void toggle_monitor_input (); virtual bool can_record() { return false; } + virtual void set_record_enable (bool yn, void *src) {} virtual bool record_enabled() const { return false; } virtual void handle_transport_stopped (bool abort, bool did_locate, bool flush_processors); @@ -110,38 +116,44 @@ class Route : public IO /* end of vfunc-based API */ void shift (nframes64_t, nframes64_t); - - /* override IO::set_gain() to provide group control */ - + void set_gain (gain_t val, 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); - bool soloed() const { return _soloed; } + bool soloed() const; - void set_solo_safe (bool yn, void *src); - bool solo_safe() const { return _solo_safe; } + void set_solo_isolated (bool yn, void *src); + bool solo_isolated() const; - void set_mute (bool yn, void *src); - bool muted() const { return _muted; } - bool solo_muted() const { return desired_solo_gain == 0.0; } + void set_phase_invert (bool yn, void* src); + bool phase_invert() const; - void set_mute_config (mute_type, bool, void *src); - bool get_mute_config (mute_type); + void set_denormal_protection (bool yn, void* src); + bool denormal_protection() const; void set_edit_group (RouteGroup *, 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 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); MeterPoint meter_point() const { return _meter_point; } + void meter (); /* Processors */ + boost::shared_ptr amp() const { return _amp; } + PeakMeter& peak_meter() { return *_meter.get(); } + const PeakMeter& peak_meter() const { return *_meter.get(); } + boost::shared_ptr shared_peak_meter() const { return _meter; } + void flush_processors (); void foreach_processor (sigc::slot > method) { @@ -180,7 +192,7 @@ class Route : public IO boost::shared_ptr control_outs() const { return _control_outs; } boost::shared_ptr main_outs() const { return _main_outs; } - + boost::shared_ptr send_for (boost::shared_ptr target) const; /** A record of the stream configuration at some point in the processor list. @@ -213,8 +225,10 @@ class Route : public IO void set_user_latency (nframes_t); nframes_t initial_delay() const { return _initial_delay; } + sigc::signal active_changed; sigc::signal solo_changed; sigc::signal solo_safe_changed; + sigc::signal solo_isolated_changed; sigc::signal comment_changed; sigc::signal mute_changed; sigc::signal pre_fader_changed; @@ -240,8 +254,8 @@ class Route : public IO virtual XMLNode& get_template(); 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); sigc::signal SelectedChanged; @@ -252,28 +266,38 @@ class Route : public IO bool feeds (boost::shared_ptr); std::set > fed_by; - struct ToggleControllable : public PBD::Controllable { - enum ToggleType { - MuteControl = 0, - SoloControl - }; - - ToggleControllable (std::string name, Route&, ToggleType); - void set_value (float); - float get_value (void) const; - - Route& route; - ToggleType type; + /* Controls (not all directly owned by the Route */ + + boost::shared_ptr get_control (const Evoral::Parameter& param); + + struct SoloControllable : public AutomationControl { + SoloControllable (std::string name, Route&); + void set_value (float); + float get_value (void) const; + + Route& route; }; - boost::shared_ptr solo_control() { + boost::shared_ptr solo_control() const { return _solo_control; } - boost::shared_ptr mute_control() { - return _mute_control; + boost::shared_ptr mute_control() const { + return _mute_master; } - + + boost::shared_ptr 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() const; + boost::shared_ptr gain_control() const; + void automation_snapshot (nframes_t now, bool force=false); void protect_automation (); @@ -288,10 +312,11 @@ class Route : public IO friend class Session; 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); bool has_external_redirects() const; void curve_reallocate (); + void just_meter_input (sframes_t start_frame, sframes_t end_frame, nframes_t nframes); protected: 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, nframes_t nframes, bool with_processors, int declick); - Flag _flags; - int _pending_declick; - MeterPoint _meter_point; + boost::shared_ptr _input; + boost::shared_ptr _output; - 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 _roll_delay; + ProcessorList _processors; mutable Glib::RWLock _processor_lock; boost::shared_ptr _main_outs; boost::shared_ptr _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 _solo_control; - boost::shared_ptr _mute_control; - - /* 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; + Flag _flags; + int _pending_declick; + MeterPoint _meter_point; + uint32_t _phase_invert; + bool _denormal_protection; + 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 _declickable : 1; + boost::shared_ptr _solo_control; + boost::shared_ptr _mute_master; + + RouteGroup* _edit_group; + RouteGroup* _mix_group; + std::string _comment; + bool _have_internal_generator; + bool _solo_safe; + DataType _default_type; + protected: virtual XMLNode& state(bool); @@ -358,13 +377,14 @@ class Route : public IO uint32_t pans_required() const; ChanCount n_process_buffers (); - void setup_peak_meters (); - virtual int _set_state (const XMLNode&, bool call_base); - virtual void _set_processor_states (const XMLNodeList&); boost::shared_ptr add_listener (boost::shared_ptr, const std::string&); + boost::shared_ptr _amp; + boost::shared_ptr _meter; + sigc::connection _meter_connection; + private: void init (); @@ -386,8 +406,7 @@ class Route : public IO int configure_processors (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&, ProcessorList::iterator iter); diff --git a/libs/ardour/ardour/send.h b/libs/ardour/ardour/send.h index b47263b547..302f512c9c 100644 --- a/libs/ardour/ardour/send.h +++ b/libs/ardour/ardour/send.h @@ -23,40 +23,52 @@ #include #include - #include "pbd/stateful.h" + #include "ardour/ardour.h" #include "ardour/audioengine.h" #include "ardour/delivery.h" namespace ARDOUR { +class PeakMeter; +class Amp; + class Send : public Delivery { public: - Send (Session&); - Send (Session&, const XMLNode&); + Send (Session&, boost::shared_ptr); + Send (Session&, boost::shared_ptr, const XMLNode&); virtual ~Send (); uint32_t bit_slot() const { return _bitslot; } - - void activate() {} - void deactivate () {} + boost::shared_ptr amp() const { return _amp; } + boost::shared_ptr meter() const { return _meter; } + + bool metering() const { return _metering; } + void set_metering (bool yn) { _metering = yn; } + XMLNode& state(bool full); XMLNode& get_state(void); int set_state(const XMLNode& node); 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 configure_io (ChanCount in, ChanCount out); bool set_name (const std::string& str); static uint32_t how_many_sends(); static void make_unique (XMLNode &, Session &); + protected: + bool _metering; + boost::shared_ptr _amp; + boost::shared_ptr _meter; + private: /* disallow copy construction */ Send (const Send&); diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index 3d85c8d200..d476a958d8 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -730,8 +730,8 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable /* 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_mute (bool); @@ -743,8 +743,8 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable /* control/master out */ - boost::shared_ptr control_out() const { return _control_out; } - boost::shared_ptr master_out() const { return _master_out; } + boost::shared_ptr control_out() const { return _control_out; } + boost::shared_ptr master_out() const { return _master_out; } /* insert/send management */ @@ -1040,6 +1040,7 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable bool _have_captured; float _meter_hold; float _meter_falloff; + bool _non_soloed_outs_muted; void set_worst_io_latencies (); void set_worst_io_latencies_x (IOChange asifwecare, void *ignored) { @@ -1688,8 +1689,8 @@ class Session : public PBD::StatefulDestructible, public boost::noncopyable /* main outs */ uint32_t main_outs; - boost::shared_ptr _master_out; - boost::shared_ptr _control_out; + boost::shared_ptr _master_out; + boost::shared_ptr _control_out; gain_t* _gain_automation_buffer; pan_t** _pan_automation_buffer; diff --git a/libs/ardour/audio_diskstream.cc b/libs/ardour/audio_diskstream.cc index 910239f630..4e8e2bf12d 100644 --- a/libs/ardour/audio_diskstream.cc +++ b/libs/ardour/audio_diskstream.cc @@ -160,6 +160,8 @@ AudioDiskstream::free_working_buffers() void AudioDiskstream::non_realtime_input_change () { + cerr << "AD::NRIC ... " << name() << endl; + { Glib::Mutex::Lock lm (state_lock); @@ -173,10 +175,10 @@ AudioDiskstream::non_realtime_input_change () _n_channels.set(DataType::AUDIO, c->size()); - if (_io->n_inputs().n_audio() > _n_channels.n_audio()) { - add_channel_to (c, _io->n_inputs().n_audio() - _n_channels.n_audio()); - } else if (_io->n_inputs().n_audio() < _n_channels.n_audio()) { - remove_channel_from (c, _n_channels.n_audio() - _io->n_inputs().n_audio()); + if (_io->n_ports().n_audio() > _n_channels.n_audio()) { + add_channel_to (c, _io->n_ports().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_ports().n_audio()); } } @@ -227,14 +229,14 @@ AudioDiskstream::get_input_sources () uint32_t n; ChannelList::iterator chan; - uint32_t ni = _io->n_inputs().n_audio(); + uint32_t ni = _io->n_ports().n_audio(); vector connections; for (n = 0, chan = c->begin(); chan != c->end() && n < ni; ++chan, ++n) { connections.clear (); - if (_io->input(n)->get_connections (connections) == 0) { + if (_io->nth (n)->get_connections (connections) == 0) { if ((*chan)->source) { // _source->disable_metering (); @@ -633,7 +635,7 @@ AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can 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 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 */ - AudioPort* const ap = _io->audio_input(n); + AudioPort* const ap = _io->audio (n); assert(ap); 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); @@ -671,7 +673,7 @@ AudioDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can goto out; } - AudioPort* const ap = _io->audio_input(n); + AudioPort* const ap = _io->audio (n); assert(ap); Sample* buf = ap->get_audio_buffer(nframes).data(); @@ -1822,7 +1824,7 @@ AudioDiskstream::finish_capture (bool rec_monitors_input, boost::shared_ptrn_inputs().n_audio() == 0) { + if (!recordable() || !_session.record_enabling_legal() || _io->n_ports().n_audio() == 0) { return; } @@ -2110,6 +2112,8 @@ AudioDiskstream::reset_write_sources (bool mark_write_complete, bool force) boost::shared_ptr c = channels.reader(); uint32_t n; + cerr << _name << " RWS!!!\n"; + if (!recordable()) { return; } diff --git a/libs/ardour/audio_track.cc b/libs/ardour/audio_track.cc index 70e317c880..a41fdbe6b6 100644 --- a/libs/ardour/audio_track.cc +++ b/libs/ardour/audio_track.cc @@ -36,6 +36,7 @@ #include "ardour/buffer_set.h" #include "ardour/io_processor.h" #include "ardour/panner.h" +#include "ardour/meter.h" #include "ardour/playlist_factory.h" #include "ardour/plugin_insert.h" #include "ardour/processor.h" @@ -140,8 +141,7 @@ AudioTrack::deprecated_use_diskstream_connections () diskstream->deprecated_io_node = 0; if ((prop = node.property ("gain")) != 0) { - set_gain (atof (prop->value().c_str()), this); - _gain = _gain_control->user_float(); + _amp->set_gain (atof (prop->value().c_str()), this); } 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) { - 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; return -1; } @@ -176,14 +176,14 @@ int AudioTrack::set_diskstream (boost::shared_ptr ds, void *src) { _diskstream = ds; - _diskstream->set_io (*this); + _diskstream->set_io (*(_input.get())); _diskstream->set_destructive (_mode == Destructive); _diskstream->set_non_layered (_mode == NonLayered); if (audio_diskstream()->deprecated_io_node) { - if (!connecting_legal) { - ConnectingLegal.connect (mem_fun (*this, &AudioTrack::deprecated_use_diskstream_connections)); + if (!IO::connecting_legal) { + IO::ConnectingLegal.connect (mem_fun (*this, &AudioTrack::deprecated_use_diskstream_connections)); } else { deprecated_use_diskstream_connections (); } @@ -193,7 +193,7 @@ AudioTrack::set_diskstream (boost::shared_ptr ds, void *src) _diskstream->monitor_input (false); 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 */ @@ -479,8 +479,6 @@ AudioTrack::roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame, transport_frame = _session.transport_frame(); - prepare_inputs (nframes); - if ((nframes = check_initial_delay (nframes, transport_frame)) == 0) { /* 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 */ 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()) { @@ -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) */ if (!diskstream->record_enabled() && _session.transport_rolling()) { +#ifdef XXX_MOVE_THIS_TO_AMP Glib::Mutex::Lock am (data().control_lock(), Glib::TRY_LOCK); 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 ( 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); @@ -759,9 +759,9 @@ AudioTrack::freeze (InterThreadInfo& itt) new_playlist = PlaylistFactory::create (DataType::AUDIO, _session, new_playlist_name, false); - _freeze_record.gain = _gain; - _freeze_record.gain_automation_state = _gain_control->automation_state(); - _freeze_record.pan_automation_state = _panner->automation_state(); + _freeze_record.gain = _amp->gain(); + _freeze_record.gain_automation_state = _amp->gain_control()->automation_state(); + /* XXX need main outs automation state _freeze_record.pan_automation_state = _mainpanner->automation_state(); */ 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 */ set_gain (1.0, this); - _gain_control->set_automation_state (Off); - _panner->set_automation_state (Off); + _amp->gain_control()->set_automation_state (Off); + /* XXX need to use _main_outs _panner->set_automation_state (Off); */ _freeze_record.state = Frozen; FreezeChange(); /* EMIT SIGNAL */ @@ -811,8 +811,8 @@ AudioTrack::unfreeze () _freeze_record.playlist.reset (); set_gain (_freeze_record.gain, this); - _gain_control->set_automation_state (_freeze_record.gain_automation_state); - _panner->set_automation_state (_freeze_record.pan_automation_state); + _amp->gain_control()->set_automation_state (_freeze_record.gain_automation_state); + /* XXX need to use _main_outs _panner->set_automation_state (_freeze_record.pan_automation_state); */ } _freeze_record.state = UnFrozen; diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc index fe9c064efa..b563537cb3 100644 --- a/libs/ardour/audioengine.cc +++ b/libs/ardour/audioengine.cc @@ -33,9 +33,11 @@ #include "ardour/audioengine.h" #include "ardour/buffer.h" +#include "ardour/delivery.h" #include "ardour/port.h" #include "ardour/audio_port.h" #include "ardour/midi_port.h" +#include "ardour/meter.h" #include "ardour/session.h" #include "ardour/cycle_timer.h" #include "ardour/utils.h" @@ -358,9 +360,9 @@ AudioEngine::process_callback (nframes_t nframes) 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); /* 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)) { break; } - IO::update_meters (); + Metering::update_meters (); } } diff --git a/libs/ardour/auditioner.cc b/libs/ardour/auditioner.cc index b62d0f3406..35a1b70137 100644 --- a/libs/ardour/auditioner.cc +++ b/libs/ardour/auditioner.cc @@ -24,6 +24,7 @@ #include "ardour/audio_diskstream.h" #include "ardour/audioregion.h" #include "ardour/audioengine.h" +#include "ardour/delivery.h" #include "ardour/route.h" #include "ardour/session.h" #include "ardour/auditioner.h" @@ -57,22 +58,21 @@ Auditioner::Auditioner (Session& s) return; } - defer_pan_reset (); + _main_outs->defer_pan_reset (); if (left.length()) { - add_output_port (left, this, DataType::AUDIO); + _output->add_port (left, this, DataType::AUDIO); } if (right.length()) { audio_diskstream()->add_channel (1); - add_output_port (right, this, DataType::AUDIO); + _output->add_port (right, this, DataType::AUDIO); } - - allow_pan_reset (); - reset_panner (); + _main_outs->allow_pan_reset (); + _main_outs->reset_panner (); - IO::output_changed.connect (mem_fun (*this, &Auditioner::output_changed)); + _output->changed.connect (mem_fun (*this, &Auditioner::output_changed)); the_region.reset ((AudioRegion*) 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 */ - _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); } @@ -148,7 +148,7 @@ Auditioner::audition_region (boost::shared_ptr region) /* force a panner reset now that we have all channels */ - reset_panner(); + _main_outs->reset_panner(); length = the_region->length(); @@ -206,7 +206,7 @@ Auditioner::output_changed (IOChange change, void* src) if (change & ConnectionsChanged) { vector connections; - if (output (0)->get_connections (connections)) { + if (_output->nth (0)->get_connections (connections)) { phys = _session.engine().get_nth_physical_output (DataType::AUDIO, 0); if (phys != connections[0]) { _session.config.set_auditioner_output_left (connections[0]); @@ -219,7 +219,7 @@ Auditioner::output_changed (IOChange change, void* src) 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); if (phys != connections[0]) { _session.config.set_auditioner_output_right (connections[0]); diff --git a/libs/ardour/automatable.cc b/libs/ardour/automatable.cc index 0fa4e9c67a..bf08a4026c 100644 --- a/libs/ardour/automatable.cc +++ b/libs/ardour/automatable.cc @@ -24,8 +24,11 @@ #include #include "pbd/error.h" #include "pbd/enumwriter.h" + #include "midi++/names.h" + #include "ardour/automatable.h" +#include "ardour/amp.h" #include "ardour/event_type_map.h" #include "ardour/midi_track.h" #include "ardour/panner.h" @@ -382,7 +385,7 @@ Automatable::automation_snapshot (nframes_t now, bool force) } void -Automatable::transport_stopped (nframes_t now) +Automatable::transport_stopped (sframes_t now) { 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) { control = new PluginInsert::PluginControl((PluginInsert*)this, param); } 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) { Panner* me = dynamic_cast(this); if (me) { diff --git a/libs/ardour/delivery.cc b/libs/ardour/delivery.cc index bf15242094..75b026618b 100644 --- a/libs/ardour/delivery.cc +++ b/libs/ardour/delivery.cc @@ -20,58 +20,102 @@ #include #include "pbd/enumwriter.h" +#include "pbd/convert.h" + #include "ardour/delivery.h" #include "ardour/audio_buffer.h" +#include "ardour/amp.h" #include "ardour/buffer_set.h" #include "ardour/configuration.h" #include "ardour/io.h" #include "ardour/meter.h" +#include "ardour/mute_master.h" +#include "ardour/panner.h" +#include "ardour/port.h" #include "ardour/session.h" +#include "i18n.h" + using namespace std; +using namespace PBD; using namespace ARDOUR; +sigc::signal Delivery::CycleStart; +sigc::signal Delivery::PannersLegal; +bool Delivery::panners_legal = false; + /* deliver to an existing IO object */ -Delivery::Delivery (Session& s, IO* io, const string& name, Role r) - : IOProcessor(s, io, name) +Delivery::Delivery (Session& s, boost::shared_ptr io, boost::shared_ptr mm, const string& name, Role r) + : IOProcessor(s, boost::shared_ptr(), io, name) , _role (r) - , _metering (false) - , _muted_by_self (false) - , _muted_by_others (false) + , _output_buffers (new BufferSet()) + , _solo_level (0) + , _solo_isolated (false) + , _mute_master (mm) { + _output_offset = 0; + _current_gain = 1.0; + _panner = boost::shared_ptr(new Panner (_name, _session)); + + _output->changed.connect (mem_fun (*this, &Delivery::output_changed)); } /* deliver to a new IO object */ -Delivery::Delivery (Session& s, const string& name, Role r) - : IOProcessor(s, name) +Delivery::Delivery (Session& s, boost::shared_ptr mm, const string& name, Role r) + : IOProcessor(s, false, true, name) , _role (r) - , _metering (false) - , _muted_by_self (false) - , _muted_by_others (false) + , _output_buffers (new BufferSet()) + , _solo_level (0) + , _solo_isolated (false) + , _mute_master (mm) { + _output_offset = 0; + _current_gain = 1.0; + _panner = boost::shared_ptr(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) - : IOProcessor (s, "reset") +Delivery::Delivery (Session& s, boost::shared_ptr mm, const XMLNode& node) + : IOProcessor (s, false, true, "reset") , _role (Role (0)) - , _metering (false) - , _muted_by_self (false) - , _muted_by_others (false) + , _output_buffers (new BufferSet()) + , _solo_level (0) + , _solo_isolated (false) + , _mute_master (mm) { + _output_offset = 0; + _current_gain = 1.0; + _panner = boost::shared_ptr(new Panner (_name, _session)); + if (set_state (node)) { 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 Delivery::visible () const { - if (_role & (Main|Solo)) { + if (_role & Main) { return false; } @@ -91,6 +135,8 @@ Delivery::configure_io (ChanCount in, ChanCount out) if (out != in) { // always 1:1 return false; } + + reset_panner (); return Processor::configure_io (in, out); } @@ -98,64 +144,46 @@ Delivery::configure_io (ChanCount in, ChanCount out) void 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; } - if (!active() || _muted_by_self || _muted_by_others) { - silence (nframes); - if (_metering) { - _io->peak_meter().reset(); - } - } else { + // this Delivery processor is not a derived type, and thus we assume + // we really can modify the buffers passed in (it is almost certainly + // the main output stage of a Route). Contrast with Send::run_in_place() + // which cannot do this. - // we have to copy the input, because IO::deliver_output may alter the buffers - // in-place, which a send must never do. + gain_t tgain = target_gain (); + + if (tgain != _current_gain) { + Amp::apply_gain (bufs, nframes, _current_gain, tgain); + _current_gain = tgain; + } - BufferSet& sendbufs = _session.get_mix_buffers (bufs.count()); + // Attach output buffers to port buffers - sendbufs.read_from(bufs, nframes); - assert(sendbufs.count() == bufs.count()); + PortSet& ports (_output->ports()); + output_buffers().attach_buffers (ports, nframes, _output_offset); - _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); - } + 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 { + // Do a 1:1 copy of data to output ports + + if (bufs.count().n_audio() > 0 && ports.count().n_audio () > 0) { + _output->copy_to_outputs (bufs, DataType::AUDIO, nframes, _output_offset); } - } -} -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 + if (bufs.count().n_midi() > 0 && ports.count().n_midi () > 0) { + _output->copy_to_outputs (bufs, DataType::MIDI, nframes, _output_offset); + } } } -void -Delivery::set_nonself_mute (bool yn) -{ - if (yn != _muted_by_others) { - _muted_by_others = yn; - OtherMuteChange (); // emit signal - } -} XMLNode& Delivery::state (bool full_state) @@ -170,10 +198,8 @@ Delivery::state (bool full_state) 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_child_nocopy (_panner->state (full_state)); return node; } @@ -182,22 +208,236 @@ int Delivery::set_state (const XMLNode& node) { const XMLProperty* prop; + + if (IOProcessor::set_state (node)) { + return -1; + } if ((prop = node.property ("role")) != 0) { _role = Role (string_2_enum (prop->value(), _role)); } - if ((prop = node.property ("metering")) != 0) { - set_metering (prop->value() == "yes"); + if ((prop = node.property ("solo_level")) != 0) { + _solo_level = 0; // needed for the reset to work + mod_solo_level (atoi (prop->value())); } - if ((prop = node.property ("self-muted")) != 0) { - set_self_mute (prop->value() == "yes"); + if ((prop = node.property ("solo-isolated")) != 0) { + set_solo_isolated (prop->value() == "yes"); } - if ((prop = node.property ("other-muted")) != 0) { - set_nonself_mute (prop->value() == "yes"); + XMLNode* pan_node = node.child (X_("Panner")); + + if (pan_node) { + cerr << _name << " reset pan state from XML\n"; + _panner->set_state (*pan_node); + } + + reset_panner (); + + 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 (); + } +} diff --git a/libs/ardour/diskstream.cc b/libs/ardour/diskstream.cc index bca3c74241..27a1c18ff4 100644 --- a/libs/ardour/diskstream.cc +++ b/libs/ardour/diskstream.cc @@ -138,6 +138,8 @@ void Diskstream::set_io (IO& io) { _io = &io; + input_change_pending = ConfigurationChanged; + non_realtime_input_change (); set_align_style_from_io (); } @@ -233,7 +235,7 @@ Diskstream::set_capture_offset () return; } - _capture_offset = _io->input_latency(); + _capture_offset = _io->latency(); } void @@ -420,6 +422,11 @@ Diskstream::remove_region_from_last_capture (boost::weak_ptr wregion) void Diskstream::playlist_ranges_moved (list< Evoral::RangeMove > const & movements_frames) { +#if 0 + + XXX THIS HAS TO BE FIXED FOR 3.0 + + if (Config->get_automation_follows_regions () == false) { return; } @@ -431,7 +438,7 @@ Diskstream::playlist_ranges_moved (list< Evoral::RangeMove > const & } /* move gain automation */ - boost::shared_ptr gain_alist = _io->gain_control()->alist(); + boost::shared_ptr gain_alist = _io->gain_control()->list(); XMLNode & before = gain_alist->get_state (); gain_alist->move_ranges (movements); _session.add_command ( @@ -458,11 +465,12 @@ Diskstream::playlist_ranges_moved (list< Evoral::RangeMove > const & if (route) { route->foreach_processor (sigc::bind (sigc::mem_fun (*this, &Diskstream::move_processor_automation), movements_frames)); } +#endif } void Diskstream::move_processor_automation (boost::weak_ptr p, - list< Evoral::RangeMove > const & movements_frames) + list< Evoral::RangeMove > const & movements_frames) { boost::shared_ptr processor (p.lock ()); if (!processor) { diff --git a/libs/ardour/enums.cc b/libs/ardour/enums.cc index 7767381499..60d2b5177e 100644 --- a/libs/ardour/enums.cc +++ b/libs/ardour/enums.cc @@ -19,20 +19,21 @@ #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/diskstream.h" #include "ardour/audioregion.h" -#include "ardour/route_group.h" -#include "ardour/panner.h" -#include "ardour/track.h" -#include "ardour/midi_track.h" +#include "ardour/delivery.h" +#include "ardour/diskstream.h" #include "ardour/export_filename.h" #include "ardour/export_format_base.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 PBD; @@ -70,7 +71,6 @@ setup_enum_writer () SlaveSource _SlaveSource; ShuttleBehaviour _ShuttleBehaviour; ShuttleUnits _ShuttleUnits; - mute_type _mute_type; Session::RecordState _Session_RecordState; Session::Event::Type _Session_Event_Type; SmpteFormat _Session_SmpteFormat; @@ -105,6 +105,7 @@ setup_enum_writer () ExportFormatBase::SRCQuality _ExportFormatBase_SRCQuality; ExportProfileManager::TimeFormat _ExportProfileManager_TimeFormat; 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_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 (_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, MasterOut); REGISTER_CLASS_ENUM (Route, ControlOut); @@ -502,9 +497,13 @@ setup_enum_writer () REGISTER_CLASS_ENUM (ExportProfileManager, Off); REGISTER (_ExportProfileManager_TimeFormat); - REGISTER_CLASS_ENUM (Delivery, Solo); + REGISTER_CLASS_ENUM (Delivery, Insert); REGISTER_CLASS_ENUM (Delivery, Send); REGISTER_CLASS_ENUM (Delivery, Listen); REGISTER_CLASS_ENUM (Delivery, Main); REGISTER_BITS (_Delivery_Role); + + REGISTER_CLASS_ENUM (IO, Input); + REGISTER_CLASS_ENUM (IO, Output); + REGISTER (_IO_Direction); } diff --git a/libs/ardour/io.cc b/libs/ardour/io.cc index ba3d70c184..a5d4e639e3 100644 --- a/libs/ardour/io.cc +++ b/libs/ardour/io.cc @@ -30,8 +30,10 @@ #include "pbd/xml++.h" #include "pbd/replace_all.h" #include "pbd/unknown_type.h" +#include "pbd/enumwriter.h" #include "ardour/audioengine.h" +#include "ardour/buffer.h" #include "ardour/io.h" #include "ardour/route.h" #include "ardour/port.h" @@ -67,131 +69,46 @@ using namespace PBD; const string IO::state_node_name = "IO"; bool IO::connecting_legal = false; -bool IO::ports_legal = false; -bool IO::panners_legal = false; -sigc::signal IO::Meter; sigc::signal IO::ConnectingLegal; -sigc::signal IO::PortsLegal; -sigc::signal IO::PannersLegal; sigc::signal IO::PortCountChanged; -sigc::signal IO::CycleStart; - -Glib::StaticMutex IO::m_meter_signal_lock = GLIBMM_STATIC_MUTEX_INIT; - -/* this is a default mapper of [0 .. 1.0] control values to a gain coefficient. - others can be imagined. -*/ - -#if 0 -static gain_t direct_control_to_gain (double fract) { - /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */ - /* this maxes at +6dB */ - return pow (2.0,(sqrt(sqrt(sqrt(fract)))*198.0-192.0)/6.0); -} - -static double direct_gain_to_control (gain_t gain) { - /* XXX Marcus writes: this doesn't seem right to me. but i don't have a better answer ... */ - if (gain == 0) return 0.0; - - return pow((6.0*log(gain)/log(2.0)+192.0)/198.0, 8.0); -} -#endif /** @param default_type The type of port that will be created by ensure_io * and friends if no type is explicitly requested (to avoid breakage). */ -IO::IO (Session& s, const string& name, DataType default_type) +IO::IO (Session& s, const string& name, Direction dir, DataType default_type) : SessionObject (s, name) - , AutomatableControls (s) - , _output_buffers (new BufferSet()) - , _active (true) + , _direction (dir) , _default_type (default_type) - , _amp (new Amp(s, *this)) - , _meter (new PeakMeter(s)) - , _panner (new Panner(name, s)) { - _gain = 1.0; + _active = true; pending_state_node = 0; - no_panner_reset = false; - _phase_invert = false; - deferred_state = 0; - - boost::shared_ptr gl( - new AutomationList(Evoral::Parameter(GainAutomation))); - - _gain_control = boost::shared_ptr( new GainControl( X_("gaincontrol"), this, Evoral::Parameter(GainAutomation), gl )); - - add_control(_gain_control); - - { - // IO::Meter is emitted from another thread so the - // Meter signal must be protected. - Glib::Mutex::Lock guard (m_meter_signal_lock); - m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter)); - } - - _output_offset = 0; - CycleStart.connect (mem_fun (*this, &IO::cycle_start)); - - _session.add_controllable (_gain_control); - - setup_bundles_for_inputs_and_outputs (); + setup_bundles (); + cerr << "+++ IO created with name = " << _name << endl; } IO::IO (Session& s, const XMLNode& node, DataType dt) : SessionObject(s, "unnamed io") - , AutomatableControls (s) - , _output_buffers (new BufferSet()) - , _active(true) + , _direction (Input) , _default_type (dt) - , _amp (new Amp(s, *this)) - , _meter(new PeakMeter (_session)) { - deferred_state = 0; - no_panner_reset = false; - _gain = 1.0; - - boost::shared_ptr gl( - new AutomationList(Evoral::Parameter(GainAutomation))); - - _gain_control = boost::shared_ptr( - new GainControl( X_("gaincontrol"), this, Evoral::Parameter(GainAutomation), gl)); - - add_control(_gain_control); + _active = true; + pending_state_node = 0; set_state (node); - { - // IO::Meter is emitted from another thread so the - // Meter signal must be protected. - Glib::Mutex::Lock guard (m_meter_signal_lock); - m_meter_connection = Meter.connect (mem_fun (*this, &IO::meter)); - } - - _output_offset = 0; - CycleStart.connect (mem_fun (*this, &IO::cycle_start)); - - _session.add_controllable (_gain_control); - - setup_bundles_for_inputs_and_outputs (); + setup_bundles (); + cerr << "+++ IO created from XML with name = " << _name << endl; } IO::~IO () { - Glib::Mutex::Lock guard (m_meter_signal_lock); Glib::Mutex::Lock lm (io_lock); BLOCK_PROCESS_CALLBACK (); - for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) { - _session.engine().unregister_port (*i); - } - - for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) { + for (PortSet::iterator i = _ports.begin(); i != _ports.end(); ++i) { _session.engine().unregister_port (*i); } - - m_meter_connection.disconnect(); } void @@ -199,131 +116,15 @@ IO::silence (nframes_t nframes) { /* io_lock, not taken: function must be called from Session::process() calltree */ - for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) { + for (PortSet::iterator i = _ports.begin(); i != _ports.end(); ++i) { i->get_buffer(nframes).silence (nframes); } } -/** Deliver bufs to the IO's output ports - * - * This function should automatically do whatever it necessary to correctly deliver bufs - * to the outputs, eg applying gain or pan or whatever else needs to be done. - */ -void -IO::deliver_output (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes) -{ - // Attach output buffers to port buffers - output_buffers().attach_buffers (_outputs, nframes, _output_offset); - - // Use the panner to distribute audio to output port buffers - if (_panner && _panner->npanners() && !_panner->bypassed()) { - - _panner->run_out_of_place(bufs, output_buffers(), start_frame, end_frame, nframes); - - // Do a 1:1 copy of data to output ports - } else { - if (bufs.count().n_audio() > 0 && _outputs.count().n_audio () > 0) { - copy_to_outputs (bufs, DataType::AUDIO, nframes); - } - if (bufs.count().n_midi() > 0 && _outputs.count().n_midi () > 0) { - copy_to_outputs (bufs, DataType::MIDI, nframes); - } - } - - // Apply gain to output buffers if gain automation isn't playing - if ( ! _amp->apply_gain_automation()) { - - gain_t dg = _gain; // desired gain - - { - Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK); - - if (dm.locked()) { - dg = _gain_control->user_float(); - } - - } - - if (dg != _gain || dg != 1.0) { - Amp::apply_gain(output_buffers(), nframes, _gain, dg, _phase_invert); - _gain = dg; - } - } - -} - -void -IO::copy_to_outputs (BufferSet& bufs, DataType type, nframes_t nframes) -{ - // Copy any buffers 1:1 to outputs - - PortSet::iterator o = _outputs.begin(type); - BufferSet::iterator i = bufs.begin(type); - BufferSet::iterator prev = i; - - while (i != bufs.end(type) && o != _outputs.end (type)) { - Buffer& port_buffer (o->get_buffer (nframes)); - port_buffer.read_from (*i, nframes, _output_offset); - prev = i; - ++i; - ++o; - } - - // Copy last buffer to any extra outputs - while (o != _outputs.end(type)) { - Buffer& port_buffer (o->get_buffer (nframes)); - port_buffer.read_from (*prev, nframes, _output_offset); - ++o; - } -} - -void -IO::collect_input (BufferSet& outs, nframes_t nframes, ChanCount offset) -{ - assert(outs.available() >= n_inputs()); - - if (n_inputs() == ChanCount::ZERO) { - return; - } - - outs.set_count(n_inputs()); - - for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) { - PortSet::iterator i = _inputs.begin(*t); - BufferSet::iterator o = outs.begin(*t); - - for (uint32_t off = 0; off < offset.get(*t); ++off, ++o) { - if (o == outs.end(*t)) { - continue; - } - } - - for ( ; i != _inputs.end(*t); ++i, ++o) { - Buffer& b (i->get_buffer (nframes)); - o->read_from (b, nframes); - } - } -} - -void -IO::just_meter_input (sframes_t start_frame, sframes_t end_frame, nframes_t nframes) -{ - BufferSet& bufs = _session.get_scratch_buffers (n_inputs()); - collect_input (bufs, nframes); - _meter->run_in_place (bufs, start_frame, end_frame, nframes); -} - - -void -IO::check_bundles_connected_to_inputs () -{ - check_bundles (_bundles_connected_to_inputs, inputs()); -} - void -IO::check_bundles_connected_to_outputs () +IO::check_bundles_connected () { - check_bundles (_bundles_connected_to_outputs, outputs()); + check_bundles (_bundles_connected, ports()); } void @@ -335,7 +136,7 @@ IO::check_bundles (std::vector& list, const PortSet& ports) uint32_t const N = i->bundle->nchannels (); - if (ports.num_ports (default_type()) < N) { + if (_ports.num_ports (default_type()) < N) { continue; } @@ -368,7 +169,7 @@ IO::check_bundles (std::vector& list, const PortSet& ports) int -IO::disconnect_input (Port* our_port, string other_port, void* src) +IO::disconnect (Port* our_port, string other_port, void* src) { if (other_port.length() == 0 || our_port == 0) { return 0; @@ -382,29 +183,29 @@ IO::disconnect_input (Port* our_port, string other_port, void* src) /* check that our_port is really one of ours */ - if ( ! _inputs.contains(our_port)) { + if ( ! _ports.contains(our_port)) { return -1; } /* disconnect it from the source */ if (our_port->disconnect (other_port)) { - error << string_compose(_("IO: cannot disconnect input port %1 from %2"), our_port->name(), other_port) << endmsg; + error << string_compose(_("IO: cannot disconnect port %1 from %2"), our_port->name(), other_port) << endmsg; return -1; } - check_bundles_connected_to_inputs (); + check_bundles_connected (); } } - input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */ + changed (ConnectionsChanged, src); /* EMIT SIGNAL */ _session.set_dirty (); return 0; } int -IO::connect_input (Port* our_port, string other_port, void* src) +IO::connect (Port* our_port, string other_port, void* src) { if (other_port.length() == 0 || our_port == 0) { return 0; @@ -418,7 +219,7 @@ IO::connect_input (Port* our_port, string other_port, void* src) /* check that our_port is really one of ours */ - if ( ! _inputs.contains(our_port) ) { + if ( ! _ports.contains(our_port) ) { return -1; } @@ -430,99 +231,13 @@ IO::connect_input (Port* our_port, string other_port, void* src) } } - input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */ - _session.set_dirty (); - return 0; -} - -int -IO::disconnect_output (Port* our_port, string other_port, void* src) -{ - if (other_port.length() == 0 || our_port == 0) { - return 0; - } - - { - BLOCK_PROCESS_CALLBACK (); - - { - Glib::Mutex::Lock lm (io_lock); - - /* check that our_port is really one of ours */ - - if ( ! _outputs.contains(our_port) ) { - return -1; - } - - /* disconnect it from the destination */ - - if (our_port->disconnect (other_port)) { - error << string_compose(_("IO: cannot disconnect output port %1 from %2"), our_port->name(), other_port) << endmsg; - return -1; - } - - check_bundles_connected_to_outputs (); - } - } - - output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */ - _session.set_dirty (); - return 0; -} - -int -IO::connect_output (Port* our_port, string other_port, void* src) -{ - if (other_port.length() == 0 || our_port == 0) { - return 0; - } - - { - BLOCK_PROCESS_CALLBACK (); - - - { - Glib::Mutex::Lock lm (io_lock); - - /* check that our_port is really one of ours */ - - if ( ! _outputs.contains(our_port) ) { - return -1; - } - - /* connect it to the destination */ - - if (our_port->connect (other_port)) { - return -1; - } - } - } - - output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */ + changed (ConnectionsChanged, src); /* EMIT SIGNAL */ _session.set_dirty (); return 0; } int -IO::set_input (Port* other_port, void* src) -{ - /* this removes all but one ports, and connects that one port - to the specified source. - */ - - if (!other_port) { - return -1; - } - - if (ensure_inputs (ChanCount(other_port->type(), 1), true, true, src)) { - return -1; - } - - return connect_input (_inputs.port(0), other_port->name(), src); -} - -int -IO::remove_output_port (Port* port, void* src) +IO::remove_port (Port* port, void* src) { IOChange change (NoChange); @@ -533,7 +248,7 @@ IO::remove_output_port (Port* port, void* src) { Glib::Mutex::Lock lm (io_lock); - if (_outputs.remove(port)) { + if (_ports.remove(port)) { change = IOChange (change|ConfigurationChanged); if (port->connected()) { @@ -541,22 +256,19 @@ IO::remove_output_port (Port* port, void* src) } _session.engine().unregister_port (*port); - check_bundles_connected_to_outputs (); - - setup_peak_meters (); - reset_panner (); + check_bundles_connected (); } } - PortCountChanged (n_outputs()); /* EMIT SIGNAL */ + PortCountChanged (n_ports()); /* EMIT SIGNAL */ } if (change == ConfigurationChanged) { - setup_bundle_for_outputs (); + setup_bundles (); } if (change != NoChange) { - output_changed (change, src); + changed (change, src); _session.set_dirty (); return 0; } @@ -571,12 +283,13 @@ IO::remove_output_port (Port* port, void* src) * @param type Data type of port. Default value (NIL) will use this IO's default type. */ int -IO::add_output_port (string destination, void* src, DataType type) +IO::add_port (string destination, void* src, DataType type) { Port* our_port; - if (type == DataType::NIL) + if (type == DataType::NIL) { type = _default_type; + } { BLOCK_PROCESS_CALLBACK (); @@ -587,19 +300,24 @@ IO::add_output_port (string destination, void* src, DataType type) /* Create a new output port */ - string portname = build_legal_port_name (type, false); - - if ((our_port = _session.engine().register_output_port (type, portname)) == 0) { - error << string_compose(_("IO: cannot register output port %1"), portname) << endmsg; - return -1; + string portname = build_legal_port_name (type); + + if (_direction == Input) { + if ((our_port = _session.engine().register_input_port (type, portname)) == 0) { + error << string_compose(_("IO: cannot register input port %1"), portname) << endmsg; + return -1; + } + } else { + if ((our_port = _session.engine().register_output_port (type, portname)) == 0) { + error << string_compose(_("IO: cannot register output port %1"), portname) << endmsg; + return -1; + } } - - _outputs.add (our_port); - setup_peak_meters (); - reset_panner (); + + _ports.add (our_port); } - PortCountChanged (n_outputs()); /* EMIT SIGNAL */ + PortCountChanged (n_ports()); /* EMIT SIGNAL */ } if (destination.length()) { @@ -609,433 +327,95 @@ IO::add_output_port (string destination, void* src, DataType type) } // pan_changed (src); /* EMIT SIGNAL */ - output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */ - setup_bundle_for_outputs (); + changed (ConfigurationChanged, src); /* EMIT SIGNAL */ + setup_bundles (); _session.set_dirty (); return 0; } int -IO::remove_input_port (Port* port, void* src) +IO::disconnect (void* src) { - IOChange change (NoChange); - - { + { BLOCK_PROCESS_CALLBACK (); - { Glib::Mutex::Lock lm (io_lock); - - if (_inputs.remove(port)) { - change = IOChange (change|ConfigurationChanged); - - if (port->connected()) { - change = IOChange (change|ConnectionsChanged); - } - - _session.engine().unregister_port (*port); - check_bundles_connected_to_inputs (); - - setup_peak_meters (); - reset_panner (); + + for (PortSet::iterator i = _ports.begin(); i != _ports.end(); ++i) { + i->disconnect_all (); } - } - - PortCountChanged (n_inputs ()); /* EMIT SIGNAL */ - } - if (change == ConfigurationChanged) { - setup_bundle_for_inputs (); + check_bundles_connected (); + } } - - if (change != NoChange) { - input_changed (change, src); - _session.set_dirty (); - return 0; - } - return -1; + changed (ConnectionsChanged, src); /* EMIT SIGNAL */ + + return 0; } - -/** Add an input port. - * - * @param type Data type of port. The appropriate port type, and @ref Port will be created. - * @param destination Name of input port to connect new port to. - * @param src Source for emitted ConfigurationChanged signal. - */ -int -IO::add_input_port (string source, void* src, DataType type) +bool +IO::ensure_ports_locked (ChanCount count, bool clear, void* src) { - Port* our_port; + Port* port = 0; + bool changed = false; - if (type == DataType::NIL) - type = _default_type; - - { - BLOCK_PROCESS_CALLBACK (); + for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) { - { - Glib::Mutex::Lock lm (io_lock); - - /* Create a new input port */ + const size_t n = count.get(*t); + + /* remove unused ports */ + for (size_t i = n_ports().get(*t); i > n; --i) { + port = _ports.port(*t, i-1); - string portname = build_legal_port_name (type, true); - - if ((our_port = _session.engine().register_input_port (type, portname)) == 0) { - error << string_compose(_("IO: cannot register input port %1"), portname) << endmsg; - return -1; - } + assert(port); + _ports.remove(port); + _session.engine().unregister_port (*port); - _inputs.add (our_port); - setup_peak_meters (); - reset_panner (); + changed = true; } - PortCountChanged (n_inputs()); /* EMIT SIGNAL */ - } - - if (source.length()) { + /* create any necessary new ports */ + while (n_ports().get(*t) < n) { - if (our_port->connect (source)) { - return -1; - } - } + string portname = build_legal_port_name (*t); - // pan_changed (src); /* EMIT SIGNAL */ - input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */ - setup_bundle_for_inputs (); - _session.set_dirty (); - - return 0; -} + try { -int -IO::disconnect_inputs (void* src) -{ - { - BLOCK_PROCESS_CALLBACK (); - - { - Glib::Mutex::Lock lm (io_lock); - - for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) { - i->disconnect_all (); - } - - check_bundles_connected_to_inputs (); - } - } - - input_changed (ConnectionsChanged, src); /* EMIT SIGNAL */ - - return 0; -} - -int -IO::disconnect_outputs (void* src) -{ - { - BLOCK_PROCESS_CALLBACK (); - - { - Glib::Mutex::Lock lm (io_lock); - - for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) { - i->disconnect_all (); - } - - check_bundles_connected_to_outputs (); - } - } - - output_changed (ConnectionsChanged, src); /* EMIT SIGNAL */ - _session.set_dirty (); - - return 0; -} - -bool -IO::ensure_inputs_locked (ChanCount count, bool clear, void* src) -{ - Port* input_port = 0; - bool changed = false; - - for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) { - - const size_t n = count.get(*t); - - /* remove unused ports */ - for (size_t i = n_inputs().get(*t); i > n; --i) { - input_port = _inputs.port(*t, i-1); - - assert(input_port); - _inputs.remove(input_port); - _session.engine().unregister_port (*input_port); - - changed = true; - } - - /* create any necessary new ports */ - while (n_inputs().get(*t) < n) { - - string portname = build_legal_port_name (*t, true); - - try { - - if ((input_port = _session.engine().register_input_port (*t, portname)) == 0) { - error << string_compose(_("IO: cannot register input port %1"), portname) << endmsg; - return -1; - } - } - - catch (AudioEngine::PortRegistrationFailure& err) { - setup_peak_meters (); - reset_panner (); - /* pass it on */ - throw AudioEngine::PortRegistrationFailure(); - } - - _inputs.add (input_port); - changed = true; - } - } - - if (changed) { - check_bundles_connected_to_inputs (); - setup_peak_meters (); - reset_panner (); - PortCountChanged (n_inputs()); /* EMIT SIGNAL */ - _session.set_dirty (); - } - - if (clear) { - /* disconnect all existing ports so that we get a fresh start */ - for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) { - i->disconnect_all (); - } - } - - return changed; -} - -int -IO::ensure_io (ChanCount in, ChanCount out, bool clear, void* src) -{ - bool in_changed = false; - bool out_changed = false; - - assert(in != ChanCount::INFINITE); - assert(out != ChanCount::INFINITE); - - if (in == n_inputs() && out == n_outputs() && !clear) { - return 0; - } - - { - BLOCK_PROCESS_CALLBACK (); - Glib::Mutex::Lock lm (io_lock); - - Port* port; - - for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) { - - const size_t nin = in.get(*t); - const size_t nout = out.get(*t); - - Port* output_port = 0; - Port* input_port = 0; - - /* remove unused output ports */ - for (size_t i = n_outputs().get(*t); i > nout; --i) { - output_port = _outputs.port(*t, i-1); - - assert(output_port); - _outputs.remove(output_port); - _session.engine().unregister_port (*output_port); - - out_changed = true; - } - - /* remove unused input ports */ - for (size_t i = n_inputs().get(*t); i > nin; --i) { - input_port = _inputs.port(*t, i-1); - - assert(input_port); - _inputs.remove(input_port); - _session.engine().unregister_port (*input_port); - - in_changed = true; - } - - /* create any necessary new input ports */ - while (n_inputs().get(*t) < nin) { - string portname = build_legal_port_name (*t, true); - - try { + if (_direction == Input) { if ((port = _session.engine().register_input_port (*t, portname)) == 0) { error << string_compose(_("IO: cannot register input port %1"), portname) << endmsg; return -1; } - } - - catch (AudioEngine::PortRegistrationFailure& err) { - setup_peak_meters (); - reset_panner (); - /* pass it on */ - throw err; - } - - _inputs.add (port); - in_changed = true; - } - - /* create any necessary new output ports */ - - while (n_outputs().get(*t) < nout) { - - string portname = build_legal_port_name (*t, false); - - try { + } else { if ((port = _session.engine().register_output_port (*t, portname)) == 0) { error << string_compose(_("IO: cannot register output port %1"), portname) << endmsg; return -1; } } - - catch (AudioEngine::PortRegistrationFailure& err) { - setup_peak_meters (); - reset_panner (); - /* pass it on */ - throw err; - } - - _outputs.add (port); - out_changed = true; - } - } - - if (clear) { - - /* disconnect all existing ports so that we get a fresh start */ - - for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) { - i->disconnect_all (); } - - for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) { - i->disconnect_all (); - } - } - - if (in_changed || out_changed) { - setup_peak_meters (); - reset_panner (); - } - } - - if (out_changed) { - check_bundles_connected_to_outputs (); - output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */ - setup_bundle_for_outputs (); - } - - if (in_changed) { - check_bundles_connected_to_inputs (); - input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */ - setup_bundle_for_inputs (); - } - - if (in_changed || out_changed) { - PortCountChanged (max (n_outputs(), n_inputs())); /* EMIT SIGNAL */ - _session.set_dirty (); - } - - return 0; -} - -int -IO::ensure_inputs (ChanCount count, bool clear, bool lockit, void* src) -{ - bool changed = false; - - if (count == n_inputs() && !clear) { - return 0; - } - if (lockit) { - BLOCK_PROCESS_CALLBACK (); - Glib::Mutex::Lock im (io_lock); - changed = ensure_inputs_locked (count, clear, src); - } else { - changed = ensure_inputs_locked (count, clear, src); - } - - if (changed) { - input_changed (ConfigurationChanged, src); /* EMIT SIGNAL */ - setup_bundle_for_inputs (); - _session.set_dirty (); - } - return 0; -} - -bool -IO::ensure_outputs_locked (ChanCount count, bool clear, void* src) -{ - Port* output_port = 0; - bool changed = false; - bool need_pan_reset = false; - - if (n_outputs() != count) { - need_pan_reset = true; - } - - for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) { - - const size_t n = count.get(*t); - - /* remove unused ports */ - for (size_t i = n_outputs().get(*t); i > n; --i) { - output_port = _outputs.port(*t, i-1); - - assert(output_port); - _outputs.remove(output_port); - _session.engine().unregister_port (*output_port); - - changed = true; - } - - /* create any necessary new ports */ - while (n_outputs().get(*t) < n) { - - string portname = build_legal_port_name (*t, false); - - if ((output_port = _session.engine().register_output_port (*t, portname)) == 0) { - error << string_compose(_("IO: cannot register output port %1"), portname) << endmsg; - return -1; + catch (AudioEngine::PortRegistrationFailure& err) { + /* pass it on */ + throw AudioEngine::PortRegistrationFailure(); } - _outputs.add (output_port); + _ports.add (port); changed = true; - setup_peak_meters (); - - if (need_pan_reset) { - reset_panner (); - } } } if (changed) { - check_bundles_connected_to_outputs (); - PortCountChanged (n_outputs()); /* EMIT SIGNAL */ + check_bundles_connected (); + PortCountChanged (n_ports()); /* EMIT SIGNAL */ _session.set_dirty (); } if (clear) { /* disconnect all existing ports so that we get a fresh start */ - for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) { + for (PortSet::iterator i = _ports.begin(); i != _ports.end(); ++i) { i->disconnect_all (); } } @@ -1043,71 +423,45 @@ IO::ensure_outputs_locked (ChanCount count, bool clear, void* src) return changed; } + int -IO::ensure_outputs (ChanCount count, bool clear, bool lockit, void* src) +IO::ensure_ports (ChanCount count, bool clear, bool lockit, void* src) { bool changed = false; - /* XXX caller should hold io_lock, but generally doesn't */ + cerr << "Ensure that IO " << _name << '/' << (_direction == Input ? "input" : "output") + << " has " << count << endl; + + if (count == n_ports() && !clear) { + cerr << "\talready has " << n_ports() << endl; + return 0; + } if (lockit) { BLOCK_PROCESS_CALLBACK (); Glib::Mutex::Lock im (io_lock); - changed = ensure_outputs_locked (count, clear, src); + changed = ensure_ports_locked (count, clear, src); } else { - changed = ensure_outputs_locked (count, clear, src); + changed = ensure_ports_locked (count, clear, src); } if (changed) { - output_changed (ConfigurationChanged, src); /* EMIT SIGNAL */ - setup_bundle_for_outputs (); + this->changed (ConfigurationChanged, src); /* EMIT SIGNAL */ + setup_bundles (); + _session.set_dirty (); } + cerr << "\t@" << this << " established with " << n_ports() << endl; + return 0; } -gain_t -IO::effective_gain () const -{ - return _gain_control->get_value(); -} - -void -IO::reset_panner () -{ - if (panners_legal) { - if (!no_panner_reset) { - _panner->reset (n_outputs().n_audio(), pans_required()); - } - } else { - panner_legal_c.disconnect (); - panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal)); - } -} - int -IO::panners_became_legal () -{ - _panner->reset (n_outputs().n_audio(), pans_required()); - _panner->load (); // automation - panner_legal_c.disconnect (); - return 0; -} - -void -IO::defer_pan_reset () -{ - no_panner_reset = true; -} - -void -IO::allow_pan_reset () +IO::ensure_io (ChanCount count, bool clear, void* src) { - no_panner_reset = false; - reset_panner (); + return ensure_ports (count, clear, true, src); } - XMLNode& IO::get_state (void) { @@ -1128,44 +482,26 @@ IO::state (bool full_state) node->add_property("name", _name); id().print (buf, sizeof (buf)); node->add_property("id", buf); + node->add_property ("direction", enum_2_string (_direction)); + node->add_property ("default-type", _default_type.to_string()); - for ( - std::vector::iterator i = _bundles_connected_to_inputs.begin(); - i != _bundles_connected_to_inputs.end(); - ++i - ) - { - XMLNode* n = new XMLNode ("InputBundle"); - n->add_property ("name", i->bundle->name ()); - node->add_child_nocopy (*n); - } - - for ( - std::vector::iterator i = _bundles_connected_to_outputs.begin(); - i != _bundles_connected_to_outputs.end(); - ++i - ) - { - XMLNode* n = new XMLNode ("OutputBundle"); + for (std::vector::iterator i = _bundles_connected.begin(); i != _bundles_connected.end(); ++i) { + XMLNode* n = new XMLNode ("Bundle"); n->add_property ("name", i->bundle->name ()); node->add_child_nocopy (*n); } - - str = ""; - for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) { - + for (PortSet::iterator i = _ports.begin(); i != _ports.end(); ++i) { + vector connections; + XMLNode* pnode = new XMLNode (X_("port")); + pnode->add_property (X_("type"), i->type().to_string()); + if (i->get_connections (connections)) { - str += '{'; - for (n = 0, ci = connections.begin(); ci != connections.end(); ++ci, ++n) { - if (n) { - str += ','; - } - + /* if its a connection to our own port, return only the port name, not the whole thing. this allows connections @@ -1173,60 +509,12 @@ IO::state (bool full_state) client name is different. */ - str += _session.engine().make_port_name_relative (*ci); + pnode->add_property (X_("connection"), _session.engine().make_port_name_relative (*ci)); } - - str += '}'; - - } else { - str += "{}"; } - } - - node->add_property ("inputs", str); - - str = ""; - - for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) { - vector connections; - - if (i->get_connections (connections)) { - - str += '{'; - - for (n = 0, ci = connections.begin(); ci != connections.end(); ++ci, ++n) { - if (n) { - str += ','; - } - - str += _session.engine().make_port_name_relative (*ci); - } - - str += '}'; - - } else { - str += "{}"; - } + node->add_child_nocopy (*pnode); } - - node->add_property ("outputs", str); - - node->add_child_nocopy (_panner->state (full_state)); - node->add_child_nocopy (_gain_control->get_state ()); - - snprintf (buf, sizeof(buf), "%2.12f", gain()); - node->add_property ("gain", buf); - - /* port counts */ - - node->add_child_nocopy(*n_inputs().state("Inputs")); - node->add_child_nocopy(*n_outputs().state("Outputs")); - - /* automation */ - - if (full_state) - node->add_child_nocopy (get_automation_state()); return *node; } @@ -1246,79 +534,34 @@ IO::set_state (const XMLNode& node) error << string_compose(_("incorrect XML node \"%1\" passed to IO object"), node.name()) << endmsg; return -1; } - + if ((prop = node.property ("name")) != 0) { - _name = prop->value(); - /* used to set panner name with this, but no more */ + set_name (prop->value()); } - if ((prop = node.property ("id")) != 0) { - _id = prop->value (); - } - - if ((prop = node.property ("gain")) != 0) { - set_gain (atof (prop->value().c_str()), this); - _gain = _gain_control->user_float(); - } - - if ((prop = node.property ("automation-state")) != 0 || (prop = node.property ("automation-style")) != 0) { - /* old school automation handling */ + if ((prop = node.property (X_("default-type"))) != 0) { + _default_type = DataType(prop->value()); + assert(_default_type != DataType::NIL); } - for (iter = node.children().begin(); iter != node.children().end(); ++iter) { - - // Old school Panner. - if ((*iter)->name() == "Panner") { - if (!_panner) { - _panner = boost::shared_ptr(new Panner (_name, _session)); - } - _panner->set_state (**iter); - } - - if ((*iter)->name() == "Processor") { - if ((*iter)->property ("type") && ((*iter)->property ("type")->value() == "panner" ) ) { - if (!_panner) { - _panner = boost::shared_ptr(new Panner (_name, _session)); - } - _panner->set_state (**iter); - } - } - - if ((*iter)->name() == X_("Automation")) { - - set_automation_state (*(*iter), Evoral::Parameter(GainAutomation)); - } - - if ((*iter)->name() == X_("Controllable")) { - if ((prop = (*iter)->property("name")) != 0 && prop->value() == "gaincontrol") { - _gain_control->set_state (**iter); - } - } + if ((prop = node.property ("id")) != 0) { + _id = prop->value (); } - if (ports_legal) { - - if (create_ports (node)) { - return -1; - } - - } else { - - port_legal_c = PortsLegal.connect (mem_fun (*this, &IO::ports_became_legal)); + if ((prop = node.property ("direction")) != 0) { + _direction = (Direction) string_2_enum (prop->value(), _direction); } - if (!_panner) { - _panner = boost::shared_ptr(new Panner (_name, _session)); - } + if (!connecting_legal) { + pending_state_node = new XMLNode (node); + } - if (panners_legal) { - reset_panner (); - } else { - panner_legal_c = PannersLegal.connect (mem_fun (*this, &IO::panners_became_legal)); + if (create_ports (node)) { + return -1; } if (connecting_legal) { - + if (make_connections (node)) { return -1; } @@ -1328,83 +571,6 @@ IO::set_state (const XMLNode& node) connection_legal_c = ConnectingLegal.connect (mem_fun (*this, &IO::connecting_became_legal)); } - if (!ports_legal || !connecting_legal) { - pending_state_node = new XMLNode (node); - } - - return 0; -} - -int -IO::load_automation (string path) -{ - string fullpath; - ifstream in; - char line[128]; - uint32_t linecnt = 0; - float version; - LocaleGuard lg (X_("POSIX")); - - fullpath = Glib::build_filename(_session.automation_dir(), path); - - in.open (fullpath.c_str()); - - if (!in) { - fullpath = Glib::build_filename(_session.automation_dir(), _session.snap_name() + '-' + path); - - in.open (fullpath.c_str()); - - if (!in) { - error << string_compose(_("%1: cannot open automation event file \"%2\""), _name, fullpath) << endmsg; - return -1; - } - } - - clear_automation (); - - while (in.getline (line, sizeof(line), '\n')) { - char type; - nframes_t when; - double value; - - if (++linecnt == 1) { - if (memcmp (line, "version", 7) == 0) { - if (sscanf (line, "version %f", &version) != 1) { - error << string_compose(_("badly formed version number in automation event file \"%1\""), path) << endmsg; - return -1; - } - } else { - error << string_compose(_("no version information in automation event file \"%1\""), path) << endmsg; - return -1; - } - - continue; - } - - if (sscanf (line, "%c %" PRIu32 " %lf", &type, &when, &value) != 3) { - warning << string_compose(_("badly formatted automation event record at line %1 of %2 (ignored)"), linecnt, path) << endmsg; - continue; - } - - switch (type) { - case 'g': - _gain_control->list()->fast_simple_add (when, value); - break; - - case 's': - break; - - case 'm': - break; - - case 'p': - /* older (pre-1.0) versions of ardour used this */ - break; - - default: - warning << _("dubious automation event found (and ignored)") << endmsg; - } - } return 0; } @@ -1414,51 +580,25 @@ IO::connecting_became_legal () { int ret; - if (pending_state_node == 0) { - fatal << _("IO::connecting_became_legal() called without a pending state node") << endmsg; - /*NOTREACHED*/ - return -1; - } + assert (pending_state_node); connection_legal_c.disconnect (); ret = make_connections (*pending_state_node); - - if (ports_legal) { - delete pending_state_node; - pending_state_node = 0; - } - - return ret; -} -int -IO::ports_became_legal () -{ - int ret; - - if (pending_state_node == 0) { - fatal << _("IO::ports_became_legal() called without a pending state node") << endmsg; - /*NOTREACHED*/ - return -1; - } - - port_legal_c.disconnect (); - - ret = create_ports (*pending_state_node); - - if (connecting_legal) { - delete pending_state_node; - pending_state_node = 0; - } + + delete pending_state_node; + pending_state_node = 0; return ret; } boost::shared_ptr -IO::find_possible_bundle (const string &desired_name, const string &default_name, const string &bundle_type_name) +IO::find_possible_bundle (const string &desired_name) { static const string digits = "0123456789"; - + const string &default_name = (_direction == Input ? _("in") : _("out")); + const string &bundle_type_name = (_direction == Input ? _("input") : _("output")); + boost::shared_ptr c = _session.bundle_by_name (desired_name); if (!c) { @@ -1547,77 +687,71 @@ IO::find_possible_bundle (const string &desired_name, const string &default_name } int -IO::get_port_counts (const XMLNode& node, ChanCount& in, ChanCount& out, - boost::shared_ptr& ic, boost::shared_ptr& oc) +IO::get_port_counts (const XMLNode& node, ChanCount& n, boost::shared_ptr& c) { XMLProperty const * prop; XMLNodeConstIterator iter; + uint32_t n_audio = 0; + uint32_t n_midi = 0; + ChanCount cnt; - in = n_inputs(); - out = n_outputs(); + n = n_ports(); - for (iter = node.children().begin(); iter != node.children().end(); ++iter) { - if ((*iter)->name() == X_("Inputs")) { - in = ChanCount::max(in, ChanCount(**iter)); - } else if ((*iter)->name() == X_("Outputs")) { - out = ChanCount::max(out, ChanCount(**iter)); + if ((prop = node.property ("connection")) != 0) { + + if ((c = find_possible_bundle (prop->value())) != 0) { + n = ChanCount::max (n, ChanCount(c->type(), c->nchannels())); } + return 0; } + + for (iter = node.children().begin(); iter != node.children().end(); ++iter) { - if ((prop = node.property ("input-connection")) != 0) { - - ic = find_possible_bundle (prop->value(), _("in"), _("input")); - if (ic) { - in = ChanCount::max(in, ChanCount(ic->type(), ic->nchannels())); + if ((*iter)->name() == X_("Bundle")) { + if ((c = find_possible_bundle (prop->value())) != 0) { + n = ChanCount::max (n, ChanCount(c->type(), c->nchannels())); + return 0; + } else { + return -1; + } } - } else if ((prop = node.property ("inputs")) != 0) { + if ((*iter)->name() == X_("port")) { + prop = (*iter)->property (X_("type")); - in = ChanCount::max(in, ChanCount(_default_type, - count (prop->value().begin(), prop->value().end(), '{'))); - } - - if ((prop = node.property ("output-connection")) != 0) { - - oc = find_possible_bundle (prop->value(), _("out"), _("output")); - if (oc) { - out = ChanCount::max(out, ChanCount(oc->type(), oc->nchannels())); + if (!prop) { + continue; + } + + if (prop->value() == X_("audio")) { + cnt.set_audio (++n_audio); + } else if (prop->value() == X_("midi")) { + cnt.set_midi (++n_midi); + } } - - } else if ((prop = node.property ("outputs")) != 0) { - - out = ChanCount::max(out, ChanCount(_default_type, - count (prop->value().begin(), prop->value().end(), '{'))); } + n = ChanCount::max (n, cnt); return 0; } int IO::create_ports (const XMLNode& node) { - if (pending_state_node) { + ChanCount n; + boost::shared_ptr c; + + get_port_counts (node, n, c); + + cerr << _name << " got " << n << " from XML node" << endl; - ChanCount in; - ChanCount out; - boost::shared_ptr ic; - boost::shared_ptr oc; - - no_panner_reset = true; - - get_port_counts (*pending_state_node, in, out, ic, oc); - - if (ensure_io (in, out, true, this)) { - error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg; - return -1; - } - - /* XXX use ic and oc if relevant */ - - no_panner_reset = false; + if (ensure_ports (n, true, true, this)) { + error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg; + return -1; } - set_deferred_state (); + /* XXX use c */ + return 0; } @@ -1626,60 +760,41 @@ IO::make_connections (const XMLNode& node) { const XMLProperty* prop; - if ((prop = node.property ("input-connection")) != 0) { - boost::shared_ptr c = find_possible_bundle (prop->value(), _("in"), _("input")); + if ((prop = node.property ("connection")) != 0) { + boost::shared_ptr c = find_possible_bundle (prop->value()); if (!c) { return -1; } - if (n_inputs().get(c->type()) == c->nchannels() && c->ports_are_outputs()) { - connect_input_ports_to_bundle (c, this); - } - - } else if ((prop = node.property ("inputs")) != 0) { - if (set_inputs (prop->value())) { - error << string_compose(_("improper input channel list in XML node (%1)"), prop->value()) << endmsg; - return -1; + if (n_ports().get(c->type()) == c->nchannels() && c->ports_are_outputs()) { + connect_ports_to_bundle (c, this); } - } - if ((prop = node.property ("output-connection")) != 0) { - boost::shared_ptr c = find_possible_bundle (prop->value(), _("out"), _("output")); - - if (!c) { - return -1; - } - - if (n_outputs().get(c->type()) == c->nchannels() && c->ports_are_inputs()) { - connect_output_ports_to_bundle (c, this); - } + return 0; + } - } else if ((prop = node.property ("outputs")) != 0) { - if (set_outputs (prop->value())) { - error << string_compose(_("improper output channel list in XML node (%1)"), prop->value()) << endmsg; - return -1; - } - } + uint32_t n = 0; for (XMLNodeConstIterator i = node.children().begin(); i != node.children().end(); ++i) { - if ((*i)->name() == "InputBundle") { + if ((*i)->name() == "Bundle") { XMLProperty const * prop = (*i)->property ("name"); if (prop) { - boost::shared_ptr b = find_possible_bundle (prop->value(), _("in"), _("input")); + boost::shared_ptr b = find_possible_bundle (prop->value()); if (b) { - connect_input_ports_to_bundle (b, this); + connect_ports_to_bundle (b, this); } } - - } else if ((*i)->name() == "OutputBundle") { - XMLProperty const * prop = (*i)->property ("name"); - if (prop) { - boost::shared_ptr b = find_possible_bundle (prop->value(), _("out"), _("output")); - if (b) { - connect_output_ports_to_bundle (b, this); - } + + return 0; + } + + if ((*i)->name() == "port") { + Port* p = nth (n++); + XMLProperty* prop = (*i)->property ("connection"); + if (p && prop) { + p->connect (prop->value()); } } } @@ -1688,7 +803,7 @@ IO::make_connections (const XMLNode& node) } int -IO::set_inputs (const string& str) +IO::set_ports (const string& str) { vector ports; int i; @@ -1700,7 +815,7 @@ IO::set_inputs (const string& str) } // FIXME: audio-only - if (ensure_inputs (ChanCount(DataType::AUDIO, nports), true, true, this)) { + if (ensure_ports (ChanCount(DataType::AUDIO, nports), true, true, this)) { return -1; } @@ -1727,58 +842,7 @@ IO::set_inputs (const string& str) } else if (n > 0) { for (int x = 0; x < n; ++x) { - connect_input (input (i), ports[x], this); - } - } - - ostart = end+1; - i++; - } - - return 0; -} - -int -IO::set_outputs (const string& str) -{ - vector ports; - int i; - int n; - uint32_t nports; - - if ((nports = count (str.begin(), str.end(), '{')) == 0) { - return 0; - } - - // FIXME: audio-only - need a way to identify port types from XML/string - if (ensure_outputs (ChanCount(DataType::AUDIO, nports), true, true, this)) { - return -1; - } - - string::size_type start, end, ostart; - - ostart = 0; - start = 0; - end = 0; - i = 0; - - while ((start = str.find_first_of ('{', ostart)) != string::npos) { - start += 1; - - if ((end = str.find_first_of ('}', start)) == string::npos) { - error << string_compose(_("IO: badly formed string in XML node for outputs \"%1\""), str) << endmsg; - return -1; - } - - if ((n = parse_io_string (str.substr (start, end - start), ports)) < 0) { - error << string_compose(_("IO: bad output string in XML node \"%1\""), str) << endmsg; - - return -1; - - } else if (n > 0) { - - for (int x = 0; x < n; ++x) { - connect_output (output (i), ports[x], this); + connect (nth (i), ports[x], this); } } @@ -1858,13 +922,7 @@ IO::set_name (const string& requested_name) warning << _("you cannot use colons to name objects with I/O connections") << endmsg; } - for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) { - string current_name = i->name(); - current_name.replace (current_name.find (_name), _name.length(), name); - i->set_name (current_name); - } - - for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) { + for (PortSet::iterator i = _ports.begin(); i != _ports.end(); ++i) { string current_name = i->name(); current_name.replace (current_name.find (_name), _name.length(), name); i->set_name (current_name); @@ -1872,7 +930,7 @@ IO::set_name (const string& requested_name) bool const r = SessionObject::set_name(name); - setup_bundles_for_inputs_and_outputs (); + setup_bundles (); return r; } @@ -1882,32 +940,13 @@ IO::set_port_latency (nframes_t nframes) { Glib::Mutex::Lock lm (io_lock); - for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) { + for (PortSet::iterator i = _ports.begin(); i != _ports.end(); ++i) { i->set_latency (nframes); } } nframes_t -IO::output_latency () const -{ - nframes_t max_latency; - nframes_t latency; - - max_latency = 0; - - /* io lock not taken - must be protected by other means */ - - for (PortSet::const_iterator i = _outputs.begin(); i != _outputs.end(); ++i) { - if ((latency = i->total_latency ()) > max_latency) { - max_latency = latency; - } - } - - return max_latency; -} - -nframes_t -IO::input_latency () const +IO::latency () const { nframes_t max_latency; nframes_t latency; @@ -1916,7 +955,7 @@ IO::input_latency () const /* io lock not taken - must be protected by other means */ - for (PortSet::const_iterator i = _inputs.begin(); i != _inputs.end(); ++i) { + for (PortSet::const_iterator i = _ports.begin(); i != _ports.end(); ++i) { if ((latency = i->total_latency ()) > max_latency) { max_latency = latency; } @@ -1925,371 +964,101 @@ IO::input_latency () const return max_latency; } -int -IO::connect_input_ports_to_bundle (boost::shared_ptr c, void* src) -{ - { - BLOCK_PROCESS_CALLBACK (); - Glib::Mutex::Lock lm2 (io_lock); - - c->connect (_bundle_for_inputs, _session.engine()); - - /* If this is a UserBundle, make a note of what we've done */ - - boost::shared_ptr ub = boost::dynamic_pointer_cast (c); - if (ub) { - - /* See if we already know about this one */ - std::vector::iterator i = _bundles_connected_to_inputs.begin(); - while (i != _bundles_connected_to_inputs.end() && i->bundle != ub) { - ++i; - } - - if (i == _bundles_connected_to_inputs.end()) { - /* We don't, so make a note */ - _bundles_connected_to_inputs.push_back (UserBundleInfo (this, ub)); - } - } - } - - input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */ - return 0; -} - -int -IO::disconnect_input_ports_from_bundle (boost::shared_ptr c, void* src) -{ - { - BLOCK_PROCESS_CALLBACK (); - Glib::Mutex::Lock lm2 (io_lock); - - c->disconnect (_bundle_for_inputs, _session.engine()); - - /* If this is a UserBundle, make a note of what we've done */ - - boost::shared_ptr ub = boost::dynamic_pointer_cast (c); - if (ub) { - - std::vector::iterator i = _bundles_connected_to_inputs.begin(); - while (i != _bundles_connected_to_inputs.end() && i->bundle != ub) { - ++i; - } - - if (i != _bundles_connected_to_inputs.end()) { - _bundles_connected_to_inputs.erase (i); - } - } - } - - input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */ - return 0; -} - -int -IO::connect_output_ports_to_bundle (boost::shared_ptr c, void* src) -{ - { - BLOCK_PROCESS_CALLBACK (); - Glib::Mutex::Lock lm2 (io_lock); - - c->connect (_bundle_for_outputs, _session.engine()); - - /* If this is a UserBundle, make a note of what we've done */ - - boost::shared_ptr ub = boost::dynamic_pointer_cast (c); - if (ub) { - - /* See if we already know about this one */ - std::vector::iterator i = _bundles_connected_to_outputs.begin(); - while (i != _bundles_connected_to_outputs.end() && i->bundle != ub) { - ++i; - } - - if (i == _bundles_connected_to_outputs.end()) { - /* We don't, so make a note */ - _bundles_connected_to_outputs.push_back (UserBundleInfo (this, ub)); - } - } - } - - output_changed (IOChange (ConnectionsChanged|ConfigurationChanged), src); /* EMIT SIGNAL */ - - return 0; -} - -int -IO::disconnect_output_ports_from_bundle (boost::shared_ptr c, void* src) -{ - { - BLOCK_PROCESS_CALLBACK (); - Glib::Mutex::Lock lm2 (io_lock); - - c->disconnect (_bundle_for_outputs, _session.engine()); - - /* If this is a UserBundle, make a note of what we've done */ - - boost::shared_ptr ub = boost::dynamic_pointer_cast (c); - if (ub) { - - std::vector::iterator i = _bundles_connected_to_outputs.begin(); - while (i != _bundles_connected_to_outputs.end() && i->bundle != ub) { - ++i; - } - - if (i != _bundles_connected_to_outputs.end()) { - _bundles_connected_to_outputs.erase (i); - } - } - } - - output_changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */ - return 0; -} - - -int -IO::disable_connecting () -{ - connecting_legal = false; - return 0; -} - -int -IO::enable_connecting () -{ - connecting_legal = true; - return ConnectingLegal (); -} - -int -IO::disable_ports () -{ - ports_legal = false; - return 0; -} - -int -IO::enable_ports () -{ - ports_legal = true; - return PortsLegal (); -} - -int -IO::disable_panners (void) -{ - panners_legal = false; - return 0; -} - -int -IO::reset_panners () -{ - panners_legal = true; - return PannersLegal (); -} - -void -IO::bundle_changed (Bundle::Change c) -{ - //XXX -// connect_input_ports_to_bundle (_input_bundle, this); -} - void -IO::GainControl::set_value (float val) -{ - // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05)) - if (val > 1.99526231f) - val = 1.99526231f; - - _io->set_gain (val, this); - - AutomationControl::set_value(val); -} - -float -IO::GainControl::get_value (void) const -{ - return AutomationControl::get_value(); -} - -void -IO::setup_peak_meters() -{ - ChanCount max_streams = std::max (_inputs.count(), _outputs.count()); - _meter->configure_io (max_streams, max_streams); -} - -/** - Update the peak 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 -IO::update_meters() -{ - Glib::Mutex::Lock guard (m_meter_signal_lock); - Meter(); /* EMIT SIGNAL */ -} - -void -IO::meter () -{ - // FIXME: Ugly. Meter should manage the lock, if it's necessary - - Glib::Mutex::Lock lm (io_lock); // READER: meter thread. - _meter->meter(); -} - -void -IO::clear_automation () -{ - data().clear_controls (); // clears gain automation - _panner->data().clear_controls (); -} - -void -IO::set_parameter_automation_state (Evoral::Parameter param, AutoState state) +IO::update_port_total_latencies () { - // XXX: would be nice to get rid of this special hack + /* io_lock, not taken: function must be called from Session::process() calltree */ - if (param.type() == GainAutomation) { + for (PortSet::iterator i = _ports.begin(); i != _ports.end(); ++i) { + _session.engine().update_total_latency (*i); + } +} - bool changed = false; +int +IO::connect_ports_to_bundle (boost::shared_ptr c, void* src) +{ + { + BLOCK_PROCESS_CALLBACK (); + Glib::Mutex::Lock lm2 (io_lock); - { - Glib::Mutex::Lock lm (control_lock()); + c->connect (_bundle, _session.engine()); - boost::shared_ptr gain_auto - = boost::dynamic_pointer_cast(_gain_control->list()); + /* If this is a UserBundle, make a note of what we've done */ - if (state != gain_auto->automation_state()) { - changed = true; - _last_automation_snapshot = 0; - gain_auto->set_automation_state (state); + boost::shared_ptr ub = boost::dynamic_pointer_cast (c); + if (ub) { - if (state != Off) { - // FIXME: shouldn't this use Curve? - set_gain (gain_auto->eval (_session.transport_frame()), this); - } + /* See if we already know about this one */ + std::vector::iterator i = _bundles_connected.begin(); + while (i != _bundles_connected.end() && i->bundle != ub) { + ++i; } - } - if (changed) { - _session.set_dirty (); + if (i == _bundles_connected.end()) { + /* We don't, so make a note */ + _bundles_connected.push_back (UserBundleInfo (this, ub)); + } } - - } else { - AutomatableControls::set_parameter_automation_state(param, state); } -} -void -IO::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); - } + changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */ + return 0; } -void -IO::set_gain (gain_t val, void *src) +int +IO::disconnect_ports_from_bundle (boost::shared_ptr c, void* src) { - // max gain at about +6dB (10.0 ^ ( 6 dB * 0.05)) - if (val > 1.99526231f) { - val = 1.99526231f; - } + { + BLOCK_PROCESS_CALLBACK (); + Glib::Mutex::Lock lm2 (io_lock); - //cerr << "set desired gain to " << val << " when curgain = " << _gain_control->get_value () << endl; + c->disconnect (_bundle, _session.engine()); + + /* If this is a UserBundle, make a note of what we've done */ - 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; - } + boost::shared_ptr ub = boost::dynamic_pointer_cast (c); + if (ub) { - { - Glib::Mutex::Lock dm (declick_lock); - _gain_control->set_float(val, false); - } + std::vector::iterator i = _bundles_connected.begin(); + while (i != _bundles_connected.end() && i->bundle != ub) { + ++i; + } - 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); - + if (i != _bundles_connected.end()) { + _bundles_connected.erase (i); + } + } } - */ - _session.set_dirty(); + changed (IOChange (ConfigurationChanged|ConnectionsChanged), src); /* EMIT SIGNAL */ + return 0; } -void -IO::start_pan_touch (uint32_t which) -{ - if (which < _panner->npanners()) { - (*_panner).pan_control(which)->start_touch(); - } -} -void -IO::end_pan_touch (uint32_t which) +int +IO::disable_connecting () { - if (which < _panner->npanners()) { - (*_panner).pan_control(which)->stop_touch(); - } - + connecting_legal = false; + return 0; } -void -IO::automation_snapshot (nframes_t now, bool force) +int +IO::enable_connecting () { - AutomatableControls::automation_snapshot (now, force); - // XXX: This seems to be wrong. - // drobilla: shouldnt automation_snapshot for panner be called - // "automagically" because its an Automatable now ? - // - // we could dump this whole method then. <3 - - if (_last_automation_snapshot > now || (now - _last_automation_snapshot) > _automation_interval) { - _panner->automation_snapshot (now, force); - } - - _panner->automation_snapshot (now, force); - _last_automation_snapshot = now; + connecting_legal = true; + return ConnectingLegal (); } void -IO::transport_stopped (nframes_t frame) +IO::bundle_changed (Bundle::Change c) { - _gain_control->list()->reposition_for_rt_add (frame); - - if (_gain_control->automation_state() != Off) { - - /* the src=0 condition is a special signal to not propagate - automation gain changes into the mix group when locating. - */ - - // FIXME: shouldn't this use Curve? - set_gain (_gain_control->list()->eval (frame), 0); - } - - _panner->transport_stopped (frame); + //XXX +// connect_input_ports_to_bundle (_input_bundle, this); } + string -IO::build_legal_port_name (DataType type, bool in) +IO::build_legal_port_name (DataType type) { const int name_size = jack_port_name_size(); int limit; @@ -2303,7 +1072,7 @@ IO::build_legal_port_name (DataType type, bool in) throw unknown_type(); } - if (in) { + if (_direction == Input) { suffix += _("_in"); } else { suffix += _("_out"); @@ -2318,60 +1087,20 @@ IO::build_legal_port_name (DataType type, bool in) snprintf (buf1, name_size+1, ("%.*s/%s"), limit, _name.c_str(), suffix.c_str()); - int port_number; - - if (in) { - port_number = find_input_port_hole (buf1); - } else { - port_number = find_output_port_hole (buf1); - } - + int port_number = find_port_hole (buf1); snprintf (buf2, name_size+1, "%s %d", buf1, port_number); return string (buf2); } int32_t -IO::find_input_port_hole (const char* base) -{ - /* CALLER MUST HOLD IO LOCK */ - - uint32_t n; - - if (_inputs.empty()) { - return 1; - } - - /* we only allow up to 4 characters for the port number - */ - - for (n = 1; n < 9999; ++n) { - char buf[jack_port_name_size()]; - PortSet::iterator i = _inputs.begin(); - - snprintf (buf, jack_port_name_size(), _("%s %u"), base, n); - - for ( ; i != _inputs.end(); ++i) { - if (i->name() == buf) { - break; - } - } - - if (i == _inputs.end()) { - break; - } - } - return n; -} - -int32_t -IO::find_output_port_hole (const char* base) +IO::find_port_hole (const char* base) { /* CALLER MUST HOLD IO LOCK */ uint32_t n; - if (_outputs.empty()) { + if (_ports.empty()) { return 1; } @@ -2380,213 +1109,109 @@ IO::find_output_port_hole (const char* base) for (n = 1; n < 9999; ++n) { char buf[jack_port_name_size()]; - PortSet::iterator i = _outputs.begin(); + PortSet::iterator i = _ports.begin(); snprintf (buf, jack_port_name_size(), _("%s %u"), base, n); - for ( ; i != _outputs.end(); ++i) { + for ( ; i != _ports.end(); ++i) { if (i->name() == buf) { break; } } - if (i == _outputs.end()) { + if (i == _ports.end()) { break; } } - return n; } -void -IO::set_active (bool yn) -{ - _active = yn; - active_changed(); /* EMIT SIGNAL */ -} - -AudioPort* -IO::audio_input(uint32_t n) const -{ - return dynamic_cast(input(n)); -} AudioPort* -IO::audio_output(uint32_t n) const +IO::audio(uint32_t n) const { - return dynamic_cast(output(n)); -} + return _ports.nth_audio_port (n); -MidiPort* -IO::midi_input(uint32_t n) const -{ - return dynamic_cast(input(n)); } MidiPort* -IO::midi_output(uint32_t n) const -{ - return dynamic_cast(output(n)); -} - -void -IO::set_phase_invert (bool yn, void *src) -{ - if (_phase_invert != yn) { - _phase_invert = yn; - // phase_invert_changed (src); /* EMIT SIGNAL */ - } -} - -void -IO::set_denormal_protection (bool yn, void *src) -{ - if (_denormal_protection != yn) { - _denormal_protection = yn; - // denormal_protection_changed (src); /* EMIT SIGNAL */ - } -} - -void -IO::update_port_total_latencies () +IO::midi(uint32_t n) const { - /* io_lock, not taken: function must be called from Session::process() calltree */ - - for (PortSet::iterator i = _inputs.begin(); i != _inputs.end(); ++i) { - _session.engine().update_total_latency (*i); - } - - for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) { - _session.engine().update_total_latency (*i); - } + return _ports.nth_midi_port (n); } - /** * Setup bundles that describe our inputs and outputs. Also creates bundles if necessary. */ void -IO::setup_bundles_for_inputs_and_outputs () -{ - setup_bundle_for_inputs (); - setup_bundle_for_outputs (); -} - - -void -IO::setup_bundle_for_inputs () +IO::setup_bundles () { char buf[32]; - if (!_bundle_for_inputs) { - _bundle_for_inputs.reset (new Bundle (true)); - } - - _bundle_for_inputs->suspend_signals (); - - _bundle_for_inputs->set_type (default_type ()); - - _bundle_for_inputs->remove_channels (); - - snprintf(buf, sizeof (buf), _("%s in"), _name.c_str()); - _bundle_for_inputs->set_name (buf); - uint32_t const ni = inputs().num_ports(); - for (uint32_t i = 0; i < ni; ++i) { - _bundle_for_inputs->add_channel (bundle_channel_name (i, ni)); - _bundle_for_inputs->set_port (i, _session.engine().make_port_name_non_relative (inputs().port(i)->name())); + if (!_bundle) { + _bundle.reset (new Bundle (true)); } - _bundle_for_inputs->resume_signals (); -} + _bundle->suspend_signals (); + _bundle->set_type (default_type ()); -void -IO::setup_bundle_for_outputs () -{ - char buf[32]; + _bundle->remove_channels (); - if (!_bundle_for_outputs) { - _bundle_for_outputs.reset (new Bundle (false)); + if (_direction == Input) { + snprintf(buf, sizeof (buf), _("%s in"), _name.c_str()); + } else { + snprintf(buf, sizeof (buf), _("%s out"), _name.c_str()); } - - _bundle_for_outputs->suspend_signals (); - - _bundle_for_outputs->set_type (default_type ()); - - _bundle_for_outputs->remove_channels (); - - snprintf(buf, sizeof (buf), _("%s out"), _name.c_str()); - _bundle_for_outputs->set_name (buf); - uint32_t const no = outputs().num_ports(); - for (uint32_t i = 0; i < no; ++i) { - _bundle_for_outputs->add_channel (bundle_channel_name (i, no)); - _bundle_for_outputs->set_port (i, _session.engine().make_port_name_non_relative (outputs().port(i)->name())); + _bundle->set_name (buf); + uint32_t const ni = _ports.num_ports(); + for (uint32_t i = 0; i < ni; ++i) { + _bundle->add_channel (bundle_channel_name (i, ni)); + _bundle->set_port (i, _session.engine().make_port_name_non_relative (_ports.port(i)->name())); } - _bundle_for_outputs->resume_signals (); + _bundle->resume_signals (); } - -/** @return Bundles connected to our inputs */ +/** @return Bundles connected to our ports */ BundleList -IO::bundles_connected_to_inputs () +IO::bundles_connected () { BundleList bundles; /* User bundles */ - for (std::vector::iterator i = _bundles_connected_to_inputs.begin(); i != _bundles_connected_to_inputs.end(); ++i) { + for (std::vector::iterator i = _bundles_connected.begin(); i != _bundles_connected.end(); ++i) { bundles.push_back (i->bundle); } /* Session bundles */ boost::shared_ptr b = _session.bundles (); for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) { - if ((*i)->connected_to (_bundle_for_inputs, _session.engine())) { + if ((*i)->connected_to (_bundle, _session.engine())) { bundles.push_back (*i); } } /* Route bundles */ - boost::shared_ptr r = _session.get_routes (); - for (ARDOUR::RouteList::iterator i = r->begin(); i != r->end(); ++i) { - if ((*i)->bundle_for_outputs()->connected_to (_bundle_for_inputs, _session.engine())) { - bundles.push_back ((*i)->bundle_for_outputs()); - } - } - - return bundles; -} - - -/* @return Bundles connected to our outputs */ -BundleList -IO::bundles_connected_to_outputs () -{ - BundleList bundles; - /* User bundles */ - for (std::vector::iterator i = _bundles_connected_to_outputs.begin(); i != _bundles_connected_to_outputs.end(); ++i) { - bundles.push_back (i->bundle); - } + boost::shared_ptr r = _session.get_routes (); - /* Session bundles */ - boost::shared_ptr b = _session.bundles (); - for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) { - if ((*i)->connected_to (_bundle_for_outputs, _session.engine())) { - bundles.push_back (*i); + if (_direction == Input) { + for (ARDOUR::RouteList::iterator i = r->begin(); i != r->end(); ++i) { + if ((*i)->output()->bundle()->connected_to (_bundle, _session.engine())) { + bundles.push_back ((*i)->output()->bundle()); + } } - } - - /* Route bundles */ - boost::shared_ptr r = _session.get_routes (); - for (ARDOUR::RouteList::iterator i = r->begin(); i != r->end(); ++i) { - if ((*i)->bundle_for_inputs()->connected_to (_bundle_for_outputs, _session.engine())) { - bundles.push_back ((*i)->bundle_for_inputs()); + } else { + for (ARDOUR::RouteList::iterator i = r->begin(); i != r->end(); ++i) { + if ((*i)->input()->bundle()->connected_to (_bundle, _session.engine())) { + bundles.push_back ((*i)->input()->bundle()); + } } } - - return bundles; + + return bundles; } @@ -2598,22 +1223,6 @@ IO::UserBundleInfo::UserBundleInfo (IO* io, boost::shared_ptr b) ); } -void -IO::prepare_inputs (nframes_t nframes) -{ - /* io_lock, not taken: function must be called from Session::process() calltree */ -} - -void -IO::flush_outputs (nframes_t nframes) -{ - /* io_lock, not taken: function must be called from Session::process() calltree */ - - for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) { - (*i).flush_buffers (nframes, _output_offset); - } -} - std::string IO::bundle_channel_name (uint32_t c, uint32_t n) const { @@ -2654,29 +1263,18 @@ IO::set_name_in_state (XMLNode& node, const string& new_name) } } -void -IO::cycle_start (nframes_t nframes) -{ - _output_offset = 0; -} - -void -IO::increment_output_offset (nframes_t n) -{ - _output_offset += n; -} - bool IO::connected_to (boost::shared_ptr other) const { + assert (_direction != other->direction()); + uint32_t i, j; - - uint32_t no = n_outputs().n_total(); - uint32_t ni = other->n_inputs ().n_total(); + uint32_t no = n_ports().n_total(); + uint32_t ni = other->n_ports ().n_total(); for (i = 0; i < no; ++i) { for (j = 0; j < ni; ++j) { - if (output(i)->connected_to (other->input(j)->name())) { + if (nth(i)->connected_to (other->nth(j)->name())) { return true; } } @@ -2685,3 +1283,67 @@ IO::connected_to (boost::shared_ptr other) const return false; } +void +IO::process_input (boost::shared_ptr proc, sframes_t start_frame, sframes_t end_frame, nframes_t nframes) +{ + BufferSet bufs; + + /* don't read the data into new buffers - just use the port buffers directly */ + + bufs.attach_buffers (_ports, nframes, 0); + proc->run_in_place (bufs, start_frame, end_frame, nframes); +} + +void +IO::collect_input (BufferSet& bufs, nframes_t nframes, ChanCount offset) +{ + assert(bufs.available() >= _ports.count()); + + if (_ports.count() == ChanCount::ZERO) { + return; + } + + bufs.set_count (_ports.count()); + + for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) { + PortSet::iterator i = _ports.begin(*t); + BufferSet::iterator b = bufs.begin(*t); + + for (uint32_t off = 0; off < offset.get(*t); ++off, ++b) { + if (b == bufs.end(*t)) { + continue; + } + } + + for ( ; i != _ports.end(*t); ++i, ++b) { + Buffer& bb (i->get_buffer (nframes)); + b->read_from (bb, nframes); + } + } +} + +void +IO::copy_to_outputs (BufferSet& bufs, DataType type, nframes_t nframes, nframes_t offset) +{ + // Copy any buffers 1:1 to outputs + + PortSet::iterator o = _ports.begin(type); + BufferSet::iterator i = bufs.begin(type); + BufferSet::iterator prev = i; + + while (i != bufs.end(type) && o != _ports.end (type)) { + Buffer& port_buffer (o->get_buffer (nframes)); + port_buffer.read_from (*i, nframes, offset); + prev = i; + ++i; + ++o; + } + + // Copy last buffer to any extra outputs + + while (o != _ports.end(type)) { + Buffer& port_buffer (o->get_buffer (nframes)); + port_buffer.read_from (*prev, nframes, offset); + ++o; + } +} diff --git a/libs/ardour/io_processor.cc b/libs/ardour/io_processor.cc index 2eac9dc88b..7e0d4a771c 100644 --- a/libs/ardour/io_processor.cc +++ b/libs/ardour/io_processor.cc @@ -46,20 +46,36 @@ using namespace PBD; /* 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) - , _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 */ -IOProcessor::IOProcessor (Session& s, IO* io, const string& proc_name, DataType dtype) +IOProcessor::IOProcessor (Session& s, boost::shared_ptr in, boost::shared_ptr out, + const string& proc_name, DataType dtype) : Processor(s, proc_name) - , _io (io) + , _input (in) + , _output (out) { - _own_io = false; + _own_input = false; + _own_output = false; } IOProcessor::~IOProcessor () @@ -68,12 +84,21 @@ IOProcessor::~IOProcessor () } void -IOProcessor::set_io (boost::shared_ptr io) +IOProcessor::set_input (boost::shared_ptr io) +{ + /* CALLER MUST HOLD PROCESS LOCK */ + + _input = io; + _own_input = false; +} + +void +IOProcessor::set_output (boost::shared_ptr io) { /* CALLER MUST HOLD PROCESS LOCK */ - _io = io; - _own_io = false; + _output = io; + _own_output = false; } XMLNode& @@ -81,12 +106,28 @@ IOProcessor::state (bool full_state) { XMLNode& node (Processor::state (full_state)); - if (_own_io) { - node.add_child_nocopy (_io->state (full_state)); - node.add_property ("own-io", "yes"); + if (_own_input) { + XMLNode& i (_input->state (full_state)); + // i.name() = X_("output"); + node.add_child_nocopy (i); + node.add_property ("own-input", "yes"); + } else { + node.add_property ("own-input", "no"); + 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-io", "no"); - node.add_property ("io", _io->name()); + node.add_property ("own-output", "no"); + if (_output) { + node.add_property ("output", _output->name()); + } } return node; @@ -100,67 +141,59 @@ IOProcessor::set_state (const XMLNode& node) Processor::set_state(node); - if ((prop = node.property ("own-io")) != 0) { - _own_io = prop->value() == "yes"; + if ((prop = node.property ("own-input")) != 0) { + _own_input = (prop->value() == "yes"); } - /* 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 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 (r); - - return 0; + 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 */ + XMLNodeList nlist = node.children(); XMLNodeIterator niter; - - for (niter = nlist.begin(); niter != nlist.end(); ++niter) { - if ((*niter)->name() == IO::state_node_name) { - io_node = (*niter); - break; - } else if ((*niter)->name() == "Redirect") { - 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 (_own_input) { + for (niter = nlist.begin(); niter != nlist.end(); ++niter) { + if ((*niter)->name() == "input") { + io_node = (*niter); + 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) { - _io->set_state(*io_node); - - // legacy sessions: use IO name - if ((prop = node.property ("name")) == 0) { - set_name (_io->name()); + + if (_own_output) { + for (niter = nlist.begin(); niter != nlist.end(); ++niter) { + if ((*niter)->name() == "output") { + io_node = (*niter); + break; + } } - - } else { - error << _("XML node describing a redirect is missing an IO node") << endmsg; - return -1; + + if (io_node) { + _output->set_state(*io_node); + + // legacy sessions: use IO name + if ((prop = node.property ("name")) == 0) { + set_name (_output->name()); + } + } } return 0; @@ -169,41 +202,33 @@ IOProcessor::set_state (const XMLNode& node) void IOProcessor::silence (nframes_t nframes) { - if (_own_io) { - _io->silence (nframes); + if (_own_output && _output) { + _output->silence (nframes); } } ChanCount IOProcessor::output_streams() const { - return _io->n_outputs(); + return _output ? _output->n_ports() : ChanCount::ZERO; } ChanCount IOProcessor::input_streams () const { - return _io->n_inputs(); + return _input ? _input->n_ports() : ChanCount::ZERO; } ChanCount IOProcessor::natural_output_streams() const { - return _io->n_outputs(); + return _output ? _output->n_ports() : ChanCount::ZERO; } ChanCount IOProcessor::natural_input_streams () const { - return _io->n_inputs(); -} - -void -IOProcessor::automation_snapshot (nframes_t now, bool force) -{ - if (_own_io) { - _io->automation_snapshot(now, force); - } + return _input ? _input->n_ports() : ChanCount::ZERO; } bool @@ -211,8 +236,12 @@ IOProcessor::set_name (const std::string& name) { bool ret = SessionObject::set_name (name); - if (ret && _own_io) { - ret = _io->set_name (name); + if (ret && _own_input && _input) { + ret = _input->set_name (name); + } + + if (ret && _own_output && _output) { + ret = _output->set_name (name); } return ret; diff --git a/libs/ardour/meter.cc b/libs/ardour/meter.cc index 371e0c5a90..ed50479c74 100644 --- a/libs/ardour/meter.cc +++ b/libs/ardour/meter.cc @@ -29,8 +29,41 @@ using namespace std; -namespace ARDOUR { +using namespace ARDOUR; +sigc::signal Metering::Meter; +Glib::StaticMutex Metering::m_meter_signal_lock; + +sigc::connection +Metering::connect (sigc::slot 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 * 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. - * Caller MUST hold io_lock! + * Caller MUST hold its own processor_lock to prevent reconfiguration + * of meter size during this call. */ + void PeakMeter::meter () { @@ -139,12 +174,10 @@ PeakMeter::meter () for (size_t n = 0; n < limit; ++n) { - /* XXX we should use atomic exchange here */ - /* grab peak since last read */ - float new_peak = _peak_power[n]; - _peak_power[n] = 0; + float new_peak = _peak_power[n]; /* XXX we should use atomic exchange from here ... */ + _peak_power[n] = 0; /* ... to here */ /* compute new visible value using falloff */ @@ -176,4 +209,3 @@ PeakMeter::state (bool full_state) return node; } -} // namespace ARDOUR diff --git a/libs/ardour/midi_diskstream.cc b/libs/ardour/midi_diskstream.cc index 30b1542974..e0921d8916 100644 --- a/libs/ardour/midi_diskstream.cc +++ b/libs/ardour/midi_diskstream.cc @@ -159,8 +159,8 @@ MidiDiskstream::non_realtime_input_change () } if (input_change_pending & ConfigurationChanged) { - if (_io->n_inputs().n_midi() != _n_channels.n_midi()) { - error << "Can not feed IO " << _io->n_inputs() + if (_io->n_ports().n_midi() != _n_channels.n_midi()) { + error << "Can not feed IO " << _io->n_ports() << " with diskstream " << _n_channels << endl; } } @@ -199,7 +199,7 @@ MidiDiskstream::non_realtime_input_change () void MidiDiskstream::get_input_sources () { - uint32_t ni = _io->n_inputs().n_midi(); + uint32_t ni = _io->n_ports().n_midi(); if (ni == 0) { return; @@ -208,7 +208,7 @@ MidiDiskstream::get_input_sources () // This is all we do for now at least assert(ni == 1); - _source_port = _io->midi_input(0); + _source_port = _io->midi(0); // do... stuff? } @@ -421,6 +421,7 @@ MidiDiskstream::check_record_status (nframes_t transport_frame, nframes_t nframe last_possibly_recording = possibly_recording; } +#if 0 static void 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; } } +#endif int MidiDiskstream::process (nframes_t transport_frame, nframes_t nframes, bool can_record, bool rec_monitors_input) diff --git a/libs/ardour/midi_track.cc b/libs/ardour/midi_track.cc index c993b17ced..a6ff1b93f4 100644 --- a/libs/ardour/midi_track.cc +++ b/libs/ardour/midi_track.cc @@ -27,6 +27,7 @@ #include "ardour/amp.h" #include "ardour/buffer_set.h" +#include "ardour/delivery.h" #include "ardour/io_processor.h" #include "ardour/meter.h" #include "ardour/midi_diskstream.h" @@ -94,14 +95,14 @@ int MidiTrack::set_diskstream (boost::shared_ptr ds) { _diskstream = ds; - _diskstream->set_io (*this); + _diskstream->set_io (*(_input.get())); _diskstream->set_destructive (_mode == Destructive); _diskstream->set_record_enabled (false); //_diskstream->monitor_input (false); 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 */ @@ -113,11 +114,14 @@ MidiTrack::use_diskstream (string name) { boost::shared_ptr dstream; + cerr << "\n\n\nMIDI use diskstream\n"; + if ((dstream = boost::dynamic_pointer_cast(_session.diskstream_by_name (name))) == 0) { error << string_compose(_("MidiTrack: midi diskstream \"%1\" not known by session"), name) << endmsg; return -1; } + cerr << "\n\n\nMIDI found DS\n"; return set_diskstream (dstream); } @@ -191,6 +195,8 @@ MidiTrack::_set_state (const XMLNode& node, bool call_base) that means "you should create a new diskstream here, not look for an old one. */ + + cerr << "\n\n\n\n MIDI track " << name() << " found DS id " << id << endl; if (id == zero) { use_new_diskstream (); @@ -363,8 +369,6 @@ MidiTrack::roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame, int dret; boost::shared_ptr diskstream = midi_diskstream(); - prepare_inputs (nframes); - { Glib::RWLock::ReaderLock lm (_processor_lock, Glib::TRY_LOCK); if (lm.locked()) { @@ -405,7 +409,7 @@ MidiTrack::roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame, /* special condition applies */ 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()) { @@ -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; } diff --git a/libs/ardour/mute_master.cc b/libs/ardour/mute_master.cc new file mode 100644 index 0000000000..ca64fb01a5 --- /dev/null +++ b/libs/ardour/mute_master.cc @@ -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(), name) + , _mute_point (MutePoint (0)) +{ + // default range for parameter is fine + + _automation = new AutomationList (MuteAutomation); + set_list (boost::shared_ptr(_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"))); +} diff --git a/libs/ardour/panner.cc b/libs/ardour/panner.cc index 73326e12a4..3b700631cb 100644 --- a/libs/ardour/panner.cc +++ b/libs/ardour/panner.cc @@ -703,7 +703,8 @@ Multi2dPanner::set_state (const XMLNode& node) /*---------------------------------------------------------------------- */ Panner::Panner (string name, Session& s) - : Processor(s, name) + : SessionObject (s, name) + , AutomatableControls (s) { //set_name_old_auto (name); set_name (name); @@ -829,6 +830,8 @@ Panner::reset (uint32_t nouts, uint32_t npans) bool changed = false; 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 the config hasn't changed, we're done. */ @@ -1058,15 +1061,13 @@ Panner::get_state (void) XMLNode& Panner::state (bool full) { - XMLNode& node = Processor::state(full); - - node.add_property ("type", "panner"); + XMLNode* node = new XMLNode ("Panner"); char buf[32]; - node.add_property (X_("linked"), (_linked ? "yes" : "no")); - node.add_property (X_("link_direction"), enum_2_string (_link_direction)); - node.add_property (X_("bypassed"), (bypassed() ? "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_("bypassed"), (bypassed() ? "yes" : "no")); for (vector::iterator o = outputs.begin(); o != outputs.end(); ++o) { XMLNode* onode = new XMLNode (X_("Output")); @@ -1074,15 +1075,15 @@ Panner::state (bool full) onode->add_property (X_("x"), buf); snprintf (buf, sizeof (buf), "%.12g", (*o).y); onode->add_property (X_("y"), buf); - node.add_child_nocopy (*onode); + node->add_child_nocopy (*onode); } - + for (vector::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 @@ -1098,8 +1099,6 @@ Panner::set_state (const XMLNode& node) clear_panners (); - Processor::set_state(node); - ChanCount ins = ChanCount::ZERO; ChanCount outs = ChanCount::ZERO; @@ -1419,7 +1418,7 @@ Panner::distribute_no_automation (BufferSet& inbufs, BufferSet& outbufs, nframes } 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) { // 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()); // If we shouldn't play automation defer to distribute_no_automation - if ( !( automation_state() & Play || - ((automation_state() & Touch) && !touching()) ) ) { + if (!(automation_state() & Play || ((automation_state() & Touch) && !touching()))) { // Speed quietning gain_t gain_coeff = 1.0; + if (fabsf(_session.transport_speed()) > 1.5f) { gain_coeff = speed_quietning; } - distribute_no_automation(inbufs, outbufs, nframes, gain_coeff); + distribute_no_automation (inbufs, outbufs, nframes, gain_coeff); return; } diff --git a/libs/ardour/port_insert.cc b/libs/ardour/port_insert.cc index 9d0d65ccd5..8ff2633771 100644 --- a/libs/ardour/port_insert.cc +++ b/libs/ardour/port_insert.cc @@ -24,6 +24,7 @@ #include "pbd/failed_constructor.h" #include "pbd/xml++.h" +#include "ardour/delivery.h" #include "ardour/port_insert.h" #include "ardour/plugin.h" #include "ardour/port.h" @@ -40,15 +41,17 @@ using namespace std; using namespace ARDOUR; using namespace PBD; -PortInsert::PortInsert (Session& s) - : IOProcessor (s, string_compose (_("insert %1"), (bitslot = s.next_insert_id()) + 1), "") +PortInsert::PortInsert (Session& s, boost::shared_ptr mm) + : 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 */ } -PortInsert::PortInsert (Session& s, const XMLNode& node) - : IOProcessor (s, "unnamed port insert") +PortInsert::PortInsert (Session& s, boost::shared_ptr mm, const XMLNode& node) + : IOProcessor (s, true, true, "unnamed port insert") + , _out (new Delivery (s, _output, mm, _name, Delivery::Insert)) + { if (set_state (node)) { throw failed_constructor(); @@ -62,30 +65,21 @@ PortInsert::~PortInsert () 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 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; } if (!active()) { /* deliver silence */ - _io->silence (nframes); + silence (nframes); return; } - _io->deliver_output (bufs, start_frame, end_frame, nframes); - _io->collect_input (bufs, nframes); + _out->run_in_place (bufs, start_frame, end_frame, nframes); + _input->collect_input (bufs, nframes, ChanCount::ZERO); } XMLNode& @@ -97,7 +91,7 @@ PortInsert::get_state(void) XMLNode& PortInsert::state (bool full) { - XMLNode& node = IOProcessor::state(full); + XMLNode& node = Processor::state(full); char buf[32]; node.add_property ("type", "port"); 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; } @@ -156,7 +150,7 @@ PortInsert::signal_latency() const 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 @@ -164,7 +158,11 @@ PortInsert::configure_io (ChanCount in, ChanCount out) { /* 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; } @@ -178,3 +176,12 @@ PortInsert::can_support_io_configuration (const ChanCount& in, ChanCount& out) c 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; +} diff --git a/libs/ardour/processor.cc b/libs/ardour/processor.cc index 3fc9fcaee2..2e39c52d67 100644 --- a/libs/ardour/processor.cc +++ b/libs/ardour/processor.cc @@ -211,7 +211,8 @@ Processor::configure_io (ChanCount in, ChanCount out) { /* This class assumes 1:1 input:output.static output stream count. 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_output = out; diff --git a/libs/ardour/return.cc b/libs/ardour/return.cc index 1f228d01ca..4942f9023b 100644 --- a/libs/ardour/return.cc +++ b/libs/ardour/return.cc @@ -21,14 +21,15 @@ #include "pbd/xml++.h" -#include "ardour/return.h" -#include "ardour/session.h" -#include "ardour/port.h" +#include "ardour/amp.h" #include "ardour/audio_port.h" #include "ardour/buffer_set.h" +#include "ardour/io.h" #include "ardour/meter.h" #include "ardour/panner.h" -#include "ardour/io.h" +#include "ardour/port.h" +#include "ardour/return.h" +#include "ardour/session.h" #include "i18n.h" @@ -36,14 +37,26 @@ using namespace ARDOUR; using namespace PBD; 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())); + _meter.reset (new PeakMeter (_session)); + ProcessorCreated (this); /* EMIT SIGNAL */ } 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())); + _meter.reset (new PeakMeter (_session)); + if (set_state (node)) { throw failed_constructor(); } @@ -108,23 +121,38 @@ Return::set_state(const XMLNode& node) void Return::run_in_place (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes) { - if (active()) { - _io->collect_input (bufs, nframes, _configured_input); - bufs.set_count(_configured_output); + if (!active() || _input->n_ports() == ChanCount::ZERO) { + return; + } + + _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 Return::can_support_io_configuration (const ChanCount& in, ChanCount& out) const { - out = in + _io->n_inputs(); + out = in + _input->n_ports(); return true; } bool Return::configure_io (ChanCount in, ChanCount out) { - if (out != in + _io->n_inputs()) { + if (out != in + _input->n_ports()) { return false; } @@ -162,3 +190,4 @@ Return::make_unique (XMLNode &state, Session &session) } } + diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index ccdd523654..edd38eb80c 100644 --- a/libs/ardour/route.cc +++ b/libs/ardour/route.cc @@ -64,19 +64,23 @@ uint32_t Route::order_key_cnt = 0; sigc::signal Route::SyncOrderKeys; Route::Route (Session& sess, string name, Flag flg, DataType default_type) - : IO (sess, name, default_type) + : SessionObject (sess, name) + , AutomatableControls (sess) , _flags (flg) - , _solo_control (new ToggleControllable (X_("solo"), *this, ToggleControllable::SoloControl)) - , _mute_control (new ToggleControllable (X_("mute"), *this, ToggleControllable::MuteControl)) + , _solo_control (new SoloControllable (X_("solo"), *this)) + , _mute_master (new MuteMaster (sess, name)) + , _default_type (default_type) + { init (); - } Route::Route (Session& sess, const XMLNode& node, DataType default_type) - : IO (sess, *node.child ("IO"), default_type) - , _solo_control (new ToggleControllable (X_("solo"), *this, ToggleControllable::SoloControl)) - , _mute_control (new ToggleControllable (X_("mute"), *this, ToggleControllable::MuteControl)) + : SessionObject (sess, "toBeReset") + , AutomatableControls (sess) + , _solo_control (new SoloControllable (X_("solo"), *this)) + , _mute_master (new MuteMaster (sess, "toBeReset")) + , _default_type (default_type) { init (); _set_state (node, false); @@ -85,21 +89,15 @@ Route::Route (Session& sess, const XMLNode& node, DataType default_type) void Route::init () { + _active = true; processor_max_streams.reset(); - _muted = false; - _soloed = false; _solo_safe = false; _recordable = true; - _active = true; - _phase_invert = false; - _denormal_protection = false; order_keys[strdup (N_("signal"))] = order_key_cnt++; _silent = false; _meter_point = MeterPostFader; _initial_delay = 0; _roll_delay = 0; - _own_latency = 0; - _user_latency = 0; _have_internal_generator = false; _declickable = false; _pending_declick = true; @@ -109,32 +107,42 @@ Route::init () _edit_group = 0; _mix_group = 0; - _mute_affects_pre_fader = Config->get_mute_affects_pre_fader(); - _mute_affects_post_fader = Config->get_mute_affects_post_fader(); - _mute_affects_control_outs = Config->get_mute_affects_control_outs(); - _mute_affects_main_outs = Config->get_mute_affects_main_outs(); - - solo_gain = 1.0; - desired_solo_gain = 1.0; - mute_gain = 1.0; - desired_mute_gain = 1.0; + _phase_invert = 0; + _denormal_protection = false; + + /* add standard controls */ - input_changed.connect (mem_fun (this, &Route::input_change_handler)); - output_changed.connect (mem_fun (this, &Route::output_change_handler)); + add_control (_solo_control); + add_control (_mute_master); - /* add standard processors: amp, meter, main outs */ + /* input and output objects */ - /* amp & meter belong to IO but need to be added to our processor list */ + _input.reset (new IO (_session, _name, IO::Input, _default_type)); + _output.reset (new IO (_session, _name, IO::Output, _default_type)); + _input->changed.connect (mem_fun (this, &Route::input_change_handler)); + _output->changed.connect (mem_fun (this, &Route::output_change_handler)); + + /* add standard processors */ + + _amp.reset (new Amp (_session, _mute_master)); add_processor (_amp, PostFader); + + _meter.reset (new PeakMeter (_session)); add_processor (_meter, PreFader); - _main_outs.reset (new Delivery (_session, this, _name, Delivery::Main)); + _main_outs.reset (new Delivery (_session, _output, _mute_master, _name, Delivery::Main)); add_processor (_main_outs, PostFader); + + /* now we can meter */ + + _meter_connection = Metering::connect (mem_fun (*this, &Route::meter)); } Route::~Route () { + Metering::disconnect (_meter_connection); + clear_processors (PreFader); clear_processors (PostFader); @@ -224,10 +232,11 @@ Route::ensure_track_or_route_name(string name, Session &session) return newname; } + void Route::inc_gain (gain_t fraction, void *src) { - IO::inc_gain (fraction, src); + _amp->inc_gain (fraction, src); } void @@ -237,7 +246,7 @@ Route::set_gain (gain_t val, void *src) if (_mix_group->is_relative()) { - gain_t usable_gain = gain(); + gain_t usable_gain = _amp->gain(); if (usable_gain < 0.000001f) { usable_gain = 0.000001f; } @@ -257,13 +266,13 @@ Route::set_gain (gain_t val, void *src) if (factor > 0.0f) { factor = _mix_group->get_max_factor(factor); if (factor == 0.0f) { - _gain_control->Changed(); /* EMIT SIGNAL */ + _amp->gain_control()->Changed(); /* EMIT SIGNAL */ return; } } else { factor = _mix_group->get_min_factor(factor); if (factor == 0.0f) { - _gain_control->Changed(); /* EMIT SIGNAL */ + _amp->gain_control()->Changed(); /* EMIT SIGNAL */ return; } } @@ -278,11 +287,11 @@ Route::set_gain (gain_t val, void *src) return; } - if (val == gain()) { + if (val == _amp->gain()) { return; } - IO::set_gain (val, src); + _amp->set_gain (val, src); } /** Process this route for one (sub) cycle (process thread) @@ -300,132 +309,78 @@ Route::process_output_buffers (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes, bool with_processors, int declick) { - ProcessorList::iterator i; - bool mute_declick_applied = false; - gain_t dmg, dsg, dg; - bool no_monitor; + bool monitor; - bufs.is_silent(false); + bufs.is_silent (false); switch (Config->get_monitoring_model()) { case HardwareMonitoring: case ExternalMonitoring: - no_monitor = true; + monitor = record_enabled() && (_session.config.get_auto_input() || _session.actively_recording()); break; default: - no_monitor = false; - } - - declick = _pending_declick; - - const bool recording_without_monitoring = no_monitor && record_enabled() - && (!_session.config.get_auto_input() || _session.actively_recording()); - - - /* ------------------------------------------------------------------------------------------- - SET UP GAIN (FADER) - ----------------------------------------------------------------------------------------- */ - - { - Glib::Mutex::Lock dm (declick_lock, Glib::TRY_LOCK); - - if (dm.locked()) { - dmg = desired_mute_gain; - dsg = desired_solo_gain; - dg = _gain_control->user_float(); - } else { - dmg = mute_gain; - dsg = solo_gain; - dg = _gain; - } + monitor = true; } - - // apply gain at the amp if... - _amp->apply_gain( - // we're not recording - !(record_enabled() && _session.actively_recording()) - // or (we are recording, and) software monitoring is required - || Config->get_monitoring_model() == SoftwareMonitoring); - - // mute at the amp if... - _amp->apply_mute (!_soloed && (mute_gain != dmg) && !mute_declick_applied && _mute_affects_post_fader, - mute_gain, dmg); - _amp->set_gain (_gain, dg); - - - /* ------------------------------------------------------------------------------------------- - SET UP CONTROL OUTPUTS - ----------------------------------------------------------------------------------------- */ - - boost::shared_ptr co = _control_outs; - if (co) { - // deliver control outputs unless we're ... - bool self_mute = ((dmg == 0 && _mute_affects_control_outs) || // or muted by mute of this track - !recording_without_monitoring); // or rec-enabled w/o s/w monitoring - bool other_mute = (dsg == 0); // muted by solo of another track - - co->set_self_mute (self_mute); - co->set_nonself_mute (other_mute); + if (!declick) { + declick = _pending_declick; } - /* ------------------------------------------------------------------------------------------- - SET UP MAIN OUTPUT STAGE - ----------------------------------------------------------------------------------------- */ + /* figure out if we're going to use gain automation */ - bool solo_audible = dsg > 0; - bool mute_audible = dmg > 0 || !_mute_affects_main_outs; + _amp->setup_gain_automation (start_frame, end_frame, nframes); + + /* tell main outs what to do about monitoring */ - bool silent_anyway = (_gain == 0 && !_amp->apply_gain_automation()); - bool muted_by_other_solo = (!solo_audible && (Config->get_solo_model() != SoloBus)); - bool muted_by_self = !mute_audible; + _main_outs->no_outs_cuz_we_no_monitor (!monitor); - _main_outs->set_nonself_mute (recording_without_monitoring || muted_by_other_solo || silent_anyway); - _main_outs->set_self_mute (muted_by_self); - /* ------------------------------------------------------------------------------------------- GLOBAL DECLICK (for transport changes etc.) ----------------------------------------------------------------------------------------- */ if (declick > 0) { - Amp::apply_gain (bufs, nframes, 0.0, 1.0, false); - _pending_declick = 0; + Amp::apply_gain (bufs, nframes, 0.0, 1.0); } else if (declick < 0) { - Amp::apply_gain (bufs, nframes, 1.0, 0.0, false); - _pending_declick = 0; - } else { // no global declick - if (solo_gain != dsg) { - Amp::apply_gain (bufs, nframes, solo_gain, dsg, false); - solo_gain = dsg; - } - } - + Amp::apply_gain (bufs, nframes, 1.0, 0.0); + } + _pending_declick = 0; + /* ------------------------------------------------------------------------------------------- - PRE-FADER MUTING + DENORMAL CONTROL/PHASE INVERT ----------------------------------------------------------------------------------------- */ - if (!_soloed && _mute_affects_pre_fader && (mute_gain != dmg)) { - Amp::apply_gain (bufs, nframes, mute_gain, dmg, false); - mute_gain = dmg; - mute_declick_applied = true; - } - if (mute_gain == 0.0f && dmg == 0.0f) { - bufs.is_silent(true); - } + if (_phase_invert) { + + int chn = 0; + if (_denormal_protection || Config->get_denormal_protection()) { + + for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i, ++chn) { + Sample* const sp = i->data(); - /* ------------------------------------------------------------------------------------------- - DENORMAL CONTROL - ----------------------------------------------------------------------------------------- */ + if (_phase_invert & chn) { + for (nframes_t nx = 0; nx < nframes; ++nx) { + sp[nx] = -sp[nx]; + sp[nx] += 1.0e-27f; + } + } else { + for (nframes_t nx = 0; nx < nframes; ++nx) { + sp[nx] += 1.0e-27f; + } + } + } - if (_denormal_protection || Config->get_denormal_protection()) { + } else { - for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i) { - Sample* const sp = i->data(); - - for (nframes_t nx = 0; nx < nframes; ++nx) { - sp[nx] += 1.0e-27f; + for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i, ++chn) { + Sample* const sp = i->data(); + + if (_phase_invert & chn) { + for (nframes_t nx = 0; nx < nframes; ++nx) { + sp[nx] = -sp[nx]; + } + } } } } @@ -437,57 +392,48 @@ Route::process_output_buffers (BufferSet& bufs, Glib::RWLock::ReaderLock rm (_processor_lock, Glib::TRY_LOCK); if (rm.locked()) { - for (i = _processors.begin(); i != _processors.end(); ++i) { - bufs.set_count(ChanCount::max(bufs.count(), (*i)->input_streams())); + for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { + bufs.set_count (ChanCount::max(bufs.count(), (*i)->input_streams())); (*i)->run_in_place (bufs, start_frame, end_frame, nframes); - bufs.set_count(ChanCount::max(bufs.count(), (*i)->output_streams())); + bufs.set_count (ChanCount::max(bufs.count(), (*i)->output_streams())); } if (!_processors.empty()) { - bufs.set_count(ChanCount::max(bufs.count(), _processors.back()->output_streams())); + bufs.set_count (ChanCount::max (bufs.count(), _processors.back()->output_streams())); } } - - /* ------------------------------------------------------------------------------------------- - POST-FADER MUTING - ----------------------------------------------------------------------------------------- */ - - if (!_soloed && (mute_gain != dmg) && !mute_declick_applied && _mute_affects_main_outs) { - Amp::apply_gain (bufs, nframes, mute_gain, dmg, false); - mute_gain = dmg; - mute_declick_applied = true; - } - - if (mute_gain == 0.0f && dmg == 0.0f) { - bufs.is_silent(true); - } - - // at this point we've reached the desired mute gain regardless - mute_gain = dmg; } ChanCount Route::n_process_buffers () { - return max (n_inputs(), processor_max_streams); -} - -void -Route::setup_peak_meters() -{ - ChanCount max_streams = std::max (_inputs.count(), _outputs.count()); - max_streams = std::max (max_streams, processor_max_streams); - _meter->configure_io (max_streams, max_streams); + return max (_input->n_ports(), processor_max_streams); } void Route::passthru (sframes_t start_frame, sframes_t end_frame, nframes_t nframes, int declick) { - BufferSet& bufs = _session.get_scratch_buffers(n_process_buffers()); + BufferSet& bufs = _session.get_scratch_buffers (n_process_buffers()); _silent = false; - collect_input (bufs, nframes); + assert (bufs.available() >= _input->n_ports()); + + if (_input->n_ports() == ChanCount::ZERO) { + silence (nframes); + } + + bufs.set_count (_input->n_ports()); + + for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) { + + BufferSet::iterator o = bufs.begin(*t); + PortSet& ports (_input->ports()); + + for (PortSet::iterator i = ports.begin(*t); i != ports.end(*t); ++i, ++o) { + o->read_from (i->get_buffer(nframes), nframes); + } + } process_output_buffers (bufs, start_frame, end_frame, nframes, true, declick); } @@ -510,82 +456,58 @@ Route::set_solo (bool yn, void *src) return; } - if (_soloed != yn) { - _soloed = yn; + if (_main_outs->soloed() != yn) { + _main_outs->mod_solo_level (yn ? 1 : -1); solo_changed (src); /* EMIT SIGNAL */ _solo_control->Changed (); /* EMIT SIGNAL */ } - - catch_up_on_solo_mute_override (); } -void -Route::catch_up_on_solo_mute_override () +bool +Route::soloed() const { - if (Config->get_solo_model() != InverseMute) { - return; - } - - { - Glib::Mutex::Lock lm (declick_lock); - - if (_muted) { - if (Config->get_solo_mute_override()) { - desired_mute_gain = (_soloed?1.0:0.0); - } else { - desired_mute_gain = 0.0; - } - } else { - desired_mute_gain = 1.0; - } - } + return _main_outs->soloed (); } void -Route::set_solo_mute (bool yn) +Route::set_solo_isolated (bool yn, void *src) { - Glib::Mutex::Lock lm (declick_lock); + if (_mix_group && src != _mix_group && _mix_group->is_active()) { + _mix_group->apply (&Route::set_solo_isolated, yn, _mix_group); + return; + } - /* Called by Session in response to another Route being soloed. - */ - - desired_solo_gain = (yn?0.0:1.0); + _main_outs->set_solo_isolated (yn); + solo_isolated_changed (src); } -void -Route::set_solo_safe (bool yn, void *src) +bool +Route::solo_isolated () const { - if (_solo_safe != yn) { - _solo_safe = yn; - solo_safe_changed (src); /* EMIT SIGNAL */ - } + return _main_outs->solo_isolated(); } void Route::set_mute (bool yn, void *src) - { if (_mix_group && src != _mix_group && _mix_group->is_active()) { _mix_group->apply (&Route::set_mute, yn, _mix_group); return; } - if (_muted != yn) { - _muted = yn; - mute_changed (src); /* EMIT SIGNAL */ - - _mute_control->Changed (); /* EMIT SIGNAL */ - - Glib::Mutex::Lock lm (declick_lock); - - if (_soloed && Config->get_solo_mute_override()) { - desired_mute_gain = 1.0f; - } else { - desired_mute_gain = (yn?0.0f:1.0f); - } + if (muted() != yn) { + _mute_master->mute (yn); + mute_changed (src); } +} + +bool +Route::muted() const +{ + return _mute_master->muted (); } +#if DEFINE_IF_YOU_NEED_THIS static void dump_processors(const string& name, const list >& procs) { @@ -596,6 +518,7 @@ dump_processors(const string& name, const list >& p } cerr << "}" << endl; } +#endif Route::ProcessorList::iterator Route::prefader_iterator() @@ -702,22 +625,19 @@ Route::add_processor (boost::shared_ptr processor, ProcessorList::ite } - // Ensure peak vector sizes before the plugin is activated - ChanCount potential_max_streams = ChanCount::max (processor->input_streams(), processor->output_streams()); - - _meter->configure_io (potential_max_streams, potential_max_streams); + if (_meter) { + // Ensure peak vector sizes before the plugin is activated + ChanCount potential_max_streams = ChanCount::max (processor->input_streams(), processor->output_streams()); + _meter->configure_io (potential_max_streams, potential_max_streams); + } // XXX: do we want to emit the signal here ? change call order. processor->activate (); processor->ActiveChanged.connect (bind (mem_fun (_session, &Session::update_latency_compensation), false, false)); - _user_latency = 0; + _output->set_user_latency (0); } - if (processor_max_streams != old_pms || old_pms == ChanCount::ZERO) { - reset_panner (); - } - processors_changed (); /* EMIT SIGNAL */ return 0; @@ -747,7 +667,7 @@ Route::add_processor_from_xml (const XMLNode& node, ProcessorList::iterator iter if (node.name() == "Send") { try { - boost::shared_ptr send (new Send (_session, node)); + boost::shared_ptr send (new Send (_session, _mute_master, node)); add_processor (send, iter); return true; } @@ -762,6 +682,9 @@ Route::add_processor_from_xml (const XMLNode& node, ProcessorList::iterator iter try { if ((prop = node.property ("type")) != 0) { + + cerr << _name << " : got processor type " << prop->value() << endl; + boost::shared_ptr processor; bool have_insert = false; @@ -775,31 +698,35 @@ Route::add_processor_from_xml (const XMLNode& node, ProcessorList::iterator iter } else if (prop->value() == "port") { - processor.reset (new PortInsert (_session, node)); + processor.reset (new PortInsert (_session, _mute_master, node)); } else if (prop->value() == "send") { - processor.reset (new Send (_session, node)); + processor.reset (new Send (_session, _mute_master, node)); have_insert = true; } else if (prop->value() == "meter") { processor = _meter; + processor->set_state (node); } else if (prop->value() == "amp") { processor = _amp; + processor->set_state (node); } else if (prop->value() == "listen" || prop->value() == "deliver") { /* XXX need to generalize */ processor = _control_outs; + processor->set_state (node); } else if (prop->value() == "main-outs") { processor = _main_outs; - + processor->set_state (node); + } else { error << string_compose(_("unknown Processor type \"%1\"; ignored"), prop->value()) << endmsg; @@ -884,7 +811,7 @@ Route::add_processors (const ProcessorList& others, ProcessorList::iterator iter ProcessorList::iterator existing_end = _processors.end(); --existing_end; - ChanCount potential_max_streams = ChanCount::max (n_inputs(), n_outputs()); + ChanCount potential_max_streams = ChanCount::max (_input->n_ports(), _output->n_ports()); for (ProcessorList::const_iterator i = others.begin(); i != others.end(); ++i) { @@ -921,11 +848,7 @@ Route::add_processors (const ProcessorList& others, ProcessorList::iterator iter (*i)->ActiveChanged.connect (bind (mem_fun (_session, &Session::update_latency_compensation), false, false)); } - _user_latency = 0; - } - - if (processor_max_streams != old_pms || old_pms == ChanCount::ZERO) { - reset_panner (); + _output->set_user_latency (0); } processors_changed (); /* EMIT SIGNAL */ @@ -1081,7 +1004,7 @@ Route::pre_fader_streams() const if (processor) { return processor->output_streams(); } else { - return n_inputs (); + return _input->n_ports (); } } @@ -1134,10 +1057,6 @@ Route::clear_processors (Placement p) configure_processors_unlocked (&err); // this can't fail } - if (processor_max_streams != old_pms) { - reset_panner (); - } - processor_max_streams.reset(); _have_internal_generator = false; processors_changed (); /* EMIT SIGNAL */ @@ -1173,7 +1092,7 @@ Route::remove_processor (boost::shared_ptr processor, ProcessorStream if (*i == processor) { /* move along, see failure case for configure_processors() - where we may need to reprocessor the processor. + where we may need to reconfigure the processor. */ /* stop redirects that send signals to JACK ports @@ -1181,13 +1100,17 @@ Route::remove_processor (boost::shared_ptr processor, ProcessorStream run. */ - boost::shared_ptr redirect; - - if ((redirect = boost::dynamic_pointer_cast (*i)) != 0) { - redirect->io()->disconnect_inputs (this); - redirect->io()->disconnect_outputs (this); + boost::shared_ptr iop; + + if ((iop = boost::dynamic_pointer_cast (*i)) != 0) { + if (iop->input()) { + iop->input()->disconnect (this); + } + if (iop->output()) { + iop->output()->disconnect (this); + } } - + i = _processors.erase (i); removed = true; break; @@ -1196,7 +1119,7 @@ Route::remove_processor (boost::shared_ptr processor, ProcessorStream ++i; } - _user_latency = 0; + _output->set_user_latency (0); } if (!removed) { @@ -1226,10 +1149,6 @@ Route::remove_processor (boost::shared_ptr processor, ProcessorStream } } - if (old_pms != processor_max_streams) { - reset_panner (); - } - processor->drop_references (); processors_changed (); /* EMIT SIGNAL */ @@ -1259,7 +1178,7 @@ Route::configure_processors_unlocked (ProcessorStreams* err) _in_configure_processors = true; // Check each processor in order to see if we can configure as requested - ChanCount in = n_inputs(); + ChanCount in = _input->n_ports (); ChanCount out; list< pair > configuration; uint32_t index = 0; @@ -1288,8 +1207,8 @@ Route::configure_processors_unlocked (ProcessorStreams* err) } // Ensure route outputs match last processor's outputs - if (out != n_outputs()) { - ensure_io (n_inputs(), out, false, this); + if (out != _output->n_ports ()) { + _output->ensure_io (out, false, this); } _in_configure_processors = false; @@ -1354,6 +1273,12 @@ Route::all_processors_active (Placement p, bool state) int Route::reorder_processors (const ProcessorList& new_order, Placement placement, ProcessorStreams* err) { + /* "new_order" is an ordered list of processors to be positioned according to "placement". + NOTE: all processors in "new_order" MUST be marked as visible. There maybe additional + processors in the current actual processor list that are hidden. Any visible processors + in the current list but not in "new_order" will be assumed to be deleted. + */ + { Glib::RWLock::WriterLock lm (_processor_lock); ChanCount old_pms = processor_max_streams; @@ -1384,6 +1309,10 @@ Route::reorder_processors (const ProcessorList& new_order, Placement placement, */ as_it_will_be.insert (as_it_will_be.end(), niter, new_order.end()); + while (niter != new_order.end()) { + (*niter)->set_placement (placement); + ++niter; + } break; } else { @@ -1391,16 +1320,18 @@ Route::reorder_processors (const ProcessorList& new_order, Placement placement, if (!(*oiter)->visible()) { as_it_will_be.push_back (*oiter); + (*oiter)->set_placement (placement); } else { /* visible processor: check that its in the new order */ if (find (new_order.begin(), new_order.end(), (*oiter)) == new_order.end()) { - /* deleted: do nothing */ + /* deleted: do nothing, shared_ptr<> will clean up */ } else { /* ignore this one, and add the next item from the new order instead */ as_it_will_be.push_back (*niter); + (*niter)->set_placement (placement); ++niter; } } @@ -1420,8 +1351,6 @@ Route::reorder_processors (const ProcessorList& new_order, Placement placement, } } - /* do we really need to do this every time? */ - reset_panner (); processors_changed (); /* EMIT SIGNAL */ return 0; @@ -1446,21 +1375,16 @@ Route::state(bool full_state) ProcessorList::iterator i; char buf[32]; + node->add_property ("name", _name); + node->add_property("default-type", _default_type.to_string()); + if (_flags) { node->add_property("flags", enum_2_string (_flags)); } - - node->add_property("default-type", _default_type.to_string()); node->add_property("active", _active?"yes":"no"); - node->add_property("muted", _muted?"yes":"no"); - node->add_property("soloed", _soloed?"yes":"no"); node->add_property("phase-invert", _phase_invert?"yes":"no"); node->add_property("denormal-protection", _denormal_protection?"yes":"no"); - node->add_property("mute-affects-pre-fader", _mute_affects_pre_fader?"yes":"no"); - node->add_property("mute-affects-post-fader", _mute_affects_post_fader?"yes":"no"); - node->add_property("mute-affects-control-outs", _mute_affects_control_outs?"yes":"no"); - node->add_property("mute-affects-main-outs", _mute_affects_main_outs?"yes":"no"); node->add_property("meter-point", enum_2_string (_meter_point)); if (_edit_group) { @@ -1489,9 +1413,10 @@ Route::state(bool full_state) } node->add_property ("order-keys", order_string); - node->add_child_nocopy (IO::state (full_state)); + node->add_child_nocopy (_input->state (full_state)); + node->add_child_nocopy (_output->state (full_state)); node->add_child_nocopy (_solo_control->get_state ()); - node->add_child_nocopy (_mute_control->get_state ()); + node->add_child_nocopy (_mute_master->get_state ()); XMLNode* remote_control_node = new XMLNode (X_("RemoteControl")); snprintf (buf, sizeof (buf), "%d", _remote_control_id); @@ -1514,92 +1439,6 @@ Route::state(bool full_state) return *node; } -XMLNode& -Route::get_processor_state () -{ - XMLNode* root = new XMLNode (X_("redirects")); - for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { - root->add_child_nocopy ((*i)->state (true)); - } - - return *root; -} - -int -Route::set_processor_state (const XMLNode& root) -{ - if (root.name() != X_("redirects")) { - return -1; - } - - XMLNodeList nlist; - XMLNodeList nnlist; - XMLNodeConstIterator iter; - XMLNodeConstIterator niter; - Glib::RWLock::ReaderLock lm (_processor_lock); - - nlist = root.children(); - - for (iter = nlist.begin(); iter != nlist.end(); ++iter){ - - /* iter now points to a IOProcessor state node */ - - nnlist = (*iter)->children (); - - for (niter = nnlist.begin(); niter != nnlist.end(); ++niter) { - - /* find the IO child node, since it contains the ID we need */ - - /* XXX OOP encapsulation violation, ugh */ - - if ((*niter)->name() == IO::state_node_name) { - - XMLProperty* prop = (*niter)->property (X_("id")); - - if (!prop) { - warning << _("IOProcessor node has no ID, ignored") << endmsg; - break; - } - - ID id = prop->value (); - - /* now look for a processor with that ID */ - - for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { - if ((*i)->id() == id) { - (*i)->set_state (**iter); - break; - } - } - - break; - - } - } - - } - - return 0; -} - -void -Route::set_deferred_state () -{ - XMLNodeList nlist; - XMLNodeConstIterator niter; - - if (!deferred_state) { - return; - } - - nlist = deferred_state->children(); - - _set_processor_states (nlist); - - delete deferred_state; - deferred_state = 0; -} - int Route::set_state (const XMLNode& node) { @@ -1609,6 +1448,7 @@ Route::set_state (const XMLNode& node) int Route::_set_state (const XMLNode& node, bool call_base) { + XMLNodeList nlist; XMLNodeConstIterator niter; XMLNode *child; @@ -1620,17 +1460,16 @@ Route::_set_state (const XMLNode& node, bool call_base) return -1; } + if ((prop = node.property (X_("name"))) != 0) { + Route::set_name (prop->value()); + } + if ((prop = node.property (X_("flags"))) != 0) { _flags = Flag (string_2_enum (prop->value(), _flags)); } else { _flags = Flag (0); } - if ((prop = node.property (X_("default-type"))) != 0) { - _default_type = DataType(prop->value()); - assert(_default_type != DataType::NIL); - } - if ((prop = node.property (X_("phase-invert"))) != 0) { set_phase_invert (prop->value()=="yes"?true:false, this); } @@ -1639,45 +1478,18 @@ Route::_set_state (const XMLNode& node, bool call_base) set_denormal_protection (prop->value()=="yes"?true:false, this); } - _active = true; if ((prop = node.property (X_("active"))) != 0) { - set_active (prop->value() == "yes"); - } - - if ((prop = node.property (X_("muted"))) != 0) { - bool yn = prop->value()=="yes"?true:false; - - /* force reset of mute status */ - - _muted = !yn; - set_mute(yn, this); - mute_gain = desired_mute_gain; + bool yn = (prop->value() == "yes"); + _active = !yn; // force switch + set_active (yn); } if ((prop = node.property (X_("soloed"))) != 0) { - bool yn = prop->value()=="yes"?true:false; + bool yn = (prop->value()=="yes"); - /* force reset of solo status */ + /* XXX force reset of solo status */ - _soloed = !yn; set_solo (yn, this); - solo_gain = desired_solo_gain; - } - - if ((prop = node.property (X_("mute-affects-pre-fader"))) != 0) { - _mute_affects_pre_fader = (prop->value()=="yes")?true:false; - } - - if ((prop = node.property (X_("mute-affects-post-fader"))) != 0) { - _mute_affects_post_fader = (prop->value()=="yes")?true:false; - } - - if ((prop = node.property (X_("mute-affects-control-outs"))) != 0) { - _mute_affects_control_outs = (prop->value()=="yes")?true:false; - } - - if ((prop = node.property (X_("mute-affects-main-outs"))) != 0) { - _mute_affects_main_outs = (prop->value()=="yes")?true:false; } if ((prop = node.property (X_("meter-point"))) != 0) { @@ -1725,51 +1537,35 @@ Route::_set_state (const XMLNode& node, bool call_base) } nlist = node.children(); - - delete deferred_state; - deferred_state = new XMLNode(X_("deferred state")); - - /* set parent class properties before anything else */ + XMLNode processor_state (X_("processor_state")); for (niter = nlist.begin(); niter != nlist.end(); ++niter){ - + child = *niter; - if (child->name() == IO::state_node_name && call_base) { - IO::set_state (*child); - break; + if (child->name() == IO::state_node_name) { + if ((prop = child->property (X_("direction"))) == 0) { + continue; + } + + if (prop->value() == "Input") { + _input->set_state (*child); + } else if (prop->value() == "Output") { + _output->set_state (*child); + } } - } - - for (niter = nlist.begin(); niter != nlist.end(); ++niter){ - - child = *niter; - if (child->name() == X_("Send") || child->name() == X_("Processor")) { - deferred_state->add_child_copy (*child); + if (child->name() == X_("Processor")) { + processor_state.add_child_copy (*child); } } - if (ports_legal) { - _set_processor_states (deferred_state->children()); - delete deferred_state; - deferred_state = 0; - } - + set_processor_state (processor_state); + for (niter = nlist.begin(); niter != nlist.end(); ++niter){ child = *niter; - if (child->name() == X_("Automation")) { - - if ((prop = child->property (X_("path"))) != 0) { - load_automation (prop->value()); - } - - } else if (child->name() == X_("ControlOuts")) { - - /* ignore this - deprecated */ - - } else if (child->name() == X_("Comment")) { + if (child->name() == X_("Comment")) { /* XXX this is a terrible API design in libxml++ */ @@ -1785,17 +1581,15 @@ Route::_set_state (const XMLNode& node, bool call_base) if (prop->value() == "solo") { _solo_control->set_state (*child); _session.add_controllable (_solo_control); - } else if (prop->value() == "mute") { - _mute_control->set_state (*child); - _session.add_controllable (_mute_control); - } + } + } else if (child->name() == X_("RemoteControl")) { if ((prop = child->property (X_("id"))) != 0) { int32_t x; sscanf (prop->value().c_str(), "%d", &x); set_remote_control_id (x); } - } + } } if ((prop = node.property (X_("mix-group"))) != 0) { @@ -1810,13 +1604,27 @@ Route::_set_state (const XMLNode& node, bool call_base) return 0; } +XMLNode& +Route::get_processor_state () +{ + XMLNode* root = new XMLNode (X_("redirects")); + for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { + root->add_child_nocopy ((*i)->state (true)); + } + + return *root; +} + void -Route::_set_processor_states(const XMLNodeList &nlist) +Route::set_processor_state (const XMLNode& node) { + const XMLNodeList &nlist = node.children(); XMLNodeConstIterator niter; bool has_meter_processor = false; // legacy sessions don't ProcessorList::iterator i, o; + cerr << _name << " _set_processor_states\n"; + // Iterate through existing processors, remove those which are not in the state list for (i = _processors.begin(); i != _processors.end(); ) { ProcessorList::iterator tmp = i; @@ -1852,6 +1660,8 @@ Route::_set_processor_states(const XMLNodeList &nlist) has_meter_processor = true; } + cerr << _name << " setting up proc state for " << prop->value() << endl; + o = i; if (prop->value() != "meter" && prop->value() != "amp" && prop->value() != "main-outs") { @@ -1872,6 +1682,8 @@ Route::_set_processor_states(const XMLNodeList &nlist) // create it and move it to the correct location if (o == _processors.end()) { + cerr << "\tproc not in list\n"; + if (add_processor_from_xml (**niter, i)) { --i; // move iterator to the newly inserted processor } else { @@ -1882,6 +1694,8 @@ Route::_set_processor_states(const XMLNodeList &nlist) // ensure it is at the location provided in the XML state } else { + cerr << "\tproc in wrong place in list\n"; + if (i != o) { boost::shared_ptr tmp = (*o); _processors.erase (o); // remove the old copy @@ -1889,6 +1703,7 @@ Route::_set_processor_states(const XMLNodeList &nlist) --i; // move iterator to the correct processor } + cerr << "\tnow reset proc " << (*i)->name() << endl; (*i)->set_state (**niter); } } @@ -1902,9 +1717,6 @@ Route::_set_processor_states(const XMLNodeList &nlist) } processors_changed (); - - - } void @@ -1919,7 +1731,7 @@ Route::silence (nframes_t nframes) { if (!_silent) { - IO::silence (nframes); + _output->silence (nframes); { Glib::RWLock::ReaderLock lm (_processor_lock, Glib::TRY_LOCK); @@ -1953,7 +1765,7 @@ Route::add_listener (boost::shared_ptr io, const string& listen_name) name += listen_name; name += ']'; - boost::shared_ptr listener (new Delivery (_session, name, Delivery::Listen)); + boost::shared_ptr listener (new Delivery (_session, _mute_master, name, Delivery::Listen)); /* As an IO, our control outs need as many IO outputs as we have outputs * (we track the changes in ::output_change_handler()). @@ -1961,7 +1773,7 @@ Route::add_listener (boost::shared_ptr io, const string& listen_name) * (i.e. it does not modify its input buffers whatsoever) */ - if (listener->io()->ensure_io (ChanCount::ZERO, n_outputs(), true, this)) { + if (listener->output()->ensure_io (n_outputs(), true, this)) { return boost::shared_ptr(); } @@ -1982,17 +1794,17 @@ Route::listen_via (boost::shared_ptr io, const string& listen_name) for (ProcessorList::const_iterator x = _processors.begin(); x != _processors.end(); ++x) { boost::shared_ptr d = boost::dynamic_pointer_cast(*x); - if (d && d->io() == io) { + if (d && d->output() == io) { /* already listening via the specified IO: do nothing */ return 0; } } } - uint32_t ni = io->n_inputs().n_total(); + uint32_t ni = io->n_ports().n_total(); for (uint32_t n = 0; n < ni; ++n) { - ports.push_back (io->input(n)->name()); + ports.push_back (io->nth (n)->name()); } if (ports.empty()) { @@ -2007,13 +1819,13 @@ Route::listen_via (boost::shared_ptr io, const string& listen_name) /* now connect to the named ports */ - ni = listen_point->io()->n_outputs().n_total(); + ni = listen_point->output()->n_ports().n_total(); size_t psize = ports.size(); for (size_t n = 0; n < ni; ++n) { - if (listen_point->io()->connect_output (listen_point->io()->output (n), ports[n % psize], this)) { + if (listen_point->output()->connect (listen_point->output()->nth (n), ports[n % psize], this)) { error << string_compose (_("could not connect %1 to %2"), - listen_point->io()->output(n)->name(), ports[n % psize]) << endmsg; + listen_point->output()->nth (n)->name(), ports[n % psize]) << endmsg; return -1; } } @@ -2037,7 +1849,7 @@ Route::drop_listen (boost::shared_ptr io) boost::shared_ptr d = boost::dynamic_pointer_cast(*x); - if (d && d->io() == io) { + if (d && d->output() == io) { /* already listening via the specified IO: do nothing */ remove_processor (*x, &err); @@ -2114,7 +1926,7 @@ Route::set_comment (string cmt, void *src) bool Route::feeds (boost::shared_ptr other) { - if (connected_to (other)) { + if (_output->connected_to (other)) { return true; } @@ -2122,10 +1934,10 @@ Route::feeds (boost::shared_ptr other) for (ProcessorList::iterator r = _processors.begin(); r != _processors.end(); r++) { - boost::shared_ptr proc; - - if ((proc = boost::dynamic_pointer_cast(*r)) != 0) { - if (proc->io()->connected_to (other)) { + boost::shared_ptr iop; + + if ((iop = boost::dynamic_pointer_cast(*r)) != 0) { + if (iop->output() && iop->output()->connected_to (other)) { return true; } } @@ -2134,55 +1946,6 @@ Route::feeds (boost::shared_ptr other) return false; } -void -Route::set_mute_config (mute_type t, bool onoff, void *src) -{ - switch (t) { - case PRE_FADER: - _mute_affects_pre_fader = onoff; - pre_fader_changed(src); /* EMIT SIGNAL */ - break; - - case POST_FADER: - _mute_affects_post_fader = onoff; - post_fader_changed(src); /* EMIT SIGNAL */ - break; - - case CONTROL_OUTS: - _mute_affects_control_outs = onoff; - control_outs_changed(src); /* EMIT SIGNAL */ - break; - - case MAIN_OUTS: - _mute_affects_main_outs = onoff; - main_outs_changed(src); /* EMIT SIGNAL */ - break; - } -} - -bool -Route::get_mute_config (mute_type t) -{ - bool onoff = false; - - switch (t){ - case PRE_FADER: - onoff = _mute_affects_pre_fader; - break; - case POST_FADER: - onoff = _mute_affects_post_fader; - break; - case CONTROL_OUTS: - onoff = _mute_affects_control_outs; - break; - case MAIN_OUTS: - onoff = _mute_affects_main_outs; - break; - } - - return onoff; -} - void Route::handle_transport_stopped (bool abort_ignored, bool did_locate, bool can_flush_processors) { @@ -2206,8 +1969,6 @@ Route::handle_transport_stopped (bool abort_ignored, bool did_locate, bool can_f } } - IO::transport_stopped (now); - _roll_delay = _initial_delay; } @@ -2223,11 +1984,10 @@ void Route::output_change_handler (IOChange change, void *src) { if ((change & ConfigurationChanged)) { - if (_control_outs) { - _control_outs->io()->ensure_io (ChanCount::ZERO, n_outputs(), true, this); - } - configure_processors (0); + /* XXX resize all listeners to match _main_outs? */ + + // configure_processors (0); } } @@ -2249,18 +2009,13 @@ Route::no_roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame, return 0; } - if (session_state_changing || !_active) { + if (session_state_changing || !_active || n_inputs() == ChanCount::ZERO) { silence (nframes); return 0; } - _amp->apply_gain_automation(false); - - if (n_inputs() != ChanCount::ZERO) { - passthru (start_frame, end_frame, nframes, 0); - } else { - silence (nframes); - } + _amp->apply_gain_automation (false); + passthru (start_frame, end_frame, nframes, 0); return 0; } @@ -2283,7 +2038,7 @@ Route::check_initial_delay (nframes_t nframes, nframes_t& transport_frame) output ports, so make a note of that for future reference. */ - increment_output_offset (_roll_delay); + _main_outs->increment_output_offset (_roll_delay); transport_frame += _roll_delay; _roll_delay = 0; @@ -2297,15 +2052,20 @@ Route::roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame, int bool can_record, bool rec_monitors_input) { { + // automation snapshot can also be called from the non-rt context + // and it uses the processor list, so we try to acquire the lock here Glib::RWLock::ReaderLock lm (_processor_lock, Glib::TRY_LOCK); + if (lm.locked()) { - // automation snapshot can also be called from the non-rt context - // and it uses the processor list, so we take the lock out here automation_snapshot (_session.transport_frame(), false); } } - if ((n_outputs().n_total() == 0 && _processors.empty()) || n_inputs().n_total() == 0 || !_active) { + if (n_outputs().n_total() == 0) { + return 0; + } + + if (!_active || n_inputs().n_total() == 0) { silence (nframes); return 0; } @@ -2318,21 +2078,6 @@ Route::roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame, int _silent = false; - _amp->apply_gain_automation(false); - - { - Glib::Mutex::Lock am (data().control_lock(), Glib::TRY_LOCK); - - if (am.locked() && _session.transport_rolling()) { - - if (_gain_control->automation_playback()) { - _amp->apply_gain_automation( - _gain_control->list()->curve().rt_safe_get_vector ( - start_frame, end_frame, _session.gain_automation_buffer(), nframes)); - } - } - } - passthru (start_frame, end_frame, nframes, declick); return 0; @@ -2349,7 +2094,7 @@ Route::silent_roll (nframes_t nframes, sframes_t start_frame, sframes_t end_fram void Route::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()); } } @@ -2357,15 +2102,15 @@ Route::toggle_monitor_input () bool Route::has_external_redirects () const { - // FIXME: what about sends? + // FIXME: what about sends? - they don't return a signal back to ardour? boost::shared_ptr pi; for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) { + if ((pi = boost::dynamic_pointer_cast(*i)) != 0) { - for (PortSet::const_iterator port = pi->io()->outputs().begin(); - port != pi->io()->outputs().end(); ++port) { + for (PortSet::const_iterator port = pi->output()->ports().begin(); port != pi->output()->ports().end(); ++port) { string port_name = port->name(); string client_name = port_name.substr (0, port_name.find(':')); @@ -2428,55 +2173,51 @@ Route::set_meter_point (MeterPoint p, void *src) nframes_t Route::update_total_latency () { - nframes_t old = _own_latency; - - if (_user_latency) { - _own_latency = _user_latency; - } else { - _own_latency = 0; + nframes_t old = _output->effective_latency(); + nframes_t own_latency = _output->user_latency(); - for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { - if ((*i)->active ()) { - _own_latency += (*i)->signal_latency (); - } + for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { + if ((*i)->active ()) { + own_latency += (*i)->signal_latency (); } } #undef DEBUG_LATENCY #ifdef DEBUG_LATENCY - cerr << _name << ": internal redirect latency = " << _own_latency << endl; + cerr << _name << ": internal redirect latency = " << own_latency << endl; #endif - set_port_latency (_own_latency); + _output->set_port_latency (own_latency); - if (!_user_latency) { + if (_output->user_latency() == 0) { + /* this (virtual) function is used for pure Routes, not derived classes like AudioTrack. this means that the data processed here comes from an input port, not prerecorded material, and therefore we have to take into account any input latency. */ - - - _own_latency += input_latency (); + + own_latency += _input->signal_latency (); } - if (old != _own_latency) { + if (old != own_latency) { + _output->set_latency_delay (own_latency); signal_latency_changed (); /* EMIT SIGNAL */ } #ifdef DEBUG_LATENCY - cerr << _name << ": input latency = " << input_latency() << " total = " - << _own_latency << endl; + cerr << _name << ": input latency = " << _input->signal_latency() << " total = " + << own_latency << endl; #endif - return _own_latency; + return _output->effective_latency (); } void Route::set_user_latency (nframes_t nframes) { - Latent::set_user_latency (nframes); + _output->set_user_latency (nframes); _session.update_latency_compensation (false, false); } @@ -2485,8 +2226,8 @@ Route::set_latency_delay (nframes_t longest_session_latency) { nframes_t old = _initial_delay; - if (_own_latency < longest_session_latency) { - _initial_delay = longest_session_latency - _own_latency; + if (_output->effective_latency() < longest_session_latency) { + _initial_delay = longest_session_latency - _output->effective_latency(); } else { _initial_delay = 0; } @@ -2503,57 +2244,32 @@ Route::set_latency_delay (nframes_t longest_session_latency) void Route::automation_snapshot (nframes_t now, bool force) { - if (!force && !should_snapshot(now)) { - return; - } - - IO::automation_snapshot (now, force); - for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { (*i)->automation_snapshot (now, force); } } -Route::ToggleControllable::ToggleControllable (std::string name, Route& s, ToggleType tp) - : Controllable (name), route (s), type(tp) +Route::SoloControllable::SoloControllable (std::string name, Route& r) + : AutomationControl (r.session(), Evoral::Parameter (SoloAutomation), + boost::shared_ptr(), name) + , route (r) { - + boost::shared_ptr gl(new AutomationList(Evoral::Parameter(SoloAutomation))); + set_list (gl); } void -Route::ToggleControllable::set_value (float val) +Route::SoloControllable::set_value (float val) { bool bval = ((val >= 0.5f) ? true: false); - switch (type) { - case MuteControl: - route.set_mute (bval, this); - break; - case SoloControl: - route.set_solo (bval, this); - break; - default: - break; - } + route.set_solo (bval, this); } float -Route::ToggleControllable::get_value (void) const +Route::SoloControllable::get_value (void) const { - float val = 0.0f; - - switch (type) { - case MuteControl: - val = route.muted() ? 1.0f : 0.0f; - break; - case SoloControl: - val = route.soloed() ? 1.0f : 0.0f; - break; - default: - break; - } - - return val; + return route.soloed() ? 1.0f : 0.0f; } void @@ -2568,8 +2284,6 @@ Route::set_block_size (nframes_t nframes) void Route::protect_automation () { - Automatable::protect_automation(); - for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) (*i)->protect_automation(); } @@ -2656,23 +2370,28 @@ Route::set_name (const string& str) { bool ret; string ioproc_name; + + SessionObject::set_name (str); + + ret = (_input->set_name(str) && _output->set_name(str)); - if ((ret = IO::set_name (str)) == true) { + if (ret) { + Glib::RWLock::ReaderLock lm (_processor_lock); for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { - /* rename all delivery objects to reflect our new name */ + /* rename all processors with outputs to reflect our new name */ - boost::shared_ptr dp = boost::dynamic_pointer_cast (*i); + boost::shared_ptr iop = boost::dynamic_pointer_cast (*i); - if (dp) { - string dp_name = str; - dp_name += '['; - dp_name += "XXX FIX ME XXX"; - dp_name += ']'; + if (iop) { + string iop_name = str; + iop_name += '['; + iop_name += "XXX FIX ME XXX"; + iop_name += ']'; - if (!dp->set_name (dp_name)) { + if (!iop->set_name (iop_name)) { ret = false; } } @@ -2692,7 +2411,7 @@ Route::send_for (boost::shared_ptr target) const boost::shared_ptr send; if ((send = boost::dynamic_pointer_cast(*i)) != 0) { - if (send->io()->connected_to (target)) { + if (send->output()->connected_to (target)) { return send; } } @@ -2700,3 +2419,95 @@ Route::send_for (boost::shared_ptr target) const return boost::shared_ptr(); } + +void +Route::set_phase_invert (bool yn, void *src) +{ + if (_phase_invert != yn) { + _phase_invert = yn; + // phase_invert_changed (src); /* EMIT SIGNAL */ + } +} + +bool +Route::phase_invert () const +{ + return _phase_invert != 0; +} + +void +Route::set_denormal_protection (bool yn, void *src) +{ + if (_denormal_protection != yn) { + _denormal_protection = yn; + // denormal_protection_changed (src); /* EMIT SIGNAL */ + } +} + +bool +Route::denormal_protection () const +{ + return _denormal_protection; +} + +void +Route::set_active (bool yn) +{ + if (_active != yn) { + _active = yn; + _input->set_active (yn); + _output->set_active (yn); + active_changed (); // EMIT SIGNAL + } +} + +void +Route::meter () +{ + Glib::RWLock::ReaderLock rm (_processor_lock, Glib::TRY_LOCK); + _meter->meter (); +} + +boost::shared_ptr +Route::panner() const +{ + + return _main_outs->panner(); +} + +boost::shared_ptr +Route::gain_control() const +{ + + return _amp->gain_control(); +} + +boost::shared_ptr +Route::get_control (const Evoral::Parameter& param) +{ + /* either we own the control or .... */ + + boost::shared_ptr c = boost::dynamic_pointer_cast(data().control (param)); + + if (!c) { + + /* maybe one of our processors does or ... */ + + Glib::RWLock::ReaderLock rm (_processor_lock, Glib::TRY_LOCK); + for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { + if ((c = boost::dynamic_pointer_cast((*i)->data().control (param))) != 0) { + break; + } + } + } + + if (!c) { + + /* nobody does so we'll make a new one */ + + c = boost::dynamic_pointer_cast(control_factory(param)); + add_control(c); + } + + return c; +} diff --git a/libs/ardour/route_group.cc b/libs/ardour/route_group.cc index 527597548d..438d0395d0 100644 --- a/libs/ardour/route_group.cc +++ b/libs/ardour/route_group.cc @@ -27,6 +27,7 @@ #include "pbd/error.h" #include "pbd/enumwriter.h" +#include "ardour/amp.h" #include "ardour/route_group.h" #include "ardour/audio_track.h" #include "ardour/audio_diskstream.h" @@ -87,7 +88,7 @@ RouteGroup::get_min_factor(gain_t factor) gain_t g; for (list::iterator i = routes.begin(); i != routes.end(); i++) { - g = (*i)->gain(); + g = (*i)->amp()->gain(); if ( (g+g*factor) >= 0.0f) continue; @@ -106,7 +107,7 @@ RouteGroup::get_max_factor(gain_t factor) gain_t g; for (list::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 ( (g+g*factor) <= 1.99526231f) diff --git a/libs/ardour/send.cc b/libs/ardour/send.cc index 5874b91cf6..61c235e60a 100644 --- a/libs/ardour/send.cc +++ b/libs/ardour/send.cc @@ -21,6 +21,7 @@ #include "pbd/xml++.h" +#include "ardour/amp.h" #include "ardour/send.h" #include "ardour/session.h" #include "ardour/port.h" @@ -35,15 +36,23 @@ using namespace ARDOUR; using namespace PBD; -Send::Send (Session& s) - : Delivery (s, string_compose (_("send %1"), (_bitslot = s.next_send_id()) + 1), Delivery::Send) +Send::Send (Session& s, boost::shared_ptr mm) + : 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 */ } -Send::Send (Session& s, const XMLNode& node) - : Delivery (s, "send", Delivery::Send) +Send::Send (Session& s, boost::shared_ptr mm, const XMLNode& node) + : Delivery (s, mm, "send", Delivery::Send) + , _metering (false) { + _amp.reset (new Amp (_session, _mute_master)); + _meter.reset (new PeakMeter (_session)); + if (set_state (node)) { throw failed_constructor(); } @@ -56,6 +65,43 @@ Send::~Send () 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& Send::get_state(void) { @@ -90,17 +136,9 @@ Send::set_state(const XMLNode& node) const XMLNode* insert_node = &node; - /* Send has regular IO automation (gain, pan) */ - - for (niter = nlist.begin(); niter != nlist.end(); ++niter) { - if ((*niter)->name() == IOProcessor::state_node_name) { - insert_node = *niter; - } else if ((*niter)->name() == X_("Automation")) { - // _io->set_automation_state (*(*niter), Evoral::Parameter(GainAutomation)); - } - } + /* XXX need to load automation state & data for amp */ - IOProcessor::set_state (*insert_node); + Delivery::set_state (*insert_node); return 0; } @@ -108,7 +146,7 @@ Send::set_state(const XMLNode& node) bool 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 */ @@ -126,25 +164,6 @@ Send::can_support_io_configuration (const ChanCount& in, ChanCount& out) const 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. * @param state XML send state. * @param session Session. diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index db6063e7f4..25f3f6a368 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -272,7 +272,8 @@ Session::Session (AudioEngine &eng, if (control_out_channels) { ChanCount count(DataType::AUDIO, control_out_channels); shared_ptr 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++); rl.push_back (r); @@ -280,9 +281,9 @@ Session::Session (AudioEngine &eng, if (master_out_channels) { ChanCount count(DataType::AUDIO, master_out_channels); - cerr << "new MO with " << count << endl; shared_ptr 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); rl.push_back (r); @@ -516,8 +517,8 @@ Session::set_worst_io_latencies () boost::shared_ptr r = routes.reader (); for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { - _worst_output_latency = max (_worst_output_latency, (*i)->output_latency()); - _worst_input_latency = max (_worst_input_latency, (*i)->input_latency()); + _worst_output_latency = max (_worst_output_latency, (*i)->output()->latency()); + _worst_input_latency = max (_worst_input_latency, (*i)->input()->latency()); } } @@ -574,15 +575,15 @@ Session::when_engine_running () for (int physport = 0; physport < 2; ++physport) { string physical_output = _engine.get_nth_physical_output (DataType::AUDIO, physport); - + 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 } } } - if (_click_io->n_outputs () > ChanCount::ZERO) { + if (_click_io->n_ports () > ChanCount::ZERO) { _clicking = Config->get_clicking (); } } @@ -665,12 +666,6 @@ Session::when_engine_running () 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. */ @@ -678,11 +673,11 @@ Session::when_engine_running () uint32_t limit = _master_out->n_outputs().n_total(); 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); 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) << endmsg; 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 */ if (_control_out) { @@ -777,7 +768,7 @@ Session::hookup_io () boost::shared_ptr t = boost::dynamic_pointer_cast (*x); 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 */ - IO::reset_panners (); + Delivery::reset_panners (); /* Anyone who cares about input state, wake up and do something */ @@ -1468,7 +1459,7 @@ Session::resort_routes_using (shared_ptr r) continue; } - if ((*j)->feeds (*i)) { + if ((*j)->feeds ((*i)->input())) { (*i)->fed_by.insert (*j); } } @@ -1553,7 +1544,13 @@ Session::new_midi_track (TrackMode mode, uint32_t how_many) try { track = boost::shared_ptr((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; goto failed; } @@ -1711,7 +1708,14 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod try { track = boost::shared_ptr((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"), input_channels, output_channels) << endmsg; @@ -1729,7 +1733,7 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod 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; } } @@ -1745,11 +1749,11 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod port = physoutputs[(channels_used+x)%nphysical_out]; } else if (Config->get_output_auto_connect() & AutoConnectMaster) { 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; } } @@ -1889,7 +1893,15 @@ Session::new_audio_route (int input_channels, int output_channels, uint32_t how_ try { shared_ptr 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"), input_channels, output_channels) << 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)]; } else if (Config->get_output_auto_connect() & AutoConnectMaster) { 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; } } @@ -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 loading this normally happens in a different way. */ - route->input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), this); - route->output_changed (IOChange (ConfigurationChanged|ConnectionsChanged), this); + route->input()->changed (IOChange (ConfigurationChanged|ConnectionsChanged), this); + route->output()->changed (IOChange (ConfigurationChanged|ConnectionsChanged), this); } 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)->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)); if ((*x)->is_master()) { @@ -2085,7 +2097,7 @@ Session::add_routes (RouteList& new_routes, bool save) if (_control_out && IO::connecting_legal) { 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) /* cancel control outs for all routes */ 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 (); @@ -2176,8 +2188,8 @@ Session::remove_route (shared_ptr route) // We need to disconnect the routes inputs and outputs - route->disconnect_inputs (0); - route->disconnect_outputs (0); + route->input()->disconnect (0); + route->output()->disconnect (0); update_latency_compensation (false, false); set_dirty(); @@ -2215,7 +2227,6 @@ Session::route_solo_changed (void* src, boost::weak_ptr wpr) return; } - bool is_track; boost::shared_ptr route = wpr.lock (); if (!route) { @@ -2224,86 +2235,39 @@ Session::route_solo_changed (void* src, boost::weak_ptr wpr) return; } - is_track = (boost::dynamic_pointer_cast(route) != 0); - shared_ptr r = routes.reader (); + int32_t delta; - for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { - - /* 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(*i) == 0) { - continue; - } - - } else { - - /* don't mess with tracks */ - - if (boost::dynamic_pointer_cast(*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; - } - } + if (route->soloed()) { + delta = 1; + } else { + delta = -1; + } + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { + if ((*i)->feeds (route->input())) { /* do it */ - + solo_update_disabled = true; - (*i)->set_solo (false, src); + (*i)->main_outs()->mod_solo_level (delta); solo_update_disabled = false; } } + /* now figure out if anything is soloed */ + bool something_soloed = false; - bool same_thing_soloed = false; - bool signal = false; - for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { if ((*i)->soloed()) { something_soloed = true; - if (boost::dynamic_pointer_cast(*i)) { - if (is_track) { - same_thing_soloed = true; - break; - } - } else { - if (!is_track) { - same_thing_soloed = true; - break; - } - } break; } } - if (something_soloed != currently_soloing) { - signal = true; - currently_soloing = something_soloed; - } - - modify_solo_mute (is_track, same_thing_soloed); - - if (signal) { - SoloActive (currently_soloing); /* EMIT SIGNAL */ + if (something_soloed != _non_soloed_outs_muted) { + _non_soloed_outs_muted = something_soloed; + SoloActive (_non_soloed_outs_muted); /* EMIT SIGNAL */ } SoloChanged (); /* EMIT SIGNAL */ @@ -2343,70 +2307,18 @@ Session::update_route_solo_state () /* nothing is soloed */ - for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { - (*i)->set_solo_mute (false); - } - if (signal) { SoloActive (false); } return; } - - modify_solo_mute (is_track, mute); - + if (signal) { SoloActive (currently_soloing); } } -void -Session::modify_solo_mute (bool is_track, bool mute) -{ - shared_ptr 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(*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(*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 Session::catch_up_on_solo () @@ -2432,7 +2344,7 @@ Session::catch_up_on_solo_mute_override () shared_ptr r = routes.reader (); for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { - (*i)->catch_up_on_solo_mute_override (); + // (*i)->catch_up_on_solo_mute_override (); } } diff --git a/libs/ardour/session_click.cc b/libs/ardour/session_click.cc index cbe085b82d..dfbd599c4c 100644 --- a/libs/ardour/session_click.cc +++ b/libs/ardour/session_click.cc @@ -127,7 +127,7 @@ Session::click (nframes_t start, nframes_t nframes) i = next; } - _click_io->deliver_output (bufs, start, end, nframes); + _click_io->copy_to_outputs (bufs, DataType::AUDIO, nframes, 0); } void diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index 4d07a6c6e2..0391e1f962 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -151,7 +151,7 @@ Session::first_stage_init (string fullpath, string snapshot_name) _tempo_map->StateChanged.connect (mem_fun (*this, &Session::tempo_map_changed)); - + _non_soloed_outs_muted = false; g_atomic_int_set (&processing_prohibited, 0); insert_cnt = 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 */ - IO::disable_panners (); - IO::disable_ports (); + Delivery::disable_panners (); IO::disable_connecting (); } @@ -1155,7 +1154,6 @@ Session::set_state (const XMLNode& node) } - IO::disable_ports (); IO::disable_connecting (); /* Object loading order: @@ -3215,7 +3213,7 @@ Session::config_changed (std::string p, bool ours) // deliver_midi (_mmc_port, buf, 2); } } else if (p == "solo-mute-override") { - catch_up_on_solo_mute_override (); + // catch_up_on_solo_mute_override (); } set_dirty (); diff --git a/libs/ardour/session_transport.cc b/libs/ardour/session_transport.cc index b3fa34419a..31dc52a11b 100644 --- a/libs/ardour/session_transport.cc +++ b/libs/ardour/session_transport.cc @@ -1335,11 +1335,12 @@ Session::update_latency_compensation (bool with_stop, bool abort) (!(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 (); 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; } diff --git a/libs/ardour/track.cc b/libs/ardour/track.cc index fa3193cba3..96d44de555 100644 --- a/libs/ardour/track.cc +++ b/libs/ardour/track.cc @@ -26,7 +26,7 @@ #include "ardour/audiosource.h" #include "ardour/diskstream.h" #include "ardour/io_processor.h" -#include "ardour/panner.h" +#include "ardour/meter.h" #include "ardour/port.h" #include "ardour/processor.h" #include "ardour/route_group_specialized.h" @@ -84,7 +84,7 @@ Track::get_template () void 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()); } } @@ -92,32 +92,28 @@ Track::toggle_monitor_input () ARDOUR::nframes_t Track::update_total_latency () { - nframes_t old = _own_latency; - - if (_user_latency) { - _own_latency = _user_latency; - } else { - _own_latency = 0; - - for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { - if ((*i)->active ()) { - _own_latency += (*i)->signal_latency (); - } + nframes_t old = _output->effective_latency(); + nframes_t own_latency = _output->user_latency(); + + for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { + if ((*i)->active ()) { + own_latency += (*i)->signal_latency (); } } #undef DEBUG_LATENCY #ifdef DEBUG_LATENCY - cerr << _name << ": internal redirect (final) latency = " << _own_latency << endl; + cerr << _name << ": internal redirect (final) latency = " << own_latency << endl; #endif - set_port_latency (_own_latency); - - if (old != _own_latency) { + _output->set_port_latency (own_latency); + + if (old != own_latency) { + _output->set_latency_delay (own_latency); signal_latency_changed (); /* EMIT SIGNAL */ } - return _own_latency; + return _output->effective_latency(); } Track::FreezeRecord::~FreezeRecord () @@ -155,14 +151,14 @@ Track::RecEnableControllable::get_value (void) const bool Track::record_enabled () const { - return _diskstream->record_enabled (); + return _diskstream && _diskstream->record_enabled (); } bool Track::can_record() { 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()) 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); } else { 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); } diff --git a/libs/ardour/wscript b/libs/ardour/wscript index 7079a64a08..98bc7106f3 100644 --- a/libs/ardour/wscript +++ b/libs/ardour/wscript @@ -135,7 +135,7 @@ def build(bld): gdither.cc globals.cc import.cc - io.cc + io.cc io_processor.cc jack_slave.cc ladspa_plugin.cc @@ -157,6 +157,7 @@ def build(bld): midi_track.cc mix.cc mtc_slave.cc + mute_master.cc named_selection.cc onset_detector.cc panner.cc @@ -178,7 +179,7 @@ def build(bld): resampled_source.cc return.cc reverse.cc - route.cc + route.cc route_group.cc send.cc session.cc diff --git a/libs/gtkmm2ext/gtkmm2ext/barcontroller.h b/libs/gtkmm2ext/gtkmm2ext/barcontroller.h index 0b074a0f90..5970fe2d5f 100644 --- a/libs/gtkmm2ext/gtkmm2ext/barcontroller.h +++ b/libs/gtkmm2ext/gtkmm2ext/barcontroller.h @@ -23,9 +23,6 @@ #include #include -namespace ARDOUR { - class Controllable; -} namespace Gtkmm2ext { diff --git a/libs/midi++2/midi.cc b/libs/midi++2/midi.cc index eacd85bf28..6b5bca8a98 100644 --- a/libs/midi++2/midi.cc +++ b/libs/midi++2/midi.cc @@ -158,7 +158,7 @@ MIDI::byte MIDI::decode_controller_name (const char *name) { - char *lparen; + const char *lparen; size_t len; if ((lparen = strrchr (name, '(')) != 0) { diff --git a/libs/surfaces/control_protocol/control_protocol.cc b/libs/surfaces/control_protocol/control_protocol.cc index f95aadb2b8..2d59912dc8 100644 --- a/libs/surfaces/control_protocol/control_protocol.cc +++ b/libs/surfaces/control_protocol/control_protocol.cc @@ -18,11 +18,12 @@ */ -#include -#include -#include -#include -#include +#include "ardour/session.h" +#include "ardour/route.h" +#include "ardour/audio_track.h" +#include "ardour/meter.h" +#include "ardour/amp.h" +#include "control_protocol/control_protocol.h" using namespace ARDOUR; using namespace std; @@ -212,7 +213,7 @@ ControlProtocol::route_get_gain (uint32_t table_index) return 0.0f; } - return r->gain (); + return r->amp()->gain (); } void @@ -242,7 +243,7 @@ ControlProtocol::route_get_effective_gain (uint32_t table_index) return 0.0f; } - return r->effective_gain (); + return r->amp()->gain_control()->get_value(); } diff --git a/wscript b/wscript index 471ed1f0bf..051d97d07c 100644 --- a/wscript +++ b/wscript @@ -95,7 +95,7 @@ def set_options(opt): help='Compile with support for LV2 (if slv2 is available)') opt.add_option('--nls', action='store_true', default=True, dest='nls', 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') opt.add_option('--syslibs', action='store_true', default=True, dest='syslibs', help='Use existing system versions of various libraries instead of internal ones') -- cgit v1.2.3