[SCM] calf/master: + Multiband Compressor: new module (first version, by Markus Schmidt, based on code by me and Thor) plus associated refactoring and graph colour scheme update
js at users.alioth.debian.org
js at users.alioth.debian.org
Tue May 7 15:39:36 UTC 2013
The following commit has been merged in the master branch:
commit 9912931955299424aac7f32685d1a04003765995
Author: Krzysztof Foltman <wdev at foltman.com>
Date: Thu Oct 8 23:34:28 2009 +0100
+ Multiband Compressor: new module (first version, by Markus Schmidt, based on code by me and Thor) plus associated refactoring and graph colour scheme update
diff --git a/knob.png b/knob.png
deleted file mode 100644
index 1047e49..0000000
Binary files a/knob.png and /dev/null differ
diff --git a/src/calf/giface.h b/src/calf/giface.h
index 320b04b..63d165e 100644
--- a/src/calf/giface.h
+++ b/src/calf/giface.h
@@ -195,7 +195,7 @@ struct line_graph_iface
/// @param subindex_dot First dot that has to be redrawn
/// @param subindex_gridline First gridline/legend that has to be redrawn
/// @retval Current generation (to pass when calling the function next time); if different than passed generation value, call the function again to retrieve which graph offsets should be put into cache
- virtual int get_changed_offsets(int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) { subindex_graph = subindex_dot = subindex_gridline = 0; return 0; }
+ virtual int get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline) { subindex_graph = subindex_dot = subindex_gridline = 0; return 0; }
/// Standard destructor to make compiler happy
virtual ~line_graph_iface() {}
diff --git a/src/calf/metadata.h b/src/calf/metadata.h
index 4d2bd0c..a10ef3b 100644
--- a/src/calf/metadata.h
+++ b/src/calf/metadata.h
@@ -136,6 +136,27 @@ struct compressor_metadata: public plugin_metadata<compressor_metadata>
PLUGIN_NAME_ID_LABEL("compressor", "compressor", "Compressor")
};
+/// Markus's multibandcompressor - metadata
+struct multibandcompressor_metadata: public plugin_metadata<multibandcompressor_metadata>
+{
+ enum { in_count = 2, out_count = 2, support_midi = false, require_midi = false, rt_capable = true };
+ enum { param_bypass, param_level_in, param_level_out, param_meter_inL, param_meter_inR,
+ param_meter_outL, param_meter_outR, param_clip_inL, param_clip_inR, param_clip_outL, param_clip_outR,
+ param_freq0, param_freq1, param_freq2,
+ param_sep0, param_sep1, param_sep2,
+ param_q0, param_q1, param_q2,
+ param_threshold0, param_ratio0, param_attack0, param_release0, param_makeup0, param_knee0,
+ param_detection0, param_compression0, param_output0, param_bypass0, param_mute0,
+ param_threshold1, param_ratio1, param_attack1, param_release1, param_makeup1, param_knee1,
+ param_detection1, param_compression1, param_output1, param_bypass1, param_mute1,
+ param_threshold2, param_ratio2, param_attack2, param_release2, param_makeup2, param_knee2,
+ param_detection2, param_compression2, param_output2, param_bypass2, param_mute2,
+ param_threshold3, param_ratio3, param_attack3, param_release3, param_makeup3, param_knee3,
+ param_detection3, param_compression3, param_output3, param_bypass3, param_mute3,
+ param_count };
+ PLUGIN_NAME_ID_LABEL("multibandcompressor", "multibandcompressor", "Multibandcompressor")
+};
+
/// 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 0c9f0b8..ca99065 100644
--- a/src/calf/modulelist.h
+++ b/src/calf/modulelist.h
@@ -10,6 +10,7 @@
PER_MODULE_ITEM(phaser, false, "phaser")
PER_MODULE_ITEM(multichorus, false, "multichorus")
PER_MODULE_ITEM(compressor, false, "compressor")
+ PER_MODULE_ITEM(multibandcompressor, false, "multibandcompressor")
#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 29aa47e..de0e46c 100644
--- a/src/calf/modules.h
+++ b/src/calf/modules.h
@@ -66,7 +66,7 @@ class frequency_response_line_graph: public line_graph_iface
{
public:
bool get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context);
- virtual int get_changed_offsets(int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline);
+ virtual int get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline);
};
class flanger_audio_module: public audio_module<flanger_metadata>, public frequency_response_line_graph
@@ -754,7 +754,7 @@ public:
}
bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context);
- int get_changed_offsets(int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline);
+ int get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline);
};
/// A multitap stereo chorus thing - processing
@@ -875,18 +875,18 @@ public:
virtual bool get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context);
virtual bool get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context);
- virtual int get_changed_offsets(int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline)
+ virtual int get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline)
{
- subindex_graph = 0;
- subindex_dot = 0;
- subindex_gridline = generation ? INT_MAX : 0;
+ subindex_graph = 0;
+ subindex_dot = 0;
+ subindex_gridline = generation ? INT_MAX : 0;
if (fabs(threshold-old_threshold) + fabs(ratio - old_ratio) + fabs(knee - old_knee) + fabs( makeup - old_makeup) + fabs( *params[param_bypass] - old_bypass) > 0.01f)
{
- old_threshold = threshold;
- old_ratio = ratio;
- old_knee = knee;
- old_makeup = makeup;
+ old_threshold = threshold;
+ old_ratio = ratio;
+ old_knee = knee;
+ old_makeup = makeup;
old_bypass = *params[param_bypass];
last_generation++;
}
@@ -897,6 +897,64 @@ public:
}
};
+class gain_reduction_audio_module {
+private:
+ float linSlope, detected, kneeSqrt, kneeStart, linKneeStart, kneeStop;
+ float compressedKneeStop, adjKneeStart, thres;
+ float attack, release, threshold, ratio, knee, makeup, detection, bypass, mute, meter_out, meter_comp;
+ float old_threshold, old_ratio, old_knee, old_makeup, old_bypass;
+ int last_generation;
+ uint32_t srate;
+ bool is_active;
+ inline float output_level(float slope);
+ inline float output_gain(float linSlope, bool rms);
+public:
+ gain_reduction_audio_module();
+ void set_params(float att, float rel, float thr, float rat, float kn, float mak, float det, float byp, float mu);
+ void process(float &left, float &right);
+ void activate();
+ void deactivate();
+ int id;
+ void set_sample_rate(uint32_t sr);
+ float get_output_level();
+ float get_comp_level();
+ virtual bool get_graph(int subindex, float *data, int points, cairo_iface *context);
+ virtual bool get_dot(int subindex, float &x, float &y, int &size, cairo_iface *context);
+ virtual bool get_gridline(int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context);
+ virtual int get_changed_offsets(int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline);
+};
+
+/// Multibandcompressor by Markus Schmidt
+class multibandcompressor_audio_module: public audio_module<multibandcompressor_metadata>, public line_graph_iface {
+private:
+ static const int strips = 4;
+ float meter_out[strips];
+ float meter_comp[strips];
+ bool mute[strips];
+ uint32_t clip_inL, clip_inR, clip_outL, clip_outR;
+ float meter_inL, meter_inR, meter_outL, meter_outR;
+ gain_reduction_audio_module strip[strips];
+ dsp::biquad_d2<float> lpL0, lpR0, lpL1, lpR1, lpL2, lpR2, hpL0, hpR0, hpL1, hpR1, hpL2, hpR2;
+ float freq_old[strips - 1], sep_old[strips - 1], q_old[strips - 1];
+public:
+ float *ins[in_count];
+ float *outs[out_count];
+ float *params[param_count];
+ uint32_t srate;
+ bool is_active;
+ multibandcompressor_audio_module();
+ void activate();
+ void deactivate();
+ void params_changed();
+ uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask);
+ void set_sample_rate(uint32_t sr);
+ virtual bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context);
+ virtual bool get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context);
+ virtual bool get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context);
+ virtual int get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline);
+};
+
+
/// Filterclavier --- MIDI controlled filter by Hans Baier
class filterclavier_audio_module:
public audio_module<filterclavier_metadata>,
diff --git a/src/custom_ctl.cpp b/src/custom_ctl.cpp
index 586b7da..969ab7c 100644
--- a/src/custom_ctl.cpp
+++ b/src/custom_ctl.cpp
@@ -17,6 +17,8 @@
* 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>
@@ -70,37 +72,37 @@ calf_line_graph_draw_grid( cairo_t *c, std::string &legend, bool vertical, float
int ox=1, oy=1;
cairo_text_extents_t tx;
if (!legend.empty())
- cairo_text_extents(c, legend.c_str(), &tx);
+ cairo_text_extents(c, legend.c_str(), &tx);
if (vertical)
{
- float x = floor(ox + pos * sx) + 0.5;
- if (phase == 1)
- {
- cairo_move_to(c, x, oy);
- cairo_line_to(c, x, oy + sy);
- cairo_stroke(c);
- }
- if (phase == 2 && !legend.empty()) {
-
- cairo_set_source_rgba(c, 1.0, 1.0, 1.0, 0.75);
- cairo_move_to(c, x - (tx.x_bearing + tx.width / 2.0), oy + sy - 2);
- cairo_show_text(c, legend.c_str());
- }
+ float x = floor(ox + pos * sx) + 0.5;
+ if (phase == 1)
+ {
+ cairo_move_to(c, x, oy);
+ cairo_line_to(c, x, oy + sy);
+ cairo_stroke(c);
+ }
+ if (phase == 2 && !legend.empty()) {
+
+ cairo_set_source_rgba(c, 0.0, 0.0, 0.0, 0.7);
+ cairo_move_to(c, x - (tx.x_bearing + tx.width / 2.0) - 2, oy + sy - 2);
+ cairo_show_text(c, legend.c_str());
+ }
}
else
{
- float y = floor(oy + sy / 2 - (sy / 2 - 1) * pos) + 0.5;
- if (phase == 1)
- {
- cairo_move_to(c, ox, y);
- cairo_line_to(c, ox + sx, y);
- cairo_stroke(c);
- }
- if (phase == 2 && !legend.empty()) {
- cairo_set_source_rgba(c, 1.0, 1.0, 1.0, 0.75);
- cairo_move_to(c, ox + sx - 2 - tx.width, y + tx.height/2 - 1);
- cairo_show_text(c, legend.c_str());
- }
+ float y = floor(oy + sy / 2 - (sy / 2 - 1) * pos) + 0.5;
+ if (phase == 1)
+ {
+ cairo_move_to(c, ox, y);
+ cairo_line_to(c, ox + sx, y);
+ cairo_stroke(c);
+ }
+ if (phase == 2 && !legend.empty()) {
+ cairo_set_source_rgba(c, 0.0, 0.0, 0.0, 0.7);
+ cairo_move_to(c, ox + sx - 4 - tx.width, y + tx.height/2);
+ cairo_show_text(c, legend.c_str());
+ }
}
}
@@ -111,13 +113,13 @@ calf_line_graph_draw_graph( cairo_t *c, float *data, int sx, int sy )
for (int i = 0; i < 2 * 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);
- else
- cairo_move_to(c, ox, y);
+ 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);
+ else
+ cairo_move_to(c, ox, y);
}
cairo_stroke(c);
}
@@ -126,37 +128,35 @@ static gboolean
calf_line_graph_expose (GtkWidget *widget, GdkEventExpose *event)
{
g_assert(CALF_IS_LINE_GRAPH(widget));
-
+
CalfLineGraph *lg = CALF_LINE_GRAPH(widget);
//int ox = widget->allocation.x + 1, oy = widget->allocation.y + 1;
int ox = 1, oy = 1;
int sx = widget->allocation.width - 2, sy = widget->allocation.height - 2;
-
- cairo_t *c = gdk_cairo_create(GDK_DRAWABLE(widget->window));
+ cairo_t *c = gdk_cairo_create(GDK_DRAWABLE(widget->window));
+ GtkStyle *style;
+ style = gtk_widget_get_style(widget);
GdkColor sc = { 0, 0, 0, 0 };
bool cache_dirty = 0;
-
-
if( lg->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 );
- lg->cache_surface = cairo_surface_create_similar( window_surface,
- CAIRO_CONTENT_COLOR,
- widget->allocation.width,
- widget->allocation.height );
- //cairo_set_source_surface( cache_cr, window_surface, 0,0 );
- //cairo_paint( cache_cr );
-
- cache_dirty = 1;
+ // 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->cache_surface = cairo_surface_create_similar( window_surface,
+ CAIRO_CONTENT_COLOR,
+ widget->allocation.width,
+ widget->allocation.height );
+ //cairo_set_source_surface( cache_cr, window_surface, 0,0 );
+ //cairo_paint( cache_cr );
+
+ cache_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_rectangle(c, ox, oy, sx, sy);
cairo_clip(c);
@@ -170,75 +170,83 @@ calf_line_graph_expose (GtkWidget *widget, GdkEventExpose *event)
bool vertical = false;
std::string legend;
float *data = new float[2 * sx];
- GdkColor sc2 = { 0, 0, 65535, 0 };
+ GdkColor sc2 = { 0, 0.35 * 65535, 0.4 * 65535, 0.2 * 65535 };
float x, y;
int size = 0;
- GdkColor sc3 = { 0, 32767, 65535, 0 };
-
- int graph_n, grid_n, dot_n, grid_n_save;
-
- int cache_graph_index, cache_dot_index, cache_grid_index;
- int gen_index = lg->source->get_changed_offsets( lg->last_generation, cache_graph_index, cache_dot_index, cache_grid_index );
-
- if( cache_dirty || (gen_index != lg->last_generation) ) {
-
- cairo_t *cache_cr = cairo_create( lg->cache_surface );
- cairo_select_font_face(cache_cr, "Bitstream Vera Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
- cairo_set_font_size(cache_cr, 9);
-
- gdk_cairo_set_source_color(cache_cr, &sc);
- cairo_rectangle(cache_cr, ox, oy, sx, sy);
- cairo_clip_preserve(cache_cr);
- cairo_fill(cache_cr);
-
- cairo_impl cache_cimpl;
- cache_cimpl.context = cache_cr;
-
- lg->source->get_changed_offsets( gen_index, cache_graph_index, cache_dot_index, cache_grid_index );
- lg->last_generation = gen_index;
-
- cairo_set_line_width(cache_cr, 1);
- for(int phase = 1; phase <= 2; phase++)
- {
- for(grid_n = 0; legend = std::string(), cairo_set_source_rgba(cache_cr, 1, 1, 1, 0.5), (grid_n<cache_grid_index) && lg->source->get_gridline(lg->source_id, grid_n, pos, vertical, legend, &cache_cimpl); grid_n++)
- {
- calf_line_graph_draw_grid( cache_cr, legend, vertical, pos, phase, sx, sy );
- }
- }
- grid_n_save = grid_n;
-
- 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++)
- {
- calf_line_graph_draw_graph( cache_cr, data, sx, sy );
- }
- gdk_cairo_set_source_color(cache_cr, &sc3);
- for(dot_n = 0; (dot_n<cache_dot_index) && lg->source->get_dot(lg->source_id, dot_n, x, y, size = 3, &cache_cimpl); dot_n++)
- {
- int yv = (int)(oy + sy / 2 - (sy / 2 - 1) * y);
- cairo_arc(cache_cr, ox + x * sx, yv, size, 0, 2 * M_PI);
- 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 );
- }
+ GdkColor sc3 = { 0, 0.35 * 65535, 0.4 * 65535, 0.2 * 65535 };
+
+ int graph_n, grid_n, dot_n, grid_n_save;
+
+ int cache_graph_index, cache_dot_index, cache_grid_index;
+ int gen_index = lg->source->get_changed_offsets( lg->source_id, lg->last_generation, cache_graph_index, cache_dot_index, cache_grid_index );
+
+ if( cache_dirty || (gen_index != lg->last_generation) ) {
+
+ cairo_t *cache_cr = cairo_create( lg->cache_surface );
+ 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_pattern_t *pt = cairo_pattern_create_linear(ox, oy, ox, sy);
+ cairo_pattern_add_color_stop_rgb(pt, 0.0, 0.85, 0.95, 0.45);
+ cairo_pattern_add_color_stop_rgb(pt, 0.5, 0.8, 0.9, 0.4);
+ cairo_pattern_add_color_stop_rgb(pt, 1.0, 0.85, 0.95, 0.45);
+ //gdk_cairo_set_source_color(cache_cr, &sc);
+ cairo_set_source (cache_cr, pt);
+ cairo_rectangle(cache_cr, ox, oy, sx, sy);
+ cairo_clip_preserve(cache_cr);
+ cairo_fill_preserve(cache_cr);
+// cairo_set_source_rgba(cache_cr, 0, 0, 0, 0.5);
+// cairo_set_line_width(cache_cr, 1);
+// cairo_stroke(cache_cr);
+
+ cairo_impl cache_cimpl;
+ cache_cimpl.context = cache_cr;
+
+ lg->source->get_changed_offsets( lg->source_id, gen_index, cache_graph_index, cache_dot_index, cache_grid_index );
+ lg->last_generation = gen_index;
+
+ cairo_set_line_width(cache_cr, 1);
+ for(int phase = 1; phase <= 2; phase++)
+ {
+ for(grid_n = 0; legend = std::string(), cairo_set_source_rgba(cache_cr, 0, 0, 0, 0.6), (grid_n<cache_grid_index) && lg->source->get_gridline(lg->source_id, grid_n, pos, vertical, legend, &cache_cimpl); grid_n++)
+ {
+ calf_line_graph_draw_grid( cache_cr, legend, vertical, pos, phase, sx, sy );
+ }
+ }
+ grid_n_save = grid_n;
+
+ 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++)
+ {
+ calf_line_graph_draw_graph( cache_cr, data, sx, sy );
+ }
+ gdk_cairo_set_source_color(cache_cr, &sc3);
+ for(dot_n = 0; (dot_n<cache_dot_index) && lg->source->get_dot(lg->source_id, dot_n, x, y, size = 3, &cache_cimpl); dot_n++)
+ {
+ int yv = (int)(oy + sy / 2 - (sy / 2 - 1) * y);
+ cairo_arc(cache_cr, ox + x * sx, yv, size, 0, 2 * M_PI);
+ 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_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, 1, 1, 1, 0.5), 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, &cimpl); gn++)
{
- calf_line_graph_draw_grid( c, legend, vertical, pos, phase, sx, sy );
+ calf_line_graph_draw_grid( c, legend, vertical, pos, phase, sx, sy );
}
}
@@ -247,7 +255,7 @@ calf_line_graph_expose (GtkWidget *widget, GdkEventExpose *event)
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 );
+ calf_line_graph_draw_graph( c, 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++)
@@ -258,12 +266,12 @@ calf_line_graph_expose (GtkWidget *widget, GdkEventExpose *event)
}
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 %dx%d %d+%d\n", widget->window, event->area.x, event->area.y, event->area.width, event->area.height);
-
+
return TRUE;
}
@@ -280,7 +288,7 @@ int calf_line_graph_update_if(CalfLineGraph *graph, int last_drawn_generation)
if (graph->source)
{
int subgraph, dot, gridline;
- generation = graph->source->get_changed_offsets(generation, subgraph, dot, gridline);
+ generation = graph->source->get_changed_offsets(graph->source_id, generation, subgraph, dot, gridline);
if (subgraph == INT_MAX && dot == INT_MAX && gridline == INT_MAX && generation == last_drawn_generation)
return generation;
gtk_widget_queue_draw(GTK_WIDGET(graph));
@@ -303,11 +311,11 @@ calf_line_graph_size_allocate (GtkWidget *widget,
{
g_assert(CALF_IS_LINE_GRAPH(widget));
CalfLineGraph *lg = CALF_LINE_GRAPH(widget);
-
+
GtkWidgetClass *parent_class = (GtkWidgetClass *) g_type_class_peek_parent( CALF_LINE_GRAPH_GET_CLASS( lg ) );
if( lg->cache_surface )
- cairo_surface_destroy( lg->cache_surface );
+ cairo_surface_destroy( lg->cache_surface );
lg->cache_surface = NULL;
widget->allocation = *allocation;
@@ -397,87 +405,93 @@ calf_vumeter_expose (GtkWidget *widget, GdkEventExpose *event)
{
g_assert(CALF_IS_VUMETER(widget));
-
+
CalfVUMeter *vu = CALF_VUMETER(widget);
+ GtkStyle *style;
//int ox = widget->allocation.x + 1, oy = widget->allocation.y + 1;
int ox = 1, oy = 1;
- int sx = widget->allocation.width - 2, sy = widget->allocation.height - 2;
-
+ int sx = widget->allocation.width - 1 - ((widget->allocation.width - 2) % 3), sy = widget->allocation.height - 2;
+ style = gtk_widget_get_style(widget);
cairo_t *c = gdk_cairo_create(GDK_DRAWABLE(widget->window));
if( vu->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 );
- vu->cache_surface = cairo_surface_create_similar( window_surface,
- CAIRO_CONTENT_COLOR,
- widget->allocation.width,
- widget->allocation.height );
-
- // And render the meterstuff again.
-
- cairo_t *cache_cr = cairo_create( vu->cache_surface );
- GdkColor sc = { 0, 0, 0, 0 };
- gdk_cairo_set_source_color(cache_cr, &sc);
- cairo_rectangle(cache_cr, ox, oy, sx, sy);
- cairo_fill(cache_cr);
- cairo_set_line_width(cache_cr, 1);
-
- for (int x = ox; x <= ox + sx; x += 3)
- {
- float ts = (x - ox) * 1.0 / sx;
- float r = 0.f, g = 0.f, b = 0.f;
- switch(vu->mode)
- {
- case VU_STANDARD:
- default:
- if (ts < 0.75)
- r = ts / 0.75, g = 1, b = 0;
- else
- r = 1, g = 1 - (ts - 0.75) / 0.25, b = 0;
- // if (vu->value < ts || vu->value <= 0)
- // r *= 0.5, g *= 0.5, b *= 0.5;
- break;
- case VU_MONOCHROME_REVERSE:
- r = 1, g = 1, b = 0;
- // if (!(vu->value < ts) || vu->value >= 1.0)
- // r *= 0.5, g *= 0.5, b *= 0.5;
- break;
- case VU_MONOCHROME:
- r = 1, g = 1, b = 0;
- // if (vu->value < ts || vu->value <= 0)
- // r *= 0.5, g *= 0.5, b *= 0.5;
- break;
- }
- GdkColor sc2 = { 0, (guint16)(65535 * r), (guint16)(65535 * g), (guint16)(65535 * b) };
- gdk_cairo_set_source_color(cache_cr, &sc2);
- cairo_move_to(cache_cr, x, oy);
- cairo_line_to(cache_cr, x, oy + sy + 1);
- cairo_move_to(cache_cr, x, oy + sy);
- cairo_line_to(cache_cr, x, oy );
- cairo_stroke(cache_cr);
- }
+ // 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 );
+ vu->cache_surface = cairo_surface_create_similar( window_surface,
+ CAIRO_CONTENT_COLOR,
+ widget->allocation.width,
+ widget->allocation.height );
+
+ // And render the meterstuff again.
+
+ cairo_t *cache_cr = cairo_create( vu->cache_surface );
+ GdkColor sc = { 0, 0, 0, 0 };
+ gdk_cairo_set_source_color(cache_cr,&style->bg[GTK_STATE_NORMAL]);
+ cairo_paint(cache_cr);
+ gdk_cairo_set_source_color(cache_cr, &sc);
+ cairo_rectangle(cache_cr, ox, oy, sx, sy);
+ cairo_fill(cache_cr);
+ cairo_set_line_width(cache_cr, 1);
+
+ for (int x = ox + 1; x <= ox + sx - 3; x += 3)
+ {
+ float ts = (x - ox) * 1.0 / sx;
+ float r = 0.f, g = 0.f, b = 0.f;
+ switch(vu->mode)
+ {
+ case VU_STANDARD:
+ default:
+ if (ts < 0.75)
+ r = ts / 0.75, g = 0.5 + ts * 0.66, b = 1 - ts / 0.75;
+ else
+ r = 1, g = 1 - (ts - 0.75) / 0.25, b = 0;
+ // if (vu->value < ts || vu->value <= 0)
+ // r *= 0.5, g *= 0.5, b *= 0.5;
+ break;
+ case VU_MONOCHROME_REVERSE:
+ r = 0, g = 170.0 / 255.0, b = 1;
+ // if (!(vu->value < ts) || vu->value >= 1.0)
+ // r *= 0.5, g *= 0.5, b *= 0.5;
+ break;
+ case VU_MONOCHROME:
+ r = 0, g = 170.0 / 255.0, b = 1;
+ // if (vu->value < ts || vu->value <= 0)
+ // r *= 0.5, g *= 0.5, b *= 0.5;
+ break;
+ }
+ GdkColor sc2 = { 0, (guint16)(65535 * r + 0.2), (guint16)(65535 * g), (guint16)(65535 * b) };
+ GdkColor sc3 = { 0, (guint16)(65535 * r * 0.7), (guint16)(65535 * g * 0.7), (guint16)(65535 * b * 0.7) };
+ gdk_cairo_set_source_color(cache_cr, &sc2);
+ cairo_move_to(cache_cr, x + 0.5, oy + 1);
+ cairo_line_to(cache_cr, x + 0.5, oy + sy - 1);
+ cairo_stroke(cache_cr);
+ gdk_cairo_set_source_color(cache_cr, &sc3);
+ cairo_move_to(cache_cr, x + 1.5, oy + sy - 1);
+ cairo_line_to(cache_cr, x + 1.5, oy + 1);
+ cairo_stroke(cache_cr);
+ }
cairo_destroy( cache_cr );
}
cairo_set_source_surface( c, vu->cache_surface, 0,0 );
cairo_paint( c );
- cairo_set_source_rgba( c, 0,0,0, 0.5 );
+ cairo_set_source_rgba( c, 0,0,0, 0.6 );
if( vu->mode == VU_MONOCHROME_REVERSE )
- cairo_rectangle( c, ox,oy, vu->value * (sx-ox) + 1, sy-oy+1 );
+ cairo_rectangle( c, ox,oy, vu->value * sx, sy );
else
- cairo_rectangle( c, ox + vu->value * (sx-ox), oy, sx-ox+1, sy-oy+1 );
+ cairo_rectangle( c, ox + vu->value * sx, oy, sx * (1 - vu->value), sy );
cairo_fill( c );
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;
}
@@ -486,7 +500,7 @@ calf_vumeter_size_request (GtkWidget *widget,
GtkRequisition *requisition)
{
g_assert(CALF_IS_VUMETER(widget));
-
+
requisition->width = 50;
requisition->height = 14;
}
@@ -503,7 +517,7 @@ calf_vumeter_size_allocate (GtkWidget *widget,
parent_class->size_allocate( widget, allocation );
if( vu->cache_surface )
- cairo_surface_destroy( vu->cache_surface );
+ cairo_surface_destroy( vu->cache_surface );
vu->cache_surface = NULL;
}
@@ -610,10 +624,10 @@ calf_knob_expose (GtkWidget *widget, GdkEventExpose *event)
// printf("adjustment = %p value = %f\n", adj, adj->value);
int ox = widget->allocation.x, oy = widget->allocation.y;
-
- ox += (widget->allocation.width - 40) / 2;
- oy += (widget->allocation.height - 40) / 2;
-
+
+ ox += (widget->allocation.width - self->knob_size * 20) / 2;
+ oy += (widget->allocation.height - self->knob_size * 20) / 2;
+
int phase = (int)((adj->value - adj->lower) * 64 / (adj->upper - adj->lower));
// skip middle phase except for true middle value
if (self->knob_type == 1 && phase == 32) {
@@ -634,13 +648,13 @@ calf_knob_expose (GtkWidget *widget, GdkEventExpose *event)
if (diff < -0.0001)
phase = (phase + 63) % 64;
}
- gdk_draw_pixbuf(GDK_DRAWABLE(widget->window), widget->style->fg_gc[0], CALF_KNOB_CLASS(GTK_OBJECT_GET_CLASS(widget))->knob_image, phase * 40, self->knob_type * 40, ox, oy, 40, 40, GDK_RGB_DITHER_NORMAL, 0, 0);
+ gdk_draw_pixbuf(GDK_DRAWABLE(widget->window), widget->style->fg_gc[0], CALF_KNOB_CLASS(GTK_OBJECT_GET_CLASS(widget))->knob_image[self->knob_size - 1], phase * self->knob_size * 20, self->knob_type * self->knob_size * 20, ox, oy, self->knob_size * 20, self->knob_size * 20, GDK_RGB_DITHER_NORMAL, 0, 0);
// printf("exposed %p %d+%d\n", widget->window, widget->allocation.x, widget->allocation.y);
if (gtk_widget_is_focus(widget))
{
- gtk_paint_focus(widget->style, window, GTK_STATE_NORMAL, NULL, widget, NULL, ox, oy, 40, 40);
+ gtk_paint_focus(widget->style, window, GTK_STATE_NORMAL, NULL, widget, NULL, ox, oy, self->knob_size * 20, self->knob_size * 20);
}
-
+
return TRUE;
}
@@ -649,10 +663,13 @@ calf_knob_size_request (GtkWidget *widget,
GtkRequisition *requisition)
{
g_assert(CALF_IS_KNOB(widget));
-
+
+ CalfKnob *self = CALF_KNOB(widget);
+
// width/height is hardwired at 40px now
- requisition->width = 40;
- requisition->height = 40;
+ // is now chooseable by "size" value in XML (1-4)
+ requisition->width = 20 * self->knob_size;
+ requisition->height = 20 * self->knob_size;
}
static void
@@ -661,7 +678,7 @@ calf_knob_incr (GtkWidget *widget, int dir_down)
g_assert(CALF_IS_KNOB(widget));
CalfKnob *self = CALF_KNOB(widget);
GtkAdjustment *adj = gtk_range_get_adjustment(GTK_RANGE(widget));
-
+
int oldstep = (int)(0.5f + (adj->value - adj->lower) / adj->step_increment);
int step;
int nsteps = (int)(0.5f + (adj->upper - adj->lower) / adj->step_increment); // less 1 actually
@@ -673,7 +690,7 @@ calf_knob_incr (GtkWidget *widget, int dir_down)
step %= nsteps;
if (self->knob_type == 3 && step < 0)
step = nsteps - (nsteps - step) % nsteps;
-
+
// trying to reduce error cumulation here, by counting from lowest or from highest
float value = adj->lower + step * double(adj->upper - adj->lower) / nsteps;
gtk_range_set_value(GTK_RANGE(widget), value);
@@ -711,7 +728,7 @@ calf_knob_key_press (GtkWidget *widget, GdkEventKey *event)
self->start_y = self->last_y;
return TRUE;
}
-
+
return FALSE;
}
@@ -772,9 +789,9 @@ static inline float deadzone(float value, float incr, float scale)
value += dzw;
if (value < 0.499)
value -= dzw;
-
+
value += incr;
-
+
if (value >= (0.5 - dzw) && value <= (0.5 + dzw))
return 0.5;
if (value < 0.5)
@@ -788,27 +805,29 @@ calf_knob_pointer_motion (GtkWidget *widget, GdkEventMotion *event)
g_assert(CALF_IS_KNOB(widget));
CalfKnob *self = CALF_KNOB(widget);
- float scale = (event->state & GDK_SHIFT_MASK) ? 1000 : 100;
+ float scale = (event->state & GDK_SHIFT_MASK) ? 10 : 1;
gboolean moved = FALSE;
if (GTK_WIDGET_HAS_GRAB(widget))
{
+ float sens=1/(75*(1+fabs((self->start_x - event->x)/10)));
if (self->knob_type == 3)
{
- gtk_range_set_value(GTK_RANGE(widget), endless(self->start_value - (event->y - self->start_y) / scale));
+ gtk_range_set_value(GTK_RANGE(widget), endless(gtk_range_get_value(GTK_RANGE(widget)) - (event->y - self->last_y) / scale * sens));
}
+// else
+// if (self->knob_type == 1)
+// {
+// gtk_range_set_value(GTK_RANGE(widget), deadzone(gtk_range_get_value(GTK_RANGE(widget)), -(event->y - self->last_y) / scale * sens, scale * sens));
+// }
else
- if (self->knob_type == 1)
{
- gtk_range_set_value(GTK_RANGE(widget), deadzone(self->start_value, -(event->y - self->start_y) / scale, scale));
- }
- else
- {
- gtk_range_set_value(GTK_RANGE(widget), self->start_value - (event->y - self->start_y) / scale);
+ gtk_range_set_value(GTK_RANGE(widget), gtk_range_get_value(GTK_RANGE(widget)) - (event->y - self->last_y) / scale * sens);
}
moved = TRUE;
}
self->last_y = event->y;
+ self->last_x = event->x;
return moved;
}
@@ -833,7 +852,10 @@ calf_knob_class_init (CalfKnobClass *klass)
widget_class->key_release_event = calf_knob_key_release;
widget_class->scroll_event = calf_knob_scroll;
GError *error = NULL;
- klass->knob_image = gdk_pixbuf_new_from_file(PKGLIBDIR "/knob.png", &error);
+ klass->knob_image[0] = gdk_pixbuf_new_from_file(PKGLIBDIR "/knob1.png", &error);
+ klass->knob_image[1] = gdk_pixbuf_new_from_file(PKGLIBDIR "/knob2.png", &error);
+ klass->knob_image[2] = gdk_pixbuf_new_from_file(PKGLIBDIR "/knob3.png", &error);
+ klass->knob_image[3] = gdk_pixbuf_new_from_file(PKGLIBDIR "/knob4.png", &error);
g_assert(klass->knob_image != NULL);
}
@@ -905,4 +927,3 @@ calf_knob_get_type (void)
}
return type;
}
-
diff --git a/src/modules.cpp b/src/modules.cpp
index 048eb93..f4cc264 100644
--- a/src/modules.cpp
+++ b/src/modules.cpp
@@ -235,6 +235,92 @@ CALF_PLUGIN_INFO(compressor) = { 0x8502, "Compressor", "Calf Compressor", "Thor
////////////////////////////////////////////////////////////////////////////
+CALF_PORT_NAMES(multibandcompressor) = {"In L", "In R", "Out L", "Out R"};
+
+const char *multibandcompressor_detection_names[] = { "RMS", "Peak" };
+
+CALF_PORT_PROPS(multibandcompressor) = {
+ { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "bypass", "Bypass" },
+ { 1, 0, 64, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "level_in", "Input" },
+ { 1, 0, 64, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "level_out", "Output" },
+ { 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_inL", "Input 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_inR", "Input R" },
+ { 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_outL", "Output 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_outR", "Output R" },
+ { 0, 0, 1, 0, PF_BOOL | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_inL", "0dB" },
+ { 0, 0, 1, 0, PF_BOOL | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_inR", "0dB" },
+ { 0, 0, 1, 0, PF_BOOL | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_outL", "0dB" },
+ { 0, 0, 1, 0, PF_BOOL | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_outR", "0dB" },
+
+ { 120, 10, 20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ | PF_PROP_GRAPH, NULL, "freq0", "Split 1/2" },
+ { 1200, 10, 20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ | PF_PROP_GRAPH, NULL, "freq1", "Split 2/3" },
+ { 6000, 10, 20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ | PF_PROP_GRAPH, NULL, "freq2", "Split 3/4" },
+
+ { -0.17, -0.5, 0.5, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_GRAPH, NULL, "sep0", "S" },
+ { -0.17, -0.5, 0.5, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_GRAPH, NULL, "sep1", "S" },
+ { -0.17, -0.5, 0.5, 0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_GRAPH, NULL, "sep2", "S" },
+
+ { 0.895025, 0.25, 4, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB | PF_PROP_GRAPH, NULL, "q0", "Q" },
+ { 0.895025, 0.25, 4, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB | PF_PROP_GRAPH, NULL, "q1", "Q" },
+ { 0.895025, 0.25, 4, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB | PF_PROP_GRAPH, NULL, "q2", "Q" },
+
+
+ { 0.0625, 0.000976563, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "threshold0", "Threshold" },
+ { 3, 1, 20, 21, PF_FLOAT | PF_SCALE_LOG_INF | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "ratio0", "Ratio" },
+ { 50, 0.01, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "attack0", "Attack" },
+ { 100, 0.01, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "release0", "Release" },
+ { 2, 1, 64, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "makeup0", "Makeup" },
+ { 2.828427125, 1, 8, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "knee0", "Knee" },
+ { 1, 0, 1, 0, PF_ENUM | PF_CTL_COMBO, multibandcompressor_detection_names, "detection0", "Detection" },
+ { 1, 0.03125, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_CTLO_REVERSE | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL| PF_PROP_GRAPH, NULL, "compression0", "Gain Reduction" },
+ { 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, "output0", "Output" },
+ { 1, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "bypass0", "Bypass" },
+ { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "mute0", "Mute" },
+
+
+ { 0.03125, 0.000976563, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "threshold1", "Threshold" },
+ { 3, 1, 20, 21, PF_FLOAT | PF_SCALE_LOG_INF | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "ratio1", "Ratio" },
+ { 25, 0.01, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "attack1", "Attack" },
+ { 50, 0.01, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "release1", "Release" },
+ { 2, 1, 64, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "makeup1", "Makeup" },
+ { 2.828427125, 1, 8, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "knee1", "Knee" },
+ { 1, 0, 1, 0, PF_ENUM | PF_CTL_COMBO, multibandcompressor_detection_names, "detection1", "Detection" },
+ { 1, 0.03125, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_CTLO_REVERSE | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL| PF_PROP_GRAPH, NULL, "compression1", "Gain Reduction" },
+ { 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, "output1", "Output" },
+ { 1, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "bypass1", "Bypass" },
+ { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "mute1", "Mute" },
+
+
+ { 0.015625, 0.000976563, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "threshold2", "Threshold" },
+ { 3, 1, 20, 21, PF_FLOAT | PF_SCALE_LOG_INF | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "ratio2", "Ratio" },
+ { 12.5, 0.01, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "attack2", "Attack" },
+ { 25, 0.01, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "release2", "Release" },
+ { 2, 1, 64, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "makeup2", "Makeup" },
+ { 2.828427125, 1, 8, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "knee2", "Knee" },
+ { 1, 0, 1, 0, PF_ENUM | PF_CTL_COMBO, multibandcompressor_detection_names, "detection2", "Detection" },
+ { 1, 0.03125, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_CTLO_REVERSE | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL| PF_PROP_GRAPH, NULL, "compression2", "Gain Reduction" },
+ { 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, "output2", "Output" },
+ { 1, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "bypass2", "Bypass" },
+ { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "mute2", "Mute" },
+
+
+ { 0.0078125, 0.000976563, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "threshold3", "Threshold" },
+ { 3, 1, 20, 21, PF_FLOAT | PF_SCALE_LOG_INF | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "ratio3", "Ratio" },
+ { 6.25, 0.01, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "attack3", "Attack" },
+ { 12.5, 0.01, 2000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "release3", "Release" },
+ { 2, 1, 64, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "makeup3", "Makeup" },
+ { 2.828427125, 1, 8, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "knee3", "Knee" },
+ { 1, 0, 1, 0, PF_ENUM | PF_CTL_COMBO, multibandcompressor_detection_names, "detection3", "Detection" },
+ { 1, 0.03125, 1, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_CTLO_REVERSE | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL| PF_PROP_GRAPH, NULL, "compression3", "Gain Reduction" },
+ { 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, "output3", "Output" },
+ { 1, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "bypass3", "Bypass" },
+ { 0, 0, 1, 0, PF_BOOL | PF_CTL_TOGGLE, NULL, "mute3", "Mute" },
+};
+
+CALF_PLUGIN_INFO(multibandcompressor) = { 0x8502, "Multibandcompressor", "Calf Multibandcompressor", "Markus Schmidt", calf_plugins::calf_copyright_info, "CompressorPlugin" };
+
+////////////////////////////////////////////////////////////////////////////
+
CALF_PORT_NAMES(monosynth) = {
"Out L", "Out R",
};
diff --git a/src/modules_dsp.cpp b/src/modules_dsp.cpp
index ac8fb77..8ce742d 100644
--- a/src/modules_dsp.cpp
+++ b/src/modules_dsp.cpp
@@ -59,9 +59,9 @@ static inline float dB_grid_inv(float pos)
static void set_channel_color(cairo_iface *context, int channel)
{
if (channel & 1)
- context->set_source_rgba(0.75, 1, 0);
+ context->set_source_rgba(0.35, 0.4, 0.2, 1);
else
- context->set_source_rgba(0, 1, 0.75);
+ context->set_source_rgba(0.35, 0.4, 0.2, 0.5);
context->set_line_width(1.5);
}
@@ -88,9 +88,9 @@ static bool get_freq_gridline(int subindex, float &pos, bool &vertical, std::str
freq = 10000 * (subindex - 27 + 1);
pos = log(freq / 20.0) / log(1000);
if (!legend.empty())
- context->set_source_rgba(0.25, 0.25, 0.25, 0.75);
+ context->set_source_rgba(0, 0, 0, 0.2);
else
- context->set_source_rgba(0.25, 0.25, 0.25, 0.5);
+ context->set_source_rgba(0, 0, 0, 0.1);
return true;
}
subindex -= 28;
@@ -102,7 +102,7 @@ static bool get_freq_gridline(int subindex, float &pos, bool &vertical, std::str
if (pos < -1)
return false;
if (subindex != 4)
- context->set_source_rgba(0.25, 0.25, 0.25, subindex & 1 ? 0.5 : 0.75);
+ context->set_source_rgba(0, 0, 0, subindex & 1 ? 0.1 : 0.2);
if (!(subindex & 1))
{
std::stringstream ss;
@@ -120,7 +120,7 @@ bool frequency_response_line_graph::get_gridline(int index, int subindex, float
return get_freq_gridline(subindex, pos, vertical, legend, context);
}
-int frequency_response_line_graph::get_changed_offsets(int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline)
+int frequency_response_line_graph::get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline)
{
subindex_graph = 0;
subindex_dot = 0;
@@ -243,7 +243,7 @@ bool filter_audio_module::get_graph(int index, int subindex, float *data, int po
return false;
}
-int filter_audio_module::get_changed_offsets(int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline)
+int filter_audio_module::get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline)
{
if (fabs(inertia_cutoff.get_last() - old_cutoff) + 100 * fabs(inertia_resonance.get_last() - old_resonance) + fabs(*params[par_mode] - old_mode) > 0.1f)
{
@@ -360,7 +360,7 @@ bool multichorus_audio_module::get_graph(int index, int subindex, float *data, i
if (subindex < 2)
set_channel_color(context, subindex);
else {
- context->set_source_rgba(0, 1, 0);
+ context->set_source_rgba(0.35, 0.4, 0.2);
context->set_line_width(1.0);
}
return ::get_graph(*this, subindex, data, points);
@@ -471,9 +471,9 @@ bool compressor_audio_module::get_graph(int index, int subindex, float *data, in
data[i] = dB_grid(output);
}
if (subindex == (*params[param_bypass] > 0.5f ? 1 : 0))
- context->set_source_rgba(0.5, 0.5, 0.5, 0.5);
+ context->set_source_rgba(0.35, 0.4, 0.2, 0.3);
else {
- context->set_source_rgba(0, 1, 0, 1);
+ context->set_source_rgba(0.35, 0.4, 0.2, 1);
context->set_line_width(2);
}
return true;
@@ -637,3 +637,628 @@ uint32_t compressor_audio_module::process(uint32_t offset, uint32_t numsamples,
return inputs_mask;
}
+
+/// Multibandcompressor by Markus Schmidt
+///////////////////////////////////////////////////////////////////////////////////////////////
+
+multibandcompressor_audio_module::multibandcompressor_audio_module()
+{
+ is_active = false;
+ srate = 0;
+ // zero all dsplays
+ clip_inL = 0.f;
+ clip_inR = 0.f;
+ clip_outL = 0.f;
+ clip_outR = 0.f;
+ meter_inL = 0.f;
+ meter_inR = 0.f;
+ meter_outL = 0.f;
+ meter_outR = 0.f;
+}
+
+void multibandcompressor_audio_module::activate()
+{
+ is_active = true;
+ // set all filters and strips
+ params_changed();
+ // activate all strips
+ for (int j = 0; j < strips; j ++) {
+ strip[j].activate();
+ strip[j].id = j;
+ }
+}
+
+void multibandcompressor_audio_module::deactivate()
+{
+ is_active = false;
+ // deactivate all strips
+ for (int j = 0; j < strips; j ++) {
+ strip[j].deactivate();
+ }
+}
+
+void multibandcompressor_audio_module::params_changed()
+{
+ // set the params of all filters
+ if(*params[param_freq0] != freq_old[0] or *params[param_sep0] != sep_old[0] or *params[param_q0] != q_old[0]) {
+ lpL0.set_lp_rbj((float)(*params[param_freq0] * (1 - *params[param_sep0])), *params[param_q0], (float)srate);
+ lpR0.set_lp_rbj((float)(*params[param_freq0] * (1 - *params[param_sep0])), *params[param_q0], (float)srate);
+ hpL0.set_hp_rbj((float)(*params[param_freq0] * (1 + *params[param_sep0])), *params[param_q0], (float)srate);
+ hpR0.set_hp_rbj((float)(*params[param_freq0] * (1 + *params[param_sep0])), *params[param_q0], (float)srate);
+ freq_old[0] = *params[param_freq0];
+ sep_old[0] = *params[param_sep2];
+ q_old[0] = *params[param_q2];
+ }
+ if(*params[param_freq1] != freq_old[1] or *params[param_sep1] != sep_old[1] or *params[param_q1] != q_old[1]) {
+ lpL1.set_lp_rbj((float)(*params[param_freq1] * (1 - *params[param_sep1])), *params[param_q1], (float)srate);
+ lpR1.set_lp_rbj((float)(*params[param_freq1] * (1 - *params[param_sep1])), *params[param_q1], (float)srate);
+ hpL1.set_hp_rbj((float)(*params[param_freq1] * (1 + *params[param_sep1])), *params[param_q1], (float)srate);
+ hpR1.set_hp_rbj((float)(*params[param_freq1] * (1 + *params[param_sep1])), *params[param_q1], (float)srate);
+ freq_old[1] = *params[param_freq1];
+ sep_old[1] = *params[param_sep2];
+ q_old[1] = *params[param_q2];
+ }
+ if(*params[param_freq2] != freq_old[2] or *params[param_sep2] != sep_old[2] or *params[param_q2] != q_old[2]) {
+ lpL2.set_lp_rbj((float)(*params[param_freq2] * (1 - *params[param_sep2])), *params[param_q2], (float)srate);
+ lpR2.set_lp_rbj((float)(*params[param_freq2] * (1 - *params[param_sep2])), *params[param_q2], (float)srate);
+ hpL2.set_hp_rbj((float)(*params[param_freq2] * (1 + *params[param_sep2])), *params[param_q2], (float)srate);
+ hpR2.set_hp_rbj((float)(*params[param_freq2] * (1 + *params[param_sep2])), *params[param_q2], (float)srate);
+ freq_old[2] = *params[param_freq2];
+ sep_old[2] = *params[param_sep2];
+ q_old[2] = *params[param_q2];
+ }
+ // set the params of all strips
+ for (int j = 0; j < strips; j ++) {
+ switch (j) {
+ case 0:
+ strip[j].set_params(*params[param_attack0], *params[param_release0], *params[param_threshold0], *params[param_ratio0], *params[param_knee0], *params[param_makeup0], *params[param_detection0], *params[param_bypass0], *params[param_mute0]);
+ break;
+ case 1:
+ strip[j].set_params(*params[param_attack1], *params[param_release1], *params[param_threshold1], *params[param_ratio1], *params[param_knee1], *params[param_makeup1], *params[param_detection1], *params[param_bypass1], *params[param_mute1]);
+ break;
+ case 2:
+ strip[j].set_params(*params[param_attack2], *params[param_release2], *params[param_threshold2], *params[param_ratio2], *params[param_knee2], *params[param_makeup2], *params[param_detection2], *params[param_bypass2], *params[param_mute2]);
+ break;
+ case 3:
+ strip[j].set_params(*params[param_attack3], *params[param_release3], *params[param_threshold3], *params[param_ratio3], *params[param_knee3], *params[param_makeup3], *params[param_detection3], *params[param_bypass3], *params[param_mute3]);
+ break;
+ }
+ }
+}
+
+void multibandcompressor_audio_module::set_sample_rate(uint32_t sr)
+{
+ srate = sr;
+ // set srate of all strips
+ for (int j = 0; j < strips; j ++) {
+ strip[j].set_sample_rate(srate);
+ }
+}
+
+uint32_t multibandcompressor_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask)
+{
+ bool bypass = *params[param_bypass] > 0.5f;
+ numsamples += offset;
+ if(bypass) {
+ // everything bypassed
+ while(offset < numsamples) {
+ outs[0][offset] = ins[0][offset];
+ outs[1][offset] = ins[1][offset];
+ ++offset;
+ }
+ // displays, too
+ clip_inL = 0.f;
+ clip_inR = 0.f;
+ clip_outL = 0.f;
+ clip_outR = 0.f;
+ meter_inL = 0.f;
+ meter_inR = 0.f;
+ meter_outL = 0.f;
+ meter_outR = 0.f;
+ } else {
+ // process all strips
+
+ // determine mute state of strips
+ mute[0] = *params[param_mute0] > 0.f ? true : false;
+ mute[1] = *params[param_mute1] > 0.f ? true : false;
+ mute[2] = *params[param_mute2] > 0.f ? true : false;
+ mute[3] = *params[param_mute3] > 0.f ? true : false;
+
+ // let meters fall a bit
+ clip_inL -= std::min(clip_inL, numsamples);
+ clip_inR -= std::min(clip_inR, numsamples);
+ clip_outL -= std::min(clip_outL, numsamples);
+ clip_outR -= std::min(clip_outR, numsamples);
+ meter_inL -= meter_inL * 5.f * numsamples / srate;
+ meter_inR -= meter_inR * 5.f * numsamples / srate;
+ meter_outL -= meter_outL * 5.f * numsamples / srate;
+ meter_outR -= meter_outR * 5.f * numsamples / srate;
+ for(int k = 0; k < strips; k ++) {
+ meter_out[k] -= meter_out[k] * 5.f * numsamples / srate;
+ }
+
+ while(offset < numsamples) {
+ // cycle trough samples
+ float inL = ins[0][offset];
+ float inR = ins[1][offset];
+ // in level
+ inR *= *params[param_level_in];
+ inL *= *params[param_level_in];
+ // out vars
+ float outL = 0.f;
+ float outR = 0.f;
+ for (int i = 0; i < strips; i ++) {
+ // cycle trough strips
+ if (!mute[i]) {
+ // strip unmuted
+ float left = inL;
+ float right = inR;
+ // send trough filters
+ switch (i) {
+ case 0:
+ left = lpL0.process(left);
+ right = lpR0.process(right);
+ lpL0.sanitize();
+ lpR0.sanitize();
+ break;
+ case 1:
+ left = lpL1.process(left);
+ right = lpR1.process(right);
+ left = hpL0.process(left);
+ right = hpR0.process(right);
+ lpL1.sanitize();
+ lpR1.sanitize();
+ hpL0.sanitize();
+ hpR0.sanitize();
+ break;
+ case 2:
+ left = lpL2.process(left);
+ right = lpR2.process(right);
+ left = hpL1.process(left);
+ right = hpR1.process(right);
+ lpL2.sanitize();
+ lpR2.sanitize();
+ hpL1.sanitize();
+ hpR1.sanitize();
+ break;
+ case 3:
+ left = hpL2.process(left);
+ right = hpR2.process(right);
+ hpL2.sanitize();
+ hpR2.sanitize();
+ break;
+ }
+ // process gain reduction
+ strip[i].process(left, right);
+ // sum up output
+ outL += left;
+ outR += right;
+ } else {
+ // strip muted
+
+ }
+
+
+ } // process single strip
+
+ // even out filters gain reduction
+ // 3dB - levelled manually (based on sep and q settings)
+ outL *= 1.414213562;
+ outR *= 1.414213562;
+
+ // out level
+ outL *= *params[param_level_out];
+ outR *= *params[param_level_out];
+
+ // send to output
+ outs[0][offset] = outL;
+ outs[1][offset] = outR;
+
+ // clip LED's
+ if(inL > 1.f) {
+ clip_inL = srate >> 3;
+ }
+ if(inR > 1.f) {
+ clip_inR = srate >> 3;
+ }
+ if(outL > 1.f) {
+ clip_outL = srate >> 3;
+ }
+ if(outR > 1.f) {
+ clip_outR = srate >> 3;
+ }
+ // in / out meters
+ if(meter_inL < inL) {
+ meter_inL = inL;
+ }
+ if(meter_inR < inR) {
+ meter_inR = inR;
+ }
+ if(meter_outL < outL) {
+ meter_outL = outL;
+ }
+ if(meter_outR < outR) {
+ meter_outR = outR;
+ }
+ // next sample
+ ++offset;
+// printf("inL: %+7.4f inR: %+7.4f outL: %+7.4f outR: %+7.4f input: %+7.4f output: %+7.4f\n", inL, inR, outL, outR, *params[param_level_in], *params[param_level_out]);
+ } // cycle trough samples
+
+ } // process all strips (no bypass)
+
+ // draw meters
+ if(params[param_clip_inL] != NULL) {
+ *params[param_clip_inL] = clip_inL;
+ }
+ if(params[param_clip_inR] != NULL) {
+ *params[param_clip_inR] = clip_inR;
+ }
+ if(params[param_clip_outL] != NULL) {
+ *params[param_clip_outL] = clip_outL;
+ }
+ if(params[param_clip_outR] != NULL) {
+ *params[param_clip_outR] = clip_outR;
+ }
+
+ if(params[param_meter_inL] != NULL) {
+ *params[param_meter_inL] = meter_inL;
+ }
+ if(params[param_meter_inR] != NULL) {
+ *params[param_meter_inR] = meter_inR;
+ }
+ if(params[param_meter_outL] != NULL) {
+ *params[param_meter_outL] = meter_outL;
+ }
+ if(params[param_meter_outR] != NULL) {
+ *params[param_meter_outR] = meter_outR;
+ }
+ // draw strip meters
+ if(bypass > 0.5f) {
+ if(params[param_compression0] != NULL) {
+ *params[param_compression0] = 1.0f;
+ }
+ if(params[param_compression1] != NULL) {
+ *params[param_compression1] = 1.0f;
+ }
+ if(params[param_compression2] != NULL) {
+ *params[param_compression2] = 1.0f;
+ }
+ if(params[param_compression3] != NULL) {
+ *params[param_compression3] = 1.0f;
+ }
+
+ if(params[param_output0] != NULL) {
+ *params[param_output0] = 0.0f;
+ }
+ if(params[param_output1] != NULL) {
+ *params[param_output1] = 0.0f;
+ }
+ if(params[param_output2] != NULL) {
+ *params[param_output2] = 0.0f;
+ }
+ if(params[param_output3] != NULL) {
+ *params[param_output3] = 0.0f;
+ }
+ } else {
+ if(params[param_compression0] != NULL) {
+ *params[param_compression0] = strip[0].get_comp_level();
+ }
+ if(params[param_compression1] != NULL) {
+ *params[param_compression1] = strip[1].get_comp_level();
+ }
+ if(params[param_compression2] != NULL) {
+ *params[param_compression2] = strip[2].get_comp_level();
+ }
+ if(params[param_compression3] != NULL) {
+ *params[param_compression3] = strip[3].get_comp_level();
+ }
+
+ if(params[param_output0] != NULL) {
+ *params[param_output0] = strip[0].get_output_level();
+ }
+ if(params[param_output1] != NULL) {
+ *params[param_output1] = strip[1].get_output_level();
+ }
+ if(params[param_output2] != NULL) {
+ *params[param_output2] = strip[2].get_output_level();
+ }
+ if(params[param_output3] != NULL) {
+ *params[param_output3] = strip[3].get_output_level();
+ }
+ }
+ // whatever has to be returned x)
+ return outputs_mask;
+}
+bool multibandcompressor_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context)
+{
+// printf("get_graph : %i\n", index);
+ switch (index) {
+ case param_compression0:
+ return strip[0].get_graph(subindex, data, points, context);
+ break;
+ case param_compression1:
+ return strip[1].get_graph(subindex, data, points, context);
+ break;
+ case param_compression2:
+ return strip[2].get_graph(subindex, data, points, context);
+ break;
+ case param_compression3:
+ return strip[3].get_graph(subindex, data, points, context);
+ break;
+ }
+ return false;
+}
+
+bool multibandcompressor_audio_module::get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context)
+{
+// printf("get_dot : %i\n", index);
+ switch (index) {
+ case param_compression0:
+ return strip[0].get_dot(subindex, x, y, size, context);
+ break;
+ case param_compression1:
+ return strip[1].get_dot(subindex, x, y, size, context);
+ break;
+ case param_compression2:
+ return strip[2].get_dot(subindex, x, y, size, context);
+ break;
+ case param_compression3:
+ return strip[3].get_dot(subindex, x, y, size, context);
+ break;
+ }
+ return false;
+}
+
+bool multibandcompressor_audio_module::get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context)
+{
+// printf("get_gridline: %i\n", index);
+ switch (index) {
+ case param_compression0:
+ return strip[0].get_gridline(subindex, pos, vertical, legend, context);
+ break;
+ case param_compression1:
+ return strip[1].get_gridline(subindex, pos, vertical, legend, context);
+ break;
+ case param_compression2:
+ return strip[2].get_gridline(subindex, pos, vertical, legend, context);
+ break;
+ case param_compression3:
+ return strip[3].get_gridline(subindex, pos, vertical, legend, context);
+ break;
+ }
+ return false;
+}
+
+int multibandcompressor_audio_module::get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline)
+{
+// printf("get_changed : %i\n", index);
+ switch (index) {
+ case param_compression0:
+ return strip[0].get_changed_offsets(generation, subindex_graph, subindex_dot, subindex_gridline);
+ break;
+ case param_compression1:
+ return strip[1].get_changed_offsets(generation, subindex_graph, subindex_dot, subindex_gridline);
+ break;
+ case param_compression2:
+ return strip[2].get_changed_offsets(generation, subindex_graph, subindex_dot, subindex_gridline);
+ break;
+ case param_compression3:
+ return strip[3].get_changed_offsets(generation, subindex_graph, subindex_dot, subindex_gridline);
+ break;
+ }
+ return 0;
+}
+/// Gain reduction module by Markus Schmidt
+////////////////////////////////////////////////////////////////////////////////
+gain_reduction_audio_module::gain_reduction_audio_module()
+{
+ is_active = false;
+ last_generation = 0;
+}
+
+void gain_reduction_audio_module::activate()
+{
+ is_active = true;
+ linSlope = 0.f;
+ meter_out = 0.f;
+ meter_comp = 0.f;
+ float l, r;
+ float byp = bypass;
+ bypass = 0.0;
+ process(l, r);
+ bypass = byp;
+}
+
+void gain_reduction_audio_module::deactivate()
+{
+ is_active = false;
+}
+
+void gain_reduction_audio_module::process(float &left, float &right)
+{
+ if(bypass > 0.5f) {
+ meter_comp = 1.f;
+ meter_out = 0.f;
+ return;
+ }
+ // this routine is mainly copied from thor's compressor module
+ // greatest sounding compressor I've heard!
+ bool rms = detection == 0;
+ float linThreshold = threshold;
+ float attack_coeff = std::min(1.f, 1.f / (attack * srate / 4000.f));
+ float release_coeff = std::min(1.f, 1.f / (release * srate / 4000.f));
+ float linKneeSqrt = sqrt(knee);
+ linKneeStart = linThreshold / linKneeSqrt;
+ adjKneeStart = linKneeStart*linKneeStart;
+ float linKneeStop = linThreshold * linKneeSqrt;
+ thres = log(linThreshold);
+ kneeStart = log(linKneeStart);
+ kneeStop = log(linKneeStop);
+ compressedKneeStop = (kneeStop - thres) / ratio + thres;
+ float compression = 1.f;
+ float absample = (fabs(left) + fabs(right)) * 0.5f;
+ if(rms) absample *= absample;
+ meter_out -= meter_out * 5.f * 1 / srate;
+
+ linSlope += (absample - linSlope) * (absample > linSlope ? attack_coeff : release_coeff);
+
+ float gain = 1.f;
+
+ if(linSlope > 0.f) {
+ gain = output_gain(linSlope, rms);
+ }
+
+ compression = gain;
+ gain *= makeup;
+
+ left *= gain;
+ right *= gain;
+
+ float maxLR = std::max(fabs(left), fabs(right));
+
+ if(maxLR > meter_out) {
+ meter_out = maxLR;
+ }
+ meter_comp = compression;
+
+ detected = rms ? sqrt(linSlope) : linSlope;
+}
+
+float gain_reduction_audio_module::output_level(float slope) {
+ return slope * output_gain(slope, false) * makeup;
+}
+
+float gain_reduction_audio_module::output_gain(float linSlope, bool rms) {
+ //this calculation is also thor's work
+ if(linSlope > (rms ? adjKneeStart : linKneeStart)) {
+ float slope = log(linSlope);
+ if(rms) slope *= 0.5f;
+
+ float gain = 0.f;
+ float delta = 0.f;
+ if(IS_FAKE_INFINITY(ratio)) {
+ gain = thres;
+ delta = 0.f;
+ } else {
+ gain = (slope - thres) / ratio + thres;
+ delta = 1.f / ratio;
+ }
+
+ if(knee > 1.f && slope < kneeStop) {
+ gain = hermite_interpolation(slope, kneeStart, kneeStop, kneeStart, compressedKneeStop, 1.f, delta);
+ }
+
+ return exp(gain - slope);
+ }
+
+ return 1.f;
+}
+
+void gain_reduction_audio_module::set_sample_rate(uint32_t sr)
+{
+ srate = sr;
+}
+void gain_reduction_audio_module::set_params(float att, float rel, float thr, float rat, float kn, float mak, float det, float byp, float mu)
+{
+ // set all params
+ attack = att;
+ release = rel;
+ threshold = thr;
+ ratio = rat;
+ knee = kn;
+ makeup = mak;
+ detection = det;
+ bypass = byp;
+ mute = mu;
+ // if bypass, zero meters
+ if(bypass > 0.5 or mute > 0.f) {
+ meter_out = 0.f;
+ meter_comp = 1.f;
+ }
+}
+float gain_reduction_audio_module::get_output_level() {
+ // returns output level (max(left, right))
+ return meter_out;
+}
+float gain_reduction_audio_module::get_comp_level() {
+ // returns amount of compression
+ return meter_comp;
+}
+
+bool gain_reduction_audio_module::get_graph(int subindex, float *data, int points, cairo_iface *context)
+{
+ if (!is_active)
+ return false;
+ if (subindex > 1) // 1
+ return false;
+ for (int i = 0; i < points; i++)
+ {
+ float input = dB_grid_inv(-1.0 + i * 2.0 / (points - 1));
+ float output = output_level(input);
+ if (subindex == 0)
+ data[i] = dB_grid(input);
+ else
+ data[i] = dB_grid(output);
+ }
+ if (subindex == (bypass > 0.5f ? 1 : 0))
+ context->set_source_rgba(0.35, 0.4, 0.2, 0.3);
+ else {
+ context->set_source_rgba(0.35, 0.4, 0.2, 1);
+ context->set_line_width(2);
+ }
+ return true;
+}
+
+bool gain_reduction_audio_module::get_dot(int subindex, float &x, float &y, int &size, cairo_iface *context)
+{
+ if (!is_active)
+ return false;
+ if (!subindex)
+ {
+ x = 0.5 + 0.5 * dB_grid(detected);
+ y = dB_grid(bypass > 0.5f ? detected : output_level(detected));
+ return bypass > 0.5f ? false : true;
+ }
+ return false;
+}
+
+bool gain_reduction_audio_module::get_gridline(int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context)
+{
+ bool tmp;
+ vertical = (subindex & 1) != 0;
+ bool result = get_freq_gridline(subindex >> 1, pos, tmp, legend, context, false);
+ if (result && vertical) {
+ if ((subindex & 4) && !legend.empty()) {
+ legend = "";
+ }
+ else {
+ size_t pos = legend.find(" dB");
+ if (pos != std::string::npos)
+ legend.erase(pos);
+ }
+ pos = 0.5 + 0.5 * pos;
+ }
+ return result;
+}
+
+int gain_reduction_audio_module::get_changed_offsets(int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline)
+{
+ subindex_graph = 0;
+ subindex_dot = 0;
+ subindex_gridline = generation ? INT_MAX : 0;
+
+ if (fabs(threshold-old_threshold) + fabs(ratio - old_ratio) + fabs(knee - old_knee) + fabs(makeup - old_makeup) + fabs(bypass - old_bypass) > 0.01f)
+ {
+ old_threshold = threshold;
+ old_ratio = ratio;
+ old_knee = knee;
+ old_makeup = makeup;
+ old_bypass = bypass;
+ last_generation++;
+ }
+
+ if (generation == last_generation)
+ subindex_graph = 2;
+ return last_generation;
+}
--
calf audio plugins packaging
More information about the pkg-multimedia-commits
mailing list