@@ -521,7 +521,7 @@ const CarlaStateSave& CarlaPlugin::getStateSave(const bool callPrepareForSave) | |||
prepareForSave(true); | |||
} | |||
const PluginType pluginType(getType()); | |||
const PluginType pluginType = getType(); | |||
char strBuf[STR_MAX+1]; | |||
carla_zeroChars(strBuf, STR_MAX+1); | |||
@@ -567,7 +567,7 @@ const CarlaStateSave& CarlaPlugin::getStateSave(const bool callPrepareForSave) | |||
if (pData->options & PLUGIN_OPTION_USE_CHUNKS) | |||
{ | |||
void* data = nullptr; | |||
const std::size_t dataSize(getChunkData(&data)); | |||
const std::size_t dataSize = getChunkData(&data); | |||
if (data != nullptr && dataSize > 0) | |||
{ | |||
@@ -601,7 +601,7 @@ const CarlaStateSave& CarlaPlugin::getStateSave(const bool callPrepareForSave) | |||
// --------------------------------------------------------------- | |||
// Parameters | |||
const float sampleRate(static_cast<float>(pData->engine->getSampleRate())); | |||
const float sampleRate = static_cast<float>(pData->engine->getSampleRate()); | |||
for (uint32_t i=0; i < pData->param.count; ++i) | |||
{ | |||
@@ -683,8 +683,8 @@ const CarlaStateSave& CarlaPlugin::getStateSave(const bool callPrepareForSave) | |||
void CarlaPlugin::loadStateSave(const CarlaStateSave& stateSave) | |||
{ | |||
const bool usesMultiProgs(pData->hints & PLUGIN_USES_MULTI_PROGS); | |||
const PluginType pluginType(getType()); | |||
const bool usesMultiProgs = pData->hints & PLUGIN_USES_MULTI_PROGS; | |||
const PluginType pluginType = getType(); | |||
char strBuf[STR_MAX+1]; | |||
carla_zeroChars(strBuf, STR_MAX+1); | |||
@@ -753,7 +753,7 @@ void CarlaPlugin::loadStateSave(const CarlaStateSave& stateSave) | |||
LinkedList<ParamSymbol*> paramSymbols; | |||
if (pluginType == PLUGIN_LADSPA || pluginType == PLUGIN_LV2) | |||
if (pluginType == PLUGIN_LADSPA || pluginType == PLUGIN_LV2 || pluginType == PLUGIN_CLAP) | |||
{ | |||
for (uint32_t i=0; i < pData->param.count; ++i) | |||
{ | |||
@@ -771,7 +771,7 @@ void CarlaPlugin::loadStateSave(const CarlaStateSave& stateSave) | |||
// --------------------------------------------------------------- | |||
// Part 4b - set parameter values (carefully) | |||
const float sampleRate(static_cast<float>(pData->engine->getSampleRate())); | |||
const float sampleRate = static_cast<float>(pData->engine->getSampleRate()); | |||
for (CarlaStateSave::ParameterItenerator it = stateSave.parameters.begin2(); it.valid(); it.next()) | |||
{ | |||
@@ -805,7 +805,7 @@ void CarlaPlugin::loadStateSave(const CarlaStateSave& stateSave) | |||
index = stateParameter->index; | |||
} | |||
} | |||
else if (pluginType == PLUGIN_LV2) | |||
else if (pluginType == PLUGIN_LV2 || pluginType == PLUGIN_CLAP) | |||
{ | |||
// Symbol only | |||
if (stateParameter->symbol != nullptr && stateParameter->symbol[0] != '\0') | |||
@@ -823,12 +823,21 @@ void CarlaPlugin::loadStateSave(const CarlaStateSave& stateSave) | |||
} | |||
} | |||
if (index == -1) | |||
carla_stderr("Failed to find LV2 parameter symbol '%s' for '%s'", | |||
stateParameter->symbol, pData->name); | |||
{ | |||
if (pluginType == PLUGIN_LV2) | |||
carla_stderr("Failed to find LV2 parameter symbol '%s' for '%s'", | |||
stateParameter->symbol, pData->name); | |||
else | |||
carla_stderr("Failed to find CLAP parameter id '%s' for '%s'", | |||
stateParameter->symbol, pData->name); | |||
} | |||
} | |||
else | |||
{ | |||
carla_stderr("LV2 Plugin parameter '%s' has no symbol", stateParameter->name); | |||
if (pluginType == PLUGIN_LV2) | |||
carla_stderr("LV2 Plugin parameter '%s' has no symbol", stateParameter->name); | |||
else | |||
carla_stderr("CLAP Plugin parameter '%s' has no id", stateParameter->name); | |||
} | |||
} | |||
else | |||
@@ -941,7 +950,7 @@ void CarlaPlugin::loadStateSave(const CarlaStateSave& stateSave) | |||
// --------------------------------------------------------------- | |||
// Part 6 - set internal stuff | |||
const uint availOptions(getOptionsAvailable()); | |||
const uint availOptions = getOptionsAvailable(); | |||
for (uint i=0; i<10; ++i) // FIXME - get this value somehow... | |||
{ | |||
@@ -132,6 +132,7 @@ struct carla_clap_host : clap_host_t { | |||
virtual void clapRequestRestart() = 0; | |||
virtual void clapRequestProcess() = 0; | |||
virtual void clapRequestCallback() = 0; | |||
virtual void clapMarkDirty() = 0; | |||
#ifdef CLAP_WINDOW_API_NATIVE | |||
// gui | |||
virtual void clapGuiResizeHintsChanged() = 0; | |||
@@ -147,6 +148,7 @@ struct carla_clap_host : clap_host_t { | |||
Callbacks* const hostCallbacks; | |||
clap_host_state_t state; | |||
#ifdef CLAP_WINDOW_API_NATIVE | |||
clap_host_gui_t gui; | |||
clap_host_timer_support_t timer; | |||
@@ -167,12 +169,15 @@ struct carla_clap_host : clap_host_t { | |||
request_process = carla_request_process; | |||
request_callback = carla_request_callback; | |||
state.mark_dirty = carla_mark_dirty; | |||
#ifdef CLAP_WINDOW_API_NATIVE | |||
gui.resize_hints_changed = carla_resize_hints_changed; | |||
gui.request_resize = carla_request_resize; | |||
gui.request_show = carla_request_show; | |||
gui.request_hide = carla_request_hide; | |||
gui.closed = carla_closed; | |||
timer.register_timer = carla_register_timer; | |||
timer.unregister_timer = carla_unregister_timer; | |||
#endif | |||
@@ -213,6 +218,11 @@ struct carla_clap_host : clap_host_t { | |||
static_cast<const carla_clap_host*>(host->host_data)->hostCallbacks->clapRequestCallback(); | |||
} | |||
static void carla_mark_dirty(const clap_host_t* const host) | |||
{ | |||
static_cast<const carla_clap_host*>(host->host_data)->hostCallbacks->clapMarkDirty(); | |||
} | |||
#ifdef CLAP_WINDOW_API_NATIVE | |||
static void carla_resize_hints_changed(const clap_host_t* const host) | |||
{ | |||
@@ -571,10 +581,11 @@ public: | |||
fInputAudioBuffers(), | |||
fOutputAudioBuffers(), | |||
fInputEvents(), | |||
fOutputEvents() | |||
fOutputEvents(), | |||
#ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||
, fAudioOutBuffers(nullptr) | |||
fAudioOutBuffers(nullptr), | |||
#endif | |||
fLastChunk(nullptr) | |||
{ | |||
carla_debug("CarlaPluginCLAP::CarlaPluginCLAP(%p, %i)", engine, id); | |||
} | |||
@@ -607,6 +618,12 @@ public: | |||
fPlugin = nullptr; | |||
} | |||
if (fLastChunk != nullptr) | |||
{ | |||
std::free(fLastChunk); | |||
fLastChunk = nullptr; | |||
} | |||
clearBuffers(); | |||
if (fPluginEntry != nullptr) | |||
@@ -692,11 +709,19 @@ public: | |||
CARLA_SAFE_ASSERT_RETURN(fExtensions.state != nullptr, 0); | |||
CARLA_SAFE_ASSERT_RETURN(dataPtr != nullptr, 0); | |||
*dataPtr = nullptr; | |||
// TODO | |||
std::free(fLastChunk); | |||
return 0; | |||
clap_ostream_impl stream; | |||
if (fExtensions.state->save(fPlugin, &stream)) | |||
{ | |||
*dataPtr = fLastChunk = stream.buffer; | |||
return stream.size; | |||
} | |||
else | |||
{ | |||
*dataPtr = fLastChunk = nullptr; | |||
return 0; | |||
} | |||
} | |||
// ------------------------------------------------------------------- | |||
@@ -877,9 +902,9 @@ public: | |||
CARLA_SAFE_ASSERT_RETURN(data != nullptr,); | |||
CARLA_SAFE_ASSERT_RETURN(dataSize > 0,); | |||
// TODO | |||
pData->updateParameterValues(this, true, true, false); | |||
const clap_istream_impl stream(data, dataSize); | |||
if (fExtensions.state->load(fPlugin, &stream)) | |||
pData->updateParameterValues(this, true, true, false); | |||
} | |||
// ------------------------------------------------------------------- | |||
@@ -1048,7 +1073,10 @@ public: | |||
HostTimerDetails& timer(it.getValue(kTimerFallbackNC)); | |||
if (currentTimeInMs > timer.lastCallTimeInMs + timer.periodInMs) | |||
{ | |||
timer.lastCallTimeInMs = currentTimeInMs; | |||
fExtensions.timer->on_timer(fPlugin, timer.clapId); | |||
} | |||
} | |||
CarlaPlugin::uiIdle(); | |||
@@ -1363,7 +1391,7 @@ public: | |||
continue; | |||
pData->param.data[j].index = j; | |||
pData->param.data[j].rindex = paramInfo.id; | |||
pData->param.data[j].rindex = static_cast<int32_t>(paramInfo.id); | |||
double min, max, def, step, stepSmall, stepLarge; | |||
@@ -2189,7 +2217,7 @@ public: | |||
case CLAP_EVENT_PARAM_VALUE: | |||
for (uint32_t j=0; j<pData->param.count; ++j) | |||
{ | |||
if (pData->param.data[j].rindex != ev.param.param_id) | |||
if (pData->param.data[j].rindex != static_cast<int32_t>(ev.param.param_id)) | |||
continue; | |||
pData->postponeParameterChangeRtEvent(true, static_cast<int32_t>(j), ev.param.value); | |||
break; | |||
@@ -2328,6 +2356,12 @@ protected: | |||
// ------------------------------------------------------------------- | |||
void clapMarkDirty() override | |||
{ | |||
} | |||
// ------------------------------------------------------------------- | |||
#ifdef CLAP_WINDOW_API_NATIVE | |||
void clapGuiResizeHintsChanged() override | |||
{ | |||
@@ -2431,12 +2465,6 @@ public: | |||
return false; | |||
} | |||
if (id == nullptr || id[0] == '\0') | |||
{ | |||
pData->engine->setLastError("null label/id"); | |||
return false; | |||
} | |||
// --------------------------------------------------------------- | |||
const clap_plugin_entry_t* entry; | |||
@@ -2512,16 +2540,36 @@ public: | |||
if (const uint32_t count = factory->get_plugin_count(factory)) | |||
{ | |||
for (uint32_t i=0; i<count; ++i) | |||
// null id requested, use first available plugin | |||
if (id == nullptr || id[0] == '\0') | |||
{ | |||
const clap_plugin_descriptor_t* const desc = factory->get_plugin_descriptor(factory, i); | |||
CARLA_SAFE_ASSERT_CONTINUE(desc != nullptr); | |||
CARLA_SAFE_ASSERT_CONTINUE(desc->id != nullptr); | |||
fPluginDescriptor = factory->get_plugin_descriptor(factory, 0); | |||
if (std::strcmp(desc->id, id) == 0) | |||
if (fPluginDescriptor == nullptr) | |||
{ | |||
fPluginDescriptor = desc; | |||
break; | |||
pData->engine->setLastError("Plugin library does not contain a valid first plugin"); | |||
return false; | |||
} | |||
} | |||
else | |||
{ | |||
for (uint32_t i=0; i<count; ++i) | |||
{ | |||
const clap_plugin_descriptor_t* const desc = factory->get_plugin_descriptor(factory, i); | |||
CARLA_SAFE_ASSERT_CONTINUE(desc != nullptr); | |||
CARLA_SAFE_ASSERT_CONTINUE(desc->id != nullptr); | |||
if (std::strcmp(desc->id, id) == 0) | |||
{ | |||
fPluginDescriptor = desc; | |||
break; | |||
} | |||
} | |||
if (fPluginDescriptor == nullptr) | |||
{ | |||
pData->engine->setLastError("Plugin library does not contain the requested plugin"); | |||
return false; | |||
} | |||
} | |||
} | |||
@@ -2531,12 +2579,6 @@ public: | |||
return false; | |||
} | |||
if (fPluginDescriptor == nullptr) | |||
{ | |||
pData->engine->setLastError("Plugin library does not contain the requested plugin"); | |||
return false; | |||
} | |||
// --------------------------------------------------------------- | |||
fPlugin = factory->create_plugin(factory, &fHost, fPluginDescriptor->id); | |||
@@ -2679,6 +2721,7 @@ private: | |||
#ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||
float** fAudioOutBuffers; | |||
#endif | |||
void* fLastChunk; | |||
#ifdef CARLA_OS_MAC | |||
BundleLoader fBundleLoader; | |||
@@ -148,7 +148,6 @@ bool clapFeaturesContainInstrument(const char* const* const features) noexcept | |||
if (features == nullptr) | |||
return false; | |||
// 1st pass for main categories | |||
for (uint32_t i=0; features[i] != nullptr; ++i) | |||
{ | |||
if (std::strcmp(features[i], CLAP_PLUGIN_FEATURE_INSTRUMENT) == 0) | |||
@@ -160,6 +159,72 @@ bool clapFeaturesContainInstrument(const char* const* const features) noexcept | |||
// -------------------------------------------------------------------------------------------------------------------- | |||
struct clap_istream_impl : clap_istream_t { | |||
const void* buffer; | |||
const uint64_t size; | |||
uint64_t readPos; | |||
clap_istream_impl(const void* const buf, const uint64_t bufsize) noexcept | |||
: buffer(buf), | |||
size(bufsize), | |||
readPos(0) | |||
{ | |||
ctx = this; | |||
read = read_impl; | |||
} | |||
static int64_t read_impl(const clap_istream_t* const stream, void* const buffer, const uint64_t size) noexcept | |||
{ | |||
clap_istream_impl* const self = static_cast<clap_istream_impl*>(stream->ctx); | |||
if (const uint64_t bytesRead = std::min(self->size - self->readPos, size)) | |||
{ | |||
std::memcpy(buffer, static_cast<const uint8_t*>(self->buffer) + self->readPos, bytesRead); | |||
self->readPos += bytesRead; | |||
return bytesRead; | |||
} | |||
return 0; | |||
} | |||
}; | |||
// -------------------------------------------------------------------------------------------------------------------- | |||
struct clap_ostream_impl : clap_ostream_t { | |||
void* buffer; | |||
uint64_t size; | |||
clap_ostream_impl() noexcept | |||
: buffer(nullptr), | |||
size(0) | |||
{ | |||
ctx = this; | |||
write = write_impl; | |||
} | |||
static int64_t write_impl(const clap_ostream* const stream, const void* const buffer, const uint64_t size) noexcept | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(size != 0, 0); | |||
clap_ostream_impl* const self = static_cast<clap_ostream_impl*>(stream->ctx); | |||
void* const oldBuffer = self->buffer; | |||
self->buffer = std::realloc(self->buffer, self->size + size); | |||
if (self->buffer == nullptr) | |||
{ | |||
std::free(oldBuffer); | |||
return -1; | |||
} | |||
std::memcpy(static_cast<uint8_t*>(self->buffer) + self->size, buffer, size); | |||
self->size += size; | |||
return size; | |||
} | |||
}; | |||
// -------------------------------------------------------------------------------------------------------------------- | |||
CARLA_BACKEND_END_NAMESPACE | |||
#endif // CARLA_CLAP_UTILS_HPP_INCLUDED |
@@ -429,7 +429,7 @@ bool CarlaStateSave::fillFromXmlElement(const XmlElement* const xmlElement) | |||
{ | |||
stateParameter->name = xmlSafeStringCharDup(pText, false); | |||
} | |||
else if (pTag == "Symbol") | |||
else if (pTag == "Symbol" || pTag == "Identifier") | |||
{ | |||
stateParameter->symbol = xmlSafeStringCharDup(pText, false); | |||
} | |||
@@ -559,6 +559,8 @@ bool CarlaStateSave::fillFromXmlElement(const XmlElement* const xmlElement) | |||
void CarlaStateSave::dumpToMemoryStream(MemoryOutputStream& content) const | |||
{ | |||
const PluginType pluginType = getPluginTypeFromString(type); | |||
{ | |||
MemoryOutputStream infoXml; | |||
@@ -566,7 +568,7 @@ void CarlaStateSave::dumpToMemoryStream(MemoryOutputStream& content) const | |||
infoXml << " <Type>" << String(type != nullptr ? type : "") << "</Type>\n"; | |||
infoXml << " <Name>" << xmlSafeString(name, true) << "</Name>\n"; | |||
switch (getPluginTypeFromString(type)) | |||
switch (pluginType) | |||
{ | |||
case PLUGIN_NONE: | |||
break; | |||
@@ -666,7 +668,12 @@ void CarlaStateSave::dumpToMemoryStream(MemoryOutputStream& content) const | |||
parameterXml << " <Name>" << xmlSafeString(stateParameter->name, true) << "</Name>\n"; | |||
if (stateParameter->symbol != nullptr && stateParameter->symbol[0] != '\0') | |||
parameterXml << " <Symbol>" << xmlSafeString(stateParameter->symbol, true) << "</Symbol>\n"; | |||
{ | |||
if (pluginType == PLUGIN_CLAP) | |||
parameterXml << " <Identifier>" << xmlSafeString(stateParameter->symbol, true) << "</Identifier>\n"; | |||
else | |||
parameterXml << " <Symbol>" << xmlSafeString(stateParameter->symbol, true) << "</Symbol>\n"; | |||
} | |||
#ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||
if (stateParameter->mappedControlIndex > CONTROL_INDEX_NONE && stateParameter->mappedControlIndex <= CONTROL_INDEX_MAX_ALLOWED) | |||