829N/A/*
6321N/A * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
829N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
829N/A *
829N/A * This code is free software; you can redistribute it and/or modify it
829N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
829N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
829N/A *
829N/A * This code is distributed in the hope that it will be useful, but WITHOUT
829N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
829N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
829N/A * version 2 for more details (a copy is included in the LICENSE file that
829N/A * accompanied this code).
829N/A *
829N/A * You should have received a copy of the GNU General Public License version
829N/A * 2 along with this work; if not, write to the Free Software Foundation,
829N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
829N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
829N/A */
829N/Apackage com.sun.media.sound;
829N/A
829N/Aimport java.io.IOException;
829N/Aimport java.io.InputStream;
829N/Aimport java.util.HashSet;
829N/Aimport java.util.Iterator;
829N/Aimport java.util.Set;
829N/Aimport java.util.TreeMap;
829N/Aimport java.util.Map.Entry;
829N/A
829N/Aimport javax.sound.midi.MidiMessage;
829N/Aimport javax.sound.midi.Patch;
829N/Aimport javax.sound.midi.ShortMessage;
829N/Aimport javax.sound.sampled.AudioInputStream;
829N/Aimport javax.sound.sampled.AudioSystem;
829N/A
829N/A/**
829N/A * Software synthesizer main audio mixer.
829N/A *
829N/A * @author Karl Helgason
829N/A */
6321N/Apublic final class SoftMainMixer {
829N/A
1990N/A // A private class thats contains a ModelChannelMixer and it's private buffers.
1990N/A // This becomes necessary when we want to have separate delay buffers for each channel mixer.
1990N/A private class SoftChannelMixerContainer
1990N/A {
1990N/A ModelChannelMixer mixer;
1990N/A SoftAudioBuffer[] buffers;
1990N/A }
1990N/A
829N/A public final static int CHANNEL_LEFT = 0;
829N/A public final static int CHANNEL_RIGHT = 1;
1170N/A public final static int CHANNEL_MONO = 2;
1990N/A public final static int CHANNEL_DELAY_LEFT = 3;
1990N/A public final static int CHANNEL_DELAY_RIGHT = 4;
1990N/A public final static int CHANNEL_DELAY_MONO = 5;
1990N/A public final static int CHANNEL_EFFECT1 = 6;
1990N/A public final static int CHANNEL_EFFECT2 = 7;
1990N/A public final static int CHANNEL_DELAY_EFFECT1 = 8;
1990N/A public final static int CHANNEL_DELAY_EFFECT2 = 9;
829N/A public final static int CHANNEL_LEFT_DRY = 10;
829N/A public final static int CHANNEL_RIGHT_DRY = 11;
829N/A public final static int CHANNEL_SCRATCH1 = 12;
829N/A public final static int CHANNEL_SCRATCH2 = 13;
6321N/A boolean active_sensing_on = false;
829N/A private long msec_last_activity = -1;
829N/A private boolean pusher_silent = false;
829N/A private int pusher_silent_count = 0;
1990N/A private long sample_pos = 0;
6321N/A boolean readfully = true;
6321N/A private final Object control_mutex;
829N/A private SoftSynthesizer synth;
1990N/A private float samplerate = 44100;
829N/A private int nrofchannels = 2;
829N/A private SoftVoice[] voicestatus = null;
829N/A private SoftAudioBuffer[] buffers;
829N/A private SoftReverb reverb;
829N/A private SoftAudioProcessor chorus;
829N/A private SoftAudioProcessor agc;
829N/A private long msec_buffer_len = 0;
1990N/A private int buffer_len = 0;
6321N/A TreeMap<Long, Object> midimessages = new TreeMap<Long, Object>();
1990N/A private int delay_midievent = 0;
1990N/A private int max_delay_midievent = 0;
829N/A double last_volume_left = 1.0;
829N/A double last_volume_right = 1.0;
829N/A private double[] co_master_balance = new double[1];
829N/A private double[] co_master_volume = new double[1];
829N/A private double[] co_master_coarse_tuning = new double[1];
829N/A private double[] co_master_fine_tuning = new double[1];
829N/A private AudioInputStream ais;
1990N/A private Set<SoftChannelMixerContainer> registeredMixers = null;
829N/A private Set<ModelChannelMixer> stoppedMixers = null;
1990N/A private SoftChannelMixerContainer[] cur_registeredMixers = null;
6321N/A SoftControl co_master = new SoftControl() {
829N/A
829N/A double[] balance = co_master_balance;
829N/A double[] volume = co_master_volume;
829N/A double[] coarse_tuning = co_master_coarse_tuning;
829N/A double[] fine_tuning = co_master_fine_tuning;
829N/A
829N/A public double[] get(int instance, String name) {
829N/A if (name == null)
829N/A return null;
829N/A if (name.equals("balance"))
829N/A return balance;
829N/A if (name.equals("volume"))
829N/A return volume;
829N/A if (name.equals("coarse_tuning"))
829N/A return coarse_tuning;
829N/A if (name.equals("fine_tuning"))
829N/A return fine_tuning;
829N/A return null;
829N/A }
829N/A };
829N/A
829N/A private void processSystemExclusiveMessage(byte[] data) {
829N/A synchronized (synth.control_mutex) {
829N/A activity();
829N/A
829N/A // Universal Non-Real-Time SysEx
829N/A if ((data[1] & 0xFF) == 0x7E) {
829N/A int deviceID = data[2] & 0xFF;
829N/A if (deviceID == 0x7F || deviceID == synth.getDeviceID()) {
829N/A int subid1 = data[3] & 0xFF;
829N/A int subid2;
829N/A switch (subid1) {
829N/A case 0x08: // MIDI Tuning Standard
829N/A subid2 = data[4] & 0xFF;
829N/A switch (subid2) {
829N/A case 0x01: // BULK TUNING DUMP
829N/A {
829N/A // http://www.midi.org/about-midi/tuning.shtml
829N/A SoftTuning tuning = synth.getTuning(new Patch(0,
829N/A data[5] & 0xFF));
829N/A tuning.load(data);
829N/A break;
829N/A }
829N/A case 0x04: // KEY-BASED TUNING DUMP
829N/A case 0x05: // SCALE/OCTAVE TUNING DUMP, 1 byte format
829N/A case 0x06: // SCALE/OCTAVE TUNING DUMP, 2 byte format
829N/A case 0x07: // SINGLE NOTE TUNING CHANGE (NON REAL-TIME)
829N/A // (BANK)
829N/A {
829N/A // http://www.midi.org/about-midi/tuning_extens.shtml
829N/A SoftTuning tuning = synth.getTuning(new Patch(
829N/A data[5] & 0xFF, data[6] & 0xFF));
829N/A tuning.load(data);
829N/A break;
829N/A }
829N/A case 0x08: // scale/octave tuning 1-byte form (Non
829N/A // Real-Time)
829N/A case 0x09: // scale/octave tuning 2-byte form (Non
829N/A // Real-Time)
829N/A {
829N/A // http://www.midi.org/about-midi/tuning-scale.shtml
829N/A SoftTuning tuning = new SoftTuning(data);
829N/A int channelmask = (data[5] & 0xFF) * 16384
829N/A + (data[6] & 0xFF) * 128 + (data[7] & 0xFF);
829N/A SoftChannel[] channels = synth.channels;
829N/A for (int i = 0; i < channels.length; i++)
829N/A if ((channelmask & (1 << i)) != 0)
829N/A channels[i].tuning = tuning;
829N/A break;
829N/A }
829N/A default:
829N/A break;
829N/A }
829N/A break;
829N/A case 0x09: // General Midi Message
829N/A subid2 = data[4] & 0xFF;
829N/A switch (subid2) {
829N/A case 0x01: // General Midi 1 On
829N/A synth.setGeneralMidiMode(1);
829N/A reset();
829N/A break;
829N/A case 0x02: // General Midi Off
829N/A synth.setGeneralMidiMode(0);
829N/A reset();
829N/A break;
829N/A case 0x03: // General MidI Level 2 On
829N/A synth.setGeneralMidiMode(2);
829N/A reset();
829N/A break;
829N/A default:
829N/A break;
829N/A }
829N/A break;
829N/A case 0x0A: // DLS Message
829N/A subid2 = data[4] & 0xFF;
829N/A switch (subid2) {
829N/A case 0x01: // DLS On
829N/A if (synth.getGeneralMidiMode() == 0)
829N/A synth.setGeneralMidiMode(1);
829N/A synth.voice_allocation_mode = 1;
829N/A reset();
829N/A break;
829N/A case 0x02: // DLS Off
829N/A synth.setGeneralMidiMode(0);
829N/A synth.voice_allocation_mode = 0;
829N/A reset();
829N/A break;
829N/A case 0x03: // DLS Static Voice Allocation Off
829N/A synth.voice_allocation_mode = 0;
829N/A break;
829N/A case 0x04: // DLS Static Voice Allocation On
829N/A synth.voice_allocation_mode = 1;
829N/A break;
829N/A default:
829N/A break;
829N/A }
829N/A break;
829N/A
829N/A default:
829N/A break;
829N/A }
829N/A }
829N/A }
829N/A
829N/A // Universal Real-Time SysEx
829N/A if ((data[1] & 0xFF) == 0x7F) {
829N/A int deviceID = data[2] & 0xFF;
829N/A if (deviceID == 0x7F || deviceID == synth.getDeviceID()) {
829N/A int subid1 = data[3] & 0xFF;
829N/A int subid2;
829N/A switch (subid1) {
829N/A case 0x04: // Device Control
829N/A
829N/A subid2 = data[4] & 0xFF;
829N/A switch (subid2) {
829N/A case 0x01: // Master Volume
829N/A case 0x02: // Master Balane
829N/A case 0x03: // Master fine tuning
829N/A case 0x04: // Master coarse tuning
829N/A int val = (data[5] & 0x7F)
829N/A + ((data[6] & 0x7F) * 128);
829N/A if (subid2 == 0x01)
829N/A setVolume(val);
829N/A else if (subid2 == 0x02)
829N/A setBalance(val);
829N/A else if (subid2 == 0x03)
829N/A setFineTuning(val);
829N/A else if (subid2 == 0x04)
829N/A setCoarseTuning(val);
829N/A break;
829N/A case 0x05: // Global Parameter Control
829N/A int ix = 5;
829N/A int slotPathLen = (data[ix++] & 0xFF);
829N/A int paramWidth = (data[ix++] & 0xFF);
829N/A int valueWidth = (data[ix++] & 0xFF);
829N/A int[] slotPath = new int[slotPathLen];
829N/A for (int i = 0; i < slotPathLen; i++) {
829N/A int msb = (data[ix++] & 0xFF);
829N/A int lsb = (data[ix++] & 0xFF);
829N/A slotPath[i] = msb * 128 + lsb;
829N/A }
829N/A int paramCount = (data.length - 1 - ix)
829N/A / (paramWidth + valueWidth);
829N/A long[] params = new long[paramCount];
829N/A long[] values = new long[paramCount];
829N/A for (int i = 0; i < paramCount; i++) {
829N/A values[i] = 0;
829N/A for (int j = 0; j < paramWidth; j++)
829N/A params[i] = params[i] * 128
829N/A + (data[ix++] & 0xFF);
829N/A for (int j = 0; j < valueWidth; j++)
829N/A values[i] = values[i] * 128
829N/A + (data[ix++] & 0xFF);
829N/A
829N/A }
829N/A globalParameterControlChange(slotPath, params, values);
829N/A break;
829N/A default:
829N/A break;
829N/A }
829N/A break;
829N/A
829N/A case 0x08: // MIDI Tuning Standard
829N/A subid2 = data[4] & 0xFF;
829N/A switch (subid2) {
829N/A case 0x02: // SINGLE NOTE TUNING CHANGE (REAL-TIME)
829N/A {
829N/A // http://www.midi.org/about-midi/tuning.shtml
829N/A SoftTuning tuning = synth.getTuning(new Patch(0,
829N/A data[5] & 0xFF));
829N/A tuning.load(data);
829N/A SoftVoice[] voices = synth.getVoices();
829N/A for (int i = 0; i < voices.length; i++)
829N/A if (voices[i].active)
829N/A if (voices[i].tuning == tuning)
829N/A voices[i].updateTuning(tuning);
829N/A break;
829N/A }
829N/A case 0x07: // SINGLE NOTE TUNING CHANGE (REAL-TIME)
829N/A // (BANK)
829N/A {
829N/A // http://www.midi.org/about-midi/tuning_extens.shtml
829N/A SoftTuning tuning = synth.getTuning(new Patch(
829N/A data[5] & 0xFF, data[6] & 0xFF));
829N/A tuning.load(data);
829N/A SoftVoice[] voices = synth.getVoices();
829N/A for (int i = 0; i < voices.length; i++)
829N/A if (voices[i].active)
829N/A if (voices[i].tuning == tuning)
829N/A voices[i].updateTuning(tuning);
829N/A break;
829N/A }
829N/A case 0x08: // scale/octave tuning 1-byte form
829N/A //(Real-Time)
829N/A case 0x09: // scale/octave tuning 2-byte form
829N/A // (Real-Time)
829N/A {
829N/A // http://www.midi.org/about-midi/tuning-scale.shtml
829N/A SoftTuning tuning = new SoftTuning(data);
829N/A int channelmask = (data[5] & 0xFF) * 16384
829N/A + (data[6] & 0xFF) * 128 + (data[7] & 0xFF);
829N/A SoftChannel[] channels = synth.channels;
829N/A for (int i = 0; i < channels.length; i++)
829N/A if ((channelmask & (1 << i)) != 0)
829N/A channels[i].tuning = tuning;
829N/A SoftVoice[] voices = synth.getVoices();
829N/A for (int i = 0; i < voices.length; i++)
829N/A if (voices[i].active)
829N/A if ((channelmask & (1 << (voices[i].channel))) != 0)
829N/A voices[i].updateTuning(tuning);
829N/A break;
829N/A }
829N/A default:
829N/A break;
829N/A }
829N/A break;
829N/A case 0x09: // Control Destination Settings
829N/A subid2 = data[4] & 0xFF;
829N/A switch (subid2) {
829N/A case 0x01: // Channel Pressure
829N/A {
829N/A int[] destinations = new int[(data.length - 7) / 2];
829N/A int[] ranges = new int[(data.length - 7) / 2];
829N/A int ix = 0;
829N/A for (int j = 6; j < data.length - 1; j += 2) {
829N/A destinations[ix] = data[j] & 0xFF;
829N/A ranges[ix] = data[j + 1] & 0xFF;
829N/A ix++;
829N/A }
829N/A int channel = data[5] & 0xFF;
829N/A SoftChannel softchannel = synth.channels[channel];
829N/A softchannel.mapChannelPressureToDestination(
829N/A destinations, ranges);
829N/A break;
829N/A }
829N/A case 0x02: // Poly Pressure
829N/A {
829N/A int[] destinations = new int[(data.length - 7) / 2];
829N/A int[] ranges = new int[(data.length - 7) / 2];
829N/A int ix = 0;
829N/A for (int j = 6; j < data.length - 1; j += 2) {
829N/A destinations[ix] = data[j] & 0xFF;
829N/A ranges[ix] = data[j + 1] & 0xFF;
829N/A ix++;
829N/A }
829N/A int channel = data[5] & 0xFF;
829N/A SoftChannel softchannel = synth.channels[channel];
829N/A softchannel.mapPolyPressureToDestination(
829N/A destinations, ranges);
829N/A break;
829N/A }
829N/A case 0x03: // Control Change
829N/A {
829N/A int[] destinations = new int[(data.length - 7) / 2];
829N/A int[] ranges = new int[(data.length - 7) / 2];
829N/A int ix = 0;
829N/A for (int j = 7; j < data.length - 1; j += 2) {
829N/A destinations[ix] = data[j] & 0xFF;
829N/A ranges[ix] = data[j + 1] & 0xFF;
829N/A ix++;
829N/A }
829N/A int channel = data[5] & 0xFF;
829N/A SoftChannel softchannel = synth.channels[channel];
829N/A int control = data[6] & 0xFF;
829N/A softchannel.mapControlToDestination(control,
829N/A destinations, ranges);
829N/A break;
829N/A }
829N/A default:
829N/A break;
829N/A }
829N/A break;
829N/A
829N/A case 0x0A: // Key Based Instrument Control
829N/A {
829N/A subid2 = data[4] & 0xFF;
829N/A switch (subid2) {
829N/A case 0x01: // Basic Message
829N/A int channel = data[5] & 0xFF;
829N/A int keynumber = data[6] & 0xFF;
829N/A SoftChannel softchannel = synth.channels[channel];
829N/A for (int j = 7; j < data.length - 1; j += 2) {
829N/A int controlnumber = data[j] & 0xFF;
829N/A int controlvalue = data[j + 1] & 0xFF;
829N/A softchannel.controlChangePerNote(keynumber,
829N/A controlnumber, controlvalue);
829N/A }
829N/A break;
829N/A default:
829N/A break;
829N/A }
829N/A break;
829N/A }
829N/A default:
829N/A break;
829N/A }
829N/A }
829N/A }
829N/A
829N/A }
829N/A }
829N/A
829N/A private void processMessages(long timeStamp) {
829N/A Iterator<Entry<Long, Object>> iter = midimessages.entrySet().iterator();
829N/A while (iter.hasNext()) {
829N/A Entry<Long, Object> entry = iter.next();
1990N/A if (entry.getKey() >= (timeStamp + msec_buffer_len))
829N/A return;
1990N/A long msec_delay = entry.getKey() - timeStamp;
1990N/A delay_midievent = (int)(msec_delay * (samplerate / 1000000.0) + 0.5);
1990N/A if(delay_midievent > max_delay_midievent)
1990N/A delay_midievent = max_delay_midievent;
1990N/A if(delay_midievent < 0)
1990N/A delay_midievent = 0;
829N/A processMessage(entry.getValue());
829N/A iter.remove();
829N/A }
1990N/A delay_midievent = 0;
829N/A }
829N/A
6321N/A void processAudioBuffers() {
1990N/A
1990N/A if(synth.weakstream != null && synth.weakstream.silent_samples != 0)
1990N/A {
1990N/A sample_pos += synth.weakstream.silent_samples;
1990N/A synth.weakstream.silent_samples = 0;
1990N/A }
1990N/A
829N/A for (int i = 0; i < buffers.length; i++) {
1990N/A if(i != CHANNEL_DELAY_LEFT &&
1990N/A i != CHANNEL_DELAY_RIGHT &&
1990N/A i != CHANNEL_DELAY_MONO &&
1990N/A i != CHANNEL_DELAY_EFFECT1 &&
1990N/A i != CHANNEL_DELAY_EFFECT2)
1990N/A buffers[i].clear();
1990N/A }
1990N/A
1990N/A if(!buffers[CHANNEL_DELAY_LEFT].isSilent())
1990N/A {
1990N/A buffers[CHANNEL_LEFT].swap(buffers[CHANNEL_DELAY_LEFT]);
1990N/A }
1990N/A if(!buffers[CHANNEL_DELAY_RIGHT].isSilent())
1990N/A {
1990N/A buffers[CHANNEL_RIGHT].swap(buffers[CHANNEL_DELAY_RIGHT]);
1990N/A }
1990N/A if(!buffers[CHANNEL_DELAY_MONO].isSilent())
1990N/A {
1990N/A buffers[CHANNEL_MONO].swap(buffers[CHANNEL_DELAY_MONO]);
1990N/A }
1990N/A if(!buffers[CHANNEL_DELAY_EFFECT1].isSilent())
1990N/A {
1990N/A buffers[CHANNEL_EFFECT1].swap(buffers[CHANNEL_DELAY_EFFECT1]);
1990N/A }
1990N/A if(!buffers[CHANNEL_DELAY_EFFECT2].isSilent())
1990N/A {
1990N/A buffers[CHANNEL_EFFECT2].swap(buffers[CHANNEL_DELAY_EFFECT2]);
829N/A }
829N/A
829N/A double volume_left;
829N/A double volume_right;
829N/A
1990N/A SoftChannelMixerContainer[] act_registeredMixers;
829N/A
829N/A // perform control logic
829N/A synchronized (control_mutex) {
829N/A
1990N/A long msec_pos = (long)(sample_pos * (1000000.0 / samplerate));
1990N/A
829N/A processMessages(msec_pos);
829N/A
829N/A if (active_sensing_on) {
829N/A // Active Sensing
829N/A // if no message occurs for max 1000 ms
829N/A // then do AllSoundOff on all channels
829N/A if ((msec_pos - msec_last_activity) > 1000000) {
829N/A active_sensing_on = false;
829N/A for (SoftChannel c : synth.channels)
829N/A c.allSoundOff();
829N/A }
829N/A
829N/A }
829N/A
829N/A for (int i = 0; i < voicestatus.length; i++)
829N/A if (voicestatus[i].active)
829N/A voicestatus[i].processControlLogic();
1990N/A sample_pos += buffer_len;
829N/A
829N/A double volume = co_master_volume[0];
829N/A volume_left = volume;
829N/A volume_right = volume;
829N/A
829N/A double balance = co_master_balance[0];
829N/A if (balance > 0.5)
829N/A volume_left *= (1 - balance) * 2;
829N/A else
829N/A volume_right *= balance * 2;
829N/A
829N/A chorus.processControlLogic();
829N/A reverb.processControlLogic();
829N/A agc.processControlLogic();
829N/A
829N/A if (cur_registeredMixers == null) {
829N/A if (registeredMixers != null) {
829N/A cur_registeredMixers =
1990N/A new SoftChannelMixerContainer[registeredMixers.size()];
829N/A registeredMixers.toArray(cur_registeredMixers);
829N/A }
829N/A }
829N/A
829N/A act_registeredMixers = cur_registeredMixers;
829N/A if (act_registeredMixers != null)
829N/A if (act_registeredMixers.length == 0)
829N/A act_registeredMixers = null;
829N/A
829N/A }
829N/A
829N/A if (act_registeredMixers != null) {
829N/A
1990N/A // Make backup of left,right,mono channels
829N/A SoftAudioBuffer leftbak = buffers[CHANNEL_LEFT];
829N/A SoftAudioBuffer rightbak = buffers[CHANNEL_RIGHT];
1170N/A SoftAudioBuffer monobak = buffers[CHANNEL_MONO];
1990N/A SoftAudioBuffer delayleftbak = buffers[CHANNEL_DELAY_LEFT];
1990N/A SoftAudioBuffer delayrightbak = buffers[CHANNEL_DELAY_RIGHT];
1990N/A SoftAudioBuffer delaymonobak = buffers[CHANNEL_DELAY_MONO];
829N/A
829N/A int bufferlen = buffers[CHANNEL_LEFT].getSize();
829N/A
829N/A float[][] cbuffer = new float[nrofchannels][];
829N/A float[][] obuffer = new float[nrofchannels][];
829N/A obuffer[0] = leftbak.array();
829N/A if (nrofchannels != 1)
829N/A obuffer[1] = rightbak.array();
829N/A
1990N/A for (SoftChannelMixerContainer cmixer : act_registeredMixers) {
1990N/A
1990N/A // Reroute default left,right output
1990N/A // to channelmixer left,right input/output
1990N/A buffers[CHANNEL_LEFT] = cmixer.buffers[CHANNEL_LEFT];
1990N/A buffers[CHANNEL_RIGHT] = cmixer.buffers[CHANNEL_RIGHT];
1990N/A buffers[CHANNEL_MONO] = cmixer.buffers[CHANNEL_MONO];
1990N/A buffers[CHANNEL_DELAY_LEFT] = cmixer.buffers[CHANNEL_DELAY_LEFT];
1990N/A buffers[CHANNEL_DELAY_RIGHT] = cmixer.buffers[CHANNEL_DELAY_RIGHT];
1990N/A buffers[CHANNEL_DELAY_MONO] = cmixer.buffers[CHANNEL_DELAY_MONO];
1990N/A
1990N/A buffers[CHANNEL_LEFT].clear();
1990N/A buffers[CHANNEL_RIGHT].clear();
1170N/A buffers[CHANNEL_MONO].clear();
1990N/A
1990N/A if(!buffers[CHANNEL_DELAY_LEFT].isSilent())
1990N/A {
1990N/A buffers[CHANNEL_LEFT].swap(buffers[CHANNEL_DELAY_LEFT]);
1990N/A }
1990N/A if(!buffers[CHANNEL_DELAY_RIGHT].isSilent())
1990N/A {
1990N/A buffers[CHANNEL_RIGHT].swap(buffers[CHANNEL_DELAY_RIGHT]);
1990N/A }
1990N/A if(!buffers[CHANNEL_DELAY_MONO].isSilent())
1990N/A {
1990N/A buffers[CHANNEL_MONO].swap(buffers[CHANNEL_DELAY_MONO]);
1990N/A }
1990N/A
1990N/A cbuffer[0] = buffers[CHANNEL_LEFT].array();
1990N/A if (nrofchannels != 1)
1990N/A cbuffer[1] = buffers[CHANNEL_RIGHT].array();
1990N/A
829N/A boolean hasactivevoices = false;
829N/A for (int i = 0; i < voicestatus.length; i++)
829N/A if (voicestatus[i].active)
1990N/A if (voicestatus[i].channelmixer == cmixer.mixer) {
829N/A voicestatus[i].processAudioLogic(buffers);
829N/A hasactivevoices = true;
829N/A }
829N/A
1170N/A if(!buffers[CHANNEL_MONO].isSilent())
1170N/A {
1170N/A float[] mono = buffers[CHANNEL_MONO].array();
1170N/A float[] left = buffers[CHANNEL_LEFT].array();
1170N/A if (nrofchannels != 1) {
1170N/A float[] right = buffers[CHANNEL_RIGHT].array();
1170N/A for (int i = 0; i < bufferlen; i++) {
1170N/A float v = mono[i];
1170N/A left[i] += v;
1170N/A right[i] += v;
1170N/A }
1170N/A }
1170N/A else
1170N/A {
1170N/A for (int i = 0; i < bufferlen; i++) {
1170N/A left[i] += mono[i];
1170N/A }
1170N/A }
1170N/A }
1170N/A
1990N/A if (!cmixer.mixer.process(cbuffer, 0, bufferlen)) {
1990N/A synchronized (control_mutex) {
1990N/A registeredMixers.remove(cmixer);
1990N/A cur_registeredMixers = null;
1990N/A }
1990N/A }
1990N/A
829N/A for (int i = 0; i < cbuffer.length; i++) {
829N/A float[] cbuff = cbuffer[i];
829N/A float[] obuff = obuffer[i];
829N/A for (int j = 0; j < bufferlen; j++)
829N/A obuff[j] += cbuff[j];
829N/A }
829N/A
829N/A if (!hasactivevoices) {
829N/A synchronized (control_mutex) {
829N/A if (stoppedMixers != null) {
829N/A if (stoppedMixers.contains(cmixer)) {
829N/A stoppedMixers.remove(cmixer);
1990N/A cmixer.mixer.stop();
829N/A }
829N/A }
829N/A }
829N/A }
829N/A
829N/A }
829N/A
829N/A buffers[CHANNEL_LEFT] = leftbak;
829N/A buffers[CHANNEL_RIGHT] = rightbak;
1170N/A buffers[CHANNEL_MONO] = monobak;
1990N/A buffers[CHANNEL_DELAY_LEFT] = delayleftbak;
1990N/A buffers[CHANNEL_DELAY_RIGHT] = delayrightbak;
1990N/A buffers[CHANNEL_DELAY_MONO] = delaymonobak;
829N/A
829N/A }
829N/A
829N/A for (int i = 0; i < voicestatus.length; i++)
829N/A if (voicestatus[i].active)
829N/A if (voicestatus[i].channelmixer == null)
829N/A voicestatus[i].processAudioLogic(buffers);
829N/A
1170N/A if(!buffers[CHANNEL_MONO].isSilent())
1170N/A {
1170N/A float[] mono = buffers[CHANNEL_MONO].array();
1170N/A float[] left = buffers[CHANNEL_LEFT].array();
1170N/A int bufferlen = buffers[CHANNEL_LEFT].getSize();
1170N/A if (nrofchannels != 1) {
1170N/A float[] right = buffers[CHANNEL_RIGHT].array();
1170N/A for (int i = 0; i < bufferlen; i++) {
1170N/A float v = mono[i];
1170N/A left[i] += v;
1170N/A right[i] += v;
1170N/A }
1170N/A }
1170N/A else
1170N/A {
1170N/A for (int i = 0; i < bufferlen; i++) {
1170N/A left[i] += mono[i];
1170N/A }
1170N/A }
1170N/A }
1170N/A
829N/A // Run effects
829N/A if (synth.chorus_on)
829N/A chorus.processAudio();
829N/A
829N/A if (synth.reverb_on)
829N/A reverb.processAudio();
829N/A
829N/A if (nrofchannels == 1)
829N/A volume_left = (volume_left + volume_right) / 2;
829N/A
829N/A // Set Volume / Balance
829N/A if (last_volume_left != volume_left || last_volume_right != volume_right) {
829N/A float[] left = buffers[CHANNEL_LEFT].array();
829N/A float[] right = buffers[CHANNEL_RIGHT].array();
829N/A int bufferlen = buffers[CHANNEL_LEFT].getSize();
829N/A
829N/A float amp;
829N/A float amp_delta;
829N/A amp = (float)(last_volume_left * last_volume_left);
829N/A amp_delta = (float)((volume_left * volume_left - amp) / bufferlen);
829N/A for (int i = 0; i < bufferlen; i++) {
829N/A amp += amp_delta;
829N/A left[i] *= amp;
829N/A }
829N/A if (nrofchannels != 1) {
829N/A amp = (float)(last_volume_right * last_volume_right);
829N/A amp_delta = (float)((volume_right*volume_right - amp) / bufferlen);
829N/A for (int i = 0; i < bufferlen; i++) {
829N/A amp += amp_delta;
829N/A right[i] *= volume_right;
829N/A }
829N/A }
829N/A last_volume_left = volume_left;
829N/A last_volume_right = volume_right;
829N/A
829N/A } else {
829N/A if (volume_left != 1.0 || volume_right != 1.0) {
829N/A float[] left = buffers[CHANNEL_LEFT].array();
829N/A float[] right = buffers[CHANNEL_RIGHT].array();
829N/A int bufferlen = buffers[CHANNEL_LEFT].getSize();
829N/A float amp;
829N/A amp = (float) (volume_left * volume_left);
829N/A for (int i = 0; i < bufferlen; i++)
829N/A left[i] *= amp;
829N/A if (nrofchannels != 1) {
829N/A amp = (float)(volume_right * volume_right);
829N/A for (int i = 0; i < bufferlen; i++)
829N/A right[i] *= amp;
829N/A }
829N/A
829N/A }
829N/A }
829N/A
829N/A if(buffers[CHANNEL_LEFT].isSilent()
829N/A && buffers[CHANNEL_RIGHT].isSilent())
829N/A {
1990N/A
1990N/A int midimessages_size;
1990N/A synchronized (control_mutex) {
1990N/A midimessages_size = midimessages.size();
1990N/A }
1990N/A
1990N/A if(midimessages_size == 0)
829N/A {
1990N/A pusher_silent_count++;
1990N/A if(pusher_silent_count > 5)
1990N/A {
1990N/A pusher_silent_count = 0;
1990N/A synchronized (control_mutex) {
1990N/A pusher_silent = true;
1990N/A if(synth.weakstream != null)
1990N/A synth.weakstream.setInputStream(null);
1990N/A }
829N/A }
829N/A }
829N/A }
829N/A else
829N/A pusher_silent_count = 0;
829N/A
829N/A if (synth.agc_on)
829N/A agc.processAudio();
829N/A
829N/A }
829N/A
829N/A // Must only we called within control_mutex synchronization
829N/A public void activity()
829N/A {
1990N/A long silent_samples = 0;
829N/A if(pusher_silent)
829N/A {
829N/A pusher_silent = false;
829N/A if(synth.weakstream != null)
1990N/A {
829N/A synth.weakstream.setInputStream(ais);
1990N/A silent_samples = synth.weakstream.silent_samples;
1990N/A }
829N/A }
1990N/A msec_last_activity = (long)((sample_pos + silent_samples)
1990N/A * (1000000.0 / samplerate));
829N/A }
829N/A
829N/A public void stopMixer(ModelChannelMixer mixer) {
829N/A if (stoppedMixers == null)
829N/A stoppedMixers = new HashSet<ModelChannelMixer>();
829N/A stoppedMixers.add(mixer);
829N/A }
829N/A
829N/A public void registerMixer(ModelChannelMixer mixer) {
829N/A if (registeredMixers == null)
1990N/A registeredMixers = new HashSet<SoftChannelMixerContainer>();
1990N/A SoftChannelMixerContainer mixercontainer = new SoftChannelMixerContainer();
1990N/A mixercontainer.buffers = new SoftAudioBuffer[6];
1990N/A for (int i = 0; i < mixercontainer.buffers.length; i++) {
1990N/A mixercontainer.buffers[i] =
1990N/A new SoftAudioBuffer(buffer_len, synth.getFormat());
1990N/A }
1990N/A mixercontainer.mixer = mixer;
1990N/A registeredMixers.add(mixercontainer);
829N/A cur_registeredMixers = null;
829N/A }
829N/A
829N/A public SoftMainMixer(SoftSynthesizer synth) {
829N/A this.synth = synth;
829N/A
1990N/A sample_pos = 0;
829N/A
829N/A co_master_balance[0] = 0.5;
829N/A co_master_volume[0] = 1;
829N/A co_master_coarse_tuning[0] = 0.5;
829N/A co_master_fine_tuning[0] = 0.5;
829N/A
829N/A msec_buffer_len = (long) (1000000.0 / synth.getControlRate());
1990N/A samplerate = synth.getFormat().getSampleRate();
829N/A nrofchannels = synth.getFormat().getChannels();
829N/A
829N/A int buffersize = (int) (synth.getFormat().getSampleRate()
829N/A / synth.getControlRate());
829N/A
1990N/A buffer_len = buffersize;
1990N/A
1990N/A max_delay_midievent = buffersize;
1990N/A
829N/A control_mutex = synth.control_mutex;
1990N/A buffers = new SoftAudioBuffer[14];
829N/A for (int i = 0; i < buffers.length; i++) {
829N/A buffers[i] = new SoftAudioBuffer(buffersize, synth.getFormat());
829N/A }
829N/A voicestatus = synth.getVoices();
829N/A
829N/A reverb = new SoftReverb();
829N/A chorus = new SoftChorus();
829N/A agc = new SoftLimiter();
829N/A
829N/A float samplerate = synth.getFormat().getSampleRate();
829N/A float controlrate = synth.getControlRate();
829N/A reverb.init(samplerate, controlrate);
829N/A chorus.init(samplerate, controlrate);
829N/A agc.init(samplerate, controlrate);
829N/A
829N/A reverb.setLightMode(synth.reverb_light);
829N/A
829N/A reverb.setMixMode(true);
829N/A chorus.setMixMode(true);
829N/A agc.setMixMode(false);
829N/A
829N/A chorus.setInput(0, buffers[CHANNEL_EFFECT2]);
829N/A chorus.setOutput(0, buffers[CHANNEL_LEFT]);
829N/A if (nrofchannels != 1)
829N/A chorus.setOutput(1, buffers[CHANNEL_RIGHT]);
829N/A chorus.setOutput(2, buffers[CHANNEL_EFFECT1]);
829N/A
829N/A reverb.setInput(0, buffers[CHANNEL_EFFECT1]);
829N/A reverb.setOutput(0, buffers[CHANNEL_LEFT]);
829N/A if (nrofchannels != 1)
829N/A reverb.setOutput(1, buffers[CHANNEL_RIGHT]);
829N/A
829N/A agc.setInput(0, buffers[CHANNEL_LEFT]);
829N/A if (nrofchannels != 1)
829N/A agc.setInput(1, buffers[CHANNEL_RIGHT]);
829N/A agc.setOutput(0, buffers[CHANNEL_LEFT]);
829N/A if (nrofchannels != 1)
829N/A agc.setOutput(1, buffers[CHANNEL_RIGHT]);
829N/A
829N/A InputStream in = new InputStream() {
829N/A
6321N/A private final SoftAudioBuffer[] buffers = SoftMainMixer.this.buffers;
6321N/A private final int nrofchannels
829N/A = SoftMainMixer.this.synth.getFormat().getChannels();
6321N/A private final int buffersize = buffers[0].getSize();
6321N/A private final byte[] bbuffer = new byte[buffersize
829N/A * (SoftMainMixer.this.synth.getFormat()
829N/A .getSampleSizeInBits() / 8)
829N/A * nrofchannels];
829N/A private int bbuffer_pos = 0;
6321N/A private final byte[] single = new byte[1];
829N/A
829N/A public void fillBuffer() {
829N/A /*
829N/A boolean pusher_silent2;
829N/A synchronized (control_mutex) {
829N/A pusher_silent2 = pusher_silent;
829N/A }
829N/A if(!pusher_silent2)*/
829N/A processAudioBuffers();
829N/A for (int i = 0; i < nrofchannels; i++)
829N/A buffers[i].get(bbuffer, i);
829N/A bbuffer_pos = 0;
829N/A }
829N/A
829N/A public int read(byte[] b, int off, int len) {
829N/A int bbuffer_len = bbuffer.length;
829N/A int offlen = off + len;
829N/A int orgoff = off;
829N/A byte[] bbuffer = this.bbuffer;
829N/A while (off < offlen) {
829N/A if (available() == 0)
829N/A fillBuffer();
829N/A else {
829N/A int bbuffer_pos = this.bbuffer_pos;
829N/A while (off < offlen && bbuffer_pos < bbuffer_len)
829N/A b[off++] = bbuffer[bbuffer_pos++];
829N/A this.bbuffer_pos = bbuffer_pos;
829N/A if (!readfully)
829N/A return off - orgoff;
829N/A }
829N/A }
829N/A return len;
829N/A }
829N/A
829N/A public int read() throws IOException {
829N/A int ret = read(single);
829N/A if (ret == -1)
829N/A return -1;
829N/A return single[0] & 0xFF;
829N/A }
829N/A
829N/A public int available() {
829N/A return bbuffer.length - bbuffer_pos;
829N/A }
829N/A
829N/A public void close() {
829N/A SoftMainMixer.this.synth.close();
829N/A }
829N/A };
829N/A
829N/A ais = new AudioInputStream(in, synth.getFormat(), AudioSystem.NOT_SPECIFIED);
829N/A
829N/A }
829N/A
829N/A public AudioInputStream getInputStream() {
829N/A return ais;
829N/A }
829N/A
829N/A public void reset() {
829N/A
829N/A SoftChannel[] channels = synth.channels;
829N/A for (int i = 0; i < channels.length; i++) {
829N/A channels[i].allSoundOff();
829N/A channels[i].resetAllControllers(true);
829N/A
829N/A if (synth.getGeneralMidiMode() == 2) {
829N/A if (i == 9)
829N/A channels[i].programChange(0, 0x78 * 128);
829N/A else
829N/A channels[i].programChange(0, 0x79 * 128);
829N/A } else
829N/A channels[i].programChange(0, 0);
829N/A }
829N/A setVolume(0x7F * 128 + 0x7F);
829N/A setBalance(0x40 * 128 + 0x00);
829N/A setCoarseTuning(0x40 * 128 + 0x00);
829N/A setFineTuning(0x40 * 128 + 0x00);
829N/A // Reset Reverb
829N/A globalParameterControlChange(
829N/A new int[]{0x01 * 128 + 0x01}, new long[]{0}, new long[]{4});
829N/A // Reset Chorus
829N/A globalParameterControlChange(
829N/A new int[]{0x01 * 128 + 0x02}, new long[]{0}, new long[]{2});
829N/A }
829N/A
829N/A public void setVolume(int value) {
829N/A synchronized (control_mutex) {
829N/A co_master_volume[0] = value / 16384.0;
829N/A }
829N/A }
829N/A
829N/A public void setBalance(int value) {
829N/A synchronized (control_mutex) {
829N/A co_master_balance[0] = value / 16384.0;
829N/A }
829N/A }
829N/A
829N/A public void setFineTuning(int value) {
829N/A synchronized (control_mutex) {
829N/A co_master_fine_tuning[0] = value / 16384.0;
829N/A }
829N/A }
829N/A
829N/A public void setCoarseTuning(int value) {
829N/A synchronized (control_mutex) {
829N/A co_master_coarse_tuning[0] = value / 16384.0;
829N/A }
829N/A }
829N/A
829N/A public int getVolume() {
829N/A synchronized (control_mutex) {
829N/A return (int) (co_master_volume[0] * 16384.0);
829N/A }
829N/A }
829N/A
829N/A public int getBalance() {
829N/A synchronized (control_mutex) {
829N/A return (int) (co_master_balance[0] * 16384.0);
829N/A }
829N/A }
829N/A
829N/A public int getFineTuning() {
829N/A synchronized (control_mutex) {
829N/A return (int) (co_master_fine_tuning[0] * 16384.0);
829N/A }
829N/A }
829N/A
829N/A public int getCoarseTuning() {
829N/A synchronized (control_mutex) {
829N/A return (int) (co_master_coarse_tuning[0] * 16384.0);
829N/A }
829N/A }
829N/A
829N/A public void globalParameterControlChange(int[] slothpath, long[] params,
829N/A long[] paramsvalue) {
829N/A if (slothpath.length == 0)
829N/A return;
829N/A
829N/A synchronized (control_mutex) {
829N/A
829N/A // slothpath: 01xx are reserved only for GM2
829N/A
829N/A if (slothpath[0] == 0x01 * 128 + 0x01) {
829N/A for (int i = 0; i < paramsvalue.length; i++) {
829N/A reverb.globalParameterControlChange(slothpath, params[i],
829N/A paramsvalue[i]);
829N/A }
829N/A }
829N/A if (slothpath[0] == 0x01 * 128 + 0x02) {
829N/A for (int i = 0; i < paramsvalue.length; i++) {
829N/A chorus.globalParameterControlChange(slothpath, params[i],
829N/A paramsvalue[i]);
829N/A }
829N/A
829N/A }
829N/A
829N/A }
829N/A }
829N/A
829N/A public void processMessage(Object object) {
829N/A if (object instanceof byte[])
829N/A processMessage((byte[]) object);
829N/A if (object instanceof MidiMessage)
829N/A processMessage((MidiMessage)object);
829N/A }
829N/A
829N/A public void processMessage(MidiMessage message) {
829N/A if (message instanceof ShortMessage) {
829N/A ShortMessage sms = (ShortMessage)message;
829N/A processMessage(sms.getChannel(), sms.getCommand(),
829N/A sms.getData1(), sms.getData2());
829N/A return;
829N/A }
829N/A processMessage(message.getMessage());
829N/A }
829N/A
829N/A public void processMessage(byte[] data) {
829N/A int status = 0;
829N/A if (data.length > 0)
829N/A status = data[0] & 0xFF;
829N/A
829N/A if (status == 0xF0) {
829N/A processSystemExclusiveMessage(data);
829N/A return;
829N/A }
829N/A
829N/A int cmd = (status & 0xF0);
829N/A int ch = (status & 0x0F);
829N/A
829N/A int data1;
829N/A int data2;
829N/A if (data.length > 1)
829N/A data1 = data[1] & 0xFF;
829N/A else
829N/A data1 = 0;
829N/A if (data.length > 2)
829N/A data2 = data[2] & 0xFF;
829N/A else
829N/A data2 = 0;
829N/A
829N/A processMessage(ch, cmd, data1, data2);
829N/A
829N/A }
829N/A
829N/A public void processMessage(int ch, int cmd, int data1, int data2) {
829N/A synchronized (synth.control_mutex) {
829N/A activity();
829N/A }
829N/A
829N/A if (cmd == 0xF0) {
829N/A int status = cmd | ch;
829N/A switch (status) {
829N/A case ShortMessage.ACTIVE_SENSING:
829N/A synchronized (synth.control_mutex) {
829N/A active_sensing_on = true;
829N/A }
829N/A break;
829N/A default:
829N/A break;
829N/A }
829N/A return;
829N/A }
829N/A
829N/A SoftChannel[] channels = synth.channels;
829N/A if (ch >= channels.length)
829N/A return;
829N/A SoftChannel softchannel = channels[ch];
829N/A
829N/A switch (cmd) {
829N/A case ShortMessage.NOTE_ON:
1990N/A if(delay_midievent != 0)
1990N/A softchannel.noteOn(data1, data2, delay_midievent);
1990N/A else
1990N/A softchannel.noteOn(data1, data2);
829N/A break;
829N/A case ShortMessage.NOTE_OFF:
829N/A softchannel.noteOff(data1, data2);
829N/A break;
829N/A case ShortMessage.POLY_PRESSURE:
829N/A softchannel.setPolyPressure(data1, data2);
829N/A break;
829N/A case ShortMessage.CONTROL_CHANGE:
829N/A softchannel.controlChange(data1, data2);
829N/A break;
829N/A case ShortMessage.PROGRAM_CHANGE:
829N/A softchannel.programChange(data1);
829N/A break;
829N/A case ShortMessage.CHANNEL_PRESSURE:
829N/A softchannel.setChannelPressure(data1);
829N/A break;
829N/A case ShortMessage.PITCH_BEND:
829N/A softchannel.setPitchBend(data1 + data2 * 128);
829N/A break;
829N/A default:
829N/A break;
829N/A }
829N/A
829N/A }
829N/A
829N/A public long getMicrosecondPosition() {
1990N/A if(pusher_silent)
1990N/A {
1990N/A if(synth.weakstream != null)
1990N/A {
1990N/A return (long)((sample_pos + synth.weakstream.silent_samples)
1990N/A * (1000000.0 / samplerate));
1990N/A }
1990N/A }
1990N/A return (long)(sample_pos * (1000000.0 / samplerate));
829N/A }
829N/A
829N/A public void close() {
829N/A }
829N/A}