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;
public final class SoftChannel implements MidiChannel, ModelDirectedPlayer {
private static final boolean[] dontResetControls = new boolean[128];
static {
for (int i = 0; i < dontResetControls.length; i++)
dontResetControls[i] = false;
dontResetControls[0] = true;
dontResetControls[32] = true;
dontResetControls[7] = true;
dontResetControls[8] = true;
dontResetControls[10] = true;
dontResetControls[11] = true;
dontResetControls[91] = true;
dontResetControls[92] = true;
dontResetControls[93] = true;
dontResetControls[94] = true;
dontResetControls[95] = true;
dontResetControls[70] = true;
dontResetControls[71] = true;
dontResetControls[72] = true;
dontResetControls[73] = true;
dontResetControls[74] = true;
dontResetControls[75] = true;
dontResetControls[76] = true;
dontResetControls[77] = true;
dontResetControls[78] = true;
dontResetControls[79] = true;
dontResetControls[120] = true;
dontResetControls[121] = true;
dontResetControls[122] = true;
dontResetControls[123] = true;
dontResetControls[124] = true;
dontResetControls[125] = true;
dontResetControls[126] = true;
dontResetControls[127] = true;
dontResetControls[6] = true;
dontResetControls[38] = true;
dontResetControls[96] = true;
dontResetControls[97] = true;
dontResetControls[98] = true;
dontResetControls[99] = true;
dontResetControls[100] = true;
dontResetControls[101] = true;
}
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;
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 final int channel;
private final SoftVoice[] voices;
private int bank;
private int program;
private final SoftSynthesizer synthesizer;
private final SoftMainMixer mainmixer;
private final int[] polypressure = new int[128];
private int channelpressure = 0;
private final int[] controller = new int[128];
private int pitchbend;
private final double[] co_midi_pitch = new double[1];
private final 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;
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];
@Override
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 final SoftControl[] co_midi = new SoftControl[128];
{
for (int i = 0; i < co_midi.length; i++) {
co_midi[i] = new MidiControlObject();
}
}
private final double[][] co_midi_cc_cc = new double[128][1];
private final SoftControl co_midi_cc = new SoftControl() {
double[][] cc = co_midi_cc_cc;
@Override
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 final SoftControl co_midi_rpn = new SoftControl() {
Map<Integer, double[]> rpn = co_midi_rpn_rpn;
@Override
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 final SoftControl co_midi_nrpn = new SoftControl() {
Map<Integer, double[]> nrpn = co_midi_nrpn_nrpn;
@Override
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)
{
return -1;
}
for (int i = x; i < voices.length; i++)
if (!voices[i].active)
return i;
int vmode = synthesizer.getVoiceAllocationMode();
if (vmode == 1) {
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;
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;
}
}
}
}
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 {
int voiceNo = -1;
SoftVoice v = null;
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;
}
}
}
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.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;
}
}
}
}
@Override
public void noteOn(int noteNumber, int velocity) {
noteOn(noteNumber, velocity, 0);
}
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);
}
}
@Override
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);
}
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;
}
}
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 final 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;
@Override
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);
}
@Override
public void noteOff(int noteNumber) {
if(noteNumber < 0 || noteNumber > 127) return;
noteOff_internal(noteNumber, 64);
}
@Override
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);
}
}
}
@Override
public int getPolyPressure(int noteNumber) {
synchronized (control_mutex) {
return polypressure[noteNumber];
}
}
@Override
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);
}
}
}
@Override
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) {
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;
@Override
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;
@Override
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) {
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);
}
@Override
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) {
case 5:
double x = -Math.asin((value / 128.0) * 2 - 1) / Math.PI + 0.5;
x = Math.pow(100000.0, x) / 100.0;
x = x / 100.0;
x = x * 1000.0;
x = x / synthesizer.getControlRate();
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:
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:
portamento = value >= 64;
portamento_lastnote[0] = -1;
portamento_lastnote_ix = 0;
break;
case 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 = (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);
}
}
@Override
public int getController(int controller) {
synchronized (control_mutex) {
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));
}
}
@Override
public void programChange(int program) {
programChange(bank, program);
}
@Override
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;
}
}
}
@Override
public int getProgram() {
synchronized (control_mutex) {
return program;
}
}
@Override
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);
}
}
@Override
public int getPitchBend() {
synchronized (control_mutex) {
return pitchbend;
}
}
public void nrpnChange(int controller, int value) {
if (synthesizer.getGeneralMidiMode() == 0) {
if (controller == (0x01 << 7) + (0x08))
controlChange(76, value >> 7);
if (controller == (0x01 << 7) + (0x09))
controlChange(77, value >> 7);
if (controller == (0x01 << 7) + (0x0A))
controlChange(78, value >> 7);
if (controller == (0x01 << 7) + (0x20))
controlChange(74, value >> 7);
if (controller == (0x01 << 7) + (0x21))
controlChange(71, value >> 7);
if (controller == (0x01 << 7) + (0x63))
controlChange(73, value >> 7);
if (controller == (0x01 << 7) + (0x64))
controlChange(75, value >> 7);
if (controller == (0x01 << 7) + (0x66))
controlChange(72, value >> 7);
if (controller >> 7 == 0x18)
controlChangePerNote(controller % 128, 120, value >> 7);
if (controller >> 7 == 0x1A)
controlChangePerNote(controller % 128, 7, value >> 7);
if (controller >> 7 == 0x1C)
controlChangePerNote(controller % 128, 10, value >> 7);
if (controller >> 7 == 0x1D)
controlChangePerNote(controller % 128, 91, value >> 7);
if (controller >> 7 == 0x1E)
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) {
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]);
}
@Override
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);
controlChange(72, 64);
controlChange(73, 64);
controlChange(74, 64);
controlChange(75, 64);
controlChange(76, 64);
controlChange(77, 64);
controlChange(78, 64);
controlChange(8, 64);
controlChange(11, 127);
controlChange(98, 127);
controlChange(99, 127);
controlChange(100, 127);
controlChange(101, 127);
if (allControls) {
keybasedcontroller_active = null;
keybasedcontroller_value = null;
controlChange(7, 100);
controlChange(10, 64);
controlChange(91, 40);
for (int controller : co_midi_rpn_rpn.keySet()) {
if (controller != 3 && controller != 4)
rpnChange(controller, 0);
}
for (int controller : co_midi_nrpn_nrpn.keySet())
nrpnChange(controller, 0);
rpnChange(0, 2 << 7);
rpnChange(1, 64 << 7);
rpnChange(2, 64 << 7);
rpnChange(5, 64);
tuning_bank = 0;
tuning_program = 0;
tuning = new SoftTuning();
}
}
}
@Override
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);
}
}
}
@Override
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();
}
}
@Override
public boolean localControl(boolean on) {
return false;
}
@Override
public void setMono(boolean on) {
if (current_mixer != null)
current_mixer.setMono(on);
synchronized (control_mutex) {
allNotesOff();
mono = on;
}
}
@Override
public boolean getMono() {
synchronized (control_mutex) {
return mono;
}
}
@Override
public void setOmni(boolean on) {
if (current_mixer != null)
current_mixer.setOmni(on);
allNotesOff();
}
@Override
public boolean getOmni() {
return false;
}
@Override
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);
}
}
@Override
public boolean getMute() {
synchronized (control_mutex) {
return mute;
}
}
@Override
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);
}
}
@Override
public boolean getSolo() {
synchronized (control_mutex) {
return solo;
}
}
}