1 /***************************************************************************
2 **                                                                        **
3 **  Polyphone, a soundfont editor                                         **
4 **  Copyright (C) 2013-2019 Davy Triponney                                **
5 **                                                                        **
6 **  This program is free software: you can redistribute it and/or modify  **
7 **  it under the terms of the GNU General Public License as published by  **
8 **  the Free Software Foundation, either version 3 of the License, or     **
9 **  (at your option) any later version.                                   **
10 **                                                                        **
11 **  This program is distributed in the hope that it will be useful,       **
12 **  but WITHOUT ANY WARRANTY; without even the implied warranty of        **
13 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the          **
14 **  GNU General Public License for more details.                          **
15 **                                                                        **
16 **  You should have received a copy of the GNU General Public License     **
17 **  along with this program. If not, see http://www.gnu.org/licenses/.    **
18 **                                                                        **
19 ****************************************************************************
20 **           Author: Davy Triponney                                       **
21 **  Website/Contact: https://www.polyphone-soundfonts.com                 **
22 **             Date: 01.01.2013                                           **
23 ***************************************************************************/
24 
25 #include "sfzparamlist.h"
26 #include "soundfontmanager.h"
27 
28 int SfzParamList::_boucleGlobale = -2;
29 
SfzParamList(SoundfontManager * sf2,EltID id)30 SfzParamList::SfzParamList(SoundfontManager * sf2, EltID id)
31 {
32     if (id.typeElement == elementPrstInst)
33     {
34         // Chargement d'un preset
35         id.typeElement = elementPrstInstGen;
36         load(sf2, id);
37 
38         // Prise en compte des paramètres globaux
39         id.typeElement = elementPrstGen;
40         load(sf2, id);
41     }
42 }
43 
SfzParamList(SoundfontManager * sf2,SfzParamList * paramPrst,EltID idInst)44 SfzParamList::SfzParamList(SoundfontManager * sf2, SfzParamList * paramPrst, EltID idInst)
45 {
46     if (idInst.typeElement == elementInst)
47     {
48         // Chargement des paramètres globaux d'un instrument
49         idInst.typeElement = elementInstGen;
50         load(sf2, idInst);
51 
52         idInst.typeElement = elementInst;
53         if (sf2->isSet(idInst, champ_sampleModes))
54             _boucleGlobale = sf2->get(idInst, champ_sampleModes).wValue;
55         else
56         {
57             // Toutes les divisions ont-elles le même paramètre de bouclage ?
58             idInst.typeElement = elementInstSmpl;
59             _boucleGlobale = -2;
60             foreach (int i, sf2->getSiblings(idInst))
61             {
62                 idInst.indexElt2 = i;
63                 int valTmp = 0;
64                 if (sf2->isSet(idInst, champ_sampleModes))
65                     valTmp = sf2->get(idInst, champ_sampleModes).wValue;
66                 if (_boucleGlobale == -2)
67                     _boucleGlobale = valTmp;
68                 else if (_boucleGlobale != valTmp)
69                     _boucleGlobale = -1;
70             }
71             idInst.typeElement = elementInst;
72         }
73 
74         if (_boucleGlobale >= 0)
75         {
76             // Ajustement de la boucle globale
77             if (!_listeChamps.contains(champ_sampleModes))
78             {
79                 _listeChamps << champ_sampleModes;
80                 _listeValeurs << _boucleGlobale;
81             }
82             else
83                 _listeValeurs[_listeChamps.indexOf(champ_sampleModes)] = _boucleGlobale;
84         }
85         else
86         {
87             // Pas de boucle si non défini
88             if (!_listeChamps.contains(champ_sampleModes))
89             {
90                 _listeChamps << champ_sampleModes;
91                 _listeValeurs << 0;
92                 _boucleGlobale = 0;
93             }
94             else
95                 _boucleGlobale = _listeValeurs.at(_listeChamps.indexOf(champ_sampleModes));
96         }
97     }
98     else if (idInst.typeElement == elementInstSmpl)
99     {
100         // Chargement des paramètres d'une zone dans un instrument
101         idInst.typeElement = elementInstSmplGen;
102         load(sf2, idInst);
103 
104         // Lecture du sample associé
105         EltID idSmpl = idInst;
106         idSmpl.typeElement = elementSmpl;
107         idInst.typeElement = elementInstSmpl;
108         idSmpl.indexElt = sf2->get(idInst, champ_sampleID).wValue;
109 
110         if (!_listeChamps.contains(champ_overridingRootKey))
111         {
112             EltID instGlob = idInst;
113             instGlob.typeElement = elementInst;
114             if (!sf2->isSet(instGlob, champ_overridingRootKey))
115             {
116                 _listeChamps << champ_overridingRootKey;
117                 _listeValeurs << sf2->get(idSmpl, champ_byOriginalPitch).bValue;
118             }
119         }
120 
121         if (!_listeChamps.contains(champ_fineTune))
122         {
123             int fineTuneSample = sf2->get(idSmpl, champ_chPitchCorrection).cValue;
124             if (fineTuneSample != 0)
125             {
126                 _listeChamps << champ_fineTune;
127                 EltID idInstGlobal = idInst;
128                 idInstGlobal.typeElement = elementInst;
129                 _listeValeurs << sf2->get(idInstGlobal, champ_fineTune).shValue + fineTuneSample;
130             }
131         }
132         else
133         {
134             _listeValeurs[_listeChamps.indexOf(champ_fineTune)] +=
135                     sf2->get(idSmpl, champ_chPitchCorrection).cValue;
136         }
137 
138         // Suppression sample mode si égal à la division globale
139         if (_listeChamps.contains(champ_sampleModes))
140         {
141             int index = _listeChamps.indexOf(champ_sampleModes);
142             if (_listeValeurs.at(index) == _boucleGlobale)
143             {
144                 _listeChamps.removeAt(index);
145                 _listeValeurs.removeAt(index);
146             }
147         }
148 
149         // Adaptation des offsets
150         mix(champ_startAddrsCoarseOffset, champ_startAddrsOffset);
151         mix(champ_endAddrsCoarseOffset, champ_endAddrsOffset, sf2->get(idSmpl, champ_dwLength).dwValue);
152         mix(champ_startloopAddrsCoarseOffset, champ_startloopAddrsOffset, sf2->get(idSmpl, champ_dwStartLoop).dwValue);
153         mix(champ_endloopAddrsCoarseOffset, champ_endloopAddrsOffset, sf2->get(idSmpl, champ_dwEndLoop).dwValue);
154 
155         // Suppression début / fin de loop si 0 - 0
156         if (_listeChamps.contains(champ_startAddrsOffset) && _listeChamps.contains(champ_endloopAddrsOffset))
157         {
158             int startLoop = _listeValeurs.at(_listeChamps.indexOf(champ_startloopAddrsOffset));
159             int endLoop = _listeValeurs.at(_listeChamps.indexOf(champ_endloopAddrsOffset));
160             if (startLoop == endLoop)
161             {
162                 int index = _listeChamps.indexOf(champ_startloopAddrsOffset);
163                 _listeChamps.removeAt(index);
164                 _listeValeurs.removeAt(index);
165                 index = _listeChamps.indexOf(champ_endloopAddrsOffset);
166                 _listeChamps.removeAt(index);
167                 _listeValeurs.removeAt(index);
168             }
169         }
170 
171         // Gestion de la note fixe
172         if (_listeChamps.contains(champ_keynum))
173         {
174             int indexKeynum = _listeChamps.indexOf(champ_keynum);
175             int delta = _listeValeurs.at(indexKeynum) -
176                     _listeValeurs.at(_listeChamps.indexOf(champ_overridingRootKey));
177 
178             // Equivalence en utilisant scaleTuning / rootkey / coarse tune
179             if (_listeChamps.contains(champ_scaleTuning))
180                 _listeValeurs[_listeChamps.indexOf(champ_scaleTuning)] = 0;
181             else
182             {
183                 _listeChamps << champ_scaleTuning;
184                 _listeValeurs << 0;
185             }
186             _listeValeurs[_listeChamps.indexOf(champ_overridingRootKey)] =
187                     _listeValeurs.at(indexKeynum);
188             if (_listeChamps.contains(champ_coarseTune))
189                 _listeValeurs[_listeChamps.indexOf(champ_coarseTune)] += delta;
190             else
191             {
192                 _listeChamps << champ_coarseTune;
193                 _listeValeurs << delta;
194             }
195 
196             _listeChamps.removeAt(indexKeynum);
197             _listeValeurs.removeAt(indexKeynum);
198         }
199 
200         // Adaptation des keynum2...
201         adaptKeynum2();
202 
203         // Adaptation LFO
204         adaptLfo(sf2, idInst);
205 
206         // Atténuation du volume si défini uniquement dans la division globale
207         if (!_listeChamps.contains(champ_initialAttenuation))
208         {
209             EltID instGlob = idInst;
210             instGlob.typeElement = elementInst;
211             if (sf2->isSet(instGlob, champ_initialAttenuation))
212             {
213                 _listeChamps << champ_initialAttenuation;
214                 _listeValeurs << Attribute::toRealValue(champ_initialAttenuation, false, sf2->get(instGlob, champ_initialAttenuation));
215             }
216         }
217     }
218 
219     // Fusion des 2 listes de paramètres
220     if (idInst.typeElement == elementInst)
221     {
222         for (int i = 0; i < paramPrst->_listeChamps.size(); i++)
223             fusion(paramPrst->_listeChamps.at(i), paramPrst->_listeValeurs.at(i));
224     }
225     else if (idInst.typeElement == elementInstSmpl)
226     {
227         // On fusionne uniquement avec les éléments présents
228         for (int i = 0; i < paramPrst->_listeChamps.size(); i++)
229             if (_listeChamps.contains(paramPrst->_listeChamps.at(i)))
230                 fusion(paramPrst->_listeChamps.at(i), paramPrst->_listeValeurs.at(i));
231     }
232 
233     // On tente d'éliminer le champ modLfoToPitch si vib LFO est disponible
234     if (_listeChamps.contains(champ_modLfoToPitch) && !_listeChamps.contains(champ_vibLfoToPitch))
235     {
236         int index = _listeChamps.indexOf(champ_modLfoToPitch);
237         _listeChamps << champ_vibLfoToPitch;
238         _listeValeurs << _listeValeurs.at(index);
239 
240         // Recopie des paramètres
241         if (_listeChamps.contains(champ_delayModLFO))
242         {
243             int index2 = _listeChamps.indexOf(champ_delayModLFO);
244             if (_listeChamps.contains(champ_delayVibLFO))
245                 _listeValeurs[_listeChamps.indexOf(champ_delayVibLFO)] = _listeValeurs[index2];
246             else
247             {
248                 _listeChamps << champ_delayVibLFO;
249                 _listeValeurs << _listeValeurs[index2];
250             }
251         }
252         if (_listeChamps.contains(champ_freqModLFO))
253         {
254             int index2 = _listeChamps.indexOf(champ_freqModLFO);
255             if (_listeChamps.contains(champ_freqVibLFO))
256                 _listeValeurs[_listeChamps.indexOf(champ_freqVibLFO)] = _listeValeurs[index2];
257             else
258             {
259                 _listeChamps << champ_freqVibLFO;
260                 _listeValeurs << _listeValeurs[index2];
261             }
262         }
263 
264         _listeChamps.removeAt(index);
265         _listeValeurs.removeAt(index);
266 
267         // Suppression complète du mod lfo ?
268         if (!_listeChamps.contains(champ_modLfoToVolume) && !_listeChamps.contains(champ_modLfoToFilterFc))
269         {
270             if (_listeChamps.contains(champ_delayModLFO))
271             {
272                 int index2 = _listeChamps.indexOf(champ_delayModLFO);
273                 _listeChamps.removeAt(index2);
274                 _listeValeurs.removeAt(index2);
275             }
276             if (_listeChamps.contains(champ_freqModLFO))
277             {
278                 int index2 = _listeChamps.indexOf(champ_freqModLFO);
279                 _listeChamps.removeAt(index2);
280                 _listeValeurs.removeAt(index2);
281             }
282         }
283     }
284 
285     // Valeurs par défaut
286     if (idInst.typeElement == elementInst)
287     {
288         // Attaque par défaut si non définie
289         if (!_listeChamps.contains(champ_attackVolEnv))
290         {
291             _listeChamps << champ_attackVolEnv;
292             _listeValeurs << Attribute::getDefaultRealValue(champ_attackVolEnv, false);
293         }
294 
295         // Fréquences par défaut si non définies
296         if (!_listeChamps.contains(champ_freqModLFO))
297         {
298             _listeChamps << champ_freqModLFO;
299             _listeValeurs << Attribute::getDefaultRealValue(champ_freqModLFO, false);
300         }
301         if (!_listeChamps.contains(champ_freqVibLFO))
302         {
303             _listeChamps << champ_freqVibLFO;
304             _listeValeurs << Attribute::getDefaultRealValue(champ_freqVibLFO, false);
305         }
306 
307         // Fréquence de coupure par défaut si non définie
308         if (!_listeChamps.contains(champ_initialFilterFc))
309         {
310             _listeChamps << champ_initialFilterFc;
311             _listeValeurs << Attribute::getDefaultRealValue(champ_initialFilterFc, false);
312         }
313     }
314 
315     // Limites
316     for (int i = 0; i < _listeChamps.size(); i++)
317         _listeValeurs[i] = limit(_listeValeurs.at(i), _listeChamps.at(i));
318 
319     // Correction volume si modLfoToVolume est actif
320     double correction = 0;
321     idInst.typeElement = elementInst;
322     if (_listeChamps.contains(champ_modLfoToVolume))
323         correction = qAbs(_listeValeurs.at(_listeChamps.indexOf(champ_modLfoToVolume)));
324     else if (sf2->isSet(idInst, champ_modLfoToVolume))
325         correction = qAbs((double)sf2->get(idInst, champ_modLfoToVolume).shValue / 10.);
326     if (correction != 0)
327     {
328         if (_listeChamps.contains(champ_initialAttenuation))
329             _listeValeurs[_listeChamps.indexOf(champ_initialAttenuation)] += correction;
330         else
331         {
332             _listeChamps << champ_initialAttenuation;
333             _listeValeurs << correction / DB_SF2_TO_SFZ;
334         }
335     }
336 
337     // Ordre
338     prepend(champ_velRange);
339     prepend(champ_keynum);
340     prepend(champ_overridingRootKey);
341     prepend(champ_keyRange);
342 }
343 
adaptKeynum2()344 void SfzParamList::adaptKeynum2()
345 {
346     int minKey = 0, maxKey = 127;
347     if (_listeChamps.contains(champ_keyRange))
348     {
349         double keyRange = _listeValeurs.at(_listeChamps.indexOf(champ_keyRange));
350         minKey = qRound(keyRange / 1000);
351         maxKey = qRound(keyRange - 1000 * minKey);
352     }
353 
354     adaptKeynum2(minKey, maxKey, champ_decayModEnv, champ_keynumToModEnvDecay);
355     adaptKeynum2(minKey, maxKey, champ_holdModEnv, champ_keynumToModEnvHold);
356     adaptKeynum2(minKey, maxKey, champ_decayVolEnv, champ_keynumToVolEnvDecay);
357     adaptKeynum2(minKey, maxKey, champ_holdVolEnv, champ_keynumToVolEnvHold);
358 }
adaptKeynum2(int minKey,int maxKey,AttributeType champBase,AttributeType champKeynum)359 void SfzParamList::adaptKeynum2(int minKey, int maxKey, AttributeType champBase, AttributeType champKeynum)
360 {
361     double valBase = 0.001;
362     double valMin, valMax;
363     double keyNum;
364 
365     int indexKeynum = _listeChamps.indexOf(champKeynum);
366     if (indexKeynum != -1)
367     {
368         keyNum = _listeValeurs.at(indexKeynum);
369 
370         int indexValBase = _listeChamps.indexOf(champBase);
371         if (indexValBase != -1)
372             valBase = _listeValeurs.at(indexValBase);
373 
374         valMin = getValKeynum(valBase, minKey, keyNum);
375         valMax = getValKeynum(valBase, maxKey, keyNum);
376         if (minKey == maxKey)
377         {
378             if (indexValBase == -1)
379             {
380                 _listeChamps << champBase;
381                 _listeValeurs << valMin;
382             }
383             else
384                 _listeValeurs[indexValBase] = valMin;
385             _listeValeurs.removeAt(indexKeynum);
386             _listeChamps.removeAt(indexKeynum);
387         }
388         else
389         {
390             keyNum = 127. * (valMin - valMax) / (double)(minKey - maxKey);
391             valBase = (valMax * minKey - valMin * maxKey) / (double)(minKey - maxKey);
392             _listeValeurs[indexKeynum] = keyNum;
393             if (indexValBase == -1)
394             {
395                 _listeChamps << champBase;
396                 _listeValeurs << valBase;
397             }
398             else
399                 _listeValeurs[indexValBase] = valBase;
400         }
401     }
402 }
403 
adaptLfo(SoundfontManager * sf2,EltID idInstSmpl)404 void SfzParamList::adaptLfo(SoundfontManager * sf2, EltID idInstSmpl)
405 {
406     // On se trouve dans une division d'un instrument
407     EltID idInst = idInstSmpl;
408     idInst.typeElement = elementInst;
409 
410     // Reprise des valeurs de la division globale
411     if (_listeChamps.contains(champ_modLfoToPitch) || _listeChamps.contains(champ_modLfoToFilterFc) ||
412             _listeChamps.contains(champ_modLfoToVolume) || _listeChamps.contains(champ_delayModLFO) ||
413             _listeChamps.contains(champ_freqModLFO))
414     {
415         if (!_listeChamps.contains(champ_delayModLFO) && sf2->isSet(idInst, champ_delayModLFO))
416         {
417             _listeChamps << champ_delayModLFO;
418             _listeValeurs << Attribute::toRealValue(champ_delayModLFO, false, sf2->get(idInst, champ_delayModLFO));
419         }
420         if (!_listeChamps.contains(champ_freqModLFO) && sf2->isSet(idInst, champ_freqModLFO))
421         {
422             _listeChamps << champ_freqModLFO;
423             _listeValeurs << Attribute::toRealValue(champ_freqModLFO, false, sf2->get(idInst, champ_freqModLFO));
424         }
425         if (!_listeChamps.contains(champ_modLfoToPitch) && sf2->isSet(idInst, champ_modLfoToPitch))
426         {
427             _listeChamps << champ_modLfoToPitch;
428             _listeValeurs << Attribute::toRealValue(champ_modLfoToPitch, false, sf2->get(idInst, champ_modLfoToPitch));
429         }
430         if (!_listeChamps.contains(champ_modLfoToFilterFc) && sf2->isSet(idInst, champ_modLfoToFilterFc))
431         {
432             _listeChamps << champ_modLfoToFilterFc;
433             _listeValeurs << Attribute::toRealValue(champ_modLfoToFilterFc, false, sf2->get(idInst, champ_modLfoToFilterFc));
434         }
435         if (!_listeChamps.contains(champ_modLfoToVolume) && sf2->isSet(idInst, champ_modLfoToVolume))
436         {
437             _listeChamps << champ_modLfoToVolume;
438             _listeValeurs << Attribute::toRealValue(champ_modLfoToVolume, false, sf2->get(idInst, champ_modLfoToVolume));
439         }
440     }
441     if (_listeChamps.contains(champ_vibLfoToPitch) || _listeChamps.contains(champ_delayVibLFO) ||
442             _listeChamps.contains(champ_freqVibLFO))
443     {
444         if (!_listeChamps.contains(champ_delayVibLFO) && sf2->isSet(idInst, champ_delayVibLFO))
445         {
446             _listeChamps << champ_delayVibLFO;
447             _listeValeurs << Attribute::toRealValue(champ_delayVibLFO, false, sf2->get(idInst, champ_delayVibLFO));
448         }
449         if (!_listeChamps.contains(champ_freqVibLFO) && sf2->isSet(idInst, champ_freqVibLFO))
450         {
451             _listeChamps << champ_freqVibLFO;
452             _listeValeurs << Attribute::toRealValue(champ_freqVibLFO, false, sf2->get(idInst, champ_freqVibLFO));
453         }
454         if (!_listeChamps.contains(champ_vibLfoToPitch) && sf2->isSet(idInst, champ_vibLfoToPitch))
455         {
456             _listeChamps << champ_vibLfoToPitch;
457             _listeValeurs << Attribute::toRealValue(champ_vibLfoToPitch, false, sf2->get(idInst, champ_vibLfoToPitch));
458         }
459     }
460 }
461 
getValKeynum(double valBase,int key,double keynum)462 double SfzParamList::getValKeynum(double valBase, int key, double keynum)
463 {
464     return valBase * qPow(2., (60. - (double)key) * keynum / 1200.);
465 }
466 
prepend(AttributeType champ)467 void SfzParamList::prepend(AttributeType champ)
468 {
469     if (_listeChamps.indexOf(champ) != -1)
470     {
471         int index = _listeChamps.indexOf(champ);
472         AttributeType chTmp = _listeChamps.takeAt(index);
473         double value = _listeValeurs.takeAt(index);
474         _listeChamps.prepend(chTmp);
475         _listeValeurs.prepend(value);
476     }
477 }
478 
load(SoundfontManager * sf2,EltID id)479 void SfzParamList::load(SoundfontManager * sf2, EltID id)
480 {
481     // Charge les paramètres, n'écrase pas les valeurs existantes
482     bool isPrst = (id.typeElement == elementPrstInstGen || id.typeElement == elementPrstGen);
483     EltID parent = id.parent();
484 
485     foreach (int champ, sf2->getSiblings(id))
486     {
487         if (!_listeChamps.contains((AttributeType)champ))
488         {
489             if (id.typeElement != elementInstGen || (
490                         champ != champ_startAddrsCoarseOffset &&
491                         champ != champ_startAddrsOffset &&
492                         champ != champ_startloopAddrsCoarseOffset &&
493                         champ != champ_startloopAddrsOffset &&
494                         champ != champ_endAddrsCoarseOffset &&
495                         champ != champ_endAddrsOffset &&
496                         champ != champ_endloopAddrsCoarseOffset &&
497                         champ != champ_endloopAddrsOffset &&
498                         champ != champ_keynum &&
499                         champ != champ_keynumToModEnvDecay &&
500                         champ != champ_keynumToModEnvHold &&
501                         champ != champ_keynumToVolEnvDecay &&
502                         champ != champ_keynumToVolEnvHold))
503             {
504                 _listeChamps << (AttributeType)champ;
505                 _listeValeurs << Attribute::toRealValue((AttributeType)champ, isPrst, sf2->get(parent, (AttributeType)champ));
506             }
507         }
508     }
509 
510     if (id.typeElement == elementInstSmplGen)
511     {
512         id.typeElement = elementInst;
513 
514         // Chargement des offsets de la division globale
515         getGlobalValue(sf2, id, champ_startAddrsCoarseOffset);
516         getGlobalValue(sf2, id, champ_startAddrsOffset);
517         getGlobalValue(sf2, id, champ_startloopAddrsCoarseOffset);
518         getGlobalValue(sf2, id, champ_startloopAddrsOffset);
519         getGlobalValue(sf2, id, champ_endAddrsCoarseOffset);
520         getGlobalValue(sf2, id, champ_endAddrsOffset);
521         getGlobalValue(sf2, id, champ_endloopAddrsCoarseOffset);
522         getGlobalValue(sf2, id, champ_endloopAddrsOffset);
523 
524         // Chargement de la note fixe de la division globale
525         getGlobalValue(sf2, id, champ_keynum);
526 
527         // Chargement des keynum2... de la division globale, avec les valeurs modulées
528         getGlobalValue(sf2, id, champ_keynumToModEnvDecay);
529         if (_listeChamps.contains(champ_keynumToModEnvDecay))
530             if (_listeValeurs.at(_listeChamps.indexOf(champ_keynumToModEnvDecay)) != 0)
531                 getGlobalValue(sf2, id, champ_decayModEnv);
532         getGlobalValue(sf2, id, champ_keynumToModEnvHold);
533         if (_listeChamps.contains(champ_keynumToModEnvHold))
534             if (_listeValeurs.at(_listeChamps.indexOf(champ_keynumToModEnvHold)) != 0)
535                 getGlobalValue(sf2, id, champ_holdModEnv);
536         getGlobalValue(sf2, id, champ_keynumToVolEnvDecay);
537         if (_listeChamps.contains(champ_keynumToVolEnvDecay))
538             if (_listeValeurs.at(_listeChamps.indexOf(champ_keynumToVolEnvDecay)) != 0)
539                 getGlobalValue(sf2, id, champ_decayVolEnv);
540         getGlobalValue(sf2, id, champ_keynumToVolEnvHold);
541         if (_listeChamps.contains(champ_keynumToVolEnvHold))
542             if (_listeValeurs.at(_listeChamps.indexOf(champ_keynumToVolEnvHold)) != 0)
543                 getGlobalValue(sf2, id, champ_holdVolEnv);
544     }
545 }
546 
getGlobalValue(SoundfontManager * sf2,EltID id,AttributeType champ)547 void SfzParamList::getGlobalValue(SoundfontManager * sf2, EltID id, AttributeType champ)
548 {
549     // Chargement d'une valeur de la division globale
550     if (!_listeChamps.contains(champ) && sf2->isSet(id, champ))
551     {
552         _listeChamps << champ;
553         _listeValeurs << Attribute::toRealValue(champ, false, sf2->get(id, champ));
554     }
555 }
556 
mix(AttributeType champCoarse,AttributeType champFine,int addValue)557 void SfzParamList::mix(AttributeType champCoarse, AttributeType champFine, int addValue)
558 {
559     if (_listeChamps.contains(champCoarse))
560     {
561         int indexCoarse = _listeChamps.indexOf(champCoarse);
562         if (_listeChamps.contains(champFine))
563         {
564             _listeValeurs[_listeChamps.indexOf(champFine)] += _listeValeurs[indexCoarse];
565             _listeChamps.removeAt(indexCoarse);
566             _listeValeurs.removeAt(indexCoarse);
567         }
568         else
569             _listeChamps[indexCoarse] = champFine;
570     }
571 
572     if (_listeChamps.contains(champFine))
573         _listeValeurs[_listeChamps.indexOf(champFine)] += addValue;
574     else
575     {
576         _listeChamps << champFine;
577         _listeValeurs << addValue;
578     }
579 }
580 
fusion(AttributeType champ,double value)581 void SfzParamList::fusion(AttributeType champ, double value)
582 {
583     int index = _listeChamps.indexOf(champ);
584     if (index == -1)
585     {
586         index = _listeChamps.size();
587         _listeChamps.append(champ);
588         _listeValeurs.append(Attribute::getDefaultRealValue(champ, false));
589     }
590 
591     switch (champ)
592     {
593     case champ_fineTune: case champ_coarseTune: case champ_initialAttenuation: case champ_startAddrsOffset:
594     case champ_endAddrsOffset: case champ_startloopAddrsOffset: case champ_endloopAddrsOffset:
595     case champ_pan: case champ_scaleTuning: case champ_initialFilterQ: case champ_reverbEffectsSend:
596     case champ_chorusEffectsSend: case champ_keynumToVolEnvHold: case champ_keynumToVolEnvDecay:
597     case champ_sustainVolEnv: case champ_keynumToModEnvHold: case champ_keynumToModEnvDecay:
598     case champ_sustainModEnv: case champ_modEnvToPitch: case champ_modEnvToFilterFc: case champ_modLfoToPitch:
599     case champ_modLfoToFilterFc: case champ_vibLfoToPitch: case champ_modLfoToVolume:
600         _listeValeurs[index] += value;
601         break;
602     case champ_keynum: case champ_overridingRootKey: case champ_velocity: case champ_exclusiveClass:
603     case champ_sampleModes:
604         _listeValeurs[index] = value;
605         break;
606     case champ_initialFilterFc: case champ_delayVolEnv: case champ_attackVolEnv: case champ_holdVolEnv:
607     case champ_decayVolEnv: case champ_releaseVolEnv: case champ_delayModEnv: case champ_attackModEnv:
608     case champ_holdModEnv: case champ_decayModEnv: case champ_releaseModEnv: case champ_delayModLFO:
609     case champ_freqModLFO: case champ_delayVibLFO: case champ_freqVibLFO:
610         _listeValeurs[index] *= value;
611         break;
612     case champ_keyRange: case champ_velRange:{
613         int minNew = qRound(value / 1000.);
614         int maxNew = qRound(value - 1000. * minNew);
615         int minOld = qRound(_listeValeurs.at(index) / 1000.);
616         int maxOld = qRound(_listeValeurs.at(index) - 1000. * minOld);
617         if (minNew > maxNew)
618         {
619             int tmp = maxNew;
620             maxNew = minNew;
621             minNew = tmp;
622         }
623         if (minOld > maxOld)
624         {
625             int tmp = maxOld;
626             maxOld = minOld;
627             minOld = tmp;
628         }
629         if (maxNew < minOld || maxOld < minNew)
630         {
631             minNew = 0;
632             maxNew = 0;
633         }
634         else
635         {
636             minNew = qMax(minOld, minNew);
637             maxNew = qMin(maxOld, maxNew);
638         }
639         _listeValeurs[index] = 1000. * minNew + maxNew;
640     }break;
641     default:
642         break;
643     }
644 }
645 
limit(double val,AttributeType champ)646 double SfzParamList::limit(double val, AttributeType champ)
647 {
648     double min = 0;
649     double max = 0;
650 
651     switch (champ)
652     {
653     case champ_fineTune:
654         min = -99;      max = 99;
655         break;
656     case champ_coarseTune:
657         min = -120;     max = 120;
658         break;
659     case champ_pan:
660         min = -50;      max = 50;
661         break;
662     case champ_initialAttenuation: case champ_sustainVolEnv: case champ_sustainModEnv:
663         min = 0;        max = 144;
664         break;
665     case champ_reverbEffectsSend: case champ_chorusEffectsSend:
666         min = 0;        max = 100;
667         break;
668     case champ_scaleTuning:
669         min = 0;        max = 1200;
670         break;
671     case champ_initialFilterFc:
672         min = 18;       max = 19914;
673         break;
674     case champ_initialFilterQ:
675         min = 0;      max = 96;
676         break;
677     case champ_delayVolEnv: case champ_holdVolEnv: case champ_holdModEnv:
678     case champ_delayModEnv:
679         min = 0.001;      max = 18;
680         break;
681     case champ_delayModLFO: case champ_delayVibLFO:
682         min = 0.001;      max = 20;
683         break;
684     case champ_freqModLFO: case champ_freqVibLFO:
685         min = 0.001;      max = 100;
686         break;
687     case champ_attackVolEnv: case champ_decayVolEnv: case champ_releaseVolEnv: case champ_releaseModEnv:
688     case champ_attackModEnv: case champ_decayModEnv:
689         min = 0.001;      max = 101.6;
690         break;
691     case champ_keynumToVolEnvHold: case champ_keynumToVolEnvDecay:
692     case champ_keynumToModEnvHold: case champ_keynumToModEnvDecay:
693         min = -1200;      max = 1200;
694         break;
695     case champ_modLfoToVolume:
696         min = -96;        max = 96;
697         break;
698     case champ_modEnvToPitch: case champ_modEnvToFilterFc: case champ_modLfoToPitch:
699     case champ_modLfoToFilterFc: case champ_vibLfoToPitch:
700         min = -12000;     max = 12000;
701         break;
702     case champ_keynum: case champ_overridingRootKey: case champ_velocity: case champ_exclusiveClass:
703         min = 0;          max = 127;
704         break;
705     default:
706         break;
707     }
708 
709     if (min != max)
710     {
711         if (val < min)
712             return min;
713         else if (val > max)
714             return max;
715     }
716 
717     return val;
718 }
719