From 89566a1a0fe8a54be6aba31ccedb896078989283 Mon Sep 17 00:00:00 2001 From: falkTX Date: Thu, 25 Jun 2020 14:37:57 +0100 Subject: [PATCH] Add API to know current project folder Signed-off-by: falkTX --- source/backend/CarlaEngine.hpp | 7 +++ source/backend/CarlaHost.h | 12 ++++ source/backend/CarlaStandalone.cpp | 24 ++++++++ source/backend/engine/CarlaEngine.cpp | 44 +++++++++++++- source/backend/engine/CarlaEngineInternal.cpp | 1 + source/backend/engine/CarlaEngineInternal.hpp | 1 + source/backend/engine/CarlaEngineNative.cpp | 48 +++++++++++---- source/backend/plugin/CarlaPluginJack.cpp | 47 ++++++++++----- source/backend/plugin/CarlaPluginNative.cpp | 60 ++++++++++++++++--- source/frontend/carla-plugin | 3 + 10 files changed, 209 insertions(+), 38 deletions(-) diff --git a/source/backend/CarlaEngine.hpp b/source/backend/CarlaEngine.hpp index 69ff4aa45..94c52ac16 100644 --- a/source/backend/CarlaEngine.hpp +++ b/source/backend/CarlaEngine.hpp @@ -1060,8 +1060,15 @@ public: bool saveProject(const char* filename, bool setAsCurrentProject); #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH + /*! + * Get the currently set project folder. + * @note Valid for both standalone and plugin versions. + */ + virtual const char* getCurrentProjectFolder() const noexcept; + /*! * Get the currently set project filename. + * @note Valid only for both standalone version. */ const char* getCurrentProjectFilename() const noexcept; diff --git a/source/backend/CarlaHost.h b/source/backend/CarlaHost.h index 0b966b41a..a78547281 100644 --- a/source/backend/CarlaHost.h +++ b/source/backend/CarlaHost.h @@ -528,6 +528,18 @@ CARLA_EXPORT bool carla_load_project(CarlaHostHandle handle, const char* filenam CARLA_EXPORT bool carla_save_project(CarlaHostHandle handle, const char* filename); #ifndef BUILD_BRIDGE +/*! + * Get the currently set project folder. + * @note Valid for both standalone and plugin versions. + */ +CARLA_EXPORT const char* carla_get_current_project_folder(CarlaHostHandle handle); + +/*! + * Get the currently set project filename. + * @note Valid only for both standalone version. + */ +CARLA_EXPORT const char* carla_get_current_project_filename(CarlaHostHandle handle); + /*! * Clear the currently set project filename. */ diff --git a/source/backend/CarlaStandalone.cpp b/source/backend/CarlaStandalone.cpp index 3e70b1d7c..26e16ab82 100644 --- a/source/backend/CarlaStandalone.cpp +++ b/source/backend/CarlaStandalone.cpp @@ -944,6 +944,30 @@ bool carla_save_project(CarlaHostHandle handle, const char* filename) } #ifndef BUILD_BRIDGE +const char* carla_get_current_project_folder(CarlaHostHandle handle) +{ + CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr, gNullCharPtr); + + carla_debug("carla_get_current_project_folder(%p)", handle); + + if (const char* const ret = handle->engine->getCurrentProjectFolder()) + return ret; + + return gNullCharPtr; +} + +const char* carla_get_current_project_filename(CarlaHostHandle handle) +{ + CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr && handle->isStandalone, gNullCharPtr); + + carla_debug("carla_get_current_project_filename(%p)", handle); + + if (const char* const ret = handle->engine->getCurrentProjectFilename()) + return ret; + + return gNullCharPtr; +} + void carla_clear_project_filename(CarlaHostHandle handle) { CARLA_SAFE_ASSERT_RETURN(handle->engine != nullptr,); diff --git a/source/backend/engine/CarlaEngine.cpp b/source/backend/engine/CarlaEngine.cpp index b910352b8..e0f5e4fe5 100644 --- a/source/backend/engine/CarlaEngine.cpp +++ b/source/backend/engine/CarlaEngine.cpp @@ -1254,13 +1254,29 @@ bool CarlaEngine::loadProject(const char* const filename, const bool setAsCurren carla_debug("CarlaEngine::loadProject(\"%s\")", filename); const String jfilename = String(CharPointer_UTF8(filename)); - File file(jfilename); + const File file(jfilename); CARLA_SAFE_ASSERT_RETURN_ERR(file.existsAsFile(), "Requested file does not exist or is not a readable file"); if (setAsCurrentProject) { #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH - pData->currentProjectFilename = filename; + if (pData->currentProjectFilename != filename) + { + pData->currentProjectFilename = filename; + + bool found; + const size_t r = pData->currentProjectFilename.rfind(CARLA_OS_SEP, &found); + + if (found) + { + pData->currentProjectFolder = filename; + pData->currentProjectFolder[r] = '\0'; + } + else + { + pData->currentProjectFolder.clear(); + } + } #endif } @@ -1282,7 +1298,23 @@ bool CarlaEngine::saveProject(const char* const filename, const bool setAsCurren if (setAsCurrentProject) { #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH - pData->currentProjectFilename = filename; + if (pData->currentProjectFilename != filename) + { + pData->currentProjectFilename = filename; + + bool found; + const size_t r = pData->currentProjectFilename.rfind(CARLA_OS_SEP, &found); + + if (found) + { + pData->currentProjectFolder = filename; + pData->currentProjectFolder[r] = '\0'; + } + else + { + pData->currentProjectFolder.clear(); + } + } #endif } @@ -1294,6 +1326,11 @@ bool CarlaEngine::saveProject(const char* const filename, const bool setAsCurren } #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH +const char* CarlaEngine::getCurrentProjectFolder() const noexcept +{ + return pData->currentProjectFolder; +} + const char* CarlaEngine::getCurrentProjectFilename() const noexcept { return pData->currentProjectFilename; @@ -1302,6 +1339,7 @@ const char* CarlaEngine::getCurrentProjectFilename() const noexcept void CarlaEngine::clearCurrentProjectFilename() noexcept { pData->currentProjectFilename.clear(); + pData->currentProjectFolder.clear(); } #endif diff --git a/source/backend/engine/CarlaEngineInternal.cpp b/source/backend/engine/CarlaEngineInternal.cpp index 22eb65e30..d322307e3 100644 --- a/source/backend/engine/CarlaEngineInternal.cpp +++ b/source/backend/engine/CarlaEngineInternal.cpp @@ -386,6 +386,7 @@ CarlaEngine::ProtectedData::ProtectedData(CarlaEngine* const engine) #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH loadingProject(false), currentProjectFilename(), + currentProjectFolder(), #endif bufferSize(0), sampleRate(0.0), diff --git a/source/backend/engine/CarlaEngineInternal.hpp b/source/backend/engine/CarlaEngineInternal.hpp index eac9494f9..0c0e9488d 100644 --- a/source/backend/engine/CarlaEngineInternal.hpp +++ b/source/backend/engine/CarlaEngineInternal.hpp @@ -247,6 +247,7 @@ struct CarlaEngine::ProtectedData { #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH bool loadingProject; CarlaString currentProjectFilename; + CarlaString currentProjectFolder; #endif uint32_t bufferSize; diff --git a/source/backend/engine/CarlaEngineNative.cpp b/source/backend/engine/CarlaEngineNative.cpp index bd0bd1d1f..77f59bd1c 100644 --- a/source/backend/engine/CarlaEngineNative.cpp +++ b/source/backend/engine/CarlaEngineNative.cpp @@ -184,6 +184,7 @@ public: fIsRunning(false), fUiServer(this), fLastScaleFactor(1.0f), + fLastProjectFolder(), fOptionsForced(false) { carla_debug("CarlaEngineNative::CarlaEngineNative()"); @@ -319,6 +320,21 @@ public: return "Plugin"; } + const char* getCurrentProjectFolder() const noexcept override + { + CARLA_SAFE_ASSERT_RETURN(pHost != nullptr, nullptr); + + static char filetype[] = "carla\0"; + + try { + return (const char*)(uintptr_t)pHost->dispatcher(pHost->handle, + NATIVE_HOST_OPCODE_GET_FILE_PATH, + 0, 0, + (void*)filetype, + 0.0f); + } CARLA_SAFE_EXCEPTION_RETURN("get_file_path", nullptr); + } + void callback(const bool sendHost, const bool sendOsc, const EngineCallbackOpcode action, const uint pluginId, const int value1, const int value2, const int value3, @@ -420,7 +436,7 @@ protected: { const CarlaMutexLocker cml(fUiServer.getPipeLock()); - if (fUiServer.writeAndFixMessage("buffer-size")) + if (fUiServer.writeMessage("buffer-size\n")) { char tmpBuf[STR_MAX+1]; carla_zeroChars(tmpBuf, STR_MAX+1); @@ -444,7 +460,7 @@ protected: { const CarlaMutexLocker cml(fUiServer.getPipeLock()); - if (fUiServer.writeAndFixMessage("sample-rate")) + if (fUiServer.writeMessage("sample-rate\n")) { char tmpBuf[STR_MAX+1]; carla_zeroChars(tmpBuf, STR_MAX+1); @@ -485,8 +501,7 @@ protected: if (const char* const filename = plugin->getFilename()) { - std::snprintf(tmpBuf, STR_MAX, "%s", filename); - CARLA_SAFE_ASSERT_RETURN(fUiServer.writeAndFixMessage(tmpBuf),); + CARLA_SAFE_ASSERT_RETURN(fUiServer.writeAndFixMessage(filename),); } else { @@ -495,8 +510,7 @@ protected: if (const char* const name = plugin->getName()) { - std::snprintf(tmpBuf, STR_MAX, "%s", name); - CARLA_SAFE_ASSERT_RETURN(fUiServer.writeAndFixMessage(tmpBuf),); + CARLA_SAFE_ASSERT_RETURN(fUiServer.writeAndFixMessage(name),); } else { @@ -505,8 +519,7 @@ protected: if (const char* const iconName = plugin->getIconName()) { - std::snprintf(tmpBuf, STR_MAX, "%s", iconName); - CARLA_SAFE_ASSERT_RETURN(fUiServer.writeAndFixMessage(tmpBuf),); + CARLA_SAFE_ASSERT_RETURN(fUiServer.writeAndFixMessage(iconName),); } else { @@ -680,8 +693,7 @@ protected: std::snprintf(tmpBuf, STR_MAX, "%i:%i\n", mpData.bank, mpData.program); CARLA_SAFE_ASSERT_RETURN(fUiServer.writeMessage(tmpBuf),); - std::snprintf(tmpBuf, STR_MAX, "%s", mpData.name); - CARLA_SAFE_ASSERT_RETURN(fUiServer.writeAndFixMessage(tmpBuf),); + CARLA_SAFE_ASSERT_RETURN(fUiServer.writeAndFixMessage(mpData.name),); } fUiServer.flushMessages(); @@ -1409,16 +1421,27 @@ protected: // ------------------------------------------------------------------------------------------------------------ // send engine info - CARLA_SAFE_ASSERT_RETURN(fUiServer.writeAndFixMessage("runtime-info"),); std::snprintf(tmpBuf, STR_MAX, "%.12g:0\n", static_cast(getDSPLoad())); + CARLA_SAFE_ASSERT_RETURN(fUiServer.writeMessage("runtime-info\n"),); CARLA_SAFE_ASSERT_RETURN(fUiServer.writeMessage(tmpBuf),); fUiServer.flushMessages(); + if (const char* const projFolder = getCurrentProjectFolder()) + { + if (fLastProjectFolder != projFolder) + { + fLastProjectFolder = projFolder; + CARLA_SAFE_ASSERT_RETURN(fUiServer.writeMessage("project-folder\n"),); + CARLA_SAFE_ASSERT_RETURN(fUiServer.writeAndFixMessage(projFolder),); + fUiServer.flushMessages(); + } + } + // ------------------------------------------------------------------------------------------------------------ // send transport - CARLA_SAFE_ASSERT_RETURN(fUiServer.writeAndFixMessage("transport"),); + CARLA_SAFE_ASSERT_RETURN(fUiServer.writeMessage("transport\n"),); CARLA_SAFE_ASSERT_RETURN(fUiServer.writeMessage(timeInfo.playing ? "true\n" : "false\n"),); if (timeInfo.bbt.valid) @@ -1676,6 +1699,7 @@ private: float fParameters[kNumInParams+kNumOutParams]; float fLastScaleFactor; + CarlaString fLastProjectFolder; bool fOptionsForced; diff --git a/source/backend/plugin/CarlaPluginJack.cpp b/source/backend/plugin/CarlaPluginJack.cpp index 01132d576..c42f5e463 100644 --- a/source/backend/plugin/CarlaPluginJack.cpp +++ b/source/backend/plugin/CarlaPluginJack.cpp @@ -164,6 +164,11 @@ public: return ret.releaseBufferPointer(); } + const CarlaString& getAppName() const noexcept + { + return fProject.appName; + } + protected: #ifdef HAVE_LIBLO static void _osc_error_handler(int num, const char* msg, const char* path) @@ -184,7 +189,9 @@ protected: if (fSetupLabel.length() <= 6) return; - if (fProject.path.isNotEmpty() || fProject.init(kEngine->getCurrentProjectFilename(), &fSetupLabel[6])) + if (fProject.path.isNotEmpty() || fProject.init(kPlugin->getName(), + kEngine->getCurrentProjectFolder(), + &fSetupLabel[6])) { carla_stdout("Sending open signal %s %s %s", fProject.path.buffer(), fProject.display.buffer(), fProject.clientName.buffer()); @@ -465,17 +472,23 @@ private: display(), clientName() {} - bool init(const char* const engineProjectFilename, const char* const uniqueCodeID) + bool init(const char* const pluginName, + const char* const engineProjectFolder, + const char* const uniqueCodeID) { - CARLA_SAFE_ASSERT_RETURN(engineProjectFilename != nullptr && engineProjectFilename[0] != '\0', false); + CARLA_SAFE_ASSERT_RETURN(engineProjectFolder != nullptr && engineProjectFolder[0] != '\0', false); CARLA_SAFE_ASSERT_RETURN(uniqueCodeID != nullptr && uniqueCodeID[0] != '\0', false); CARLA_SAFE_ASSERT_RETURN(appName.isNotEmpty(), false); - const File file(File(engineProjectFilename).withFileExtension(uniqueCodeID)); + String child(pluginName); + child += "."; + child += uniqueCodeID; + + const File file(File(engineProjectFolder).getChildFile(child)); + clientName = appName + "." + uniqueCodeID; path = file.getFullPathName().toRawUTF8(); display = file.getFileNameWithoutExtension().toRawUTF8(); - clientName = appName + "." + uniqueCodeID; return true; } @@ -630,8 +643,6 @@ public: #ifdef HAVE_LIBLO if (fInfo.setupLabel.length() == 6) setupUniqueProjectID(); - - fBridgeThread.nsmSave(fInfo.setupLabel); #endif { @@ -640,6 +651,10 @@ public: fShmNonRtClientControl.writeOpcode(kPluginBridgeNonRtClientPrepareForSave); fShmNonRtClientControl.commitWrite(); } + +#ifdef HAVE_LIBLO + fBridgeThread.nsmSave(fInfo.setupLabel); +#endif } // ------------------------------------------------------------------- @@ -1776,19 +1791,20 @@ private: void setupUniqueProjectID() { - const char* const engineProjectFilename = pData->engine->getCurrentProjectFilename(); - carla_stdout("setupUniqueProjectID %s", engineProjectFilename); + const char* const engineProjectFolder = pData->engine->getCurrentProjectFolder(); + carla_stdout("setupUniqueProjectID %s", engineProjectFolder); - if (engineProjectFilename == nullptr || engineProjectFilename[0] == '\0') + if (engineProjectFolder == nullptr || engineProjectFolder[0] == '\0') return; - const File file(engineProjectFilename); - CARLA_SAFE_ASSERT_RETURN(file.existsAsFile(),); - CARLA_SAFE_ASSERT_RETURN(file.getFileExtension().isNotEmpty(),); + const File file(engineProjectFolder); + CARLA_SAFE_ASSERT_RETURN(file.exists(),); char code[6]; code[5] = '\0'; + String child; + for (;;) { static const char* const kValidChars = @@ -1804,7 +1820,10 @@ private: code[3] = kValidChars[safe_rand(kValidCharsLen)]; code[4] = kValidChars[safe_rand(kValidCharsLen)]; - const File newFile(file.withFileExtension(code)); + child = pData->name; + child += "."; + child += code; + const File newFile(file.getChildFile(child)); if (newFile.existsAsFile()) continue; diff --git a/source/backend/plugin/CarlaPluginNative.cpp b/source/backend/plugin/CarlaPluginNative.cpp index a71c4fc5f..2e0b1db0f 100644 --- a/source/backend/plugin/CarlaPluginNative.cpp +++ b/source/backend/plugin/CarlaPluginNative.cpp @@ -256,6 +256,8 @@ public: fNeedsIdle(false), fInlineDisplayNeedsRedraw(false), fInlineDisplayLastRedrawTime(0), + fLastProjectFilename(), + fLastProjectFolder(), fAudioAndCvInBuffers(nullptr), fAudioAndCvOutBuffers(nullptr), fMidiEventInCount(0), @@ -2690,70 +2692,107 @@ protected: carla_debug("CarlaPluginNative::handleDispatcher(%i, %i, " P_INTPTR ", %p, %f)", opcode, index, value, ptr, static_cast(opt)); - intptr_t ret = 0; - switch (opcode) { case NATIVE_HOST_OPCODE_NULL: break; + case NATIVE_HOST_OPCODE_UPDATE_PARAMETER: // TODO pData->engine->callback(true, true, ENGINE_CALLBACK_UPDATE, pData->id, -1, 0, 0, 0.0f, nullptr); break; + case NATIVE_HOST_OPCODE_UPDATE_MIDI_PROGRAM: // TODO pData->engine->callback(true, true, ENGINE_CALLBACK_UPDATE, pData->id, -1, 0, 0, 0.0f, nullptr); break; + case NATIVE_HOST_OPCODE_RELOAD_PARAMETERS: reloadParameters(nullptr, nullptr); pData->engine->callback(true, true, ENGINE_CALLBACK_RELOAD_ALL, pData->id, -1, 0, 0, 0.0f, nullptr); break; + case NATIVE_HOST_OPCODE_RELOAD_MIDI_PROGRAMS: reloadPrograms(false); pData->engine->callback(true, true, ENGINE_CALLBACK_RELOAD_PROGRAMS, pData->id, -1, 0, 0, 0.0f, nullptr); break; + case NATIVE_HOST_OPCODE_RELOAD_ALL: reload(); pData->engine->callback(true, true, ENGINE_CALLBACK_RELOAD_ALL, pData->id, -1, 0, 0, 0.0f, nullptr); break; + case NATIVE_HOST_OPCODE_UI_UNAVAILABLE: pData->engine->callback(true, true, ENGINE_CALLBACK_UI_STATE_CHANGED, pData->id, -1, 0, 0, 0.0f, nullptr); fIsUiAvailable = false; break; + case NATIVE_HOST_OPCODE_HOST_IDLE: pData->engine->callback(true, false, ENGINE_CALLBACK_IDLE, 0, 0, 0, 0, 0.0f, nullptr); break; + case NATIVE_HOST_OPCODE_INTERNAL_PLUGIN: - ret = 1; - break; + return 1; + case NATIVE_HOST_OPCODE_QUEUE_INLINE_DISPLAY: fInlineDisplayNeedsRedraw = true; break; + case NATIVE_HOST_OPCODE_UI_TOUCH_PARAMETER: CARLA_SAFE_ASSERT_RETURN(index >= 0, 0); pData->engine->touchPluginParameter(pData->id, static_cast(index), value != 0); break; + case NATIVE_HOST_OPCODE_REQUEST_IDLE: fNeedsIdle = true; break; + case NATIVE_HOST_OPCODE_GET_FILE_PATH: CARLA_SAFE_ASSERT_RETURN(ptr != nullptr, 0); { const EngineOptions& opts(pData->engine->getOptions()); const char* const filetype = (const char*)ptr; + const char* ret = nullptr; + + if (std::strcmp(filetype, "carla") == 0) + { + ret = pData->engine->getCurrentProjectFilename(); - if (std::strcmp(filetype, "audio") == 0) - return static_cast((uintptr_t)opts.pathAudio); - if (std::strcmp(filetype, "midi") == 0) - return static_cast((uintptr_t)opts.pathMIDI); + if (fLastProjectFilename != ret) + { + fLastProjectFilename = ret; + + bool found; + const size_t r = fLastProjectFilename.rfind(CARLA_OS_SEP, &found); + if (found) + { + fLastProjectFolder = ret; + fLastProjectFolder[r] = '\0'; + } + else + { + fLastProjectFolder.clear(); + } + } + + ret = fLastProjectFolder.buffer(); + } + + else if (std::strcmp(filetype, "audio") == 0) + ret = opts.pathAudio; + else if (std::strcmp(filetype, "midi") == 0) + ret = opts.pathMIDI; + + return static_cast((uintptr_t)ret); } break; + case NATIVE_HOST_OPCODE_UI_RESIZE: // unused here break; } - return ret; + return 0; // unused for now (void)opt; @@ -2956,6 +2995,9 @@ private: bool fInlineDisplayNeedsRedraw; int64_t fInlineDisplayLastRedrawTime; + CarlaString fLastProjectFilename; + CarlaString fLastProjectFolder; + float** fAudioAndCvInBuffers; float** fAudioAndCvOutBuffers; uint32_t fMidiEventInCount; diff --git a/source/frontend/carla-plugin b/source/frontend/carla-plugin index 9820a76e8..8529b8b76 100755 --- a/source/frontend/carla-plugin +++ b/source/frontend/carla-plugin @@ -174,6 +174,9 @@ class CarlaMiniW(ExternalUI, HostWindow): xruns = int(values[1]) self.host._set_runtime_info(load, xruns) + elif msg == "project-folder": + self.fProjectFilename = self.readlineblock() + elif msg == "transport": playing = self.readlineblock_bool() frame, bar, beat, tick = [int(i) for i in self.readlineblock().split(":")]