File: voice.h

package info (click to toggle)
musescore-snapshot 3.2.s20190704+dfsg1-1
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 218,116 kB
  • sloc: cpp: 290,563; xml: 200,238; sh: 3,706; ansic: 1,447; python: 393; makefile: 222; perl: 82; pascal: 79
file content (275 lines) | stat: -rw-r--r-- 10,123 bytes parent folder | download | duplicates (5)
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
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
/* 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
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
 * 02111-1307, USA
 */

#ifndef _FLUID_VOICE_H
#define _FLUID_VOICE_H

#include "fluid.h"
#include "gen.h"

namespace FluidS {

#define NO_CHANNEL             0xff

enum fluid_voice_status {
	FLUID_VOICE_OFF,
	FLUID_VOICE_ON,
	FLUID_VOICE_SUSTAINED
      };

/*
 * envelope data
 */
struct fluid_env_data_t {
	unsigned int count;     // sample count
	float coeff;
	float incr;
	float min;
	float 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
      };

//---------------------------------------------------------
//   Voice
//---------------------------------------------------------

class Voice
      {
      static float interp_coeff_linear[FLUID_INTERP_MAX][2];
      static float interp_coeff[FLUID_INTERP_MAX][4];
      static float sinc_table7[FLUID_INTERP_MAX][7];

      Fluid* _fluid;
      double _noteTuning;             // +/- in midicent

      //keeps number of frames that are now in cache
      //Cached frames are the frames that are calculated in terms of DSP (digital sound processing) and interpolated.
      unsigned _cachedFrames = 0;
      //Keeps number of the initially cached frames. It's used to calculate actual shift in cache arrays for setting cache to output stream.
      unsigned _initialCacheFrames = 0;
      //Cache arrays keep actual calculated data after applying effects. Its size is twice bigger than framesBuffer (2 channels).
      std::vector<float> _cacheOut;
      std::vector<float> _cacheReverb;
      std::vector<float> _cacheChorus;
            
      /*
       / Applies effects to the calculated interpolation and put frames to output containers.
       / @startBufIdx is used to specify start index of interpolation data array that is used to put data to frames array.
       / @count specifies how many frames should be calculated. Note, size of output arrays must be twice bigger, than @count.
      */
      void effects(int startBufIdx, int count, float* out, float* effect1, float* effect2);
            
      /*
       / Generates DSP data required for sound interpolation. @frames defines number of available frames to generate sound envelope.
       / Note, the minimal viable number of frames is NUM_FRAMES_DELAY. That is why we need all that stuff with caching. Using bluetooth or some specific hardware leads to less number of frames and silence.
      */
      bool generateDataForDSPChain(unsigned frames);
            
      /*
       / Generates sound data from calculated DSP data. Resulting data is stored in @dsp_buf.
       / The data is generated for @n frames. Note, number of generated frames can be less than @n.
       */
      std::tuple<unsigned, bool> interpolateGeneratedDSPData(unsigned n);

public:
	unsigned int id;                // the id is incremented for every new noteon.
					        // it's used for noteoff's
	unsigned char status;
	unsigned char chan;             // the channel number, quick access for channel messages
	unsigned char key;              // the key, quick access for noteoff
	unsigned char vel;              // the velocity

	Channel* channel;
	Generator gen[GEN_LAST];
	Mod mod[FLUID_NUM_MOD];

	int mod_count;
	bool has_looped;                /* Flag that is set as soon as the first loop is completed. */
	Sample* sample;
	int check_sample_sanity_flag;   /* Flag that initiates, that sample-related parameters
					           have to be checked. */
	unsigned int ticks;

	float amp;                       /* the linear amplitude */
	Phase phase;                     // the phase of the sample wave

	// Temporary variables used in write()
	float phase_incr;	      /* the phase increment for the next 64 samples */
      qreal amp_incr;		/* amplitude increment value */
      std::vector<float> dsp_buf;	      /* buffer to store interpolated sample data to */

	/* basic parameters */
	float pitch;              /* the pitch in midicents */
	float attenuation;        /* the attenuation in centibels */
	float min_attenuation_cB; /* Estimate on the smallest possible attenuation
					          * during the lifetime of the voice */
	float root_pitch, root_pitch_hz;

	/* sample and loop start and end points (offset in sample memory).  */
	int start;
	int end;
	int loopstart;
	int loopend;

	/* vol env */
	fluid_env_data_t volenv_data[FLUID_VOICE_ENVLAST];
	unsigned int volenv_count;
	int volenv_section;
   std::map<int, qreal> Sample2AmpInc;
	float volenv_val;
	float amplitude_that_reaches_noise_floor_nonloop;
	float amplitude_that_reaches_noise_floor_loop;
   int positionToTurnOff; // this is the sample accurate position where the sample reaches the noise floor

	/* mod env */
	fluid_env_data_t modenv_data[FLUID_VOICE_ENVLAST];
	unsigned int modenv_count;
	int modenv_section;
	float modenv_val;         /* the value of the modulation envelope */
	float modenv_to_fc;
	float modenv_to_pitch;

	/* mod lfo */
	float modlfo_val;          /* the value of the modulation LFO */
	unsigned int modlfo_delay;       /* the delay of the lfo in samples */
   unsigned int modlfo_pos;
   unsigned int modlfo_dur; // duration in samples
   float modlfo_to_fc;
	float modlfo_to_pitch;
	float modlfo_to_vol;

	/* vib lfo */
	float viblfo_val;        /* the value of the vibrato LFO */
	unsigned int viblfo_delay;      /* the delay of the lfo in samples */
	float viblfo_incr;       /* the lfo frequency is converted to a per-buffer increment */
	float viblfo_to_pitch;

	/* resonant filter */
	float fres;              /* the resonance frequency, in cents (not absolute cents) */
	float last_fres;         /* Current resonance frequency of the IIR filter */
	/* Serves as a flag: A deviation between fres and last_fres */
	/* indicates, that the filter has to be recalculated. */
	float q_lin;             /* the q-factor on a linear scale */
	float filter_gain;       /* Gain correction factor, depends on q */
	float hist1, hist2;      /* Sample history for the IIR filter */
	int filter_startup;             /* Flag: If set, the filter will be set directly.
					   Else it changes smoothly. */

	/* filter coefficients */
	/* The coefficients are normalized to a0. */
	/* b0 and b2 are identical => b02 */
	float b02;              /* b0 / a0 */
	float b1;              /* b1 / a0 */
	float a1;              /* a0 / a0 */
	float a2;              /* a1 / a0 */

	float b02_incr;
	float b1_incr;
	float a1_incr;
	float a2_incr;
	int filter_coeff_incr_count;

	/* pan */
	float pan;
	float amp_left;
	float amp_right;

	/* reverb */
	float reverb_send;
	float amp_reverb;

	/* chorus */
	float chorus_send;
	float amp_chorus;

	/* interpolation method, as in fluid_interp in fluidsynth.h */
	int interp_method;

	/* for debugging */
	int debug;
	double ref;

   public:
      Voice(Fluid*);
      Channel* get_channel() const    { return channel; }
      void voice_start();
      void off();
      void init(Sample*, Channel*, int key, int vel, unsigned id, double tuning);
      void gen_incr(int i, float val);
      void gen_set(int i, float val);
      float gen_get(int gen);
      unsigned int get_id() const { return id; }
      bool isPlaying()            { return ((status == FLUID_VOICE_ON) || (status == FLUID_VOICE_SUSTAINED)); }
      void set_param(int gen, float nrpn_value, int abs);

      // Update all the synthesis parameters, which depend on generator
      // 'gen'. This is only necessary after changing a generator of an
      // already operating voice.  Most applications will not need this
      // function.

      void update_param(int gen);

      double GEN(int n) { return gen[n].val + gen[n].mod + gen[n].nrpn; }

      void modulate_all();
      void modulate(bool _cc, int _ctrl);
      float get_lower_boundary_for_attenuation();
      void check_sample_sanity();
      void noteoff();
      void kill_excl();
      int calculate_hold_decay_frames(int gen_base, int gen_key2base, int is_decay);
      void calculate_gen_pitch();

      /* A voice is 'ON', if it has not yet received a noteoff
       * event. Sending a noteoff event will advance the envelopes to
       * section 5 (release).
       */
      bool RELEASED() const    { return chan == NO_CHANNEL; }
      bool SUSTAINED() const   { return status == FLUID_VOICE_SUSTAINED; }
      bool PLAYING() const     { return (status == FLUID_VOICE_ON) || (status == FLUID_VOICE_SUSTAINED); }
      bool ON() const          { return (status == FLUID_VOICE_ON) && (volenv_section < FLUID_VOICE_ENVRELEASE); }
      int SAMPLEMODE() const   { return ((int)gen[GEN_SAMPLEMODE].val); }

      void calcVolEnv(int n, fluid_env_data_t *env_data);
      void write(unsigned n, float* out, float* reverb, float* chorus);
      void add_mod(const Mod* mod, int mode);

      static void dsp_float_config();
      bool updateAmpInc(unsigned int &nextNewAmpInc, std::map<int, qreal>::iterator &curSample2AmpInc, qreal &dsp_amp_incr, unsigned int &dsp_i);
      int dsp_float_interpolate_none(unsigned);
      int dsp_float_interpolate_linear(unsigned);
      int dsp_float_interpolate_4th_order(unsigned);
      int dsp_float_interpolate_7th_order(unsigned);
      };
}


#endif /* _FLUID_VOICE_H */