| 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
 | 
 | 
package com.sun.media.sound;  | 
 | 
 | 
 | 
import java.io.BufferedInputStream;  | 
 | 
import java.io.File;  | 
 | 
import java.io.FileInputStream;  | 
 | 
import java.io.FileNotFoundException;  | 
 | 
import java.io.FileOutputStream;  | 
 | 
import java.io.IOException;  | 
 | 
import java.io.InputStream;  | 
 | 
import java.io.OutputStream;  | 
 | 
import java.lang.ref.WeakReference;  | 
 | 
import java.security.AccessController;  | 
 | 
import java.security.PrivilegedAction;  | 
 | 
import java.util.ArrayList;  | 
 | 
import java.util.Arrays;  | 
 | 
import java.util.HashMap;  | 
 | 
import java.util.List;  | 
 | 
import java.util.Map;  | 
 | 
import java.util.Properties;  | 
 | 
import java.util.StringTokenizer;  | 
 | 
import java.util.prefs.BackingStoreException;  | 
 | 
import java.util.prefs.Preferences;  | 
 | 
 | 
 | 
import javax.sound.midi.Instrument;  | 
 | 
import javax.sound.midi.MidiChannel;  | 
 | 
import javax.sound.midi.MidiDevice;  | 
 | 
import javax.sound.midi.MidiSystem;  | 
 | 
import javax.sound.midi.MidiUnavailableException;  | 
 | 
import javax.sound.midi.Patch;  | 
 | 
import javax.sound.midi.Receiver;  | 
 | 
import javax.sound.midi.Soundbank;  | 
 | 
import javax.sound.midi.Transmitter;  | 
 | 
import javax.sound.midi.VoiceStatus;  | 
 | 
import javax.sound.sampled.AudioFormat;  | 
 | 
import javax.sound.sampled.AudioInputStream;  | 
 | 
import javax.sound.sampled.AudioSystem;  | 
 | 
import javax.sound.sampled.LineUnavailableException;  | 
 | 
import javax.sound.sampled.SourceDataLine;  | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
public final class SoftSynthesizer implements AudioSynthesizer,  | 
 | 
        ReferenceCountingDevice { | 
 | 
 | 
 | 
    protected static final class WeakAudioStream extends InputStream  | 
 | 
    { | 
 | 
        private volatile AudioInputStream stream;  | 
 | 
        public SoftAudioPusher pusher = null;  | 
 | 
        public AudioInputStream jitter_stream = null;  | 
 | 
        public SourceDataLine sourceDataLine = null;  | 
 | 
        public volatile long silent_samples = 0;  | 
 | 
        private int framesize = 0;  | 
 | 
        private WeakReference<AudioInputStream> weak_stream_link;  | 
 | 
        private AudioFloatConverter converter;  | 
 | 
        private float[] silentbuffer = null;  | 
 | 
        private int samplesize;  | 
 | 
 | 
 | 
        public void setInputStream(AudioInputStream stream)  | 
 | 
        { | 
 | 
            this.stream = stream;  | 
 | 
        }  | 
 | 
 | 
 | 
        public int available() throws IOException { | 
 | 
            AudioInputStream local_stream = stream;  | 
 | 
            if(local_stream != null)  | 
 | 
                return local_stream.available();  | 
 | 
            return 0;  | 
 | 
        }  | 
 | 
 | 
 | 
        public int read() throws IOException { | 
 | 
             byte[] b = new byte[1];  | 
 | 
             if (read(b) == -1)  | 
 | 
                  return -1;  | 
 | 
             return b[0] & 0xFF;  | 
 | 
        }  | 
 | 
 | 
 | 
        public int read(byte[] b, int off, int len) throws IOException { | 
 | 
             AudioInputStream local_stream = stream;  | 
 | 
             if(local_stream != null)  | 
 | 
                 return local_stream.read(b, off, len);  | 
 | 
             else  | 
 | 
             { | 
 | 
                 int flen = len / samplesize;  | 
 | 
                 if(silentbuffer == null || silentbuffer.length < flen)  | 
 | 
                     silentbuffer = new float[flen];  | 
 | 
                 converter.toByteArray(silentbuffer, flen, b, off);  | 
 | 
 | 
 | 
                 silent_samples += (long)((len / framesize));  | 
 | 
 | 
 | 
                 if(pusher != null)  | 
 | 
                 if(weak_stream_link.get() == null)  | 
 | 
                 { | 
 | 
                     Runnable runnable = new Runnable()  | 
 | 
                     { | 
 | 
                         SoftAudioPusher _pusher = pusher;  | 
 | 
                         AudioInputStream _jitter_stream = jitter_stream;  | 
 | 
                         SourceDataLine _sourceDataLine = sourceDataLine;  | 
 | 
                         public void run()  | 
 | 
                         { | 
 | 
                             _pusher.stop();  | 
 | 
                             if(_jitter_stream != null)  | 
 | 
                                try { | 
 | 
                                    _jitter_stream.close();  | 
 | 
                                } catch (IOException e) { | 
 | 
                                    e.printStackTrace();  | 
 | 
                                }  | 
 | 
                             if(_sourceDataLine != null)  | 
 | 
                                 _sourceDataLine.close();  | 
 | 
                         }  | 
 | 
                     };  | 
 | 
                     pusher = null;  | 
 | 
                     jitter_stream = null;  | 
 | 
                     sourceDataLine = null;  | 
 | 
                     new Thread(runnable).start();  | 
 | 
                 }  | 
 | 
                 return len;  | 
 | 
             }  | 
 | 
        }  | 
 | 
 | 
 | 
        public WeakAudioStream(AudioInputStream stream) { | 
 | 
            this.stream = stream;  | 
 | 
            weak_stream_link = new WeakReference<AudioInputStream>(stream);  | 
 | 
            converter = AudioFloatConverter.getConverter(stream.getFormat());  | 
 | 
            samplesize = stream.getFormat().getFrameSize() / stream.getFormat().getChannels();  | 
 | 
            framesize = stream.getFormat().getFrameSize();  | 
 | 
        }  | 
 | 
 | 
 | 
        public AudioInputStream getAudioInputStream()  | 
 | 
        { | 
 | 
            return new AudioInputStream(this, stream.getFormat(), AudioSystem.NOT_SPECIFIED);  | 
 | 
        }  | 
 | 
 | 
 | 
        public void close() throws IOException  | 
 | 
        { | 
 | 
            AudioInputStream astream  = weak_stream_link.get();  | 
 | 
            if(astream != null)  | 
 | 
                astream.close();  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    private static class Info extends MidiDevice.Info { | 
 | 
        Info() { | 
 | 
            super(INFO_NAME, INFO_VENDOR, INFO_DESCRIPTION, INFO_VERSION);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    static final String INFO_NAME = "Gervill";  | 
 | 
    static final String INFO_VENDOR = "OpenJDK";  | 
 | 
    static final String INFO_DESCRIPTION = "Software MIDI Synthesizer";  | 
 | 
    static final String INFO_VERSION = "1.0";  | 
 | 
    final static MidiDevice.Info info = new Info();  | 
 | 
 | 
 | 
    private static SourceDataLine testline = null;  | 
 | 
 | 
 | 
    private static Soundbank defaultSoundBank = null;  | 
 | 
 | 
 | 
    WeakAudioStream weakstream = null;  | 
 | 
 | 
 | 
    final Object control_mutex = this;  | 
 | 
 | 
 | 
    int voiceIDCounter = 0;  | 
 | 
 | 
 | 
    // 0: default  | 
 | 
      | 
 | 
    int voice_allocation_mode = 0;  | 
 | 
 | 
 | 
    boolean load_default_soundbank = false;  | 
 | 
    boolean reverb_light = true;  | 
 | 
    boolean reverb_on = true;  | 
 | 
    boolean chorus_on = true;  | 
 | 
    boolean agc_on = true;  | 
 | 
 | 
 | 
    SoftChannel[] channels;  | 
 | 
    SoftChannelProxy[] external_channels = null;  | 
 | 
 | 
 | 
    private boolean largemode = false;  | 
 | 
 | 
 | 
    // 0: GM Mode off (default)  | 
 | 
    // 1: GM Level 1  | 
 | 
      | 
 | 
    private int gmmode = 0;  | 
 | 
 | 
 | 
    private int deviceid = 0;  | 
 | 
 | 
 | 
    private AudioFormat format = new AudioFormat(44100, 16, 2, true, false);  | 
 | 
 | 
 | 
    private SourceDataLine sourceDataLine = null;  | 
 | 
 | 
 | 
    private SoftAudioPusher pusher = null;  | 
 | 
    private AudioInputStream pusher_stream = null;  | 
 | 
 | 
 | 
    private float controlrate = 147f;  | 
 | 
 | 
 | 
    private boolean open = false;  | 
 | 
    private boolean implicitOpen = false;  | 
 | 
 | 
 | 
    private String resamplerType = "linear";  | 
 | 
    private SoftResampler resampler = new SoftLinearResampler();  | 
 | 
 | 
 | 
    private int number_of_midi_channels = 16;  | 
 | 
    private int maxpoly = 64;  | 
 | 
    private long latency = 200000;   | 
 | 
    private boolean jitter_correction = false;  | 
 | 
 | 
 | 
    private SoftMainMixer mainmixer;  | 
 | 
    private SoftVoice[] voices;  | 
 | 
 | 
 | 
    private Map<String, SoftTuning> tunings  | 
 | 
            = new HashMap<String, SoftTuning>();  | 
 | 
    private Map<String, SoftInstrument> inslist  | 
 | 
            = new HashMap<String, SoftInstrument>();  | 
 | 
    private Map<String, ModelInstrument> loadedlist  | 
 | 
            = new HashMap<String, ModelInstrument>();  | 
 | 
 | 
 | 
    private ArrayList<Receiver> recvslist = new ArrayList<Receiver>();  | 
 | 
 | 
 | 
    private void getBuffers(ModelInstrument instrument,  | 
 | 
            List<ModelByteBuffer> buffers) { | 
 | 
        for (ModelPerformer performer : instrument.getPerformers()) { | 
 | 
            if (performer.getOscillators() != null) { | 
 | 
                for (ModelOscillator osc : performer.getOscillators()) { | 
 | 
                    if (osc instanceof ModelByteBufferWavetable) { | 
 | 
                        ModelByteBufferWavetable w = (ModelByteBufferWavetable)osc;  | 
 | 
                        ModelByteBuffer buff = w.getBuffer();  | 
 | 
                        if (buff != null)  | 
 | 
                            buffers.add(buff);  | 
 | 
                        buff = w.get8BitExtensionBuffer();  | 
 | 
                        if (buff != null)  | 
 | 
                            buffers.add(buff);  | 
 | 
                    }  | 
 | 
                }  | 
 | 
            }  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    private boolean loadSamples(List<ModelInstrument> instruments) { | 
 | 
        if (largemode)  | 
 | 
            return true;  | 
 | 
        List<ModelByteBuffer> buffers = new ArrayList<ModelByteBuffer>();  | 
 | 
        for (ModelInstrument instrument : instruments)  | 
 | 
            getBuffers(instrument, buffers);  | 
 | 
        try { | 
 | 
            ModelByteBuffer.loadAll(buffers);  | 
 | 
        } catch (IOException e) { | 
 | 
            return false;  | 
 | 
        }  | 
 | 
        return true;  | 
 | 
    }  | 
 | 
 | 
 | 
    private boolean loadInstruments(List<ModelInstrument> instruments) { | 
 | 
        if (!isOpen())  | 
 | 
            return false;  | 
 | 
        if (!loadSamples(instruments))  | 
 | 
            return false;  | 
 | 
 | 
 | 
        synchronized (control_mutex) { | 
 | 
            if (channels != null)  | 
 | 
                for (SoftChannel c : channels)  | 
 | 
                { | 
 | 
                    c.current_instrument = null;  | 
 | 
                    c.current_director = null;  | 
 | 
                }  | 
 | 
            for (Instrument instrument : instruments) { | 
 | 
                String pat = patchToString(instrument.getPatch());  | 
 | 
                SoftInstrument softins  | 
 | 
                        = new SoftInstrument((ModelInstrument) instrument);  | 
 | 
                inslist.put(pat, softins);  | 
 | 
                loadedlist.put(pat, (ModelInstrument) instrument);  | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
        return true;  | 
 | 
    }  | 
 | 
 | 
 | 
    private void processPropertyInfo(Map<String, Object> info) { | 
 | 
        AudioSynthesizerPropertyInfo[] items = getPropertyInfo(info);  | 
 | 
 | 
 | 
        String resamplerType = (String)items[0].value;  | 
 | 
        if (resamplerType.equalsIgnoreCase("point")) | 
 | 
        { | 
 | 
            this.resampler = new SoftPointResampler();  | 
 | 
            this.resamplerType = "point";  | 
 | 
        }  | 
 | 
        else if (resamplerType.equalsIgnoreCase("linear")) | 
 | 
        { | 
 | 
            this.resampler = new SoftLinearResampler2();  | 
 | 
            this.resamplerType = "linear";  | 
 | 
        }  | 
 | 
        else if (resamplerType.equalsIgnoreCase("linear1")) | 
 | 
        { | 
 | 
            this.resampler = new SoftLinearResampler();  | 
 | 
            this.resamplerType = "linear1";  | 
 | 
        }  | 
 | 
        else if (resamplerType.equalsIgnoreCase("linear2")) | 
 | 
        { | 
 | 
            this.resampler = new SoftLinearResampler2();  | 
 | 
            this.resamplerType = "linear2";  | 
 | 
        }  | 
 | 
        else if (resamplerType.equalsIgnoreCase("cubic")) | 
 | 
        { | 
 | 
            this.resampler = new SoftCubicResampler();  | 
 | 
            this.resamplerType = "cubic";  | 
 | 
        }  | 
 | 
        else if (resamplerType.equalsIgnoreCase("lanczos")) | 
 | 
        { | 
 | 
            this.resampler = new SoftLanczosResampler();  | 
 | 
            this.resamplerType = "lanczos";  | 
 | 
        }  | 
 | 
        else if (resamplerType.equalsIgnoreCase("sinc")) | 
 | 
        { | 
 | 
            this.resampler = new SoftSincResampler();  | 
 | 
            this.resamplerType = "sinc";  | 
 | 
        }  | 
 | 
 | 
 | 
        setFormat((AudioFormat)items[2].value);  | 
 | 
        controlrate = (Float)items[1].value;  | 
 | 
        latency = (Long)items[3].value;  | 
 | 
        deviceid = (Integer)items[4].value;  | 
 | 
        maxpoly = (Integer)items[5].value;  | 
 | 
        reverb_on = (Boolean)items[6].value;  | 
 | 
        chorus_on = (Boolean)items[7].value;  | 
 | 
        agc_on = (Boolean)items[8].value;  | 
 | 
        largemode = (Boolean)items[9].value;  | 
 | 
        number_of_midi_channels = (Integer)items[10].value;  | 
 | 
        jitter_correction = (Boolean)items[11].value;  | 
 | 
        reverb_light = (Boolean)items[12].value;  | 
 | 
        load_default_soundbank = (Boolean)items[13].value;  | 
 | 
    }  | 
 | 
 | 
 | 
    private String patchToString(Patch patch) { | 
 | 
        if (patch instanceof ModelPatch && ((ModelPatch) patch).isPercussion())  | 
 | 
            return "p." + patch.getProgram() + "." + patch.getBank();  | 
 | 
        else  | 
 | 
            return patch.getProgram() + "." + patch.getBank();  | 
 | 
    }  | 
 | 
 | 
 | 
    private void setFormat(AudioFormat format) { | 
 | 
        if (format.getChannels() > 2) { | 
 | 
            throw new IllegalArgumentException(  | 
 | 
                    "Only mono and stereo audio supported.");  | 
 | 
        }  | 
 | 
        if (AudioFloatConverter.getConverter(format) == null)  | 
 | 
            throw new IllegalArgumentException("Audio format not supported."); | 
 | 
        this.format = format;  | 
 | 
    }  | 
 | 
 | 
 | 
    void removeReceiver(Receiver recv) { | 
 | 
        boolean perform_close = false;  | 
 | 
        synchronized (control_mutex) { | 
 | 
            if (recvslist.remove(recv)) { | 
 | 
                if (implicitOpen && recvslist.isEmpty())  | 
 | 
                    perform_close = true;  | 
 | 
            }  | 
 | 
        }  | 
 | 
        if (perform_close)  | 
 | 
            close();  | 
 | 
    }  | 
 | 
 | 
 | 
    SoftMainMixer getMainMixer() { | 
 | 
        if (!isOpen())  | 
 | 
            return null;  | 
 | 
        return mainmixer;  | 
 | 
    }  | 
 | 
 | 
 | 
    SoftInstrument findInstrument(int program, int bank, int channel) { | 
 | 
 | 
 | 
        // Add support for GM2 banks 0x78 and 0x79  | 
 | 
        // as specified in DLS 2.2 in Section 1.4.6  | 
 | 
        // which allows using percussion and melodic instruments  | 
 | 
          | 
 | 
        if (bank >> 7 == 0x78 || bank >> 7 == 0x79) { | 
 | 
            SoftInstrument current_instrument  | 
 | 
                    = inslist.get(program + "." + bank);  | 
 | 
            if (current_instrument != null)  | 
 | 
                return current_instrument;  | 
 | 
 | 
 | 
            String p_plaf;  | 
 | 
            if (bank >> 7 == 0x78)  | 
 | 
                p_plaf = "p.";  | 
 | 
            else  | 
 | 
                p_plaf = "";  | 
 | 
 | 
 | 
              | 
 | 
            current_instrument = inslist.get(p_plaf + program + "."  | 
 | 
                    + ((bank & 128) << 7));  | 
 | 
            if (current_instrument != null)  | 
 | 
                return current_instrument;  | 
 | 
              | 
 | 
            current_instrument = inslist.get(p_plaf + program + "."  | 
 | 
                    + (bank & 128));  | 
 | 
            if (current_instrument != null)  | 
 | 
                return current_instrument;  | 
 | 
              | 
 | 
            current_instrument = inslist.get(p_plaf + program + ".0");  | 
 | 
            if (current_instrument != null)  | 
 | 
                return current_instrument;  | 
 | 
              | 
 | 
            current_instrument = inslist.get(p_plaf + program + "0.0");  | 
 | 
            if (current_instrument != null)  | 
 | 
                return current_instrument;  | 
 | 
            return null;  | 
 | 
        }  | 
 | 
 | 
 | 
          | 
 | 
        String p_plaf;  | 
 | 
        if (channel == 9)  | 
 | 
            p_plaf = "p.";  | 
 | 
        else  | 
 | 
            p_plaf = "";  | 
 | 
 | 
 | 
        SoftInstrument current_instrument  | 
 | 
                = inslist.get(p_plaf + program + "." + bank);  | 
 | 
        if (current_instrument != null)  | 
 | 
            return current_instrument;  | 
 | 
          | 
 | 
        current_instrument = inslist.get(p_plaf + program + ".0");  | 
 | 
        if (current_instrument != null)  | 
 | 
            return current_instrument;  | 
 | 
          | 
 | 
        current_instrument = inslist.get(p_plaf + "0.0");  | 
 | 
        if (current_instrument != null)  | 
 | 
            return current_instrument;  | 
 | 
        return null;  | 
 | 
    }  | 
 | 
 | 
 | 
    int getVoiceAllocationMode() { | 
 | 
        return voice_allocation_mode;  | 
 | 
    }  | 
 | 
 | 
 | 
    int getGeneralMidiMode() { | 
 | 
        return gmmode;  | 
 | 
    }  | 
 | 
 | 
 | 
    void setGeneralMidiMode(int gmmode) { | 
 | 
        this.gmmode = gmmode;  | 
 | 
    }  | 
 | 
 | 
 | 
    int getDeviceID() { | 
 | 
        return deviceid;  | 
 | 
    }  | 
 | 
 | 
 | 
    float getControlRate() { | 
 | 
        return controlrate;  | 
 | 
    }  | 
 | 
 | 
 | 
    SoftVoice[] getVoices() { | 
 | 
        return voices;  | 
 | 
    }  | 
 | 
 | 
 | 
    SoftTuning getTuning(Patch patch) { | 
 | 
        String t_id = patchToString(patch);  | 
 | 
        SoftTuning tuning = tunings.get(t_id);  | 
 | 
        if (tuning == null) { | 
 | 
            tuning = new SoftTuning(patch);  | 
 | 
            tunings.put(t_id, tuning);  | 
 | 
        }  | 
 | 
        return tuning;  | 
 | 
    }  | 
 | 
 | 
 | 
    public long getLatency() { | 
 | 
        synchronized (control_mutex) { | 
 | 
            return latency;  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    public AudioFormat getFormat() { | 
 | 
        synchronized (control_mutex) { | 
 | 
            return format;  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    public int getMaxPolyphony() { | 
 | 
        synchronized (control_mutex) { | 
 | 
            return maxpoly;  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    public MidiChannel[] getChannels() { | 
 | 
 | 
 | 
        synchronized (control_mutex) { | 
 | 
            // if (external_channels == null) => the synthesizer is not open,  | 
 | 
            // create 16 proxy channels  | 
 | 
              | 
 | 
            if (external_channels == null) { | 
 | 
                external_channels = new SoftChannelProxy[16];  | 
 | 
                for (int i = 0; i < external_channels.length; i++)  | 
 | 
                    external_channels[i] = new SoftChannelProxy();  | 
 | 
            }  | 
 | 
            MidiChannel[] ret;  | 
 | 
            if (isOpen())  | 
 | 
                ret = new MidiChannel[channels.length];  | 
 | 
            else  | 
 | 
                ret = new MidiChannel[16];  | 
 | 
            for (int i = 0; i < ret.length; i++)  | 
 | 
                ret[i] = external_channels[i];  | 
 | 
            return ret;  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    public VoiceStatus[] getVoiceStatus() { | 
 | 
        if (!isOpen()) { | 
 | 
            VoiceStatus[] tempVoiceStatusArray  | 
 | 
                    = new VoiceStatus[getMaxPolyphony()];  | 
 | 
            for (int i = 0; i < tempVoiceStatusArray.length; i++) { | 
 | 
                VoiceStatus b = new VoiceStatus();  | 
 | 
                b.active = false;  | 
 | 
                b.bank = 0;  | 
 | 
                b.channel = 0;  | 
 | 
                b.note = 0;  | 
 | 
                b.program = 0;  | 
 | 
                b.volume = 0;  | 
 | 
                tempVoiceStatusArray[i] = b;  | 
 | 
            }  | 
 | 
            return tempVoiceStatusArray;  | 
 | 
        }  | 
 | 
 | 
 | 
        synchronized (control_mutex) { | 
 | 
            VoiceStatus[] tempVoiceStatusArray = new VoiceStatus[voices.length];  | 
 | 
            for (int i = 0; i < voices.length; i++) { | 
 | 
                VoiceStatus a = voices[i];  | 
 | 
                VoiceStatus b = new VoiceStatus();  | 
 | 
                b.active = a.active;  | 
 | 
                b.bank = a.bank;  | 
 | 
                b.channel = a.channel;  | 
 | 
                b.note = a.note;  | 
 | 
                b.program = a.program;  | 
 | 
                b.volume = a.volume;  | 
 | 
                tempVoiceStatusArray[i] = b;  | 
 | 
            }  | 
 | 
            return tempVoiceStatusArray;  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    public boolean isSoundbankSupported(Soundbank soundbank) { | 
 | 
        for (Instrument ins: soundbank.getInstruments())  | 
 | 
            if (!(ins instanceof ModelInstrument))  | 
 | 
                return false;  | 
 | 
        return true;  | 
 | 
    }  | 
 | 
 | 
 | 
    public boolean loadInstrument(Instrument instrument) { | 
 | 
        if (instrument == null || (!(instrument instanceof ModelInstrument))) { | 
 | 
            throw new IllegalArgumentException("Unsupported instrument: " + | 
 | 
                    instrument);  | 
 | 
        }  | 
 | 
        List<ModelInstrument> instruments = new ArrayList<ModelInstrument>();  | 
 | 
        instruments.add((ModelInstrument)instrument);  | 
 | 
        return loadInstruments(instruments);  | 
 | 
    }  | 
 | 
 | 
 | 
    public void unloadInstrument(Instrument instrument) { | 
 | 
        if (instrument == null || (!(instrument instanceof ModelInstrument))) { | 
 | 
            throw new IllegalArgumentException("Unsupported instrument: " + | 
 | 
                    instrument);  | 
 | 
        }  | 
 | 
        if (!isOpen())  | 
 | 
            return;  | 
 | 
 | 
 | 
        String pat = patchToString(instrument.getPatch());  | 
 | 
        synchronized (control_mutex) { | 
 | 
            for (SoftChannel c: channels)  | 
 | 
                c.current_instrument = null;  | 
 | 
            inslist.remove(pat);  | 
 | 
            loadedlist.remove(pat);  | 
 | 
            for (int i = 0; i < channels.length; i++) { | 
 | 
                channels[i].allSoundOff();  | 
 | 
            }  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    public boolean remapInstrument(Instrument from, Instrument to) { | 
 | 
 | 
 | 
        if (from == null)  | 
 | 
            throw new NullPointerException();  | 
 | 
        if (to == null)  | 
 | 
            throw new NullPointerException();  | 
 | 
        if (!(from instanceof ModelInstrument)) { | 
 | 
            throw new IllegalArgumentException("Unsupported instrument: " + | 
 | 
                    from.toString());  | 
 | 
        }  | 
 | 
        if (!(to instanceof ModelInstrument)) { | 
 | 
            throw new IllegalArgumentException("Unsupported instrument: " + | 
 | 
                    to.toString());  | 
 | 
        }  | 
 | 
        if (!isOpen())  | 
 | 
            return false;  | 
 | 
 | 
 | 
        synchronized (control_mutex) { | 
 | 
            if (!loadedlist.containsValue(to))  | 
 | 
                throw new IllegalArgumentException("Instrument to is not loaded."); | 
 | 
            unloadInstrument(from);  | 
 | 
            ModelMappedInstrument mfrom = new ModelMappedInstrument(  | 
 | 
                    (ModelInstrument)to, from.getPatch());  | 
 | 
            return loadInstrument(mfrom);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    public Soundbank getDefaultSoundbank() { | 
 | 
        synchronized (SoftSynthesizer.class) { | 
 | 
            if (defaultSoundBank != null)  | 
 | 
                return defaultSoundBank;  | 
 | 
 | 
 | 
            List<PrivilegedAction<InputStream>> actions =  | 
 | 
                new ArrayList<PrivilegedAction<InputStream>>();  | 
 | 
 | 
 | 
            actions.add(new PrivilegedAction<InputStream>() { | 
 | 
                public InputStream run() { | 
 | 
                    File javahome = new File(System.getProperties()  | 
 | 
                            .getProperty("java.home")); | 
 | 
                    File libaudio = new File(new File(javahome, "lib"), "audio");  | 
 | 
                    if (libaudio.exists()) { | 
 | 
                        File foundfile = null;  | 
 | 
                        File[] files = libaudio.listFiles();  | 
 | 
                        if (files != null) { | 
 | 
                            for (int i = 0; i < files.length; i++) { | 
 | 
                                File file = files[i];  | 
 | 
                                if (file.isFile()) { | 
 | 
                                    String lname = file.getName().toLowerCase();  | 
 | 
                                    if (lname.endsWith(".sf2") | 
 | 
                                            || lname.endsWith(".dls")) { | 
 | 
                                        if (foundfile == null  | 
 | 
                                                || (file.length() > foundfile  | 
 | 
                                                        .length())) { | 
 | 
                                            foundfile = file;  | 
 | 
                                        }  | 
 | 
                                    }  | 
 | 
                                }  | 
 | 
                            }  | 
 | 
                        }  | 
 | 
                        if (foundfile != null) { | 
 | 
                            try { | 
 | 
                                return new FileInputStream(foundfile);  | 
 | 
                            } catch (IOException e) { | 
 | 
                            }  | 
 | 
                        }  | 
 | 
                    }  | 
 | 
                    return null;  | 
 | 
                }  | 
 | 
            });  | 
 | 
 | 
 | 
            actions.add(new PrivilegedAction<InputStream>() { | 
 | 
                public InputStream run() { | 
 | 
                    if (System.getProperties().getProperty("os.name") | 
 | 
                            .startsWith("Linux")) { | 
 | 
 | 
 | 
                        File[] systemSoundFontsDir = new File[] { | 
 | 
                              | 
 | 
                            new File("/usr/share/soundfonts/"), | 
 | 
                            new File("/usr/local/share/soundfonts/"), | 
 | 
                              | 
 | 
                            new File("/usr/share/sounds/sf2/"), | 
 | 
                            new File("/usr/local/share/sounds/sf2/"), | 
 | 
                        };  | 
 | 
 | 
 | 
                          | 
 | 
 | 
 | 
                         */  | 
 | 
                        for (File systemSoundFontDir : systemSoundFontsDir) { | 
 | 
                            if (systemSoundFontDir.exists()) { | 
 | 
                                File defaultSoundFont = new File(systemSoundFontDir, "default.sf2");  | 
 | 
                                if (defaultSoundFont.exists()) { | 
 | 
                                    try { | 
 | 
                                        return new FileInputStream(defaultSoundFont);  | 
 | 
                                    } catch (IOException e) { | 
 | 
                                        // continue with lookup  | 
 | 
                                    }  | 
 | 
                                }  | 
 | 
                            }  | 
 | 
                        }  | 
 | 
                    }  | 
 | 
                    return null;  | 
 | 
                }  | 
 | 
            });  | 
 | 
 | 
 | 
            actions.add(new PrivilegedAction<InputStream>() { | 
 | 
                public InputStream run() { | 
 | 
                    if (System.getProperties().getProperty("os.name") | 
 | 
                            .startsWith("Windows")) { | 
 | 
                        File gm_dls = new File(System.getenv("SystemRoot") | 
 | 
                                + "\\system32\\drivers\\gm.dls");  | 
 | 
                        if (gm_dls.exists()) { | 
 | 
                            try { | 
 | 
                                return new FileInputStream(gm_dls);  | 
 | 
                            } catch (IOException e) { | 
 | 
                            }  | 
 | 
                        }  | 
 | 
                    }  | 
 | 
                    return null;  | 
 | 
                }  | 
 | 
            });  | 
 | 
 | 
 | 
            actions.add(new PrivilegedAction<InputStream>() { | 
 | 
                public InputStream run() { | 
 | 
                      | 
 | 
 | 
 | 
                     */  | 
 | 
                    File userhome = new File(System.getProperty("user.home"), | 
 | 
                            ".gervill");  | 
 | 
                    File emg_soundbank_file = new File(userhome,  | 
 | 
                            "soundbank-emg.sf2");  | 
 | 
                    if (emg_soundbank_file.exists()) { | 
 | 
                        try { | 
 | 
                            return new FileInputStream(emg_soundbank_file);  | 
 | 
                        } catch (IOException e) { | 
 | 
                        }  | 
 | 
                    }  | 
 | 
                    return null;  | 
 | 
                }  | 
 | 
            });  | 
 | 
 | 
 | 
            for (PrivilegedAction<InputStream> action : actions) { | 
 | 
                try { | 
 | 
                    InputStream is = AccessController.doPrivileged(action);  | 
 | 
                    if(is == null) continue;  | 
 | 
                    Soundbank sbk;  | 
 | 
                    try { | 
 | 
                        sbk = MidiSystem.getSoundbank(new BufferedInputStream(is));  | 
 | 
                    } finally { | 
 | 
                        is.close();  | 
 | 
                    }  | 
 | 
                    if (sbk != null) { | 
 | 
                        defaultSoundBank = sbk;  | 
 | 
                        return defaultSoundBank;  | 
 | 
                    }  | 
 | 
                } catch (Exception e) { | 
 | 
                }  | 
 | 
            }  | 
 | 
 | 
 | 
            try { | 
 | 
                  | 
 | 
 | 
 | 
                 */  | 
 | 
                defaultSoundBank = EmergencySoundbank.createSoundbank();  | 
 | 
            } catch (Exception e) { | 
 | 
            }  | 
 | 
 | 
 | 
            if (defaultSoundBank != null) { | 
 | 
                  | 
 | 
 | 
 | 
                 */  | 
 | 
                OutputStream out = AccessController  | 
 | 
                        .doPrivileged((PrivilegedAction<OutputStream>) () -> { | 
 | 
                            try { | 
 | 
                                File userhome = new File(System  | 
 | 
                                        .getProperty("user.home"), ".gervill"); | 
 | 
                                if (!userhome.exists()) { | 
 | 
                                    userhome.mkdirs();  | 
 | 
                                }  | 
 | 
                                File emg_soundbank_file = new File(  | 
 | 
                                        userhome, "soundbank-emg.sf2");  | 
 | 
                                if (emg_soundbank_file.exists()) { | 
 | 
                                    return null;  | 
 | 
                                }  | 
 | 
                                return new FileOutputStream(emg_soundbank_file);  | 
 | 
                            } catch (final FileNotFoundException ignored) { | 
 | 
                            }  | 
 | 
                            return null;  | 
 | 
                        });  | 
 | 
                if (out != null) { | 
 | 
                    try { | 
 | 
                        ((SF2Soundbank) defaultSoundBank).save(out);  | 
 | 
                        out.close();  | 
 | 
                    } catch (final IOException ignored) { | 
 | 
                    }  | 
 | 
                }  | 
 | 
            }  | 
 | 
        }  | 
 | 
        return defaultSoundBank;  | 
 | 
    }  | 
 | 
 | 
 | 
    public Instrument[] getAvailableInstruments() { | 
 | 
        Soundbank defsbk = getDefaultSoundbank();  | 
 | 
        if (defsbk == null)  | 
 | 
            return new Instrument[0];  | 
 | 
        Instrument[] inslist_array = defsbk.getInstruments();  | 
 | 
        Arrays.sort(inslist_array, new ModelInstrumentComparator());  | 
 | 
        return inslist_array;  | 
 | 
    }  | 
 | 
 | 
 | 
    public Instrument[] getLoadedInstruments() { | 
 | 
        if (!isOpen())  | 
 | 
            return new Instrument[0];  | 
 | 
 | 
 | 
        synchronized (control_mutex) { | 
 | 
            ModelInstrument[] inslist_array =  | 
 | 
                    new ModelInstrument[loadedlist.values().size()];  | 
 | 
            loadedlist.values().toArray(inslist_array);  | 
 | 
            Arrays.sort(inslist_array, new ModelInstrumentComparator());  | 
 | 
            return inslist_array;  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    public boolean loadAllInstruments(Soundbank soundbank) { | 
 | 
        List<ModelInstrument> instruments = new ArrayList<ModelInstrument>();  | 
 | 
        for (Instrument ins: soundbank.getInstruments()) { | 
 | 
            if (ins == null || !(ins instanceof ModelInstrument)) { | 
 | 
                throw new IllegalArgumentException(  | 
 | 
                        "Unsupported instrument: " + ins);  | 
 | 
            }  | 
 | 
            instruments.add((ModelInstrument)ins);  | 
 | 
        }  | 
 | 
        return loadInstruments(instruments);  | 
 | 
    }  | 
 | 
 | 
 | 
    public void unloadAllInstruments(Soundbank soundbank) { | 
 | 
        if (soundbank == null || !isSoundbankSupported(soundbank))  | 
 | 
            throw new IllegalArgumentException("Unsupported soundbank: " + soundbank); | 
 | 
 | 
 | 
        if (!isOpen())  | 
 | 
            return;  | 
 | 
 | 
 | 
        for (Instrument ins: soundbank.getInstruments()) { | 
 | 
            if (ins instanceof ModelInstrument) { | 
 | 
                unloadInstrument(ins);  | 
 | 
            }  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    public boolean loadInstruments(Soundbank soundbank, Patch[] patchList) { | 
 | 
        List<ModelInstrument> instruments = new ArrayList<ModelInstrument>();  | 
 | 
        for (Patch patch: patchList) { | 
 | 
            Instrument ins = soundbank.getInstrument(patch);  | 
 | 
            if (ins == null || !(ins instanceof ModelInstrument)) { | 
 | 
                throw new IllegalArgumentException(  | 
 | 
                        "Unsupported instrument: " + ins);  | 
 | 
            }  | 
 | 
            instruments.add((ModelInstrument)ins);  | 
 | 
        }  | 
 | 
        return loadInstruments(instruments);  | 
 | 
    }  | 
 | 
 | 
 | 
    public void unloadInstruments(Soundbank soundbank, Patch[] patchList) { | 
 | 
        if (soundbank == null || !isSoundbankSupported(soundbank))  | 
 | 
            throw new IllegalArgumentException("Unsupported soundbank: " + soundbank); | 
 | 
 | 
 | 
        if (!isOpen())  | 
 | 
            return;  | 
 | 
 | 
 | 
        for (Patch pat: patchList) { | 
 | 
            Instrument ins = soundbank.getInstrument(pat);  | 
 | 
            if (ins instanceof ModelInstrument) { | 
 | 
                unloadInstrument(ins);  | 
 | 
            }  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    public MidiDevice.Info getDeviceInfo() { | 
 | 
        return info;  | 
 | 
    }  | 
 | 
 | 
 | 
    private Properties getStoredProperties() { | 
 | 
        return AccessController  | 
 | 
                .doPrivileged((PrivilegedAction<Properties>) () -> { | 
 | 
                    Properties p = new Properties();  | 
 | 
                    String notePath = "/com/sun/media/sound/softsynthesizer";  | 
 | 
                    try { | 
 | 
                        Preferences prefroot = Preferences.userRoot();  | 
 | 
                        if (prefroot.nodeExists(notePath)) { | 
 | 
                            Preferences prefs = prefroot.node(notePath);  | 
 | 
                            String[] prefs_keys = prefs.keys();  | 
 | 
                            for (String prefs_key : prefs_keys) { | 
 | 
                                String val = prefs.get(prefs_key, null);  | 
 | 
                                if (val != null) { | 
 | 
                                    p.setProperty(prefs_key, val);  | 
 | 
                                }  | 
 | 
                            }  | 
 | 
                        }  | 
 | 
                    } catch (final BackingStoreException ignored) { | 
 | 
                    }  | 
 | 
                    return p;  | 
 | 
                });  | 
 | 
    }  | 
 | 
 | 
 | 
    public AudioSynthesizerPropertyInfo[] getPropertyInfo(Map<String, Object> info) { | 
 | 
        List<AudioSynthesizerPropertyInfo> list =  | 
 | 
                new ArrayList<AudioSynthesizerPropertyInfo>();  | 
 | 
 | 
 | 
        AudioSynthesizerPropertyInfo item;  | 
 | 
 | 
 | 
        // If info != null or synthesizer is closed  | 
 | 
        //   we return how the synthesizer will be set on next open  | 
 | 
        // If info == null and synthesizer is open  | 
 | 
          | 
 | 
        boolean o = info == null && open;  | 
 | 
 | 
 | 
        item = new AudioSynthesizerPropertyInfo("interpolation", o?resamplerType:"linear"); | 
 | 
        item.choices = new String[]{"linear", "linear1", "linear2", "cubic", | 
 | 
                                    "lanczos", "sinc", "point"};  | 
 | 
        item.description = "Interpolation method";  | 
 | 
        list.add(item);  | 
 | 
 | 
 | 
        item = new AudioSynthesizerPropertyInfo("control rate", o?controlrate:147f); | 
 | 
        item.description = "Control rate";  | 
 | 
        list.add(item);  | 
 | 
 | 
 | 
        item = new AudioSynthesizerPropertyInfo("format", | 
 | 
                o?format:new AudioFormat(44100, 16, 2, true, false));  | 
 | 
        item.description = "Default audio format";  | 
 | 
        list.add(item);  | 
 | 
 | 
 | 
        item = new AudioSynthesizerPropertyInfo("latency", o?latency:120000L); | 
 | 
        item.description = "Default latency";  | 
 | 
        list.add(item);  | 
 | 
 | 
 | 
        item = new AudioSynthesizerPropertyInfo("device id", o?deviceid:0); | 
 | 
        item.description = "Device ID for SysEx Messages";  | 
 | 
        list.add(item);  | 
 | 
 | 
 | 
        item = new AudioSynthesizerPropertyInfo("max polyphony", o?maxpoly:64); | 
 | 
        item.description = "Maximum polyphony";  | 
 | 
        list.add(item);  | 
 | 
 | 
 | 
        item = new AudioSynthesizerPropertyInfo("reverb", o?reverb_on:true); | 
 | 
        item.description = "Turn reverb effect on or off";  | 
 | 
        list.add(item);  | 
 | 
 | 
 | 
        item = new AudioSynthesizerPropertyInfo("chorus", o?chorus_on:true); | 
 | 
        item.description = "Turn chorus effect on or off";  | 
 | 
        list.add(item);  | 
 | 
 | 
 | 
        item = new AudioSynthesizerPropertyInfo("auto gain control", o?agc_on:true); | 
 | 
        item.description = "Turn auto gain control on or off";  | 
 | 
        list.add(item);  | 
 | 
 | 
 | 
        item = new AudioSynthesizerPropertyInfo("large mode", o?largemode:false); | 
 | 
        item.description = "Turn large mode on or off.";  | 
 | 
        list.add(item);  | 
 | 
 | 
 | 
        item = new AudioSynthesizerPropertyInfo("midi channels", o?channels.length:16); | 
 | 
        item.description = "Number of midi channels.";  | 
 | 
        list.add(item);  | 
 | 
 | 
 | 
        item = new AudioSynthesizerPropertyInfo("jitter correction", o?jitter_correction:true); | 
 | 
        item.description = "Turn jitter correction on or off.";  | 
 | 
        list.add(item);  | 
 | 
 | 
 | 
        item = new AudioSynthesizerPropertyInfo("light reverb", o?reverb_light:true); | 
 | 
        item.description = "Turn light reverb mode on or off";  | 
 | 
        list.add(item);  | 
 | 
 | 
 | 
        item = new AudioSynthesizerPropertyInfo("load default soundbank", o?load_default_soundbank:true); | 
 | 
        item.description = "Enabled/disable loading default soundbank";  | 
 | 
        list.add(item);  | 
 | 
 | 
 | 
        AudioSynthesizerPropertyInfo[] items;  | 
 | 
        items = list.toArray(new AudioSynthesizerPropertyInfo[list.size()]);  | 
 | 
 | 
 | 
        Properties storedProperties = getStoredProperties();  | 
 | 
 | 
 | 
        for (AudioSynthesizerPropertyInfo item2 : items) { | 
 | 
            Object v = (info == null) ? null : info.get(item2.name);  | 
 | 
            v = (v != null) ? v : storedProperties.getProperty(item2.name);  | 
 | 
            if (v != null) { | 
 | 
                Class c = (item2.valueClass);  | 
 | 
                if (c.isInstance(v))  | 
 | 
                    item2.value = v;  | 
 | 
                else if (v instanceof String) { | 
 | 
                    String s = (String) v;  | 
 | 
                    if (c == Boolean.class) { | 
 | 
                        if (s.equalsIgnoreCase("true")) | 
 | 
                            item2.value = Boolean.TRUE;  | 
 | 
                        if (s.equalsIgnoreCase("false")) | 
 | 
                            item2.value = Boolean.FALSE;  | 
 | 
                    } else if (c == AudioFormat.class) { | 
 | 
                        int channels = 2;  | 
 | 
                        boolean signed = true;  | 
 | 
                        boolean bigendian = false;  | 
 | 
                        int bits = 16;  | 
 | 
                        float sampleRate = 44100f;  | 
 | 
                        try { | 
 | 
                            StringTokenizer st = new StringTokenizer(s, ", ");  | 
 | 
                            String prevToken = "";  | 
 | 
                            while (st.hasMoreTokens()) { | 
 | 
                                String token = st.nextToken().toLowerCase();  | 
 | 
                                if (token.equals("mono")) | 
 | 
                                    channels = 1;  | 
 | 
                                if (token.startsWith("channel")) | 
 | 
                                    channels = Integer.parseInt(prevToken);  | 
 | 
                                if (token.contains("unsigned")) | 
 | 
                                    signed = false;  | 
 | 
                                if (token.equals("big-endian")) | 
 | 
                                    bigendian = true;  | 
 | 
                                if (token.equals("bit")) | 
 | 
                                    bits = Integer.parseInt(prevToken);  | 
 | 
                                if (token.equals("hz")) | 
 | 
                                    sampleRate = Float.parseFloat(prevToken);  | 
 | 
                                prevToken = token;  | 
 | 
                            }  | 
 | 
                            item2.value = new AudioFormat(sampleRate, bits,  | 
 | 
                                    channels, signed, bigendian);  | 
 | 
                        } catch (NumberFormatException e) { | 
 | 
                        }  | 
 | 
 | 
 | 
                    } else  | 
 | 
                        try { | 
 | 
                            if (c == Byte.class)  | 
 | 
                                item2.value = Byte.valueOf(s);  | 
 | 
                            else if (c == Short.class)  | 
 | 
                                item2.value = Short.valueOf(s);  | 
 | 
                            else if (c == Integer.class)  | 
 | 
                                item2.value = Integer.valueOf(s);  | 
 | 
                            else if (c == Long.class)  | 
 | 
                                item2.value = Long.valueOf(s);  | 
 | 
                            else if (c == Float.class)  | 
 | 
                                item2.value = Float.valueOf(s);  | 
 | 
                            else if (c == Double.class)  | 
 | 
                                item2.value = Double.valueOf(s);  | 
 | 
                        } catch (NumberFormatException e) { | 
 | 
                        }  | 
 | 
                } else if (v instanceof Number) { | 
 | 
                    Number n = (Number) v;  | 
 | 
                    if (c == Byte.class)  | 
 | 
                        item2.value = Byte.valueOf(n.byteValue());  | 
 | 
                    if (c == Short.class)  | 
 | 
                        item2.value = Short.valueOf(n.shortValue());  | 
 | 
                    if (c == Integer.class)  | 
 | 
                        item2.value = Integer.valueOf(n.intValue());  | 
 | 
                    if (c == Long.class)  | 
 | 
                        item2.value = Long.valueOf(n.longValue());  | 
 | 
                    if (c == Float.class)  | 
 | 
                        item2.value = Float.valueOf(n.floatValue());  | 
 | 
                    if (c == Double.class)  | 
 | 
                        item2.value = Double.valueOf(n.doubleValue());  | 
 | 
                }  | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
        return items;  | 
 | 
    }  | 
 | 
 | 
 | 
    public void open() throws MidiUnavailableException { | 
 | 
        if (isOpen()) { | 
 | 
            synchronized (control_mutex) { | 
 | 
                implicitOpen = false;  | 
 | 
            }  | 
 | 
            return;  | 
 | 
        }  | 
 | 
        open(null, null);  | 
 | 
    }  | 
 | 
 | 
 | 
    public void open(SourceDataLine line, Map<String, Object> info) throws MidiUnavailableException { | 
 | 
        if (isOpen()) { | 
 | 
            synchronized (control_mutex) { | 
 | 
                implicitOpen = false;  | 
 | 
            }  | 
 | 
            return;  | 
 | 
        }  | 
 | 
        synchronized (control_mutex) { | 
 | 
            try { | 
 | 
                if (line != null) { | 
 | 
                      | 
 | 
                    setFormat(line.getFormat());  | 
 | 
                }  | 
 | 
 | 
 | 
                AudioInputStream ais = openStream(getFormat(), info);  | 
 | 
 | 
 | 
                weakstream = new WeakAudioStream(ais);  | 
 | 
                ais = weakstream.getAudioInputStream();  | 
 | 
 | 
 | 
                if (line == null)  | 
 | 
                { | 
 | 
                    if (testline != null) { | 
 | 
                        line = testline;  | 
 | 
                    } else { | 
 | 
                        // can throw LineUnavailableException,  | 
 | 
                          | 
 | 
                        line = AudioSystem.getSourceDataLine(getFormat());  | 
 | 
                    }  | 
 | 
                }  | 
 | 
 | 
 | 
                double latency = this.latency;  | 
 | 
 | 
 | 
                if (!line.isOpen()) { | 
 | 
                    int bufferSize = getFormat().getFrameSize()  | 
 | 
                        * (int)(getFormat().getFrameRate() * (latency/1000000f));  | 
 | 
                    // can throw LineUnavailableException,  | 
 | 
                      | 
 | 
                    line.open(getFormat(), bufferSize);  | 
 | 
 | 
 | 
                    // Remember that we opened that line  | 
 | 
                      | 
 | 
                    sourceDataLine = line;  | 
 | 
                }  | 
 | 
                if (!line.isActive())  | 
 | 
                    line.start();  | 
 | 
 | 
 | 
                int controlbuffersize = 512;  | 
 | 
                try { | 
 | 
                    controlbuffersize = ais.available();  | 
 | 
                } catch (IOException e) { | 
 | 
                }  | 
 | 
 | 
 | 
                // Tell mixer not fill read buffers fully.  | 
 | 
                // This lowers latency, and tells DataPusher  | 
 | 
                // to read in smaller amounts.  | 
 | 
                //mainmixer.readfully = false;  | 
 | 
                //pusher = new DataPusher(line, ais);  | 
 | 
 | 
 | 
                int buffersize = line.getBufferSize();  | 
 | 
                buffersize -= buffersize % controlbuffersize;  | 
 | 
 | 
 | 
                if (buffersize < 3 * controlbuffersize)  | 
 | 
                    buffersize = 3 * controlbuffersize;  | 
 | 
 | 
 | 
                if (jitter_correction) { | 
 | 
                    ais = new SoftJitterCorrector(ais, buffersize,  | 
 | 
                            controlbuffersize);  | 
 | 
                    if(weakstream != null)  | 
 | 
                        weakstream.jitter_stream = ais;  | 
 | 
                }  | 
 | 
                pusher = new SoftAudioPusher(line, ais, controlbuffersize);  | 
 | 
                pusher_stream = ais;  | 
 | 
                pusher.start();  | 
 | 
 | 
 | 
                if(weakstream != null)  | 
 | 
                { | 
 | 
                    weakstream.pusher = pusher;  | 
 | 
                    weakstream.sourceDataLine = sourceDataLine;  | 
 | 
                }  | 
 | 
 | 
 | 
            } catch (final LineUnavailableException | SecurityException  | 
 | 
                    | IllegalArgumentException e) { | 
 | 
                if (isOpen()) { | 
 | 
                    close();  | 
 | 
                }  | 
 | 
                  | 
 | 
                MidiUnavailableException ex = new MidiUnavailableException(  | 
 | 
                        "Can not open line");  | 
 | 
                ex.initCause(e);  | 
 | 
                throw ex;  | 
 | 
            }  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    public AudioInputStream openStream(AudioFormat targetFormat,  | 
 | 
            Map<String, Object> info) throws MidiUnavailableException { | 
 | 
 | 
 | 
        if (isOpen())  | 
 | 
            throw new MidiUnavailableException("Synthesizer is already open"); | 
 | 
 | 
 | 
        synchronized (control_mutex) { | 
 | 
 | 
 | 
            gmmode = 0;  | 
 | 
            voice_allocation_mode = 0;  | 
 | 
 | 
 | 
            processPropertyInfo(info);  | 
 | 
 | 
 | 
            open = true;  | 
 | 
            implicitOpen = false;  | 
 | 
 | 
 | 
            if (targetFormat != null)  | 
 | 
                setFormat(targetFormat);  | 
 | 
 | 
 | 
            if (load_default_soundbank)  | 
 | 
            { | 
 | 
                Soundbank defbank = getDefaultSoundbank();  | 
 | 
                if (defbank != null) { | 
 | 
                    loadAllInstruments(defbank);  | 
 | 
                }  | 
 | 
            }  | 
 | 
 | 
 | 
            voices = new SoftVoice[maxpoly];  | 
 | 
            for (int i = 0; i < maxpoly; i++)  | 
 | 
                voices[i] = new SoftVoice(this);  | 
 | 
 | 
 | 
            mainmixer = new SoftMainMixer(this);  | 
 | 
 | 
 | 
            channels = new SoftChannel[number_of_midi_channels];  | 
 | 
            for (int i = 0; i < channels.length; i++)  | 
 | 
                channels[i] = new SoftChannel(this, i);  | 
 | 
 | 
 | 
            if (external_channels == null) { | 
 | 
                // Always create external_channels array  | 
 | 
                // with 16 or more channels  | 
 | 
                // so getChannels works correctly  | 
 | 
                  | 
 | 
                if (channels.length < 16)  | 
 | 
                    external_channels = new SoftChannelProxy[16];  | 
 | 
                else  | 
 | 
                    external_channels = new SoftChannelProxy[channels.length];  | 
 | 
                for (int i = 0; i < external_channels.length; i++)  | 
 | 
                    external_channels[i] = new SoftChannelProxy();  | 
 | 
            } else { | 
 | 
                // We must resize external_channels array  | 
 | 
                // but we must also copy the old SoftChannelProxy  | 
 | 
                  | 
 | 
                if (channels.length > external_channels.length) { | 
 | 
                    SoftChannelProxy[] new_external_channels  | 
 | 
                            = new SoftChannelProxy[channels.length];  | 
 | 
                    for (int i = 0; i < external_channels.length; i++)  | 
 | 
                        new_external_channels[i] = external_channels[i];  | 
 | 
                    for (int i = external_channels.length;  | 
 | 
                            i < new_external_channels.length; i++) { | 
 | 
                        new_external_channels[i] = new SoftChannelProxy();  | 
 | 
                    }  | 
 | 
                }  | 
 | 
            }  | 
 | 
 | 
 | 
            for (int i = 0; i < channels.length; i++)  | 
 | 
                external_channels[i].setChannel(channels[i]);  | 
 | 
 | 
 | 
            for (SoftVoice voice: getVoices())  | 
 | 
                voice.resampler = resampler.openStreamer();  | 
 | 
 | 
 | 
            for (Receiver recv: getReceivers()) { | 
 | 
                SoftReceiver srecv = ((SoftReceiver)recv);  | 
 | 
                srecv.open = open;  | 
 | 
                srecv.mainmixer = mainmixer;  | 
 | 
                srecv.midimessages = mainmixer.midimessages;  | 
 | 
            }  | 
 | 
 | 
 | 
            return mainmixer.getInputStream();  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    public void close() { | 
 | 
 | 
 | 
        if (!isOpen())  | 
 | 
            return;  | 
 | 
 | 
 | 
        SoftAudioPusher pusher_to_be_closed = null;  | 
 | 
        AudioInputStream pusher_stream_to_be_closed = null;  | 
 | 
        synchronized (control_mutex) { | 
 | 
            if (pusher != null) { | 
 | 
                pusher_to_be_closed = pusher;  | 
 | 
                pusher_stream_to_be_closed = pusher_stream;  | 
 | 
                pusher = null;  | 
 | 
                pusher_stream = null;  | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
        if (pusher_to_be_closed != null) { | 
 | 
            // Pusher must not be closed synchronized against control_mutex,  | 
 | 
            // this may result in synchronized conflict between pusher  | 
 | 
              | 
 | 
            pusher_to_be_closed.stop();  | 
 | 
 | 
 | 
            try { | 
 | 
                pusher_stream_to_be_closed.close();  | 
 | 
            } catch (IOException e) { | 
 | 
                //e.printStackTrace();  | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
        synchronized (control_mutex) { | 
 | 
 | 
 | 
            if (mainmixer != null)  | 
 | 
                mainmixer.close();  | 
 | 
            open = false;  | 
 | 
            implicitOpen = false;  | 
 | 
            mainmixer = null;  | 
 | 
            voices = null;  | 
 | 
            channels = null;  | 
 | 
 | 
 | 
            if (external_channels != null)  | 
 | 
                for (int i = 0; i < external_channels.length; i++)  | 
 | 
                    external_channels[i].setChannel(null);  | 
 | 
 | 
 | 
            if (sourceDataLine != null) { | 
 | 
                sourceDataLine.close();  | 
 | 
                sourceDataLine = null;  | 
 | 
            }  | 
 | 
 | 
 | 
            inslist.clear();  | 
 | 
            loadedlist.clear();  | 
 | 
            tunings.clear();  | 
 | 
 | 
 | 
            while (recvslist.size() != 0)  | 
 | 
                recvslist.get(recvslist.size() - 1).close();  | 
 | 
 | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    public boolean isOpen() { | 
 | 
        synchronized (control_mutex) { | 
 | 
            return open;  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    public long getMicrosecondPosition() { | 
 | 
 | 
 | 
        if (!isOpen())  | 
 | 
            return 0;  | 
 | 
 | 
 | 
        synchronized (control_mutex) { | 
 | 
            return mainmixer.getMicrosecondPosition();  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    public int getMaxReceivers() { | 
 | 
        return -1;  | 
 | 
    }  | 
 | 
 | 
 | 
    public int getMaxTransmitters() { | 
 | 
        return 0;  | 
 | 
    }  | 
 | 
 | 
 | 
    public Receiver getReceiver() throws MidiUnavailableException { | 
 | 
 | 
 | 
        synchronized (control_mutex) { | 
 | 
            SoftReceiver receiver = new SoftReceiver(this);  | 
 | 
            receiver.open = open;  | 
 | 
            recvslist.add(receiver);  | 
 | 
            return receiver;  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    public List<Receiver> getReceivers() { | 
 | 
 | 
 | 
        synchronized (control_mutex) { | 
 | 
            ArrayList<Receiver> recvs = new ArrayList<Receiver>();  | 
 | 
            recvs.addAll(recvslist);  | 
 | 
            return recvs;  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    public Transmitter getTransmitter() throws MidiUnavailableException { | 
 | 
 | 
 | 
        throw new MidiUnavailableException("No transmitter available"); | 
 | 
    }  | 
 | 
 | 
 | 
    public List<Transmitter> getTransmitters() { | 
 | 
 | 
 | 
        return new ArrayList<Transmitter>();  | 
 | 
    }  | 
 | 
 | 
 | 
    public Receiver getReceiverReferenceCounting()  | 
 | 
            throws MidiUnavailableException { | 
 | 
 | 
 | 
        if (!isOpen()) { | 
 | 
            open();  | 
 | 
            synchronized (control_mutex) { | 
 | 
                implicitOpen = true;  | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
        return getReceiver();  | 
 | 
    }  | 
 | 
 | 
 | 
    public Transmitter getTransmitterReferenceCounting()  | 
 | 
            throws MidiUnavailableException { | 
 | 
 | 
 | 
        throw new MidiUnavailableException("No transmitter available"); | 
 | 
    }  | 
 | 
}  |