[SCM] calf/master: + Monosynth: moved to separate .cpp file (might be slightly slower, but nothing worth keeping huge mess in .h file) + Monosynth: another attempt at fixing ADSR envelope, hope it's 100% right this time + Monosynth: started adding more waveforms, changed "Skewed" waveforms too so that they are less chirpy + Added missing presets.xml file to repository

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


The following commit has been merged in the master branch:
commit e7d7a806861e16a4d32dc5c62a5613ad10ee628d
Author: kfoltman <kfoltman at 78b06b96-2940-0410-b7fc-879d825d01d8>
Date:   Sun Dec 23 23:57:04 2007 +0000

    + Monosynth: moved to separate .cpp file (might be slightly slower, but nothing worth keeping huge mess in .h file)
    + Monosynth: another attempt at fixing ADSR envelope, hope it's 100% right this time
    + Monosynth: started adding more waveforms, changed "Skewed" waveforms too so that they are less chirpy
    + Added missing presets.xml file to repository
    
    
    
    git-svn-id: https://calf.svn.sourceforge.net/svnroot/calf/trunk@41 78b06b96-2940-0410-b7fc-879d825d01d8

diff --git a/presets.xml b/presets.xml
new file mode 100644
index 0000000..ceedc6d
--- /dev/null
+++ b/presets.xml
@@ -0,0 +1,165 @@
+<presets>
+<preset bank="0" program="0" plugin="monosynth" name="Synth Brass">
+  <param name="o1_wave" value="0" />
+  <param name="o2_wave" value="0" />
+  <param name="o12_detune" value="5.53015" />
+  <param name="o2_xpose" value="0" />
+  <param name="phase_mode" value="5" />
+  <param name="o12_mix" value="0.5" />
+  <param name="Filter" value="2" />
+  <param name="cutoff" value="661.957" />
+  <param name="res" value="0.7" />
+  <param name="filter_sep" value="0" />
+  <param name="env2cutoff" value="6443.01" />
+  <param name="env2res" value="1" />
+  <param name="adsr_a" value="84.5126" />
+  <param name="adsr_d" value="350" />
+  <param name="adsr_s" value="0.682958" />
+  <param name="adsr_r" value="59.6428" />
+  <param name="key_follow" value="1" />
+  <param name="legato" value="2" />
+  <param name="portamento" value="64.4744" />
+  <param name="vel2amp" value="0.530111" />
+  <param name="vel2filter" value="0.225724" />
+</preset>
+<preset bank="0" program="0" plugin="monosynth" name="Octaved Square">
+  <param name="o1_wave" value="3" />
+  <param name="o2_wave" value="1" />
+  <param name="o12_detune" value="0.60614" />
+  <param name="o2_xpose" value="24" />
+  <param name="phase_mode" value="1" />
+  <param name="o12_mix" value="0.5" />
+  <param name="Filter" value="4" />
+  <param name="cutoff" value="1170.34" />
+  <param name="res" value="0.7" />
+  <param name="filter_sep" value="-777.368" />
+  <param name="env2cutoff" value="9325.2" />
+  <param name="env2res" value="1" />
+  <param name="adsr_a" value="1" />
+  <param name="adsr_d" value="108.852" />
+  <param name="adsr_s" value="0.0176431" />
+  <param name="adsr_r" value="91.6363" />
+  <param name="key_follow" value="1" />
+  <param name="legato" value="0" />
+  <param name="portamento" value="1" />
+  <param name="vel2amp" value="1" />
+  <param name="vel2filter" value="0.225724" />
+</preset>
+<preset bank="0" program="0" plugin="monosynth" name="Move it!">
+  <param name="o1_wave" value="2" />
+  <param name="o2_wave" value="2" />
+  <param name="o12_detune" value="13.1621" />
+  <param name="o2_xpose" value="0" />
+  <param name="phase_mode" value="1" />
+  <param name="o12_mix" value="0.5" />
+  <param name="Filter" value="1" />
+  <param name="cutoff" value="90.3129" />
+  <param name="res" value="3.0757" />
+  <param name="filter_sep" value="1272.27" />
+  <param name="env2cutoff" value="7551.9" />
+  <param name="env2res" value="1" />
+  <param name="adsr_a" value="53.3753" />
+  <param name="adsr_d" value="50.9018" />
+  <param name="adsr_s" value="1" />
+  <param name="adsr_r" value="91.6363" />
+  <param name="key_follow" value="1" />
+  <param name="legato" value="0" />
+  <param name="portamento" value="1" />
+  <param name="vel2amp" value="1" />
+  <param name="vel2filter" value="1" />
+</preset>
+<preset bank="0" program="0" plugin="monosynth" name="Fat Bass">
+  <param name="o1_wave" value="0" />
+  <param name="o2_wave" value="0" />
+  <param name="o12_detune" value="7.49069" />
+  <param name="o2_xpose" value="0" />
+  <param name="phase_mode" value="1" />
+  <param name="o12_mix" value="0.5" />
+  <param name="Filter" value="1" />
+  <param name="cutoff" value="116.961" />
+  <param name="res" value="2" />
+  <param name="filter_sep" value="0" />
+  <param name="env2cutoff" value="10800" />
+  <param name="env2res" value="1" />
+  <param name="adsr_a" value="1" />
+  <param name="adsr_d" value="125.992" />
+  <param name="adsr_s" value="0.530111" />
+  <param name="adsr_r" value="50" />
+  <param name="key_follow" value="1" />
+  <param name="legato" value="0" />
+  <param name="portamento" value="1" />
+  <param name="vel2amp" value="0" />
+  <param name="vel2filter" value="0.5" />
+</preset>
+<preset bank="0" program="0" plugin="monosynth" name="Cut Through Bass">
+  <param name="o1_wave" value="1" />
+  <param name="o2_wave" value="1" />
+  <param name="o12_detune" value="18.0793" />
+  <param name="o2_xpose" value="0" />
+  <param name="phase_mode" value="1" />
+  <param name="o12_mix" value="0.5" />
+  <param name="filter" value="2" />
+  <param name="cutoff" value="88.9763" />
+  <param name="res" value="2" />
+  <param name="filter_sep" value="640.487" />
+  <param name="env2cutoff" value="8000" />
+  <param name="env2res" value="1" />
+  <param name="adsr_a" value="1" />
+  <param name="adsr_d" value="350" />
+  <param name="adsr_s" value="0.166667" />
+  <param name="adsr_r" value="63.9728" />
+  <param name="key_follow" value="1" />
+  <param name="legato" value="0" />
+  <param name="portamento" value="1" />
+  <param name="vel2amp" value="1" />
+  <param name="vel2filter" value="1" />
+</preset>
+<preset bank="0" program="0" plugin="monosynth" name="Fat Cats">
+  <param name="o1_wave" value="0" />
+  <param name="o2_wave" value="2" />
+  <param name="o12_detune" value="9.26552" />
+  <param name="o2_xpose" value="0" />
+  <param name="phase_mode" value="5" />
+  <param name="o12_mix" value="0.5" />
+  <param name="filter" value="1" />
+  <param name="cutoff" value="159.315" />
+  <param name="res" value="4.42802" />
+  <param name="filter_sep" value="1212.42" />
+  <param name="env2cutoff" value="8000" />
+  <param name="env2res" value="1" />
+  <param name="env2amp" value="1" />
+  <param name="adsr_a" value="736.806" />
+  <param name="adsr_d" value="10" />
+  <param name="adsr_s" value="1" />
+  <param name="adsr_r" value="162.197" />
+  <param name="key_follow" value="1" />
+  <param name="legato" value="3" />
+  <param name="portamento" value="167.215" />
+  <param name="vel2filter" value="1" />
+  <param name="vel2amp" value="0" />
+</preset>
+<preset bank="0" program="0" plugin="monosynth" name="Twinkle">
+  <param name="o1_wave" value="4" />
+  <param name="o2_wave" value="3" />
+  <param name="o12_detune" value="0.60614" />
+  <param name="o2_xpose" value="24" />
+  <param name="phase_mode" value="1" />
+  <param name="o12_mix" value="0.5" />
+  <param name="filter" value="2" />
+  <param name="cutoff" value="1170.34" />
+  <param name="res" value="0.7" />
+  <param name="filter_sep" value="-1202.13" />
+  <param name="env2cutoff" value="3841.02" />
+  <param name="env2res" value="1" />
+  <param name="env2amp" value="1" />
+  <param name="adsr_a" value="1" />
+  <param name="adsr_d" value="108.852" />
+  <param name="adsr_s" value="0.0176431" />
+  <param name="adsr_r" value="91.6363" />
+  <param name="key_follow" value="1" />
+  <param name="legato" value="2" />
+  <param name="portamento" value="12.5992" />
+  <param name="vel2filter" value="0" />
+  <param name="vel2amp" value="1" />
+</preset>
+</presets>
\ No newline at end of file
diff --git a/src/Makefile.am b/src/Makefile.am
index 4d535af..cc12308 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -44,10 +44,10 @@ endif
 calfbenchmark_SOURCES = benchmark.cpp
 calfbenchmark_LDADD = 
 
-calf_la_SOURCES = modules.cpp giface.cpp synth.cpp preset.cpp
+calf_la_SOURCES = modules.cpp giface.cpp monosynth.cpp synth.cpp preset.cpp
 calf_la_LDFLAGS = -rpath $(ladspadir) -avoid-version -module -lexpat
 
-libcalfstatic_la_SOURCES = modules.cpp giface.cpp synth.cpp preset.cpp
+libcalfstatic_la_SOURCES = modules.cpp giface.cpp monosynth.cpp synth.cpp preset.cpp
 libcalfstatic_la_LDFLAGS = -static -lexpat
 
 libcalfgui_la_SOURCES = gui.cpp preset_gui.cpp
diff --git a/src/calf/modules_synths.h b/src/calf/modules_synths.h
index b20eda3..329fa35 100644
--- a/src/calf/modules_synths.h
+++ b/src/calf/modules_synths.h
@@ -35,7 +35,7 @@ namespace synth {
 class monosynth_audio_module: public null_audio_module
 {
 public:
-    enum { wave_saw, wave_sqr, wave_pulse, wave_sine, wave_triangle, wave_varistep, wave_skewsaw, wave_skewsqr, wave_count };
+    enum { wave_saw, wave_sqr, wave_pulse, wave_sine, wave_triangle, wave_varistep, wave_skewsaw, wave_skewsqr, wave_test1, wave_test2, wave_test3, wave_test4, wave_test5, wave_test6, wave_test7, wave_test8, 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_envtoamp, par_attack, par_decay, par_sustain, par_release, par_keyfollow, par_legato, par_portamento, par_vel2filter, par_vel2amp, param_count };
     enum { in_count = 0, out_count = 2, support_midi = true, rt_capable = true };
@@ -64,69 +64,8 @@ public:
     synth::adsr envelope;
     
     static parameter_properties param_props[];
-    void set_sample_rate(uint32_t sr) {
-        srate = sr;
-        crate = sr / step_size;
-        odcr = (float)(1.0 / crate);
-        phaseshifter.set_ap(1000.f, sr);
-        fgain = 0.f;
-        fgain_delta = 0.f;
-    }
-    void delayed_note_on()
-    {
-        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 (legato >= 2)
-                porta_time = -1.f;
-            osc1.reset();
-            osc2.reset();
-            filter.reset();
-            filter2.reset();
-            switch((int)*params[par_oscmode])
-            {
-            case 1:
-                osc2.phase = 0x80000000;
-                break;
-            case 2:
-                osc2.phase = 0x40000000;
-                break;
-            case 3:
-                osc1.phase = osc2.phase = 0x40000000;
-                break;
-            case 4:
-                osc1.phase = 0x40000000;
-                osc2.phase = 0xC0000000;
-                break;
-            case 5:
-                // rand() is crap, but I don't have any better RNG in Calf yet
-                osc1.phase = rand() << 16;
-                osc2.phase = rand() << 16;
-                break;
-            default:
-                break;
-            }
-            envelope.note_on();
-            running = true;
-        }
-        if (legato >= 2 && !gate)
-            porta_time = -1.f;
-        gate = true;
-        stopping = false;
-        if (!(legato & 1) || envelope.released()) {
-            envelope.note_on();
-        }
-        envelope.advance();
-        queue_note_on = -1;
-    }
+    void set_sample_rate(uint32_t sr);
+    void delayed_note_on();
     void note_on(int note, int vel)
     {
         queue_note_on = note;
@@ -140,11 +79,11 @@ public:
             envelope.note_off();
         }
     }
-    void pitch_bend(int value)
+    inline void pitch_bend(int value)
     {
         pitchbend = pow(2.0, value / 8192.0);
     }
-    void set_frequency()
+    inline void set_frequency()
     {
         osc1.set_freq(freq * (2 - detune) * pitchbend, srate);
         osc2.set_freq(freq * (detune)  * pitchbend * xpose, srate);
@@ -163,62 +102,8 @@ public:
         legato = dsp::fastf2i_drm(*params[par_legato]);
         set_frequency();
     }
-    void activate() {
-        running = false;
-        output_pos = 0;
-        queue_note_on = -1;
-        pitchbend = 1.f;
-        filter.reset();
-        filter2.reset();
-        float data[2048];
-        bandlimiter<11> bl;
-
-        // yes these waves don't have really perfect 1/x spectrum because of aliasing
-        // (so what?)
-        for (int i = 0 ; i < 1024; i++)
-            data[i] = (float)(i / 1024.f),
-            data[i + 1024] = (float)(i / 1024.f - 1.0f);
-        waves[wave_saw].make(bl, data);
-
-        for (int i = 0 ; i < 2048; i++)
-            data[i] = (float)(i < 1024 ? -1.f : 1.f);
-        waves[wave_sqr].make(bl, data);
-
-        for (int i = 0 ; i < 2048; i++)
-            data[i] = (float)(i < 64 ? -1.f : 1.f);
-        waves[wave_pulse].make(bl, data);
-
-        // XXXKF sure this is a waste of space, this will be fixed some day by better bandlimiter
-        for (int i = 0 ; i < 2048; i++)
-            data[i] = (float)sin(i * PI / 1024);
-        waves[wave_sine].make(bl, data);
-
-        for (int i = 0 ; i < 512; i++) {
-            data[i] = i / 512.0,
-            data[i + 512] = 1 - i / 512.0,
-            data[i + 1024] = - i / 512.0,
-            data[i + 1536] = -1 + i / 512.0;
-        }
-        waves[wave_triangle].make(bl, data);
-        
-        for (int i = 0, j = 1; i < 2048; i++) {
-            data[i] = -1 + j / 1024.0;
-            if (i == j)
-                j *= 2;
-        }
-        waves[wave_varistep].make(bl, data);
-
-        for (int i = 0; i < 2048; i++) {
-            data[i] = (min(1.f, (float)(i / 64.f))) * (-1 + fmod (i * i / 8192.0, 2.0));
-        }
-        waves[wave_skewsaw].make(bl, data);
-        for (int i = 0; i < 2048; i++) {
-            data[i] = (min(1.f, (float)(i / 64.f))) * (fmod (i * i / 2048.0, 2.0) < 1.0 ? -1.0 : +1.0);
-        }
-        waves[wave_skewsqr].make(bl, data);
-    }
-    void deactivate() {
-    }
+    void activate();
+    void deactivate() {}
     inline float softclip(float wave) const
     {
         float abswave = fabs(wave);
@@ -231,154 +116,14 @@ public:
         }
         return wave;
     }
-    void calculate_buffer_ser()
-    {
-        for (uint32_t i = 0; i < step_size; i++) 
-        {
-            float osc1val = osc1.get();
-            float osc2val = osc2.get();
-            float wave = fgain * (osc1val + (osc2val - osc1val) * xfade);
-            wave = filter.process_d1(wave);
-            wave = filter2.process_d1(wave);
-            buffer[i] = softclip(wave);
-            fgain += fgain_delta;
-        }
-    }
-    void calculate_buffer_single()
-    {
-        for (uint32_t i = 0; i < step_size; i++) 
-        {
-            float osc1val = osc1.get();
-            float osc2val = osc2.get();
-            float wave = fgain * (osc1val + (osc2val - osc1val) * xfade);
-            wave = filter.process_d1(wave);
-            buffer[i] = softclip(wave);
-            fgain += fgain_delta;
-        }
-    }
-    void calculate_buffer_stereo()
-    {
-        for (uint32_t i = 0; i < step_size; i++) 
-        {
-            float osc1val = osc1.get();
-            float osc2val = osc2.get();
-            float wave1 = osc1val + (osc2val - osc1val) * xfade;
-            float wave2 = phaseshifter.process_ap(wave1);
-            buffer[i] = softclip(fgain * filter.process_d1(wave1));
-            buffer2[i] = softclip(fgain * filter2.process_d1(wave2));
-            fgain += fgain_delta;
-        }
-    }
-    bool is_stereo_filter() const
+    void calculate_buffer_ser();
+    void calculate_buffer_single();
+    void calculate_buffer_stereo();
+    inline bool is_stereo_filter() const
     {
         return filter_type == flt_2lp12 || filter_type == flt_2bp6;
     }
-    void calculate_step() {
-        if (queue_note_on != -1)
-            delayed_note_on();
-        else if (stopping)
-        {
-            running = false;
-            dsp::zero(buffer, step_size);
-            if (is_stereo_filter())
-                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();
-        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;
-        cutoff = dsp::clip(cutoff , 10.f, 18000.f);
-        float resonance = *params[par_resonance];
-        float e2r = *params[par_envtores];
-        float e2a = *params[par_envtoamp];
-        resonance = resonance * (1 - e2r) + (0.7 + (resonance - 0.7) * env * env) * e2r;
-        float cutoff2 = dsp::clip(cutoff * separation, 10.f, 18000.f);
-        float newfgain = 0.f;
-        switch(filter_type)
-        {
-        case flt_lp12:
-            filter.set_lp_rbj(cutoff, resonance, srate);
-            newfgain = min(0.7f, 0.7f / resonance) * ampctl;
-            break;
-        case flt_hp12:
-            filter.set_hp_rbj(cutoff, resonance, srate);
-            newfgain = min(0.7f, 0.7f / resonance) * ampctl;
-            break;
-        case flt_lp24:
-            filter.set_lp_rbj(cutoff, resonance, srate);
-            filter2.set_lp_rbj(cutoff2, resonance, srate);
-            newfgain = min(0.5f, 0.5f / resonance) * ampctl;
-            break;
-        case flt_lpbr:
-            filter.set_lp_rbj(cutoff, resonance, srate);
-            filter2.set_br_rbj(cutoff2, resonance, srate);
-            newfgain = min(0.5f, 0.5f / resonance) * ampctl;        
-            break;
-        case flt_hpbr:
-            filter.set_hp_rbj(cutoff, resonance, srate);
-            filter2.set_br_rbj(cutoff2, resonance, srate);
-            newfgain = min(0.5f, 0.5f / resonance) * ampctl;        
-            break;
-        case flt_2lp12:
-            filter.set_lp_rbj(cutoff, resonance, srate);
-            filter2.set_lp_rbj(cutoff2, resonance, srate);
-            newfgain = min(0.7f, 0.7f / resonance) * ampctl;
-            break;
-        case flt_bp6:
-            filter.set_bp_rbj(cutoff, resonance, srate);
-            newfgain = ampctl;
-            break;
-        case flt_2bp6:
-            filter.set_bp_rbj(cutoff, resonance, srate);
-            filter2.set_bp_rbj(cutoff2, resonance, srate);
-            newfgain = ampctl;        
-            break;
-        }
-        newfgain *= 1.0 - (1.0 - env) * e2a;
-        fgain_delta = (newfgain - fgain) * (1.0 / step_size);
-        switch(filter_type)
-        {
-        case flt_lp24:
-        case flt_lpbr:
-        case flt_hpbr: // Oomek's wish
-            calculate_buffer_ser();
-            break;
-        case flt_lp12:
-        case flt_hp12:
-        case flt_bp6:
-            calculate_buffer_single();
-            break;
-        case flt_2lp12:
-        case flt_2bp6:
-            calculate_buffer_stereo();
-            break;
-        }
-        if (envelope.state == adsr::STOP)
-        {
-            for (int i = 0; i < step_size; i++)
-                buffer[i] *= (step_size - i) * (1.0f / step_size);
-            if (is_stereo_filter())
-                for (int i = 0; i < step_size; i++)
-                    buffer2[i] *= (step_size - i) * (1.0f / step_size);
-            stopping = true;
-        }
-    }
+    void calculate_step();
     uint32_t process(uint32_t offset, uint32_t nsamples, uint32_t inputs_mask, uint32_t outputs_mask) {
         if (!running && queue_note_on == -1)
             return 0;
diff --git a/src/calf/synth.h b/src/calf/synth.h
index 7df5b97..eb0bbb4 100644
--- a/src/calf/synth.h
+++ b/src/calf/synth.h
@@ -166,17 +166,18 @@ public:
     
     env_state state;
     // note: these are *rates*, not times
-    double attack, decay, sustain, release;
-    double value, thisrelease, releasemul;
+    double attack, decay, sustain, release, release_time;
+    double value, thisrelease, thiss;
     
     adsr()
     {
-        attack = decay = sustain = release = thisrelease = releasemul = 0.f;
+        attack = decay = sustain = release = thisrelease = thiss = 0.f;
         reset();
     }
     inline void reset()
     {
         value = 0.f;
+        thiss = 0.f;
         state = STOP;
     }
     inline void set(float a, float d, float s, float r, float er)
@@ -184,8 +185,14 @@ public:
         attack = 1.0 / (a * er);
         decay = (1 - s) / (d * er);
         sustain = s;
-        release = s / (r * er);
-        thisrelease = releasemul * release;
+        release_time = r * er;
+        release = s / release_time;
+        // in release:
+        // lock thiss setting (start of release for current note) and unlock thisrelease setting (current note's release rate)
+        if (state != RELEASE)
+            thiss = s;
+        else
+            thisrelease = thiss / release_time;
     }
     inline bool released()
     {
@@ -194,19 +201,22 @@ public:
     inline void note_on()
     {
         state = ATTACK;
+        thiss = sustain;
     }
     inline void note_off()
     {
         if (state == STOP)
             return;
-        if (sustain > 0)
-            releasemul = value / sustain;
-        else
-            releasemul = 1.f;
-        thisrelease = releasemul * release;
-        if (value > sustain && decay > thisrelease)
+        thiss = std::max(sustain, value);
+        thisrelease = thiss / release_time;
+        // we're in attack or decay, and if decay is faster than release
+        if (value > sustain && decay > thisrelease) {
+            // use standard release time later (because we'll be switching at sustain point)
+            thisrelease = release;
             state = LOCKDECAY;
-        else {
+        } else {
+            // in attack/decay, but use fixed release time
+            // in case value fell below sustain, assume it didn't (for the purpose of calculating release rate only)
             state = RELEASE;
         }
     }
@@ -237,7 +247,6 @@ public:
                     value = 0.f;
                 state = RELEASE;
                 thisrelease = release;
-                releasemul = 1.f;
             }
             break;
         case SUSTAIN:
diff --git a/src/modules.cpp b/src/modules.cpp
index 3dfb323..80756fa 100644
--- a/src/modules.cpp
+++ b/src/modules.cpp
@@ -171,53 +171,6 @@ static synth::ladspa_wrapper<organ_audio_module> organ(organ_info);
 #endif
 ////////////////////////////////////////////////////////////////////////////
 
-const char *monosynth_audio_module::port_names[] = {
-    "Out L", "Out R", 
-};
-
-const char *monosynth_waveform_names[] = { "Sawtooth", "Square", "Pulse", "Sine", "Triangle", "Varistep", "Skewed Saw", "Skewed Square" };
-const char *monosynth_mode_names[] = { "0 : 0", "0 : 180", "0 : 90", "90 : 90", "90 : 270", "Random" };
-const char *monosynth_legato_names[] = { "Retrig", "Legato", "Fng Retrig", "Fng Legato" };
-
-const char *monosynth_filter_choices[] = {
-    "12dB/oct Lowpass",
-    "24dB/oct Lowpass",
-    "2x12dB/oct Lowpass",
-    "12dB/oct Highpass",
-    "Lowpass+Notch",
-    "Highpass+Notch",
-    "6dB/oct Bandpass",
-    "2x6dB/oct Bandpass",
-};
-
-parameter_properties monosynth_audio_module::param_props[] = {
-    { wave_saw,         0, wave_count - 1, 1, PF_ENUM | PF_CTL_COMBO, monosynth_waveform_names, "o1_wave", "Osc1 Wave" },
-    { wave_sqr,         0, wave_count - 1, 1, PF_ENUM | PF_CTL_COMBO, monosynth_waveform_names, "o2_wave", "Osc2 Wave" },
-    { 10,         0,  100, 1.01, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "o12_detune", "O1<>2 Detune" },
-    { 12,       -24,   24, 1.01, PF_INT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_SEMITONES, NULL, "o2_xpose", "Osc 2 transpose" },
-    { 0,          0,    5, 1.01, PF_ENUM | PF_CTL_COMBO, monosynth_mode_names, "phase_mode", "Phase mode" },
-    { 0.5,        0,    1, 1.01, PF_FLOAT | PF_SCALE_PERC, NULL, "o12_mix", "O1<>2 Mix" },
-    { 1,          0,    7, 1.01, PF_ENUM | PF_CTL_COMBO, monosynth_filter_choices, "filter", "Filter" },
-    { 33,        10,16000, 1.01, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "cutoff", "Cutoff" },
-    { 2,        0.7,    8, 1.01, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB, NULL, "res", "Resonance" },
-    { 0,      -2400, 2400, 1.01, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "filter_sep", "Separation" },
-    { 8000,  -10800,10800, 1.01, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "env2cutoff", "Env->Cutoff" },
-    { 1,          0,    1, 1.01, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "env2res", "Env->Res" },
-    { 1,          0,    1, 1.01, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "env2amp", "Env->Amp" },
-    
-    { 1,          1,20000, 1.01, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "adsr_a", "Attack" },
-    { 350,       10,20000, 1.01, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "adsr_d", "Decay" },
-    { 0.5,        0,    1, 1.01, PF_FLOAT | PF_SCALE_PERC, NULL, "adsr_s", "Sustain" },
-    { 50,       10,20000, 1.01, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "adsr_r", "Release" },
-    
-    { 0,          0,    1, 1.01, PF_BOOL | PF_CTL_TOGGLE, NULL, "key_follow", "Key Follow" },
-    { 0,          0,    3, 1.01, PF_ENUM | PF_CTL_COMBO, monosynth_legato_names, "legato", "Legato Mode" },
-    { 1,          1, 2000, 1.01, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "portamento", "Portamento" },
-    
-    { 0.5,        0,    1,  0.1, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "vel2filter", "Vel->Filter" },
-    { 0,          0,    1,  0.1, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "vel2amp", "Vel->Amp" },
-};
-
 static synth::ladspa_info monosynth_info = { 0x8480, "Monosynth", "Calf Monosynth", "Krzysztof Foltman", copyright, "SynthesizerPlugin" };
 
 #if USE_LADSPA
diff --git a/src/monosynth.cpp b/src/monosynth.cpp
new file mode 100644
index 0000000..d6024a3
--- /dev/null
+++ b/src/monosynth.cpp
@@ -0,0 +1,376 @@
+/* Calf DSP Library
+ * Example audio modules - monosynth
+ *
+ * Copyright (C) 2001-2007 Krzysztof Foltman
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#include <assert.h>
+#include <memory.h>
+#if USE_JACK
+#include <jack/jack.h>
+#endif
+#include <calf/giface.h>
+#include <calf/modules.h>
+#include <calf/modules_synths.h>
+
+using namespace synth;
+
+const char *monosynth_audio_module::port_names[] = {
+    "Out L", "Out R", 
+};
+
+const char *monosynth_waveform_names[] = { "Sawtooth", "Square", "Pulse", "Sine", "Triangle", "Varistep", "Skewed Saw", "Skewed Square", 
+    "Test 1", "Test 2", "Test 3", "Test 4", "Test 5", "Test 6", "Test 7", "Test 8" };
+const char *monosynth_mode_names[] = { "0 : 0", "0 : 180", "0 : 90", "90 : 90", "90 : 270", "Random" };
+const char *monosynth_legato_names[] = { "Retrig", "Legato", "Fng Retrig", "Fng Legato" };
+
+const char *monosynth_filter_choices[] = {
+    "12dB/oct Lowpass",
+    "24dB/oct Lowpass",
+    "2x12dB/oct Lowpass",
+    "12dB/oct Highpass",
+    "Lowpass+Notch",
+    "Highpass+Notch",
+    "6dB/oct Bandpass",
+    "2x6dB/oct Bandpass",
+};
+
+parameter_properties monosynth_audio_module::param_props[] = {
+    { wave_saw,         0, wave_count - 1, 1, PF_ENUM | PF_CTL_COMBO, monosynth_waveform_names, "o1_wave", "Osc1 Wave" },
+    { wave_sqr,         0, wave_count - 1, 1, PF_ENUM | PF_CTL_COMBO, monosynth_waveform_names, "o2_wave", "Osc2 Wave" },
+    { 10,         0,  100, 1.01, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "o12_detune", "O1<>2 Detune" },
+    { 12,       -24,   24, 1.01, PF_INT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_SEMITONES, NULL, "o2_xpose", "Osc 2 transpose" },
+    { 0,          0,    5, 1.01, PF_ENUM | PF_CTL_COMBO, monosynth_mode_names, "phase_mode", "Phase mode" },
+    { 0.5,        0,    1, 1.01, PF_FLOAT | PF_SCALE_PERC, NULL, "o12_mix", "O1<>2 Mix" },
+    { 1,          0,    7, 1.01, PF_ENUM | PF_CTL_COMBO, monosynth_filter_choices, "filter", "Filter" },
+    { 33,        10,16000, 1.01, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "cutoff", "Cutoff" },
+    { 2,        0.7,    8, 1.01, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB, NULL, "res", "Resonance" },
+    { 0,      -2400, 2400, 1.01, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "filter_sep", "Separation" },
+    { 8000,  -10800,10800, 1.01, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "env2cutoff", "Env->Cutoff" },
+    { 1,          0,    1, 1.01, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "env2res", "Env->Res" },
+    { 1,          0,    1, 1.01, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "env2amp", "Env->Amp" },
+    
+    { 1,          1,20000, 1.01, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "adsr_a", "Attack" },
+    { 350,       10,20000, 1.01, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "adsr_d", "Decay" },
+    { 0.5,        0,    1, 1.01, PF_FLOAT | PF_SCALE_PERC, NULL, "adsr_s", "Sustain" },
+    { 50,       10,20000, 1.01, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "adsr_r", "Release" },
+    
+    { 0,          0,    1, 1.01, PF_BOOL | PF_CTL_TOGGLE, NULL, "key_follow", "Key Follow" },
+    { 0,          0,    3, 1.01, PF_ENUM | PF_CTL_COMBO, monosynth_legato_names, "legato", "Legato Mode" },
+    { 1,          1, 2000, 1.01, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "portamento", "Portamento" },
+    
+    { 0.5,        0,    1,  0.1, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "vel2filter", "Vel->Filter" },
+    { 0,          0,    1,  0.1, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "vel2amp", "Vel->Amp" },
+};
+
+void monosynth_audio_module::activate() {
+    running = false;
+    output_pos = 0;
+    queue_note_on = -1;
+    pitchbend = 1.f;
+    filter.reset();
+    filter2.reset();
+    float data[2048];
+    bandlimiter<11> bl;
+
+    // yes these waves don't have really perfect 1/x spectrum because of aliasing
+    // (so what?)
+    for (int i = 0 ; i < 1024; i++)
+        data[i] = (float)(i / 1024.f),
+        data[i + 1024] = (float)(i / 1024.f - 1.0f);
+    waves[wave_saw].make(bl, data);
+
+    for (int i = 0 ; i < 2048; i++)
+        data[i] = (float)(i < 1024 ? -1.f : 1.f);
+    waves[wave_sqr].make(bl, data);
+
+    for (int i = 0 ; i < 2048; i++)
+        data[i] = (float)(i < 64 ? -1.f : 1.f);
+    waves[wave_pulse].make(bl, data);
+
+    // XXXKF sure this is a waste of space, this will be fixed some day by better bandlimiter
+    for (int i = 0 ; i < 2048; i++)
+        data[i] = (float)sin(i * PI / 1024);
+    waves[wave_sine].make(bl, data);
+
+    for (int i = 0 ; i < 512; i++) {
+        data[i] = i / 512.0,
+        data[i + 512] = 1 - i / 512.0,
+        data[i + 1024] = - i / 512.0,
+        data[i + 1536] = -1 + i / 512.0;
+    }
+    waves[wave_triangle].make(bl, data);
+    
+    for (int i = 0, j = 1; i < 2048; i++) {
+        data[i] = -1 + j / 1024.0;
+        if (i == j)
+            j *= 2;
+    }
+    waves[wave_varistep].make(bl, data);
+
+    for (int i = 0; i < 2048; i++) {
+        int ii = (i < 1024) ? i : 2048 - i;
+        
+        data[i] = (min(1.f, (float)(i / 64.f))) * (1.0 - i / 2048.0) * (-1 + fmod (i * ii / 65536.0, 2.0));
+    }
+    waves[wave_skewsaw].make(bl, data);
+    for (int i = 0; i < 2048; i++) {
+        int ii = (i < 1024) ? i : 2048 - i;
+        data[i] = (min(1.f, (float)(i / 64.f))) * (1.0 - i / 2048.0) * (fmod (i * ii / 32768.0, 2.0) < 1.0 ? -1.0 : +1.0);
+    }
+    waves[wave_skewsqr].make(bl, data);
+
+    for (int i = 0; i < 1024; i++) {
+        data[i] = exp(-i / 1024.0);
+        data[i + 1024] = -exp(-i / 1024.0);
+    }
+    waves[wave_test1].make(bl, data);
+    for (int i = 0; i < 2048; i++) {
+        data[i] = exp(-i / 1024.0) * sin(i * PI / 1024) * cos(2 * PI * i / 1024);
+    }
+    waves[wave_test2].make(bl, data);
+    for (int i = 0; i < 2048; i++) {
+        int ii = (i < 1024) ? i : 2048 - i;
+        data[i] = (ii / 1024.0) * sin(i * 15 * PI / 1024 + 2 * PI * sin(i * 18 * PI / 1024)) * sin(i * 12 * PI / 1024 + 2 * PI * sin(i * 11 * PI / 1024));
+    }
+    waves[wave_test3].make(bl, data);
+    for (int i = 0; i < 2048; i++) {
+        data[i] = sin(i * 2 * PI / 1024) * sin(i * 2 * PI / 1024 + 0.5 * PI * sin(i * 18 * PI / 1024)) * sin(i * 1 * PI / 1024 + 0.5 * PI * sin(i * 11 * PI / 1024));
+    }
+    waves[wave_test4].make(bl, data);
+    for (int i = 0; i < 2048; i++) {
+        data[i] = sin(i * 2 * PI / 1024 + 0.2 * PI * sin(i * 13 * PI / 1024)) * sin(i * PI / 1024 + 0.2 * PI * sin(i * 15 * PI / 1024));
+    }
+    waves[wave_test5].make(bl, data);
+    waves[wave_test6].make(bl, data);
+    waves[wave_test7].make(bl, data);
+    waves[wave_test8].make(bl, data);
+}
+
+void monosynth_audio_module::calculate_buffer_ser()
+{
+    for (uint32_t i = 0; i < step_size; i++) 
+    {
+        float osc1val = osc1.get();
+        float osc2val = osc2.get();
+        float wave = fgain * (osc1val + (osc2val - osc1val) * xfade);
+        wave = filter.process_d1(wave);
+        wave = filter2.process_d1(wave);
+        buffer[i] = softclip(wave);
+        fgain += fgain_delta;
+    }
+}
+
+void monosynth_audio_module::calculate_buffer_single()
+{
+    for (uint32_t i = 0; i < step_size; i++) 
+    {
+        float osc1val = osc1.get();
+        float osc2val = osc2.get();
+        float wave = fgain * (osc1val + (osc2val - osc1val) * xfade);
+        wave = filter.process_d1(wave);
+        buffer[i] = softclip(wave);
+        fgain += fgain_delta;
+    }
+}
+
+void monosynth_audio_module::calculate_buffer_stereo()
+{
+    for (uint32_t i = 0; i < step_size; i++) 
+    {
+        float osc1val = osc1.get();
+        float osc2val = osc2.get();
+        float wave1 = osc1val + (osc2val - osc1val) * xfade;
+        float wave2 = phaseshifter.process_ap(wave1);
+        buffer[i] = softclip(fgain * filter.process_d1(wave1));
+        buffer2[i] = softclip(fgain * filter2.process_d1(wave2));
+        fgain += fgain_delta;
+    }
+}
+
+void monosynth_audio_module::delayed_note_on()
+{
+    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 (legato >= 2)
+            porta_time = -1.f;
+        osc1.reset();
+        osc2.reset();
+        filter.reset();
+        filter2.reset();
+        switch((int)*params[par_oscmode])
+        {
+        case 1:
+            osc2.phase = 0x80000000;
+            break;
+        case 2:
+            osc2.phase = 0x40000000;
+            break;
+        case 3:
+            osc1.phase = osc2.phase = 0x40000000;
+            break;
+        case 4:
+            osc1.phase = 0x40000000;
+            osc2.phase = 0xC0000000;
+            break;
+        case 5:
+            // rand() is crap, but I don't have any better RNG in Calf yet
+            osc1.phase = rand() << 16;
+            osc2.phase = rand() << 16;
+            break;
+        default:
+            break;
+        }
+        envelope.note_on();
+        running = true;
+    }
+    if (legato >= 2 && !gate)
+        porta_time = -1.f;
+    gate = true;
+    stopping = false;
+    if (!(legato & 1) || envelope.released()) {
+        envelope.note_on();
+    }
+    envelope.advance();
+    queue_note_on = -1;
+}
+
+void monosynth_audio_module::set_sample_rate(uint32_t sr) {
+    srate = sr;
+    crate = sr / step_size;
+    odcr = (float)(1.0 / crate);
+    phaseshifter.set_ap(1000.f, sr);
+    fgain = 0.f;
+    fgain_delta = 0.f;
+}
+
+void monosynth_audio_module::calculate_step()
+{
+    if (queue_note_on != -1)
+        delayed_note_on();
+    else if (stopping)
+    {
+        running = false;
+        dsp::zero(buffer, step_size);
+        if (is_stereo_filter())
+            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();
+    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;
+    cutoff = dsp::clip(cutoff , 10.f, 18000.f);
+    float resonance = *params[par_resonance];
+    float e2r = *params[par_envtores];
+    float e2a = *params[par_envtoamp];
+    resonance = resonance * (1 - e2r) + (0.7 + (resonance - 0.7) * env * env) * e2r;
+    float cutoff2 = dsp::clip(cutoff * separation, 10.f, 18000.f);
+    float newfgain = 0.f;
+    switch(filter_type)
+    {
+    case flt_lp12:
+        filter.set_lp_rbj(cutoff, resonance, srate);
+        newfgain = min(0.7f, 0.7f / resonance) * ampctl;
+        break;
+    case flt_hp12:
+        filter.set_hp_rbj(cutoff, resonance, srate);
+        newfgain = min(0.7f, 0.7f / resonance) * ampctl;
+        break;
+    case flt_lp24:
+        filter.set_lp_rbj(cutoff, resonance, srate);
+        filter2.set_lp_rbj(cutoff2, resonance, srate);
+        newfgain = min(0.5f, 0.5f / resonance) * ampctl;
+        break;
+    case flt_lpbr:
+        filter.set_lp_rbj(cutoff, resonance, srate);
+        filter2.set_br_rbj(cutoff2, resonance, srate);
+        newfgain = min(0.5f, 0.5f / resonance) * ampctl;        
+        break;
+    case flt_hpbr:
+        filter.set_hp_rbj(cutoff, resonance, srate);
+        filter2.set_br_rbj(cutoff2, resonance, srate);
+        newfgain = min(0.5f, 0.5f / resonance) * ampctl;        
+        break;
+    case flt_2lp12:
+        filter.set_lp_rbj(cutoff, resonance, srate);
+        filter2.set_lp_rbj(cutoff2, resonance, srate);
+        newfgain = min(0.7f, 0.7f / resonance) * ampctl;
+        break;
+    case flt_bp6:
+        filter.set_bp_rbj(cutoff, resonance, srate);
+        newfgain = ampctl;
+        break;
+    case flt_2bp6:
+        filter.set_bp_rbj(cutoff, resonance, srate);
+        filter2.set_bp_rbj(cutoff2, resonance, srate);
+        newfgain = ampctl;        
+        break;
+    }
+    newfgain *= 1.0 - (1.0 - env) * e2a;
+    fgain_delta = (newfgain - fgain) * (1.0 / step_size);
+    switch(filter_type)
+    {
+    case flt_lp24:
+    case flt_lpbr:
+    case flt_hpbr: // Oomek's wish
+        calculate_buffer_ser();
+        break;
+    case flt_lp12:
+    case flt_hp12:
+    case flt_bp6:
+        calculate_buffer_single();
+        break;
+    case flt_2lp12:
+    case flt_2bp6:
+        calculate_buffer_stereo();
+        break;
+    }
+    if (envelope.state == adsr::STOP)
+    {
+        for (int i = 0; i < step_size; i++)
+            buffer[i] *= (step_size - i) * (1.0f / step_size);
+        if (is_stereo_filter())
+            for (int i = 0; i < step_size; i++)
+                buffer2[i] *= (step_size - i) * (1.0f / step_size);
+        stopping = true;
+    }
+}

-- 
calf audio plugins packaging



More information about the pkg-multimedia-commits mailing list