diff --git a/source/backend/CarlaPlugin.hpp b/source/backend/CarlaPlugin.hpp index 07dd96c46..80b45a005 100644 --- a/source/backend/CarlaPlugin.hpp +++ b/source/backend/CarlaPlugin.hpp @@ -263,7 +263,7 @@ public: * * \see setChunkData() */ - virtual int32_t getChunkData(void** const dataPtr) const noexcept; + virtual std::size_t getChunkData(void** const dataPtr) noexcept; // ------------------------------------------------------------------- // Information (per-plugin data) diff --git a/source/backend/CarlaStandalone.cpp b/source/backend/CarlaStandalone.cpp index e94a1d711..c5ece88d7 100644 --- a/source/backend/CarlaStandalone.cpp +++ b/source/backend/CarlaStandalone.cpp @@ -1682,7 +1682,6 @@ const char* carla_get_chunk_data(uint pluginId) if (data != nullptr && dataSize > 0) { chunkData = CarlaString::asBase64(data, static_cast(dataSize)); - return chunkData; } else diff --git a/source/backend/engine/CarlaEngineBridge.cpp b/source/backend/engine/CarlaEngineBridge.cpp index 5f032b3d1..409f4cb8f 100644 --- a/source/backend/engine/CarlaEngineBridge.cpp +++ b/source/backend/engine/CarlaEngineBridge.cpp @@ -31,6 +31,9 @@ #include #include +using juce::File; +using juce::String; + #ifdef JACKBRIDGE_EXPORT // ------------------------------------------------------------------- @@ -44,10 +47,6 @@ bool jackbridge_is_ok() noexcept CARLA_BACKEND_START_NAMESPACE -#if 0 -} // Fix editor indentation -#endif - // ------------------------------------------------------------------- template @@ -478,6 +477,38 @@ public: break; } + case kPluginBridgeOpcodeSetChunkFile: { + const uint32_t size(fShmControl.readUInt()); + CARLA_SAFE_ASSERT_BREAK(size > 0); + + char chunkFilePathTry[size+1]; + carla_zeroChar(chunkFilePathTry, size+1); + fShmControl.readCustomData(chunkFilePathTry, size); + + CARLA_SAFE_ASSERT_BREAK(chunkFilePathTry[0] != '\0'); + + String chunkFilePath(chunkFilePathTry); +#ifdef CARLA_OS_WIN + if (chunkFilePath.startsWith("/")) + { + // running under Wine, posix host + chunkFilePath = chunkFilePath.replaceSection(0, 1, "Z:\\"); + chunkFilePath = chunkFilePath.replace("/", "\\"); + } +#endif + + File chunkFile(chunkFilePath); + CARLA_SAFE_ASSERT_BREAK(chunkFile.existsAsFile()); + + String chunkData(chunkFile.loadFileAsString()); + chunkFile.deleteFile(); + CARLA_SAFE_ASSERT_BREAK(chunkData.isNotEmpty()); + + carla_set_chunk_data(0, chunkData.toRawUTF8()); + carla_stdout("chunk sent, size:%i", chunkData.length()); + break; + } + case kPluginBridgeOpcodePrepareForSave: { carla_prepare_for_save(0); @@ -491,28 +522,16 @@ public: //if (fPlugin->getOptionsEnabled() & CarlaBackend::PLUGIN_OPTION_USE_CHUNKS) { - //if (const char* const chunkData = carla_get_chunk_data(0)) + if (const char* const chunkData = carla_get_chunk_data(0)) { -#if 0 - QString filePath; - filePath = QDir::tempPath(); - #ifdef Q_OS_WIN - filePath += "\\.CarlaChunk_"; - #else - filePath += "/.CarlaChunk_"; - #endif - filePath += fPlugin->getName(); - - QFile file(filePath); - - if (file.open(QIODevice::WriteOnly)) - { - QByteArray chunk((const char*)data, dataSize); - file.write(chunk); - file.close(); - fEngine->oscSend_bridge_set_chunk_data(filePath.toUtf8().constData()); - } -#endif + String filePath(File::getSpecialLocation(File::tempDirectory).getFullPathName()); + + filePath += OS_SEP_STR; + filePath += ".CarlaChunk_"; + filePath += fShmAudioPool.filename.buffer() + 18; + + if (File(filePath).replaceWithText(chunkData)) + oscSend_bridge_set_chunk_data(filePath.toRawUTF8()); } } diff --git a/source/backend/plugin/BridgePlugin.cpp b/source/backend/plugin/BridgePlugin.cpp index ac62bc7eb..42bb3cbc0 100644 --- a/source/backend/plugin/BridgePlugin.cpp +++ b/source/backend/plugin/BridgePlugin.cpp @@ -21,6 +21,7 @@ #ifndef BUILD_BRIDGE #include "CarlaBackendUtils.hpp" +#include "CarlaBase64Utils.hpp" #include "CarlaBridgeUtils.hpp" #include "CarlaMathUtils.hpp" #include "CarlaShmUtils.hpp" @@ -54,6 +55,13 @@ } \ } +// ------------------------------------------------------------------------------------------------------------------- + +using juce::File; +using juce::MemoryBlock; +using juce::String; +using juce::StringArray; + CARLA_BACKEND_START_NAMESPACE // ------------------------------------------------------------------------------------------------------------------- @@ -282,7 +290,6 @@ struct BridgeTime { // ------------------------------------------------------------------------------------------------------------------- -// FIXME - use CarlaString struct BridgeParamInfo { float value; CarlaString name; @@ -362,7 +369,7 @@ public: clearBuffers(); - //info.chunk.clear(); + fInfo.chunk.clear(); } // ------------------------------------------------------------------- @@ -404,20 +411,14 @@ public: // ------------------------------------------------------------------- // Information (current data) - int32_t getChunkData(void** const dataPtr) const noexcept override + std::size_t getChunkData(void** const dataPtr) noexcept override { - CARLA_ASSERT(pData->options & PLUGIN_OPTION_USE_CHUNKS); - CARLA_ASSERT(dataPtr != nullptr); + CARLA_SAFE_ASSERT_RETURN(pData->options & PLUGIN_OPTION_USE_CHUNKS, 0); + CARLA_SAFE_ASSERT_RETURN(dataPtr != nullptr, 0); + CARLA_SAFE_ASSERT_RETURN(fInfo.chunk.size() > 0, 0); -#if 0 - if (! info.chunk.isEmpty()) - { - *dataPtr = info.chunk.data(); - return info.chunk.size(); - } -#endif - - return 0; + *dataPtr = fInfo.chunk.data(); + return fInfo.chunk.size(); } // ------------------------------------------------------------------- @@ -588,32 +589,29 @@ public: CarlaPlugin::setCustomData(type, key, value, sendGui); } +#endif void setChunkData(const char* const stringData) override { - CARLA_ASSERT(m_hints & PLUGIN_USES_CHUNKS); - CARLA_ASSERT(stringData); + CARLA_SAFE_ASSERT_RETURN(pData->options & PLUGIN_OPTION_USE_CHUNKS,); + CARLA_SAFE_ASSERT_RETURN(stringData != nullptr,); - QString filePath; - filePath = QDir::tempPath(); - filePath += "/.CarlaChunk_"; - filePath += m_name; + String filePath(File::getSpecialLocation(File::tempDirectory).getFullPathName()); - filePath = QDir::toNativeSeparators(filePath); + filePath += OS_SEP_STR; + filePath += ".CarlaChunk_"; + filePath += fShmAudioPool.filename.buffer() + 18; - QFile file(filePath); - - if (file.open(QIODevice::WriteOnly | QIODevice::Text)) + if (File(filePath).replaceWithText(stringData)) { - QTextStream out(&file); - out << stringData; - file.close(); - osc_send_configure(&osc.data, CARLA_BRIDGE_MSG_SET_CHUNK, filePath.toUtf8().constData()); - } + const CarlaMutexLocker _cml(fShmControl.lock); - pData->updateParameterValues(this, pData->engine->isOscControlRegistered(), true, false); + fShmControl.writeOpcode(kPluginBridgeOpcodeSetChunkFile); + fShmControl.writeInt(filePath.length()); + fShmControl.writeCustomData(filePath.toRawUTF8(), filePath.length()); + fShmControl.commitWrite(); + } } -#endif // ------------------------------------------------------------------- // Set ui stuff @@ -1707,51 +1705,45 @@ public: case kPluginBridgeSetChunkData: { CARLA_BRIDGE_CHECK_OSC_TYPES(1, "s"); -#if 0 - const char* const chunkFileChar = (const char*)&argv[0]->s; - CARLA_ASSERT(chunkFileChar); + const char* const chunkFilePath = (const char*)&argv[0]->s; + + CARLA_SAFE_ASSERT_BREAK(chunkFilePath != nullptr); - QString chunkFileStr(chunkFileChar); + String realChunkFilePath(chunkFilePath); + carla_stdout("chunk save path BEFORE => %s", realChunkFilePath.toRawUTF8()); #ifndef CARLA_OS_WIN // Using Wine, fix temp dir - if (m_binary == BINARY_WIN32 || m_binary == BINARY_WIN64) + if (fBinaryType == BINARY_WIN32 || fBinaryType == BINARY_WIN64) { // Get WINEPREFIX - QString wineDir; + String wineDir; if (const char* const WINEPREFIX = getenv("WINEPREFIX")) - wineDir = QString(WINEPREFIX); + wineDir = String(WINEPREFIX); else - wineDir = QDir::homePath() + "/.wine"; - - QStringList chunkFileStrSplit1 = chunkFileStr.split(":/"); - QStringList chunkFileStrSplit2 = chunkFileStrSplit1.at(1).split("\\"); - - QString wineDrive = chunkFileStrSplit1.at(0).toLower(); - QString wineTMP = chunkFileStrSplit2.at(0); - QString baseName = chunkFileStrSplit2.at(1); - - chunkFileStr = wineDir; - chunkFileStr += "/drive_"; - chunkFileStr += wineDrive; - chunkFileStr += "/"; - chunkFileStr += wineTMP; - chunkFileStr += "/"; - chunkFileStr += baseName; - chunkFileStr = QDir::toNativeSeparators(chunkFileStr); + wineDir = File::getSpecialLocation(File::userHomeDirectory).getFullPathName() + "/.wine"; + + const StringArray driveLetterSplit(StringArray::fromTokens(realChunkFilePath, ":/", "")); + + realChunkFilePath = wineDir; + realChunkFilePath += "/drive_"; + realChunkFilePath += driveLetterSplit[0].toLowerCase(); + realChunkFilePath += "/"; + realChunkFilePath += driveLetterSplit[1]; + + realChunkFilePath = realChunkFilePath.replace("\\", "/"); + carla_stdout("chunk save path AFTER => %s", realChunkFilePath.toRawUTF8()); } #endif - QFile chunkFile(chunkFileStr); + File chunkFile(realChunkFilePath); - if (chunkFile.open(QIODevice::ReadOnly)) + if (chunkFile.existsAsFile()) { - info.chunk = chunkFile.readAll(); - chunkFile.close(); - chunkFile.remove(); + fInfo.chunk = carla_getChunkFromBase64String(chunkFile.loadFileAsString().toRawUTF8()); + chunkFile.deleteFile(); } -#endif break; } @@ -1994,6 +1986,18 @@ public: return false; } + // --------------------------------------------------------------- + // set default options + + pData->options = 0x0; + pData->options |= PLUGIN_OPTION_MAP_PROGRAM_CHANGES; + pData->options |= PLUGIN_OPTION_USE_CHUNKS; + pData->options |= PLUGIN_OPTION_SEND_CONTROL_CHANGES; + pData->options |= PLUGIN_OPTION_SEND_CHANNEL_PRESSURE; + pData->options |= PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH; + pData->options |= PLUGIN_OPTION_SEND_PITCHBEND; + pData->options |= PLUGIN_OPTION_SEND_ALL_SOUND_OFF; + return true; } @@ -2024,7 +2028,7 @@ private: CarlaString label; CarlaString maker; CarlaString copyright; - //QByteArray chunk; + std::vector chunk; Info() : aIns(0), diff --git a/source/backend/plugin/CarlaPlugin.cpp b/source/backend/plugin/CarlaPlugin.cpp index f7b0c2809..9963451ba 100644 --- a/source/backend/plugin/CarlaPlugin.cpp +++ b/source/backend/plugin/CarlaPlugin.cpp @@ -261,7 +261,7 @@ const CustomData& CarlaPlugin::getCustomData(const uint32_t index) const noexcep return pData->custom.getAt(index, kCustomDataNull); } -int32_t CarlaPlugin::getChunkData(void** const dataPtr) const noexcept +std::size_t CarlaPlugin::getChunkData(void** const dataPtr) noexcept { CARLA_SAFE_ASSERT_RETURN(dataPtr != nullptr, 0); CARLA_SAFE_ASSERT(false); // this should never happen diff --git a/source/backend/plugin/DssiPlugin.cpp b/source/backend/plugin/DssiPlugin.cpp index dd89e89dd..88928ce3b 100644 --- a/source/backend/plugin/DssiPlugin.cpp +++ b/source/backend/plugin/DssiPlugin.cpp @@ -143,7 +143,7 @@ public: // ------------------------------------------------------------------- // Information (current data) - int32_t getChunkData(void** const dataPtr) const noexcept override + std::size_t getChunkData(void** const dataPtr) noexcept override { CARLA_SAFE_ASSERT_RETURN(fUsesCustomData, 0); CARLA_SAFE_ASSERT_RETURN(pData->options & PLUGIN_OPTION_USE_CHUNKS, 0); @@ -162,7 +162,7 @@ public: ret = fDssiDescriptor->get_custom_data(fHandle, dataPtr, &dataSize); } CARLA_SAFE_EXCEPTION_RETURN("DssiPlugin::getChunkData", 0); - return (ret != 0) ? static_cast(dataSize) : 0; + return (ret != 0) ? dataSize : 0; } // ------------------------------------------------------------------- diff --git a/source/backend/plugin/JucePlugin.cpp b/source/backend/plugin/JucePlugin.cpp index e4cee1aeb..5b04d40a0 100644 --- a/source/backend/plugin/JucePlugin.cpp +++ b/source/backend/plugin/JucePlugin.cpp @@ -21,6 +21,7 @@ #if (defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN)) #include "CarlaBackendUtils.hpp" +#include "CarlaBase64Utils.hpp" #include "JucePluginWindow.hpp" #include "juce_audio_processors.h" @@ -113,7 +114,27 @@ public: // ------------------------------------------------------------------- // Information (current data) - // nothing + std::size_t getChunkData(void** const dataPtr) noexcept override + { + CARLA_SAFE_ASSERT_RETURN(pData->options & PLUGIN_OPTION_USE_CHUNKS, 0); + CARLA_SAFE_ASSERT_RETURN(fInstance != nullptr, 0); + CARLA_SAFE_ASSERT_RETURN(dataPtr != nullptr, 0); + + *dataPtr = nullptr; + + try { + fChunk.reset(); + fInstance->getStateInformation(fChunk); + } CARLA_SAFE_EXCEPTION_RETURN("JucePlugin::getChunkData", 0); + + if (const std::size_t size = fChunk.getSize()) + { + *dataPtr = fChunk.getData(); + return size; + } + + return 0; + } // ------------------------------------------------------------------- // Information (per-plugin data) @@ -125,7 +146,7 @@ public: uint options = 0x0; options |= PLUGIN_OPTION_MAP_PROGRAM_CHANGES; - //options |= PLUGIN_OPTION_USE_CHUNKS; + options |= PLUGIN_OPTION_USE_CHUNKS; if (fInstance->acceptsMidi()) { @@ -227,6 +248,28 @@ public: CarlaPlugin::setParameterValue(parameterId, fixedValue, sendGui, sendOsc, sendCallback); } + void setChunkData(const char* const stringData) override + { + CARLA_SAFE_ASSERT_RETURN(pData->options & PLUGIN_OPTION_USE_CHUNKS,); + CARLA_SAFE_ASSERT_RETURN(fInstance != nullptr,); + CARLA_SAFE_ASSERT_RETURN(stringData != nullptr,); + + std::vector chunk(carla_getChunkFromBase64String(stringData)); + CARLA_SAFE_ASSERT_RETURN(chunk.size() > 0,); + + { + const ScopedSingleProcessLocker spl(this, true); + fInstance->setStateInformation(chunk.data(), chunk.size()); + } + +#ifdef BUILD_BRIDGE + const bool sendOsc(false); +#else + const bool sendOsc(pData->engine->isOscControlRegistered()); +#endif + pData->updateParameterValues(this, sendOsc, true, false); + } + // ------------------------------------------------------------------- // Set ui stuff @@ -234,10 +277,6 @@ public: { CARLA_SAFE_ASSERT_RETURN(fInstance != nullptr,); -#ifdef CARLA_OS_LINUX - const MessageManagerLock mmLock; -#endif - if (yesNo) { if (fWindow == nullptr) @@ -1032,10 +1071,6 @@ public: return false; } -#ifdef CARLA_OS_LINUX - const MessageManagerLock mmLock; -#endif - // --------------------------------------------------------------- // fix path for wine usage @@ -1096,7 +1131,7 @@ public: pData->options = 0x0; pData->options |= PLUGIN_OPTION_FIXED_BUFFERS; pData->options |= PLUGIN_OPTION_MAP_PROGRAM_CHANGES; - //pData->options |= PLUGIN_OPTION_USE_CHUNKS; + pData->options |= PLUGIN_OPTION_USE_CHUNKS; if (fInstance->acceptsMidi()) { @@ -1117,6 +1152,7 @@ private: AudioSampleBuffer fAudioBuffer; MidiBuffer fMidiBuffer; CurrentPositionInfo fPosInfo; + MemoryBlock fChunk; const char* fUniqueId; diff --git a/source/backend/plugin/VstPlugin.cpp b/source/backend/plugin/VstPlugin.cpp index 0bebbadf5..a851a85c7 100644 --- a/source/backend/plugin/VstPlugin.cpp +++ b/source/backend/plugin/VstPlugin.cpp @@ -182,7 +182,7 @@ public: // ------------------------------------------------------------------- // Information (current data) - int32_t getChunkData(void** const dataPtr) const noexcept override + std::size_t getChunkData(void** const dataPtr) noexcept override { CARLA_SAFE_ASSERT_RETURN(pData->options & PLUGIN_OPTION_USE_CHUNKS, 0); CARLA_SAFE_ASSERT_RETURN(fEffect != nullptr, 0); @@ -191,7 +191,9 @@ public: *dataPtr = nullptr; try { - return static_cast(dispatcher(effGetChunk, 0 /* bank */, 0, dataPtr, 0.0f)); + const intptr_t ret = dispatcher(effGetChunk, 0 /* bank */, 0, dataPtr, 0.0f); + CARLA_SAFE_ASSERT_RETURN(ret >= 0, 0); + return static_cast(ret); } CARLA_SAFE_EXCEPTION_RETURN("VstPlugin::getChunkData", 0); } diff --git a/source/bridges-plugin/CarlaBridgePlugin.cpp b/source/bridges-plugin/CarlaBridgePlugin.cpp index 153f52efb..a4c473ef1 100644 --- a/source/bridges-plugin/CarlaBridgePlugin.cpp +++ b/source/bridges-plugin/CarlaBridgePlugin.cpp @@ -362,40 +362,6 @@ private: } }; -#if 0 -int CarlaBridgeOsc::handleMsgPluginSetChunk(CARLA_BRIDGE_OSC_HANDLE_ARGS) -{ - CARLA_BRIDGE_OSC_CHECK_OSC_TYPES(1, "s"); - CARLA_SAFE_ASSERT_RETURN(fClient != nullptr, 1); - carla_debug("CarlaBridgeOsc::handleMsgPluginSetChunk()"); - - const char* const chunkFilePathTry = (const char*)&argv[0]->s; - - CARLA_SAFE_ASSERT_RETURN(chunkFilePathTry != nullptr && chunkFilePathTry[0] != '\0', 0); - - String chunkFilePath(chunkFilePathTry); - -#ifdef CARLA_OS_WIN - if (chunkFilePath.startsWith("/")) - { - // running under Wine, posix host - chunkFilePath = chunkFilePath.replaceSection(0, 1, "Z:\\"); - chunkFilePath = chunkFilePath.replace("/", "\\"); - } -#endif - - File chunkFile(chunkFilePath); - CARLA_SAFE_ASSERT_RETURN(chunkFile.existsAsFile(), 0); - - String chunkData(chunkFile.loadFileAsString()); - chunkFile.deleteFile(); - CARLA_SAFE_ASSERT_RETURN(chunkData.isNotEmpty(), 0); - - carla_set_chunk_data(0, chunkData.toRawUTF8()); - return 0; -} -#endif - // ------------------------------------------------------------------------- int main(int argc, char* argv[]) diff --git a/source/utils/CarlaBridgeUtils.hpp b/source/utils/CarlaBridgeUtils.hpp index 0f532a038..4f5c057d0 100644 --- a/source/utils/CarlaBridgeUtils.hpp +++ b/source/utils/CarlaBridgeUtils.hpp @@ -60,8 +60,8 @@ enum PluginBridgeOpcode { kPluginBridgeOpcodeSetParameterMidiCC = 7, // int, float kPluginBridgeOpcodeSetProgram = 8, // int kPluginBridgeOpcodeSetMidiProgram = 9, // int - kPluginBridgeOpcodeSetCustomData = 10, // str, str, str - kPluginBridgeOpcodeSetChunkFile = 11, // str + kPluginBridgeOpcodeSetCustomData = 10, // int/size, str, int/size, str, int/size, str + kPluginBridgeOpcodeSetChunkFile = 11, // int/size, str kPluginBridgeOpcodePrepareForSave = 12, kPluginBridgeOpcodeMidiEvent = 13, // long, int, char[] (long = timeFrame, int = size max 4) kPluginBridgeOpcodeProcess = 14,