File: fluid.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 (695 lines) | stat: -rw-r--r-- 24,116 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
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
/*
 *
 * 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_S_H__
#define __FLUID_S_H__

#include "synthesizer/synthesizer.h"
#include "synthesizer/midipatch.h"

namespace FluidS {

using namespace Ms;

class Voice;
class SFont;
class Preset;
class Sample;
class Channel;
struct Mod;
class Fluid;

#define FLUID_NUM_PROGRAMS      129

enum fluid_loop {
      FLUID_UNLOOPED            = 0,
      FLUID_LOOP_DURING_RELEASE = 1,
      FLUID_NOTUSED             = 2,
      FLUID_LOOP_UNTIL_RELEASE  = 3
      };

enum fluid_synth_status {
      FLUID_SYNTH_CLEAN,
      FLUID_SYNTH_PLAYING,
      FLUID_SYNTH_QUIET,
      FLUID_SYNTH_STOPPED
      };

//---------------------------------------------------------
//   BankOffset
//---------------------------------------------------------

struct BankOffset {
      int sfont_id;
      int offset;
      };

enum fluid_midi_control_change {
      BANK_SELECT_MSB = 0x00,
      MODULATION_MSB = 0x01,
      BREATH_MSB = 0x02,
      FOOT_MSB = 0x04,
      PORTAMENTO_TIME_MSB = 0x05,
      DATA_ENTRY_MSB = 0x06,
      VOLUME_MSB = 0x07,
      BALANCE_MSB = 0x08,
      PAN_MSB = 0x0A,
      EXPRESSION_MSB = 0x0B,
      EFFECTS1_MSB = 0x0C,
      EFFECTS2_MSB = 0x0D,
      GPC1_MSB = 0x10, /* general purpose controller */
      GPC2_MSB = 0x11,
      GPC3_MSB = 0x12,
      GPC4_MSB = 0x13,
      BANK_SELECT_LSB = 0x20,
      MODULATION_WHEEL_LSB = 0x21,
      BREATH_LSB = 0x22,
      FOOT_LSB = 0x24,
      PORTAMENTO_TIME_LSB = 0x25,
      DATA_ENTRY_LSB = 0x26,
      VOLUME_LSB = 0x27,
      BALANCE_LSB = 0x28,
      PAN_LSB = 0x2A,
      EXPRESSION_LSB = 0x2B,
      EFFECTS1_LSB = 0x2C,
      EFFECTS2_LSB = 0x2D,
      GPC1_LSB = 0x30,
      GPC2_LSB = 0x31,
      GPC3_LSB = 0x32,
      GPC4_LSB = 0x33,
      SUSTAIN_SWITCH = 0x40,
      PORTAMENTO_SWITCH = 0x41,
      SOSTENUTO_SWITCH = 0x42,
      SOFT_PEDAL_SWITCH = 0x43,
      LEGATO_SWITCH = 0x45,
      HOLD2_SWITCH = 0x45,
      SOUND_CTRL1 = 0x46,
      SOUND_CTRL2 = 0x47,
      SOUND_CTRL3 = 0x48,
      SOUND_CTRL4 = 0x49,
      SOUND_CTRL5 = 0x4A,
      SOUND_CTRL6 = 0x4B,
      SOUND_CTRL7 = 0x4C,
      SOUND_CTRL8 = 0x4D,
      SOUND_CTRL9 = 0x4E,
      SOUND_CTRL10 = 0x4F,
      GPC5 = 0x50,
      GPC6 = 0x51,
      GPC7 = 0x52,
      GPC8 = 0x53,
      PORTAMENTO_CTRL = 0x54,
      EFFECTS_DEPTH1 = 0x5B,
      EFFECTS_DEPTH2 = 0x5C,
      EFFECTS_DEPTH3 = 0x5D,
      EFFECTS_DEPTH4 = 0x5E,
      EFFECTS_DEPTH5 = 0x5F,
      DATA_ENTRY_INCR = 0x60,
      DATA_ENTRY_DECR = 0x61,
      NRPN_LSB = 0x62,
      NRPN_MSB = 0x63,
      RPN_LSB = 0x64,
      RPN_MSB = 0x65,
      ALL_SOUND_OFF = 0x78,
      ALL_CTRL_OFF = 0x79,
      LOCAL_CONTROL = 0x7A,
      ALL_NOTES_OFF = 0x7B,
      OMNI_OFF = 0x7C,
      OMNI_ON = 0x7D,
      POLY_OFF = 0x7E,
      POLY_ON = 0x7F
      };

/**
 * Generator (effect) numbers (SoundFont 2.01 specifications section 8.1.3)
 */
enum fluid_gen_type {
  GEN_STARTADDROFS,		/**< Sample start address offset (0-32767) */
  GEN_ENDADDROFS,		      /**< Sample end address offset (-32767-0) */
  GEN_STARTLOOPADDROFS,		/**< Sample loop start address offset (-32767-32767) */
  GEN_ENDLOOPADDROFS,		/**< Sample loop end address offset (-32767-32767) */
  GEN_STARTADDRCOARSEOFS,	/**< Sample start address coarse offset (X 32768) */
  GEN_MODLFOTOPITCH,		/**< Modulation LFO to pitch */
  GEN_VIBLFOTOPITCH,		/**< Vibrato LFO to pitch */
  GEN_MODENVTOPITCH,		/**< Modulation envelope to pitch */
  GEN_FILTERFC,			/**< Filter cutoff */
  GEN_FILTERQ,			/**< Filter Q */
  GEN_MODLFOTOFILTERFC,		/**< Modulation LFO to filter cutoff */
  GEN_MODENVTOFILTERFC,		/**< Modulation envelope to filter cutoff */
  GEN_ENDADDRCOARSEOFS,		/**< Sample end address coarse offset (X 32768) */
  GEN_MODLFOTOVOL,		/**< Modulation LFO to volume */
  GEN_UNUSED1,			/**< Unused */
  GEN_CHORUSSEND,		      /**< Chorus send amount */
  GEN_REVERBSEND,		      /**< Reverb send amount */
  GEN_PAN,			      /**< Stereo panning */
  GEN_UNUSED2,			/**< Unused */
  GEN_UNUSED3,			/**< Unused */
  GEN_UNUSED4,			/**< Unused */
  GEN_MODLFODELAY,		/**< Modulation LFO delay */
  GEN_MODLFOFREQ,		      /**< Modulation LFO frequency */
  GEN_VIBLFODELAY,		/**< Vibrato LFO delay */
  GEN_VIBLFOFREQ,		      /**< Vibrato LFO frequency */
  GEN_MODENVDELAY,		/**< Modulation envelope delay */
  GEN_MODENVATTACK,		/**< Modulation envelope attack */
  GEN_MODENVHOLD,		      /**< Modulation envelope hold */
  GEN_MODENVDECAY,		/**< Modulation envelope decay */
  GEN_MODENVSUSTAIN,		/**< Modulation envelope sustain */
  GEN_MODENVRELEASE,		/**< Modulation envelope release */
  GEN_KEYTOMODENVHOLD,		/**< Key to modulation envelope hold */
  GEN_KEYTOMODENVDECAY,		/**< Key to modulation envelope decay */
  GEN_VOLENVDELAY,		/**< Volume envelope delay */
  GEN_VOLENVATTACK,		/**< Volume envelope attack */
  GEN_VOLENVHOLD,		      /**< Volume envelope hold */
  GEN_VOLENVDECAY,		/**< Volume envelope decay */
  GEN_VOLENVSUSTAIN,		/**< Volume envelope sustain */
  GEN_VOLENVRELEASE,		/**< Volume envelope release */
  GEN_KEYTOVOLENVHOLD,		/**< Key to volume envelope hold */
  GEN_KEYTOVOLENVDECAY,		/**< Key to volume envelope decay */
  GEN_INSTRUMENT,		      /**< Instrument ID (shouldn't be set by user) */
  GEN_RESERVED1,		      /**< Reserved */
  GEN_KEYRANGE,			/**< MIDI note range */
  GEN_VELRANGE,			/**< MIDI velocity range */
  GEN_STARTLOOPADDRCOARSEOFS,	/**< Sample start loop address coarse offset (X 32768) */
  GEN_KEYNUM,			/**< Fixed MIDI note number */
  GEN_VELOCITY,			/**< Fixed MIDI velocity value */
  GEN_ATTENUATION,		/**< Initial volume attenuation */
  GEN_RESERVED2,		      /**< Reserved */
  GEN_ENDLOOPADDRCOARSEOFS,	/**< Sample end loop address coarse offset (X 32768) */
  GEN_COARSETUNE,		      /**< Coarse tuning */
  GEN_FINETUNE,			/**< Fine tuning */
  GEN_SAMPLEID,			/**< Sample ID (shouldn't be set by user) */
  GEN_SAMPLEMODE,		      /**< Sample mode flags */
  GEN_RESERVED3,		      /**< Reserved */
  GEN_SCALETUNE,		      /**< Scale tuning */
  GEN_EXCLUSIVECLASS,		/**< Exclusive class number */
  GEN_OVERRIDEROOTKEY,		/**< Sample root note override */

  /* the initial pitch is not a "standard" generator. It is not
   * mentioned in the list of generator in the SF2 specifications. It
   * is used, however, as the destination for the default pitch wheel
   * modulator. */
  GEN_PITCH,			/**< Pitch (NOTE: Not a real SoundFont generator) */
  GEN_LAST			      /**< Value defines the count of generators (#fluid_gen_type) */
      };

//---------------------------------------------------------
//   Channel
//---------------------------------------------------------

class Channel {
      Fluid* synth;

      unsigned int sfontnum;
      unsigned int banknum;
      unsigned int prognum;
      Preset* _preset;

   public:
      int channum;
      short key_pressure;
      short channel_pressure;
      short pitch_bend;
      short pitch_wheel_sensitivity;

      short cc[128];          // controller values

      /* cached values of last MSB values of MSB/LSB controllers */
      unsigned char bank_msb;
      int interp_method;

      /* NRPN system */
      short nrpn_select;

      /* The values of the generators, set by NRPN messages, or by
       * fluid_synth_set_gen(), are cached in the channel so they can be
       * applied to future notes. They are copied to a voice's generators
       * in fluid_voice_init(), wihich calls fluid_gen_init().  */

      float gen[GEN_LAST];

      /* By default, the NRPN values are relative to the values of the
       * generators set in the SoundFont. For example, if the NRPN
       * specifies an attack of 100 msec then 100 msec will be added to the
       * combined attack time of the sound font and the modulators.
       *
       * However, it is useful to be able to specify the generator value
       * absolutely, completely ignoring the generators of the sound font
       * and the values of modulators. The gen_abs field, is a boolean
       * flag indicating whether the NRPN value is absolute or not.
       */
      char gen_abs[GEN_LAST];

   public:
      Channel(Fluid* synth, int num);

      bool sustained() const              { return cc[SUSTAIN_SWITCH] >= 64; }
      void setGen(int n, float v, char a) { gen[n] = v; gen_abs[n] = a; }
      float getGen(int n) const           { return gen[n]; }
      char getGenAbs(int n) const         { return gen_abs[n]; }
      void init();
      void initCtrl();
      void setCC(int n, int val)          { cc[n] = val; }
      void reset();
      void setPreset(Preset* p);
      Preset* preset() const              { return _preset;  }
      unsigned int getSfontnum() const    { return sfontnum; }
      void setSfontnum(unsigned int s)    { sfontnum = s;    }
      unsigned int getBanknum() const     { return banknum;  }
      void setBanknum(unsigned int b)     { banknum = b;     }
      void setPrognum(int p)              { prognum = p;     }
      int getPrognum() const              { return prognum;  }
      void setcc(int ctrl, int val);
      void pitchBend(int val);
      int getPitchBend() const            { return pitch_bend; }
      void pitchWheelSens(int val);
      int getCC(int num);
      int getNum() const                  { return channum;    }
      void setInterpMethod(int m)         { interp_method = m; }
      int getInterpMethod() const         { return interp_method; }
      };

// subsystems:
enum {
      FLUID_GROUP  = 0,
      };

//---------------------------------------------------------
//   Fluid
//---------------------------------------------------------

class Fluid : public Synthesizer {
      QList<SFont*> sfonts;               // the loaded soundfonts
      QList<MidiPatch*> patches;

      QList<Voice*> freeVoices;           // unused synthesis processes
      QList<Voice*> activeVoices;         // active synthesis processes
      QString _error;                     // last error message

      static bool initialized;

      double sample_rate;                 // The sample rate
      float _masterTuning;                // usually 440.0
      double _tuning[128];                // the pitch of every key, in cents

      int _loadProgress = 0;
      bool _loadWasCanceled = false;

      QMutex mutex;
      void updatePatchList();

      //the variable is used to stop loading samples from the sf files
      bool _globalTerminate = false;

   protected:
      int _state;                         // the synthesizer state

      unsigned int sfont_id;

      QList<Channel*> channel;            // the channels

      unsigned int noteid;                // the id is incremented for every new note. it's used for noteoff's

      SFont* get_sfont_by_name(const QString& name);
      SFont* get_sfont_by_id(int id);
      SFont* get_sfont(int idx) const     { return sfonts[idx];   }
      bool sfunload(int id);
      int sfload(const QString& filename);

   public:
      Fluid();
      ~Fluid();
      virtual void init(float sampleRate);

      virtual const char* name() const { return "Fluid"; }

      virtual void play(const PlayEvent&);
      virtual const QList<MidiPatch*>& getPatchInfo() const { return patches; }

      // get/set synthesizer state (parameter set)
      virtual SynthesizerGroup state() const;
      virtual bool setState(const SynthesizerGroup&);

      virtual void allSoundsOff(int);
      virtual void allNotesOff(int);

      int loadProgress()            { return _loadProgress; }
      void setLoadProgress(int val) { _loadProgress = val; }
      bool loadWasCanceled()        { return _loadWasCanceled; }
      void setLoadWasCanceled(bool status)     { _loadWasCanceled = status; }

      Preset* get_preset(unsigned int sfontnum, unsigned int banknum, unsigned int prognum);
      Preset* find_preset(unsigned int banknum, unsigned int prognum);
      void modulate_voices(int chan, bool is_cc, int ctrl);
      void modulate_voices_all(int chan);
      void damp_voices(int chan);
      int kill_voice(Voice * voice);
      void print_voice();

      /** This function assures that every MIDI channels has a valid preset
       *  (NULL is okay). This function is called after a SoundFont is
       *  unloaded or reloaded. */
      void update_presets();

      int get_cc(int chan, int num) const { return channel[chan]->cc[num]; }

      void system_reset();
      void program_change(int chan, int prognum);

      void set_gen2(int chan, int param, float value, int absolute, int normalized);
      float get_gen(int chan, int param);
      void set_gen(int chan, int param, float value);
      void set_interp_method(int chan, int interp_method);

      Preset* get_channel_preset(int chan) const { return channel[chan]->preset(); }

      virtual bool loadSoundFonts(const QStringList& s);
      virtual bool addSoundFont(const QString& s);
      virtual bool removeSoundFont(const QString& s);
      QStringList soundFonts() const;
      std::vector<SoundFontInfo> soundFontsInfo() const override;

      void start_voice(Voice* voice);
      Voice* alloc_voice(unsigned id, Sample* sample, int chan, int key, int vel, double vt);
      void free_voice_by_kill();

      virtual void process(unsigned len, float* out, float* effect1, float* effect2);

      bool program_select(int chan, unsigned sfont_id, unsigned bank_num, unsigned preset_num);
      void get_program(int chan, unsigned* sfont_id, unsigned* bank_num, unsigned* preset_num);
//      void sfont_select(int chan, unsigned int sfont_id)    { channel[chan]->setSfontnum(sfont_id); }
//      void bank_select(int chan, unsigned int bank)         { channel[chan]->setBanknum(bank); }

      void get_pitch_wheel_sens(int chan, int* pval);
      void pitch_wheel_sens(int chan, int val);
      void get_pitch_bend(int chan, int* ppitch_bend);

      void freeVoice(Voice* v);

      double getPitch(int k) const   { return _tuning[k]; }
      float ct2hz_real(float cents)  { return powf(2.0f, (cents - 6900.0f) / 1200.0f) * _masterTuning; }

      float act2hz(float c)          { return 8.176 * pow(2.0, (double) c / 1200.0); }
      float ct2hz(float cents)       { return act2hz(qBound(1500.0f, cents, 13500.0f)); }

      virtual double masterTuning() const     { return _masterTuning; }
      virtual void setMasterTuning(double f)  { _masterTuning = f;    }

      QString error() const { return _error; }

      virtual SynthesizerGui* gui();

      static QFileInfoList sfFiles();

      bool globalTerminate() { return _globalTerminate; }
      void setGlobalTerminate(bool terminate = true) { _globalTerminate = terminate; }

      friend class Voice;
      friend class Preset;
      };

  /*
   *
   * Chorus
   *
   */

enum fluid_chorus_mod {
      FLUID_CHORUS_MOD_SINE = 0,
      FLUID_CHORUS_MOD_TRIANGLE = 1
      };

/* Those are the default settings for the chorus. */
#define FLUID_CHORUS_DEFAULT_N      3
#define FLUID_CHORUS_DEFAULT_LEVEL  2.0f
#define FLUID_CHORUS_DEFAULT_SPEED  0.3f
#define FLUID_CHORUS_DEFAULT_DEPTH  8.0f
#define FLUID_CHORUS_DEFAULT_TYPE   FLUID_CHORUS_MOD_SINE


  /*
   *
   * Synthesis parameters
   *
   */

  /* Flags to choose the interpolation method */
enum fluid_interp {
      /* no interpolation: Fastest, but questionable audio quality */
      FLUID_INTERP_NONE     = 0,
      /* Straight-line interpolation: A bit slower, reasonable audio quality */
      FLUID_INTERP_LINEAR   = 1,
      /* Fourth-order interpolation: Requires 50 % of the whole DSP processing time, good quality
       * Default. */
      FLUID_INTERP_DEFAULT  = 4,
      FLUID_INTERP_4THORDER = 4,
      FLUID_INTERP_7THORDER = 7,
      FLUID_INTERP_HIGHEST  = 7
      };

#define fluid_sample_refcount(_sample) ((_sample)->refcount)


/** Sample types */

enum {
      FLUID_SAMPLETYPE_MONO =	      1,
      FLUID_SAMPLETYPE_RIGHT =	2,
      FLUID_SAMPLETYPE_LEFT =	      4,
      FLUID_SAMPLETYPE_LINKED =	8,
      FLUID_SAMPLETYPE_OGG_VORBIS = 0x10,
      FLUID_SAMPLETYPE_ROM =	      0x8000
      };

/* Sets the sound data of the sample
 *     Warning : if copy_data is FALSE, data should have 8 unused frames at start
 *     and 8 unused frames at the end.
 */
int fluid_sample_set_sound_data(Sample* sample, short *data,
			       unsigned int nbframes, short copy_data, int rootkey);

/*
 *
 *  Utility functions
 */

  /* Maximum number of modulators in a voice */
#define FLUID_NUM_MOD           64

/**
 * SoundFont generator structure.
 */
class Generator {
   public:
      unsigned char flags; /**< Is the generator set or not (#fluid_gen_flags) */
      double val;          /**< The nominal value           */
      double mod;          /**< Change by modulators        */
      double nrpn;         /**< Change by NRPN messages     */

      void set_mod(double _val)  { mod  = _val; }
      void set_nrpn(double _val) { nrpn = _val; }
      };

/**
 * Enum value for 'flags' field of #_Generator (not really flags).
 */
enum fluid_gen_flags {
      GEN_UNUSED,		/**< Generator value is not set */
      GEN_SET,		/**< Generator value is set     */
      GEN_ABS_NRPN	/**< DOCME                      */
      };

void fluid_gen_set_default_values(Generator* gen);
  /*
   *  The interface to the synthesizer's voices
   *  Examples on using them can be found in fluid_defsfont.c
   */

  /* for fluid_voice_add_mod */
enum fluid_voice_add_mod {
      FLUID_VOICE_OVERWRITE,
      FLUID_VOICE_ADD,
      FLUID_VOICE_DEFAULT
      };

/* Disable FPE exception check */
#define fluid_check_fpe(expl)

unsigned int fluid_check_fpe_i386(char * explanation_in_case_of_fpe);

/*
 * interpolation data
 */
struct fluid_interp_coeff_t {
      float a0, a1, a2, a3;
      };

/* Flags telling the polarity of a modulator.  Compare with SF2.01
   section 8.2. Note: The numbers of the bits are different!  (for
   example: in the flags of a SF modulator, the polarity bit is bit
   nr. 9) */

enum fluid_mod_flags {
      FLUID_MOD_POSITIVE = 0,
      FLUID_MOD_NEGATIVE = 1,
      FLUID_MOD_UNIPOLAR = 0,
      FLUID_MOD_BIPOLAR  = 2,
      FLUID_MOD_LINEAR   = 0,
      FLUID_MOD_CONCAVE  = 4,
      FLUID_MOD_CONVEX   = 8,
      FLUID_MOD_SWITCH   = 12,
      FLUID_MOD_GC       = 0,
      FLUID_MOD_CC       = 16
      };

//---------------------------------------------------------
//   Mod
//---------------------------------------------------------

struct Mod
      {
      unsigned char dest;
      unsigned char src1;
      unsigned char flags1;
      unsigned char src2;
      unsigned char flags2;
      double amount;

      void clone(Mod* mod) const;
      void dump() const;
      int has_source(bool cc, int ctrl) {
            return (((src1 == ctrl) && (flags1 & FLUID_MOD_CC)    && cc)
                || (((src1 == ctrl) && (!(flags1 & FLUID_MOD_CC)) && !cc)))
                || (((src2 == ctrl) && (flags2 & FLUID_MOD_CC)    && cc)
                || (((src2 == ctrl) && (!(flags2 & FLUID_MOD_CC)) && !cc)));
            }
      void set_source1(int src, int flags);
      void set_source2(int src, int flags);
      void set_dest(int val)                    { dest = val;    }
      void set_amount(double val)               { amount = val;  }
      int get_source1() const                   { return src1;   }
      int get_flags1() const                    { return flags1; }
      int get_source2() const                   { return src2;   }
      int get_flags2() const                    { return flags2; }
      int get_dest() const                      { return dest;   }
      double get_amount() const                 { return amount; }
      float get_value(Channel* chan, Voice* voice);
      };

/* Flags telling the source of a modulator.  This corresponds to
 * SF2.01 section 8.2.1 */

enum fluid_mod_src {
      FLUID_MOD_NONE             = 0,
      FLUID_MOD_VELOCITY         = 2,
      FLUID_MOD_KEY              = 3,
      FLUID_MOD_KEYPRESSURE      = 10,
      FLUID_MOD_CHANNELPRESSURE  = 13,
      FLUID_MOD_PITCHWHEEL       = 14,
      FLUID_MOD_PITCHWHEELSENS   = 16
      };

/* Determines, if two modulators are 'identical' (all parameters
   except the amount match) */
bool test_identity(const Mod * mod1, const Mod * mod2);

void fluid_dump_modulator(Mod * mod);

#define fluid_mod_has_source(mod,cc,ctrl)  \
( ((((mod)->src1 == ctrl) && (((mod)->flags1 & FLUID_MOD_CC) != 0) && (cc != 0)) \
   || ((((mod)->src1 == ctrl) && (((mod)->flags1 & FLUID_MOD_CC) == 0) && (cc == 0)))) \
|| ((((mod)->src2 == ctrl) && (((mod)->flags2 & FLUID_MOD_CC) != 0) && (cc != 0)) \
    || ((((mod)->src2 == ctrl) && (((mod)->flags2 & FLUID_MOD_CC) == 0) && (cc == 0)))))

#define fluid_mod_has_dest(mod,gen)  ((mod)->dest == gen)

/*
 *  phase
 */

#define FLUID_INTERP_BITS        8
#define FLUID_INTERP_BITS_MASK   0xff000000
#define FLUID_INTERP_BITS_SHIFT  24
#define FLUID_INTERP_MAX         256

#define FLUID_FRACT_MAX ((double)4294967296.0)

//---------------------------------------------------------
//   Phase
/* Purpose:
* Playing pointer for voice playback
*
* When a sample is played back at a different pitch, the playing pointer in the
* source sample will not advance exactly one sample per output sample.
* This playing pointer is implemented using Phase.
* It is a 64 bit number. The higher 32 bits contain the 'index' (number of
* the current sample), the lower 32 bits the fractional part.
* Access is possible in two ways:
* -through the 64 bit part 'b64', if the architecture supports 64 bit integers
* -through 'index' and 'fract'
* Note: b64 and index / fract share the same memory location!
*/

struct Phase {
      qint64 data;

      void operator+=(const Phase& p) { data += p.data; }
      void setInt(qint32 b)           { data = qint64(b) << 32; }
      void setFloat(double b)          {
             data = (((qint64)(b)) << 32) | (quint32) (((double)(b) - (int)(b)) * (double)FLUID_FRACT_MAX);
            }

      void operator-=(const Phase& b) { data -= b.data;  }
      void operator-=(int b)          { data -= (qint64(b) << 32);  }
      int index() const               { return data >> 32; }
      quint32 fract() const           { return quint32(data & 0xffffffff); }
      quint32 index_round() const     { return quint32((data+0x80000000) >> 32); }

      Phase() {}
      Phase(qint64 v) : data(v) {}
      };

/* Purpose:
 * Takes the fractional part of the argument phase and
 * calculates the corresponding position in the interpolation table.
 * The fractional position of the playing pointer is calculated with a quite high
 * resolution (32 bits). It would be unpractical to keep a set of interpolation
 * coefficients for each possible fractional part...
 */
#define fluid_phase_fract_to_tablerow(_x) \
  ((int)(((_x).fract() & FLUID_INTERP_BITS_MASK) >> FLUID_INTERP_BITS_SHIFT))

#define fluid_phase_double(_x) \
  ((double)((_x).index()) + ((double)((_x).fract()) / FLUID_FRACT_MAX))

/* Purpose:
 * The playing pointer is _phase. How many output samples are produced, until the point _p1 in the sample is reached,
 * if _phase advances in steps of _incr?
 */
#define fluid_phase_steps(_phase,_idx,_incr) \
  (int)(((double)(_idx) - fluid_phase_double(_phase)) / (double)_incr)

/* Purpose:
 * Creates the expression a.index++.
*/
#define fluid_phase_index_plusplus(a) (((a)._index)++)

}  // namespace Fluid

#endif  // __FLUID_S_H__