Merge branch 'calf-updates'

* calf-updates:
  + DSP primitives: fix a rather stupid bug in clamping functions
  + Monosynth: fix type bug that made it impossible to compile with g++ 4.2
  + AutoHell: update AUTHORS file
  + GUI, Multiband Compressor, Toggle button: apply more fixes and additions by Markus Schmidt
  + Multiband Compressor: better metadata
  + Multiband Compressor: new module (first version, by Markus Schmidt, based on code by me and Thor) plus associated refactoring and graph colour scheme update
(cherry picked from commit 65f6bb7135)
This commit is contained in:
Tobias Doerffel
2009-10-17 23:34:23 +02:00
parent dd055b210b
commit ed23c82c23
9 changed files with 839 additions and 29 deletions

View File

@@ -4,6 +4,8 @@ Thor Harald Johansen <thj@thj.no>
Thorsten Wilms <t_w_@freenet.de>
Hans Baier <hansfbaier@googlemail.com>
Torben Hohn <torbenh@gmx.de>
Markus Schmidt <schmidt@boomshop.net>
Additional bugfixes/enhancement patches:
David Täht <d@teklibre.com>
Dave Robillard <dave@drobilla.net>

View File

@@ -45,7 +45,7 @@ enum parameter_flags
PF_TYPEMASK = 0x000F, ///< bit mask for type
PF_FLOAT = 0x0000, ///< any float value
PF_INT = 0x0001, ///< integer value (still represented as float)
PF_BOOL = 0x0002, ///< bool value (usually >=0.5f is treated as true, which is inconsistent with LV2 etc. which treats anything >0 as true)
PF_BOOL = 0x0002, ///< bool value (usually >=0.5f is treated as TRUE, which is inconsistent with LV2 etc. which treats anything >0 as TRUE)
PF_ENUM = 0x0003, ///< enum value (min, min+1, ..., max, only guaranteed to work when min = 0)
PF_ENUM_MULTI = 0x0004, ///< SET / multiple-choice
PF_STRING = 0x0005, ///< see: http://lv2plug.in/docs/index.php?title=String_port
@@ -190,12 +190,13 @@ struct line_graph_iface
virtual bool get_static_graph(int index, int subindex, float value, float *data, int points, cairo_iface *context) { return false; }
/// Return which graphs need to be redrawn and which can be cached for later reuse
/// @param index Parameter/graph number (usually tied to particular plugin control port)
/// @param generation 0 (at start) or the last value returned by the function (corresponds to a set of input values)
/// @param subindex_graph First graph that has to be redrawn (because it depends on values that might have changed)
/// @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() {}

View File

@@ -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("multiband_compressor", "multibandcompressor", "Multiband Compressor")
};
/// 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

View File

@@ -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")

View File

@@ -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,61 @@ 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, old_mute, old_detection;
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;
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>,

View File

@@ -224,14 +224,14 @@ inline T clip(T value, T min, T max) {
inline double clip11(double value) {
double a = fabs(value);
if (a<=1) return value;
return (a<0) ? -1.0 : 1.0;
return (value<0) ? -1.0 : 1.0;
}
/// Clip a float to [-1.0f, +1.0f]
inline float clip11(float value) {
float a = fabsf(value);
if (a<=1) return value;
return (a<0) ? -1.0f : 1.0f;
return (value<0) ? -1.0f : 1.0f;
}
/// Clip a double to [0.0, +1.0]
@@ -245,7 +245,7 @@ inline double clip01(double value) {
inline float clip01(float value) {
float a = fabsf(value-0.5f);
if (a<=0.5f) return value;
return (a<0) ? -0.0f : 1.0f;
return (value < 0) ? -0.0f : 1.0f;
}
// Linear interpolation (mix-way between v1 and v2).

View File

@@ -234,6 +234,94 @@ 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" },
{ 100, 10, 20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ | PF_PROP_GRAPH, NULL, "freq0", "Split 1/2" },
{ 1000, 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 Multiband Compressor", "Markus Schmidt / Thor Harald Johansen", calf_plugins::calf_copyright_info, "CompressorPlugin" };
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
CALF_PORT_NAMES(monosynth) = {
"Out L", "Out R",
};

View File

@@ -58,9 +58,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);
}
@@ -87,9 +87,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;
@@ -101,7 +101,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;
@@ -119,7 +119,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;
@@ -242,7 +242,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)
{
@@ -359,7 +359,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);
@@ -470,9 +470,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;
@@ -519,9 +519,12 @@ uint32_t compressor_audio_module::process(uint32_t offset, uint32_t numsamples,
bool bypass = *params[param_bypass] > 0.5f;
if(bypass) {
int count = numsamples * sizeof(float);
memcpy(outs[0], ins[0], count);
memcpy(outs[1], ins[1], count);
numsamples += offset;
while(offset < numsamples) {
outs[0][offset] = ins[0][offset];
outs[1][offset] = ins[1][offset];
++offset;
}
if(params[param_compression] != NULL) {
*params[param_compression] = 1.f;
@@ -636,3 +639,642 @@ uint32_t compressor_audio_module::process(uint32_t offset, uint32_t numsamples,
return inputs_mask;
}
/// Multibandcompressor by Markus Schmidt
///
/// This module splits the signal in four different bands
/// and sends them through multiple filters (implemented by
/// Krzysztof). They are processed by a compressing routine
/// (implemented by Thor) afterwards and summed up to the
/// final output again.
///////////////////////////////////////////////////////////////////////////////////////////////
multibandcompressor_audio_module::multibandcompressor_audio_module()
{
is_active = false;
srate = 0;
// zero all displays
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 * 2.5 * numsamples / srate;
meter_inR -= meter_inR * 2.5 * numsamples / srate;
meter_outL -= meter_outL * 2.5 * numsamples / srate;
meter_outR -= meter_outR * 2.5 * numsamples / srate;
while(offset < numsamples) {
// cycle through 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 default 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;
}
// rise up in / out meters
if(inL > meter_inL) {
meter_inL = inL;
}
if(inR > meter_inR) {
meter_inR = inR;
}
if(outL > meter_outL) {
meter_outL = outL;
}
if(outR > meter_outR) {
meter_outR = outR;
}
// next sample
++offset;
} // 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)
{
// let's handle by the corresponding strip
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)
{
// let's handle by the corresponding strip
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)
{
// let's handle by the corresponding strip
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)
{
// let's handle by the corresponding strip
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 implemented by Markus Schmidt
/// Nearly all functions of this module are originally written
/// by Thor, while some features have been stripped (mainly stereo linking
/// and frequency correction as implemented in his Compressor above)
/// To save some CPU.
////////////////////////////////////////////////////////////////////////////////
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 = 1.f;
float l, r;
l = r = 0.f;
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)
{
float compression = 1.f;
meter_out -= meter_out * 5.f * 1 / srate;
if(bypass < 0.5f) {
// 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 absample = (fabs(left) + fabs(right)) * 0.5f;
if(rms) absample *= absample;
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;
detected = rms ? sqrt(linSlope) : linSlope;
}
float maxLR = std::max(fabs(left), fabs(right));
if(maxLR > meter_out) {
meter_out = maxLR;
}
meter_comp = compression;
}
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(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));
if (subindex == 0)
data[i] = dB_grid(input);
else {
float output = output_level(input);
data[i] = dB_grid(output);
}
}
if (subindex == (bypass > 0.5f ? 1 : 0) or mute > 0.1f)
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(1.5);
}
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)
{
if(bypass > 0.5f or mute > 0.f) {
return false;
} else {
bool rms = detection == 0;
float det = rms ? sqrt(detected) : detected;
x = 0.5 + 0.5 * dB_grid(det);
y = dB_grid(bypass > 0.5f or mute > 0.f ? det : output_level(det));
return 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(detection - old_detection) + fabs(bypass - old_bypass) + fabs(mute - old_mute) > 0.000001f)
{
old_threshold = threshold;
old_ratio = ratio;
old_knee = knee;
old_makeup = makeup;
old_detection = detection;
old_bypass = bypass;
old_mute = mute;
last_generation++;
}
if (generation == last_generation)
subindex_graph = 2;
return last_generation;
}

View File

@@ -626,7 +626,7 @@ void monosynth_audio_module::set_frequency()
{
float detune_scaled = (detune - 1); // * log(freq / 440);
if (*params[par_scaledetune] > 0)
detune_scaled *= pow(20.0 / freq, *params[par_scaledetune]);
detune_scaled *= pow(20.0 / freq, (double)*params[par_scaledetune]);
float p1 = 1, p2 = 1;
if (moddest[moddest_o1detune] != 0)
p1 = pow(2.0, moddest[moddest_o1detune] * (1.0 / 1200.0));