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