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