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  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18  * 02111-1307, USA
19  */
20 
21 #include "fluid.h"
22 #include "sfont.h"
23 #include "conv.h"
24 #include "gen.h"
25 #include "voice.h"
26 
27 #include "midi/event.h"
28 #include "midi/msynthesizer.h"
29 
30 #include "mscore/preferences.h"
31 #include "mscore/extension.h"
32 
33 namespace FluidS {
34 
35 /***************************************************************
36  *
37  *                         GLOBAL
38  */
39 
40 bool Fluid::initialized = false;
41 
42 /* better than a macro to determine inappropriate values for notes*/
validNote(const int input)43 bool validNote(const int input) {
44       return (input < 255 && input > -1);
45       }
46 
47 /* default modulators
48  * SF2.01 page 52 ff:
49  *
50  * There is a set of predefined default modulators. They have to be
51  * explicitly overridden by the sound font in order to turn them off.
52  */
53 
54 static const Mod defaultMod[] = {
55       { GEN_ATTENUATION, FLUID_MOD_VELOCITY, FLUID_MOD_GC | FLUID_MOD_CONCAVE | FLUID_MOD_UNIPOLAR | FLUID_MOD_NEGATIVE, 0, 0, 960.0 },
56       { GEN_FILTERFC,
57          FLUID_MOD_VELOCITY, FLUID_MOD_GC | FLUID_MOD_LINEAR | FLUID_MOD_UNIPOLAR | FLUID_MOD_NEGATIVE,
58          FLUID_MOD_VELOCITY, FLUID_MOD_GC | FLUID_MOD_SWITCH | FLUID_MOD_UNIPOLAR | FLUID_MOD_POSITIVE,
59          -2400 },
60       { GEN_VIBLFOTOPITCH, FLUID_MOD_CHANNELPRESSURE, FLUID_MOD_GC | FLUID_MOD_LINEAR | FLUID_MOD_UNIPOLAR | FLUID_MOD_POSITIVE, 0, 0, 50 },
61       { GEN_VIBLFOTOPITCH, 1, FLUID_MOD_CC | FLUID_MOD_LINEAR | FLUID_MOD_UNIPOLAR | FLUID_MOD_POSITIVE, 0, 0, 50 },
62       { GEN_ATTENUATION, 7, FLUID_MOD_CC | FLUID_MOD_CONCAVE | FLUID_MOD_UNIPOLAR | FLUID_MOD_NEGATIVE, 0, 0, 960.0 },
63       { GEN_PAN, 10, FLUID_MOD_CC | FLUID_MOD_LINEAR | FLUID_MOD_BIPOLAR | FLUID_MOD_POSITIVE, 0, 0, 500.0 },
64       { GEN_ATTENUATION, 11, FLUID_MOD_CC | FLUID_MOD_CONCAVE | FLUID_MOD_UNIPOLAR | FLUID_MOD_NEGATIVE, 0, 0, 960.0 },
65       { GEN_REVERBSEND, 91, FLUID_MOD_CC | FLUID_MOD_LINEAR | FLUID_MOD_UNIPOLAR | FLUID_MOD_POSITIVE, 0, 0, 200 },
66       { GEN_CHORUSSEND, 93, FLUID_MOD_CC | FLUID_MOD_LINEAR | FLUID_MOD_UNIPOLAR | FLUID_MOD_POSITIVE, 0, 0, 200 },
67       { GEN_PITCH,
68            FLUID_MOD_PITCHWHEEL,     FLUID_MOD_GC | FLUID_MOD_LINEAR | FLUID_MOD_BIPOLAR  | FLUID_MOD_POSITIVE,
69            FLUID_MOD_PITCHWHEELSENS, FLUID_MOD_GC | FLUID_MOD_LINEAR | FLUID_MOD_UNIPOLAR | FLUID_MOD_POSITIVE,
70         12700.0 },
71       };
72 
73 static const Mod forcePanMod = { GEN_PAN, 10, FLUID_MOD_CC | FLUID_MOD_LINEAR | FLUID_MOD_BIPOLAR | FLUID_MOD_POSITIVE, 0, 0, 1000.0 };
74 
75 //---------------------------------------------------------
76 //   Fluid
77 //---------------------------------------------------------
78 
Fluid()79 Fluid::Fluid()
80    : Synthesizer()
81       {
82       }
83 
84 //---------------------------------------------------------
85 //   init
86 //    instance initialization
87 //---------------------------------------------------------
88 
init(float sampleRate)89 void Fluid::init(float sampleRate)
90       {
91       if (!initialized) {     // initialize all the conversion tables and other stuff
92             initialized = true;
93             fluid_conversion_config();
94             Voice::dsp_float_config();
95             }
96       Synthesizer::init(sampleRate);
97       sample_rate        = sampleRate;
98       sfont_id           = 0;
99 
100       _state       = FLUID_SYNTH_PLAYING; // as soon as the synth is created it starts playing.
101       noteid      = 0;
102       for (int i = 0; i < 128; ++i)
103             _tuning[i] = i * 100.0;
104       _masterTuning = 440.0;
105 
106       fromkey_portamento = Channel::INVALID_NOTE;
107       lastNote = Channel::INVALID_NOTE;
108 
109       for (int i = 0; i < 512; i++)
110             freeVoices.append(new Voice(this));
111       }
112 
113 //---------------------------------------------------------
114 //   ~Fluid
115 //---------------------------------------------------------
116 
~Fluid()117 Fluid::~Fluid()
118       {
119       _state = FLUID_SYNTH_STOPPED;
120       _globalTerminate = true;
121       while (!mutex.tryLock()) {}
122       qDeleteAll(activeVoices);
123       qDeleteAll(freeVoices);
124       qDeleteAll(sfonts);
125       qDeleteAll(channel);
126       qDeleteAll(patches);
127       }
128 
129 //---------------------------------------------------------
130 //   freeVoice
131 //---------------------------------------------------------
132 
freeVoice(Voice * v)133 void Fluid::freeVoice(Voice* v)
134       {
135       if (activeVoices.removeOne(v))
136             freeVoices.append(v);
137       }
138 
139 //---------------------------------------------------------
140 //   play
141 //---------------------------------------------------------
142 
play(const PlayEvent & event)143 void Fluid::play(const PlayEvent& event)
144       {
145       bool err = false;
146       int ch   = event.channel();
147 
148       if (ch >= channel.size()) {
149             for (int i = channel.size(); i < ch+1; i++)
150                   channel.append(new Channel(this, i));
151             }
152 
153       int type    = event.type();
154       Channel* cp = channel[ch];
155 
156       if (type == ME_NOTEON) {
157             int key = event.dataA();
158             int vel = event.dataB();
159             if (vel == 0) {
160                   //
161                   // process note off
162                   //
163                   for (Voice* v : qAsConst(activeVoices)) {
164                         if (v->ON() && (v->chan == ch) && (v->key == key))
165                               v->noteoff();
166                         }
167                   return;
168                   }
169             if (cp->preset() == 0) {
170                   qDebug("channel has no preset");
171                   err = true;
172                   }
173             else {
174                   /*
175                    * If the same note is hit twice on the same channel, then the older
176                    * voice process is advanced to the release stage.  Using a mechanical
177                    * MIDI controller, the only way this can happen is when the sustain
178                    * pedal is held.  In this case the behaviour implemented here is
179                    * natural for many instruments.  Note: One noteon event can trigger
180                    * several voice processes, for example a stereo sample.  Don't
181                    * release those...
182                    */
183                   for(Voice* v : qAsConst(activeVoices)) {
184                         if (v->isPlaying() && (v->chan == ch) && (v->key == key) && (v->get_id() != noteid))
185                               v->noteoff();
186                         }
187                   err = !cp->preset()->noteon(this, noteid++, ch, key, vel, event.tuning());
188                   }
189             }
190       else if (type == ME_CONTROLLER) {
191             switch(event.dataA()) {
192                   case CTRL_PROGRAM:
193                         program_change(ch, event.dataB());
194                         break;
195                   case CTRL_PRESS:
196                         break;
197                   default:
198                         cp->setcc(event.dataA(), event.dataB());
199                         break;
200                   }
201             }
202       else if (type == ME_PITCHBEND){
203             int midiPitch = event.dataB() * 128 + event.dataA();  // msb * 128 + lsb
204             cp->pitchBend(midiPitch);
205             }
206       /*
207        *    MIDI spec.: One data byte follows the Status. It is the pressure amount, a value
208        *    from 0 to 127 (where 127 is the most pressure).
209        */
210       else if (type == ME_AFTERTOUCH){
211             cp->setChannelPressure(event.dataA());
212             }
213       /*
214        *    MIDI spec.: Two data bytes follow the Status. The first data is the note number.
215        *    This indicates to which note the pressure is being applied. The second data byte is the
216        *    pressure amount, a value from 0 to 127 (where 127 is the most pressure).
217        */
218       else if (type == ME_POLYAFTER){
219             cp->setKeyPressure(event.dataA(), event.dataB());
220             }
221 
222       if (err) {
223             // TODO: distinguish between types of error code.
224             // Lack of a soundfont should not produce qDebug messages, because user could deliberately be using MIDI out only.
225             //qWarning("FluidSynth error: event 0x%2x channel %d: %s", type, ch, qPrintable(error()));
226             }
227       }
228 
229 //---------------------------------------------------------
230 //   damp_voices
231 //---------------------------------------------------------
232 
damp_voices(int chan)233 void Fluid::damp_voices(int chan)
234       {
235       for(Voice* v : qAsConst(activeVoices)) {
236             if ((v->chan == chan) && v->SUSTAINED())
237                   v->noteoff();
238             }
239       }
240 
241 //---------------------------------------------------------
242 //   allNotesOff
243 //---------------------------------------------------------
244 
allNotesOff(int chan)245 void Fluid::allNotesOff(int chan)
246       {
247       for(Voice* v : qAsConst(activeVoices)) {
248             if (chan == -1 || v->chan == chan)
249                   v->noteoff();
250             }
251       }
252 
253 //---------------------------------------------------------
254 //   allSoundsOff
255 //    immediately stop all notes on this channel.
256 //    stop all channel if chan==-1
257 //---------------------------------------------------------
258 
allSoundsOff(int chan)259 void Fluid::allSoundsOff(int chan)
260       {
261       for(Voice* v : qAsConst(activeVoices)) {
262             if (chan == -1 || v->chan == chan)
263                   v->off();
264             }
265       }
266 
267 //---------------------------------------------------------
268 //   system_reset
269 //
270 //    Purpose:
271 //    Respond to the MIDI command 'system reset' (0xFF, big red 'panic' button)
272 //---------------------------------------------------------
273 
system_reset()274 void Fluid::system_reset()
275       {
276       for(Voice* v : qAsConst(activeVoices))
277             v->off();
278       for(Channel* c : qAsConst(channel))
279             c->reset();
280       }
281 
282 /*
283  * fluid_synth_modulate_voices
284  *
285  * tell all synthesis processes on this channel to update their
286  * synthesis parameters after a control change.
287  */
modulate_voices(int chan,bool is_cc,int ctrl)288 void Fluid::modulate_voices(int chan, bool is_cc, int ctrl)
289       {
290       for(Voice* v : qAsConst(activeVoices)) {
291             if (v->chan == chan)
292                   v->modulate(is_cc, ctrl);
293             }
294       }
295 
296 /*
297  * fluid_synth_modulate_voices_all
298  *
299  * Tell all synthesis processes on this channel to update their
300  * synthesis parameters after an all control off message (i.e. all
301  * controller have been reset to their default value).
302  */
modulate_voices_all(int chan)303 void Fluid::modulate_voices_all(int chan)
304       {
305       for(Voice* v : qAsConst(activeVoices)) {
306             if (v->chan == chan)
307                   v->modulate_all();
308             }
309       }
310 
311 /*
312  * fluid_synth_get_pitch_bend
313  */
get_pitch_bend(int chan,int * ppitch_bend)314 void Fluid::get_pitch_bend(int chan, int* ppitch_bend)
315       {
316       *ppitch_bend = channel[chan]->getPitchBend();
317       }
318 
319 /*
320  * Fluid_synth_pitch_wheel_sens
321  */
pitch_wheel_sens(int chan,int val)322 void Fluid::pitch_wheel_sens(int chan, int val)
323       {
324       /* set the pitch-bend value in the channel */
325       channel[chan]->pitchWheelSens(val);
326       }
327 
328 /*
329  * setFromKeyPortamento
330  * requires an input for a default value, usually the TPC
331  */
setFromKeyPortamento(int chan,int defaultValue)332 void Fluid::setFromKeyPortamento(int chan, int defaultValue) {
333       int ptc = get_cc(chan, PORTAMENTO_CTRL);
334       if (validNote(ptc)) {
335             resetPortamento(chan);
336             fromkey_portamento = ptc;
337             /*
338             // Assumedly this fixed some sort of bug in FluidSynth2
339             if (!validNote(defaultValue))
340                   defaultValue = ptc;*/
341             }
342       else {
343 
344             /* determines and returns fromkey portamento */
345             fromkey_portamento = Channel::INVALID_NOTE;
346 
347             if (portamentoTime(chan)) {
348                   /* Portamento when Portamento pedal is On */
349                   /* 'fromkey portamento'is determined from the portamento mode
350                    and the most recent note played (prev_note)*/
351                   if (validNote(defaultValue))
352                         fromkey_portamento = ptc;
353                   else
354                         fromkey_portamento = lastNote;
355                   }
356             }
357       }
358 
359 /*
360  * fluid_synth_get_preset
361  */
get_preset(unsigned int sfontnum,unsigned banknum,unsigned prognum)362 Preset* Fluid::get_preset(unsigned int sfontnum, unsigned banknum, unsigned prognum)
363       {
364       SFont* sf = get_sfont_by_id(sfontnum);
365       if (sf) {
366             Preset* preset = sf->get_preset(banknum, prognum);
367             if (preset != 0)
368                   return preset;
369             }
370       return 0;
371       }
372 
373 //---------------------------------------------------------
374 //   find_preset
375 //---------------------------------------------------------
376 
find_preset(unsigned banknum,unsigned prognum)377 Preset* Fluid::find_preset(unsigned banknum, unsigned prognum)
378       {
379       for (SFont* sf : qAsConst(sfonts)) {
380             Preset* preset = sf->get_preset(banknum, prognum);
381             if (preset)
382                   return preset;
383             }
384       return 0;
385       }
386 
387 //---------------------------------------------------------
388 //   program_change
389 //---------------------------------------------------------
390 
program_change(int chan,int prognum)391 void Fluid::program_change(int chan, int prognum)
392       {
393       Channel* c       = channel[chan];
394       unsigned banknum = c->getBanknum();
395       c->setPrognum(prognum);
396 
397       Preset* preset = find_preset(banknum, prognum);
398       if (!preset) {
399             //Suppressing qDebug because might not have soundfont if using MIDI out only.
400             //qDebug("Fluid::program_change: preset %d %d not found", banknum, prognum);
401             preset = find_preset(0, prognum);
402             if (!preset)
403                   preset = find_preset(0, 0);
404             }
405 
406       unsigned sfont_idl = preset? preset->sfont->id() : 0;
407       c->setSfontnum(sfont_idl);
408       c->setPreset(preset);
409       }
410 
411 /*
412  * fluid_synth_get_program
413  */
get_program(int chan,unsigned * sfont_idl,unsigned * bank_num,unsigned * preset_num)414 void Fluid::get_program(int chan, unsigned* sfont_idl, unsigned* bank_num, unsigned* preset_num)
415       {
416       Channel* c       = channel[chan];
417       *sfont_idl       = c->getSfontnum();
418       *bank_num        = c->getBanknum();
419       *preset_num      = c->getPrognum();
420       }
421 
422 //---------------------------------------------------------
423 //   program_select
424 //---------------------------------------------------------
425 
program_select(int chan,unsigned sfont_idl,unsigned bank_num,unsigned preset_num)426 bool Fluid::program_select(int chan, unsigned sfont_idl, unsigned bank_num, unsigned preset_num)
427       {
428       Channel* c     = channel[chan];
429       Preset* preset = get_preset(sfont_idl, bank_num, preset_num);
430       if (preset == 0) {
431             qDebug("There is no preset with bank number %d and preset number %d in SoundFont %d", bank_num, preset_num, sfont_idl);
432             return false;
433             }
434 
435       /* inform the channel of the new bank and program number */
436       c->setSfontnum(sfont_idl);
437       c->setBanknum(bank_num);
438       c->setPrognum(preset_num);
439       c->setPreset(preset);
440       return true;
441       }
442 
443 //---------------------------------------------------------
444 //   update_presets
445 //---------------------------------------------------------
446 
update_presets()447 void Fluid::update_presets()
448       {
449       for (Channel* c : qAsConst(channel))
450             c->setPreset(get_preset(c->getSfontnum(), c->getBanknum(), c->getPrognum()));
451       }
452 
453 //---------------------------------------------------------
454 //   process
455 //---------------------------------------------------------
456 
process(unsigned len,float * out,float * effect1,float * effect2)457 void Fluid::process(unsigned len, float* out, float* effect1, float* effect2)
458       {
459       if (mutex.tryLock()) {
460             //we have to copy voices array for proper output sound processing in for loop
461             auto tempVoices = activeVoices;
462             for (Voice* v : tempVoices)
463                   v->write(len, out, effect1, effect2);
464             mutex.unlock();
465             }
466       }
467 
468 /*
469  * fluid_synth_free_voice_by_kill
470  *
471  * selects a voice for killing. the selection algorithm is a refinement
472  * of the algorithm previously in fluid_synth_alloc_voice.
473  */
474 
free_voice_by_kill()475 void Fluid::free_voice_by_kill()
476       {
477       float best_prio = 999999.;
478       float this_voice_prio;
479       Voice* best_voice = 0;
480 
481       for(Voice* v : qAsConst(activeVoices)) {
482             /* Determine, how 'important' a voice is.
483              * Start with an arbitrary number */
484             this_voice_prio = 10000.;
485 
486             /* Is this voice on the drum channel?
487              * Then it is very important.
488              * Also, forget about the released-note condition:
489              * Typically, drum notes are triggered only very briefly, they run most
490              * of the time in release phase.
491              */
492             if (v->chan == 9) {
493                   this_voice_prio += 4000;
494 
495                   }
496             else if (v->RELEASED()) {
497                   /* The key for this voice has been released. Consider it much less important
498                   * than a voice, which is still held.
499                   */
500                   this_voice_prio -= 2000.;
501                   }
502 
503             if (v->SUSTAINED()) {
504               /* The sustain pedal is held down on this channel.
505                * Consider it less important than non-sustained channels.
506                * This decision is somehow subjective. But usually the sustain pedal
507                * is used to play 'more-voices-than-fingers', so it shouldn't hurt
508                * if we kill one voice.
509                */
510                   this_voice_prio -= 1000;
511                   }
512 
513             /* We are not enthusiastic about releasing voices, which have just been started.
514              * Otherwise hitting a chord may result in killing notes belonging to that very same
515              * chord.
516              * So subtract the age of the voice from the priority - an older voice is just a little
517              * bit less important than a younger voice.
518              * This is a number between roughly 0 and 100.*/
519 
520             this_voice_prio -= (noteid - v->get_id());
521 
522             /* take a rough estimate of loudness into account. Louder voices are more important. */
523             if (v->volenv_section != FLUID_VOICE_ENVATTACK) {
524                   this_voice_prio += v->volenv_val * 1000.;
525                   }
526 
527             /* check if this voice has less priority than the previous candidate. */
528             if (this_voice_prio < best_prio) {
529                   best_voice = v;
530                   best_prio = this_voice_prio;
531                   }
532             }
533       if (best_voice)
534             best_voice->off();
535       }
536 
537 //---------------------------------------------------------
538 //   alloc_voice
539 //---------------------------------------------------------
540 
alloc_voice(unsigned id,Sample * sample,int chan,int key,int vel,double vt)541 Voice* Fluid::alloc_voice(unsigned id, Sample* sample, int chan, int key, int vel, double vt)
542       {
543       Channel* c = 0;
544 
545       /* check if there's an available synthesis process */
546       if (freeVoices.isEmpty())
547             free_voice_by_kill();
548 
549       if (freeVoices.isEmpty()) {
550             qDebug("Failed to allocate a synthesis process. (chan=%d,key=%d)", chan, key);
551             return 0;
552             }
553 
554       Voice* v = freeVoices.takeLast();
555       activeVoices.append(v);
556 
557       if (chan >= 0)
558             c = channel[chan];
559 
560       v->init(sample, c, key, vel, id, vt);
561 
562       /* add the default modulators to the synthesis process. */
563       for (unsigned i = 0; i < sizeof(defaultMod)/sizeof(*defaultMod); ++i)
564             v->add_mod(&defaultMod[i],  FLUID_VOICE_DEFAULT);
565       v->add_mod(&forcePanMod, FLUID_VOICE_OVERWRITE);
566       return v;
567       }
568 
569 //---------------------------------------------------------
570 //   start_voice
571 //---------------------------------------------------------
572 
start_voice(Voice * voice)573 void Fluid::start_voice(Voice* voice)
574       {
575       /* Find the exclusive class of this voice. If set, kill all voices
576       * that match the exclusive class and are younger than the first
577       * voice process created by this noteon event. */
578 
579       /** Kill all voices on a given channel, which belong into
580           excl_class.  This function is called by a SoundFont's preset in
581           response to a noteon event.  If one noteon event results in
582           several voice processes (stereo samples), ignore_ID must name
583           the voice ID of the first generated voice (so that it is not
584           stopped). The first voice uses ignore_ID=-1, which will
585           terminate all voices on a channel belonging into the exclusive
586           class excl_class.
587       */
588 
589       /* Check if the voice belongs to an exclusive class. In that case,
590          previous notes from the same class are released. */
591 
592       int excl_class = voice->GEN(GEN_EXCLUSIVECLASS);
593       if (excl_class) {
594 
595             /* Kill all notes on the same channel with the same exclusive class */
596 
597             for(Voice* existing_voice : qAsConst(activeVoices)) {
598                   /* Existing voice does not play? Leave it alone. */
599                   if (!existing_voice->isPlaying())
600                         continue;
601 
602                   /* An exclusive class is valid for a whole channel (or preset).
603                    * Is the voice on a different channel? Leave it alone. */
604                   if (existing_voice->chan != voice->chan)
605                         continue;
606 
607                   /* Existing voice has a different (or no) exclusive class? Leave it alone. */
608                   if ((int)existing_voice->GEN(GEN_EXCLUSIVECLASS) != excl_class)
609                         continue;
610 
611                   /* Existing voice is a voice process belonging to this noteon
612                    * event (for example: stereo sample)?  Leave it alone. */
613                   if (existing_voice->get_id() == voice->get_id())
614                         continue;
615                   existing_voice->kill_excl();
616                   }
617             }
618       voice->voice_start();
619       }
620 
621 //---------------------------------------------------------
622 //   updatePatchList
623 //---------------------------------------------------------
624 
updatePatchList()625 void Fluid::updatePatchList()
626       {
627       qDeleteAll(patches);
628       patches.clear();
629 
630       int bankOffset = 0;
631       int sfid = 0;
632       for (SFont* sf : qAsConst(sfonts)) {
633             sf->setBankOffset(bankOffset);
634             int banks = 0;
635             for (Preset* p : sf->getPresets()) {
636                   MidiPatch* patch = new MidiPatch;
637                   patch->drum = (p->get_banknum() == 128);
638                   patch->synti = name();
639                   if (p->get_banknum() > banks)
640                         banks = p->get_banknum();
641                   patch->bank = p->get_banknum() + bankOffset;
642                   patch->prog = p->get_num();
643                   patch->name = p->get_name();
644                   patch->sfid = sfid;
645                   patches.append(patch);
646                   }
647             sfid++;
648             bankOffset += (banks + 1);
649             }
650 
651       /* try to set the correct presets */
652       int n = channel.size();
653       for (int i = 0; i < n; i++)
654             program_change(i, channel[i]->getPrognum());
655       }
656 
657 //---------------------------------------------------------
658 //   soundFonts
659 //---------------------------------------------------------
660 
soundFonts() const661 QStringList Fluid::soundFonts() const
662       {
663       QStringList sf;
664       for (SFont* f : sfonts)
665             sf.append(QFileInfo(f->get_name()).fileName());
666       return sf;
667       }
668 
669 //---------------------------------------------------------
670 //   soundFontsInfo
671 //---------------------------------------------------------
672 
soundFontsInfo() const673 std::vector<SoundFontInfo> Fluid::soundFontsInfo() const
674       {
675       std::vector<SoundFontInfo> sl;
676       sl.reserve(sfonts.size());
677       for (SFont* f : sfonts)
678             sl.emplace_back(QFileInfo(f->get_name()).fileName(), f->fontName());
679       return sl;
680       }
681 
682 //---------------------------------------------------------
683 //   loadSoundFont
684 //    return false on error
685 //---------------------------------------------------------
686 
loadSoundFonts(const QStringList & sl)687 bool Fluid::loadSoundFonts(const QStringList& sl)
688       {
689       QStringList ol = soundFonts();
690       if (ol == sl) {
691             qDebug("Fluid:loadSoundFonts: already loaded");
692             return true;
693             }
694       QMutexLocker locker(&mutex);
695       for(Voice* v : qAsConst(activeVoices))
696             v->off();
697       for(Channel* c : qAsConst(channel))
698             c->reset();
699       for (SFont* sf : qAsConst(sfonts))
700             sfunload(sf->id());
701       locker.unlock();
702       bool ok = true;
703 
704       QFileInfoList l = sfFiles();
705       for (int i = sl.size() - 1; i >= 0; --i) {
706             QString s = sl[i];
707             if (s.isEmpty())
708                   continue;
709             QString path;
710             QFileInfo fis(s);
711             QString fileName = fis.fileName();
712             for (const QFileInfo& fi : qAsConst(l)) {
713                   if (fi.fileName() == fileName) {
714                         path = fi.absoluteFilePath();
715                         break;
716                         }
717                   }
718             if (path.isEmpty()) {
719                   qDebug("Fluid: sf <%s> not found", qPrintable(s));
720                   ok = false;
721                   }
722             else {
723                   locker.relock();
724                   if (sfload(path) == -1) {
725                         qDebug("loading sf failed: <%s>", qPrintable(path));
726                         ok = false;
727                         }
728                   locker.unlock();
729                   }
730             }
731       return ok;
732       }
733 
734 //---------------------------------------------------------
735 //   addSoundFont
736 //    return false on error
737 //---------------------------------------------------------
738 
addSoundFont(const QString & s)739 bool Fluid::addSoundFont(const QString& s)
740       {
741       QMutexLocker locker(&mutex);
742       bool rv = (sfload(s) == -1) ? false : true;
743       return rv;
744       }
745 
746 //---------------------------------------------------------
747 //   removeSoundFont
748 //    return false on error
749 //---------------------------------------------------------
750 
removeSoundFont(const QString & s)751 bool Fluid::removeSoundFont(const QString& s)
752       {
753       QMutexLocker locker(&mutex);
754       for(Voice* v : qAsConst(activeVoices))
755             v->off();
756       SFont* sf = get_sfont_by_name(s);
757       if (!sf)
758             return false;
759 
760       sfunload(sf->id());
761       return true;
762       }
763 
764 //---------------------------------------------------------
765 //   sfload
766 //---------------------------------------------------------
767 
sfload(const QString & filename)768 int Fluid::sfload(const QString& filename)
769       {
770       if (filename.isEmpty())
771             return -1;
772 
773       SFont* sf = new SFont(this);
774       try {
775             if (!sf->read(filename)) {
776                   delete sf;
777                   sf = 0;
778                   return -1;
779                   }
780             }
781       catch(...) {
782             delete sf;
783             sf = 0;
784             return -1;
785             }
786 
787       sf->setId(++sfont_id);
788 
789       /* insert the sfont as the first one on the list */
790       sfonts.prepend(sf);
791 
792       /* reset the presets for all channels */
793 
794       updatePatchList();
795       return sf->id();
796       }
797 
798 //---------------------------------------------------------
799 //   sfunload
800 //---------------------------------------------------------
801 
sfunload(int id)802 bool Fluid::sfunload(int id)
803       {
804       SFont* sf = get_sfont_by_id(id);
805 
806       if (!sf) {
807             qDebug("No SoundFont with id = %d", id);
808             return false;
809             }
810 
811       sfonts.removeAll(sf);   // remove the SoundFont from the list
812       updatePatchList();
813 
814       delete sf;
815       return true;
816       }
817 
818 //---------------------------------------------------------
819 //   get_sfont_by_id
820 //---------------------------------------------------------
821 
get_sfont_by_id(int id)822 SFont* Fluid::get_sfont_by_id(int id)
823       {
824       for(SFont* sf : qAsConst(sfonts)) {
825             if (sf->id() == id)
826                   return sf;
827             }
828       return 0;
829       }
830 
831 //---------------------------------------------------------
832 //   get_sfont_by_name
833 //---------------------------------------------------------
834 
get_sfont_by_name(const QString & name)835 SFont* Fluid::get_sfont_by_name(const QString& name)
836       {
837       for(SFont* sf : qAsConst(sfonts)) {
838             if (QFileInfo(sf->get_name()).fileName() == name)
839                   return sf;
840             }
841       return 0;
842       }
843 
844 //---------------------------------------------------------
845 //   set_interp_method
846 //    Sets the interpolation method to use on channel chan.
847 //    If chan is < 0, then set the interpolation method on all channels.
848 //---------------------------------------------------------
849 
set_interp_method(int chan,int interp_method)850 void Fluid::set_interp_method(int chan, int interp_method)
851       {
852       for(Channel* c : qAsConst(channel)) {
853             if (chan < 0 || c->getNum() == chan)
854                   c->setInterpMethod(interp_method);
855             }
856       }
857 
858 //---------------------------------------------------------
859 //   set_gen
860 //---------------------------------------------------------
861 
set_gen(int chan,int param,float value)862 void Fluid::set_gen(int chan, int param, float value)
863       {
864       channel[chan]->setGen(param, value, 0);
865       for(Voice* v : qAsConst(activeVoices)) {
866             if (v->chan == chan)
867                   v->set_param(param, value, 0);
868             }
869       }
870 
871 /** Change the value of a generator. This function allows to control
872     all synthesis parameters in real-time. The changes are additive,
873     i.e. they add up to the existing parameter value. This function is
874     similar to sending an NRPN message to the synthesizer. The
875     function accepts a float as the value of the parameter. The
876     parameter numbers and ranges are described in the SoundFont 2.01
877     specification, paragraph 8.1.3, page 48. See also
878     'fluid_gen_type'.
879 
880     Using the fluid_synth_set_gen2() function, it is possible to set
881     the absolute value of a generator. This is an extension to the
882     SoundFont standard. If 'absolute' is non-zero, the value of the
883     generator specified in the SoundFont is completely ignored and the
884     generator is fixed to the value passed as argument. To undo this
885     behavior, you must call fluid_synth_set_gen2 again, with
886     'absolute' set to 0 (and possibly 'value' set to zero).
887 
888     If 'normalized' is non-zero, the value is supposed to be
889     normalized between 0 and 1. Before applying the value, it will be
890     scaled and shifted to the range defined in the SoundFont
891     specifications.
892 
893  */
set_gen2(int chan,int param,float value,int absolute,int normalized)894 void Fluid::set_gen2(int chan, int param, float value, int absolute, int normalized)
895       {
896       float v = (normalized)? fluid_gen_scale(param, value) : value;
897       channel[chan]->setGen(param, v, absolute);
898 
899       for(Voice* vo : qAsConst(activeVoices)) {
900             if (vo->chan == chan)
901                   vo->set_param(param, v, absolute);
902             }
903       }
904 
get_gen(int chan,int param)905 float Fluid::get_gen(int chan, int param)
906       {
907       if ((param < 0) || (param >= GEN_LAST)) {
908             qDebug("Parameter number out of range");
909             return 0.0;
910             }
911       return channel[chan]->getGen(param);
912       }
913 
914 //---------------------------------------------------------
915 //   state
916 //---------------------------------------------------------
917 
state() const918 SynthesizerGroup Fluid::state() const
919       {
920       SynthesizerGroup g;
921       g.setName(name());
922 
923       QStringList sfl = soundFonts();
924       for (const QString &sf : qAsConst(sfl))
925             g.push_back(IdValue(0, sf));
926 
927       return g;
928       }
929 
930 //---------------------------------------------------------
931 //   setState
932 //---------------------------------------------------------
933 
setState(const SynthesizerGroup & sp)934 bool Fluid::setState(const SynthesizerGroup& sp)
935       {
936       QStringList sfl;
937       for (const IdValue& v : sp) {
938             if (v.id == 0)
939                   sfl.append(v.data);
940             else
941                   qDebug("Fluid::setState: unknown id %d", v.id);
942             }
943       return loadSoundFonts(sfl);
944       }
945 
946 //---------------------------------------------------------
947 //   collectFiles
948 //---------------------------------------------------------
949 
collectFiles(QFileInfoList * l,const QString & path)950 static void collectFiles(QFileInfoList* l, const QString& path)
951       {
952       QDir dir(path);
953       for (const QFileInfo& s : dir.entryInfoList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot)) {
954             if (path == s.absoluteFilePath())
955                   return;
956 
957             if (s.isDir() && !s.isHidden())
958                   collectFiles(l, s.absoluteFilePath());
959             else {
960                   QString suffix = s.suffix().toLower();
961                   if (suffix == "sf" || suffix == "sf2" || suffix == "sf3")
962                         l->append(s);
963                   }
964             }
965       }
966 
967 //---------------------------------------------------------
968 //   sfFiles
969 //---------------------------------------------------------
970 
sfFiles()971 QFileInfoList Fluid::sfFiles()
972       {
973       QFileInfoList l;
974 
975       QStringList pl = preferences.getString(PREF_APP_PATHS_MYSOUNDFONTS).split(";");
976       pl.prepend(QFileInfo(QString("%1%2").arg(mscoreGlobalShare, "sound")).absoluteFilePath());
977 
978       // append extensions directory
979       QStringList extensionsDir = Ms::Extension::getDirectoriesByType(Ms::Extension::soundfontsDir);
980       pl.append(extensionsDir);
981 
982       foreach (const QString& s, pl) {
983             QString ss(s);
984             if (!s.isEmpty() && s[0] == '~')
985                   ss = QDir::homePath() + s.mid(1);
986             collectFiles(&l, ss);
987             }
988       return l;
989       }
990 }
991