/* 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 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * 02111-1307, USA */ #include "fluid.h" #include "conv.h" #include "voice.h" namespace FluidS { //--------------------------------------------------------- // Mod //--------------------------------------------------------- Mod::Mod() { dest = 0; src1 = 0; flags1 = 0; src2 = 0; flags2 = 0; amount = 0.0; } /* * fluid_mod_get_value */ float Mod::get_value(Channel* chan, Voice* voice) { float v1 = 0.0, v2 = 1.0; float range1 = 127.0, range2 = 127.0; if (chan == 0) 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 ((src2 == FLUID_MOD_VELOCITY) && (src1 == FLUID_MOD_VELOCITY) && (flags1 == (FLUID_MOD_GC | FLUID_MOD_NEGATIVE)) && (flags2 == (FLUID_MOD_GC | FLUID_MOD_SWITCH)) && (dest == GEN_FILTERFC) ) { #if 0 // S. Christian Collins' mod, to stop forcing velocity based filtering if (voice->vel < 64) return (float) mod->amount / 2.0; else return (float) mod->amount * (127 - voice->vel) / 127; #endif return 0.0; } /* get the initial value of the first source */ if (src1 > 0) { if (flags1 & FLUID_MOD_CC) v1 = chan->getCC(src1); else { /* source 1 is one of the direct controllers */ switch (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 = chan->key_pressure; break; case FLUID_MOD_CHANNELPRESSURE: v1 = chan->channel_pressure; break; case FLUID_MOD_PITCHWHEEL: v1 = chan->pitch_bend; range1 = 0x4000; break; case FLUID_MOD_PITCHWHEELSENS: v1 = chan->pitch_wheel_sensitivity; break; default: v1 = 0.0; } } /* transform the input value */ switch (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 (src2 > 0) { if (flags2 & FLUID_MOD_CC) v2 = chan->getCC(src2); else { switch (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 = chan->key_pressure; break; case FLUID_MOD_CHANNELPRESSURE: v2 = chan->channel_pressure; break; case FLUID_MOD_PITCHWHEEL: v2 = chan->pitch_bend; break; case FLUID_MOD_PITCHWHEELSENS: v2 = chan->pitch_wheel_sensitivity; break; default: v1 = 0.0f; } } /* transform the second input value */ switch (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 amount * v1 * v2; } /* * test_identity */ /* Purpose: * Checks, if two modulators are identical. * SF2.01 section 9.5.1 page 69, 'bullet' 3 defines 'identical'. */ bool test_identity(const Mod * mod1, const Mod * mod2) { return (mod1->dest == mod2->dest) && (mod1->src1 == mod2->src1) && (mod1->src2 == mod2->src2) && (mod1->flags1 == mod2->flags1) && (mod1->flags2 == mod2->flags2); } //--------------------------------------------------------- // dump // debug function: Prints the contents of a modulator //--------------------------------------------------------- void Mod::dump() const { const Mod* mod = this; int src1 = mod->src1; int dest = mod->dest; int src2 = mod->src2; int flags1 = mod->flags1; int flags2 = mod->flags2; float amount = (float)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); break; } /* switch dest */ printf(", amount %f flags %i src2 %i flags2 %i\n",amount, flags1, src2, flags2); } }