[SCM] calf/master: + Added a new GTK+ widget - cairo-based waveform drawing widget - line-graph + Monosynth: Added waveform and filter displays to GUI + Monosynth: Modified notch filters a little so that notches are more pronounced (might be changed more in future, I still don't like it)

js at users.alioth.debian.org js at users.alioth.debian.org
Tue May 7 15:36:49 UTC 2013


The following commit has been merged in the master branch:
commit 9cdb746e1d925663319b8a3ae46b47d22dc6ac1f
Author: kfoltman <kfoltman at 78b06b96-2940-0410-b7fc-879d825d01d8>
Date:   Wed Dec 26 23:31:24 2007 +0000

    + Added a new GTK+ widget - cairo-based waveform drawing widget - line-graph
    + Monosynth: Added waveform and filter displays to GUI
    + Monosynth: Modified notch filters a little so that notches are more pronounced (might be changed more in future, I still don't like it)
    
    
    
    git-svn-id: https://calf.svn.sourceforge.net/svnroot/calf/trunk@45 78b06b96-2940-0410-b7fc-879d825d01d8

diff --git a/ChangeLog b/ChangeLog
index f92fb5e..07bf2bd 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,4 @@
 Version 0.0.9
 
 + started creating an XML-based GUI (for monosynth only in this version)
++ created a GTK+ control for displaying waveforms and filter response graphs
diff --git a/src/Makefile.am b/src/Makefile.am
index cc12308..03929dc 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -50,7 +50,7 @@ calf_la_LDFLAGS = -rpath $(ladspadir) -avoid-version -module -lexpat
 libcalfstatic_la_SOURCES = modules.cpp giface.cpp monosynth.cpp synth.cpp preset.cpp
 libcalfstatic_la_LDFLAGS = -static -lexpat
 
-libcalfgui_la_SOURCES = gui.cpp preset_gui.cpp
+libcalfgui_la_SOURCES = gui.cpp preset_gui.cpp custom_ctl.cpp
 libcalfgui_la_LDFLAGS = -static
 
 clean-local:
diff --git a/src/calf/biquad.h b/src/calf/biquad.h
index ae26b94..bc4f73e 100644
--- a/src/calf/biquad.h
+++ b/src/calf/biquad.h
@@ -50,6 +50,12 @@ public:
         reset();
     }
     
+    inline void set_null()
+    {
+        a0 = 1.0;
+        b1 = b2 = a1 = a2 = 0.f;
+    }
+    
     /** Lowpass filter based on Robert Bristow-Johnson's equations
      * Perhaps every synth code that doesn't use SVF uses these
      * equations :)
diff --git a/src/calf/custom_ctl.h b/src/calf/custom_ctl.h
new file mode 100644
index 0000000..c971b9d
--- /dev/null
+++ b/src/calf/custom_ctl.h
@@ -0,0 +1,33 @@
+#ifndef __CALF_CUSTOM_CTL
+#define __CALF_CUSTOM_CTL
+
+#include <gtk/gtk.h>
+#include <calf/giface.h>
+
+G_BEGIN_DECLS
+
+#define CALF_TYPE_LINE_GRAPH          (calf_line_graph_get_type())
+#define CALF_LINE_GRAPH(obj)          (G_TYPE_CHECK_INSTANCE_CAST ((obj), CALF_TYPE_LINE_GRAPH, CalfLineGraph))
+#define CALF_IS_LINE_GRAPH(obj)       (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CALF_TYPE_LINE_GRAPH))
+#define CALF_LINE_GRAPH_CLASS(klass)  (G_TYPE_CHECK_CLASS_CAST ((klass),  CALF_TYPE_LINE_GRAPH, CalfLineGraphClass))
+#define CALF_IS_LINE_GRAPH_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE ((klass),  CALF_TYPE_LINE_GRAPH))
+
+struct CalfLineGraph
+{
+    GtkWidget parent;
+    synth::line_graph_iface *source;
+    int source_id;
+};
+
+struct CalfLineGraphClass
+{
+    GtkWidgetClass parent_class;
+};
+
+extern GtkWidget *calf_line_graph_new();
+
+extern GType calf_line_graph_get_type();
+
+G_END_DECLS
+
+#endif
diff --git a/src/calf/giface.h b/src/calf/giface.h
index e618f06..286e38b 100644
--- a/src/calf/giface.h
+++ b/src/calf/giface.h
@@ -96,6 +96,12 @@ struct parameter_properties
     std::string to_string(float value) const;
 };
 
+struct line_graph_iface
+{
+    virtual bool get_graph(int index, float *data, int points) = 0;
+    virtual ~line_graph_iface() {}
+};
+
 struct plugin_ctl_iface
 {
     virtual parameter_properties *get_param_props(int param_no) = 0;
@@ -103,6 +109,7 @@ struct plugin_ctl_iface
     virtual void set_param_value(int param_no, float value) = 0;
     virtual int get_param_count() = 0;
     virtual const char *get_gui_xml() = 0;
+    virtual line_graph_iface *get_line_graph_iface() = 0;
     virtual ~plugin_ctl_iface() {}
 };
 
@@ -177,6 +184,10 @@ struct ladspa_instance: public Module, public plugin_ctl_iface
     virtual const char *get_gui_xml() {
         return Module::get_gui_xml();
     }
+    virtual line_graph_iface *get_line_graph_iface()
+    {
+        return this;
+    }
 };
 
 template<class Module>
diff --git a/src/calf/gui.h b/src/calf/gui.h
index c459956..39f58fb 100644
--- a/src/calf/gui.h
+++ b/src/calf/gui.h
@@ -29,6 +29,7 @@
 #if USE_PHAT
 #include <phat/phatknob.h>
 #endif
+#include "custom_ctl.h"
 
 namespace synth {
 
@@ -162,6 +163,17 @@ struct combo_box_param_control: public param_control
     static void combo_value_changed(GtkComboBox *widget, gpointer value);
 };
 
+struct line_graph_param_control: public param_control
+{
+    CalfLineGraph *graph;
+
+    virtual GtkWidget *create(plugin_gui *_gui, int _param_no);
+    virtual void get() {}
+    virtual void set();
+    virtual ~line_graph_param_control();
+    static gboolean update(void *data);
+};
+
 #if USE_PHAT
 struct knob_param_control: public param_control
 {
diff --git a/src/calf/jackhost.h b/src/calf/jackhost.h
index b445b89..01d9857 100644
--- a/src/calf/jackhost.h
+++ b/src/calf/jackhost.h
@@ -307,6 +307,10 @@ public:
     virtual const char *get_gui_xml() {
         return Module::get_gui_xml();
     }
+    virtual line_graph_iface *get_line_graph_iface()
+    {
+        return &module;
+    }
 };
 
 extern jack_host_base *create_jack_host(const char *name);
diff --git a/src/calf/modules.h b/src/calf/modules.h
index 3d3ae69..202b006 100644
--- a/src/calf/modules.h
+++ b/src/calf/modules.h
@@ -30,7 +30,7 @@ namespace synth {
 
 using namespace dsp;
 
-class null_audio_module
+class null_audio_module: public line_graph_iface
 {
 public:
     inline void note_on(int note, int velocity) {}
@@ -42,6 +42,7 @@ public:
     inline void activate() {}
     inline void deactivate() {}
     inline void set_sample_rate(uint32_t sr) { }
+    inline bool get_graph(int index, float *data, int points) { return false; }
     inline static const char *get_gui_xml() { return NULL; }
 };
 
diff --git a/src/calf/modules_synths.h b/src/calf/modules_synths.h
index 44e58e7..2f7b87d 100644
--- a/src/calf/modules_synths.h
+++ b/src/calf/modules_synths.h
@@ -91,7 +91,7 @@ public:
     }
     void params_changed() {
         float sf = 0.001f;
-        envelope.set(*params[par_attack] * sf, *params[par_decay] * sf, *params[par_sustain], *params[par_release] * sf, srate / step_size);
+        envelope.set(*params[par_attack] * sf, *params[par_decay] * sf, min(0.999f, *params[par_sustain]), *params[par_release] * sf, srate / step_size);
         filter_type = fastf2i_drm(*params[par_filtertype]);
         decay_factor = odcr * 1000.0 / *params[par_decay];
         separation = pow(2.0, *params[par_cutoffsep] / 1200.0);
@@ -120,6 +120,7 @@ public:
     void calculate_buffer_ser();
     void calculate_buffer_single();
     void calculate_buffer_stereo();
+    bool get_graph(int index, float *data, int points);
     inline bool is_stereo_filter() const
     {
         return filter_type == flt_2lp12 || filter_type == flt_2bp6;
diff --git a/src/custom_ctl.cpp b/src/custom_ctl.cpp
new file mode 100644
index 0000000..25dd423
--- /dev/null
+++ b/src/custom_ctl.cpp
@@ -0,0 +1,121 @@
+#include <calf/custom_ctl.h>
+#include <cairo/cairo.h>
+#include <math.h>
+
+static gboolean
+calf_line_graph_expose (GtkWidget *widget, GdkEventExpose *event)
+{
+    g_assert(CALF_IS_LINE_GRAPH(widget));
+    
+    CalfLineGraph *lg = CALF_LINE_GRAPH(widget);
+    GdkWindow *window = widget->window;
+    int ox = widget->allocation.x + 1, oy = widget->allocation.y + 1;
+    int sx = widget->allocation.width - 2, sy = widget->allocation.height - 2;
+    
+    cairo_t *c = gdk_cairo_create(GDK_DRAWABLE(widget->window));
+
+    GdkColor sc = { 0, 0, 0, 0 }, sc2 = { 0, 0, 65535, 0 };
+
+    gdk_cairo_set_source_color(c, &sc);
+    cairo_rectangle(c, ox, oy, sx, sy);
+    cairo_fill(c);
+
+    if (lg->source) {
+        float *data = new float[2 * sx];
+        if (lg->source->get_graph(lg->source_id, data, 2 * sx))
+        {
+            gdk_cairo_set_source_color(c, &sc2);
+            cairo_set_line_join(c, CAIRO_LINE_JOIN_MITER);
+            cairo_set_line_width(c, 1);
+            for (int i = 0; i < 2 * sx; i++)
+            {
+                int y = oy + sy / 2 - (sy / 2 - 1) * data[i];
+                if (y < oy) y = oy;
+                if (y >= oy + sy) y = oy + sy - 1;
+                if (i)
+                    cairo_line_to(c, ox + i * 0.5, y);
+                else
+                    cairo_move_to(c, ox, y);
+            }
+            cairo_stroke(c);
+        }
+        delete []data;
+    }
+    
+    cairo_destroy(c);
+    
+    gtk_paint_shadow(widget->style, widget->window, GTK_STATE_NORMAL, GTK_SHADOW_IN, NULL, widget, NULL, ox - 1, oy - 1, sx + 2, sy + 2);
+    // printf("exposed %p %d+%d\n", widget->window, widget->allocation.x, widget->allocation.y);
+    
+    return TRUE;
+}
+
+static void
+calf_line_graph_size_request (GtkWidget *widget,
+                           GtkRequisition *requisition)
+{
+    g_assert(CALF_IS_LINE_GRAPH(widget));
+    
+    CalfLineGraph *lg = CALF_LINE_GRAPH(widget);
+
+    requisition->width = 64;
+    requisition->height = 64;
+}
+
+static void
+calf_line_graph_size_allocate (GtkWidget *widget,
+                           GtkAllocation *allocation)
+{
+    g_assert(CALF_IS_LINE_GRAPH(widget));
+    
+    widget->allocation = *allocation;
+    printf("allocation %d x %d\n", allocation->width, allocation->height);
+}
+
+static void
+calf_line_graph_class_init (CalfLineGraphClass *klass)
+{
+    // GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
+    GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
+    widget_class->expose_event = calf_line_graph_expose;
+    widget_class->size_request = calf_line_graph_size_request;
+    widget_class->size_allocate = calf_line_graph_size_allocate;
+}
+
+static void
+calf_line_graph_init (CalfLineGraph *self)
+{
+    GTK_WIDGET_SET_FLAGS (GTK_WIDGET(self), GTK_NO_WINDOW);
+}
+
+GtkWidget *
+calf_line_graph_new()
+{
+    return GTK_WIDGET( g_object_new (CALF_TYPE_LINE_GRAPH, NULL ));
+}
+
+GType
+calf_line_graph_get_type (void)
+{
+  static GType type = 0;
+  if (!type) {
+    static const GTypeInfo type_info = {
+      sizeof(CalfLineGraphClass),
+      NULL, /* base_init */
+      NULL, /* base_finalize */
+      (GClassInitFunc)calf_line_graph_class_init,
+      NULL, /* class_finalize */
+      NULL, /* class_data */
+      sizeof(CalfLineGraph),
+      0,    /* n_preallocs */
+      (GInstanceInitFunc)calf_line_graph_init
+    };
+    
+    type = g_type_register_static(GTK_TYPE_WIDGET,
+                                  "CalfLineGraph",
+                                  &type_info,
+                                  (GTypeFlags)0);
+  }
+  return type;
+}
+
diff --git a/src/gui.cpp b/src/gui.cpp
index 90457c4..498d55c 100644
--- a/src/gui.cpp
+++ b/src/gui.cpp
@@ -243,6 +243,43 @@ void knob_param_control::knob_value_changed(PhatKnob *widget, gpointer value)
 }
 #endif
 
+// line graph
+
+gboolean line_graph_param_control::update(void *data)
+{
+    line_graph_param_control *self = (line_graph_param_control *)data;
+    self->set();
+    return TRUE;
+}
+
+GtkWidget *line_graph_param_control::create(plugin_gui *_gui, int _param_no)
+{
+    gui = _gui;
+    param_no = _param_no;
+    const parameter_properties &props = get_props();
+    
+    widget = calf_line_graph_new ();
+    CalfLineGraph *clg = CALF_LINE_GRAPH(widget);
+    clg->source = gui->plugin->get_line_graph_iface();
+    clg->source_id = param_no;
+    
+    if (get_int("refresh", 0))
+        g_idle_add(update, this);
+    
+    return widget;
+}
+
+void line_graph_param_control::set()
+{
+    gtk_widget_queue_draw(widget);
+}
+
+line_graph_param_control::~line_graph_param_control()
+{
+    if (get_int("refresh", 0))
+        g_idle_remove_by_data(this);
+}
+
 /******************************** GUI proper ********************************/
 
 plugin_gui::plugin_gui(plugin_gui_window *_window)
@@ -435,6 +472,8 @@ param_control *plugin_gui::create_control_from_xml(const char *element, const ch
         return new label_param_control;
     if (!strcmp(element, "value"))
         return new value_param_control;
+    if (!strcmp(element, "line-graph"))
+        return new line_graph_param_control;
     return NULL;
 }
 
@@ -662,6 +701,7 @@ void plugin_gui_window::fill_gui_presets()
 void plugin_gui_window::create(plugin_ctl_iface *_jh, const char *title, const char *effect)
 {
     toplevel = GTK_WINDOW(gtk_window_new (GTK_WINDOW_TOPLEVEL));
+    gtk_window_set_type_hint(toplevel, GDK_WINDOW_TYPE_HINT_DIALOG);
     GtkVBox *vbox = GTK_VBOX(gtk_vbox_new(false, 5));
     
     GtkRequisition req, req2;
diff --git a/src/monosynth.cpp b/src/monosynth.cpp
index a20809c..b9cf98a 100644
--- a/src/monosynth.cpp
+++ b/src/monosynth.cpp
@@ -20,6 +20,7 @@
  */
 #include <assert.h>
 #include <memory.h>
+#include <complex>
 #if USE_JACK
 #include <jack/jack.h>
 #endif
@@ -28,6 +29,7 @@
 #include <calf/modules_synths.h>
 
 using namespace synth;
+using namespace std;
 
 const char *monosynth_audio_module::port_names[] = {
     "Out L", "Out R", 
@@ -53,15 +55,21 @@ static const char *monosynth_gui_xml =
     "<vbox border=\"10\">"
         "<hbox spacing=\"10\">"
             "<frame label=\"Oscillators\">"
-                "<vbox border=\"10\">"
+                "<vbox border=\"10\" spacing=\"10\">"
                     "<table rows=\"2\" cols=\"2\">"
                     "<label attach-x=\"0\" attach-y=\"0\" param=\"o1_wave\" />"
                     "<label attach-x=\"1\" attach-y=\"0\" param=\"o2_wave\" />"
                     "<combo attach-x=\"0\" attach-y=\"1\" param=\"o1_wave\" />"
                     "<combo attach-x=\"1\" attach-y=\"1\" param=\"o2_wave\" />"
                     "</table>"
-                    "<label param=\"o12_mix\"/>"
-                    "<hscale param=\"o12_mix\" position=\"bottom\"/>"
+                    "<hbox>"
+                        "<line-graph param=\"o1_wave\"/>"
+                        "<vbox>"
+                            "<label param=\"o12_mix\"/>"
+                            "<hscale param=\"o12_mix\" position=\"bottom\"/>"
+                        "</vbox>"
+                        "<line-graph param=\"o2_wave\"/>"
+                    "</hbox>"
                     "<hbox>"
                         "<vbox>"
                         "  <label param=\"o12_detune\" />"
@@ -85,6 +93,7 @@ static const char *monosynth_gui_xml =
                     "<align align-x=\"0.5\" align-y=\"0.5\">"
                         "<hbox>"
                             "<label param=\"filter\" /><combo param=\"filter\" />"
+                            "<line-graph param=\"filter\" refresh=\"1\"/>"
                         "</hbox>"
                     "</align>"
                     "<hbox>"
@@ -289,6 +298,38 @@ void monosynth_audio_module::activate() {
     waves[wave_test8].make(bl, data);
 }
 
+bool monosynth_audio_module::get_graph(int index, float *data, int points)
+{
+    // printf("get_graph %d %p %d wave1=%d wave2=%d\n", index, data, points, wave1, wave2);
+    if (index == par_wave1 || index == par_wave2) {
+        int wave = dsp::clip(dsp::fastf2i_drm(*params[index]), 0, (int)wave_count - 1);
+
+        float *waveform = waves[wave].get_level(0);
+        for (int i = 0; i < points; i++)
+            data[i] = 0.5 * (waveform[i * 2047 / points] + waveform[i * 2047 / points + 1]);
+        return true;
+    }
+    if (index == par_filtertype) {
+        if (!running)
+            return false;
+        for (int i = 0; i < points; i++)
+        {
+            typedef complex<double> cfloat;
+            double freq = 20.0 * pow (20000.0 / 20.0, i * 1.0 / points) * PI / srate;
+            cfloat z = 1.0 / exp(cfloat(0.0, freq));
+            
+            float level = abs((cfloat(filter.a0) + double(filter.a1) * z + double(filter.a2) * z*z) / (cfloat(1.0) + double(filter.b1) * z + double(filter.b2) * z*z));
+            if (!is_stereo_filter())
+                level *= abs((cfloat(filter2.a0) + double(filter2.a1) * z + double(filter2.a2) * z*z) / (cfloat(1.0) + double(filter2.b1) * z + double(filter2.b2) * z*z));
+            level *= fgain;
+            
+            data[i] = log(level) / log(1024.0) + 0.25;
+        }
+        return true;
+    }
+    return false;
+}
+
 void monosynth_audio_module::calculate_buffer_ser()
 {
     for (uint32_t i = 0; i < step_size; i++) 
@@ -437,10 +478,12 @@ void monosynth_audio_module::calculate_step()
     {
     case flt_lp12:
         filter.set_lp_rbj(cutoff, resonance, srate);
+        filter2.set_null();
         newfgain = min(0.7f, 0.7f / resonance) * ampctl;
         break;
     case flt_hp12:
         filter.set_hp_rbj(cutoff, resonance, srate);
+        filter2.set_null();
         newfgain = min(0.7f, 0.7f / resonance) * ampctl;
         break;
     case flt_lp24:
@@ -450,12 +493,12 @@ void monosynth_audio_module::calculate_step()
         break;
     case flt_lpbr:
         filter.set_lp_rbj(cutoff, resonance, srate);
-        filter2.set_br_rbj(cutoff2, resonance, srate);
+        filter2.set_br_rbj(cutoff2, 1.0 / resonance, srate);
         newfgain = min(0.5f, 0.5f / resonance) * ampctl;        
         break;
     case flt_hpbr:
         filter.set_hp_rbj(cutoff, resonance, srate);
-        filter2.set_br_rbj(cutoff2, resonance, srate);
+        filter2.set_br_rbj(cutoff2, 1.0 / resonance, srate);
         newfgain = min(0.5f, 0.5f / resonance) * ampctl;        
         break;
     case flt_2lp12:
@@ -465,6 +508,7 @@ void monosynth_audio_module::calculate_step()
         break;
     case flt_bp6:
         filter.set_bp_rbj(cutoff, resonance, srate);
+        filter2.set_null();
         newfgain = ampctl;
         break;
     case flt_2bp6:

-- 
calf audio plugins packaging



More information about the pkg-multimedia-commits mailing list