1145 lines · 43.4 KB · Java
RawDownload
/* * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */package com.sun.media.sound; import java.io.IOException;import java.io.InputStream;import java.util.HashSet;import java.util.Iterator;import java.util.Set;import java.util.TreeMap;import java.util.Map.Entry; import javax.sound.midi.MidiMessage;import javax.sound.midi.Patch;import javax.sound.midi.ShortMessage;import javax.sound.sampled.AudioInputStream;import javax.sound.sampled.AudioSystem; /** * Software synthesizer main audio mixer. * * @author Karl Helgason */public class SoftMainMixer {     // A private class thats contains a ModelChannelMixer and it's private buffers.    // This becomes necessary when we want to have separate delay buffers for each channel mixer.    private class SoftChannelMixerContainer    {        ModelChannelMixer mixer;        SoftAudioBuffer[] buffers;    }     public final static int CHANNEL_LEFT = 0;    public final static int CHANNEL_RIGHT = 1;    public final static int CHANNEL_MONO = 2;    public final static int CHANNEL_DELAY_LEFT = 3;    public final static int CHANNEL_DELAY_RIGHT = 4;    public final static int CHANNEL_DELAY_MONO = 5;    public final static int CHANNEL_EFFECT1 = 6;    public final static int CHANNEL_EFFECT2 = 7;    public final static int CHANNEL_DELAY_EFFECT1 = 8;    public final static int CHANNEL_DELAY_EFFECT2 = 9;    public final static int CHANNEL_LEFT_DRY = 10;    public final static int CHANNEL_RIGHT_DRY = 11;    public final static int CHANNEL_SCRATCH1 = 12;    public final static int CHANNEL_SCRATCH2 = 13;    protected boolean active_sensing_on = false;    private long msec_last_activity = -1;    private boolean pusher_silent = false;    private int pusher_silent_count = 0;    private long sample_pos = 0;    protected boolean readfully = true;    private Object control_mutex;    private SoftSynthesizer synth;    private float samplerate = 44100;    private int nrofchannels = 2;    private SoftVoice[] voicestatus = null;    private SoftAudioBuffer[] buffers;    private SoftReverb reverb;    private SoftAudioProcessor chorus;    private SoftAudioProcessor agc;    private long msec_buffer_len = 0;    private int buffer_len = 0;    protected TreeMap<Long, Object> midimessages = new TreeMap<Long, Object>();    private int delay_midievent = 0;    private int max_delay_midievent = 0;    double last_volume_left = 1.0;    double last_volume_right = 1.0;    private double[] co_master_balance = new double[1];    private double[] co_master_volume = new double[1];    private double[] co_master_coarse_tuning = new double[1];    private double[] co_master_fine_tuning = new double[1];    private AudioInputStream ais;    private Set<SoftChannelMixerContainer> registeredMixers = null;    private Set<ModelChannelMixer> stoppedMixers = null;    private SoftChannelMixerContainer[] cur_registeredMixers = null;    protected SoftControl co_master = new SoftControl() {         double[] balance = co_master_balance;        double[] volume = co_master_volume;        double[] coarse_tuning = co_master_coarse_tuning;        double[] fine_tuning = co_master_fine_tuning;         public double[] get(int instance, String name) {            if (name == null)                return null;            if (name.equals("balance"))                return balance;            if (name.equals("volume"))                return volume;            if (name.equals("coarse_tuning"))                return coarse_tuning;            if (name.equals("fine_tuning"))                return fine_tuning;            return null;        }    };     private void processSystemExclusiveMessage(byte[] data) {        synchronized (synth.control_mutex) {            activity();             // Universal Non-Real-Time SysEx            if ((data[1] & 0xFF) == 0x7E) {                int deviceID = data[2] & 0xFF;                if (deviceID == 0x7F || deviceID == synth.getDeviceID()) {                    int subid1 = data[3] & 0xFF;                    int subid2;                    switch (subid1) {                    case 0x08:  // MIDI Tuning Standard                        subid2 = data[4] & 0xFF;                        switch (subid2) {                        case 0x01:  // BULK TUNING DUMP                        {                            // http://www.midi.org/about-midi/tuning.shtml                            SoftTuning tuning = synth.getTuning(new Patch(0,                                    data[5] & 0xFF));                            tuning.load(data);                            break;                        }                        case 0x04:  // KEY-BASED TUNING DUMP                        case 0x05:  // SCALE/OCTAVE TUNING DUMP, 1 byte format                        case 0x06:  // SCALE/OCTAVE TUNING DUMP, 2 byte format                        case 0x07:  // SINGLE NOTE TUNING CHANGE (NON REAL-TIME)                                    // (BANK)                        {                            // http://www.midi.org/about-midi/tuning_extens.shtml                            SoftTuning tuning = synth.getTuning(new Patch(                                    data[5] & 0xFF, data[6] & 0xFF));                            tuning.load(data);                            break;                        }                        case 0x08:  // scale/octave tuning 1-byte form (Non                                    // Real-Time)                        case 0x09:  // scale/octave tuning 2-byte form (Non                                    // Real-Time)                        {                            // http://www.midi.org/about-midi/tuning-scale.shtml                            SoftTuning tuning = new SoftTuning(data);                            int channelmask = (data[5] & 0xFF) * 16384                                    + (data[6] & 0xFF) * 128 + (data[7] & 0xFF);                            SoftChannel[] channels = synth.channels;                            for (int i = 0; i < channels.length; i++)                                if ((channelmask & (1 << i)) != 0)                                    channels[i].tuning = tuning;                            break;                        }                        default:                            break;                        }                        break;                    case 0x09:  // General Midi Message                        subid2 = data[4] & 0xFF;                        switch (subid2) {                        case 0x01:  // General Midi 1 On                            synth.setGeneralMidiMode(1);                            reset();                            break;                        case 0x02:  // General Midi Off                            synth.setGeneralMidiMode(0);                            reset();                            break;                        case 0x03:  // General MidI Level 2 On                            synth.setGeneralMidiMode(2);                            reset();                            break;                        default:                            break;                        }                        break;                    case 0x0A: // DLS Message                        subid2 = data[4] & 0xFF;                        switch (subid2) {                        case 0x01:  // DLS On                            if (synth.getGeneralMidiMode() == 0)                                synth.setGeneralMidiMode(1);                            synth.voice_allocation_mode = 1;                            reset();                            break;                        case 0x02:  // DLS Off                            synth.setGeneralMidiMode(0);                            synth.voice_allocation_mode = 0;                            reset();                            break;                        case 0x03:  // DLS Static Voice Allocation Off                            synth.voice_allocation_mode = 0;                            break;                        case 0x04:  // DLS Static Voice Allocation On                            synth.voice_allocation_mode = 1;                            break;                        default:                            break;                        }                        break;                     default:                        break;                    }                }            }             // Universal Real-Time SysEx            if ((data[1] & 0xFF) == 0x7F) {                int deviceID = data[2] & 0xFF;                if (deviceID == 0x7F || deviceID == synth.getDeviceID()) {                    int subid1 = data[3] & 0xFF;                    int subid2;                    switch (subid1) {                    case 0x04: // Device Control                         subid2 = data[4] & 0xFF;                        switch (subid2) {                        case 0x01: // Master Volume                        case 0x02: // Master Balane                        case 0x03: // Master fine tuning                        case 0x04: // Master coarse tuning                            int val = (data[5] & 0x7F)                                    + ((data[6] & 0x7F) * 128);                            if (subid2 == 0x01)                                setVolume(val);                            else if (subid2 == 0x02)                                setBalance(val);                            else if (subid2 == 0x03)                                setFineTuning(val);                            else if (subid2 == 0x04)                                setCoarseTuning(val);                            break;                        case 0x05: // Global Parameter Control                            int ix = 5;                            int slotPathLen = (data[ix++] & 0xFF);                            int paramWidth = (data[ix++] & 0xFF);                            int valueWidth = (data[ix++] & 0xFF);                            int[] slotPath = new int[slotPathLen];                            for (int i = 0; i < slotPathLen; i++) {                                int msb = (data[ix++] & 0xFF);                                int lsb = (data[ix++] & 0xFF);                                slotPath[i] = msb * 128 + lsb;                            }                            int paramCount = (data.length - 1 - ix)                                    / (paramWidth + valueWidth);                            long[] params = new long[paramCount];                            long[] values = new long[paramCount];                            for (int i = 0; i < paramCount; i++) {                                values[i] = 0;                                for (int j = 0; j < paramWidth; j++)                                    params[i] = params[i] * 128                                            + (data[ix++] & 0xFF);                                for (int j = 0; j < valueWidth; j++)                                    values[i] = values[i] * 128                                            + (data[ix++] & 0xFF);                             }                            globalParameterControlChange(slotPath, params, values);                            break;                        default:                            break;                        }                        break;                     case 0x08:  // MIDI Tuning Standard                        subid2 = data[4] & 0xFF;                        switch (subid2) {                        case 0x02:  // SINGLE NOTE TUNING CHANGE (REAL-TIME)                        {                            // http://www.midi.org/about-midi/tuning.shtml                            SoftTuning tuning = synth.getTuning(new Patch(0,                                    data[5] & 0xFF));                            tuning.load(data);                            SoftVoice[] voices = synth.getVoices();                            for (int i = 0; i < voices.length; i++)                                if (voices[i].active)                                    if (voices[i].tuning == tuning)                                        voices[i].updateTuning(tuning);                            break;                        }                        case 0x07:  // SINGLE NOTE TUNING CHANGE (REAL-TIME)                                    // (BANK)                        {                            // http://www.midi.org/about-midi/tuning_extens.shtml                            SoftTuning tuning = synth.getTuning(new Patch(                                    data[5] & 0xFF, data[6] & 0xFF));                            tuning.load(data);                            SoftVoice[] voices = synth.getVoices();                            for (int i = 0; i < voices.length; i++)                                if (voices[i].active)                                    if (voices[i].tuning == tuning)                                        voices[i].updateTuning(tuning);                            break;                        }                        case 0x08:  // scale/octave tuning 1-byte form                                    //(Real-Time)                        case 0x09:  // scale/octave tuning 2-byte form                                    // (Real-Time)                        {                            // http://www.midi.org/about-midi/tuning-scale.shtml                            SoftTuning tuning = new SoftTuning(data);                            int channelmask = (data[5] & 0xFF) * 16384                                    + (data[6] & 0xFF) * 128 + (data[7] & 0xFF);                            SoftChannel[] channels = synth.channels;                            for (int i = 0; i < channels.length; i++)                                if ((channelmask & (1 << i)) != 0)                                    channels[i].tuning = tuning;                            SoftVoice[] voices = synth.getVoices();                            for (int i = 0; i < voices.length; i++)                                if (voices[i].active)                                    if ((channelmask & (1 << (voices[i].channel))) != 0)                                        voices[i].updateTuning(tuning);                            break;                        }                        default:                            break;                        }                        break;                    case 0x09:  // Control Destination Settings                        subid2 = data[4] & 0xFF;                        switch (subid2) {                        case 0x01: // Channel Pressure                        {                            int[] destinations = new int[(data.length - 7) / 2];                            int[] ranges = new int[(data.length - 7) / 2];                            int ix = 0;                            for (int j = 6; j < data.length - 1; j += 2) {                                destinations[ix] = data[j] & 0xFF;                                ranges[ix] = data[j + 1] & 0xFF;                                ix++;                            }                            int channel = data[5] & 0xFF;                            SoftChannel softchannel = synth.channels[channel];                            softchannel.mapChannelPressureToDestination(                                    destinations, ranges);                            break;                        }                        case 0x02: // Poly Pressure                        {                            int[] destinations = new int[(data.length - 7) / 2];                            int[] ranges = new int[(data.length - 7) / 2];                            int ix = 0;                            for (int j = 6; j < data.length - 1; j += 2) {                                destinations[ix] = data[j] & 0xFF;                                ranges[ix] = data[j + 1] & 0xFF;                                ix++;                            }                            int channel = data[5] & 0xFF;                            SoftChannel softchannel = synth.channels[channel];                            softchannel.mapPolyPressureToDestination(                                    destinations, ranges);                            break;                        }                        case 0x03: // Control Change                        {                            int[] destinations = new int[(data.length - 7) / 2];                            int[] ranges = new int[(data.length - 7) / 2];                            int ix = 0;                            for (int j = 7; j < data.length - 1; j += 2) {                                destinations[ix] = data[j] & 0xFF;                                ranges[ix] = data[j + 1] & 0xFF;                                ix++;                            }                            int channel = data[5] & 0xFF;                            SoftChannel softchannel = synth.channels[channel];                            int control = data[6] & 0xFF;                            softchannel.mapControlToDestination(control,                                    destinations, ranges);                            break;                        }                        default:                            break;                        }                        break;                     case 0x0A:  // Key Based Instrument Control                    {                        subid2 = data[4] & 0xFF;                        switch (subid2) {                        case 0x01: // Basic Message                            int channel = data[5] & 0xFF;                            int keynumber = data[6] & 0xFF;                            SoftChannel softchannel = synth.channels[channel];                            for (int j = 7; j < data.length - 1; j += 2) {                                int controlnumber = data[j] & 0xFF;                                int controlvalue = data[j + 1] & 0xFF;                                softchannel.controlChangePerNote(keynumber,                                        controlnumber, controlvalue);                            }                            break;                        default:                            break;                        }                        break;                    }                    default:                        break;                    }                }            }         }    }     private void processMessages(long timeStamp) {        Iterator<Entry<Long, Object>> iter = midimessages.entrySet().iterator();        while (iter.hasNext()) {            Entry<Long, Object> entry = iter.next();            if (entry.getKey() >= (timeStamp + msec_buffer_len))                return;            long msec_delay = entry.getKey() - timeStamp;            delay_midievent = (int)(msec_delay * (samplerate / 1000000.0) + 0.5);            if(delay_midievent > max_delay_midievent)                delay_midievent = max_delay_midievent;            if(delay_midievent < 0)                delay_midievent = 0;            processMessage(entry.getValue());            iter.remove();        }        delay_midievent = 0;    }     protected void processAudioBuffers() {         if(synth.weakstream != null && synth.weakstream.silent_samples != 0)        {            sample_pos += synth.weakstream.silent_samples;            synth.weakstream.silent_samples = 0;        }         for (int i = 0; i < buffers.length; i++) {            if(i != CHANNEL_DELAY_LEFT &&                    i != CHANNEL_DELAY_RIGHT &&                    i != CHANNEL_DELAY_MONO &&                    i != CHANNEL_DELAY_EFFECT1 &&                    i != CHANNEL_DELAY_EFFECT2)                buffers[i].clear();        }         if(!buffers[CHANNEL_DELAY_LEFT].isSilent())        {            buffers[CHANNEL_LEFT].swap(buffers[CHANNEL_DELAY_LEFT]);        }        if(!buffers[CHANNEL_DELAY_RIGHT].isSilent())        {            buffers[CHANNEL_RIGHT].swap(buffers[CHANNEL_DELAY_RIGHT]);        }        if(!buffers[CHANNEL_DELAY_MONO].isSilent())        {            buffers[CHANNEL_MONO].swap(buffers[CHANNEL_DELAY_MONO]);        }        if(!buffers[CHANNEL_DELAY_EFFECT1].isSilent())        {            buffers[CHANNEL_EFFECT1].swap(buffers[CHANNEL_DELAY_EFFECT1]);        }        if(!buffers[CHANNEL_DELAY_EFFECT2].isSilent())        {            buffers[CHANNEL_EFFECT2].swap(buffers[CHANNEL_DELAY_EFFECT2]);        }         double volume_left;        double volume_right;         SoftChannelMixerContainer[] act_registeredMixers;         // perform control logic        synchronized (control_mutex) {             long msec_pos = (long)(sample_pos * (1000000.0 / samplerate));             processMessages(msec_pos);             if (active_sensing_on) {                // Active Sensing                // if no message occurs for max 1000 ms                // then do AllSoundOff on all channels                if ((msec_pos - msec_last_activity) > 1000000) {                    active_sensing_on = false;                    for (SoftChannel c : synth.channels)                        c.allSoundOff();                } 

Lines 1–500 of 1145.