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 
  51     public SF2Instrument() {
  52         super(null, null, null, null);
  53     }
  54 
  55     public SF2Instrument(SF2Soundbank soundbank) {
  56         super(soundbank, null, null, null);
  57     }
  58 
  59     @Override
  60     public String getName() {
  61         return name;
  62     }
  63 
  64     public void setName(String name) {
  65         this.name = name;
  66     }
  67 
  68     @Override
  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 
  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
  87     public Object getData() {
  88         return null;
  89     }
  90 
  91     public long getGenre() {
  92         return genre;
  93     }
  94 
  95     public void setGenre(long genre) {
  96         this.genre = genre;
  97     }
  98 
  99     public long getLibrary() {
 100         return library;
 101     }
 102 
 103     public void setLibrary(long library) {
 104         this.library = library;
 105     }
 106 
 107     public long getMorphology() {
 108         return morphology;
 109     }
 110 
 111     public void setMorphology(long morphology) {
 112         this.morphology = morphology;
 113     }
 114 
 115     public List<SF2InstrumentRegion> getRegions() {
 116         return regions;
 117     }
 118 
 119     public SF2GlobalRegion getGlobalRegion() {
 120         return globalregion;
 121     }
 122 
 123     public void setGlobalZone(SF2GlobalRegion zone) {
 124         globalregion = zone;
 125     }
 126 
 127     @Override
 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
 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 
 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 
 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 
 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 
 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 
 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 
 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 
 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 }