| @@ -100,6 +100,7 @@ struct JackPortState { | |||
| void* buffer; | |||
| uint index; | |||
| uint flags; | |||
| jack_uuid_t uuid; | |||
| bool isMidi : 1; | |||
| bool isSystem : 1; | |||
| bool isConnected : 1; | |||
| @@ -111,34 +112,39 @@ struct JackPortState { | |||
| buffer(nullptr), | |||
| index(0), | |||
| flags(0), | |||
| uuid(0), | |||
| isMidi(false), | |||
| isSystem(false), | |||
| isConnected(false), | |||
| unused(false) {} | |||
| JackPortState(const char* const cn, const char* const pn, const uint i, const uint f, | |||
| JackPortState(const char* const clientName, const char* const portName, const uint i, const uint f, | |||
| const bool midi, const bool sys, const bool con) | |||
| : name(strdup(pn)), | |||
| : name(portName != nullptr ? strdup(portName) : nullptr), | |||
| fullname(nullptr), | |||
| buffer(nullptr), | |||
| index(i), | |||
| flags(f), | |||
| uuid(0), | |||
| isMidi(midi), | |||
| isSystem(sys), | |||
| isConnected(con), | |||
| unused(false) | |||
| { | |||
| char strBuf[STR_MAX+1]; | |||
| snprintf(strBuf, STR_MAX, "%s:%s", cn, pn); | |||
| strBuf[STR_MAX] = '\0'; | |||
| if (clientName != nullptr && portName != nullptr) | |||
| { | |||
| char strBuf[STR_MAX+1]; | |||
| snprintf(strBuf, STR_MAX, "%s:%s", clientName, portName); | |||
| strBuf[STR_MAX] = '\0'; | |||
| fullname = strdup(strBuf); | |||
| fullname = strdup(strBuf); | |||
| } | |||
| } | |||
| ~JackPortState() | |||
| { | |||
| free(name); | |||
| free(fullname); | |||
| std::free(name); | |||
| std::free(fullname); | |||
| } | |||
| CARLA_DECLARE_NON_COPY_STRUCT(JackPortState) | |||
| @@ -232,11 +238,13 @@ struct JackClientState { | |||
| delete jport; | |||
| } | |||
| free(name); | |||
| std::free(name); | |||
| name = nullptr; | |||
| audioIns.clear(); | |||
| audioOuts.clear(); | |||
| midiIns.clear(); | |||
| midiOuts.clear(); | |||
| } | |||
| CARLA_DECLARE_NON_COPY_STRUCT(JackClientState) | |||
| @@ -17,10 +17,28 @@ | |||
| #include "libjack.hpp" | |||
| #include "CarlaStringList.hpp" | |||
| CARLA_BACKEND_USE_NAMESPACE | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| const char* allocate_port_name(const char* const prefix, const uint32_t num) | |||
| { | |||
| static CarlaStringList portList; | |||
| char portName[STR_MAX]; | |||
| carla_zeroChars(portName, STR_MAX); | |||
| std::snprintf(portName, STR_MAX-1, "%s%u", prefix, num+1); | |||
| if (const char* const storedPortName = portList.containsAndReturnString(portName)) | |||
| return storedPortName; | |||
| CARLA_SAFE_ASSERT_RETURN(portList.append(portName), nullptr); | |||
| return portList.getLast(); | |||
| } | |||
| CARLA_EXPORT | |||
| const char** jack_get_ports(jack_client_t* client, const char* a, const char* b, unsigned long flags) | |||
| { | |||
| @@ -29,42 +47,53 @@ const char** jack_get_ports(jack_client_t* client, const char* a, const char* b, | |||
| JackClientState* const jclient = (JackClientState*)client; | |||
| CARLA_SAFE_ASSERT_RETURN(jclient != nullptr, nullptr); | |||
| static const char* capture_1 = "system:capture_1"; | |||
| static const char* capture_2 = "system:capture_2"; | |||
| static const char* playback_1 = "system:playback_1"; | |||
| static const char* playback_2 = "system:playback_2"; | |||
| const JackServerState& jserver(jclient->server); | |||
| const uint32_t numIns = jserver.numAudioIns + jserver.numMidiIns; | |||
| const uint32_t numOuts = jserver.numAudioOuts + jserver.numMidiOuts; | |||
| if (flags == 0 || (flags & (JackPortIsInput|JackPortIsOutput)) == (JackPortIsInput|JackPortIsOutput)) | |||
| { | |||
| if (const char** const ret = (const char**)calloc(5, sizeof(const char*))) | |||
| if (const char** const ret = (const char**)calloc(numIns+numOuts, sizeof(const char*))) | |||
| { | |||
| ret[0] = capture_1; | |||
| ret[1] = capture_2; | |||
| ret[2] = playback_1; | |||
| ret[3] = playback_2; | |||
| ret[4] = nullptr; | |||
| uint32_t i=0; | |||
| for (uint32_t j=0; j<jserver.numAudioIns; ++i, ++j) | |||
| ret[i] = allocate_port_name("system:capture_", j); | |||
| for (uint32_t j=0; j<jserver.numAudioOuts; ++i, ++j) | |||
| ret[i] = allocate_port_name("system:playback_", j); | |||
| for (uint32_t j=0; j<jserver.numMidiIns; ++i, ++j) | |||
| ret[i] = allocate_port_name("system:midi_capture_", j); | |||
| for (uint32_t j=0; j<jserver.numMidiOuts; ++i, ++j) | |||
| ret[i] = allocate_port_name("system:midi_playback_", j); | |||
| return ret; | |||
| } | |||
| } | |||
| if (flags & JackPortIsInput) | |||
| { | |||
| if (const char** const ret = (const char**)calloc(3, sizeof(const char*))) | |||
| if (const char** const ret = (const char**)calloc(numIns, sizeof(const char*))) | |||
| { | |||
| ret[0] = playback_1; | |||
| ret[1] = playback_2; | |||
| ret[2] = nullptr; | |||
| uint32_t i=0; | |||
| for (uint32_t j=0; j<jserver.numAudioOuts; ++i, ++j) | |||
| ret[i] = allocate_port_name("system:playback_", j); | |||
| for (uint32_t j=0; j<jserver.numMidiOuts; ++i, ++j) | |||
| ret[i] = allocate_port_name("system:midi_playback_", j); | |||
| return ret; | |||
| } | |||
| } | |||
| if (flags & JackPortIsOutput) | |||
| { | |||
| if (const char** const ret = (const char**)calloc(3, sizeof(const char*))) | |||
| if (const char** const ret = (const char**)calloc(numOuts, sizeof(const char*))) | |||
| { | |||
| ret[0] = capture_1; | |||
| ret[1] = capture_2; | |||
| ret[2] = nullptr; | |||
| uint32_t i=0; | |||
| for (uint32_t j=0; j<jserver.numAudioIns; ++i, ++j) | |||
| ret[i] = allocate_port_name("system:capture_", j); | |||
| for (uint32_t j=0; j<jserver.numMidiIns; ++i, ++j) | |||
| ret[i] = allocate_port_name("system:midi_capture_", j); | |||
| return ret; | |||
| } | |||
| } | |||
| @@ -83,42 +112,81 @@ jack_port_t* jack_port_by_name(jack_client_t* client, const char* name) | |||
| const JackServerState& jserver(jclient->server); | |||
| const int commonFlags = JackPortIsPhysical|JackPortIsTerminal; | |||
| static const JackPortState capturePorts[] = { | |||
| { "system", "capture_1", 0, JackPortIsOutput|commonFlags, false, true, jserver.numAudioIns > 0 }, | |||
| { "system", "capture_2", 1, JackPortIsOutput|commonFlags, false, true, jserver.numAudioIns > 1 }, | |||
| }; | |||
| static const JackPortState playbackPorts[] = { | |||
| { "system", "playback_1", 3, JackPortIsInput|commonFlags, false, true, jserver.numAudioOuts > 0 }, | |||
| { "system", "playback_2", 4, JackPortIsInput|commonFlags, false, true, jserver.numAudioOuts > 1 }, | |||
| }; | |||
| static JackPortState retPort( | |||
| /* name */ nullptr, | |||
| /* fullname */ nullptr, | |||
| /* index */ 0, | |||
| /* flags */ 0x0, | |||
| /* isMidi */ false, | |||
| /* isSystem */ true, | |||
| /* isConnected */ false | |||
| ); | |||
| if (std::strncmp(name, "system:", 7) == 0) | |||
| { | |||
| std::free(retPort.fullname); | |||
| retPort.fullname = strdup(name); | |||
| name += 7; | |||
| std::free(retPort.name); | |||
| retPort.name = strdup(name); | |||
| /**/ if (std::strncmp(name, "capture_", 8) == 0) | |||
| { | |||
| name += 8; | |||
| const int index = std::atoi(name)-1; | |||
| CARLA_SAFE_ASSERT_RETURN(index >= 0 && index < 2, nullptr); | |||
| CARLA_SAFE_ASSERT_RETURN(index >= 0 && index < jserver.numAudioIns, nullptr); | |||
| return (jack_port_t*)&capturePorts[index]; | |||
| retPort.index = index; | |||
| retPort.flags = commonFlags|JackPortIsOutput; | |||
| retPort.isMidi = false; | |||
| retPort.isConnected = jserver.numAudioIns > index; | |||
| } | |||
| else if (std::strncmp(name, "playback_", 9) == 0) | |||
| { | |||
| name += 9; | |||
| const int index = std::atoi(name)-1; | |||
| CARLA_SAFE_ASSERT_RETURN(index >= 0, nullptr); | |||
| CARLA_SAFE_ASSERT_RETURN(index >= 0 && index < jserver.numAudioOuts, nullptr); | |||
| retPort.index = (jserver.numAudioIns) + index; | |||
| retPort.flags = commonFlags|JackPortIsInput; | |||
| retPort.isMidi = false; | |||
| retPort.isConnected = jserver.numAudioOuts > index; | |||
| } | |||
| else if (std::strncmp(name, "midi_capture_", 13) == 0) | |||
| { | |||
| name += 13; | |||
| const int index = std::atoi(name)-1; | |||
| CARLA_SAFE_ASSERT_RETURN(index >= 0 && index < jserver.numAudioIns, nullptr); | |||
| return (jack_port_t*)&playbackPorts[index]; | |||
| retPort.index = index; | |||
| retPort.flags = commonFlags|JackPortIsOutput; | |||
| retPort.isMidi = true; | |||
| retPort.isConnected = jserver.numMidiIns > index; | |||
| } | |||
| else if (std::strncmp(name, "midi_playback_", 14) == 0) | |||
| { | |||
| name += 14; | |||
| const int index = std::atoi(name)-1; | |||
| CARLA_SAFE_ASSERT_RETURN(index >= 0 && index < jserver.numAudioOuts, nullptr); | |||
| retPort.index = (jserver.numAudioIns) + index; | |||
| retPort.flags = commonFlags|JackPortIsInput; | |||
| retPort.isMidi = true; | |||
| retPort.isConnected = jserver.numMidiOuts > index; | |||
| } | |||
| else | |||
| { | |||
| carla_stderr2("jack_port_by_name: invalid port short name '%s'", name); | |||
| return nullptr; | |||
| } | |||
| return (jack_port_t*)&retPort; | |||
| } | |||
| carla_stderr2("jack_port_by_name: invalid port name '%s'", name); | |||
| @@ -43,9 +43,11 @@ jack_port_t* jack_port_register(jack_client_t* client, const char* port_name, co | |||
| JackPortState* const port = new JackPortState(jclient->name, port_name, index, flags, | |||
| false, false, index < jserver.numAudioIns); | |||
| const CarlaMutexLocker cms(jclient->mutex); | |||
| { | |||
| const CarlaMutexLocker cms(jclient->mutex); | |||
| jclient->audioIns.append(port); | |||
| } | |||
| jclient->audioIns.append(port); | |||
| return (jack_port_t*)port; | |||
| } | |||
| @@ -55,9 +57,11 @@ jack_port_t* jack_port_register(jack_client_t* client, const char* port_name, co | |||
| JackPortState* const port = new JackPortState(jclient->name, port_name, index, flags, | |||
| false, false, index < jserver.numAudioOuts); | |||
| const CarlaMutexLocker cms(jclient->mutex); | |||
| { | |||
| const CarlaMutexLocker cms(jclient->mutex); | |||
| jclient->audioOuts.append(port); | |||
| } | |||
| jclient->audioOuts.append(port); | |||
| return (jack_port_t*)port; | |||
| } | |||
| @@ -73,9 +77,11 @@ jack_port_t* jack_port_register(jack_client_t* client, const char* port_name, co | |||
| JackPortState* const port = new JackPortState(jclient->name, port_name, index, flags, | |||
| true, false, index < jserver.numMidiIns); | |||
| const CarlaMutexLocker cms(jclient->mutex); | |||
| { | |||
| const CarlaMutexLocker cms(jclient->mutex); | |||
| jclient->midiIns.append(port); | |||
| } | |||
| jclient->midiIns.append(port); | |||
| return (jack_port_t*)port; | |||
| } | |||
| @@ -85,9 +91,11 @@ jack_port_t* jack_port_register(jack_client_t* client, const char* port_name, co | |||
| JackPortState* const port = new JackPortState(jclient->name, port_name, index, flags, | |||
| true, false, index < jserver.numMidiOuts); | |||
| const CarlaMutexLocker cms(jclient->mutex); | |||
| { | |||
| const CarlaMutexLocker cms(jclient->mutex); | |||
| jclient->midiOuts.append(port); | |||
| } | |||
| jclient->midiOuts.append(port); | |||
| return (jack_port_t*)port; | |||
| } | |||
| @@ -108,45 +116,47 @@ int jack_port_unregister(jack_client_t* client, jack_port_t* port) | |||
| carla_debug("%s(%p, %p)", __FUNCTION__, client, port); | |||
| JackClientState* const jclient = (JackClientState*)client; | |||
| CARLA_SAFE_ASSERT_RETURN(jclient != nullptr, 1); | |||
| CARLA_SAFE_ASSERT_RETURN(jclient != nullptr, EINVAL); | |||
| JackPortState* const jport = (JackPortState*)port; | |||
| CARLA_SAFE_ASSERT_RETURN(jport != nullptr, 1); | |||
| CARLA_SAFE_ASSERT_RETURN(! jport->isSystem, 1); | |||
| CARLA_SAFE_ASSERT_RETURN(jport != nullptr, EINVAL); | |||
| CARLA_SAFE_ASSERT_RETURN(! jport->isSystem, EINVAL); | |||
| const CarlaMutexLocker cms(jclient->mutex); | |||
| if (jport->isMidi) | |||
| { | |||
| if (jport->flags & JackPortIsInput) | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(jclient->midiIns.removeOne(jport), 1); | |||
| return 0; | |||
| } | |||
| const CarlaMutexLocker cms(jclient->mutex); | |||
| if (jport->flags & JackPortIsOutput) | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(jclient->midiOuts.removeOne(jport), 1); | |||
| return 0; | |||
| } | |||
| } | |||
| else | |||
| { | |||
| if (jport->flags & JackPortIsInput) | |||
| if (jport->isMidi) | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(jclient->audioIns.removeOne(jport), 1); | |||
| return 0; | |||
| if (jport->flags & JackPortIsInput) | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(jclient->midiIns.removeOne(jport), ENOENT); | |||
| return 0; | |||
| } | |||
| if (jport->flags & JackPortIsOutput) | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(jclient->midiOuts.removeOne(jport), ENOENT); | |||
| return 0; | |||
| } | |||
| } | |||
| if (jport->flags & JackPortIsOutput) | |||
| else | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(jclient->audioOuts.removeOne(jport), 1); | |||
| return 0; | |||
| if (jport->flags & JackPortIsInput) | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(jclient->audioIns.removeOne(jport), ENOENT); | |||
| return 0; | |||
| } | |||
| if (jport->flags & JackPortIsOutput) | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(jclient->audioOuts.removeOne(jport), ENOENT); | |||
| return 0; | |||
| } | |||
| } | |||
| } | |||
| carla_stderr2("jack_port_register: invalid port '%s'", jport->name); | |||
| return 1; | |||
| return EINVAL; | |||
| } | |||
| CARLA_EXPORT | |||
| @@ -163,8 +173,12 @@ void* jack_port_get_buffer(jack_port_t* port, jack_nframes_t) | |||
| CARLA_EXPORT | |||
| jack_uuid_t jack_port_uuid(const jack_port_t* port) | |||
| { | |||
| carla_stderr2("%s(%p)", __FUNCTION__, port); | |||
| return 0; | |||
| carla_debug("%s(%p)", __FUNCTION__, port); | |||
| JackPortState* const jport = (JackPortState*)port; | |||
| CARLA_SAFE_ASSERT_RETURN(jport != nullptr, 0); | |||
| return jport->uuid; | |||
| } | |||
| CARLA_EXPORT | |||
| @@ -248,7 +262,15 @@ int jack_port_connected(const jack_port_t* port) | |||
| CARLA_EXPORT | |||
| int jack_port_connected_to(const jack_port_t* port, const char* port_name) | |||
| { | |||
| carla_stderr2("%s(%p, %s)", __FUNCTION__, port, port_name); | |||
| carla_stderr2("%s(%p, %s) WIP", __FUNCTION__, port, port_name); | |||
| JackPortState* const jport = (JackPortState*)port; | |||
| CARLA_SAFE_ASSERT_RETURN(jport != nullptr, 0); | |||
| if (! jport->isConnected) | |||
| return 0; | |||
| // TODO | |||
| return 1; | |||
| } | |||
| @@ -273,15 +295,21 @@ const char** jack_port_get_all_connections(const jack_client_t* client, const ja | |||
| CARLA_EXPORT | |||
| int jack_port_tie(jack_port_t* src, jack_port_t* dst) | |||
| { | |||
| carla_stderr2("%s(%p, %p)", __FUNCTION__, src, dst); | |||
| carla_debug("%s(%p, %p)", __FUNCTION__, src, dst); | |||
| return ENOSYS; | |||
| // unused | |||
| (void)src; (void)dst; | |||
| } | |||
| CARLA_EXPORT | |||
| int jack_port_untie(jack_port_t* port) | |||
| { | |||
| carla_stderr2("%s(%p)", __FUNCTION__, port); | |||
| carla_debug("%s(%p)", __FUNCTION__, port); | |||
| return ENOSYS; | |||
| // unused | |||
| (void)port; | |||
| } | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| @@ -120,21 +120,21 @@ String& StringArray::getReference (const int index) noexcept | |||
| return strings.getReference (index); | |||
| } | |||
| void StringArray::add (const String& newString) | |||
| bool StringArray::add (const String& newString) | |||
| { | |||
| strings.add (newString); | |||
| return strings.add (newString); | |||
| } | |||
| #if WATER_COMPILER_SUPPORTS_MOVE_SEMANTICS | |||
| void StringArray::add (String&& stringToAdd) | |||
| bool StringArray::add (String&& stringToAdd) | |||
| { | |||
| strings.add (static_cast<String&&> (stringToAdd)); | |||
| return strings.add (static_cast<String&&> (stringToAdd)); | |||
| } | |||
| #endif | |||
| void StringArray::insert (const int index, const String& newString) | |||
| bool StringArray::insert (const int index, const String& newString) | |||
| { | |||
| strings.insert (index, newString); | |||
| return strings.insert (index, newString); | |||
| } | |||
| bool StringArray::addIfNotAlreadyThere (const String& newString, const bool ignoreCase) | |||
| @@ -142,8 +142,7 @@ bool StringArray::addIfNotAlreadyThere (const String& newString, const bool igno | |||
| if (contains (newString, ignoreCase)) | |||
| return false; | |||
| add (newString); | |||
| return true; | |||
| return add (newString); | |||
| } | |||
| void StringArray::addArray (const StringArray& otherArray, int startIndex, int numElementsToAdd) | |||
| @@ -157,11 +157,11 @@ public: | |||
| //============================================================================== | |||
| /** Appends a string at the end of the array. */ | |||
| void add (const String& stringToAdd); | |||
| bool add (const String& stringToAdd); | |||
| #if WATER_COMPILER_SUPPORTS_MOVE_SEMANTICS | |||
| /** Appends a string at the end of the array. */ | |||
| void add (String&& stringToAdd); | |||
| bool add (String&& stringToAdd); | |||
| #endif | |||
| /** Inserts a string into the array. | |||
| @@ -171,7 +171,7 @@ public: | |||
| If the index is less than zero or greater than the size of the array, | |||
| the new string will be added to the end of the array. | |||
| */ | |||
| void insert (int index, const String& stringToAdd); | |||
| bool insert (int index, const String& stringToAdd); | |||
| /** Adds a string to the array as long as it's not already in there. | |||
| The search can optionally be case-insensitive. | |||
| @@ -259,6 +259,26 @@ public: | |||
| return data->value; | |||
| } | |||
| const char* getFirst() const noexcept | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(fCount > 0, nullptr); | |||
| const Data* const data(list_entry_const(fQueue.next, Data, siblings)); | |||
| CARLA_SAFE_ASSERT_RETURN(data != nullptr, nullptr); | |||
| return data->value; | |||
| } | |||
| const char* getLast() const noexcept | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(fCount > 0, nullptr); | |||
| const Data* const data(list_entry_const(fQueue.prev, Data, siblings)); | |||
| CARLA_SAFE_ASSERT_RETURN(data != nullptr, nullptr); | |||
| return data->value; | |||
| } | |||
| // ------------------------------------------------------------------- | |||
| bool contains(const char* const string) noexcept | |||
| @@ -280,6 +300,25 @@ public: | |||
| return false; | |||
| } | |||
| const char* containsAndReturnString(const char* const string) noexcept | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(string != nullptr, nullptr); | |||
| if (fCount == 0) | |||
| return nullptr; | |||
| for (Itenerator it = begin2(); it.valid(); it.next()) | |||
| { | |||
| const char* const stringComp(it.getValue(nullptr)); | |||
| CARLA_SAFE_ASSERT_CONTINUE(stringComp != nullptr); | |||
| if (std::strcmp(string, stringComp) == 0) | |||
| return stringComp; | |||
| } | |||
| return nullptr; | |||
| } | |||
| // ------------------------------------------------------------------- | |||
| void remove(Itenerator& it) noexcept | |||