public inbox for cygwin-apps@cygwin.com
 help / color / mirror / Atom feed
* [ITA] calf
@ 2023-09-13 14:34 Takashi Yano
  2023-09-14 13:27 ` Jon Turney
  0 siblings, 1 reply; 2+ messages in thread
From: Takashi Yano @ 2023-09-13 14:34 UTC (permalink / raw)
  Cc: cygwin-apps

[-- Attachment #1: Type: text/plain, Size: 100 bytes --]

I'd like to adopt the package calf.
Thanks in advance.

-- 
Takashi Yano <takashi.yano@nifty.ne.jp>

[-- Attachment #2: add-LADSPA-DSSI.patch --]
[-- Type: text/plain, Size: 117662 bytes --]

--- origsrc/calf-0.90.3/configure.ac	2019-07-17 02:04:43.000000000 +0900
+++ src/calf-0.90.3/configure.ac	2023-09-13 08:07:51.862676200 +0900
@@ -19,9 +19,15 @@ AC_PROG_INSTALL
 
 ############################################################################################
 # Set initial values of shell variables
+LADSPA_ENABLED="yes"
+DSSI_ENABLED="no"
+EXEC_GUI_ENABLED="no"
+DSSI_GUI_ENABLED="no"
+LV2_GTK_GUI_ENABLED="no"
 LV2_GUI_ENABLED="no"
 JACK_FOUND="no"
 JACK_ENABLED="no"
+JACK_HAS_RENAME="no"
 OLD_JACK="no"
 GUI_ENABLED="no"
 LASH_ENABLED="no"
@@ -51,6 +57,10 @@ PKG_PROG_PKG_CONFIG
 AC_HEADER_STDC
 AC_CHECK_HEADERS([memory.h stdint.h stdlib.h string.h time.h math.h])
 
+AC_CHECK_HEADER(ladspa.h, LADSPA_FOUND="yes", LADSPA_FOUND="no")
+
+AC_CHECK_HEADER(dssi.h, DSSI_FOUND="yes", DSSI_FOUND="no")
+
 AC_CHECK_HEADER(expat.h, true, AC_MSG_ERROR([Expat XML library not found]))
 AC_CHECK_LIB(expat, XML_Parse, true, AC_MSG_ERROR([Expat XML library not found]))
 
@@ -106,6 +116,22 @@ fi
 
 ############################################################################################
 # Look for settings and installed libraries to determine what to compile/install/use
+if test "$LADSPA_FOUND" = "yes"; then
+  AC_MSG_CHECKING([whether to allow LADSPA])
+  AC_ARG_WITH(ladspa,
+    AC_HELP_STRING([--without-ladspa],[disable LADSPA and DSSI interfaces]),
+      [if test "$withval" = "no"; then LADSPA_ENABLED="no"; DSSI_ENABLED="no"; fi],[])
+  AC_MSG_RESULT($LADSPA_ENABLED)
+fi
+
+if test "$DSSI_FOUND" = "yes"; then
+  AC_MSG_CHECKING([whether to allow DSSI])
+  AC_ARG_WITH(dssi,
+    AC_HELP_STRING([--without-dssi],[disable DSSI interface]),
+      [if test "$withval" = "no"; then DSSI_ENABLED="no"; fi],[])
+  AC_MSG_RESULT($DSSI_ENABLED)
+fi
+
 if test "$LV2_FOUND" = "yes"; then
   AC_MSG_CHECKING([whether to allow LV2])
   AC_ARG_WITH(lv2,
@@ -136,6 +162,14 @@ AC_ARG_ENABLE(experimental,
   [set_enable_experimental="no"])
 AC_MSG_RESULT($set_enable_experimental)
 
+AC_MSG_CHECKING([whether to enable old-style in-process GTK+ GUI])
+AC_ARG_ENABLE(in-process-lv2-gui,
+  AC_HELP_STRING([--enable-in-process-lv2-gui],[enable old-style in-process GTK+ GUI - not recommended!]),
+  [set_enable_gtk_gui="$enableval"],
+  [set_enable_gtk_gui="no"])
+AC_MSG_RESULT($set_enable_gtk_gui)
+
+
 AC_MSG_CHECKING([whether to enable debugging mode])
 AC_ARG_ENABLE(debug,
   AC_HELP_STRING([--enable-debug],[enable debug mode - slow!]),
@@ -156,9 +190,19 @@ AC_MSG_RESULT($set_enable_sse)
 if test "$GUI_ENABLED" = "yes" -a "$JACK_FOUND" = "yes"; then
   JACK_ENABLED="yes"
 fi
+ 
+if test "$GUI_ENABLED" = "yes" -a "$DSSI_ENABLED" = "yes"; then
+  DSSI_GUI_ENABLED="yes"
+  EXEC_GUI_ENABLED="yes"
+fi
 
 if test "$GUI_ENABLED" = "yes" -a "$LV2_ENABLED" = "yes"; then
   LV2_GUI_ENABLED="yes"
+  EXEC_GUI_ENABLED="yes"
+fi
+
+if test "$set_enable_gtk_gui" = "yes" -a "$LV2_ENABLED" = "yes" -a "$GUI_ENABLED" = "yes"; then
+  LV2_GTK_GUI_ENABLED="yes"
 fi
 
 if test "$set_enable_debug" = "yes"; then
@@ -174,10 +218,15 @@ fi
 
 ############################################################################################
 # Create automake conditional symbols
+AM_CONDITIONAL(USE_DSSI, test "$DSSI_ENABLED" = "yes")
+AM_CONDITIONAL(USE_LADSPA, test "$LADSPA_ENABLED" = "yes")
 AM_CONDITIONAL(USE_JACK, test "$JACK_ENABLED" = "yes")
 AM_CONDITIONAL(USE_LV2, test "$LV2_ENABLED" = "yes")
 AM_CONDITIONAL(USE_GUI, test "$GUI_ENABLED" = "yes")
+AM_CONDITIONAL(USE_DSSI_GUI, test "$DSSI_GUI_ENABLED" = "yes")
+AM_CONDITIONAL(USE_EXEC_GUI, test "$EXEC_GUI_ENABLED" = "yes")
 AM_CONDITIONAL(USE_LV2_GUI, test "$LV2_GUI_ENABLED" = "yes")
+AM_CONDITIONAL(USE_LV2_GTK_GUI, test "$set_enable_gtk_gui" = "yes")
 AM_CONDITIONAL(USE_LASH, test "$LASH_ENABLED" = "yes")
 AM_CONDITIONAL(USE_LASH_0_6, test "$LASH_0_6_ENABLED" = "yes")
 AM_CONDITIONAL(USE_DEBUG, test "$set_enable_debug" = "yes")
@@ -185,6 +234,12 @@ AM_CONDITIONAL(USE_SORDI, test "$SORDI_E
 
 ############################################################################################
 # Create autoconf symbols for config.h
+if test "$LADSPA_ENABLED" = "yes"; then
+  AC_DEFINE(USE_LADSPA, 1, [LADSPA wrapper will be built])
+fi
+if test "$DSSI_ENABLED" = "yes"; then
+  AC_DEFINE(USE_DSSI, 1, [DSSI wrapper will be built])
+fi
 if test "$LV2_ENABLED" = "yes"; then
   AC_DEFINE(USE_LV2, 1, [LV2 wrapper will be built])
 fi
@@ -203,17 +258,50 @@ if test "$LASH_ENABLED" = "yes"; then
     AC_DEFINE(USE_LASH_0_6, 1, [Unstable LASH API is enabled])
   fi
 fi
+if test "$EXEC_GUI_ENABLED" = "yes"; then
+  AC_DEFINE(USE_EXEC_GUI, 1, [Out-of-process GTK+ GUI for LV2/DSSI will be built])
+fi
+if test "$DSSI_GUI_ENABLED" = "yes"; then
+  AC_DEFINE(USE_DSSI_GUI, 1, [GTK+ GUI executable will be used for DSSI])
+fi
 if test "$LV2_GUI_ENABLED" = "yes"; then
   AC_DEFINE(USE_LV2_GUI, 1, [GTK+ GUI executable will be used for LV2])
 fi
 if test "$set_enable_experimental" = "yes"; then
   AC_DEFINE([ENABLE_EXPERIMENTAL], [1], [Experimental features are enabled])
 fi
+if test "$set_enable_gtk_gui" = "yes"; then
+  AC_DEFINE([USE_LV2_GTK_GUI], [1], "In-process GTK+ LV2 GUI features is enabled")
+fi
 if test "$SORDI_ENABLED" = "yes"; then
   AC_DEFINE(USE_SORDI, 1, [Sordi sanity checks are enabled])
 fi
 ############################################################################################
 # Output directories
+AC_MSG_CHECKING(where to install LADSPA plugins)
+AC_ARG_WITH(ladspa_dir,
+  AC_HELP_STRING([--with-ladspa-dir],[install LADSPA plugins to DIR (default=$prefix/lib/ladspa/)]),
+  ,
+  [with_ladspa_dir="$prefix/lib/ladspa/"])
+AC_MSG_RESULT($with_ladspa_dir)
+AC_SUBST(with_ladspa_dir)
+
+AC_MSG_CHECKING(where to install LADSPA RDF file)
+AC_ARG_WITH(ladspa_rdf_dir,
+  AC_HELP_STRING([--with-ladspa-rdf-dir],[install RDF file to DIR (default=$prefix/share/ladspa/rdf/)]),
+  ,
+  [with_ladspa_rdf_dir="$prefix/share/ladspa/rdf/"])
+AC_MSG_RESULT($with_ladspa_rdf_dir)
+AC_SUBST(with_ladspa_rdf_dir)
+
+AC_MSG_CHECKING(where to install DSSI plugins)
+AC_ARG_WITH(dssi_dir,
+  AC_HELP_STRING([--with-dssi-dir],[install DSSI plugins to DIR (default=$prefix/lib/dssi/)]),
+  ,
+  [with_dssi_dir="$prefix/lib/dssi/"])
+AC_MSG_RESULT($with_dssi_dir)
+AC_SUBST(with_dssi_dir)
+
 if test "$LV2_ENABLED" == "yes"; then
   AC_MSG_CHECKING(where to install LV2 plugins)
   AC_ARG_WITH(lv2_dir,
@@ -269,9 +357,14 @@ AC_MSG_RESULT([
     Debug mode:                  $set_enable_debug
     With SSE:                    $set_enable_sse
     Experimental plugins:        $set_enable_experimental
+    LADSPA enabled:              $LADSPA_ENABLED
     Common GUI code:             $GUI_ENABLED
+    Out-of-process GUI code:     $EXEC_GUI_ENABLED
+    DSSI enabled:                $DSSI_ENABLED
+    DSSI GUI enabled:            $DSSI_GUI_ENABLED
     LV2 enabled:                 $LV2_ENABLED
-    LV2 GTK+ GUI enabled:        $LV2_GUI_ENABLED
+    LV2 in-process GUI enabled:  $LV2_GTK_GUI_ENABLED
+    LV2 GUI enabled:             $LV2_GUI_ENABLED
     JACK host enabled:           $JACK_ENABLED
     LASH enabled:                $LASH_ENABLED])
 if test "$LASH_ENABLED" = "yes"; then
--- origsrc/calf-0.90.3/src/Makefile.am	2018-01-31 07:46:08.000000000 +0900
+++ src/calf-0.90.3/src/Makefile.am	2023-09-13 08:01:08.568583600 +0900
@@ -2,6 +2,7 @@
 
 SUBDIRS = calf
 
+ladspadir = $(with_ladspa_dir)
 lv2dir = $(with_lv2_dir)/calf.lv2
 
 bin_PROGRAMS = 
@@ -9,6 +10,13 @@ noinst_LTLIBRARIES =
 
 noinst_PROGRAMS = calfbenchmark
 pkglib_LTLIBRARIES = calf.la
+if USE_DSSI_GUI
+bin_PROGRAMS += calf_gtk
+endif
+if USE_LV2_GUI
+noinst_LTLIBRARIES += calflv2gui.la
+bin_PROGRAMS += calf_gtk
+endif
 
 AM_CPPFLAGS = -I$(top_srcdir) -I$(srcdir)
 # TODO: Remove -finline flags is clang is used
@@ -36,33 +40,55 @@ endif
 
 calfbenchmark_SOURCES = benchmark.cpp
 calfbenchmark_LDADD = calf.la
+
+if USE_EXEC_GUI
+calf_gtk_SOURCES = dssigui.cpp
+calf_gtk_LDADD = calf.la libcalfgui.la $(GLIB_DEPS_LIBS) $(GUI_DEPS_LIBS) preset.o giface.o metadata.o
+calfbenchmark_CXXFLAGS = $(AM_CXXFLAGS) -DTEST_OSC
+calfbenchmark_LDADD += libcalfgui.la
+endif
 
-calf_la_SOURCES = audio_fx.cpp analyzer.cpp lv2wrap.cpp metadata.cpp modules_tools.cpp modules_delay.cpp modules_comp.cpp modules_limit.cpp modules_dist.cpp modules_filter.cpp modules_mod.cpp modules_pitch.cpp fluidsynth.cpp giface.cpp monosynth.cpp organ.cpp osctl.cpp plugin.cpp preset.cpp synth.cpp utils.cpp wavetable.cpp modmatrix.cpp
+calf_la_SOURCES = audio_fx.cpp analyzer.cpp lv2wrap.cpp metadata.cpp modules_tools.cpp modules_delay.cpp modules_comp.cpp modules_limit.cpp modules_dist.cpp modules_filter.cpp modules_mod.cpp modules_pitch.cpp fluidsynth.cpp giface.cpp monosynth.cpp organ.cpp osctl.cpp osctlnet.cpp plugin.cpp preset.cpp synth.cpp utils.cpp wavetable.cpp modmatrix.cpp
 calf_la_LIBADD = $(FLUIDSYNTH_DEPS_LIBS) $(GLIB_DEPS_LIBS) 
 if USE_DEBUG
 calf_la_LDFLAGS = -rpath $(pkglibdir) -avoid-version -module -lexpat -disable-static
 else
-calf_la_LDFLAGS = -rpath $(pkglibdir) -avoid-version -module -lexpat -disable-static -export-symbols-regex "lv2_descriptor"
+calf_la_LDFLAGS = -rpath $(pkglibdir) -avoid-version -module -lexpat -disable-static -export-symbols-regex "(ladspa_|lv2_|dssi_)descriptor"
 endif
 
-if USE_LV2_GUI
+if USE_LV2_GTK_GUI
 
 # Version WITH out-of-process GUI - links GTK+, UI controls etc.
 
 noinst_LTLIBRARIES += calflv2gui.la
 
-calflv2gui_la_SOURCES = gui.cpp gui_config.cpp gui_controls.cpp ctl_curve.cpp ctl_keyboard.cpp ctl_knob.cpp ctl_led.cpp ctl_tube.cpp ctl_vumeter.cpp ctl_frame.cpp ctl_fader.cpp ctl_buttons.cpp ctl_notebook.cpp ctl_meterscale.cpp ctl_combobox.cpp ctl_tuner.cpp ctl_phasegraph.cpp ctl_pattern.cpp metadata.cpp giface.cpp plugin_gui_window.cpp preset.cpp preset_gui.cpp lv2gui.cpp osctl.cpp utils.cpp ctl_linegraph.cpp drawingutils.cpp
+calflv2gui_la_SOURCES = gui.cpp gui_config.cpp gui_controls.cpp ctl_curve.cpp ctl_keyboard.cpp ctl_knob.cpp ctl_led.cpp ctl_tube.cpp ctl_vumeter.cpp ctl_frame.cpp ctl_fader.cpp ctl_buttons.cpp ctl_notebook.cpp ctl_meterscale.cpp ctl_combobox.cpp ctl_tuner.cpp ctl_phasegraph.cpp ctl_pattern.cpp metadata.cpp giface.cpp plugin_gui_window.cpp preset.cpp preset_gui.cpp lv2gui.cpp osctl.cpp osctlnet.cpp utils.cpp ctl_linegraph.cpp drawingutils.cpp
 
 if USE_DEBUG
 calflv2gui_la_LDFLAGS = -rpath $(lv2dir) -avoid-version -module -lexpat $(GUI_DEPS_LIBS) -disable-static  -Wl,-z,nodelete
 else
 calflv2gui_la_LDFLAGS = -rpath $(lv2dir) -avoid-version -module -lexpat -export-symbols-regex "lv2ui_descriptor" $(GUI_DEPS_LIBS) -disable-static  -Wl,-z,nodelete
+endif
+
+else
+
+# Version WITHOUT out-of-process GUI - links GLib only
+
+if USE_LV2_GUI
+calflv2gui_la_SOURCES = metadata.cpp giface.cpp preset.cpp lv2gui.cpp osctl.cpp osctlnet.cpp utils.cpp
+
+if USE_DEBUG
+calflv2gui_la_LDFLAGS = -rpath $(lv2dir) -avoid-version -module -lexpat $(GLIB_DEPS_LIBS) -disable-static
+else
+calflv2gui_la_LDFLAGS = -rpath $(lv2dir) -avoid-version -module -lexpat -export-symbols-regex "lv2ui_descriptor" $(GLIB_DEPS_LIBS) -disable-static
+endif
+
 endif
 
 endif
 
 if USE_GUI
-libcalfgui_la_SOURCES = ctl_curve.cpp ctl_keyboard.cpp ctl_knob.cpp ctl_led.cpp ctl_tube.cpp ctl_vumeter.cpp ctl_frame.cpp ctl_fader.cpp ctl_buttons.cpp ctl_notebook.cpp ctl_meterscale.cpp ctl_combobox.cpp ctl_tuner.cpp ctl_phasegraph.cpp ctl_pattern.cpp gui.cpp gui_config.cpp gui_controls.cpp osctl.cpp plugin_gui_window.cpp preset_gui.cpp utils.cpp ctl_linegraph.cpp drawingutils.cpp
+libcalfgui_la_SOURCES = ctl_curve.cpp ctl_keyboard.cpp ctl_knob.cpp ctl_led.cpp ctl_tube.cpp ctl_vumeter.cpp ctl_frame.cpp ctl_fader.cpp ctl_buttons.cpp ctl_notebook.cpp ctl_meterscale.cpp ctl_combobox.cpp ctl_tuner.cpp ctl_phasegraph.cpp ctl_pattern.cpp gui.cpp gui_config.cpp gui_controls.cpp osctl.cpp osctlnet.cpp osctl_glib.cpp plugin_gui_window.cpp preset_gui.cpp utils.cpp ctl_linegraph.cpp drawingutils.cpp
 libcalfgui_la_LDFLAGS = -static -disable-shared -lexpat
 endif
 
@@ -75,9 +105,22 @@ install-data-hook:
 if USE_GUI
 	install -c -m 644 $(top_srcdir)/calf-gui.xml $(DESTDIR)$(pkgdatadir)
 endif
+if USE_LADSPA
+	install -d -m 755 $(DESTDIR)$(with_ladspa_dir)
+	install -d -m 755 $(DESTDIR)$(with_ladspa_rdf_dir)
+	ln -sf $(pkglibdir)/calf.so $(DESTDIR)$(with_ladspa_dir)/calf.so
+	$(top_builddir)/src/calfmakerdf > $(DESTDIR)$(with_ladspa_rdf_dir)/calf.rdf
+endif
+if USE_DSSI
+	install -d -m 755 $(DESTDIR)$(with_dssi_dir)
+	install -d -m 755 $(DESTDIR)$(with_dssi_dir)/calf
+	ln -sf $(pkglibdir)/calf.so $(DESTDIR)$(with_dssi_dir)/calf.so
+	ln -sf $(bindir)/calf_gtk $(DESTDIR)$(with_dssi_dir)/calf/calf_gtk
+endif
 if USE_LV2
 	install -d -m 755 $(DESTDIR)$(lv2dir)
 	ln -sf $(pkglibdir)/calf.so $(DESTDIR)$(lv2dir)/calf.so
+	ln -sf $(bindir)/calf_gtk $(DESTDIR)$(lv2dir)/calf_gtk
 if USE_LV2_GUI
 	install -c -m 755 $(top_builddir)/src/.libs/calflv2gui.so $(DESTDIR)$(lv2dir)/calflv2gui.so
 endif
@@ -93,6 +136,7 @@ uninstall-hook:
 if USE_LV2
 if USE_LV2_GUI
 	rm -f $(DESTDIR)$(lv2dir)/calflv2gui.so
+	rm -f $(DESTDIR)$(lv2dir)/calf_gtk
 endif
 	rm -f $(DESTDIR)$(lv2dir)/calf.so
 	rm -f $(DESTDIR)$(lv2dir)/*.ttl
@@ -103,3 +147,15 @@ if USE_GUI
 endif
 	rm -f $(DESTDIR)$(pkgdatadir)/presets*.xml
 	rmdir $(DESTDIR)$(pkgdatadir) || true
+if USE_LADSPA
+	$(RM) -f $(DESTDIR)$(with_ladspa_dir)/calf.so
+	$(RM) -f $(DESTDIR)$(with_ladspa_rdf_dir)/calf.rdf
+	rmdir -p $(DESTDIR)$(with_ladspa_rdf_dir) || true
+endif
+if USE_DSSI
+	$(RM) -f $(DESTDIR)$(with_dssi_dir)/calf.so
+if USE_DSSI_GUI
+	$(RM) -f $(DESTDIR)$(with_dssi_dir)/calf/calf_gtk
+endif
+	rmdir -p $(DESTDIR)$(with_dssi_dir)/calf || true
+endif
--- origsrc/calf-0.90.3/src/calf/Makefile.am	2018-01-31 07:46:08.000000000 +0900
+++ src/calf-0.90.3/src/calf/Makefile.am	2023-09-13 07:34:00.757172200 +0900
@@ -4,12 +4,12 @@ noinst_HEADERS = audio_fx.h benchmark.h
     ctl_curve.h ctl_keyboard.h ctl_knob.h ctl_led.h ctl_tube.h ctl_vumeter.h drawingutils.h \
     connector.h delay.h envelope.h fft.h fixed_point.h giface.h gtk_session_env.h gtk_main_win.h \
     gui.h gui_config.h gui_controls.h inertia.h jackhost.h \
-    host_session.h loudness.h analyzer.h \
+    host_session.h ladspa_wrap.h loudness.h analyzer.h \
     lv2_data_access.h lv2_atom.h lv2_atom_util.h lv2_midi.h lv2_external_ui.h \
     lv2_state.h  lv2_progress.h lv2_options.h lv2_ui.h lv2_urid.h lv2helpers.h lv2wrap.h \
     metadata.h modmatrix.h \
     modules_tools.h modules_comp.h modules_dev.h modules_dist.h modules_filter.h \
     modules_delay.h modules_limit.h modules_mod.h modules_pitch.h modules_synths.h \
     modulelist.h \
-    multichorus.h onepole.h organ.h orfanidis_eq.h osc.h osctl.h plugin_tools.h preset.h \
+    multichorus.h onepole.h organ.h orfanidis_eq.h osc.h osctl.h osctlnet.h osctl_glib.h  plugin_tools.h preset.h \
     preset_gui.h primitives.h session_mgr.h synth.h utils.h vumeter.h wave.h waveshaping.h wavetable.h
--- origsrc/calf-0.90.3/src/calf/giface.h	2019-03-04 06:24:12.000000000 +0900
+++ src/calf-0.90.3/src/calf/giface.h	2023-09-13 07:34:00.767171300 +0900
@@ -696,6 +696,9 @@ struct dssi_feedback_sender
     void add_graphs(const calf_plugins::parameter_properties *props, int num_params);
     void update();
     ~dssi_feedback_sender();
+    
+    // always valid iface context
+    cairo_iface *_context;
 };
 #endif
 
--- origsrc/calf-0.90.3/src/calf/ladspa_wrap.h	1970-01-01 09:00:00.000000000 +0900
+++ src/calf-0.90.3/src/calf/ladspa_wrap.h	2023-09-13 07:34:00.767171300 +0900
@@ -0,0 +1,131 @@
+/* Calf DSP Library
+ * API wrappers for LADSPA/DSSI
+ *
+ * Copyright (C) 2007-2008 Krzysztof Foltman
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA 02111-1307, USA.
+ */
+#ifndef __CALF_LADSPA_WRAP_H
+#define __CALF_LADSPA_WRAP_H
+
+#if USE_LADSPA
+
+#include <string.h>
+#include <ladspa.h>
+#if USE_DSSI
+#include <dssi.h>
+#endif
+#include "giface.h"
+#include "preset.h"
+
+namespace calf_plugins {
+
+struct ladspa_plugin_metadata_set;
+/// A template implementing plugin_ctl_iface for a given plugin
+struct ladspa_instance: public plugin_ctl_iface
+{
+    audio_module_iface *module;
+    const plugin_metadata_iface *metadata;
+    ladspa_plugin_metadata_set *ladspa;
+    bool activate_flag;
+    float **ins, **outs, **params;
+#if USE_DSSI
+    dssi_feedback_sender *feedback_sender;
+#endif
+    
+    ladspa_instance(audio_module_iface *_module, ladspa_plugin_metadata_set *_ladspa, int sample_rate);
+    virtual const line_graph_iface *get_line_graph_iface() const { return module->get_line_graph_iface(); }
+    virtual const phase_graph_iface *get_phase_graph_iface() const { return module->get_phase_graph_iface(); }
+    virtual float get_param_value(int param_no);
+    virtual void set_param_value(int param_no, float value);
+    virtual bool activate_preset(int bank, int program);
+    virtual char *configure(const char *key, const char *value);
+    virtual float get_level(unsigned int port) { return 0.f; }
+    virtual void execute(int cmd_no) {
+        module->execute(cmd_no);
+    }
+    virtual void send_configures(send_configure_iface *sci) { 
+        module->send_configures(sci);
+    }
+    virtual int send_status_updates(send_updates_iface *sui, int last_serial) { return module->send_status_updates(sui, last_serial); }
+    void run(unsigned long SampleCount);
+#if USE_DSSI
+    /// Utility function: handle MIDI event (only handles a subset in this version)
+    void process_dssi_event(snd_seq_event_t &event);
+    void run_synth(unsigned long SampleCount, snd_seq_event_t *Events, unsigned long EventCount);
+#endif
+    virtual const plugin_metadata_iface *get_metadata_iface() const
+    {
+        return metadata;
+    }
+};
+
+/// Set of metadata produced by LADSPA wrapper for LADSPA-related purposes
+struct ladspa_plugin_metadata_set
+{
+    /// LADSPA descriptor
+    LADSPA_Descriptor descriptor;
+    /// LADSPA descriptor for DSSI (uses a different name for the plugin, otherwise same as descriptor)
+    LADSPA_Descriptor descriptor_for_dssi;
+#if USE_DSSI
+    /// Extended DSSI descriptor (points to descriptor_for_dssi for things like name/label/port info etc.)
+    DSSI_Descriptor dssi_descriptor;
+    DSSI_Program_Descriptor dssi_default_program;
+
+    std::vector<plugin_preset> *presets;
+    std::vector<DSSI_Program_Descriptor> *preset_descs;
+#endif
+    
+    int input_count, output_count, param_count;
+    const plugin_metadata_iface *metadata;
+    
+    ladspa_plugin_metadata_set();
+    void prepare(const plugin_metadata_iface *md, LADSPA_Handle (*cb_instantiate)(const struct _LADSPA_Descriptor * Descriptor, unsigned long sample_rate));
+    void prepare_dssi();
+    ~ladspa_plugin_metadata_set();
+};
+
+/// A wrapper class for plugin class object (there is only one ladspa_wrapper singleton for many instances of the same plugin)
+template<class Module>
+struct ladspa_wrapper
+{
+    static ladspa_plugin_metadata_set output;
+    
+private:
+    ladspa_wrapper(const plugin_metadata_iface *md)
+    {
+        output.prepare(md, cb_instantiate);
+    }
+
+public:
+    /// LADSPA instantiation function (create a plugin instance)
+    static LADSPA_Handle cb_instantiate(const struct _LADSPA_Descriptor * Descriptor, unsigned long sample_rate)
+    {
+        return new ladspa_instance(new Module, &output, sample_rate);
+    }
+
+    /// Get a wrapper singleton - used to prevent initialization order problems which were present in older versions
+    static ladspa_plugin_metadata_set &get() { 
+        static ladspa_wrapper instance(new typename Module::metadata_class);
+        return instance.output;
+    }
+};
+
+};
+
+#endif
+
+#endif
--- origsrc/calf-0.90.3/src/calf/lv2_programs.h	1970-01-01 09:00:00.000000000 +0900
+++ src/calf-0.90.3/src/calf/lv2_programs.h	2023-09-13 07:34:00.767171300 +0900
@@ -0,0 +1,171 @@
+/*
+  LV2 Programs Extension
+  Copyright 2012 Filipe Coelho <falktx@falktx.com>
+
+  Permission to use, copy, modify, and/or distribute this software for any
+  purpose with or without fee is hereby granted, provided that the above
+  copyright notice and this permission notice appear in all copies.
+
+  THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+/**
+   @file lv2_programs.h
+   C header for the LV2 programs extension <http://kxstudio.sf.net/ns/lv2ext/programs>.
+*/
+
+#ifndef LV2_PROGRAMS_H
+#define LV2_PROGRAMS_H
+
+#include "lv2/lv2plug.in/ns/lv2core/lv2.h"
+#include "lv2/lv2plug.in/ns/extensions/ui/ui.h"
+
+#define LV2_PROGRAMS_URI    "http://kxstudio.sf.net/ns/lv2ext/programs"
+#define LV2_PROGRAMS_PREFIX LV2_PROGRAMS_URI "#"
+
+#define LV2_PROGRAMS__Host        LV2_PROGRAMS_PREFIX "Host"
+#define LV2_PROGRAMS__Interface   LV2_PROGRAMS_PREFIX "Interface"
+#define LV2_PROGRAMS__UIInterface LV2_PROGRAMS_PREFIX "UIInterface"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void* LV2_Programs_Handle;
+
+typedef struct _LV2_Program_Descriptor {
+
+    /** Bank number for this program. Note that this extension does not
+        support MIDI-style separation of bank LSB and MSB values. There is
+        no restriction on the set of available banks: the numbers do not
+        need to be contiguous, there does not need to be a bank 0, etc. */
+    uint32_t bank;
+
+    /** Program number (unique within its bank) for this program. There is
+        no restriction on the set of available programs: the numbers do not
+        need to be contiguous, there does not need to be a program 0, etc. */
+    uint32_t program;
+
+    /** Name of the program. */
+    const char * name;
+
+} LV2_Program_Descriptor;
+
+/**
+   Programs extension, plugin data.
+
+   When the plugin's extension_data is called with argument LV2_PROGRAMS__Interface,
+   the plugin MUST return an LV2_Programs_Instance structure, which remains valid
+   for the lifetime of the plugin.
+*/
+typedef struct _LV2_Programs_Interface {
+    /**
+     * get_program()
+     *
+     * This member is a function pointer that provides a description
+     * of a program (named preset sound) available on this plugin.
+     *
+     * The index argument is an index into the plugin's list of
+     * programs, not a program number as represented by the Program
+     * field of the LV2_Program_Descriptor. (This distinction is
+     * needed to support plugins that use non-contiguous program or
+     * bank numbers.)
+     *
+     * This function returns a LV2_Program_Descriptor pointer that is
+     * guaranteed to be valid only until the next call to get_program
+     * or deactivate, on the same plugin instance. This function must
+     * return NULL if passed an index argument out of range, so that
+     * the host can use it to query the number of programs as well as
+     * their properties.
+     */
+    const LV2_Program_Descriptor *(*get_program)(LV2_Handle handle,
+                                                 uint32_t index);
+
+    /**
+     * select_program()
+     *
+     * This member is a function pointer that selects a new program
+     * for this plugin. The program change should take effect
+     * immediately at the start of the next run() call. (This
+     * means that a host providing the capability of changing programs
+     * between any two notes on a track must vary the block size so as
+     * to place the program change at the right place. A host that
+     * wanted to avoid this would probably just instantiate a plugin
+     * for each program.)
+     *
+     * Plugins should ignore a select_program() call with an invalid
+     * bank or program.
+     *
+     * A plugin is not required to select any particular default
+     * program on activate(): it's the host's duty to set a program
+     * explicitly.
+     *
+     * A plugin is permitted to re-write the values of its input
+     * control ports when select_program is called. The host should
+     * re-read the input control port values and update its own
+     * records appropriately. (This is the only circumstance in which
+     * a LV2 plugin is allowed to modify its own control-input ports.)
+     */
+    void (*select_program)(LV2_Handle handle,
+                           uint32_t bank,
+                           uint32_t program);
+
+} LV2_Programs_Interface;
+
+/**
+   Programs extension, UI data.
+
+   When the UI's extension_data is called with argument LV2_PROGRAMS__UIInterface,
+   the UI MUST return an LV2_Programs_UI_Interface structure, which remains valid
+   for the lifetime of the UI.
+*/
+typedef struct _LV2_Programs_UI_Interface {
+    /**
+     * select_program()
+     *
+     * This is exactly the same as select_program in LV2_Programs_Instance,
+     * but this struct relates to the UI instead of the plugin.
+     *
+     * When called, UIs should update their state to match the selected program.
+     */
+    void (*select_program)(LV2UI_Handle handle,
+                           uint32_t bank,
+                           uint32_t program);
+
+} LV2_Programs_UI_Interface;
+
+/**
+    Feature data for LV2_PROGRAMS__Host.
+*/
+typedef struct _LV2_Programs_Host {
+    /**
+     *  Opaque host data.
+     */
+    LV2_Programs_Handle handle;
+
+    /**
+     * program_changed()
+     *
+     * Tell the host to reload a plugin's program.
+     * Parameter handle MUST be the 'handle' member of this struct.
+     * Parameter index is program index to change.
+     * When index is -1, host should reload all the programs.
+     *
+     * NOTE: The plugin MUST NEVER call this function on a RT context or during run().
+     */
+    void (*program_changed)(LV2_Programs_Handle handle,
+                            int32_t index);
+
+} LV2_Programs_Host;
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* LV2_PROGRAMS_H */
--- origsrc/calf-0.90.3/src/calf/lv2wrap.h	2019-03-04 06:24:12.000000000 +0900
+++ src/calf-0.90.3/src/calf/lv2wrap.h	2023-09-13 07:34:00.767171300 +0900
@@ -27,11 +27,13 @@
 #include <vector>
 #include "lv2/lv2plug.in/ns/lv2core/lv2.h"
 #include <calf/giface.h>
+#include <calf/preset.h>
 #include <calf/lv2_atom.h>
 #include <calf/lv2_atom_util.h>
 #include <calf/lv2_midi.h>
 #include <calf/lv2_state.h>
 #include <calf/lv2_options.h>
+#include <calf/lv2_programs.h>
 #include <calf/lv2_progress.h>
 #include <calf/lv2_urid.h>
 #include <string.h>
@@ -54,6 +56,9 @@ struct lv2_instance: public plugin_ctl_i
     int in_count;
     int out_count;
     int real_param_count;
+    std::vector<plugin_preset> *presets;
+    std::vector<LV2_Program_Descriptor> *preset_descs;
+
     struct lv2_var
     {
         std::string name;
@@ -63,6 +68,19 @@ struct lv2_instance: public plugin_ctl_i
     std::map<uint32_t, int> uri_to_var;
 
     lv2_instance(audio_module_iface *_module);
+    ~lv2_instance()
+    {
+        if (presets)
+        {
+            presets->clear();
+            delete presets;
+        }
+        if (preset_descs)
+        {
+            preset_descs->clear();
+            delete preset_descs;
+        }
+    }
     void lv2_instantiate(const LV2_Descriptor * Descriptor, double sample_rate, const char *bundle_path, const LV2_Feature *const *features);
 
 /// This, and not Module::post_instantiate, is actually called by lv2_instantiate
@@ -151,6 +169,8 @@ struct lv2_wrapper
     static LV2_Descriptor descriptor;
     static LV2_Calf_Descriptor calf_descriptor;
     static LV2_State_Interface state_iface;
+    static LV2_Programs_Interface programs_iface;
+    static LV2_Program_Descriptor lv2_default_program;
     std::string uri;
     
     lv2_wrapper()
@@ -168,6 +188,11 @@ struct lv2_wrapper
         state_iface.save = cb_state_save;
         state_iface.restore = cb_state_restore;
         calf_descriptor.get_pci = cb_get_pci;
+        programs_iface.get_program = cb_get_program;
+        programs_iface.select_program = cb_select_program;
+        lv2_default_program.bank = 0;
+        lv2_default_program.program = 0;
+        lv2_default_program.name = "default";
     }
 
     static void cb_connect(LV2_Handle Instance, uint32_t port, void *DataLocation)
@@ -237,6 +262,8 @@ struct lv2_wrapper
             return &calf_descriptor;
         if (!strcmp(URI, LV2_STATE__interface))
             return &state_iface;
+        if (!strcmp(URI, LV2_PROGRAMS__Interface))
+            return &programs_iface;
         return NULL;
     }
     static LV2_State_Status cb_state_save(
@@ -254,7 +281,32 @@ struct lv2_wrapper
         inst->impl_restore(retrieve, callback_data);
         return LV2_STATE_SUCCESS;
     }
-    
+    static const LV2_Program_Descriptor* cb_get_program(LV2_Handle Instance, uint32_t index)
+    {
+        instance *const inst = (instance *)Instance;
+        if (index > inst->presets->size())
+            return NULL;
+        if (index)
+            return &(*inst->preset_descs)[index - 1];
+        return &lv2_default_program;
+    }
+    static void cb_select_program(LV2_Handle Instance, uint32_t bank, uint32_t program)
+    {
+        instance *const inst = (instance *)Instance;
+        unsigned int no = (bank << 7) + program - 1;
+        if (no == -1U) {
+            int rpc = inst->real_param_count;
+            for (int i =0 ; i < rpc; i++)
+                *inst->params[i] = inst->metadata->get_param_props(i)->def_value;
+            return;
+        }
+        if (no >= inst->presets->size())
+            return;
+        plugin_preset &p = (*inst->presets)[no];
+        // printf("activating preset %s\n", p.name.c_str());
+        p.activate(inst);
+    }
+
     static lv2_wrapper &get() { 
         static lv2_wrapper instance;
         return instance;
--- origsrc/calf-0.90.3/src/calf/modulelist.h	2018-01-31 07:46:08.000000000 +0900
+++ src/calf-0.90.3/src/calf/modulelist.h	2023-09-13 07:34:00.777171300 +0900
@@ -3,7 +3,7 @@
     PER_MODULE_ITEM(organ,               true,  "organ")
 #ifdef ENABLE_EXPERIMENTAL
     PER_MODULE_ITEM(fluidsynth,          true,  "fluidsynth")
-    PER_MODULE_ITEM(wavetable,           true,  "wavetable")
+    //PER_MODULE_ITEM(wavetable,           true,  "wavetable")
 #endif
     // Modulator
     PER_MODULE_ITEM(multichorus,         false, "multichorus")
--- origsrc/calf-0.90.3/src/calf/modules_synths.h	2017-07-05 06:41:59.000000000 +0900
+++ src/calf-0.90.3/src/calf/modules_synths.h	2023-09-13 07:34:00.777171300 +0900
@@ -192,7 +192,7 @@ private:
 
 };
 
-#if ENABLE_EXPERIMENTAL
+#if 0 // ENABLE_EXPERIMENTAL
     
 #include "wavetable.h"
 
--- origsrc/calf-0.90.3/src/calf/osctl_glib.h	1970-01-01 09:00:00.000000000 +0900
+++ src/calf-0.90.3/src/calf/osctl_glib.h	2023-09-13 07:34:00.777171300 +0900
@@ -0,0 +1,46 @@
+/* Calf DSP Library
+ * Open Sound Control UDP server support
+ *
+ * Copyright (C) 2007-2009 Krzysztof Foltman
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef __CALF_OSCTLGLIB_H
+#define __CALF_OSCTLGLIB_H
+
+#include <glib.h>
+#include "osctlnet.h"
+
+namespace osctl
+{
+    
+/// Glib main loop based implementation of OSC server.
+struct osc_glib_server: public osc_server
+{
+    GIOChannel *ioch;
+    
+    osc_glib_server() : ioch(NULL) {}
+    
+    virtual void on_bind();
+    
+    static gboolean on_data(GIOChannel *channel, GIOCondition cond, void *obj);
+    ~osc_glib_server();
+};
+
+};
+
+#endif
--- origsrc/calf-0.90.3/src/calf/osctlnet.h	1970-01-01 09:00:00.000000000 +0900
+++ src/calf-0.90.3/src/calf/osctlnet.h	2023-09-13 07:34:00.777171300 +0900
@@ -0,0 +1,71 @@
+/* Calf DSP Library
+ * Open Sound Control UDP support
+ *
+ * Copyright (C) 2007 Krzysztof Foltman
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __CALF_OSCTLNET_H
+#define __CALF_OSCTLNET_H
+
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <calf/osctl.h>
+
+namespace osctl
+{
+    
+struct osc_socket
+{
+    int socket, srcid;
+    std::string prefix;
+
+    osc_socket() : socket(-1), srcid(0) {}
+    void bind(const char *hostaddr = "0.0.0.0", int port = 0);
+    std::string get_url() const;
+    virtual void on_bind() {}
+    virtual ~osc_socket();
+};
+
+struct osc_client: public osc_socket
+{
+    sockaddr_in addr;
+    
+    void set_addr(const char *hostaddr, int port);
+    void set_url(const char *url);
+    bool send(const std::string &address, osctl::osc_typed_strstream &stream);
+    bool send(const std::string &address);
+};
+
+/// Base implementation for OSC server - requires the interfacing code
+/// to poll periodically for messages. Alternatively, one can use
+/// osc_glib_server that hooks into glib main loop.
+struct osc_server: public osc_socket
+{
+    osc_message_dump<osc_strstream, std::ostream> dump;
+    osc_message_sink<osc_strstream> *sink;
+    
+    osc_server() : dump(std::cout), sink(&dump) {}
+    
+    void read_from_socket();
+    void parse_message(const char *buffer, int len);    
+    ~osc_server();
+};
+
+};
+
+#endif
--- origsrc/calf-0.90.3/src/dssigui.cpp	1970-01-01 09:00:00.000000000 +0900
+++ src/calf-0.90.3/src/dssigui.cpp	2023-09-13 07:34:00.787157100 +0900
@@ -0,0 +1,686 @@
+/* Calf DSP Library utility application.
+ * DSSI GUI application.
+ * Copyright (C) 2007 Krzysztof Foltman
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+#include <calf/giface.h>
+#include <calf/gui.h>
+#include <calf/osctl_glib.h>
+#include <calf/preset.h>
+#include <getopt.h>
+
+using namespace std;
+using namespace dsp;
+using namespace calf_plugins;
+using namespace osctl;
+
+#define debug_printf(...)
+
+struct cairo_params
+{
+    enum { HAS_COLOR = 1, HAS_WIDTH = 2 };
+    uint32_t flags;
+    float r, g, b, a;
+    float line_width;
+    
+    cairo_params()
+    : flags(0)
+    , r(0.f)
+    , g(0.f)
+    , b(0.f)
+    , a(1.f)
+    , line_width(1)
+    {
+    }
+};
+
+struct graph_item: public cairo_params
+{
+    float data[128];
+    int mode;
+
+    graph_item(int mode_)
+      : mode(mode_) {}
+};
+
+struct dot_item: public cairo_params
+{
+    float x, y;
+    int32_t size;
+};
+
+struct gridline_item: public cairo_params
+{
+    float pos;
+    int32_t vertical;
+    std::string text;
+};
+
+struct param_line_graphs
+{
+    vector<graph_item *> graphs;
+    vector<dot_item *> dots;
+    vector<gridline_item *> gridlines;
+    
+    void clear();
+};
+
+void param_line_graphs::clear()
+{
+    for (size_t i = 0; i < graphs.size(); i++)
+        delete graphs[i];
+    graphs.clear();
+
+    for (size_t i = 0; i < dots.size(); i++)
+        delete dots[i];
+    dots.clear();
+
+    for (size_t i = 0; i < gridlines.size(); i++)
+        delete gridlines[i];
+    gridlines.clear();
+
+}
+
+struct plugin_proxy: public plugin_ctl_iface, public line_graph_iface, public phase_graph_iface
+{
+    osc_client *client;
+    bool send_osc;
+    plugin_gui *gui;
+    map<string, string> cfg_vars;
+    int param_count;
+    float *params;
+    map<int, param_line_graphs> graphs;
+    bool update_graphs;
+    const plugin_metadata_iface *metadata;
+    vector<string> new_status;
+    uint32_t new_status_serial;
+    bool is_lv2;
+
+    plugin_proxy(const plugin_metadata_iface *md, bool _is_lv2)
+    {
+        new_status_serial = 0;
+        metadata = md;
+        client = NULL;
+        send_osc = false;
+        update_graphs = true;
+        gui = NULL;
+        param_count = md->get_param_count();
+        params = new float[param_count];
+        for (int i = 0; i < param_count; i++)
+            params[i] = metadata->get_param_props(i)->def_value;
+        is_lv2 = _is_lv2;
+    }
+    virtual float get_param_value(int param_no) {
+        if (param_no < 0 || param_no >= param_count)
+            return 0;
+        return params[param_no];
+    }
+    virtual void set_param_value(int param_no, float value) {
+        if (param_no < 0 || param_no >= param_count)
+            return;
+        update_graphs = true;
+        params[param_no] = value;
+        if (send_osc)
+        {
+            osc_inline_typed_strstream str;
+            str << (uint32_t)(param_no + metadata->get_param_port_offset()) << value;
+            client->send("/control", str);
+        }
+    }
+    virtual bool activate_preset(int bank, int program) { 
+        if (send_osc) {
+            osc_inline_typed_strstream str;
+            str << (uint32_t)(bank) << (uint32_t)(program);
+            client->send("/program", str);
+            return false;
+        }
+        return false;
+    }
+    virtual float get_level(unsigned int port) { return 0.f; }
+    virtual void execute(int command_no) { 
+        if (send_osc) {
+            stringstream ss;
+            ss << command_no;
+            
+            osc_inline_typed_strstream str;
+            str << "ExecCommand" << ss.str();
+            client->send("/configure", str);
+            
+            str.clear();
+            str << "ExecCommand" << "";
+            client->send("/configure", str);
+        }
+    }
+    char *configure(const char *key, const char *value) { 
+        // do not store temporary vars in presets
+        osc_inline_typed_strstream str;
+        if (value)
+        {
+            if (strncmp(key, "OSC:", 4))
+                cfg_vars[key] = value;
+            str << key << value;
+        }
+        else
+            str << key;
+        client->send("/configure", str);
+        return NULL;
+    }
+    void send_configures(send_configure_iface *sci) { 
+        for (map<string, string>::iterator i = cfg_vars.begin(); i != cfg_vars.end(); i++)
+            sci->send_configure(i->first.c_str(), i->second.c_str());
+    }
+    virtual int send_status_updates(send_updates_iface *sui, int last_serial)
+    {
+        if ((int)new_status_serial != last_serial)
+        {
+            for (size_t i = 0; i < (new_status.size() & ~1); i += 2)
+            {
+                sui->send_status(new_status[i].c_str(), new_status[i + 1].c_str());
+            }
+            return new_status_serial;
+        }
+        if (!is_lv2)
+        {
+            osc_inline_typed_strstream str;
+            str << "OSC:SEND_STATUS" << calf_utils::i2s(last_serial);
+            client->send("/configure", str);
+            return last_serial;
+        }
+        else
+        {
+            osc_inline_typed_strstream str;
+            str << (uint32_t)last_serial;
+            client->send("/send_status", str);
+            return last_serial;
+        }
+    }
+    virtual const line_graph_iface *get_line_graph_iface() const { return this; }
+    virtual const phase_graph_iface *get_phase_graph_iface() const { return this; }
+    virtual bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context, int *mode) const;
+    virtual bool get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context) const;
+    virtual bool get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const;
+    void update_cairo_context(cairo_iface *context, cairo_params &item) const;
+    virtual const plugin_metadata_iface *get_metadata_iface() const { return metadata; }
+};
+
+bool plugin_proxy::get_graph(int index, int subindex, float *data, int points, cairo_iface *context, int *mode) const
+{
+    if (!graphs.count(index))
+        return false;
+    const param_line_graphs &g = graphs.find(index)->second;
+    if (subindex < (int)g.graphs.size())
+    {
+        *mode = g.graphs[subindex]->mode;
+        float *sdata = g.graphs[subindex]->data;
+        for (int i = 0; i < points; i++) {
+            float pos = i * 127.0 / points;
+            int ipos = i * 127 / points;
+            data[i] = sdata[ipos] + (sdata[ipos + 1] - sdata[ipos]) * (pos-ipos);
+        }
+        update_cairo_context(context, *g.graphs[subindex]);
+        return true;
+    }
+    return false;
+}
+
+bool plugin_proxy::get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context) const
+{
+    if (!graphs.count(index))
+        return false;
+    const param_line_graphs &g = graphs.find(index)->second;
+    if (subindex < (int)g.dots.size())
+    {
+        dot_item &item = *g.dots[subindex];
+        x = item.x;
+        y = item.y;
+        size = item.size;
+        update_cairo_context(context, item);
+        return true;
+    }
+    return false;
+}
+
+bool plugin_proxy::get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const
+{
+    if (!graphs.count(index))
+        return false;
+    const param_line_graphs &g = graphs.find(index)->second;
+    if (subindex < (int)g.gridlines.size())
+    {
+        gridline_item &item = *g.gridlines[subindex];
+        pos = item.pos;
+        vertical = item.vertical != 0;
+        legend = item.text;
+        update_cairo_context(context, item);
+        return true;
+    }
+    return false;
+}
+
+void plugin_proxy::update_cairo_context(cairo_iface *context, cairo_params &item) const
+{
+    if (item.flags & cairo_params::HAS_COLOR)
+        context->set_source_rgba(item.r, item.g, item.b, item.a);
+    if (item.flags & cairo_params::HAS_WIDTH)
+        context->set_line_width(item.line_width);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+GMainLoop *mainloop;
+
+static bool osc_debug = false;
+
+struct dssi_osc_server: public osc_glib_server, public osc_message_sink<osc_strstream>, public gui_environment
+{
+    plugin_proxy *plugin;
+    plugin_gui_window *window;
+    string effect_name, title;
+    osc_client cli;
+    bool in_program, enable_dump;
+    vector<plugin_preset> presets;
+    /// Timeout callback source ID
+    int source_id;
+    bool osc_link_active;
+    /// If we're communicating with the LV2 external UI bridge, use a slightly different protocol
+    bool is_lv2;
+    
+    dssi_osc_server()
+    : plugin(NULL)
+    , window(new plugin_gui_window(this, NULL))
+    {
+        sink = this;
+        source_id = 0;
+        osc_link_active = false;
+        is_lv2 = false;
+    }
+    
+    void set_plugin(const char *arg)
+    {
+        const plugin_metadata_iface *pmi = plugin_registry::instance().get_by_id(arg);
+        if (!pmi)
+        {
+            pmi = plugin_registry::instance().get_by_uri(arg);
+            if (pmi)
+                is_lv2 = true;
+        }
+        if (!pmi)
+        {
+            fprintf(stderr, "Unknown plugin: %s\n", arg);
+            exit(1);
+        }
+        effect_name = pmi->get_id();
+        plugin = new plugin_proxy(pmi, is_lv2);
+    }
+    
+    static void on_destroy(GtkWindow *window, dssi_osc_server *self)
+    {
+        debug_printf("on_destroy, have to send \"exiting\"\n");
+        bool result = self->cli.send("/exiting");
+        debug_printf("result = %d\n", result ? 1 : 0);
+        g_main_loop_quit(mainloop);
+        // eliminate a warning with empty debug_printf
+        result = false;
+    }
+    
+    void create_window()
+    {
+        plugin->client = &cli;
+        plugin->send_osc = true;
+        conditions.insert("dssi");
+        conditions.insert("configure");
+        conditions.insert("directlink");
+        window->create(plugin, title.c_str(), effect_name.c_str());
+        plugin->gui = window->get_gui();
+        gtk_signal_connect(GTK_OBJECT(window->toplevel), "destroy", G_CALLBACK(on_destroy), this);
+        vector<plugin_preset> tmp_presets;
+        get_builtin_presets().get_for_plugin(presets, effect_name.c_str());
+        get_user_presets().get_for_plugin(tmp_presets, effect_name.c_str());
+        presets.insert(presets.end(), tmp_presets.begin(), tmp_presets.end());
+        source_id = g_timeout_add_full(G_PRIORITY_LOW, 1000/30, on_idle, this, NULL);
+    }
+    
+    static gboolean on_idle(void *self)
+    {
+        dssi_osc_server *self_ptr = (dssi_osc_server *)(self);
+        if (self_ptr->osc_link_active)
+            self_ptr->send_osc_update();
+        return TRUE;
+    }
+    
+    void set_osc_update(bool enabled);
+    void send_osc_update();
+    
+    virtual void receive_osc_message(std::string address, std::string args, osc_strstream &buffer);
+    void unmarshal_line_graph(osc_strstream &buffer);
+};
+
+void dssi_osc_server::set_osc_update(bool enabled)
+{
+    if (is_lv2)
+    {
+        osc_inline_typed_strstream data;
+        data << ((uint32_t)(enabled ? 1 : 0));
+        cli.send("/enable_updates", data);
+    }
+    else
+    {
+        osc_link_active = enabled;
+        osc_inline_typed_strstream data;
+        data << "OSC:FEEDBACK_URI";
+        data << (enabled ? get_url() : "");
+        cli.send("/configure", data);
+    }
+}
+
+void dssi_osc_server::send_osc_update()
+{
+    // LV2 is updating via run() callback in the external UI library, so this is not needed
+    if (is_lv2)
+        return;
+    
+    static int serial_no = 0;
+    osc_inline_typed_strstream data;
+    data << "OSC:UPDATE";
+    data << calf_utils::i2s(serial_no++);
+    cli.send("/configure", data);
+}
+
+void dssi_osc_server::unmarshal_line_graph(osc_strstream &buffer)
+{
+    uint32_t cmd;
+    
+    do {
+        buffer >> cmd;
+        if (cmd == LGI_GRAPH)
+        {
+            uint32_t param;
+            buffer >> param;
+            param_line_graphs &graphs = plugin->graphs[param];
+            
+            graphs.clear();
+            cairo_params params;
+
+            do {
+                buffer >> cmd;
+                if (cmd == LGI_SET_RGBA)
+                {
+                    params.flags |= cairo_params::HAS_COLOR;
+                    buffer >> params.r >> params.g >> params.b >> params.a;
+                }
+                else
+                if (cmd == LGI_SET_WIDTH)
+                {
+                    params.flags |= cairo_params::HAS_WIDTH;
+                    buffer >> params.line_width;
+                }
+                else
+                if (cmd == LGI_SUBGRAPH)
+                {
+                    uint32_t mode;
+                    buffer >> mode;
+                    buffer >> param; // ignore number of points
+                    graph_item *gi = new graph_item(mode);
+                    (cairo_params &)*gi = params;
+                    for (int i = 0; i < 128; i++)
+                        buffer >> gi->data[i];
+                    graphs.graphs.push_back(gi);
+                    params.flags = 0;
+                }
+                else
+                if (cmd == LGI_DOT)
+                {
+                    dot_item *di = new dot_item;
+                    (cairo_params &)*di = params;
+                    buffer >> di->x >> di->y >> di->size;
+                    graphs.dots.push_back(di);
+                    params.flags = 0;
+                }
+                else
+                if (cmd == LGI_LEGEND)
+                {
+                    gridline_item *li = new gridline_item;
+                    (cairo_params &)*li = params;
+                    buffer >> li->pos >> li->vertical >> li->text;
+                    graphs.gridlines.push_back(li);
+                    params.flags = 0;
+                }
+                else
+                    break;
+            } while(1);
+            
+        }
+        else
+            break;
+    } while(1);
+}
+
+void dssi_osc_server::receive_osc_message(std::string address, std::string args, osc_strstream &buffer)
+{
+    if (osc_debug)
+        dump.receive_osc_message(address, args, buffer);
+    if (address == prefix + "/update" && args == "s")
+    {
+        string str;
+        buffer >> str;
+        debug_printf("UPDATE: %s\n", str.c_str());
+        set_osc_update(true);
+        send_osc_update();
+        return;
+    }
+    else if (address == prefix + "/quit")
+    {
+        set_osc_update(false);
+        debug_printf("QUIT\n");
+        g_main_loop_quit(mainloop);
+        return;
+    }
+    else if (address == prefix + "/configure"&& args == "ss")
+    {
+        string key, value;
+        buffer >> key >> value;
+        // do not store temporary vars in presets
+        if (strncmp(key.c_str(), "OSC:", 4))
+            plugin->cfg_vars[key] = value;
+        // XXXKF perhaps this should be queued !
+        window->get_gui()->refresh();
+        return;
+    }
+    else if (address == prefix + "/program"&& args == "ii")
+    {
+        uint32_t bank, program;
+        
+        buffer >> bank >> program;
+        
+        unsigned int nr = bank * 128 + program;
+        debug_printf("PROGRAM %d\n", nr);
+        if (nr == 0)
+        {
+            bool sosc = plugin->send_osc;
+            plugin->send_osc = false;
+            int count = plugin->metadata->get_param_count();
+            for (int i =0 ; i < count; i++)
+                plugin->set_param_value(i, plugin->metadata->get_param_props(i)->def_value);
+            plugin->send_osc = sosc;
+            window->get_gui()->refresh();
+            // special handling for default preset
+            return;
+        }
+        nr--;
+        if (nr >= presets.size())
+            return;
+        bool sosc = plugin->send_osc;
+        plugin->send_osc = false;
+        presets[nr].activate(plugin);
+        plugin->send_osc = sosc;
+        window->get_gui()->refresh();
+        
+        // cli.send("/update", data);
+        return;
+    }
+    else if (address == prefix + "/control" && args == "if")
+    {
+        uint32_t port;
+        float val;
+        
+        buffer >> port >> val;
+        
+        int idx = port - plugin->metadata->get_param_port_offset();
+        debug_printf("CONTROL %d %f\n", idx, val);
+        bool sosc = plugin->send_osc;
+        plugin->send_osc = false;
+        window->get_gui()->set_param_value(idx, val);
+        plugin->send_osc = sosc;
+        if (plugin->metadata->get_param_props(idx)->flags & PF_PROP_GRAPH)
+            plugin->update_graphs = true;
+        return;
+    }
+    else if (address == prefix + "/show")
+    {
+        set_osc_update(true);
+
+        gtk_widget_show(GTK_WIDGET(window->toplevel));
+        return;
+    }
+    else if (address == prefix + "/hide")
+    {
+        set_osc_update(false);
+
+        gtk_widget_hide(GTK_WIDGET(window->toplevel));
+        return;
+    }
+    else if (address == prefix + "/lineGraph")
+    {
+        unmarshal_line_graph(buffer);
+        if (plugin->update_graphs) {
+            // updates graphs that are only redrawn on startup and parameter changes
+            // (the OSC message may come a while after the parameter has been changed,
+            // so the redraw triggered by parameter change usually shows stale values)
+            window->get_gui()->refresh();
+            plugin->update_graphs = false;
+        }
+        return;
+    }
+    else if (address == prefix + "/status_data" && (args.length() & 1) && args[args.length() - 1] == 'i')
+    {
+        int len = (int)args.length();
+        plugin->new_status.clear();
+        
+        for (int pos = 0; pos < len - 2; pos += 2)
+        {
+            if (args[pos] == 's' && args[pos+1] == 's')
+            {
+                string key, value;
+                buffer >> key >> value;
+                plugin->new_status.push_back(key);
+                plugin->new_status.push_back(value);
+            }
+        }
+        buffer >> plugin->new_status_serial;
+        return;
+    }
+    else
+        printf("Unknown OSC address: %s\n", address.c_str());
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+
+void help(char *argv[])
+{
+    printf("GTK+ user interface for Calf DSSI plugins\nSyntax: %s [--help] [--version] <osc-url> <so-file> <plugin-label> <instance-name>\n", argv[0]);
+}
+
+static struct option long_options[] = {
+    {"help", 0, 0, 'h'},
+    {"version", 0, 0, 'v'},
+    {"debug", 0, 0, 'd'},
+    {0,0,0,0},
+};
+
+int main(int argc, char *argv[])
+{
+    char *debug_var = getenv("OSC_DEBUG");
+    if (debug_var && atoi(debug_var))
+        osc_debug = true;
+    
+    gtk_rc_add_default_file(PKGLIBDIR "calf.rc");
+    gtk_init(&argc, &argv);
+    while(1) {
+        int option_index;
+        int c = getopt_long(argc, argv, "dhv", long_options, &option_index);
+        if (c == -1)
+            break;
+        switch(c) {
+            case 'd':
+                osc_debug = true;
+                break;
+            case 'h':
+                help(argv);
+                return 0;
+            case 'v':
+                printf("%s\n", PACKAGE_STRING);
+                return 0;
+        }
+    }
+    if (argc - optind != 4)
+    {
+        help(argv);
+        exit(0);
+    }
+
+    try {
+        get_builtin_presets().load_defaults(true);
+        get_user_presets().load_defaults(false);
+    }
+    catch(calf_plugins::preset_exception &e)
+    {
+        fprintf(stderr, "Error while loading presets: %s\n", e.what());
+        exit(1);
+    }
+
+    dssi_osc_server srv;
+    srv.set_plugin(argv[optind + 2]);
+    srv.prefix = "/dssi/"+string(argv[optind + 1]) + "/" + srv.effect_name;
+    srv.title = argv[optind + 3];
+    
+    srv.bind();
+    srv.create_window();
+    
+    mainloop = g_main_loop_new(NULL, FALSE);
+
+    srv.cli.bind();
+    srv.cli.set_url(argv[optind]);
+    
+    debug_printf("URI = %s\n", srv.get_url().c_str());
+    
+    osc_inline_typed_strstream data;
+    data << srv.get_url();
+    if (!srv.cli.send("/update", data))
+    {
+        g_error("Could not send the initial update message via OSC to %s", argv[optind]);
+        return 1;
+    }
+    
+    g_main_loop_run(mainloop);
+    if (srv.source_id)
+        g_source_remove(srv.source_id);
+
+    srv.set_osc_update(false);
+    debug_printf("exited\n");
+    
+    return 0;
+}
--- origsrc/calf-0.90.3/src/giface.cpp	2019-03-04 06:24:12.000000000 +0900
+++ src/calf-0.90.3/src/giface.cpp	2023-09-13 07:34:00.787157100 +0900
@@ -23,6 +23,7 @@
 #include <stdlib.h>
 #include <math.h>
 #include <calf/giface.h>
+#include <calf/osctlnet.h>
 #include <calf/utils.h>
 #include <string.h>
 
@@ -604,6 +605,124 @@ void mod_matrix_metadata::get_configure_
 ////////////////////////////////////////////////////////////////////////
 
 #if USE_EXEC_GUI
+struct osc_cairo_control: public cairo_iface
+{
+    osctl::osc_inline_typed_strstream os;
+    
+    osc_cairo_control() {}
+    virtual void set_source_rgba(float r, float g, float b, float a = 1.f)
+    {
+        os << (uint32_t)LGI_SET_RGBA << r << g << b << a;
+    }
+    virtual void set_line_width(float width)
+    {
+        os << (uint32_t)LGI_SET_WIDTH << width;
+    }
+    virtual void set_dash(const double *dash, int length)
+    {
+    }
+    virtual void draw_label(const char *label, float x, float y, int pos, float margin, float align)
+    {
+    }
+};
+
+static void serialize_graphs(osc_cairo_control *cairoctl, osctl::osc_inline_typed_strstream &os, const line_graph_iface *graph, std::vector<int> &params)
+{
+    for (size_t i = 0; i < params.size(); i++)
+    {
+        int index = params[i];
+        os << (uint32_t)LGI_GRAPH;
+        os << (uint32_t)index;
+        for (int j = 0; ; j++)
+        {
+            int mode = 0;
+            float data[128];
+            if (graph->get_graph(index, j, 0, data, 128, cairoctl, &mode))
+            {
+                os << (uint32_t)LGI_SUBGRAPH;
+                os << (uint32_t)mode;
+                os << (uint32_t)128;
+                for (int p = 0; p < 128; p++)
+                    os << data[p];
+            }
+            else
+                break;
+        }
+        for (int j = 0; ; j++)
+        {
+            float x, y;
+            int size = 3;
+            if (graph->get_dot(index, j, 0, x, y, size, cairoctl))
+                os << (uint32_t)LGI_DOT << x << y << (uint32_t)size;
+            else
+                break;
+        }
+        for (int j = 0; ; j++)
+        {
+            float pos = 0;
+            bool vertical = false;
+            string legend;
+            if (graph->get_gridline(index, j, 0, pos, vertical, legend, cairoctl))
+                os << (uint32_t)LGI_LEGEND << pos << (uint32_t)(vertical ? 1 : 0) << legend;
+            else
+                break;
+        }
+        os << (uint32_t)LGI_END_ITEM;
+    }
+    os << (uint32_t)LGI_END;
+}
+
+calf_plugins::dssi_feedback_sender::dssi_feedback_sender(const char *URI, const line_graph_iface *_graph)
+{
+    graph = _graph;
+    is_client_shared = false;
+    client = new osctl::osc_client;
+    client->bind("0.0.0.0", 0);
+    client->set_url(URI);
+    _context = NULL;
+}
+
+calf_plugins::dssi_feedback_sender::dssi_feedback_sender(osctl::osc_client *_client, const line_graph_iface *_graph)
+{
+    graph = _graph;
+    client = _client;
+    is_client_shared = true;
+    _context = NULL;
+}
+
+void calf_plugins::dssi_feedback_sender::add_graphs(const calf_plugins::parameter_properties *props, int num_params)
+{
+    for (int i = 0; i < num_params; i++)
+    {
+        if (props[i].flags & PF_PROP_GRAPH)
+            indices.push_back(i);
+    }
+}
+
+void calf_plugins::dssi_feedback_sender::update()
+{
+    if (graph)
+    {
+        osc_cairo_control* cairoctl;
+        if (_context)
+        {
+            cairoctl = (osc_cairo_control*)_context;
+            cairoctl->os.clear();
+        }
+        else
+            cairoctl = new osc_cairo_control();
+        serialize_graphs(cairoctl, cairoctl->os, graph, indices);
+        client->send("/lineGraph", cairoctl->os);
+    }
+}
+
+calf_plugins::dssi_feedback_sender::~dssi_feedback_sender()
+{
+    if (_context)
+        delete (osc_cairo_control*)_context;
+    if (!is_client_shared)
+        delete client;
+}
 
 table_via_configure::table_via_configure()
 {
--- origsrc/calf-0.90.3/src/lv2gui.cpp	2018-02-03 06:14:19.000000000 +0900
+++ src/calf-0.90.3/src/lv2gui.cpp	2023-09-13 07:34:00.797168800 +0900
@@ -18,8 +18,11 @@
  * Boston, MA  02110-1301  USA
  */
 #include <sys/wait.h>
+#include <unistd.h>
 #include "config.h"
+#if USE_LV2_GTK_GUI
 #include <calf/gui.h>
+#endif
 #include <calf/giface.h>
 #include <calf/lv2_atom.h>
 #include <calf/lv2_data_access.h>
@@ -27,13 +30,16 @@
 #include <calf/lv2_ui.h>
 #include <calf/lv2_urid.h>
 #include <calf/lv2_external_ui.h>
+#include <calf/lv2_programs.h>
 #include <calf/lv2helpers.h>
+#include <calf/osctlnet.h>
 #include <calf/utils.h>
 #include <glib.h>
 
 using namespace std;
 using namespace calf_plugins;
 using namespace calf_utils;
+using namespace osctl;
 
 struct LV2_Calf_Descriptor {
     plugin_ctl_iface *(*get_pci)(LV2_Handle Instance);
@@ -253,6 +259,7 @@ void plugin_proxy_base::enable_all_sends
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
+#if USE_LV2_GTK_GUI
 /// Plugin controller that uses LV2 host with help of instance/data access to remotely
 /// control a plugin from the GUI
 struct lv2_plugin_proxy: public plugin_ctl_iface, public plugin_proxy_base, public gui_environment
@@ -289,6 +296,7 @@ struct lv2_plugin_proxy: public plugin_c
     
     virtual bool activate_preset(int bank, int program)
     {
+        // TODO
         return false;
     }
     
@@ -551,19 +559,321 @@ int gui_idle(LV2UI_Handle handle)
     return 0;
 }
 
+void gui_select_program(LV2UI_Handle handle, uint32_t bank, uint32_t program)
+{
+    plugin_gui *gui = (plugin_gui *)handle;
+    lv2_plugin_proxy *proxy = dynamic_cast<lv2_plugin_proxy *>(gui->plugin);
+    proxy->activate_preset(bank, program);
+}
+
 const void *gui_extension(const char *uri)
 {
     static const LV2UI_Show_Interface show = { gui_show, gui_hide };
     static const LV2UI_Idle_Interface idle = { gui_idle };
+    static LV2_Programs_UI_Interface uiPrograms = { gui_select_program };
     if (!strcmp(uri, LV2_UI__showInterface))
         return &show;
     if (!strcmp(uri, LV2_UI__idleInterface))
         return &idle;
+    if (strcmp(uri, LV2_PROGRAMS__UIInterface) == 0)
+        return &uiPrograms;
+    return NULL;
+}
+
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////
+
+class ext_plugin_gui: public lv2_external_ui, public plugin_proxy_base, public osc_message_sink<osc_strstream>, public send_updates_iface
+{
+public:
+    GPid child_pid;
+    osc_server srv;
+    osc_client cli;
+    bool confirmed;
+    string prefix;
+    dssi_feedback_sender *feedback_sender;
+    bool enable_graph_updates;
+    osc_inline_typed_strstream status_data;
+
+    ext_plugin_gui(const plugin_metadata_iface *metadata, LV2UI_Write_Function wf, LV2UI_Controller c, const LV2_Feature* const* f);
+
+    bool initialise();
+
+    void show_impl();
+    void hide_impl();
+    void run_impl();
+    void port_event_impl(uint32_t port, uint32_t buffer_size, uint32_t format, const void *buffer);
+
+    bool activate_preset(int bank, int program)
+    {
+        if (confirmed) {
+            osc_inline_typed_strstream str;
+            str << (uint32_t)(bank) << (uint32_t)(program);
+            cli.send("/program", str);
+            return false;
+        }
+        return false;
+    }
+
+    virtual void send_status(const char *key, const char *value);
+    virtual void receive_osc_message(std::string address, std::string args, osc_strstream &buffer);
+    virtual ~ext_plugin_gui();
+        
+private:
+    static void show_(lv2_external_ui *h) { ((ext_plugin_gui *)(h))->show_impl(); }
+    static void hide_(lv2_external_ui *h) { ((ext_plugin_gui *)(h))->hide_impl(); }
+    static void run_(lv2_external_ui *h) { ((ext_plugin_gui *)(h))->run_impl(); }
+};
+
+ext_plugin_gui::ext_plugin_gui(const plugin_metadata_iface *metadata, LV2UI_Write_Function wf, LV2UI_Controller c, const LV2_Feature* const* f)
+: plugin_proxy_base(metadata, wf, c, f)
+{
+    confirmed = false;
+    feedback_sender = NULL;
+    
+    show = show_;
+    hide = hide_;
+    run = run_;
+}
+
+bool ext_plugin_gui::initialise()
+{
+    if (ext_ui_host == NULL)
+        return false;
+    
+    srv.sink = this;
+    srv.bind("127.0.0.1");
+    
+    return true;
+}
+
+void ext_plugin_gui::show_impl()
+{
+    struct osc_configure_sender: public send_configure_iface
+    {
+        osc_client &cli;
+        
+        osc_configure_sender(osc_client &c)
+        : cli(c)
+        {
+        }
+        
+        virtual void send_configure(const char *key, const char *value)
+        {
+            osc_inline_typed_strstream data;
+            data << key;
+            data << value;
+            cli.send("/configure", data);
+        }
+    };
+
+    osc_configure_sender sender(cli);
+    
+    if (instance)
+        instance->send_configures(&sender);
+    
+    cli.send("/show");
+}
+
+void ext_plugin_gui::hide_impl()
+{
+    cli.send("/hide");
+}
+
+void ext_plugin_gui::send_status(const char *key, const char *value)
+{
+    status_data << key << value;
+}
+
+void ext_plugin_gui::port_event_impl(uint32_t port, uint32_t buffer_size, uint32_t format, const void *buffer)
+{
+    assert(confirmed);
+    assert(port >= (uint32_t)param_offset);
+    if (port >= (uint32_t)param_offset)
+    {
+        int param = port - param_offset;
+        if (!sends[param])
+            return;
+        TempSendSetter _a_(sends[param], false);
+        if (format == 0)
+        {
+            osc_inline_typed_strstream data;
+            data << port; 
+            data << *(float *)buffer;
+            cli.send("/control", data);
+        }
+    }
+}
+
+void ext_plugin_gui::run_impl()
+{
+    srv.read_from_socket();
+    if (waitpid(child_pid, NULL, WNOHANG) != 0)
+    {
+        ext_ui_host->ui_closed(controller);
+        return;
+    }
+    if (feedback_sender && enable_graph_updates)
+        feedback_sender->update();
+}
+
+void ext_plugin_gui::receive_osc_message(std::string address, std::string args, osc_strstream &buffer)
+{
+    if (address == "/bridge/update" && args == "s")
+    {
+        if (confirmed)
+        {
+            g_warning("Update message already received, ignoring");
+            return;
+        }
+        string url;
+        buffer >> url;
+        cli.bind();
+        cli.set_url(url.c_str());
+        if (get_line_graph_iface())
+        {
+            feedback_sender = new dssi_feedback_sender(&cli, get_line_graph_iface());
+            feedback_sender->add_graphs(plugin_metadata->get_param_props(0), param_count);
+        }
+        confirmed = true;
+    }
+    else
+    if (address == "/bridge/control" && args == "if")
+    {
+        int port;
+        float value;
+        buffer >> port >> value;
+        assert(port >= param_offset);
+        send_float_to_host(port - param_offset, value);
+    }
+    else
+    if (address == "/bridge/enable_updates" && args == "i")
+    {
+        int updates;
+        buffer >> updates;
+        enable_graph_updates = updates != 0;
+        if (enable_graph_updates && feedback_sender)
+            feedback_sender->update();
+    }
+    else
+    if (address == "/bridge/configure" && (args == "s" || args == "ss"))
+    {
+        string key, value;
+        buffer >> key;
+        if (args == "ss")
+        {
+            buffer >> value;
+            plugin_proxy_base::configure(key.c_str(), value.c_str());
+        }
+        else
+            plugin_proxy_base::configure(key.c_str(), NULL);
+    }
+    else
+    if (address == "/bridge/send_status" && args == "i")
+    {
+        if (instance)
+        {
+            int serial;
+            buffer >> serial;
+
+            status_data.clear();
+            status_data << (uint32_t)instance->send_status_updates(this, serial);
+            cli.send("/status_data", status_data);
+        }
+    }
+    else
+        srv.dump.receive_osc_message(address, args, buffer);
+}
+
+ext_plugin_gui::~ext_plugin_gui()
+{
+    if (confirmed)
+    {
+        cli.send("/quit");
+    }
+    if (feedback_sender)
+        delete feedback_sender;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////
+
+LV2UI_Handle extgui_instantiate(const struct _LV2UI_Descriptor* descriptor,
+                          const char*                     plugin_uri,
+                          const char*                     bundle_path,
+                          LV2UI_Write_Function            write_function,
+                          LV2UI_Controller                controller,
+                          LV2UI_Widget*                   widget,
+                          const LV2_Feature* const*       features)
+{
+    const plugin_metadata_iface *plugin_metadata = plugin_registry::instance().get_by_uri(plugin_uri);
+    if (!plugin_metadata)
+        return NULL;
+    
+    ext_plugin_gui *ui = new ext_plugin_gui(plugin_metadata, write_function, controller, features);
+    if (!ui->initialise())
+        return NULL;
+    
+    string url = ui->srv.get_url() + "/bridge";
+    const gchar *argv[] = { "./calf_gtk", url.c_str(), "calf.so", plugin_uri, (ui->ext_ui_host->plugin_human_id ? ui->ext_ui_host->plugin_human_id : "Unknown"), NULL };
+    GError *error = NULL;
+    if (g_spawn_async(bundle_path, (gchar **)argv, NULL, (GSpawnFlags)G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &ui->child_pid, &error))
+    {
+        // wait for the sign of life from the GUI
+        while(!ui->confirmed && waitpid(ui->child_pid, NULL, WNOHANG) == 0)
+        {
+            printf("Waiting for the GUI to open\n");
+            ui->srv.read_from_socket();
+            usleep(500000);
+        }
+        
+        if (ui->confirmed)
+        {
+            *(lv2_external_ui **)widget = ui;
+            ui->enable_all_sends();
+            return (LV2UI_Handle)ui;
+        }
+        else
+        {
+            g_warning("The GUI exited before establishing contact with the host");
+            return NULL;
+        }
+    }
+    else
+    {
+        g_warning("%s", error->message);
+        return NULL;
+    }
+}
+
+void extgui_cleanup(LV2UI_Handle handle)
+{
+    ext_plugin_gui *gui = (ext_plugin_gui *)handle;
+    delete gui;
+}
+
+void extgui_port_event(LV2UI_Handle handle, uint32_t port, uint32_t buffer_size, uint32_t format, const void *buffer)
+{
+    ((ext_plugin_gui *)handle)->port_event_impl(port, buffer_size, format, buffer);;
+}
+
+void extgui_select_program(LV2UI_Handle handle, uint32_t bank, uint32_t program)
+{
+    ((ext_plugin_gui *)handle)->activate_preset(bank, program);
+}
+
+const void *extgui_extension(const char *uri)
+{
+    printf("extgui_extension %s\n", uri);
+    static LV2_Programs_UI_Interface uiProgramsExt = { extgui_select_program };
+    if (strcmp(uri, LV2_PROGRAMS__UIInterface) == 0)
+        return &uiProgramsExt;
     return NULL;
 }
 
 const LV2UI_Descriptor* lv2ui_descriptor(uint32_t index)
 {
+#if USE_LV2_GTK_GUI
     static LV2UI_Descriptor gtkgui;
     gtkgui.URI = "http://calf.sourceforge.net/plugins/gui/gtk2-gui";
     gtkgui.instantiate = gui_instantiate;
@@ -572,15 +882,15 @@ const LV2UI_Descriptor* lv2ui_descriptor
     gtkgui.extension_data = gui_extension;
     if (!index--)
         return &gtkgui;
-    
-    static LV2UI_Descriptor gtkguireq;
-    gtkguireq.URI = "http://calf.sourceforge.net/plugins/gui/gtk2-gui-req";
-    gtkguireq.instantiate = gui_instantiate;
-    gtkguireq.cleanup = gui_cleanup;
-    gtkguireq.port_event = gui_port_event;
-    gtkguireq.extension_data = gui_extension;
+#endif
+    static LV2UI_Descriptor extgui;
+    extgui.URI = "http://calf.sourceforge.net/plugins/gui/ext-gui";
+    extgui.instantiate = extgui_instantiate;
+    extgui.cleanup = extgui_cleanup;
+    extgui.port_event = extgui_port_event;
+    extgui.extension_data = extgui_extension;
     if (!index--)
-        return &gtkguireq;
+        return &extgui;
     
     return NULL;
 }
--- origsrc/calf-0.90.3/src/lv2wrap.cpp	2018-01-31 07:46:08.000000000 +0900
+++ src/calf-0.90.3/src/lv2wrap.cpp	2023-09-13 07:34:00.797168800 +0900
@@ -23,6 +23,9 @@ lv2_instance::lv2_instance(audio_module_
 
     srate_to_set = 44100;
     set_srate = true;
+        
+    presets = NULL;
+    preset_descs = NULL;
 }
 
 void lv2_instance::lv2_instantiate(const LV2_Descriptor * Descriptor, double sample_rate, const char *bundle_path, const LV2_Feature *const *features)
@@ -82,6 +85,30 @@ void lv2_instance::post_instantiate()
         assert(property_type);
     }
     module->post_instantiate(srate_to_set);
+
+    presets = new std::vector<plugin_preset>;
+    preset_descs = new std::vector<LV2_Program_Descriptor>;
+
+    preset_list plist_tmp, plist;
+    plist.load_defaults(true);
+    plist_tmp.load_defaults(false);
+    plist.presets.insert(plist.presets.end(), plist_tmp.presets.begin(), plist_tmp.presets.end());
+
+    int pos = 1;
+    const char* label = metadata->get_label();
+
+    for (unsigned int i = 0; i < plist.presets.size(); i++)
+    {
+        plugin_preset &pp = plist.presets[i];
+        if (strcasecmp(pp.plugin.c_str(), label))
+            continue;
+        LV2_Program_Descriptor pd;
+        pd.bank = pos >> 7;
+        pd.program = pos++;
+        pd.name = pp.name.c_str();
+        preset_descs->push_back(pd);
+        presets->push_back(pp);
+    }
 }
 
 void lv2_instance::impl_restore(LV2_State_Retrieve_Function retrieve, void *callback_data)
--- origsrc/calf-0.90.3/src/makerdf.cpp	2019-03-04 06:24:12.000000000 +0900
+++ src/calf-0.90.3/src/makerdf.cpp	2023-09-13 07:34:00.797168800 +0900
@@ -25,6 +25,7 @@
 #include "lv2/lv2plug.in/ns/lv2core/lv2.h"
 #include <calf/lv2_atom.h>
 #include <calf/lv2_options.h>
+#include <calf/lv2_programs.h>
 #include <calf/lv2_state.h>
 #include <calf/lv2_urid.h>
 #endif
@@ -58,6 +59,118 @@ static FILE *open_and_check(const std::s
     return f;
 }
 
+#if USE_LADSPA
+
+static std::string unit_to_string(const parameter_properties &props)
+{
+    uint32_t flags = props.flags & PF_UNITMASK;
+    
+    switch(flags) {
+        case PF_UNIT_DB:
+            return "ladspa:hasUnit=\"&ladspa;dB\" ";
+        case PF_UNIT_COEF:
+            return "ladspa:hasUnit=\"&ladspa;coef\" ";
+        case PF_UNIT_HZ:
+            return "ladspa:hasUnit=\"&ladspa;Hz\" ";
+        case PF_UNIT_SEC:
+            return "ladspa:hasUnit=\"&ladspa;seconds\" ";
+        case PF_UNIT_MSEC:
+            return "ladspa:hasUnit=\"&ladspa;milliseconds\" ";
+        default:
+            return string();
+    }
+}
+
+static std::string scale_to_string(const parameter_properties &props)
+{
+    if ((props.flags & PF_TYPEMASK) != PF_ENUM) {
+        return "/";
+    }
+    string tmp = "><ladspa:hasScale><ladspa:Scale>\n";
+    for (int i = (int)props.min; i <= (int)props.max; i++) {
+        tmp += "          <ladspa:hasPoint><ladspa:Point rdf:value=\""+i2s(i)+"\" ladspa:hasLabel=\""+props.choices[(int)(i - props.min)]+"\" /></ladspa:hasPoint>\n";
+    }
+    return tmp+"        </ladspa:Scale></ladspa:hasScale></ladspa:InputControlPort";
+}
+
+std::string generate_ladspa_rdf(const ladspa_plugin_info &info, const parameter_properties *params, const char *param_names[], unsigned int count,
+                                       unsigned int ctl_ofs)
+{
+    string rdf;
+    string plugin_id = "&ladspa;" + i2s(info.unique_id);
+    string plugin_type = string(info.plugin_type); 
+    
+    rdf += "  <ladspa:" + plugin_type + " rdf:about=\"" + plugin_id + "\">\n";
+    rdf += "    <dc:creator>" + xml_escape(info.maker) + "</dc:creator>\n";
+    rdf += "    <dc:title>" + xml_escape(info.name) + "</dc:title>\n";
+    
+    for (unsigned int i = 0; i < count; i++) {
+        rdf += 
+            "    <ladspa:hasPort>\n"
+            "      <ladspa:" + string(params[i].flags & PF_PROP_OUTPUT ? "Output" : "Input") 
+            + "ControlPort rdf:about=\"" + plugin_id + "."+i2s(ctl_ofs + i)+"\" "
+            + unit_to_string(params[i]) +
+            "ladspa:hasLabel=\"" + params[i].short_name + "\" "
+            + scale_to_string(params[i]) + 
+            ">\n"
+            "    </ladspa:hasPort>\n";
+    }
+    rdf += "    <ladspa:hasSetting>\n"
+        "      <ladspa:Default>\n";
+    for (unsigned int i = 0; i < count; i++) {
+        rdf += 
+            "        <ladspa:hasPortValue>\n"
+            "           <ladspa:PortValue rdf:value=\"" + f2s(params[i].def_value) + "\">\n"
+            "             <ladspa:forPort rdf:resource=\"" + plugin_id + "." + i2s(ctl_ofs + i) + "\"/>\n"
+            "           </ladspa:PortValue>\n"
+            "        </ladspa:hasPortValue>\n";
+    }
+    rdf += "      </ladspa:Default>\n"
+        "    </ladspa:hasSetting>\n";
+
+    rdf += "  </ladspa:" + plugin_type + ">\n";
+    return rdf;
+}
+
+void make_rdf()
+{
+    string rdf;
+    rdf = 
+        "<?xml version='1.0' encoding='ISO-8859-1'?>\n"
+        "<!DOCTYPE rdf:RDF [\n"
+        "  <!ENTITY rdf 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'>\n"
+        "  <!ENTITY rdfs 'http://www.w3.org/2000/01/rdf-schema#'>\n"
+        "  <!ENTITY dc 'http://purl.org/dc/elements/1.1/'>\n"
+        "  <!ENTITY ladspa 'http://ladspa.org/ontology#'>\n"
+        "]>\n";
+    
+    rdf += "<rdf:RDF xmlns:rdf=\"&rdf;\" xmlns:rdfs=\"&rdfs;\" xmlns:dc=\"&dc;\" xmlns:ladspa=\"&ladspa;\">\n";
+
+    const plugin_registry::plugin_vector &plugins = plugin_registry::instance().get_all();
+    set<int> used_ids;
+    for (unsigned int i = 0; i < plugins.size(); i++)
+    {
+        const plugin_metadata_iface *p = plugins[i];
+        const ladspa_plugin_info &info = p->get_plugin_info();
+        
+        if(used_ids.count(info.unique_id))
+        {
+            fprintf(stderr, "ERROR: Duplicate ID %d in plugin %s\n", info.unique_id, info.name);
+            assert(0);
+        }
+        used_ids.insert(info.unique_id);
+
+        if (!p->requires_midi()) {
+            rdf += generate_ladspa_rdf(info, p->get_param_props(0), p->get_port_names(), p->get_param_count(), p->get_param_port_offset());
+        }
+        delete p;
+    }    
+    rdf += "</rdf:RDF>\n";
+    
+    printf("%s\n", rdf.c_str());
+}
+#endif
+
 #if USE_LV2
 static void add_port(string &ports, const char *symbol, const char *name, const char *direction, int pidx, const char *type = "lv2:AudioPort", bool optional = false)
 {
@@ -257,13 +370,14 @@ void make_ttl(string path_prefix, const
     string gui_header;
     
 #if USE_LV2_GUI
+#if USE_LV2_GTK_GUI
     string gtkgui_uri     = "<" + plugin_uri_prefix + "gui/gtk2-gui>";
     string gtkgui_uri_req = "<" + plugin_uri_prefix + "gui/gtk2-gui-req>";
     gui_header = gtkgui_uri + "\n"
         "    a uiext:GtkUI ;\n"
         "    lv2:extensionData uiext:idleInterface ,\n"
         "        uiext:showInterface ;\n"
-        "    lv2:requiredFeature uiext:makeResident ;\n"
+        "    lv2:optionalFeature uiext:noUserResize .\n"
         "    lv2:optionalFeature <http://lv2plug.in/ns/ext/data-access> ;\n"
         //"    lv2:optionalFeature <" LV2_OPTIONS_URI "> ;\n"
         //"    lv2:optionalFeature <" LV2_ATOM_URI "> ;\n"
@@ -272,7 +386,7 @@ void make_ttl(string path_prefix, const
         "    a uiext:GtkUI ;\n"
         "    lv2:extensionData uiext:idleInterface ,\n"
         "        uiext:showInterface ;\n"
-        "    lv2:requiredFeature uiext:makeResident ;\n"
+        "    lv2:optionalFeature uiext:noUserResize .\n"
         "    lv2:requiredFeature <http://lv2plug.in/ns/ext/instance-access> ;\n"
         "    lv2:requiredFeature <http://lv2plug.in/ns/ext/data-access> ;\n"
         //"    lv2:optionalFeature <" LV2_OPTIONS_URI "> ;\n"
@@ -280,6 +394,13 @@ void make_ttl(string path_prefix, const
         "    uiext:binary <calflv2gui.so> .\n"
     ;
 #endif
+    string extgui_uri = "<http://calf.sourceforge.net/plugins/gui/ext-gui>";
+    gui_header += extgui_uri + "\n"
+        "    a uiext:external ;\n"
+        "    uiext:binary <calflv2gui.so> .\n"
+        "\n"
+    ;
+#endif
     
     map<string, pair<string, string> > id_to_info;
     
@@ -295,7 +416,7 @@ void make_ttl(string path_prefix, const
         ttl = "@prefix : <" + unquoted_uri + "#> .\n";
         ttl += header + gui_header + "\n";
 
-#if USE_LV2_GUI
+#if USE_LV2_GTK_GUI
         string gui_uri = (pi->requires_instance_access()) ? gtkgui_uri_req : gtkgui_uri;
 
         for (int j = 0; j < pi->get_param_count(); j++)
@@ -305,6 +426,7 @@ void make_ttl(string path_prefix, const
             {
                 string portnot = " uiext:portNotification [\n    uiext:plugin " + uri + " ;\n    uiext:portIndex " + i2s(j) + "\n] .\n\n";
                 ttl += gui_uri + portnot;
+                ttl += extgui_uri + portnot;
             }
         }
 #endif
@@ -342,7 +464,12 @@ void make_ttl(string path_prefix, const
         ttl += "    doap:maintainer <http://calf.sourceforge.net/team> ;\n";
 
 #if USE_LV2_GUI
-        ttl += "    uiext:ui " + gui_uri + " ;\n";
+#if USE_LV2_GTK_GUI
+        ttl += "    uiext:ui <http://calf.sourceforge.net/plugins/gui/ext-gui> ,\n";
+        ttl += "             <http://calf.sourceforge.net/plugins/gui/gtk2-gui> ;\n";
+#else
+        ttl += "    uiext:ui <http://calf.sourceforge.net/plugins/gui/ext-gui> ;\n";
+#endif
 #endif
         
         ttl += "    dct:replaces <urn:ladspa:" + i2s(lpi.unique_id) + "> ;\n";
@@ -360,6 +487,8 @@ void make_ttl(string path_prefix, const
             }
         }
         
+        ttl += "    lv2:extensionData <" LV2_PROGRAMS__Interface "> ;\n";
+
         vector<string> configure_keys;
         pi->get_configure_vars(configure_keys);
         if (!configure_keys.empty())
@@ -489,11 +618,7 @@ void make_ttl(string path_prefix, const
             + string(plugins[i]->get_plugin_info().label)
             + "> a lv2:Plugin ;\n    dct:replaces <urn:ladspa:"
             + i2s(plugins[i]->get_plugin_info().unique_id) + "> ;\n    "
-            + "lv2:binary <calf.so> ; rdfs:seeAlso <" + label + ".ttl> ";
-        if (preset_data.count(label))
-            ttl += ", <presets-" + label + ".ttl>";
-        ttl += ".\n";
-        
+            + "lv2:binary <calf.so> ; rdfs:seeAlso <" + label + ".ttl> .\n";
     }
     FILE *f = open_and_check(path_prefix+"manifest.ttl");
     fprintf(f, "%s\n", ttl.c_str());
@@ -649,7 +774,7 @@ int main(int argc, char *argv[])
         switch(c) {
             case 'h':
             case '?':
-                printf("LV2 TTL / XML GUI generator for Calf plugin pack\nSyntax: %s [--help] [--version] [--mode rdf|ttl|gui] [--path <path>]\n", argv[0]);
+                printf("LADSPA RDF / LV2 TTL / XML GUI generator for Calf plugin pack\nSyntax: %s [--help] [--version] [--mode rdf|ttl|gui] [--path <path>]\n", argv[0]);
                 return 0;
             case 'v':
                 printf("%s\n", PACKAGE_STRING);
@@ -685,6 +810,11 @@ int main(int argc, char *argv[])
                 break;
         }
     }
+#if USE_LADSPA
+    if (mode == "rdf")
+        make_rdf();
+    else
+#endif
 #if USE_LV2
     if (mode == "ttl")
         make_ttl(path_prefix, !pkglibdir_path.empty() ? &pkglibdir_path : NULL);
--- origsrc/calf-0.90.3/src/metadata.cpp	2018-12-17 03:35:32.000000000 +0900
+++ src/calf-0.90.3/src/metadata.cpp	2023-09-13 07:34:00.797168800 +0900
@@ -345,7 +345,8 @@ CALF_PORT_PROPS(reverse_delay) = {
     {}
 };
 
-CALF_PLUGIN_INFO(reverse_delay) = { 0x8482, "ReverseDelay", "Calf Reverse Delay", "Calf Studio Gear", calf_plugins::calf_copyright_info, "DelayPlugin" };
+/* NOTE: A lax value is assigned for ID. */
+CALF_PLUGIN_INFO(reverse_delay) = { 0x8487, "ReverseDelay", "Calf Reverse Delay", "Calf Studio Gear", calf_plugins::calf_copyright_info, "DelayPlugin" };
 
 ////////////////////////////////////////////////////////////////////////////
 
@@ -1027,7 +1028,8 @@ CALF_PORT_PROPS(equalizer30band) = {
     {}
 };
 
-CALF_PLUGIN_INFO(equalizer30band) = { 0x8514, "Equalizer30Band", "Calf Equalizer 30 Band", "Calf Studio Gear", calf_plugins::calf_copyright_info, "EQPlugin" };
+/* NOTE: A lax value is assigned for ID. */
+CALF_PLUGIN_INFO(equalizer30band) = { 0x851a, "Equalizer30Band", "Calf Equalizer 30 Band", "Calf Studio Gear", calf_plugins::calf_copyright_info, "EQPlugin" };
 
 ////////////////////////////////////////////////////////////////////////////
 
@@ -1053,7 +1055,8 @@ CALF_PORT_PROPS(xover2) = {
     XOVER_BAND_PARAMS(2)
     {}
 };
-CALF_PLUGIN_INFO(xover2) = { 0x8515, "XOver2Band", "Calf X-Over 2 Band", "Calf Studio Gear", calf_plugins::calf_copyright_info, "UtilityPlugin" };
+/* NOTE: A lax value is assigned for ID. */
+CALF_PLUGIN_INFO(xover2) = { 0x851b, "XOver2Band", "Calf X-Over 2 Band", "Calf Studio Gear", calf_plugins::calf_copyright_info, "UtilityPlugin" };
 
 ////////////////////////////////////////////////////////////////////////////
 
@@ -1071,7 +1074,8 @@ CALF_PORT_PROPS(xover3) = {
     XOVER_BAND_PARAMS(3)
     {}
 };
-CALF_PLUGIN_INFO(xover3) = { 0x8515, "XOver3Band", "Calf X-Over 3 Band", "Calf Studio Gear", calf_plugins::calf_copyright_info, "UtilityPlugin" };
+/* NOTE: A lax value is assigned for ID. */
+CALF_PLUGIN_INFO(xover3) = { 0x851c, "XOver3Band", "Calf X-Over 3 Band", "Calf Studio Gear", calf_plugins::calf_copyright_info, "UtilityPlugin" };
 
 ////////////////////////////////////////////////////////////////////////////
 
@@ -1091,7 +1095,8 @@ CALF_PORT_PROPS(xover4) = {
     XOVER_BAND_PARAMS(4)
     {}
 };
-CALF_PLUGIN_INFO(xover4) = { 0x8515, "XOver4Band", "Calf X-Over 4 Band", "Calf Studio Gear", calf_plugins::calf_copyright_info, "UtilityPlugin" };
+/* NOTE: A lax value is assigned for ID. */
+CALF_PLUGIN_INFO(xover4) = { 0x851d, "XOver4Band", "Calf X-Over 4 Band", "Calf Studio Gear", calf_plugins::calf_copyright_info, "UtilityPlugin" };
 
 ////////////////////////////////////////////////////////////////////////////
 
@@ -1184,7 +1189,8 @@ CALF_PORT_PROPS(vocoder) = {
     {}
 };
 
-CALF_PLUGIN_INFO(vocoder) = { 0x8514, "Vocoder", "Calf Vocoder", "Calf Studio Gear", calf_plugins::calf_copyright_info, "FilterPlugin" };
+/* NOTE: A lax value is assigned for ID. */
+CALF_PLUGIN_INFO(vocoder) = { 0x8519, "Vocoder", "Calf Vocoder", "Calf Studio Gear", calf_plugins::calf_copyright_info, "FilterPlugin" };
 
 
 ////////////////////////////////////////////////////////////////////////////
@@ -1251,7 +1257,8 @@ CALF_PORT_PROPS(ringmodulator) = {
     {}
 };
 
-CALF_PLUGIN_INFO(ringmodulator) = { 0x8514, "RingModulator", "Calf Ring Modulator", "Calf Studio Gear", calf_plugins::calf_copyright_info, "ModulatorPlugin" };
+/* NOTE: A lax value is assigned for ID. */
+CALF_PLUGIN_INFO(ringmodulator) = { 0x8518, "RingModulator", "Calf Ring Modulator", "Calf Studio Gear", calf_plugins::calf_copyright_info, "ModulatorPlugin" };
 
 
 ////////////////////////////////////////////////////////////////////////////
@@ -1372,7 +1379,8 @@ CALF_PORT_PROPS(stereo) = {
     {}
 };
 
-CALF_PLUGIN_INFO(stereo) = { 0x8588, "StereoTools", "Calf Stereo Tools", "Calf Studio Gear", calf_plugins::calf_copyright_info, "SpatialPlugin" };
+/* NOTE: A lax value is assigned for ID. */
+CALF_PLUGIN_INFO(stereo) = { 0x858b, "StereoTools", "Calf Stereo Tools", "Calf Studio Gear", calf_plugins::calf_copyright_info, "SpatialPlugin" };
 
 ////////////////////////////////////////////////////////////////////////////
 
@@ -1539,7 +1547,8 @@ CALF_PORT_PROPS(analyzer) = {
     {}
 };
 
-CALF_PLUGIN_INFO(analyzer) = { 0x8588, "Analyzer", "Calf Analyzer", "Calf Studio Gear", calf_plugins::calf_copyright_info, "AnalyserPlugin" };
+/* NOTE: A lax value is assigned for ID. */
+CALF_PLUGIN_INFO(analyzer) = { 0x858c, "Analyzer", "Calf Analyzer", "Calf Studio Gear", calf_plugins::calf_copyright_info, "AnalyserPlugin" };
 
 ////////////////////////////////////////////////////////////////////////////
 const char *transientdesigner_view_names[] = { "Output", "Envelope", "Attack", "Release" };
@@ -1566,7 +1575,8 @@ CALF_PORT_PROPS(transientdesigner) = {
     {}
 };
 
-CALF_PLUGIN_INFO(transientdesigner) = { 0x8588, "TransientDesigner", "Calf Transient Designer", "Calf Studio Gear", calf_plugins::calf_copyright_info, "EnvelopePlugin" };
+/* NOTE: A lax value is assigned for ID. */
+CALF_PLUGIN_INFO(transientdesigner) = { 0x858a, "TransientDesigner", "Calf Transient Designer", "Calf Studio Gear", calf_plugins::calf_copyright_info, "EnvelopePlugin" };
 
 ////////////////////////////////////////////////////////////////////////////
 
--- origsrc/calf-0.90.3/src/osctl_glib.cpp	1970-01-01 09:00:00.000000000 +0900
+++ src/calf-0.90.3/src/osctl_glib.cpp	2023-09-13 07:34:00.807158700 +0900
@@ -0,0 +1,44 @@
+/* Calf DSP Library
+ * Open Sound Control UDP server support
+ *
+ * Copyright (C) 2007-2009 Krzysztof Foltman
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#include <calf/osctl_glib.h>
+
+using namespace osctl;
+using namespace std;
+
+void osc_glib_server::on_bind()
+{    
+    ioch = g_io_channel_unix_new(socket);
+    srcid = g_io_add_watch(ioch, G_IO_IN, on_data, this);
+}
+
+gboolean osc_glib_server::on_data(GIOChannel *channel, GIOCondition cond, void *obj)
+{
+    osc_server *self = (osc_server *)obj;
+    self->read_from_socket();
+    return TRUE;
+}
+
+osc_glib_server::~osc_glib_server()
+{
+    if (ioch)
+        g_source_remove(srcid);
+}
--- origsrc/calf-0.90.3/src/osctlnet.cpp	1970-01-01 09:00:00.000000000 +0900
+++ src/calf-0.90.3/src/osctlnet.cpp	2023-09-13 07:34:00.807158700 +0900
@@ -0,0 +1,167 @@
+/* Calf DSP Library
+ * Open Sound Control UDP support
+ *
+ * Copyright (C) 2007-2009 Krzysztof Foltman
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+#include <calf/osctl.h>
+#include <calf/osctlnet.h>
+#include <assert.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <stdlib.h>
+#include <sstream>
+#include <stdio.h>
+#include <unistd.h>
+using namespace osctl;
+using namespace std;
+
+void osc_socket::bind(const char *hostaddr, int port)
+{
+    socket = ::socket(PF_INET, SOCK_DGRAM, 0);
+    if (socket < 0)
+        throw osc_net_exception("socket");
+    
+    sockaddr_in sadr;
+    memset(&sadr, 0, sizeof(sadr));
+    sadr.sin_family = AF_INET;
+    sadr.sin_port = htons(port);
+    inet_aton(hostaddr, &sadr.sin_addr);
+    if (::bind(socket, (sockaddr *)&sadr, sizeof(sadr)) < 0)
+        throw osc_net_exception("bind");
+    on_bind();
+}
+
+std::string osc_socket::get_url() const
+{
+    sockaddr_in sadr;
+    socklen_t len = sizeof(sadr);
+    if (getsockname(socket, (sockaddr *)&sadr, &len) < 0)
+        throw osc_net_exception("getsockname");
+    
+    char name[INET_ADDRSTRLEN], buf[32];
+    
+    inet_ntop(AF_INET, &sadr.sin_addr, name, INET_ADDRSTRLEN);
+    sprintf(buf, "%d", ntohs(sadr.sin_port));
+    
+    return string("osc.udp://") + name + ":" + buf + prefix;
+}
+
+osc_socket::~osc_socket()
+{
+    close(socket);
+}
+
+//////////////////////////////////////////////////////////////
+
+void osc_client::set_addr(const char *hostaddr, int port)
+{
+    addr.sin_family = AF_INET;
+    addr.sin_port = htons(port);
+    inet_aton(hostaddr, &addr.sin_addr);
+}
+
+void osc_client::set_url(const char *url)
+{
+    const char *orig_url = url;
+    if (strncmp(url, "osc.udp://", 10))
+        throw osc_net_bad_address(url);
+    url += 10;
+    
+    const char *pos = strchr(url, ':');
+    const char *pos2 = strchr(url, '/');
+    if (!pos || !pos2)
+        throw osc_net_bad_address(orig_url);
+    
+    // XXXKF perhaps there is a default port for osc.udp?
+    if (pos2 - pos < 0)
+        throw osc_net_bad_address(orig_url);
+    
+    string hostname = string(url, pos - url);
+    int port = atoi(pos + 1);
+    prefix = string(pos2);
+    printf("hostname %s port %d\n", hostname.c_str(), port);
+
+    addr.sin_family = AF_INET;
+    addr.sin_port = htons(port);
+
+    hostent *he = gethostbyname(hostname.c_str());
+    if (!he)
+        throw osc_net_dns_exception("gethostbyname");
+    
+    addr.sin_addr = *(struct in_addr *)he->h_addr;
+}
+
+bool osc_client::send(const std::string &address, osctl::osc_typed_strstream &stream)
+{
+    std::string type_tag = "," + stream.type_buffer->data;
+    osc_inline_strstream hdr;
+    hdr << prefix + address << "," + stream.type_buffer->data;
+    string str = hdr.data + stream.buffer.data;
+    
+    // printf("sending %s\n", str.buffer.c_str());
+
+    return ::sendto(socket, str.data(), str.length(), 0, (sockaddr *)&addr, sizeof(addr)) == (int)str.length();
+}
+
+bool osc_client::send(const std::string &address)
+{
+    osc_inline_strstream hdr;
+    hdr << prefix + address << ",";
+    
+    return ::sendto(socket, hdr.data.data(), hdr.data.length(), 0, (sockaddr *)&addr, sizeof(addr)) == (int)hdr.data.length();
+}
+
+void osc_server::parse_message(const char *buffer, int len)
+{
+    osctl::string_buffer buf(string(buffer, len));
+    osc_strstream str(buf);
+    string address, type_tag;
+    str >> address;
+    str >> type_tag;
+    // cout << "Address " << address << " type tag " << type_tag << endl << flush;
+    if (!address.empty() && address[0] == '/'
+      &&!type_tag.empty() && type_tag[0] == ',')
+    {
+        sink->receive_osc_message(address, type_tag.substr(1), str);
+    }
+}
+
+void osc_server::read_from_socket()
+{
+    do {
+        char buf[65536];
+        int len = recv(socket, buf, 65536, MSG_DONTWAIT);
+        if (len > 0)
+        {
+            if (buf[0] == '/')
+            {
+                parse_message(buf, len);
+            }
+            if (buf[0] == '#')
+            {
+                // XXXKF bundles are not supported yet
+            }
+        }
+        else
+            break;
+    } while(1);
+}
+
+osc_server::~osc_server()
+{
+}
--- origsrc/calf-0.90.3/src/plugin.cpp	2018-01-31 07:46:08.000000000 +0900
+++ src/calf-0.90.3/src/plugin.cpp	2023-09-13 07:34:00.807158700 +0900
@@ -19,6 +19,7 @@
  * Boston, MA  02110-1301  USA
  */
 #include <config.h>
+#include <calf/ladspa_wrap.h>
 #include <calf/lv2wrap.h>
 #include <calf/modules_tools.h>
 #include <calf/modules_delay.h>
@@ -31,8 +32,451 @@
 #include <calf/modules_pitch.h>
 #include <calf/modules_synths.h>
 #include <calf/organ.h>
+#include <calf/osctlnet.h>
 
 using namespace calf_plugins;
+using namespace osctl;
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+#if USE_LADSPA
+
+ladspa_instance::ladspa_instance(audio_module_iface *_module, ladspa_plugin_metadata_set *_ladspa, int sample_rate)
+{
+    module = _module;
+    metadata = module->get_metadata_iface();
+    ladspa = _ladspa;
+    
+    module->get_port_arrays(ins, outs, params);
+    
+    activate_flag = true;
+#if USE_DSSI
+    feedback_sender = NULL;
+#endif
+
+    module->set_sample_rate(sample_rate);
+    module->post_instantiate(sample_rate);
+}
+
+float ladspa_instance::get_param_value(int param_no)
+{
+    // XXXKF hack
+    if (param_no >= ladspa->param_count)
+        return 0;
+    return *params[param_no];
+}
+
+void ladspa_instance::set_param_value(int param_no, float value)
+{
+    // XXXKF hack
+    if (param_no >= ladspa->param_count)
+        return;
+    *params[param_no] = value;
+}
+
+bool ladspa_instance::activate_preset(int bank, int program)
+{
+    return false;
+}
+
+/// LADSPA run function - does set sample rate / activate logic when it's run first time after activation
+void ladspa_instance::run(unsigned long SampleCount)
+{
+    if (activate_flag)
+    {
+        module->activate();
+        activate_flag = false;
+    }
+    module->params_changed();
+    module->process_slice(0, SampleCount);
+}
+
+#if USE_DSSI
+
+void ladspa_instance::run_synth(unsigned long SampleCount, snd_seq_event_t *Events, unsigned long EventCount)
+{
+    if (activate_flag)
+    {
+        module->activate();
+        activate_flag = false;
+    }
+    module->params_changed();
+    
+    uint32_t offset = 0;
+    for (uint32_t e = 0; e < EventCount; e++)
+    {
+        uint32_t timestamp = Events[e].time.tick;
+        if (timestamp != offset)
+            module->process_slice(offset, timestamp);
+        process_dssi_event(Events[e]);
+        offset = timestamp;
+    }
+    if (offset != SampleCount)
+        module->process_slice(offset, SampleCount);
+}
+
+#endif
+
+char *ladspa_instance::configure(const char *key, const char *value)
+{
+#if USE_DSSI_GUI
+    if (!strcmp(key, "OSC:FEEDBACK_URI"))
+    {
+        const line_graph_iface *lgi = dynamic_cast<const line_graph_iface *>(metadata);
+        //if (!lgi)
+        //    return NULL;
+        if (*value)
+        {
+            if (feedback_sender) {
+                delete feedback_sender;
+                feedback_sender = NULL;
+            }
+            feedback_sender = new dssi_feedback_sender(value, lgi);
+            feedback_sender->add_graphs(metadata->get_param_props(0), metadata->get_param_count());
+        }
+        else
+        {
+            if (feedback_sender) {
+                delete feedback_sender;
+                feedback_sender = NULL;
+            }
+        }
+        return NULL;
+    }
+    else 
+    if (!strcmp(key, "OSC:UPDATE"))
+    {
+        if (feedback_sender)
+            feedback_sender->update();
+        return NULL;
+    }
+    else 
+    if (!strcmp(key, "OSC:SEND_STATUS"))
+    {
+        if (!feedback_sender)
+            return NULL;
+        struct status_gatherer: public send_updates_iface
+        {
+            osc_inline_typed_strstream str;            
+            void send_status(const char *key, const char *value)
+            {
+                str << key << value;
+            }
+        } sg;
+        int serial = atoi(value);
+        serial = module->send_status_updates(&sg, serial);
+        sg.str << (uint32_t)serial;
+        feedback_sender->client->send("/status_data", sg.str);
+        return NULL;
+    }
+    else
+#endif
+    if (!strcmp(key, "ExecCommand"))
+    {
+        if (*value)
+        {
+            execute(atoi(value));
+        }
+        return NULL;
+    }
+    return module->configure(key, value);
+}
+
+template<class Module>
+ladspa_plugin_metadata_set ladspa_wrapper<Module>::output;
+
+#if USE_DSSI
+
+/// Utility function: handle MIDI event (only handles a subset in this version)
+void ladspa_instance::process_dssi_event(snd_seq_event_t &event)
+{
+    switch(event.type) {
+        case SND_SEQ_EVENT_NOTEON:
+            module->note_on(event.data.note.channel, event.data.note.note, event.data.note.velocity);
+            break;
+        case SND_SEQ_EVENT_NOTEOFF:
+            module->note_off(event.data.note.channel, event.data.note.note, event.data.note.velocity);
+            break;
+        case SND_SEQ_EVENT_PGMCHANGE:
+            module->program_change(event.data.control.channel, event.data.control.value);
+            break;
+        case SND_SEQ_EVENT_CONTROLLER:
+            module->control_change(event.data.control.channel, event.data.control.param, event.data.control.value);
+            break;
+        case SND_SEQ_EVENT_PITCHBEND:
+            module->pitch_bend(event.data.control.channel, event.data.control.value);
+            break;
+        case SND_SEQ_EVENT_CHANPRESS:
+            module->channel_pressure(event.data.control.channel, event.data.control.value);
+            break;
+    }
+}
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// LADSPA callbacks
+
+/// LADSPA activate function (note that at this moment the ports are not set)
+static void cb_activate(LADSPA_Handle Instance)
+{
+    ((ladspa_instance *)(Instance))->activate_flag = true;
+}
+
+/// LADSPA run function - does set sample rate / activate logic when it's run first time after activation
+static void cb_run(LADSPA_Handle Instance, unsigned long SampleCount) {
+    ((ladspa_instance *)(Instance))->run(SampleCount);
+}
+
+/// LADSPA port connection function
+static void cb_connect(LADSPA_Handle Instance, unsigned long port, LADSPA_Data *DataLocation)
+{
+    ladspa_instance *const mod = (ladspa_instance *)Instance;
+    
+    int first_out = mod->ladspa->input_count;
+    int first_param = first_out + mod->ladspa->output_count;
+    int ladspa_port_count = first_param + mod->ladspa->param_count;
+    
+    if ((int)port < first_out)
+        mod->ins[port] = DataLocation;
+    else if ((int)port < first_param)
+        mod->outs[port - first_out] = DataLocation;
+    else if ((int)port < ladspa_port_count) {
+        int i = port - first_param;
+        mod->params[i] = DataLocation;
+        *mod->params[i] = mod->metadata->get_param_props(i)->def_value;
+    }
+}
+
+
+/// LADSPA deactivate function
+static void cb_deactivate(LADSPA_Handle Instance) {
+    ((ladspa_instance *)(Instance))->module->deactivate();
+}
+
+/// LADSPA cleanup (delete instance) function
+static void cb_cleanup(LADSPA_Handle Instance) {
+    delete ((ladspa_instance *)(Instance));
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// DSSI callbacks
+
+#if USE_DSSI
+/// DSSI "run synth" function, same as run() except it allows for event delivery
+static void cb_run_synth(LADSPA_Handle Instance, unsigned long SampleCount, 
+        snd_seq_event_t *Events, unsigned long EventCount) {
+    ((ladspa_instance *)(Instance))->run_synth(SampleCount, Events, EventCount);
+}
+
+/// DSSI configure function (named properties)
+static char *cb_configure(LADSPA_Handle Instance,
+                   const char *Key,
+                   const char *Value)
+{
+    return ((ladspa_instance *)(Instance))->configure(Key, Value);
+}
+
+/// DSSI get program descriptor function; for 0, it returns the default program (from parameter properties table), for others, it uses global or user preset
+static const DSSI_Program_Descriptor *cb_get_program(LADSPA_Handle Instance, unsigned long index)
+{
+    ladspa_plugin_metadata_set *ladspa = ((ladspa_instance *)(Instance))->ladspa;
+    if (index > ladspa->presets->size())
+        return NULL;
+    if (index)
+        return &(*ladspa->preset_descs)[index - 1];
+    return &ladspa->dssi_default_program;
+}
+
+/// DSSI select program function; for 0, it sets the defaults, for others, it sets global or user preset
+static void cb_select_program(LADSPA_Handle Instance, unsigned long Bank, unsigned long Program)
+{
+    ladspa_instance *mod = (ladspa_instance *)Instance;
+    ladspa_plugin_metadata_set *ladspa = mod->ladspa;
+    unsigned int no = (Bank << 7) + Program - 1;
+    // printf("no = %d presets = %p:%d\n", no, presets, presets->size());
+    if (no == -1U) {
+        int rpc = ladspa->param_count;
+        for (int i =0 ; i < rpc; i++)
+            *mod->params[i] = mod->metadata->get_param_props(i)->def_value;
+        return;
+    }
+    if (no >= ladspa->presets->size())
+        return;
+    plugin_preset &p = (*ladspa->presets)[no];
+    // printf("activating preset %s\n", p.name.c_str());
+    p.activate(mod);
+}
+
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ladspa_plugin_metadata_set::ladspa_plugin_metadata_set()
+{
+    metadata = NULL;
+    memset(&descriptor, 0, sizeof(descriptor));
+
+#if USE_DSSI
+    presets = NULL;
+    preset_descs = NULL;
+    memset(&descriptor_for_dssi, 0, sizeof(descriptor_for_dssi));
+    memset(&dssi_descriptor, 0, sizeof(dssi_descriptor));
+#endif
+}
+
+void ladspa_plugin_metadata_set::prepare(const plugin_metadata_iface *md, LADSPA_Handle (*cb_instantiate)(const struct _LADSPA_Descriptor * Descriptor, unsigned long sample_rate))
+{
+    metadata = md;
+    
+    input_count = md->get_input_count();
+    output_count = md->get_output_count();
+    param_count = md->get_param_count(); // XXXKF ladspa_instance<Module>::real_param_count();
+    
+    const ladspa_plugin_info &plugin_info = md->get_plugin_info();
+    descriptor.UniqueID = plugin_info.unique_id;
+    descriptor.Label = plugin_info.label;
+    descriptor.Name = strdup((std::string(plugin_info.name) + " LADSPA").c_str());
+    descriptor.Maker = plugin_info.maker;
+    descriptor.Copyright = plugin_info.copyright;
+    descriptor.Properties = md->is_rt_capable() ? LADSPA_PROPERTY_HARD_RT_CAPABLE : 0;
+    descriptor.PortCount = input_count + output_count + param_count;
+    descriptor.PortNames = new char *[descriptor.PortCount];
+    descriptor.PortDescriptors = new LADSPA_PortDescriptor[descriptor.PortCount];
+    descriptor.PortRangeHints = new LADSPA_PortRangeHint[descriptor.PortCount];
+    int i;
+    for (i = 0; i < input_count + output_count; i++)
+    {
+        LADSPA_PortRangeHint &prh = ((LADSPA_PortRangeHint *)descriptor.PortRangeHints)[i];
+        ((int *)descriptor.PortDescriptors)[i] = i < input_count ? LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO
+                                              : LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO;
+        prh.HintDescriptor = 0;
+        ((const char **)descriptor.PortNames)[i] = md->get_port_names()[i];
+    }
+    for (; i < input_count + output_count + param_count; i++)
+    {
+        LADSPA_PortRangeHint &prh = ((LADSPA_PortRangeHint *)descriptor.PortRangeHints)[i];
+        const parameter_properties &pp = *md->get_param_props(i - input_count - output_count);
+        ((int *)descriptor.PortDescriptors)[i] = 
+            LADSPA_PORT_CONTROL | (pp.flags & PF_PROP_OUTPUT ? LADSPA_PORT_OUTPUT : LADSPA_PORT_INPUT);
+        prh.HintDescriptor = LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW;
+        ((const char **)descriptor.PortNames)[i] = pp.name;
+        prh.LowerBound = pp.min;
+        prh.UpperBound = pp.max;
+        switch(pp.flags & PF_TYPEMASK) {
+            case PF_BOOL: 
+                prh.HintDescriptor |= LADSPA_HINT_TOGGLED;
+                prh.HintDescriptor &= ~(LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW);
+                break;
+            case PF_INT: 
+            case PF_ENUM: 
+                prh.HintDescriptor |= LADSPA_HINT_INTEGER;
+                break;
+            default: {
+                int defpt = (int)(100 * (pp.def_value - pp.min) / (pp.max - pp.min));
+                if ((pp.flags & PF_SCALEMASK) == PF_SCALE_LOG)
+                    defpt = (int)(100 * log(pp.def_value / pp.min) / log(pp.max / pp.min));
+                if (defpt < 12)
+                    prh.HintDescriptor |= LADSPA_HINT_DEFAULT_MINIMUM;
+                else if (defpt < 37)
+                    prh.HintDescriptor |= LADSPA_HINT_DEFAULT_LOW;
+                else if (defpt < 63)
+                    prh.HintDescriptor |= LADSPA_HINT_DEFAULT_MIDDLE;
+                else if (defpt < 88)
+                    prh.HintDescriptor |= LADSPA_HINT_DEFAULT_HIGH;
+                else
+                    prh.HintDescriptor |= LADSPA_HINT_DEFAULT_MAXIMUM;
+            }
+        }
+        if (pp.def_value == 0 || pp.def_value == 1 || pp.def_value == 100 || pp.def_value == 440 ) {
+            prh.HintDescriptor &= ~LADSPA_HINT_DEFAULT_MASK;
+            if (pp.def_value == 1)
+                prh.HintDescriptor |= LADSPA_HINT_DEFAULT_1;
+            else if (pp.def_value == 100)
+                prh.HintDescriptor |= LADSPA_HINT_DEFAULT_100;
+            else if (pp.def_value == 440)
+                prh.HintDescriptor |= LADSPA_HINT_DEFAULT_440;
+            else
+                prh.HintDescriptor |= LADSPA_HINT_DEFAULT_0;
+        }
+        switch(pp.flags & PF_SCALEMASK) {
+            case PF_SCALE_LOG:
+                prh.HintDescriptor |= LADSPA_HINT_LOGARITHMIC;
+                break;
+        }
+    }
+    descriptor.ImplementationData = this;
+    descriptor.instantiate = cb_instantiate;
+    descriptor.connect_port = cb_connect;
+    descriptor.activate = cb_activate;
+    descriptor.run = cb_run;
+    descriptor.run_adding = NULL;
+    descriptor.set_run_adding_gain = NULL;
+    descriptor.deactivate = cb_deactivate;
+    descriptor.cleanup = cb_cleanup;
+    prepare_dssi();
+}
+
+void ladspa_plugin_metadata_set::prepare_dssi()
+{
+#if USE_DSSI
+    const ladspa_plugin_info &plugin_info = metadata->get_plugin_info();
+    memcpy(&descriptor_for_dssi, &descriptor, sizeof(descriptor));
+    descriptor_for_dssi.Name = strdup((std::string(plugin_info.name) + " DSSI").c_str());
+    memset(&dssi_descriptor, 0, sizeof(dssi_descriptor));
+    dssi_descriptor.DSSI_API_Version = 1;
+    dssi_descriptor.LADSPA_Plugin = &descriptor_for_dssi;
+    dssi_descriptor.configure = cb_configure;
+    dssi_descriptor.get_program = cb_get_program;
+    dssi_descriptor.select_program = cb_select_program;
+    if (metadata->get_midi())
+        dssi_descriptor.run_synth = cb_run_synth;
+    
+    presets = new std::vector<plugin_preset>;
+    preset_descs = new std::vector<DSSI_Program_Descriptor>;
+
+    preset_list plist_tmp, plist;
+    plist.load_defaults(true);
+    plist_tmp.load_defaults(false);
+    plist.presets.insert(plist.presets.end(), plist_tmp.presets.begin(), plist_tmp.presets.end());
+    
+    // XXXKF this assumes that plugin name in preset is case-insensitive equal to plugin label
+    // if I forget about this, I'll be in a deep trouble
+    dssi_default_program.Bank = 0;
+    dssi_default_program.Program = 0;
+    dssi_default_program.Name = "default";
+
+    int pos = 1;
+    for (unsigned int i = 0; i < plist.presets.size(); i++)
+    {
+        plugin_preset &pp = plist.presets[i];
+        if (strcasecmp(pp.plugin.c_str(), descriptor.Label))
+            continue;
+        DSSI_Program_Descriptor pd;
+        pd.Bank = pos >> 7;
+        pd.Program = pos++;
+        pd.Name = pp.name.c_str();
+        preset_descs->push_back(pd);
+        presets->push_back(pp);
+    }
+#endif
+}
+
+ladspa_plugin_metadata_set::~ladspa_plugin_metadata_set()
+{
+    delete []descriptor.PortNames;
+    delete []descriptor.PortDescriptors;
+    delete []descriptor.PortRangeHints;
+#if USE_DSSI
+    if (presets)
+        presets->clear();
+    if (preset_descs)
+        preset_descs->clear();
+    delete presets;
+    delete preset_descs;
+#endif
+}
+
+#endif
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -41,6 +485,8 @@ using namespace calf_plugins;
 template<class Module> LV2_Descriptor calf_plugins::lv2_wrapper<Module>::descriptor;
 template<class Module> LV2_Calf_Descriptor calf_plugins::lv2_wrapper<Module>::calf_descriptor;
 template<class Module> LV2_State_Interface calf_plugins::lv2_wrapper<Module>::state_iface;
+template<class Module> LV2_Programs_Interface calf_plugins::lv2_wrapper<Module>::programs_iface;
+template<class Module> LV2_Program_Descriptor calf_plugins::lv2_wrapper<Module>::lv2_default_program;
 
 extern "C" {
 
@@ -55,6 +501,33 @@ const LV2_Descriptor *lv2_descriptor(uin
 
 #endif
 
+#if USE_LADSPA
+extern "C" {
+
+const LADSPA_Descriptor *ladspa_descriptor(unsigned long Index)
+{
+    #define PER_MODULE_ITEM(name, isSynth, jackname) if (!isSynth && !(Index--)) return &ladspa_wrapper<name##_audio_module>::get().descriptor;
+    #include <calf/modulelist.h>
+    return NULL;
+}
+
+};
+
+#if USE_DSSI
+extern "C" {
+
+const DSSI_Descriptor *dssi_descriptor(unsigned long Index)
+{
+    #define PER_MODULE_ITEM(name, isSynth, jackname) if (!(Index--)) return &calf_plugins::ladspa_wrapper<name##_audio_module>::get().dssi_descriptor;
+    #include <calf/modulelist.h>
+    return NULL;
+}
+
+};
+#endif
+
+#endif
+
 #if USE_JACK
 
 extern "C" {
--- origsrc/calf-0.90.3/src/wavetable.cpp	2018-12-17 03:35:32.000000000 +0900
+++ src/calf-0.90.3/src/wavetable.cpp	2023-09-13 07:34:00.807158700 +0900
@@ -21,7 +21,7 @@
 
 #include <config.h>
 
-#if ENABLE_EXPERIMENTAL
+#if 0 // ENABLE_EXPERIMENTAL
     
 #include <calf/giface.h>
 #include <calf/modules_synths.h>

[-- Attachment #3: calf.cygport --]
[-- Type: text/plain, Size: 1392 bytes --]

NAME="calf"
VERSION=0.90.3
RELEASE=1
LICENSE="GPL-2.0-or-later and LGPL-2.0-or-later"
CATEGORY="Audio"
SUMMARY="Calf audio plugin pack"
DESCRIPTION="The Calf project aims at providing a set of high quality open
source audio plugins for musicians. All the included plugins are designed to
be used with multitrack software, as software replacement for instruments and
guitar stomp boxes."
HOMEPAGE="https://calf-studio-gear.org/"
SRC_URI="https://calf-studio-gear.org/files/${NAME}-${VERSION}.tar.gz"
# patch based on https://src.fedoraproject.org/rpms/calf/raw/f34/f/calf-falktx-96c9e772-add-LADSPA-DSSI.patch
PATCH_URI="
	add-LADSPA-DSSI.patch
	Fix-segfault-in-limiter.patch
"

PKG_NAMES="calf-common ladspa-calf lv2-calf" # dssi-calf
calf_common_CONTENTS="--exclude=ladspa etc/ usr/share/ usr/bin/ usr/lib/calf/"
#dssi_calf_CONTENTS="usr/lib/dssi/"
ladspa_calf_SUMMARY="LADSPA ${SUMMARY}"
ladspa_calf_REQUIRES="calf-common"
ladspa_calf_CONTENTS="usr/lib/ladspa/ usr/share/ladspa/"
lv2_calf_SUMMARY="LV2 ${SUMMARY}"
lv2_calf_REQUIRES="calf-common lv2"
lv2_calf_CONTENTS="usr/lib/lv2/"

DISTCLEANFILES="
	src/calf/ladspa_wrap.h
	src/calf/lv2_programs.h
	src/calf/osctl_glib.h
	src/calf/osctlnet.h
	src/dssigui.cpp
	src/osctl_glib.cpp
	src/osctlnet.cpp
"
CYGCONF_ARGS="--without-obsolete-check"

BUILD_REQUIRES="lv2-devel libfluidsynth-devel ladspa-sdk"

[-- Attachment #4: calf-0.90.3-1.src.patch --]
[-- Type: text/plain, Size: 2241 bytes --]

--- origsrc/calf-0.90.3/src/Makefile.am	2023-09-13 10:23:08.407859100 +0900
+++ src/calf-0.90.3/src/Makefile.am	2023-09-13 10:23:09.279412300 +0900
@@ -40,10 +40,10 @@ endif
 AM_CXXFLAGS += $(GLIB_DEPS_CFLAGS)
 noinst_PROGRAMS += calfmakerdf
 calfmakerdf_SOURCES = makerdf.cpp
-calfmakerdf_LDADD = calf.la
+calfmakerdf_LDADD = calf.la utils.o giface.o preset.o metadata.o osctlnet.o
 
 calfbenchmark_SOURCES = benchmark.cpp
-calfbenchmark_LDADD = calf.la
+calfbenchmark_LDADD = calf.la modules_comp.o audio_fx.o modules_mod.o modules_delay.o giface.o metadata.o
 
 if USE_EXEC_GUI
 calf_gtk_SOURCES = dssigui.cpp
@@ -57,7 +57,7 @@ calf_la_LIBADD = $(FLUIDSYNTH_DEPS_LIBS)
 if USE_DEBUG
 calf_la_LDFLAGS = -rpath $(pkglibdir) -avoid-version -module -lexpat -disable-static
 else
-calf_la_LDFLAGS = -rpath $(pkglibdir) -avoid-version -module -lexpat -disable-static -export-symbols-regex "(ladspa_|lv2_|dssi_)descriptor"
+calf_la_LDFLAGS = -rpath $(pkglibdir) -avoid-version -module -lexpat -disable-static -export-symbols-regex "(ladspa_|lv2_|dssi_)descriptor" -no-undefined -shrext ".so"
 endif
 
 if USE_LV2_GTK_GUI
@@ -71,7 +71,7 @@ calflv2gui_la_SOURCES = gui.cpp gui_conf
 if USE_DEBUG
 calflv2gui_la_LDFLAGS = -rpath $(lv2dir) -avoid-version -module -lexpat $(GUI_DEPS_LIBS) -disable-static  -Wl,-z,nodelete
 else
-calflv2gui_la_LDFLAGS = -rpath $(lv2dir) -avoid-version -module -lexpat -export-symbols-regex "lv2ui_descriptor" $(GUI_DEPS_LIBS) -disable-static  -Wl,-z,nodelete
+calflv2gui_la_LDFLAGS = -rpath $(lv2dir) -avoid-version -module -lexpat -export-symbols-regex "lv2ui_descriptor" $(GUI_DEPS_LIBS) -disable-static -no-undefined -shrext ".so"
 endif
 
 else
@@ -84,7 +84,7 @@ calflv2gui_la_SOURCES = metadata.cpp gif
 if USE_DEBUG
 calflv2gui_la_LDFLAGS = -rpath $(lv2dir) -avoid-version -module -lexpat $(GLIB_DEPS_LIBS) -disable-static
 else
-calflv2gui_la_LDFLAGS = -rpath $(lv2dir) -avoid-version -module -lexpat -export-symbols-regex "lv2ui_descriptor" $(GLIB_DEPS_LIBS) -disable-static
+calflv2gui_la_LDFLAGS = -rpath $(lv2dir) -avoid-version -module -lexpat -export-symbols-regex "lv2ui_descriptor" $(GLIB_DEPS_LIBS) -disable-static -no-undefined -shrext ".so"
 endif
 
 endif

[-- Attachment #5: Fix-segfault-in-limiter.patch --]
[-- Type: text/plain, Size: 1571 bytes --]

--- origsrc/calf-0.90.3/src/audio_fx.cpp	2019-03-04 06:24:12.000000000 +0900
+++ src/calf-0.90.3/src/audio_fx.cpp	2023-09-13 13:47:13.866045100 +0900
@@ -679,7 +679,8 @@ void lookahead_limiter::reset() {
     buffer_size = bs - bs % channels; // buffer size attack rate
     _sanitize = true;
     pos = 0;
-    nextpos[0] = -1;
+    if (nextpos)
+        nextpos[0] = -1;
     nextlen = 0;
     nextiter = 0;
     delta = 0.f;
--- origsrc/calf-0.90.3/src/modules_limit.cpp	2019-03-04 06:24:12.000000000 +0900
+++ src/calf-0.90.3/src/modules_limit.cpp	2023-09-13 13:45:03.266307900 +0900
@@ -69,10 +69,6 @@ void limiter_audio_module::set_srates()
 void limiter_audio_module::params_changed()
 {
     limiter.set_params(*params[param_limit], *params[param_attack], *params[param_release], 1.f, *params[param_asc], pow(0.5, (*params[param_asc_coeff] - 0.5) * 2 * -1), true);
-    if( *params[param_attack] != attack_old) {
-        attack_old = *params[param_attack];
-        limiter.reset();
-    }
     if(*params[param_limit] != limit_old || *params[param_asc] != asc_old) {
         asc_old = *params[param_asc];
         limit_old = *params[param_limit];
@@ -82,6 +78,10 @@ void limiter_audio_module::params_change
         oversampling_old = *params[param_oversampling];
         set_srates();
     }
+    if( *params[param_attack] != attack_old) {
+        attack_old = *params[param_attack];
+        limiter.reset(); /* Needs set_srates() before reset(). */
+    }
 }
 
 void limiter_audio_module::set_sample_rate(uint32_t sr)

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [ITA] calf
  2023-09-13 14:34 [ITA] calf Takashi Yano
@ 2023-09-14 13:27 ` Jon Turney
  0 siblings, 0 replies; 2+ messages in thread
From: Jon Turney @ 2023-09-14 13:27 UTC (permalink / raw)
  To: Takashi Yano, cygwin-apps

On 13/09/2023 15:34, Takashi Yano via Cygwin-apps wrote:
> I'd like to adopt the package calf.
> Thanks in advance.
> 

Looks good.

I added this to your packages.

Thanks.


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2023-09-14 13:27 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-09-13 14:34 [ITA] calf Takashi Yano
2023-09-14 13:27 ` Jon Turney

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).