Beginnings of writing to the LCD strip display. Some other tweaks and output thing, mostly related to alsa/sequencer weirdness.

git-svn-id: svn://localhost/ardour2/branches/2.0-ongoing@2144 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
John Anderson 2007-07-18 19:09:33 +00:00
parent 5c8830f952
commit bfb5ddedab
12 changed files with 157 additions and 14 deletions

View file

@ -1,3 +1,5 @@
* alsa/sequencer ports unstable
* crash when mmc port set to mcu
* how long can UI signal callbacks take to execute? What happens if they block?
where ENSURE_CORRECT_THREAD is a macro that is modelled on ENSURE_GUI_THREAD
if the handler is not called in the "correct thread", it will use a pseudo-RT-safe-enough technique to get the correct thread to recall "handler" later on, and return.

View file

@ -83,6 +83,9 @@ class Fader;
class Strip : public Group
{
public:
/**
\param is the index of the strip. 0-based.
*/
Strip( const std::string & name, int index );
virtual bool is_strip() const
@ -92,10 +95,11 @@ public:
virtual void add( Control & control );
/// This is the index of the strip
/// This is the index of the strip. zero-based.
int index() const { return _index; }
/// This is for Surface only
/// index is zero-based
void index( int rhs ) { _index = rhs; }
Button & solo();

View file

@ -38,6 +38,7 @@
#include <pbd/pthread_utils.h>
#include <pbd/error.h>
#include <pbd/memento_command.h>
#include <pbd/convert.h>
#include <ardour/route.h>
#include <ardour/session.h>
@ -366,7 +367,7 @@ void MackieControlProtocol::zero_all()
}
}
int MackieControlProtocol::set_active (bool yn)
int MackieControlProtocol::set_active( bool yn )
{
if ( yn != _active )
{
@ -563,6 +564,10 @@ void MackieControlProtocol::connect_session_signals()
void MackieControlProtocol::add_port( MIDI::Port & midi_port, int number )
{
#ifdef DEBUG
cout << "add port " << midi_port.name() << ", " << midi_port.device() << endl;
#endif
MackiePort * sport = new MackiePort( *this, midi_port, number );
_ports.push_back( sport );
@ -998,7 +1003,30 @@ void MackieControlProtocol::notify_name_changed( void *, RouteSignal * route_sig
{
try
{
// TODO implement MackieControlProtocol::notify_name_changed
Strip & strip = route_signal->strip();
if ( !strip.is_master() )
{
string line1;
string line2;
string fullname = route_signal->route().name();
if ( fullname.length() <= 6 )
{
line1 = fullname;
}
else
{
line1 = PBD::short_version( fullname, 6 );
line2 = fullname.substr( fullname.length() - 6, 6 );
}
route_signal->port().write_sysex(
builder.strip_display( strip.index(), 0, line1 )
);
route_signal->port().write_sysex(
builder.strip_display( strip.index(), 1, line2 )
);
}
}
catch( exception & e )
{
@ -1012,7 +1040,6 @@ void MackieControlProtocol::notify_panner_changed( RouteSignal * route_signal )
{
Pot & pot = route_signal->strip().vpot();
const Panner & panner = route_signal->route().panner();
cout << "panner from ardour" << panner.size() << " " << boolalpha << panner.linked() << endl;
if ( panner.size() == 1 || ( panner.size() == 2 && panner.linked() ) )
{
float pos;

View file

@ -29,7 +29,15 @@ const char * MackieControlProtocol::default_port_name = "mcu";
bool MackieControlProtocol::probe()
{
return MIDI::Manager::instance()->port( default_port_name ) != 0;
if ( MIDI::Manager::instance()->port( default_port_name ) == 0 )
{
error << "No port called mcu. Add it to ardour.rc." << endmsg;
return false;
}
else
{
return true;
}
}
void * MackieControlProtocol::monitor_work()
@ -47,6 +55,8 @@ void * MackieControlProtocol::monitor_work()
{
if ( poll_ports() )
{
cout << "--------------------------------------" << endl;
cout << "MackieControlProtocol::read_ports _ports: " << _ports.size() << ", nfds: " << nfds << endl;
try { read_ports(); }
catch ( exception & e ) {
cout << "MackieControlProtocol::poll_ports caught exception: " << e.what() << endl;
@ -82,14 +92,14 @@ void MackieControlProtocol::update_ports()
{
// create new pollfd structures
if ( pfd != 0 ) delete[] pfd;
// TODO This might be a memory leak. How does thread cancellation cleanup work?
pfd = new pollfd[_ports.size()];
nfds = 0;
for( MackiePorts::iterator it = _ports.begin(); it != _ports.end(); ++it )
{
// add the port any handler
(*it)->connect_any();
#ifdef DEBUG
cout << "adding port " << (*it)->port().name() << " to pollfd" << endl;
cout << "adding pollfd for port " << (*it)->port().name() << " to pollfd" << endl;
#endif
pfd[nfds].fd = (*it)->port().selectable();
pfd[nfds].events = POLLIN|POLLHUP|POLLERR;
@ -108,6 +118,8 @@ void MackieControlProtocol::read_ports()
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?
@ -129,12 +141,14 @@ bool MackieControlProtocol::poll_ports()
if ( nfds < 1 )
{
lock.release();
//cout << "poll_ports no ports" << endl;
#ifdef DEBUG
cout << "poll_ports no ports" << endl;
#endif
usleep( no_ports_sleep * 1000 );
return false;
}
int retval = poll( pfd, nfds, timeout );
int retval = ::poll( pfd, nfds, timeout );
if ( retval < 0 )
{
// gdb at work, perhaps

View file

@ -171,3 +171,40 @@ MidiByteArray MackieMidiBuilder::two_char_display( unsigned int value, const std
os << setfill('0') << setw(2) << value % 100;
return two_char_display( os.str() );
}
MidiByteArray MackieMidiBuilder::strip_display( unsigned int strip_index, unsigned int line_number, const std::string & line )
{
if ( line_number > 1 )
{
throw runtime_error( "line_number must be 0 or 1" );
}
if ( strip_index > 7 )
{
throw runtime_error( "strip_index must be between 0 and 7" );
}
cout << "MackieMidiBuilder::strip_display index: " << strip_index << ", line " << line_number << ": " << line << endl;
MidiByteArray retval;
// code for display
retval << 0x12;
// offset (0 to 0x37 first line, 0x38 to 0x6f for second line )
retval << ( strip_index * 7 + ( line_number * 0x38 ) );
retval << line;
if ( strip_index != 7 )
{
retval << ' ';
}
cout << "MackieMidiBuilder::strip_display midi: " << retval << endl;
return retval;
}
MidiByteArray MackieMidiBuilder::all_strips_display( std::vector<std::string> & lines1, std::vector<std::string> & lines2 )
{
MidiByteArray retval;
retval << 0x12 << 0;
retval << "Not working yet";
return retval;
}

View file

@ -73,6 +73,13 @@ public:
MidiByteArray two_char_display( const std::string & msg, const std::string & dots = " " );
MidiByteArray two_char_display( unsigned int value, const std::string & dots = " " );
/// for displaying a particular strip name
/// index is zero-based
MidiByteArray strip_display( unsigned int strip_index, unsigned int line_number, const std::string & line );
/// for generating all strip names
MidiByteArray all_strips_display( std::vector<std::string> & lines1, std::vector<std::string> & lines2 );
protected:
static MIDI::byte calculate_pot_value( midi_pot_mode mode, const ControlState & );
};

View file

@ -296,13 +296,38 @@ void MackiePort::finalise_init( bool yn )
active_event();
// start handling messages from controls
_any = port().input()->any.connect( ( mem_fun (*this, &MackiePort::handle_midi_any) ) );
connect_any();
}
_initialising = false;
init_cond.signal();
init_mutex.unlock();
}
void MackiePort::connect_any()
{
/*
Doesn't work because there isn't and == operator for slots
MIDI::Signal::slot_list_type slots = port().input()->any.slots();
if ( find( slots.begin(), slots.end(), mem_fun( *this, &MackiePort::handle_midi_any ) ) == slots.end() )
*/
// but this will break if midi tracing is turned on
if ( port().input()->any.empty() )
{
#ifdef DEBUG
cout << "connect input parser " << port().input() << " to handle_midi_any" << endl;
#endif
_any = port().input()->any.connect( mem_fun( *this, &MackiePort::handle_midi_any ) );
#ifdef DEBUG
cout << "input parser any connections: " << port().input()->any.size() << endl;
#endif
}
else
{
cout << "MackiePort::connect_any already connected" << endl;
}
}
bool MackiePort::wait_for_init()
{
Glib::Mutex::Lock lock( init_mutex );
@ -346,6 +371,9 @@ void MackiePort::handle_midi_sysex (MIDI::Parser & parser, MIDI::byte * raw_byte
void MackiePort::handle_midi_any (MIDI::Parser & parser, MIDI::byte * raw_bytes, size_t count )
{
MidiByteArray bytes( count, raw_bytes );
#ifdef DEBUG
cout << "MackiePort::handle_midi_any " << bytes << endl;
#endif
try
{
// ignore sysex messages
@ -394,6 +422,9 @@ void MackiePort::handle_midi_any (MIDI::Parser & parser, MIDI::byte * raw_bytes,
}
catch( MackieControlException & e )
{
//cout << bytes << ' ' << e.what() << endl;
cout << bytes << ' ' << e.what() << endl;
}
#ifdef DEBUG
cout << "finished MackiePort::handle_midi_any " << bytes << endl;
#endif
}

View file

@ -71,6 +71,10 @@ public:
emulation_t emulation() const { return _emulation; }
/// Connect the any signal from the parser to handle_midi_any
/// unless it's already connected
void connect_any();
protected:
/**
The initialisation sequence is fairly complex. First a lock is acquired

View file

@ -24,6 +24,7 @@
#include <algorithm>
#include <cstdarg>
#include <iomanip>
#include <stdexcept>
using namespace std;
@ -96,3 +97,12 @@ ostream & operator << ( ostream & os, const MidiByteArray & mba )
os << "]";
return os;
}
MidiByteArray & operator << ( MidiByteArray & mba, const std::string & st )
{
for ( string::const_iterator it = st.begin(); it != st.end(); ++it )
{
mba << *it;
}
return mba;
}

View file

@ -67,6 +67,9 @@ public:
/// append the given byte to the end of the array
MidiByteArray & operator << ( MidiByteArray & mba, const MIDI::byte & b );
/// append the given string to the end of the array
MidiByteArray & operator << ( MidiByteArray & mba, const std::string & );
/// append the given array to the end of this array
MidiByteArray & operator << ( MidiByteArray & mba, const MidiByteArray & barr );

View file

@ -123,4 +123,3 @@ void Strip::add( Control & control )
throw MackieControlException( os.str() );
}
}

View file

@ -67,6 +67,7 @@ MidiByteArray SurfacePort::read()
if ( !active() ) return retval;
// return nothing read if the lock isn't acquired
#if 0
Glib::RecMutex::Lock lock( _rwlock, Glib::TRY_LOCK );
if ( !lock.locked() )
@ -77,6 +78,7 @@ MidiByteArray SurfacePort::read()
// check active again - destructor sequence
if ( !active() ) return retval;
#endif
// read port and copy to return value
int nread = port().read( buf, sizeof (buf) );
@ -85,6 +87,9 @@ MidiByteArray SurfacePort::read()
retval.copy( nread, buf );
if ((size_t) nread == sizeof (buf))
{
#ifdef DEBUG
cout << "SurfacePort::read recursive" << endl;
#endif
retval << read();
}
}
@ -136,7 +141,7 @@ void SurfacePort::write( const MidiByteArray & mba )
}
}
#ifdef DEBUG
if ( mba[0] == 0xf0 ) cout << "SurfacePort::write " << count << endl;
cout << "SurfacePort::wrote " << count << endl;
#endif
}