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