mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-08 07:45:00 +01:00
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:
parent
aae367b63c
commit
96cd6c993b
5 changed files with 728 additions and 942 deletions
|
|
@ -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
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue