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