Signed-off-by: falkTX <falktx@falktx.com>tags/v2.2.0-RC1
@@ -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; | |||
@@ -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. | |||
*/ | |||
@@ -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,); | |||
@@ -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 | |||
@@ -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), | |||
@@ -247,6 +247,7 @@ struct CarlaEngine::ProtectedData { | |||
#ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||
bool loadingProject; | |||
CarlaString currentProjectFilename; | |||
CarlaString currentProjectFolder; | |||
#endif | |||
uint32_t bufferSize; | |||
@@ -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<double>(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; | |||
@@ -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; | |||
@@ -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<double>(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<uint32_t>(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<intptr_t>((uintptr_t)opts.pathAudio); | |||
if (std::strcmp(filetype, "midi") == 0) | |||
return static_cast<intptr_t>((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<intptr_t>((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; | |||
@@ -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(":")] | |||