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
This commit is contained in:
Paul Davis 2009-12-20 16:49:55 +00:00
parent aae367b63c
commit 96cd6c993b
5 changed files with 728 additions and 942 deletions

View file

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

File diff suppressed because it is too large Load diff

View file

@ -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 <glibmm/thread.h>
#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<boost::shared_ptr<ARDOUR::Route> > 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<Mackie::RouteSignal*> 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<ARDOUR::Route> );
bool handle_strip_button(Mackie::Control &, Mackie::ButtonState, boost::shared_ptr<ARDOUR::Route>);
/// 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();
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<ARDOUR::Route> master_route();
Mackie::Strip & master_strip();
private:
boost::shared_ptr<Mackie::RouteSignal> 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<Mackie::MackiePort*> 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;

View file

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

View file

@ -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" <<endl;
#endif
DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::MackiePort\n");
}
MackiePort::~MackiePort()
{
#ifdef PORT_DEBUG
cout << "~MackiePort" << endl;
#endif
DEBUG_TRACE (DEBUG::MackieControl, "MackiePort::~MackiePort\n");
close();
#ifdef PORT_DEBUG
cout << "~MackiePort finished" << endl;
#endif
DEBUG_TRACE (DEBUG::MackieControl, "~MackiePort finished\n");
}
int MackiePort::strips() const
@ -91,29 +88,23 @@ int MackiePort::strips() const
// should really be in MackiePort
void MackiePort::open()
{
#ifdef PORT_DEBUG
cout << "MackiePort::open " << *this << endl;
#endif
port().input()->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<bool> 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<bool> 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));
}