From d60cc42e2febaf61a9358b22df5599dab3db3df6 Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Sat, 21 Nov 2020 19:31:35 -0300 Subject: [PATCH] Some LV2 work, does not work, may never do because it sucks. --- bin/zytrax.cpp | 9 +- drivers/lv2/audio_effect_lv2.cpp | 12 +-- drivers/lv2/audio_effect_lv2.h | 3 + drivers/lv2/audio_effect_provider_lv2.h | 4 +- drivers/lv2/effect_editor_lv2.cpp | 138 ++++++++++++++++++++++++ drivers/lv2/effect_editor_lv2.h | 32 ++++++ 6 files changed, 190 insertions(+), 8 deletions(-) create mode 100644 drivers/lv2/effect_editor_lv2.cpp create mode 100644 drivers/lv2/effect_editor_lv2.h diff --git a/bin/zytrax.cpp b/bin/zytrax.cpp index 705fa44..6b87fec 100644 --- a/bin/zytrax.cpp +++ b/bin/zytrax.cpp @@ -6,6 +6,7 @@ #ifdef LV2_ENABLED #include "drivers/lv2/audio_effect_provider_lv2.h" +#include "drivers/lv2/effect_editor_lv2.h" #endif #include "effects/effects.h" @@ -34,6 +35,7 @@ int main(int argc, char *argv[]) { #ifdef LV2_ENABLED AudioEffectProviderLV2 provider_lv2(&argc, &argv); effect_factory.add_provider(&provider_lv2); + EffectEditorLV2::initialize_lv2_editor(); #endif printf("three\n"); #ifdef RTAUDIO_ENABLED @@ -243,6 +245,9 @@ int main(int argc, char *argv[]) { window.set_default_size(1280, 720); #ifdef VST2_ENABLED window.add_editor_plugin_function(get_vst2_editor_function()); +#endif +#ifdef LV2_ENABLED + window.add_editor_plugin_function(get_lv2_editor_function()); #endif int ret = app->run(window); @@ -257,6 +262,8 @@ int main(int argc, char *argv[]) { #ifdef RTAUDIO_ENABLED cleanup_rtaudio_driver(); #endif - +#ifdef LV2_ENABLED + EffectEditorLV2::finalize_lv2_editor(); +#endif return ret; } diff --git a/drivers/lv2/audio_effect_lv2.cpp b/drivers/lv2/audio_effect_lv2.cpp index 0dfb0fc..5769aa9 100644 --- a/drivers/lv2/audio_effect_lv2.cpp +++ b/drivers/lv2/audio_effect_lv2.cpp @@ -337,13 +337,13 @@ void AudioEffectLV2::_plugin_init() { { LV2_BUF_SIZE__boundedBlockLength, NULL } }; - const LV2_Feature *features[12] = { + const LV2_Feature *features[] = { &uri_map_feature, &map_feature, &unmap_feature, - &sched_feature, - &log_feature, - &options_feature, - &def_state_feature, - &safe_restore_feature, + //&sched_feature, + //&log_feature, + //&options_feature, + //&def_state_feature, + //&safe_restore_feature, &buf_size_features[0], &buf_size_features[1], &buf_size_features[2], diff --git a/drivers/lv2/audio_effect_lv2.h b/drivers/lv2/audio_effect_lv2.h index 874ec39..1c54b00 100644 --- a/drivers/lv2/audio_effect_lv2.h +++ b/drivers/lv2/audio_effect_lv2.h @@ -180,6 +180,9 @@ class AudioEffectLV2 : public AudioEffectMIDI { virtual JSON::Node _internal_to_json() const; virtual Error _internal_from_json(const JSON::Node &node); + LilvInstance *get_instance() { return instance; } + const LilvPlugin *get_plugin() { return plugin; } + Error setup(const LilvPlugin *p_plugin, bool p_has_ui); AudioEffectLV2(); diff --git a/drivers/lv2/audio_effect_provider_lv2.h b/drivers/lv2/audio_effect_provider_lv2.h index 35654d6..631e9cd 100644 --- a/drivers/lv2/audio_effect_provider_lv2.h +++ b/drivers/lv2/audio_effect_provider_lv2.h @@ -165,12 +165,14 @@ class AudioEffectProviderLV2 : public AudioEffectProvider { static AudioEffect *create_effects(const AudioEffectInfo *p_info); //static uint32_t uri_to_id(LV2_URI_Map_Callback_Data callback_data, const char *map, const char *uri); friend class AudioEffectLV2; - static AudioEffectProviderLV2 *singleton; const LilvPlugins *plugins; public: + static AudioEffectProviderLV2 *singleton; + static const URIS &get_uris() { return uris; } + static LilvWorld *get_world() { return singleton->world; } virtual AudioEffect *instantiate_effect(const AudioEffectInfo *p_info); virtual void scan_effects(AudioEffectFactory *p_factory, ScanCallback p_callback, void *p_userdata); virtual String get_id() const; diff --git a/drivers/lv2/effect_editor_lv2.cpp b/drivers/lv2/effect_editor_lv2.cpp new file mode 100644 index 0000000..914d463 --- /dev/null +++ b/drivers/lv2/effect_editor_lv2.cpp @@ -0,0 +1,138 @@ +#include "effect_editor_lv2.h" +#include "audio_effect_provider_lv2.h" + +#define UI_TYPE "http://lv2plug.in/ns/extensions/ui#Gtk3UI" + +static LV2_URI_Map_Feature uri_map = { NULL, &AudioEffectLV2::uri_to_id }; + +static LV2_Extension_Data_Feature ext_data = { NULL }; + +static LV2_Feature uri_map_feature = { NS_EXT "uri-map", NULL }; +static LV2_Feature map_feature = { LV2_URID__map, NULL }; +static LV2_Feature unmap_feature = { LV2_URID__unmap, NULL }; +static LV2_Feature make_path_feature = { LV2_STATE__makePath, NULL }; +static LV2_Feature sched_feature = { LV2_WORKER__schedule, NULL }; +static LV2_Feature state_sched_feature = { LV2_WORKER__schedule, NULL }; +static LV2_Feature safe_restore_feature = { LV2_STATE__threadSafeRestore, NULL }; +static LV2_Feature log_feature = { LV2_LOG__log, NULL }; +static LV2_Feature options_feature = { LV2_OPTIONS__options, NULL }; +static LV2_Feature def_state_feature = { LV2_STATE__loadDefaultState, NULL }; + +bool EffectEditorLV2::initialize() { + return false; +} + +void EffectEditorLV2::_port_write_func(void *ud, uint32_t port_index, uint32_t buffer_size, uint32_t protocol, void const *buffer) { +} +uint32_t EffectEditorLV2::_port_index_func(void *ud, const char *port_symbol) { + return 0; +} + +SuilHost *EffectEditorLV2::ui_host = nullptr; + +EffectEditorLV2::EffectEditorLV2(AudioEffectLV2 *p_lv2, EffectEditor *p_editor, const LilvUI *p_ui, const LilvNode *p_ui_type, const LilvNode *p_native_ui_type) : + effect_editor_midi(p_lv2, p_editor) { + + lv2_effect = p_lv2; + + pack_start(effect_editor_midi, Gtk::PACK_EXPAND_WIDGET); + + const LV2_Feature parent_feature = { + LV2_UI__parent, nullptr //? + }; + const LV2_Feature instance_feature = { + NS_EXT "instance-access", lilv_instance_get_handle(p_lv2->get_instance()) + }; + const LV2_Feature data_feature = { + LV2_DATA_ACCESS_URI, &ext_data + }; + const LV2_Feature idle_feature = { + LV2_UI__idleInterface, NULL + }; + const LV2_Feature *ui_features[] = { + &uri_map_feature, &map_feature, &unmap_feature, + &instance_feature, + &data_feature, + &log_feature, + &parent_feature, + &options_feature, + &idle_feature, + NULL + }; + + const char *bundle_uri = lilv_node_as_uri(lilv_ui_get_bundle_uri(p_ui)); + const char *binary_uri = lilv_node_as_uri(lilv_ui_get_binary_uri(p_ui)); + char *bundle_path = lilv_file_uri_parse(bundle_uri, NULL); + char *binary_path = lilv_file_uri_parse(binary_uri, NULL); + + ui_instance = suil_instance_new( + ui_host, + this, + UI_TYPE, + lilv_node_as_uri(lilv_plugin_get_uri(p_lv2->get_plugin())), + lilv_node_as_uri(lilv_ui_get_uri(p_ui)), + lilv_node_as_uri(p_ui_type), + bundle_path, + binary_path, + ui_features); + + lilv_free(binary_path); + lilv_free(bundle_path); + + GtkWidget *w = (GtkWidget *)suil_instance_get_widget( + ui_instance); + + widget = Glib::wrap(w); + + effect_editor_midi.prepend_page(*widget, "LV2 Plugin"); + + //need window to be mapped, so wait + init_timer = Glib::signal_timeout().connect(sigc::mem_fun(*this, &EffectEditorLV2::initialize), + 50, Glib::PRIORITY_DEFAULT); + + show_all_children(); +} + +EffectEditorLV2::~EffectEditorLV2() { + delete widget; +} + +void EffectEditorLV2::initialize_lv2_editor() { + + ui_host = suil_host_new(_port_write_func, _port_index_func, NULL, NULL); +} + +void EffectEditorLV2::finalize_lv2_editor() { + suil_host_free(ui_host); +} + +static Gtk::Widget *create_lv2_editor(AudioEffect *p_lv2, EffectEditor *p_editor) { + + if (p_lv2->get_provider_id() != AudioEffectProviderLV2::singleton->get_id()) { + return NULL; + } + + AudioEffectLV2 *effect = (AudioEffectLV2 *)p_lv2; + + const LilvNode *ui_type; + const LilvNode *native_ui_type = lilv_new_uri(AudioEffectProviderLV2::get_world(), UI_TYPE); + LilvUIs *supported_uis = lilv_plugin_get_uis(effect->get_plugin()); + const LilvUI *ui = nullptr; + LILV_FOREACH(uis, u, supported_uis) { + const LilvUI *ui = lilv_uis_get(supported_uis, u); + if (lilv_ui_is_supported(ui, + suil_ui_supported, + native_ui_type, + &ui_type)) { + break; + } + } + + ERR_FAIL_COND_V(ui == nullptr, nullptr); + + return new EffectEditorLV2(effect, p_editor, ui, ui_type, native_ui_type); +} + +EffectEditorPluginFunc get_lv2_editor_function() { + return &create_lv2_editor; +} diff --git a/drivers/lv2/effect_editor_lv2.h b/drivers/lv2/effect_editor_lv2.h new file mode 100644 index 0000000..ed9b119 --- /dev/null +++ b/drivers/lv2/effect_editor_lv2.h @@ -0,0 +1,32 @@ +#ifndef EFFECTEDITORLV2_H +#define EFFECTEDITORLV2_H + +#include "drivers/lv2/audio_effect_lv2.h" +#include "gui/effect_editor_midi.h" +#include "suil/suil.h" + +class EffectEditorLV2 : public Gtk::VBox { + + AudioEffectLV2 *lv2_effect; + Gtk::Widget *widget = nullptr; + EffectEditorMIDI effect_editor_midi; + + sigc::connection init_timer; + bool initialize(); + + static SuilHost *ui_host; + SuilInstance *ui_instance; + static void _port_write_func(void *ud, uint32_t port_index, uint32_t buffer_size, uint32_t protocol, void const *buffer); + static uint32_t _port_index_func(void *ud, const char *port_symbol); + +public: + static void initialize_lv2_editor(); + static void finalize_lv2_editor(); + + EffectEditorLV2(AudioEffectLV2 *p_vst, EffectEditor *p_editor, const LilvUI *p_ui, const LilvNode *p_ui_type, const LilvNode *p_native_ui_type); + ~EffectEditorLV2(); +}; + +EffectEditorPluginFunc get_lv2_editor_function(); + +#endif // EFFECTEDITORLV2_H