You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdemultimedia/arts/midi/alsamidigateway_impl.cc

244 lines
5.4 KiB

/*
Copyright (C) 2001-2002 Stefan Westerfeld
stefan@space.twc.de
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "artsmidi.h"
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
/**
* compile real version if we have ALSA support, dummy version otherwise
*/
#if defined(HAVE_ARTS_LIBASOUND2) || defined(HAVE_ARTS_LIBASOUND)
#ifdef HAVE_ALSA_ASOUNDLIB_H
#include <alsa/asoundlib.h>
#elif defined(HAVE_SYS_ASOUNDLIB_H)
#include <sys/asoundlib.h>
#endif
#include "alsamidiport_impl.h"
#include <arts/debug.h>
#include <stdio.h>
using namespace Arts;
using namespace std;
class AlsaMidiGateway_impl : virtual public AlsaMidiGateway_skel {
protected:
snd_seq_t *seq;
struct PortEntry {
int alsaClient, alsaPort;
bool keep;
AlsaMidiPort port;
MidiClient client;
};
list<PortEntry> ports;
#ifdef HAVE_ARTS_LIBASOUND2
/* ALSA-0.9 specific code */
int alsaOpen() {
return snd_seq_open(&seq, "hw", SND_SEQ_OPEN_DUPLEX, 0);
}
bool alsaScan(MidiManager midiManager) {
snd_seq_client_info_t *cinfo;
snd_seq_port_info_t *pinfo;
snd_seq_client_info_alloca(&cinfo);
snd_seq_client_info_set_client(cinfo, -1);
while (snd_seq_query_next_client(seq, cinfo) >= 0) {
int client = snd_seq_client_info_get_client(cinfo);
snd_seq_port_info_alloca(&pinfo);
snd_seq_port_info_set_client(pinfo, client);
snd_seq_port_info_set_port(pinfo, -1);
while (snd_seq_query_next_port(seq, pinfo) >= 0) {
unsigned int cap;
cap = (SND_SEQ_PORT_CAP_SUBS_WRITE|SND_SEQ_PORT_CAP_WRITE);
if ((snd_seq_port_info_get_capability(pinfo) & cap) == cap) {
string name = snd_seq_port_info_get_name(pinfo);
int client = snd_seq_port_info_get_client(pinfo);
int port = snd_seq_port_info_get_port(pinfo);
createPort(midiManager, name, client, port);
}
}
}
return true;
}
#else
/* ALSA-0.5 specific code */
int alsaOpen() {
return snd_seq_open(&seq, SND_SEQ_OPEN);
}
bool alsaScan(MidiManager midiManager) {
snd_seq_system_info_t sysinfo;
int err = snd_seq_system_info(seq, &sysinfo);
if (err < 0)
{
arts_warning("snd_seq_systeminfo failed: %s", snd_strerror(err));
return false;
}
for(int client = 0; client < sysinfo.clients; client++)
{
snd_seq_client_info_t cinfo;
if (snd_seq_get_any_client_info(seq, client, &cinfo) == 0)
{
for(int port = 0; port < sysinfo.ports; port++)
{
snd_seq_port_info_t pinfo;
if(snd_seq_get_any_port_info(seq, client, port, &pinfo) == 0)
{
unsigned int cap;
cap = (SND_SEQ_PORT_CAP_SUBS_WRITE|SND_SEQ_PORT_CAP_WRITE);
if ((pinfo.capability & cap) == cap)
createPort(midiManager, pinfo.name, client, port);
}
}
}
}
return true;
}
#endif
public:
AlsaMidiGateway_impl() : seq(0)
{
}
~AlsaMidiGateway_impl()
{
if(seq)
snd_seq_close(seq);
}
void createPort(MidiManager midiManager, string name, int client, int port)
{
if(name != "aRts")
{
char nr[1024];
sprintf(nr, " (%3d:%-3d)", client, port);
name += nr;
list<PortEntry>::iterator pi = ports.begin();
while(pi != ports.end() && (pi->alsaClient != client || pi->alsaPort != port))
pi++;
if(pi != ports.end()) /* we already have this port */
pi->keep = true;
else /* we need to create it */
{
PortEntry pe;
pe.port = AlsaMidiPort::_from_base(
new AlsaMidiPort_impl(seq, client, port));
if(pe.port.open())
{
pe.client = midiManager.addClient(mcdRecord,
mctDestination,
name, name);
pe.client.addInputPort(pe.port);
pe.alsaClient = client;
pe.alsaPort = port;
pe.keep = true;
ports.push_back(pe);
}
}
}
}
bool rescan()
{
MidiManager midiManager = DynamicCast(Reference("global:Arts_MidiManager"));
if(midiManager.isNull())
{
arts_warning("AlsaMidiGateway: can't find MidiManager");
return false;
}
if(!seq)
{
int err = alsaOpen();
if (err < 0)
{
arts_warning("AlsaMidiGateway: could not open sequencer %s",
snd_strerror(err));
seq = 0;
return false;
}
}
list<PortEntry>::iterator pi;
for(pi = ports.begin(); pi != ports.end(); pi++)
pi->keep = false;
if(!alsaScan(midiManager))
return false;
/* erase those ports that are no longer needed */
pi = ports.begin();
while(pi != ports.end())
{
if(!pi->keep)
pi = ports.erase(pi);
else
pi++;
}
return true;
}
};
#else
using namespace Arts;
using namespace std;
class AlsaMidiGateway_impl : virtual public AlsaMidiGateway_skel {
public:
bool rescan()
{
/* dummy version: no ALSA support compiled in */
return false;
}
};
#endif
namespace Arts {
REGISTER_IMPLEMENTATION(AlsaMidiGateway_impl);
}