alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (SoftChannel.java)

This example Java source code file (SoftChannel.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

audio, controller, depth, effects, map, midi, modelconnectionblock, modeldestination, modelsource, msb, rpn_null_value, softchannel, softcontrol, sound, time, util, vibrato

The SoftChannel.java Java example source code

/*
 * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
package com.sun.media.sound;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.sound.midi.MidiChannel;
import javax.sound.midi.Patch;

/**
 * Software Synthesizer MIDI channel class.
 *
 * @author Karl Helgason
 */
public final class SoftChannel implements MidiChannel, ModelDirectedPlayer {

    private static boolean[] dontResetControls = new boolean[128];
    static {
        for (int i = 0; i < dontResetControls.length; i++)
            dontResetControls[i] = false;

        dontResetControls[0] = true;   // Bank Select (MSB)
        dontResetControls[32] = true;  // Bank Select (LSB)
        dontResetControls[7] = true;   // Channel Volume (MSB)
        dontResetControls[8] = true;   // Balance (MSB)
        dontResetControls[10] = true;  // Pan (MSB)
        dontResetControls[11] = true;  // Expression (MSB)
        dontResetControls[91] = true;  // Effects 1 Depth (default: Reverb Send)
        dontResetControls[92] = true;  // Effects 2 Depth (default: Tremolo Depth)
        dontResetControls[93] = true;  // Effects 3 Depth (default: Chorus Send)
        dontResetControls[94] = true;  // Effects 4 Depth (default: Celeste [Detune] Depth)
        dontResetControls[95] = true;  // Effects 5 Depth (default: Phaser Depth)
        dontResetControls[70] = true;  // Sound Controller 1 (default: Sound Variation)
        dontResetControls[71] = true;  // Sound Controller 2 (default: Timbre / Harmonic Quality)
        dontResetControls[72] = true;  // Sound Controller 3 (default: Release Time)
        dontResetControls[73] = true;  // Sound Controller 4 (default: Attack Time)
        dontResetControls[74] = true;  // Sound Controller 5 (default: Brightness)
        dontResetControls[75] = true;  // Sound Controller 6 (GM2 default: Decay Time)
        dontResetControls[76] = true;  // Sound Controller 7 (GM2 default: Vibrato Rate)
        dontResetControls[77] = true;  // Sound Controller 8 (GM2 default: Vibrato Depth)
        dontResetControls[78] = true;  // Sound Controller 9 (GM2 default: Vibrato Delay)
        dontResetControls[79] = true;  // Sound Controller 10 (GM2 default: Undefined)
        dontResetControls[120] = true; // All Sound Off
        dontResetControls[121] = true; // Reset All Controllers
        dontResetControls[122] = true; // Local Control On/Off
        dontResetControls[123] = true; // All Notes Off
        dontResetControls[124] = true; // Omni Mode Off
        dontResetControls[125] = true; // Omni Mode On
        dontResetControls[126] = true; // Poly Mode Off
        dontResetControls[127] = true; // Poly Mode On

        dontResetControls[6] = true;   // Data Entry (MSB)
        dontResetControls[38] = true;  // Data Entry (LSB)
        dontResetControls[96] = true;  // Data Increment
        dontResetControls[97] = true;  // Data Decrement
        dontResetControls[98] = true;  // Non-Registered Parameter Number (LSB)
        dontResetControls[99] = true;  // Non-Registered Parameter Number(MSB)
        dontResetControls[100] = true; // RPN = Null
        dontResetControls[101] = true; // RPN = Null

    }

    private static final int RPN_NULL_VALUE = (127 << 7) + 127;
    private int rpn_control = RPN_NULL_VALUE;
    private int nrpn_control = RPN_NULL_VALUE;
    double portamento_time = 1; // keyschanges per control buffer time
    int[] portamento_lastnote = new int[128];
    int portamento_lastnote_ix = 0;
    private boolean portamento = false;
    private boolean mono = false;
    private boolean mute = false;
    private boolean solo = false;
    private boolean solomute = false;
    private final Object control_mutex;
    private int channel;
    private SoftVoice[] voices;
    private int bank;
    private int program;
    private SoftSynthesizer synthesizer;
    private SoftMainMixer mainmixer;
    private int[] polypressure = new int[128];
    private int channelpressure = 0;
    private int[] controller = new int[128];
    private int pitchbend;
    private double[] co_midi_pitch = new double[1];
    private double[] co_midi_channel_pressure = new double[1];
    SoftTuning tuning = new SoftTuning();
    int tuning_bank = 0;
    int tuning_program = 0;
    SoftInstrument current_instrument = null;
    ModelChannelMixer current_mixer = null;
    ModelDirector current_director = null;

    // Controller Destination Settings
    int cds_control_number = -1;
    ModelConnectionBlock[] cds_control_connections = null;
    ModelConnectionBlock[] cds_channelpressure_connections = null;
    ModelConnectionBlock[] cds_polypressure_connections = null;
    boolean sustain = false;
    boolean[][] keybasedcontroller_active = null;
    double[][] keybasedcontroller_value = null;

    private class MidiControlObject implements SoftControl {
        double[] pitch = co_midi_pitch;
        double[] channel_pressure = co_midi_channel_pressure;
        double[] poly_pressure = new double[1];

        public double[] get(int instance, String name) {
            if (name == null)
                return null;
            if (name.equals("pitch"))
                return pitch;
            if (name.equals("channel_pressure"))
                return channel_pressure;
            if (name.equals("poly_pressure"))
                return poly_pressure;
            return null;
        }
    }

    private SoftControl[] co_midi = new SoftControl[128];
    {
        for (int i = 0; i < co_midi.length; i++) {
            co_midi[i] = new MidiControlObject();
        }
    }

    private double[][] co_midi_cc_cc = new double[128][1];
    private SoftControl co_midi_cc = new SoftControl() {
        double[][] cc = co_midi_cc_cc;
        public double[] get(int instance, String name) {
            if (name == null)
                return null;
            return cc[Integer.parseInt(name)];
        }
    };
    Map<Integer, int[]> co_midi_rpn_rpn_i = new HashMap();
    Map<Integer, double[]> co_midi_rpn_rpn = new HashMap();
    private SoftControl co_midi_rpn = new SoftControl() {
        Map<Integer, double[]> rpn = co_midi_rpn_rpn;
        public double[] get(int instance, String name) {
            if (name == null)
                return null;
            int iname = Integer.parseInt(name);
            double[] v = rpn.get(iname);
            if (v == null) {
                v = new double[1];
                rpn.put(iname, v);
            }
            return v;
        }
    };
    Map<Integer, int[]> co_midi_nrpn_nrpn_i = new HashMap();
    Map<Integer, double[]> co_midi_nrpn_nrpn = new HashMap();
    private SoftControl co_midi_nrpn = new SoftControl() {
        Map<Integer, double[]> nrpn = co_midi_nrpn_nrpn;
        public double[] get(int instance, String name) {
            if (name == null)
                return null;
            int iname = Integer.parseInt(name);
            double[] v = nrpn.get(iname);
            if (v == null) {
                v = new double[1];
                nrpn.put(iname, v);
            }
            return v;
        }
    };

    private static int restrict7Bit(int value)
    {
        if(value < 0) return 0;
        if(value > 127) return 127;
        return value;
    }

    private static int restrict14Bit(int value)
    {
        if(value < 0) return 0;
        if(value > 16256) return 16256;
        return value;
    }

    public SoftChannel(SoftSynthesizer synth, int channel) {
        this.channel = channel;
        this.voices = synth.getVoices();
        this.synthesizer = synth;
        this.mainmixer = synth.getMainMixer();
        control_mutex = synth.control_mutex;
        resetAllControllers(true);
    }

    private int findFreeVoice(int x) {
        if(x == -1)
        {
            // x = -1 means that there where no available voice
            // last time we called findFreeVoice
            // and it hasn't changed because no audio has been
            // rendered in the meantime.
            // Therefore we have to return -1.
            return -1;
        }
        for (int i = x; i < voices.length; i++)
            if (!voices[i].active)
                return i;

        // No free voice was found, we must steal one

        int vmode = synthesizer.getVoiceAllocationMode();
        if (vmode == 1) {
            // DLS Static Voice Allocation

            //  * priority ( 10, 1-9, 11-16)
            // Search for channel to steal from
            int steal_channel = channel;
            for (int j = 0; j < voices.length; j++) {
                if (voices[j].stealer_channel == null) {
                    if (steal_channel == 9) {
                        steal_channel = voices[j].channel;
                    } else {
                        if (voices[j].channel != 9) {
                            if (voices[j].channel > steal_channel)
                                steal_channel = voices[j].channel;
                        }
                    }
                }
            }

            int voiceNo = -1;

            SoftVoice v = null;
            // Search for oldest voice in off state on steal_channel
            for (int j = 0; j < voices.length; j++) {
                if (voices[j].channel == steal_channel) {
                    if (voices[j].stealer_channel == null && !voices[j].on) {
                        if (v == null) {
                            v = voices[j];
                            voiceNo = j;
                        }
                        if (voices[j].voiceID < v.voiceID) {
                            v = voices[j];
                            voiceNo = j;
                        }
                    }
                }
            }
            // Search for oldest voice in on state on steal_channel
            if (voiceNo == -1) {
                for (int j = 0; j < voices.length; j++) {
                    if (voices[j].channel == steal_channel) {
                        if (voices[j].stealer_channel == null) {
                            if (v == null) {
                                v = voices[j];
                                voiceNo = j;
                            }
                            if (voices[j].voiceID < v.voiceID) {
                                v = voices[j];
                                voiceNo = j;
                            }
                        }
                    }
                }
            }

            return voiceNo;

        } else {
            // Default Voice Allocation
            //  * Find voice that is on
            //    and Find voice which has lowest voiceID ( oldest voice)
            //  * Or find voice that is off
            //    and Find voice which has lowest voiceID ( oldest voice)

            int voiceNo = -1;

            SoftVoice v = null;
            // Search for oldest voice in off state
            for (int j = 0; j < voices.length; j++) {
                if (voices[j].stealer_channel == null && !voices[j].on) {
                    if (v == null) {
                        v = voices[j];
                        voiceNo = j;
                    }
                    if (voices[j].voiceID < v.voiceID) {
                        v = voices[j];
                        voiceNo = j;
                    }
                }
            }
            // Search for oldest voice in on state
            if (voiceNo == -1) {

                for (int j = 0; j < voices.length; j++) {
                    if (voices[j].stealer_channel == null) {
                        if (v == null) {
                            v = voices[j];
                            voiceNo = j;
                        }
                        if (voices[j].voiceID < v.voiceID) {
                            v = voices[j];
                            voiceNo = j;
                        }
                    }
                }
            }

            return voiceNo;
        }

    }

    void initVoice(SoftVoice voice, SoftPerformer p, int voiceID,
            int noteNumber, int velocity, int delay, ModelConnectionBlock[] connectionBlocks,
            ModelChannelMixer channelmixer, boolean releaseTriggered) {
        if (voice.active) {
            // Voice is active , we must steal the voice
            voice.stealer_channel = this;
            voice.stealer_performer = p;
            voice.stealer_voiceID = voiceID;
            voice.stealer_noteNumber = noteNumber;
            voice.stealer_velocity = velocity;
            voice.stealer_extendedConnectionBlocks = connectionBlocks;
            voice.stealer_channelmixer = channelmixer;
            voice.stealer_releaseTriggered = releaseTriggered;
            for (int i = 0; i < voices.length; i++)
                if (voices[i].active && voices[i].voiceID == voice.voiceID)
                    voices[i].soundOff();
            return;
        }

        voice.extendedConnectionBlocks = connectionBlocks;
        voice.channelmixer = channelmixer;
        voice.releaseTriggered = releaseTriggered;
        voice.voiceID = voiceID;
        voice.tuning = tuning;
        voice.exclusiveClass = p.exclusiveClass;
        voice.softchannel = this;
        voice.channel = channel;
        voice.bank = bank;
        voice.program = program;
        voice.instrument = current_instrument;
        voice.performer = p;
        voice.objects.clear();
        voice.objects.put("midi", co_midi[noteNumber]);
        voice.objects.put("midi_cc", co_midi_cc);
        voice.objects.put("midi_rpn", co_midi_rpn);
        voice.objects.put("midi_nrpn", co_midi_nrpn);
        voice.noteOn(noteNumber, velocity, delay);
        voice.setMute(mute);
        voice.setSoloMute(solomute);
        if (releaseTriggered)
            return;
        if (controller[84] != 0) {
            voice.co_noteon_keynumber[0]
                    = (tuning.getTuning(controller[84]) / 100.0)
                    * (1f / 128f);
            voice.portamento = true;
            controlChange(84, 0);
        } else if (portamento) {
            if (mono) {
                if (portamento_lastnote[0] != -1) {
                    voice.co_noteon_keynumber[0]
                            = (tuning.getTuning(portamento_lastnote[0]) / 100.0)
                            * (1f / 128f);
                    voice.portamento = true;
                    controlChange(84, 0);
                }
                portamento_lastnote[0] = noteNumber;
            } else {
                if (portamento_lastnote_ix != 0) {
                    portamento_lastnote_ix--;
                    voice.co_noteon_keynumber[0]
                            = (tuning.getTuning(
                                    portamento_lastnote[portamento_lastnote_ix])
                                / 100.0)
                            * (1f / 128f);
                    voice.portamento = true;
                }
            }
        }
    }

    public void noteOn(int noteNumber, int velocity) {
        noteOn(noteNumber, velocity, 0);
    }

    /* A special noteOn with delay parameter, which is used to
     * start note within control buffers.
     */
    void noteOn(int noteNumber, int velocity, int delay) {
        noteNumber = restrict7Bit(noteNumber);
        velocity = restrict7Bit(velocity);
        noteOn_internal(noteNumber, velocity, delay);
        if (current_mixer != null)
            current_mixer.noteOn(noteNumber, velocity);
    }

    private void noteOn_internal(int noteNumber, int velocity, int delay) {

        if (velocity == 0) {
            noteOff_internal(noteNumber, 64);
            return;
        }

        synchronized (control_mutex) {
            if (sustain) {
                sustain = false;
                for (int i = 0; i < voices.length; i++) {
                    if ((voices[i].sustain || voices[i].on)
                            && voices[i].channel == channel && voices[i].active
                            && voices[i].note == noteNumber) {
                        voices[i].sustain = false;
                        voices[i].on = true;
                        voices[i].noteOff(0);
                    }
                }
                sustain = true;
            }

            mainmixer.activity();

            if (mono) {
                if (portamento) {
                    boolean n_found = false;
                    for (int i = 0; i < voices.length; i++) {
                        if (voices[i].on && voices[i].channel == channel
                                && voices[i].active
                                && voices[i].releaseTriggered == false) {
                            voices[i].portamento = true;
                            voices[i].setNote(noteNumber);
                            n_found = true;
                        }
                    }
                    if (n_found) {
                        portamento_lastnote[0] = noteNumber;
                        return;
                    }
                }

                if (controller[84] != 0) {
                    boolean n_found = false;
                    for (int i = 0; i < voices.length; i++) {
                        if (voices[i].on && voices[i].channel == channel
                                && voices[i].active
                                && voices[i].note == controller[84]
                                && voices[i].releaseTriggered == false) {
                            voices[i].portamento = true;
                            voices[i].setNote(noteNumber);
                            n_found = true;
                        }
                    }
                    controlChange(84, 0);
                    if (n_found)
                        return;
                }
            }

            if (mono)
                allNotesOff();

            if (current_instrument == null) {
                current_instrument
                        = synthesizer.findInstrument(program, bank, channel);
                if (current_instrument == null)
                    return;
                if (current_mixer != null)
                    mainmixer.stopMixer(current_mixer);
                current_mixer = current_instrument.getSourceInstrument()
                        .getChannelMixer(this, synthesizer.getFormat());
                if (current_mixer != null)
                    mainmixer.registerMixer(current_mixer);
                current_director = current_instrument.getDirector(this, this);
                applyInstrumentCustomization();
            }
            prevVoiceID = synthesizer.voiceIDCounter++;
            firstVoice = true;
            voiceNo = 0;

            int tunedKey = (int)(Math.round(tuning.getTuning(noteNumber)/100.0));
            play_noteNumber = noteNumber;
            play_velocity = velocity;
            play_delay = delay;
            play_releasetriggered = false;
            lastVelocity[noteNumber] = velocity;
            current_director.noteOn(tunedKey, velocity);

            /*
            SoftPerformer[] performers = current_instrument.getPerformers();
            for (int i = 0; i < performers.length; i++) {
                SoftPerformer p = performers[i];
                if (p.keyFrom <= tunedKey && p.keyTo >= tunedKey) {
                    if (p.velFrom <= velocity && p.velTo >= velocity) {
                        if (firstVoice) {
                            firstVoice = false;
                            if (p.exclusiveClass != 0) {
                                int x = p.exclusiveClass;
                                for (int j = 0; j < voices.length; j++) {
                                    if (voices[j].active
                                            && voices[j].channel == channel
                                            && voices[j].exclusiveClass == x) {
                                        if (!(p.selfNonExclusive
                                                && voices[j].note == noteNumber))
                                            voices[j].shutdown();
                                    }
                                }
                            }
                        }
                        voiceNo = findFreeVoice(voiceNo);
                        if (voiceNo == -1)
                            return;
                        initVoice(voices[voiceNo], p, prevVoiceID, noteNumber,
                                velocity);
                    }
                }
            }
            */
        }
    }

    public void noteOff(int noteNumber, int velocity) {
        noteNumber = restrict7Bit(noteNumber);
        velocity = restrict7Bit(velocity);
        noteOff_internal(noteNumber, velocity);

        if (current_mixer != null)
            current_mixer.noteOff(noteNumber, velocity);
    }

    private void noteOff_internal(int noteNumber, int velocity) {
        synchronized (control_mutex) {

            if (!mono) {
                if (portamento) {
                    if (portamento_lastnote_ix != 127) {
                        portamento_lastnote[portamento_lastnote_ix] = noteNumber;
                        portamento_lastnote_ix++;
                    }
                }
            }

            mainmixer.activity();
            for (int i = 0; i < voices.length; i++) {
                if (voices[i].on && voices[i].channel == channel
                        && voices[i].note == noteNumber
                        && voices[i].releaseTriggered == false) {
                    voices[i].noteOff(velocity);
                }
                // We must also check stolen voices
                if (voices[i].stealer_channel == this && voices[i].stealer_noteNumber == noteNumber) {
                    SoftVoice v = voices[i];
                    v.stealer_releaseTriggered = false;
                    v.stealer_channel = null;
                    v.stealer_performer = null;
                    v.stealer_voiceID = -1;
                    v.stealer_noteNumber = 0;
                    v.stealer_velocity = 0;
                    v.stealer_extendedConnectionBlocks = null;
                    v.stealer_channelmixer = null;
                }
            }

            // Try play back note-off triggered voices,

            if (current_instrument == null) {
                current_instrument
                        = synthesizer.findInstrument(program, bank, channel);
                if (current_instrument == null)
                    return;
                if (current_mixer != null)
                    mainmixer.stopMixer(current_mixer);
                current_mixer = current_instrument.getSourceInstrument()
                        .getChannelMixer(this, synthesizer.getFormat());
                if (current_mixer != null)
                    mainmixer.registerMixer(current_mixer);
                current_director = current_instrument.getDirector(this, this);
                applyInstrumentCustomization();

            }
            prevVoiceID = synthesizer.voiceIDCounter++;
            firstVoice = true;
            voiceNo = 0;

            int tunedKey = (int)(Math.round(tuning.getTuning(noteNumber)/100.0));
            play_noteNumber = noteNumber;
            play_velocity = lastVelocity[noteNumber];
            play_releasetriggered = true;
            play_delay = 0;
            current_director.noteOff(tunedKey, velocity);

        }
    }
    private int[] lastVelocity = new int[128];
    private int prevVoiceID;
    private boolean firstVoice = true;
    private int voiceNo = 0;
    private int play_noteNumber = 0;
    private int play_velocity = 0;
    private int play_delay = 0;
    private boolean play_releasetriggered = false;

    public void play(int performerIndex, ModelConnectionBlock[] connectionBlocks) {

        int noteNumber = play_noteNumber;
        int velocity = play_velocity;
        int delay = play_delay;
        boolean releasetriggered = play_releasetriggered;

        SoftPerformer p = current_instrument.getPerformer(performerIndex);

        if (firstVoice) {
            firstVoice = false;
            if (p.exclusiveClass != 0) {
                int x = p.exclusiveClass;
                for (int j = 0; j < voices.length; j++) {
                    if (voices[j].active && voices[j].channel == channel
                            && voices[j].exclusiveClass == x) {
                        if (!(p.selfNonExclusive && voices[j].note == noteNumber))
                            voices[j].shutdown();
                    }
                }
            }
        }

        voiceNo = findFreeVoice(voiceNo);

        if (voiceNo == -1)
            return;

        initVoice(voices[voiceNo], p, prevVoiceID, noteNumber, velocity, delay,
                connectionBlocks, current_mixer, releasetriggered);
    }

    public void noteOff(int noteNumber) {
        if(noteNumber < 0 || noteNumber > 127) return;
        noteOff_internal(noteNumber, 64);
    }

    public void setPolyPressure(int noteNumber, int pressure) {
        noteNumber = restrict7Bit(noteNumber);
        pressure = restrict7Bit(pressure);

        if (current_mixer != null)
            current_mixer.setPolyPressure(noteNumber, pressure);

        synchronized (control_mutex) {
            mainmixer.activity();
            co_midi[noteNumber].get(0, "poly_pressure")[0] = pressure*(1.0/128.0);
            polypressure[noteNumber] = pressure;
            for (int i = 0; i < voices.length; i++) {
                if (voices[i].active && voices[i].note == noteNumber)
                    voices[i].setPolyPressure(pressure);
            }
        }
    }

    public int getPolyPressure(int noteNumber) {
        synchronized (control_mutex) {
            return polypressure[noteNumber];
        }
    }

    public void setChannelPressure(int pressure) {
        pressure = restrict7Bit(pressure);
        if (current_mixer != null)
            current_mixer.setChannelPressure(pressure);
        synchronized (control_mutex) {
            mainmixer.activity();
            co_midi_channel_pressure[0] = pressure * (1.0 / 128.0);
            channelpressure = pressure;
            for (int i = 0; i < voices.length; i++) {
                if (voices[i].active)
                    voices[i].setChannelPressure(pressure);
            }
        }
    }

    public int getChannelPressure() {
        synchronized (control_mutex) {
            return channelpressure;
        }
    }

    void applyInstrumentCustomization() {
        if (cds_control_connections == null
                && cds_channelpressure_connections == null
                && cds_polypressure_connections == null) {
            return;
        }

        ModelInstrument src_instrument = current_instrument.getSourceInstrument();
        ModelPerformer[] performers = src_instrument.getPerformers();
        ModelPerformer[] new_performers = new ModelPerformer[performers.length];
        for (int i = 0; i < new_performers.length; i++) {
            ModelPerformer performer = performers[i];
            ModelPerformer new_performer = new ModelPerformer();
            new_performer.setName(performer.getName());
            new_performer.setExclusiveClass(performer.getExclusiveClass());
            new_performer.setKeyFrom(performer.getKeyFrom());
            new_performer.setKeyTo(performer.getKeyTo());
            new_performer.setVelFrom(performer.getVelFrom());
            new_performer.setVelTo(performer.getVelTo());
            new_performer.getOscillators().addAll(performer.getOscillators());
            new_performer.getConnectionBlocks().addAll(
                    performer.getConnectionBlocks());
            new_performers[i] = new_performer;

            List<ModelConnectionBlock> connblocks =
                    new_performer.getConnectionBlocks();

            if (cds_control_connections != null) {
                String cc = Integer.toString(cds_control_number);
                Iterator<ModelConnectionBlock> iter = connblocks.iterator();
                while (iter.hasNext()) {
                    ModelConnectionBlock conn = iter.next();
                    ModelSource[] sources = conn.getSources();
                    boolean removeok = false;
                    if (sources != null) {
                        for (int j = 0; j < sources.length; j++) {
                            ModelSource src = sources[j];
                            if ("midi_cc".equals(src.getIdentifier().getObject())
                                    && cc.equals(src.getIdentifier().getVariable())) {
                                removeok = true;
                            }
                        }
                    }
                    if (removeok)
                        iter.remove();
                }
                for (int j = 0; j < cds_control_connections.length; j++)
                    connblocks.add(cds_control_connections[j]);
            }

            if (cds_polypressure_connections != null) {
                Iterator<ModelConnectionBlock> iter = connblocks.iterator();
                while (iter.hasNext()) {
                    ModelConnectionBlock conn = iter.next();
                    ModelSource[] sources = conn.getSources();
                    boolean removeok = false;
                    if (sources != null) {
                        for (int j = 0; j < sources.length; j++) {
                            ModelSource src = sources[j];
                            if ("midi".equals(src.getIdentifier().getObject())
                                    && "poly_pressure".equals(
                                        src.getIdentifier().getVariable())) {
                                removeok = true;
                            }
                        }
                    }
                    if (removeok)
                        iter.remove();
                }
                for (int j = 0; j < cds_polypressure_connections.length; j++)
                    connblocks.add(cds_polypressure_connections[j]);
            }


            if (cds_channelpressure_connections != null) {
                Iterator<ModelConnectionBlock> iter = connblocks.iterator();
                while (iter.hasNext()) {
                    ModelConnectionBlock conn = iter.next();
                    ModelSource[] sources = conn.getSources();
                    boolean removeok = false;
                    if (sources != null) {
                        for (int j = 0; j < sources.length; j++) {
                            ModelIdentifier srcid = sources[j].getIdentifier();
                            if ("midi".equals(srcid.getObject()) &&
                                    "channel_pressure".equals(srcid.getVariable())) {
                                removeok = true;
                            }
                        }
                    }
                    if (removeok)
                        iter.remove();
                }
                for (int j = 0; j < cds_channelpressure_connections.length; j++)
                    connblocks.add(cds_channelpressure_connections[j]);
            }

        }

        current_instrument = new SoftInstrument(src_instrument, new_performers);

    }

    private ModelConnectionBlock[] createModelConnections(ModelIdentifier sid,
            int[] destination, int[] range) {

        /*
        controlled parameter (pp)|range (rr)| Description             |Default
        -------------------------|----------|-------------------------|-------
        00 Pitch Control         | 28H..58H | -24..+24 semitones      | 40H
        01 Filter Cutoff Control | 00H..7FH | -9600..+9450 cents      | 40H
        02 Amplitude Control     | 00H..7FH | 0..(127/64)*100 percent | 40H
        03 LFO Pitch Depth       | 00H..7FH | 0..600 cents            |  0
        04 LFO Filter Depth      | 00H..7FH | 0..2400 cents           |  0
        05 LFO Amplitude Depth   | 00H..7FH | 0..100 percent          |  0
        */

        List<ModelConnectionBlock> conns = new ArrayList();

        for (int i = 0; i < destination.length; i++) {
            int d = destination[i];
            int r = range[i];
            if (d == 0) {
                double scale = (r - 64) * 100;
                ModelConnectionBlock conn = new ModelConnectionBlock(
                        new ModelSource(sid,
                            ModelStandardTransform.DIRECTION_MIN2MAX,
                            ModelStandardTransform.POLARITY_UNIPOLAR,
                            ModelStandardTransform.TRANSFORM_LINEAR),
                        scale,
                        new ModelDestination(
                            new ModelIdentifier("osc", "pitch")));
                conns.add(conn);

            }
            if (d == 1) {
                double scale = (r / 64.0 - 1.0) * 9600.0;
                ModelConnectionBlock conn;
                if (scale > 0) {
                    conn = new ModelConnectionBlock(
                            new ModelSource(sid,
                                ModelStandardTransform.DIRECTION_MAX2MIN,
                                ModelStandardTransform.POLARITY_UNIPOLAR,
                                ModelStandardTransform.TRANSFORM_LINEAR),
                            -scale,
                            new ModelDestination(
                                ModelDestination.DESTINATION_FILTER_FREQ));
                } else {
                    conn = new ModelConnectionBlock(
                            new ModelSource(sid,
                                ModelStandardTransform.DIRECTION_MIN2MAX,
                                ModelStandardTransform.POLARITY_UNIPOLAR,
                                ModelStandardTransform.TRANSFORM_LINEAR),
                            scale,
                            new ModelDestination(
                                ModelDestination.DESTINATION_FILTER_FREQ));
                }
                conns.add(conn);
            }
            if (d == 2) {
                final double scale = (r / 64.0);
                ModelTransform mt = new ModelTransform() {
                    double s = scale;
                    public double transform(double value) {
                        if (s < 1)
                            value = s + (value * (1.0 - s));
                        else if (s > 1)
                            value = 1 + (value * (s - 1.0));
                        else
                            return 0;
                        return -((5.0 / 12.0) / Math.log(10)) * Math.log(value);
                    }
                };

                ModelConnectionBlock conn = new ModelConnectionBlock(
                        new ModelSource(sid, mt), -960,
                        new ModelDestination(ModelDestination.DESTINATION_GAIN));
                conns.add(conn);

            }
            if (d == 3) {
                double scale = (r / 64.0 - 1.0) * 9600.0;
                ModelConnectionBlock conn = new ModelConnectionBlock(
                        new ModelSource(ModelSource.SOURCE_LFO1,
                            ModelStandardTransform.DIRECTION_MIN2MAX,
                            ModelStandardTransform.POLARITY_BIPOLAR,
                            ModelStandardTransform.TRANSFORM_LINEAR),
                        new ModelSource(sid,
                            ModelStandardTransform.DIRECTION_MIN2MAX,
                            ModelStandardTransform.POLARITY_UNIPOLAR,
                            ModelStandardTransform.TRANSFORM_LINEAR),
                        scale,
                        new ModelDestination(
                            ModelDestination.DESTINATION_PITCH));
                conns.add(conn);
            }
            if (d == 4) {
                double scale = (r / 128.0) * 2400.0;
                ModelConnectionBlock conn = new ModelConnectionBlock(
                        new ModelSource(ModelSource.SOURCE_LFO1,
                            ModelStandardTransform.DIRECTION_MIN2MAX,
                            ModelStandardTransform.POLARITY_BIPOLAR,
                            ModelStandardTransform.TRANSFORM_LINEAR),
                        new ModelSource(sid,
                            ModelStandardTransform.DIRECTION_MIN2MAX,
                            ModelStandardTransform.POLARITY_UNIPOLAR,
                            ModelStandardTransform.TRANSFORM_LINEAR),
                        scale,
                        new ModelDestination(
                            ModelDestination.DESTINATION_FILTER_FREQ));
                conns.add(conn);
            }
            if (d == 5) {
                final double scale = (r / 127.0);

                ModelTransform mt = new ModelTransform() {
                    double s = scale;
                    public double transform(double value) {
                        return -((5.0 / 12.0) / Math.log(10))
                                * Math.log(1 - value * s);
                    }
                };

                ModelConnectionBlock conn = new ModelConnectionBlock(
                        new ModelSource(ModelSource.SOURCE_LFO1,
                            ModelStandardTransform.DIRECTION_MIN2MAX,
                            ModelStandardTransform.POLARITY_UNIPOLAR,
                            ModelStandardTransform.TRANSFORM_LINEAR),
                        new ModelSource(sid, mt),
                        -960,
                        new ModelDestination(
                            ModelDestination.DESTINATION_GAIN));
                conns.add(conn);
            }
        }

        return conns.toArray(new ModelConnectionBlock[conns.size()]);
    }

    public void mapPolyPressureToDestination(int[] destination, int[] range) {
        current_instrument = null;
        if (destination.length == 0) {
            cds_polypressure_connections = null;
            return;
        }
        cds_polypressure_connections
                = createModelConnections(
                    new ModelIdentifier("midi", "poly_pressure"),
                    destination, range);
    }

    public void mapChannelPressureToDestination(int[] destination, int[] range) {
        current_instrument = null;
        if (destination.length == 0) {
            cds_channelpressure_connections = null;
            return;
        }
        cds_channelpressure_connections
                = createModelConnections(
                    new ModelIdentifier("midi", "channel_pressure"),
                    destination, range);
    }

    public void mapControlToDestination(int control, int[] destination, int[] range) {

        if (!((control >= 0x01 && control <= 0x1F)
                || (control >= 0x40 && control <= 0x5F))) {
            cds_control_connections = null;
            return;
        }

        current_instrument = null;
        cds_control_number = control;
        if (destination.length == 0) {
            cds_control_connections = null;
            return;
        }
        cds_control_connections
                = createModelConnections(
                    new ModelIdentifier("midi_cc", Integer.toString(control)),
                    destination, range);
    }

    public void controlChangePerNote(int noteNumber, int controller, int value) {

/*
 CC# | nn   | Name                    | vv             | default    | description
-----|------|-------------------------|----------------|------------|-------------------------------
7    |07H   |Note Volume              |00H-40H-7FH     |40H         |0-100-(127/64)*100(%)(Relative)
10   |0AH   |*Pan                     |00H-7FH absolute|Preset Value|Left-Center-Right (absolute)
33-63|21-3FH|LSB for                  |01H-1FH         |            |
71   |47H   |Timbre/Harmonic Intensity|00H-40H-7FH     |40H (???)   |
72   |48H   |Release Time             |00H-40H-7FH     |40H (???)   |
73   |49H   |Attack Time              |00H-40H-7FH     |40H (???)   |
74   |4AH   |Brightness               |00H-40H-7FH     |40H (???)   |
75   |4BH   |Decay Time               |00H-40H-7FH     |40H (???)   |
76   |4CH   |Vibrato Rate             |00H-40H-7FH     |40H (???)   |
77   |4DH   |Vibrato Depth            |00H-40H-7FH     |40H (???)   |
78   |4EH   |Vibrato Delay            |00H-40H-7FH     |40H (???)   |
91   |5BH   |*Reverb Send             |00H-7FH absolute|Preset Value|Left-Center-Right (absolute)
93   |5DH   |*Chorus Send             |00H-7FH absolute|Preset Value|Left-Center-Right (absolute)
120  |78H   |**Fine Tuning            |00H-40H-7FH     |40H (???)   |
121  |79H   |**Coarse Tuning          |00H-40H-7FH     |40H (???)   |
*/

        if (keybasedcontroller_active == null) {
            keybasedcontroller_active = new boolean[128][];
            keybasedcontroller_value = new double[128][];
        }
        if (keybasedcontroller_active[noteNumber] == null) {
            keybasedcontroller_active[noteNumber] = new boolean[128];
            Arrays.fill(keybasedcontroller_active[noteNumber], false);
            keybasedcontroller_value[noteNumber] = new double[128];
            Arrays.fill(keybasedcontroller_value[noteNumber], 0);
        }

        if (value == -1) {
            keybasedcontroller_active[noteNumber][controller] = false;
        } else {
            keybasedcontroller_active[noteNumber][controller] = true;
            keybasedcontroller_value[noteNumber][controller] = value / 128.0;
        }

        if (controller < 120) {
            for (int i = 0; i < voices.length; i++)
                if (voices[i].active)
                    voices[i].controlChange(controller, -1);
        } else if (controller == 120) {
            for (int i = 0; i < voices.length; i++)
                if (voices[i].active)
                    voices[i].rpnChange(1, -1);
        } else if (controller == 121) {
            for (int i = 0; i < voices.length; i++)
                if (voices[i].active)
                    voices[i].rpnChange(2, -1);
        }

    }

    public int getControlPerNote(int noteNumber, int controller) {
        if (keybasedcontroller_active == null)
            return -1;
        if (keybasedcontroller_active[noteNumber] == null)
            return -1;
        if (!keybasedcontroller_active[noteNumber][controller])
            return -1;
        return (int)(keybasedcontroller_value[noteNumber][controller] * 128);
    }

    public void controlChange(int controller, int value) {
        controller = restrict7Bit(controller);
        value = restrict7Bit(value);
        if (current_mixer != null)
            current_mixer.controlChange(controller, value);

        synchronized (control_mutex) {
            switch (controller) {
            /*
            Map<String, int[]>co_midi_rpn_rpn_i = new HashMap();
            Map<String, double[]>co_midi_rpn_rpn = new HashMap();
            Map<String, int[]>co_midi_nrpn_nrpn_i = new HashMap();
            Map<String, double[]>co_midi_nrpn_nrpn = new HashMap();
             */

            case 5:
                // This produce asin-like curve
                // as described in General Midi Level 2 Specification, page 6
                double x = -Math.asin((value / 128.0) * 2 - 1) / Math.PI + 0.5;
                x = Math.pow(100000.0, x) / 100.0;  // x is now cent/msec
                // Convert x from cent/msec to key/controlbuffertime
                x = x / 100.0;                      // x is now keys/msec
                x = x * 1000.0;                     // x is now keys/sec
                x = x / synthesizer.getControlRate(); // x is now keys/controlbuffertime
                portamento_time = x;
                break;
            case 6:
            case 38:
            case 96:
            case 97:
                int val = 0;
                if (nrpn_control != RPN_NULL_VALUE) {
                    int[] val_i = co_midi_nrpn_nrpn_i.get(nrpn_control);
                    if (val_i != null)
                        val = val_i[0];
                }
                if (rpn_control != RPN_NULL_VALUE) {
                    int[] val_i = co_midi_rpn_rpn_i.get(rpn_control);
                    if (val_i != null)
                        val = val_i[0];
                }

                if (controller == 6)
                    val = (val & 127) + (value << 7);
                else if (controller == 38)
                    val = (val & (127 << 7)) + value;
                else if (controller == 96 || controller == 97) {
                    int step = 1;
                    if (rpn_control == 2 || rpn_control == 3 || rpn_control == 4)
                        step = 128;
                    if (controller == 96)
                        val += step;
                    if (controller == 97)
                        val -= step;
                }

                if (nrpn_control != RPN_NULL_VALUE)
                    nrpnChange(nrpn_control, val);
                if (rpn_control != RPN_NULL_VALUE)
                    rpnChange(rpn_control, val);

                break;
            case 64: // Hold1 (Damper) (cc#64)
                boolean on = value >= 64;
                if (sustain != on) {
                    sustain = on;
                    if (!on) {
                        for (int i = 0; i < voices.length; i++) {
                            if (voices[i].active && voices[i].sustain &&
                                    voices[i].channel == channel) {
                                voices[i].sustain = false;
                                if (!voices[i].on) {
                                    voices[i].on = true;
                                    voices[i].noteOff(0);
                                }
                            }
                        }
                    } else {
                        for (int i = 0; i < voices.length; i++)
                            if (voices[i].active && voices[i].channel == channel)
                                voices[i].redamp();
                    }
                }
                break;
            case 65:
                //allNotesOff();
                portamento = value >= 64;
                portamento_lastnote[0] = -1;
                /*
                for (int i = 0; i < portamento_lastnote.length; i++)
                    portamento_lastnote[i] = -1;
                 */
                portamento_lastnote_ix = 0;
                break;
            case 66: // Sostenuto (cc#66)
                on = value >= 64;
                if (on) {
                    for (int i = 0; i < voices.length; i++) {
                        if (voices[i].active && voices[i].on &&
                                voices[i].channel == channel) {
                            voices[i].sostenuto = true;
                        }
                    }
                }
                if (!on) {
                    for (int i = 0; i < voices.length; i++) {
                        if (voices[i].active && voices[i].sostenuto &&
                                voices[i].channel == channel) {
                            voices[i].sostenuto = false;
                            if (!voices[i].on) {
                                voices[i].on = true;
                                voices[i].noteOff(0);
                            }
                        }
                    }
                }
                break;
            case 98:
                nrpn_control = (nrpn_control & (127 << 7)) + value;
                rpn_control = RPN_NULL_VALUE;
                break;
            case 99:
                nrpn_control = (nrpn_control & 127) + (value << 7);
                rpn_control = RPN_NULL_VALUE;
                break;
            case 100:
                rpn_control = (rpn_control & (127 << 7)) + value;
                nrpn_control = RPN_NULL_VALUE;
                break;
            case 101:
                rpn_control = (rpn_control & 127) + (value << 7);
                nrpn_control = RPN_NULL_VALUE;
                break;
            case 120:
                allSoundOff();
                break;
            case 121:
                resetAllControllers(value == 127);
                break;
            case 122:
                localControl(value >= 64);
                break;
            case 123:
                allNotesOff();
                break;
            case 124:
                setOmni(false);
                break;
            case 125:
                setOmni(true);
                break;
            case 126:
                if (value == 1)
                    setMono(true);
                break;
            case 127:
                setMono(false);
                break;

            default:
                break;
            }

            co_midi_cc_cc[controller][0] = value * (1.0 / 128.0);

            if (controller == 0x00) {
                bank = /*(bank & 127) +*/ (value << 7);
                return;
            }

            if (controller == 0x20) {
                bank = (bank & (127 << 7)) + value;
                return;
            }

            this.controller[controller] = value;
            if(controller < 0x20)
                this.controller[controller + 0x20] = 0;

            for (int i = 0; i < voices.length; i++)
                if (voices[i].active)
                    voices[i].controlChange(controller, value);

        }
    }

    public int getController(int controller) {
        synchronized (control_mutex) {
            // Should only return lower 7 bits,
            // even when controller is "boosted" higher.
            return this.controller[controller] & 127;
        }
    }

    public void tuningChange(int program) {
        tuningChange(0, program);
    }

    public void tuningChange(int bank, int program) {
        synchronized (control_mutex) {
            tuning = synthesizer.getTuning(new Patch(bank, program));
        }
    }

    public void programChange(int program) {
        programChange(bank, program);
    }

    public void programChange(int bank, int program) {
        bank = restrict14Bit(bank);
        program = restrict7Bit(program);
        synchronized (control_mutex) {
            mainmixer.activity();
            if(this.bank != bank || this.program != program)
            {
                this.bank = bank;
                this.program = program;
                current_instrument = null;
            }
        }
    }

    public int getProgram() {
        synchronized (control_mutex) {
            return program;
        }
    }

    public void setPitchBend(int bend) {
        bend = restrict14Bit(bend);
        if (current_mixer != null)
            current_mixer.setPitchBend(bend);
        synchronized (control_mutex) {
            mainmixer.activity();
            co_midi_pitch[0] = bend * (1.0 / 16384.0);
            pitchbend = bend;
            for (int i = 0; i < voices.length; i++)
                if (voices[i].active)
                    voices[i].setPitchBend(bend);
        }
    }

    public int getPitchBend() {
        synchronized (control_mutex) {
            return pitchbend;
        }
    }

    public void nrpnChange(int controller, int value) {

        /*
        System.out.println("(" + channel + ").nrpnChange("
                + Integer.toHexString(controller >> 7)
                + " " + Integer.toHexString(controller & 127)
                + ", " + Integer.toHexString(value >> 7)
                + " " + Integer.toHexString(value & 127) + ")");
         */

        if (synthesizer.getGeneralMidiMode() == 0) {
            if (controller == (0x01 << 7) + (0x08)) // Vibrato Rate
                controlChange(76, value >> 7);
            if (controller == (0x01 << 7) + (0x09)) // Vibrato Depth
                controlChange(77, value >> 7);
            if (controller == (0x01 << 7) + (0x0A)) // Vibrato Delay
                controlChange(78, value >> 7);
            if (controller == (0x01 << 7) + (0x20)) // Brightness
                controlChange(74, value >> 7);
            if (controller == (0x01 << 7) + (0x21)) // Filter Resonance
                controlChange(71, value >> 7);
            if (controller == (0x01 << 7) + (0x63)) // Attack Time
                controlChange(73, value >> 7);
            if (controller == (0x01 << 7) + (0x64)) // Decay Time
                controlChange(75, value >> 7);
            if (controller == (0x01 << 7) + (0x66)) // Release Time
                controlChange(72, value >> 7);

            if (controller >> 7 == 0x18) // Pitch coarse
                controlChangePerNote(controller % 128, 120, value >> 7);
            if (controller >> 7 == 0x1A) // Volume
                controlChangePerNote(controller % 128, 7, value >> 7);
            if (controller >> 7 == 0x1C) // Panpot
                controlChangePerNote(controller % 128, 10, value >> 7);
            if (controller >> 7 == 0x1D) // Reverb
                controlChangePerNote(controller % 128, 91, value >> 7);
            if (controller >> 7 == 0x1E) // Chorus
                controlChangePerNote(controller % 128, 93, value >> 7);
        }

        int[] val_i = co_midi_nrpn_nrpn_i.get(controller);
        double[] val_d = co_midi_nrpn_nrpn.get(controller);
        if (val_i == null) {
            val_i = new int[1];
            co_midi_nrpn_nrpn_i.put(controller, val_i);
        }
        if (val_d == null) {
            val_d = new double[1];
            co_midi_nrpn_nrpn.put(controller, val_d);
        }
        val_i[0] = value;
        val_d[0] = val_i[0] * (1.0 / 16384.0);

        for (int i = 0; i < voices.length; i++)
            if (voices[i].active)
                voices[i].nrpnChange(controller, val_i[0]);

    }

    public void rpnChange(int controller, int value) {

        /*
        System.out.println("(" + channel + ").rpnChange("
                + Integer.toHexString(controller >> 7)
                + " " + Integer.toHexString(controller & 127)
                + ", " + Integer.toHexString(value >> 7)
                + " " + Integer.toHexString(value & 127) + ")");
         */

        if (controller == 3) {
            tuning_program = (value >> 7) & 127;
            tuningChange(tuning_bank, tuning_program);
        }
        if (controller == 4) {
            tuning_bank = (value >> 7) & 127;
        }

        int[] val_i = co_midi_rpn_rpn_i.get(controller);
        double[] val_d = co_midi_rpn_rpn.get(controller);
        if (val_i == null) {
            val_i = new int[1];
            co_midi_rpn_rpn_i.put(controller, val_i);
        }
        if (val_d == null) {
            val_d = new double[1];
            co_midi_rpn_rpn.put(controller, val_d);
        }
        val_i[0] = value;
        val_d[0] = val_i[0] * (1.0 / 16384.0);

        for (int i = 0; i < voices.length; i++)
            if (voices[i].active)
                voices[i].rpnChange(controller, val_i[0]);
    }

    public void resetAllControllers() {
        resetAllControllers(false);
    }

    public void resetAllControllers(boolean allControls) {
        synchronized (control_mutex) {
            mainmixer.activity();

            for (int i = 0; i < 128; i++) {
                setPolyPressure(i, 0);
            }
            setChannelPressure(0);
            setPitchBend(8192);
            for (int i = 0; i < 128; i++) {
                if (!dontResetControls[i])
                    controlChange(i, 0);
            }

            controlChange(71, 64); // Filter Resonance
            controlChange(72, 64); // Release Time
            controlChange(73, 64); // Attack Time
            controlChange(74, 64); // Brightness
            controlChange(75, 64); // Decay Time
            controlChange(76, 64); // Vibrato Rate
            controlChange(77, 64); // Vibrato Depth
            controlChange(78, 64); // Vibrato Delay

            controlChange(8, 64); // Balance
            controlChange(11, 127); // Expression
            controlChange(98, 127); // NRPN Null
            controlChange(99, 127); // NRPN Null
            controlChange(100, 127); // RPN = Null
            controlChange(101, 127); // RPN = Null

            // see DLS 2.1 (Power-on Default Values)
            if (allControls) {

                keybasedcontroller_active = null;
                keybasedcontroller_value = null;

                controlChange(7, 100); // Volume
                controlChange(10, 64); // Pan
                controlChange(91, 40); // Reverb

                for (int controller : co_midi_rpn_rpn.keySet()) {
                    // don't reset tuning settings
                    if (controller != 3 && controller != 4)
                        rpnChange(controller, 0);
                }
                for (int controller : co_midi_nrpn_nrpn.keySet())
                    nrpnChange(controller, 0);
                rpnChange(0, 2 << 7);   // Bitch Bend sensitivity
                rpnChange(1, 64 << 7);  // Channel fine tunning
                rpnChange(2, 64 << 7);  // Channel Coarse Tuning
                rpnChange(5, 64);       // Modulation Depth, +/- 50 cent

                tuning_bank = 0;
                tuning_program = 0;
                tuning = new SoftTuning();

            }

        }
    }

    public void allNotesOff() {
        if (current_mixer != null)
            current_mixer.allNotesOff();
        synchronized (control_mutex) {
            for (int i = 0; i < voices.length; i++)
                if (voices[i].on && voices[i].channel == channel
                        && voices[i].releaseTriggered == false) {
                    voices[i].noteOff(0);
                }
        }
    }

    public void allSoundOff() {
        if (current_mixer != null)
            current_mixer.allSoundOff();
        synchronized (control_mutex) {
            for (int i = 0; i < voices.length; i++)
                if (voices[i].on && voices[i].channel == channel)
                    voices[i].soundOff();
        }
    }

    public boolean localControl(boolean on) {
        return false;
    }

    public void setMono(boolean on) {
        if (current_mixer != null)
            current_mixer.setMono(on);
        synchronized (control_mutex) {
            allNotesOff();
            mono = on;
        }
    }

    public boolean getMono() {
        synchronized (control_mutex) {
            return mono;
        }
    }

    public void setOmni(boolean on) {
        if (current_mixer != null)
            current_mixer.setOmni(on);
        allNotesOff();
    // Omni is not supported by GM2
    }

    public boolean getOmni() {
        return false;
    }

    public void setMute(boolean mute) {
        if (current_mixer != null)
            current_mixer.setMute(mute);
        synchronized (control_mutex) {
            this.mute = mute;
            for (int i = 0; i < voices.length; i++)
                if (voices[i].active && voices[i].channel == channel)
                    voices[i].setMute(mute);
        }
    }

    public boolean getMute() {
        synchronized (control_mutex) {
            return mute;
        }
    }

    public void setSolo(boolean soloState) {
        if (current_mixer != null)
            current_mixer.setSolo(soloState);

        synchronized (control_mutex) {
            this.solo = soloState;

            boolean soloinuse = false;
            for (SoftChannel c : synthesizer.channels) {
                if (c.solo) {
                    soloinuse = true;
                    break;
                }
            }

            if (!soloinuse) {
                for (SoftChannel c : synthesizer.channels)
                    c.setSoloMute(false);
                return;
            }

            for (SoftChannel c : synthesizer.channels)
                c.setSoloMute(!c.solo);

        }

    }

    private void setSoloMute(boolean mute) {
        synchronized (control_mutex) {
            if (solomute == mute)
                return;
            this.solomute = mute;
            for (int i = 0; i < voices.length; i++)
                if (voices[i].active && voices[i].channel == channel)
                    voices[i].setSoloMute(solomute);
        }
    }

    public boolean getSolo() {
        synchronized (control_mutex) {
            return solo;
        }
    }
}

Other Java examples (source code examples)

Here is a short list of links related to this Java SoftChannel.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.