new design (inherited from softwerk) to properly handle I/O via ALSA sequencer, where multiple ports are multiplexed via one selectable/pollable fd; fix failure to save an entire class of ALSA sequencer port connections, which helps save/restore control surface sate

git-svn-id: svn://localhost/ardour2/branches/2.0-ongoing@13202 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis 2012-10-04 20:09:35 +00:00
parent da96d01950
commit f5a5889f18
4 changed files with 80 additions and 22 deletions

View File

@ -27,6 +27,7 @@
#include <midi++/types.h>
#include <midi++/alsa_sequencer.h>
#include <midi++/manager.h>
#include "i18n.h"
@ -45,6 +46,9 @@ using namespace MIDI;
using namespace PBD;
snd_seq_t* ALSA_SequencerMidiPort::seq = 0;
ALSA_SequencerMidiPort::AllPorts ALSA_SequencerMidiPort::_all_ports;
bool ALSA_SequencerMidiPort::_read_done = false;
bool ALSA_SequencerMidiPort::_read_signal_connected = false;
ALSA_SequencerMidiPort::ALSA_SequencerMidiPort (const XMLNode& node)
: Port (node)
@ -67,6 +71,13 @@ ALSA_SequencerMidiPort::ALSA_SequencerMidiPort (const XMLNode& node)
snd_midi_event_init (decoder);
snd_midi_event_init (encoder);
_ok = true;
if (!_read_signal_connected) {
/* we need to do some magic just before a read is initiated
*/
Manager::PreRead.connect (sigc::ptr_fun (ALSA_SequencerMidiPort::prepare_read));
_read_signal_connected = true;
}
}
}
@ -75,6 +86,8 @@ ALSA_SequencerMidiPort::ALSA_SequencerMidiPort (const XMLNode& node)
ALSA_SequencerMidiPort::~ALSA_SequencerMidiPort ()
{
_all_ports.erase (port_id);
if (decoder) {
snd_midi_event_free (decoder);
}
@ -136,31 +149,65 @@ ALSA_SequencerMidiPort::write (byte *msg, size_t msglen)
return totwritten;
}
void
ALSA_SequencerMidiPort::prepare_read ()
{
_read_done = false;
}
int
ALSA_SequencerMidiPort::read (byte *buf, size_t max)
{
if (!_read_done) {
read_all_ports (buf, max);
_read_done = true;
}
return 0;
}
int
ALSA_SequencerMidiPort::read_all_ports (byte *buf, size_t max)
{
TR_FN();
int err;
snd_seq_event_t *ev;
if (0 <= (err = snd_seq_event_input (seq, &ev))) {
TR_VAL(err);
err = snd_midi_event_decode (decoder, buf, max, ev);
}
err = snd_seq_event_input (seq, &ev);
if (err > 0) {
bytes_read += err;
if (input_parser) {
input_parser->raw_preparse (*input_parser, buf, err);
for (int i = 0; i < err; i++) {
input_parser->scanner (buf[i]);
}
input_parser->raw_postparse (*input_parser, buf, err);
}
}
AllPorts::iterator p = _all_ports.find (ev->dest.port);
if (p == _all_ports.end()) {
/* no error reading but port does not exist */
return 0;
}
return p->second->read_self (buf, max, ev);
}
return -ENOENT == err ? 0 : err;
}
int
ALSA_SequencerMidiPort::read_self (byte* buf, size_t max, snd_seq_event_t* ev)
{
int evsize = snd_midi_event_decode (decoder, buf, max, ev);
bytes_read += evsize;
if (input_parser) {
input_parser->raw_preparse (*input_parser, buf, evsize);
for (int i = 0; i < evsize; i++) {
input_parser->scanner (buf[i]);
}
input_parser->raw_postparse (*input_parser, buf, evsize);
}
return 0;
}
int
ALSA_SequencerMidiPort::create_ports (const Port::Descriptor& desc)
{
@ -184,6 +231,8 @@ ALSA_SequencerMidiPort::create_ports (const Port::Descriptor& desc)
snd_seq_ev_set_subs (&SEv);
snd_seq_ev_set_direct (&SEv);
_all_ports.insert (make_pair (port_id, this));
return 0;
}
@ -311,16 +360,12 @@ ALSA_SequencerMidiPort::get_connections (vector<SequencerPortAddress>& connectio
while (snd_seq_query_port_subscribers(seq, subs) >= 0) {
if (snd_seq_query_subscribe_get_time_real (subs)) {
/* interesting connection */
seq_addr = *snd_seq_query_subscribe_get_addr (subs);
connections.push_back (SequencerPortAddress (seq_addr.client,
seq_addr = *snd_seq_query_subscribe_get_addr (subs);
connections.push_back (SequencerPortAddress (seq_addr.client,
seq_addr.port));
}
snd_seq_query_subscribe_set_index(subs, snd_seq_query_subscribe_get_index(subs) + 1);
snd_seq_query_subscribe_set_index (subs, snd_seq_query_subscribe_get_index(subs) + 1);
}
}

View File

@ -47,6 +47,11 @@ class ALSA_SequencerMidiPort : public Port
XMLNode& get_state() const;
void set_state (const XMLNode&);
static int read_all_ports (byte* buf, size_t max);
static void prepare_read ();
int read_self (byte* buf, size_t max, snd_seq_event_t* ev);
protected:
/* Direct I/O */
@ -64,6 +69,11 @@ class ALSA_SequencerMidiPort : public Port
int create_ports (const Port::Descriptor&);
typedef std::map<int,ALSA_SequencerMidiPort*> AllPorts;
static AllPorts _all_ports;
static bool _read_done;
static bool _read_signal_connected;
static int init_client (std::string name);
static snd_seq_t* seq;

View File

@ -69,6 +69,8 @@ class Manager {
int get_known_ports (std::vector<PortSet>&);
static sigc::signal0<void> PreRead;
private:
/* This is a SINGLETON pattern */

View File

@ -36,8 +36,9 @@ using namespace PBD;
Manager *Manager::theManager = 0;
sigc::signal0<void> Manager::PreRead;
Manager::Manager ()
{
inputPort = 0;
outputPort = 0;