[SCM] calf/master: + Monosynth: added LFO-based PWM

js at users.alioth.debian.org js at users.alioth.debian.org
Tue May 7 15:39:17 UTC 2013


The following commit has been merged in the master branch:
commit 6630872c2cc3dfeef45842eb5733efe6c56c8c2b
Author: Krzysztof Foltman <wdev at foltman.com>
Date:   Tue Feb 3 23:45:41 2009 +0000

    + Monosynth: added LFO-based PWM

diff --git a/gui/gui-monosynth.xml b/gui/gui-monosynth.xml
index cf26686..f8aada4 100644
--- a/gui/gui-monosynth.xml
+++ b/gui/gui-monosynth.xml
@@ -85,14 +85,19 @@
         <value param="lfo_delay"/>
       </vbox>
       <vbox>
-        <label param="lfo_filter"/>
-        <knob param="lfo_filter" type="1"/>
-        <value param="lfo_filter"/>
+        <label param="lfo2filter"/>
+        <knob param="lfo2filter" type="1"/>
+        <value param="lfo2filter"/>
       </vbox>
       <vbox>
-        <label param="lfo_pitch"/>
-        <knob param="lfo_pitch"/>
-        <value param="lfo_pitch"/>
+        <label param="lfo2pitch"/>
+        <knob param="lfo2pitch"/>
+        <value param="lfo2pitch"/>
+      </vbox>
+      <vbox>
+        <label param="lfo2pw"/>
+        <knob param="lfo2pw"/>
+        <value param="lfo2pw"/>
       </vbox>
     </hbox>
   </frame>
diff --git a/src/calf/metadata.h b/src/calf/metadata.h
index 4b857bb..81bb0e6 100644
--- a/src/calf/metadata.h
+++ b/src/calf/metadata.h
@@ -99,7 +99,7 @@ struct monosynth_metadata: public plugin_metadata<monosynth_metadata>
     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, par_master, 
-        par_lforate, par_lfodelay, par_lfofilter, par_lfopitch,
+        par_lforate, par_lfodelay, par_lfofilter, par_lfopitch, par_lfopw,
         param_count };
     enum { in_count = 0, out_count = 2, support_midi = true, require_midi = true, rt_capable = true };
     enum { step_size = 64 };
diff --git a/src/calf/modules_synths.h b/src/calf/modules_synths.h
index 5dd6692..712434d 100644
--- a/src/calf/modules_synths.h
+++ b/src/calf/modules_synths.h
@@ -58,7 +58,7 @@ public:
     int wave1, wave2, filter_type, last_filter_type;
     float freq, start_freq, target_freq, cutoff, decay_factor, fgain, fgain_delta, separation;
     float detune, xpose, xfade, pitchbend, ampctl, fltctl, queue_vel;
-    float odcr, porta_time, lfo_bend, lfo_clock;
+    float odcr, porta_time, lfo_bend, lfo_clock, last_lfov;
     int queue_note_on, stop_count;
     int legato;
     dsp::adsr envelope;
@@ -108,11 +108,13 @@ public:
     {
         precalculate_waves(progress_report);
     }
-    /// Run oscillators and two filters in series to produce mono output samples.
+    /// Run oscillators
+    void calculate_buffer_oscs(float lfo);
+    /// Run two filters in series to produce mono output samples.
     void calculate_buffer_ser();
-    /// Run oscillators and just one filter to produce mono output samples.
+    /// Run one filter to produce mono output samples.
     void calculate_buffer_single();
-    /// Run oscillators and two filters (one per channel) to produce stereo output samples.
+    /// Run two filters (one per channel) to produce stereo output samples.
     void calculate_buffer_stereo();
     /// Retrieve filter graph (which is 'live' so it cannot be generated by get_static_graph), or fall back to get_static_graph.
     bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context);
diff --git a/src/calf/osc.h b/src/calf/osc.h
index dd1eb37..de47ef2 100644
--- a/src/calf/osc.h
+++ b/src/calf/osc.h
@@ -183,11 +183,19 @@ struct waveform_family: public std::map<uint32_t, float *>
         for (unsigned int i = 0; i < cutoff; i++)
             vmax = std::max(vmax, abs(bl.spectrum[i]));
         float vthres = vmax / 1024.0;  // -60dB
+        float cumul = 0.f;
         while(cutoff > (SIZE / limit)) {
             if (!foldover)
             {
-                while(cutoff > 1 && abs(bl.spectrum[cutoff - 1]) < vthres)
+                // skip harmonics too quiet to be heard, but measure their loudness cumulatively,
+                // because even if a single harmonic is too quiet, a whole bunch of them may add up 
+                // to considerable amount of space
+                cumul = 0.f;
+                while(cutoff > 1 && cumul + abs(bl.spectrum[cutoff - 1]) < vthres)
+                {
+                    cumul += abs(bl.spectrum[cutoff - 1]);
                     cutoff--;
+                }
             }
             float *wf = new float[SIZE+1];
             bl.make_waveform(wf, cutoff, foldover);
@@ -233,6 +241,17 @@ struct waveform_oscillator: public simple_oscillator
         phase += phasedelta;
         return value;
     }
+    /// Add/substract two phase-shifted values
+    inline float get_phaseshifted(uint32_t shift, float mix)
+    {
+        uint32_t wpos = phase >> (32 - SIZE_BITS);
+        float value1 = dsp::lerp(waveform[wpos], waveform[(wpos + 1) & MASK], (phase & (SIZE - 1)) * (1.0f / SIZE));
+        wpos = (phase + shift) >> (32 - SIZE_BITS);
+        float value2 = dsp::lerp(waveform[wpos], waveform[(wpos + 1) & MASK], ((phase + shift) & (SIZE - 1)) * (1.0f / SIZE));
+        float value = value1 + mix * value2;
+        phase += phasedelta;
+        return value;
+    }
 };
 
 /**
diff --git a/src/modules.cpp b/src/modules.cpp
index 7d4f188..1bd0a99 100644
--- a/src/modules.cpp
+++ b/src/modules.cpp
@@ -287,8 +287,9 @@ CALF_PORT_PROPS(monosynth) = {
 
     { 5,       0.01, 20,    0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "lfo_rate", "LFO Rate" },
     { 0.5,      0.1,  5,    0, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_SEC, NULL, "lfo_delay", "LFO Delay" },
-    { 0,      -4800, 4800,  0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "lfo_filter", "LFO->Filter" },
-    { 0,          0, 1200,  0, PF_FLOAT | PF_SCALE_QUAD | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "lfo_pitch", "LFO->Pitch" },
+    { 0,      -4800, 4800,  0, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "lfo2filter", "LFO->Filter" },
+    { 0,          0, 1200,  0, PF_FLOAT | PF_SCALE_QUAD | PF_CTL_KNOB | PF_UNIT_CENTS, NULL, "lfo2pitch", "LFO->Pitch" },
+    { 0,          0,    1,  0.1, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL, "lfo2pw", "LFO->PW" },
 };
 
 ////////////////////////////////////////////////////////////////////////////
diff --git a/src/monosynth.cpp b/src/monosynth.cpp
index 77a3ccc..81b6a5c 100644
--- a/src/monosynth.cpp
+++ b/src/monosynth.cpp
@@ -72,9 +72,10 @@ void monosynth_audio_module::precalculate_waves(progress_report_iface *reporter)
         data[i + HS] = (float)(i * 1.0 / HS - 1.0f);
     waves[wave_saw].make(bl, data);
 
+    // this one is dummy, fake and sham, we're using a difference of two sawtooths for square wave due to PWM
     for (int i = 0 ; i < S; i++)
         data[i] = (float)(i < HS ? -1.f : 1.f);
-    waves[wave_sqr].make(bl, data);
+    waves[wave_sqr].make(bl, data, 4);
 
     for (int i = 0 ; i < S; i++)
         data[i] = (float)(i < (64 * S / 2048)? -1.f : 1.f);
@@ -213,13 +214,34 @@ bool monosynth_audio_module::get_graph(int index, int subindex, float *data, int
     return get_static_graph(index, subindex, *params[index], data, points, context);
 }
 
-void monosynth_audio_module::calculate_buffer_ser()
+void monosynth_audio_module::calculate_buffer_oscs(float lfo)
 {
+    uint32_t shift = (int32_t)(0x70000000 * last_lfov * *params[par_lfopw]);
+    int flag1 = (wave1 == wave_sqr);
+    int flag2 = (wave2 == wave_sqr);
+    uint32_t shift_delta = (int32_t)(0x70000000 * (lfo - last_lfov) * *params[par_lfopw] * (1.0 / step_size));
+    
+    uint32_t shift1 = (flag1 << 31) + shift;
+    uint32_t shift2 = (flag2 << 31) + shift;
+    float mix1 = 1 - 2 * flag1, mix2 = 1 - 2 * flag2;
+    
     for (uint32_t i = 0; i < step_size; i++) 
     {
-        float osc1val = osc1.get();
-        float osc2val = osc2.get();
+        float osc1val = osc1.get_phaseshifted(shift1, mix1);
+        float osc2val = osc2.get_phaseshifted(shift2, mix2);
         float wave = fgain * (osc1val + (osc2val - osc1val) * xfade);
+        buffer[i] = wave;
+        shift1 += shift_delta;
+        shift2 += shift_delta;
+    }
+    last_lfov = lfo;
+}
+
+void monosynth_audio_module::calculate_buffer_ser()
+{
+    for (uint32_t i = 0; i < step_size; i++) 
+    {
+        float wave = buffer[i];
         wave = filter.process(wave);
         wave = filter2.process(wave);
         buffer[i] = wave;
@@ -231,9 +253,7 @@ 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);
+        float wave = buffer[i];
         wave = filter.process(wave);
         buffer[i] = wave;
         fgain += fgain_delta;
@@ -244,9 +264,7 @@ 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 wave1 = buffer[i];
         float wave2 = phaseshifter.process_ap(wave1);
         buffer[i] = fgain * filter.process(wave1);
         buffer2[i] = fgain * filter2.process(wave2);
@@ -264,8 +282,8 @@ void monosynth_audio_module::delayed_note_on()
     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);
+    osc1.waveform = waves[wave1 == wave_sqr ? wave_saw : wave1].get_level(osc1.phasedelta);
+    osc2.waveform = waves[wave2 == wave_sqr ? wave_saw : wave2].get_level(osc2.phasedelta);
     if (!osc1.waveform) osc1.waveform = silence;
     if (!osc2.waveform) osc2.waveform = silence;
     lfo_clock = 0.f;
@@ -423,6 +441,7 @@ void monosynth_audio_module::calculate_step()
     if (*params[par_envtoamp] > 0.f)
         newfgain *= 1.0 - (1.0 - aenv) * e2a;
     fgain_delta = (newfgain - fgain) * (1.0 / step_size);
+    calculate_buffer_oscs(lfov);
     switch(filter_type)
     {
     case flt_lp24:

-- 
calf audio plugins packaging



More information about the pkg-multimedia-commits mailing list