[SCM] calf/master: + Monosynth: initial implementation of mod matrix (standalone only, no persistence, few sources/destinations, inefficient)

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


The following commit has been merged in the master branch:
commit f6939cd112c17d50d098bfd4990ab5cc11c399fa
Author: Krzysztof Foltman <wdev at foltman.com>
Date:   Sat Apr 25 23:41:19 2009 +0100

    + Monosynth: initial implementation of mod matrix (standalone only, no persistence, few sources/destinations, inefficient)

diff --git a/gui/gui-monosynth.xml b/gui/gui-monosynth.xml
index c484732..7226e64 100644
--- a/gui/gui-monosynth.xml
+++ b/gui/gui-monosynth.xml
@@ -214,5 +214,8 @@
         </frame>
       </hbox>
     </vbox>
+    <vbox border="10" page="Modulation Matrix">
+        <listview param="scale_detune" />
+    </vbox>
   </notebook>
 </vbox>
diff --git a/src/calf/giface.h b/src/calf/giface.h
index eef4a89..320b04b 100644
--- a/src/calf/giface.h
+++ b/src/calf/giface.h
@@ -232,10 +232,10 @@ struct table_edit_iface
     virtual uint32_t get_table_rows(int param) = 0;
     
     /// retrieve data item from the plugin
-    virtual std::string get_cell(int param, int column) { return calf_utils::i2s(param)+":"+calf_utils::i2s(column); }
+    virtual std::string get_cell(int param, int row, int column) { return calf_utils::i2s(row)+":"+calf_utils::i2s(column); }
 
     /// set data item to the plugin
-    virtual void set_cell(int param, int column, const std::string &src, std::string &error) { error.clear(); }
+    virtual void set_cell(int param, int row, int column, const std::string &src, std::string &error) { error.clear(); }
     
     /// return a line graph interface for a specific parameter/column (unused for now)
     virtual line_graph_iface *get_graph_iface(int param, int column) { return NULL; }
@@ -402,6 +402,9 @@ public:
     /// Handle MIDI Pitch Bend
     /// @param value pitch bend value (-8192 to 8191, defined as in MIDI ie. 8191 = 200 ct by default)
     inline void pitch_bend(int value) {}
+    /// Handle MIDI Channel Pressure
+    /// @param value channel pressure (0 to 127)
+    inline void channel_pressure(int value) {}
     /// Called when params are changed (before processing)
     inline void params_changed() {}
     /// LADSPA-esque activate function, except it is called after ports are connected, not before
diff --git a/src/calf/gui.h b/src/calf/gui.h
index 06d2860..de74547 100644
--- a/src/calf/gui.h
+++ b/src/calf/gui.h
@@ -313,7 +313,7 @@ struct listview_param_control: public param_control, public send_configure_iface
     virtual void get() {}
     virtual void set() {}
     virtual void send_configure(const char *key, const char *value);
-    void update_store(const std::string &data);
+    void update_store();
     static void on_edited(GtkCellRenderer *renderer, gchar *path, gchar *new_text, listview_param_control *pThis);
     static void on_editing_canceled(GtkCellRenderer *renderer, listview_param_control *pThis);
 };
diff --git a/src/calf/jackhost.h b/src/calf/jackhost.h
index 3223eb8..38b7b02 100644
--- a/src/calf/jackhost.h
+++ b/src/calf/jackhost.h
@@ -248,6 +248,9 @@ public:
         case 12:
             Module::program_change(buffer[1]);
             break;
+        case 13:
+            Module::channel_pressure(buffer[1]);
+            break;
         case 14:
             value = buffer[1] + 128 * buffer[2] - 8192;
             Module::pitch_bend(value);
diff --git a/src/calf/metadata.h b/src/calf/metadata.h
index a3ccb32..5b2b22b 100644
--- a/src/calf/metadata.h
+++ b/src/calf/metadata.h
@@ -114,13 +114,11 @@ struct monosynth_metadata: public plugin_metadata<monosynth_metadata>
     };
     enum {
         moddest_none,
-        moddest_amplitude,
+        moddest_attenuation,
         moddest_cutoff,
         moddest_resonance,
         moddest_o1detune,
         moddest_o2detune,
-        moddest_o1pitch,
-        moddest_o2pitch,
         moddest_o1pw,
         moddest_o2pw,
         moddest_count,
diff --git a/src/calf/modules_synths.h b/src/calf/modules_synths.h
index f1ec9ee..bb054e4 100644
--- a/src/calf/modules_synths.h
+++ b/src/calf/modules_synths.h
@@ -35,11 +35,19 @@ namespace calf_plugins {
 
 #define MONOSYNTH_WAVE_BITS 12
     
+struct modulation_entry
+{
+    int src1, src2;
+    float amount;
+    int dest;
+};
+
 /// Monosynth-in-making. Parameters may change at any point, so don't make songs with it!
 /// It lacks inertia for parameters, even for those that really need it.
 class monosynth_audio_module: public audio_module<monosynth_metadata>, public line_graph_iface, public table_edit_iface
 {
 public:
+    enum { mod_matrix_slots = 10 };
     float *ins[in_count]; 
     float *outs[out_count];
     float *params[param_count];
@@ -76,8 +84,18 @@ public:
     dsp::adsr envelope;
     dsp::keystack stack;
     dsp::gain_smoothing master;
+    /// Smoothed cutoff value
     dsp::inertia<dsp::exponential_ramp> inertia_cutoff;
+    /// Smoothed pitch bend value
     dsp::inertia<dsp::exponential_ramp> inertia_pitchbend;
+    /// Smoothed channel pressure value
+    dsp::inertia<dsp::linear_ramp> inertia_pressure;
+    /// Rows of the modulation matrix
+    modulation_entry mod_matrix[mod_matrix_slots];
+    /// Currently used velocity
+    float velocity;
+    /// Current calculated mod matrix outputs
+    float moddest[moddest_count];
      
     monosynth_audio_module();    
     static void precalculate_waves(progress_report_iface *reporter);
@@ -88,6 +106,8 @@ public:
     void note_on(int note, int vel);
     /// Handle MIDI Note Off message
     void note_off(int note, int vel);
+    /// Handle MIDI Channel Pressure
+    void channel_pressure(int value);
     /// Handle pitch bend message.
     inline void pitch_bend(int value)
     {
@@ -99,8 +119,13 @@ public:
         float detune_scaled = (detune - 1); // * log(freq / 440);
         if (*params[par_scaledetune] > 0)
             detune_scaled *= pow(20.0 / freq, *params[par_scaledetune]);
-        osc1.set_freq(freq * (1 - detune_scaled) * inertia_pitchbend.get_last() * lfo_bend, srate);
-        osc2.set_freq(freq * (1 + detune_scaled)  * inertia_pitchbend.get_last() * lfo_bend * xpose, srate);
+        float p1 = 1, p2 = 1;
+        if (moddest[moddest_o1detune] != 0)
+            p1 = pow(2.0, moddest[moddest_o1detune] * (1.0 / 1200.0));
+        if (moddest[moddest_o2detune] != 0)
+            p2 = pow(2.0, moddest[moddest_o2detune] * (1.0 / 1200.0));
+        osc1.set_freq(freq * (1 - detune_scaled) * p1 * inertia_pitchbend.get_last() * lfo_bend, srate);
+        osc2.set_freq(freq * (1 + detune_scaled) * p2 * inertia_pitchbend.get_last() * lfo_bend * xpose, srate);
     }
     /// Handle control change messages.
     void control_change(int controller, int value);
@@ -152,48 +177,15 @@ public:
     bool is_noisy(int param_no) { return param_no != par_cutoff; }
     /// Calculate control signals and produce step_size samples of output.
     void calculate_step();
+    /// Process modulation matrix
+    void calculate_modmatrix(float *modsrc);
     /// Main processing function
-    uint32_t process(uint32_t offset, uint32_t nsamples, uint32_t inputs_mask, uint32_t outputs_mask) {
-        if (!running && queue_note_on == -1) {
-            for (uint32_t i = 0; i < nsamples / step_size; i++)
-                envelope.advance();
-            return 0;
-        }
-        uint32_t op = offset;
-        uint32_t op_end = offset + nsamples;
-        while(op < op_end) {
-            if (output_pos == 0) {
-                if (running || queue_note_on != -1)
-                    calculate_step();
-                else {
-                    envelope.advance();
-                    dsp::zero(buffer, step_size);
-                }
-            }
-            if(op < op_end) {
-                uint32_t ip = output_pos;
-                uint32_t len = std::min(step_size - output_pos, op_end - op);
-                if (is_stereo_filter())
-                    for(uint32_t i = 0 ; i < len; i++) {
-                        float vol = master.get();
-                        outs[0][op + i] = buffer[ip + i] * vol,
-                        outs[1][op + i] = buffer2[ip + i] * vol;
-                    }
-                else
-                    for(uint32_t i = 0 ; i < len; i++)
-                        outs[0][op + i] = outs[1][op + i] = buffer[ip + i] * master.get();
-                op += len;
-                output_pos += len;
-                if (output_pos == step_size)
-                    output_pos = 0;
-            }
-        }
-            
-        return 3;
-    }
+    uint32_t process(uint32_t offset, uint32_t nsamples, uint32_t inputs_mask, uint32_t outputs_mask);
     
     virtual const table_column_info *get_table_columns(int param);
     virtual uint32_t get_table_rows(int param);
+    virtual std::string get_cell(int param, int row, int column);
+    virtual void set_cell(int param, int row, int column, const std::string &src, std::string &error);
 };
 
 struct organ_audio_module: public audio_module<organ_metadata>, public dsp::drawbar_organ, public line_graph_iface
diff --git a/src/gui.cpp b/src/gui.cpp
index f713e38..81a7869 100644
--- a/src/gui.cpp
+++ b/src/gui.cpp
@@ -710,7 +710,7 @@ GtkWidget *listview_param_control::create(plugin_gui *_gui, int _param_no)
     for (int i = 0; i < cols; i++)
         p[i] = G_TYPE_STRING;
     lstore = gtk_list_store_newv(cols, p);
-    update_store("");
+    update_store();
     widget = gtk_tree_view_new_with_model(GTK_TREE_MODEL(lstore));
     delete []p;
     tree = GTK_TREE_VIEW(widget);
@@ -743,7 +743,7 @@ GtkWidget *listview_param_control::create(plugin_gui *_gui, int _param_no)
     return widget;
 }
 
-void listview_param_control::update_store(const std::string &data)
+void listview_param_control::update_store()
 {
     gtk_list_store_clear(lstore);
     uint32_t rows = teif->get_table_rows(param_no);
@@ -753,7 +753,7 @@ void listview_param_control::update_store(const std::string &data)
         gtk_list_store_insert(lstore, &iter, i);
         for (int j = 0; j < cols; j++)
         {
-            gtk_list_store_set(lstore, &iter, j, teif->get_cell(i, j).c_str(), -1);
+            gtk_list_store_set(lstore, &iter, j, teif->get_cell(param_no, i, j).c_str(), -1);
         }
         positions.push_back(iter);
     }
@@ -763,15 +763,28 @@ void listview_param_control::send_configure(const char *key, const char *value)
 {
     if (attribs["key"] == key)
     {
-        update_store(value);
+        update_store();
     }
 }
 
 void listview_param_control::on_edited(GtkCellRenderer *renderer, gchar *path, gchar *new_text, listview_param_control *pThis)
 {
     const table_column_info *tci = pThis->teif->get_table_columns(pThis->param_no);
-    gtk_list_store_set(pThis->lstore, &pThis->positions[atoi(path)], ((table_column_info *)g_object_get_data(G_OBJECT(renderer), "column")) - tci, new_text, -1);
-    gtk_widget_grab_focus(pThis->widget);
+    int column = ((table_column_info *)g_object_get_data(G_OBJECT(renderer), "column")) - tci;
+    string error;
+    pThis->teif->set_cell(pThis->param_no, atoi(path), column, new_text, error);
+    if (error.empty()) {
+        pThis->update_store();
+        gtk_widget_grab_focus(pThis->widget);
+    }
+    else
+    {
+        GtkWidget *dialog = gtk_message_dialog_new(pThis->gui->window->toplevel, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, 
+            "%s", error.c_str());
+        gtk_dialog_run(GTK_DIALOG(dialog));
+        gtk_widget_destroy(dialog);
+        gtk_widget_grab_focus(pThis->widget);
+    }
 }
 
 void listview_param_control::on_editing_canceled(GtkCellRenderer *renderer, listview_param_control *pThis)
diff --git a/src/monosynth.cpp b/src/monosynth.cpp
index 9e66851..e4c858e 100644
--- a/src/monosynth.cpp
+++ b/src/monosynth.cpp
@@ -35,9 +35,17 @@ using namespace std;
 float silence[4097];
 
 monosynth_audio_module::monosynth_audio_module()
-: inertia_cutoff(exponential_ramp(1))
-, inertia_pitchbend(exponential_ramp(1))
+: inertia_cutoff(1)
+, inertia_pitchbend(1)
+, inertia_pressure(64)
 {
+    for (int i = 0; i < mod_matrix_slots; i++)
+    {
+        mod_matrix[i].src1 = modsrc_none;
+        mod_matrix[i].src2 = modsrc_none;
+        mod_matrix[i].amount = 0.f;
+        mod_matrix[i].dest = moddest_none;
+    }
 }
 
 void monosynth_audio_module::activate() {
@@ -50,6 +58,7 @@ void monosynth_audio_module::activate() {
     modwheel_value = 0.f;
     modwheel_value_int = 0;
     inertia_cutoff.set_now(*params[par_cutoff]);
+    inertia_pressure.set_now(0);
     filter.reset();
     filter2.reset();
     stack.clear();
@@ -233,8 +242,8 @@ void monosynth_audio_module::calculate_buffer_oscs(float lfo)
     int flag2 = (wave2 == wave_sqr);
     int32_t shift1 = last_pwshift1;
     int32_t shift2 = last_pwshift2;
-    int32_t shift_target1 = (int32_t)(0x78000000 * dsp::clip11(*params[par_pw1] + lfo * *params[par_lfopw]));
-    int32_t shift_target2 = (int32_t)(0x78000000 * dsp::clip11(*params[par_pw2] + lfo * *params[par_lfopw]));
+    int32_t shift_target1 = (int32_t)(0x78000000 * dsp::clip11(*params[par_pw1] + lfo * *params[par_lfopw] + moddest[moddest_o1pw]));
+    int32_t shift_target2 = (int32_t)(0x78000000 * dsp::clip11(*params[par_pw2] + lfo * *params[par_lfopw] + moddest[moddest_o2pw]));
     int32_t shift_delta1 = ((shift_target1 >> 1) - (last_pwshift1 >> 1)) >> (step_shift - 1);
     int32_t shift_delta2 = ((shift_target2 >> 1) - (last_pwshift2 >> 1)) >> (step_shift - 1);
     last_lfov = lfo;
@@ -313,6 +322,7 @@ 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);
+    velocity = queue_vel;
     ampctl = 1.0 + (queue_vel - 1.0) * *params[par_vel2amp];
     fltctl = 1.0 + (queue_vel - 1.0) * *params[par_vel2filter];
     set_frequency();
@@ -363,6 +373,8 @@ void monosynth_audio_module::delayed_note_on()
     }
     envelope.advance();
     queue_note_on = -1;
+    float modsrc[modsrc_count] = { 1, velocity, inertia_pressure.get_last(), modwheel_value, 0, last_lfov};
+    calculate_modmatrix(modsrc);
 }
 
 void monosynth_audio_module::set_sample_rate(uint32_t sr) {
@@ -376,6 +388,18 @@ void monosynth_audio_module::set_sample_rate(uint32_t sr) {
     inertia_pitchbend.ramp.set_length(crate / 30); // 1/30s    
 }
 
+void monosynth_audio_module::calculate_modmatrix(float *modsrc)
+{
+    for (int i = 0; i < moddest_count; i++)
+        moddest[i] = 0;
+    for (int i = 0; i < mod_matrix_slots; i++)
+    {
+        modulation_entry &slot = mod_matrix[i];
+        if (slot.dest)
+            moddest[slot.dest] += modsrc[slot.src1] * modsrc[slot.src2] * slot.amount;
+    }
+}
+
 void monosynth_audio_module::calculate_step()
 {
     if (queue_note_on != -1)
@@ -413,15 +437,21 @@ void monosynth_audio_module::calculate_step()
     set_frequency();
     envelope.advance();
     float env = envelope.value;
+    
+    // mod matrix
+    // this should be optimized heavily; I think I'll do it when MIDI in Ardour 3 gets stable :>
+    float modsrc[modsrc_count] = { 1, velocity, inertia_pressure.get(), modwheel_value, env, lfov};
+    calculate_modmatrix(modsrc);
+    
     inertia_cutoff.set_inertia(*params[par_cutoff]);
-    cutoff = inertia_cutoff.get() * pow(2.0f, (lfov * *params[par_lfofilter] + env * fltctl * *params[par_envmod]) * (1.f / 1200.f));
+    cutoff = inertia_cutoff.get() * pow(2.0f, (lfov * *params[par_lfofilter] + env * fltctl * *params[par_envmod] + moddest[moddest_cutoff]) * (1.f / 1200.f));
     if (*params[par_keyfollow] > 0.01f)
         cutoff *= pow(freq / 264.f, *params[par_keyfollow]);
     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;
+    resonance = resonance * (1 - e2r) + (0.7 + (resonance - 0.7) * env * env) * e2r + moddest[moddest_resonance];
     float cutoff2 = dsp::clip(cutoff * separation, 10.f, 18000.f);
     float newfgain = 0.f;
     if (filter_type != last_filter_type)
@@ -476,6 +506,8 @@ void monosynth_audio_module::calculate_step()
     float aenv = env;
     if (*params[par_envtoamp] > 0.f)
         newfgain *= 1.0 - (1.0 - aenv) * e2a;
+    if (moddest[moddest_attenuation] != 0.f)
+        newfgain *= dsp::clip<float>(1 - moddest[moddest_attenuation] * moddest[moddest_attenuation], 0.f, 1.f);
     fgain_delta = (newfgain - fgain) * (1.0 / step_size);
     calculate_buffer_oscs(lfov);
     switch(filter_type)
@@ -541,6 +573,10 @@ void monosynth_audio_module::note_off(int note, int vel)
     }
 }
 
+void monosynth_audio_module::channel_pressure(int value)
+{
+    inertia_pressure.set_inertia(value * (1.0 / 127.0));
+}
 
 void monosynth_audio_module::control_change(int controller, int value)
 {
@@ -575,6 +611,45 @@ void monosynth_audio_module::deactivate()
     stack.clear();
 }
 
+uint32_t monosynth_audio_module::process(uint32_t offset, uint32_t nsamples, uint32_t inputs_mask, uint32_t outputs_mask) {
+    if (!running && queue_note_on == -1) {
+        for (uint32_t i = 0; i < nsamples / step_size; i++)
+            envelope.advance();
+        return 0;
+    }
+    uint32_t op = offset;
+    uint32_t op_end = offset + nsamples;
+    while(op < op_end) {
+        if (output_pos == 0) {
+            if (running || queue_note_on != -1)
+                calculate_step();
+            else {
+                envelope.advance();
+                dsp::zero(buffer, step_size);
+            }
+        }
+        if(op < op_end) {
+            uint32_t ip = output_pos;
+            uint32_t len = std::min(step_size - output_pos, op_end - op);
+            if (is_stereo_filter())
+                for(uint32_t i = 0 ; i < len; i++) {
+                    float vol = master.get();
+                    outs[0][op + i] = buffer[ip + i] * vol,
+                    outs[1][op + i] = buffer2[ip + i] * vol;
+                }
+            else
+                for(uint32_t i = 0 ; i < len; i++)
+                    outs[0][op + i] = outs[1][op + i] = buffer[ip + i] * master.get();
+            op += len;
+            output_pos += len;
+            if (output_pos == step_size)
+                output_pos = 0;
+        }
+    }
+        
+    return 3;
+}
+
 static const char *monosynth_mod_src_names[] = {
     "None", 
     "Velocity",
@@ -587,16 +662,11 @@ static const char *monosynth_mod_src_names[] = {
 
 static const char *monosynth_mod_dest_names[] = {
     "None",
-    "Amplitude",
+    "Attenuation",
     "Cutoff",
     "Resonance",
-    "OX: Detune",
     "O1: Detune",
     "O2: Detune",
-    "OX: Pitch",
-    "O1: Pitch",
-    "O2: Pitch",
-    "OX: PW",
     "O1: PW",
     "O2: PW",
     NULL
@@ -617,5 +687,73 @@ const table_column_info *monosynth_audio_module::get_table_columns(int param)
 
 uint32_t monosynth_audio_module::get_table_rows(int param)
 {
-    return 2;
+    return mod_matrix_slots;
 }
+
+std::string monosynth_audio_module::get_cell(int param, int row, int column)
+{
+    assert(row >= 0 && row < mod_matrix_slots);
+    modulation_entry &slot = mod_matrix[row];
+    switch(column) {
+        case 0: // source 1
+            return monosynth_mod_src_names[slot.src1];
+        case 1: // source 2
+            return monosynth_mod_src_names[slot.src2];
+        case 2: // amount
+            return calf_utils::f2s(slot.amount);
+        case 3: // destination
+            return monosynth_mod_dest_names[slot.dest];
+        default: 
+            assert(0);
+            return "";
+    }
+}
+    
+void monosynth_audio_module::set_cell(int param, int row, int column, const std::string &src, std::string &error)
+{
+    assert(row >= 0 && row < mod_matrix_slots);
+    modulation_entry &slot = mod_matrix[row];
+    switch(column) {
+        case 0:
+        case 1:
+        {
+            for (int i = 0; monosynth_mod_src_names[i]; i++)
+            {
+                if (src == monosynth_mod_src_names[i])
+                {
+                    if (column == 0)
+                        slot.src1 = i;
+                    else
+                        slot.src2 = i;
+                    error.clear();
+                    return;
+                }
+            }
+            error = "Invalid source name";
+            return;
+        }
+        case 2:
+        {
+            stringstream ss(src);
+            ss >> slot.amount;
+            error.clear();
+            return;
+        }
+        case 3:
+        {
+            for (int i = 0; monosynth_mod_dest_names[i]; i++)
+            {
+                if (src == monosynth_mod_dest_names[i])
+                {
+                    slot.dest = i;
+                    error.clear();
+                    return;
+                }
+            }
+            error = "Invalid destination name";
+            return;
+        }
+        
+    }
+}
+

-- 
calf audio plugins packaging



More information about the pkg-multimedia-commits mailing list