1 /*
2  * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package com.sun.media.sound;
27 
28 import java.util.ArrayList;
29 import java.util.HashMap;
30 import java.util.List;
31 import java.util.Map;
32 
33 import javax.sound.midi.Patch;
34 
35 /**
36  * Soundfont instrument.
37  *
38  * @author Karl Helgason
39  */
40 public final class SF2Instrument extends ModelInstrument {
41 
42     String name = "";
43     int preset = 0;
44     int bank = 0;
45     long library = 0;
46     long genre = 0;
47     long morphology = 0;
48     SF2GlobalRegion globalregion = null;
49     List<SF2InstrumentRegion> regions = new ArrayList<>();
50 
SF2Instrument()51     public SF2Instrument() {
52         super(null, null, null, null);
53     }
54 
SF2Instrument(SF2Soundbank soundbank)55     public SF2Instrument(SF2Soundbank soundbank) {
56         super(soundbank, null, null, null);
57     }
58 
59     @Override
getName()60     public String getName() {
61         return name;
62     }
63 
setName(String name)64     public void setName(String name) {
65         this.name = name;
66     }
67 
68     @Override
getPatch()69     public Patch getPatch() {
70         if (bank == 128)
71             return new ModelPatch(0, preset, true);
72         else
73             return new ModelPatch(bank << 7, preset, false);
74     }
75 
setPatch(Patch patch)76     public void setPatch(Patch patch) {
77         if (patch instanceof ModelPatch && ((ModelPatch) patch).isPercussion()) {
78             bank = 128;
79             preset = patch.getProgram();
80         } else {
81             bank = patch.getBank() >> 7;
82             preset = patch.getProgram();
83         }
84     }
85 
86     @Override
getData()87     public Object getData() {
88         return null;
89     }
90 
getGenre()91     public long getGenre() {
92         return genre;
93     }
94 
setGenre(long genre)95     public void setGenre(long genre) {
96         this.genre = genre;
97     }
98 
getLibrary()99     public long getLibrary() {
100         return library;
101     }
102 
setLibrary(long library)103     public void setLibrary(long library) {
104         this.library = library;
105     }
106 
getMorphology()107     public long getMorphology() {
108         return morphology;
109     }
110 
setMorphology(long morphology)111     public void setMorphology(long morphology) {
112         this.morphology = morphology;
113     }
114 
getRegions()115     public List<SF2InstrumentRegion> getRegions() {
116         return regions;
117     }
118 
getGlobalRegion()119     public SF2GlobalRegion getGlobalRegion() {
120         return globalregion;
121     }
122 
setGlobalZone(SF2GlobalRegion zone)123     public void setGlobalZone(SF2GlobalRegion zone) {
124         globalregion = zone;
125     }
126 
127     @Override
toString()128     public String toString() {
129         if (bank == 128)
130             return "Drumkit: " + name + " preset #" + preset;
131         else
132             return "Instrument: " + name + " bank #" + bank
133                     + " preset #" + preset;
134     }
135 
136     @Override
getPerformers()137     public ModelPerformer[] getPerformers() {
138         int performercount = 0;
139         for (SF2InstrumentRegion presetzone : regions)
140             performercount += presetzone.getLayer().getRegions().size();
141         ModelPerformer[] performers = new ModelPerformer[performercount];
142         int pi = 0;
143 
144         SF2GlobalRegion presetglobal = globalregion;
145         for (SF2InstrumentRegion presetzone : regions) {
146             Map<Integer, Short> pgenerators = new HashMap<>();
147             pgenerators.putAll(presetzone.getGenerators());
148             if (presetglobal != null)
149                 pgenerators.putAll(presetglobal.getGenerators());
150 
151             SF2Layer layer = presetzone.getLayer();
152             SF2GlobalRegion layerglobal = layer.getGlobalRegion();
153             for (SF2LayerRegion layerzone : layer.getRegions()) {
154                 ModelPerformer performer = new ModelPerformer();
155                 if (layerzone.getSample() != null)
156                     performer.setName(layerzone.getSample().getName());
157                 else
158                     performer.setName(layer.getName());
159 
160                 performers[pi++] = performer;
161 
162                 int keyfrom = 0;
163                 int keyto = 127;
164                 int velfrom = 0;
165                 int velto = 127;
166 
167                 if (layerzone.contains(SF2Region.GENERATOR_EXCLUSIVECLASS)) {
168                     performer.setExclusiveClass(layerzone.getInteger(
169                             SF2Region.GENERATOR_EXCLUSIVECLASS));
170                 }
171                 if (layerzone.contains(SF2Region.GENERATOR_KEYRANGE)) {
172                     byte[] bytes = layerzone.getBytes(
173                             SF2Region.GENERATOR_KEYRANGE);
174                     if (bytes[0] >= 0)
175                         if (bytes[0] > keyfrom)
176                             keyfrom = bytes[0];
177                     if (bytes[1] >= 0)
178                         if (bytes[1] < keyto)
179                             keyto = bytes[1];
180                 }
181                 if (layerzone.contains(SF2Region.GENERATOR_VELRANGE)) {
182                     byte[] bytes = layerzone.getBytes(
183                             SF2Region.GENERATOR_VELRANGE);
184                     if (bytes[0] >= 0)
185                         if (bytes[0] > velfrom)
186                             velfrom = bytes[0];
187                     if (bytes[1] >= 0)
188                         if (bytes[1] < velto)
189                             velto = bytes[1];
190                 }
191                 if (presetzone.contains(SF2Region.GENERATOR_KEYRANGE)) {
192                     byte[] bytes = presetzone.getBytes(
193                             SF2Region.GENERATOR_KEYRANGE);
194                     if (bytes[0] > keyfrom)
195                         keyfrom = bytes[0];
196                     if (bytes[1] < keyto)
197                         keyto = bytes[1];
198                 }
199                 if (presetzone.contains(SF2Region.GENERATOR_VELRANGE)) {
200                     byte[] bytes = presetzone.getBytes(
201                             SF2Region.GENERATOR_VELRANGE);
202                     if (bytes[0] > velfrom)
203                         velfrom = bytes[0];
204                     if (bytes[1] < velto)
205                         velto = bytes[1];
206                 }
207                 performer.setKeyFrom(keyfrom);
208                 performer.setKeyTo(keyto);
209                 performer.setVelFrom(velfrom);
210                 performer.setVelTo(velto);
211 
212                 int startAddrsOffset = layerzone.getShort(
213                         SF2Region.GENERATOR_STARTADDRSOFFSET);
214                 int endAddrsOffset = layerzone.getShort(
215                         SF2Region.GENERATOR_ENDADDRSOFFSET);
216                 int startloopAddrsOffset = layerzone.getShort(
217                         SF2Region.GENERATOR_STARTLOOPADDRSOFFSET);
218                 int endloopAddrsOffset = layerzone.getShort(
219                         SF2Region.GENERATOR_ENDLOOPADDRSOFFSET);
220 
221                 startAddrsOffset += layerzone.getShort(
222                         SF2Region.GENERATOR_STARTADDRSCOARSEOFFSET) * 32768;
223                 endAddrsOffset += layerzone.getShort(
224                         SF2Region.GENERATOR_ENDADDRSCOARSEOFFSET) * 32768;
225                 startloopAddrsOffset += layerzone.getShort(
226                         SF2Region.GENERATOR_STARTLOOPADDRSCOARSEOFFSET) * 32768;
227                 endloopAddrsOffset += layerzone.getShort(
228                         SF2Region.GENERATOR_ENDLOOPADDRSCOARSEOFFSET) * 32768;
229                 startloopAddrsOffset -= startAddrsOffset;
230                 endloopAddrsOffset -= startAddrsOffset;
231 
232                 SF2Sample sample = layerzone.getSample();
233                 int rootkey = sample.originalPitch;
234                 if (layerzone.getShort(SF2Region.GENERATOR_OVERRIDINGROOTKEY) != -1) {
235                     rootkey = layerzone.getShort(
236                             SF2Region.GENERATOR_OVERRIDINGROOTKEY);
237                 }
238                 float pitchcorrection = (-rootkey * 100) + sample.pitchCorrection;
239                 ModelByteBuffer buff = sample.getDataBuffer();
240                 ModelByteBuffer buff24 = sample.getData24Buffer();
241 
242                 if (startAddrsOffset != 0 || endAddrsOffset != 0) {
243                     buff = buff.subbuffer(startAddrsOffset * 2,
244                             buff.capacity() + endAddrsOffset * 2);
245                     if (buff24 != null) {
246                         buff24 = buff24.subbuffer(startAddrsOffset,
247                                 buff24.capacity() + endAddrsOffset);
248                     }
249 
250                     /*
251                     if (startAddrsOffset < 0)
252                         startAddrsOffset = 0;
253                     if (endAddrsOffset > (buff.capacity()/2-startAddrsOffset))
254                         startAddrsOffset = (int)buff.capacity()/2-startAddrsOffset;
255                     byte[] data = buff.array();
256                     int off = (int)buff.arrayOffset() + startAddrsOffset*2;
257                     int len = (int)buff.capacity() + endAddrsOffset*2;
258                     if (off+len > data.length)
259                         len = data.length - off;
260                     buff = new ModelByteBuffer(data, off, len);
261                     if(buff24 != null) {
262                         data = buff.array();
263                         off = (int)buff.arrayOffset() + startAddrsOffset;
264                         len = (int)buff.capacity() + endAddrsOffset;
265                         buff24 = new ModelByteBuffer(data, off, len);
266                     }
267                     */
268                 }
269 
270                 ModelByteBufferWavetable osc = new ModelByteBufferWavetable(
271                         buff, sample.getFormat(), pitchcorrection);
272                 if (buff24 != null)
273                     osc.set8BitExtensionBuffer(buff24);
274 
275                 Map<Integer, Short> generators = new HashMap<>();
276                 if (layerglobal != null)
277                     generators.putAll(layerglobal.getGenerators());
278                 generators.putAll(layerzone.getGenerators());
279                 for (Map.Entry<Integer, Short> gen : pgenerators.entrySet()) {
280                     short val;
281                     if (!generators.containsKey(gen.getKey()))
282                         val = layerzone.getShort(gen.getKey());
283                     else
284                         val = generators.get(gen.getKey());
285                     val += gen.getValue();
286                     generators.put(gen.getKey(), val);
287                 }
288 
289                 // SampleMode:
290                 // 0 indicates a sound reproduced with no loop
291                 // 1 indicates a sound which loops continuously
292                 // 2 is unused but should be interpreted as indicating no loop
293                 // 3 indicates a sound which loops for the duration of key
294                 //   depression then proceeds to play the remainder of the sample.
295                 int sampleMode = getGeneratorValue(generators,
296                         SF2Region.GENERATOR_SAMPLEMODES);
297                 if ((sampleMode == 1) || (sampleMode == 3)) {
298                     if (sample.startLoop >= 0 && sample.endLoop > 0) {
299                         osc.setLoopStart((int)(sample.startLoop
300                                 + startloopAddrsOffset));
301                         osc.setLoopLength((int)(sample.endLoop - sample.startLoop
302                                 + endloopAddrsOffset - startloopAddrsOffset));
303                         if (sampleMode == 1)
304                             osc.setLoopType(ModelWavetable.LOOP_TYPE_FORWARD);
305                         if (sampleMode == 3)
306                             osc.setLoopType(ModelWavetable.LOOP_TYPE_RELEASE);
307                     }
308                 }
309                 performer.getOscillators().add(osc);
310 
311 
312                 short volDelay = getGeneratorValue(generators,
313                         SF2Region.GENERATOR_DELAYVOLENV);
314                 short volAttack = getGeneratorValue(generators,
315                         SF2Region.GENERATOR_ATTACKVOLENV);
316                 short volHold = getGeneratorValue(generators,
317                         SF2Region.GENERATOR_HOLDVOLENV);
318                 short volDecay = getGeneratorValue(generators,
319                         SF2Region.GENERATOR_DECAYVOLENV);
320                 short volSustain = getGeneratorValue(generators,
321                         SF2Region.GENERATOR_SUSTAINVOLENV);
322                 short volRelease = getGeneratorValue(generators,
323                         SF2Region.GENERATOR_RELEASEVOLENV);
324 
325                 if (volHold != -12000) {
326                     short volKeyNumToHold = getGeneratorValue(generators,
327                             SF2Region.GENERATOR_KEYNUMTOVOLENVHOLD);
328                     volHold += 60 * volKeyNumToHold;
329                     float fvalue = -volKeyNumToHold * 128;
330                     ModelIdentifier src = ModelSource.SOURCE_NOTEON_KEYNUMBER;
331                     ModelIdentifier dest = ModelDestination.DESTINATION_EG1_HOLD;
332                     performer.getConnectionBlocks().add(
333                         new ModelConnectionBlock(new ModelSource(src), fvalue,
334                             new ModelDestination(dest)));
335                 }
336                 if (volDecay != -12000) {
337                     short volKeyNumToDecay = getGeneratorValue(generators,
338                             SF2Region.GENERATOR_KEYNUMTOVOLENVDECAY);
339                     volDecay += 60 * volKeyNumToDecay;
340                     float fvalue = -volKeyNumToDecay * 128;
341                     ModelIdentifier src = ModelSource.SOURCE_NOTEON_KEYNUMBER;
342                     ModelIdentifier dest = ModelDestination.DESTINATION_EG1_DECAY;
343                     performer.getConnectionBlocks().add(
344                         new ModelConnectionBlock(new ModelSource(src), fvalue,
345                             new ModelDestination(dest)));
346                 }
347 
348                 addTimecentValue(performer,
349                         ModelDestination.DESTINATION_EG1_DELAY, volDelay);
350                 addTimecentValue(performer,
351                         ModelDestination.DESTINATION_EG1_ATTACK, volAttack);
352                 addTimecentValue(performer,
353                         ModelDestination.DESTINATION_EG1_HOLD, volHold);
354                 addTimecentValue(performer,
355                         ModelDestination.DESTINATION_EG1_DECAY, volDecay);
356                 //float fvolsustain = (960-volSustain)*(1000.0f/960.0f);
357 
358                 volSustain = (short)(1000 - volSustain);
359                 if (volSustain < 0)
360                     volSustain = 0;
361                 if (volSustain > 1000)
362                     volSustain = 1000;
363 
364                 addValue(performer,
365                         ModelDestination.DESTINATION_EG1_SUSTAIN, volSustain);
366                 addTimecentValue(performer,
367                         ModelDestination.DESTINATION_EG1_RELEASE, volRelease);
368 
369                 if (getGeneratorValue(generators,
370                             SF2Region.GENERATOR_MODENVTOFILTERFC) != 0
371                         || getGeneratorValue(generators,
372                             SF2Region.GENERATOR_MODENVTOPITCH) != 0) {
373                     short modDelay = getGeneratorValue(generators,
374                             SF2Region.GENERATOR_DELAYMODENV);
375                     short modAttack = getGeneratorValue(generators,
376                             SF2Region.GENERATOR_ATTACKMODENV);
377                     short modHold = getGeneratorValue(generators,
378                             SF2Region.GENERATOR_HOLDMODENV);
379                     short modDecay = getGeneratorValue(generators,
380                             SF2Region.GENERATOR_DECAYMODENV);
381                     short modSustain = getGeneratorValue(generators,
382                             SF2Region.GENERATOR_SUSTAINMODENV);
383                     short modRelease = getGeneratorValue(generators,
384                             SF2Region.GENERATOR_RELEASEMODENV);
385 
386 
387                     if (modHold != -12000) {
388                         short modKeyNumToHold = getGeneratorValue(generators,
389                                 SF2Region.GENERATOR_KEYNUMTOMODENVHOLD);
390                         modHold += 60 * modKeyNumToHold;
391                         float fvalue = -modKeyNumToHold * 128;
392                         ModelIdentifier src = ModelSource.SOURCE_NOTEON_KEYNUMBER;
393                         ModelIdentifier dest = ModelDestination.DESTINATION_EG2_HOLD;
394                         performer.getConnectionBlocks().add(
395                             new ModelConnectionBlock(new ModelSource(src),
396                                 fvalue, new ModelDestination(dest)));
397                     }
398                     if (modDecay != -12000) {
399                         short modKeyNumToDecay = getGeneratorValue(generators,
400                                 SF2Region.GENERATOR_KEYNUMTOMODENVDECAY);
401                         modDecay += 60 * modKeyNumToDecay;
402                         float fvalue = -modKeyNumToDecay * 128;
403                         ModelIdentifier src = ModelSource.SOURCE_NOTEON_KEYNUMBER;
404                         ModelIdentifier dest = ModelDestination.DESTINATION_EG2_DECAY;
405                         performer.getConnectionBlocks().add(
406                             new ModelConnectionBlock(new ModelSource(src),
407                                 fvalue, new ModelDestination(dest)));
408                     }
409 
410                     addTimecentValue(performer,
411                             ModelDestination.DESTINATION_EG2_DELAY, modDelay);
412                     addTimecentValue(performer,
413                             ModelDestination.DESTINATION_EG2_ATTACK, modAttack);
414                     addTimecentValue(performer,
415                             ModelDestination.DESTINATION_EG2_HOLD, modHold);
416                     addTimecentValue(performer,
417                             ModelDestination.DESTINATION_EG2_DECAY, modDecay);
418                     if (modSustain < 0)
419                         modSustain = 0;
420                     if (modSustain > 1000)
421                         modSustain = 1000;
422                     addValue(performer, ModelDestination.DESTINATION_EG2_SUSTAIN,
423                             1000 - modSustain);
424                     addTimecentValue(performer,
425                             ModelDestination.DESTINATION_EG2_RELEASE, modRelease);
426 
427                     if (getGeneratorValue(generators,
428                             SF2Region.GENERATOR_MODENVTOFILTERFC) != 0) {
429                         double fvalue = getGeneratorValue(generators,
430                                 SF2Region.GENERATOR_MODENVTOFILTERFC);
431                         ModelIdentifier src = ModelSource.SOURCE_EG2;
432                         ModelIdentifier dest
433                                 = ModelDestination.DESTINATION_FILTER_FREQ;
434                         performer.getConnectionBlocks().add(
435                             new ModelConnectionBlock(new ModelSource(src),
436                                 fvalue, new ModelDestination(dest)));
437                     }
438 
439                     if (getGeneratorValue(generators,
440                             SF2Region.GENERATOR_MODENVTOPITCH) != 0) {
441                         double fvalue = getGeneratorValue(generators,
442                                 SF2Region.GENERATOR_MODENVTOPITCH);
443                         ModelIdentifier src = ModelSource.SOURCE_EG2;
444                         ModelIdentifier dest = ModelDestination.DESTINATION_PITCH;
445                         performer.getConnectionBlocks().add(
446                             new ModelConnectionBlock(new ModelSource(src),
447                                 fvalue, new ModelDestination(dest)));
448                     }
449 
450                 }
451 
452                 if (getGeneratorValue(generators,
453                             SF2Region.GENERATOR_MODLFOTOFILTERFC) != 0
454                         || getGeneratorValue(generators,
455                             SF2Region.GENERATOR_MODLFOTOPITCH) != 0
456                         || getGeneratorValue(generators,
457                             SF2Region.GENERATOR_MODLFOTOVOLUME) != 0) {
458                     short lfo_freq = getGeneratorValue(generators,
459                             SF2Region.GENERATOR_FREQMODLFO);
460                     short lfo_delay = getGeneratorValue(generators,
461                             SF2Region.GENERATOR_DELAYMODLFO);
462                     addTimecentValue(performer,
463                             ModelDestination.DESTINATION_LFO1_DELAY, lfo_delay);
464                     addValue(performer,
465                             ModelDestination.DESTINATION_LFO1_FREQ, lfo_freq);
466                 }
467 
468                 short vib_freq = getGeneratorValue(generators,
469                         SF2Region.GENERATOR_FREQVIBLFO);
470                 short vib_delay = getGeneratorValue(generators,
471                         SF2Region.GENERATOR_DELAYVIBLFO);
472                 addTimecentValue(performer,
473                         ModelDestination.DESTINATION_LFO2_DELAY, vib_delay);
474                 addValue(performer,
475                         ModelDestination.DESTINATION_LFO2_FREQ, vib_freq);
476 
477 
478                 if (getGeneratorValue(generators,
479                         SF2Region.GENERATOR_VIBLFOTOPITCH) != 0) {
480                     double fvalue = getGeneratorValue(generators,
481                             SF2Region.GENERATOR_VIBLFOTOPITCH);
482                     ModelIdentifier src = ModelSource.SOURCE_LFO2;
483                     ModelIdentifier dest = ModelDestination.DESTINATION_PITCH;
484                     performer.getConnectionBlocks().add(
485                         new ModelConnectionBlock(
486                             new ModelSource(src,
487                                 ModelStandardTransform.DIRECTION_MIN2MAX,
488                                 ModelStandardTransform.POLARITY_BIPOLAR),
489                             fvalue, new ModelDestination(dest)));
490                 }
491 
492                 if (getGeneratorValue(generators,
493                         SF2Region.GENERATOR_MODLFOTOFILTERFC) != 0) {
494                     double fvalue = getGeneratorValue(generators,
495                             SF2Region.GENERATOR_MODLFOTOFILTERFC);
496                     ModelIdentifier src = ModelSource.SOURCE_LFO1;
497                     ModelIdentifier dest = ModelDestination.DESTINATION_FILTER_FREQ;
498                     performer.getConnectionBlocks().add(
499                         new ModelConnectionBlock(
500                             new ModelSource(src,
501                                 ModelStandardTransform.DIRECTION_MIN2MAX,
502                                 ModelStandardTransform.POLARITY_BIPOLAR),
503                             fvalue, new ModelDestination(dest)));
504                 }
505 
506                 if (getGeneratorValue(generators,
507                         SF2Region.GENERATOR_MODLFOTOPITCH) != 0) {
508                     double fvalue = getGeneratorValue(generators,
509                             SF2Region.GENERATOR_MODLFOTOPITCH);
510                     ModelIdentifier src = ModelSource.SOURCE_LFO1;
511                     ModelIdentifier dest = ModelDestination.DESTINATION_PITCH;
512                     performer.getConnectionBlocks().add(
513                         new ModelConnectionBlock(
514                             new ModelSource(src,
515                                 ModelStandardTransform.DIRECTION_MIN2MAX,
516                                 ModelStandardTransform.POLARITY_BIPOLAR),
517                             fvalue, new ModelDestination(dest)));
518                 }
519 
520                 if (getGeneratorValue(generators,
521                         SF2Region.GENERATOR_MODLFOTOVOLUME) != 0) {
522                     double fvalue = getGeneratorValue(generators,
523                             SF2Region.GENERATOR_MODLFOTOVOLUME);
524                     ModelIdentifier src = ModelSource.SOURCE_LFO1;
525                     ModelIdentifier dest = ModelDestination.DESTINATION_GAIN;
526                     performer.getConnectionBlocks().add(
527                         new ModelConnectionBlock(
528                             new ModelSource(src,
529                                 ModelStandardTransform.DIRECTION_MIN2MAX,
530                                 ModelStandardTransform.POLARITY_BIPOLAR),
531                             fvalue, new ModelDestination(dest)));
532                 }
533 
534                 if (layerzone.getShort(SF2Region.GENERATOR_KEYNUM) != -1) {
535                     double val = layerzone.getShort(SF2Region.GENERATOR_KEYNUM)/128.0;
536                     addValue(performer, ModelDestination.DESTINATION_KEYNUMBER, val);
537                 }
538 
539                 if (layerzone.getShort(SF2Region.GENERATOR_VELOCITY) != -1) {
540                     double val = layerzone.getShort(SF2Region.GENERATOR_VELOCITY)
541                                  / 128.0;
542                     addValue(performer, ModelDestination.DESTINATION_VELOCITY, val);
543                 }
544 
545                 if (getGeneratorValue(generators,
546                         SF2Region.GENERATOR_INITIALFILTERFC) < 13500) {
547                     short filter_freq = getGeneratorValue(generators,
548                             SF2Region.GENERATOR_INITIALFILTERFC);
549                     short filter_q = getGeneratorValue(generators,
550                             SF2Region.GENERATOR_INITIALFILTERQ);
551                     addValue(performer,
552                             ModelDestination.DESTINATION_FILTER_FREQ, filter_freq);
553                     addValue(performer,
554                             ModelDestination.DESTINATION_FILTER_Q, filter_q);
555                 }
556 
557                 int tune = 100 * getGeneratorValue(generators,
558                         SF2Region.GENERATOR_COARSETUNE);
559                 tune += getGeneratorValue(generators,
560                         SF2Region.GENERATOR_FINETUNE);
561                 if (tune != 0) {
562                     addValue(performer,
563                             ModelDestination.DESTINATION_PITCH, (short) tune);
564                 }
565                 if (getGeneratorValue(generators, SF2Region.GENERATOR_PAN) != 0) {
566                     short val = getGeneratorValue(generators,
567                             SF2Region.GENERATOR_PAN);
568                     addValue(performer, ModelDestination.DESTINATION_PAN, val);
569                 }
570                 if (getGeneratorValue(generators, SF2Region.GENERATOR_INITIALATTENUATION) != 0) {
571                     short val = getGeneratorValue(generators,
572                             SF2Region.GENERATOR_INITIALATTENUATION);
573                     addValue(performer,
574                             ModelDestination.DESTINATION_GAIN, -0.376287f * val);
575                 }
576                 if (getGeneratorValue(generators,
577                         SF2Region.GENERATOR_CHORUSEFFECTSSEND) != 0) {
578                     short val = getGeneratorValue(generators,
579                             SF2Region.GENERATOR_CHORUSEFFECTSSEND);
580                     addValue(performer, ModelDestination.DESTINATION_CHORUS, val);
581                 }
582                 if (getGeneratorValue(generators,
583                         SF2Region.GENERATOR_REVERBEFFECTSSEND) != 0) {
584                     short val = getGeneratorValue(generators,
585                             SF2Region.GENERATOR_REVERBEFFECTSSEND);
586                     addValue(performer, ModelDestination.DESTINATION_REVERB, val);
587                 }
588                 if (getGeneratorValue(generators,
589                         SF2Region.GENERATOR_SCALETUNING) != 100) {
590                     short fvalue = getGeneratorValue(generators,
591                             SF2Region.GENERATOR_SCALETUNING);
592                     if (fvalue == 0) {
593                         ModelIdentifier dest = ModelDestination.DESTINATION_PITCH;
594                         performer.getConnectionBlocks().add(
595                             new ModelConnectionBlock(null, rootkey * 100,
596                                 new ModelDestination(dest)));
597                     } else {
598                         ModelIdentifier dest = ModelDestination.DESTINATION_PITCH;
599                         performer.getConnectionBlocks().add(
600                             new ModelConnectionBlock(null, rootkey * (100 - fvalue),
601                                 new ModelDestination(dest)));
602                     }
603 
604                     ModelIdentifier src = ModelSource.SOURCE_NOTEON_KEYNUMBER;
605                     ModelIdentifier dest = ModelDestination.DESTINATION_PITCH;
606                     performer.getConnectionBlocks().add(
607                         new ModelConnectionBlock(new ModelSource(src),
608                             128 * fvalue, new ModelDestination(dest)));
609 
610                 }
611 
612                 performer.getConnectionBlocks().add(
613                     new ModelConnectionBlock(
614                         new ModelSource(ModelSource.SOURCE_NOTEON_VELOCITY,
615                             new ModelTransform() {
616                                 @Override
617                                 public double transform(double value) {
618                                     if (value < 0.5)
619                                         return 1 - value * 2;
620                                     else
621                                         return 0;
622                                 }
623                             }),
624                         -2400,
625                         new ModelDestination(
626                             ModelDestination.DESTINATION_FILTER_FREQ)));
627 
628 
629                 performer.getConnectionBlocks().add(
630                     new ModelConnectionBlock(
631                         new ModelSource(ModelSource.SOURCE_LFO2,
632                             ModelStandardTransform.DIRECTION_MIN2MAX,
633                             ModelStandardTransform.POLARITY_BIPOLAR,
634                             ModelStandardTransform.TRANSFORM_LINEAR),
635                         new ModelSource(new ModelIdentifier("midi_cc", "1", 0),
636                             ModelStandardTransform.DIRECTION_MIN2MAX,
637                             ModelStandardTransform.POLARITY_UNIPOLAR,
638                             ModelStandardTransform.TRANSFORM_LINEAR),
639                         50, new ModelDestination(
640                             ModelDestination.DESTINATION_PITCH)));
641 
642                 if (layer.getGlobalRegion() != null) {
643                     for (SF2Modulator modulator
644                             : layer.getGlobalRegion().getModulators()) {
645                         convertModulator(performer, modulator);
646                     }
647                 }
648                 for (SF2Modulator modulator : layerzone.getModulators())
649                     convertModulator(performer, modulator);
650 
651                 if (presetglobal != null) {
652                     for (SF2Modulator modulator : presetglobal.getModulators())
653                         convertModulator(performer, modulator);
654                 }
655                 for (SF2Modulator modulator : presetzone.getModulators())
656                     convertModulator(performer, modulator);
657 
658             }
659         }
660         return performers;
661     }
662 
convertModulator(ModelPerformer performer, SF2Modulator modulator)663     private void convertModulator(ModelPerformer performer,
664             SF2Modulator modulator) {
665         ModelSource src1 = convertSource(modulator.getSourceOperator());
666         ModelSource src2 = convertSource(modulator.getAmountSourceOperator());
667         if (src1 == null && modulator.getSourceOperator() != 0)
668             return;
669         if (src2 == null && modulator.getAmountSourceOperator() != 0)
670             return;
671         double amount = modulator.getAmount();
672         double[] amountcorrection = new double[1];
673         ModelSource[] extrasrc = new ModelSource[1];
674         amountcorrection[0] = 1;
675         ModelDestination dst = convertDestination(
676                 modulator.getDestinationOperator(), amountcorrection, extrasrc);
677         amount *= amountcorrection[0];
678         if (dst == null)
679             return;
680         if (modulator.getTransportOperator() == SF2Modulator.TRANSFORM_ABSOLUTE) {
681             ((ModelStandardTransform)dst.getTransform()).setTransform(
682                     ModelStandardTransform.TRANSFORM_ABSOLUTE);
683         }
684         ModelConnectionBlock conn = new ModelConnectionBlock(src1, src2, amount, dst);
685         if (extrasrc[0] != null)
686             conn.addSource(extrasrc[0]);
687         performer.getConnectionBlocks().add(conn);
688 
689     }
690 
convertSource(int src)691     private static ModelSource convertSource(int src) {
692         if (src == 0)
693             return null;
694         ModelIdentifier id = null;
695         int idsrc = src & 0x7F;
696         if ((src & SF2Modulator.SOURCE_MIDI_CONTROL) != 0) {
697             id = new ModelIdentifier("midi_cc", Integer.toString(idsrc));
698         } else {
699             if (idsrc == SF2Modulator.SOURCE_NOTE_ON_VELOCITY)
700                 id = ModelSource.SOURCE_NOTEON_VELOCITY;
701             if (idsrc == SF2Modulator.SOURCE_NOTE_ON_KEYNUMBER)
702                 id = ModelSource.SOURCE_NOTEON_KEYNUMBER;
703             if (idsrc == SF2Modulator.SOURCE_POLY_PRESSURE)
704                 id = ModelSource.SOURCE_MIDI_POLY_PRESSURE;
705             if (idsrc == SF2Modulator.SOURCE_CHANNEL_PRESSURE)
706                 id = ModelSource.SOURCE_MIDI_CHANNEL_PRESSURE;
707             if (idsrc == SF2Modulator.SOURCE_PITCH_WHEEL)
708                 id = ModelSource.SOURCE_MIDI_PITCH;
709             if (idsrc == SF2Modulator.SOURCE_PITCH_SENSITIVITY)
710                 id = new ModelIdentifier("midi_rpn", "0");
711         }
712         if (id == null)
713             return null;
714 
715         ModelSource msrc = new ModelSource(id);
716         ModelStandardTransform transform
717                 = (ModelStandardTransform) msrc.getTransform();
718 
719         if ((SF2Modulator.SOURCE_DIRECTION_MAX_MIN & src) != 0)
720             transform.setDirection(ModelStandardTransform.DIRECTION_MAX2MIN);
721         else
722             transform.setDirection(ModelStandardTransform.DIRECTION_MIN2MAX);
723 
724         if ((SF2Modulator.SOURCE_POLARITY_BIPOLAR & src) != 0)
725             transform.setPolarity(ModelStandardTransform.POLARITY_BIPOLAR);
726         else
727             transform.setPolarity(ModelStandardTransform.POLARITY_UNIPOLAR);
728 
729         if ((SF2Modulator.SOURCE_TYPE_CONCAVE & src) != 0)
730             transform.setTransform(ModelStandardTransform.TRANSFORM_CONCAVE);
731         if ((SF2Modulator.SOURCE_TYPE_CONVEX & src) != 0)
732             transform.setTransform(ModelStandardTransform.TRANSFORM_CONVEX);
733         if ((SF2Modulator.SOURCE_TYPE_SWITCH & src) != 0)
734             transform.setTransform(ModelStandardTransform.TRANSFORM_SWITCH);
735 
736         return msrc;
737     }
738 
convertDestination(int dst, double[] amountcorrection, ModelSource[] extrasrc)739     static ModelDestination convertDestination(int dst,
740             double[] amountcorrection, ModelSource[] extrasrc) {
741         ModelIdentifier id = null;
742         switch (dst) {
743             case SF2Region.GENERATOR_INITIALFILTERFC:
744                 id = ModelDestination.DESTINATION_FILTER_FREQ;
745                 break;
746             case SF2Region.GENERATOR_INITIALFILTERQ:
747                 id = ModelDestination.DESTINATION_FILTER_Q;
748                 break;
749             case SF2Region.GENERATOR_CHORUSEFFECTSSEND:
750                 id = ModelDestination.DESTINATION_CHORUS;
751                 break;
752             case SF2Region.GENERATOR_REVERBEFFECTSSEND:
753                 id = ModelDestination.DESTINATION_REVERB;
754                 break;
755             case SF2Region.GENERATOR_PAN:
756                 id = ModelDestination.DESTINATION_PAN;
757                 break;
758             case SF2Region.GENERATOR_DELAYMODLFO:
759                 id = ModelDestination.DESTINATION_LFO1_DELAY;
760                 break;
761             case SF2Region.GENERATOR_FREQMODLFO:
762                 id = ModelDestination.DESTINATION_LFO1_FREQ;
763                 break;
764             case SF2Region.GENERATOR_DELAYVIBLFO:
765                 id = ModelDestination.DESTINATION_LFO2_DELAY;
766                 break;
767             case SF2Region.GENERATOR_FREQVIBLFO:
768                 id = ModelDestination.DESTINATION_LFO2_FREQ;
769                 break;
770 
771             case SF2Region.GENERATOR_DELAYMODENV:
772                 id = ModelDestination.DESTINATION_EG2_DELAY;
773                 break;
774             case SF2Region.GENERATOR_ATTACKMODENV:
775                 id = ModelDestination.DESTINATION_EG2_ATTACK;
776                 break;
777             case SF2Region.GENERATOR_HOLDMODENV:
778                 id = ModelDestination.DESTINATION_EG2_HOLD;
779                 break;
780             case SF2Region.GENERATOR_DECAYMODENV:
781                 id = ModelDestination.DESTINATION_EG2_DECAY;
782                 break;
783             case SF2Region.GENERATOR_SUSTAINMODENV:
784                 id = ModelDestination.DESTINATION_EG2_SUSTAIN;
785                 amountcorrection[0] = -1;
786                 break;
787             case SF2Region.GENERATOR_RELEASEMODENV:
788                 id = ModelDestination.DESTINATION_EG2_RELEASE;
789                 break;
790             case SF2Region.GENERATOR_DELAYVOLENV:
791                 id = ModelDestination.DESTINATION_EG1_DELAY;
792                 break;
793             case SF2Region.GENERATOR_ATTACKVOLENV:
794                 id = ModelDestination.DESTINATION_EG1_ATTACK;
795                 break;
796             case SF2Region.GENERATOR_HOLDVOLENV:
797                 id = ModelDestination.DESTINATION_EG1_HOLD;
798                 break;
799             case SF2Region.GENERATOR_DECAYVOLENV:
800                 id = ModelDestination.DESTINATION_EG1_DECAY;
801                 break;
802             case SF2Region.GENERATOR_SUSTAINVOLENV:
803                 id = ModelDestination.DESTINATION_EG1_SUSTAIN;
804                 amountcorrection[0] = -1;
805                 break;
806             case SF2Region.GENERATOR_RELEASEVOLENV:
807                 id = ModelDestination.DESTINATION_EG1_RELEASE;
808                 break;
809             case SF2Region.GENERATOR_KEYNUM:
810                 id = ModelDestination.DESTINATION_KEYNUMBER;
811                 break;
812             case SF2Region.GENERATOR_VELOCITY:
813                 id = ModelDestination.DESTINATION_VELOCITY;
814                 break;
815 
816             case SF2Region.GENERATOR_COARSETUNE:
817                 amountcorrection[0] = 100;
818                 id = ModelDestination.DESTINATION_PITCH;
819                 break;
820 
821             case SF2Region.GENERATOR_FINETUNE:
822                 id = ModelDestination.DESTINATION_PITCH;
823                 break;
824 
825             case SF2Region.GENERATOR_INITIALATTENUATION:
826                 id = ModelDestination.DESTINATION_GAIN;
827                 amountcorrection[0] = -0.376287f;
828                 break;
829 
830             case SF2Region.GENERATOR_VIBLFOTOPITCH:
831                 id = ModelDestination.DESTINATION_PITCH;
832                 extrasrc[0] = new ModelSource(
833                         ModelSource.SOURCE_LFO2,
834                         ModelStandardTransform.DIRECTION_MIN2MAX,
835                         ModelStandardTransform.POLARITY_BIPOLAR);
836                 break;
837 
838             case SF2Region.GENERATOR_MODLFOTOPITCH:
839                 id = ModelDestination.DESTINATION_PITCH;
840                 extrasrc[0] = new ModelSource(
841                         ModelSource.SOURCE_LFO1,
842                         ModelStandardTransform.DIRECTION_MIN2MAX,
843                         ModelStandardTransform.POLARITY_BIPOLAR);
844                 break;
845 
846             case SF2Region.GENERATOR_MODLFOTOFILTERFC:
847                 id = ModelDestination.DESTINATION_FILTER_FREQ;
848                 extrasrc[0] = new ModelSource(
849                         ModelSource.SOURCE_LFO1,
850                         ModelStandardTransform.DIRECTION_MIN2MAX,
851                         ModelStandardTransform.POLARITY_BIPOLAR);
852                 break;
853 
854             case SF2Region.GENERATOR_MODLFOTOVOLUME:
855                 id = ModelDestination.DESTINATION_GAIN;
856                 amountcorrection[0] = -0.376287f;
857                 extrasrc[0] = new ModelSource(
858                         ModelSource.SOURCE_LFO1,
859                         ModelStandardTransform.DIRECTION_MIN2MAX,
860                         ModelStandardTransform.POLARITY_BIPOLAR);
861                 break;
862 
863             case SF2Region.GENERATOR_MODENVTOPITCH:
864                 id = ModelDestination.DESTINATION_PITCH;
865                 extrasrc[0] = new ModelSource(
866                         ModelSource.SOURCE_EG2,
867                         ModelStandardTransform.DIRECTION_MIN2MAX,
868                         ModelStandardTransform.POLARITY_BIPOLAR);
869                 break;
870 
871             case SF2Region.GENERATOR_MODENVTOFILTERFC:
872                 id = ModelDestination.DESTINATION_FILTER_FREQ;
873                 extrasrc[0] = new ModelSource(
874                         ModelSource.SOURCE_EG2,
875                         ModelStandardTransform.DIRECTION_MIN2MAX,
876                         ModelStandardTransform.POLARITY_BIPOLAR);
877                 break;
878 
879             default:
880                 break;
881         }
882         if (id != null)
883             return new ModelDestination(id);
884         return null;
885     }
886 
addTimecentValue(ModelPerformer performer, ModelIdentifier dest, short value)887     private void addTimecentValue(ModelPerformer performer,
888             ModelIdentifier dest, short value) {
889         double fvalue;
890         if (value == -12000)
891             fvalue = Double.NEGATIVE_INFINITY;
892         else
893             fvalue = value;
894         performer.getConnectionBlocks().add(
895                 new ModelConnectionBlock(fvalue, new ModelDestination(dest)));
896     }
897 
addValue(ModelPerformer performer, ModelIdentifier dest, short value)898     private void addValue(ModelPerformer performer,
899             ModelIdentifier dest, short value) {
900         double fvalue = value;
901         performer.getConnectionBlocks().add(
902                 new ModelConnectionBlock(fvalue, new ModelDestination(dest)));
903     }
904 
addValue(ModelPerformer performer, ModelIdentifier dest, double value)905     private void addValue(ModelPerformer performer,
906             ModelIdentifier dest, double value) {
907         double fvalue = value;
908         performer.getConnectionBlocks().add(
909                 new ModelConnectionBlock(fvalue, new ModelDestination(dest)));
910     }
911 
getGeneratorValue(Map<Integer, Short> generators, int gen)912     private short getGeneratorValue(Map<Integer, Short> generators, int gen) {
913         if (generators.containsKey(gen))
914             return generators.get(gen);
915         return SF2Region.getDefaultValue(gen);
916     }
917 }
918