[SCM] calf/master: + True ADSR envelope (ok, kfoltman's own cheated ADSR, but that shouldn't matter) - still needs clicks fixed, but pretty functional already + Basic constant-time portamento (not really great!)

js at users.alioth.debian.org js at users.alioth.debian.org
Tue May 7 15:36:45 UTC 2013


The following commit has been merged in the master branch:
commit 0e9e9937c44e1afb64272970ad4b5ff47209ff01
Author: kfoltman <kfoltman at 78b06b96-2940-0410-b7fc-879d825d01d8>
Date:   Sat Dec 15 00:09:13 2007 +0000

    + True ADSR envelope (ok, kfoltman's own cheated ADSR, but that shouldn't matter) - still needs clicks fixed, but pretty functional already
    + Basic constant-time portamento (not really great!)
    
    
    
    git-svn-id: https://calf.svn.sourceforge.net/svnroot/calf/trunk@21 78b06b96-2940-0410-b7fc-879d825d01d8

diff --git a/src/calf/modules_dev.h b/src/calf/modules_dev.h
index b9c2d89..0928d8f 100644
--- a/src/calf/modules_dev.h
+++ b/src/calf/modules_dev.h
@@ -41,7 +41,7 @@ class monosynth_audio_module: public null_audio_module
 public:
     enum { wave_saw, wave_sqr, wave_pulse, wave_sine, wave_triangle, wave_count };
     enum { flt_lp12, flt_lp24, flt_2lp12, flt_hp12, flt_lpbr, flt_hpbr, flt_bp6, flt_2bp6 };
-    enum { par_wave1, par_wave2, par_detune, par_osc2xpose, par_oscmode, par_oscmix, par_filtertype, par_cutoff, par_resonance, par_cutoffsep, par_envmod, par_envtores, par_decay, par_keyfollow, par_legato, par_vel2amp, par_vel2filter, param_count };
+    enum { par_wave1, par_wave2, par_detune, par_osc2xpose, par_oscmode, par_oscmix, par_filtertype, par_cutoff, par_resonance, par_cutoffsep, par_envmod, par_envtores, par_attack, par_decay, par_sustain, par_release, par_keyfollow, par_legato, par_portamento, par_vel2amp, par_vel2filter, param_count };
     enum { in_count = 0, out_count = 2, support_midi = true, rt_capable = true };
     enum { step_size = 64 };
     static const char *param_names[];
@@ -59,12 +59,12 @@ public:
     biquad<float> filter;
     biquad<float> filter2;
     int wave1, wave2, filter_type;
-    float freq, cutoff, decay_factor, fgain, separation;
+    float freq, start_freq, target_freq, cutoff, decay_factor, fgain, separation;
     float detune, xpose, xfade, pitchbend, ampctl, fltctl, queue_vel;
-    int voice_age;
-    float odcr;
+    float odcr, porta_time;
     int queue_note_on;
     bool legato;
+    adsr envelope;
     
     static parameter_properties param_props[];
     void set_sample_rate(uint32_t sr) {
@@ -74,14 +74,16 @@ public:
     }
     void delayed_note_on()
     {
-        freq = 440 * pow(2.0, (queue_note_on - 69) / 12.0);
+        porta_time = 0.f;
+        start_freq = freq;
+        target_freq = freq = 440 * pow(2.0, (queue_note_on - 69) / 12.0);
         ampctl = 1.0 + (queue_vel - 1.0) * *params[par_vel2amp];
         fltctl = 1.0 + (queue_vel - 1.0) * *params[par_vel2filter];
         set_frequency();
         osc1.waveform = waves[wave1].get_level(osc1.phasedelta);
         osc2.waveform = waves[wave2].get_level(osc2.phasedelta);
         
-        if (!running)
+        if (!running || envelope.released())
         {
             osc1.reset();
             osc2.reset();
@@ -110,13 +112,13 @@ public:
             default:
                 break;
             }
-            voice_age = 0;
+            envelope.note_on();
             running = true;
         }
         gate = true;
         stopping = false;
         if (!legato)
-            voice_age = 0;
+            envelope.note_on();
         queue_note_on = -1;
     }
     void note_on(int note, int vel)
@@ -127,8 +129,10 @@ public:
     }
     void note_off(int note, int vel)
     {
-        if (note == last_key)
+        if (note == last_key) {
             gate = false;
+            envelope.note_off();
+        }
     }
     void pitch_bend(int value)
     {
@@ -140,6 +144,8 @@ public:
         osc2.set_freq(freq * (detune)  * pitchbend * xpose, srate);
     }
     void params_changed() {
+        float sf = 0.001f;
+        envelope.set(*params[par_attack] * sf, *params[par_decay] * sf, *params[par_sustain], *params[par_release] * sf, srate / step_size);
         filter_type = fastf2i_drm(*params[par_filtertype]);
         decay_factor = odcr * 1000.0 / *params[par_decay];
         separation = pow(2.0, *params[par_cutoffsep] / 1200.0);
@@ -253,8 +259,22 @@ public:
                 dsp::zero(buffer2, step_size);
             return;
         }
+        float porta_total_time = *params[par_portamento] * 0.001f;
+        
+        if (porta_total_time >= 0.00101f && porta_time >= 0) {
+            // XXXKF this is criminal, optimize!
+            float point = porta_time / porta_total_time;
+            if (point >= 1.0f) {
+                freq = target_freq;
+                porta_time = -1;
+            } else {
+                freq = start_freq * pow(target_freq / start_freq, point);
+                porta_time += odcr;
+            }
+        }
         set_frequency();
-        float env = max(0.f, 1.f - voice_age * decay_factor);
+        envelope.advance();
+        float env = envelope.value;
         cutoff = *params[par_cutoff] * pow(2.0f, env * fltctl * *params[par_envmod] * (1.f / 1200.f));
         if (*params[par_keyfollow] >= 0.5f)
             cutoff *= freq / 264.0f;
@@ -320,7 +340,7 @@ public:
             calculate_buffer_stereo();
             break;
         }
-        if (!gate)
+        if (envelope.state == adsr::STOP)
         {
             for (int i = 0; i < step_size; i++)
                 buffer[i] *= (step_size - i) * (1.0f / step_size);
@@ -329,8 +349,6 @@ public:
                     buffer2[i] *= (step_size - i) * (1.0f / step_size);
             stopping = true;
         }
-
-        voice_age++;
     }
     uint32_t process(uint32_t offset, uint32_t nsamples, uint32_t inputs_mask, uint32_t outputs_mask) {
         if (!running && queue_note_on == -1)
diff --git a/src/calf/synth.h b/src/calf/synth.h
index 7efc54a..3c02c90 100644
--- a/src/calf/synth.h
+++ b/src/calf/synth.h
@@ -156,6 +156,99 @@ public:
     virtual ~basic_synth();
 };
 
+// temporarily here, will be moved to separate file later
+// this is a weird envelope and perhaps won't turn out to
+// be a good idea in the long run, still, worth trying
+class adsr
+{
+public:
+    enum env_state { STOP, ATTACK, DECAY, SUSTAIN, RELEASE, LOCKDECAY };
+    
+    env_state state;
+    // note: these are *rates*, not times
+    float attack, decay, sustain, release;
+    float value;
+    
+    adsr()
+    {
+        attack = decay = sustain = release = 0.f;
+        reset();
+    }
+    inline void reset()
+    {
+        value = 0.f;
+        state = STOP;
+    }
+    inline void set(float a, float d, float s, float r, float er)
+    {
+        attack = 1.0 / (a * er);
+        decay = (1 - s) / (d * er);
+        sustain = s;
+        release = s / (r * er);
+    }
+    inline bool released()
+    {
+        return state == LOCKDECAY || state == RELEASE || state == STOP;
+    }
+    inline void note_on()
+    {
+        state = ATTACK;
+    }
+    inline void note_off()
+    {
+        if (state == STOP)
+            return;
+        if (value > sustain && decay > release)
+            state = LOCKDECAY;
+        else
+            state = RELEASE;
+    }
+    inline void advance()
+    {
+        switch(state)
+        {
+        case ATTACK:
+            value += attack;
+            if (value >= 1.0) {
+                value = 1.0;
+                state = DECAY;
+            }
+            break;
+        case DECAY:
+            value -= decay;
+            if (value < sustain)
+            {
+                value = sustain;
+                state = SUSTAIN;
+            }
+            break;
+        case LOCKDECAY:
+            value -= decay;
+            if (value < sustain)
+            {
+                if (value < 0.f)
+                    value = 0.f;
+                state = RELEASE;
+            }
+            break;
+        case SUSTAIN:
+            value = sustain;
+            break;
+        case RELEASE:
+            value -= release;
+            if (value < 0.f) {
+                value = 0.f;
+                state = STOP;
+            }
+            break;
+        case STOP:
+            value = 0.f;
+            break;
+        }
+    }
+};
+
+
 }
 
 #endif
diff --git a/src/modules.cpp b/src/modules.cpp
index a173753..f4ae503 100644
--- a/src/modules.cpp
+++ b/src/modules.cpp
@@ -140,7 +140,13 @@ synth::ladspa_wrapper<organ_audio_module> organ(organ_info);
 ////////////////////////////////////////////////////////////////////////////
 #ifdef ENABLE_EXPERIMENTAL
 
-const char *monosynth_audio_module::param_names[] = {"Out L", "Out R", "Osc1 Wave", "Osc2 Wave", "Osc 1/2 Detune", "Osc 2 Transpose", "Phase Mode", "Osc Mix", "Filter", "Cutoff", "Resonance", "Separation", "Env->Cutoff", "Env->Res", "Decay", "Key Follow", "Legato", "Vel->Amp", "Vel->Filter"};
+const char *monosynth_audio_module::param_names[] = {
+    "Out L", "Out R", 
+    "Osc1 Wave", "Osc2 Wave", "Osc 1/2 Detune", "Osc 2 Transpose", "Phase Mode", "Osc Mix", 
+    "Filter", "Cutoff", "Resonance", "Separation", "Env->Cutoff", "Env->Res", 
+    "Attack", "Decay", "Sustain", "Release", 
+    "Key Follow", "Legato", "Portamento", 
+    "Vel->Amp", "Vel->Filter"};
 
 const char *monosynth_waveform_names[] = { "Sawtooth", "Square", "Pulse", "Sine", "Triangle" };
 const char *monosynth_mode_names[] = { "0 : 0", "0 : 180", "0 : 90", "90 : 90", "90 : 270", "Random" };
@@ -169,9 +175,16 @@ parameter_properties monosynth_audio_module::param_props[] = {
     { 0,      -2400, 2400, 1.01, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL },
     { 8000,  -10800,10800, 1.01, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL },
     { 0.5,        0,    1, 1.01, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB, NULL },
+    
+    { 10,         1,20000, 1.01, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL },
+    { 350,       10,20000, 1.01, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL },
+    { 0.5,        0,    1, 1.01, PF_FLOAT | PF_SCALE_PERC, NULL },
     { 350,       10,20000, 1.01, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL },
+    
     { 0,          0,    1, 1.01, PF_BOOL | PF_CTL_TOGGLE, NULL },
     { 0,          0,    1, 1.01, PF_BOOL | PF_CTL_TOGGLE, NULL },
+    { 1,          1, 2000, 1.01, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL },
+    
     { 0,          0,    1,  0.1, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL },
     { 0,          0,    1,  0.1, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL },
 };

-- 
calf audio plugins packaging



More information about the pkg-multimedia-commits mailing list