Path: blob/master/libs/fluidsynth/src/synth/fluid_mod.c
8725 views
/* FluidSynth - A Software Synthesizer1*2* Copyright (C) 2003 Peter Hanappe and others.3*4* This library is free software; you can redistribute it and/or5* modify it under the terms of the GNU Lesser General Public License6* as published by the Free Software Foundation; either version 2.1 of7* the License, or (at your option) any later version.8*9* This library is distributed in the hope that it will be useful, but10* WITHOUT ANY WARRANTY; without even the implied warranty of11* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU12* Lesser General Public License for more details.13*14* You should have received a copy of the GNU Lesser General Public15* License along with this library; if not, write to the Free16* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA17* 02110-1301, USA18*/1920#include "fluid_mod.h"21#include "fluid_chan.h"22#include "fluid_voice.h"2324/**25* Clone the modulators destination, sources, flags and amount.26*27* @param mod the modulator to store the copy to28* @param src the source modulator to retrieve the information from29*30* @note The \c next member of \c mod will be left unchanged.31*/32void33fluid_mod_clone(fluid_mod_t *mod, const fluid_mod_t *src)34{35mod->dest = src->dest;36mod->src1 = src->src1;37mod->flags1 = src->flags1;38mod->src2 = src->src2;39mod->flags2 = src->flags2;40mod->amount = src->amount;41mod->trans = src->trans;42}4344/**45* Set a modulator's primary source controller and flags.46*47* @param mod The modulator instance48* @param src Modulator source (#fluid_mod_src or a MIDI controller number)49* @param flags Flags determining mapping function and whether the source50* controller is a general controller (#FLUID_MOD_GC) or a MIDI CC controller51* (#FLUID_MOD_CC), see #fluid_mod_flags.52*/53void54fluid_mod_set_source1(fluid_mod_t *mod, int src, int flags)55{56mod->src1 = src;57mod->flags1 = flags;58}5960/**61* Set a modulator's secondary source controller and flags.62*63* @param mod The modulator instance64* @param src Modulator source (#fluid_mod_src or a MIDI controller number)65* @param flags Flags determining mapping function and whether the source66* controller is a general controller (#FLUID_MOD_GC) or a MIDI CC controller67* (#FLUID_MOD_CC), see #fluid_mod_flags.68*/69void70fluid_mod_set_source2(fluid_mod_t *mod, int src, int flags)71{72mod->src2 = src;73mod->flags2 = flags;74}7576/**77* Set the destination effect of a modulator.78*79* @param mod The modulator instance80* @param dest Destination generator (#fluid_gen_type)81*/82void83fluid_mod_set_dest(fluid_mod_t *mod, int dest)84{85mod->dest = dest;86}8788/**89* Set the scale amount of a modulator.90*91* @param mod The modulator instance92* @param amount Scale amount to assign93*/94void95fluid_mod_set_amount(fluid_mod_t *mod, double amount)96{97mod->amount = (double) amount;98}99100/**101* Set the transform type of a modulator.102*103* @param mod The modulator instance104* @param type Transform type, see #fluid_mod_transforms105*/106void107fluid_mod_set_transform(fluid_mod_t *mod, int type)108{109unsigned char flag = (unsigned char) type;110if(flag != FLUID_MOD_TRANSFORM_LINEAR && flag != FLUID_MOD_TRANSFORM_ABS)111{112FLUID_LOG(FLUID_ERR, "fluid_mod_set_transform() called with invalid transform type %d", type);113return;114}115mod->trans = flag;116}117118/**119* Get the primary source value from a modulator.120*121* @param mod The modulator instance122* @return The primary source value (#fluid_mod_src or a MIDI CC controller value).123*/124int125fluid_mod_get_source1(const fluid_mod_t *mod)126{127return mod->src1;128}129130/**131* Get primary source flags from a modulator.132*133* @param mod The modulator instance134* @return The primary source flags (#fluid_mod_flags).135*/136int137fluid_mod_get_flags1(const fluid_mod_t *mod)138{139return mod->flags1;140}141142/**143* Get the secondary source value from a modulator.144*145* @param mod The modulator instance146* @return The secondary source value (#fluid_mod_src or a MIDI CC controller value).147*/148int149fluid_mod_get_source2(const fluid_mod_t *mod)150{151return mod->src2;152}153154/**155* Get secondary source flags from a modulator.156*157* @param mod The modulator instance158* @return The secondary source flags (#fluid_mod_flags).159*/160int161fluid_mod_get_flags2(const fluid_mod_t *mod)162{163return mod->flags2;164}165166/**167* Get destination effect from a modulator.168*169* @param mod The modulator instance170* @return Destination generator (#fluid_gen_type)171*/172int173fluid_mod_get_dest(const fluid_mod_t *mod)174{175return mod->dest;176}177178/**179* Get the scale amount from a modulator.180*181* @param mod The modulator instance182* @return Scale amount183*/184double185fluid_mod_get_amount(const fluid_mod_t *mod)186{187return (double) mod->amount;188}189190/**191* Get the transform type of a modulator.192*193* @param mod The modulator instance194* @param type Transform type, see #fluid_mod_transforms195*/196int197fluid_mod_get_transform(fluid_mod_t *mod)198{199return (int) mod->trans;200}201202/*203* retrieves the initial value from the given source of the modulator204*/205static fluid_real_t206fluid_mod_get_source_value(const unsigned char mod_src,207const unsigned char mod_flags,208fluid_real_t *range,209const fluid_voice_t *voice210)211{212const fluid_channel_t *chan = voice->channel;213fluid_real_t val;214215if(mod_flags & FLUID_MOD_CC)216{217val = fluid_channel_get_cc(chan, mod_src);218219if(mod_src == PORTAMENTO_CTRL)220{221// an invalid portamento fromkey should be treated as 0 when it's actually used for modulating222if(!fluid_channel_is_valid_note(val))223{224val = 0;225}226}227}228else229{230switch(mod_src)231{232case FLUID_MOD_NONE: /* SF 2.01 8.2.1 item 0: src enum=0 => value is 1 */233val = *range;234break;235236case FLUID_MOD_VELOCITY:237val = fluid_voice_get_actual_velocity(voice);238break;239240case FLUID_MOD_KEY:241val = fluid_voice_get_actual_key(voice);242break;243244case FLUID_MOD_KEYPRESSURE:245val = fluid_channel_get_key_pressure(chan, voice->key);246break;247248case FLUID_MOD_CHANNELPRESSURE:249val = fluid_channel_get_channel_pressure(chan);250break;251252case FLUID_MOD_PITCHWHEEL:253val = fluid_channel_get_pitch_bend(chan);254*range = 0x4000;255break;256257case FLUID_MOD_PITCHWHEELSENS:258val = fluid_channel_get_pitch_wheel_sensitivity(chan);259break;260261default:262FLUID_LOG(FLUID_ERR, "Unknown modulator source '%d', disabling modulator.", mod_src);263val = 0.0;264}265}266267return val;268}269270/**271* transforms the initial value retrieved by \c fluid_mod_get_source_value into [0.0;1.0]272*/273fluid_real_t274fluid_mod_transform_source_value(fluid_real_t val, unsigned char mod_flags, const fluid_real_t range)275{276/* normalized value, i.e. usually in the range [0;1] */277const fluid_real_t val_norm = val / range;278/* inverted value used for negative mapping functions */279const fluid_real_t inv_norm = 1.0f - 1.0f / range - val_norm;280281/* we could also only switch case the lower nibble of mod_flags, however282* this would keep us from adding further mod types in the future283*284* instead just remove the flag(s) we already took care of285*/286mod_flags &= ~FLUID_MOD_CC;287288switch(mod_flags/* & 0x0f*/)289{290case FLUID_MOD_LINEAR | FLUID_MOD_UNIPOLAR | FLUID_MOD_POSITIVE: /* =0 */291val = val_norm;292break;293294case FLUID_MOD_LINEAR | FLUID_MOD_UNIPOLAR | FLUID_MOD_NEGATIVE: /* =1 */295val = inv_norm;296break;297298case FLUID_MOD_LINEAR | FLUID_MOD_BIPOLAR | FLUID_MOD_POSITIVE: /* =2 */299val = -1.0f + 2.0f * val_norm;300break;301302case FLUID_MOD_LINEAR | FLUID_MOD_BIPOLAR | FLUID_MOD_NEGATIVE: /* =3 */303val = -1.0f + 2.0f * inv_norm;304break;305306case FLUID_MOD_CONCAVE | FLUID_MOD_UNIPOLAR | FLUID_MOD_POSITIVE: /* =4 */307val = fluid_concave(127 * (val_norm));308break;309310case FLUID_MOD_CONCAVE | FLUID_MOD_UNIPOLAR | FLUID_MOD_NEGATIVE: /* =5 */311val = fluid_concave(127 * (inv_norm));312break;313314case FLUID_MOD_CONCAVE | FLUID_MOD_BIPOLAR | FLUID_MOD_POSITIVE: /* =6 */315val = (val_norm > 0.5f) ? fluid_concave(127 * 2 * (val_norm - 0.5f))316: -fluid_concave(127 * 2 * (0.5f - val_norm));317break;318319case FLUID_MOD_CONCAVE | FLUID_MOD_BIPOLAR | FLUID_MOD_NEGATIVE: /* =7 */320val = (inv_norm > 0.5f) ? fluid_concave(127 * 2 * (inv_norm - 0.5f))321: -fluid_concave(127 * 2 * (0.5f - inv_norm));322break;323324case FLUID_MOD_CONVEX | FLUID_MOD_UNIPOLAR | FLUID_MOD_POSITIVE: /* =8 */325val = fluid_convex(127 * (val_norm));326break;327328case FLUID_MOD_CONVEX | FLUID_MOD_UNIPOLAR | FLUID_MOD_NEGATIVE: /* =9 */329val = fluid_convex(127 * (inv_norm));330break;331332case FLUID_MOD_CONVEX | FLUID_MOD_BIPOLAR | FLUID_MOD_POSITIVE: /* =10 */333val = (val_norm > 0.5f) ? fluid_convex(127 * 2 * (val_norm - 0.5f))334: -fluid_convex(127 * 2 * (0.5f - val_norm));335break;336337case FLUID_MOD_CONVEX | FLUID_MOD_BIPOLAR | FLUID_MOD_NEGATIVE: /* =11 */338val = (inv_norm > 0.5f) ? fluid_convex(127 * 2 * (inv_norm - 0.5f))339: -fluid_convex(127 * 2 * (0.5f - inv_norm));340break;341342case FLUID_MOD_SWITCH | FLUID_MOD_UNIPOLAR | FLUID_MOD_POSITIVE: /* =12 */343val = (val_norm >= 0.5f) ? 1.0f : 0.0f;344break;345346case FLUID_MOD_SWITCH | FLUID_MOD_UNIPOLAR | FLUID_MOD_NEGATIVE: /* =13 */347val = (inv_norm >= 0.5f) ? 1.0f : 0.0f;348break;349350case FLUID_MOD_SWITCH | FLUID_MOD_BIPOLAR | FLUID_MOD_POSITIVE: /* =14 */351val = (val_norm >= 0.5f) ? 1.0f : -1.0f;352break;353354case FLUID_MOD_SWITCH | FLUID_MOD_BIPOLAR | FLUID_MOD_NEGATIVE: /* =15 */355val = (inv_norm >= 0.5f) ? 1.0f : -1.0f;356break;357358/*359* MIDI CCs only have a resolution of 7 bits. The closer val_norm gets to 1,360* the less will be the resulting change of the sinus. When using this sin()361* for scaling the cutoff frequency, there will be no audible difference between362* MIDI CCs 118 to 127. To avoid this waste of CCs multiply with 0.87363* (at least for unipolar) which makes sin() never get to 1.0 but to 0.98 which364* is close enough.365*/366case FLUID_MOD_SIN | FLUID_MOD_UNIPOLAR | FLUID_MOD_POSITIVE: /* custom sin(x) */367val = FLUID_SIN((FLUID_M_PI / 2.0f * 0.87f) * val_norm);368break;369370case FLUID_MOD_SIN | FLUID_MOD_UNIPOLAR | FLUID_MOD_NEGATIVE: /* custom */371val = FLUID_SIN((FLUID_M_PI / 2.0f * 0.87f) * (inv_norm));372break;373374case FLUID_MOD_SIN | FLUID_MOD_BIPOLAR | FLUID_MOD_POSITIVE: /* custom */375val = (val_norm > 0.5f) ? FLUID_SIN(FLUID_M_PI * (val_norm - 0.5f))376: -FLUID_SIN(FLUID_M_PI * (0.5f - val_norm));377break;378379case FLUID_MOD_SIN | FLUID_MOD_BIPOLAR | FLUID_MOD_NEGATIVE: /* custom */380val = (inv_norm > 0.5f) ? FLUID_SIN(FLUID_M_PI * (inv_norm - 0.5f))381: -FLUID_SIN(FLUID_M_PI * (0.5f - inv_norm));382break;383384default:385FLUID_LOG(FLUID_ERR, "Unknown modulator type '%d', disabling modulator.", mod_flags);386val = 0.0f;387break;388}389390return val;391}392393/*394* fluid_mod_get_value.395* Computes and return modulator output following SF2.01396* (See SoundFont Modulator Controller Model Chapter 9.5).397*398* Output = Transform(Amount * Map(primary source input) * Map(secondary source input))399*400* Note:401* fluid_mod_get_value ignores the Transform operator. The result is:402*403* Output = Amount * Map(primary source input) * Map(secondary source input)404*/405fluid_real_t406fluid_mod_get_value(fluid_mod_t *mod, fluid_voice_t *voice)407{408extern fluid_mod_t default_vel2filter_mod;409410fluid_real_t v1, v2;411fluid_real_t final_value;412/* The wording of the default modulators refers to a range of 127/128.413* And the table in section 9.5.3 suggests, that this mapping should be applied414* to all unipolar and bipolar mappings respectively.415*416* Thinking about this further, this is actually pretty clever, as this is properly417* addresses MIDI Recommended Practice (RP-036) Default Pan Formula418* "Since MIDI controller values range from 0 to 127, the exact center419* of the range, 63.5, cannot be represented."420*421* When changing the overall range to 127/128 however, the "middle pan" value of 64422* can be correctly represented.423*/424fluid_real_t range1 = 128.0, range2 = 128.0;425426/* 'special treatment' for default controller427*428* Reference: SF2.01 section 8.4.2429*430* The GM default controller 'vel-to-filter cut off' is not clearly431* defined: If implemented according to the specs, the filter432* frequency jumps between vel=63 and vel=64. To maintain433* compatibility with existing sound fonts, the implementation is434* 'hardcoded', it is impossible to implement using only one435* modulator otherwise.436*437* I assume here, that the 'intention' of the paragraph is one438* octave (1200 cents) filter frequency shift between vel=127 and439* vel=64. 'amount' is (-2400), at least as long as the controller440* is set to default.441*442* Further, the 'appearance' of the modulator (source enumerator,443* destination enumerator, flags etc) is different from that444* described in section 8.4.2, but it matches the definition used in445* several SF2.1 sound fonts (where it is used only to turn it off).446* */447if(fluid_mod_test_identity(mod, &default_vel2filter_mod))448{449/*450if (voice->vel < 64){451return (fluid_real_t) mod->amount / 2.0;452} else {453return (fluid_real_t) mod->amount * (127 - voice->vel) / 127;454}455return (fluid_real_t) mod->amount / 2.0;456*/457// S. Christian Collins' mod, to stop forcing velocity based filtering458return 0;459}460461/* Get the initial value of the first source.462*463* Even if the src is FLUID_MOD_NONE, the value has to be transformed, see #1389464*/465v1 = fluid_mod_get_source_value(mod->src1, mod->flags1, &range1, voice);466467/* transform the input value */468v1 = fluid_mod_transform_source_value(v1, mod->flags1, range1);469470/* get the second input source */471v2 = fluid_mod_get_source_value(mod->src2, mod->flags2, &range2, voice);472473/* transform the second input value */474v2 = fluid_mod_transform_source_value(v2, mod->flags2, range2);475476/* it indeed is as simple as that: */477final_value = (fluid_real_t) mod->amount * v1 * v2;478479/* check for absolute value transform */480if(mod->trans == FLUID_MOD_TRANSFORM_ABS)481{482final_value = FLUID_FABS(final_value);483}484return final_value;485}486487/**488* Create a new uninitialized modulator structure.489*490* @return New allocated modulator or NULL if out of memory491*/492fluid_mod_t *493new_fluid_mod(void)494{495fluid_mod_t *mod = FLUID_NEW(fluid_mod_t);496497if(mod == NULL)498{499FLUID_LOG(FLUID_ERR, "Out of memory");500return NULL;501}502// for the sake of backward compatibility503mod->trans = FLUID_MOD_TRANSFORM_LINEAR;504return mod;505}506507/**508* Free a modulator structure.509*510* @param mod Modulator to free511*/512void513delete_fluid_mod(fluid_mod_t *mod)514{515FLUID_FREE(mod);516}517518/**519* Returns the size of the fluid_mod_t structure.520*521* @return Size of fluid_mod_t in bytes522*523* Useful in low latency scenarios e.g. to allocate a modulator on the stack.524*/525size_t fluid_mod_sizeof(void)526{527return sizeof(fluid_mod_t);528}529530/**531* Checks if modulator with source 1 other than CC is FLUID_MOD_NONE.532*533* @param mod, modulator.534* @return TRUE if modulator source 1 other than cc is FLUID_MOD_NONE, FALSE otherwise.535*/536static int537fluid_mod_is_src1_none(const fluid_mod_t *mod)538{539return(((mod->flags1 & FLUID_MOD_CC) == 0) && (mod->src1 == FLUID_MOD_NONE));540}541542/**543* Checks if modulators source other than CC source is invalid.544*545* @param mod, modulator.546* @param src1_select, source input selection to check.547* 1 to check src1 source.548* 0 to check src2 source.549* @return FALSE if selected modulator source other than cc is invalid, TRUE otherwise.550*551* (specs SF 2.01 7.4, 7.8, 8.2.1)552*/553static int554fluid_mod_check_non_cc_source(const fluid_mod_t *mod, unsigned char src1_select)555{556unsigned char flags, src;557558if(src1_select)559{560flags = mod->flags1;561src = mod->src1;562}563else564{565flags = mod->flags2;566src = mod->src2;567}568569return(((flags & FLUID_MOD_CC) != 0) /* src is a CC */570/* SF2.01 section 8.2.1: Constant value */571|| ((src == FLUID_MOD_NONE)572|| (src == FLUID_MOD_VELOCITY) /* Note-on velocity */573|| (src == FLUID_MOD_KEY) /* Note-on key number */574|| (src == FLUID_MOD_KEYPRESSURE) /* Poly pressure */575|| (src == FLUID_MOD_CHANNELPRESSURE) /* Channel pressure */576|| (src == FLUID_MOD_PITCHWHEEL) /* Pitch wheel */577|| (src == FLUID_MOD_PITCHWHEELSENS) /* Pitch wheel sensitivity */578));579}580581/**582* Checks if modulator CC source is invalid (specs SF 2.01 7.4, 7.8, 8.2.1).583*584* @param mod, modulator.585* @src1_select, source input selection:586* 1 to check src1 source or587* 0 to check src2 source.588* @return FALSE if selected modulator's source CC is invalid, TRUE otherwise.589*/590static int591fluid_mod_check_cc_source(const fluid_mod_t *mod, unsigned char src1_select)592{593unsigned char flags, src;594595if(src1_select)596{597flags = mod->flags1;598src = mod->src1;599}600else601{602flags = mod->flags2;603src = mod->src2;604}605606return(((flags & FLUID_MOD_CC) == 0) /* src is non CC */607|| ((src != BANK_SELECT_MSB)608&& (src != BANK_SELECT_LSB)609&& (src != DATA_ENTRY_MSB)610&& (src != DATA_ENTRY_LSB)611/* is src not NRPN_LSB, NRPN_MSB, RPN_LSB, RPN_MSB */612&& ((src < NRPN_LSB) || (RPN_MSB < src))613/* is src not ALL_SOUND_OFF, ALL_CTRL_OFF, LOCAL_CONTROL, ALL_NOTES_OFF ? */614/* is src not OMNI_OFF, OMNI_ON, POLY_OFF, POLY_ON ? */615&& (src < ALL_SOUND_OFF)616/* CC lsb shouldn't allowed to modulate (spec SF 2.01 - 8.2.1)617However, as long fluidsynth will use only CC 7 bits resolution,618it is safe to ignore these SF recommendations on CC receive.619See explanations in fluid_synth_cc_LOCAL() */620/* uncomment next line to forbid CC lsb */621/* && ((src < 32) || (63 < src)) */622));623}624625/**626* Checks valid modulator sources (specs SF 2.01 7.4, 7.8, 8.2.1)627*628* @param mod, modulator.629* @param name,if not NULL, pointer on a string displayed as a warning.630* @return TRUE if modulator sources src1, src2 are valid, FALSE otherwise.631*/632int fluid_mod_check_sources(const fluid_mod_t *mod, char *name)633{634static const char invalid_non_cc_src[] =635"Invalid modulator, using non-CC source %s.src%d=%d";636static const char invalid_cc_src[] =637"Invalid modulator, using CC source %s.src%d=%d";638static const char src1_is_none[] =639"Modulator with source 1 none %s.src1=%d";640641/* checks valid non cc sources */642if(!fluid_mod_check_non_cc_source(mod, 1)) /* check src1 */643{644if(name)645{646FLUID_LOG(FLUID_WARN, invalid_non_cc_src, name, 1, mod->src1);647}648649return FALSE;650}651652/*653When src1 is non CC source FLUID_MOD_NONE, the modulator is valid but654the output of this modulator will be forced to 0 at synthesis time.655Also this modulator cannot be used to overwrite a default modulator (as656there is no default modulator with src1 source equal to FLUID_MOD_NONE).657Consequently it is useful to return FALSE to indicate this modulator658being useless. It will be removed later with others invalid modulators.659*/660if(fluid_mod_is_src1_none(mod))661{662if(name)663{664FLUID_LOG(FLUID_WARN, src1_is_none, name, mod->src1);665}666667return FALSE;668}669670if(!fluid_mod_check_non_cc_source(mod, 0)) /* check src2 */671{672if(name)673{674FLUID_LOG(FLUID_WARN, invalid_non_cc_src, name, 2, mod->src2);675}676677return FALSE;678}679680/* checks valid cc sources */681if(!fluid_mod_check_cc_source(mod, 1)) /* check src1 */682{683if(name)684{685FLUID_LOG(FLUID_WARN, invalid_cc_src, name, 1, mod->src1);686}687688return FALSE;689}690691if(!fluid_mod_check_cc_source(mod, 0)) /* check src2 */692{693if(name)694{695FLUID_LOG(FLUID_WARN, invalid_cc_src, name, 2, mod->src2);696}697698return FALSE;699}700701return TRUE;702}703704/**705* Checks if two modulators are identical in sources, flags and destination.706*707* @param mod1 First modulator708* @param mod2 Second modulator709* @return TRUE if identical, FALSE otherwise710*711* SF2.01 section 9.5.1 page 69, 'bullet' 3 defines 'identical'.712*/713int714fluid_mod_test_identity(const fluid_mod_t *mod1, const fluid_mod_t *mod2)715{716return mod1->dest == mod2->dest717&& mod1->src1 == mod2->src1718&& mod1->src2 == mod2->src2719&& mod1->flags1 == mod2->flags1720&& mod1->flags2 == mod2->flags2;721}722723/**724* Check if the modulator has the given source.725*726* @param mod The modulator instance727* @param cc Boolean value indicating if ctrl is a CC controller or not728* @param ctrl The source to check for (if \c cc == FALSE : a value of type #fluid_mod_src, else the value of the MIDI CC to check for)729*730* @return TRUE if the modulator has the given source, FALSE otherwise.731*/732int fluid_mod_has_source(const fluid_mod_t *mod, int cc, int ctrl)733{734return735(736(737((mod->src1 == ctrl) && ((mod->flags1 & FLUID_MOD_CC) != 0) && (cc != 0))738|| ((mod->src1 == ctrl) && ((mod->flags1 & FLUID_MOD_CC) == 0) && (cc == 0))739)740||741(742((mod->src2 == ctrl) && ((mod->flags2 & FLUID_MOD_CC) != 0) && (cc != 0))743|| ((mod->src2 == ctrl) && ((mod->flags2 & FLUID_MOD_CC) == 0) && (cc == 0))744)745);746}747748/**749* Check if the modulator has the given destination.750*751* @param mod The modulator instance752* @param gen The destination generator of type #fluid_gen_type to check for753* @return TRUE if the modulator has the given destination, FALSE otherwise.754*/755int fluid_mod_has_dest(const fluid_mod_t *mod, int gen)756{757return mod->dest == gen;758}759760761/* debug function: Prints the contents of a modulator */762#ifdef DEBUG763void fluid_dump_modulator(fluid_mod_t *mod)764{765int src1 = mod->src1;766int dest = mod->dest;767int src2 = mod->src2;768int flags1 = mod->flags1;769int flags2 = mod->flags2;770fluid_real_t amount = (fluid_real_t)mod->amount;771772printf("Src: ");773774if(flags1 & FLUID_MOD_CC)775{776printf("MIDI CC=%i", src1);777}778else779{780switch(src1)781{782case FLUID_MOD_NONE:783printf("None");784break;785786case FLUID_MOD_VELOCITY:787printf("note-on velocity");788break;789790case FLUID_MOD_KEY:791printf("Key nr");792break;793794case FLUID_MOD_KEYPRESSURE:795printf("Poly pressure");796break;797798case FLUID_MOD_CHANNELPRESSURE:799printf("Chan pressure");800break;801802case FLUID_MOD_PITCHWHEEL:803printf("Pitch Wheel");804break;805806case FLUID_MOD_PITCHWHEELSENS:807printf("Pitch Wheel sens");808break;809810default:811printf("(unknown: %i)", src1);812}; /* switch src1 */813}; /* if not CC */814815if(flags1 & FLUID_MOD_NEGATIVE)816{817printf("- ");818}819else820{821printf("+ ");822};823824if(flags1 & FLUID_MOD_BIPOLAR)825{826printf("bip ");827}828else829{830printf("unip ");831};832833printf("-> ");834835switch(dest)836{837case GEN_FILTERQ:838printf("Q");839break;840841case GEN_FILTERFC:842printf("fc");843break;844845case GEN_CUSTOM_FILTERQ:846printf("custom-Q");847break;848849case GEN_CUSTOM_FILTERFC:850printf("custom-fc");851break;852853case GEN_VIBLFOTOPITCH:854printf("VibLFO-to-pitch");855break;856857case GEN_MODENVTOPITCH:858printf("ModEnv-to-pitch");859break;860861case GEN_MODLFOTOPITCH:862printf("ModLFO-to-pitch");863break;864865case GEN_CHORUSSEND:866printf("Chorus send");867break;868869case GEN_REVERBSEND:870printf("Reverb send");871break;872873case GEN_PAN:874printf("pan");875break;876877case GEN_CUSTOM_BALANCE:878printf("balance");879break;880881case GEN_ATTENUATION:882printf("att");883break;884885default:886printf("dest %i", dest);887}; /* switch dest */888889printf(", amount %f flags %i src2 %i flags2 %i\n", amount, flags1, src2, flags2);890};891#endif892893894