summaryrefslogtreecommitdiff
path: root/libs/fluidsynth/src/fluid_mod.c
diff options
context:
space:
mode:
Diffstat (limited to 'libs/fluidsynth/src/fluid_mod.c')
-rw-r--r--libs/fluidsynth/src/fluid_mod.c488
1 files changed, 488 insertions, 0 deletions
diff --git a/libs/fluidsynth/src/fluid_mod.c b/libs/fluidsynth/src/fluid_mod.c
new file mode 100644
index 0000000000..5931aa52a6
--- /dev/null
+++ b/libs/fluidsynth/src/fluid_mod.c
@@ -0,0 +1,488 @@
+/* FluidSynth - A Software Synthesizer
+ *
+ * Copyright (C) 2003 Peter Hanappe and others.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+#include "fluid_mod.h"
+#include "fluid_chan.h"
+#include "fluid_voice.h"
+
+/*
+ * fluid_mod_clone
+ */
+void
+fluid_mod_clone(fluid_mod_t* mod, fluid_mod_t* src)
+{
+ mod->dest = src->dest;
+ mod->src1 = src->src1;
+ mod->flags1 = src->flags1;
+ mod->src2 = src->src2;
+ mod->flags2 = src->flags2;
+ mod->amount = src->amount;
+}
+
+/**
+ * Set a modulator's primary source controller and flags.
+ * @param mod Modulator
+ * @param src Modulator source (#fluid_mod_src or a MIDI controller number)
+ * @param flags Flags determining mapping function and whether the source
+ * controller is a general controller (#FLUID_MOD_GC) or a MIDI CC controller
+ * (#FLUID_MOD_CC), see #fluid_mod_flags.
+ */
+void
+fluid_mod_set_source1(fluid_mod_t* mod, int src, int flags)
+{
+ mod->src1 = src;
+ mod->flags1 = flags;
+}
+
+/**
+ * Set a modulator's secondary source controller and flags.
+ * @param mod Modulator
+ * @param src Modulator source (#fluid_mod_src or a MIDI controller number)
+ * @param flags Flags determining mapping function and whether the source
+ * controller is a general controller (#FLUID_MOD_GC) or a MIDI CC controller
+ * (#FLUID_MOD_CC), see #fluid_mod_flags.
+ */
+void
+fluid_mod_set_source2(fluid_mod_t* mod, int src, int flags)
+{
+ mod->src2 = src;
+ mod->flags2 = flags;
+}
+
+/**
+ * Set the destination effect of a modulator.
+ * @param mod Modulator
+ * @param dest Destination generator (#fluid_gen_type)
+ */
+void
+fluid_mod_set_dest(fluid_mod_t* mod, int dest)
+{
+ mod->dest = dest;
+}
+
+/**
+ * Set the scale amount of a modulator.
+ * @param mod Modulator
+ * @param amount Scale amount to assign
+ */
+void
+fluid_mod_set_amount(fluid_mod_t* mod, double amount)
+{
+ mod->amount = (double) amount;
+}
+
+/**
+ * Get the primary source value from a modulator.
+ * @param mod Modulator
+ * @return The primary source value (#fluid_mod_src or a MIDI CC controller value).
+ */
+int
+fluid_mod_get_source1(fluid_mod_t* mod)
+{
+ return mod->src1;
+}
+
+/**
+ * Get primary source flags from a modulator.
+ * @param mod Modulator
+ * @return The primary source flags (#fluid_mod_flags).
+ */
+int
+fluid_mod_get_flags1(fluid_mod_t* mod)
+{
+ return mod->flags1;
+}
+
+/**
+ * Get the secondary source value from a modulator.
+ * @param mod Modulator
+ * @return The secondary source value (#fluid_mod_src or a MIDI CC controller value).
+ */
+int
+fluid_mod_get_source2(fluid_mod_t* mod)
+{
+ return mod->src2;
+}
+
+/**
+ * Get secondary source flags from a modulator.
+ * @param mod Modulator
+ * @return The secondary source flags (#fluid_mod_flags).
+ */
+int
+fluid_mod_get_flags2(fluid_mod_t* mod)
+{
+ return mod->flags2;
+}
+
+/**
+ * Get destination effect from a modulator.
+ * @param mod Modulator
+ * @return Destination generator (#fluid_gen_type)
+ */
+int
+fluid_mod_get_dest(fluid_mod_t* mod)
+{
+ return mod->dest;
+}
+
+/**
+ * Get the scale amount from a modulator.
+ * @param mod Modulator
+ * @return Scale amount
+ */
+double
+fluid_mod_get_amount(fluid_mod_t* mod)
+{
+ return (fluid_real_t) mod->amount;
+}
+
+
+/*
+ * fluid_mod_get_value
+ */
+fluid_real_t
+fluid_mod_get_value(fluid_mod_t* mod, fluid_channel_t* chan, fluid_voice_t* voice)
+{
+ fluid_real_t v1 = 0.0, v2 = 1.0;
+ fluid_real_t range1 = 127.0, range2 = 127.0;
+
+ if (chan == NULL) {
+ return 0.0f;
+ }
+
+ /* 'special treatment' for default controller
+ *
+ * Reference: SF2.01 section 8.4.2
+ *
+ * The GM default controller 'vel-to-filter cut off' is not clearly
+ * defined: If implemented according to the specs, the filter
+ * frequency jumps between vel=63 and vel=64. To maintain
+ * compatibility with existing sound fonts, the implementation is
+ * 'hardcoded', it is impossible to implement using only one
+ * modulator otherwise.
+ *
+ * I assume here, that the 'intention' of the paragraph is one
+ * octave (1200 cents) filter frequency shift between vel=127 and
+ * vel=64. 'amount' is (-2400), at least as long as the controller
+ * is set to default.
+ *
+ * Further, the 'appearance' of the modulator (source enumerator,
+ * destination enumerator, flags etc) is different from that
+ * described in section 8.4.2, but it matches the definition used in
+ * several SF2.1 sound fonts (where it is used only to turn it off).
+ * */
+ if ((mod->src2 == FLUID_MOD_VELOCITY) &&
+ (mod->src1 == FLUID_MOD_VELOCITY) &&
+ (mod->flags1 == (FLUID_MOD_GC | FLUID_MOD_UNIPOLAR
+ | FLUID_MOD_NEGATIVE | FLUID_MOD_LINEAR)) &&
+ (mod->flags2 == (FLUID_MOD_GC | FLUID_MOD_UNIPOLAR
+ | FLUID_MOD_POSITIVE | FLUID_MOD_SWITCH)) &&
+ (mod->dest == GEN_FILTERFC)) {
+// S. Christian Collins' mod, to stop forcing velocity based filtering
+/*
+ if (voice->vel < 64){
+ return (fluid_real_t) mod->amount / 2.0;
+ } else {
+ return (fluid_real_t) mod->amount * (127 - voice->vel) / 127;
+ }
+*/
+ return 0; // (fluid_real_t) mod->amount / 2.0;
+ }
+// end S. Christian Collins' mod
+
+ /* get the initial value of the first source */
+ if (mod->src1 > 0) {
+ if (mod->flags1 & FLUID_MOD_CC) {
+ v1 = fluid_channel_get_cc(chan, mod->src1);
+ } else { /* source 1 is one of the direct controllers */
+ switch (mod->src1) {
+ case FLUID_MOD_NONE: /* SF 2.01 8.2.1 item 0: src enum=0 => value is 1 */
+ v1 = range1;
+ break;
+ case FLUID_MOD_VELOCITY:
+ v1 = voice->vel;
+ break;
+ case FLUID_MOD_KEY:
+ v1 = voice->key;
+ break;
+ case FLUID_MOD_KEYPRESSURE:
+ v1 = fluid_channel_get_key_pressure (chan);
+ break;
+ case FLUID_MOD_CHANNELPRESSURE:
+ v1 = fluid_channel_get_channel_pressure (chan);
+ break;
+ case FLUID_MOD_PITCHWHEEL:
+ v1 = fluid_channel_get_pitch_bend (chan);
+ range1 = 0x4000;
+ break;
+ case FLUID_MOD_PITCHWHEELSENS:
+ v1 = fluid_channel_get_pitch_wheel_sensitivity (chan);
+ break;
+ default:
+ v1 = 0.0;
+ }
+ }
+
+ /* transform the input value */
+ switch (mod->flags1 & 0x0f) {
+ case 0: /* linear, unipolar, positive */
+ v1 /= range1;
+ break;
+ case 1: /* linear, unipolar, negative */
+ v1 = 1.0f - v1 / range1;
+ break;
+ case 2: /* linear, bipolar, positive */
+ v1 = -1.0f + 2.0f * v1 / range1;
+ break;
+ case 3: /* linear, bipolar, negative */
+ v1 = 1.0f - 2.0f * v1 / range1;
+ break;
+ case 4: /* concave, unipolar, positive */
+ v1 = fluid_concave(v1);
+ break;
+ case 5: /* concave, unipolar, negative */
+ v1 = fluid_concave(127 - v1);
+ break;
+ case 6: /* concave, bipolar, positive */
+ v1 = (v1 > 64)? fluid_concave(2 * (v1 - 64)) : -fluid_concave(2 * (64 - v1));
+ break;
+ case 7: /* concave, bipolar, negative */
+ v1 = (v1 > 64)? -fluid_concave(2 * (v1 - 64)) : fluid_concave(2 * (64 - v1));
+ break;
+ case 8: /* convex, unipolar, positive */
+ v1 = fluid_convex(v1);
+ break;
+ case 9: /* convex, unipolar, negative */
+ v1 = fluid_convex(127 - v1);
+ break;
+ case 10: /* convex, bipolar, positive */
+ v1 = (v1 > 64)? fluid_convex(2 * (v1 - 64)) : -fluid_convex(2 * (64 - v1));
+ break;
+ case 11: /* convex, bipolar, negative */
+ v1 = (v1 > 64)? -fluid_convex(2 * (v1 - 64)) : fluid_convex(2 * (64 - v1));
+ break;
+ case 12: /* switch, unipolar, positive */
+ v1 = (v1 >= 64)? 1.0f : 0.0f;
+ break;
+ case 13: /* switch, unipolar, negative */
+ v1 = (v1 >= 64)? 0.0f : 1.0f;
+ break;
+ case 14: /* switch, bipolar, positive */
+ v1 = (v1 >= 64)? 1.0f : -1.0f;
+ break;
+ case 15: /* switch, bipolar, negative */
+ v1 = (v1 >= 64)? -1.0f : 1.0f;
+ break;
+ }
+ } else {
+ return 0.0;
+ }
+
+ /* no need to go further */
+ if (v1 == 0.0f) {
+ return 0.0f;
+ }
+
+ /* get the second input source */
+ if (mod->src2 > 0) {
+ if (mod->flags2 & FLUID_MOD_CC) {
+ v2 = fluid_channel_get_cc(chan, mod->src2);
+ } else {
+ switch (mod->src2) {
+ case FLUID_MOD_NONE: /* SF 2.01 8.2.1 item 0: src enum=0 => value is 1 */
+ v2 = range2;
+ break;
+ case FLUID_MOD_VELOCITY:
+ v2 = voice->vel;
+ break;
+ case FLUID_MOD_KEY:
+ v2 = voice->key;
+ break;
+ case FLUID_MOD_KEYPRESSURE:
+ v2 = fluid_channel_get_key_pressure (chan);
+ break;
+ case FLUID_MOD_CHANNELPRESSURE:
+ v2 = fluid_channel_get_channel_pressure (chan);
+ break;
+ case FLUID_MOD_PITCHWHEEL:
+ v2 = fluid_channel_get_pitch_bend (chan);
+ break;
+ case FLUID_MOD_PITCHWHEELSENS:
+ v2 = fluid_channel_get_pitch_wheel_sensitivity (chan);
+ break;
+ default:
+ v1 = 0.0f;
+ }
+ }
+
+ /* transform the second input value */
+ switch (mod->flags2 & 0x0f) {
+ case 0: /* linear, unipolar, positive */
+ v2 /= range2;
+ break;
+ case 1: /* linear, unipolar, negative */
+ v2 = 1.0f - v2 / range2;
+ break;
+ case 2: /* linear, bipolar, positive */
+ v2 = -1.0f + 2.0f * v2 / range2;
+ break;
+ case 3: /* linear, bipolar, negative */
+ v2 = -1.0f + 2.0f * v2 / range2;
+ break;
+ case 4: /* concave, unipolar, positive */
+ v2 = fluid_concave(v2);
+ break;
+ case 5: /* concave, unipolar, negative */
+ v2 = fluid_concave(127 - v2);
+ break;
+ case 6: /* concave, bipolar, positive */
+ v2 = (v2 > 64)? fluid_concave(2 * (v2 - 64)) : -fluid_concave(2 * (64 - v2));
+ break;
+ case 7: /* concave, bipolar, negative */
+ v2 = (v2 > 64)? -fluid_concave(2 * (v2 - 64)) : fluid_concave(2 * (64 - v2));
+ break;
+ case 8: /* convex, unipolar, positive */
+ v2 = fluid_convex(v2);
+ break;
+ case 9: /* convex, unipolar, negative */
+ v2 = 1.0f - fluid_convex(v2);
+ break;
+ case 10: /* convex, bipolar, positive */
+ v2 = (v2 > 64)? -fluid_convex(2 * (v2 - 64)) : fluid_convex(2 * (64 - v2));
+ break;
+ case 11: /* convex, bipolar, negative */
+ v2 = (v2 > 64)? -fluid_convex(2 * (v2 - 64)) : fluid_convex(2 * (64 - v2));
+ break;
+ case 12: /* switch, unipolar, positive */
+ v2 = (v2 >= 64)? 1.0f : 0.0f;
+ break;
+ case 13: /* switch, unipolar, negative */
+ v2 = (v2 >= 64)? 0.0f : 1.0f;
+ break;
+ case 14: /* switch, bipolar, positive */
+ v2 = (v2 >= 64)? 1.0f : -1.0f;
+ break;
+ case 15: /* switch, bipolar, negative */
+ v2 = (v2 >= 64)? -1.0f : 1.0f;
+ break;
+ }
+ } else {
+ v2 = 1.0f;
+ }
+
+ /* it's as simple as that: */
+ return (fluid_real_t) mod->amount * v1 * v2;
+}
+
+/**
+ * Create a new uninitialized modulator structure.
+ * @return New allocated modulator or NULL if out of memory
+ */
+fluid_mod_t*
+fluid_mod_new()
+{
+ fluid_mod_t* mod = FLUID_NEW (fluid_mod_t);
+ if (mod == NULL) {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return NULL;
+ }
+ return mod;
+}
+
+/**
+ * Free a modulator structure.
+ * @param mod Modulator to free
+ */
+void
+fluid_mod_delete (fluid_mod_t *mod)
+{
+ FLUID_FREE(mod);
+}
+
+/**
+ * Checks if two modulators are identical in sources, flags and destination.
+ * @param mod1 First modulator
+ * @param mod2 Second modulator
+ * @return TRUE if identical, FALSE otherwise
+ *
+ * SF2.01 section 9.5.1 page 69, 'bullet' 3 defines 'identical'.
+ */
+int
+fluid_mod_test_identity (fluid_mod_t *mod1, fluid_mod_t *mod2)
+{
+ return mod1->dest == mod2->dest
+ && mod1->src1 == mod2->src1
+ && mod1->src2 == mod2->src2
+ && mod1->flags1 == mod2->flags1
+ && mod1->flags2 == mod2->flags2;
+}
+
+/* debug function: Prints the contents of a modulator */
+void fluid_dump_modulator(fluid_mod_t * mod){
+ int src1=mod->src1;
+ int dest=mod->dest;
+ int src2=mod->src2;
+ int flags1=mod->flags1;
+ int flags2=mod->flags2;
+ fluid_real_t amount=(fluid_real_t)mod->amount;
+
+ printf("Src: ");
+ if (flags1 & FLUID_MOD_CC){
+ printf("MIDI CC=%i",src1);
+ } else {
+ switch(src1){
+ case FLUID_MOD_NONE:
+ printf("None"); break;
+ case FLUID_MOD_VELOCITY:
+ printf("note-on velocity"); break;
+ case FLUID_MOD_KEY:
+ printf("Key nr"); break;
+ case FLUID_MOD_KEYPRESSURE:
+ printf("Poly pressure"); break;
+ case FLUID_MOD_CHANNELPRESSURE:
+ printf("Chan pressure"); break;
+ case FLUID_MOD_PITCHWHEEL:
+ printf("Pitch Wheel"); break;
+ case FLUID_MOD_PITCHWHEELSENS:
+ printf("Pitch Wheel sens"); break;
+ default:
+ printf("(unknown: %i)", src1);
+ }; /* switch src1 */
+ }; /* if not CC */
+ if (flags1 & FLUID_MOD_NEGATIVE){printf("- ");} else {printf("+ ");};
+ if (flags1 & FLUID_MOD_BIPOLAR){printf("bip ");} else {printf("unip ");};
+ printf("-> ");
+ switch(dest){
+ case GEN_FILTERQ: printf("Q"); break;
+ case GEN_FILTERFC: printf("fc"); break;
+ case GEN_VIBLFOTOPITCH: printf("VibLFO-to-pitch"); break;
+ case GEN_MODENVTOPITCH: printf("ModEnv-to-pitch"); break;
+ case GEN_MODLFOTOPITCH: printf("ModLFO-to-pitch"); break;
+ case GEN_CHORUSSEND: printf("Chorus send"); break;
+ case GEN_REVERBSEND: printf("Reverb send"); break;
+ case GEN_PAN: printf("pan"); break;
+ case GEN_ATTENUATION: printf("att"); break;
+ default: printf("dest %i",dest);
+ }; /* switch dest */
+ printf(", amount %f flags %i src2 %i flags2 %i\n",amount, flags1, src2, flags2);
+};
+
+