[SCM] calf/master: Add LR and RL modes to Vintage Delay (idea by Louigi Verona).

js at users.alioth.debian.org js at users.alioth.debian.org
Tue May 7 15:40:08 UTC 2013


The following commit has been merged in the master branch:
commit da582087b18e3d0c82e895f1d8ff29c301db20aa
Author: Krzysztof Foltman <wdev at foltman.com>
Date:   Tue May 4 00:29:57 2010 +0100

    Add LR and RL modes to Vintage Delay (idea by Louigi Verona).
    
    Those modes work by having two separate outputs from the delay line, the 'main'
    one (used for output) and the 'feedback' one (used for feedback). For example,
    in LR mode, the left channel signal is first delayed 'left' ticks then
    'left+right' ticks (the feedback time = left+right). The right channel is
    always delayed by 'left+right' ticks. This way, a ping pong effect is achieved
    when left and right time is set to the same value.

diff --git a/src/calf/modules.h b/src/calf/modules.h
index 730b28c..7c0e9f5 100644
--- a/src/calf/modules.h
+++ b/src/calf/modules.h
@@ -122,13 +122,13 @@ class vintage_delay_audio_module: public audio_module<vintage_delay_metadata>
 public:    
     // 1MB of delay memory per channel... uh, RAM is cheap
     enum { MAX_DELAY = 262144, ADDR_MASK = MAX_DELAY - 1 };
+    enum { MIXMODE_STEREO, MIXMODE_PINGPONG, MIXMODE_LR, MIXMODE_RL }; 
     float buffers[2][MAX_DELAY];
     int bufptr, deltime_l, deltime_r, mixmode, medium, old_medium;
     /// number of table entries written (value is only important when it is less than MAX_DELAY, which means that the buffer hasn't been totally filled yet)
     int age;
     
-    gain_smoothing amt_left, amt_right, fb_left, fb_right;
-    float dry;
+    gain_smoothing amt_left, amt_right, fb_left, fb_right, dry;
     
     dsp::biquad_d2<float> biquad_left[2], biquad_right[2];
     
diff --git a/src/modules.cpp b/src/modules.cpp
index 71e6bcc..fa14c53 100644
--- a/src/modules.cpp
+++ b/src/modules.cpp
@@ -141,6 +141,8 @@ CALF_PORT_NAMES(vintage_delay) = {"In L", "In R", "Out L", "Out R"};
 const char *vintage_delay_mixmodes[] = {
     "Stereo",
     "Ping-Pong",
+    "L then R",
+    "R then L",
 };
 
 const char *vintage_delay_fbmodes[] = {
@@ -156,7 +158,7 @@ CALF_PORT_PROPS(vintage_delay) = {
     {  5,        1,    16,    1, PF_INT | PF_SCALE_LINEAR | PF_CTL_FADER, NULL, "time_r", "Time R"},
     { 0.5,       0,    1,     0, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "feedback", "Feedback" },
     { 0.25,      0,    4,   100, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "amount", "Amount" },
-    { 1,         0,    1,     0, PF_ENUM | PF_CTL_COMBO, vintage_delay_mixmodes, "mix_mode", "Mix mode" },
+    { 1,         0,    3,     0, PF_ENUM | PF_CTL_COMBO, vintage_delay_mixmodes, "mix_mode", "Mix mode" },
     { 1,         0,    2,     0, PF_ENUM | PF_CTL_COMBO, vintage_delay_fbmodes, "medium", "Medium" },
     { 1.0,       0,    4,     0, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "dry", "Dry Amount" },
 };
diff --git a/src/modules_dsp.cpp b/src/modules_dsp.cpp
index c334682..ecc3095 100644
--- a/src/modules_dsp.cpp
+++ b/src/modules_dsp.cpp
@@ -298,18 +298,39 @@ void vintage_delay_audio_module::params_changed()
     float unit = 60.0 * srate / (*params[par_bpm] * *params[par_divide]);
     deltime_l = dsp::fastf2i_drm(unit * *params[par_time_l]);
     deltime_r = dsp::fastf2i_drm(unit * *params[par_time_r]);
-    amt_left.set_inertia(*params[par_amount]); amt_right.set_inertia(*params[par_amount]);
+    int deltime_fb = deltime_l + deltime_r;
     float fb = *params[par_feedback];
-    dry = *params[par_dryamount];
+    dry.set_inertia(*params[par_dryamount]);
     mixmode = dsp::fastf2i_drm(*params[par_mixmode]);
     medium = dsp::fastf2i_drm(*params[par_medium]);
-    if (mixmode == 0)
+    switch(mixmode)
     {
+    case MIXMODE_STEREO:
         fb_left.set_inertia(fb);
         fb_right.set_inertia(pow(fb, *params[par_time_r] / *params[par_time_l]));
-    } else {
+        amt_left.set_inertia(*params[par_amount]);
+        amt_right.set_inertia(*params[par_amount]);
+        break;
+    case MIXMODE_PINGPONG:
+        fb_left.set_inertia(fb);
+        fb_right.set_inertia(fb);
+        amt_left.set_inertia(*params[par_amount]);
+        amt_right.set_inertia(*params[par_amount]);
+        break;
+    case MIXMODE_LR:
+        fb_left.set_inertia(fb);
+        fb_right.set_inertia(fb);
+        amt_left.set_inertia(*params[par_amount]);                                          // L is straight 'amount'
+        amt_right.set_inertia(*params[par_amount] * pow(fb, 1.0 * deltime_r / deltime_fb)); // R is amount with feedback based dampening as if it ran through R/FB*100% of delay line's dampening
+        // deltime_l <<< deltime_r -> pow() = fb -> full delay line worth of dampening
+        // deltime_l >>> deltime_r -> pow() = 1 -> no dampening
+        break;
+    case MIXMODE_RL:
         fb_left.set_inertia(fb);
         fb_right.set_inertia(fb);
+        amt_left.set_inertia(*params[par_amount] * pow(fb, 1.0 * deltime_l / deltime_fb));
+        amt_right.set_inertia(*params[par_amount]);
+        break;
     }
     if (medium != old_medium)
         calc_filters();
@@ -343,47 +364,86 @@ void vintage_delay_audio_module::calc_filters()
     biquad_right[1].copy_coeffs(biquad_left[1]);
 }
 
+/// Single delay line with feedback at the same tap
+static inline void delayline_impl(int age, int deltime, float dry_value, const float &delayed_value, float &out, float &del, gain_smoothing &amt, gain_smoothing &fb, float dry)
+{
+    // if the buffer hasn't been cleared yet (after activation), pretend we've read zeros
+    if (age <= deltime) {
+        out = dry * dry_value;
+        amt.step();
+        fb.step();
+    }
+    else
+    {
+        float delayed = delayed_value; // avoid dereferencing the pointer in 'then' branch of the if()
+        dsp::sanitize(delayed);
+        out = dry * dry_value + delayed * amt.get();
+        del = dry_value + delayed * fb.get();
+    }
+}
+
+/// Single delay line with tap output
+static inline void delayline2_impl(int age, int deltime, float dry_value, const float &delayed_value, const float &delayed_value_for_fb, float &out, float &del, gain_smoothing &amt, gain_smoothing &fb, float dry)
+{
+    if (age <= deltime) {
+        out = dry * dry_value;
+        amt.step();
+        fb.step();
+    }
+    else
+    {
+        out = dry * dry_value + delayed_value * amt.get();
+        del = dry_value + delayed_value_for_fb * fb.get();
+        dsp::sanitize(out);
+        dsp::sanitize(del);
+    }
+}
+
 uint32_t vintage_delay_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask)
 {
     uint32_t ostate = 3; // XXXKF optimize!
     uint32_t end = offset + numsamples;
-    int v = mixmode ? 1 : 0;
     int orig_bufptr = bufptr;
-    for(uint32_t i = offset; i < end; i++)
+    float out_left, out_right, del_left, del_right;
+    
+    switch(mixmode)
     {
-        float out_left, out_right, del_left, del_right;
-        // if the buffer hasn't been cleared yet (after activation), pretend we've read zeros
-
-        if (deltime_l >= age) {
-            del_left = ins[0][i];
-            out_left = dry * del_left;
-            amt_left.step();
-            fb_left.step();
-        }
-        else
+        case MIXMODE_STEREO:
+        case MIXMODE_PINGPONG:
         {
-            float in_left = buffers[v][(bufptr - deltime_l) & ADDR_MASK];
-            dsp::sanitize(in_left);
-            out_left = dry * ins[0][i] + in_left * amt_left.get();
-            del_left = ins[0][i] + in_left * fb_left.get();
-        }
-        if (deltime_r >= age) {
-            del_right = ins[1][i];
-            out_right = dry * del_right;
-            amt_right.step();
-            fb_right.step();
+            int v = mixmode == MIXMODE_PINGPONG ? 1 : 0;
+            for(uint32_t i = offset; i < end; i++)
+            {                
+                float cur_dry = dry.get();
+                delayline_impl(age, deltime_l, ins[0][i], buffers[v][(bufptr - deltime_l) & ADDR_MASK], out_left, del_left, amt_left, fb_left, cur_dry);
+                delayline_impl(age, deltime_r, ins[1][i], buffers[1 - v][(bufptr - deltime_r) & ADDR_MASK], out_right, del_right, amt_right, fb_right, cur_dry);
+                
+                age++;
+                outs[0][i] = out_left; outs[1][i] = out_right; buffers[0][bufptr] = del_left; buffers[1][bufptr] = del_right;
+                bufptr = (bufptr + 1) & (MAX_DELAY - 1);
+            }
         }
-        else
+        break;
+        
+        case MIXMODE_LR:
+        case MIXMODE_RL:
         {
-            float in_right = buffers[1 - v][(bufptr - deltime_r) & ADDR_MASK];
-            dsp::sanitize(in_right);
-            out_right = dry * ins[1][i] + in_right * amt_right.get();
-            del_right = ins[1][i] + in_right * fb_right.get();
+            int v = mixmode == MIXMODE_RL ? 1 : 0;
+            int deltime_fb = deltime_l + deltime_r;
+            int deltime_l_corr = mixmode == MIXMODE_RL ? deltime_fb : deltime_l;
+            int deltime_r_corr = mixmode == MIXMODE_LR ? deltime_fb : deltime_r;
+            
+            for(uint32_t i = offset; i < end; i++)
+            {
+                float cur_dry = dry.get();
+                delayline2_impl(age, deltime_l, ins[0][i], buffers[v][(bufptr - deltime_l_corr) & ADDR_MASK], buffers[v][(bufptr - deltime_fb) & ADDR_MASK], out_left, del_left, amt_left, fb_left, cur_dry);
+                delayline2_impl(age, deltime_r, ins[1][i], buffers[1 - v][(bufptr - deltime_r_corr) & ADDR_MASK], buffers[1-v][(bufptr - deltime_fb) & ADDR_MASK], out_right, del_right, amt_right, fb_right, cur_dry);
+                
+                age++;
+                outs[0][i] = out_left; outs[1][i] = out_right; buffers[0][bufptr] = del_left; buffers[1][bufptr] = del_right;
+                bufptr = (bufptr + 1) & (MAX_DELAY - 1);
+            }
         }
-        
-        age++;
-        outs[0][i] = out_left; outs[1][i] = out_right; buffers[0][bufptr] = del_left; buffers[1][bufptr] = del_right;
-        bufptr = (bufptr + 1) & (MAX_DELAY - 1);
     }
     if (age >= MAX_DELAY)
         age = MAX_DELAY;

-- 
calf audio plugins packaging



More information about the pkg-multimedia-commits mailing list