| @@ -21,6 +21,7 @@ | |||
| #include "CarlaEngineInternal.hpp" | |||
| #include "CarlaBackendUtils.hpp" | |||
| #include "CarlaStringList.hpp" | |||
| #include "RtLinkedList.hpp" | |||
| @@ -37,23 +38,14 @@ CARLA_BACKEND_START_NAMESPACE | |||
| // ------------------------------------------------------------------------------------------------------------------- | |||
| // Global static data | |||
| static const char** gRetNames = nullptr; | |||
| static OwnedArray<AudioIODeviceType> gJuceDeviceTypes; | |||
| static CharStringListPtr gDeviceNames; | |||
| static OwnedArray<AudioIODeviceType> gDeviceTypes; | |||
| struct JuceCleanup : public DeletedAtShutdown { | |||
| JuceCleanup() noexcept {} | |||
| ~JuceCleanup() | |||
| { | |||
| if (gRetNames != nullptr) | |||
| { | |||
| for (int i=0; gRetNames[i] != nullptr; ++i) | |||
| delete[] gRetNames[i]; | |||
| delete[] gRetNames; | |||
| gRetNames = nullptr; | |||
| } | |||
| gJuceDeviceTypes.clear(true); | |||
| gDeviceTypes.clear(true); | |||
| } | |||
| }; | |||
| @@ -71,15 +63,16 @@ static void initJuceDevicesIfNeeded() | |||
| needsInit = false; | |||
| new JuceCleanup(); | |||
| sDeviceManager.createAudioDeviceTypes(gJuceDeviceTypes); | |||
| sDeviceManager.createAudioDeviceTypes(gDeviceTypes); | |||
| // remove JACK from device list | |||
| for (int i=0, count=gJuceDeviceTypes.size(); i < count; ++i) | |||
| for (int i=0, count=gDeviceTypes.size(); i < count; ++i) | |||
| { | |||
| if (gJuceDeviceTypes[i]->getTypeName() != "JACK") | |||
| continue; | |||
| gJuceDeviceTypes.remove(i, true); | |||
| if (gDeviceTypes[i]->getTypeName() == "JACK") | |||
| { | |||
| gDeviceTypes.remove(i, true); | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| @@ -863,9 +856,9 @@ CarlaEngine* CarlaEngine::newJuce(const AudioApi api) | |||
| AudioIODeviceType* deviceType = nullptr; | |||
| for (int i=0, count=gJuceDeviceTypes.size(); i < count; ++i) | |||
| for (int i=0, count=gDeviceTypes.size(); i < count; ++i) | |||
| { | |||
| deviceType = gJuceDeviceTypes[i]; | |||
| deviceType = gDeviceTypes[i]; | |||
| if (deviceType == nullptr || deviceType->getTypeName() == juceApi) | |||
| break; | |||
| @@ -883,7 +876,7 @@ uint CarlaEngine::getJuceApiCount() | |||
| { | |||
| initJuceDevicesIfNeeded(); | |||
| return static_cast<uint>(gJuceDeviceTypes.size()); | |||
| return static_cast<uint>(gDeviceTypes.size()); | |||
| } | |||
| const char* CarlaEngine::getJuceApiName(const uint uindex) | |||
| @@ -892,9 +885,9 @@ const char* CarlaEngine::getJuceApiName(const uint uindex) | |||
| const int index(static_cast<int>(uindex)); | |||
| CARLA_SAFE_ASSERT_RETURN(index < gJuceDeviceTypes.size(), nullptr); | |||
| CARLA_SAFE_ASSERT_RETURN(index < gDeviceTypes.size(), nullptr); | |||
| AudioIODeviceType* const deviceType(gJuceDeviceTypes[index]); | |||
| AudioIODeviceType* const deviceType(gDeviceTypes[index]); | |||
| CARLA_SAFE_ASSERT_RETURN(deviceType != nullptr, nullptr); | |||
| return deviceType->getTypeName().toRawUTF8(); | |||
| @@ -906,34 +899,27 @@ const char* const* CarlaEngine::getJuceApiDeviceNames(const uint uindex) | |||
| const int index(static_cast<int>(uindex)); | |||
| CARLA_SAFE_ASSERT_RETURN(index < gJuceDeviceTypes.size(), nullptr); | |||
| CARLA_SAFE_ASSERT_RETURN(index < gDeviceTypes.size(), nullptr); | |||
| AudioIODeviceType* const deviceType(gJuceDeviceTypes[index]); | |||
| AudioIODeviceType* const deviceType(gDeviceTypes[index]); | |||
| CARLA_SAFE_ASSERT_RETURN(deviceType != nullptr, nullptr); | |||
| deviceType->scanForDevices(); | |||
| StringArray deviceNames(deviceType->getDeviceNames()); | |||
| const int deviceNameCount(deviceNames.size()); | |||
| StringArray juceDeviceNames(deviceType->getDeviceNames()); | |||
| const int juceDeviceNameCount(juceDeviceNames.size()); | |||
| if (deviceNameCount <= 0) | |||
| if (juceDeviceNameCount <= 0) | |||
| return nullptr; | |||
| if (gRetNames != nullptr) | |||
| { | |||
| for (int i=0; gRetNames[i] != nullptr; ++i) | |||
| delete[] gRetNames[i]; | |||
| delete[] gRetNames; | |||
| } | |||
| gRetNames = new const char*[deviceNameCount+1]; | |||
| CarlaStringList devNames; | |||
| for (int i=0; i < deviceNameCount; ++i) | |||
| gRetNames[i] = carla_strdup(deviceNames[i].toRawUTF8()); | |||
| for (int i=0; i < juceDeviceNameCount; ++i) | |||
| devNames.append(juceDeviceNames[i].toRawUTF8()); | |||
| gRetNames[deviceNameCount] = nullptr; | |||
| gDeviceNames = devNames.toCharStringListPtr(); | |||
| return gRetNames; | |||
| return gDeviceNames; | |||
| } | |||
| const EngineDriverDeviceInfo* CarlaEngine::getJuceDeviceInfo(const uint uindex, const char* const deviceName) | |||
| @@ -942,9 +928,9 @@ const EngineDriverDeviceInfo* CarlaEngine::getJuceDeviceInfo(const uint uindex, | |||
| const int index(static_cast<int>(uindex)); | |||
| CARLA_SAFE_ASSERT_RETURN(index < gJuceDeviceTypes.size(), nullptr); | |||
| CARLA_SAFE_ASSERT_RETURN(index < gDeviceTypes.size(), nullptr); | |||
| AudioIODeviceType* const deviceType(gJuceDeviceTypes[index]); | |||
| AudioIODeviceType* const deviceType(gDeviceTypes[index]); | |||
| CARLA_SAFE_ASSERT_RETURN(deviceType != nullptr, nullptr); | |||
| deviceType->scanForDevices(); | |||
| @@ -18,6 +18,7 @@ | |||
| #include "CarlaEngineInternal.hpp" | |||
| #include "CarlaBackendUtils.hpp" | |||
| #include "CarlaMathUtils.hpp" | |||
| #include "CarlaStringList.hpp" | |||
| #include "RtLinkedList.hpp" | |||
| @@ -35,31 +36,13 @@ CARLA_BACKEND_START_NAMESPACE | |||
| // ------------------------------------------------------------------------------------------------------------------- | |||
| // Global static data | |||
| static const char** gRetNames = nullptr; | |||
| static CharStringListPtr gDeviceNames; | |||
| static std::vector<RtAudio::Api> gRtAudioApis; | |||
| struct RtAudioCleanup { | |||
| RtAudioCleanup() noexcept {} | |||
| ~RtAudioCleanup() | |||
| { | |||
| if (gRetNames != nullptr) | |||
| { | |||
| for (int i=0; gRetNames[i] != nullptr; ++i) | |||
| delete[] gRetNames[i]; | |||
| delete[] gRetNames; | |||
| gRetNames = nullptr; | |||
| } | |||
| gRtAudioApis.clear(); | |||
| } | |||
| }; | |||
| // ------------------------------------------------------------------------------------------------------------------- | |||
| static void initRtAudioAPIsIfNeeded() | |||
| { | |||
| static const RtAudioCleanup sRtAudioCleanup; | |||
| static bool needsInit = true; | |||
| if (! needsInit) | |||
| @@ -1114,39 +1097,19 @@ const char* const* CarlaEngine::getRtAudioApiDeviceNames(const uint index) | |||
| if (devCount == 0) | |||
| return nullptr; | |||
| LinkedList<const char*> devNames; | |||
| CarlaStringList devNames; | |||
| for (uint i=0; i < devCount; ++i) | |||
| { | |||
| RtAudio::DeviceInfo devInfo(rtAudio.getDeviceInfo(i)); | |||
| if (devInfo.probed && devInfo.outputChannels > 0 /*&& (devInfo.nativeFormats & RTAUDIO_FLOAT32) != 0*/) | |||
| devNames.append(carla_strdup(devInfo.name.c_str())); | |||
| } | |||
| const size_t realDevCount(devNames.count()); | |||
| if (gRetNames != nullptr) | |||
| { | |||
| for (int i=0; gRetNames[i] != nullptr; ++i) | |||
| delete[] gRetNames[i]; | |||
| delete[] gRetNames; | |||
| } | |||
| gRetNames = new const char*[realDevCount+1]; | |||
| for (size_t i=0; i < realDevCount; ++i) | |||
| { | |||
| gRetNames[i] = devNames.getAt(i, nullptr); | |||
| if (gRetNames[i] == nullptr) | |||
| gRetNames[i] = carla_strdup("(unknown)"); | |||
| devNames.append(devInfo.name.c_str()); | |||
| } | |||
| gRetNames[realDevCount] = nullptr; | |||
| devNames.clear(); | |||
| gDeviceNames = devNames.toCharStringListPtr(); | |||
| return gRetNames; | |||
| return gDeviceNames; | |||
| } | |||
| const EngineDriverDeviceInfo* CarlaEngine::getRtAudioDeviceInfo(const uint index, const char* const deviceName) | |||
| @@ -0,0 +1,215 @@ | |||
| /* | |||
| * Carla String List | |||
| * Copyright (C) 2014 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 | |||
| * published by the Free Software Foundation; either version 2 of | |||
| * the License, or any later version. | |||
| * | |||
| * This program is distributed in the hope that it will be useful, | |||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| * GNU General Public License for more details. | |||
| * | |||
| * For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||
| */ | |||
| #ifndef CARLA_STRING_LIST_HPP_INCLUDED | |||
| #define CARLA_STRING_LIST_HPP_INCLUDED | |||
| #include "CarlaString.hpp" | |||
| #include "LinkedList.hpp" | |||
| // ----------------------------------------------------------------------- | |||
| // Helper class to manage the lifetime of a "char**" object | |||
| class CharStringListPtr | |||
| { | |||
| public: | |||
| CharStringListPtr() noexcept | |||
| : charList(nullptr) {} | |||
| CharStringListPtr(const char* const* const c) noexcept | |||
| : charList(c) {} | |||
| CharStringListPtr(const CharStringListPtr& ptr) noexcept | |||
| : charList(nullptr) | |||
| { | |||
| copy(ptr.charList); | |||
| } | |||
| CharStringListPtr(const LinkedList<CarlaString>& list) noexcept | |||
| : charList(nullptr) | |||
| { | |||
| copy(list); | |||
| } | |||
| ~CharStringListPtr() noexcept | |||
| { | |||
| clear(); | |||
| } | |||
| operator const char* const*() const noexcept | |||
| { | |||
| return charList; | |||
| } | |||
| CharStringListPtr& operator=(const char* const* const c) noexcept | |||
| { | |||
| clear(); | |||
| charList = c; | |||
| return *this; | |||
| } | |||
| CharStringListPtr& operator=(const CharStringListPtr& ptr) | |||
| { | |||
| clear(); | |||
| copy(ptr.charList); | |||
| return *this; | |||
| } | |||
| CharStringListPtr& operator=(const LinkedList<CarlaString>& list) | |||
| { | |||
| clear(); | |||
| copy(list); | |||
| return *this; | |||
| } | |||
| protected: | |||
| void clear() noexcept | |||
| { | |||
| if (charList == nullptr) | |||
| return; | |||
| for (int i=0; charList[i] != nullptr; ++i) | |||
| delete[] charList[i]; | |||
| delete[] charList; | |||
| charList = nullptr; | |||
| } | |||
| void copy(const char* const* const c) noexcept | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(c != nullptr,); | |||
| CARLA_SAFE_ASSERT_RETURN(charList == nullptr,); | |||
| size_t count = 0; | |||
| for (; c[count] != nullptr; ++count) {} | |||
| CARLA_SAFE_ASSERT_RETURN(count > 0,); | |||
| const char** tmpList; | |||
| try { | |||
| tmpList = new const char*[count+1]; | |||
| } CARLA_SAFE_EXCEPTION_RETURN("CharStringListPtr::copy",); | |||
| for (size_t i=0; i<count; ++i) | |||
| { | |||
| try { | |||
| tmpList[i] = carla_strdup(c[i]); | |||
| } | |||
| catch(...) { | |||
| tmpList[i] = nullptr; | |||
| break; | |||
| } | |||
| } | |||
| tmpList[count] = nullptr; | |||
| charList = tmpList; | |||
| } | |||
| void copy(const LinkedList<CarlaString>& list) noexcept | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(charList == nullptr,); | |||
| const size_t count(list.count()); | |||
| CARLA_SAFE_ASSERT_RETURN(count > 0,); | |||
| const char** tmpList; | |||
| try { | |||
| tmpList = new const char*[count+1]; | |||
| } CARLA_SAFE_EXCEPTION_RETURN("CharStringListPtr::copy",); | |||
| size_t i=0; | |||
| for (LinkedList<CarlaString>::Itenerator it = list.begin(); it.valid(); it.next(), ++i) | |||
| { | |||
| const CarlaString& string(it.getValue()); | |||
| try { | |||
| tmpList[i] = string.dup(); | |||
| } | |||
| catch(...) { | |||
| tmpList[i] = nullptr; | |||
| break; | |||
| } | |||
| } | |||
| tmpList[count] = nullptr; | |||
| charList = tmpList; | |||
| } | |||
| private: | |||
| const char* const* charList; | |||
| }; | |||
| // ----------------------------------------------------------------------- | |||
| // CarlaStringList | |||
| class CarlaStringList : public LinkedList<CarlaString> | |||
| { | |||
| public: | |||
| CarlaStringList() noexcept | |||
| : LinkedList<CarlaString>(true) {} | |||
| #if 0 | |||
| CarlaStringList(const CarlaStringList& list) noexcept | |||
| : LinkedList<CarlaString>(true) | |||
| { | |||
| for (Itenerator it = list.begin(); it.valid(); it.next()) | |||
| LinkedList<CarlaString>::append(it.getValue()); | |||
| } | |||
| #endif | |||
| ~CarlaStringList() noexcept | |||
| { | |||
| clear(); | |||
| } | |||
| bool append(const char* const strBuf) noexcept | |||
| { | |||
| const CarlaString string(strBuf); | |||
| return LinkedList<CarlaString>::append(string); | |||
| } | |||
| bool appendAt(const char* const strBuf, const Itenerator& it) noexcept | |||
| { | |||
| const CarlaString string(strBuf); | |||
| return LinkedList<CarlaString>::appendAt(string, it); | |||
| } | |||
| bool insert(const char* const strBuf) noexcept | |||
| { | |||
| const CarlaString string(strBuf); | |||
| return LinkedList<CarlaString>::insert(string); | |||
| } | |||
| bool insertAt(const char* const strBuf, const Itenerator& it) noexcept | |||
| { | |||
| const CarlaString string(strBuf); | |||
| return LinkedList<CarlaString>::insertAt(string, it); | |||
| } | |||
| CharStringListPtr toCharStringListPtr() const noexcept | |||
| { | |||
| return CharStringListPtr(*this); | |||
| } | |||
| private: | |||
| LinkedList<CarlaString> fList; | |||
| }; | |||
| // ----------------------------------------------------------------------- | |||
| #endif // CARLA_STRING_LIST_HPP_INCLUDED | |||