[SCM] calf/master: + MultiChorus: first attempt at filtered chorus (nothing too innovative, alas)
js at users.alioth.debian.org
js at users.alioth.debian.org
Tue May 7 15:38:49 UTC 2013
The following commit has been merged in the master branch:
commit 840c825affd3870173de681d91dded484e1841db
Author: Krzysztof Foltman <wdev at foltman.com>
Date: Sun Jan 11 22:03:39 2009 +0000
+ MultiChorus: first attempt at filtered chorus (nothing too innovative, alas)
diff --git a/gui/gui-multichorus.xml b/gui/gui-multichorus.xml
index 0e7e8dd..f3068f5 100644
--- a/gui/gui-multichorus.xml
+++ b/gui/gui-multichorus.xml
@@ -62,4 +62,23 @@
</frame>
</hbox>
</if>
+ <frame label="LFO" attach-x="0" attach-y="3" shrink-y="1">
+ <hbox>
+ <vbox border="10">
+ <label param="freq" />
+ <knob param="freq" />
+ <value param="freq" />
+ </vbox>
+ <vbox border="10">
+ <label param="freq2" />
+ <knob param="freq2" />
+ <value param="freq2" />
+ </vbox>
+ <vbox border="10">
+ <label param="q" />
+ <knob param="q" />
+ <value param="q" />
+ </vbox>
+ </hbox>
+ </frame>
</table>
diff --git a/src/calf/biquad.h b/src/calf/biquad.h
index f98bcc1..aa81c8a 100644
--- a/src/calf/biquad.h
+++ b/src/calf/biquad.h
@@ -47,6 +47,7 @@ class biquad_coeffs
public:
// filter coefficients
Coeff a0, a1, a2, b1, b2;
+ typedef std::complex<double> cfloat;
biquad_coeffs()
{
@@ -310,7 +311,16 @@ public:
freq *= 2.0 * M_PI / sr;
cfloat z = 1.0 / exp(cfloat(0.0, freq));
- return std::abs((cfloat(a0) + double(a1) * z + double(a2) * z*z) / (cfloat(1.0) + double(b1) * z + double(b2) * z*z));
+ return std::abs(h_z(z));
+ }
+
+ /// Return H(z) the filter's gain at frequency freq
+ /// @param freq Frequency to look up
+ /// @param sr Filter sample rate (used to convert frequency to angular frequency)
+ cfloat h_z(const cfloat &z)
+ {
+
+ return (cfloat(a0) + double(a1) * z + double(a2) * z*z) / (cfloat(1.0) + double(b1) * z + double(b2) * z*z);
}
};
diff --git a/src/calf/metadata.h b/src/calf/metadata.h
index b340218..1b1273e 100644
--- a/src/calf/metadata.h
+++ b/src/calf/metadata.h
@@ -77,7 +77,7 @@ public:
struct multichorus_metadata: public plugin_metadata<multichorus_metadata>
{
public:
- enum { par_delay, par_depth, par_rate, par_stereo, par_voices, par_vphase, par_amount, par_dryamount, param_count };
+ enum { par_delay, par_depth, par_rate, par_stereo, par_voices, par_vphase, par_amount, par_dryamount, par_freq, par_freq2, par_q, param_count };
enum { in_count = 2, out_count = 2, rt_capable = true, support_midi = false, require_midi = false };
PLUGIN_NAME_ID_LABEL("multichorus", "multichorus", "Multi Chorus")
};
diff --git a/src/calf/modules.h b/src/calf/modules.h
index 16f6e7f..3cc35bb 100644
--- a/src/calf/modules.h
+++ b/src/calf/modules.h
@@ -626,6 +626,74 @@ public:
virtual void control_change(int ctl, int val);
};
+/// Compose two filters in series
+template<class F1, class F2>
+class filter_compose {
+public:
+ typedef std::complex<float> cfloat;
+ F1 f1;
+ F2 f2;
+public:
+ float process(float value) {
+ return f2.process(f1.process(value));
+ }
+
+ cfloat h_z(const cfloat &z) {
+ return f1.h_z(z) * f2.h_z(z);
+ }
+
+ /// Return the filter's gain at frequency freq
+ /// @param freq Frequency to look up
+ /// @param sr Filter sample rate (used to convert frequency to angular frequency)
+ float freq_gain(float freq, float sr)
+ {
+ typedef std::complex<double> cfloat;
+ freq *= 2.0 * M_PI / sr;
+ cfloat z = 1.0 / exp(cfloat(0.0, freq));
+
+ return std::abs(h_z(z));
+ }
+
+ void sanitize() {
+ f1.sanitize();
+ f2.sanitize();
+ }
+};
+
+/// Compose two filters in parallel
+template<class F1, class F2>
+class filter_sum {
+public:
+ typedef std::complex<double> cfloat;
+ F1 f1;
+ F2 f2;
+public:
+ float process(float value) {
+ return f2.process(value) + f1.process(value);
+ }
+
+ inline cfloat h_z(const cfloat &z) {
+ return f1.h_z(z) + f2.h_z(z);
+ }
+
+ /// Return the filter's gain at frequency freq
+ /// @param freq Frequency to look up
+ /// @param sr Filter sample rate (used to convert frequency to angular frequency)
+ float freq_gain(float freq, float sr)
+ {
+ typedef std::complex<double> cfloat;
+ freq *= 2.0 * M_PI / sr;
+ cfloat z = 1.0 / exp(cfloat(0.0, freq));
+
+ return std::abs(h_z(z));
+ }
+
+ void sanitize() {
+ f1.sanitize();
+ f2.sanitize();
+ }
+};
+
/// A multitap stereo chorus thing - processing
class multichorus_audio_module: public audio_module<multichorus_metadata>, public line_graph_iface
{
@@ -634,8 +702,9 @@ public:
float *outs[out_count];
float *params[param_count];
uint32_t srate;
- dsp::multichorus<float, sine_multi_lfo<float, 8>, 4096> left, right;
+ dsp::multichorus<float, sine_multi_lfo<float, 8>, filter_sum<dsp::biquad_d2<>, dsp::biquad_d2<> >, 4096> left, right;
float last_r_phase;
+ float cutoff;
bool is_active;
public:
@@ -667,6 +736,10 @@ public:
right.lfo.phase += chorus_phase(r_phase * 4096);
last_r_phase = r_phase;
}
+ left.post.f1.set_bp_rbj(*params[par_freq], *params[par_q], srate);
+ left.post.f2.set_bp_rbj(*params[par_freq2], *params[par_q], srate);
+ right.post.f1.copy_coeffs(left.post.f1);
+ right.post.f2.copy_coeffs(left.post.f2);
}
uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask) {
left.process(outs[0] + offset, ins[0] + offset, numsamples);
diff --git a/src/calf/multichorus.h b/src/calf/multichorus.h
index fcd96da..f4ab7ce 100644
--- a/src/calf/multichorus.h
+++ b/src/calf/multichorus.h
@@ -86,13 +86,15 @@ public:
* Multi-tap chorus without feedback.
* Perhaps MaxDelay should be a bit longer!
*/
-template<class T, class MultiLfo, int MaxDelay=4096>
+template<class T, class MultiLfo, class Postprocessor, int MaxDelay=4096>
class multichorus: public chorus_base
{
protected:
simple_delay<MaxDelay,T> delay;
public:
MultiLfo lfo;
+ Postprocessor post;
+public:
multichorus() {
rate = 0.63f;
dry = 0.5f;
@@ -140,17 +142,20 @@ public:
{
int lfo_output = lfo.get_value(v);
// 3 = log2(32 >> 2) + 1 because the LFO value is in range of [-65535, 65535] (17 bits)
- int v = mds + (mdepth * lfo_output >> (3 + 1));
- int ifv = v >> 16;
+ int dv = mds + (mdepth * lfo_output >> (3 + 1));
+ int ifv = dv >> 16;
T fd; // signal from delay's output
- delay.get_interp(fd, ifv, (v & 0xFFFF)*(1.0/65536.0));
+ delay.get_interp(fd, ifv, (dv & 0xFFFF)*(1.0/65536.0));
out += fd;
}
+ // apply the post filter
+ out = post.process(out);
T sdry = in * gs_dry.get();
T swet = out * gs_wet.get() * scale;
*buf_out++ = sdry + swet;
lfo.step();
}
+ post.sanitize();
}
float freq_gain(float freq, float sr)
{
@@ -167,12 +172,13 @@ public:
{
int lfo_output = lfo.get_value(v);
// 3 = log2(32 >> 2) + 1 because the LFO value is in range of [-65535, 65535] (17 bits)
- int v = mds + (mdepth * lfo_output >> (3 + 1));
- int fldp = v >> 16;
+ int dv = mds + (mdepth * lfo_output >> (3 + 1));
+ int fldp = dv >> 16;
cfloat zn = std::pow(z, fldp); // z^-N
- h += zn + (zn * z - zn) * cfloat(v / 65536.0 - fldp);
+ h += zn + (zn * z - zn) * cfloat(dv / 65536.0 - fldp);
}
- // simulate a lerped comb filter - H(z) = 1 / (1 + fb * (lerp(z^-N, z^-(N+1), fracpos))), N = int(pos), fracpos = pos - int(pos)
+ // apply the post filter
+ h *= post.h_z(z);
// mix with dry signal
float v = std::abs(cfloat(gs_dry.get_last()) + cfloat(scale * gs_wet.get_last()) * h);
return v;
diff --git a/src/modules.cpp b/src/modules.cpp
index bd490b6..feef0bc 100644
--- a/src/modules.cpp
+++ b/src/modules.cpp
@@ -167,6 +167,9 @@ CALF_PORT_PROPS(multichorus) = {
{ 64, 0, 360, 91, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_DEG, NULL, "vphase", "Inter-voice phase" },
{ 2, 0, 4, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "amount", "Amount" },
{ 1.0, 0, 4, 0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "dry", "Dry Amount" },
+ { 100, 10,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ | PF_PROP_GRAPH, NULL, "freq", "Center Frq 1" },
+ { 5000, 10,20000, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ | PF_PROP_GRAPH, NULL, "freq2", "Center Frq 2" },
+ { 0.125, 0.125, 8, 0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "q", "Q" },
};
CALF_PLUGIN_INFO(multichorus) = { 0x8501, "MultiChorus", "Calf MultiChorus", "Krzysztof Foltman", calf_plugins::calf_copyright_info, "ChorusPlugin" };
diff --git a/src/modules_dsp.cpp b/src/modules_dsp.cpp
index 2447b88..cdec24f 100644
--- a/src/modules_dsp.cpp
+++ b/src/modules_dsp.cpp
@@ -293,9 +293,14 @@ bool multichorus_audio_module::get_graph(int index, int subindex, float *data, i
{
if (!is_active)
return false;
- if (index == par_delay && subindex < 2)
+ if (index == par_delay && subindex < 3)
{
- set_channel_color(context, subindex);
+ if (subindex < 2)
+ set_channel_color(context, subindex);
+ else {
+ context->set_source_rgba(0, 1, 0);
+ context->set_line_width(1.0);
+ }
return ::get_graph(*this, subindex, data, points);
}
if (index == par_rate && !subindex) {
@@ -342,6 +347,8 @@ bool multichorus_audio_module::get_gridline(int index, int subindex, float &pos,
float multichorus_audio_module::freq_gain(int subindex, float freq, float srate)
{
+ if (subindex == 2)
+ return *params[par_amount] * left.post.freq_gain(freq, srate);
return (subindex ? right : left).freq_gain(freq, srate);
}
--
calf audio plugins packaging
More information about the pkg-multimedia-commits
mailing list