Signed-off-by: falkTX <falktx@falktx.com>tags/v2.1-rc1
| @@ -59,8 +59,10 @@ struct PluginListManager { | |||||
| std::strcmp(desc->label, "carlapatchbay3s" ) == 0 || | std::strcmp(desc->label, "carlapatchbay3s" ) == 0 || | ||||
| std::strcmp(desc->label, "carlapatchbay16" ) == 0 || | std::strcmp(desc->label, "carlapatchbay16" ) == 0 || | ||||
| std::strcmp(desc->label, "carlapatchbay32" ) == 0 || | std::strcmp(desc->label, "carlapatchbay32" ) == 0 || | ||||
| std::strcmp(desc->label, "bigmeter" ) == 0 /*|| | |||||
| std::strcmp(desc->label, "notes" ) == 0*/) | |||||
| std::strcmp(desc->label, "bigmeter" ) == 0 || | |||||
| /*std::strcmp(desc->label, "notes" ) == 0*/ | |||||
| std::strcmp(desc->label, "audiofile" ) == 0 || | |||||
| std::strcmp(desc->label, "midifile" ) == 0) | |||||
| { | { | ||||
| descs.append(desc); | descs.append(desc); | ||||
| } | } | ||||
| @@ -24,6 +24,7 @@ | |||||
| #include "lv2/midi.h" | #include "lv2/midi.h" | ||||
| #include "lv2/options.h" | #include "lv2/options.h" | ||||
| #include "lv2/parameters.h" | #include "lv2/parameters.h" | ||||
| #include "lv2/patch.h" | |||||
| #include "lv2/port-props.h" | #include "lv2/port-props.h" | ||||
| #include "lv2/state.h" | #include "lv2/state.h" | ||||
| #include "lv2/time.h" | #include "lv2/time.h" | ||||
| @@ -111,6 +112,7 @@ static void writeManifestFile(PluginListManager& plm) | |||||
| // ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
| // Header | // Header | ||||
| text += "@prefix atom: <" LV2_ATOM_PREFIX "> .\n"; | |||||
| text += "@prefix lv2: <" LV2_CORE_PREFIX "> .\n"; | text += "@prefix lv2: <" LV2_CORE_PREFIX "> .\n"; | ||||
| text += "@prefix opts: <" LV2_OPTIONS_PREFIX "> .\n"; | text += "@prefix opts: <" LV2_OPTIONS_PREFIX "> .\n"; | ||||
| text += "@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n"; | text += "@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n"; | ||||
| @@ -158,6 +160,15 @@ static void writeManifestFile(PluginListManager& plm) | |||||
| # endif | # endif | ||||
| #endif | #endif | ||||
| // ------------------------------------------------------------------- | |||||
| // File handling | |||||
| text += "<http://kxstudio.sf.net/carla/file>\n"; | |||||
| text += " a lv2:Parameter ;\n"; | |||||
| text += " rdfs:label \"file\" ;\n"; | |||||
| text += " rdfs:range atom:Path .\n"; | |||||
| text += "\n"; | |||||
| // ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
| // Write file now | // Write file now | ||||
| @@ -216,15 +227,16 @@ static void writePluginFile(const NativePluginDescriptor* const pluginDesc) | |||||
| // ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
| // Header | // Header | ||||
| text += "@prefix atom: <" LV2_ATOM_PREFIX "> .\n"; | |||||
| text += "@prefix doap: <http://usefulinc.com/ns/doap#> .\n"; | |||||
| text += "@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n"; | |||||
| text += "@prefix lv2: <" LV2_CORE_PREFIX "> .\n"; | |||||
| text += "@prefix opts: <" LV2_OPTIONS_PREFIX "> .\n"; | |||||
| text += "@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .\n"; | |||||
| text += "@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n"; | |||||
| text += "@prefix ui: <" LV2_UI_PREFIX "> .\n"; | |||||
| text += "@prefix unit: <" LV2_UNITS_PREFIX "> .\n"; | |||||
| text += "@prefix atom: <" LV2_ATOM_PREFIX "> .\n"; | |||||
| text += "@prefix doap: <http://usefulinc.com/ns/doap#> .\n"; | |||||
| text += "@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n"; | |||||
| text += "@prefix lv2: <" LV2_CORE_PREFIX "> .\n"; | |||||
| text += "@prefix opts: <" LV2_OPTIONS_PREFIX "> .\n"; | |||||
| text += "@prefix patch: <" LV2_PATCH_PREFIX "> .\n"; | |||||
| text += "@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .\n"; | |||||
| text += "@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n"; | |||||
| text += "@prefix ui: <" LV2_UI_PREFIX "> .\n"; | |||||
| text += "@prefix unit: <" LV2_UNITS_PREFIX "> .\n"; | |||||
| text += "\n"; | text += "\n"; | ||||
| // ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
| @@ -287,7 +299,7 @@ static void writePluginFile(const NativePluginDescriptor* const pluginDesc) | |||||
| text += " lv2:extensionData <" LV2_OPTIONS__interface "> ;\n"; | text += " lv2:extensionData <" LV2_OPTIONS__interface "> ;\n"; | ||||
| if (pluginDesc->hints & NATIVE_PLUGIN_USES_STATE) | |||||
| if ((pluginDesc->hints & NATIVE_PLUGIN_USES_STATE) || (pluginDesc->hints & NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE)) | |||||
| text += " lv2:extensionData <" LV2_STATE__interface "> ;\n"; | text += " lv2:extensionData <" LV2_STATE__interface "> ;\n"; | ||||
| if (pluginDesc->category != NATIVE_PLUGIN_CATEGORY_SYNTH) | if (pluginDesc->category != NATIVE_PLUGIN_CATEGORY_SYNTH) | ||||
| @@ -310,7 +322,7 @@ static void writePluginFile(const NativePluginDescriptor* const pluginDesc) | |||||
| // UIs | // UIs | ||||
| #ifdef HAVE_PYQT | #ifdef HAVE_PYQT | ||||
| if (pluginDesc->hints & NATIVE_PLUGIN_HAS_UI) | |||||
| if ((pluginDesc->hints & NATIVE_PLUGIN_HAS_UI) != 0 && (pluginDesc->hints & NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE) == 0) | |||||
| { | { | ||||
| text += " ui:ui <http://kxstudio.sf.net/carla/ui-ext> ;\n"; | text += " ui:ui <http://kxstudio.sf.net/carla/ui-ext> ;\n"; | ||||
| text += "\n"; | text += "\n"; | ||||
| @@ -320,7 +332,8 @@ static void writePluginFile(const NativePluginDescriptor* const pluginDesc) | |||||
| // ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
| // First input MIDI/Time/UI port | // First input MIDI/Time/UI port | ||||
| const bool hasEventInPort = (pluginDesc->hints & NATIVE_PLUGIN_USES_TIME) != 0 || (pluginDesc->hints & NATIVE_PLUGIN_HAS_UI) != 0; | |||||
| const bool hasEventInPort = (pluginDesc->hints & NATIVE_PLUGIN_USES_TIME) != 0 | |||||
| || (pluginDesc->hints & NATIVE_PLUGIN_HAS_UI) != 0; | |||||
| if (pluginDesc->midiIns > 0 || hasEventInPort) | if (pluginDesc->midiIns > 0 || hasEventInPort) | ||||
| { | { | ||||
| @@ -375,6 +388,9 @@ static void writePluginFile(const NativePluginDescriptor* const pluginDesc) | |||||
| text += " ] ;\n\n"; | text += " ] ;\n\n"; | ||||
| } | } | ||||
| if (pluginDesc->hints & NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE) | |||||
| text += " patch:writable <http://kxstudio.sf.net/carla/file> ;\n\n"; | |||||
| // ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
| // MIDI inputs | // MIDI inputs | ||||
| @@ -71,6 +71,7 @@ public: | |||||
| #ifdef USING_JUCE | #ifdef USING_JUCE | ||||
| fJuceInitialiser(), | fJuceInitialiser(), | ||||
| #endif | #endif | ||||
| fLoadedFile(), | |||||
| fWorkerUISignal(0) | fWorkerUISignal(0) | ||||
| { | { | ||||
| carla_zeroStruct(fHost); | carla_zeroStruct(fHost); | ||||
| @@ -244,6 +245,8 @@ public: | |||||
| if (event->body.type == fURIs.uiEvents && fWorkerUISignal != -1) | if (event->body.type == fURIs.uiEvents && fWorkerUISignal != -1) | ||||
| { | { | ||||
| CARLA_SAFE_ASSERT_CONTINUE((fDescriptor->hints & NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE) == 0); | |||||
| if (fWorker != nullptr) | if (fWorker != nullptr) | ||||
| { | { | ||||
| // worker is supported by the host, we can continue | // worker is supported by the host, we can continue | ||||
| @@ -260,6 +263,34 @@ public: | |||||
| continue; | continue; | ||||
| } | } | ||||
| if (event->body.type == fURIs.atomObject) | |||||
| { | |||||
| const LV2_Atom_Object* const obj = (const LV2_Atom_Object*)(&event->body); | |||||
| if (obj->body.otype == fURIs.patchSet) { | |||||
| // Get property URI. | |||||
| const LV2_Atom* property = NULL; | |||||
| lv2_atom_object_get(obj, fURIs.patchProperty, &property, 0); | |||||
| CARLA_SAFE_ASSERT_CONTINUE(property != nullptr); | |||||
| CARLA_SAFE_ASSERT_CONTINUE(property->type == fURIs.atomURID); | |||||
| CARLA_SAFE_ASSERT_CONTINUE(((const LV2_Atom_URID*)property)->body == fURIs.carlaFile); | |||||
| // Get value. | |||||
| const LV2_Atom* fileobj = NULL; | |||||
| lv2_atom_object_get(obj, fURIs.patchValue, &fileobj, 0); | |||||
| CARLA_SAFE_ASSERT_CONTINUE(fileobj != nullptr); | |||||
| CARLA_SAFE_ASSERT_CONTINUE(fileobj->type == fURIs.atomPath); | |||||
| const char* const filepath((const char*)(fileobj + 1)); | |||||
| fWorker->schedule_work(fWorker->handle, | |||||
| static_cast<uint32_t>(std::strlen(filepath) + 1U), | |||||
| filepath); | |||||
| } | |||||
| continue; | |||||
| } | |||||
| if (event->body.type != fURIs.midiEvent) | if (event->body.type != fURIs.midiEvent) | ||||
| continue; | continue; | ||||
| if (event->body.size > 4) | if (event->body.size > 4) | ||||
| @@ -366,6 +397,17 @@ public: | |||||
| LV2_State_Status lv2_save(const LV2_State_Store_Function store, const LV2_State_Handle handle, | LV2_State_Status lv2_save(const LV2_State_Store_Function store, const LV2_State_Handle handle, | ||||
| const uint32_t /*flags*/, const LV2_Feature* const* const /*features*/) const | const uint32_t /*flags*/, const LV2_Feature* const* const /*features*/) const | ||||
| { | { | ||||
| if (fDescriptor->hints & NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE) | |||||
| { | |||||
| store(handle, | |||||
| fUridMap->map(fUridMap->handle, "http://kxstudio.sf.net/ns/carla/file"), | |||||
| fLoadedFile.buffer(), | |||||
| fLoadedFile.length()+1, | |||||
| fURIs.atomPath, | |||||
| LV2_STATE_IS_POD); | |||||
| return LV2_STATE_SUCCESS; | |||||
| } | |||||
| if ((fDescriptor->hints & NATIVE_PLUGIN_USES_STATE) == 0 || fDescriptor->get_state == nullptr) | if ((fDescriptor->hints & NATIVE_PLUGIN_USES_STATE) == 0 || fDescriptor->get_state == nullptr) | ||||
| return LV2_STATE_ERR_NO_FEATURE; | return LV2_STATE_ERR_NO_FEATURE; | ||||
| @@ -380,13 +422,31 @@ public: | |||||
| } | } | ||||
| LV2_State_Status lv2_restore(const LV2_State_Retrieve_Function retrieve, const LV2_State_Handle handle, | LV2_State_Status lv2_restore(const LV2_State_Retrieve_Function retrieve, const LV2_State_Handle handle, | ||||
| uint32_t flags, const LV2_Feature* const* const /*features*/) const | |||||
| uint32_t flags, const LV2_Feature* const* const /*features*/) | |||||
| { | { | ||||
| size_t size = 0; | |||||
| uint32_t type = 0; | |||||
| if (fDescriptor->hints & NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE) | |||||
| { | |||||
| size = type = 0; | |||||
| const void* const data = retrieve(handle, | |||||
| fUridMap->map(fUridMap->handle, "http://kxstudio.sf.net/ns/carla/file"), | |||||
| &size, &type, &flags); | |||||
| CARLA_SAFE_ASSERT_RETURN(type == fURIs.atomPath, LV2_STATE_ERR_UNKNOWN); | |||||
| const char* const filename = (const char*)data; | |||||
| fLoadedFile = filename; | |||||
| fDescriptor->set_custom_data(fHandle, "file", filename); | |||||
| return LV2_STATE_SUCCESS; | |||||
| } | |||||
| if ((fDescriptor->hints & NATIVE_PLUGIN_USES_STATE) == 0 || fDescriptor->set_state == nullptr) | if ((fDescriptor->hints & NATIVE_PLUGIN_USES_STATE) == 0 || fDescriptor->set_state == nullptr) | ||||
| return LV2_STATE_ERR_NO_FEATURE; | return LV2_STATE_ERR_NO_FEATURE; | ||||
| size_t size = 0; | |||||
| uint32_t type = 0; | |||||
| size = type = 0; | |||||
| const void* const data = retrieve(handle, fUridMap->map(fUridMap->handle, "http://kxstudio.sf.net/ns/carla/chunk"), &size, &type, &flags); | const void* const data = retrieve(handle, fUridMap->map(fUridMap->handle, "http://kxstudio.sf.net/ns/carla/chunk"), &size, &type, &flags); | ||||
| if (size == 0) | if (size == 0) | ||||
| @@ -409,6 +469,13 @@ public: | |||||
| { | { | ||||
| const char* const msg = (const char*)data; | const char* const msg = (const char*)data; | ||||
| if (fDescriptor->hints & NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE) | |||||
| { | |||||
| fLoadedFile = msg; | |||||
| fDescriptor->set_custom_data(fHandle, "file", msg); | |||||
| return LV2_WORKER_SUCCESS; | |||||
| } | |||||
| /**/ if (std::strncmp(msg, "control ", 8) == 0) | /**/ if (std::strncmp(msg, "control ", 8) == 0) | ||||
| { | { | ||||
| if (fDescriptor->ui_set_parameter_value == nullptr) | if (fDescriptor->ui_set_parameter_value == nullptr) | ||||
| @@ -767,6 +834,7 @@ private: | |||||
| juce::SharedResourcePointer<juce::ScopedJuceInitialiser_GUI> fJuceInitialiser; | juce::SharedResourcePointer<juce::ScopedJuceInitialiser_GUI> fJuceInitialiser; | ||||
| #endif | #endif | ||||
| CarlaString fLoadedFile; | |||||
| int fWorkerUISignal; | int fWorkerUISignal; | ||||
| // ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
| @@ -569,6 +569,7 @@ public: | |||||
| fBufferSize(0), | fBufferSize(0), | ||||
| fSampleRate(sampleRate), | fSampleRate(sampleRate), | ||||
| fUridMap(nullptr), | fUridMap(nullptr), | ||||
| fUridUnmap(nullptr), | |||||
| fWorker(nullptr), | fWorker(nullptr), | ||||
| fTimeInfo(), | fTimeInfo(), | ||||
| fLastPositionData(), | fLastPositionData(), | ||||
| @@ -660,6 +661,7 @@ public: | |||||
| fUridMap = uridMap; | fUridMap = uridMap; | ||||
| fURIs.map(uridMap); | fURIs.map(uridMap); | ||||
| fUridUnmap = uridUnmap; | |||||
| fWorker = worker; | fWorker = worker; | ||||
| clearTimeData(); | clearTimeData(); | ||||
| @@ -1175,6 +1177,7 @@ protected: | |||||
| // LV2 host features | // LV2 host features | ||||
| const LV2_URID_Map* fUridMap; | const LV2_URID_Map* fUridMap; | ||||
| const LV2_URID_Unmap* fUridUnmap; | |||||
| const LV2_Worker_Schedule* fWorker; | const LV2_Worker_Schedule* fWorker; | ||||
| // Time info stuff | // Time info stuff | ||||
| @@ -1475,9 +1478,15 @@ protected: | |||||
| LV2_URID atomFloat; | LV2_URID atomFloat; | ||||
| LV2_URID atomInt; | LV2_URID atomInt; | ||||
| LV2_URID atomLong; | LV2_URID atomLong; | ||||
| LV2_URID atomPath; | |||||
| LV2_URID atomSequence; | LV2_URID atomSequence; | ||||
| LV2_URID atomString; | LV2_URID atomString; | ||||
| LV2_URID atomURID; | |||||
| LV2_URID carlaFile; | |||||
| LV2_URID midiEvent; | LV2_URID midiEvent; | ||||
| LV2_URID patchProperty; | |||||
| LV2_URID patchSet; | |||||
| LV2_URID patchValue; | |||||
| LV2_URID timePos; | LV2_URID timePos; | ||||
| LV2_URID timeBar; | LV2_URID timeBar; | ||||
| LV2_URID timeBarBeat; | LV2_URID timeBarBeat; | ||||
| @@ -1496,9 +1505,15 @@ protected: | |||||
| atomFloat(0), | atomFloat(0), | ||||
| atomInt(0), | atomInt(0), | ||||
| atomLong(0), | atomLong(0), | ||||
| atomPath(0), | |||||
| atomSequence(0), | atomSequence(0), | ||||
| atomString(0), | atomString(0), | ||||
| atomURID(0), | |||||
| carlaFile(0), | |||||
| midiEvent(0), | midiEvent(0), | ||||
| patchProperty(0), | |||||
| patchSet(0), | |||||
| patchValue(0), | |||||
| timePos(0), | timePos(0), | ||||
| timeBar(0), | timeBar(0), | ||||
| timeBarBeat(0), | timeBarBeat(0), | ||||
| @@ -1518,9 +1533,15 @@ protected: | |||||
| atomFloat = uridMap->map(uridMap->handle, LV2_ATOM__Float); | atomFloat = uridMap->map(uridMap->handle, LV2_ATOM__Float); | ||||
| atomInt = uridMap->map(uridMap->handle, LV2_ATOM__Int); | atomInt = uridMap->map(uridMap->handle, LV2_ATOM__Int); | ||||
| atomLong = uridMap->map(uridMap->handle, LV2_ATOM__Long); | atomLong = uridMap->map(uridMap->handle, LV2_ATOM__Long); | ||||
| atomPath = uridMap->map(uridMap->handle, LV2_ATOM__Path); | |||||
| atomSequence = uridMap->map(uridMap->handle, LV2_ATOM__Sequence); | atomSequence = uridMap->map(uridMap->handle, LV2_ATOM__Sequence); | ||||
| atomString = uridMap->map(uridMap->handle, LV2_ATOM__String); | atomString = uridMap->map(uridMap->handle, LV2_ATOM__String); | ||||
| atomURID = uridMap->map(uridMap->handle, LV2_ATOM__URID); | |||||
| carlaFile = uridMap->map(uridMap->handle, "http://kxstudio.sf.net/carla/file"); | |||||
| midiEvent = uridMap->map(uridMap->handle, LV2_MIDI__MidiEvent); | midiEvent = uridMap->map(uridMap->handle, LV2_MIDI__MidiEvent); | ||||
| patchProperty = uridMap->map(uridMap->handle, LV2_PATCH__property); | |||||
| patchSet = uridMap->map(uridMap->handle, LV2_PATCH__Set); | |||||
| patchValue = uridMap->map(uridMap->handle, LV2_PATCH__value); | |||||
| timePos = uridMap->map(uridMap->handle, LV2_TIME__Position); | timePos = uridMap->map(uridMap->handle, LV2_TIME__Position); | ||||
| timeBar = uridMap->map(uridMap->handle, LV2_TIME__bar); | timeBar = uridMap->map(uridMap->handle, LV2_TIME__bar); | ||||
| timeBarBeat = uridMap->map(uridMap->handle, LV2_TIME__barBeat); | timeBarBeat = uridMap->map(uridMap->handle, LV2_TIME__barBeat); | ||||