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.Arrays;
  29 import java.util.Comparator;
  30 import java.util.HashMap;
  31 import java.util.List;
  32 import java.util.Map;
  33 
  34 /**
  35  * This class decodes information from ModelPeformer for use in SoftVoice.
  36  * It also adds default connections if they where missing in ModelPerformer.
  37  *
  38  * @author Karl Helgason
  39  */
  40 public final class SoftPerformer {
  41 
  42     static ModelConnectionBlock[] defaultconnections
  43             = new ModelConnectionBlock[42];
  44 
  45     static {
  46         int o = 0;
  47         defaultconnections[o++] = new ModelConnectionBlock(
  48             new ModelSource(
  49                 new ModelIdentifier("noteon", "on", 0),
  50                 ModelStandardTransform.DIRECTION_MIN2MAX,
  51                 ModelStandardTransform.POLARITY_UNIPOLAR,
  52                 ModelStandardTransform.TRANSFORM_LINEAR),
  53             1, new ModelDestination(new ModelIdentifier("eg", "on", 0)));
  54 
  55         defaultconnections[o++] = new ModelConnectionBlock(
  56             new ModelSource(
  57                 new ModelIdentifier("noteon", "on", 0),
  58                 ModelStandardTransform.DIRECTION_MIN2MAX,
  59                 ModelStandardTransform.POLARITY_UNIPOLAR,
  60                 ModelStandardTransform.TRANSFORM_LINEAR),
  61             1, new ModelDestination(new ModelIdentifier("eg", "on", 1)));
  62 
  63         defaultconnections[o++] = new ModelConnectionBlock(
  64             new ModelSource(
  65                 new ModelIdentifier("eg", "active", 0),
  66                 ModelStandardTransform.DIRECTION_MIN2MAX,
  67                 ModelStandardTransform.POLARITY_UNIPOLAR,
  68                 ModelStandardTransform.TRANSFORM_LINEAR),
  69             1, new ModelDestination(new ModelIdentifier("mixer", "active", 0)));
  70 
  71         defaultconnections[o++] = new ModelConnectionBlock(
  72             new ModelSource(
  73                 new ModelIdentifier("eg", 0),
  74                 ModelStandardTransform.DIRECTION_MAX2MIN,
  75                 ModelStandardTransform.POLARITY_UNIPOLAR,
  76                 ModelStandardTransform.TRANSFORM_LINEAR),
  77             -960, new ModelDestination(new ModelIdentifier("mixer", "gain")));
  78 
  79         defaultconnections[o++] = new ModelConnectionBlock(
  80             new ModelSource(
  81                 new ModelIdentifier("noteon", "velocity"),
  82                 ModelStandardTransform.DIRECTION_MAX2MIN,
  83                 ModelStandardTransform.POLARITY_UNIPOLAR,
  84                 ModelStandardTransform.TRANSFORM_CONCAVE),
  85             -960, new ModelDestination(new ModelIdentifier("mixer", "gain")));
  86 
  87         defaultconnections[o++] = new ModelConnectionBlock(
  88             new ModelSource(
  89                 new ModelIdentifier("midi", "pitch"),
  90                 ModelStandardTransform.DIRECTION_MIN2MAX,
  91                 ModelStandardTransform.POLARITY_BIPOLAR,
  92                 ModelStandardTransform.TRANSFORM_LINEAR),
  93             new ModelSource(new ModelIdentifier("midi_rpn", "0"),
  94                 new ModelTransform() {
  95                     public double transform(double value) {
  96                         int v = (int) (value * 16384.0);
  97                         int msb = v >> 7;
  98                         int lsb = v & 127;
  99                         return msb * 100 + lsb;
 100                     }
 101                 }),
 102             new ModelDestination(new ModelIdentifier("osc", "pitch")));
 103 
 104         defaultconnections[o++] = new ModelConnectionBlock(
 105             new ModelSource(
 106                 new ModelIdentifier("noteon", "keynumber"),
 107                 ModelStandardTransform.DIRECTION_MIN2MAX,
 108                 ModelStandardTransform.POLARITY_UNIPOLAR,
 109                 ModelStandardTransform.TRANSFORM_LINEAR),
 110             12800, new ModelDestination(new ModelIdentifier("osc", "pitch")));
 111 
 112         defaultconnections[o++] = new ModelConnectionBlock(
 113             new ModelSource(
 114                 new ModelIdentifier("midi_cc", "7"),
 115                 ModelStandardTransform.DIRECTION_MAX2MIN,
 116                 ModelStandardTransform.POLARITY_UNIPOLAR,
 117                 ModelStandardTransform.TRANSFORM_CONCAVE),
 118             -960, new ModelDestination(new ModelIdentifier("mixer", "gain")));
 119 
 120         defaultconnections[o++] = new ModelConnectionBlock(
 121             new ModelSource(
 122                 new ModelIdentifier("midi_cc", "8"),
 123                 ModelStandardTransform.DIRECTION_MIN2MAX,
 124                 ModelStandardTransform.POLARITY_UNIPOLAR,
 125                 ModelStandardTransform.TRANSFORM_LINEAR),
 126             1000, new ModelDestination(new ModelIdentifier("mixer", "balance")));
 127 
 128         defaultconnections[o++] = new ModelConnectionBlock(
 129             new ModelSource(
 130                 new ModelIdentifier("midi_cc", "10"),
 131                 ModelStandardTransform.DIRECTION_MIN2MAX,
 132                 ModelStandardTransform.POLARITY_UNIPOLAR,
 133                 ModelStandardTransform.TRANSFORM_LINEAR),
 134             1000, new ModelDestination(new ModelIdentifier("mixer", "pan")));
 135 
 136         defaultconnections[o++] = new ModelConnectionBlock(
 137             new ModelSource(
 138                 new ModelIdentifier("midi_cc", "11"),
 139                 ModelStandardTransform.DIRECTION_MAX2MIN,
 140                 ModelStandardTransform.POLARITY_UNIPOLAR,
 141                 ModelStandardTransform.TRANSFORM_CONCAVE),
 142             -960, new ModelDestination(new ModelIdentifier("mixer", "gain")));
 143 
 144         defaultconnections[o++] = new ModelConnectionBlock(
 145             new ModelSource(
 146                 new ModelIdentifier("midi_cc", "91"),
 147                 ModelStandardTransform.DIRECTION_MIN2MAX,
 148                 ModelStandardTransform.POLARITY_UNIPOLAR,
 149                 ModelStandardTransform.TRANSFORM_LINEAR),
 150             1000, new ModelDestination(new ModelIdentifier("mixer", "reverb")));
 151 
 152         defaultconnections[o++] = new ModelConnectionBlock(
 153             new ModelSource(
 154                 new ModelIdentifier("midi_cc", "93"),
 155                 ModelStandardTransform.DIRECTION_MIN2MAX,
 156                 ModelStandardTransform.POLARITY_UNIPOLAR,
 157                 ModelStandardTransform.TRANSFORM_LINEAR),
 158             1000, new ModelDestination(new ModelIdentifier("mixer", "chorus")));
 159 
 160         defaultconnections[o++] = new ModelConnectionBlock(
 161             new ModelSource(
 162                 new ModelIdentifier("midi_cc", "71"),
 163                 ModelStandardTransform.DIRECTION_MIN2MAX,
 164                 ModelStandardTransform.POLARITY_BIPOLAR,
 165                 ModelStandardTransform.TRANSFORM_LINEAR),
 166             200, new ModelDestination(new ModelIdentifier("filter", "q")));
 167         defaultconnections[o++] = new ModelConnectionBlock(
 168             new ModelSource(
 169                 new ModelIdentifier("midi_cc", "74"),
 170                 ModelStandardTransform.DIRECTION_MIN2MAX,
 171                 ModelStandardTransform.POLARITY_BIPOLAR,
 172                 ModelStandardTransform.TRANSFORM_LINEAR),
 173             9600, new ModelDestination(new ModelIdentifier("filter", "freq")));
 174 
 175         defaultconnections[o++] = new ModelConnectionBlock(
 176             new ModelSource(
 177                 new ModelIdentifier("midi_cc", "72"),
 178                 ModelStandardTransform.DIRECTION_MIN2MAX,
 179                 ModelStandardTransform.POLARITY_BIPOLAR,
 180                 ModelStandardTransform.TRANSFORM_LINEAR),
 181             6000, new ModelDestination(new ModelIdentifier("eg", "release2")));
 182 
 183         defaultconnections[o++] = new ModelConnectionBlock(
 184             new ModelSource(
 185                 new ModelIdentifier("midi_cc", "73"),
 186                 ModelStandardTransform.DIRECTION_MIN2MAX,
 187                 ModelStandardTransform.POLARITY_BIPOLAR,
 188                 ModelStandardTransform.TRANSFORM_LINEAR),
 189             2000, new ModelDestination(new ModelIdentifier("eg", "attack2")));
 190 
 191         defaultconnections[o++] = new ModelConnectionBlock(
 192             new ModelSource(
 193                 new ModelIdentifier("midi_cc", "75"),
 194                 ModelStandardTransform.DIRECTION_MIN2MAX,
 195                 ModelStandardTransform.POLARITY_BIPOLAR,
 196                 ModelStandardTransform.TRANSFORM_LINEAR),
 197             6000, new ModelDestination(new ModelIdentifier("eg", "decay2")));
 198 
 199         defaultconnections[o++] = new ModelConnectionBlock(
 200             new ModelSource(
 201                 new ModelIdentifier("midi_cc", "67"),
 202                 ModelStandardTransform.DIRECTION_MIN2MAX,
 203                 ModelStandardTransform.POLARITY_UNIPOLAR,
 204                 ModelStandardTransform.TRANSFORM_SWITCH),
 205             -50, new ModelDestination(ModelDestination.DESTINATION_GAIN));
 206 
 207         defaultconnections[o++] = new ModelConnectionBlock(
 208             new ModelSource(
 209                 new ModelIdentifier("midi_cc", "67"),
 210                 ModelStandardTransform.DIRECTION_MIN2MAX,
 211                 ModelStandardTransform.POLARITY_UNIPOLAR,
 212                 ModelStandardTransform.TRANSFORM_SWITCH),
 213             -2400, new ModelDestination(ModelDestination.DESTINATION_FILTER_FREQ));
 214 
 215         defaultconnections[o++] = new ModelConnectionBlock(
 216             new ModelSource(
 217                 new ModelIdentifier("midi_rpn", "1"),
 218                 ModelStandardTransform.DIRECTION_MIN2MAX,
 219                 ModelStandardTransform.POLARITY_BIPOLAR,
 220                 ModelStandardTransform.TRANSFORM_LINEAR),
 221             100, new ModelDestination(new ModelIdentifier("osc", "pitch")));
 222 
 223         defaultconnections[o++] = new ModelConnectionBlock(
 224             new ModelSource(
 225                 new ModelIdentifier("midi_rpn", "2"),
 226                 ModelStandardTransform.DIRECTION_MIN2MAX,
 227                 ModelStandardTransform.POLARITY_BIPOLAR,
 228                 ModelStandardTransform.TRANSFORM_LINEAR),
 229             12800, new ModelDestination(new ModelIdentifier("osc", "pitch")));
 230 
 231         defaultconnections[o++] = new ModelConnectionBlock(
 232             new ModelSource(
 233                 new ModelIdentifier("master", "fine_tuning"),
 234                 ModelStandardTransform.DIRECTION_MIN2MAX,
 235                 ModelStandardTransform.POLARITY_BIPOLAR,
 236                 ModelStandardTransform.TRANSFORM_LINEAR),
 237             100, new ModelDestination(new ModelIdentifier("osc", "pitch")));
 238 
 239         defaultconnections[o++] = new ModelConnectionBlock(
 240             new ModelSource(
 241                 new ModelIdentifier("master", "coarse_tuning"),
 242                 ModelStandardTransform.DIRECTION_MIN2MAX,
 243                 ModelStandardTransform.POLARITY_BIPOLAR,
 244                 ModelStandardTransform.TRANSFORM_LINEAR),
 245             12800, new ModelDestination(new ModelIdentifier("osc", "pitch")));
 246 
 247         defaultconnections[o++] = new ModelConnectionBlock(13500,
 248                 new ModelDestination(new ModelIdentifier("filter", "freq", 0)));
 249 
 250         defaultconnections[o++] = new ModelConnectionBlock(
 251                 Float.NEGATIVE_INFINITY, new ModelDestination(
 252                 new ModelIdentifier("eg", "delay", 0)));
 253         defaultconnections[o++] = new ModelConnectionBlock(
 254                 Float.NEGATIVE_INFINITY, new ModelDestination(
 255                 new ModelIdentifier("eg", "attack", 0)));
 256         defaultconnections[o++] = new ModelConnectionBlock(
 257                 Float.NEGATIVE_INFINITY, new ModelDestination(
 258                 new ModelIdentifier("eg", "hold", 0)));
 259         defaultconnections[o++] = new ModelConnectionBlock(
 260                 Float.NEGATIVE_INFINITY, new ModelDestination(
 261                 new ModelIdentifier("eg", "decay", 0)));
 262         defaultconnections[o++] = new ModelConnectionBlock(1000,
 263                 new ModelDestination(new ModelIdentifier("eg", "sustain", 0)));
 264         defaultconnections[o++] = new ModelConnectionBlock(
 265                 Float.NEGATIVE_INFINITY, new ModelDestination(
 266                 new ModelIdentifier("eg", "release", 0)));
 267         defaultconnections[o++] = new ModelConnectionBlock(1200.0
 268                 * Math.log(0.015) / Math.log(2), new ModelDestination(
 269                 new ModelIdentifier("eg", "shutdown", 0))); // 15 msec default
 270 
 271         defaultconnections[o++] = new ModelConnectionBlock(
 272                 Float.NEGATIVE_INFINITY, new ModelDestination(
 273                 new ModelIdentifier("eg", "delay", 1)));
 274         defaultconnections[o++] = new ModelConnectionBlock(
 275                 Float.NEGATIVE_INFINITY, new ModelDestination(
 276                 new ModelIdentifier("eg", "attack", 1)));
 277         defaultconnections[o++] = new ModelConnectionBlock(
 278                 Float.NEGATIVE_INFINITY, new ModelDestination(
 279                 new ModelIdentifier("eg", "hold", 1)));
 280         defaultconnections[o++] = new ModelConnectionBlock(
 281                 Float.NEGATIVE_INFINITY, new ModelDestination(
 282                 new ModelIdentifier("eg", "decay", 1)));
 283         defaultconnections[o++] = new ModelConnectionBlock(1000,
 284                 new ModelDestination(new ModelIdentifier("eg", "sustain", 1)));
 285         defaultconnections[o++] = new ModelConnectionBlock(
 286                 Float.NEGATIVE_INFINITY, new ModelDestination(
 287                 new ModelIdentifier("eg", "release", 1)));
 288 
 289         defaultconnections[o++] = new ModelConnectionBlock(-8.51318,
 290                 new ModelDestination(new ModelIdentifier("lfo", "freq", 0)));
 291         defaultconnections[o++] = new ModelConnectionBlock(
 292                 Float.NEGATIVE_INFINITY, new ModelDestination(
 293                 new ModelIdentifier("lfo", "delay", 0)));
 294         defaultconnections[o++] = new ModelConnectionBlock(-8.51318,
 295                 new ModelDestination(new ModelIdentifier("lfo", "freq", 1)));
 296         defaultconnections[o++] = new ModelConnectionBlock(
 297                 Float.NEGATIVE_INFINITY, new ModelDestination(
 298                 new ModelIdentifier("lfo", "delay", 1)));
 299 
 300     }
 301     public int keyFrom = 0;
 302     public int keyTo = 127;
 303     public int velFrom = 0;
 304     public int velTo = 127;
 305     public int exclusiveClass = 0;
 306     public boolean selfNonExclusive = false;
 307     public boolean forcedVelocity = false;
 308     public boolean forcedKeynumber = false;
 309     public ModelPerformer performer;
 310     public ModelConnectionBlock[] connections;
 311     public ModelOscillator[] oscillators;
 312     public Map<Integer, int[]> midi_rpn_connections = new HashMap<Integer, int[]>();
 313     public Map<Integer, int[]> midi_nrpn_connections = new HashMap<Integer, int[]>();
 314     public int[][] midi_ctrl_connections;
 315     public int[][] midi_connections;
 316     public int[] ctrl_connections;
 317     private List<Integer> ctrl_connections_list = new ArrayList<Integer>();
 318 
 319     private static class KeySortComparator implements Comparator<ModelSource> {
 320 
 321         public int compare(ModelSource o1, ModelSource o2) {
 322             return o1.getIdentifier().toString().compareTo(
 323                     o2.getIdentifier().toString());
 324         }
 325     }
 326     private static KeySortComparator keySortComparator = new KeySortComparator();
 327 
 328     private String extractKeys(ModelConnectionBlock conn) {
 329         StringBuilder sb = new StringBuilder();
 330         if (conn.getSources() != null) {
 331             sb.append("[");
 332             ModelSource[] srcs = conn.getSources();
 333             ModelSource[] srcs2 = new ModelSource[srcs.length];
 334             for (int i = 0; i < srcs.length; i++)
 335                 srcs2[i] = srcs[i];
 336             Arrays.sort(srcs2, keySortComparator);
 337             for (int i = 0; i < srcs.length; i++) {
 338                 sb.append(srcs[i].getIdentifier());
 339                 sb.append(";");
 340             }
 341             sb.append("]");
 342         }
 343         sb.append(";");
 344         if (conn.getDestination() != null) {
 345             sb.append(conn.getDestination().getIdentifier());
 346         }
 347         sb.append(";");
 348         return sb.toString();
 349     }
 350 
 351     private void processSource(ModelSource src, int ix) {
 352         ModelIdentifier id = src.getIdentifier();
 353         String o = id.getObject();
 354         if (o.equals("midi_cc"))
 355             processMidiControlSource(src, ix);
 356         else if (o.equals("midi_rpn"))
 357             processMidiRpnSource(src, ix);
 358         else if (o.equals("midi_nrpn"))
 359             processMidiNrpnSource(src, ix);
 360         else if (o.equals("midi"))
 361             processMidiSource(src, ix);
 362         else if (o.equals("noteon"))
 363             processNoteOnSource(src, ix);
 364         else if (o.equals("osc"))
 365             return;
 366         else if (o.equals("mixer"))
 367             return;
 368         else
 369             ctrl_connections_list.add(ix);
 370     }
 371 
 372     private void processMidiControlSource(ModelSource src, int ix) {
 373         String v = src.getIdentifier().getVariable();
 374         if (v == null)
 375             return;
 376         int c = Integer.parseInt(v);
 377         if (midi_ctrl_connections[c] == null)
 378             midi_ctrl_connections[c] = new int[]{ix};
 379         else {
 380             int[] olda = midi_ctrl_connections[c];
 381             int[] newa = new int[olda.length + 1];
 382             for (int i = 0; i < olda.length; i++)
 383                 newa[i] = olda[i];
 384             newa[newa.length - 1] = ix;
 385             midi_ctrl_connections[c] = newa;
 386         }
 387     }
 388 
 389     private void processNoteOnSource(ModelSource src, int ix) {
 390         String v = src.getIdentifier().getVariable();
 391         int c = -1;
 392         if (v.equals("on"))
 393             c = 3;
 394         if (v.equals("keynumber"))
 395             c = 4;
 396         if (c == -1)
 397             return;
 398         if (midi_connections[c] == null)
 399             midi_connections[c] = new int[]{ix};
 400         else {
 401             int[] olda = midi_connections[c];
 402             int[] newa = new int[olda.length + 1];
 403             for (int i = 0; i < olda.length; i++)
 404                 newa[i] = olda[i];
 405             newa[newa.length - 1] = ix;
 406             midi_connections[c] = newa;
 407         }
 408     }
 409 
 410     private void processMidiSource(ModelSource src, int ix) {
 411         String v = src.getIdentifier().getVariable();
 412         int c = -1;
 413         if (v.equals("pitch"))
 414             c = 0;
 415         if (v.equals("channel_pressure"))
 416             c = 1;
 417         if (v.equals("poly_pressure"))
 418             c = 2;
 419         if (c == -1)
 420             return;
 421         if (midi_connections[c] == null)
 422             midi_connections[c] = new int[]{ix};
 423         else {
 424             int[] olda = midi_connections[c];
 425             int[] newa = new int[olda.length + 1];
 426             for (int i = 0; i < olda.length; i++)
 427                 newa[i] = olda[i];
 428             newa[newa.length - 1] = ix;
 429             midi_connections[c] = newa;
 430         }
 431     }
 432 
 433     private void processMidiRpnSource(ModelSource src, int ix) {
 434         String v = src.getIdentifier().getVariable();
 435         if (v == null)
 436             return;
 437         int c = Integer.parseInt(v);
 438         if (midi_rpn_connections.get(c) == null)
 439             midi_rpn_connections.put(c, new int[]{ix});
 440         else {
 441             int[] olda = midi_rpn_connections.get(c);
 442             int[] newa = new int[olda.length + 1];
 443             for (int i = 0; i < olda.length; i++)
 444                 newa[i] = olda[i];
 445             newa[newa.length - 1] = ix;
 446             midi_rpn_connections.put(c, newa);
 447         }
 448     }
 449 
 450     private void processMidiNrpnSource(ModelSource src, int ix) {
 451         String v = src.getIdentifier().getVariable();
 452         if (v == null)
 453             return;
 454         int c = Integer.parseInt(v);
 455         if (midi_nrpn_connections.get(c) == null)
 456             midi_nrpn_connections.put(c, new int[]{ix});
 457         else {
 458             int[] olda = midi_nrpn_connections.get(c);
 459             int[] newa = new int[olda.length + 1];
 460             for (int i = 0; i < olda.length; i++)
 461                 newa[i] = olda[i];
 462             newa[newa.length - 1] = ix;
 463             midi_nrpn_connections.put(c, newa);
 464         }
 465     }
 466 
 467     public SoftPerformer(ModelPerformer performer) {
 468         this.performer = performer;
 469 
 470         keyFrom = performer.getKeyFrom();
 471         keyTo = performer.getKeyTo();
 472         velFrom = performer.getVelFrom();
 473         velTo = performer.getVelTo();
 474         exclusiveClass = performer.getExclusiveClass();
 475         selfNonExclusive = performer.isSelfNonExclusive();
 476 
 477         Map<String, ModelConnectionBlock> connmap = new HashMap<String, ModelConnectionBlock>();
 478 
 479         List<ModelConnectionBlock> performer_connections = new ArrayList<ModelConnectionBlock>();
 480         performer_connections.addAll(performer.getConnectionBlocks());
 481 
 482         if (performer.isDefaultConnectionsEnabled()) {
 483 
 484             // Add modulation depth range (RPN 5) to the modulation wheel (cc#1)
 485 
 486             boolean isModulationWheelConectionFound = false;
 487             for (int j = 0; j < performer_connections.size(); j++) {
 488                 ModelConnectionBlock connection = performer_connections.get(j);
 489                 ModelSource[] sources = connection.getSources();
 490                 ModelDestination dest = connection.getDestination();
 491                 boolean isModulationWheelConection = false;
 492                 if (dest != null && sources != null && sources.length > 1) {
 493                     for (int i = 0; i < sources.length; i++) {
 494                         // check if connection block has the source "modulation
 495                         // wheel cc#1"
 496                         if (sources[i].getIdentifier().getObject().equals(
 497                                 "midi_cc")) {
 498                             if (sources[i].getIdentifier().getVariable()
 499                                     .equals("1")) {
 500                                 isModulationWheelConection = true;
 501                                 isModulationWheelConectionFound = true;
 502                                 break;
 503                             }
 504                         }
 505                     }
 506                 }
 507                 if (isModulationWheelConection) {
 508 
 509                     ModelConnectionBlock newconnection = new ModelConnectionBlock();
 510                     newconnection.setSources(connection.getSources());
 511                     newconnection.setDestination(connection.getDestination());
 512                     newconnection.addSource(new ModelSource(
 513                             new ModelIdentifier("midi_rpn", "5")));
 514                     newconnection.setScale(connection.getScale() * 256.0);
 515                     performer_connections.set(j, newconnection);
 516                 }
 517             }
 518 
 519             if (!isModulationWheelConectionFound) {
 520                 ModelConnectionBlock conn = new ModelConnectionBlock(
 521                         new ModelSource(ModelSource.SOURCE_LFO1,
 522                         ModelStandardTransform.DIRECTION_MIN2MAX,
 523                         ModelStandardTransform.POLARITY_BIPOLAR,
 524                         ModelStandardTransform.TRANSFORM_LINEAR),
 525                         new ModelSource(new ModelIdentifier("midi_cc", "1", 0),
 526                         ModelStandardTransform.DIRECTION_MIN2MAX,
 527                         ModelStandardTransform.POLARITY_UNIPOLAR,
 528                         ModelStandardTransform.TRANSFORM_LINEAR),
 529                         50,
 530                         new ModelDestination(ModelDestination.DESTINATION_PITCH));
 531                 conn.addSource(new ModelSource(new ModelIdentifier("midi_rpn",
 532                         "5")));
 533                 conn.setScale(conn.getScale() * 256.0);
 534                 performer_connections.add(conn);
 535 
 536             }
 537 
 538             // Let Aftertouch to behave just like modulation wheel (cc#1)
 539             boolean channel_pressure_set = false;
 540             boolean poly_pressure = false;
 541             ModelConnectionBlock mod_cc_1_connection = null;
 542             int mod_cc_1_connection_src_ix = 0;
 543 
 544             for (ModelConnectionBlock connection : performer_connections) {
 545                 ModelSource[] sources = connection.getSources();
 546                 ModelDestination dest = connection.getDestination();
 547                 // if(dest != null && sources != null)
 548                 if (dest != null && sources != null) {
 549                     for (int i = 0; i < sources.length; i++) {
 550                         ModelIdentifier srcid = sources[i].getIdentifier();
 551                         // check if connection block has the source "modulation
 552                         // wheel cc#1"
 553                         if (srcid.getObject().equals("midi_cc")) {
 554                             if (srcid.getVariable().equals("1")) {
 555                                 mod_cc_1_connection = connection;
 556                                 mod_cc_1_connection_src_ix = i;
 557                             }
 558                         }
 559                         // check if channel or poly pressure are already
 560                         // connected
 561                         if (srcid.getObject().equals("midi")) {
 562                             if (srcid.getVariable().equals("channel_pressure"))
 563                                 channel_pressure_set = true;
 564                             if (srcid.getVariable().equals("poly_pressure"))
 565                                 poly_pressure = true;
 566                         }
 567                     }
 568                 }
 569 
 570             }
 571 
 572             if (mod_cc_1_connection != null) {
 573                 if (!channel_pressure_set) {
 574                     ModelConnectionBlock mc = new ModelConnectionBlock();
 575                     mc.setDestination(mod_cc_1_connection.getDestination());
 576                     mc.setScale(mod_cc_1_connection.getScale());
 577                     ModelSource[] src_list = mod_cc_1_connection.getSources();
 578                     ModelSource[] src_list_new = new ModelSource[src_list.length];
 579                     for (int i = 0; i < src_list_new.length; i++)
 580                         src_list_new[i] = src_list[i];
 581                     src_list_new[mod_cc_1_connection_src_ix] = new ModelSource(
 582                             new ModelIdentifier("midi", "channel_pressure"));
 583                     mc.setSources(src_list_new);
 584                     connmap.put(extractKeys(mc), mc);
 585                 }
 586                 if (!poly_pressure) {
 587                     ModelConnectionBlock mc = new ModelConnectionBlock();
 588                     mc.setDestination(mod_cc_1_connection.getDestination());
 589                     mc.setScale(mod_cc_1_connection.getScale());
 590                     ModelSource[] src_list = mod_cc_1_connection.getSources();
 591                     ModelSource[] src_list_new = new ModelSource[src_list.length];
 592                     for (int i = 0; i < src_list_new.length; i++)
 593                         src_list_new[i] = src_list[i];
 594                     src_list_new[mod_cc_1_connection_src_ix] = new ModelSource(
 595                             new ModelIdentifier("midi", "poly_pressure"));
 596                     mc.setSources(src_list_new);
 597                     connmap.put(extractKeys(mc), mc);
 598                 }
 599             }
 600 
 601             // Enable Vibration Sound Controllers : 76, 77, 78
 602             ModelConnectionBlock found_vib_connection = null;
 603             for (ModelConnectionBlock connection : performer_connections) {
 604                 ModelSource[] sources = connection.getSources();
 605                 if (sources.length != 0
 606                         && sources[0].getIdentifier().getObject().equals("lfo")) {
 607                     if (connection.getDestination().getIdentifier().equals(
 608                             ModelDestination.DESTINATION_PITCH)) {
 609                         if (found_vib_connection == null)
 610                             found_vib_connection = connection;
 611                         else {
 612                             if (found_vib_connection.getSources().length > sources.length)
 613                                 found_vib_connection = connection;
 614                             else if (found_vib_connection.getSources()[0]
 615                                     .getIdentifier().getInstance() < 1) {
 616                                 if (found_vib_connection.getSources()[0]
 617                                         .getIdentifier().getInstance() >
 618                                         sources[0].getIdentifier().getInstance()) {
 619                                     found_vib_connection = connection;
 620                                 }
 621                             }
 622                         }
 623 
 624                     }
 625                 }
 626             }
 627 
 628             int instance = 1;
 629 
 630             if (found_vib_connection != null) {
 631                 instance = found_vib_connection.getSources()[0].getIdentifier()
 632                         .getInstance();
 633             }
 634             ModelConnectionBlock connection;
 635 
 636             connection = new ModelConnectionBlock(
 637                 new ModelSource(new ModelIdentifier("midi_cc", "78"),
 638                     ModelStandardTransform.DIRECTION_MIN2MAX,
 639                     ModelStandardTransform.POLARITY_BIPOLAR,
 640                     ModelStandardTransform.TRANSFORM_LINEAR),
 641                 2000, new ModelDestination(
 642                     new ModelIdentifier("lfo", "delay2", instance)));
 643             connmap.put(extractKeys(connection), connection);
 644 
 645             final double scale = found_vib_connection == null ? 0
 646                     : found_vib_connection.getScale();
 647             connection = new ModelConnectionBlock(
 648                 new ModelSource(new ModelIdentifier("lfo", instance)),
 649                 new ModelSource(new ModelIdentifier("midi_cc", "77"),
 650                     new ModelTransform() {
 651                         double s = scale;
 652                         public double transform(double value) {
 653                             value = value * 2 - 1;
 654                             value *= 600;
 655                             if (s == 0) {
 656                                 return value;
 657                             } else if (s > 0) {
 658                                 if (value < -s)
 659                                     value = -s;
 660                                 return value;
 661                             } else {
 662                                 if (value < s)
 663                                     value = -s;
 664                                 return -value;
 665                             }
 666                         }
 667                     }), new ModelDestination(ModelDestination.DESTINATION_PITCH));
 668             connmap.put(extractKeys(connection), connection);
 669 
 670             connection = new ModelConnectionBlock(
 671                 new ModelSource(new ModelIdentifier("midi_cc", "76"),
 672                     ModelStandardTransform.DIRECTION_MIN2MAX,
 673                     ModelStandardTransform.POLARITY_BIPOLAR,
 674                     ModelStandardTransform.TRANSFORM_LINEAR),
 675                 2400, new ModelDestination(
 676                     new ModelIdentifier("lfo", "freq", instance)));
 677             connmap.put(extractKeys(connection), connection);
 678 
 679         }
 680 
 681         // Add default connection blocks
 682         if (performer.isDefaultConnectionsEnabled())
 683             for (ModelConnectionBlock connection : defaultconnections)
 684                 connmap.put(extractKeys(connection), connection);
 685         // Add connection blocks from modelperformer
 686         for (ModelConnectionBlock connection : performer_connections)
 687             connmap.put(extractKeys(connection), connection);
 688         // seperate connection blocks : Init time, Midi Time, Midi/Control Time,
 689         // Control Time
 690         List<ModelConnectionBlock> connections = new ArrayList<ModelConnectionBlock>();
 691 
 692         midi_ctrl_connections = new int[128][];
 693         for (int i = 0; i < midi_ctrl_connections.length; i++) {
 694             midi_ctrl_connections[i] = null;
 695         }
 696         midi_connections = new int[5][];
 697         for (int i = 0; i < midi_connections.length; i++) {
 698             midi_connections[i] = null;
 699         }
 700 
 701         int ix = 0;
 702         boolean mustBeOnTop = false;
 703 
 704         for (ModelConnectionBlock connection : connmap.values()) {
 705             if (connection.getDestination() != null) {
 706                 ModelDestination dest = connection.getDestination();
 707                 ModelIdentifier id = dest.getIdentifier();
 708                 if (id.getObject().equals("noteon")) {
 709                     mustBeOnTop = true;
 710                     if (id.getVariable().equals("keynumber"))
 711                         forcedKeynumber = true;
 712                     if (id.getVariable().equals("velocity"))
 713                         forcedVelocity = true;
 714                 }
 715             }
 716             if (mustBeOnTop) {
 717                 connections.add(0, connection);
 718                 mustBeOnTop = false;
 719             } else
 720                 connections.add(connection);
 721         }
 722 
 723         for (ModelConnectionBlock connection : connections) {
 724             if (connection.getSources() != null) {
 725                 ModelSource[] srcs = connection.getSources();
 726                 for (int i = 0; i < srcs.length; i++) {
 727                     processSource(srcs[i], ix);
 728                 }
 729             }
 730             ix++;
 731         }
 732 
 733         this.connections = new ModelConnectionBlock[connections.size()];
 734         connections.toArray(this.connections);
 735 
 736         this.ctrl_connections = new int[ctrl_connections_list.size()];
 737 
 738         for (int i = 0; i < this.ctrl_connections.length; i++)
 739             this.ctrl_connections[i] = ctrl_connections_list.get(i);
 740 
 741         oscillators = new ModelOscillator[performer.getOscillators().size()];
 742         performer.getOscillators().toArray(oscillators);
 743 
 744         for (ModelConnectionBlock conn : connections) {
 745             if (conn.getDestination() != null) {
 746                 if (isUnnecessaryTransform(conn.getDestination().getTransform())) {
 747                     conn.getDestination().setTransform(null);
 748                 }
 749             }
 750             if (conn.getSources() != null) {
 751                 for (ModelSource src : conn.getSources()) {
 752                     if (isUnnecessaryTransform(src.getTransform())) {
 753                         src.setTransform(null);
 754                     }
 755                 }
 756             }
 757         }
 758 
 759     }
 760 
 761     private static boolean isUnnecessaryTransform(ModelTransform transform) {
 762         if (transform == null)
 763             return false;
 764         if (!(transform instanceof ModelStandardTransform))
 765             return false;
 766         ModelStandardTransform stransform = (ModelStandardTransform)transform;
 767         if (stransform.getDirection() != ModelStandardTransform.DIRECTION_MIN2MAX)
 768             return false;
 769         if (stransform.getPolarity() != ModelStandardTransform.POLARITY_UNIPOLAR)
 770             return false;
 771         if (stransform.getTransform() != ModelStandardTransform.TRANSFORM_LINEAR)
 772             return false;
 773         return false;
 774     }
 775 }