[SCM] calf/master: + Organ: percussion enhancements, first attempt at foldover bandlimiting for 'bell' waves

js at users.alioth.debian.org js at users.alioth.debian.org
Tue May 7 15:37:11 UTC 2013


The following commit has been merged in the master branch:
commit 564991172be68fd1a6e7dc15af9957fb90f5ff14
Author: kfoltman <kfoltman at 78b06b96-2940-0410-b7fc-879d825d01d8>
Date:   Sat May 3 23:32:08 2008 +0000

    + Organ: percussion enhancements, first attempt at foldover bandlimiting for 'bell' waves
    
    
    git-svn-id: https://calf.svn.sourceforge.net/svnroot/calf/trunk@168 78b06b96-2940-0410-b7fc-879d825d01d8

diff --git a/src/calf/biquad.h b/src/calf/biquad.h
index bc4f73e..0e1c049 100644
--- a/src/calf/biquad.h
+++ b/src/calf/biquad.h
@@ -277,6 +277,18 @@ public:
         dsp::zero(y2);
         dsp::zero(w2);
     }
+    inline void reset_d1()
+    {
+        dsp::zero(x1);
+        dsp::zero(y1);
+    }
+    inline void reset_d2()
+    {
+        dsp::zero(w1);
+        dsp::zero(x2);
+        dsp::zero(y2);
+        dsp::zero(w2);
+    }
 };
 
 };
diff --git a/src/calf/organ.h b/src/calf/organ.h
index 51040c7..2dacf85 100644
--- a/src/calf/organ.h
+++ b/src/calf/organ.h
@@ -52,7 +52,8 @@ struct organ_parameters {
     float foldover;
     float percussion_time;
     float percussion_level;
-    float percussion_harmonic;
+    float percussion_timbre;
+    float percussion_trigger;
     float master;
     
     organ_filter_parameters filters[organ_parameters::FilterCount];
@@ -69,7 +70,7 @@ struct organ_parameters {
     float cutoff;
     unsigned int foldvalue;
 
-    inline int get_percussion_harmonic() { return dsp::fastf2i_drm(percussion_harmonic); }
+    inline int get_percussion_timbre() { return dsp::fastf2i_drm(percussion_timbre); }
 };
 
 #define ORGAN_WAVE_BITS 12
@@ -78,7 +79,7 @@ struct organ_parameters {
 class organ_voice_base
 {
 public:
-    enum { 
+    enum organ_waveform { 
         wave_sine, 
         wave_sinepl1, wave_sinepl2, wave_sinepl3,
         wave_ssaw, wave_ssqr, wave_spls, wave_saw, wave_sqr, wave_pulse, wave_sinepl05, wave_sqr05, wave_halfsin, wave_clvg, wave_bell, wave_bell2,
@@ -102,6 +103,12 @@ public:
         lfomode_global,
         lfomode_count
     };
+    enum {
+        perctrig_first = 0,
+        perctrig_each,
+        perctrig_eachplus,
+        perctrig_count
+    };
 protected:
     static waveform_family<ORGAN_WAVE_BITS> waves[wave_count];
     // dsp::sine_table<float, ORGAN_WAVE_SIZE, 1> sine_wave;
@@ -196,6 +203,7 @@ class percussion_voice: public organ_voice_base {
 public:
     int sample_rate;
     dsp::fixed_point<int64_t, 20> phase, dphase;
+    dsp::biquad<float> filter;
 
     percussion_voice(organ_parameters *_parameters)
     : organ_voice_base(_parameters)
@@ -208,9 +216,16 @@ public:
     }
 
     void note_on(int note, int /*vel*/) {
-        reset();
+        // do not reset phase if voice is still running (to prevent clicks, even at cost of slight loss of "percussiveness")
+        if (!amp.get_active())
+        {
+            phase = 0;
+            filter.reset_d1();
+        }
         this->note = note;
-        dphase.set(synth::midi_note_to_phase(note, 0, sample_rate));
+        int timbre = parameters->get_percussion_timbre();
+        static const int harm_muls[8] = { 1, 2, 3, 4, 8, 1, 2, 4 };
+        dphase.set(synth::midi_note_to_phase(note, 0, sample_rate) * harm_muls[timbre]);
         amp.set(1.0f);
     }
 
@@ -223,23 +238,44 @@ public:
             return;
         if (parameters->percussion_level < small_value<float>())
             return;
-        int percussion_harmonic = 2 * parameters->get_percussion_harmonic();
+        static const organ_waveform wave_ids[] = { wave_sine, wave_sine, wave_sine, wave_bell, wave_bell, wave_sqr, wave_sqr, wave_sqr };
         float level = parameters->percussion_level * 9;
         // XXXKF the decay needs work!
         double age_const = parameters->perc_decay_const;
-        float *data = waves[wave_sine].begin()->second;
-        for (int i = 0; i < nsamples; i++) {
-            float osc = level * wave(data, percussion_harmonic * phase);
-            osc *= level * amp.get();
-            buf[i][0] += osc;
-            buf[i][1] += osc;
-            amp.age_exp(age_const, 1.0 / 32768.0);
-            phase += dphase;
+        int timbre = parameters->get_percussion_timbre();
+        float *data = waves[wave_ids[timbre]].get_level(dphase.get());
+        if (timbre < 3)
+        {
+            for (int i = 0; i < nsamples; i++) {
+                float osc = level * wave(data, phase);
+                osc *= level * amp.get();
+                buf[i][0] += osc;
+                buf[i][1] += osc;
+                amp.age_exp(age_const, 1.0 / 32768.0);
+                phase += dphase;
+            }
+        }
+        else
+        {
+            float av = amp.get();
+            filter.set_lp_rbj(400 + 5000 * (av * 0.2 + av * av * 0.8), 0.707, sample_rate);
+            for (int i = 0; i < nsamples; i++) {
+                float osc = filter.process_d1(level * wave(data, phase));
+                osc *= level * amp.get();
+                buf[i][0] += osc;
+                buf[i][1] += osc;
+                amp.age_exp(age_const, 1.0 / 32768.0);
+                phase += dphase;
+            }
+            filter.sanitize_d1();
         }
     }
     bool get_active() {
         return (note != -1) && amp.get_active();
     }
+    bool get_noticable() {
+        return (note != -1) && (amp.get() > 0.2);
+    }
     void setup(int sr) {
         sample_rate = sr;
     }
@@ -259,7 +295,8 @@ struct drawbar_organ: public synth::basic_synth {
         par_pan1, par_pan2, par_pan3, par_pan4, par_pan5, par_pan6, par_pan7, par_pan8, par_pan9, 
         par_routing1, par_routing2, par_routing3, par_routing4, par_routing5, par_routing6, par_routing7, par_routing8, par_routing9, 
         par_foldover,
-        par_percdecay, par_perclevel, par_percharm, par_master, 
+        par_percdecay, par_perclevel, par_perctimbre, par_perctrigger,
+        par_master, 
         par_f1cutoff, par_f1res, par_f1env1, par_f1env2, par_f1env3, par_f1keyf,
         par_f2cutoff, par_f2res, par_f2env1, par_f2env2, par_f2env3, par_f2keyf,
         par_eg1attack, par_eg1decay, par_eg1sustain, par_eg1release, par_eg1velscl, par_eg1ampctl, 
@@ -296,7 +333,7 @@ struct drawbar_organ: public synth::basic_synth {
         v->parameters = parameters;
         return v;
     }
-    virtual void first_note_on(int note, int vel) {
+    virtual void percussion_note_on(int note, int vel) {
         percussion.note_on(note, vel);
     }
     virtual void setup(int sr) {
@@ -314,6 +351,18 @@ struct drawbar_organ: public synth::basic_synth {
         }
         synth::basic_synth::control_change(controller, value);
     }
+    virtual bool check_percussion() { 
+        switch(dsp::fastf2i_drm(parameters->percussion_trigger))
+        {        
+            case organ_voice_base::perctrig_first:
+                return active_voices.empty();
+            case organ_voice_base::perctrig_each: 
+            default:
+                return true;
+            case organ_voice_base::perctrig_eachplus:
+                return !percussion.get_noticable();
+        }
+    }
 };
 
 };
diff --git a/src/calf/osc.h b/src/calf/osc.h
index 1948282..e3d9915 100644
--- a/src/calf/osc.h
+++ b/src/calf/osc.h
@@ -81,15 +81,30 @@ struct bandlimiter
     
     /// very basic bandlimiting (brickwall filter)
     /// might need to be improved much in future!
-    void make_waveform(float output[SIZE], int cutoff)
+    void make_waveform(float output[SIZE], int cutoff, bool foldover = false)
     {
         std::complex<float> new_spec[SIZE], iffted[SIZE];
         for (int i = 0; i < cutoff; i++)
             new_spec[i] = spectrum[i], 
             new_spec[SIZE - 1 - i] = spectrum[SIZE - 1 - i];
-        for (int i = cutoff; i < SIZE / 2; i++)
-            new_spec[i] = 0.f,
-            new_spec[SIZE - 1 - i] = 0.f;
+        if (foldover)
+        {
+            std::complex<float> half(0.5);
+            cutoff /= 2;
+            for (int i = SIZE / 2; i >= cutoff; i--)
+            {
+                new_spec[i / 2] += new_spec[i] * half;
+                new_spec[SIZE - 1 - i / 2] += new_spec[SIZE - 1 - i] * half;
+                new_spec[i] = 0.f,
+                new_spec[SIZE - 1 - i] = 0.f;
+            }
+        }
+        else
+        {
+            for (int i = cutoff; i < SIZE / 2; i++)
+                new_spec[i] = 0.f,
+                new_spec[SIZE - 1 - i] = 0.f;
+        }
         fft.calculate(new_spec, iffted, true);
         for (int i = 0; i < SIZE; i++)
             output[i] = iffted[i].real();
@@ -109,7 +124,7 @@ struct waveform_family: public map<uint32_t, float *>
     using map<uint32_t, float *>::lower_bound;
     float original[SIZE];
     
-    void make(bandlimiter<SIZE_BITS> &bl, float input[SIZE])
+    void make(bandlimiter<SIZE_BITS> &bl, float input[SIZE], bool foldover = false)
     {
         memcpy(original, input, sizeof(original));
         bl.compute_spectrum(input);
@@ -118,7 +133,7 @@ struct waveform_family: public map<uint32_t, float *>
         uint32_t multiple = 1, base = 1 << (32 - SIZE_BITS);
         while(multiple < SIZE / 2) {
             float *wf = new float[SIZE+1];
-            bl.make_waveform(wf, (int)((1 << SIZE_BITS) / (1.5 * multiple)));
+            bl.make_waveform(wf, (int)((1 << SIZE_BITS) / (1.5 * multiple)), foldover);
             wf[SIZE] = wf[0];
             (*this)[base * multiple] = wf;
             multiple = multiple << 1;
diff --git a/src/calf/synth.h b/src/calf/synth.h
index 4d74eab..2fbbcf5 100644
--- a/src/calf/synth.h
+++ b/src/calf/synth.h
@@ -199,10 +199,11 @@ public:
     virtual synth::voice *alloc_voice()=0;
     virtual void render_to(float (*output)[2], int nsamples);
     virtual void note_on(int note, int vel);
-    virtual void first_note_on(int note, int vel) {}
+    virtual void percussion_note_on(int note, int vel) {}
     virtual void control_change(int ctl, int val);
     virtual void note_off(int note, int vel);
     virtual void on_pedal_release();
+    virtual bool check_percussion() { return active_voices.empty(); }
     virtual ~basic_synth();
 };
 
diff --git a/src/organ.cpp b/src/organ.cpp
index f9601da..16daba7 100644
--- a/src/organ.cpp
+++ b/src/organ.cpp
@@ -69,8 +69,12 @@ const char *organ_audio_module::get_gui_xml()
                 "<value param=\"perc_level\"/>"
             "</vbox>"        
             "<vbox>"
-                "<label param=\"perc_harm\"/>"
-                "<combo param=\"perc_harm\"/>"
+                "<label param=\"perc_timbre\"/>"
+                "<combo param=\"perc_timbre\"/>"
+            "</vbox>"        
+            "<vbox>"
+                "<label param=\"perc_trigger\"/>"
+                "<combo param=\"perc_trigger\"/>"
             "</vbox>"        
             "<vbox>"
                 "<label param=\"master\"/>"
@@ -286,7 +290,11 @@ const char *organ_audio_module::get_gui_xml()
 
 const char *organ_audio_module::port_names[] = {"Out L", "Out R"};
 
-const char *organ_percussion_harmonic_names[] = { "2nd", "3rd" };
+const char *organ_percussion_timbre_names[] = { 
+    "16' Sine", "8' Sine", "5 1/3' Sine", 
+    "4' Bell", "2' Bell", 
+    "16' Sqr", "8' Sqr", "4' Sqr" };
+const char *organ_percussion_trigger_names[] = { "First note", "Each note", "Each, no retrig" };
 
 const char *organ_wave_names[] = { 
     "Sin", 
@@ -379,7 +387,8 @@ parameter_properties organ_audio_module::param_props[] = {
     { 96,      0,  127, 128, PF_INT | PF_CTL_KNOB | PF_UNIT_NOTE, NULL, "foldnote", "Foldover" },
     { 200,         10,  3000, 100, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "perc_decay", "Perc. decay" },
     { 0.25,      0,  1, 100, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB, NULL, "perc_level", "Perc. level" },
-    { 3,         2,  3, 1, PF_ENUM | PF_CTL_COMBO, organ_percussion_harmonic_names, "perc_harm", "Perc. harmonic" },
+    { 2,         0,  7, 1, PF_ENUM | PF_CTL_COMBO, organ_percussion_timbre_names, "perc_timbre", "Perc. timbre" },
+    { 0,         0,  organ_voice_base::perctrig_count - 1, 0, PF_ENUM | PF_CTL_COMBO, organ_percussion_trigger_names, "perc_trigger", "Perc. trigger" },
 
     { 0.1,         0,  1, 100, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB, NULL, "master", "Volume" },
     
@@ -525,11 +534,11 @@ organ_voice_base::organ_voice_base(organ_parameters *_parameters)
         for (int i = 0; i < ORGAN_WAVE_SIZE; i++)
         {
             float ph = i * 2 * M_PI / ORGAN_WAVE_SIZE;
-            float fm = 0.3 * sin(6*ph) + 0.3 * sin(11*ph) + 0.3 * cos(17*ph) - 0.3 * cos(19*ph);
-            tmp[i] = sin(5*ph + fm) + cos(7*ph - fm);
+            float fm = 0.3 * sin(6*ph) + 0.2 * sin(11*ph) + 0.2 * cos(17*ph) - 0.2 * cos(19*ph);
+            tmp[i] = sin(5*ph + fm) + 0.7 * cos(7*ph - fm);
         }
         normalize_waveform(tmp, ORGAN_WAVE_SIZE);
-        waves[wave_bell].make(bl, tmp);
+        waves[wave_bell].make(bl, tmp, true);
         for (int i = 0; i < ORGAN_WAVE_SIZE; i++)
         {
             float ph = i * 2 * M_PI / ORGAN_WAVE_SIZE;
@@ -537,7 +546,7 @@ organ_voice_base::organ_voice_base(organ_parameters *_parameters)
             tmp[i] = sin(3*ph + fm) + cos(7*ph - fm);
         }
         normalize_waveform(tmp, ORGAN_WAVE_SIZE);
-        waves[wave_bell2].make(bl, tmp);
+        waves[wave_bell2].make(bl, tmp, true);
         for (int i = 0; i < ORGAN_WAVE_SIZE; i++)
         {
             float ph = i * 2 * M_PI / ORGAN_WAVE_SIZE;
diff --git a/src/synth.cpp b/src/synth.cpp
index 682be9b..f659fe8 100644
--- a/src/synth.cpp
+++ b/src/synth.cpp
@@ -60,7 +60,7 @@ void basic_synth::note_on(int note, int vel)
         note_off(note, 0);
         return;
     }
-    bool perc = active_voices.empty();
+    bool perc = check_percussion();
     synth::voice *v = alloc_voice();
     v->setup(sample_rate);
     v->released = false;
@@ -69,7 +69,7 @@ void basic_synth::note_on(int note, int vel)
     v->note_on(note, vel);
     active_voices.push_back(v);
     if (perc) {
-        first_note_on(note, vel);
+        percussion_note_on(note, vel);
     }
 }
 

-- 
calf audio plugins packaging



More information about the pkg-multimedia-commits mailing list