Remove non-JACK midi++ ports.

git-svn-id: svn://localhost/ardour2/branches/3.0@7377 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Carl Hetherington 2010-07-06 00:16:36 +00:00
parent dc1e5d09a2
commit 91850f0eb4
28 changed files with 507 additions and 2174 deletions

View File

@ -8,7 +8,6 @@
#include "pbd/cpus.h"
#include "midi++/manager.h"
#include "midi++/factory.h"
#include "ardour/audioengine.h"
#include "ardour/dB.h"
@ -209,7 +208,6 @@ private:
node.add_property ("tag", dialog.port_name.get_text());
node.add_property ("device", X_("ardour")); // XXX this can't be right for all types
node.add_property ("type", MIDI::PortFactory::default_port_type());
node.add_property ("mode", smod);
if (MIDI::Manager::instance()->add_port (node) != 0) {

View File

@ -19,7 +19,6 @@
*/
#include "midi++/jack.h"
#include "pbd/signals.h"
#include "ardour/types.h"
@ -29,6 +28,10 @@
#ifndef TICKER_H_
#define TICKER_H_
namespace MIDI {
class Port;
}
namespace ARDOUR
{

View File

@ -32,7 +32,7 @@
#include "pbd/stacktrace.h"
#include "pbd/unknown_type.h"
#include "midi++/jack.h"
#include "midi++/port.h"
#include "midi++/mmc.h"
#include "midi++/manager.h"
@ -147,7 +147,7 @@ _thread_init_callback (void * /*arg*/)
SessionEvent::create_per_thread_pool (X_("Audioengine"), 512);
MIDI::JACK_MidiPort::set_process_thread (pthread_self());
MIDI::Port::set_process_thread (pthread_self());
MIDI::MachineControl::set_sending_thread (pthread_self ());
}
@ -263,7 +263,7 @@ AudioEngine::stop (bool forever)
} else {
jack_deactivate (_priv_jack);
Stopped(); /* EMIT SIGNAL */
MIDI::JACK_MidiPort::JackHalted (); /* EMIT SIGNAL */
MIDI::Port::JackHalted (); /* EMIT SIGNAL */
}
}
@ -1074,7 +1074,7 @@ AudioEngine::halted (void *arg)
if (was_running) {
ae->Halted(""); /* EMIT SIGNAL */
MIDI::JACK_MidiPort::JackHalted (); /* EMIT SIGNAL */
MIDI::Port::JackHalted (); /* EMIT SIGNAL */
}
}
@ -1358,7 +1358,7 @@ AudioEngine::disconnect_from_jack ()
if (_running) {
_running = false;
Stopped(); /* EMIT SIGNAL */
MIDI::JACK_MidiPort::JackHalted (); /* EMIT SIGNAL */
MIDI::Port::JackHalted (); /* EMIT SIGNAL */
}
return 0;

View File

@ -28,7 +28,6 @@
#include "pbd/pthread_utils.h"
#include "midi++/port.h"
#include "midi++/jack.h"
#include "ardour/debug.h"
#include "ardour/slave.h"

View File

@ -104,9 +104,7 @@ MidiControlUI::midi_input_handler (IOCondition ioc, MIDI::Port* port)
if (ioc & IO_IN) {
if (port->must_drain_selectable()) {
CrossThreadChannel::drain (port->selectable());
}
CrossThreadChannel::drain (port->selectable());
DEBUG_TRACE (DEBUG::MidiIO, string_compose ("data available on %1\n", port->name()));
nframes64_t now = _session.engine().frame_time();

View File

@ -98,7 +98,7 @@
#include "ardour/utils.h"
#include "ardour/graph.h"
#include "midi++/jack.h"
#include "midi++/port.h"
#include "midi++/mmc.h"
#include "i18n.h"
@ -645,7 +645,7 @@ Session::hookup_io ()
/* Tell all IO objects to connect themselves together */
IO::enable_connecting ();
MIDI::JACK_MidiPort::MakeConnections ();
MIDI::Port::MakeConnections ();
/* Now reset all panners */

View File

@ -18,6 +18,8 @@
$Id$
*/
#include "midi++/port.h"
#include "evoral/midi_events.h"
#include "ardour/ticker.h"
#include "ardour/session.h"
#include "ardour/tempo.h"
@ -138,9 +140,6 @@ void MidiClockTicker::tick(const nframes_t& transport_frames, const BBT_Time& /*
if (!Config->get_send_midi_clock() || _session == 0 || _session->transport_speed() != 1.0f || _midi_port == 0)
return;
MIDI::JACK_MidiPort* jack_port = dynamic_cast<MIDI::JACK_MidiPort*>(_midi_port);
assert(jack_port);
while (true) {
double next_tick = _last_tick + one_ppqn_in_frames(transport_frames);
nframes_t next_tick_offset = nframes_t(next_tick) - transport_frames;
@ -150,11 +149,11 @@ void MidiClockTicker::tick(const nframes_t& transport_frames, const BBT_Time& /*
<< ":Last tick time:" << _last_tick << ":"
<< ":Next tick time:" << next_tick << ":"
<< "Offset:" << next_tick_offset << ":"
<< "cycle length:" << jack_port->nframes_this_cycle()
<< "cycle length:" << _midi_port->nframes_this_cycle()
<< endl;
#endif
if (next_tick_offset >= jack_port->nframes_this_cycle())
if (next_tick_offset >= _midi_port->nframes_this_cycle())
return;
send_midi_clock_event(next_tick_offset);
@ -183,9 +182,7 @@ void MidiClockTicker::send_midi_clock_event(nframes_t offset)
return;
}
#ifdef WITH_JACK_MIDI
assert (MIDI::JACK_MidiPort::is_process_thread());
#endif // WITH_JACK_MIDI
assert (MIDI::Port::is_process_thread());
#ifdef DEBUG_MIDI_CLOCK
cerr << "Tick with offset " << offset << endl;
#endif // DEBUG_MIDI_CLOCK

View File

@ -1,429 +0,0 @@
/*
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 "pbd/failed_constructor.h"
#include "pbd/error.h"
#include "pbd/xml++.h"
#include "midi++/types.h"
#include "midi++/alsa_sequencer.h"
#include "i18n.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;
using namespace PBD;
snd_seq_t* ALSA_SequencerMidiPort::seq = 0;
ALSA_SequencerMidiPort::ALSA_SequencerMidiPort (const XMLNode& node)
: Port (node)
, decoder (0)
, encoder (0)
, port_id (-1)
{
TR_FN();
int err;
Descriptor desc (node);
if (!seq && init_client (desc.device) < 0) {
_ok = false;
} else {
if (0 <= (err = create_ports (desc)) &&
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;
}
}
set_state (node);
}
ALSA_SequencerMidiPort::~ALSA_SequencerMidiPort ()
{
if (decoder) {
snd_midi_event_free (decoder);
}
if (encoder) {
snd_midi_event_free (encoder);
}
if (port_id >= 0) {
snd_seq_delete_port (seq, port_id);
}
}
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, timestamp_t ignored)
{
TR_FN ();
int R;
int totwritten = 0;
snd_midi_event_reset_encode (encoder);
int nwritten = snd_midi_event_encode (encoder, msg, msglen, &SEv);
TR_VAL (nwritten);
while (0 < nwritten) {
if (0 <= (R = snd_seq_event_output (seq, &SEv)) &&
0 <= (R = snd_seq_drain_output (seq))) {
bytes_written += nwritten;
totwritten += 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);
}
} else {
TR_VAL(R);
return R;
}
msglen -= nwritten;
msg += nwritten;
if (msglen > 0) {
nwritten = snd_midi_event_encode (encoder, msg, msglen, &SEv);
TR_VAL(nwritten);
}
else {
break;
}
}
return totwritten;
}
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::create_ports (const Port::Descriptor& desc)
{
int err;
unsigned int caps = 0;
if (desc.mode == O_WRONLY || desc.mode == O_RDWR)
caps |= SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE;
if (desc.mode == O_RDONLY || desc.mode == O_RDWR)
caps |= SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ;
if (0 <= (err = snd_seq_create_simple_port (seq, desc.tag.c_str(), caps,
(SND_SEQ_PORT_TYPE_MIDI_GENERIC|
SND_SEQ_PORT_TYPE_SOFTWARE|
SND_SEQ_PORT_TYPE_APPLICATION)))) {
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);
return 0;
}
return err;
}
int
ALSA_SequencerMidiPort::init_client (std::string name)
{
static bool called = false;
if (called) {
return -1;
}
called = true;
if (snd_seq_open (&seq, "default", SND_SEQ_OPEN_DUPLEX, 0) >= 0) {
snd_seq_set_client_name (seq, name.c_str());
return 0;
} else {
warning << "The ALSA MIDI system is not available. No ports based on it will be created"
<< endmsg;
return -1;
}
}
int
ALSA_SequencerMidiPort::discover (vector<PortSet>& ports)
{
int n = 0;
snd_seq_client_info_t *client_info;
snd_seq_port_info_t *port_info;
snd_seq_client_info_alloca (&client_info);
snd_seq_port_info_alloca (&port_info);
snd_seq_client_info_set_client (client_info, -1);
while (snd_seq_query_next_client(seq, client_info) >= 0) {
int alsa_client;
if ((alsa_client = snd_seq_client_info_get_client(client_info)) <= 0) {
break;
}
snd_seq_port_info_set_client(port_info, alsa_client);
snd_seq_port_info_set_port(port_info, -1);
char client[256];
snprintf (client, sizeof (client), "%d:%s", alsa_client, snd_seq_client_info_get_name(client_info));
ports.push_back (PortSet (client));
while (snd_seq_query_next_port(seq, port_info) >= 0) {
#if 0
int type = snd_seq_port_info_get_type(pinfo);
if (!(type & SND_SEQ_PORT_TYPE_PORT)) {
continue;
}
#endif
unsigned int port_capability = snd_seq_port_info_get_capability(port_info);
if ((port_capability & SND_SEQ_PORT_CAP_NO_EXPORT) == 0) {
int alsa_port = snd_seq_port_info_get_port(port_info);
char port[256];
snprintf (port, sizeof (port), "%d:%s", alsa_port, snd_seq_port_info_get_name(port_info));
std::string mode;
if (port_capability & SND_SEQ_PORT_CAP_READ) {
if (port_capability & SND_SEQ_PORT_CAP_WRITE) {
mode = "duplex";
} else {
mode = "output";
}
} else if (port_capability & SND_SEQ_PORT_CAP_WRITE) {
if (port_capability & SND_SEQ_PORT_CAP_READ) {
mode = "duplex";
} else {
mode = "input";
}
}
XMLNode node (X_("MIDI-port"));
node.add_property ("device", client);
node.add_property ("tag", port);
node.add_property ("mode", mode);
node.add_property ("type", "alsa/sequencer");
ports.back().ports.push_back (node);
++n;
}
}
}
return n;
}
void
ALSA_SequencerMidiPort::get_connections (vector<SequencerPortAddress>& connections, int dir) const
{
snd_seq_query_subscribe_t *subs;
snd_seq_addr_t seq_addr;
snd_seq_query_subscribe_alloca (&subs);
// Get port connections...
if (dir) {
snd_seq_query_subscribe_set_type(subs, SND_SEQ_QUERY_SUBS_WRITE);
} else {
snd_seq_query_subscribe_set_type(subs, SND_SEQ_QUERY_SUBS_READ);
}
snd_seq_query_subscribe_set_index(subs, 0);
seq_addr.client = snd_seq_client_id (seq);
seq_addr.port = port_id;
snd_seq_query_subscribe_set_root(subs, &seq_addr);
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.port));
}
snd_seq_query_subscribe_set_index(subs, snd_seq_query_subscribe_get_index(subs) + 1);
}
}
XMLNode&
ALSA_SequencerMidiPort::get_state () const
{
XMLNode& root (Port::get_state ());
vector<SequencerPortAddress> connections;
XMLNode* sub = 0;
char buf[256];
get_connections (connections, 1);
if (!connections.empty()) {
if (!sub) {
sub = new XMLNode (X_("connections"));
}
for (vector<SequencerPortAddress>::iterator i = connections.begin(); i != connections.end(); ++i) {
XMLNode* cnode = new XMLNode (X_("read"));
snprintf (buf, sizeof (buf), "%d:%d", i->first, i->second);
cnode->add_property ("dest", buf);
sub->add_child_nocopy (*cnode);
}
}
connections.clear ();
get_connections (connections, 0);
if (!connections.empty()) {
if (!sub) {
sub = new XMLNode (X_("connections"));
}
for (vector<SequencerPortAddress>::iterator i = connections.begin(); i != connections.end(); ++i) {
XMLNode* cnode = new XMLNode (X_("write"));
snprintf (buf, sizeof (buf), "%d:%d", i->first, i->second);
cnode->add_property ("dest", buf);
sub->add_child_nocopy (*cnode);
}
}
if (sub) {
root.add_child_nocopy (*sub);
}
return root;
}
void
ALSA_SequencerMidiPort::set_state (const XMLNode& node)
{
Port::set_state (node);
XMLNodeList children (node.children());
XMLNodeIterator iter;
for (iter = children.begin(); iter != children.end(); ++iter) {
if ((*iter)->name() == X_("connections")) {
XMLNodeList gchildren ((*iter)->children());
XMLNodeIterator gciter;
for (gciter = gchildren.begin(); gciter != gchildren.end(); ++gciter) {
XMLProperty* prop;
if ((prop = (*gciter)->property ("dest")) != 0) {
int client;
int port;
if (sscanf (prop->value().c_str(), "%d:%d", &client, &port) == 2) {
snd_seq_port_subscribe_t *sub;
snd_seq_addr_t seq_addr;
snd_seq_port_subscribe_alloca(&sub);
if ((*gciter)->name() == X_("write")) {
seq_addr.client = snd_seq_client_id (seq);
seq_addr.port = port_id;
snd_seq_port_subscribe_set_sender(sub, &seq_addr);
seq_addr.client = client;
seq_addr.port = port;
snd_seq_port_subscribe_set_dest(sub, &seq_addr);
} else {
seq_addr.client = snd_seq_client_id (seq);
seq_addr.port = port_id;
snd_seq_port_subscribe_set_dest(sub, &seq_addr);
seq_addr.client = client;
seq_addr.port = port;
snd_seq_port_subscribe_set_sender(sub, &seq_addr);
}
snd_seq_subscribe_port (seq, sub);
}
}
}
break;
}
}
}

View File

@ -1,157 +0,0 @@
/*
Copyright (C) 2004 Paul Davis
Copyright (C) 2004 Grame
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.
*/
#include <fcntl.h>
#include <cerrno>
#include "midi++/coremidi_midiport.h"
#include "midi++/types.h"
#include <mach/mach_time.h>
#include "pbd/pthread_utils.h"
using namespace std;
using namespace MIDI;
MIDITimeStamp CoreMidi_MidiPort::MIDIGetCurrentHostTime()
{
return mach_absolute_time();
}
CoreMidi_MidiPort::CoreMidi_MidiPort (const XMLNode& node) : Port (node)
{
Descriptor desc (node);
firstrecv = true;
int err;
if (0 == (err = Open(desc))) {
_ok = true;
}
}
CoreMidi_MidiPort::~CoreMidi_MidiPort () {Close();}
void CoreMidi_MidiPort::Close ()
{
if (midi_destination) MIDIEndpointDispose(midi_destination);
if (midi_source) MIDIEndpointDispose(midi_source);
if (midi_client) MIDIClientDispose(midi_client);
}
int CoreMidi_MidiPort::write (byte *msg, size_t msglen, timestamp_t ignored)
{
OSStatus err;
MIDIPacketList* pktlist = (MIDIPacketList*)midi_buffer;
MIDIPacket* packet = MIDIPacketListInit(pktlist);
packet = MIDIPacketListAdd(pktlist,sizeof(midi_buffer),packet,MIDIGetCurrentHostTime(),msglen,msg);
if (packet) {
err = MIDIReceived(midi_source,pktlist);
if (err != noErr) {
//error << "MIDIReceived error" << err << endmsg.
}
bytes_written += msglen;
return msglen;
}else{
return 0;
}
}
int CoreMidi_MidiPort::Open (const Descriptor& desc)
{
OSStatus err;
CFStringRef coutputStr;
string str;
coutputStr = CFStringCreateWithCString(0, desc.device.c_str(), CFStringGetSystemEncoding());
err = MIDIClientCreate(coutputStr, 0, 0, &midi_client);
CFRelease(coutputStr);
if (!midi_client) {
//error << "Cannot open CoreMidi client : " << err << endmsg.
goto error;
}
str = desc.tag + string("_in");
coutputStr = CFStringCreateWithCString(0, str.c_str(), CFStringGetSystemEncoding());
err = MIDIDestinationCreate(midi_client, coutputStr, read_proc, this, &midi_destination);
CFRelease(coutputStr);
if (!midi_destination) {
//error << "Cannot create CoreMidi destination : " << err << endmsg.
goto error;
}
str = desc.tag + string("_out");
coutputStr = CFStringCreateWithCString(0, str.c_str(), CFStringGetSystemEncoding());
err = MIDISourceCreate(midi_client, coutputStr, &midi_source);
CFRelease(coutputStr);
if (!midi_source) {
//error << "Cannot create CoreMidi source : " << err << endmsg.
goto error;
}
return err;
error:
Close();
return err;
}
void CoreMidi_MidiPort::read_proc (const MIDIPacketList *pktlist, void *refCon, void *connRefCon)
{
CoreMidi_MidiPort* driver = (CoreMidi_MidiPort*)refCon;
MIDIPacket *packet = (MIDIPacket *)pktlist->packet;
if (driver->firstrecv) {
driver->firstrecv = false;
PBD::notify_gui_about_thread_creation ("gui", pthread_self(), "COREMIDI", 256);
}
for (unsigned int i = 0; i < pktlist->numPackets; ++i) {
driver->bytes_read += packet->length;
if (driver->input_parser) {
//driver->input_parser->raw_preparse (*driver->input_parser, packet->data, packet->length);
/* XXX This is technically the wrong timebase, since it is based on
host time.
*/
driver->input_parser->set_timestamp (packet->timestamp);
for (int i = 0; i < packet->length; i++) {
driver->input_parser->scanner (packet->data[i]);
}
//driver->input_parser->raw_postparse (*driver->input_parser, packet->data, packet->length);
}
packet = MIDIPacketNext(packet);
}
}
int
CoreMidi_MidiPort::discover (vector<PortSet>& ports)
{
/* XXX do dynamic port discovery here */
return 0;
}

View File

@ -25,78 +25,13 @@
#include "midi++/types.h"
#include "midi++/factory.h"
#include "midi++/fifomidi.h"
#ifdef WITH_JACK_MIDI
#include "midi++/jack.h"
std::string MIDI::JACK_MidiPort::typestring = "jack";
#endif // WITH_JACK_MIDI
std::string MIDI::FIFO_MidiPort::typestring = "fifo";
#ifdef WITH_ALSA
#include "midi++/alsa_sequencer.h"
#include "midi++/alsa_rawmidi.h"
std::string MIDI::ALSA_SequencerMidiPort::typestring = "alsa/sequencer";
std::string MIDI::ALSA_RawMidiPort::typestring = "alsa/raw";
#endif // WITH_ALSA
#ifdef WITH_COREMIDI
#include "midi++/coremidi_midiport.h"
std::string MIDI::CoreMidi_MidiPort::typestring = "coremidi";
#endif // WITH_COREMIDI
using namespace std;
using namespace MIDI;
using namespace PBD;
// FIXME: void* data pointer, filthy
Port *
PortFactory::create_port (const XMLNode& node, void* data)
{
Port::Descriptor desc (node);
Port *port;
switch (desc.type) {
#ifdef WITH_JACK_MIDI
case Port::JACK_Midi:
assert(data != NULL);
port = new JACK_MidiPort (node, (jack_client_t*) data);
break;
#endif // WITH_JACK_MIDI
#ifdef WITH_ALSA
case Port::ALSA_RawMidi:
port = new ALSA_RawMidiPort (node);
break;
case Port::ALSA_Sequencer:
port = new ALSA_SequencerMidiPort (node);
break;
#endif // WITH_ALSA
#ifdef WITH_COREMIDI
case Port::CoreMidi_MidiPort:
port = new CoreMidi_MidiPort (node);
break;
#endif // WITH_COREMIDI
case Port::FIFO:
port = new FIFO_MidiPort (node);
break;
default:
return 0;
}
return port;
}
bool
PortFactory::ignore_duplicate_devices (Port::Type type)
@ -104,23 +39,10 @@ PortFactory::ignore_duplicate_devices (Port::Type type)
bool ret = false;
switch (type) {
#ifdef WITH_ALSA
case Port::ALSA_Sequencer:
ret = true;
break;
#endif // WITH_ALSA
#ifdef WITH_JACK_MIDI
case Port::JACK_Midi:
ret = true;
break;
#endif // WITH_JACK_MIDI
#ifdef WITH_COREMIDI
case Port::CoreMidi_MidiPort:
ret = true;
break;
#endif // WITH_COREMIDI
default:
break;
@ -129,65 +51,17 @@ PortFactory::ignore_duplicate_devices (Port::Type type)
return ret;
}
int
#if defined (WITH_ALSA) || defined (WITH_COREMIDI)
PortFactory::get_known_ports (vector<PortSet>& ports)
#else
PortFactory::get_known_ports (vector<PortSet>&)
#endif
{
int n = 0;
#ifdef WITH_ALSA
n += ALSA_SequencerMidiPort::discover (ports);
#endif // WITH_ALSA
#ifdef WITH_COREMIDI
n += CoreMidi_MidiPort::discover (ports);
#endif // WITH_COREMIDI
return n;
}
std::string
PortFactory::default_port_type ()
{
#ifdef WITH_JACK_MIDI
return "jack";
#endif
#ifdef WITH_ALSA
return "alsa/sequencer";
#endif
#ifdef WITH_COREMIDI
return "coremidi";
#endif // WITH_COREMIDI
PBD::fatal << "programming error: no default port type defined in midifactory.cc" << endmsg;
/*NOTREACHED*/
return "";
}
Port::Type
PortFactory::string_to_type (const string& xtype)
{
if (0){
#ifdef WITH_ALSA
} else if (strings_equal_ignore_case (xtype, ALSA_RawMidiPort::typestring)) {
return Port::ALSA_RawMidi;
} else if (strings_equal_ignore_case (xtype, ALSA_SequencerMidiPort::typestring)) {
return Port::ALSA_Sequencer;
#endif
#ifdef WITH_COREMIDI
} else if (strings_equal_ignore_case (xtype, CoreMidi_MidiPort::typestring)) {
return Port::CoreMidi_MidiPort;
#endif
} else if (strings_equal_ignore_case (xtype, FIFO_MidiPort::typestring)) {
return Port::FIFO;
#ifdef WITH_JACK_MIDI
} else if (strings_equal_ignore_case (xtype, JACK_MidiPort::typestring)) {
if (strings_equal_ignore_case (xtype, JACK_MidiPort::typestring)) {
return Port::JACK_Midi;
#endif
}
return Port::Unknown;

View File

@ -1,181 +0,0 @@
/*
Copyright (C) 1999 Paul Barton-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 <cstring>
#include "pbd/error.h"
#include "pbd/pathscanner.h"
#include "midi++/types.h"
#include "midi++/fd_midiport.h"
using namespace std;
using namespace MIDI;
using namespace PBD;
string *FD_MidiPort::midi_dirpath = 0;
string *FD_MidiPort::midi_filename_pattern = 0;
FD_MidiPort::FD_MidiPort (const XMLNode& node,
const string &dirpath,
const string &pattern)
: Port (node)
{
Descriptor desc (node);
open (desc);
if (_fd < 0) {
switch (errno) {
case EBUSY:
error << "MIDI: port device in use" << endmsg;
break;
case ENOENT:
error << "MIDI: no such port device" << endmsg;
break;
case EACCES:
error << "MIDI: access to port denied" << endmsg;
break;
default:
break;
}
} else {
_ok = true;
if (midi_dirpath == 0) {
midi_dirpath = new string (dirpath);
midi_filename_pattern = new string (pattern);
}
if ((desc.mode & O_NONBLOCK) == 0) {
/* we unconditionally set O_NONBLOCK during
open, but the request didn't ask for it,
so remove it.
*/
int flags = fcntl (_fd, F_GETFL, 0);
fcntl (_fd, F_SETFL, flags & ~(O_NONBLOCK));
}
}
}
void
FD_MidiPort::open (const Descriptor& desc)
{
int mode = desc.mode | O_NONBLOCK;
_fd = ::open (desc.device.c_str(), mode);
}
vector<string *> *
FD_MidiPort::list_devices ()
{
PathScanner scanner;
return scanner (*midi_dirpath, *midi_filename_pattern, false, true, false);
}
int
FD_MidiPort::selectable () const
{
long flags;
/* turn on non-blocking mode, since we plan to use select/poll
to tell us when there is data to read.
*/
flags = fcntl (_fd, F_GETFL);
flags |= O_NONBLOCK;
if (fcntl (_fd, F_SETFL, flags)) {
error << "FD_MidiPort: could not turn on non-blocking mode"
<< " (" << strerror (errno)
<< ')'
<< endmsg;
return -1;
}
return _fd;
}
int
FD_MidiPort::do_slow_write (byte *msg, unsigned int msglen)
{
size_t n;
size_t i;
for (n = 0; n < msglen; n++) {
if (::write (_fd, &msg[n], 1) != 1) {
break;
}
bytes_written++;
for (i = 0; i < slowdown * 10000; i++) {}
}
if (n && output_parser) {
output_parser->raw_preparse (*output_parser, msg, n);
for (unsigned int i = 0; i < n; i++) {
output_parser->scanner (msg[i]);
}
output_parser->raw_postparse (*output_parser, msg, n);
}
return n;
}
int
FD_MidiPort::read (byte* buf, size_t max)
{
int nread;
if ((_mode & O_ACCMODE) == O_WRONLY) {
return -EACCES;
}
// cerr << "MIDI: read up to " << max << " from " << _fd << " (" << name() << ')' << endl;
if ((nread = ::read (_fd, buf, max)) > 0) {
bytes_read += nread;
// cerr << " read " << nread << endl;
if (input_parser) {
input_parser->raw_preparse
(*input_parser, buf, nread);
for (int i = 0; i < nread; i++) {
input_parser->scanner (buf[i]);
}
input_parser->raw_postparse
(*input_parser, buf, nread);
}
}
return nread;
}

View File

@ -1,44 +0,0 @@
/*
Copyright (C) 1998-99 Paul Barton-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 <unistd.h>
#include <errno.h>
#include "midi++/types.h"
#include "midi++/fifomidi.h"
using namespace MIDI;
FIFO_MidiPort::FIFO_MidiPort (const XMLNode& node)
: FD_MidiPort (node, ".", "midi")
{
}
void
FIFO_MidiPort::open (const Port::Descriptor& desc)
{
/* This is a placeholder for the fun-and-games I think we will
need to do with FIFO's.
*/
_fd = ::open (desc.device.c_str(), desc.mode|O_NDELAY);
}

View File

@ -1,433 +0,0 @@
/*
Copyright (C) 2006 Paul Davis
Written by Dave Robillard
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.
*/
#include <fcntl.h>
#include <cerrno>
#include <cassert>
#include <cstring>
#include <cstdlib>
#include "pbd/error.h"
#include "pbd/compose.h"
#include "pbd/strsplit.h"
#include "midi++/types.h"
#include "midi++/jack.h"
using namespace std;
using namespace MIDI;
using namespace PBD;
pthread_t JACK_MidiPort::_process_thread;
Signal0<void> JACK_MidiPort::JackHalted;
Signal0<void> JACK_MidiPort::MakeConnections;
JACK_MidiPort::JACK_MidiPort(const XMLNode& node, jack_client_t* jack_client)
: Port(node)
, _jack_client(jack_client)
, _jack_input_port(NULL)
, _jack_output_port(NULL)
, _last_read_index(0)
, output_fifo (512)
, input_fifo (1024)
{
if (!create_ports (node)) {
_ok = true;
}
MakeConnections.connect_same_thread (connect_connection, boost::bind (&JACK_MidiPort::make_connections, this));
JackHalted.connect_same_thread (halt_connection, boost::bind (&JACK_MidiPort::jack_halted, this));
set_state (node);
}
JACK_MidiPort::~JACK_MidiPort()
{
if (_jack_input_port) {
if (_jack_client) {
jack_port_unregister (_jack_client, _jack_input_port);
}
_jack_input_port = 0;
}
if (_jack_output_port) {
if (_jack_client) {
jack_port_unregister (_jack_client, _jack_input_port);
}
_jack_input_port = 0;
}
}
void
JACK_MidiPort::jack_halted ()
{
_jack_client = 0;
_jack_input_port = 0;
_jack_output_port = 0;
}
void
JACK_MidiPort::cycle_start (nframes_t nframes)
{
Port::cycle_start(nframes);
assert(_nframes_this_cycle == nframes);
_last_read_index = 0;
_last_write_timestamp = 0;
if (_jack_output_port != 0) {
// output
void *buffer = jack_port_get_buffer (_jack_output_port, nframes);
jack_midi_clear_buffer (buffer);
flush (buffer);
}
if (_jack_input_port != 0) {
// input
void* jack_buffer = jack_port_get_buffer(_jack_input_port, nframes);
const nframes_t event_count = jack_midi_get_event_count(jack_buffer);
jack_midi_event_t ev;
timestamp_t cycle_start_frame = jack_last_frame_time (_jack_client);
for (nframes_t i = 0; i < event_count; ++i) {
jack_midi_event_get (&ev, jack_buffer, i);
input_fifo.write (cycle_start_frame + ev.time, (Evoral::EventType) 0, ev.size, ev.buffer);
}
if (event_count) {
xthread.wakeup ();
}
}
}
void
JACK_MidiPort::cycle_end ()
{
if (_jack_output_port != 0) {
flush (jack_port_get_buffer (_jack_output_port, _nframes_this_cycle));
}
Port::cycle_end();
}
int
JACK_MidiPort::write(byte * msg, size_t msglen, timestamp_t timestamp)
{
int ret = 0;
if (!_jack_output_port) {
return ret;
}
if (!is_process_thread()) {
Glib::Mutex::Lock lm (output_fifo_lock);
RingBuffer< Evoral::Event<double> >::rw_vector vec = { { 0, 0 }, { 0, 0} };
output_fifo.get_write_vector (&vec);
if (vec.len[0] + vec.len[1] < 1) {
error << "no space in FIFO for non-process thread MIDI write" << endmsg;
return 0;
}
if (vec.len[0]) {
if (!vec.buf[0]->owns_buffer()) {
vec.buf[0]->set_buffer (0, 0, true);
}
vec.buf[0]->set (msg, msglen, timestamp);
} else {
if (!vec.buf[1]->owns_buffer()) {
vec.buf[1]->set_buffer (0, 0, true);
}
vec.buf[1]->set (msg, msglen, timestamp);
}
output_fifo.increment_write_idx (1);
ret = msglen;
} else {
// XXX This had to be temporarily commented out to make export work again
if (!(timestamp < _nframes_this_cycle)) {
std::cerr << "assertion timestamp < _nframes_this_cycle failed!" << std::endl;
}
if (_currently_in_cycle) {
if (timestamp == 0) {
timestamp = _last_write_timestamp;
}
if (jack_midi_event_write (jack_port_get_buffer (_jack_output_port, _nframes_this_cycle),
timestamp, msg, msglen) == 0) {
ret = msglen;
_last_write_timestamp = timestamp;
} else {
ret = 0;
cerr << "write of " << msglen << " failed, port holds "
<< jack_midi_get_event_count (jack_port_get_buffer (_jack_output_port, _nframes_this_cycle))
<< endl;
}
} else {
cerr << "write to JACK midi port failed: not currently in a process cycle." << endl;
}
}
if (ret > 0 && output_parser) {
// ardour doesn't care about this and neither should your app, probably
// output_parser->raw_preparse (*output_parser, msg, ret);
for (int i = 0; i < ret; i++) {
output_parser->scanner (msg[i]);
}
// ardour doesn't care about this and neither should your app, probably
// output_parser->raw_postparse (*output_parser, msg, ret);
}
return ret;
}
void
JACK_MidiPort::flush (void* jack_port_buffer)
{
RingBuffer< Evoral::Event<double> >::rw_vector vec = { { 0, 0 }, { 0, 0 } };
size_t written;
output_fifo.get_read_vector (&vec);
if (vec.len[0] + vec.len[1]) {
// cerr << "Flush " << vec.len[0] + vec.len[1] << " events from non-process FIFO\n";
}
if (vec.len[0]) {
Evoral::Event<double>* evp = vec.buf[0];
for (size_t n = 0; n < vec.len[0]; ++n, ++evp) {
jack_midi_event_write (jack_port_buffer,
(timestamp_t) evp->time(), evp->buffer(), evp->size());
}
}
if (vec.len[1]) {
Evoral::Event<double>* evp = vec.buf[1];
for (size_t n = 0; n < vec.len[1]; ++n, ++evp) {
jack_midi_event_write (jack_port_buffer,
(timestamp_t) evp->time(), evp->buffer(), evp->size());
}
}
if ((written = vec.len[0] + vec.len[1]) != 0) {
output_fifo.increment_read_idx (written);
}
}
int
JACK_MidiPort::read (byte *, size_t)
{
timestamp_t time;
Evoral::EventType type;
uint32_t size;
byte buffer[input_fifo.capacity()];
while (input_fifo.read (&time, &type, &size, buffer)) {
if (input_parser) {
input_parser->set_timestamp (time);
for (uint32_t i = 0; i < size; ++i) {
input_parser->scanner (buffer[i]);
}
}
}
return 0;
}
int
JACK_MidiPort::create_ports(const XMLNode& node)
{
Descriptor desc (node);
assert(!_jack_input_port);
assert(!_jack_output_port);
if (desc.mode == O_RDWR || desc.mode == O_WRONLY) {
_jack_output_port_name = string(desc.tag).append ("_out");
}
if (desc.mode == O_RDWR || desc.mode == O_RDONLY) {
_jack_input_port_name = string(desc.tag).append ("_in");
}
return create_ports ();
}
int
JACK_MidiPort::create_ports ()
{
bool ret = true;
jack_nframes_t nframes = jack_get_buffer_size(_jack_client);
if (!_jack_output_port_name.empty()) {
_jack_output_port = jack_port_register(_jack_client, _jack_output_port_name.c_str(),
JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0);
if (_jack_output_port) {
jack_midi_clear_buffer(jack_port_get_buffer(_jack_output_port, nframes));
}
ret = ret && (_jack_output_port != NULL);
}
if (!_jack_input_port_name.empty()) {
_jack_input_port = jack_port_register(_jack_client, _jack_input_port_name.c_str(),
JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0);
if (_jack_input_port) {
jack_midi_clear_buffer(jack_port_get_buffer(_jack_input_port, nframes));
}
ret = ret && (_jack_input_port != NULL);
}
return ret ? 0 : -1;
}
XMLNode&
JACK_MidiPort::get_state () const
{
XMLNode& root (Port::get_state ());
if (_jack_output_port) {
const char** jc = jack_port_get_connections (_jack_output_port);
string connection_string;
if (jc) {
for (int i = 0; jc[i]; ++i) {
if (i > 0) {
connection_string += ',';
}
connection_string += jc[i];
}
free (jc);
}
if (!connection_string.empty()) {
root.add_property ("outbound", connection_string);
}
} else {
if (!_outbound_connections.empty()) {
root.add_property ("outbound", _outbound_connections);
}
}
if (_jack_input_port) {
const char** jc = jack_port_get_connections (_jack_input_port);
string connection_string;
if (jc) {
for (int i = 0; jc[i]; ++i) {
if (i > 0) {
connection_string += ',';
}
connection_string += jc[i];
}
free (jc);
}
if (!connection_string.empty()) {
root.add_property ("inbound", connection_string);
}
} else {
if (!_inbound_connections.empty()) {
root.add_property ("inbound", _inbound_connections);
}
}
return root;
}
void
JACK_MidiPort::set_state (const XMLNode& node)
{
Port::set_state (node);
const XMLProperty* prop;
if ((prop = node.property ("inbound")) != 0 && _jack_input_port) {
_inbound_connections = prop->value ();
}
if ((prop = node.property ("outbound")) != 0 && _jack_output_port) {
_outbound_connections = prop->value();
}
}
void
JACK_MidiPort::make_connections ()
{
if (!_inbound_connections.empty()) {
vector<string> ports;
split (_inbound_connections, ports, ',');
for (vector<string>::iterator x = ports.begin(); x != ports.end(); ++x) {
if (_jack_client) {
jack_connect (_jack_client, (*x).c_str(), jack_port_name (_jack_input_port));
/* ignore failures */
}
}
}
if (!_outbound_connections.empty()) {
vector<string> ports;
split (_outbound_connections, ports, ',');
for (vector<string>::iterator x = ports.begin(); x != ports.end(); ++x) {
if (_jack_client) {
jack_connect (_jack_client, jack_port_name (_jack_output_port), (*x).c_str());
/* ignore failures */
}
}
}
connect_connection.disconnect ();
}
void
JACK_MidiPort::set_process_thread (pthread_t thr)
{
_process_thread = thr;
}
bool
JACK_MidiPort::is_process_thread()
{
return (pthread_self() == _process_thread);
}
void
JACK_MidiPort::reestablish (void* jack)
{
_jack_client = static_cast<jack_client_t*> (jack);
int const r = create_ports ();
if (r) {
PBD::error << "could not reregister ports for " << name() << endmsg;
}
}
void
JACK_MidiPort::reconnect ()
{
make_connections ();
}

View File

@ -25,8 +25,8 @@
#include "midi++/types.h"
#include "midi++/manager.h"
#include "midi++/factory.h"
#include "midi++/channel.h"
#include "midi++/port.h"
using namespace std;
using namespace MIDI;
@ -60,7 +60,6 @@ Port *
Manager::add_port (const XMLNode& node)
{
Port::Descriptor desc (node);
PortFactory factory;
Port *port;
PortList::iterator p;
@ -68,29 +67,15 @@ Manager::add_port (const XMLNode& node)
if (desc.tag == (*p)->name()) {
break;
}
if (!PortFactory::ignore_duplicate_devices (desc.type)) {
if (desc.device == (*p)->device()) {
/* If the existing is duplex, and this request
is not, then fail, because most drivers won't
allow opening twice with duplex and non-duplex
operation.
*/
if ((desc.mode == O_RDWR && (*p)->mode() != O_RDWR) ||
(desc.mode != O_RDWR && (*p)->mode() == O_RDWR)) {
break;
}
}
}
}
if (p != _ports.end()) {
return 0;
}
port = factory.create_port (node, api_data);
port = new Port (node, (jack_client_t *) api_data);
if (port == 0) {
return 0;
@ -228,13 +213,6 @@ Manager::cycle_end()
}
}
int
Manager::get_known_ports (vector<PortSet>& ports)
{
return PortFactory::get_known_ports (ports);
}
/** Re-register ports that disappear on JACK shutdown */
void
Manager::reestablish (void* a)

View File

@ -1,52 +0,0 @@
/*
Copyright (C) 1998-99 Paul Barton-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.
*/
#ifndef __alsa_rawmidi_h__
#define __alsa_rawmidi_h__
#include <vector>
#include <string>
#include <fcntl.h>
#include <unistd.h>
#include "midi++/port.h"
#include "midi++/fd_midiport.h"
namespace MIDI {
class ALSA_RawMidiPort : public MIDI::FD_MidiPort
{
public:
ALSA_RawMidiPort (const XMLNode& node)
: FD_MidiPort (node, "/dev/snd", "midi") {}
virtual ~ALSA_RawMidiPort () {}
static std::string typestring;
protected:
std::string get_typestring () const {
return typestring;
}
};
}
#endif // __alsa_rawmidi_h__

View File

@ -1,76 +0,0 @@
/*
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.
*/
#ifndef __alsa_sequencer_midiport_h__
#define __alsa_sequencer_midiport_h__
#include <vector>
#include <string>
#include <fcntl.h>
#include <unistd.h>
#include <alsa/asoundlib.h>
#include "midi++/port.h"
namespace MIDI {
class ALSA_SequencerMidiPort : public Port
{
public:
ALSA_SequencerMidiPort (const XMLNode&);
virtual ~ALSA_SequencerMidiPort ();
int write (byte *msg, size_t msglen, timestamp_t timestamp);
int read (byte *buf, size_t max);
/* select(2)/poll(2)-based I/O */
virtual int selectable() const;
static int discover (std::vector<PortSet>&);
static std::string typestring;
XMLNode& get_state() const;
void set_state (const XMLNode&);
protected:
std::string get_typestring () const {
return typestring;
}
private:
snd_midi_event_t *decoder, *encoder;
int port_id;
snd_seq_event_t SEv;
int create_ports (const Port::Descriptor&);
static int init_client (std::string name);
static snd_seq_t* seq;
typedef std::pair<int,int> SequencerPortAddress;
void get_connections (std::vector<SequencerPortAddress>&, int dir) const;
};
}; /* namespace MIDI */
#endif // __alsa_sequencer_midiport_h__

View File

@ -1,79 +0,0 @@
/*
Copyright (C) 2004 Paul Davis
Copyright (C) 2004 Grame
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 __coremidi_midiport_h__
#define __coremidi_midiport_h__
#include <list>
#include <string>
#include <vector>
#include <fcntl.h>
#include <unistd.h>
#include "midi++/port.h"
#include <CoreMIDI/CoreMIDI.h>
namespace MIDI {
class CoreMidi_MidiPort:public Port {
public:
CoreMidi_MidiPort(const XMLNode& node);
virtual ~ CoreMidi_MidiPort();
int write (byte * msg, size_t msglen, timestamp_t timestamp);
int read (byte * buf, size_t max) {
return 0;
}
virtual int selectable() const {
return -1;
}
static int discover (std::vector<PortSet>&);
static std::string typestring;
protected:
/* CoreMidi callback */
static void read_proc(const MIDIPacketList * pktlist,
void *refCon, void *connRefCon);
std::string get_typestring () const {
return typestring;
}
private:
byte midi_buffer[1024];
MIDIClientRef midi_client;
MIDIEndpointRef midi_destination;
MIDIEndpointRef midi_source;
int Open(const Port::Descriptor&);
void Close();
static MIDITimeStamp MIDIGetCurrentHostTime();
bool firstrecv;
};
} // namespace MIDI
#endif // __coremidi_midiport_h__

View File

@ -1,43 +0,0 @@
/*
Copyright (C) 1998-99 Paul Barton-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.
*/
#ifndef __midi_factory_h__
#define __midi_factory_h__
#include <vector>
#include <string>
#include "midi++/port.h"
namespace MIDI {
class PortFactory {
public:
Port *create_port (const XMLNode&, void* data);
static bool ignore_duplicate_devices (Port::Type);
static int get_known_ports (std::vector<PortSet>&);
static std::string default_port_type ();
static Port::Type string_to_type (const std::string&);
static std::string mode_to_string (int);
static int string_to_mode (const std::string&);
};
} // namespace MIDI
#endif // __midi_factory_h__

View File

@ -1,91 +0,0 @@
/*
Copyright (C) 1999 Paul Barton-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.
*/
#ifndef __fd_midiport_h__
#define __fd_midiport_h__
#include <vector>
#include <string>
#include <cerrno>
#include <cerrno>
#include <fcntl.h>
#include <unistd.h>
#include "midi++/port.h"
namespace MIDI {
class FD_MidiPort : public Port
{
public:
FD_MidiPort (const XMLNode& node,
const std::string &dirpath,
const std::string &pattern);
virtual ~FD_MidiPort () {
::close (_fd);
}
virtual int selectable() const;
static std::vector<std::string *> *list_devices ();
protected:
int _fd;
virtual void open (const Port::Descriptor&);
virtual int write (byte *msg, size_t msglen, timestamp_t) {
int nwritten;
if ((_mode & O_ACCMODE) == O_RDONLY) {
return -EACCES;
}
if (slowdown) {
return do_slow_write (msg, msglen);
}
if ((nwritten = ::write (_fd, msg, msglen)) > 0) {
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;
}
int read (byte *buf, size_t max);
private:
static std::string *midi_dirpath;
static std::string *midi_filename_pattern;
int do_slow_write (byte *msg, unsigned int msglen);
};
} // namespace MIDI
#endif // __fd_midiport_h__

View File

@ -1,52 +0,0 @@
/*
Copyright (C) 1998-99 Paul Barton-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.
*/
#ifndef __fifomidi_h__
#define __fifomidi_h__
#include <fcntl.h>
#include <vector>
#include <string>
#include <unistd.h>
#include "midi++/port.h"
#include "midi++/fd_midiport.h"
namespace MIDI {
class FIFO_MidiPort : public MIDI::FD_MidiPort
{
public:
FIFO_MidiPort (const XMLNode&);
~FIFO_MidiPort () {};
static std::string typestring;
protected:
std::string get_typestring () const {
return typestring;
}
private:
void open (const Port::Descriptor&);
};
} // namespace MIDI
#endif // __fifomidi_h__

View File

@ -1,117 +0,0 @@
/*
Copyright (C) 2006 Paul Davis
Written by Dave Robillard
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: jack.h 4 2005-05-13 20:47:18Z taybin $
*/
#ifndef __jack_midiport_h__
#define __jack_midiport_h__
#include <vector>
#include <string>
#include <fcntl.h>
#include <unistd.h>
#include <glibmm/thread.h>
#include <jack/weakjack.h>
#include <jack/jack.h>
#include <jack/midiport.h>
#include "pbd/ringbuffer.h"
#include "pbd/signals.h"
#include "pbd/crossthread.h"
#include "evoral/EventRingBuffer.hpp"
#include "midi++/port.h"
#include "midi++/event.h"
namespace MIDI
{
class JACK_MidiPort : public Port
{
public:
JACK_MidiPort (const XMLNode& node, jack_client_t* jack_client);
virtual ~JACK_MidiPort ();
int write(byte *msg, size_t msglen, timestamp_t timestamp);
int read(byte *buf, size_t max);
int selectable() const { return xthread.selectable(); }
bool must_drain_selectable() const { return true; }
void cycle_start(nframes_t nframes);
void cycle_end();
static std::string typestring;
XMLNode& get_state () const;
void set_state (const XMLNode&);
static void set_process_thread (pthread_t);
static pthread_t get_process_thread () { return _process_thread; }
static bool is_process_thread();
nframes_t nframes_this_cycle() const { return _nframes_this_cycle; }
void reestablish (void *);
void reconnect ();
static PBD::Signal0<void> MakeConnections;
static PBD::Signal0<void> JackHalted;
protected:
std::string get_typestring () const {
return typestring;
}
private:
int create_ports(const XMLNode&);
int create_ports ();
jack_client_t* _jack_client;
std::string _jack_input_port_name; /// input port name, or empty if there isn't one
jack_port_t* _jack_input_port;
std::string _jack_output_port_name; /// output port name, or empty if there isn't one
jack_port_t* _jack_output_port;
nframes_t _last_read_index;
timestamp_t _last_write_timestamp;
CrossThreadChannel xthread;
std::string _inbound_connections;
std::string _outbound_connections;
PBD::ScopedConnection connect_connection;
PBD::ScopedConnection halt_connection;
void flush (void* jack_port_buffer);
void jack_halted ();
void make_connections();
static pthread_t _process_thread;
RingBuffer< Evoral::Event<double> > output_fifo;
Evoral::EventRingBuffer<timestamp_t> input_fifo;
Glib::Mutex output_fifo_lock;
};
} /* namespace MIDI */
#endif // __jack_midiport_h__

View File

@ -81,8 +81,6 @@ class Manager {
return theManager;
}
int get_known_ports (std::vector<PortSet>&);
void reestablish (void *);
void reconnect ();

View File

@ -1,68 +0,0 @@
/*
Copyright (C) 1998-99 Paul Barton-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.
*/
#ifndef __nullmidi_h__
#define __nullmidi_h__
#include <fcntl.h>
#include <vector>
#include <string>
#include "midi++/port.h"
namespace MIDI {
class Null_MidiPort : public Port
{
public:
Null_MidiPort (PortRequest &req)
: Port (req) {
/* reset devname and tagname */
_devname = "nullmidi";
_tagname = "null";
_type = Port::Null;
_ok = true;
}
virtual ~Null_MidiPort () {};
/* Direct I/O */
int write (byte *msg, size_t msglen, timestamp_t timestamp) {
return msglen;
}
int read (byte *buf, size_t max) {
return 0;
}
virtual int selectable() const { return -1; }
static std::string typestring;
protected:
std::string get_typestring () const {
return typestring;
}
};
} // namespace MIDI
#endif // __nullmidi_h__

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 1998-99 Paul Barton-Davis
Copyright (C) 1998-2010 Paul Barton-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
@ -22,7 +22,15 @@
#include <string>
#include <iostream>
#include <jack/types.h>
#include "pbd/xml++.h"
#include "pbd/crossthread.h"
#include "pbd/signals.h"
#include "pbd/ringbuffer.h"
#include "evoral/Event.hpp"
#include "evoral/EventRingBuffer.hpp"
#include "midi++/types.h"
#include "midi++/parser.h"
@ -34,29 +42,18 @@ class PortRequest;
class Port {
public:
enum Type {
Unknown,
JACK_Midi,
ALSA_RawMidi,
ALSA_Sequencer,
CoreMidi_MidiPort,
Null,
FIFO
};
Port (const XMLNode&, jack_client_t *);
~Port ();
Port (const XMLNode&);
virtual ~Port ();
virtual XMLNode& get_state () const;
virtual void set_state (const XMLNode&);
XMLNode& get_state () const;
void set_state (const XMLNode&);
// FIXME: make Manager a friend of port so these can be hidden?
/* Only for use by MidiManager. Don't ever call this. */
virtual void cycle_start(nframes_t nframes);
void cycle_start(nframes_t nframes);
/* Only for use by MidiManager. Don't ever call this. */
virtual void cycle_end();
void cycle_end();
/** Write a message to port.
* @param msg Raw MIDI message to send
@ -64,14 +61,14 @@ class Port {
* @param timestamp Time stamp in frames of this message (relative to cycle start)
* @return number of bytes successfully written
*/
virtual int write (byte *msg, size_t msglen, timestamp_t timestamp) = 0;
int write (byte *msg, size_t msglen, timestamp_t timestamp);
/** Read raw bytes from a port.
* @param buf memory to store read data in
* @param bufsize size of @a buf
* @return number of bytes successfully read, negative if error
*/
virtual int read (byte *buf, size_t bufsize) = 0;
int read (byte *buf, size_t bufsize);
void parse (nframes_t timestamp);
@ -83,103 +80,90 @@ class Port {
return !(write (msg, len, timestamp) == (int) len);
}
int three_byte_msg (byte a, byte b, byte c, timestamp_t timestamp) {
byte msg[3];
msg[0] = a;
msg[1] = b;
msg[2] = c;
return !(write (msg, 3, timestamp) == 3);
}
bool clock (timestamp_t timestamp);
/* slowdown i/o to a loop of single byte emissions
interspersed with a busy loop of 10000 * this value.
This may be ignored by a particular instance
of this virtual class. See FD_MidiPort for an
example of where it used.
*/
void set_slowdown (size_t n) { slowdown = n; }
/* select(2)/poll(2)-based I/O */
/** Get the file descriptor for port.
* @return File descriptor, or -1 if not selectable.
*/
virtual int selectable() const = 0;
virtual bool must_drain_selectable() const { return false; }
int selectable () const {
return xthread.selectable();
}
static void gtk_read_callback (void *ptr, int fd, int cond);
static void write_callback (byte *msg, unsigned int len, void *);
Channel *channel (channel_t chn) {
return _channel[chn&0x7F];
}
Parser *input() { return input_parser; }
Parser *output() { return output_parser; }
void iostat (int *written, int *read,
const size_t **in_counts,
const size_t **out_counts) {
*written = bytes_written;
*read = bytes_read;
if (input_parser) {
*in_counts = input_parser->message_counts();
} else {
*in_counts = 0;
}
if (output_parser) {
*out_counts = output_parser->message_counts();
} else {
*out_counts = 0;
}
}
const char *device () const { return _devname.c_str(); }
const char *name () const { return _tagname.c_str(); }
Type type () const { return _type; }
int mode () const { return _mode; }
bool ok () const { return _ok; }
struct Descriptor {
std::string tag;
std::string device;
int mode;
Port::Type type;
Descriptor (const XMLNode&);
XMLNode& get_state();
};
virtual void reestablish (void *) {}
virtual void reconnect () {}
nframes_t nframes_this_cycle() const { return _nframes_this_cycle; }
protected:
void reestablish (void *);
void reconnect ();
static void set_process_thread (pthread_t);
static pthread_t get_process_thread () { return _process_thread; }
static bool is_process_thread();
static PBD::Signal0<void> MakeConnections;
static PBD::Signal0<void> JackHalted;
private:
bool _ok;
bool _currently_in_cycle;
nframes_t _nframes_this_cycle;
Type _type;
std::string _devname;
std::string _tagname;
int _mode;
size_t _number;
Channel *_channel[16];
unsigned int bytes_written;
unsigned int bytes_read;
Parser *input_parser;
Parser *output_parser;
size_t slowdown;
virtual std::string get_typestring () const = 0;
private:
static size_t nports;
int create_ports(const XMLNode&);
int create_ports ();
jack_client_t* _jack_client;
std::string _jack_input_port_name; /// input port name, or empty if there isn't one
jack_port_t* _jack_input_port;
std::string _jack_output_port_name; /// output port name, or empty if there isn't one
jack_port_t* _jack_output_port;
nframes_t _last_read_index;
timestamp_t _last_write_timestamp;
/** Channel used to signal to the MidiControlUI that input has arrived */
CrossThreadChannel xthread;
std::string _inbound_connections;
std::string _outbound_connections;
PBD::ScopedConnection connect_connection;
PBD::ScopedConnection halt_connection;
void flush (void* jack_port_buffer);
void jack_halted ();
void make_connections();
static pthread_t _process_thread;
RingBuffer< Evoral::Event<double> > output_fifo;
Evoral::EventRingBuffer<timestamp_t> input_fifo;
Glib::Mutex output_fifo_lock;
};
struct PortSet {

View File

@ -22,24 +22,37 @@
#include <fcntl.h>
#include <errno.h>
#include <jack/jack.h>
#include <jack/midiport.h>
#include "pbd/xml++.h"
#include "pbd/error.h"
#include "pbd/failed_constructor.h"
#include "pbd/convert.h"
#include "pbd/strsplit.h"
#include "midi++/types.h"
#include "midi++/port.h"
#include "midi++/channel.h"
#include "midi++/factory.h"
using namespace MIDI;
using namespace std;
using namespace PBD;
size_t Port::nports = 0;
pthread_t Port::_process_thread;
Signal0<void> Port::JackHalted;
Signal0<void> Port::MakeConnections;
Port::Port (const XMLNode& node)
: _currently_in_cycle(false)
, _nframes_this_cycle(0)
Port::Port (const XMLNode& node, jack_client_t* jack_client)
: _currently_in_cycle (false)
, _nframes_this_cycle (0)
, _jack_client (jack_client)
, _jack_input_port (0)
, _jack_output_port (0)
, _last_read_index (0)
, output_fifo (512)
, input_fifo (1024)
{
Descriptor desc (node);
@ -47,13 +60,9 @@ Port::Port (const XMLNode& node)
succeeds.
*/
bytes_written = 0;
bytes_read = 0;
input_parser = 0;
output_parser = 0;
slowdown = 0;
_devname = desc.device;
_tagname = desc.tag;
_mode = desc.mode;
@ -80,6 +89,15 @@ Port::Port (const XMLNode& node)
_channel[i]->connect_output_signals ();
}
}
if (!create_ports (node)) {
_ok = true;
}
MakeConnections.connect_same_thread (connect_connection, boost::bind (&Port::make_connections, this));
JackHalted.connect_same_thread (halt_connection, boost::bind (&Port::jack_halted, this));
set_state (node);
}
@ -88,6 +106,20 @@ Port::~Port ()
for (int i = 0; i < 16; i++) {
delete _channel[i];
}
if (_jack_input_port) {
if (_jack_client) {
jack_port_unregister (_jack_client, _jack_input_port);
}
_jack_input_port = 0;
}
if (_jack_output_port) {
if (_jack_client) {
jack_port_unregister (_jack_client, _jack_input_port);
}
_jack_input_port = 0;
}
}
void
@ -149,69 +181,54 @@ Port::cycle_start (nframes_t nframes)
{
_currently_in_cycle = true;
_nframes_this_cycle = nframes;
assert(_nframes_this_cycle == nframes);
_last_read_index = 0;
_last_write_timestamp = 0;
if (_jack_output_port != 0) {
// output
void *buffer = jack_port_get_buffer (_jack_output_port, nframes);
jack_midi_clear_buffer (buffer);
flush (buffer);
}
if (_jack_input_port != 0) {
// input
void* jack_buffer = jack_port_get_buffer(_jack_input_port, nframes);
const nframes_t event_count = jack_midi_get_event_count(jack_buffer);
jack_midi_event_t ev;
timestamp_t cycle_start_frame = jack_last_frame_time (_jack_client);
for (nframes_t i = 0; i < event_count; ++i) {
jack_midi_event_get (&ev, jack_buffer, i);
input_fifo.write (cycle_start_frame + ev.time, (Evoral::EventType) 0, ev.size, ev.buffer);
}
if (event_count) {
xthread.wakeup ();
}
}
}
void
Port::cycle_end ()
{
if (_jack_output_port != 0) {
flush (jack_port_get_buffer (_jack_output_port, _nframes_this_cycle));
}
_currently_in_cycle = false;
_nframes_this_cycle = 0;
}
XMLNode&
Port::get_state () const
{
XMLNode* node = new XMLNode ("MIDI-port");
node->add_property ("tag", _tagname);
node->add_property ("device", _devname);
node->add_property ("mode", PortFactory::mode_to_string (_mode));
node->add_property ("type", get_typestring());
#if 0
byte device_inquiry[6];
device_inquiry[0] = 0xf0;
device_inquiry[0] = 0x7e;
device_inquiry[0] = 0x7f;
device_inquiry[0] = 0x06;
device_inquiry[0] = 0x02;
device_inquiry[0] = 0xf7;
write (device_inquiry, sizeof (device_inquiry), 0);
#endif
return *node;
}
void
Port::set_state (const XMLNode& /*node*/)
{
// relax
}
void
Port::gtk_read_callback (void *ptr, int /*fd*/, int /*cond*/)
{
byte buf[64];
((Port *)ptr)->read (buf, sizeof (buf));
}
void
Port::write_callback (byte *msg, unsigned int len, void *ptr)
{
((Port *)ptr)->write (msg, len, 0);
}
std::ostream & MIDI::operator << ( std::ostream & os, const MIDI::Port & port )
{
using namespace std;
os << "MIDI::Port { ";
os << "device: " << port.device();
os << "; ";
os << "name: " << port.name();
os << "; ";
os << "type: " << port.type();
os << "; ";
os << "mode: " << port.mode();
os << "; ";
os << "ok: " << port.ok();
@ -224,8 +241,6 @@ Port::Descriptor::Descriptor (const XMLNode& node)
{
const XMLProperty *prop;
bool have_tag = false;
bool have_device = false;
bool have_type = false;
bool have_mode = false;
if ((prop = node.property ("tag")) != 0) {
@ -233,23 +248,354 @@ Port::Descriptor::Descriptor (const XMLNode& node)
have_tag = true;
}
if ((prop = node.property ("device")) != 0) {
device = prop->value();
have_device = true;
}
if ((prop = node.property ("type")) != 0) {
type = PortFactory::string_to_type (prop->value());
have_type = true;
}
if ((prop = node.property ("mode")) != 0) {
mode = PortFactory::string_to_mode (prop->value());
mode = O_RDWR;
if (strings_equal_ignore_case (prop->value(), "output") || strings_equal_ignore_case (prop->value(), "out")) {
mode = O_WRONLY;
} else if (strings_equal_ignore_case (prop->value(), "input") || strings_equal_ignore_case (prop->value(), "in")) {
mode = O_RDONLY;
}
have_mode = true;
}
if (!have_tag || !have_device || !have_type || !have_mode) {
if (!have_tag || !have_mode) {
throw failed_constructor();
}
}
void
Port::jack_halted ()
{
_jack_client = 0;
_jack_input_port = 0;
_jack_output_port = 0;
}
int
Port::write(byte * msg, size_t msglen, timestamp_t timestamp)
{
int ret = 0;
if (!_jack_output_port) {
return ret;
}
if (!is_process_thread()) {
Glib::Mutex::Lock lm (output_fifo_lock);
RingBuffer< Evoral::Event<double> >::rw_vector vec = { { 0, 0 }, { 0, 0} };
output_fifo.get_write_vector (&vec);
if (vec.len[0] + vec.len[1] < 1) {
error << "no space in FIFO for non-process thread MIDI write" << endmsg;
return 0;
}
if (vec.len[0]) {
if (!vec.buf[0]->owns_buffer()) {
vec.buf[0]->set_buffer (0, 0, true);
}
vec.buf[0]->set (msg, msglen, timestamp);
} else {
if (!vec.buf[1]->owns_buffer()) {
vec.buf[1]->set_buffer (0, 0, true);
}
vec.buf[1]->set (msg, msglen, timestamp);
}
output_fifo.increment_write_idx (1);
ret = msglen;
} else {
// XXX This had to be temporarily commented out to make export work again
if (!(timestamp < _nframes_this_cycle)) {
std::cerr << "assertion timestamp < _nframes_this_cycle failed!" << std::endl;
}
if (_currently_in_cycle) {
if (timestamp == 0) {
timestamp = _last_write_timestamp;
}
if (jack_midi_event_write (jack_port_get_buffer (_jack_output_port, _nframes_this_cycle),
timestamp, msg, msglen) == 0) {
ret = msglen;
_last_write_timestamp = timestamp;
} else {
ret = 0;
cerr << "write of " << msglen << " failed, port holds "
<< jack_midi_get_event_count (jack_port_get_buffer (_jack_output_port, _nframes_this_cycle))
<< endl;
}
} else {
cerr << "write to JACK midi port failed: not currently in a process cycle." << endl;
}
}
if (ret > 0 && output_parser) {
// ardour doesn't care about this and neither should your app, probably
// output_parser->raw_preparse (*output_parser, msg, ret);
for (int i = 0; i < ret; i++) {
output_parser->scanner (msg[i]);
}
// ardour doesn't care about this and neither should your app, probably
// output_parser->raw_postparse (*output_parser, msg, ret);
}
return ret;
}
void
Port::flush (void* jack_port_buffer)
{
RingBuffer< Evoral::Event<double> >::rw_vector vec = { { 0, 0 }, { 0, 0 } };
size_t written;
output_fifo.get_read_vector (&vec);
if (vec.len[0] + vec.len[1]) {
// cerr << "Flush " << vec.len[0] + vec.len[1] << " events from non-process FIFO\n";
}
if (vec.len[0]) {
Evoral::Event<double>* evp = vec.buf[0];
for (size_t n = 0; n < vec.len[0]; ++n, ++evp) {
jack_midi_event_write (jack_port_buffer,
(timestamp_t) evp->time(), evp->buffer(), evp->size());
}
}
if (vec.len[1]) {
Evoral::Event<double>* evp = vec.buf[1];
for (size_t n = 0; n < vec.len[1]; ++n, ++evp) {
jack_midi_event_write (jack_port_buffer,
(timestamp_t) evp->time(), evp->buffer(), evp->size());
}
}
if ((written = vec.len[0] + vec.len[1]) != 0) {
output_fifo.increment_read_idx (written);
}
}
int
Port::read (byte *, size_t)
{
timestamp_t time;
Evoral::EventType type;
uint32_t size;
byte buffer[input_fifo.capacity()];
while (input_fifo.read (&time, &type, &size, buffer)) {
if (input_parser) {
input_parser->set_timestamp (time);
for (uint32_t i = 0; i < size; ++i) {
input_parser->scanner (buffer[i]);
}
}
}
return 0;
}
int
Port::create_ports(const XMLNode& node)
{
Descriptor desc (node);
assert(!_jack_input_port);
assert(!_jack_output_port);
if (desc.mode == O_RDWR || desc.mode == O_WRONLY) {
_jack_output_port_name = string(desc.tag).append ("_out");
}
if (desc.mode == O_RDWR || desc.mode == O_RDONLY) {
_jack_input_port_name = string(desc.tag).append ("_in");
}
return create_ports ();
}
int
Port::create_ports ()
{
bool ret = true;
jack_nframes_t nframes = jack_get_buffer_size(_jack_client);
if (!_jack_output_port_name.empty()) {
_jack_output_port = jack_port_register(_jack_client, _jack_output_port_name.c_str(),
JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0);
if (_jack_output_port) {
jack_midi_clear_buffer(jack_port_get_buffer(_jack_output_port, nframes));
}
ret = ret && (_jack_output_port != NULL);
}
if (!_jack_input_port_name.empty()) {
_jack_input_port = jack_port_register(_jack_client, _jack_input_port_name.c_str(),
JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0);
if (_jack_input_port) {
jack_midi_clear_buffer(jack_port_get_buffer(_jack_input_port, nframes));
}
ret = ret && (_jack_input_port != NULL);
}
return ret ? 0 : -1;
}
XMLNode&
Port::get_state () const
{
XMLNode* root = new XMLNode ("MIDI-port");
root->add_property ("tag", _tagname);
if (_mode == O_RDONLY) {
root->add_property ("mode", "input");
} else if (_mode == O_WRONLY) {
root->add_property ("mode", "output");
} else {
root->add_property ("mode", "duplex");
}
#if 0
byte device_inquiry[6];
device_inquiry[0] = 0xf0;
device_inquiry[0] = 0x7e;
device_inquiry[0] = 0x7f;
device_inquiry[0] = 0x06;
device_inquiry[0] = 0x02;
device_inquiry[0] = 0xf7;
write (device_inquiry, sizeof (device_inquiry), 0);
#endif
if (_jack_output_port) {
const char** jc = jack_port_get_connections (_jack_output_port);
string connection_string;
if (jc) {
for (int i = 0; jc[i]; ++i) {
if (i > 0) {
connection_string += ',';
}
connection_string += jc[i];
}
free (jc);
}
if (!connection_string.empty()) {
root->add_property ("outbound", connection_string);
}
} else {
if (!_outbound_connections.empty()) {
root->add_property ("outbound", _outbound_connections);
}
}
if (_jack_input_port) {
const char** jc = jack_port_get_connections (_jack_input_port);
string connection_string;
if (jc) {
for (int i = 0; jc[i]; ++i) {
if (i > 0) {
connection_string += ',';
}
connection_string += jc[i];
}
free (jc);
}
if (!connection_string.empty()) {
root->add_property ("inbound", connection_string);
}
} else {
if (!_inbound_connections.empty()) {
root->add_property ("inbound", _inbound_connections);
}
}
return *root;
}
void
Port::set_state (const XMLNode& node)
{
const XMLProperty* prop;
if ((prop = node.property ("inbound")) != 0 && _jack_input_port) {
_inbound_connections = prop->value ();
}
if ((prop = node.property ("outbound")) != 0 && _jack_output_port) {
_outbound_connections = prop->value();
}
}
void
Port::make_connections ()
{
if (!_inbound_connections.empty()) {
vector<string> ports;
split (_inbound_connections, ports, ',');
for (vector<string>::iterator x = ports.begin(); x != ports.end(); ++x) {
if (_jack_client) {
jack_connect (_jack_client, (*x).c_str(), jack_port_name (_jack_input_port));
/* ignore failures */
}
}
}
if (!_outbound_connections.empty()) {
vector<string> ports;
split (_outbound_connections, ports, ',');
for (vector<string>::iterator x = ports.begin(); x != ports.end(); ++x) {
if (_jack_client) {
jack_connect (_jack_client, jack_port_name (_jack_output_port), (*x).c_str());
/* ignore failures */
}
}
}
connect_connection.disconnect ();
}
void
Port::set_process_thread (pthread_t thr)
{
_process_thread = thr;
}
bool
Port::is_process_thread()
{
return (pthread_self() == _process_thread);
}
void
Port::reestablish (void* jack)
{
_jack_client = static_cast<jack_client_t*> (jack);
int const r = create_ports ();
if (r) {
PBD::error << "could not reregister ports for " << name() << endmsg;
}
}
void
Port::reconnect ()
{
make_connections ();
}

View File

@ -45,11 +45,8 @@ def build(bld):
# Library
obj = bld.new_task_gen('cxx', 'shlib')
obj.source = '''
fd_midiport.cc
fifomidi.cc
midi.cc
channel.cc
factory.cc
manager.cc
parser.cc
port.cc
@ -59,21 +56,12 @@ def build(bld):
version.cc
'''
# everybody loves JACK
obj.source += ' jack_midiport.cc '
obj.cxxflags = [ '-DWITH_JACK_MIDI' ]
if bld.env['HAVE_COREAUDIO'] and bld.env['COREAUDIO']:
# OS X
obj.source += ' coremidi_midiport.cc '
obj.cxxflags += [ '-DWITH_COREMIDI' ]
elif sys.platform == 'linux':
# linux
obj.source += ' alsa_sequencer_midiport.cc '
obj.cxxflags += [ '-DWITH_ALSA' ]
obj.export_incdirs = ['.']
obj.includes = ['.', '../surfaces/control_protocol']
obj.name = 'libmidipp'
obj.target = 'midipp'
obj.uselib = 'GLIBMM SIGCPP XML JACK OSX COREAUDIO'
obj.uselib = 'GLIBMM SIGCPP XML JACK OSX'
obj.uselib_local = 'libpbd libevoral'
obj.vnum = LIBMIDIPP_LIB_VERSION
obj.install_path = os.path.join(bld.env['LIBDIR'], 'ardour3')

View File

@ -563,20 +563,14 @@ MackieControlProtocol::connect_session_signals()
void
MackieControlProtocol::add_port (MIDI::Port & midi_port, int number)
{
DEBUG_TRACE (DEBUG::MackieControl, string_compose ("add port %1,%2,%3\n", midi_port.name(), midi_port.device(), midi_port.type()));
DEBUG_TRACE (DEBUG::MackieControl, string_compose ("add port %1\n", midi_port.name()));
if (string (midi_port.device()) == string ("ardour") && midi_port.type() == MIDI::Port::ALSA_Sequencer) {
throw MackieControlException ("The Mackie MCU driver will not use a port with device=ardour");
} else if (midi_port.type() == MIDI::Port::ALSA_Sequencer) {
throw MackieControlException ("alsa/sequencer ports don't work with the Mackie MCU driver right now");
} else {
MackiePort * sport = new MackiePort (*this, midi_port, number);
_ports.push_back (sport);
sport->init_event.connect_same_thread (port_connections, boost::bind (&MackieControlProtocol::handle_port_init, this, sport));
sport->active_event.connect_same_thread (port_connections, boost::bind (&MackieControlProtocol::handle_port_active, this, sport));
sport->inactive_event.connect_same_thread (port_connections, boost::bind (&MackieControlProtocol::handle_port_inactive, this, sport));
}
MackiePort * sport = new MackiePort (*this, midi_port, number);
_ports.push_back (sport);
sport->init_event.connect_same_thread (port_connections, boost::bind (&MackieControlProtocol::handle_port_init, this, sport));
sport->active_event.connect_same_thread (port_connections, boost::bind (&MackieControlProtocol::handle_port_active, this, sport));
sport->inactive_event.connect_same_thread (port_connections, boost::bind (&MackieControlProtocol::handle_port_inactive, this, sport));
}
void

View File

@ -173,8 +173,6 @@ void SurfacePort::write_sysex( MIDI::byte msg )
ostream & Mackie::operator << ( ostream & os, const SurfacePort & port )
{
os << "{ ";
os << "device: " << port.port().device();
os << "; ";
os << "name: " << port.port().name();
os << "; ";
os << " }";