/src/share/classes/com/sun/media/sound/SoftSynthesizer.java
Java | 1351 lines | 1083 code | 183 blank | 85 comment | 277 complexity | ee374119bbc5982f1f521973275b79f1 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause-No-Nuclear-License-2014, LGPL-3.0
- /*
- * Copyright (c) 2008, 2010, 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.BufferedInputStream;
- import java.io.File;
- import java.io.FileInputStream;
- 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;
- /**
- * The software synthesizer class.
- *
- * @author Karl Helgason
- */
- public class SoftSynthesizer implements AudioSynthesizer,
- ReferenceCountingDevice {
- protected static 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 {
- public Info() {
- super(INFO_NAME, INFO_VENDOR, INFO_DESCRIPTION, INFO_VERSION);
- }
- }
- protected static final String INFO_NAME = "Gervill";
- protected static final String INFO_VENDOR = "OpenJDK";
- protected static final String INFO_DESCRIPTION = "Software MIDI Synthesizer";
- protected static final String INFO_VERSION = "1.0";
- protected final static MidiDevice.Info info = new Info();
- private static SourceDataLine testline = null;
- private static Soundbank defaultSoundBank = null;
- protected WeakAudioStream weakstream = null;
- protected Object control_mutex = this;
- protected int voiceIDCounter = 0;
- // 0: default
- // 1: DLS Voice Allocation
- protected int voice_allocation_mode = 0;
- protected boolean load_default_soundbank = false;
- protected boolean reverb_light = true;
- protected boolean reverb_on = true;
- protected boolean chorus_on = true;
- protected boolean agc_on = true;
- protected SoftChannel[] channels;
- protected SoftChannelProxy[] external_channels = null;
- private boolean largemode = false;
- // 0: GM Mode off (default)
- // 1: GM Level 1
- // 2: GM Level 2
- 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; // 200 msec
- 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;
- }
- protected 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();
- }
- protected SoftMainMixer getMainMixer() {
- if (!isOpen())
- return null;
- return mainmixer;
- }
- protected 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
- // on all channels
- 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 = "";
- // Instrument not found fallback to MSB:bank, LSB:0
- current_instrument = inslist.get(p_plaf + program + "."
- + ((bank & 128) << 7));
- if (current_instrument != null)
- return current_instrument;
- // Instrument not found fallback to MSB:0, LSB:bank
- current_instrument = inslist.get(p_plaf + program + "."
- + (bank & 128));
- if (current_instrument != null)
- return current_instrument;
- // Instrument not found fallback to MSB:0, LSB:0
- current_instrument = inslist.get(p_plaf + program + ".0");
- if (current_instrument != null)
- return current_instrument;
- // Instrument not found fallback to MSB:0, LSB:0, program=0
- current_instrument = inslist.get(p_plaf + program + "0.0");
- if (current_instrument != null)
- return current_instrument;
- return null;
- }
- // Channel 10 uses percussion instruments
- 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;
- // Instrument not found fallback to MSB:0, LSB:0
- current_instrument = inslist.get(p_plaf + program + ".0");
- if (current_instrument != null)
- return current_instrument;
- // Instrument not found fallback to MSB:0, LSB:0, program=0
- current_instrument = inslist.get(p_plaf + "0.0");
- if (current_instrument != null)
- return current_instrument;
- return null;
- }
- protected int getVoiceAllocationMode() {
- return voice_allocation_mode;
- }
- protected int getGeneralMidiMode() {
- return gmmode;
- }
- protected void setGeneralMidiMode(int gmmode) {
- this.gmmode = gmmode;
- }
- protected int getDeviceID() {
- return deviceid;
- }
- protected float getControlRate() {
- return controlrate;
- }
- protected SoftVoice[] getVoices() {
- return voices;
- }
- protected 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
- // otherwise external_channels has the same length as channels array
- 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("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() {
- /*
- * Try to load saved generated soundbank
- */
- 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 {
- /*
- * Generate emergency soundbank
- */
- defaultSoundBank = EmergencySoundbank.createSoundbank();
- } catch (Exception e) {
- }
- if (defaultSoundBank != null) {
- /*
- * Save generated soundbank to disk for faster future use.
- */
- OutputStream out = AccessController
- .doPrivileged(new PrivilegedAction<OutputStream>() {
- public OutputStream run() {
- 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 (IOException e) {
- } catch (SecurityException e) {
- }
- return null;
- }
- });
- if (out != null) {
- try {
- ((SF2Soundbank) defaultSoundBank).save(out);
- out.close();
- } catch (IOException e) {
- }
- }
- }
- }
- 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(new PrivilegedAction<Properties>() {
- public Properties run() {
- 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 (BackingStoreException e) {
- } catch (SecurityException e) {
- }
- 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
- // we return current synthesizer properties.
- 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) {
- Throwable causeException = null;
- try {
- if (line != null) {
- // can throw IllegalArgumentException
- 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,
- // IllegalArgumentException, SecurityException
- line = AudioSystem.getSourceDataLine(getFormat());
- }
- }
- double latency = this.latency;
- if (!line.isOpen()) {
- int bufferSize = getFormat().getFrameSize()
- * (int)(getFormat().getFrameRate() * (latency/1000000f));
- // can throw LineUnavailableException,
- // IllegalArgumentException, SecurityException
- line.open(getFormat(), bufferSize);
- // Remember that we opened that line
- // so we can close again in SoftSynthesizer.close()
- 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 (LineUnavailableException e) {
- causeException = e;
- } catch (IllegalArgumentException e) {
- causeException = e;
- } catch (SecurityException e) {
- causeException = e;
- }
- if (causeException != null) {
- if (isOpen())
- close();
- // am: need MidiUnavailableException(Throwable) ctor!
- MidiUnavailableException ex = new MidiUnavailableException(
- "Can not open line");
- ex.initCause(causeException);
- 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
- // when the synhtesizer is closed.
- 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
- // into the new one
- 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
- // and current thread.
- 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");
- }
- }