[SCM] calf/master: + Framework, LV2, JACK host: implement progress reporting for instantiation (the JACK host version is just a temporary hack)

js at users.alioth.debian.org js at users.alioth.debian.org
Tue May 7 15:38:48 UTC 2013


The following commit has been merged in the master branch:
commit 18cb5f13cfde459242691109d9235926b2802785
Author: Krzysztof Foltman <wdev at foltman.com>
Date:   Mon Jan 5 23:03:34 2009 +0000

    + Framework, LV2, JACK host: implement progress reporting for instantiation (the JACK host version is just a temporary hack)

diff --git a/src/calf/giface.h b/src/calf/giface.h
index 1a085fb..d5a1121 100644
--- a/src/calf/giface.h
+++ b/src/calf/giface.h
@@ -144,6 +144,12 @@ struct cairo_iface
     virtual ~cairo_iface() {}
 };
 
+struct progress_report_iface
+{
+    virtual void report_progress(float percentage, const std::string &message) = 0;
+    virtual ~progress_report_iface() {}
+};
+
 /// 'provides live line graph values' interface
 struct line_graph_iface
 {
@@ -300,6 +306,12 @@ class audio_module: public Metadata
 public:
     typedef Metadata metadata_type;
 
+    progress_report_iface *progress_report;
+
+    audio_module() {
+        progress_report = NULL;
+    }
+
     /// Handle MIDI Note On
     inline void note_on(int note, int velocity) {}
     /// Handle MIDI Note Off
@@ -327,6 +339,8 @@ public:
     inline void send_configures(send_configure_iface *sci) {}
     /// Reset parameter values for epp:trigger type parameters (ones activated by oneshot push button instead of check box)
     inline void params_reset() {}
+    /// Called after instantiating (after all the feature pointers are set - including interfaces like progress_report_iface)
+    inline void post_instantiate() {}
     /// Handle 'message context' port message
     /// @arg output_ports pointer to bit array of output port "changed" flags, note that 0 = first audio input, not first parameter (use input_count + output_count)
     inline uint32_t message_run(const void *valid_ports, void *output_ports) { 
diff --git a/src/calf/jackhost.h b/src/calf/jackhost.h
index c78cbad..98ce775 100644
--- a/src/calf/jackhost.h
+++ b/src/calf/jackhost.h
@@ -184,11 +184,12 @@ struct vumeter
 };
 
 template<class Module>
-class jack_host: public jack_host_base, public Module {
+class jack_host: public jack_host_base, public Module, public calf_plugins::progress_report_iface {
 public:
     using Module::in_count;
     using Module::out_count;
     using Module::param_count;
+    using Module::progress_report;
 
     port inputs[in_count], outputs[out_count];
     vumeter input_vus[in_count], output_vus[out_count];
@@ -203,6 +204,8 @@ public:
         }
         clear_preset();
         midi_meter = 0;
+        progress_report = this;
+        Module::post_instantiate();
     }
     
     ~jack_host()
@@ -211,6 +214,13 @@ public:
             close();
     }
     
+    virtual void report_progress(float percentage, const std::string &message) {
+        if (!message.empty())
+            printf("Message: %s\n", message.c_str());
+        printf("Percentage: %0.1f\n", percentage);
+    }
+    
+    
     virtual void init_module() {
         Module::set_sample_rate(client->sample_rate);
         Module::activate();
diff --git a/src/calf/ladspa_wrap.h b/src/calf/ladspa_wrap.h
index 398e688..5e6ae53 100644
--- a/src/calf/ladspa_wrap.h
+++ b/src/calf/ladspa_wrap.h
@@ -300,6 +300,7 @@ struct ladspa_wrapper
     {
         instance *mod = new instance();
         mod->srate = sample_rate;
+        mod->post_instantiate();
         return mod;
     }
 
diff --git a/src/calf/lv2_progress.h b/src/calf/lv2_progress.h
new file mode 100644
index 0000000..642dd4f
--- /dev/null
+++ b/src/calf/lv2_progress.h
@@ -0,0 +1,85 @@
+/* -*- Mode: C ; c-basic-offset: 2 -*- */
+/*****************************************************************************
+ *
+ *  This work is in public domain.
+ *
+ *  This file 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.
+ *
+ *  Author of this extension is Nedko Arnaudov <nedko at arnaudov.name>
+ *
+ *  Several people helped improving the extension:
+ *   * Krzysztof Foltman <wdev at foltman.com>
+ *   * Dave Robillard <dave at drobilla.net>
+ *
+ *  If you have questions ask in the #lv2 or #lad channel,
+ *  FreeNode IRC network or use the lv2 mailing list.
+ *
+ *****************************************************************************/
+
+#ifndef LV2_PROGRESS_H__F576843C_CA13_49C3_9BF9_CFF3A15AD18C__INCLUDED
+#define LV2_PROGRESS_H__F576843C_CA13_49C3_9BF9_CFF3A15AD18C__INCLUDED
+
+/**
+ * @file lv2_progress.h
+ * @brief LV2 progress notification extension definition
+ *
+ * @par Purpose and scope
+ * The purpose of this extension is to prevent thread (often the main one)
+ * freeze for plugins doing intensive computations during instantiation.
+ * Host may want to display progress bar of some sort and if it is using
+ * GUI toolkit event loop, to dispatch queued events.
+ *
+ * @par
+ * Using this extension for reporting progress of other lengthy operations
+ * is possible and encouraged but not subject of this extension alone.
+ * It is probably not good idea to call progress callback from plugin created
+ * thread nor it is good idea to call it from a LV2 audio class function.
+ * Any extension that wants to work in conjuction with progress extension
+ * must define thread context semantics for calling the progress callback.
+ *
+ * @par Plugin instantiation progress usage
+ * Plugin calls the host provided callback on regular basis during
+ * instantiation. One second between calls is good target. Everything between
+ * half second and two seconds should provide enough motion so user does
+ * not get "the thing froze" impression.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#if 0
+} /* Adjust editor indent */
+#endif
+
+/** URI for the plugin progress feature */
+#define LV2_PROGRESS_URI "http://lv2plug.in/ns/dev/progress"
+
+/** @brief host feature structure */
+typedef struct _LV2_Progress
+{
+  /** to be supplied as first parameter of progress() callback  */
+  void * context;
+
+  /**
+   * This function is called by plugin to notify host about progress of a
+   * lengthy operation.
+   *
+   * @param context Host context
+   * @param progress Progress, from 0.0 to 100.0
+   * @param message Optional (may be NULL) string describing current operation.
+   * If called once with non-NULL message, subsequent calls will NULL message
+   * mean that host will reuse the previous message.
+   */
+  void (*progress)(void * context, float progress, const char * message);
+} LV2_Progress;
+
+#if 0
+{ /* Adjust editor indent */
+#endif
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* #ifndef LV2_PROGRESS_H__F576843C_CA13_49C3_9BF9_CFF3A15AD18C__INCLUDED */
diff --git a/src/calf/lv2wrap.h b/src/calf/lv2wrap.h
index 04d12ba..c8c3a52 100644
--- a/src/calf/lv2wrap.h
+++ b/src/calf/lv2wrap.h
@@ -28,15 +28,16 @@
 #include <lv2.h>
 #include <calf/giface.h>
 #include <calf/lv2-midiport.h>
-#include <calf/lv2_event.h>
-#include <calf/lv2_uri_map.h>
 #include <calf/lv2_contexts.h>
+#include <calf/lv2_event.h>
+#include <calf/lv2_progress.h>
 #include <calf/lv2_string_port.h>
+#include <calf/lv2_uri_map.h>
 
 namespace calf_plugins {
 
 template<class Module>
-struct lv2_instance: public plugin_ctl_iface, public Module
+struct lv2_instance: public plugin_ctl_iface, public progress_report_iface, public Module
 {
     bool set_srate;
     int srate_to_set;
@@ -46,6 +47,7 @@ struct lv2_instance: public plugin_ctl_iface, public Module
     LV2_Event_Feature *event_feature;
     uint32_t midi_event_type;
     std::vector<int> message_params;
+    LV2_Progress *progress_report_feature;
     lv2_instance()
     {
         for (int i=0; i < Module::in_count; i++)
@@ -61,8 +63,16 @@ struct lv2_instance: public plugin_ctl_iface, public Module
         set_srate = true;
         srate_to_set = 44100;
         get_message_context_parameters(message_params);
+        progress_report_feature = NULL;
         // printf("message params %d\n", (int)message_params.size());
     }
+    /// This, and not Module::post_instantiate, is actually called by lv2_wrapper class
+    void post_instantiate()
+    {
+        if (progress_report_feature)
+            Module::progress_report = this;
+        Module::post_instantiate();
+    }
     virtual parameter_properties *get_param_props(int param_no)
     {
         return &Module::param_props[param_no];
@@ -112,6 +122,10 @@ struct lv2_instance: public plugin_ctl_iface, public Module
     virtual void execute(int cmd_no) {
         Module::execute(cmd_no);
     }
+    virtual void report_progress(float percentage, const std::string &message) {
+        if (progress_report_feature)
+            (*progress_report_feature->progress)(progress_report_feature->context, percentage, !message.empty() ? message.c_str() : NULL);
+    }
     void send_configures(send_configure_iface *sci) { 
         Module::send_configures(sci);
     }
@@ -229,8 +243,13 @@ struct lv2_wrapper
             {
                 mod->event_feature = (LV2_Event_Feature *)((*features)->data);
             }
+            else if (!strcmp((*features)->URI, LV2_PROGRESS_URI))
+            {
+                mod->progress_report_feature = (LV2_Progress *)((*features)->data);
+            }
             features++;
         }
+        mod->post_instantiate();
         return mod;
     }
     static inline void zero_by_mask(Module *module, uint32_t mask, uint32_t offset, uint32_t nsamples)
diff --git a/src/calf/modules_synths.h b/src/calf/modules_synths.h
index c990ddf..76fdd3b 100644
--- a/src/calf/modules_synths.h
+++ b/src/calf/modules_synths.h
@@ -209,6 +209,11 @@ public:
     {
         var_map_curve = "2\n0 1\n1 1\n"; // XXXKF hacky bugfix
     }
+    
+    void post_instantiate()
+    {
+        dsp::organ_voice_base::precalculate_waves(progress_report);
+    }
 
     void set_sample_rate(uint32_t sr) {
         srate = sr;
diff --git a/src/calf/organ.h b/src/calf/organ.h
index ca52697..2c7dbd5 100644
--- a/src/calf/organ.h
+++ b/src/calf/organ.h
@@ -152,7 +152,7 @@ public:
     static inline big_wave_family &get_big_wave(int wave) {
         return (*big_waves)[wave];
     }
-    static void precalculate_waves();
+    static void precalculate_waves(calf_plugins::progress_report_iface *reporter);
     void update_pitch()
     {
         float phase = dsp::midi_note_to_phase(note, 100 * parameters->global_transpose + parameters->global_detune, sample_rate_ref);
@@ -302,7 +302,6 @@ struct drawbar_organ: public dsp::basic_synth, public calf_plugins::organ_enums
      drawbar_organ(organ_parameters *_parameters)
     : parameters(_parameters)
     , percussion(_parameters) {
-        organ_voice_base::precalculate_waves();
     }
     void render_separate(float *output[], int nsamples)
     {
diff --git a/src/organ.cpp b/src/organ.cpp
index 280e21b..65f7e63 100644
--- a/src/organ.cpp
+++ b/src/organ.cpp
@@ -39,7 +39,7 @@ using namespace calf_plugins;
 bool organ_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context)
 {
     if (index == par_master) {
-        organ_voice_base::precalculate_waves();
+        organ_voice_base::precalculate_waves(progress_report);
         if (subindex)
             return false;
         float *waveforms[9];
@@ -190,7 +190,10 @@ static void padsynth(bandlimiter<ORGAN_WAVE_BITS> blSrc, bandlimiter<ORGAN_BIG_W
     #endif
 }
 
-void organ_voice_base::precalculate_waves()
+#define LARGE_WAVEFORM_PROGRESS() do { if (reporter) { progress += 100; reporter->report_progress(floor(progress / totalwaves), "Precalculating large waveforms"); } } while(0)
+
+
+void organ_voice_base::precalculate_waves(progress_report_iface *reporter)
 {
     static bool inited = false;
     if (!inited)
@@ -200,6 +203,10 @@ void organ_voice_base::precalculate_waves()
         organ_voice_base::waves = &waves;
         organ_voice_base::big_waves = &big_waves;
         
+        float progress = 0.0;
+        int totalwaves = 1 + wave_count_big;
+        if (reporter)
+            reporter->report_progress(0, "Precalculating small waveforms");
         float tmp[ORGAN_WAVE_SIZE];
         static bandlimiter<ORGAN_WAVE_BITS> bl;
         static bandlimiter<ORGAN_BIG_WAVE_BITS> blBig;
@@ -360,24 +367,28 @@ void organ_voice_base::precalculate_waves()
         phaseshift(bl, tmp);
         waves[wave_dpls].make(bl, tmp);
 
+        LARGE_WAVEFORM_PROGRESS();
         for (int i = 0; i < ORGAN_WAVE_SIZE; i++)
             tmp[i] = -1 + (i * 2.0 / ORGAN_WAVE_SIZE);
         normalize_waveform(tmp, ORGAN_WAVE_SIZE);
         bl.compute_spectrum(tmp);
         padsynth(bl, blBig, big_waves[wave_strings - wave_count_small], 15);
 
+        LARGE_WAVEFORM_PROGRESS();
         for (int i = 0; i < ORGAN_WAVE_SIZE; i++)
             tmp[i] = -1 + (i * 2.0 / ORGAN_WAVE_SIZE);
         normalize_waveform(tmp, ORGAN_WAVE_SIZE);
         bl.compute_spectrum(tmp);
         padsynth(bl, blBig, big_waves[wave_strings2 - wave_count_small], 40);
 
+        LARGE_WAVEFORM_PROGRESS();
         for (int i = 0; i < ORGAN_WAVE_SIZE; i++)
             tmp[i] = sin(i * 2 * M_PI / ORGAN_WAVE_SIZE);
         normalize_waveform(tmp, ORGAN_WAVE_SIZE);
         bl.compute_spectrum(tmp);
         padsynth(bl, blBig, big_waves[wave_sinepad - wave_count_small], 20);
 
+        LARGE_WAVEFORM_PROGRESS();
         for (int i = 0; i < ORGAN_WAVE_SIZE; i++)
         {
             float ph = i * 2 * M_PI / ORGAN_WAVE_SIZE;
@@ -388,6 +399,7 @@ void organ_voice_base::precalculate_waves()
         bl.compute_spectrum(tmp);
         padsynth(bl, blBig, big_waves[wave_bellpad - wave_count_small], 30, 30, true);
 
+        LARGE_WAVEFORM_PROGRESS();
         for (int i = 0; i < ORGAN_WAVE_SIZE; i++)
         {
             float ph = i * 2 * M_PI / ORGAN_WAVE_SIZE;
@@ -398,6 +410,7 @@ void organ_voice_base::precalculate_waves()
         bl.compute_spectrum(tmp);
         padsynth(bl, blBig, big_waves[wave_space - wave_count_small], 30, 30);
 
+        LARGE_WAVEFORM_PROGRESS();
         for (int i = 0; i < ORGAN_WAVE_SIZE; i++)
         {
             float ph = i * 2 * M_PI / ORGAN_WAVE_SIZE;
@@ -408,6 +421,7 @@ void organ_voice_base::precalculate_waves()
         bl.compute_spectrum(tmp);
         padsynth(bl, blBig, big_waves[wave_choir - wave_count_small], 50, 10);
 
+        LARGE_WAVEFORM_PROGRESS();
         for (int i = 0; i < ORGAN_WAVE_SIZE; i++)
         {
             float ph = i * 2 * M_PI / ORGAN_WAVE_SIZE;
@@ -418,6 +432,7 @@ void organ_voice_base::precalculate_waves()
         bl.compute_spectrum(tmp);
         padsynth(bl, blBig, big_waves[wave_choir2 - wave_count_small], 50, 10);
 
+        LARGE_WAVEFORM_PROGRESS();
         for (int i = 0; i < ORGAN_WAVE_SIZE; i++)
         {
             float ph = i * 2 * M_PI / ORGAN_WAVE_SIZE;

-- 
calf audio plugins packaging



More information about the pkg-multimedia-commits mailing list