[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