829N/A/*
6321N/A * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
829N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
829N/A *
829N/A * This code is free software; you can redistribute it and/or modify it
829N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
829N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
829N/A *
829N/A * This code is distributed in the hope that it will be useful, but WITHOUT
829N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
829N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
829N/A * version 2 for more details (a copy is included in the LICENSE file that
829N/A * accompanied this code).
829N/A *
829N/A * You should have received a copy of the GNU General Public License version
829N/A * 2 along with this work; if not, write to the Free Software Foundation,
829N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
829N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
829N/A */
829N/Apackage com.sun.media.sound;
829N/A
829N/Aimport java.util.ArrayList;
829N/Aimport java.util.Arrays;
829N/Aimport java.util.HashMap;
829N/Aimport java.util.Iterator;
829N/Aimport java.util.List;
829N/Aimport java.util.Map;
829N/A
829N/Aimport javax.sound.midi.MidiChannel;
829N/Aimport javax.sound.midi.Patch;
829N/A
829N/A/**
829N/A * Software Synthesizer MIDI channel class.
829N/A *
829N/A * @author Karl Helgason
829N/A */
6321N/Apublic final class SoftChannel implements MidiChannel, ModelDirectedPlayer {
829N/A
829N/A private static boolean[] dontResetControls = new boolean[128];
829N/A static {
829N/A for (int i = 0; i < dontResetControls.length; i++)
829N/A dontResetControls[i] = false;
829N/A
829N/A dontResetControls[0] = true; // Bank Select (MSB)
829N/A dontResetControls[32] = true; // Bank Select (LSB)
829N/A dontResetControls[7] = true; // Channel Volume (MSB)
829N/A dontResetControls[8] = true; // Balance (MSB)
829N/A dontResetControls[10] = true; // Pan (MSB)
829N/A dontResetControls[11] = true; // Expression (MSB)
829N/A dontResetControls[91] = true; // Effects 1 Depth (default: Reverb Send)
829N/A dontResetControls[92] = true; // Effects 2 Depth (default: Tremolo Depth)
829N/A dontResetControls[93] = true; // Effects 3 Depth (default: Chorus Send)
829N/A dontResetControls[94] = true; // Effects 4 Depth (default: Celeste [Detune] Depth)
829N/A dontResetControls[95] = true; // Effects 5 Depth (default: Phaser Depth)
829N/A dontResetControls[70] = true; // Sound Controller 1 (default: Sound Variation)
829N/A dontResetControls[71] = true; // Sound Controller 2 (default: Timbre / Harmonic Quality)
829N/A dontResetControls[72] = true; // Sound Controller 3 (default: Release Time)
829N/A dontResetControls[73] = true; // Sound Controller 4 (default: Attack Time)
829N/A dontResetControls[74] = true; // Sound Controller 5 (default: Brightness)
829N/A dontResetControls[75] = true; // Sound Controller 6 (GM2 default: Decay Time)
829N/A dontResetControls[76] = true; // Sound Controller 7 (GM2 default: Vibrato Rate)
829N/A dontResetControls[77] = true; // Sound Controller 8 (GM2 default: Vibrato Depth)
829N/A dontResetControls[78] = true; // Sound Controller 9 (GM2 default: Vibrato Delay)
829N/A dontResetControls[79] = true; // Sound Controller 10 (GM2 default: Undefined)
829N/A dontResetControls[120] = true; // All Sound Off
829N/A dontResetControls[121] = true; // Reset All Controllers
829N/A dontResetControls[122] = true; // Local Control On/Off
829N/A dontResetControls[123] = true; // All Notes Off
829N/A dontResetControls[124] = true; // Omni Mode Off
829N/A dontResetControls[125] = true; // Omni Mode On
829N/A dontResetControls[126] = true; // Poly Mode Off
829N/A dontResetControls[127] = true; // Poly Mode On
829N/A
829N/A dontResetControls[6] = true; // Data Entry (MSB)
829N/A dontResetControls[38] = true; // Data Entry (LSB)
829N/A dontResetControls[96] = true; // Data Increment
829N/A dontResetControls[97] = true; // Data Decrement
829N/A dontResetControls[98] = true; // Non-Registered Parameter Number (LSB)
829N/A dontResetControls[99] = true; // Non-Registered Parameter Number(MSB)
829N/A dontResetControls[100] = true; // RPN = Null
829N/A dontResetControls[101] = true; // RPN = Null
829N/A
829N/A }
829N/A
829N/A private static final int RPN_NULL_VALUE = (127 << 7) + 127;
829N/A private int rpn_control = RPN_NULL_VALUE;
829N/A private int nrpn_control = RPN_NULL_VALUE;
6321N/A double portamento_time = 1; // keyschanges per control buffer time
6321N/A int[] portamento_lastnote = new int[128];
6321N/A int portamento_lastnote_ix = 0;
829N/A private boolean portamento = false;
829N/A private boolean mono = false;
829N/A private boolean mute = false;
829N/A private boolean solo = false;
829N/A private boolean solomute = false;
6321N/A private final Object control_mutex;
829N/A private int channel;
829N/A private SoftVoice[] voices;
829N/A private int bank;
829N/A private int program;
829N/A private SoftSynthesizer synthesizer;
829N/A private SoftMainMixer mainmixer;
829N/A private int[] polypressure = new int[128];
829N/A private int channelpressure = 0;
829N/A private int[] controller = new int[128];
829N/A private int pitchbend;
829N/A private double[] co_midi_pitch = new double[1];
829N/A private double[] co_midi_channel_pressure = new double[1];
6321N/A SoftTuning tuning = new SoftTuning();
6321N/A int tuning_bank = 0;
6321N/A int tuning_program = 0;
6321N/A SoftInstrument current_instrument = null;
6321N/A ModelChannelMixer current_mixer = null;
6321N/A ModelDirector current_director = null;
829N/A
829N/A // Controller Destination Settings
6321N/A int cds_control_number = -1;
6321N/A ModelConnectionBlock[] cds_control_connections = null;
6321N/A ModelConnectionBlock[] cds_channelpressure_connections = null;
6321N/A ModelConnectionBlock[] cds_polypressure_connections = null;
6321N/A boolean sustain = false;
6321N/A boolean[][] keybasedcontroller_active = null;
6321N/A double[][] keybasedcontroller_value = null;
829N/A
829N/A private class MidiControlObject implements SoftControl {
829N/A double[] pitch = co_midi_pitch;
829N/A double[] channel_pressure = co_midi_channel_pressure;
829N/A double[] poly_pressure = new double[1];
829N/A
829N/A public double[] get(int instance, String name) {
829N/A if (name == null)
829N/A return null;
829N/A if (name.equals("pitch"))
829N/A return pitch;
829N/A if (name.equals("channel_pressure"))
829N/A return channel_pressure;
829N/A if (name.equals("poly_pressure"))
829N/A return poly_pressure;
829N/A return null;
829N/A }
829N/A }
829N/A
829N/A private SoftControl[] co_midi = new SoftControl[128];
829N/A {
829N/A for (int i = 0; i < co_midi.length; i++) {
829N/A co_midi[i] = new MidiControlObject();
829N/A }
829N/A }
829N/A
829N/A private double[][] co_midi_cc_cc = new double[128][1];
829N/A private SoftControl co_midi_cc = new SoftControl() {
829N/A double[][] cc = co_midi_cc_cc;
829N/A public double[] get(int instance, String name) {
829N/A if (name == null)
829N/A return null;
829N/A return cc[Integer.parseInt(name)];
829N/A }
829N/A };
829N/A Map<Integer, int[]> co_midi_rpn_rpn_i = new HashMap<Integer, int[]>();
829N/A Map<Integer, double[]> co_midi_rpn_rpn = new HashMap<Integer, double[]>();
829N/A private SoftControl co_midi_rpn = new SoftControl() {
829N/A Map<Integer, double[]> rpn = co_midi_rpn_rpn;
829N/A public double[] get(int instance, String name) {
829N/A if (name == null)
829N/A return null;
829N/A int iname = Integer.parseInt(name);
829N/A double[] v = rpn.get(iname);
829N/A if (v == null) {
829N/A v = new double[1];
829N/A rpn.put(iname, v);
829N/A }
829N/A return v;
829N/A }
829N/A };
829N/A Map<Integer, int[]> co_midi_nrpn_nrpn_i = new HashMap<Integer, int[]>();
829N/A Map<Integer, double[]> co_midi_nrpn_nrpn = new HashMap<Integer, double[]>();
829N/A private SoftControl co_midi_nrpn = new SoftControl() {
829N/A Map<Integer, double[]> nrpn = co_midi_nrpn_nrpn;
829N/A public double[] get(int instance, String name) {
829N/A if (name == null)
829N/A return null;
829N/A int iname = Integer.parseInt(name);
829N/A double[] v = nrpn.get(iname);
829N/A if (v == null) {
829N/A v = new double[1];
829N/A nrpn.put(iname, v);
829N/A }
829N/A return v;
829N/A }
829N/A };
829N/A
829N/A private static int restrict7Bit(int value)
829N/A {
829N/A if(value < 0) return 0;
829N/A if(value > 127) return 127;
829N/A return value;
829N/A }
829N/A
829N/A private static int restrict14Bit(int value)
829N/A {
829N/A if(value < 0) return 0;
829N/A if(value > 16256) return 16256;
829N/A return value;
829N/A }
829N/A
829N/A public SoftChannel(SoftSynthesizer synth, int channel) {
829N/A this.channel = channel;
829N/A this.voices = synth.getVoices();
829N/A this.synthesizer = synth;
829N/A this.mainmixer = synth.getMainMixer();
829N/A control_mutex = synth.control_mutex;
829N/A resetAllControllers(true);
829N/A }
829N/A
829N/A private int findFreeVoice(int x) {
1991N/A if(x == -1)
1991N/A {
1991N/A // x = -1 means that there where no available voice
1991N/A // last time we called findFreeVoice
1991N/A // and it hasn't changed because no audio has been
1991N/A // rendered in the meantime.
1991N/A // Therefore we have to return -1.
1991N/A return -1;
1991N/A }
829N/A for (int i = x; i < voices.length; i++)
829N/A if (!voices[i].active)
829N/A return i;
829N/A
829N/A // No free voice was found, we must steal one
829N/A
829N/A int vmode = synthesizer.getVoiceAllocationMode();
829N/A if (vmode == 1) {
829N/A // DLS Static Voice Allocation
829N/A
829N/A // * priority ( 10, 1-9, 11-16)
829N/A // Search for channel to steal from
829N/A int steal_channel = channel;
829N/A for (int j = 0; j < voices.length; j++) {
829N/A if (voices[j].stealer_channel == null) {
829N/A if (steal_channel == 9) {
829N/A steal_channel = voices[j].channel;
829N/A } else {
829N/A if (voices[j].channel != 9) {
829N/A if (voices[j].channel > steal_channel)
829N/A steal_channel = voices[j].channel;
829N/A }
829N/A }
829N/A }
829N/A }
829N/A
829N/A int voiceNo = -1;
829N/A
829N/A SoftVoice v = null;
829N/A // Search for oldest voice in off state on steal_channel
829N/A for (int j = 0; j < voices.length; j++) {
829N/A if (voices[j].channel == steal_channel) {
829N/A if (voices[j].stealer_channel == null && !voices[j].on) {
829N/A if (v == null) {
829N/A v = voices[j];
829N/A voiceNo = j;
829N/A }
829N/A if (voices[j].voiceID < v.voiceID) {
829N/A v = voices[j];
829N/A voiceNo = j;
829N/A }
829N/A }
829N/A }
829N/A }
829N/A // Search for oldest voice in on state on steal_channel
829N/A if (voiceNo == -1) {
829N/A for (int j = 0; j < voices.length; j++) {
829N/A if (voices[j].channel == steal_channel) {
829N/A if (voices[j].stealer_channel == null) {
829N/A if (v == null) {
829N/A v = voices[j];
829N/A voiceNo = j;
829N/A }
829N/A if (voices[j].voiceID < v.voiceID) {
829N/A v = voices[j];
829N/A voiceNo = j;
829N/A }
829N/A }
829N/A }
829N/A }
829N/A }
829N/A
829N/A return voiceNo;
829N/A
829N/A } else {
829N/A // Default Voice Allocation
829N/A // * Find voice that is on
829N/A // and Find voice which has lowest voiceID ( oldest voice)
829N/A // * Or find voice that is off
829N/A // and Find voice which has lowest voiceID ( oldest voice)
829N/A
829N/A int voiceNo = -1;
829N/A
829N/A SoftVoice v = null;
829N/A // Search for oldest voice in off state
829N/A for (int j = 0; j < voices.length; j++) {
829N/A if (voices[j].stealer_channel == null && !voices[j].on) {
829N/A if (v == null) {
829N/A v = voices[j];
829N/A voiceNo = j;
829N/A }
829N/A if (voices[j].voiceID < v.voiceID) {
829N/A v = voices[j];
829N/A voiceNo = j;
829N/A }
829N/A }
829N/A }
829N/A // Search for oldest voice in on state
829N/A if (voiceNo == -1) {
829N/A
829N/A for (int j = 0; j < voices.length; j++) {
829N/A if (voices[j].stealer_channel == null) {
829N/A if (v == null) {
829N/A v = voices[j];
829N/A voiceNo = j;
829N/A }
829N/A if (voices[j].voiceID < v.voiceID) {
829N/A v = voices[j];
829N/A voiceNo = j;
829N/A }
829N/A }
829N/A }
829N/A }
829N/A
829N/A return voiceNo;
829N/A }
829N/A
829N/A }
829N/A
6321N/A void initVoice(SoftVoice voice, SoftPerformer p, int voiceID,
1990N/A int noteNumber, int velocity, int delay, ModelConnectionBlock[] connectionBlocks,
829N/A ModelChannelMixer channelmixer, boolean releaseTriggered) {
829N/A if (voice.active) {
829N/A // Voice is active , we must steal the voice
829N/A voice.stealer_channel = this;
829N/A voice.stealer_performer = p;
829N/A voice.stealer_voiceID = voiceID;
829N/A voice.stealer_noteNumber = noteNumber;
829N/A voice.stealer_velocity = velocity;
829N/A voice.stealer_extendedConnectionBlocks = connectionBlocks;
829N/A voice.stealer_channelmixer = channelmixer;
829N/A voice.stealer_releaseTriggered = releaseTriggered;
829N/A for (int i = 0; i < voices.length; i++)
829N/A if (voices[i].active && voices[i].voiceID == voice.voiceID)
829N/A voices[i].soundOff();
829N/A return;
829N/A }
829N/A
829N/A voice.extendedConnectionBlocks = connectionBlocks;
829N/A voice.channelmixer = channelmixer;
829N/A voice.releaseTriggered = releaseTriggered;
829N/A voice.voiceID = voiceID;
829N/A voice.tuning = tuning;
829N/A voice.exclusiveClass = p.exclusiveClass;
829N/A voice.softchannel = this;
829N/A voice.channel = channel;
829N/A voice.bank = bank;
829N/A voice.program = program;
829N/A voice.instrument = current_instrument;
829N/A voice.performer = p;
829N/A voice.objects.clear();
829N/A voice.objects.put("midi", co_midi[noteNumber]);
829N/A voice.objects.put("midi_cc", co_midi_cc);
829N/A voice.objects.put("midi_rpn", co_midi_rpn);
829N/A voice.objects.put("midi_nrpn", co_midi_nrpn);
1990N/A voice.noteOn(noteNumber, velocity, delay);
829N/A voice.setMute(mute);
829N/A voice.setSoloMute(solomute);
829N/A if (releaseTriggered)
829N/A return;
1171N/A if (controller[84] != 0) {
829N/A voice.co_noteon_keynumber[0]
1171N/A = (tuning.getTuning(controller[84]) / 100.0)
829N/A * (1f / 128f);
829N/A voice.portamento = true;
1171N/A controlChange(84, 0);
829N/A } else if (portamento) {
829N/A if (mono) {
829N/A if (portamento_lastnote[0] != -1) {
829N/A voice.co_noteon_keynumber[0]
829N/A = (tuning.getTuning(portamento_lastnote[0]) / 100.0)
829N/A * (1f / 128f);
829N/A voice.portamento = true;
1171N/A controlChange(84, 0);
829N/A }
829N/A portamento_lastnote[0] = noteNumber;
829N/A } else {
829N/A if (portamento_lastnote_ix != 0) {
829N/A portamento_lastnote_ix--;
829N/A voice.co_noteon_keynumber[0]
829N/A = (tuning.getTuning(
829N/A portamento_lastnote[portamento_lastnote_ix])
829N/A / 100.0)
829N/A * (1f / 128f);
829N/A voice.portamento = true;
829N/A }
829N/A }
829N/A }
829N/A }
829N/A
829N/A public void noteOn(int noteNumber, int velocity) {
1990N/A noteOn(noteNumber, velocity, 0);
1990N/A }
1990N/A
1990N/A /* A special noteOn with delay parameter, which is used to
1990N/A * start note within control buffers.
1990N/A */
6321N/A void noteOn(int noteNumber, int velocity, int delay) {
829N/A noteNumber = restrict7Bit(noteNumber);
829N/A velocity = restrict7Bit(velocity);
1990N/A noteOn_internal(noteNumber, velocity, delay);
829N/A if (current_mixer != null)
829N/A current_mixer.noteOn(noteNumber, velocity);
829N/A }
829N/A
1990N/A private void noteOn_internal(int noteNumber, int velocity, int delay) {
829N/A
829N/A if (velocity == 0) {
829N/A noteOff_internal(noteNumber, 64);
829N/A return;
829N/A }
829N/A
829N/A synchronized (control_mutex) {
829N/A if (sustain) {
829N/A sustain = false;
829N/A for (int i = 0; i < voices.length; i++) {
829N/A if ((voices[i].sustain || voices[i].on)
829N/A && voices[i].channel == channel && voices[i].active
829N/A && voices[i].note == noteNumber) {
829N/A voices[i].sustain = false;
829N/A voices[i].on = true;
829N/A voices[i].noteOff(0);
829N/A }
829N/A }
829N/A sustain = true;
829N/A }
829N/A
829N/A mainmixer.activity();
829N/A
829N/A if (mono) {
829N/A if (portamento) {
829N/A boolean n_found = false;
829N/A for (int i = 0; i < voices.length; i++) {
829N/A if (voices[i].on && voices[i].channel == channel
829N/A && voices[i].active
829N/A && voices[i].releaseTriggered == false) {
829N/A voices[i].portamento = true;
829N/A voices[i].setNote(noteNumber);
829N/A n_found = true;
829N/A }
829N/A }
829N/A if (n_found) {
829N/A portamento_lastnote[0] = noteNumber;
829N/A return;
829N/A }
829N/A }
829N/A
1171N/A if (controller[84] != 0) {
829N/A boolean n_found = false;
829N/A for (int i = 0; i < voices.length; i++) {
829N/A if (voices[i].on && voices[i].channel == channel
829N/A && voices[i].active
1171N/A && voices[i].note == controller[84]
829N/A && voices[i].releaseTriggered == false) {
829N/A voices[i].portamento = true;
829N/A voices[i].setNote(noteNumber);
829N/A n_found = true;
829N/A }
829N/A }
1171N/A controlChange(84, 0);
829N/A if (n_found)
829N/A return;
829N/A }
829N/A }
829N/A
829N/A if (mono)
829N/A allNotesOff();
829N/A
829N/A if (current_instrument == null) {
829N/A current_instrument
829N/A = synthesizer.findInstrument(program, bank, channel);
829N/A if (current_instrument == null)
829N/A return;
829N/A if (current_mixer != null)
829N/A mainmixer.stopMixer(current_mixer);
829N/A current_mixer = current_instrument.getSourceInstrument()
829N/A .getChannelMixer(this, synthesizer.getFormat());
829N/A if (current_mixer != null)
829N/A mainmixer.registerMixer(current_mixer);
829N/A current_director = current_instrument.getDirector(this, this);
829N/A applyInstrumentCustomization();
829N/A }
829N/A prevVoiceID = synthesizer.voiceIDCounter++;
829N/A firstVoice = true;
829N/A voiceNo = 0;
829N/A
3957N/A int tunedKey = (int)(Math.round(tuning.getTuning(noteNumber)/100.0));
829N/A play_noteNumber = noteNumber;
829N/A play_velocity = velocity;
1990N/A play_delay = delay;
829N/A play_releasetriggered = false;
829N/A lastVelocity[noteNumber] = velocity;
829N/A current_director.noteOn(tunedKey, velocity);
829N/A
829N/A /*
829N/A SoftPerformer[] performers = current_instrument.getPerformers();
829N/A for (int i = 0; i < performers.length; i++) {
829N/A SoftPerformer p = performers[i];
829N/A if (p.keyFrom <= tunedKey && p.keyTo >= tunedKey) {
829N/A if (p.velFrom <= velocity && p.velTo >= velocity) {
829N/A if (firstVoice) {
829N/A firstVoice = false;
829N/A if (p.exclusiveClass != 0) {
829N/A int x = p.exclusiveClass;
829N/A for (int j = 0; j < voices.length; j++) {
829N/A if (voices[j].active
829N/A && voices[j].channel == channel
829N/A && voices[j].exclusiveClass == x) {
829N/A if (!(p.selfNonExclusive
829N/A && voices[j].note == noteNumber))
829N/A voices[j].shutdown();
829N/A }
829N/A }
829N/A }
829N/A }
829N/A voiceNo = findFreeVoice(voiceNo);
829N/A if (voiceNo == -1)
829N/A return;
829N/A initVoice(voices[voiceNo], p, prevVoiceID, noteNumber,
829N/A velocity);
829N/A }
829N/A }
829N/A }
829N/A */
829N/A }
829N/A }
829N/A
829N/A public void noteOff(int noteNumber, int velocity) {
829N/A noteNumber = restrict7Bit(noteNumber);
829N/A velocity = restrict7Bit(velocity);
829N/A noteOff_internal(noteNumber, velocity);
829N/A
829N/A if (current_mixer != null)
829N/A current_mixer.noteOff(noteNumber, velocity);
829N/A }
829N/A
829N/A private void noteOff_internal(int noteNumber, int velocity) {
829N/A synchronized (control_mutex) {
829N/A
829N/A if (!mono) {
829N/A if (portamento) {
829N/A if (portamento_lastnote_ix != 127) {
829N/A portamento_lastnote[portamento_lastnote_ix] = noteNumber;
829N/A portamento_lastnote_ix++;
829N/A }
829N/A }
829N/A }
829N/A
829N/A mainmixer.activity();
829N/A for (int i = 0; i < voices.length; i++) {
829N/A if (voices[i].on && voices[i].channel == channel
829N/A && voices[i].note == noteNumber
829N/A && voices[i].releaseTriggered == false) {
829N/A voices[i].noteOff(velocity);
829N/A }
1170N/A // We must also check stolen voices
1170N/A if (voices[i].stealer_channel == this && voices[i].stealer_noteNumber == noteNumber) {
1170N/A SoftVoice v = voices[i];
1170N/A v.stealer_releaseTriggered = false;
1170N/A v.stealer_channel = null;
1170N/A v.stealer_performer = null;
1170N/A v.stealer_voiceID = -1;
1170N/A v.stealer_noteNumber = 0;
1170N/A v.stealer_velocity = 0;
1170N/A v.stealer_extendedConnectionBlocks = null;
1170N/A v.stealer_channelmixer = null;
1170N/A }
829N/A }
829N/A
829N/A // Try play back note-off triggered voices,
829N/A
829N/A if (current_instrument == null) {
829N/A current_instrument
829N/A = synthesizer.findInstrument(program, bank, channel);
829N/A if (current_instrument == null)
829N/A return;
829N/A if (current_mixer != null)
829N/A mainmixer.stopMixer(current_mixer);
829N/A current_mixer = current_instrument.getSourceInstrument()
829N/A .getChannelMixer(this, synthesizer.getFormat());
829N/A if (current_mixer != null)
829N/A mainmixer.registerMixer(current_mixer);
829N/A current_director = current_instrument.getDirector(this, this);
829N/A applyInstrumentCustomization();
829N/A
829N/A }
829N/A prevVoiceID = synthesizer.voiceIDCounter++;
829N/A firstVoice = true;
829N/A voiceNo = 0;
829N/A
3957N/A int tunedKey = (int)(Math.round(tuning.getTuning(noteNumber)/100.0));
829N/A play_noteNumber = noteNumber;
829N/A play_velocity = lastVelocity[noteNumber];
829N/A play_releasetriggered = true;
1990N/A play_delay = 0;
829N/A current_director.noteOff(tunedKey, velocity);
829N/A
829N/A }
829N/A }
829N/A private int[] lastVelocity = new int[128];
829N/A private int prevVoiceID;
829N/A private boolean firstVoice = true;
829N/A private int voiceNo = 0;
829N/A private int play_noteNumber = 0;
829N/A private int play_velocity = 0;
1990N/A private int play_delay = 0;
829N/A private boolean play_releasetriggered = false;
829N/A
829N/A public void play(int performerIndex, ModelConnectionBlock[] connectionBlocks) {
829N/A
829N/A int noteNumber = play_noteNumber;
829N/A int velocity = play_velocity;
1990N/A int delay = play_delay;
829N/A boolean releasetriggered = play_releasetriggered;
829N/A
3957N/A SoftPerformer p = current_instrument.getPerformer(performerIndex);
829N/A
829N/A if (firstVoice) {
829N/A firstVoice = false;
829N/A if (p.exclusiveClass != 0) {
829N/A int x = p.exclusiveClass;
829N/A for (int j = 0; j < voices.length; j++) {
829N/A if (voices[j].active && voices[j].channel == channel
829N/A && voices[j].exclusiveClass == x) {
829N/A if (!(p.selfNonExclusive && voices[j].note == noteNumber))
829N/A voices[j].shutdown();
829N/A }
829N/A }
829N/A }
829N/A }
829N/A
829N/A voiceNo = findFreeVoice(voiceNo);
829N/A
829N/A if (voiceNo == -1)
829N/A return;
829N/A
1990N/A initVoice(voices[voiceNo], p, prevVoiceID, noteNumber, velocity, delay,
829N/A connectionBlocks, current_mixer, releasetriggered);
829N/A }
829N/A
829N/A public void noteOff(int noteNumber) {
829N/A if(noteNumber < 0 || noteNumber > 127) return;
829N/A noteOff_internal(noteNumber, 64);
829N/A }
829N/A
829N/A public void setPolyPressure(int noteNumber, int pressure) {
829N/A noteNumber = restrict7Bit(noteNumber);
829N/A pressure = restrict7Bit(pressure);
829N/A
829N/A if (current_mixer != null)
829N/A current_mixer.setPolyPressure(noteNumber, pressure);
829N/A
829N/A synchronized (control_mutex) {
829N/A mainmixer.activity();
829N/A co_midi[noteNumber].get(0, "poly_pressure")[0] = pressure*(1.0/128.0);
829N/A polypressure[noteNumber] = pressure;
829N/A for (int i = 0; i < voices.length; i++) {
829N/A if (voices[i].active && voices[i].note == noteNumber)
829N/A voices[i].setPolyPressure(pressure);
829N/A }
829N/A }
829N/A }
829N/A
829N/A public int getPolyPressure(int noteNumber) {
829N/A synchronized (control_mutex) {
829N/A return polypressure[noteNumber];
829N/A }
829N/A }
829N/A
829N/A public void setChannelPressure(int pressure) {
829N/A pressure = restrict7Bit(pressure);
829N/A if (current_mixer != null)
829N/A current_mixer.setChannelPressure(pressure);
829N/A synchronized (control_mutex) {
829N/A mainmixer.activity();
829N/A co_midi_channel_pressure[0] = pressure * (1.0 / 128.0);
829N/A channelpressure = pressure;
829N/A for (int i = 0; i < voices.length; i++) {
829N/A if (voices[i].active)
829N/A voices[i].setChannelPressure(pressure);
829N/A }
829N/A }
829N/A }
829N/A
829N/A public int getChannelPressure() {
829N/A synchronized (control_mutex) {
829N/A return channelpressure;
829N/A }
829N/A }
829N/A
6321N/A void applyInstrumentCustomization() {
829N/A if (cds_control_connections == null
829N/A && cds_channelpressure_connections == null
829N/A && cds_polypressure_connections == null) {
829N/A return;
829N/A }
829N/A
829N/A ModelInstrument src_instrument = current_instrument.getSourceInstrument();
829N/A ModelPerformer[] performers = src_instrument.getPerformers();
829N/A ModelPerformer[] new_performers = new ModelPerformer[performers.length];
829N/A for (int i = 0; i < new_performers.length; i++) {
829N/A ModelPerformer performer = performers[i];
829N/A ModelPerformer new_performer = new ModelPerformer();
829N/A new_performer.setName(performer.getName());
829N/A new_performer.setExclusiveClass(performer.getExclusiveClass());
829N/A new_performer.setKeyFrom(performer.getKeyFrom());
829N/A new_performer.setKeyTo(performer.getKeyTo());
829N/A new_performer.setVelFrom(performer.getVelFrom());
829N/A new_performer.setVelTo(performer.getVelTo());
829N/A new_performer.getOscillators().addAll(performer.getOscillators());
829N/A new_performer.getConnectionBlocks().addAll(
829N/A performer.getConnectionBlocks());
829N/A new_performers[i] = new_performer;
829N/A
829N/A List<ModelConnectionBlock> connblocks =
829N/A new_performer.getConnectionBlocks();
829N/A
829N/A if (cds_control_connections != null) {
829N/A String cc = Integer.toString(cds_control_number);
829N/A Iterator<ModelConnectionBlock> iter = connblocks.iterator();
829N/A while (iter.hasNext()) {
829N/A ModelConnectionBlock conn = iter.next();
829N/A ModelSource[] sources = conn.getSources();
829N/A boolean removeok = false;
829N/A if (sources != null) {
829N/A for (int j = 0; j < sources.length; j++) {
829N/A ModelSource src = sources[j];
829N/A if ("midi_cc".equals(src.getIdentifier().getObject())
829N/A && cc.equals(src.getIdentifier().getVariable())) {
829N/A removeok = true;
829N/A }
829N/A }
829N/A }
829N/A if (removeok)
829N/A iter.remove();
829N/A }
829N/A for (int j = 0; j < cds_control_connections.length; j++)
829N/A connblocks.add(cds_control_connections[j]);
829N/A }
829N/A
829N/A if (cds_polypressure_connections != null) {
829N/A Iterator<ModelConnectionBlock> iter = connblocks.iterator();
829N/A while (iter.hasNext()) {
829N/A ModelConnectionBlock conn = iter.next();
829N/A ModelSource[] sources = conn.getSources();
829N/A boolean removeok = false;
829N/A if (sources != null) {
829N/A for (int j = 0; j < sources.length; j++) {
829N/A ModelSource src = sources[j];
829N/A if ("midi".equals(src.getIdentifier().getObject())
829N/A && "poly_pressure".equals(
829N/A src.getIdentifier().getVariable())) {
829N/A removeok = true;
829N/A }
829N/A }
829N/A }
829N/A if (removeok)
829N/A iter.remove();
829N/A }
829N/A for (int j = 0; j < cds_polypressure_connections.length; j++)
829N/A connblocks.add(cds_polypressure_connections[j]);
829N/A }
829N/A
829N/A
829N/A if (cds_channelpressure_connections != null) {
829N/A Iterator<ModelConnectionBlock> iter = connblocks.iterator();
829N/A while (iter.hasNext()) {
829N/A ModelConnectionBlock conn = iter.next();
829N/A ModelSource[] sources = conn.getSources();
829N/A boolean removeok = false;
829N/A if (sources != null) {
829N/A for (int j = 0; j < sources.length; j++) {
829N/A ModelIdentifier srcid = sources[j].getIdentifier();
829N/A if ("midi".equals(srcid.getObject()) &&
829N/A "channel_pressure".equals(srcid.getVariable())) {
829N/A removeok = true;
829N/A }
829N/A }
829N/A }
829N/A if (removeok)
829N/A iter.remove();
829N/A }
829N/A for (int j = 0; j < cds_channelpressure_connections.length; j++)
829N/A connblocks.add(cds_channelpressure_connections[j]);
829N/A }
829N/A
829N/A }
829N/A
829N/A current_instrument = new SoftInstrument(src_instrument, new_performers);
829N/A
829N/A }
829N/A
829N/A private ModelConnectionBlock[] createModelConnections(ModelIdentifier sid,
829N/A int[] destination, int[] range) {
829N/A
829N/A /*
829N/A controlled parameter (pp)|range (rr)| Description |Default
829N/A -------------------------|----------|-------------------------|-------
829N/A 00 Pitch Control | 28H..58H | -24..+24 semitones | 40H
829N/A 01 Filter Cutoff Control | 00H..7FH | -9600..+9450 cents | 40H
829N/A 02 Amplitude Control | 00H..7FH | 0..(127/64)*100 percent | 40H
829N/A 03 LFO Pitch Depth | 00H..7FH | 0..600 cents | 0
829N/A 04 LFO Filter Depth | 00H..7FH | 0..2400 cents | 0
829N/A 05 LFO Amplitude Depth | 00H..7FH | 0..100 percent | 0
829N/A */
829N/A
829N/A List<ModelConnectionBlock> conns = new ArrayList<ModelConnectionBlock>();
829N/A
829N/A for (int i = 0; i < destination.length; i++) {
829N/A int d = destination[i];
829N/A int r = range[i];
829N/A if (d == 0) {
829N/A double scale = (r - 64) * 100;
829N/A ModelConnectionBlock conn = new ModelConnectionBlock(
829N/A new ModelSource(sid,
829N/A ModelStandardTransform.DIRECTION_MIN2MAX,
829N/A ModelStandardTransform.POLARITY_UNIPOLAR,
829N/A ModelStandardTransform.TRANSFORM_LINEAR),
829N/A scale,
829N/A new ModelDestination(
829N/A new ModelIdentifier("osc", "pitch")));
829N/A conns.add(conn);
829N/A
829N/A }
829N/A if (d == 1) {
829N/A double scale = (r / 64.0 - 1.0) * 9600.0;
829N/A ModelConnectionBlock conn;
829N/A if (scale > 0) {
829N/A conn = new ModelConnectionBlock(
829N/A new ModelSource(sid,
829N/A ModelStandardTransform.DIRECTION_MAX2MIN,
829N/A ModelStandardTransform.POLARITY_UNIPOLAR,
829N/A ModelStandardTransform.TRANSFORM_LINEAR),
829N/A -scale,
829N/A new ModelDestination(
829N/A ModelDestination.DESTINATION_FILTER_FREQ));
829N/A } else {
829N/A conn = new ModelConnectionBlock(
829N/A new ModelSource(sid,
829N/A ModelStandardTransform.DIRECTION_MIN2MAX,
829N/A ModelStandardTransform.POLARITY_UNIPOLAR,
829N/A ModelStandardTransform.TRANSFORM_LINEAR),
829N/A scale,
829N/A new ModelDestination(
829N/A ModelDestination.DESTINATION_FILTER_FREQ));
829N/A }
829N/A conns.add(conn);
829N/A }
829N/A if (d == 2) {
829N/A final double scale = (r / 64.0);
829N/A ModelTransform mt = new ModelTransform() {
829N/A double s = scale;
829N/A public double transform(double value) {
829N/A if (s < 1)
829N/A value = s + (value * (1.0 - s));
829N/A else if (s > 1)
829N/A value = 1 + (value * (s - 1.0));
829N/A else
829N/A return 0;
829N/A return -((5.0 / 12.0) / Math.log(10)) * Math.log(value);
829N/A }
829N/A };
829N/A
829N/A ModelConnectionBlock conn = new ModelConnectionBlock(
829N/A new ModelSource(sid, mt), -960,
829N/A new ModelDestination(ModelDestination.DESTINATION_GAIN));
829N/A conns.add(conn);
829N/A
829N/A }
829N/A if (d == 3) {
829N/A double scale = (r / 64.0 - 1.0) * 9600.0;
829N/A ModelConnectionBlock conn = new ModelConnectionBlock(
829N/A new ModelSource(ModelSource.SOURCE_LFO1,
829N/A ModelStandardTransform.DIRECTION_MIN2MAX,
829N/A ModelStandardTransform.POLARITY_BIPOLAR,
829N/A ModelStandardTransform.TRANSFORM_LINEAR),
829N/A new ModelSource(sid,
829N/A ModelStandardTransform.DIRECTION_MIN2MAX,
829N/A ModelStandardTransform.POLARITY_UNIPOLAR,
829N/A ModelStandardTransform.TRANSFORM_LINEAR),
829N/A scale,
829N/A new ModelDestination(
829N/A ModelDestination.DESTINATION_PITCH));
829N/A conns.add(conn);
829N/A }
829N/A if (d == 4) {
829N/A double scale = (r / 128.0) * 2400.0;
829N/A ModelConnectionBlock conn = new ModelConnectionBlock(
829N/A new ModelSource(ModelSource.SOURCE_LFO1,
829N/A ModelStandardTransform.DIRECTION_MIN2MAX,
829N/A ModelStandardTransform.POLARITY_BIPOLAR,
829N/A ModelStandardTransform.TRANSFORM_LINEAR),
829N/A new ModelSource(sid,
829N/A ModelStandardTransform.DIRECTION_MIN2MAX,
829N/A ModelStandardTransform.POLARITY_UNIPOLAR,
829N/A ModelStandardTransform.TRANSFORM_LINEAR),
829N/A scale,
829N/A new ModelDestination(
829N/A ModelDestination.DESTINATION_FILTER_FREQ));
829N/A conns.add(conn);
829N/A }
829N/A if (d == 5) {
829N/A final double scale = (r / 127.0);
829N/A
829N/A ModelTransform mt = new ModelTransform() {
829N/A double s = scale;
829N/A public double transform(double value) {
829N/A return -((5.0 / 12.0) / Math.log(10))
829N/A * Math.log(1 - value * s);
829N/A }
829N/A };
829N/A
829N/A ModelConnectionBlock conn = new ModelConnectionBlock(
829N/A new ModelSource(ModelSource.SOURCE_LFO1,
829N/A ModelStandardTransform.DIRECTION_MIN2MAX,
829N/A ModelStandardTransform.POLARITY_UNIPOLAR,
829N/A ModelStandardTransform.TRANSFORM_LINEAR),
829N/A new ModelSource(sid, mt),
829N/A -960,
829N/A new ModelDestination(
829N/A ModelDestination.DESTINATION_GAIN));
829N/A conns.add(conn);
829N/A }
829N/A }
829N/A
829N/A return conns.toArray(new ModelConnectionBlock[conns.size()]);
829N/A }
829N/A
829N/A public void mapPolyPressureToDestination(int[] destination, int[] range) {
829N/A current_instrument = null;
829N/A if (destination.length == 0) {
829N/A cds_polypressure_connections = null;
829N/A return;
829N/A }
829N/A cds_polypressure_connections
829N/A = createModelConnections(
829N/A new ModelIdentifier("midi", "poly_pressure"),
829N/A destination, range);
829N/A }
829N/A
829N/A public void mapChannelPressureToDestination(int[] destination, int[] range) {
829N/A current_instrument = null;
829N/A if (destination.length == 0) {
829N/A cds_channelpressure_connections = null;
829N/A return;
829N/A }
829N/A cds_channelpressure_connections
829N/A = createModelConnections(
829N/A new ModelIdentifier("midi", "channel_pressure"),
829N/A destination, range);
829N/A }
829N/A
829N/A public void mapControlToDestination(int control, int[] destination, int[] range) {
829N/A
829N/A if (!((control >= 0x01 && control <= 0x1F)
829N/A || (control >= 0x40 && control <= 0x5F))) {
829N/A cds_control_connections = null;
829N/A return;
829N/A }
829N/A
829N/A current_instrument = null;
829N/A cds_control_number = control;
829N/A if (destination.length == 0) {
829N/A cds_control_connections = null;
829N/A return;
829N/A }
829N/A cds_control_connections
829N/A = createModelConnections(
829N/A new ModelIdentifier("midi_cc", Integer.toString(control)),
829N/A destination, range);
829N/A }
829N/A
829N/A public void controlChangePerNote(int noteNumber, int controller, int value) {
829N/A
829N/A/*
829N/A CC# | nn | Name | vv | default | description
829N/A-----|------|-------------------------|----------------|------------|-------------------------------
829N/A7 |07H |Note Volume |00H-40H-7FH |40H |0-100-(127/64)*100(%)(Relative)
829N/A10 |0AH |*Pan |00H-7FH absolute|Preset Value|Left-Center-Right (absolute)
829N/A33-63|21-3FH|LSB for |01H-1FH | |
829N/A71 |47H |Timbre/Harmonic Intensity|00H-40H-7FH |40H (???) |
829N/A72 |48H |Release Time |00H-40H-7FH |40H (???) |
829N/A73 |49H |Attack Time |00H-40H-7FH |40H (???) |
829N/A74 |4AH |Brightness |00H-40H-7FH |40H (???) |
829N/A75 |4BH |Decay Time |00H-40H-7FH |40H (???) |
829N/A76 |4CH |Vibrato Rate |00H-40H-7FH |40H (???) |
829N/A77 |4DH |Vibrato Depth |00H-40H-7FH |40H (???) |
829N/A78 |4EH |Vibrato Delay |00H-40H-7FH |40H (???) |
829N/A91 |5BH |*Reverb Send |00H-7FH absolute|Preset Value|Left-Center-Right (absolute)
829N/A93 |5DH |*Chorus Send |00H-7FH absolute|Preset Value|Left-Center-Right (absolute)
829N/A120 |78H |**Fine Tuning |00H-40H-7FH |40H (???) |
829N/A121 |79H |**Coarse Tuning |00H-40H-7FH |40H (???) |
829N/A*/
829N/A
829N/A if (keybasedcontroller_active == null) {
829N/A keybasedcontroller_active = new boolean[128][];
829N/A keybasedcontroller_value = new double[128][];
829N/A }
829N/A if (keybasedcontroller_active[noteNumber] == null) {
829N/A keybasedcontroller_active[noteNumber] = new boolean[128];
829N/A Arrays.fill(keybasedcontroller_active[noteNumber], false);
829N/A keybasedcontroller_value[noteNumber] = new double[128];
829N/A Arrays.fill(keybasedcontroller_value[noteNumber], 0);
829N/A }
829N/A
829N/A if (value == -1) {
829N/A keybasedcontroller_active[noteNumber][controller] = false;
829N/A } else {
829N/A keybasedcontroller_active[noteNumber][controller] = true;
829N/A keybasedcontroller_value[noteNumber][controller] = value / 128.0;
829N/A }
829N/A
829N/A if (controller < 120) {
829N/A for (int i = 0; i < voices.length; i++)
829N/A if (voices[i].active)
829N/A voices[i].controlChange(controller, -1);
829N/A } else if (controller == 120) {
829N/A for (int i = 0; i < voices.length; i++)
829N/A if (voices[i].active)
829N/A voices[i].rpnChange(1, -1);
829N/A } else if (controller == 121) {
829N/A for (int i = 0; i < voices.length; i++)
829N/A if (voices[i].active)
829N/A voices[i].rpnChange(2, -1);
829N/A }
829N/A
829N/A }
829N/A
829N/A public int getControlPerNote(int noteNumber, int controller) {
829N/A if (keybasedcontroller_active == null)
829N/A return -1;
829N/A if (keybasedcontroller_active[noteNumber] == null)
829N/A return -1;
829N/A if (!keybasedcontroller_active[noteNumber][controller])
829N/A return -1;
829N/A return (int)(keybasedcontroller_value[noteNumber][controller] * 128);
829N/A }
829N/A
829N/A public void controlChange(int controller, int value) {
829N/A controller = restrict7Bit(controller);
829N/A value = restrict7Bit(value);
829N/A if (current_mixer != null)
829N/A current_mixer.controlChange(controller, value);
829N/A
829N/A synchronized (control_mutex) {
829N/A switch (controller) {
829N/A /*
829N/A Map<String, int[]>co_midi_rpn_rpn_i = new HashMap<String, int[]>();
829N/A Map<String, double[]>co_midi_rpn_rpn = new HashMap<String, double[]>();
829N/A Map<String, int[]>co_midi_nrpn_nrpn_i = new HashMap<String, int[]>();
829N/A Map<String, double[]>co_midi_nrpn_nrpn = new HashMap<String, double[]>();
829N/A */
829N/A
829N/A case 5:
829N/A // This produce asin-like curve
829N/A // as described in General Midi Level 2 Specification, page 6
829N/A double x = -Math.asin((value / 128.0) * 2 - 1) / Math.PI + 0.5;
829N/A x = Math.pow(100000.0, x) / 100.0; // x is now cent/msec
829N/A // Convert x from cent/msec to key/controlbuffertime
829N/A x = x / 100.0; // x is now keys/msec
829N/A x = x * 1000.0; // x is now keys/sec
829N/A x = x / synthesizer.getControlRate(); // x is now keys/controlbuffertime
829N/A portamento_time = x;
829N/A break;
829N/A case 6:
829N/A case 38:
829N/A case 96:
829N/A case 97:
829N/A int val = 0;
829N/A if (nrpn_control != RPN_NULL_VALUE) {
829N/A int[] val_i = co_midi_nrpn_nrpn_i.get(nrpn_control);
829N/A if (val_i != null)
829N/A val = val_i[0];
829N/A }
829N/A if (rpn_control != RPN_NULL_VALUE) {
829N/A int[] val_i = co_midi_rpn_rpn_i.get(rpn_control);
829N/A if (val_i != null)
829N/A val = val_i[0];
829N/A }
829N/A
829N/A if (controller == 6)
829N/A val = (val & 127) + (value << 7);
829N/A else if (controller == 38)
829N/A val = (val & (127 << 7)) + value;
829N/A else if (controller == 96 || controller == 97) {
829N/A int step = 1;
829N/A if (rpn_control == 2 || rpn_control == 3 || rpn_control == 4)
829N/A step = 128;
829N/A if (controller == 96)
829N/A val += step;
829N/A if (controller == 97)
829N/A val -= step;
829N/A }
829N/A
829N/A if (nrpn_control != RPN_NULL_VALUE)
829N/A nrpnChange(nrpn_control, val);
829N/A if (rpn_control != RPN_NULL_VALUE)
829N/A rpnChange(rpn_control, val);
829N/A
829N/A break;
829N/A case 64: // Hold1 (Damper) (cc#64)
829N/A boolean on = value >= 64;
829N/A if (sustain != on) {
829N/A sustain = on;
829N/A if (!on) {
829N/A for (int i = 0; i < voices.length; i++) {
829N/A if (voices[i].active && voices[i].sustain &&
829N/A voices[i].channel == channel) {
829N/A voices[i].sustain = false;
829N/A if (!voices[i].on) {
829N/A voices[i].on = true;
829N/A voices[i].noteOff(0);
829N/A }
829N/A }
829N/A }
829N/A } else {
829N/A for (int i = 0; i < voices.length; i++)
829N/A if (voices[i].active && voices[i].channel == channel)
829N/A voices[i].redamp();
829N/A }
829N/A }
829N/A break;
829N/A case 65:
829N/A //allNotesOff();
829N/A portamento = value >= 64;
829N/A portamento_lastnote[0] = -1;
829N/A /*
829N/A for (int i = 0; i < portamento_lastnote.length; i++)
829N/A portamento_lastnote[i] = -1;
829N/A */
829N/A portamento_lastnote_ix = 0;
829N/A break;
829N/A case 66: // Sostenuto (cc#66)
829N/A on = value >= 64;
829N/A if (on) {
829N/A for (int i = 0; i < voices.length; i++) {
829N/A if (voices[i].active && voices[i].on &&
829N/A voices[i].channel == channel) {
829N/A voices[i].sostenuto = true;
829N/A }
829N/A }
829N/A }
829N/A if (!on) {
829N/A for (int i = 0; i < voices.length; i++) {
829N/A if (voices[i].active && voices[i].sostenuto &&
829N/A voices[i].channel == channel) {
829N/A voices[i].sostenuto = false;
829N/A if (!voices[i].on) {
829N/A voices[i].on = true;
829N/A voices[i].noteOff(0);
829N/A }
829N/A }
829N/A }
829N/A }
829N/A break;
829N/A case 98:
829N/A nrpn_control = (nrpn_control & (127 << 7)) + value;
829N/A rpn_control = RPN_NULL_VALUE;
829N/A break;
829N/A case 99:
829N/A nrpn_control = (nrpn_control & 127) + (value << 7);
829N/A rpn_control = RPN_NULL_VALUE;
829N/A break;
829N/A case 100:
829N/A rpn_control = (rpn_control & (127 << 7)) + value;
829N/A nrpn_control = RPN_NULL_VALUE;
829N/A break;
829N/A case 101:
829N/A rpn_control = (rpn_control & 127) + (value << 7);
829N/A nrpn_control = RPN_NULL_VALUE;
829N/A break;
829N/A case 120:
829N/A allSoundOff();
829N/A break;
829N/A case 121:
829N/A resetAllControllers(value == 127);
829N/A break;
829N/A case 122:
829N/A localControl(value >= 64);
829N/A break;
829N/A case 123:
829N/A allNotesOff();
829N/A break;
829N/A case 124:
829N/A setOmni(false);
829N/A break;
829N/A case 125:
829N/A setOmni(true);
829N/A break;
829N/A case 126:
829N/A if (value == 1)
829N/A setMono(true);
829N/A break;
829N/A case 127:
829N/A setMono(false);
829N/A break;
829N/A
829N/A default:
829N/A break;
829N/A }
829N/A
829N/A co_midi_cc_cc[controller][0] = value * (1.0 / 128.0);
829N/A
829N/A if (controller == 0x00) {
829N/A bank = /*(bank & 127) +*/ (value << 7);
829N/A return;
829N/A }
829N/A
829N/A if (controller == 0x20) {
829N/A bank = (bank & (127 << 7)) + value;
829N/A return;
829N/A }
829N/A
829N/A this.controller[controller] = value;
829N/A if(controller < 0x20)
829N/A this.controller[controller + 0x20] = 0;
829N/A
829N/A for (int i = 0; i < voices.length; i++)
829N/A if (voices[i].active)
829N/A voices[i].controlChange(controller, value);
829N/A
829N/A }
829N/A }
829N/A
829N/A public int getController(int controller) {
829N/A synchronized (control_mutex) {
829N/A // Should only return lower 7 bits,
829N/A // even when controller is "boosted" higher.
829N/A return this.controller[controller] & 127;
829N/A }
829N/A }
829N/A
829N/A public void tuningChange(int program) {
829N/A tuningChange(0, program);
829N/A }
829N/A
829N/A public void tuningChange(int bank, int program) {
829N/A synchronized (control_mutex) {
829N/A tuning = synthesizer.getTuning(new Patch(bank, program));
829N/A }
829N/A }
829N/A
829N/A public void programChange(int program) {
829N/A programChange(bank, program);
829N/A }
829N/A
829N/A public void programChange(int bank, int program) {
2714N/A bank = restrict14Bit(bank);
829N/A program = restrict7Bit(program);
829N/A synchronized (control_mutex) {
829N/A mainmixer.activity();
2713N/A if(this.bank != bank || this.program != program)
2713N/A {
2713N/A this.bank = bank;
2713N/A this.program = program;
2713N/A current_instrument = null;
2713N/A }
829N/A }
829N/A }
829N/A
829N/A public int getProgram() {
829N/A synchronized (control_mutex) {
829N/A return program;
829N/A }
829N/A }
829N/A
829N/A public void setPitchBend(int bend) {
829N/A bend = restrict14Bit(bend);
829N/A if (current_mixer != null)
829N/A current_mixer.setPitchBend(bend);
829N/A synchronized (control_mutex) {
829N/A mainmixer.activity();
829N/A co_midi_pitch[0] = bend * (1.0 / 16384.0);
829N/A pitchbend = bend;
829N/A for (int i = 0; i < voices.length; i++)
829N/A if (voices[i].active)
829N/A voices[i].setPitchBend(bend);
829N/A }
829N/A }
829N/A
829N/A public int getPitchBend() {
829N/A synchronized (control_mutex) {
829N/A return pitchbend;
829N/A }
829N/A }
829N/A
829N/A public void nrpnChange(int controller, int value) {
829N/A
829N/A /*
829N/A System.out.println("(" + channel + ").nrpnChange("
829N/A + Integer.toHexString(controller >> 7)
829N/A + " " + Integer.toHexString(controller & 127)
829N/A + ", " + Integer.toHexString(value >> 7)
829N/A + " " + Integer.toHexString(value & 127) + ")");
829N/A */
829N/A
829N/A if (synthesizer.getGeneralMidiMode() == 0) {
829N/A if (controller == (0x01 << 7) + (0x08)) // Vibrato Rate
829N/A controlChange(76, value >> 7);
829N/A if (controller == (0x01 << 7) + (0x09)) // Vibrato Depth
829N/A controlChange(77, value >> 7);
829N/A if (controller == (0x01 << 7) + (0x0A)) // Vibrato Delay
829N/A controlChange(78, value >> 7);
829N/A if (controller == (0x01 << 7) + (0x20)) // Brightness
829N/A controlChange(74, value >> 7);
829N/A if (controller == (0x01 << 7) + (0x21)) // Filter Resonance
829N/A controlChange(71, value >> 7);
829N/A if (controller == (0x01 << 7) + (0x63)) // Attack Time
829N/A controlChange(73, value >> 7);
829N/A if (controller == (0x01 << 7) + (0x64)) // Decay Time
829N/A controlChange(75, value >> 7);
829N/A if (controller == (0x01 << 7) + (0x66)) // Release Time
829N/A controlChange(72, value >> 7);
829N/A
829N/A if (controller >> 7 == 0x18) // Pitch coarse
829N/A controlChangePerNote(controller % 128, 120, value >> 7);
829N/A if (controller >> 7 == 0x1A) // Volume
829N/A controlChangePerNote(controller % 128, 7, value >> 7);
829N/A if (controller >> 7 == 0x1C) // Panpot
829N/A controlChangePerNote(controller % 128, 10, value >> 7);
829N/A if (controller >> 7 == 0x1D) // Reverb
829N/A controlChangePerNote(controller % 128, 91, value >> 7);
829N/A if (controller >> 7 == 0x1E) // Chorus
829N/A controlChangePerNote(controller % 128, 93, value >> 7);
829N/A }
829N/A
829N/A int[] val_i = co_midi_nrpn_nrpn_i.get(controller);
829N/A double[] val_d = co_midi_nrpn_nrpn.get(controller);
829N/A if (val_i == null) {
829N/A val_i = new int[1];
829N/A co_midi_nrpn_nrpn_i.put(controller, val_i);
829N/A }
829N/A if (val_d == null) {
829N/A val_d = new double[1];
829N/A co_midi_nrpn_nrpn.put(controller, val_d);
829N/A }
829N/A val_i[0] = value;
829N/A val_d[0] = val_i[0] * (1.0 / 16384.0);
829N/A
829N/A for (int i = 0; i < voices.length; i++)
829N/A if (voices[i].active)
829N/A voices[i].nrpnChange(controller, val_i[0]);
829N/A
829N/A }
829N/A
829N/A public void rpnChange(int controller, int value) {
829N/A
829N/A /*
829N/A System.out.println("(" + channel + ").rpnChange("
829N/A + Integer.toHexString(controller >> 7)
829N/A + " " + Integer.toHexString(controller & 127)
829N/A + ", " + Integer.toHexString(value >> 7)
829N/A + " " + Integer.toHexString(value & 127) + ")");
829N/A */
829N/A
829N/A if (controller == 3) {
829N/A tuning_program = (value >> 7) & 127;
829N/A tuningChange(tuning_bank, tuning_program);
829N/A }
829N/A if (controller == 4) {
829N/A tuning_bank = (value >> 7) & 127;
829N/A }
829N/A
829N/A int[] val_i = co_midi_rpn_rpn_i.get(controller);
829N/A double[] val_d = co_midi_rpn_rpn.get(controller);
829N/A if (val_i == null) {
829N/A val_i = new int[1];
829N/A co_midi_rpn_rpn_i.put(controller, val_i);
829N/A }
829N/A if (val_d == null) {
829N/A val_d = new double[1];
829N/A co_midi_rpn_rpn.put(controller, val_d);
829N/A }
829N/A val_i[0] = value;
829N/A val_d[0] = val_i[0] * (1.0 / 16384.0);
829N/A
829N/A for (int i = 0; i < voices.length; i++)
829N/A if (voices[i].active)
829N/A voices[i].rpnChange(controller, val_i[0]);
829N/A }
829N/A
829N/A public void resetAllControllers() {
829N/A resetAllControllers(false);
829N/A }
829N/A
829N/A public void resetAllControllers(boolean allControls) {
829N/A synchronized (control_mutex) {
829N/A mainmixer.activity();
829N/A
829N/A for (int i = 0; i < 128; i++) {
829N/A setPolyPressure(i, 0);
829N/A }
829N/A setChannelPressure(0);
829N/A setPitchBend(8192);
829N/A for (int i = 0; i < 128; i++) {
829N/A if (!dontResetControls[i])
829N/A controlChange(i, 0);
829N/A }
829N/A
829N/A controlChange(71, 64); // Filter Resonance
829N/A controlChange(72, 64); // Release Time
829N/A controlChange(73, 64); // Attack Time
829N/A controlChange(74, 64); // Brightness
829N/A controlChange(75, 64); // Decay Time
829N/A controlChange(76, 64); // Vibrato Rate
829N/A controlChange(77, 64); // Vibrato Depth
829N/A controlChange(78, 64); // Vibrato Delay
829N/A
829N/A controlChange(8, 64); // Balance
829N/A controlChange(11, 127); // Expression
829N/A controlChange(98, 127); // NRPN Null
829N/A controlChange(99, 127); // NRPN Null
829N/A controlChange(100, 127); // RPN = Null
829N/A controlChange(101, 127); // RPN = Null
829N/A
829N/A // see DLS 2.1 (Power-on Default Values)
829N/A if (allControls) {
829N/A
829N/A keybasedcontroller_active = null;
829N/A keybasedcontroller_value = null;
829N/A
829N/A controlChange(7, 100); // Volume
829N/A controlChange(10, 64); // Pan
829N/A controlChange(91, 40); // Reverb
829N/A
829N/A for (int controller : co_midi_rpn_rpn.keySet()) {
829N/A // don't reset tuning settings
829N/A if (controller != 3 && controller != 4)
829N/A rpnChange(controller, 0);
829N/A }
829N/A for (int controller : co_midi_nrpn_nrpn.keySet())
829N/A nrpnChange(controller, 0);
829N/A rpnChange(0, 2 << 7); // Bitch Bend sensitivity
829N/A rpnChange(1, 64 << 7); // Channel fine tunning
829N/A rpnChange(2, 64 << 7); // Channel Coarse Tuning
829N/A rpnChange(5, 64); // Modulation Depth, +/- 50 cent
829N/A
829N/A tuning_bank = 0;
829N/A tuning_program = 0;
829N/A tuning = new SoftTuning();
829N/A
829N/A }
829N/A
829N/A }
829N/A }
829N/A
829N/A public void allNotesOff() {
829N/A if (current_mixer != null)
829N/A current_mixer.allNotesOff();
829N/A synchronized (control_mutex) {
829N/A for (int i = 0; i < voices.length; i++)
829N/A if (voices[i].on && voices[i].channel == channel
829N/A && voices[i].releaseTriggered == false) {
829N/A voices[i].noteOff(0);
829N/A }
829N/A }
829N/A }
829N/A
829N/A public void allSoundOff() {
829N/A if (current_mixer != null)
829N/A current_mixer.allSoundOff();
829N/A synchronized (control_mutex) {
829N/A for (int i = 0; i < voices.length; i++)
829N/A if (voices[i].on && voices[i].channel == channel)
829N/A voices[i].soundOff();
829N/A }
829N/A }
829N/A
829N/A public boolean localControl(boolean on) {
829N/A return false;
829N/A }
829N/A
829N/A public void setMono(boolean on) {
829N/A if (current_mixer != null)
829N/A current_mixer.setMono(on);
829N/A synchronized (control_mutex) {
829N/A allNotesOff();
829N/A mono = on;
829N/A }
829N/A }
829N/A
829N/A public boolean getMono() {
829N/A synchronized (control_mutex) {
829N/A return mono;
829N/A }
829N/A }
829N/A
829N/A public void setOmni(boolean on) {
829N/A if (current_mixer != null)
829N/A current_mixer.setOmni(on);
829N/A allNotesOff();
829N/A // Omni is not supported by GM2
829N/A }
829N/A
829N/A public boolean getOmni() {
829N/A return false;
829N/A }
829N/A
829N/A public void setMute(boolean mute) {
829N/A if (current_mixer != null)
829N/A current_mixer.setMute(mute);
829N/A synchronized (control_mutex) {
829N/A this.mute = mute;
829N/A for (int i = 0; i < voices.length; i++)
829N/A if (voices[i].active && voices[i].channel == channel)
829N/A voices[i].setMute(mute);
829N/A }
829N/A }
829N/A
829N/A public boolean getMute() {
829N/A synchronized (control_mutex) {
829N/A return mute;
829N/A }
829N/A }
829N/A
829N/A public void setSolo(boolean soloState) {
829N/A if (current_mixer != null)
829N/A current_mixer.setSolo(soloState);
829N/A
829N/A synchronized (control_mutex) {
829N/A this.solo = soloState;
829N/A
829N/A boolean soloinuse = false;
829N/A for (SoftChannel c : synthesizer.channels) {
829N/A if (c.solo) {
829N/A soloinuse = true;
829N/A break;
829N/A }
829N/A }
829N/A
829N/A if (!soloinuse) {
829N/A for (SoftChannel c : synthesizer.channels)
829N/A c.setSoloMute(false);
829N/A return;
829N/A }
829N/A
829N/A for (SoftChannel c : synthesizer.channels)
829N/A c.setSoloMute(!c.solo);
829N/A
829N/A }
829N/A
829N/A }
829N/A
829N/A private void setSoloMute(boolean mute) {
829N/A synchronized (control_mutex) {
829N/A if (solomute == mute)
829N/A return;
829N/A this.solomute = mute;
829N/A for (int i = 0; i < voices.length; i++)
829N/A if (voices[i].active && voices[i].channel == channel)
829N/A voices[i].setSoloMute(solomute);
829N/A }
829N/A }
829N/A
829N/A public boolean getSolo() {
829N/A synchronized (control_mutex) {
829N/A return solo;
829N/A }
829N/A }
829N/A}