summaryrefslogtreecommitdiff
path: root/libs/fluidsynth/src/fluid_adsr_env.h
blob: 9ed652d0b11ff15aaaee212d0e81081740c39dc6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
/* 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 Lesser General Public License
 * as published by the Free Software Foundation; either version 2.1 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser 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;
    }
    else
    {
        env->count++;
    }

    env->val = x;


}

/* This one cannot be inlined since it is referenced in
   the event queue */
DECLARE_FLUID_RVOICE_FUNCTION(fluid_adsr_env_set_data);

static FLUID_INLINE void
fluid_adsr_env_reset(fluid_adsr_env_t *env)
{
    env->count = 0;
    env->section = 0;
    env->val = 0.0f;
}

static FLUID_INLINE fluid_real_t
fluid_adsr_env_get_val(fluid_adsr_env_t *env)
{
    return env->val;
}

static FLUID_INLINE void
fluid_adsr_env_set_val(fluid_adsr_env_t *env, fluid_real_t val)
{
    env->val = val;
}

static FLUID_INLINE fluid_adsr_env_section_t
fluid_adsr_env_get_section(fluid_adsr_env_t *env)
{
    return env->section;
}

static FLUID_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 FLUID_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