324 lines
7.2 KiB
C++
324 lines
7.2 KiB
C++
#include <iostream>
|
|
#include <fstream>
|
|
#include <cstring>
|
|
#include "jack.h"
|
|
#include "portmanager.h"
|
|
|
|
void PortManager::Add(jack_port_t *port)
|
|
{
|
|
std::string jack_name = jack_port_name(port);
|
|
std::string client_name;
|
|
std::string group_name;
|
|
std::string port_name;
|
|
|
|
char *aliases[2];
|
|
aliases[0] = new char[jack_port_name_size()];
|
|
aliases[1] = new char[jack_port_name_size()];
|
|
int num_aliases = jack_port_get_aliases(port, aliases);
|
|
|
|
if (num_aliases < 2) {
|
|
pm.AliasBay(port, num_aliases, aliases);
|
|
num_aliases = jack_port_get_aliases(port, aliases);
|
|
}
|
|
|
|
if (num_aliases == 2) {
|
|
jack_name = aliases[1];
|
|
} else if (num_aliases == 1) {
|
|
jack_name = aliases[0];
|
|
}
|
|
|
|
delete aliases[0];
|
|
delete aliases[1];
|
|
|
|
size_t pos1 = jack_name.find(':');
|
|
size_t pos2 = jack_name.find('.', pos1);
|
|
|
|
// All ports must have a client part
|
|
if (pos1 == std::string::npos) return;
|
|
|
|
Port *p = new Port();
|
|
p->m_port = port;
|
|
p->m_flags = (JackPortFlags)jack_port_flags(port);
|
|
|
|
std::string type = jack_port_type(port);
|
|
p->m_is_midi = type == JACK_DEFAULT_MIDI_TYPE;
|
|
|
|
// Client
|
|
client_name = jack_name.substr(0, pos1);
|
|
p->m_client = FindOrMakeClient(client_name, p->m_flags & JackPortIsInput, p->m_is_midi);
|
|
|
|
if (pos2 != std::string::npos) {
|
|
// Group
|
|
group_name = jack_name.substr(pos1 + 1, pos2 - pos1 - 1);
|
|
port_name = jack_name.substr(pos2 + 1);
|
|
} else {
|
|
group_name = "";
|
|
port_name = jack_name.substr(pos1 + 1);
|
|
}
|
|
|
|
p->m_group = FindOrMakeGroup(p->m_client, p->m_flags, group_name);
|
|
p->m_group->m_ports.push_back(p);
|
|
|
|
p->m_name = port_name;
|
|
|
|
//std::clog << "New port (" << client_name << ") " << port_name << std::endl;
|
|
|
|
p->m_client->m_ports.push_back(p);
|
|
|
|
m_ports.push_back(p);
|
|
}
|
|
|
|
void PortManager::Delete(jack_port_t *port)
|
|
{
|
|
Port *p = FindPort(port);
|
|
if (p == NULL) {
|
|
std::cerr << "Deleting unknown port!" << std::endl;
|
|
return;
|
|
}
|
|
|
|
if (p->m_group != NULL) {
|
|
// Clean up groups
|
|
p->m_group->m_ports.remove(p);
|
|
if (p->m_group->m_ports.size() == 0) {
|
|
p->m_client->m_groups.remove(p->m_group);
|
|
delete p->m_group;
|
|
}
|
|
}
|
|
|
|
// Clean up clients
|
|
p->m_client->m_ports.remove(p);
|
|
if (p->m_client->m_ports.size() == 0) {
|
|
m_clients.remove(p->m_client);
|
|
delete p->m_client;
|
|
}
|
|
|
|
// Remove port
|
|
m_ports.remove(p);
|
|
|
|
//std::clog << "Port '" << p->m_name << "' removed" << std::endl;
|
|
|
|
delete p;
|
|
}
|
|
|
|
void PortManager::Connect(jack_port_t *port_a, jack_port_t *port_b)
|
|
{
|
|
Port *p1 = FindPort(port_a);
|
|
Port *p2 = FindPort(port_b);
|
|
|
|
if (p1 == NULL || p2 == NULL) {
|
|
std::cerr << "Connecting unknown ports!" << std::endl;
|
|
return;
|
|
}
|
|
|
|
if (p1->m_flags & JackPortIsInput) {
|
|
p1->m_connections.push_back(p2);
|
|
} else {
|
|
p2->m_connections.push_back(p1);
|
|
}
|
|
|
|
//std::clog << "Connecting '" << jack_port_name(port_a) << "' to '" << jack_port_name(port_b) << "'" << std::endl;
|
|
}
|
|
|
|
void PortManager::Disconnect(jack_port_t *port_a, jack_port_t *port_b)
|
|
{
|
|
Port *p1 = FindPort(port_a);
|
|
Port *p2 = FindPort(port_b);
|
|
|
|
if (p1 == NULL || p2 == NULL) {
|
|
std::cerr << "Disconnecting unknown ports!" << std::endl;
|
|
return;
|
|
}
|
|
|
|
if (p1->m_flags & JackPortIsInput) {
|
|
p1->m_connections.remove(p2);
|
|
} else {
|
|
p2->m_connections.remove(p1);
|
|
}
|
|
|
|
//std::clog << "Disconnecting '" << jack_port_name(port_a) << "' from '" << jack_port_name(port_b) << "'" << std::endl;
|
|
}
|
|
|
|
Client *PortManager::FindOrMakeClient(std::string name, bool is_input, bool is_midi)
|
|
{
|
|
ClientList::iterator it;
|
|
for (it = m_clients.begin(); it != m_clients.end(); ++it) {
|
|
Client *c = *it;
|
|
if (c->m_is_input == is_input && c->m_is_midi == is_midi && c->m_name == name) return c;
|
|
}
|
|
|
|
Client *c = new Client();
|
|
c->m_name = name;
|
|
c->m_is_input = is_input;
|
|
c->m_is_midi = is_midi;
|
|
c->m_expanded = true;
|
|
|
|
m_clients.push_back(c);
|
|
|
|
return c;
|
|
}
|
|
|
|
PortGroup *PortManager::FindOrMakeGroup(Client *client, JackPortFlags flags, std::string name)
|
|
{
|
|
PortGroupList::iterator it;
|
|
for (it = client->m_groups.begin(); it != client->m_groups.end(); ++it) {
|
|
PortGroup *pg = *it;
|
|
if (pg->m_flags == flags && pg->m_name == name) return pg;
|
|
}
|
|
|
|
PortGroup *pg = new PortGroup();
|
|
pg->m_name = name;
|
|
pg->m_flags = flags;
|
|
pg->m_expanded = false;
|
|
|
|
client->m_groups.push_back(pg);
|
|
|
|
return pg;
|
|
}
|
|
|
|
Port *PortManager::FindPort(jack_port_t *port)
|
|
{
|
|
PortList::iterator it;
|
|
for (it = m_ports.begin(); it != m_ports.end(); ++it) {
|
|
Port *p = *it;
|
|
if (p->m_port == port) return p;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static bool ClientSortPredicate(const Client *lhs, const Client *rhs)
|
|
{
|
|
return lhs->m_name < rhs->m_name;
|
|
}
|
|
|
|
static bool PortGroupSortPredicate(const PortGroup *lhs, const PortGroup *rhs)
|
|
{
|
|
return lhs->m_name < rhs->m_name;
|
|
}
|
|
|
|
static bool PortSortPredicate(const Port *lhs, const Port *rhs)
|
|
{
|
|
return lhs->m_name < rhs->m_name;
|
|
}
|
|
|
|
void PortManager::Sort()
|
|
{
|
|
m_clients.sort(&ClientSortPredicate);
|
|
|
|
ClientList::iterator clit;
|
|
for (clit = m_clients.begin(); clit != m_clients.end(); ++clit) {
|
|
Client *c = *clit;
|
|
|
|
c->m_groups.sort(&PortGroupSortPredicate);
|
|
|
|
PortGroupList::iterator pglit;
|
|
for (pglit = c->m_groups.begin(); pglit != c->m_groups.end(); ++pglit) {
|
|
PortGroup *pg = *pglit;
|
|
|
|
pg->m_ports.sort(&PortSortPredicate);
|
|
}
|
|
}
|
|
}
|
|
|
|
void PortManager::ToggleConnect(Port *a, Port *b)
|
|
{
|
|
ConnectionMode cm = a->ConnectedTo(b);
|
|
|
|
if (cm == CM_NONE) {
|
|
jack.Connect(b->m_port, a->m_port);
|
|
} else {
|
|
jack.Disconnect(b->m_port, a->m_port);
|
|
}
|
|
}
|
|
|
|
void PortManager::ToggleConnect(Port *a, PortGroup *b)
|
|
{
|
|
PortList::iterator plitb;
|
|
ConnectionMode cm = a->ConnectedTo(b);
|
|
|
|
for (plitb = b->m_ports.begin(); plitb != b->m_ports.end(); ++plitb) {
|
|
Port *pb = *plitb;
|
|
|
|
// if (connect == 0) {
|
|
// connect = a->ConnectedTo(pb) ? -1 : 1;
|
|
// }
|
|
if (cm == CM_NONE) {
|
|
jack.Connect(pb->m_port, a->m_port);
|
|
} else {
|
|
jack.Disconnect(pb->m_port, a->m_port);
|
|
}
|
|
}
|
|
}
|
|
|
|
void PortManager::ToggleConnect(PortGroup *a, Port *b)
|
|
{
|
|
PortList::iterator plita;
|
|
ConnectionMode cm = a->ConnectedTo(b);
|
|
|
|
for (plita = a->m_ports.begin(); plita != a->m_ports.end(); ++plita) {
|
|
Port *pa = *plita;
|
|
|
|
// if (connect == 0) {
|
|
// connect = pa->ConnectedTo(b) ? -1 : 1;
|
|
// }
|
|
if (cm == CM_NONE) {
|
|
jack.Connect(b->m_port, pa->m_port);
|
|
} else {
|
|
jack.Disconnect(b->m_port, pa->m_port);
|
|
}
|
|
}
|
|
}
|
|
|
|
void PortManager::ToggleConnect(PortGroup *a, PortGroup *b)
|
|
{
|
|
PortList::iterator plita;
|
|
PortList::iterator plitb;
|
|
ConnectionMode cm = a->ConnectedTo(b);
|
|
|
|
for (plita = a->m_ports.begin(), plitb = b->m_ports.begin(); plita != a->m_ports.end() && plitb != b->m_ports.end(); ++plita, ++plitb) {
|
|
Port *pa = *plita;
|
|
Port *pb = *plitb;
|
|
|
|
if (cm == CM_NONE) {
|
|
jack.Connect(pb->m_port, pa->m_port);
|
|
} else {
|
|
jack.Disconnect(pb->m_port, pa->m_port);
|
|
}
|
|
}
|
|
}
|
|
|
|
void PortManager::AliasBay(jack_port_t *port, int num_aliases, char *aliases[2])
|
|
{
|
|
std::string port_name = jack_port_name(port);
|
|
|
|
AliasList::iterator it;
|
|
for (it = m_aliases.begin(); it != m_aliases.end(); ++it) {
|
|
Alias &a = *it;
|
|
if (a.name == port_name) {
|
|
bool got = false;
|
|
for (int i = 0; i < num_aliases; i++) {
|
|
if (a.alias == aliases[i]) got = true;
|
|
}
|
|
if (!got) {
|
|
jack_port_set_alias(port, a.alias.c_str());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void PortManager::AliasLoad(std::string filename)
|
|
{
|
|
std::ifstream file;
|
|
file.open(filename.c_str());
|
|
if (!file) return;
|
|
|
|
char line[1024];
|
|
while (file.getline(line, sizeof line)) {
|
|
std::istringstream iss(line);
|
|
Alias a;
|
|
iss >> a.name;
|
|
iss >> a.alias;
|
|
m_aliases.push_back(a);
|
|
}
|
|
}
|