summaryrefslogtreecommitdiff
path: root/libs/midi++2/alsa_sequencer_midiport.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libs/midi++2/alsa_sequencer_midiport.cc')
-rw-r--r--libs/midi++2/alsa_sequencer_midiport.cc156
1 files changed, 156 insertions, 0 deletions
diff --git a/libs/midi++2/alsa_sequencer_midiport.cc b/libs/midi++2/alsa_sequencer_midiport.cc
new file mode 100644
index 0000000000..e0f6ad33e9
--- /dev/null
+++ b/libs/midi++2/alsa_sequencer_midiport.cc
@@ -0,0 +1,156 @@
+/*
+ Copyright (C) 2004 Paul Davis
+
+ 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.
+
+ $Id$
+*/
+
+#include <fcntl.h>
+#include <cerrno>
+
+#include <midi++/types.h>
+#include <midi++/alsa_sequencer.h>
+#include <midi++/port_request.h>
+
+//#define DOTRACE 1
+
+#ifdef DOTRACE
+#define TR_FN() (cerr << __FUNCTION__ << endl)
+#define TR_VAL(v) (cerr << __FILE__ " " << __LINE__ << " " #v "=" << v << endl)
+#else
+#define TR_FN()
+#define TR_VAL(v)
+#endif
+
+
+
+
+using namespace std;
+using namespace MIDI;
+
+ALSA_SequencerMidiPort::ALSA_SequencerMidiPort (PortRequest &req)
+ : Port (req)
+ , seq (0)
+ , decoder (0)
+ , encoder (0)
+{
+ TR_FN();
+ int err;
+ if (0 <= (err = CreatePorts (req)) &&
+ 0 <= (err = snd_midi_event_new (1024, &decoder)) && // Length taken from ARDOUR::Session::midi_read ()
+ 0 <= (err = snd_midi_event_new (64, &encoder))) { // Length taken from ARDOUR::Session::mmc_buffer
+ snd_midi_event_init (decoder);
+ snd_midi_event_init (encoder);
+ _ok = true;
+ req.status = PortRequest::OK;
+ } else
+ req.status = PortRequest::Unknown;
+}
+
+ALSA_SequencerMidiPort::~ALSA_SequencerMidiPort ()
+{
+ if (decoder)
+ snd_midi_event_free (decoder);
+ if (encoder)
+ snd_midi_event_free (encoder);
+ if (seq)
+ snd_seq_close (seq);
+}
+
+int ALSA_SequencerMidiPort::selectable () const
+{
+ struct pollfd pfd[1];
+ if (0 <= snd_seq_poll_descriptors (seq, pfd, 1, POLLIN | POLLOUT)) {
+ return pfd[0].fd;
+ }
+ return -1;
+}
+
+int ALSA_SequencerMidiPort::write (byte *msg, size_t msglen)
+{
+ TR_FN ();
+ int R;
+ snd_midi_event_reset_encode (encoder);
+ int nwritten = snd_midi_event_encode (encoder, msg, msglen, &SEv);
+ TR_VAL (nwritten);
+ if (0 < nwritten) {
+ if (0 <= (R = snd_seq_event_output (seq, &SEv)) &&
+ 0 <= (R = snd_seq_drain_output (seq))) {
+ bytes_written += nwritten;
+ if (output_parser) {
+ output_parser->raw_preparse (*output_parser, msg, nwritten);
+ for (int i = 0; i < nwritten; i++) {
+ output_parser->scanner (msg[i]);
+ }
+ output_parser->raw_postparse (*output_parser, msg, nwritten);
+ }
+ return nwritten;
+ } else {
+ TR_VAL(R);
+ return R;
+ }
+ } else
+ return nwritten;
+}
+
+int ALSA_SequencerMidiPort::read (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);
+ }
+
+ 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);
+ }
+ }
+ return -ENOENT == err ? 0 : err;
+}
+
+int ALSA_SequencerMidiPort::CreatePorts (PortRequest &req)
+{
+ int err;
+ if (0 <= (err = snd_seq_open(&seq, "default", SND_SEQ_OPEN_DUPLEX,
+ (req.mode & O_NONBLOCK) ? SND_SEQ_NONBLOCK : 0))) {
+ snd_seq_set_client_name (seq, req.devname);
+ unsigned int caps = 0;
+ if (req.mode == O_WRONLY || req.mode == O_RDWR)
+ caps |= SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE;
+ if (req.mode == O_RDONLY || req.mode == O_RDWR)
+ caps |= SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ;
+ err = snd_seq_create_simple_port (seq, req.tagname, caps, SND_SEQ_PORT_TYPE_MIDI_GENERIC);
+ if (err >= 0) {
+ port_id = err;
+ snd_seq_ev_clear (&SEv);
+ snd_seq_ev_set_source (&SEv, port_id);
+ snd_seq_ev_set_subs (&SEv);
+ snd_seq_ev_set_direct (&SEv);
+ } else
+ snd_seq_close (seq);
+ }
+ return err;
+}
+