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
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"),
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 }
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")) {
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"))
|
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
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"),
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
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
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 }
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
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")) {
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"))
|