Signed-off-by: falkTX <falktx@falktx.com>tags/v2.2.0-RC1
@@ -270,7 +270,7 @@ public: | |||
return true; | |||
} | |||
const char* getClientNameFromUUID(jack_uuid_t uuid) const | |||
const char* getClientNameFromUUID(const jack_uuid_t uuid) const noexcept | |||
{ | |||
for (LinkedList<JackClientState*>::Itenerator it = fClients.begin2(); it.valid(); it.next()) | |||
{ | |||
@@ -284,6 +284,20 @@ public: | |||
return nullptr; | |||
} | |||
jack_uuid_t getUUIDForClientName(const char* const name) const noexcept | |||
{ | |||
for (LinkedList<JackClientState*>::Itenerator it = fClients.begin2(); it.valid(); it.next()) | |||
{ | |||
JackClientState* const jclient(it.getValue(nullptr)); | |||
CARLA_SAFE_ASSERT_CONTINUE(jclient != nullptr); | |||
if (std::strcmp(jclient->name, name) == 0) | |||
return jclient->uuid; | |||
} | |||
return JACK_UUID_EMPTY_INITIALIZER; | |||
} | |||
pthread_t getRealtimeThreadId() const noexcept | |||
{ | |||
return (pthread_t)fRealtimeThread.getThreadId(); | |||
@@ -1404,6 +1418,9 @@ char* jack_get_client_name_by_uuid(jack_client_t* const client, const char* cons | |||
const char* clientName; | |||
if (jclient->server.uuid == uuid) | |||
return strdup("system"); | |||
if (jclient->uuid == uuid) | |||
{ | |||
clientName = jclient->name; | |||
@@ -1421,6 +1438,38 @@ char* jack_get_client_name_by_uuid(jack_client_t* const client, const char* cons | |||
return strdup(clientName); | |||
} | |||
CARLA_EXPORT | |||
char* jack_get_uuid_for_client_name(jack_client_t* client, const char* name) | |||
{ | |||
carla_debug("%s(%p, %s)", __FUNCTION__, client, name); | |||
JackClientState* const jclient = (JackClientState*)client; | |||
CARLA_SAFE_ASSERT_RETURN(jclient != nullptr, nullptr); | |||
if (std::strcmp(name, "system") == 0) | |||
{ | |||
char* const uuidstr = static_cast<char*>(std::malloc(JACK_UUID_STRING_SIZE)); | |||
CARLA_SAFE_ASSERT_RETURN(uuidstr != nullptr, nullptr); | |||
jack_uuid_unparse(jclient->server.uuid, uuidstr); | |||
return uuidstr; | |||
} | |||
else | |||
{ | |||
CarlaJackAppClient* const jackAppPtr = jclient->server.jackAppPtr; | |||
CARLA_SAFE_ASSERT_RETURN(jackAppPtr != nullptr && jackAppPtr == &gClient, nullptr); | |||
const jack_uuid_t uuid = jackAppPtr->getUUIDForClientName(name); | |||
CARLA_SAFE_ASSERT_RETURN(uuid != JACK_UUID_EMPTY_INITIALIZER, nullptr); | |||
char* const uuidstr = static_cast<char*>(std::malloc(JACK_UUID_STRING_SIZE)); | |||
CARLA_SAFE_ASSERT_RETURN(uuidstr != nullptr, nullptr); | |||
jack_uuid_unparse(jclient->uuid, uuidstr); | |||
return uuidstr; | |||
} | |||
} | |||
// --------------------------------------------------------------------------------------------------------------------- | |||
CARLA_EXPORT | |||
@@ -1,6 +1,6 @@ | |||
/* | |||
* Carla JACK API for external applications | |||
* Copyright (C) 2016-2019 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2016-2020 Filipe Coelho <falktx@falktx.com> | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU General Public License as | |||
@@ -103,37 +103,53 @@ struct JackMidiPortBufferDummy : JackMidiPortBufferBase { | |||
}; | |||
struct JackPortState { | |||
const char* name; | |||
const char* fullname; | |||
enum Offsets { | |||
kPortIdOffsetAudioIn = 100, | |||
kPortIdOffsetMidiIn = 300, | |||
kPortIdOffsetAudioOut = 500, | |||
kPortIdOffsetMidiOut = 700, | |||
kPortIdOffsetUser = 1000, | |||
}; | |||
char* name; | |||
char* fullname; | |||
void* buffer; | |||
uint index; | |||
int flags; | |||
uint gid; | |||
jack_uuid_t uuid; | |||
bool isMidi : 1; | |||
bool isSystem : 1; | |||
bool isConnected : 1; | |||
bool unused : 1; | |||
JackPortState() | |||
: name(nullptr), | |||
fullname(nullptr), | |||
JackPortState(const char* const fullPortName, | |||
const char* const portName, | |||
const uint i, const int f, const uint id, | |||
const bool midi, const bool con) | |||
: name(portName != nullptr ? strdup(portName) : nullptr), | |||
fullname(fullPortName != nullptr ? strdup(fullPortName) : nullptr), | |||
buffer(nullptr), | |||
index(0), | |||
flags(0), | |||
uuid(0), | |||
isMidi(false), | |||
isSystem(false), | |||
isConnected(false), | |||
index(i), | |||
flags(f), | |||
gid(id), | |||
uuid(jack_port_uuid_generate(id)), | |||
isMidi(midi), | |||
isSystem(true), | |||
isConnected(con), | |||
unused(false) {} | |||
JackPortState(const char* const clientName, const char* const portName, const uint i, const int f, | |||
JackPortState(const char* const clientName, | |||
const char* const portName, | |||
const uint i, const int f, const uint id, | |||
const bool midi, const bool sys, const bool con) | |||
: name(portName != nullptr ? strdup(portName) : nullptr), | |||
fullname(nullptr), | |||
buffer(nullptr), | |||
index(i), | |||
flags(f), | |||
uuid(0), | |||
gid(id), | |||
uuid(jack_port_uuid_generate(id)), | |||
isMidi(midi), | |||
isSystem(sys), | |||
isConnected(con), | |||
@@ -151,6 +167,11 @@ struct JackPortState { | |||
~JackPortState() | |||
{ | |||
std::free(name); | |||
name = nullptr; | |||
std::free(fullname); | |||
fullname = nullptr; | |||
} | |||
CARLA_DECLARE_NON_COPY_STRUCT(JackPortState) | |||
@@ -171,6 +192,7 @@ struct JackClientState { | |||
LinkedList<JackPortState*> midiIns; | |||
LinkedList<JackPortState*> midiOuts; | |||
std::map<uint, JackPortState*> portIdMapping; | |||
std::map<std::string, JackPortState*> portNameMapping; | |||
JackShutdownCallback shutdownCb; | |||
@@ -208,6 +230,7 @@ struct JackClientState { | |||
audioOuts(), | |||
midiIns(), | |||
midiOuts(), | |||
portIdMapping(), | |||
portNameMapping(), | |||
shutdownCb(nullptr), | |||
shutdownCbPtr(nullptr), | |||
@@ -261,6 +284,9 @@ struct JackClientState { | |||
audioOuts.clear(); | |||
midiIns.clear(); | |||
midiOuts.clear(); | |||
portIdMapping.clear(); | |||
portNameMapping.clear(); | |||
} | |||
CARLA_DECLARE_NON_COPY_STRUCT(JackClientState) | |||
@@ -272,6 +298,8 @@ struct JackServerState { | |||
uint32_t bufferSize; | |||
double sampleRate; | |||
jack_uuid_t uuid; | |||
uint8_t numAudioIns; | |||
uint8_t numAudioOuts; | |||
uint8_t numMidiIns; | |||
@@ -285,6 +313,7 @@ struct JackServerState { | |||
: jackAppPtr(app), | |||
bufferSize(0), | |||
sampleRate(0.0), | |||
uuid(jack_client_uuid_generate()), | |||
numAudioIns(0), | |||
numAudioOuts(0), | |||
numMidiIns(0), | |||
@@ -1,6 +1,6 @@ | |||
/* | |||
* Carla JACK API for external applications | |||
* Copyright (C) 2016-2018 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2016-2020 Filipe Coelho <falktx@falktx.com> | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU General Public License as | |||
@@ -60,7 +60,7 @@ void jack_free(void* ptr) | |||
{ | |||
carla_debug("%s(%p)", __FUNCTION__, ptr); | |||
free(ptr); | |||
std::free(ptr); | |||
} | |||
// -------------------------------------------------------------------------------------------------------------------- |
@@ -40,22 +40,6 @@ char* jack_get_client_name(jack_client_t* client) | |||
return jclient->name; | |||
} | |||
CARLA_EXPORT | |||
char* jack_get_uuid_for_client_name(jack_client_t* client, const char* name) | |||
{ | |||
carla_debug("%s(%p, %s)", __FUNCTION__, client, name); | |||
JackClientState* const jclient = (JackClientState*)client; | |||
CARLA_SAFE_ASSERT_RETURN(jclient != nullptr, nullptr); | |||
char* const uuidstr = static_cast<char*>(std::malloc(JACK_UUID_STRING_SIZE)); | |||
CARLA_SAFE_ASSERT_RETURN(uuidstr != nullptr, nullptr); | |||
jack_uuid_unparse(jclient->uuid, uuidstr); | |||
return uuidstr; | |||
} | |||
// -------------------------------------------------------------------------------------------------------------------- | |||
CARLA_EXPORT | |||
@@ -23,13 +23,17 @@ CARLA_BACKEND_USE_NAMESPACE | |||
// -------------------------------------------------------------------------------------------------------------------- | |||
static const char* allocate_port_name(const char* const prefix, const uint num) | |||
static const char* allocate_port_name(const char* const prefixOrFullName, const uint num = UINT32_MAX) | |||
{ | |||
static CarlaStringList portList; | |||
char portName[STR_MAX]; | |||
carla_zeroChars(portName, STR_MAX); | |||
std::snprintf(portName, STR_MAX-1, "%s%u", prefix, num+1); | |||
if (num == UINT32_MAX) | |||
std::strncpy(portName, prefixOrFullName, STR_MAX-1); | |||
else | |||
std::snprintf(portName, STR_MAX-1, "%s%u", prefixOrFullName, num+1); | |||
if (const char* const storedPortName = portList.containsAndReturnString(portName)) | |||
return storedPortName; | |||
@@ -44,17 +48,23 @@ static const char* allocate_port_name(const char* const prefix, const uint num) | |||
CARLA_EXPORT | |||
const char** jack_get_ports(jack_client_t* client, const char* a, const char* b, unsigned long flags) | |||
{ | |||
carla_stdout("%s(%p, %s, %s, 0x%lx) WIP", __FUNCTION__, client, a, b, flags); | |||
carla_stdout("%s(%p, %s, %s, 0x%lx)", __FUNCTION__, client, a, b, flags); | |||
JackClientState* const jclient = (JackClientState*)client; | |||
CARLA_SAFE_ASSERT_RETURN(jclient != nullptr, nullptr); | |||
const JackServerState& jserver(jclient->server); | |||
const uint numIns = static_cast<uint>(jserver.numAudioIns + jserver.numMidiIns); | |||
const uint numOuts = static_cast<uint>(jserver.numAudioOuts + jserver.numMidiOuts); | |||
const uint numIns = static_cast<uint>(jclient->audioIns.count() + | |||
jclient->midiIns.count() + | |||
jserver.numAudioIns + | |||
jserver.numMidiIns); | |||
const uint numOuts = static_cast<uint>(jclient->audioOuts.count() + | |||
jclient->midiOuts.count() + | |||
jserver.numAudioOuts + | |||
jserver.numMidiOuts); | |||
if (flags == 0 || (flags & (JackPortIsInput|JackPortIsOutput)) == (JackPortIsInput|JackPortIsOutput)) | |||
if (flags == 0x0 || (flags & (JackPortIsInput|JackPortIsOutput)) == (JackPortIsInput|JackPortIsOutput)) | |||
{ | |||
if (const char** const ret = (const char**)calloc(numIns+numOuts+1, sizeof(const char*))) | |||
{ | |||
@@ -68,10 +78,43 @@ const char** jack_get_ports(jack_client_t* client, const char* a, const char* b, | |||
for (uint j=0; j<jserver.numMidiOuts; ++i, ++j) | |||
ret[i] = allocate_port_name("system:midi_playback_", j); | |||
if ((flags & (JackPortIsPhysical|JackPortIsTerminal)) == 0x0) | |||
{ | |||
for (LinkedList<JackPortState*>::Itenerator it = jclient->audioIns.begin2(); it.valid(); it.next()) | |||
{ | |||
JackPortState* const jport = it.getValue(nullptr); | |||
CARLA_SAFE_ASSERT_CONTINUE(jport != nullptr); | |||
ret[i++] = allocate_port_name(jport->fullname); | |||
} | |||
for (LinkedList<JackPortState*>::Itenerator it = jclient->midiIns.begin2(); it.valid(); it.next()) | |||
{ | |||
JackPortState* const jport = it.getValue(nullptr); | |||
CARLA_SAFE_ASSERT_CONTINUE(jport != nullptr); | |||
ret[i++] = allocate_port_name(jport->fullname); | |||
} | |||
for (LinkedList<JackPortState*>::Itenerator it = jclient->audioOuts.begin2(); it.valid(); it.next()) | |||
{ | |||
JackPortState* const jport = it.getValue(nullptr); | |||
CARLA_SAFE_ASSERT_CONTINUE(jport != nullptr); | |||
ret[i++] = allocate_port_name(jport->fullname); | |||
} | |||
for (LinkedList<JackPortState*>::Itenerator it = jclient->midiOuts.begin2(); it.valid(); it.next()) | |||
{ | |||
JackPortState* const jport = it.getValue(nullptr); | |||
CARLA_SAFE_ASSERT_CONTINUE(jport != nullptr); | |||
ret[i++] = allocate_port_name(jport->fullname); | |||
} | |||
} | |||
ret[i] = nullptr; | |||
return ret; | |||
} | |||
return nullptr; | |||
} | |||
if (flags & JackPortIsInput) | |||
@@ -84,10 +127,29 @@ const char** jack_get_ports(jack_client_t* client, const char* a, const char* b, | |||
for (uint j=0; j<jserver.numMidiOuts; ++i, ++j) | |||
ret[i] = allocate_port_name("system:midi_playback_", j); | |||
if ((flags & (JackPortIsPhysical|JackPortIsTerminal)) == 0x0) | |||
{ | |||
for (LinkedList<JackPortState*>::Itenerator it = jclient->audioIns.begin2(); it.valid(); it.next()) | |||
{ | |||
JackPortState* const jport = it.getValue(nullptr); | |||
CARLA_SAFE_ASSERT_CONTINUE(jport != nullptr); | |||
ret[i++] = allocate_port_name(jport->fullname); | |||
} | |||
for (LinkedList<JackPortState*>::Itenerator it = jclient->midiIns.begin2(); it.valid(); it.next()) | |||
{ | |||
JackPortState* const jport = it.getValue(nullptr); | |||
CARLA_SAFE_ASSERT_CONTINUE(jport != nullptr); | |||
ret[i++] = allocate_port_name(jport->fullname); | |||
} | |||
} | |||
ret[i] = nullptr; | |||
return ret; | |||
} | |||
return nullptr; | |||
} | |||
if (flags & JackPortIsOutput) | |||
@@ -100,10 +162,29 @@ const char** jack_get_ports(jack_client_t* client, const char* a, const char* b, | |||
for (uint j=0; j<jserver.numMidiIns; ++i, ++j) | |||
ret[i] = allocate_port_name("system:midi_capture_", j); | |||
if ((flags & (JackPortIsPhysical|JackPortIsTerminal)) == 0x0) | |||
{ | |||
for (LinkedList<JackPortState*>::Itenerator it = jclient->audioOuts.begin2(); it.valid(); it.next()) | |||
{ | |||
JackPortState* const jport = it.getValue(nullptr); | |||
CARLA_SAFE_ASSERT_CONTINUE(jport != nullptr); | |||
ret[i++] = allocate_port_name(jport->fullname); | |||
} | |||
for (LinkedList<JackPortState*>::Itenerator it = jclient->midiOuts.begin2(); it.valid(); it.next()) | |||
{ | |||
JackPortState* const jport = it.getValue(nullptr); | |||
CARLA_SAFE_ASSERT_CONTINUE(jport != nullptr); | |||
ret[i++] = allocate_port_name(jport->fullname); | |||
} | |||
} | |||
ret[i] = nullptr; | |||
return ret; | |||
} | |||
return nullptr; | |||
} | |||
return nullptr; | |||
@@ -119,29 +200,19 @@ jack_port_t* jack_port_by_name(jack_client_t* client, const char* name) | |||
if (std::strncmp(name, "system:", 7) == 0) | |||
{ | |||
static JackPortState retPort( | |||
/* name */ nullptr, | |||
/* fullname */ nullptr, | |||
/* index */ 0, | |||
/* flags */ 0x0, | |||
/* isMidi */ false, | |||
/* isSystem */ true, | |||
/* isConnected */ false | |||
); | |||
static CarlaString rname, rfullname; | |||
static std::map<uint, JackPortState*> systemPortIdMapping; | |||
const JackServerState& jserver(jclient->server); | |||
const int commonFlags = JackPortIsPhysical|JackPortIsTerminal; | |||
rfullname = name; | |||
uint rindex, gid; | |||
int flags; | |||
bool isMidi, isConnected; | |||
const char* const fullname = name; | |||
const char* const portname = name + 7; | |||
name += 7; | |||
rname = name; | |||
retPort.name = rname.buffer(); | |||
retPort.fullname = rfullname.buffer(); | |||
/**/ if (std::strncmp(name, "capture_", 8) == 0) | |||
{ | |||
name += 8; | |||
@@ -149,10 +220,11 @@ jack_port_t* jack_port_by_name(jack_client_t* client, const char* name) | |||
const int index = std::atoi(name)-1; | |||
CARLA_SAFE_ASSERT_RETURN(index >= 0 && index < jserver.numAudioIns, nullptr); | |||
retPort.index = static_cast<uint>(index); | |||
retPort.flags = commonFlags|JackPortIsOutput; | |||
retPort.isMidi = false; | |||
retPort.isConnected = jserver.numAudioIns > index; | |||
rindex = static_cast<uint>(index); | |||
flags = commonFlags|JackPortIsOutput; | |||
gid = JackPortState::kPortIdOffsetAudioIn + rindex; | |||
isMidi = false; | |||
isConnected = jserver.numAudioIns > rindex; | |||
} | |||
else if (std::strncmp(name, "playback_", 9) == 0) | |||
{ | |||
@@ -161,10 +233,11 @@ jack_port_t* jack_port_by_name(jack_client_t* client, const char* name) | |||
const int index = std::atoi(name)-1; | |||
CARLA_SAFE_ASSERT_RETURN(index >= 0 && index < jserver.numAudioOuts, nullptr); | |||
retPort.index = static_cast<uint>(jserver.numAudioIns + index); | |||
retPort.flags = commonFlags|JackPortIsInput; | |||
retPort.isMidi = false; | |||
retPort.isConnected = jserver.numAudioOuts > index; | |||
rindex = static_cast<uint>(jserver.numAudioIns + index); | |||
flags = commonFlags|JackPortIsInput; | |||
gid = JackPortState::kPortIdOffsetAudioOut + rindex; | |||
isMidi = false; | |||
isConnected = jserver.numAudioOuts > rindex; | |||
} | |||
else if (std::strncmp(name, "midi_capture_", 13) == 0) | |||
{ | |||
@@ -173,10 +246,11 @@ jack_port_t* jack_port_by_name(jack_client_t* client, const char* name) | |||
const int index = std::atoi(name)-1; | |||
CARLA_SAFE_ASSERT_RETURN(index >= 0 && index < jserver.numMidiIns, nullptr); | |||
retPort.index = static_cast<uint>(index); | |||
retPort.flags = commonFlags|JackPortIsOutput; | |||
retPort.isMidi = true; | |||
retPort.isConnected = jserver.numMidiIns > index; | |||
rindex = static_cast<uint>(index); | |||
flags = commonFlags|JackPortIsOutput; | |||
gid = JackPortState::kPortIdOffsetMidiIn + rindex; | |||
isMidi = true; | |||
isConnected = jserver.numMidiIns > rindex; | |||
} | |||
else if (std::strncmp(name, "midi_playback_", 14) == 0) | |||
{ | |||
@@ -185,10 +259,11 @@ jack_port_t* jack_port_by_name(jack_client_t* client, const char* name) | |||
const int index = std::atoi(name)-1; | |||
CARLA_SAFE_ASSERT_RETURN(index >= 0 && index < jserver.numMidiOuts, nullptr); | |||
retPort.index = static_cast<uint>(jserver.numMidiIns + index); | |||
retPort.flags = commonFlags|JackPortIsInput; | |||
retPort.isMidi = true; | |||
retPort.isConnected = jserver.numMidiOuts > index; | |||
rindex = static_cast<uint>(jserver.numMidiIns + index); | |||
flags = commonFlags|JackPortIsInput; | |||
gid = JackPortState::kPortIdOffsetMidiOut + rindex; | |||
isMidi = true; | |||
isConnected = jserver.numMidiOuts > rindex; | |||
} | |||
else | |||
{ | |||
@@ -196,7 +271,16 @@ jack_port_t* jack_port_by_name(jack_client_t* client, const char* name) | |||
return nullptr; | |||
} | |||
return (jack_port_t*)&retPort; | |||
if (JackPortState* const port = systemPortIdMapping[gid]) | |||
return (jack_port_t*)port; | |||
JackPortState* const port = new JackPortState(fullname, | |||
portname, | |||
rindex, flags, gid, | |||
isMidi, isConnected); | |||
systemPortIdMapping[gid] = port; | |||
return (jack_port_t*)port; | |||
} | |||
else | |||
{ | |||
@@ -211,7 +295,123 @@ jack_port_t* jack_port_by_name(jack_client_t* client, const char* name) | |||
CARLA_EXPORT | |||
jack_port_t* jack_port_by_id(jack_client_t* client, jack_port_id_t port_id) | |||
{ | |||
carla_stderr2("%s(%p, %u)", __FUNCTION__, client, port_id); | |||
carla_debug("%s(%p, %u)", __FUNCTION__, client, port_id); | |||
CARLA_SAFE_ASSERT_UINT_RETURN(port_id >= JackPortState::kPortIdOffsetUser, port_id, nullptr); | |||
JackClientState* const jclient = (JackClientState*)client; | |||
CARLA_SAFE_ASSERT_RETURN(jclient != nullptr, nullptr); | |||
if (JackPortState* const port = jclient->portIdMapping[port_id]) | |||
return (jack_port_t*)port; | |||
carla_stderr2("jack_port_by_id: invalid port id %u", port_id); | |||
return nullptr; | |||
} | |||
// -------------------------------------------------------------------------------------------------------------------- | |||
CARLA_EXPORT | |||
const char** jack_port_get_connections(const jack_port_t* port) | |||
{ | |||
carla_stderr2("%s(%p)", __FUNCTION__, port); | |||
const JackPortState* const jport = (const JackPortState*)port; | |||
CARLA_SAFE_ASSERT_RETURN(jport != nullptr, nullptr); | |||
CARLA_SAFE_ASSERT_RETURN(! jport->isSystem, nullptr); | |||
if (! jport->isConnected) | |||
return nullptr; | |||
return nullptr; | |||
} | |||
CARLA_EXPORT | |||
const char** jack_port_get_all_connections(const jack_client_t* client, const jack_port_t* port) | |||
{ | |||
carla_stdout("%s(%p, %p) WIP", __FUNCTION__, client, port); | |||
JackClientState* const jclient = (JackClientState*)client; | |||
CARLA_SAFE_ASSERT_RETURN(jclient != nullptr, nullptr); | |||
const JackPortState* const jport = (const JackPortState*)port; | |||
CARLA_SAFE_ASSERT_RETURN(jport != nullptr, nullptr); | |||
CARLA_SAFE_ASSERT_UINT_RETURN(jport->gid >= JackPortState::kPortIdOffsetAudioIn, jport->gid, nullptr); | |||
if (! jport->isConnected) | |||
return nullptr; | |||
if (jport->isSystem) | |||
{ | |||
const JackPortState* connectedPort; | |||
/**/ if (jport->gid >= JackPortState::kPortIdOffsetMidiOut) | |||
connectedPort = jclient->midiOuts.getAt(jport->gid - JackPortState::kPortIdOffsetMidiOut, nullptr); | |||
else if (jport->gid >= JackPortState::kPortIdOffsetAudioOut) | |||
connectedPort = jclient->audioOuts.getAt(jport->gid - JackPortState::kPortIdOffsetAudioOut, nullptr); | |||
else if (jport->gid >= JackPortState::kPortIdOffsetMidiIn) | |||
connectedPort = jclient->midiIns.getAt(jport->gid - JackPortState::kPortIdOffsetMidiIn, nullptr); | |||
else | |||
connectedPort = jclient->audioIns.getAt(jport->gid - JackPortState::kPortIdOffsetAudioIn, nullptr); | |||
if (connectedPort == nullptr) | |||
{ | |||
carla_debug("port %s has no connections?", jport->fullname); | |||
return nullptr; | |||
} | |||
if (const char** const ret = static_cast<const char**>(malloc(sizeof(const char*)*2))) | |||
{ | |||
carla_debug("port %s is connected to %s", jport->fullname, connectedPort->fullname); | |||
ret[0] = connectedPort->fullname; | |||
ret[1] = nullptr; | |||
return ret; | |||
} | |||
} | |||
else | |||
{ | |||
const JackServerState& jserver(jclient->server); | |||
const char* connectedPortName = nullptr; | |||
if (jport->isMidi) | |||
{ | |||
if (jport->flags & JackPortIsOutput) | |||
{ | |||
if (jport->index < jserver.numMidiOuts) | |||
connectedPortName = allocate_port_name("system:midi_playback_", jport->index); | |||
} | |||
else | |||
{ | |||
if (jport->index < jserver.numMidiIns) | |||
connectedPortName = allocate_port_name("system:midi_capture_", jport->index); | |||
} | |||
} | |||
else | |||
{ | |||
if (jport->flags & JackPortIsOutput) | |||
{ | |||
if (jport->index < jserver.numAudioOuts) | |||
connectedPortName = allocate_port_name("system:playback_", jport->index); | |||
} | |||
else | |||
{ | |||
if (jport->index < jserver.numAudioIns) | |||
connectedPortName = allocate_port_name("system:capture_", jport->index); | |||
} | |||
} | |||
if (connectedPortName != nullptr) | |||
{ | |||
if (const char** const ret = static_cast<const char**>(malloc(sizeof(const char*)*2))) | |||
{ | |||
carla_debug("port %s is connected to %s", jport->fullname, connectedPortName); | |||
ret[0] = connectedPortName; | |||
ret[1] = nullptr; | |||
return ret; | |||
} | |||
} | |||
} | |||
return nullptr; | |||
} | |||
@@ -1,6 +1,6 @@ | |||
/* | |||
* Carla JACK API for external applications | |||
* Copyright (C) 2016-2019 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2016-2020 Filipe Coelho <falktx@falktx.com> | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU General Public License as | |||
@@ -21,6 +21,8 @@ CARLA_BACKEND_USE_NAMESPACE | |||
// -------------------------------------------------------------------------------------------------------------------- | |||
static uint32_t gPortId = JackPortState::kPortIdOffsetUser; | |||
CARLA_EXPORT | |||
jack_port_t* jack_port_register(jack_client_t* client, const char* port_name, const char* port_type, | |||
unsigned long flags, unsigned long buffer_size) | |||
@@ -40,9 +42,11 @@ jack_port_t* jack_port_register(jack_client_t* client, const char* port_name, co | |||
if (flags & JackPortIsInput) | |||
{ | |||
const std::size_t index = jclient->audioIns.count(); | |||
const uint gid = ++gPortId; | |||
JackPortState* const port = new JackPortState(jclient->name, port_name, | |||
static_cast<uint>(index), | |||
static_cast<int>(flags), | |||
gid, | |||
false, false, index < jserver.numAudioIns); | |||
{ | |||
@@ -50,6 +54,7 @@ jack_port_t* jack_port_register(jack_client_t* client, const char* port_name, co | |||
jclient->audioIns.append(port); | |||
} | |||
jclient->portIdMapping[gid] = port; | |||
jclient->portNameMapping[port->fullname] = port; | |||
return (jack_port_t*)port; | |||
} | |||
@@ -57,9 +62,11 @@ jack_port_t* jack_port_register(jack_client_t* client, const char* port_name, co | |||
if (flags & JackPortIsOutput) | |||
{ | |||
const std::size_t index = jclient->audioOuts.count(); | |||
const uint gid = ++gPortId; | |||
JackPortState* const port = new JackPortState(jclient->name, port_name, | |||
static_cast<uint>(index), | |||
static_cast<int>(flags), | |||
gid, | |||
false, false, index < jserver.numAudioOuts); | |||
{ | |||
@@ -67,6 +74,7 @@ jack_port_t* jack_port_register(jack_client_t* client, const char* port_name, co | |||
jclient->audioOuts.append(port); | |||
} | |||
jclient->portIdMapping[gid] = port; | |||
jclient->portNameMapping[port->fullname] = port; | |||
return (jack_port_t*)port; | |||
} | |||
@@ -80,9 +88,11 @@ jack_port_t* jack_port_register(jack_client_t* client, const char* port_name, co | |||
if (flags & JackPortIsInput) | |||
{ | |||
const std::size_t index = jclient->midiIns.count(); | |||
const uint gid = ++gPortId; | |||
JackPortState* const port = new JackPortState(jclient->name, port_name, | |||
static_cast<uint>(index), | |||
static_cast<int>(flags), | |||
gid, | |||
true, false, index < jserver.numMidiIns); | |||
{ | |||
@@ -90,6 +100,7 @@ jack_port_t* jack_port_register(jack_client_t* client, const char* port_name, co | |||
jclient->midiIns.append(port); | |||
} | |||
jclient->portIdMapping[gid] = port; | |||
jclient->portNameMapping[port->fullname] = port; | |||
return (jack_port_t*)port; | |||
} | |||
@@ -97,9 +108,11 @@ jack_port_t* jack_port_register(jack_client_t* client, const char* port_name, co | |||
if (flags & JackPortIsOutput) | |||
{ | |||
const std::size_t index = jclient->midiOuts.count(); | |||
const uint gid = ++gPortId; | |||
JackPortState* const port = new JackPortState(jclient->name, port_name, | |||
static_cast<uint>(index), | |||
static_cast<int>(flags), | |||
gid, | |||
true, false, index < jserver.numMidiOuts); | |||
{ | |||
@@ -107,6 +120,7 @@ jack_port_t* jack_port_register(jack_client_t* client, const char* port_name, co | |||
jclient->midiOuts.append(port); | |||
} | |||
jclient->portIdMapping[gid] = port; | |||
jclient->portNameMapping[port->fullname] = port; | |||
return (jack_port_t*)port; | |||
} | |||
@@ -142,6 +156,7 @@ int jack_port_unregister(jack_client_t* client, jack_port_t* port) | |||
if (jport->flags & JackPortIsInput) | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(jclient->midiIns.removeOne(jport), ENOENT); | |||
jclient->portIdMapping.erase(jport->gid); | |||
jclient->portNameMapping.erase(jport->fullname); | |||
return 0; | |||
} | |||
@@ -149,6 +164,7 @@ int jack_port_unregister(jack_client_t* client, jack_port_t* port) | |||
if (jport->flags & JackPortIsOutput) | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(jclient->midiOuts.removeOne(jport), ENOENT); | |||
jclient->portIdMapping.erase(jport->gid); | |||
jclient->portNameMapping.erase(jport->fullname); | |||
return 0; | |||
} | |||
@@ -158,6 +174,7 @@ int jack_port_unregister(jack_client_t* client, jack_port_t* port) | |||
if (jport->flags & JackPortIsInput) | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(jclient->audioIns.removeOne(jport), ENOENT); | |||
jclient->portIdMapping.erase(jport->gid); | |||
jclient->portNameMapping.erase(jport->fullname); | |||
return 0; | |||
} | |||
@@ -165,6 +182,7 @@ int jack_port_unregister(jack_client_t* client, jack_port_t* port) | |||
if (jport->flags & JackPortIsOutput) | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(jclient->audioOuts.removeOne(jport), ENOENT); | |||
jclient->portIdMapping.erase(jport->gid); | |||
jclient->portNameMapping.erase(jport->fullname); | |||
return 0; | |||
} | |||
@@ -292,22 +310,6 @@ int jack_port_connected_to(const jack_port_t* port, const char* port_name) | |||
// -------------------------------------------------------------------------------------------------------------------- | |||
CARLA_EXPORT | |||
const char** jack_port_get_connections(const jack_port_t* port) | |||
{ | |||
carla_stderr2("%s(%p)", __FUNCTION__, port); | |||
return nullptr; | |||
} | |||
CARLA_EXPORT | |||
const char** jack_port_get_all_connections(const jack_client_t* client, const jack_port_t* port) | |||
{ | |||
carla_stderr2("%s(%p, %p)", __FUNCTION__, client, port); | |||
return nullptr; | |||
} | |||
// -------------------------------------------------------------------------------------------------------------------- | |||
CARLA_EXPORT | |||
int jack_port_tie(jack_port_t* src, jack_port_t* dst) | |||
{ | |||
@@ -352,23 +354,22 @@ int jack_port_rename(jack_client_t* client, jack_port_t *port, const char *port_ | |||
CARLA_SAFE_ASSERT_RETURN(jport != nullptr, EINVAL); | |||
CARLA_SAFE_ASSERT_RETURN(! jport->isSystem, EINVAL); | |||
static CarlaString rname, rfullname; | |||
// TODO: verify uniqueness | |||
rname = port_name; | |||
CARLA_SAFE_ASSERT_RETURN(rname.isNotEmpty(), ENOMEM); | |||
char* const fullname = (char*)std::malloc(STR_MAX); | |||
CARLA_SAFE_ASSERT_RETURN(fullname != nullptr, ENOMEM); | |||
std::snprintf(fullname, STR_MAX, "%s:%s", jclient->name, port_name); | |||
fullname[STR_MAX-1] = '\0'; | |||
jport->name = rname.buffer(); | |||
jport->fullname = rfullname.buffer(); | |||
jclient->portNameMapping.erase(jport->fullname); | |||
jclient->portNameMapping[fullname] = jport; | |||
std::free(jport->name); | |||
std::free(jport->fullname); | |||
std::free(fullname); | |||
jport->name = strdup(port_name); | |||
jport->fullname = fullname; | |||
// TODO: port rename callback | |||