From 96cd6c993b0ed9a775f7ea096e2afe01be9d00b9 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Sun, 20 Dec 2009 16:49:55 +0000 Subject: [PATCH] substantial overhaul of MCU code - no more separate thread, just connect to signals on ports already listened to by the MidiUI thread in libardour (feedback is missing - needs a timeout connection); also reformat some big chunks of code to fit ardour coding style git-svn-id: svn://localhost/ardour2/branches/3.0@6377 d708f5d6-7413-0410-9779-e7cbd77b26cf --- libs/surfaces/mackie/controls.h | 2 +- .../mackie/mackie_control_protocol.cc | 1072 ++++++++--------- .../surfaces/mackie/mackie_control_protocol.h | 297 +++-- .../mackie/mackie_control_protocol_poll.cc | 147 +-- libs/surfaces/mackie/mackie_port.cc | 144 +-- 5 files changed, 724 insertions(+), 938 deletions(-) diff --git a/libs/surfaces/mackie/controls.h b/libs/surfaces/mackie/controls.h index 8a7740598f..398d7e689a 100644 --- a/libs/surfaces/mackie/controls.h +++ b/libs/surfaces/mackie/controls.h @@ -228,7 +228,7 @@ public: virtual unsigned int in_use_timeout() { return _in_use_timeout; } /// Keep track of the timeout so it can be updated with more incoming events - PBD::ScopedConnection in_use_connection; + sigc::connection in_use_connection; private: int _id; diff --git a/libs/surfaces/mackie/mackie_control_protocol.cc b/libs/surfaces/mackie/mackie_control_protocol.cc index 9698b299b9..9f4ffb10c0 100644 --- a/libs/surfaces/mackie/mackie_control_protocol.cc +++ b/libs/surfaces/mackie/mackie_control_protocol.cc @@ -8,7 +8,7 @@ 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 + 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 @@ -40,11 +40,12 @@ #include "pbd/memento_command.h" #include "pbd/convert.h" -#include "ardour/session.h" -#include "ardour/route.h" -#include "ardour/location.h" #include "ardour/dB.h" +#include "ardour/debug.h" +#include "ardour/location.h" #include "ardour/panner.h" +#include "ardour/route.h" +#include "ardour/session.h" #include "ardour/tempo.h" #include "ardour/types.h" @@ -71,105 +72,89 @@ using boost::shared_ptr; MackieMidiBuilder builder; MackieControlProtocol::MackieControlProtocol (Session& session) - : ControlProtocol (session, X_("Mackie")) - , _current_initial_bank( 0 ) - , _surface( 0 ) - , _ports_changed( false ) - , _polling( true ) - , pfd( 0 ) - , nfds( 0 ) - , _jog_wheel( *this ) - , _timecode_type( ARDOUR::AnyTime::BBT ) -{ -#ifdef DEBUG - cout << "MackieControlProtocol::MackieControlProtocol" << endl; -#endif - // will start reading from ports, as soon as there are some - pthread_create_and_store (X_("mackie monitor"), &thread, _monitor_work, this); + : ControlProtocol (session, X_("Mackie")) + , _current_initial_bank (0) + , _surface (0) + , _jog_wheel (*this) + , _timecode_type (ARDOUR::AnyTime::BBT) +{ + DEBUG_TRACE (DEBUG::MackieControl, "MackieControlProtocol::MackieControlProtocol\n"); } MackieControlProtocol::~MackieControlProtocol() { -#ifdef DEBUG - cout << "~MackieControlProtocol::MackieControlProtocol" << endl; -#endif - try - { + DEBUG_TRACE (DEBUG::MackieControl, "MackieControlProtocol::~MackieControlProtocol\n"); + + try { close(); } - catch ( exception & e ) - { + catch (exception & e) { cout << "~MackieControlProtocol caught " << e.what() << endl; } - catch ( ... ) - { + catch (...) { cout << "~MackieControlProtocol caught unknown" << endl; } -#ifdef DEBUG - cout << "finished ~MackieControlProtocol::MackieControlProtocol" << endl; -#endif + + DEBUG_TRACE (DEBUG::MackieControl, "finished ~MackieControlProtocol::MackieControlProtocol\n"); } -Mackie::Surface & MackieControlProtocol::surface() +Mackie::Surface& +MackieControlProtocol::surface() { - if ( _surface == 0 ) - { - throw MackieControlException( "_surface is 0 in MackieControlProtocol::surface" ); + if (_surface == 0) { + throw MackieControlException ("_surface is 0 in MackieControlProtocol::surface"); } return *_surface; } -const Mackie::SurfacePort & MackieControlProtocol::mcu_port() const +const Mackie::SurfacePort& +MackieControlProtocol::mcu_port() const { - if ( _ports.size() < 1 ) - { + if (_ports.size() < 1) { return _dummy_port; - } - else - { - return dynamic_cast( *_ports[0] ); + } else { + return dynamic_cast (*_ports[0]); } } -Mackie::SurfacePort & MackieControlProtocol::mcu_port() +Mackie::SurfacePort& +MackieControlProtocol::mcu_port() { - if ( _ports.size() < 1 ) - { + if (_ports.size() < 1) { return _dummy_port; - } - else - { - return dynamic_cast( *_ports[0] ); + } else { + return dynamic_cast (*_ports[0]); } } // go to the previous track. // Assume that get_sorted_routes().size() > route_table.size() -void MackieControlProtocol::prev_track() +void +MackieControlProtocol::prev_track() { - if ( _current_initial_bank >= 1 ) - { + if (_current_initial_bank >= 1) { session->set_dirty(); - switch_banks( _current_initial_bank - 1 ); + switch_banks (_current_initial_bank - 1); } } // go to the next track. // Assume that get_sorted_routes().size() > route_table.size() -void MackieControlProtocol::next_track() +void +MackieControlProtocol::next_track() { Sorted sorted = get_sorted_routes(); - if ( _current_initial_bank + route_table.size() < sorted.size() ) + if (_current_initial_bank + route_table.size() < sorted.size()) { session->set_dirty(); - switch_banks( _current_initial_bank + 1 ); + switch_banks (_current_initial_bank + 1); } } -void MackieControlProtocol::clear_route_signals() +void +MackieControlProtocol::clear_route_signals() { - for( RouteSignals::iterator it = route_signals.begin(); it != route_signals.end(); ++it ) - { + for (RouteSignals::iterator it = route_signals.begin(); it != route_signals.end(); ++it) { delete *it; } route_signals.clear(); @@ -177,41 +162,42 @@ void MackieControlProtocol::clear_route_signals() // return the port for a given id - 0 based // throws an exception if no port found -MackiePort & MackieControlProtocol::port_for_id( uint32_t index ) +MackiePort& +MackieControlProtocol::port_for_id (uint32_t index) { uint32_t current_max = 0; - for( MackiePorts::iterator it = _ports.begin(); it != _ports.end(); ++it ) - { + for (MackiePorts::iterator it = _ports.begin(); it != _ports.end(); ++it) { current_max += (*it)->strips(); - if ( index < current_max ) return **it; + if (index < current_max) return **it; } // oops - no matching port ostringstream os; os << "No port for index " << index; - throw MackieControlException( os.str() ); + throw MackieControlException (os.str()); } // predicate for sort call in get_sorted_routes struct RouteByRemoteId { - bool operator () ( const shared_ptr & a, const shared_ptr & b ) const + bool operator () (const shared_ptr & a, const shared_ptr & b) const { return a->remote_control_id() < b->remote_control_id(); } - bool operator () ( const Route & a, const Route & b ) const + bool operator () (const Route & a, const Route & b) const { return a.remote_control_id() < b.remote_control_id(); } - bool operator () ( const Route * a, const Route * b ) const + bool operator () (const Route * a, const Route * b) const { return a->remote_control_id() < b->remote_control_id(); } }; -MackieControlProtocol::Sorted MackieControlProtocol::get_sorted_routes() +MackieControlProtocol::Sorted +MackieControlProtocol::get_sorted_routes() { Sorted sorted; @@ -221,11 +207,11 @@ MackieControlProtocol::Sorted MackieControlProtocol::get_sorted_routes() // routes with remote_id 0 should never be added // TODO verify this with ardour devs - // remote_ids.insert( 0 ); + // remote_ids.insert (0); // sort in remote_id order, and exclude master, control and hidden routes // and any routes that are already set. - for (RouteList::iterator it = routes->begin(); it != routes->end(); ++it ) + for (RouteList::iterator it = routes->begin(); it != routes->end(); ++it) { Route & route = **it; if ( @@ -233,23 +219,25 @@ MackieControlProtocol::Sorted MackieControlProtocol::get_sorted_routes() && !route.is_master() && !route.is_hidden() && !route.is_control() - && remote_ids.find( route.remote_control_id() ) == remote_ids.end() + && remote_ids.find (route.remote_control_id()) == remote_ids.end() ) { - sorted.push_back( *it ); - remote_ids.insert( route.remote_control_id() ); + sorted.push_back (*it); + remote_ids.insert (route.remote_control_id()); } } - sort( sorted.begin(), sorted.end(), RouteByRemoteId() ); + sort (sorted.begin(), sorted.end(), RouteByRemoteId()); return sorted; } -void MackieControlProtocol::refresh_current_bank() +void +MackieControlProtocol::refresh_current_bank() { - switch_banks( _current_initial_bank ); + switch_banks (_current_initial_bank); } -void MackieControlProtocol::switch_banks( int initial ) +void +MackieControlProtocol::switch_banks (int initial) { // DON'T prevent bank switch if initial == _current_initial_bank // because then this method can't be used as a refresh @@ -257,11 +245,9 @@ void MackieControlProtocol::switch_banks( int initial ) // sanity checking Sorted sorted = get_sorted_routes(); int delta = sorted.size() - route_table.size(); - if ( initial < 0 || ( delta > 0 && initial > delta ) ) + if (initial < 0 || (delta > 0 && initial > delta)) { -#ifdef DEBUG - cout << "not switching to " << initial << endl; -#endif + DEBUG_TRACE (DEBUG::MackieControl, string_compose ("not switching to %1\n", initial)); return; } _current_initial_bank = initial; @@ -271,108 +257,98 @@ void MackieControlProtocol::switch_banks( int initial ) clear_route_signals(); // now set the signals for new routes - if ( _current_initial_bank <= sorted.size() ) + if (_current_initial_bank <= sorted.size()) { // fetch the bank start and end to switch to - uint32_t end_pos = min( route_table.size(), sorted.size() ); + uint32_t end_pos = min (route_table.size(), sorted.size()); Sorted::iterator it = sorted.begin() + _current_initial_bank; Sorted::iterator end = sorted.begin() + _current_initial_bank + end_pos; -#ifdef DEBUG - cout << "switch to " << _current_initial_bank << ", " << end_pos << endl; -#endif + + DEBUG_TRACE (DEBUG::MackieControl, string_compose ("switch to %1, %2\n", _current_initial_bank, end_pos)); // link routes to strips uint32_t i = 0; - for ( ; it != end && it != sorted.end(); ++it, ++i ) + for (; it != end && it != sorted.end(); ++it, ++i) { boost::shared_ptr route = *it; Strip & strip = *surface().strips[i]; -#ifdef DEBUG - cout << "remote id " << route->remote_control_id() << " connecting " << route->name() << " to " << strip.name() << " with port " << port_for_id(i) << endl; -#endif + + DEBUG_TRACE (DEBUG::MackieControl, string_compose ("remote id %1 connecting %2 to %3 with port %4\n", + route->remote_control_id(), route->name(), strip.name(), port_for_id(i))); route_table[i] = route; - RouteSignal * rs = new RouteSignal (route, *this, strip, port_for_id(i) ); - route_signals.push_back( rs ); + RouteSignal * rs = new RouteSignal (route, *this, strip, port_for_id(i)); + route_signals.push_back (rs); // update strip from route rs->notify_all(); } // create dead strips if there aren't enough routes to // fill a bank - for ( ; i < route_table.size(); ++i ) + for (; i < route_table.size(); ++i) { Strip & strip = *surface().strips[i]; // send zero for this strip MackiePort & port = port_for_id(i); - port.write( builder.zero_strip( port, strip ) ); + port.write (builder.zero_strip (port, strip)); } } // display the current start bank. - surface().display_bank_start( mcu_port(), builder, _current_initial_bank ); + surface().display_bank_start (mcu_port(), builder, _current_initial_bank); } -void MackieControlProtocol::zero_all() +void +MackieControlProtocol::zero_all() { // TODO turn off Timecode displays // zero all strips - for ( Surface::Strips::iterator it = surface().strips.begin(); it != surface().strips.end(); ++it ) + for (Surface::Strips::iterator it = surface().strips.begin(); it != surface().strips.end(); ++it) { - MackiePort & port = port_for_id( (*it)->index() ); - port.write( builder.zero_strip( port, **it ) ); + MackiePort & port = port_for_id ((*it)->index()); + port.write (builder.zero_strip (port, **it)); } // and the master strip - mcu_port().write( builder.zero_strip( dynamic_cast( mcu_port() ), master_strip() ) ); + mcu_port().write (builder.zero_strip (dynamic_cast (mcu_port()), master_strip())); // turn off global buttons and leds // global buttons are only ever on mcu_port, so we don't have // to figure out which port. - for ( Surface::Controls::iterator it = surface().controls.begin(); it != surface().controls.end(); ++it ) + for (Surface::Controls::iterator it = surface().controls.begin(); it != surface().controls.end(); ++it) { Control & control = **it; - if ( !control.group().is_strip() && control.accepts_feedback() ) + if (!control.group().is_strip() && control.accepts_feedback()) { - mcu_port().write( builder.zero_control( control ) ); + mcu_port().write (builder.zero_control (control)); } } // any hardware-specific stuff - surface().zero_all( mcu_port(), builder ); + surface().zero_all (mcu_port(), builder); } -int MackieControlProtocol::set_active( bool yn ) +int +MackieControlProtocol::set_active (bool yn) { - if ( yn != _active ) + if (yn != _active) { try { // the reason for the locking and unlocking is that // glibmm can't do a condition wait on a RecMutex - if ( yn ) + if (yn) { // TODO what happens if this fails half way? // create MackiePorts { - Glib::Mutex::Lock lock( update_mutex ); + Glib::Mutex::Lock lock (update_mutex); create_ports(); } - // make sure the ports are being listened to - update_ports(); - - // wait until poll thread is running, with ports to poll - // the mutex is only there because conditions require a mutex - { - Glib::Mutex::Lock lock( update_mutex ); - while ( nfds == 0 ) update_cond.wait( update_mutex ); - } - // now initialise MackiePorts - ie exchange sysex messages - for( MackiePorts::iterator it = _ports.begin(); it != _ports.end(); ++it ) - { + for (MackiePorts::iterator it = _ports.begin(); it != _ports.end(); ++it) { (*it)->open(); } @@ -380,8 +356,7 @@ int MackieControlProtocol::set_active( bool yn ) // TODO a more sophisticated approach would // allow things to start up with only an MCU, even if // extenders were specified but not responding. - for( MackiePorts::iterator it = _ports.begin(); it != _ports.end(); ++it ) - { + for (MackiePorts::iterator it = _ports.begin(); it != _ports.end(); ++it) { (*it)->wait_for_init(); } @@ -396,18 +371,14 @@ int MackieControlProtocol::set_active( bool yn ) // send current control positions to surface // must come after _active = true otherwise it won't run update_surface(); - } - else - { + } else { close(); _active = false; } } - catch( exception & e ) - { -#ifdef DEBUG - cout << "set_active to false because exception caught: " << e.what() << endl; -#endif + + catch (exception & e) { + DEBUG_TRACE (DEBUG::MackieControl, string_compose ("set_active to false because exception caught: %1\n", e.what())); _active = false; throw; } @@ -416,141 +387,143 @@ int MackieControlProtocol::set_active( bool yn ) return 0; } -bool MackieControlProtocol::handle_strip_button( Control & control, ButtonState bs, boost::shared_ptr route ) +bool +MackieControlProtocol::handle_strip_button (Control & control, ButtonState bs, boost::shared_ptr route) { bool state = false; - if ( bs == press ) + if (bs == press) { - if ( control.name() == "recenable" ) + if (control.name() == "recenable") { state = !route->record_enabled(); - route->set_record_enable( state, this ); + route->set_record_enable (state, this); } - else if ( control.name() == "mute" ) + else if (control.name() == "mute") { state = !route->muted(); - route->set_mute( state, this ); + route->set_mute (state, this); } - else if ( control.name() == "solo" ) + else if (control.name() == "solo") { state = !route->soloed(); - route->set_solo( state, this ); + route->set_solo (state, this); } - else if ( control.name() == "select" ) + else if (control.name() == "select") { // TODO make the track selected. Whatever that means. - //state = default_button_press( dynamic_cast( control ) ); + //state = default_button_press (dynamic_cast (control)); } - else if ( control.name() == "vselect" ) + else if (control.name() == "vselect") { // TODO could be used to select different things to apply the pot to? - //state = default_button_press( dynamic_cast( control ) ); + //state = default_button_press (dynamic_cast (control)); } } - if ( control.name() == "fader_touch" ) + if (control.name() == "fader_touch") { state = bs == press; - control.strip().gain().in_use( state ); + control.strip().gain().in_use (state); } return state; } -void MackieControlProtocol::update_led( Mackie::Button & button, Mackie::LedState ls ) +void +MackieControlProtocol::update_led (Mackie::Button & button, Mackie::LedState ls) { - if ( ls != none ) + if (ls != none) { SurfacePort * port = 0; - if ( button.group().is_strip() ) + if (button.group().is_strip()) { - if ( button.group().is_master() ) + if (button.group().is_master()) { port = &mcu_port(); } else { - port = &port_for_id( dynamic_cast( button.group() ).index() ); + port = &port_for_id (dynamic_cast (button.group()).index()); } } else { port = &mcu_port(); } - port->write( builder.build_led( button, ls ) ); + port->write (builder.build_led (button, ls)); } } -void MackieControlProtocol::update_timecode_beats_led() +void +MackieControlProtocol::update_timecode_beats_led() { - switch ( _timecode_type ) + switch (_timecode_type) { case ARDOUR::AnyTime::BBT: - update_global_led( "beats", on ); - update_global_led( "timecode", off ); + update_global_led ("beats", on); + update_global_led ("timecode", off); break; case ARDOUR::AnyTime::Timecode: - update_global_led( "timecode", on ); - update_global_led( "beats", off ); + update_global_led ("timecode", on); + update_global_led ("beats", off); break; default: ostringstream os; os << "Unknown Anytime::Type " << _timecode_type; - throw runtime_error( os.str() ); + throw runtime_error (os.str()); } } -void MackieControlProtocol::update_global_button( const string & name, LedState ls ) +void +MackieControlProtocol::update_global_button (const string & name, LedState ls) { - if ( surface().controls_by_name.find( name ) != surface().controls_by_name.end() ) + if (surface().controls_by_name.find (name) != surface().controls_by_name.end()) { - Button * button = dynamic_cast( surface().controls_by_name[name] ); - mcu_port().write( builder.build_led( button->led(), ls ) ); + Button * button = dynamic_cast (surface().controls_by_name[name]); + mcu_port().write (builder.build_led (button->led(), ls)); } else { -#ifdef DEBUG - cout << "Button " << name << " not found" << endl; -#endif + DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Button %1 not found\n", name)); } } -void MackieControlProtocol::update_global_led( const string & name, LedState ls ) +void +MackieControlProtocol::update_global_led (const string & name, LedState ls) { - if ( surface().controls_by_name.find( name ) != surface().controls_by_name.end() ) + if (surface().controls_by_name.find (name) != surface().controls_by_name.end()) { - Led * led = dynamic_cast( surface().controls_by_name[name] ); - mcu_port().write( builder.build_led( *led, ls ) ); + Led * led = dynamic_cast (surface().controls_by_name[name]); + mcu_port().write (builder.build_led (*led, ls)); } else { -#ifdef DEBUG - cout << "Led " << name << " not found" << endl; -#endif + DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Led %1 not found\n", name)); } } // send messages to surface to set controls to correct values -void MackieControlProtocol::update_surface() +void +MackieControlProtocol::update_surface() { - if ( _active ) + if (_active) { // do the initial bank switch to connect signals // _current_initial_bank is initialised by set_state - switch_banks( _current_initial_bank ); + switch_banks (_current_initial_bank); // create a RouteSignal for the master route - boost::shared_ptr mr = master_route (); - if (mr) { - master_route_signal = shared_ptr (new RouteSignal (mr, *this, master_strip(), mcu_port()) ); - // update strip from route - master_route_signal->notify_all(); - } + boost::shared_ptr mr = master_route (); + if (mr) { + master_route_signal = shared_ptr (new RouteSignal (mr, *this, master_strip(), mcu_port())); + // update strip from route + master_route_signal->notify_all(); + } // sometimes the jog wheel is a pot - surface().blank_jog_ring( mcu_port(), builder ); + surface().blank_jog_ring (mcu_port(), builder); // update global buttons and displays notify_record_state_changed(); @@ -559,7 +532,8 @@ void MackieControlProtocol::update_surface() } } -void MackieControlProtocol::connect_session_signals() +void +MackieControlProtocol::connect_session_signals() { // receive routes added session->RouteAdded.connect(session_connections, boost::bind (&MackieControlProtocol::notify_route_added, this, _1)); @@ -576,230 +550,202 @@ void MackieControlProtocol::connect_session_signals() // make sure remote id changed signals reach here // see also notify_route_added Sorted sorted = get_sorted_routes(); - for ( Sorted::iterator it = sorted.begin(); it != sorted.end(); ++it ) - { + + for (Sorted::iterator it = sorted.begin(); it != sorted.end(); ++it) { ((*it)->RemoteControlIDChanged.connect (route_connections, boost::bind(&MackieControlProtocol::notify_remote_id_changed, this))); } } -void MackieControlProtocol::add_port( MIDI::Port & midi_port, int number ) +void +MackieControlProtocol::add_port (MIDI::Port & midi_port, int number) { -#ifdef DEBUG - cout << "add port " << midi_port.name() << ", " << midi_port.device() << ", " << midi_port.type() << endl; - cout << "MIDI::Port::ALSA_Sequencer " << MIDI::Port::ALSA_Sequencer << endl; - cout << "MIDI::Port::Unknown " << MIDI::Port::Unknown << endl; -#endif - if ( string( midi_port.device() ) == string( "ardour" ) && midi_port.type() == MIDI::Port::ALSA_Sequencer ) - { - throw MackieControlException( "The Mackie MCU driver will not use a port with device=ardour" ); - } - else if ( midi_port.type() == MIDI::Port::ALSA_Sequencer ) - { - throw MackieControlException( "alsa/sequencer ports don't work with the Mackie MCU driver right now" ); - } - else - { - MackiePort * sport = new MackiePort( *this, midi_port, number ); - _ports.push_back( sport ); + DEBUG_TRACE (DEBUG::MackieControl, string_compose ("add port %1,%2,%3\n", midi_port.name(), midi_port.device(), midi_port.type())); + + if (string (midi_port.device()) == string ("ardour") && midi_port.type() == MIDI::Port::ALSA_Sequencer) { + throw MackieControlException ("The Mackie MCU driver will not use a port with device=ardour"); + } else if (midi_port.type() == MIDI::Port::ALSA_Sequencer) { + throw MackieControlException ("alsa/sequencer ports don't work with the Mackie MCU driver right now"); + } else { + MackiePort * sport = new MackiePort (*this, midi_port, number); + _ports.push_back (sport); sport->init_event.connect (port_connections, boost::bind (&MackieControlProtocol::handle_port_init, this, sport)); sport->active_event.connect (port_connections, boost::bind (&MackieControlProtocol::handle_port_active, this, sport)); sport->inactive_event.connect (port_connections, boost::bind (&MackieControlProtocol::handle_port_inactive, this, sport)); - - _ports_changed = true; } } -void MackieControlProtocol::create_ports() +void +MackieControlProtocol::create_ports() { MIDI::Manager * mm = MIDI::Manager::instance(); + MIDI::Port * midi_port = mm->port (default_port_name); - // open main port - { - MIDI::Port * midi_port = mm->port( default_port_name ); + // open main port - if ( midi_port == 0 ) { - ostringstream os; - os << string_compose( _("no MIDI port named \"%1\" exists - Mackie control disabled"), default_port_name ); - error << os.str() << endmsg; - throw MackieControlException( os.str() ); - } - add_port( *midi_port, 0 ); + if (midi_port == 0) { + ostringstream os; + os << string_compose (_("no MIDI port named \"%1\" exists - Mackie control disabled"), default_port_name); + error << os.str() << endmsg; + throw MackieControlException (os.str()); } + add_port (*midi_port, 0); + // open extender ports. Up to 9. Should be enough. // could also use mm->get_midi_ports() + string ext_port_base = "mcu_xt_"; - for ( int index = 1; index <= 9; ++index ) - { + + for (int index = 1; index <= 9; ++index) { ostringstream os; os << ext_port_base << index; - MIDI::Port * midi_port = mm->port( os.str() ); - if ( midi_port != 0 ) add_port( *midi_port, index ); + MIDI::Port * midi_port = mm->port (os.str()); + if (midi_port != 0) { + add_port (*midi_port, index); + } } } -shared_ptr MackieControlProtocol::master_route() +shared_ptr +MackieControlProtocol::master_route() { return session->master_out (); } -Strip & MackieControlProtocol::master_strip() +Strip& +MackieControlProtocol::master_strip() { - return dynamic_cast( *surface().groups["master"] ); + return dynamic_cast (*surface().groups["master"]); } -void MackieControlProtocol::initialize_surface() +void +MackieControlProtocol::initialize_surface() { // set up the route table int strips = 0; - for( MackiePorts::iterator it = _ports.begin(); it != _ports.end(); ++it ) - { + for (MackiePorts::iterator it = _ports.begin(); it != _ports.end(); ++it) { strips += (*it)->strips(); } - set_route_table_size( strips ); + set_route_table_size (strips); // TODO same as code in mackie_port.cc string emulation = ARDOUR::Config->get_mackie_emulation(); - if ( emulation == "bcf" ) + if (emulation == "bcf") { - _surface = new BcfSurface( strips ); + _surface = new BcfSurface (strips); } - else if ( emulation == "mcu" ) + else if (emulation == "mcu") { - _surface = new MackieSurface( strips ); + _surface = new MackieSurface (strips); } else { ostringstream os; os << "no Surface class found for emulation: " << emulation; - throw MackieControlException( os.str() ); + throw MackieControlException (os.str()); } _surface->init(); // Connect events. Must be after route table otherwise there will be trouble - for( MackiePorts::iterator it = _ports.begin(); it != _ports.end(); ++it ) { + for (MackiePorts::iterator it = _ports.begin(); it != _ports.end(); ++it) { (*it)->control_event.connect (port_connections, boost::bind (&MackieControlProtocol::handle_control_event, this, _1, _2, _3)); } } -void MackieControlProtocol::close() +void +MackieControlProtocol::close() { - // stop polling, and wait for it... + // must be before other shutdown otherwise polling loop // calls methods on objects that are deleted - _polling = false; - pthread_join( thread, 0 ); port_connections.drop_connections (); session_connections.drop_connections (); route_connections.drop_connections (); - if ( _surface != 0 ) - { + if (_surface != 0) { // These will fail if the port has gone away. // So catch the exception and do the rest of the // close afterwards // because the bcf doesn't respond to the next 3 sysex messages - try - { + try { zero_all(); } - catch ( exception & e ) - { -#ifdef DEBUG - cout << "MackieControlProtocol::close caught exception: " << e.what() << endl; -#endif + + catch (exception & e) { + DEBUG_TRACE (DEBUG::MackieControl, string_compose ("MackieControlProtocol::close caught exception: %1\n", e.what())); } - for( MackiePorts::iterator it = _ports.begin(); it != _ports.end(); ++it ) - { - try - { + for (MackiePorts::iterator it = _ports.begin(); it != _ports.end(); ++it) { + try { MackiePort & port = **it; // faders to minimum - port.write_sysex( 0x61 ); + port.write_sysex (0x61); // All LEDs off - port.write_sysex( 0x62 ); + port.write_sysex (0x62); // Reset (reboot into offline mode) - port.write_sysex( 0x63 ); + port.write_sysex (0x63); } - catch ( exception & e ) - { -#ifdef DEBUG - cout << "MackieControlProtocol::close caught exception: " << e.what() << endl; -#endif + catch (exception & e) { + DEBUG_TRACE (DEBUG::MackieControl, string_compose ("MackieControlProtocol::close caught exception: %1\n", e.what())); } } // disconnect routes from strips clear_route_signals(); - delete _surface; _surface = 0; } // shut down MackiePorts - for( MackiePorts::iterator it = _ports.begin(); it != _ports.end(); ++it ) - { + for (MackiePorts::iterator it = _ports.begin(); it != _ports.end(); ++it) { delete *it; } - _ports.clear(); - - // this is done already in monitor_work. But it's here so we know. - delete[] pfd; - pfd = 0; - nfds = 0; -} -void* MackieControlProtocol::_monitor_work (void* arg) -{ - return static_cast(arg)->monitor_work (); + _ports.clear(); } -XMLNode & MackieControlProtocol::get_state() +XMLNode& +MackieControlProtocol::get_state() { -#ifdef DEBUG - cout << "MackieControlProtocol::get_state" << endl; -#endif + DEBUG_TRACE (DEBUG::MackieControl, "MackieControlProtocol::get_state\n"); // add name of protocol - XMLNode* node = new XMLNode( X_("Protocol") ); - node->add_property( X_("name"), _name ); + XMLNode* node = new XMLNode (X_("Protocol")); + node->add_property (X_("name"), _name); // add current bank ostringstream os; os << _current_initial_bank; - node->add_property( X_("bank"), os.str() ); + node->add_property (X_("bank"), os.str()); return *node; } -int MackieControlProtocol::set_state (const XMLNode & node, int /*version*/) +int +MackieControlProtocol::set_state (const XMLNode & node, int /*version*/) { -#ifdef DEBUG - cout << "MackieControlProtocol::set_state: active " << _active << endl; -#endif + DEBUG_TRACE (DEBUG::MackieControl, string_compose ("MackieControlProtocol::set_state: active %1\n", _active)); + int retval = 0; // fetch current bank - if ( node.property( X_("bank") ) != 0 ) - { - string bank = node.property( X_("bank") )->value(); - try - { - set_active( true ); - uint32_t new_bank = atoi( bank.c_str() ); - if ( _current_initial_bank != new_bank ) switch_banks( new_bank ); + + if (node.property (X_("bank")) != 0) { + string bank = node.property (X_("bank"))->value(); + try { + set_active (true); + uint32_t new_bank = atoi (bank.c_str()); + if (_current_initial_bank != new_bank) { + switch_banks (new_bank); + } } - catch ( exception & e ) - { -#ifdef DEBUG - cout << "exception in MackieControlProtocol::set_state: " << e.what() << endl; -#endif + catch (exception & e) { + DEBUG_TRACE (DEBUG::MackieControl, string_compose ("exception in MackieControlProtocol::set_state: %1\n", e.what())); return -1; } } @@ -807,20 +753,17 @@ int MackieControlProtocol::set_state (const XMLNode & node, int /*version*/) return retval; } -void MackieControlProtocol::handle_control_event( SurfacePort & port, Control & control, const ControlState & state ) +void +MackieControlProtocol::handle_control_event (SurfacePort & port, Control & control, const ControlState & state) { // find the route for the control, if there is one boost::shared_ptr route; - if ( control.group().is_strip() ) - { - if ( control.group().is_master() ) - { + if (control.group().is_strip()) { + if (control.group().is_master()) { route = master_route(); - } - else - { - uint32_t index = control.ordinal() - 1 + ( port.number() * port.strips() ); - if ( index < route_table.size() ) + } else { + uint32_t index = control.ordinal() - 1 + (port.number() * port.strips()); + if (index < route_table.size()) route = route_table[index]; else cerr << "Warning: index is " << index << " which is not in the route table, size: " << route_table.size() << endl; @@ -830,61 +773,50 @@ void MackieControlProtocol::handle_control_event( SurfacePort & port, Control & // This handles control element events from the surface // the state of the controls on the surface is usually updated // from UI events. - switch ( control.type() ) - { + switch (control.type()) { case Control::type_fader: // find the route in the route table for the id // if the route isn't available, skip it // at which point the fader should just reset itself - if ( route != 0 ) + if (route != 0) { - route->gain_control()->set_value( state.pos ); + route->gain_control()->set_value (state.pos); // must echo bytes back to slider now, because // the notifier only works if the fader is not being // touched. Which it is if we're getting input. - port.write( builder.build_fader( (Fader&)control, state.pos ) ); + port.write (builder.build_fader ((Fader&)control, state.pos)); } break; case Control::type_button: - if ( control.group().is_strip() ) - { + if (control.group().is_strip()) { // strips - if ( route != 0 ) - { - handle_strip_button( control, state.button_state, route ); - } - else - { + if (route != 0) { + handle_strip_button (control, state.button_state, route); + } else { // no route so always switch the light off // because no signals will be emitted by a non-route - port.write( builder.build_led( control.led(), off ) ); + port.write (builder.build_led (control.led(), off)); } - } - else if ( control.group().is_master() ) - { + } else if (control.group().is_master()) { // master fader touch - if ( route != 0 ) - { - handle_strip_button( control, state.button_state, route ); + if (route != 0) { + handle_strip_button (control, state.button_state, route); } - } - else - { + } else { // handle all non-strip buttons - surface().handle_button( *this, state.button_state, dynamic_cast( control ) ); + surface().handle_button (*this, state.button_state, dynamic_cast (control)); } break; // pot (jog wheel, external control) case Control::type_pot: - if ( control.group().is_strip() ) - { - if ( route != 0 && route->panner() ) + if (control.group().is_strip()) { + if (route != 0 && route->panner()) { // pan for mono input routes, or stereo linked panners - if ( route->panner()->npanners() == 1 || ( route->panner()->npanners() == 2 && route->panner()->linked() ) ) + if (route->panner()->npanners() == 1 || (route->panner()->npanners() == 2 && route->panner()->linked())) { // assume pan for now float xpos; @@ -892,25 +824,25 @@ void MackieControlProtocol::handle_control_event( SurfacePort & port, Control & // calculate new value, and trim xpos += state.delta * state.sign; - if ( xpos > 1.0 ) + if (xpos > 1.0) xpos = 1.0; - else if ( xpos < 0.0 ) + else if (xpos < 0.0) xpos = 0.0; - route->panner()->streampanner (0).set_position( xpos ); + route->panner()->streampanner (0).set_position (xpos); } } else { // it's a pot for an umnapped route, so turn all the lights off - port.write( builder.build_led_ring( dynamic_cast( control ), off ) ); + port.write (builder.build_led_ring (dynamic_cast (control), off)); } } else { - if ( control.is_jog() ) + if (control.is_jog()) { - _jog_wheel.jog_event( port, control, state ); + _jog_wheel.jog_event (port, control, state); } else { @@ -927,44 +859,47 @@ void MackieControlProtocol::handle_control_event( SurfacePort & port, Control & ///////////////////////////////////////////////// // handlers for Route signals // TODO should these be part of RouteSignal? -// They started off as sigc handlers for signals +// They started off as signal/slot handlers for signals // from Route, but they're also used in polling for automation ///////////////////////////////////////////////// -void MackieControlProtocol::notify_solo_changed( RouteSignal * route_signal ) +void +MackieControlProtocol::notify_solo_changed (RouteSignal * route_signal) { try { Button & button = route_signal->strip().solo(); - route_signal->port().write( builder.build_led( button, route_signal->route()->soloed() ) ); + route_signal->port().write (builder.build_led (button, route_signal->route()->soloed())); } - catch( exception & e ) + catch (exception & e) { cout << e.what() << endl; } } -void MackieControlProtocol::notify_mute_changed( RouteSignal * route_signal ) +void +MackieControlProtocol::notify_mute_changed (RouteSignal * route_signal) { try { Button & button = route_signal->strip().mute(); - route_signal->port().write( builder.build_led( button, route_signal->route()->muted() ) ); + route_signal->port().write (builder.build_led (button, route_signal->route()->muted())); } - catch( exception & e ) + catch (exception & e) { cout << e.what() << endl; } } -void MackieControlProtocol::notify_record_enable_changed( RouteSignal * route_signal ) +void +MackieControlProtocol::notify_record_enable_changed (RouteSignal * route_signal) { try { Button & button = route_signal->strip().recenable(); - route_signal->port().write( builder.build_led( button, route_signal->route()->record_enabled() ) ); + route_signal->port().write (builder.build_led (button, route_signal->route()->record_enabled())); } - catch( exception & e ) + catch (exception & e) { cout << e.what() << endl; } @@ -974,125 +909,128 @@ void MackieControlProtocol::notify_active_changed (RouteSignal *) { try { -#ifdef DEBUG - cout << "MackieControlProtocol::notify_active_changed" << endl; -#endif + DEBUG_TRACE (DEBUG::MackieControl, "MackieControlProtocol::notify_active_changed\n"); refresh_current_bank(); } - catch( exception & e ) + catch (exception & e) { cout << e.what() << endl; } } -void MackieControlProtocol::notify_gain_changed( RouteSignal * route_signal, bool force_update ) +void +MackieControlProtocol::notify_gain_changed (RouteSignal * route_signal, bool force_update) { try { Fader & fader = route_signal->strip().gain(); - if ( !fader.in_use() ) + if (!fader.in_use()) { float gain_value = route_signal->route()->gain_control()->get_value(); // check that something has actually changed - if ( force_update || gain_value != route_signal->last_gain_written() ) + if (force_update || gain_value != route_signal->last_gain_written()) { - route_signal->port().write( builder.build_fader( fader, gain_value ) ); - route_signal->last_gain_written( gain_value ); + route_signal->port().write (builder.build_fader (fader, gain_value)); + route_signal->last_gain_written (gain_value); } } } - catch( exception & e ) + catch (exception & e) { cout << e.what() << endl; } } -void MackieControlProtocol::notify_name_changed( RouteSignal * route_signal ) +void +MackieControlProtocol::notify_name_changed (RouteSignal * route_signal) { try { Strip & strip = route_signal->strip(); - if ( !strip.is_master() ) + if (!strip.is_master()) { string line1; string fullname = route_signal->route()->name(); - if ( fullname.length() <= 6 ) + if (fullname.length() <= 6) { line1 = fullname; } else { - line1 = PBD::short_version( fullname, 6 ); + line1 = PBD::short_version (fullname, 6); } SurfacePort & port = route_signal->port(); - port.write( builder.strip_display( port, strip, 0, line1 ) ); - port.write( builder.strip_display_blank( port, strip, 1 ) ); + port.write (builder.strip_display (port, strip, 0, line1)); + port.write (builder.strip_display_blank (port, strip, 1)); } } - catch( exception & e ) + catch (exception & e) { cout << e.what() << endl; } } -void MackieControlProtocol::notify_panner_changed( RouteSignal * route_signal, bool force_update ) +void +MackieControlProtocol::notify_panner_changed (RouteSignal * route_signal, bool force_update) { try { Pot & pot = route_signal->strip().vpot(); boost::shared_ptr panner = route_signal->route()->panner(); - if ( (panner && panner->npanners() == 1) || ( panner->npanners() == 2 && panner->linked() ) ) + if ((panner && panner->npanners() == 1) || (panner->npanners() == 2 && panner->linked())) { float pos; - route_signal->route()->panner()->streampanner(0).get_effective_position( pos ); + route_signal->route()->panner()->streampanner(0).get_effective_position (pos); // cache the MidiByteArray here, because the mackie led control is much lower // resolution than the panner control. So we save lots of byte // sends in spite of more work on the comparison - MidiByteArray bytes = builder.build_led_ring( pot, ControlState( on, pos ), MackieMidiBuilder::midi_pot_mode_dot ); + MidiByteArray bytes = builder.build_led_ring (pot, ControlState (on, pos), MackieMidiBuilder::midi_pot_mode_dot); // check that something has actually changed - if ( force_update || bytes != route_signal->last_pan_written() ) + if (force_update || bytes != route_signal->last_pan_written()) { - route_signal->port().write( bytes ); - route_signal->last_pan_written( bytes ); + route_signal->port().write (bytes); + route_signal->last_pan_written (bytes); } } else { - route_signal->port().write( builder.zero_control( pot ) ); + route_signal->port().write (builder.zero_control (pot)); } } - catch( exception & e ) + catch (exception & e) { cout << e.what() << endl; } } // TODO handle plugin automation polling -void MackieControlProtocol::update_automation( RouteSignal & rs ) +void +MackieControlProtocol::update_automation (RouteSignal & rs) { ARDOUR::AutoState gain_state = rs.route()->gain_control()->automation_state(); - if ( gain_state == Touch || gain_state == Play ) + + if (gain_state == Touch || gain_state == Play) { - notify_gain_changed( &rs, false ); + notify_gain_changed (&rs, false); } - if ( rs.route()->panner() ) { + if (rs.route()->panner()) { ARDOUR::AutoState panner_state = rs.route()->panner()->automation_state(); - if ( panner_state == Touch || panner_state == Play ) + if (panner_state == Touch || panner_state == Play) { - notify_panner_changed( &rs, false ); + notify_panner_changed (&rs, false); } } - _automation_last.start(); } -string MackieControlProtocol::format_bbt_timecode( nframes_t now_frame ) +string +MackieControlProtocol::format_bbt_timecode (nframes_t now_frame) { BBT_Time bbt_time; - session->bbt_time( now_frame, bbt_time ); + session->bbt_time (now_frame, bbt_time); // According to the Logic docs // digits: 888/88/88/888 @@ -1102,15 +1040,15 @@ string MackieControlProtocol::format_bbt_timecode( nframes_t now_frame ) os << setw(2) << setfill('0') << bbt_time.beats; // figure out subdivisions per beat - const Meter & meter = session->tempo_map().meter_at( now_frame ); + const Meter & meter = session->tempo_map().meter_at (now_frame); int subdiv = 2; - if ( meter.note_divisor() == 8 && (meter.beats_per_bar() == 12.0 || meter.beats_per_bar() == 9.0 || meter.beats_per_bar() == 6.0) ) + if (meter.note_divisor() == 8 && (meter.beats_per_bar() == 12.0 || meter.beats_per_bar() == 9.0 || meter.beats_per_bar() == 6.0)) { subdiv = 3; } - uint32_t subdivisions = bbt_time.ticks / uint32_t( Meter::ticks_per_beat / subdiv ); - uint32_t ticks = bbt_time.ticks % uint32_t( Meter::ticks_per_beat / subdiv ); + uint32_t subdivisions = bbt_time.ticks / uint32_t (Meter::ticks_per_beat / subdiv); + uint32_t ticks = bbt_time.ticks % uint32_t (Meter::ticks_per_beat / subdiv); os << setw(2) << setfill('0') << subdivisions + 1; os << setw(3) << setfill('0') << ticks; @@ -1118,10 +1056,11 @@ string MackieControlProtocol::format_bbt_timecode( nframes_t now_frame ) return os.str(); } -string MackieControlProtocol::format_timecode_timecode( nframes_t now_frame ) +string +MackieControlProtocol::format_timecode_timecode (nframes_t now_frame) { Timecode::Time timecode; - session->timecode_time( now_frame, timecode ); + session->timecode_time (now_frame, timecode); // According to the Logic docs // digits: 888/88/88/888 @@ -1135,57 +1074,56 @@ string MackieControlProtocol::format_timecode_timecode( nframes_t now_frame ) return os.str(); } -void MackieControlProtocol::update_timecode_display() +void +MackieControlProtocol::update_timecode_display() { - if ( surface().has_timecode_display() ) + if (surface().has_timecode_display()) { // do assignment here so current_frame is fixed nframes_t current_frame = session->transport_frame(); string timecode; - switch ( _timecode_type ) + switch (_timecode_type) { case ARDOUR::AnyTime::BBT: - timecode = format_bbt_timecode( current_frame ); + timecode = format_bbt_timecode (current_frame); break; case ARDOUR::AnyTime::Timecode: - timecode = format_timecode_timecode( current_frame ); + timecode = format_timecode_timecode (current_frame); break; default: ostringstream os; os << "Unknown timecode: " << _timecode_type; - throw runtime_error( os.str() ); + throw runtime_error (os.str()); } // only write the timecode string to the MCU if it's changed // since last time. This is to reduce midi bandwidth used. - if ( timecode != _timecode_last ) + if (timecode != _timecode_last) { - surface().display_timecode( mcu_port(), builder, timecode, _timecode_last ); + surface().display_timecode (mcu_port(), builder, timecode, _timecode_last); _timecode_last = timecode; } } } -void MackieControlProtocol::poll_session_data() +void +MackieControlProtocol::poll_session_data() { - if ( _active && _automation_last.elapsed() >= 20 ) - { + // XXX need to attach this to a timer in the MIDI UI event loop (20msec) + + if (_active) { // do all currently mapped routes - for( RouteSignals::iterator it = route_signals.begin(); it != route_signals.end(); ++it ) - { - update_automation( **it ); + for (RouteSignals::iterator it = route_signals.begin(); it != route_signals.end(); ++it) { + update_automation (**it); } // and the master strip - if ( master_route_signal != 0 ) - { - update_automation( *master_route_signal ); + if (master_route_signal != 0) { + update_automation (*master_route_signal); } update_timecode_display(); - - _automation_last.start(); } } @@ -1193,7 +1131,8 @@ void MackieControlProtocol::poll_session_data() // Transport Buttons ///////////////////////////////////// -LedState MackieControlProtocol::frm_left_press (Button &) +LedState +MackieControlProtocol::frm_left_press (Button &) { // can use first_mark_before/after as well unsigned long elapsed = _frm_left_last.restart(); @@ -1203,191 +1142,217 @@ LedState MackieControlProtocol::frm_left_press (Button &) ); // allow a quick double to go past a previous mark - if ( session->transport_rolling() && elapsed < 500 && loc != 0 ) + if (session->transport_rolling() && elapsed < 500 && loc != 0) { - Location * loc_two_back = session->locations()->first_location_before ( loc->start() ); - if ( loc_two_back != 0 ) + Location * loc_two_back = session->locations()->first_location_before (loc->start()); + if (loc_two_back != 0) { loc = loc_two_back; } } // move to the location, if it's valid - if ( loc != 0 ) + if (loc != 0) { - session->request_locate( loc->start(), session->transport_rolling() ); + session->request_locate (loc->start(), session->transport_rolling()); } return on; } -LedState MackieControlProtocol::frm_left_release (Button &) +LedState +MackieControlProtocol::frm_left_release (Button &) { return off; } -LedState MackieControlProtocol::frm_right_press (Button &) +LedState +MackieControlProtocol::frm_right_press (Button &) { // can use first_mark_before/after as well Location * loc = session->locations()->first_location_after ( session->transport_frame() ); - if ( loc != 0 ) session->request_locate( loc->start(), session->transport_rolling() ); + if (loc != 0) session->request_locate (loc->start(), session->transport_rolling()); return on; } -LedState MackieControlProtocol::frm_right_release (Button &) +LedState +MackieControlProtocol::frm_right_release (Button &) { return off; } -LedState MackieControlProtocol::stop_press (Button &) +LedState +MackieControlProtocol::stop_press (Button &) { session->request_stop(); return on; } -LedState MackieControlProtocol::stop_release (Button &) +LedState +MackieControlProtocol::stop_release (Button &) { return session->transport_stopped(); } -LedState MackieControlProtocol::play_press (Button &) +LedState +MackieControlProtocol::play_press (Button &) { - session->request_transport_speed( 1.0 ); + session->request_transport_speed (1.0); return on; } -LedState MackieControlProtocol::play_release (Button &) +LedState +MackieControlProtocol::play_release (Button &) { return session->transport_rolling(); } -LedState MackieControlProtocol::record_press (Button &) +LedState +MackieControlProtocol::record_press (Button &) { - if ( session->get_record_enabled() ) - session->disable_record( false ); - else + if (session->get_record_enabled()) { + session->disable_record (false); + } else { session->maybe_enable_record(); + } return on; } -LedState MackieControlProtocol::record_release (Button &) +LedState +MackieControlProtocol::record_release (Button &) { - if ( session->get_record_enabled() ) - { - if ( session->transport_rolling() ) + if (session->get_record_enabled()) { + if (session->transport_rolling()) { return on; - else + } else { return flashing; - } - else + } + } else { return off; + } } -LedState MackieControlProtocol::rewind_press (Button &) +LedState +MackieControlProtocol::rewind_press (Button &) { - _jog_wheel.push( JogWheel::speed ); - _jog_wheel.transport_direction( -1 ); - session->request_transport_speed( -_jog_wheel.transport_speed() ); + _jog_wheel.push (JogWheel::speed); + _jog_wheel.transport_direction (-1); + session->request_transport_speed (-_jog_wheel.transport_speed()); return on; } -LedState MackieControlProtocol::rewind_release (Button &) +LedState +MackieControlProtocol::rewind_release (Button &) { _jog_wheel.pop(); - _jog_wheel.transport_direction( 0 ); - if ( _transport_previously_rolling ) - session->request_transport_speed( 1.0 ); + _jog_wheel.transport_direction (0); + if (_transport_previously_rolling) + session->request_transport_speed (1.0); else session->request_stop(); return off; } -LedState MackieControlProtocol::ffwd_press (Button &) +LedState +MackieControlProtocol::ffwd_press (Button &) { - _jog_wheel.push( JogWheel::speed ); - _jog_wheel.transport_direction( 1 ); - session->request_transport_speed( _jog_wheel.transport_speed() ); + _jog_wheel.push (JogWheel::speed); + _jog_wheel.transport_direction (1); + session->request_transport_speed (_jog_wheel.transport_speed()); return on; } -LedState MackieControlProtocol::ffwd_release (Button &) +LedState +MackieControlProtocol::ffwd_release (Button &) { _jog_wheel.pop(); - _jog_wheel.transport_direction( 0 ); - if ( _transport_previously_rolling ) - session->request_transport_speed( 1.0 ); + _jog_wheel.transport_direction (0); + if (_transport_previously_rolling) + session->request_transport_speed (1.0); else session->request_stop(); return off; } -LedState MackieControlProtocol::loop_press (Button &) +LedState +MackieControlProtocol::loop_press (Button &) { - session->request_play_loop( !session->get_play_loop() ); + session->request_play_loop (!session->get_play_loop()); return on; } -LedState MackieControlProtocol::loop_release (Button &) +LedState +MackieControlProtocol::loop_release (Button &) { return session->get_play_loop(); } -LedState MackieControlProtocol::punch_in_press (Button &) +LedState +MackieControlProtocol::punch_in_press (Button &) { bool state = !session->config.get_punch_in(); - session->config.set_punch_in( state ); + session->config.set_punch_in (state); return state; } -LedState MackieControlProtocol::punch_in_release (Button &) +LedState +MackieControlProtocol::punch_in_release (Button &) { return session->config.get_punch_in(); } -LedState MackieControlProtocol::punch_out_press (Button &) +LedState +MackieControlProtocol::punch_out_press (Button &) { bool state = !session->config.get_punch_out(); - session->config.set_punch_out( state ); + session->config.set_punch_out (state); return state; } -LedState MackieControlProtocol::punch_out_release (Button &) +LedState +MackieControlProtocol::punch_out_release (Button &) { return session->config.get_punch_out(); } -LedState MackieControlProtocol::home_press (Button &) +LedState +MackieControlProtocol::home_press (Button &) { session->goto_start(); return on; } -LedState MackieControlProtocol::home_release (Button &) +LedState +MackieControlProtocol::home_release (Button &) { return off; } -LedState MackieControlProtocol::end_press (Button &) +LedState +MackieControlProtocol::end_press (Button &) { session->goto_end(); return on; } -LedState MackieControlProtocol::end_release (Button &) +LedState +MackieControlProtocol::end_release (Button &) { return off; } -LedState MackieControlProtocol::clicking_press (Button &) +LedState +MackieControlProtocol::clicking_press (Button &) { bool state = !Config->get_clicking(); - Config->set_clicking( state ); + Config->set_clicking (state); return state; } -LedState MackieControlProtocol::clicking_release (Button &) +LedState +MackieControlProtocol::clicking_release (Button &) { return Config->get_clicking(); } @@ -1410,32 +1375,31 @@ LedState MackieControlProtocol::global_solo_release (Button &) void MackieControlProtocol::notify_parameter_changed (std::string const & p) { - if ( p == "punch-in" ) + if (p == "punch-in") { - update_global_button( "punch_in", session->config.get_punch_in() ); + update_global_button ("punch_in", session->config.get_punch_in()); } - else if ( p == "punch-out" ) + else if (p == "punch-out") { - update_global_button( "punch_out", session->config.get_punch_out() ); + update_global_button ("punch_out", session->config.get_punch_out()); } - else if ( p == "clicking" ) + else if (p == "clicking") { - update_global_button( "clicking", Config->get_clicking() ); + update_global_button ("clicking", Config->get_clicking()); } else { -#ifdef DEBUG - cout << "parameter changed: " << p << endl; -#endif + DEBUG_TRACE (DEBUG::MackieControl, string_compose ("parameter changed: %1\n", p)); } } // RouteList is the set of routes that have just been added -void MackieControlProtocol::notify_route_added( ARDOUR::RouteList & rl ) +void +MackieControlProtocol::notify_route_added (ARDOUR::RouteList & rl) { // currently assigned banks are less than the full set of // strips, so activate the new strip now. - if ( route_signals.size() < route_table.size() ) + if (route_signals.size() < route_table.size()) { refresh_current_bank(); } @@ -1449,22 +1413,24 @@ void MackieControlProtocol::notify_route_added( ARDOUR::RouteList & rl ) } } -void MackieControlProtocol::notify_solo_active_changed( bool active ) +void +MackieControlProtocol::notify_solo_active_changed (bool active) { - Button * rude_solo = reinterpret_cast( surface().controls_by_name["solo"] ); - mcu_port().write( builder.build_led( *rude_solo, active ? flashing : off ) ); + Button * rude_solo = reinterpret_cast (surface().controls_by_name["solo"]); + mcu_port().write (builder.build_led (*rude_solo, active ? flashing : off)); } -void MackieControlProtocol::notify_remote_id_changed() +void +MackieControlProtocol::notify_remote_id_changed() { Sorted sorted = get_sorted_routes(); // if a remote id has been moved off the end, we need to shift // the current bank backwards. - if ( sorted.size() - _current_initial_bank < route_signals.size() ) + if (sorted.size() - _current_initial_bank < route_signals.size()) { // but don't shift backwards past the zeroth channel - switch_banks( max((Sorted::size_type) 0, sorted.size() - route_signals.size() ) ); + switch_banks (max((Sorted::size_type) 0, sorted.size() - route_signals.size())); } // Otherwise just refresh the current bank else @@ -1477,41 +1443,44 @@ void MackieControlProtocol::notify_remote_id_changed() // Transport signals /////////////////////////////////////////// -void MackieControlProtocol::notify_record_state_changed() +void +MackieControlProtocol::notify_record_state_changed() { // switch rec button on / off / flashing - Button * rec = reinterpret_cast( surface().controls_by_name["record"] ); - mcu_port().write( builder.build_led( *rec, record_release( *rec ) ) ); + Button * rec = reinterpret_cast (surface().controls_by_name["record"]); + mcu_port().write (builder.build_led (*rec, record_release (*rec))); } -void MackieControlProtocol::notify_transport_state_changed() +void +MackieControlProtocol::notify_transport_state_changed() { // switch various play and stop buttons on / off - update_global_button( "play", session->transport_rolling() ); - update_global_button( "stop", !session->transport_rolling() ); - update_global_button( "loop", session->get_play_loop() ); + update_global_button ("play", session->transport_rolling()); + update_global_button ("stop", !session->transport_rolling()); + update_global_button ("loop", session->get_play_loop()); _transport_previously_rolling = session->transport_rolling(); // rec is special because it's tristate - Button * rec = reinterpret_cast( surface().controls_by_name["record"] ); - mcu_port().write( builder.build_led( *rec, record_release( *rec ) ) ); + Button * rec = reinterpret_cast (surface().controls_by_name["record"]); + mcu_port().write (builder.build_led (*rec, record_release (*rec))); } ///////////////////////////////////// // Bank Switching ///////////////////////////////////// -LedState MackieControlProtocol::left_press (Button &) +LedState +MackieControlProtocol::left_press (Button &) { Sorted sorted = get_sorted_routes(); - if ( sorted.size() > route_table.size() ) + if (sorted.size() > route_table.size()) { int new_initial = _current_initial_bank - route_table.size(); - if ( new_initial < 0 ) new_initial = 0; - if ( new_initial != int( _current_initial_bank ) ) + if (new_initial < 0) new_initial = 0; + if (new_initial != int (_current_initial_bank)) { session->set_dirty(); - switch_banks( new_initial ); + switch_banks (new_initial); } return on; @@ -1522,41 +1491,41 @@ LedState MackieControlProtocol::left_press (Button &) } } -LedState MackieControlProtocol::left_release (Button &) +LedState +MackieControlProtocol::left_release (Button &) { return off; } -LedState MackieControlProtocol::right_press (Button &) +LedState +MackieControlProtocol::right_press (Button &) { Sorted sorted = get_sorted_routes(); - if ( sorted.size() > route_table.size() ) - { - uint32_t delta = sorted.size() - ( route_table.size() + _current_initial_bank ); - if ( delta > route_table.size() ) delta = route_table.size(); - if ( delta > 0 ) - { + if (sorted.size() > route_table.size()) { + uint32_t delta = sorted.size() - (route_table.size() + _current_initial_bank); + if (delta > route_table.size()) delta = route_table.size(); + if (delta > 0) { session->set_dirty(); - switch_banks( _current_initial_bank + delta ); + switch_banks (_current_initial_bank + delta); } return on; - } - else - { + } else { return flashing; } } -LedState MackieControlProtocol::right_release (Button &) +LedState +MackieControlProtocol::right_release (Button &) { return off; } -LedState MackieControlProtocol::channel_left_press (Button &) +LedState +MackieControlProtocol::channel_left_press (Button &) { Sorted sorted = get_sorted_routes(); - if ( sorted.size() > route_table.size() ) + if (sorted.size() > route_table.size()) { prev_track(); return on; @@ -1567,15 +1536,17 @@ LedState MackieControlProtocol::channel_left_press (Button &) } } -LedState MackieControlProtocol::channel_left_release (Button &) +LedState +MackieControlProtocol::channel_left_release (Button &) { return off; } -LedState MackieControlProtocol::channel_right_press (Button &) +LedState +MackieControlProtocol::channel_right_press (Button &) { Sorted sorted = get_sorted_routes(); - if ( sorted.size() > route_table.size() ) + if (sorted.size() > route_table.size()) { next_track(); return on; @@ -1586,7 +1557,8 @@ LedState MackieControlProtocol::channel_right_press (Button &) } } -LedState MackieControlProtocol::channel_right_release (Button &) +LedState +MackieControlProtocol::channel_right_release (Button &) { return off; } @@ -1594,7 +1566,8 @@ LedState MackieControlProtocol::channel_right_release (Button &) ///////////////////////////////////// // Functions ///////////////////////////////////// -LedState MackieControlProtocol::marker_press (Button &) +LedState +MackieControlProtocol::marker_press (Button &) { // cut'n'paste from LocationUI::add_new_location() string markername; @@ -1610,42 +1583,47 @@ LedState MackieControlProtocol::marker_press (Button &) return on; } -LedState MackieControlProtocol::marker_release (Button &) +LedState +MackieControlProtocol::marker_release (Button &) { return off; } -void jog_wheel_state_display( JogWheel::State state, SurfacePort & port ) +void +jog_wheel_state_display (JogWheel::State state, SurfacePort & port) { - switch( state ) + switch (state) { - case JogWheel::zoom: port.write( builder.two_char_display( "Zm" ) ); break; - case JogWheel::scroll: port.write( builder.two_char_display( "Sc" ) ); break; - case JogWheel::scrub: port.write( builder.two_char_display( "Sb" ) ); break; - case JogWheel::shuttle: port.write( builder.two_char_display( "Sh" ) ); break; - case JogWheel::speed: port.write( builder.two_char_display( "Sp" ) ); break; - case JogWheel::select: port.write( builder.two_char_display( "Se" ) ); break; + case JogWheel::zoom: port.write (builder.two_char_display ("Zm")); break; + case JogWheel::scroll: port.write (builder.two_char_display ("Sc")); break; + case JogWheel::scrub: port.write (builder.two_char_display ("Sb")); break; + case JogWheel::shuttle: port.write (builder.two_char_display ("Sh")); break; + case JogWheel::speed: port.write (builder.two_char_display ("Sp")); break; + case JogWheel::select: port.write (builder.two_char_display ("Se")); break; } } -Mackie::LedState MackieControlProtocol::zoom_press( Mackie::Button & ) +Mackie::LedState +MackieControlProtocol::zoom_press (Mackie::Button &) { _jog_wheel.zoom_state_toggle(); - update_global_button( "scrub", _jog_wheel.jog_wheel_state() == JogWheel::scrub ); - jog_wheel_state_display( _jog_wheel.jog_wheel_state(), mcu_port() ); + update_global_button ("scrub", _jog_wheel.jog_wheel_state() == JogWheel::scrub); + jog_wheel_state_display (_jog_wheel.jog_wheel_state(), mcu_port()); return _jog_wheel.jog_wheel_state() == JogWheel::zoom; } -Mackie::LedState MackieControlProtocol::zoom_release( Mackie::Button & ) +Mackie::LedState +MackieControlProtocol::zoom_release (Mackie::Button &) { return _jog_wheel.jog_wheel_state() == JogWheel::zoom; } -Mackie::LedState MackieControlProtocol::scrub_press( Mackie::Button & ) +Mackie::LedState +MackieControlProtocol::scrub_press (Mackie::Button &) { _jog_wheel.scrub_state_cycle(); - update_global_button( "zoom", _jog_wheel.jog_wheel_state() == JogWheel::zoom ); - jog_wheel_state_display( _jog_wheel.jog_wheel_state(), mcu_port() ); + update_global_button ("zoom", _jog_wheel.jog_wheel_state() == JogWheel::zoom); + jog_wheel_state_display (_jog_wheel.jog_wheel_state(), mcu_port()); return _jog_wheel.jog_wheel_state() == JogWheel::scrub || @@ -1653,7 +1631,8 @@ Mackie::LedState MackieControlProtocol::scrub_press( Mackie::Button & ) ; } -Mackie::LedState MackieControlProtocol::scrub_release( Mackie::Button & ) +Mackie::LedState +MackieControlProtocol::scrub_release (Mackie::Button &) { return _jog_wheel.jog_wheel_state() == JogWheel::scrub @@ -1662,31 +1641,36 @@ Mackie::LedState MackieControlProtocol::scrub_release( Mackie::Button & ) ; } -LedState MackieControlProtocol::drop_press (Button &) +LedState +MackieControlProtocol::drop_press (Button &) { session->remove_last_capture(); return on; } -LedState MackieControlProtocol::drop_release (Button &) +LedState +MackieControlProtocol::drop_release (Button &) { return off; } -LedState MackieControlProtocol::save_press (Button &) +LedState +MackieControlProtocol::save_press (Button &) { - session->save_state( "" ); + session->save_state (""); return on; } -LedState MackieControlProtocol::save_release (Button &) +LedState +MackieControlProtocol::save_release (Button &) { return off; } -LedState MackieControlProtocol::timecode_beats_press (Button &) +LedState +MackieControlProtocol::timecode_beats_press (Button &) { - switch ( _timecode_type ) + switch (_timecode_type) { case ARDOUR::AnyTime::BBT: _timecode_type = ARDOUR::AnyTime::Timecode; @@ -1697,13 +1681,15 @@ LedState MackieControlProtocol::timecode_beats_press (Button &) default: ostringstream os; os << "Unknown Anytime::Type " << _timecode_type; - throw runtime_error( os.str() ); + throw runtime_error (os.str()); } update_timecode_beats_led(); return on; } -LedState MackieControlProtocol::timecode_beats_release( Button & ) +LedState +MackieControlProtocol::timecode_beats_release (Button &) { return off; } + diff --git a/libs/surfaces/mackie/mackie_control_protocol.h b/libs/surfaces/mackie/mackie_control_protocol.h index 58d05f7b7f..14be7b4370 100644 --- a/libs/surfaces/mackie/mackie_control_protocol.h +++ b/libs/surfaces/mackie/mackie_control_protocol.h @@ -1,20 +1,21 @@ /* - Copyright (C) 2006,2007 John Anderson - - 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. + Copyright (C) 2006,2007 John Anderson + + 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_mackie_control_protocol_h #define ardour_mackie_control_protocol_h @@ -26,6 +27,7 @@ #include #include "ardour/types.h" +#include "ardour/midi_ui.h" #include "midi++/types.h" #include "control_protocol/control_protocol.h" @@ -40,7 +42,6 @@ namespace MIDI { class Port; - class Parser; } namespace Mackie { @@ -66,12 +67,13 @@ namespace Mackie { up the relevant Strip in Surface. Then the state is retrieved from the Route and encoded as the correct midi message. */ -class MackieControlProtocol -: public ARDOUR::ControlProtocol -, public Mackie::MackieButtonHandler + +class MackieControlProtocol + : public ARDOUR::ControlProtocol + , public Mackie::MackieButtonHandler { public: - MackieControlProtocol( ARDOUR::Session & ); + MackieControlProtocol(ARDOUR::Session &); virtual ~MackieControlProtocol(); int set_active (bool yn); @@ -83,130 +85,131 @@ class MackieControlProtocol Mackie::Surface & surface(); - // control events - void handle_control_event( Mackie::SurfacePort & port, Mackie::Control & control, const Mackie::ControlState & state ); + // control events + void handle_control_event(Mackie::SurfacePort & port, Mackie::Control & control, const Mackie::ControlState & state); - // strip/route related stuff + // strip/route related stuff public: /// Signal handler for Route::solo - void notify_solo_changed( Mackie::RouteSignal * ); + void notify_solo_changed(Mackie::RouteSignal *); /// Signal handler for Route::mute - void notify_mute_changed( Mackie::RouteSignal * ); + void notify_mute_changed(Mackie::RouteSignal *); /// Signal handler for Route::record_enable_changed - void notify_record_enable_changed( Mackie::RouteSignal * ); - /// Signal handler for Route::gain_changed ( from IO ) - void notify_gain_changed( Mackie::RouteSignal *, bool force_update = true ); + void notify_record_enable_changed(Mackie::RouteSignal *); + /// Signal handler for Route::gain_changed (from IO) + void notify_gain_changed(Mackie::RouteSignal *, bool force_update = true); /// Signal handler for Route::name_change - void notify_name_changed( Mackie::RouteSignal * ); + void notify_name_changed(Mackie::RouteSignal *); /// Signal handler from Panner::Change - void notify_panner_changed( Mackie::RouteSignal *, bool force_update = true ); + void notify_panner_changed(Mackie::RouteSignal *, bool force_update = true); /// Signal handler for new routes added - void notify_route_added( ARDOUR::RouteList & ); + void notify_route_added(ARDOUR::RouteList &); /// Signal handler for Route::active_changed - void notify_active_changed( Mackie::RouteSignal * ); + void notify_active_changed(Mackie::RouteSignal *); void notify_remote_id_changed(); /// rebuild the current bank. Called on route added/removed and - /// remote id changed. + /// remote id changed. void refresh_current_bank(); - // global buttons (ie button not part of strips) + // global buttons (ie button not part of strips) + public: - // button-related signals + // button-related signals void notify_record_state_changed(); - void notify_transport_state_changed(); - // mainly to pick up punch-in and punch-out - void notify_parameter_changed( std::string const & ); - void notify_solo_active_changed( bool ); + void notify_transport_state_changed(); + // mainly to pick up punch-in and punch-out + void notify_parameter_changed(std::string const &); + void notify_solo_active_changed(bool); /// Turn timecode on and beats off, or vice versa, depending /// on state of _timecode_type void update_timecode_beats_led(); /// this is called to generate the midi to send in response to a button press. - void update_led( Mackie::Button & button, Mackie::LedState ); + void update_led(Mackie::Button & button, Mackie::LedState); - void update_global_button( const std::string & name, Mackie::LedState ); - void update_global_led( const std::string & name, Mackie::LedState ); + void update_global_button(const std::string & name, Mackie::LedState); + void update_global_led(const std::string & name, Mackie::LedState); - // transport button handler methods from MackieButtonHandler - virtual Mackie::LedState frm_left_press( Mackie::Button & ); - virtual Mackie::LedState frm_left_release( Mackie::Button & ); + // transport button handler methods from MackieButtonHandler + virtual Mackie::LedState frm_left_press(Mackie::Button &); + virtual Mackie::LedState frm_left_release(Mackie::Button &); - virtual Mackie::LedState frm_right_press( Mackie::Button & ); - virtual Mackie::LedState frm_right_release( Mackie::Button & ); + virtual Mackie::LedState frm_right_press(Mackie::Button &); + virtual Mackie::LedState frm_right_release(Mackie::Button &); - virtual Mackie::LedState stop_press( Mackie::Button & ); - virtual Mackie::LedState stop_release( Mackie::Button & ); + virtual Mackie::LedState stop_press(Mackie::Button &); + virtual Mackie::LedState stop_release(Mackie::Button &); - virtual Mackie::LedState play_press( Mackie::Button & ); - virtual Mackie::LedState play_release( Mackie::Button & ); + virtual Mackie::LedState play_press(Mackie::Button &); + virtual Mackie::LedState play_release(Mackie::Button &); - virtual Mackie::LedState record_press( Mackie::Button & ); - virtual Mackie::LedState record_release( Mackie::Button & ); + virtual Mackie::LedState record_press(Mackie::Button &); + virtual Mackie::LedState record_release(Mackie::Button &); - virtual Mackie::LedState loop_press( Mackie::Button & ); - virtual Mackie::LedState loop_release( Mackie::Button & ); + virtual Mackie::LedState loop_press(Mackie::Button &); + virtual Mackie::LedState loop_release(Mackie::Button &); - virtual Mackie::LedState punch_in_press( Mackie::Button & ); - virtual Mackie::LedState punch_in_release( Mackie::Button & ); + virtual Mackie::LedState punch_in_press(Mackie::Button &); + virtual Mackie::LedState punch_in_release(Mackie::Button &); - virtual Mackie::LedState punch_out_press( Mackie::Button & ); - virtual Mackie::LedState punch_out_release( Mackie::Button & ); + virtual Mackie::LedState punch_out_press(Mackie::Button &); + virtual Mackie::LedState punch_out_release(Mackie::Button &); - virtual Mackie::LedState home_press( Mackie::Button & ); - virtual Mackie::LedState home_release( Mackie::Button & ); + virtual Mackie::LedState home_press(Mackie::Button &); + virtual Mackie::LedState home_release(Mackie::Button &); - virtual Mackie::LedState end_press( Mackie::Button & ); - virtual Mackie::LedState end_release( Mackie::Button & ); + virtual Mackie::LedState end_press(Mackie::Button &); + virtual Mackie::LedState end_release(Mackie::Button &); - virtual Mackie::LedState rewind_press( Mackie::Button & button ); - virtual Mackie::LedState rewind_release( Mackie::Button & button ); + virtual Mackie::LedState rewind_press(Mackie::Button & button); + virtual Mackie::LedState rewind_release(Mackie::Button & button); - virtual Mackie::LedState ffwd_press( Mackie::Button & button ); - virtual Mackie::LedState ffwd_release( Mackie::Button & button ); + virtual Mackie::LedState ffwd_press(Mackie::Button & button); + virtual Mackie::LedState ffwd_release(Mackie::Button & button); // bank switching button handler methods from MackieButtonHandler - virtual Mackie::LedState left_press( Mackie::Button & ); - virtual Mackie::LedState left_release( Mackie::Button & ); + virtual Mackie::LedState left_press(Mackie::Button &); + virtual Mackie::LedState left_release(Mackie::Button &); - virtual Mackie::LedState right_press( Mackie::Button & ); - virtual Mackie::LedState right_release( Mackie::Button & ); + virtual Mackie::LedState right_press(Mackie::Button &); + virtual Mackie::LedState right_release(Mackie::Button &); - virtual Mackie::LedState channel_left_press( Mackie::Button & ); - virtual Mackie::LedState channel_left_release( Mackie::Button & ); + virtual Mackie::LedState channel_left_press(Mackie::Button &); + virtual Mackie::LedState channel_left_release(Mackie::Button &); - virtual Mackie::LedState channel_right_press( Mackie::Button & ); - virtual Mackie::LedState channel_right_release( Mackie::Button & ); + virtual Mackie::LedState channel_right_press(Mackie::Button &); + virtual Mackie::LedState channel_right_release(Mackie::Button &); - virtual Mackie::LedState clicking_press( Mackie::Button & ); - virtual Mackie::LedState clicking_release( Mackie::Button & ); + virtual Mackie::LedState clicking_press(Mackie::Button &); + virtual Mackie::LedState clicking_release(Mackie::Button &); - virtual Mackie::LedState global_solo_press( Mackie::Button & ); - virtual Mackie::LedState global_solo_release( Mackie::Button & ); + virtual Mackie::LedState global_solo_press(Mackie::Button &); + virtual Mackie::LedState global_solo_release(Mackie::Button &); // function buttons - virtual Mackie::LedState marker_press( Mackie::Button & ); - virtual Mackie::LedState marker_release( Mackie::Button & ); + virtual Mackie::LedState marker_press(Mackie::Button &); + virtual Mackie::LedState marker_release(Mackie::Button &); - virtual Mackie::LedState drop_press( Mackie::Button & ); - virtual Mackie::LedState drop_release( Mackie::Button & ); + virtual Mackie::LedState drop_press(Mackie::Button &); + virtual Mackie::LedState drop_release(Mackie::Button &); - virtual Mackie::LedState save_press( Mackie::Button & ); - virtual Mackie::LedState save_release( Mackie::Button & ); + virtual Mackie::LedState save_press(Mackie::Button &); + virtual Mackie::LedState save_release(Mackie::Button &); - virtual Mackie::LedState timecode_beats_press( Mackie::Button & ); - virtual Mackie::LedState timecode_beats_release( Mackie::Button & ); + virtual Mackie::LedState timecode_beats_press(Mackie::Button &); + virtual Mackie::LedState timecode_beats_release(Mackie::Button &); // jog wheel states - virtual Mackie::LedState zoom_press( Mackie::Button & ); - virtual Mackie::LedState zoom_release( Mackie::Button & ); + virtual Mackie::LedState zoom_press(Mackie::Button &); + virtual Mackie::LedState zoom_release(Mackie::Button &); - virtual Mackie::LedState scrub_press( Mackie::Button & ); - virtual Mackie::LedState scrub_release( Mackie::Button & ); + virtual Mackie::LedState scrub_press(Mackie::Button &); + virtual Mackie::LedState scrub_release(Mackie::Button &); - /// This is the main MCU port, ie not an extender port + /// This is the main MCU port, ie not an extender port /// Only for use by JogWheel const Mackie::SurfacePort & mcu_port() const; Mackie::SurfacePort & mcu_port(); @@ -225,98 +228,83 @@ class MackieControlProtocol void initialize_surface(); // This sets up the notifications and sets the - // controls to the correct values + // controls to the correct values void update_surface(); - - // connects global (not strip) signals from the Session to here - // so the surface can be notified of changes from the other UIs. - void connect_session_signals(); - - // set all controls to their zero position + + // connects global (not strip) signals from the Session to here + // so the surface can be notified of changes from the other UIs. + void connect_session_signals(); + + // set all controls to their zero position void zero_all(); /** - Fetch the set of routes to be considered for control by the - surface. Excluding master, hidden and control routes, and inactive routes + Fetch the set of routes to be considered for control by the + surface. Excluding master, hidden and control routes, and inactive routes */ typedef std::vector > Sorted; Sorted get_sorted_routes(); - // bank switching - void switch_banks( int initial ); - void prev_track(); - void next_track(); + // bank switching + void switch_banks(int initial); + void prev_track(); + void next_track(); - // delete all RouteSignal objects connecting Routes to Strips - void clear_route_signals(); + // delete all RouteSignal objects connecting Routes to Strips + void clear_route_signals(); typedef std::vector RouteSignals; RouteSignals route_signals; - // return which of the ports a particular route_table - // index belongs to - Mackie::MackiePort & port_for_id( uint32_t index ); + // return which of the ports a particular route_table + // index belongs to + Mackie::MackiePort & port_for_id(uint32_t index); /** - Handle a button press for the control and return whether - the corresponding light should be on or off. + Handle a button press for the control and return whether + the corresponding light should be on or off. */ - bool handle_strip_button( Mackie::Control &, Mackie::ButtonState, boost::shared_ptr ); - - /// thread started. Calls monitor_work. - static void* _monitor_work (void* arg); - - /// Polling midi port(s) for incoming messages - void* monitor_work (); - - /// rebuild the set of ports for this surface - void update_ports(); - - /// Returns true if there is pending data, false otherwise - bool poll_ports(); - - /// Trigger the MIDI::Parser - void read_ports(); + bool handle_strip_button(Mackie::Control &, Mackie::ButtonState, boost::shared_ptr); - void add_port( MIDI::Port &, int number ); + void add_port(MIDI::Port &, int number); /** - Read session data and send to surface. Includes - automation from the currently active routes and - timecode displays. + Read session data and send to surface. Includes + automation from the currently active routes and + timecode displays. */ void poll_session_data(); // called from poll_automation to figure out which automations need to be sent - void update_automation( Mackie::RouteSignal & ); + void update_automation(Mackie::RouteSignal &); // also called from poll_automation to update timecode display void update_timecode_display(); - std::string format_bbt_timecode (ARDOUR::nframes_t now_frame ); - std::string format_timecode_timecode (ARDOUR::nframes_t now_frame ); + std::string format_bbt_timecode (ARDOUR::nframes_t now_frame); + std::string format_timecode_timecode (ARDOUR::nframes_t now_frame); /** - notification that the port is about to start it's init sequence. - We must make sure that before this exits, the port is being polled - for new data. + notification that the port is about to start it's init sequence. + We must make sure that before this exits, the port is being polled + for new data. */ - void handle_port_init( Mackie::SurfacePort * ); + void handle_port_init(Mackie::SurfacePort *); /// notification from a MackiePort that it's now active - void handle_port_active( Mackie::SurfacePort * ); + void handle_port_active(Mackie::SurfacePort *); /// notification from a MackiePort that it's now inactive - void handle_port_inactive( Mackie::SurfacePort * ); + void handle_port_inactive(Mackie::SurfacePort *); boost::shared_ptr master_route(); Mackie::Strip & master_strip(); private: boost::shared_ptr master_route_signal; - - static const char * default_port_name; - + + static const char * default_port_name; + /// The Midi port(s) connected to the units typedef std::vector MackiePorts; MackiePorts _ports; @@ -324,18 +312,12 @@ class MackieControlProtocol /// Sometimes the real port goes away, and we want to contain the breakage Mackie::DummyPort _dummy_port; - // the thread that polls the ports for incoming midi data - pthread_t thread; - /// The initial remote_id of the currently switched in bank. - uint32_t _current_initial_bank; + uint32_t _current_initial_bank; - /// protects the port list, and polling structures + /// protects the port list Glib::Mutex update_mutex; - /// Protects set_active, and allows waiting on the poll thread - Glib::Cond update_cond; - PBD::ScopedConnectionList session_connections; PBD::ScopedConnectionList port_connections; PBD::ScopedConnectionList route_connections; @@ -343,14 +325,6 @@ class MackieControlProtocol /// The representation of the physical controls on the surface. Mackie::Surface * _surface; - /// If a port is opened or closed, this will be - /// true until the port configuration is updated; - bool _ports_changed; - - bool _polling; - struct pollfd * pfd; - int nfds; - bool _transport_previously_rolling; // timer for two quick marker left presses @@ -358,9 +332,6 @@ class MackieControlProtocol Mackie::JogWheel _jog_wheel; - // Timer for controlling midi bandwidth used by automation polls - Mackie::Timer _automation_last; - // last written timecode string std::string _timecode_last; diff --git a/libs/surfaces/mackie/mackie_control_protocol_poll.cc b/libs/surfaces/mackie/mackie_control_protocol_poll.cc index f6171c7f0e..6392a91c4f 100644 --- a/libs/surfaces/mackie/mackie_control_protocol_poll.cc +++ b/libs/surfaces/mackie/mackie_control_protocol_poll.cc @@ -29,151 +29,14 @@ const char * MackieControlProtocol::default_port_name = "mcu"; bool MackieControlProtocol::probe() { - if ( MIDI::Manager::instance()->port( default_port_name ) == 0 ) - { + if ( MIDI::Manager::instance()->port(default_port_name) == 0 ) { info << "Mackie: No MIDI port called " << default_port_name << endmsg; return false; - } - else - { + } else { return true; } } -void * MackieControlProtocol::monitor_work() -{ - register_thread (X_("MCU")); - - pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, 0); - pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0); - - // read from midi ports - while ( _polling ) - { - try - { - if ( poll_ports() ) - { - try { read_ports(); } - catch ( exception & e ) { - cout << "MackieControlProtocol::poll_ports caught exception: " << e.what() << endl; - _ports_changed = true; - update_ports(); - } - } - // poll for session data that needs to go to the unit - poll_session_data(); - } - catch ( exception & e ) - { - cout << "caught exception in MackieControlProtocol::monitor_work " << e.what() << endl; - } - } - - // TODO ports and pfd and nfds should be in a separate class - delete[] pfd; - pfd = 0; - nfds = 0; - - return (void*) 0; -} - -void MackieControlProtocol::update_ports() -{ -#ifdef DEBUG - cout << "MackieControlProtocol::update_ports" << endl; -#endif - if ( _ports_changed ) - { - Glib::Mutex::Lock ul( update_mutex ); - // yes, this is a double-test locking paradigm, or whatever it's called - // because we don't *always* need to acquire the lock for the first test -#ifdef DEBUG - cout << "MackieControlProtocol::update_ports lock acquired" << endl; -#endif - if ( _ports_changed ) - { - // create new pollfd structures - delete[] pfd; - pfd = new pollfd[_ports.size()]; -#ifdef DEBUG - cout << "pfd: " << pfd << endl; -#endif - nfds = 0; - for( MackiePorts::iterator it = _ports.begin(); it != _ports.end(); ++it ) - { - // add the port any handler - (*it)->connect_any(); -#ifdef DEBUG - cout << "adding pollfd for port " << (*it)->port().name() << " to pollfd " << nfds << endl; -#endif - pfd[nfds].fd = (*it)->port().selectable(); - pfd[nfds].events = POLLIN|POLLHUP|POLLERR; - ++nfds; - } - _ports_changed = false; - } -#ifdef DEBUG - cout << "MackieControlProtocol::update_ports signal" << endl; -#endif - update_cond.signal(); - } -#ifdef DEBUG - cout << "MackieControlProtocol::update_ports finish" << endl; -#endif -} - -void MackieControlProtocol::read_ports() -{ - /* now read any data on the ports */ - Glib::Mutex::Lock lock( update_mutex ); - for ( int p = 0; p < nfds; ++p ) - { - // this will cause handle_midi_any in the MackiePort to be triggered - // for alsa/raw ports - // alsa/sequencer ports trigger the midi parser off poll - if ( (pfd[p].revents & POLLIN) > 0 ) - { - // avoid deadlocking? - // doesn't seem to make a difference - //lock.release(); - _ports[p]->read(); - //lock.acquire(); - } - } -} - -bool MackieControlProtocol::poll_ports() -{ - int timeout = 10; // milliseconds - int no_ports_sleep = 1000; // milliseconds - - Glib::Mutex::Lock lock( update_mutex ); - // if there are no ports - if ( nfds < 1 ) - { - lock.release(); -#ifdef DEBUG - cout << "poll_ports no ports" << endl; -#endif - usleep( no_ports_sleep * 1000 ); - return false; - } - - int retval = ::poll( pfd, nfds, timeout ); - if ( retval < 0 ) - { - // gdb at work, perhaps - if ( errno != EINTR ) - { - error << string_compose(_("Mackie MIDI thread poll failed (%1)"), strerror( errno ) ) << endmsg; - } - return false; - } - - return retval > 0; -} - void MackieControlProtocol::handle_port_inactive( SurfacePort * port ) { // port gone away. So stop polling it ASAP @@ -187,9 +50,7 @@ void MackieControlProtocol::handle_port_inactive( SurfacePort * port ) _ports.erase( it ); } } - _ports_changed = true; - update_ports(); - + // TODO all the rebuilding of surfaces and so on } @@ -219,8 +80,6 @@ void MackieControlProtocol::handle_port_init (Mackie::SurfacePort *) #ifdef DEBUG cout << "MackieControlProtocol::handle_port_init" << endl; #endif - _ports_changed = true; - update_ports(); #ifdef DEBUG cout << "MackieControlProtocol::handle_port_init finish" << endl; #endif diff --git a/libs/surfaces/mackie/mackie_port.cc b/libs/surfaces/mackie/mackie_port.cc index 8cf69585e3..069ad9abb4 100644 --- a/libs/surfaces/mackie/mackie_port.cc +++ b/libs/surfaces/mackie/mackie_port.cc @@ -29,6 +29,8 @@ #include "midi++/types.h" #include "midi++/port.h" + +#include "ardour/debug.h" #include "ardour/rc_configuration.h" #include "i18n.h" @@ -37,6 +39,7 @@ using namespace std; using namespace Mackie; +using namespace ARDOUR; // The MCU sysex header MidiByteArray mackie_sysex_hdr ( 5, MIDI::sysex, 0x0, 0x0, 0x66, 0x10 ); @@ -45,26 +48,20 @@ MidiByteArray mackie_sysex_hdr ( 5, MIDI::sysex, 0x0, 0x0, 0x66, 0x10 ); MidiByteArray mackie_sysex_hdr_xt ( 5, MIDI::sysex, 0x0, 0x0, 0x66, 0x11 ); MackiePort::MackiePort( MackieControlProtocol & mcp, MIDI::Port & port, int number, port_type_t port_type ) -: SurfacePort( port, number ) -, _mcp( mcp ) -, _port_type( port_type ) -, _emulation( none ) -, _initialising( true ) + : SurfacePort( port, number ) + , _mcp( mcp ) + , _port_type( port_type ) + , _emulation( none ) + , _initialising( true ) { -#ifdef PORT_DEBUG - cout << "MackiePort::MackiePort" <sysex.connect (sysex_connection, boost::bind (&MackiePort::handle_midi_sysex, this, _1, _2, _3)); + DEBUG_TRACE (DEBUG::MackieControl, string_compose ("MackiePort::open %1\n", *this)); + port().input()->sysex.connect (sysex_connection, boost::bind (&MackiePort::handle_midi_sysex, this, _1, _2, _3)); + // make sure the device is connected init(); } void MackiePort::close() { -#ifdef PORT_DEBUG - cout << "MackiePort::close" << endl; -#endif + DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::close\n"); // disconnect signals any_connection.disconnect(); sysex_connection.disconnect(); // TODO emit a "closing" signal? -#ifdef PORT_DEBUG - cout << "MackiePort::close finished" << endl; -#endif } const MidiByteArray & MackiePort::sysex_hdr() const @@ -149,9 +140,7 @@ MidiByteArray calculate_challenge_response( MidiByteArray::iterator begin, MidiB MidiByteArray MackiePort::host_connection_query( MidiByteArray & bytes ) { // handle host connection query -#ifdef PORT_DEBUG - cout << "host connection query: " << bytes << endl; -#endif + DEBUG_TRACE (DEBUG::MackieControl, string_compose ("host connection query: %1\n", bytes)); if ( bytes.size() != 18 ) { @@ -172,9 +161,7 @@ MidiByteArray MackiePort::host_connection_query( MidiByteArray & bytes ) // not used right now MidiByteArray MackiePort::host_connection_confirmation( const MidiByteArray & bytes ) { -#ifdef PORT_DEBUG - cout << "host_connection_confirmation: " << bytes << endl; -#endif + DEBUG_TRACE (DEBUG::MackieControl, string_compose ("host_connection_confirmation: %1\n", bytes)); // decode host connection confirmation if ( bytes.size() != 14 ) @@ -213,15 +200,13 @@ void MackiePort::probe_emulation (const MidiByteArray &) void MackiePort::init() { -#ifdef PORT_DEBUG - cout << "MackiePort::init" << endl; -#endif + DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::init\n"); + init_mutex.lock(); _initialising = true; - -#ifdef PORT_DEBUG - cout << "MackiePort::init lock acquired" << endl; -#endif + + DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::init lock acquired\n"); + // emit pre-init signal init_event(); @@ -237,9 +222,8 @@ void MackiePort::init() void MackiePort::finalise_init( bool yn ) { -#ifdef PORT_DEBUG - cout << "MackiePort::finalise_init" << endl; -#endif + DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::finalise_init\n"); + bool emulation_ok = false; // probing doesn't work very well, so just use a config variable @@ -271,19 +255,18 @@ void MackiePort::finalise_init( bool yn ) SurfacePort::active( yn ); - if ( yn ) - { + if (yn) { active_event(); // start handling messages from controls connect_any(); } + _initialising = false; init_cond.signal(); init_mutex.unlock(); -#ifdef PORT_DEBUG - cout << "MackiePort::finalise_init lock released" << endl; -#endif + + DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::finalise_init lock released\n"); } void MackiePort::connect_any() @@ -296,44 +279,36 @@ void MackiePort::connect_any() bool MackiePort::wait_for_init() { Glib::Mutex::Lock lock( init_mutex ); - while ( _initialising ) - { -#ifdef PORT_DEBUG - cout << "MackiePort::wait_for_active waiting" << endl; -#endif + while (_initialising) { + DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::wait_for_active waiting\n"); init_cond.wait( init_mutex ); -#ifdef PORT_DEBUG - cout << "MackiePort::wait_for_active released" << endl; -#endif + DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::wait_for_active released\n"); } -#ifdef PORT_DEBUG - cout << "MackiePort::wait_for_active returning" << endl; -#endif + DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::wait_for_active returning\n"); return SurfacePort::active(); } void MackiePort::handle_midi_sysex (MIDI::Parser &, MIDI::byte * raw_bytes, size_t count ) { MidiByteArray bytes( count, raw_bytes ); -#ifdef PORT_DEBUG - cout << "handle_midi_sysex: " << bytes << endl; -#endif + DEBUG_TRACE (DEBUG::MackieControl, string_compose ("handle_midi_sysex: %1\n", bytes)); + switch( bytes[5] ) { case 0x01: // not used right now - write_sysex( host_connection_query( bytes ) ); + write_sysex (host_connection_query (bytes)); break; case 0x03: // not used right now - write_sysex( host_connection_confirmation( bytes ) ); + write_sysex (host_connection_confirmation (bytes)); break; case 0x04: - inactive_event(); + inactive_event (); cout << "host connection error" << bytes << endl; break; case 0x14: - probe_emulation( bytes ); + probe_emulation (bytes); break; default: cout << "unknown sysex: " << bytes << endl; @@ -345,10 +320,11 @@ Control & MackiePort::lookup_control( MIDI::byte * bytes, size_t count ) // Don't instantiate a MidiByteArray here unless it's needed for exceptions. // Reason being that this method is called for every single incoming // midi event, and it needs to be as efficient as possible. + Control * control = 0; MIDI::byte midi_type = bytes[0] & 0xf0; //0b11110000 - switch( midi_type ) - { + + switch (midi_type) { // fader case MackieMidiBuilder::midi_fader_id: { @@ -413,18 +389,16 @@ bool MackiePort::handle_control_timeout_event ( Control * control ) // because they have similar logic flows. void MackiePort::handle_midi_any (MIDI::Parser &, MIDI::byte * raw_bytes, size_t count ) { -#ifdef DEBUG MidiByteArray bytes( count, raw_bytes ); - cout << "MackiePort::handle_midi_any " << bytes << endl; -#endif + DEBUG_TRACE (DEBUG::MackieControl, string_compose ("MackiePort::handle_midi_any %1\n", bytes)); + try { // ignore sysex messages if ( raw_bytes[0] == MIDI::sysex ) return; // sanity checking - if ( count != 3 ) - { + if (count != 3) { ostringstream os; MidiByteArray mba( count, raw_bytes ); os << "MackiePort::handle_midi_any needs 3 bytes, but received " << mba; @@ -436,8 +410,7 @@ void MackiePort::handle_midi_any (MIDI::Parser &, MIDI::byte * raw_bytes, size_t // This handles incoming bytes. Outgoing bytes // are sent by the signal handlers. - switch ( control.type() ) - { + switch (control.type()) { // fader case Control::type_fader: { @@ -484,17 +457,15 @@ void MackiePort::handle_midi_any (MIDI::Parser &, MIDI::byte * raw_bytes, size_t // first disconnect any previous timeouts control.in_use_connection.disconnect(); -#if 0 // BOOSTSIGNALS // now connect a new timeout to call handle_control_timeout_event - sigc::slot timeout_slot = sigc::bind ( - mem_fun( *this, &MackiePort::handle_control_timeout_event ) - , &control - ); - control.in_use_connection = Glib::signal_timeout().connect( - timeout_slot - , control.in_use_timeout() - ); -#endif + // XXX should this use the GUI event loop (default) or the + // MIDI UI event loop ? + + sigc::slot timeout_slot = sigc::bind + (sigc::mem_fun( *this, &MackiePort::handle_control_timeout_event), &control); + + control.in_use_connection = Glib::signal_timeout().connect (timeout_slot , control.in_use_timeout()); + // emit the control event control_event( *this, control, state ); break; @@ -503,12 +474,11 @@ void MackiePort::handle_midi_any (MIDI::Parser &, MIDI::byte * raw_bytes, size_t cerr << "Do not understand control type " << control; } } - catch( MackieControlException & e ) - { + + catch( MackieControlException & e ) { MidiByteArray bytes( count, raw_bytes ); cout << bytes << ' ' << e.what() << endl; } -#ifdef DEBUG - cout << "finished MackiePort::handle_midi_any " << bytes << endl; -#endif + + DEBUG_TRACE (DEBUG::MackieControl, string_compose ("finished MackiePort::handle_midi_any %1\n", bytes)); } -- 2.30.2