[SCM] calf/master: Add Analyzer plugin. Improve Stereo Tools plugin.
js at users.alioth.debian.org
js at users.alioth.debian.org
Tue May 7 15:40:53 UTC 2013
The following commit has been merged in the master branch:
commit f834766f5cb62d7358efa61eb8077e8c07be7803
Author: Markus Schmidt <schmidt at boomshop.net>
Date: Wed Feb 22 11:21:49 2012 +0000
Add Analyzer plugin. Improve Stereo Tools plugin.
Note: slightly modified by KF (removed global variables, fixed a bug caused
by an obscure C++ rule).
diff --git a/doc/manuals/scripts/manual.js b/doc/manuals/scripts/manual.js
index 79cab78..acbe2f6 100644
--- a/doc/manuals/scripts/manual.js
+++ b/doc/manuals/scripts/manual.js
@@ -59,7 +59,8 @@ $(document).ready(function () {
["Exciter", "Exciter.html", "images/Calf - Exciter.png"],
["Bass Enhancer", "Bass Enhancer.html", "images/Calf - Bass Enhancer.png"],
["Mono Input", "Mono Input.html", "images/Calf - Mono Input.png"],
- ["Stereo Tools", "Stereo Tools.html", "images/Calf - Stereo Tools.png"]
+ ["Stereo Tools", "Stereo Tools.html", "images/Calf - Stereo Tools.png"],
+ ["Analyzer", "Analyzer.html", "images/Calf - Analyzer.png"]
]
]
];
diff --git a/src/calf/custom_ctl.h b/src/calf/custom_ctl.h
index 2162e13..826b22c 100644
--- a/src/calf/custom_ctl.h
+++ b/src/calf/custom_ctl.h
@@ -19,9 +19,14 @@
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02111-1307, USA.
*/
+
+#ifndef _USE_MATH_DEFINES
+#define _USE_MATH_DEFINES
+#endif
#ifndef __CALF_CUSTOM_CTL
#define __CALF_CUSTOM_CTL
+
#include <gtk/gtk.h>
#include <calf/giface.h>
@@ -40,7 +45,10 @@ struct CalfLineGraph
const calf_plugins::line_graph_iface *source;
int source_id;
bool is_square;
+ bool use_fade;
+ float fade;
cairo_surface_t *cache_surface;
+ cairo_surface_t *fade_surface;
//GdkPixmap *cache_pixmap;
int last_generation;
};
@@ -58,6 +66,44 @@ extern void calf_line_graph_set_square(CalfLineGraph *graph, bool is_square);
extern int calf_line_graph_update_if(CalfLineGraph *graph, int generation);
+#define CALF_TYPE_PHASE_GRAPH (calf_phase_graph_get_type())
+#define CALF_PHASE_GRAPH(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CALF_TYPE_PHASE_GRAPH, CalfPhaseGraph))
+#define CALF_IS_PHASE_GRAPH(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CALF_TYPE_PHASE_GRAPH))
+#define CALF_PHASE_GRAPH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CALF_TYPE_PHASE_GRAPH, CalfPhaseGraphClass))
+#define CALF_IS_PHASE_GRAPH_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE ((klass), CALF_TYPE_PHASE_GRAPH))
+#define CALF_PHASE_GRAPH_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CALF_TYPE_PHASE_GRAPH, CalfPhaseGraphClass))
+
+struct CalfPhaseGraph
+{
+ GtkDrawingArea parent;
+ const calf_plugins::phase_graph_iface *source;
+ int source_id;
+ cairo_surface_t *cache_surface;
+ cairo_surface_t *fade_surface;
+ inline float _atan(float x, float l, float r) {
+ // this is a wrapper for a CPU friendly implementation of atan()
+ if(l >= 0 and r >= 0) {
+ return atan(x);
+ } else if(l >= 0 and r < 0) {
+ return M_PI + atan(x);
+ } else if(l < 0 and r < 0) {
+ return M_PI + atan(x);
+ } else if(l < 0 and r >= 0) {
+ return (2.f * M_PI) + atan(x);
+ }
+ return 0.f;
+ }
+};
+
+struct CalfPhaseGraphClass
+{
+ GtkDrawingAreaClass parent_class;
+};
+
+extern GtkWidget *calf_phase_graph_new();
+
+extern GType calf_phase_graph_get_type();
+
#define CALF_TYPE_KNOB (calf_knob_get_type())
#define CALF_KNOB(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CALF_TYPE_KNOB, CalfKnob))
#define CALF_IS_KNOB(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CALF_TYPE_KNOB))
diff --git a/src/calf/giface.h b/src/calf/giface.h
index f64908b..eaad925 100644
--- a/src/calf/giface.h
+++ b/src/calf/giface.h
@@ -200,6 +200,13 @@ struct line_graph_iface
virtual ~line_graph_iface() {}
};
+/// 'provides live line graph values' interface
+struct phase_graph_iface
+{
+ virtual bool get_phase_graph(float ** _buffer, int *_length, int * _mode, bool * _use_fade, float * _fade, int * _accuracy, bool * _display) const { return false; };
+ virtual ~phase_graph_iface() {}
+};
+
enum table_column_type
{
TCT_UNKNOWN, ///< guard invalid type
@@ -355,6 +362,8 @@ struct plugin_ctl_iface
virtual const plugin_metadata_iface *get_metadata_iface() const = 0;
/// @return line_graph_iface if any
virtual const line_graph_iface *get_line_graph_iface() const = 0;
+ /// @return phase_graph_iface if any
+ virtual const phase_graph_iface *get_phase_graph_iface() const = 0;
/// Do-nothing destructor to silence compiler warning
virtual ~plugin_ctl_iface() {}
};
@@ -435,6 +444,8 @@ struct audio_module_iface
virtual uint32_t message_run(const void *valid_ports, void *output_ports) = 0;
/// @return line_graph_iface if any
virtual const line_graph_iface *get_line_graph_iface() const = 0;
+ /// @return phase_graph_iface if any
+ virtual const phase_graph_iface *get_phase_graph_iface() const = 0;
virtual ~audio_module_iface() {}
};
@@ -537,6 +548,8 @@ public:
}
/// @return line_graph_iface if any
virtual const line_graph_iface *get_line_graph_iface() const { return dynamic_cast<const line_graph_iface *>(this); }
+ /// @return phase_graph_iface if any
+ virtual const phase_graph_iface *get_phase_graph_iface() const { return dynamic_cast<const phase_graph_iface *>(this); }
};
#if USE_EXEC_GUI || USE_DSSI
@@ -567,6 +580,9 @@ struct dssi_feedback_sender
/// Source for the graph data (interface to marshal)
const calf_plugins::line_graph_iface *graph;
+ /// Source for the graph data (interface to marshal)
+ const calf_plugins::phase_graph_iface *phase;
+
/// Create using a new client
dssi_feedback_sender(const char *URI, const line_graph_iface *_graph);
dssi_feedback_sender(osctl::osc_client *_client, const line_graph_iface *_graph);
diff --git a/src/calf/gui_controls.h b/src/calf/gui_controls.h
index 15cca8e..bddbd70 100644
--- a/src/calf/gui_controls.h
+++ b/src/calf/gui_controls.h
@@ -216,6 +216,18 @@ struct line_graph_param_control: public param_control
virtual ~line_graph_param_control();
};
+/// Phase graph
+struct phase_graph_param_control: public param_control
+{
+ int last_generation;
+
+ virtual GtkWidget *create(plugin_gui *_gui, int _param_no);
+ virtual void get() {}
+ virtual void set();
+ virtual void on_idle();
+ virtual ~phase_graph_param_control();
+};
+
/// Knob
struct knob_param_control: public param_control
{
diff --git a/src/calf/jackhost.h b/src/calf/jackhost.h
index 3edb720..adcf13b 100644
--- a/src/calf/jackhost.h
+++ b/src/calf/jackhost.h
@@ -134,6 +134,7 @@ public:
virtual int send_status_updates(send_updates_iface *sui, int last_serial) { return module->send_status_updates(sui, last_serial); }
virtual const plugin_metadata_iface *get_metadata_iface() const { return module->get_metadata_iface(); }
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(); }
};
extern jack_host *create_jack_host(const char *name, const std::string &instance_name, calf_plugins::progress_report_iface *priface);
diff --git a/src/calf/lv2wrap.h b/src/calf/lv2wrap.h
index f204db6..7a9f82a 100644
--- a/src/calf/lv2wrap.h
+++ b/src/calf/lv2wrap.h
@@ -169,6 +169,7 @@ struct lv2_instance: public plugin_ctl_iface, public progress_report_iface
}
virtual const plugin_metadata_iface *get_metadata_iface() const { return metadata; }
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 int send_status_updates(send_updates_iface *sui, int last_serial) { return module->send_status_updates(sui, last_serial); }
};
diff --git a/src/calf/metadata.h b/src/calf/metadata.h
index d0035c0..c84bd02 100644
--- a/src/calf/metadata.h
+++ b/src/calf/metadata.h
@@ -379,7 +379,7 @@ struct bassenhancer_metadata: public plugin_metadata<bassenhancer_metadata>
param_freq, param_listen, param_floor_active, param_floor, param_count };
PLUGIN_NAME_ID_LABEL("bassenhancer", "bassenhancer", "Bass Enhancer")
};
-/// Markus's Mono Module - metadata
+/// Markus's Stereo Module - metadata
struct stereo_metadata: public plugin_metadata<stereo_metadata>
{
enum { in_count = 2, out_count = 2, ins_optional = 1, outs_optional = 1, support_midi = false, require_midi = false, rt_capable = true };
@@ -387,7 +387,7 @@ struct stereo_metadata: public plugin_metadata<stereo_metadata>
STEREO_VU_METER_PARAMS, param_balance_in, param_balance_out, param_softclip,
param_mute_l, param_mute_r, param_phase_l, param_phase_r,
param_mode, param_slev, param_sbal, param_mlev, param_mpan,
- param_widener, param_delay,
+ param_stereo_base, param_delay,
param_meter_phase,
param_count };
PLUGIN_NAME_ID_LABEL("stereo", "stereo", "Stereo Tools")
@@ -404,7 +404,16 @@ struct mono_metadata: public plugin_metadata<mono_metadata>
param_count };
PLUGIN_NAME_ID_LABEL("mono", "mono", "Mono Input")
};
-
+/// Markus's and Chrischi's Analyzer
+struct analyzer_metadata: public plugin_metadata<analyzer_metadata>
+{
+ enum { in_count = 2, out_count = 2, ins_optional = 1, outs_optional = 1, support_midi = false, require_midi = false, rt_capable = true };
+ enum { param_meter_L, param_meter_R, param_clip_L, param_clip_R,
+ param_analyzer_level, param_analyzer_mode, param_analyzer_accuracy, param_analyzer_speed, param_analyzer_display, param_analyzer_smoothing, param_analyzer_hold, param_analyzer_freeze,
+ param_gonio_level, param_gonio_mode, param_gonio_use_fade, param_gonio_fade, param_gonio_accuracy, param_gonio_display,
+ param_count };
+ PLUGIN_NAME_ID_LABEL("analyzer", "analyzer", "Analyzer")
+};
/// Organ - enums for parameter IDs etc. (this mess is caused by organ split between plugin and generic class - which was
/// a bad design decision and should be sorted out some day) XXXKF @todo
struct organ_enums
diff --git a/src/calf/modulelist.h b/src/calf/modulelist.h
index 8425794..4219e03 100644
--- a/src/calf/modulelist.h
+++ b/src/calf/modulelist.h
@@ -27,6 +27,7 @@
PER_MODULE_ITEM(bassenhancer, false, "bassenhancer")
PER_MODULE_ITEM(mono, false, "mono")
PER_MODULE_ITEM(stereo, false, "stereo")
+ PER_MODULE_ITEM(analyzer, false, "analyzer")
#ifdef ENABLE_EXPERIMENTAL
PER_MODULE_ITEM(fluidsynth, true, "fluidsynth")
PER_MODULE_ITEM(wavetable, true, "wavetable")
diff --git a/src/calf/modules.h b/src/calf/modules.h
index fb9ba77..deec06f 100644
--- a/src/calf/modules.h
+++ b/src/calf/modules.h
@@ -21,6 +21,7 @@
#ifndef CALF_MODULES_H
#define CALF_MODULES_H
+#include "rfftw.h"
#include <assert.h>
#include <limits.h>
#include "biquad.h"
@@ -298,6 +299,53 @@ public:
uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask);
};
+class analyzer_audio_module:
+ public audio_module<analyzer_metadata>, public frequency_response_line_graph, public phase_graph_iface
+{
+ typedef analyzer_audio_module AM;
+ uint32_t srate;
+ bool active;
+ int _accuracy;
+ int _acc_old;
+ uint32_t clip_L, clip_R;
+ float meter_L, meter_R;
+
+public:
+ analyzer_audio_module();
+ void params_changed();
+ void activate();
+ void set_sample_rate(uint32_t sr);
+ void deactivate();
+ uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask);
+ bool get_phase_graph(float ** _buffer, int * _length, int * _mode, bool * _use_fade, float * _fade, int * _accuracy, bool * _display) const;
+ bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const;
+
+
+protected:
+ static const int max_phase_buffer_size = 8192;
+ int phase_buffer_size;
+ float *phase_buffer;
+ int fft_buffer_size;
+ float *fft_buffer;
+ int plength;
+ int ppos;
+ int fpos;
+ rfftw_plan fft_plan;
+ static const int max_fft_cache_size = 32768;
+ static const int max_fft_buffer_size = max_fft_cache_size * 2;
+ fftw_real *fft_in;
+ fftw_real *fft_out;
+ fftw_real *fft_smooth;
+ float *fft_delta;
+ float *fft_hold;
+ float *fft_freeze;
+ float _hold;
+
+ mutable int ____analyzer_phase_was_drawn_here;
+ mutable int ____analyzer_smooth_dirty;
+ mutable int ____analyzer_hold_dirty;
+
+};
};
#endif
diff --git a/src/custom_ctl.cpp b/src/custom_ctl.cpp
index be8234e..d4454e1 100644
--- a/src/custom_ctl.cpp
+++ b/src/custom_ctl.cpp
@@ -18,8 +18,6 @@
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
-
-
#include "config.h"
#include <calf/custom_ctl.h>
#include <gdk/gdkkeysyms.h>
@@ -29,10 +27,10 @@
#include <sys/time.h>
static void
-calf_line_graph_copy_cache_to_window( CalfLineGraph *lg, cairo_t *c )
+calf_line_graph_copy_cache_to_window( cairo_surface_t *lg, cairo_t *c )
{
cairo_save( c );
- cairo_set_source_surface( c, lg->cache_surface, 0,0 );
+ cairo_set_source_surface( c, lg, 0,0 );
cairo_paint( c );
cairo_restore( c );
}
@@ -82,13 +80,16 @@ calf_line_graph_draw_graph( cairo_t *c, float *data, int sx, int sy )
{
int ox=5, oy=5;
- for (int i = 0; i < 2 * sx; i++)
+ for (int i = 0; i < sx; i++)
{
int y = (int)(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);
+ if (i and (data[i] < INFINITY or i == sx - 1)) {
+ cairo_line_to(c, ox + i, y);
+ } else if (i) {
+ continue;
+ }
else
cairo_move_to(c, ox, y);
}
@@ -111,7 +112,8 @@ calf_line_graph_expose (GtkWidget *widget, GdkEventExpose *event)
GdkColor sc = { 0, 0, 0, 0 };
bool cache_dirty = 0;
-
+ bool fade_dirty = 0;
+
if( lg->cache_surface == NULL ) {
// looks like its either first call or the widget has been resized.
// create the cache_surface.
@@ -125,7 +127,17 @@ calf_line_graph_expose (GtkWidget *widget, GdkEventExpose *event)
cache_dirty = 1;
}
-
+ if( lg->fade_surface == NULL ) {
+ // looks like its either first call or the widget has been resized.
+ // create the cache_surface.
+ cairo_surface_t *window_surface = cairo_get_target( c );
+ lg->fade_surface = cairo_surface_create_similar( window_surface,
+ CAIRO_CONTENT_COLOR,
+ widget->allocation.width,
+ widget->allocation.height );
+ fade_dirty = 1;
+ }
+
cairo_select_font_face(c, "Bitstream Vera Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size(c, 9);
gdk_cairo_set_source_color(c, &sc);
@@ -213,7 +225,7 @@ calf_line_graph_expose (GtkWidget *widget, GdkEventExpose *event)
gdk_cairo_set_source_color(cache_cr, &sc2);
cairo_set_line_join(cache_cr, CAIRO_LINE_JOIN_MITER);
cairo_set_line_width(cache_cr, 1);
- for(graph_n = 0; (graph_n<cache_graph_index) && lg->source->get_graph(lg->source_id, graph_n, data, 2 * sx, &cache_cimpl); graph_n++)
+ for(graph_n = 0; (graph_n<cache_graph_index) && lg->source->get_graph(lg->source_id, graph_n, data, sx, &cache_cimpl); graph_n++)
{
calf_line_graph_draw_graph( cache_cr, data, sx, sy );
}
@@ -225,47 +237,56 @@ calf_line_graph_expose (GtkWidget *widget, GdkEventExpose *event)
cairo_fill(cache_cr);
}
- // copy window to cache.
cairo_destroy( cache_cr );
- calf_line_graph_copy_cache_to_window( lg, c );
} else {
grid_n_save = cache_grid_index;
graph_n = cache_graph_index;
dot_n = cache_dot_index;
- calf_line_graph_copy_cache_to_window( lg, c );
}
-
- cairo_rectangle(c, ox, oy, sx, sy);
- cairo_clip(c);
- cairo_set_line_width(c, 1);
+ cairo_t *cache_cr = cairo_create( lg->fade_surface );
+ cairo_set_source_surface(cache_cr, lg->cache_surface, 0, 0);
+ if(fade_dirty or !lg->use_fade) {
+ cairo_paint(cache_cr);
+ } else {
+ cairo_paint_with_alpha(cache_cr, lg->fade * 0.35 + 0.05);
+ }
+
+ cairo_impl cache_cimpl;
+ cache_cimpl.context = cache_cr;
+
+ cairo_rectangle(cache_cr, ox, oy, sx, sy);
+ cairo_clip(cache_cr);
+
+ cairo_set_line_width(cache_cr, 1);
for(int phase = 1; phase <= 2; phase++)
{
- for(int gn=grid_n_save; legend = std::string(), cairo_set_source_rgba(c, 0, 0, 0, 0.6), lg->source->get_gridline(lg->source_id, gn, pos, vertical, legend, &cimpl); gn++)
+ for(int gn=grid_n_save; legend = std::string(), cairo_set_source_rgba(c, 0, 0, 0, 0.6), lg->source->get_gridline(lg->source_id, gn, pos, vertical, legend, &cache_cimpl); gn++)
{
- calf_line_graph_draw_grid( c, legend, vertical, pos, phase, sx, sy );
+ calf_line_graph_draw_grid( cache_cr, legend, vertical, pos, phase, sx, sy );
}
}
- gdk_cairo_set_source_color(c, &sc2);
- cairo_set_line_join(c, CAIRO_LINE_JOIN_MITER);
- cairo_set_line_width(c, 1);
- for(int gn = graph_n; lg->source->get_graph(lg->source_id, gn, data, 2 * sx, &cimpl); gn++)
+ gdk_cairo_set_source_color(cache_cr, &sc2);
+ cairo_set_line_join(cache_cr, CAIRO_LINE_JOIN_MITER);
+ cairo_set_line_width(cache_cr, 1);
+ for(int gn = graph_n; lg->source->get_graph(lg->source_id, gn, data, sx, &cache_cimpl); gn++)
{
- calf_line_graph_draw_graph( c, data, sx, sy );
+ calf_line_graph_draw_graph( cache_cr, data, sx, sy );
}
- gdk_cairo_set_source_color(c, &sc3);
- for(int gn = dot_n; lg->source->get_dot(lg->source_id, gn, x, y, size = 3, &cimpl); gn++)
+ gdk_cairo_set_source_color(cache_cr, &sc3);
+ for(int gn = dot_n; lg->source->get_dot(lg->source_id, gn, x, y, size = 3, &cache_cimpl); gn++)
{
int yv = (int)(oy + sy / 2 - (sy / 2 - 1) * y);
- cairo_arc(c, ox + x * sx, yv, size, 0, 2 * M_PI);
- cairo_fill(c);
+ cairo_arc(cache_cr, ox + x * sx, yv, size, 0, 2 * M_PI);
+ cairo_fill(cache_cr);
}
delete []data;
+ cairo_destroy(cache_cr);
}
-
- cairo_destroy(c);
-
+
+ calf_line_graph_copy_cache_to_window( lg->fade_surface, c );
+
// printf("exposed %p %dx%d %d+%d\n", widget->window, event->area.x, event->area.y, event->area.width, event->area.height);
return TRUE;
@@ -394,6 +415,381 @@ calf_line_graph_get_type (void)
return type;
}
+
+///////////////////////////////////////// phase graph ///////////////////////////////////////////////
+
+static void
+calf_phase_graph_copy_cache_to_window( cairo_surface_t *pg, cairo_t *c )
+{
+ cairo_save( c );
+ cairo_set_source_surface( c, pg, 0,0 );
+ cairo_paint( c );
+ cairo_restore( c );
+}
+
+static gboolean
+calf_phase_graph_expose (GtkWidget *widget, GdkEventExpose *event)
+{
+ g_assert(CALF_IS_PHASE_GRAPH(widget));
+
+ CalfPhaseGraph *pg = CALF_PHASE_GRAPH(widget);
+ //int ox = widget->allocation.x + 1, oy = widget->allocation.y + 1;
+ int ox = 5, oy = 5, pad;
+ int sx = widget->allocation.width - ox * 2, sy = widget->allocation.height - oy * 2;
+ sx += sx % 2 - 1;
+ sy += sy % 2 - 1;
+ int rad = sx / 2 * 0.8;
+ int cx = ox + sx / 2;
+ int cy = oy + sy / 2;
+ cairo_t *c = gdk_cairo_create(GDK_DRAWABLE(widget->window));
+ GdkColor sc = { 0, 0, 0, 0 };
+
+ bool cache_dirty = 0;
+ bool fade_dirty = 0;
+
+ if( pg->cache_surface == NULL ) {
+ // looks like its either first call or the widget has been resized.
+ // create the cache_surface.
+ cairo_surface_t *window_surface = cairo_get_target( c );
+ pg->cache_surface = cairo_surface_create_similar( window_surface,
+ CAIRO_CONTENT_COLOR,
+ widget->allocation.width,
+ widget->allocation.height );
+ cache_dirty = 1;
+ }
+ if( pg->fade_surface == NULL ) {
+ // looks like its either first call or the widget has been resized.
+ // create the cache_surface.
+ cairo_surface_t *window_surface = cairo_get_target( c );
+ pg->fade_surface = cairo_surface_create_similar( window_surface,
+ CAIRO_CONTENT_COLOR,
+ widget->allocation.width,
+ widget->allocation.height );
+ fade_dirty = 1;
+ }
+
+ cairo_select_font_face(c, "Bitstream Vera Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
+ cairo_set_font_size(c, 9);
+ gdk_cairo_set_source_color(c, &sc);
+
+ cairo_impl cimpl;
+ cimpl.context = c;
+
+ if (pg->source) {
+ std::string legend;
+ float *data = new float[2 * sx];
+ GdkColor sc2 = { 0, 0.35 * 65535, 0.4 * 65535, 0.2 * 65535 };
+ GdkColor sc3 = { 0, 0.35 * 65535, 0.4 * 65535, 0.2 * 65535 };
+
+ if( cache_dirty ) {
+
+ cairo_t *cache_cr = cairo_create( pg->cache_surface );
+
+// if(widget->style->bg_pixmap[0] == NULL) {
+ cairo_set_source_rgb(cache_cr, 0, 0, 0);
+// } else {
+// gdk_cairo_set_source_pixbuf(cache_cr, GDK_PIXBUF(&style->bg_pixmap[GTK_STATE_NORMAL]), widget->allocation.x, widget->allocation.y + 20);
+// }
+ cairo_paint(cache_cr);
+
+ // outer (black)
+ pad = 0;
+ cairo_rectangle(cache_cr, pad, pad, sx + ox * 2 - pad * 2, sy + oy * 2 - pad * 2);
+ cairo_set_source_rgb(cache_cr, 0, 0, 0);
+ cairo_fill(cache_cr);
+
+ // inner (bevel)
+ pad = 1;
+ cairo_rectangle(cache_cr, pad, pad, widget->allocation.width - pad * 2, widget->allocation.height - pad + 2);
+ cairo_pattern_t *pat2 = cairo_pattern_create_linear (0, 0, 0, sy + oy * 2 - pad * 2);
+ cairo_pattern_add_color_stop_rgba (pat2, 0, 0.23, 0.23, 0.23, 1);
+ cairo_pattern_add_color_stop_rgba (pat2, 0.5, 0, 0, 0, 1);
+ cairo_set_source (cache_cr, pat2);
+ cairo_fill(cache_cr);
+ cairo_pattern_destroy(pat2);
+
+ cairo_rectangle(cache_cr, ox - 1, oy - 1, sx + 2, sy + 2);
+ cairo_set_source_rgb (cache_cr, 0, 0, 0);
+ cairo_fill(cache_cr);
+
+ cairo_pattern_t *pt = cairo_pattern_create_linear(ox, oy, ox, sy);
+ cairo_pattern_add_color_stop_rgb(pt, 0.0, 0.44, 0.44, 0.30);
+ cairo_pattern_add_color_stop_rgb(pt, 0.025, 0.89, 0.99, 0.54);
+ cairo_pattern_add_color_stop_rgb(pt, 0.4, 0.78, 0.89, 0.45);
+ cairo_pattern_add_color_stop_rgb(pt, 0.400001,0.71, 0.82, 0.33);
+ cairo_pattern_add_color_stop_rgb(pt, 1.0, 0.89, 1.00, 0.45);
+ cairo_set_source (cache_cr, pt);
+ cairo_rectangle(cache_cr, ox, oy, sx, sy);
+ cairo_fill(cache_cr);
+
+ gdk_cairo_set_source_color(cache_cr, &sc2);
+
+ cairo_select_font_face(cache_cr, "Bitstream Vera Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
+ cairo_set_font_size(cache_cr, 9);
+ cairo_text_extents_t te;
+
+ cairo_text_extents (cache_cr, "M", &te);
+ cairo_move_to (cache_cr, cx + 5, oy + 12);
+ cairo_show_text (cache_cr, "M");
+
+ cairo_text_extents (cache_cr, "S", &te);
+ cairo_move_to (cache_cr, ox + 5, cy - 5);
+ cairo_show_text (cache_cr, "S");
+
+ cairo_text_extents (cache_cr, "L", &te);
+ cairo_move_to (cache_cr, ox + 18, oy + 12);
+ cairo_show_text (cache_cr, "L");
+
+ cairo_text_extents (cache_cr, "R", &te);
+ cairo_move_to (cache_cr, ox + sx - 22, oy + 12);
+ cairo_show_text (cache_cr, "R");
+
+ cairo_impl cache_cimpl;
+ cache_cimpl.context = cache_cr;
+
+ // draw style elements here
+ cairo_set_line_width(cache_cr, 1);
+
+ cairo_move_to(cache_cr, ox, oy + sy * 0.5);
+ cairo_line_to(cache_cr, ox + sx, oy + sy * 0.5);
+ cairo_stroke(cache_cr);
+
+ cairo_move_to(cache_cr, ox + sx * 0.5, oy);
+ cairo_line_to(cache_cr, ox + sx * 0.5, oy + sy);
+ cairo_stroke(cache_cr);
+
+ cairo_set_source_rgba(cache_cr, 0, 0, 0, 0.2);
+ cairo_move_to(cache_cr, ox, oy);
+ cairo_line_to(cache_cr, ox + sx, oy + sy);
+ cairo_stroke(cache_cr);
+
+ cairo_move_to(cache_cr, ox, oy + sy);
+ cairo_line_to(cache_cr, ox + sx, oy);
+ cairo_stroke(cache_cr);
+ }
+
+
+ float * phase_buffer = 0;
+ int length = 0;
+ int mode = 2;
+ float fade = 0.05;
+ bool use_fade = true;
+ int accuracy = 1;
+ bool display = true;
+
+ pg->source->get_phase_graph(&phase_buffer, &length, &mode, &use_fade, &fade, &accuracy, &display);
+
+ fade *= 0.35;
+ fade += 0.05;
+ accuracy *= 2;
+ accuracy = 12 - accuracy;
+
+ cairo_t *cache_cr = cairo_create( pg->fade_surface );
+ cairo_set_source_surface(cache_cr, pg->cache_surface, 0, 0);
+ if(fade_dirty or !use_fade or ! display) {
+ cairo_paint(cache_cr);
+ } else {
+ cairo_paint_with_alpha(cache_cr, fade);
+ }
+
+ if(display) {
+ cairo_rectangle(cache_cr, ox, oy, sx, sy);
+ cairo_clip(cache_cr);
+ gdk_cairo_set_source_color(cache_cr, &sc3);
+
+ double _a;
+ for(int i = 0; i < length; i+= accuracy) {
+ float l = phase_buffer[i];
+ float r = phase_buffer[i + 1];
+ if(l == 0.f and r == 0.f) continue;
+ else if(r == 0.f and l > 0.f) _a = M_PI / 2.f;
+ else if(r == 0.f and l < 0.f) _a = 3.f *M_PI / 2.f;
+ else _a = pg->_atan(l / r, l, r);
+ double _R = sqrt(pow(l, 2) + pow(r, 2));
+ _a += M_PI / 4.f;
+ float x = (-1.f)*_R * cos(_a);
+ float y = _R * sin(_a);
+ // mask the cached values
+ switch(mode) {
+ case 0:
+ // small dots
+ cairo_rectangle (cache_cr, x * rad + cx, y * rad + cy, 1, 1);
+ break;
+ case 1:
+ // medium dots
+ cairo_rectangle (cache_cr, x * rad + cx - 0.25, y * rad + cy - 0.25, 1.5, 1.5);
+ break;
+ case 2:
+ // big dots
+ cairo_rectangle (cache_cr, x * rad + cx - 0.5, y * rad + cy - 0.5, 2, 2);
+ break;
+ case 3:
+ // fields
+ if(i == 0) cairo_move_to(cache_cr,
+ x * rad + cx, y * rad + cy);
+ else cairo_line_to(cache_cr,
+ x * rad + cx, y * rad + cy);
+ break;
+ case 4:
+ // lines
+ if(i == 0) cairo_move_to(cache_cr,
+ x * rad + cx, y * rad + cy);
+ else cairo_line_to(cache_cr,
+ x * rad + cx, y * rad + cy);
+ break;
+ }
+ }
+ // draw
+ switch(mode) {
+ case 0:
+ case 1:
+ case 2:
+ cairo_fill (cache_cr);
+ break;
+ case 3:
+ cairo_fill (cache_cr);
+ break;
+ case 4:
+ cairo_set_line_width(cache_cr, 1);
+ cairo_stroke (cache_cr);
+ break;
+ }
+
+ cairo_destroy( cache_cr );
+ }
+
+ calf_phase_graph_copy_cache_to_window( pg->fade_surface, c );
+
+
+// cairo_set_line_width(c, 1);
+// for(int phase = 1; phase <= 2; phase++)
+// {
+// for(int gn=grid_n_save; legend = std::string(), cairo_set_source_rgba(c, 0, 0, 0, 0.6), lg->source->get_gridline(lg->source_id, gn, pos, vertical, legend, &cimpl); gn++)
+// {
+// calf_line_graph_draw_grid( c, legend, vertical, pos, phase, sx, sy );
+// }
+// }
+
+// gdk_cairo_set_source_color(c, &sc2);
+// cairo_set_line_join(c, CAIRO_LINE_JOIN_MITER);
+// cairo_set_line_width(c, 1);
+// for(int gn = graph_n; lg->source->get_graph(lg->source_id, gn, data, 2 * sx, &cimpl); gn++)
+// {
+// calf_line_graph_draw_graph( c, data, sx, sy );
+// }
+ delete []data;
+ }
+
+ cairo_destroy(c);
+
+ // printf("exposed %p %dx%d %d+%d\n", widget->window, event->area.x, event->area.y, event->area.width, event->area.height);
+
+ return TRUE;
+}
+
+static void
+calf_phase_graph_size_request (GtkWidget *widget,
+ GtkRequisition *requisition)
+{
+ g_assert(CALF_IS_PHASE_GRAPH(widget));
+
+ // CalfLineGraph *lg = CALF_LINE_GRAPH(widget);
+}
+
+static void
+calf_phase_graph_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation)
+{
+ g_assert(CALF_IS_PHASE_GRAPH(widget));
+ CalfPhaseGraph *lg = CALF_PHASE_GRAPH(widget);
+
+ GtkWidgetClass *parent_class = (GtkWidgetClass *) g_type_class_peek_parent( CALF_PHASE_GRAPH_GET_CLASS( lg ) );
+
+ if( lg->cache_surface )
+ cairo_surface_destroy( lg->cache_surface );
+ lg->cache_surface = NULL;
+ if( lg->fade_surface )
+ cairo_surface_destroy( lg->fade_surface );
+ lg->fade_surface = NULL;
+
+ widget->allocation = *allocation;
+ GtkAllocation &a = widget->allocation;
+ if (a.width > a.height)
+ {
+ a.x += (a.width - a.height) / 2;
+ a.width = a.height;
+ }
+ if (a.width < a.height)
+ {
+ a.y += (a.height - a.width) / 2;
+ a.height = a.width;
+ }
+ parent_class->size_allocate( widget, &a );
+}
+
+static void
+calf_phase_graph_class_init (CalfPhaseGraphClass *klass)
+{
+ // GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
+ widget_class->expose_event = calf_phase_graph_expose;
+ widget_class->size_request = calf_phase_graph_size_request;
+ widget_class->size_allocate = calf_phase_graph_size_allocate;
+}
+
+static void
+calf_phase_graph_init (CalfPhaseGraph *self)
+{
+ GtkWidget *widget = GTK_WIDGET(self);
+ widget->requisition.width = 40;
+ widget->requisition.height = 40;
+ self->cache_surface = NULL;
+ self->fade_surface = NULL;
+}
+
+GtkWidget *
+calf_phase_graph_new()
+{
+ return GTK_WIDGET( g_object_new (CALF_TYPE_PHASE_GRAPH, NULL ));
+}
+
+GType
+calf_phase_graph_get_type (void)
+{
+ static GType type = 0;
+ if (!type) {
+ static const GTypeInfo type_info = {
+ sizeof(CalfPhaseGraphClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc)calf_phase_graph_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof(CalfPhaseGraph),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc)calf_phase_graph_init
+ };
+
+ GTypeInfo *type_info_copy = new GTypeInfo(type_info);
+
+ for (int i = 0; ; i++) {
+ char *name = g_strdup_printf("CalfPhaseGraph%u%d", ((unsigned int)(intptr_t)calf_phase_graph_class_init) >> 16, i);
+ if (g_type_from_name(name)) {
+ free(name);
+ continue;
+ }
+ type = g_type_register_static( GTK_TYPE_DRAWING_AREA,
+ name,
+ type_info_copy,
+ (GTypeFlags)0);
+ free(name);
+ break;
+ }
+ }
+ return type;
+}
+
+
///////////////////////////////////////// knob ///////////////////////////////////////////////
static gboolean
diff --git a/src/gui.cpp b/src/gui.cpp
index dc7b7ba..dac7f76 100644
--- a/src/gui.cpp
+++ b/src/gui.cpp
@@ -72,6 +72,8 @@ param_control *plugin_gui::create_control_from_xml(const char *element, const ch
return new vumeter_param_control;
if (!strcmp(element, "line-graph"))
return new line_graph_param_control;
+ if (!strcmp(element, "phase-graph"))
+ return new phase_graph_param_control;
if (!strcmp(element, "keyboard"))
return new keyboard_param_control;
if (!strcmp(element, "curve"))
diff --git a/src/gui_controls.cpp b/src/gui_controls.cpp
index 4405c06..b35a6f9 100644
--- a/src/gui_controls.cpp
+++ b/src/gui_controls.cpp
@@ -917,6 +917,8 @@ GtkWidget *line_graph_param_control::create(plugin_gui *_gui, int _param_no)
calf_line_graph_set_square(clg, get_int("square", 0));
clg->source = gui->plugin->get_line_graph_iface();
clg->source_id = param_no;
+ CALF_LINE_GRAPH(widget)->use_fade = get_int("use_fade", 0);
+ CALF_LINE_GRAPH(widget)->fade = get_float("fade", 0.5);
gtk_widget_set_name(GTK_WIDGET(widget), "Calf-LineGraph");
return widget;
}
@@ -937,6 +939,48 @@ line_graph_param_control::~line_graph_param_control()
{
}
+// phase graph
+
+void phase_graph_param_control::on_idle()
+{
+ if (get_int("refresh", 0))
+ set();
+}
+
+GtkWidget *phase_graph_param_control::create(plugin_gui *_gui, int _param_no)
+{
+ gui = _gui;
+ param_no = _param_no;
+ last_generation = -1;
+
+ widget = calf_phase_graph_new ();
+ gtk_widget_set_name(GTK_WIDGET(widget), "calf-phase");
+ CalfPhaseGraph *clg = CALF_PHASE_GRAPH(widget);
+ widget->requisition.width = get_int("size", 40);
+ widget->requisition.height = get_int("size", 40);
+ clg->source = gui->plugin->get_phase_graph_iface();
+ clg->source_id = param_no;
+ gtk_widget_set_name(GTK_WIDGET(widget), "Calf-PhaseGraph");
+ return widget;
+}
+
+void phase_graph_param_control::set()
+{
+ GtkWidget *tw = gtk_widget_get_toplevel(widget);
+ gtk_widget_queue_draw(tw);
+// if (tw && GTK_WIDGET_TOPLEVEL(tw) && widget->window)
+// {
+// int ws = gdk_window_get_state(widget->window);
+// if (ws & (GDK_WINDOW_STATE_WITHDRAWN | GDK_WINDOW_STATE_ICONIFIED))
+// return;
+// //last_generation = calf_phase_graph_update_if(CALF_PHASE_GRAPH(widget), last_generation);
+// }
+}
+
+phase_graph_param_control::~phase_graph_param_control()
+{
+}
+
// list view
GtkWidget *listview_param_control::create(plugin_gui *_gui, int _param_no)
diff --git a/src/lv2gui.cpp b/src/lv2gui.cpp
index f10c23c..6f20aa7 100644
--- a/src/lv2gui.cpp
+++ b/src/lv2gui.cpp
@@ -88,6 +88,9 @@ struct plugin_proxy_base
/// Obtain line graph interface if available
const line_graph_iface *get_line_graph_iface() const;
+ /// Obtain phase graph interface if available
+ const phase_graph_iface *get_phase_graph_iface() const;
+
/// Map an URI to an integer value using a given URI map
uint32_t map_uri(const char *mapURI, const char *keyURI);
@@ -170,6 +173,13 @@ const line_graph_iface *plugin_proxy_base::get_line_graph_iface() const
return NULL;
}
+const phase_graph_iface *plugin_proxy_base::get_phase_graph_iface() const
+{
+ if (instance)
+ return instance->get_phase_graph_iface();
+ return NULL;
+}
+
char *plugin_proxy_base::configure(const char *key, const char *value)
{
if (instance)
@@ -249,6 +259,9 @@ struct lv2_plugin_proxy: public plugin_ctl_iface, public plugin_proxy_base, publ
virtual const plugin_metadata_iface *get_metadata_iface() const { return plugin_metadata; }
/// Override for a method in plugin_ctl_iface - trivial delegation to base class
virtual const line_graph_iface *get_line_graph_iface() const { return plugin_proxy_base::get_line_graph_iface(); }
+
+ /// Override for a method in plugin_ctl_iface - trivial delegation to base class
+ virtual const phase_graph_iface *get_phase_graph_iface() const { return plugin_proxy_base::get_phase_graph_iface(); }
};
static gboolean plugin_on_idle(void *data)
diff --git a/src/metadata.cpp b/src/metadata.cpp
index 45891e9..f5f2329 100644
--- a/src/metadata.cpp
+++ b/src/metadata.cpp
@@ -964,7 +964,7 @@ CALF_PORT_PROPS(stereo) = {
{ 0.f, -1.f, 1.f, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_GRAPH, NULL, "mlev", "M Level" },
{ 0.f, -1.f, 1.f, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_GRAPH, NULL, "mpan", "M Panorama" },
- { 0, 0, 1, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "widener", "Widener" },
+ { 0.f, -1.f, 1.f, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "stereo_base", "Stereo Base" },
{ 0.f, -20.f, 20.f, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "delay", "Delay" },
{ 0.f, 0.f, 1.f, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_COEF | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_phase", "Phase Correlation" },
@@ -974,6 +974,39 @@ CALF_PORT_PROPS(stereo) = {
CALF_PLUGIN_INFO(stereo) = { 0x8588, "StereoTools", "Calf Stereo Tools", "Markus Schmidt", calf_plugins::calf_copyright_info, "Utility" };
+////////////////////////////////////////////////////////////////////////////
+
+CALF_PORT_NAMES(analyzer) = {"In L", "In R", "Out L", "Out R"};
+const char *gonio_mode_names[] = { "Small Dots", "Medium Dots", "Big Dots", "Fields", "Lines" };
+const char *analyzer_mode_names[] = { "Average", "Maximum", "Left Channel", "Right Channel" };
+const char *analyzer_smooth_names[] = { "Falling", "Smoothing", "Off" };
+CALF_PORT_PROPS(analyzer) = {
+ { 0, 0, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_L", "Level L" },
+ { 0, 0, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_R", "Level R" },
+ { 0, 0, 1, 0, PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_L", "Clip L" },
+ { 0, 0, 1, 0, PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_R", "Clip R" },
+
+ { 1, 0.125, 8, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "analyzer_level", "Analyzer Level" },
+ { 0, 0, 3, 0, PF_ENUM | PF_CTL_COMBO, analyzer_mode_names, "analyzer_mode", "Analyzer Mode" },
+ { 6, 2, 8, 0, PF_INT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_GRAPH, NULL, "analyzer_accuracy", "Analyzer Accuracy" },
+ { 13, 1, 15, 0, PF_INT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_GRAPH, NULL, "analyzer_speed", "Analyzer Speed" },
+ { 1, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "analyzer_display", "Analyzer Display" },
+ { 0, 0, 2, 0, PF_ENUM | PF_CTL_COMBO, analyzer_smooth_names, "analyzer_smoothing", "Analyzer Smoothing" },
+ { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "analyzer_hold", "Analyzer Hold" },
+ { 0, 0, 1, 2, PF_BOOL | PF_CTL_TOGGLE , NULL, "analyzer_freeze", "Analyzer Freeze" },
+
+ { 1, 0.125, 8, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "gonio_level", "Gonio Level" },
+ { 1, 0, 4, 0, PF_ENUM | PF_CTL_COMBO, gonio_mode_names, "gonio_mode", "Gonio Mode" },
+ { 1, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "gonio_use_fade", "Gonio Fade Active" },
+ { 0.5f, 0.f, 1.f, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_GRAPH, NULL, "gonio_fade", "Gonio Fade" },
+ { 4, 1, 5, 0, PF_INT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_GRAPH, NULL, "gonio_accuracy", "Gonio Accuracy" },
+ { 1, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "gonio_display", "Gonio Display" },
+
+ {}
+};
+
+CALF_PLUGIN_INFO(analyzer) = { 0x8588, "Analyzer", "Calf Analyzer", "Markus Schmidt / Christian Holschuh", calf_plugins::calf_copyright_info, "Analyzer" };
+
////////////////////////////////////////////////////////////////////////////
diff --git a/src/modules.cpp b/src/modules.cpp
index ba06f02..206dcc2 100644
--- a/src/modules.cpp
+++ b/src/modules.cpp
@@ -20,10 +20,13 @@
*/
#include <limits.h>
#include <memory.h>
+#include <math.h>
+#include <rfftw.h>
#include <calf/giface.h>
#include <calf/modules.h>
#include <calf/modules_dev.h>
+
using namespace dsp;
using namespace calf_plugins;
@@ -607,9 +610,15 @@ uint32_t stereo_audio_module::process(uint32_t offset, uint32_t numsamples, uint
L += LL*L + RL*R;
R += RR*R + LR*L;
- // widener
- L += *params[param_widener] * R * -1;
- R += *params[param_widener] * L * -1;
+ // stereo base
+ float _sb = *params[param_stereo_base];
+ if(_sb < 0) _sb *= 0.5;
+
+ float __l = L +_sb * L - _sb * R;
+ float __r = R + _sb * R - _sb * L;
+
+ L = __l;
+ R = __r;
// delay
buffer[pos] = L;
@@ -795,3 +804,245 @@ void mono_audio_module::set_sample_rate(uint32_t sr)
memset(buffer, 0, buffer_size * sizeof(float)); // reset buffer to zero
pos = 0;
}
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+analyzer_audio_module::analyzer_audio_module() {
+ active = false;
+ clip_L = 0.f;
+ clip_R = 0.f;
+ meter_L = 0.f;
+ meter_R = 0.f;
+ _accuracy = -1;
+ _acc_old = -1;
+ ppos = 0;
+ plength = 0;
+ fpos = 0;
+ _hold = 0.f;
+ phase_buffer = (float*) calloc(max_phase_buffer_size, sizeof(float));
+ memset(phase_buffer, 0, max_phase_buffer_size * sizeof(float)); // reset buffer to zero
+ fft_buffer = (float*) calloc(max_fft_buffer_size, sizeof(float));
+ memset(fft_buffer, 0, max_fft_buffer_size * sizeof(float)); // reset buffer to zero
+ fft_in = (fftw_real*) calloc(max_fft_cache_size, sizeof(fftw_real));
+ fft_out = (fftw_real*) calloc(max_fft_cache_size, sizeof(fftw_real));
+ fft_smooth = (fftw_real*) calloc(max_fft_cache_size, sizeof(fftw_real));
+ memset(fft_smooth, 0, max_fft_cache_size * sizeof(fftw_real)); // reset buffer to zero
+ fft_delta = (float*) calloc(max_fft_cache_size, sizeof(float));
+ memset(fft_delta, 0, max_fft_cache_size * sizeof(float)); // reset buffer to zero
+ fft_hold = (float*) calloc(max_fft_cache_size, sizeof(float));
+ memset(fft_hold, 0, max_fft_cache_size * sizeof(float)); // reset buffer to zero
+ fft_freeze = (float*) calloc(max_fft_cache_size, sizeof(float));
+ memset(fft_freeze, 0, max_fft_cache_size * sizeof(float)); // reset buffer to zero
+
+ ____analyzer_phase_was_drawn_here = 0;
+ ____analyzer_smooth_dirty = 0;
+ ____analyzer_hold_dirty = 0;
+
+}
+
+void analyzer_audio_module::activate() {
+ active = true;
+}
+
+void analyzer_audio_module::deactivate() {
+ active = false;
+}
+
+void analyzer_audio_module::params_changed() {
+ if(*params[param_analyzer_accuracy] != _acc_old) {
+ _accuracy = pow(2, 7 + *params[param_analyzer_accuracy]);
+ _acc_old = *params[param_analyzer_accuracy];
+ // recreate fftw plan
+ fft_plan = rfftw_create_plan(_accuracy, FFTW_FORWARD, 0);
+ }
+ if(*params[param_analyzer_hold] != _hold) {
+ ____analyzer_hold_dirty = 1;
+ _hold = *params[param_analyzer_hold];
+ }
+}
+
+uint32_t analyzer_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask) {
+ for(uint32_t i = offset; i < offset + numsamples; i++) {
+ // let meters fall a bit
+ clip_L -= std::min(clip_L, numsamples);
+ clip_R -= std::min(clip_R, numsamples);
+ meter_L = 0.f;
+ meter_R = 0.f;
+
+ float L = ins[0][i];
+ float R = ins[1][i];
+
+ // GUI stuff
+ if(L > 1.f) clip_L = srate >> 3;
+ if(R > 1.f) clip_R = srate >> 3;
+
+ // goniometer
+ phase_buffer[ppos] = L * *params[param_gonio_level];
+ phase_buffer[ppos + 1] = R * *params[param_gonio_level];
+
+ plength = std::min(phase_buffer_size, plength + 2);
+ ppos += 2;
+ ppos %= (phase_buffer_size - 2);
+
+ // analyzer
+ fft_buffer[fpos] = L * *params[param_analyzer_level];
+ fft_buffer[fpos + 1] = R * *params[param_analyzer_level];
+
+ fpos += 2;
+ fpos %= (max_fft_buffer_size - 2);
+
+ // meter
+ meter_L = L;
+ meter_R = R;
+
+ //output
+ outs[0][i] = L;
+ outs[1][i] = R;
+ }
+ // draw meters
+ SET_IF_CONNECTED(clip_L);
+ SET_IF_CONNECTED(clip_R);
+ SET_IF_CONNECTED(meter_L);
+ SET_IF_CONNECTED(meter_R);
+ return outputs_mask;
+}
+
+void analyzer_audio_module::set_sample_rate(uint32_t sr)
+{
+ srate = sr;
+ phase_buffer_size = srate / 30 * 2;
+ phase_buffer_size -= phase_buffer_size % 2;
+ phase_buffer_size = std::min(phase_buffer_size, (int)max_phase_buffer_size);
+}
+
+bool analyzer_audio_module::get_phase_graph(float ** _buffer, int *_length, int * _mode, bool * _use_fade, float * _fade, int * _accuracy, bool * _display) const {
+ *_buffer = &phase_buffer[0];
+ *_length = plength;
+ *_use_fade = *params[param_gonio_use_fade];
+ *_fade = *params[param_gonio_fade];
+ *_mode = *params[param_gonio_mode];
+ *_accuracy = *params[param_gonio_accuracy];
+ *_display = *params[param_gonio_display];
+ return false;
+}
+
+bool analyzer_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context) const
+{
+ if (!active or subindex > 1 or !*params[param_analyzer_display]
+ or (subindex > 0 and !*params[param_analyzer_hold]))
+ return false;
+ float ret;
+ double freq;
+ int _last = 0;
+ if(subindex == 0) {
+ ____analyzer_phase_was_drawn_here ++;
+ int _param_speed = 16 - (int)*params[param_analyzer_speed];
+ if(!((int)____analyzer_phase_was_drawn_here % _param_speed)) {
+ for(int i = 0; i < _accuracy; i++) {
+ int _fpos = (fpos - _accuracy * 2 + (i * 2)) % max_fft_buffer_size;
+ if(_fpos < 0)
+ _fpos = max_fft_buffer_size + _fpos;
+ float L = fft_buffer[_fpos];
+ float R = fft_buffer[_fpos + 1];
+
+ // get the right value for calculations
+ fftw_real val;
+ switch((int)*params[param_analyzer_mode]) {
+ case 0:
+ // average
+ val = (L + R) / 2;
+ break;
+ case 1:
+ // maximum
+ val = std::max(L, R);
+ break;
+ case 2:
+ // left channel
+ val = L;
+ break;
+ case 3:
+ // right channel
+ val = R;
+ break;
+ }
+ fft_in[i] = (fftw_real)val;
+
+ // fill smoothing buffer
+ if(*params[param_analyzer_smoothing] == 1.f)
+ fft_smooth[i] = fabs(fft_out[i]);
+ if(*params[param_analyzer_smoothing] == 0.f and fft_smooth[i] < fabs(fft_out[i])) {
+ fft_smooth[i] = fabs(fft_out[i]);
+ }
+
+ // fill delta buffer
+ if(*params[param_analyzer_smoothing] == 0.f) {
+ fft_delta[i] = fft_smooth[i] / sqrt(_param_speed) / -8.f;
+ }
+
+ // fill hold buffer
+ if(____analyzer_hold_dirty) {
+ fft_hold[i] = 0.f;
+ } else if(fabs(fft_out[i]) > fft_hold[i]) {
+ fft_hold[i] = fabs(fft_out[i]);
+ }
+ }
+ rfftw_one(fft_plan, fft_in, fft_out);
+ ____analyzer_hold_dirty = 0;
+ ____analyzer_smooth_dirty = 1;
+ }
+ for (int i = 0; i < points; i++)
+ {
+ ret = 1.f;
+ freq = 20.0 * pow (20000.0 / 20.0, i * 1.0 / points);
+ int __last = floor(freq * (float)_accuracy / (float)srate);
+ if(!i or __last > _last) {
+ int iter;
+ if(!i) {
+ iter = 0;
+ } else {
+ _last = __last;
+ iter = _last;
+ }
+ if(____analyzer_smooth_dirty and *params[param_analyzer_smoothing] == 1.f) {
+ fft_delta[iter] = (fabs(fft_out[iter]) - fft_smooth[iter]) / _param_speed;
+ }
+ if(*params[param_analyzer_smoothing] == 1.f) {
+ fft_smooth[iter] += fft_delta[iter];
+ }
+ if(*params[param_analyzer_smoothing] == 0.f) {
+ fft_smooth[iter] += fft_delta[iter];
+ fft_delta[iter] /= 1.01f;
+ }
+ if (*params[param_analyzer_freeze] > 0.f)
+ ret = dB_grid(fabs(fft_freeze[iter]) / 800.f);
+ else if(*params[param_analyzer_smoothing] < 2.f) {
+ ret = dB_grid(fabs(fft_smooth[iter]) / 800.f);
+ fft_freeze[iter] = fft_smooth[iter];
+ } else {
+ ret = dB_grid(fabs(fft_out[iter]) / 800.f);
+ fft_freeze[iter] = fft_out[iter];
+ }
+ } else
+ ret = INFINITY;
+ data[i] = ret;
+
+ }
+ ____analyzer_smooth_dirty = 0;
+ return true;
+ } else {
+ context->set_source_rgba(0.35, 0.4, 0.2, 0.2);
+ for (int i = 0; i < points; i++)
+ {
+ freq = 20.0 * pow (20000.0 / 20.0, i * 1.0 / points);
+ int __last = floor(freq * (float)_accuracy / (float)srate);
+ if(!i) {
+ ret = dB_grid(fft_hold[0] / 800.f);
+ } else if(__last > _last) {
+ _last = __last;
+ ret = dB_grid(fft_hold[_last] / 800.f);
+ } else
+ ret = INFINITY;
+ data[i] = ret;
+ }
+ }
+ return true;
+}
--
calf audio plugins packaging
More information about the pkg-multimedia-commits
mailing list