From 4fd63d89ce63e87ce7c80305b194618443b95e98 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Wed, 31 Oct 2012 15:52:31 +0000 Subject: [PATCH] first pass at getting a more complex (real-world) mixer topology to work. mixer gets configured as intended, but audio does not flow at present git-svn-id: svn://localhost/ardour2/branches/3.0-SG@13372 d708f5d6-7413-0410-9779-e7cbd77b26cf --- gtk2_ardour/engine_dialog.cc | 22 +- gtk2_ardour/engine_dialog.h | 8 + gtk2_ardour/soundgrid.mm | 6 +- libs/ardour/ardour/route.h | 2 + libs/ardour/ardour/sg_rack.h | 3 + libs/ardour/ardour/soundgrid.h | 71 +++- libs/ardour/route.cc | 27 +- libs/ardour/sg_rack.cc | 124 +++++-- libs/ardour/soundgrid.mm | 587 ++++++++++++++++++++++++--------- 9 files changed, 645 insertions(+), 205 deletions(-) diff --git a/gtk2_ardour/engine_dialog.cc b/gtk2_ardour/engine_dialog.cc index ec09d8d844..8a577eef66 100644 --- a/gtk2_ardour/engine_dialog.cc +++ b/gtk2_ardour/engine_dialog.cc @@ -110,6 +110,12 @@ EngineControl::EngineControl () , outputs_label (0) , outputs_adjustment (8, 1, 32, 1) , outputs_spinner (inputs_adjustment) + , tracks_label (0) + , tracks_adjustment (8, 1, 64, 1) + , tracks_spinner (tracks_adjustment) + , busses_label (0) + , busses_adjustment (8, 1, 64, 1) + , busses_spinner (busses_adjustment) #endif { @@ -225,6 +231,14 @@ EngineControl::EngineControl () basic_packer.attach (*outputs_label, 0, 1, row, row+1, FILL|EXPAND, (AttachOptions) 0); basic_packer.attach (outputs_spinner, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0); ++row; + tracks_label = manage (left_aligned_label (_("Maximum track count:"))); + basic_packer.attach (*tracks_label, 0, 1, row, row+1, FILL|EXPAND, (AttachOptions) 0); + basic_packer.attach (tracks_spinner, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0); + ++row; + busses_label = manage (left_aligned_label (_("Maximum bus count:"))); + basic_packer.attach (*busses_label, 0, 1, row, row+1, FILL|EXPAND, (AttachOptions) 0); + basic_packer.attach (busses_spinner, 1, 2, row, row+1, FILL|EXPAND, (AttachOptions) 0); + ++row; #endif #ifndef __APPLE__ @@ -708,10 +722,10 @@ EngineControl::enumerate_devices (const string& driver) devices[driver] = enumerate_coreaudio_devices (); } else if (driver == "SoundGrid") { - /* XXX hard code 16 track estimate... takes no account of stereo, sends, busses, etc. - */ - - soundgrid_init (inputs_adjustment.get_value(), outputs_adjustment.get_value(), 16); + soundgrid_init (inputs_adjustment.get_value(), outputs_adjustment.get_value(), + 16, /* max tracks */ + 16 /* max busses */ + ); devices[driver] = SoundGrid::lan_port_names(); #else diff --git a/gtk2_ardour/engine_dialog.h b/gtk2_ardour/engine_dialog.h index fdb15300f3..e436994b15 100644 --- a/gtk2_ardour/engine_dialog.h +++ b/gtk2_ardour/engine_dialog.h @@ -195,6 +195,14 @@ class EngineControl : public Gtk::VBox { Gtk::Label* outputs_label; Gtk::Adjustment outputs_adjustment; Gtk::SpinButton outputs_spinner; + + Gtk::Label* tracks_label; + Gtk::Adjustment tracks_adjustment; + Gtk::SpinButton tracks_spinner; + + Gtk::Label* busses_label; + Gtk::Adjustment busses_adjustment; + Gtk::SpinButton busses_spinner; #endif }; diff --git a/gtk2_ardour/soundgrid.mm b/gtk2_ardour/soundgrid.mm index 2105e1db24..131f4132d9 100644 --- a/gtk2_ardour/soundgrid.mm +++ b/gtk2_ardour/soundgrid.mm @@ -81,7 +81,7 @@ soundgrid_driver_init (uint32_t max_phys_inputs, uint32_t max_phys_outputs, uint } int -soundgrid_init (uint32_t max_phys_inputs, uint32_t max_phys_outputs, uint32_t max_tracks) +soundgrid_init (uint32_t max_phys_inputs, uint32_t max_phys_outputs, uint32_t max_tracks, uint32_t max_busses) { /* create a new window that we don't display (at least not as of August 2012, but we can give it to the SoundGrid library @@ -98,7 +98,9 @@ soundgrid_init (uint32_t max_phys_inputs, uint32_t max_phys_outputs, uint32_t ma ARDOUR::SoundGrid::Shutdown.connect (sg_connection, MISSING_INVALIDATOR, soundgrid_shutdown, gui_context()); - if (ARDOUR::SoundGrid::instance().initialize ([sg_window contentView], max_tracks)) { + if (ARDOUR::SoundGrid::instance().initialize ([sg_window contentView], + max_tracks, max_busses, + max_phys_inputs, max_phys_inputs)) { [sg_window release]; sg_window = 0; diff --git a/libs/ardour/ardour/route.h b/libs/ardour/ardour/route.h index ddd6fc5643..26498e5f4f 100644 --- a/libs/ardour/ardour/route.h +++ b/libs/ardour/ardour/route.h @@ -85,6 +85,8 @@ class Route : public SessionObject, public Automatable, public RouteGroupMember, virtual int init (); + uint32_t rack_id() const; + boost::shared_ptr input() const { return _input; } boost::shared_ptr output() const { return _output; } diff --git a/libs/ardour/ardour/sg_rack.h b/libs/ardour/ardour/sg_rack.h index 35469e4f66..458be7b617 100644 --- a/libs/ardour/ardour/sg_rack.h +++ b/libs/ardour/ardour/sg_rack.h @@ -43,6 +43,9 @@ class SoundGridRack : public SessionObject { void add_plugin (boost::shared_ptr); void remove_plugin (boost::shared_ptr); + + int reconfigure (uint32_t channels); + int set_process_group (uint32_t channels); void set_input_gain (gain_t); diff --git a/libs/ardour/ardour/soundgrid.h b/libs/ardour/ardour/soundgrid.h index be0feeb01e..a646e3ed21 100644 --- a/libs/ardour/ardour/soundgrid.h +++ b/libs/ardour/ardour/soundgrid.h @@ -20,6 +20,7 @@ #ifndef __ardour_soundgrid_h__ #define __ardour_soundgrid_h__ +#include #include #include @@ -42,7 +43,7 @@ class SoundGrid : public boost::noncopyable public: ~SoundGrid (); - int initialize (void* window_handle, uint32_t max_tracks); + int initialize (void* window_handle, uint32_t max_tracks, uint32_t max_busses, uint32_t physical_inputs, uint32_t physical_outputs); int teardown (); static SoundGrid& instance(); @@ -91,8 +92,10 @@ class SoundGrid : public boost::noncopyable bool remove_rack_synchronous (uint32_t clusterType, uint32_t trackHandle); bool remove_all_racks_synchronous (); - int set_gain (uint32_t in_clusterType, uint32_t in_trackHandle, double in_gainValue); - bool get_gain (uint32_t in_clusterType, uint32_t in_trackHandle, double &out_gainValue); + int set_gain (uint32_t clusterType, uint32_t trackHandle, double in_gainValue); + bool get_gain (uint32_t clusterType, uint32_t trackHandle, double &out_gainValue); + + int configure_io (uint32_t clusterType, uint32_t trackHandle, uint32_t channels); int configure_driver (uint32_t physical_inputs, uint32_t physical_outputs, uint32_t tracks); @@ -116,15 +119,46 @@ class SoundGrid : public boost::noncopyable /* control sorting and use in STL containers */ bool operator<(const Port& other) const { - return ctype < other.ctype && - stype < other.stype && - cid < other.cid && - sid < other.sid && - sindex < other.sindex && - channel < other.channel && - position < other.position; + + if (ctype < other.ctype) { + return true; + } else if (ctype > other.ctype) { + return false; + } + + if (cid < other.cid) { + return true; + } else if (cid > other.cid) { + return false; + } + + if (stype < other.stype) { + return true; + } else if (stype > other.stype) { + return false; + } + + if (sid < other.sid) { + return true; + } else if (sid > other.sid) { + return false; + } + + if (sindex < other.sindex) { + return true; + } else if (sindex > other.sindex) { + return false; + } + + if (channel < other.channel) { + return true; + } else if (channel > other.channel) { + return false; + } + + return position < other.position; } - + bool accepts_input () const { if (ctype == eClusterType_Inputs) { return true; @@ -170,7 +204,7 @@ class SoundGrid : public boost::noncopyable : Port (eClusterType_Outputs, eClusterHandle_Physical_Driver, wvEnum_Unknown, wvEnum_Unknown, wvEnum_Unknown, channel, Port::Post) {} }; - + struct PhysicalInputPort : public Port { PhysicalInputPort (uint32_t channel) : Port (eClusterType_Inputs, eClusterHandle_Physical_IO, @@ -183,6 +217,18 @@ class SoundGrid : public boost::noncopyable wvEnum_Unknown, wvEnum_Unknown, wvEnum_Unknown, channel, Port::Post) {} }; + /** + * this is a special port type that describes the GroupTrack chainers we create to + * mix multiple signals assigned to the same physical output. They are always mono, + * because they manage the signal to a single physical output. + */ + + struct PseudoPhysicalOutputPort : public Port { + PseudoPhysicalOutputPort (uint32_t channel) + : Port (eClusterType_GroupTrack, channel, + eControlType_Input, 0, eControlID_Input_Assignment_Left, 0, Port::Pre) {} + }; + struct TrackInputPort : public Port { TrackInputPort (uint32_t chainer_id, uint32_t channel) : Port (eClusterType_InputTrack, chainer_id, @@ -272,7 +318,6 @@ class SoundGrid : public boost::noncopyable uint32_t& max_outputs, uint32_t& current_inputs, uint32_t& current_outputs); - int connect_io_to_driver (uint32_t ninputs, uint32_t noutputs); uint32_t _driver_ports; // how many total channels we tell the SG driver to allocate std::vector _driver_input_ports_in_use; diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index 4e93d658c1..86ef26e05b 100644 --- a/libs/ardour/route.cc +++ b/libs/ardour/route.cc @@ -134,7 +134,11 @@ Route::init () _output->changed.connect_same_thread (*this, boost::bind (&Route::output_change_handler, this, _1, _2)); if (Profile->get_soundgrid()) { - _sg_rack = new SoundGridRack (_session, *this, name()); + try { + _sg_rack = new SoundGridRack (_session, *this, name()); + } catch (...) { + _sg_rack = 0; + } } /* add amp processor */ @@ -204,9 +208,7 @@ Route::~Route () _processors.clear (); } - if (_sg_rack) { - delete _sg_rack; - } + delete _sg_rack; } void @@ -311,7 +313,7 @@ Route::sync_order_keys (RouteSortOrderKey base) } void -Route::set_remote_control_id_from_order_key (RouteSortOrderKey key, uint32_t rid) +Route::set_remote_control_id_from_order_key (RouteSortOrderKey /*key*/, uint32_t rid) { if (is_master() || is_monitor() || is_hidden()) { /* hard-coded remote IDs, or no remote ID */ @@ -2939,6 +2941,11 @@ Route::output_change_handler (IOChange change, void * /*src*/) contains ConfigurationChanged */ need_to_queue_solo_change = false; + + if (_sg_rack) { + _sg_rack->reconfigure (_output->ports().num_ports (DataType::AUDIO)); + _sg_rack->make_connections (); + } } if (!_output->connected() && _soloed_by_others_downstream) { @@ -4133,3 +4140,13 @@ Route::non_realtime_locate (framepos_t pos) } } } + +uint32_t +Route::rack_id() const +{ + if (_sg_rack) { + return _sg_rack->id(); + } + + return UINT32_MAX; +} diff --git a/libs/ardour/sg_rack.cc b/libs/ardour/sg_rack.cc index a9a5318cb6..e925f58216 100644 --- a/libs/ardour/sg_rack.cc +++ b/libs/ardour/sg_rack.cc @@ -41,26 +41,33 @@ SoundGridRack::SoundGridRack (Session& s, Route& r, const std::string& name) , _route (r) , _rack_id (UINT32_MAX) { - if (r.is_hidden()) { - return; - } - DEBUG_TRACE (DEBUG::SoundGrid, string_compose ("Creating SG Chainer for %1\n", r.name())); - if (dynamic_cast (&r) != 0) { + if (dynamic_cast (&r) != 0 && !_route.is_hidden()) { _cluster_type = eClusterType_InputTrack; } else { /* bus */ - if (r.is_master()) { - _cluster_type = eClusterType_InputTrack; - } else if (r.is_monitor()) { - _cluster_type = eClusterType_InputTrack; - } else { - _cluster_type = eClusterType_InputTrack; - } + _cluster_type = eClusterType_GroupTrack; } - const int32_t process_group = 0; + int32_t process_group; + + /* XXX eventually these need to be discovered from the route which sets them during a graph sort + */ + + if (_route.is_monitor()) { + /* monitor runs last */ + process_group = 6; + } else if (_route.is_monitor()) { + /* master runs before monitor */ + process_group = 5; + } else if (dynamic_cast(&_route)) { + /* tracks run before busses */ + process_group = 1; + } else { + /* busses run after tracks */ + process_group = 2; + } if (SoundGrid::instance().add_rack_synchronous (_cluster_type, process_group, r.n_outputs().n_audio(), _rack_id)) { throw failed_constructor(); @@ -81,11 +88,21 @@ SoundGridRack::~SoundGridRack () } } +int +SoundGridRack::reconfigure (uint32_t channels) +{ + return SoundGrid::instance().configure_io (_cluster_type, _rack_id, channels); +} + +int +SoundGridRack::set_process_group (uint32_t /*pg*/) +{ + return 0; +} + int SoundGridRack::make_connections () { - DEBUG_TRACE (DEBUG::SoundGrid, string_compose ("Mapping input for %1\n", _route.name())); - /* we need to deliver out output (essentially at the fader) to the SG server, which will happen via the native OS audio driver (and thus via JACK). the output needs to get to our chainer, so we map its input(s) to one or more unused JACK ports. we then connect @@ -93,37 +110,86 @@ SoundGridRack::make_connections () */ _route.output()->disconnect (this); - -// SoundGrid::instance().connect (SoundGrid::PhysicalInputPort (0), -// SoundGrid::DriverOutputPort (0)); PortSet& ports (_route.output()->ports()); uint32_t channel = 0; + boost::shared_ptr master_out = _route.session().master_out(); + bool is_track = (dynamic_cast(&_route) != 0) && !_route.is_hidden(); + + DEBUG_TRACE (DEBUG::SoundGrid, string_compose ("Mapping input for %1 (track ? %2) with %3 outputs\n", + _route.name(), is_track, ports.num_ports())); for (PortSet::iterator p = ports.begin(); p != ports.end(); ++p, ++channel) { + DEBUG_TRACE (DEBUG::SoundGrid, string_compose ("Looking at output %1\n", p->name())); + if (p->type() != DataType::AUDIO) { continue; } - /* find a JACK port that will be used to deliver data to the chainer input */ + if (is_track) { - string portname = SoundGrid::instance().sg_port_as_jack_port (SoundGrid::TrackInputPort (_rack_id, channel)); - - if (portname.empty()) { - continue; + /* find a JACK port that will be used to deliver data to the track's chainer's input */ + + string portname; + + if (dynamic_cast (&_route) != 0) { + portname = SoundGrid::instance().sg_port_as_jack_port (SoundGrid::TrackInputPort (_rack_id, channel)); + } else { + /* bus */ + portname = SoundGrid::instance().sg_port_as_jack_port (SoundGrid::BusInputPort (_rack_id, channel)); + } + + if (portname.empty()) { + DEBUG_TRACE (DEBUG::SoundGrid, "no JACK port found to route track audio to SG\n"); + continue; + } + + /* connect this port to it */ + + p->connect (portname); } - /* connect this port to it */ - - p->connect (portname); - /* Now wire up the output of our SG chainer to ... yes, to what precisely ? - For now, wire it up to physical outputs 1 ( + 2, etc) + For now: + + - if its the master or monitor bus, wire it up to physical outputs 1 ( + 2, etc) + - otherwise, wire it up to the master bus. */ - SoundGrid::instance().connect (SoundGrid::TrackOutputPort (_rack_id, channel), SoundGrid::PhysicalOutputPort (channel)); + + if (_route.is_master()) { + + SoundGrid::instance().connect (SoundGrid::BusOutputPort (_rack_id, channel), + SoundGrid::PseudoPhysicalOutputPort (channel)); + + /* how to wire to the monitor bus ? */ + + } else if (_route.is_monitor()) { + + /* XXX force different physical wiring for the monitor bus just so that it shows up + differently in any wiring graphs. + */ + + SoundGrid::instance().connect (SoundGrid::BusOutputPort (_rack_id, channel), + SoundGrid::PseudoPhysicalOutputPort (channel+4)); + + + } else if (_route.is_hidden()) { + + /* auditioner - wire it directly to the "outputs" */ + + SoundGrid::instance().connect (SoundGrid::BusOutputPort (_rack_id, channel), + SoundGrid::PseudoPhysicalOutputPort (channel)); + + } else { + + /* wire normal tracks and busses to the master bus */ + + SoundGrid::instance().connect (SoundGrid::TrackOutputPort (_rack_id, channel), + SoundGrid::BusInputPort (master_out->rack_id(), channel)); + } } return 0; diff --git a/libs/ardour/soundgrid.mm b/libs/ardour/soundgrid.mm index c90406e2a1..3c3f5f79c4 100644 --- a/libs/ardour/soundgrid.mm +++ b/libs/ardour/soundgrid.mm @@ -104,104 +104,8 @@ SoundGrid::~SoundGrid() } int -SoundGrid::connect_io_to_driver (uint32_t ninputs, uint32_t noutputs) -{ - /* the JACK ports for the native OS audio driver already exist, - because JACK will have created them based on the native - driver will have told JACK how many there are. - - but we still need to connect the SG ports so that signal - does actually flow between the physical IO ports and the - native driver (thus enabling JACK to read/write data) - - this is a special case that benefits from not calling connect() many times. - */ - - DEBUG_TRACE (DEBUG::SoundGrid, string_compose ("setting up wiring for %1 inputs and %2 outputs\n", ninputs, noutputs)); - - if (ninputs) { - - WSAssignmentsCommand inputsCommand; - Init_WSAddAssignmentsCommand(&inputsCommand, ninputs, (WSDControllerHandle)this, 0); - - for (uint32_t n = 0; n < ninputs; ++n) { - - ARDOUR::SoundGrid::DriverOutputPort dst (n); // readable driver/JACK port - ARDOUR::SoundGrid::PhysicalInputPort src (n); // where the signal should come from - WSAudioAssignment &assignment (inputsCommand.in_Assignments.m_aAssignments[n]); - - src.set_source (assignment); - dst.set_destination (assignment); - } - - int ret = command (&inputsCommand.m_command); - - Dispose_WSAudioAssignmentBatch (&inputsCommand.in_Assignments); - - if (ret != 0) { - return -1; - } - } - - if (noutputs) { - - WSAssignmentsCommand outputsCommand; - Init_WSAddAssignmentsCommand(&outputsCommand, noutputs, (WSDControllerHandle)this, 0); - - for (uint32_t n = 0; n < noutputs; ++n) { - - ARDOUR::SoundGrid::DriverInputPort src (n); // writable driver/JACK port - ARDOUR::SoundGrid::PhysicalOutputPort dst (n); // physical channel where the signal should go - WSAudioAssignment &assignment (outputsCommand.in_Assignments.m_aAssignments[n]); - - src.set_source (assignment); - dst.set_destination (assignment); - } - - int ret = command (&outputsCommand.m_command); - - Dispose_WSAudioAssignmentBatch (&outputsCommand.in_Assignments); - - if (ret != 0) { - return -1; - } - } - - return 0; -} - -int -SoundGrid::configure_driver (uint32_t inputs, uint32_t outputs, uint32_t tracks) -{ - WSConfigSGDriverCommand myCommand; - uint32_t in = inputs+tracks; - uint32_t out = outputs+tracks; - - in = std::min (in, 32U); - out = std::min (out, 32U); - - Init_WSConfigSGDriverCommand (&myCommand, in, out, (WSDControllerHandle)this, 0); - - DEBUG_TRACE (DEBUG::SoundGrid, string_compose ("Initializing SG driver to use %1 inputs + %2 outputs\n", in, out)); - - if (command (&myCommand.m_command)) { - return -1; - } - - /* wire up inputs and outputs */ - - connect_io_to_driver (inputs, outputs); - - /* set up the in-use bool vector */ - - _driver_output_ports_in_use.assign (outputs, false); - _driver_input_ports_in_use.assign (inputs, false); - - return 0; -} - -int -SoundGrid::initialize (void* window_handle, uint32_t max_tracks) +SoundGrid::initialize (void* window_handle, uint32_t max_tracks, uint32_t max_busses, + uint32_t /*physical_inputs*/, uint32_t physical_outputs) { if (!_sg) { WTErr ret; @@ -219,6 +123,11 @@ SoundGrid::initialize (void* window_handle, uint32_t max_tracks) //This will probably be changed to eClusterType_GroupTrack in future. mixer_limits.m_clusterConfigs[eClusterType_InputTrack].m_uiIndexNum = max_tracks; + // number of group (mixing) tracks needs to match the number of physical outputs, plus + // the number of busses we expect + + mixer_limits.m_clusterConfigs[eClusterType_GroupTrack].m_uiIndexNum = max_busses + physical_outputs; + DEBUG_TRACE (DEBUG::SoundGrid, string_compose ("Initializing SG Core with %1 tracks\n", max_tracks)); // XXX use portable, installable technique for this @@ -274,6 +183,142 @@ SoundGrid::available () return instance().dl_handle != 0; } +int +SoundGrid::configure_driver (uint32_t inputs, uint32_t outputs, uint32_t tracks) +{ + WSConfigSGDriverCommand myCommand; + uint32_t in = inputs+tracks; + uint32_t out = outputs+tracks; + + in = std::min (in, 32U); + out = std::min (out, 32U); + + Init_WSConfigSGDriverCommand (&myCommand, in, out, (WSDControllerHandle)this, 0); + + DEBUG_TRACE (DEBUG::SoundGrid, string_compose ("Initializing SG driver to use %1 inputs + %2 outputs\n", in, out)); + + if (command (&myCommand.m_command)) { + return -1; + } + + /* set up the in-use bool vector */ + + _driver_output_ports_in_use.assign (out, false); + _driver_input_ports_in_use.assign (in, false); + + /* reserve the actual inputs and outputs */ + + for (uint32_t n = 0; n < inputs; ++n) { + _driver_input_ports_in_use[n] = true; + } + + for (uint32_t n = 0; n < outputs; ++n) { + _driver_output_ports_in_use[n] = true; + } + + /* Create mono GroupTracks for mixing inputs sent to each driver input. + + These are the ONLY chainers that talk to the physical outputs, anything + else that wants to route to a physical output must go via the corresponding + PseudoPhysicalOutputPort (which corresponds to one of these GroupTracks). + */ + + for (uint32_t n = 0; n < outputs; ++n) { + uint32_t handle; + + /* process group is set to 7, because these should run last no matter what + */ + + if (add_rack_synchronous (eClusterType_GroupTrack, 7, 1, handle)) { + error << string_compose (_("Cannot create mixing channel for driver output %1"), n) << endmsg; + return -1; + } + if (set_gain (eClusterType_GroupTrack, handle, 1000.0)) { + error << string_compose (_("Cannot set gain for mixing channel for driver output %1"), n) << endmsg; + return -1; + } + } + + if (outputs) { + WSAssignmentsCommand outputsCommand; + Init_WSAddAssignmentsCommand(&outputsCommand, outputs, (WSDControllerHandle)this, 0); + + for (uint32_t n = 0; n < outputs; ++n) { + + ARDOUR::SoundGrid::BusOutputPort src (n, 0); // single output of the group track + ARDOUR::SoundGrid::PhysicalOutputPort dst (n); // real physical channel where the signal should go + WSAudioAssignment &assignment (outputsCommand.in_Assignments.m_aAssignments[n]); + + src.set_source (assignment); + dst.set_destination (assignment); + } + + int ret = command (&outputsCommand.m_command); + + Dispose_WSAudioAssignmentBatch (&outputsCommand.in_Assignments); + + if (ret != 0) { + return -1; + } + } + + /* wire up inputs and outputs */ + + if (inputs) { + + DEBUG_TRACE (DEBUG::SoundGrid, string_compose ("setting up wiring for %1 inputs\n", inputs)); + + WSAssignmentsCommand inputsCommand; + Init_WSAddAssignmentsCommand(&inputsCommand, inputs, (WSDControllerHandle)this, 0); + + for (uint32_t n = 0; n < inputs; ++n) { + + ARDOUR::SoundGrid::PhysicalInputPort src (n); // physical channel where the signal should come from + ARDOUR::SoundGrid::DriverOutputPort dst (n); // driver channel/JACK port where it should be readable from + WSAudioAssignment &assignment (inputsCommand.in_Assignments.m_aAssignments[n]); + + src.set_source (assignment); + dst.set_destination (assignment); + } + + int ret = command (&inputsCommand.m_command); + + Dispose_WSAudioAssignmentBatch (&inputsCommand.in_Assignments); + + if (ret != 0) { + return -1; + } + } + + if (outputs) { + + DEBUG_TRACE (DEBUG::SoundGrid, string_compose ("setting up wiring for %1 outputs\n", outputs)); + + WSAssignmentsCommand outputsCommand; + Init_WSAddAssignmentsCommand(&outputsCommand, outputs, (WSDControllerHandle)this, 0); + + for (uint32_t n = 0; n < outputs; ++n) { + + ARDOUR::SoundGrid::DriverInputPort src (n); // writable driver/JACK port + ARDOUR::SoundGrid::PseudoPhysicalOutputPort dst (n); // physical channel where the signal should go + WSAudioAssignment &assignment (outputsCommand.in_Assignments.m_aAssignments[n]); + + src.set_source (assignment); + dst.set_destination (assignment); + } + + int ret = command (&outputsCommand.m_command); + + Dispose_WSAudioAssignmentBatch (&outputsCommand.in_Assignments); + + if (ret != 0) { + return -1; + } + } + + return 0; +} + int SoundGrid::get (WSControlID* id, WSControlInfo* info) { @@ -665,6 +710,9 @@ SoundGrid::add_rack_synchronous (uint32_t clusterType, int32_t process_group, ui channels = 1; + DEBUG_TRACE (DEBUG::SoundGrid, string_compose ("add rack sync, type %1 channels %2 pgroup %3\n", + clusterType, channels, process_group)); + command (Init_WSAddTrackCommand (&myCommand, clusterType, channels, process_group, (WSDControllerHandle)this, 0)); if (0 == myCommand.m_command.out_status) { @@ -766,44 +814,51 @@ SoundGrid::jack_port_as_sg_port (const string& jack_port, Port& result) return false; } -std::string +string SoundGrid::sg_port_as_jack_port (const Port& sgport) { - SG_JACKMap::iterator x = soundgrid_jack_map.find (sgport); + string jack_port; + SG_JACKMap::iterator x = soundgrid_jack_map.find (sgport); + + if (x != soundgrid_jack_map.end()) { + DEBUG_TRACE (DEBUG::SoundGrid, string_compose ("sgport %1 found in SG/Jack map as %2\n", sgport, x->second)); - if (x != soundgrid_jack_map.end()) { - return x->second; - } + for (SG_JACKMap::iterator nn = soundgrid_jack_map.begin(); nn != soundgrid_jack_map.end(); ++nn) { + cerr << "SG_JACKMAP " << nn->first << " => " << nn->second << endl; + } - /* OK, so this SG port has never been connected (and thus mapped) to - a JACK port. We need to find a free driver channel and connect it - to the specified sgport. - */ - - DEBUG_TRACE (DEBUG::SoundGrid, string_compose ("Try to map SG port as JACK port\n", sgport)); - - uint32_t driver_channel; - bool found = false; - bool inputs = false; - - if (sgport.accepts_input()) { - - inputs = true; - - uint32_t n = _driver_output_ports_in_use.size () - 1; - - /* Find next free driver channel to use to represent the given SG port. - - Note that we search backwards. This doesn't eliminate the issues that - will arise if we end up overlapping with the ports used for normal - physical output, but makes it less likely. - */ - - for (vector::reverse_iterator x = _driver_output_ports_in_use.rbegin(); x != _driver_output_ports_in_use.rend(); ++x) { - if (!(*x)) { - - DEBUG_TRACE (DEBUG::SoundGrid, string_compose ("Found unused driver output channel %1 to map %2\n", n, sgport)); - driver_channel = n; + return x->second; + } + + /* OK, so this SG port has never been connected (and thus mapped) to + a JACK port. We need to find a free driver channel and connect it + to the specified sgport. + */ + + DEBUG_TRACE (DEBUG::SoundGrid, string_compose ("Try to map SG port %1 as JACK port\n", sgport)); + + uint32_t driver_channel; + bool found = false; + bool inputs = false; + + if (sgport.accepts_input()) { + + inputs = true; + + uint32_t n = _driver_output_ports_in_use.size () - 1; + + /* Find next free driver channel to use to represent the given SG port. + + Note that we search backwards. This doesn't eliminate the issues that + will arise if we end up overlapping with the ports used for normal + physical output, but makes it less likely. + */ + + for (vector::reverse_iterator x = _driver_output_ports_in_use.rbegin(); x != _driver_output_ports_in_use.rend(); ++x) { + if (!(*x)) { + + DEBUG_TRACE (DEBUG::SoundGrid, string_compose ("Found unused driver output channel %1 to map %2\n", n, sgport)); + driver_channel = n; found = true; break; } @@ -836,37 +891,36 @@ SoundGrid::sg_port_as_jack_port (const Port& sgport) if (found) { if (inputs) { Port driverport = DriverInputPort (driver_channel); - DEBUG_TRACE (DEBUG::SoundGrid, string_compose ("connecting driver_channel %2 to sgport %1\n", - sgport, driver_channel)); if (connect (driverport, sgport) != 0) { return string(); } } else { Port driverport = DriverOutputPort (driver_channel); - DEBUG_TRACE (DEBUG::SoundGrid, string_compose ("connecting sgport %1 to driver channel %2\n", - sgport, driver_channel)); if (connect (sgport, driverport) != 0) { return string(); } } - } - /* successfully connected SG physical IO to SG driver: do record keeping */ + /* do record keeping */ + + if (inputs) { + _driver_output_ports_in_use[driver_channel] = true; + jack_port = string_compose ("system:playback_%1", driver_channel+1); + } else { + _driver_input_ports_in_use[driver_channel] = true; + jack_port = string_compose ("system:capture_%1", driver_channel+1); + } + + jack_soundgrid_map.insert (make_pair (jack_port, sgport)); + soundgrid_jack_map.insert (make_pair (sgport, jack_port)); - string jack_port; - - if (inputs) { - _driver_output_ports_in_use[driver_channel] = true; - jack_port = string_compose ("system:playback_%1", driver_channel+1); + + DEBUG_TRACE (DEBUG::SoundGrid, string_compose ("map SG port %1 as %2\n", sgport, jack_port)); + } else { - _driver_input_ports_in_use[driver_channel] = true; - jack_port = string_compose ("system:capture_%1", driver_channel+1); + DEBUG_TRACE (DEBUG::SoundGrid, "no spare driver channels/JACK ports were found to use for routing to SG\n"); } - jack_soundgrid_map.insert (make_pair (jack_port, sgport)); - soundgrid_jack_map.insert (make_pair (sgport, jack_port)); - - DEBUG_TRACE (DEBUG::SoundGrid, string_compose ("map SG port %1 as %2\n", sgport, jack_port)); return jack_port; } @@ -955,12 +1009,241 @@ SoundGrid::Port::set_destination (WSAudioAssignment& assignment) const assignment.m_asgnDest.m_PrePost = sg_source(); } +int +SoundGrid::configure_io (uint32_t cluster_type, uint32_t rack_id, uint32_t channels) +{ + WSEvent configEvent; + Init_WSEvent(&configEvent); + + /* XXX not sure how this works for multichannel as of oct 30th 2012 */ + + configEvent.eventID = eEventID_MoveTo; + configEvent.controllerValue = (channels == 2) ? 1 : 0; + + Init_WSControlID(&configEvent.controlID); + configEvent.controlID.clusterID.clusterType = cluster_type; + configEvent.controlID.clusterID.clusterHandle = rack_id; + + configEvent.controlID.sectionControlID.sectionType = eControlType_Input; + configEvent.controlID.sectionControlID.sectionIndex = eControlType_Input_Local; + configEvent.controlID.sectionControlID.channelIndex = wvEnum_Unknown; + configEvent.controlID.sectionControlID.controlID = eControlID_Input_MonoStereo; + + if (set (&configEvent, "I/O configure")) { + return -1; + } + + return 0; +} + std::ostream& operator<< (std::ostream& out, const SoundGrid::Port& p) { - out << p.ctype << ':' << p.cid - << ':' << p.stype << ':' << p.sindex << ':' << p.sid - << ':' << p.channel << ':' << p.position; + switch (p.ctype) { + case eClusterType_Inputs: + out << "inputs"; + switch (p.cid) { + case eClusterHandle_Physical_Driver: + out << ":driver"; + break; + case eClusterHandle_Physical_IO: + out << ":IO"; + break; + default: + out << ":unknown"; + } + break; + case eClusterType_Outputs: + out << "outputs"; + switch (p.cid) { + case eClusterHandle_Physical_Driver: + out << ":driver"; + break; + case eClusterHandle_Physical_IO: + out << ":IO"; + break; + default: + out << ":unknown"; + } + break; + case eClusterType_InputTrack: + out << "InputTrack"; + break; + case eClusterType_GroupTrack: + out << "GroupTrack"; + break; + case eClusterType_AuxTrack: + out << "AuxTrack"; + break; + case eClusterType_MatrixTrack: + out << "MatrixTrack"; + break; + case eClusterType_LCRMTrack: + out << "LCRMTrack"; + break; + case eClusterType_DCATrack: + out << "DCATrack"; + break; + case eClusterType_CueTrack: + out << "CueTrack"; + break; + case eClusterType_TBTrack: + out << "TBTrack"; + break; + default: + out << "unknown"; + break; + } + + if (p.ctype != eClusterType_Inputs && p.ctype != eClusterType_Outputs) { + + out << ":ID " << p.cid << ':'; + + switch (p.stype) { + + case eControlType_Input: + out << "input " << p.sindex << ':'; + switch (p.sid) { + case eControlID_Input_Assignment_Left: + out << "assignment_left"; + break; + case eControlID_Input_Assignment_Right: + out << "assignment_right"; + break; + case eControlID_Input_MonoStereo: + out << "monostereo"; + break; + case eControlID_Input_Choose_Left_Right: + out << "choose_left_right"; + break; + case eControlID_Input_Choose_Link_UnLink: + out << "choose_link_unlink"; + break; + case eControlID_Input_Trim: + out << "trim"; + break; + case eControlID_Input_Phase_On_Off: + out << "phase_on_off"; + break; + case eControlID_Input_Pad_On_Off: + out << "pad_on_off"; + break; + case eControlID_Input_48V_On_Off: + out << "48v_on_off"; + break; + case eControlID_Input_Digital_Trim: + out << "digital_trim"; + break; + case eControlID_Input_Digital_Delay: + out << "digital_delay"; + break; + case eControlID_Input_Direct: + out << "direct"; + break; + case eControlID_Input_Choose_In_Pre_Post: + out << "choose_in_pre_post"; + break; + case eControlID_Input_VU_Left: + out << "vu_left"; + break; + case eControlID_Input_VU_Right: + out << "vu_right"; + break; + default: + out << "unknown"; + } + break; + case eControlType_Output: + out << "output " << p.sindex << ':'; + switch (p.sid) { + case eControlID_Output_Gain: + out << "gain"; + break; + case eControlID_Output_Pan: + out << "pan"; + break; + case eControlID_Output_Arm_On_Off: + out << "arm_on_off"; + break; + case eControlID_Output_Assign_On_Off: + out << "assign_on_off"; + break; + case eControlID_Output_Select_On_Off: + out << "select_on_off"; + break; + case eControlID_Output_Cue_On_Off: + out << "cue_on_off"; + break; + case eControlID_Output_Mute_On_Off: + out << "mute_on_off"; + break; + case eControlID_Output_VU_Left: + out << "vu_left"; + break; + case eControlID_Output_VU_Right: + out << "vu_right"; + break; + case eControlID_Output_MonoStereoPreFader: + out << "monostereoprefader"; + break; + case eControlID_Output_MonoStereoPostFader: + out << "monostereopostfader"; + break; + case eControlID_Output_MonoStereoPostPan: + out << "monostereopostpan"; + break; + case eControlID_Output_DirectMixMtxSrc: + out << "directmixmtxsrc"; + break; + case eControlID_Output_DirectLeft: + out << "directleft"; + break; + case eControlID_Output_DirectRight: + out << "directright"; + break; + default: + out << "unknown"; + break; + } + break; + case eControlType_Filter: + out << "filter"; + break; + case eControlType_Dynamics: + out << "dynamics"; + break; + case eControlType_EQ: + out << "eq"; + break; + case eControlType_UserPlugins: + out << "userplugins"; + break; + case eControlType_AuxSend: + out << "auxsend"; + break; + case eControlType_AuxReturn: + out << "auxreturn"; + break; + case eControlType_Name: + out << "name"; + break; + case eControlType_Display: + out << "display"; + break; + } + } + + out << ":chn " << p.channel << ':'; + + switch (p.position) { + case SoundGrid::Port::Post: + out << "post"; + break; + case SoundGrid::Port::Pre: + out << "pre"; + break; + } + return out; }