@@ -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) | |||
@@ -1682,7 +1682,6 @@ const char* carla_get_chunk_data(uint pluginId) | |||
if (data != nullptr && dataSize > 0) | |||
{ | |||
chunkData = CarlaString::asBase64(data, static_cast<std::size_t>(dataSize)); | |||
return chunkData; | |||
} | |||
else | |||
@@ -31,6 +31,9 @@ | |||
#include <cerrno> | |||
#include <ctime> | |||
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<typename T> | |||
@@ -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()); | |||
} | |||
} | |||
@@ -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<uint8_t> chunk; | |||
Info() | |||
: aIns(0), | |||
@@ -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 | |||
@@ -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<int32_t>(dataSize) : 0; | |||
return (ret != 0) ? dataSize : 0; | |||
} | |||
// ------------------------------------------------------------------- | |||
@@ -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<uint8_t> 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; | |||
@@ -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<int32_t>(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<std::size_t>(ret); | |||
} CARLA_SAFE_EXCEPTION_RETURN("VstPlugin::getChunkData", 0); | |||
} | |||
@@ -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[]) | |||
@@ -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, | |||