Signed-off-by: falkTX <falktx@falktx.com>tags/v2.2.0-RC1
@@ -270,7 +270,7 @@ public: | |||||
return true; | 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()) | for (LinkedList<JackClientState*>::Itenerator it = fClients.begin2(); it.valid(); it.next()) | ||||
{ | { | ||||
@@ -284,6 +284,20 @@ public: | |||||
return nullptr; | 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 | pthread_t getRealtimeThreadId() const noexcept | ||||
{ | { | ||||
return (pthread_t)fRealtimeThread.getThreadId(); | 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; | const char* clientName; | ||||
if (jclient->server.uuid == uuid) | |||||
return strdup("system"); | |||||
if (jclient->uuid == uuid) | if (jclient->uuid == uuid) | ||||
{ | { | ||||
clientName = jclient->name; | 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); | 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 | CARLA_EXPORT | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* Carla JACK API for external applications | * 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 | * This program is free software; you can redistribute it and/or | ||||
* modify it under the terms of the GNU General Public License as | * modify it under the terms of the GNU General Public License as | ||||
@@ -103,37 +103,53 @@ struct JackMidiPortBufferDummy : JackMidiPortBufferBase { | |||||
}; | }; | ||||
struct JackPortState { | 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; | void* buffer; | ||||
uint index; | uint index; | ||||
int flags; | int flags; | ||||
uint gid; | |||||
jack_uuid_t uuid; | jack_uuid_t uuid; | ||||
bool isMidi : 1; | bool isMidi : 1; | ||||
bool isSystem : 1; | bool isSystem : 1; | ||||
bool isConnected : 1; | bool isConnected : 1; | ||||
bool unused : 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), | 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) {} | 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) | const bool midi, const bool sys, const bool con) | ||||
: name(portName != nullptr ? strdup(portName) : nullptr), | : name(portName != nullptr ? strdup(portName) : nullptr), | ||||
fullname(nullptr), | fullname(nullptr), | ||||
buffer(nullptr), | buffer(nullptr), | ||||
index(i), | index(i), | ||||
flags(f), | flags(f), | ||||
uuid(0), | |||||
gid(id), | |||||
uuid(jack_port_uuid_generate(id)), | |||||
isMidi(midi), | isMidi(midi), | ||||
isSystem(sys), | isSystem(sys), | ||||
isConnected(con), | isConnected(con), | ||||
@@ -151,6 +167,11 @@ struct JackPortState { | |||||
~JackPortState() | ~JackPortState() | ||||
{ | { | ||||
std::free(name); | |||||
name = nullptr; | |||||
std::free(fullname); | |||||
fullname = nullptr; | |||||
} | } | ||||
CARLA_DECLARE_NON_COPY_STRUCT(JackPortState) | CARLA_DECLARE_NON_COPY_STRUCT(JackPortState) | ||||
@@ -171,6 +192,7 @@ struct JackClientState { | |||||
LinkedList<JackPortState*> midiIns; | LinkedList<JackPortState*> midiIns; | ||||
LinkedList<JackPortState*> midiOuts; | LinkedList<JackPortState*> midiOuts; | ||||
std::map<uint, JackPortState*> portIdMapping; | |||||
std::map<std::string, JackPortState*> portNameMapping; | std::map<std::string, JackPortState*> portNameMapping; | ||||
JackShutdownCallback shutdownCb; | JackShutdownCallback shutdownCb; | ||||
@@ -208,6 +230,7 @@ struct JackClientState { | |||||
audioOuts(), | audioOuts(), | ||||
midiIns(), | midiIns(), | ||||
midiOuts(), | midiOuts(), | ||||
portIdMapping(), | |||||
portNameMapping(), | portNameMapping(), | ||||
shutdownCb(nullptr), | shutdownCb(nullptr), | ||||
shutdownCbPtr(nullptr), | shutdownCbPtr(nullptr), | ||||
@@ -261,6 +284,9 @@ struct JackClientState { | |||||
audioOuts.clear(); | audioOuts.clear(); | ||||
midiIns.clear(); | midiIns.clear(); | ||||
midiOuts.clear(); | midiOuts.clear(); | ||||
portIdMapping.clear(); | |||||
portNameMapping.clear(); | |||||
} | } | ||||
CARLA_DECLARE_NON_COPY_STRUCT(JackClientState) | CARLA_DECLARE_NON_COPY_STRUCT(JackClientState) | ||||
@@ -272,6 +298,8 @@ struct JackServerState { | |||||
uint32_t bufferSize; | uint32_t bufferSize; | ||||
double sampleRate; | double sampleRate; | ||||
jack_uuid_t uuid; | |||||
uint8_t numAudioIns; | uint8_t numAudioIns; | ||||
uint8_t numAudioOuts; | uint8_t numAudioOuts; | ||||
uint8_t numMidiIns; | uint8_t numMidiIns; | ||||
@@ -285,6 +313,7 @@ struct JackServerState { | |||||
: jackAppPtr(app), | : jackAppPtr(app), | ||||
bufferSize(0), | bufferSize(0), | ||||
sampleRate(0.0), | sampleRate(0.0), | ||||
uuid(jack_client_uuid_generate()), | |||||
numAudioIns(0), | numAudioIns(0), | ||||
numAudioOuts(0), | numAudioOuts(0), | ||||
numMidiIns(0), | numMidiIns(0), | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* Carla JACK API for external applications | * 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 | * This program is free software; you can redistribute it and/or | ||||
* modify it under the terms of the GNU General Public License as | * 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); | 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; | 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 | 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; | static CarlaStringList portList; | ||||
char portName[STR_MAX]; | char portName[STR_MAX]; | ||||
carla_zeroChars(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)) | if (const char* const storedPortName = portList.containsAndReturnString(portName)) | ||||
return storedPortName; | return storedPortName; | ||||
@@ -44,17 +48,23 @@ static const char* allocate_port_name(const char* const prefix, const uint num) | |||||
CARLA_EXPORT | CARLA_EXPORT | ||||
const char** jack_get_ports(jack_client_t* client, const char* a, const char* b, unsigned long flags) | 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; | JackClientState* const jclient = (JackClientState*)client; | ||||
CARLA_SAFE_ASSERT_RETURN(jclient != nullptr, nullptr); | CARLA_SAFE_ASSERT_RETURN(jclient != nullptr, nullptr); | ||||
const JackServerState& jserver(jclient->server); | 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*))) | 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) | for (uint j=0; j<jserver.numMidiOuts; ++i, ++j) | ||||
ret[i] = allocate_port_name("system:midi_playback_", 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; | ret[i] = nullptr; | ||||
return ret; | return ret; | ||||
} | } | ||||
return nullptr; | |||||
} | } | ||||
if (flags & JackPortIsInput) | 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) | for (uint j=0; j<jserver.numMidiOuts; ++i, ++j) | ||||
ret[i] = allocate_port_name("system:midi_playback_", 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; | ret[i] = nullptr; | ||||
return ret; | return ret; | ||||
} | } | ||||
return nullptr; | |||||
} | } | ||||
if (flags & JackPortIsOutput) | 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) | for (uint j=0; j<jserver.numMidiIns; ++i, ++j) | ||||
ret[i] = allocate_port_name("system:midi_capture_", 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; | ret[i] = nullptr; | ||||
return ret; | return ret; | ||||
} | } | ||||
return nullptr; | |||||
} | } | ||||
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) | 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 JackServerState& jserver(jclient->server); | ||||
const int commonFlags = JackPortIsPhysical|JackPortIsTerminal; | 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; | name += 7; | ||||
rname = name; | |||||
retPort.name = rname.buffer(); | |||||
retPort.fullname = rfullname.buffer(); | |||||
/**/ if (std::strncmp(name, "capture_", 8) == 0) | /**/ if (std::strncmp(name, "capture_", 8) == 0) | ||||
{ | { | ||||
name += 8; | 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; | const int index = std::atoi(name)-1; | ||||
CARLA_SAFE_ASSERT_RETURN(index >= 0 && index < jserver.numAudioIns, nullptr); | 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) | 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; | const int index = std::atoi(name)-1; | ||||
CARLA_SAFE_ASSERT_RETURN(index >= 0 && index < jserver.numAudioOuts, nullptr); | 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) | 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; | const int index = std::atoi(name)-1; | ||||
CARLA_SAFE_ASSERT_RETURN(index >= 0 && index < jserver.numMidiIns, nullptr); | 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) | 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; | const int index = std::atoi(name)-1; | ||||
CARLA_SAFE_ASSERT_RETURN(index >= 0 && index < jserver.numMidiOuts, nullptr); | 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 | else | ||||
{ | { | ||||
@@ -196,7 +271,16 @@ jack_port_t* jack_port_by_name(jack_client_t* client, const char* name) | |||||
return nullptr; | 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 | else | ||||
{ | { | ||||
@@ -211,7 +295,123 @@ jack_port_t* jack_port_by_name(jack_client_t* client, const char* name) | |||||
CARLA_EXPORT | CARLA_EXPORT | ||||
jack_port_t* jack_port_by_id(jack_client_t* client, jack_port_id_t port_id) | 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; | return nullptr; | ||||
} | } | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* Carla JACK API for external applications | * 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 | * This program is free software; you can redistribute it and/or | ||||
* modify it under the terms of the GNU General Public License as | * 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 | CARLA_EXPORT | ||||
jack_port_t* jack_port_register(jack_client_t* client, const char* port_name, const char* port_type, | 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) | 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) | if (flags & JackPortIsInput) | ||||
{ | { | ||||
const std::size_t index = jclient->audioIns.count(); | const std::size_t index = jclient->audioIns.count(); | ||||
const uint gid = ++gPortId; | |||||
JackPortState* const port = new JackPortState(jclient->name, port_name, | JackPortState* const port = new JackPortState(jclient->name, port_name, | ||||
static_cast<uint>(index), | static_cast<uint>(index), | ||||
static_cast<int>(flags), | static_cast<int>(flags), | ||||
gid, | |||||
false, false, index < jserver.numAudioIns); | 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->audioIns.append(port); | ||||
} | } | ||||
jclient->portIdMapping[gid] = port; | |||||
jclient->portNameMapping[port->fullname] = port; | jclient->portNameMapping[port->fullname] = port; | ||||
return (jack_port_t*)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) | if (flags & JackPortIsOutput) | ||||
{ | { | ||||
const std::size_t index = jclient->audioOuts.count(); | const std::size_t index = jclient->audioOuts.count(); | ||||
const uint gid = ++gPortId; | |||||
JackPortState* const port = new JackPortState(jclient->name, port_name, | JackPortState* const port = new JackPortState(jclient->name, port_name, | ||||
static_cast<uint>(index), | static_cast<uint>(index), | ||||
static_cast<int>(flags), | static_cast<int>(flags), | ||||
gid, | |||||
false, false, index < jserver.numAudioOuts); | 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->audioOuts.append(port); | ||||
} | } | ||||
jclient->portIdMapping[gid] = port; | |||||
jclient->portNameMapping[port->fullname] = port; | jclient->portNameMapping[port->fullname] = port; | ||||
return (jack_port_t*)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) | if (flags & JackPortIsInput) | ||||
{ | { | ||||
const std::size_t index = jclient->midiIns.count(); | const std::size_t index = jclient->midiIns.count(); | ||||
const uint gid = ++gPortId; | |||||
JackPortState* const port = new JackPortState(jclient->name, port_name, | JackPortState* const port = new JackPortState(jclient->name, port_name, | ||||
static_cast<uint>(index), | static_cast<uint>(index), | ||||
static_cast<int>(flags), | static_cast<int>(flags), | ||||
gid, | |||||
true, false, index < jserver.numMidiIns); | 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->midiIns.append(port); | ||||
} | } | ||||
jclient->portIdMapping[gid] = port; | |||||
jclient->portNameMapping[port->fullname] = port; | jclient->portNameMapping[port->fullname] = port; | ||||
return (jack_port_t*)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) | if (flags & JackPortIsOutput) | ||||
{ | { | ||||
const std::size_t index = jclient->midiOuts.count(); | const std::size_t index = jclient->midiOuts.count(); | ||||
const uint gid = ++gPortId; | |||||
JackPortState* const port = new JackPortState(jclient->name, port_name, | JackPortState* const port = new JackPortState(jclient->name, port_name, | ||||
static_cast<uint>(index), | static_cast<uint>(index), | ||||
static_cast<int>(flags), | static_cast<int>(flags), | ||||
gid, | |||||
true, false, index < jserver.numMidiOuts); | 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->midiOuts.append(port); | ||||
} | } | ||||
jclient->portIdMapping[gid] = port; | |||||
jclient->portNameMapping[port->fullname] = port; | jclient->portNameMapping[port->fullname] = port; | ||||
return (jack_port_t*)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) | if (jport->flags & JackPortIsInput) | ||||
{ | { | ||||
CARLA_SAFE_ASSERT_RETURN(jclient->midiIns.removeOne(jport), ENOENT); | CARLA_SAFE_ASSERT_RETURN(jclient->midiIns.removeOne(jport), ENOENT); | ||||
jclient->portIdMapping.erase(jport->gid); | |||||
jclient->portNameMapping.erase(jport->fullname); | jclient->portNameMapping.erase(jport->fullname); | ||||
return 0; | return 0; | ||||
} | } | ||||
@@ -149,6 +164,7 @@ int jack_port_unregister(jack_client_t* client, jack_port_t* port) | |||||
if (jport->flags & JackPortIsOutput) | if (jport->flags & JackPortIsOutput) | ||||
{ | { | ||||
CARLA_SAFE_ASSERT_RETURN(jclient->midiOuts.removeOne(jport), ENOENT); | CARLA_SAFE_ASSERT_RETURN(jclient->midiOuts.removeOne(jport), ENOENT); | ||||
jclient->portIdMapping.erase(jport->gid); | |||||
jclient->portNameMapping.erase(jport->fullname); | jclient->portNameMapping.erase(jport->fullname); | ||||
return 0; | return 0; | ||||
} | } | ||||
@@ -158,6 +174,7 @@ int jack_port_unregister(jack_client_t* client, jack_port_t* port) | |||||
if (jport->flags & JackPortIsInput) | if (jport->flags & JackPortIsInput) | ||||
{ | { | ||||
CARLA_SAFE_ASSERT_RETURN(jclient->audioIns.removeOne(jport), ENOENT); | CARLA_SAFE_ASSERT_RETURN(jclient->audioIns.removeOne(jport), ENOENT); | ||||
jclient->portIdMapping.erase(jport->gid); | |||||
jclient->portNameMapping.erase(jport->fullname); | jclient->portNameMapping.erase(jport->fullname); | ||||
return 0; | return 0; | ||||
} | } | ||||
@@ -165,6 +182,7 @@ int jack_port_unregister(jack_client_t* client, jack_port_t* port) | |||||
if (jport->flags & JackPortIsOutput) | if (jport->flags & JackPortIsOutput) | ||||
{ | { | ||||
CARLA_SAFE_ASSERT_RETURN(jclient->audioOuts.removeOne(jport), ENOENT); | CARLA_SAFE_ASSERT_RETURN(jclient->audioOuts.removeOne(jport), ENOENT); | ||||
jclient->portIdMapping.erase(jport->gid); | |||||
jclient->portNameMapping.erase(jport->fullname); | jclient->portNameMapping.erase(jport->fullname); | ||||
return 0; | 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 | CARLA_EXPORT | ||||
int jack_port_tie(jack_port_t* src, jack_port_t* dst) | 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 != nullptr, EINVAL); | ||||
CARLA_SAFE_ASSERT_RETURN(! jport->isSystem, EINVAL); | CARLA_SAFE_ASSERT_RETURN(! jport->isSystem, EINVAL); | ||||
static CarlaString rname, rfullname; | |||||
// TODO: verify uniqueness | // TODO: verify uniqueness | ||||
rname = port_name; | |||||
CARLA_SAFE_ASSERT_RETURN(rname.isNotEmpty(), ENOMEM); | |||||
char* const fullname = (char*)std::malloc(STR_MAX); | char* const fullname = (char*)std::malloc(STR_MAX); | ||||
CARLA_SAFE_ASSERT_RETURN(fullname != nullptr, ENOMEM); | CARLA_SAFE_ASSERT_RETURN(fullname != nullptr, ENOMEM); | ||||
std::snprintf(fullname, STR_MAX, "%s:%s", jclient->name, port_name); | std::snprintf(fullname, STR_MAX, "%s:%s", jclient->name, port_name); | ||||
fullname[STR_MAX-1] = '\0'; | 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 | // TODO: port rename callback | ||||