|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
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 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 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; |
|
|
|
|
|
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<Integer, int[]>(); |
|
Map<Integer, double[]> co_midi_rpn_rpn = new HashMap<Integer, double[]>(); |
|
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<Integer, int[]>(); |
|
Map<Integer, double[]> co_midi_nrpn_nrpn = new HashMap<Integer, double[]>(); |
|
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. |
|
|
|
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) |
|
|
|
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 { |
|
// 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; |
|
|
|
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; |
|
} |
|
} |
|
} |
|
} |
|
|
|
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); |
|
|
|
/* |
|
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); |
|
} |
|
|
|
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<ModelConnectionBlock>(); |
|
|
|
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<String, int[]>(); |
|
Map<String, double[]>co_midi_rpn_rpn = new HashMap<String, double[]>(); |
|
Map<String, int[]>co_midi_nrpn_nrpn_i = new HashMap<String, int[]>(); |
|
Map<String, double[]>co_midi_nrpn_nrpn = new HashMap<String, double[]>(); |
|
*/ |
|
|
|
case 5: |
|
// This produce asin-like curve |
|
|
|
double x = -Math.asin((value / 128.0) * 2 - 1) / Math.PI + 0.5; |
|
x = Math.pow(100000.0, x) / 100.0; |
|
// Convert x from cent/msec to key/controlbuffertime |
|
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); |
|
|
|
} |
|
} |
|
|
|
public int getController(int controller) { |
|
synchronized (control_mutex) { |
|
// Should only return lower 7 bits, |
|
|
|
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)) |
|
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) { |
|
|
|
/* |
|
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); |
|
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(); |
|
|
|
} |
|
|
|
} |
|
} |
|
|
|
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; |
|
} |
|
} |
|
} |