/* 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 */ #ifndef _FLUID_ADSR_ENVELOPE_H #define _FLUID_ADSR_ENVELOPE_H #include "fluidsynth_priv.h" #include "fluid_sys.h" /* * envelope data */ struct _fluid_env_data_t { unsigned int count; fluid_real_t coeff; fluid_real_t increment; fluid_real_t min; fluid_real_t max; }; /* Indices for envelope tables */ enum fluid_voice_envelope_index_t{ FLUID_VOICE_ENVDELAY, FLUID_VOICE_ENVATTACK, FLUID_VOICE_ENVHOLD, FLUID_VOICE_ENVDECAY, FLUID_VOICE_ENVSUSTAIN, FLUID_VOICE_ENVRELEASE, FLUID_VOICE_ENVFINISHED, FLUID_VOICE_ENVLAST }; typedef enum fluid_voice_envelope_index_t fluid_adsr_env_section_t; typedef struct _fluid_adsr_env_t fluid_adsr_env_t; struct _fluid_adsr_env_t { fluid_env_data_t data[FLUID_VOICE_ENVLAST]; unsigned int count; int section; fluid_real_t val; /* the current value of the envelope */ }; /* For performance, all functions are inlined */ static FLUID_INLINE void fluid_adsr_env_calc(fluid_adsr_env_t* env, int is_volenv) { fluid_env_data_t* env_data; fluid_real_t x; env_data = &env->data[env->section]; /* skip to the next section of the envelope if necessary */ while (env->count >= env_data->count) { // If we're switching envelope stages from decay to sustain, force the value to be the end value of the previous stage // Hmm, should this only apply to volenv? It was so before refactoring, so keep it for now. [DH] if (env->section == FLUID_VOICE_ENVDECAY && is_volenv) env->val = env_data->min * env_data->coeff; env_data = &env->data[++env->section]; env->count = 0; } /* calculate the envelope value and check for valid range */ x = env_data->coeff * env->val + env_data->increment; if (x < env_data->min) { x = env_data->min; env->section++; env->count = 0; } else if (x > env_data->max) { x = env_data->max; env->section++; env->count = 0; } env->val = x; env->count++; } /* This one cannot be inlined since it is referenced in the event queue */ void fluid_adsr_env_set_data(fluid_adsr_env_t* env, fluid_adsr_env_section_t section, unsigned int count, fluid_real_t coeff, fluid_real_t increment, fluid_real_t min, fluid_real_t max); static inline void fluid_adsr_env_reset(fluid_adsr_env_t* env) { env->count = 0; env->section = 0; env->val = 0.0f; } static inline fluid_real_t fluid_adsr_env_get_val(fluid_adsr_env_t* env) { return env->val; } static inline void fluid_adsr_env_set_val(fluid_adsr_env_t* env, fluid_real_t val) { env->val = val; } static inline fluid_adsr_env_section_t fluid_adsr_env_get_section(fluid_adsr_env_t* env) { return env->section; } static inline void fluid_adsr_env_set_section(fluid_adsr_env_t* env, fluid_adsr_env_section_t section) { env->section = section; env->count = 0; } /* Used for determining which voice to kill. Returns max amplitude from now, and forward in time. */ static inline fluid_real_t fluid_adsr_env_get_max_val(fluid_adsr_env_t* env) { if (env->section > FLUID_VOICE_ENVATTACK){ return env->val * 1000; } else { return env->data[FLUID_VOICE_ENVATTACK].max; } } #endif