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 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 final class SF2Instrument extends ModelInstrument {
  40 
  41     String name = "";
  42     int preset = 0;
  43     int bank = 0;
  44     long library = 0;
  45     long genre = 0;
  46     long morphology = 0;
  47     SF2GlobalRegion globalregion = null;
  48     List<SF2InstrumentRegion> regions
  49             = new ArrayList<SF2InstrumentRegion>();
  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     public String getName() {
  60         return name;
  61     }
  62 
  63     public void setName(String name) {
  64         this.name = name;
  65     }
  66 
  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 
  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 
  84     public Object getData() {
  85         return null;
  86     }
  87 
  88     public long getGenre() {
  89         return genre;
  90     }
  91 
  92     public void setGenre(long genre) {
  93         this.genre = genre;
  94     }
  95 
  96     public long getLibrary() {
  97         return library;
  98     }
  99 
 100     public void setLibrary(long library) {
 101         this.library = library;
 102     }
 103 
 104     public long getMorphology() {
 105         return morphology;
 106     }
 107 
 108     public void setMorphology(long morphology) {
 109         this.morphology = morphology;
 110     }
 111 
 112     public List<SF2InstrumentRegion> getRegions() {
 113         return regions;
 114     }
 115 
 116     public SF2GlobalRegion getGlobalRegion() {
 117         return globalregion;
 118     }
 119 
 120     public void setGlobalZone(SF2GlobalRegion zone) {
 121         globalregion = zone;
 122     }
 123 
 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 
 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 
 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 
 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 
 733     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 
 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 
 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 
 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 
 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 }