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.
rosegarden/src/sound/AlsaPort.cpp

192 lines
4.9 KiB

/*
Rosegarden
A sequencer and musical notation editor.
This program is Copyright 2000-2008
Guillaume Laurent <glaurent@telegraph-road.org>,
Chris Cannam <cannam@all-day-breakfast.com>,
Richard Bown <bownie@bownie.com>
The moral right of the authors to claim authorship of this work
has been asserted.
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. See the file
COPYING included with this distribution for more information.
*/
#include "AlsaPort.h"
#include <iostream>
#include <cstdlib>
#include <cstdio>
#ifdef HAVE_ALSA
// ALSA
#include <alsa/asoundlib.h>
#include <alsa/seq_event.h>
#include <alsa/version.h>
#include "MappedInstrument.h"
#include "Midi.h"
#include "WAVAudioFile.h"
#include "MappedStudio.h"
#include "misc/Strings.h"
#ifdef HAVE_LIBJACK
#include <jack/types.h>
#include <unistd.h> // for usleep
#include <cmath>
#endif
namespace Rosegarden
{
AlsaPortDescription::AlsaPortDescription(Instrument::InstrumentType type,
const std::string &name,
int client,
int port,
unsigned int clientType,
unsigned int portType,
unsigned int capability,
PortDirection direction):
m_type(type),
m_name(name),
m_client(client),
m_port(port),
m_clientType(clientType),
m_portType(portType),
m_capability(capability),
m_direction(direction)
{}
bool
AlsaPortCmp::operator()(AlsaPortDescription *a1, AlsaPortDescription *a2)
{
// Ordering for ALSA ports in the list:
//
// * Hardware ports (client id 64-127) sorted by direction
// (write, duplex, read) then client id then port id
//
// * Software ports (client id 128+) sorted by client id
// then port id
//
// * System ports (client id 0-63) sorted by client id then
// port id
// See comment in AlsaDriver::createMidiDevice -- the client
// numbering scheme changed in ALSA driver 1.0.11rc1.
// We now order:
//
// * Write-only software ports (client id 128+) sorted by client
// id then port id
//
// * Probable hardware ports (client id 16-127) sorted by
// direction (write, duplex, read) then client id (64+
// preferred) then port id
//
// * Read-write or read-only software ports (client id 128+)
// sorted by client id then port id
//
// * System ports (client id 0-15) sorted by client id then
// port id
//
// It's necessary to handle software ports ahead of
// hardware/system ports, because we want to keep all the hardware
// ports together (we don't want to change the priority of a
// hardware port relative to a software port based on its client
// ID) and we can't know for sure whether the 16-63 range are
// hardware or system ports.
enum Category {
WRITE_ONLY_SOFTWARE,
HARDWARE_PROBABLY,
MIXED_SOFTWARE,
SYSTEM
};
bool oldScheme = (SND_LIB_MAJOR == 0 ||
(SND_LIB_MAJOR == 1 &&
SND_LIB_MINOR == 0 &&
SND_LIB_SUBMINOR < 11));
Category a1cat;
if (a1->m_client < 16)
a1cat = SYSTEM;
else if (oldScheme && (a1->m_client < 64))
a1cat = SYSTEM;
else if (a1->m_client < 128)
a1cat = HARDWARE_PROBABLY;
else
a1cat = MIXED_SOFTWARE;
if (a1cat == MIXED_SOFTWARE) {
if (a1->m_direction == WriteOnly)
a1cat = WRITE_ONLY_SOFTWARE;
}
Category a2cat;
if (a2->m_client < 16)
a2cat = SYSTEM;
else if (oldScheme && (a2->m_client < 64))
a2cat = SYSTEM;
else if (a2->m_client < 128)
a2cat = HARDWARE_PROBABLY;
else
a2cat = MIXED_SOFTWARE;
if (a2cat == MIXED_SOFTWARE) {
if (a2->m_direction == WriteOnly)
a2cat = WRITE_ONLY_SOFTWARE;
}
if (a1cat != a2cat)
return int(a1cat) < int(a2cat);
if (a1cat == HARDWARE_PROBABLY) {
if (a1->m_direction == WriteOnly) {
if (a2->m_direction != WriteOnly)
return true;
} else if (a1->m_direction == Duplex) {
if (a2->m_direction == ReadOnly)
return true;
}
int c1 = a1->m_client;
int c2 = a2->m_client;
if (c1 < 64)
c1 += 1000;
if (c2 < 64)
c2 += 1000;
if (c1 != c2)
return c1 < c2;
} else if (a1cat == SYSTEM) {
int c1 = a1->m_client;
int c2 = a2->m_client;
if (c1 < 16)
c1 += 1000;
if (c2 < 16)
c2 += 1000;
if (c1 != c2)
return c1 < c2;
}
if (a1->m_client != a2->m_client) {
return a1->m_client < a2->m_client;
} else {
return a1->m_port < a2->m_port;
}
}
}
#endif // HAVE_ALSA