1 /* FluidSynth - A Software Synthesizer
2  *
3  * Copyright (C) 2003  Peter Hanappe and others.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public License
7  * as published by the Free Software Foundation; either version 2 of
8  * the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the Free
17  * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18  * 02110-1301, USA
19  */
20 
21 #ifndef _FLUID_ADSR_ENVELOPE_H
22 #define _FLUID_ADSR_ENVELOPE_H
23 
24 #include "fluidsynth_priv.h"
25 #include "fluid_sys.h"
26 
27 /*
28  * envelope data
29  */
30 struct _fluid_env_data_t {
31 	unsigned int count;
32 	fluid_real_t coeff;
33 	fluid_real_t increment;
34 	fluid_real_t min;
35 	fluid_real_t max;
36 };
37 
38 /* Indices for envelope tables */
39 enum fluid_voice_envelope_index_t{
40 	FLUID_VOICE_ENVDELAY,
41 	FLUID_VOICE_ENVATTACK,
42 	FLUID_VOICE_ENVHOLD,
43 	FLUID_VOICE_ENVDECAY,
44 	FLUID_VOICE_ENVSUSTAIN,
45 	FLUID_VOICE_ENVRELEASE,
46 	FLUID_VOICE_ENVFINISHED,
47 	FLUID_VOICE_ENVLAST
48 };
49 
50 typedef enum fluid_voice_envelope_index_t fluid_adsr_env_section_t;
51 
52 typedef struct _fluid_adsr_env_t fluid_adsr_env_t;
53 
54 struct _fluid_adsr_env_t {
55 	fluid_env_data_t data[FLUID_VOICE_ENVLAST];
56 	unsigned int count;
57 	int section;
58 	fluid_real_t val;         /* the current value of the envelope */
59 };
60 
61 /* For performance, all functions are inlined */
62 
63 static FLUID_INLINE void
fluid_adsr_env_calc(fluid_adsr_env_t * env,int is_volenv)64 fluid_adsr_env_calc(fluid_adsr_env_t* env, int is_volenv)
65 {
66   fluid_env_data_t* env_data;
67   fluid_real_t x;
68 
69   env_data = &env->data[env->section];
70 
71   /* skip to the next section of the envelope if necessary */
72   while (env->count >= env_data->count)
73   {
74     // If we're switching envelope stages from decay to sustain, force the value to be the end value of the previous stage
75     // Hmm, should this only apply to volenv? It was so before refactoring, so keep it for now. [DH]
76     if (env->section == FLUID_VOICE_ENVDECAY && is_volenv)
77       env->val = env_data->min * env_data->coeff;
78 
79     env_data = &env->data[++env->section];
80     env->count = 0;
81   }
82 
83   /* calculate the envelope value and check for valid range */
84   x = env_data->coeff * env->val + env_data->increment;
85 
86   if (x < env_data->min)
87   {
88     x = env_data->min;
89     env->section++;
90     env->count = 0;
91   }
92   else if (x > env_data->max)
93   {
94     x = env_data->max;
95     env->section++;
96     env->count = 0;
97   }
98 
99   env->val = x;
100   env->count++;
101 }
102 
103 /* This one cannot be inlined since it is referenced in
104    the event queue */
105 void
106 fluid_adsr_env_set_data(fluid_adsr_env_t* env,
107                         fluid_adsr_env_section_t section,
108                         unsigned int count,
109                         fluid_real_t coeff,
110                         fluid_real_t increment,
111                         fluid_real_t min,
112                         fluid_real_t max);
113 
114 static inline void
fluid_adsr_env_reset(fluid_adsr_env_t * env)115 fluid_adsr_env_reset(fluid_adsr_env_t* env)
116 {
117   env->count = 0;
118   env->section = 0;
119   env->val = 0.0f;
120 }
121 
122 static inline fluid_real_t
fluid_adsr_env_get_val(fluid_adsr_env_t * env)123 fluid_adsr_env_get_val(fluid_adsr_env_t* env)
124 {
125   return env->val;
126 }
127 
128 static inline void
fluid_adsr_env_set_val(fluid_adsr_env_t * env,fluid_real_t val)129 fluid_adsr_env_set_val(fluid_adsr_env_t* env, fluid_real_t val)
130 {
131   env->val = val;
132 }
133 
134 static inline fluid_adsr_env_section_t
fluid_adsr_env_get_section(fluid_adsr_env_t * env)135 fluid_adsr_env_get_section(fluid_adsr_env_t* env)
136 {
137   return env->section;
138 }
139 
140 static inline void
fluid_adsr_env_set_section(fluid_adsr_env_t * env,fluid_adsr_env_section_t section)141 fluid_adsr_env_set_section(fluid_adsr_env_t* env,
142                            fluid_adsr_env_section_t section)
143 {
144   env->section = section;
145   env->count = 0;
146 }
147 
148 /* Used for determining which voice to kill.
149    Returns max amplitude from now, and forward in time.
150 */
151 static inline fluid_real_t
fluid_adsr_env_get_max_val(fluid_adsr_env_t * env)152 fluid_adsr_env_get_max_val(fluid_adsr_env_t* env)
153 {
154   if (env->section > FLUID_VOICE_ENVATTACK){
155     return env->val * 1000;
156   } else {
157     return env->data[FLUID_VOICE_ENVATTACK].max;
158   }
159 }
160 
161 #endif
162 
163