Save This Page
Home » openjdk-7 » com.sun.media » sound » [javadoc | source]
    1   /*
    2    * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Oracle designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Oracle in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   22    * or visit www.oracle.com if you need additional information or have any
   23    * questions.
   24    */
   25   
   26   package com.sun.media.sound;
   27   
   28   import java.io.BufferedInputStream;
   29   import java.io.File;
   30   import java.io.FileInputStream;
   31   import java.io.FileOutputStream;
   32   import java.io.IOException;
   33   import java.io.InputStream;
   34   import java.io.OutputStream;
   35   import java.lang.ref.WeakReference;
   36   import java.security.AccessController;
   37   import java.security.PrivilegedAction;
   38   import java.util.ArrayList;
   39   import java.util.Arrays;
   40   import java.util.HashMap;
   41   import java.util.List;
   42   import java.util.Map;
   43   import java.util.Properties;
   44   import java.util.StringTokenizer;
   45   import java.util.prefs.BackingStoreException;
   46   import java.util.prefs.Preferences;
   47   
   48   import javax.sound.midi.Instrument;
   49   import javax.sound.midi.MidiChannel;
   50   import javax.sound.midi.MidiDevice;
   51   import javax.sound.midi.MidiSystem;
   52   import javax.sound.midi.MidiUnavailableException;
   53   import javax.sound.midi.Patch;
   54   import javax.sound.midi.Receiver;
   55   import javax.sound.midi.Soundbank;
   56   import javax.sound.midi.Transmitter;
   57   import javax.sound.midi.VoiceStatus;
   58   import javax.sound.sampled.AudioFormat;
   59   import javax.sound.sampled.AudioInputStream;
   60   import javax.sound.sampled.AudioSystem;
   61   import javax.sound.sampled.LineUnavailableException;
   62   import javax.sound.sampled.SourceDataLine;
   63   
   64   /**
   65    * The software synthesizer class.
   66    *
   67    * @author Karl Helgason
   68    */
   69   public class SoftSynthesizer implements AudioSynthesizer,
   70           ReferenceCountingDevice {
   71   
   72       protected static class WeakAudioStream extends InputStream
   73       {
   74           private volatile AudioInputStream stream;
   75           public SoftAudioPusher pusher = null;
   76           public AudioInputStream jitter_stream = null;
   77           public SourceDataLine sourceDataLine = null;
   78           public volatile long silent_samples = 0;
   79           private int framesize = 0;
   80           private WeakReference<AudioInputStream> weak_stream_link;
   81           private AudioFloatConverter converter;
   82           private float[] silentbuffer = null;
   83           private int samplesize;
   84   
   85           public void setInputStream(AudioInputStream stream)
   86           {
   87               this.stream = stream;
   88           }
   89   
   90           public int available() throws IOException {
   91               AudioInputStream local_stream = stream;
   92               if(local_stream != null)
   93                   return local_stream.available();
   94               return 0;
   95           }
   96   
   97           public int read() throws IOException {
   98                byte[] b = new byte[1];
   99                if (read(b) == -1)
  100                     return -1;
  101                return b[0] & 0xFF;
  102           }
  103   
  104           public int read(byte[] b, int off, int len) throws IOException {
  105                AudioInputStream local_stream = stream;
  106                if(local_stream != null)
  107                    return local_stream.read(b, off, len);
  108                else
  109                {
  110                    int flen = len / samplesize;
  111                    if(silentbuffer == null || silentbuffer.length < flen)
  112                        silentbuffer = new float[flen];
  113                    converter.toByteArray(silentbuffer, flen, b, off);
  114   
  115                    silent_samples += (long)((len / framesize));
  116   
  117                    if(pusher != null)
  118                    if(weak_stream_link.get() == null)
  119                    {
  120                        Runnable runnable = new Runnable()
  121                        {
  122                            SoftAudioPusher _pusher = pusher;
  123                            AudioInputStream _jitter_stream = jitter_stream;
  124                            SourceDataLine _sourceDataLine = sourceDataLine;
  125                            public void run()
  126                            {
  127                                _pusher.stop();
  128                                if(_jitter_stream != null)
  129                                   try {
  130                                       _jitter_stream.close();
  131                                   } catch (IOException e) {
  132                                       e.printStackTrace();
  133                                   }
  134                                if(_sourceDataLine != null)
  135                                    _sourceDataLine.close();
  136                            }
  137                        };
  138                        pusher = null;
  139                        jitter_stream = null;
  140                        sourceDataLine = null;
  141                        new Thread(runnable).start();
  142                    }
  143                    return len;
  144                }
  145           }
  146   
  147           public WeakAudioStream(AudioInputStream stream) {
  148               this.stream = stream;
  149               weak_stream_link = new WeakReference<AudioInputStream>(stream);
  150               converter = AudioFloatConverter.getConverter(stream.getFormat());
  151               samplesize = stream.getFormat().getFrameSize() / stream.getFormat().getChannels();
  152               framesize = stream.getFormat().getFrameSize();
  153           }
  154   
  155           public AudioInputStream getAudioInputStream()
  156           {
  157               return new AudioInputStream(this, stream.getFormat(), AudioSystem.NOT_SPECIFIED);
  158           }
  159   
  160           public void close() throws IOException
  161           {
  162               AudioInputStream astream  = weak_stream_link.get();
  163               if(astream != null)
  164                   astream.close();
  165           }
  166       }
  167   
  168       private static class Info extends MidiDevice.Info {
  169           public Info() {
  170               super(INFO_NAME, INFO_VENDOR, INFO_DESCRIPTION, INFO_VERSION);
  171           }
  172       }
  173   
  174       protected static final String INFO_NAME = "Gervill";
  175       protected static final String INFO_VENDOR = "OpenJDK";
  176       protected static final String INFO_DESCRIPTION = "Software MIDI Synthesizer";
  177       protected static final String INFO_VERSION = "1.0";
  178       protected final static MidiDevice.Info info = new Info();
  179   
  180       private static SourceDataLine testline = null;
  181   
  182       private static Soundbank defaultSoundBank = null;
  183   
  184       protected WeakAudioStream weakstream = null;
  185   
  186       protected Object control_mutex = this;
  187   
  188       protected int voiceIDCounter = 0;
  189   
  190       // 0: default
  191       // 1: DLS Voice Allocation
  192       protected int voice_allocation_mode = 0;
  193   
  194       protected boolean load_default_soundbank = false;
  195       protected boolean reverb_light = true;
  196       protected boolean reverb_on = true;
  197       protected boolean chorus_on = true;
  198       protected boolean agc_on = true;
  199   
  200       protected SoftChannel[] channels;
  201       protected SoftChannelProxy[] external_channels = null;
  202   
  203       private boolean largemode = false;
  204   
  205       // 0: GM Mode off (default)
  206       // 1: GM Level 1
  207       // 2: GM Level 2
  208       private int gmmode = 0;
  209   
  210       private int deviceid = 0;
  211   
  212       private AudioFormat format = new AudioFormat(44100, 16, 2, true, false);
  213   
  214       private SourceDataLine sourceDataLine = null;
  215   
  216       private SoftAudioPusher pusher = null;
  217       private AudioInputStream pusher_stream = null;
  218   
  219       private float controlrate = 147f;
  220   
  221       private boolean open = false;
  222       private boolean implicitOpen = false;
  223   
  224       private String resamplerType = "linear";
  225       private SoftResampler resampler = new SoftLinearResampler();
  226   
  227       private int number_of_midi_channels = 16;
  228       private int maxpoly = 64;
  229       private long latency = 200000; // 200 msec
  230       private boolean jitter_correction = false;
  231   
  232       private SoftMainMixer mainmixer;
  233       private SoftVoice[] voices;
  234   
  235       private Map<String, SoftTuning> tunings
  236               = new HashMap<String, SoftTuning>();
  237       private Map<String, SoftInstrument> inslist
  238               = new HashMap<String, SoftInstrument>();
  239       private Map<String, ModelInstrument> loadedlist
  240               = new HashMap<String, ModelInstrument>();
  241   
  242       private ArrayList<Receiver> recvslist = new ArrayList<Receiver>();
  243   
  244       private void getBuffers(ModelInstrument instrument,
  245               List<ModelByteBuffer> buffers) {
  246           for (ModelPerformer performer : instrument.getPerformers()) {
  247               if (performer.getOscillators() != null) {
  248                   for (ModelOscillator osc : performer.getOscillators()) {
  249                       if (osc instanceof ModelByteBufferWavetable) {
  250                           ModelByteBufferWavetable w = (ModelByteBufferWavetable)osc;
  251                           ModelByteBuffer buff = w.getBuffer();
  252                           if (buff != null)
  253                               buffers.add(buff);
  254                           buff = w.get8BitExtensionBuffer();
  255                           if (buff != null)
  256                               buffers.add(buff);
  257                       }
  258                   }
  259               }
  260           }
  261       }
  262   
  263       private boolean loadSamples(List<ModelInstrument> instruments) {
  264           if (largemode)
  265               return true;
  266           List<ModelByteBuffer> buffers = new ArrayList<ModelByteBuffer>();
  267           for (ModelInstrument instrument : instruments)
  268               getBuffers(instrument, buffers);
  269           try {
  270               ModelByteBuffer.loadAll(buffers);
  271           } catch (IOException e) {
  272               return false;
  273           }
  274           return true;
  275       }
  276   
  277       private boolean loadInstruments(List<ModelInstrument> instruments) {
  278           if (!isOpen())
  279               return false;
  280           if (!loadSamples(instruments))
  281               return false;
  282   
  283           synchronized (control_mutex) {
  284               if (channels != null)
  285                   for (SoftChannel c : channels)
  286                   {
  287                       c.current_instrument = null;
  288                       c.current_director = null;
  289                   }
  290               for (Instrument instrument : instruments) {
  291                   String pat = patchToString(instrument.getPatch());
  292                   SoftInstrument softins
  293                           = new SoftInstrument((ModelInstrument) instrument);
  294                   inslist.put(pat, softins);
  295                   loadedlist.put(pat, (ModelInstrument) instrument);
  296               }
  297           }
  298   
  299           return true;
  300       }
  301   
  302       private void processPropertyInfo(Map<String, Object> info) {
  303           AudioSynthesizerPropertyInfo[] items = getPropertyInfo(info);
  304   
  305           String resamplerType = (String)items[0].value;
  306           if (resamplerType.equalsIgnoreCase("point"))
  307           {
  308               this.resampler = new SoftPointResampler();
  309               this.resamplerType = "point";
  310           }
  311           else if (resamplerType.equalsIgnoreCase("linear"))
  312           {
  313               this.resampler = new SoftLinearResampler2();
  314               this.resamplerType = "linear";
  315           }
  316           else if (resamplerType.equalsIgnoreCase("linear1"))
  317           {
  318               this.resampler = new SoftLinearResampler();
  319               this.resamplerType = "linear1";
  320           }
  321           else if (resamplerType.equalsIgnoreCase("linear2"))
  322           {
  323               this.resampler = new SoftLinearResampler2();
  324               this.resamplerType = "linear2";
  325           }
  326           else if (resamplerType.equalsIgnoreCase("cubic"))
  327           {
  328               this.resampler = new SoftCubicResampler();
  329               this.resamplerType = "cubic";
  330           }
  331           else if (resamplerType.equalsIgnoreCase("lanczos"))
  332           {
  333               this.resampler = new SoftLanczosResampler();
  334               this.resamplerType = "lanczos";
  335           }
  336           else if (resamplerType.equalsIgnoreCase("sinc"))
  337           {
  338               this.resampler = new SoftSincResampler();
  339               this.resamplerType = "sinc";
  340           }
  341   
  342           setFormat((AudioFormat)items[2].value);
  343           controlrate = (Float)items[1].value;
  344           latency = (Long)items[3].value;
  345           deviceid = (Integer)items[4].value;
  346           maxpoly = (Integer)items[5].value;
  347           reverb_on = (Boolean)items[6].value;
  348           chorus_on = (Boolean)items[7].value;
  349           agc_on = (Boolean)items[8].value;
  350           largemode = (Boolean)items[9].value;
  351           number_of_midi_channels = (Integer)items[10].value;
  352           jitter_correction = (Boolean)items[11].value;
  353           reverb_light = (Boolean)items[12].value;
  354           load_default_soundbank = (Boolean)items[13].value;
  355       }
  356   
  357       private String patchToString(Patch patch) {
  358           if (patch instanceof ModelPatch && ((ModelPatch) patch).isPercussion())
  359               return "p." + patch.getProgram() + "." + patch.getBank();
  360           else
  361               return patch.getProgram() + "." + patch.getBank();
  362       }
  363   
  364       private void setFormat(AudioFormat format) {
  365           if (format.getChannels() > 2) {
  366               throw new IllegalArgumentException(
  367                       "Only mono and stereo audio supported.");
  368           }
  369           if (AudioFloatConverter.getConverter(format) == null)
  370               throw new IllegalArgumentException("Audio format not supported.");
  371           this.format = format;
  372       }
  373   
  374       protected void removeReceiver(Receiver recv) {
  375           boolean perform_close = false;
  376           synchronized (control_mutex) {
  377               if (recvslist.remove(recv)) {
  378                   if (implicitOpen && recvslist.isEmpty())
  379                       perform_close = true;
  380               }
  381           }
  382           if (perform_close)
  383               close();
  384       }
  385   
  386       protected SoftMainMixer getMainMixer() {
  387           if (!isOpen())
  388               return null;
  389           return mainmixer;
  390       }
  391   
  392       protected SoftInstrument findInstrument(int program, int bank, int channel) {
  393   
  394           // Add support for GM2 banks 0x78 and 0x79
  395           // as specified in DLS 2.2 in Section 1.4.6
  396           // which allows using percussion and melodic instruments
  397           // on all channels
  398           if (bank >> 7 == 0x78 || bank >> 7 == 0x79) {
  399               SoftInstrument current_instrument
  400                       = inslist.get(program + "." + bank);
  401               if (current_instrument != null)
  402                   return current_instrument;
  403   
  404               String p_plaf;
  405               if (bank >> 7 == 0x78)
  406                   p_plaf = "p.";
  407               else
  408                   p_plaf = "";
  409   
  410               // Instrument not found fallback to MSB:bank, LSB:0
  411               current_instrument = inslist.get(p_plaf + program + "."
  412                       + ((bank & 128) << 7));
  413               if (current_instrument != null)
  414                   return current_instrument;
  415               // Instrument not found fallback to MSB:0, LSB:bank
  416               current_instrument = inslist.get(p_plaf + program + "."
  417                       + (bank & 128));
  418               if (current_instrument != null)
  419                   return current_instrument;
  420               // Instrument not found fallback to MSB:0, LSB:0
  421               current_instrument = inslist.get(p_plaf + program + ".0");
  422               if (current_instrument != null)
  423                   return current_instrument;
  424               // Instrument not found fallback to MSB:0, LSB:0, program=0
  425               current_instrument = inslist.get(p_plaf + program + "0.0");
  426               if (current_instrument != null)
  427                   return current_instrument;
  428               return null;
  429           }
  430   
  431           // Channel 10 uses percussion instruments
  432           String p_plaf;
  433           if (channel == 9)
  434               p_plaf = "p.";
  435           else
  436               p_plaf = "";
  437   
  438           SoftInstrument current_instrument
  439                   = inslist.get(p_plaf + program + "." + bank);
  440           if (current_instrument != null)
  441               return current_instrument;
  442           // Instrument not found fallback to MSB:0, LSB:0
  443           current_instrument = inslist.get(p_plaf + program + ".0");
  444           if (current_instrument != null)
  445               return current_instrument;
  446           // Instrument not found fallback to MSB:0, LSB:0, program=0
  447           current_instrument = inslist.get(p_plaf + "0.0");
  448           if (current_instrument != null)
  449               return current_instrument;
  450           return null;
  451       }
  452   
  453       protected int getVoiceAllocationMode() {
  454           return voice_allocation_mode;
  455       }
  456   
  457       protected int getGeneralMidiMode() {
  458           return gmmode;
  459       }
  460   
  461       protected void setGeneralMidiMode(int gmmode) {
  462           this.gmmode = gmmode;
  463       }
  464   
  465       protected int getDeviceID() {
  466           return deviceid;
  467       }
  468   
  469       protected float getControlRate() {
  470           return controlrate;
  471       }
  472   
  473       protected SoftVoice[] getVoices() {
  474           return voices;
  475       }
  476   
  477       protected SoftTuning getTuning(Patch patch) {
  478           String t_id = patchToString(patch);
  479           SoftTuning tuning = tunings.get(t_id);
  480           if (tuning == null) {
  481               tuning = new SoftTuning(patch);
  482               tunings.put(t_id, tuning);
  483           }
  484           return tuning;
  485       }
  486   
  487       public long getLatency() {
  488           synchronized (control_mutex) {
  489               return latency;
  490           }
  491       }
  492   
  493       public AudioFormat getFormat() {
  494           synchronized (control_mutex) {
  495               return format;
  496           }
  497       }
  498   
  499       public int getMaxPolyphony() {
  500           synchronized (control_mutex) {
  501               return maxpoly;
  502           }
  503       }
  504   
  505       public MidiChannel[] getChannels() {
  506   
  507           synchronized (control_mutex) {
  508               // if (external_channels == null) => the synthesizer is not open,
  509               // create 16 proxy channels
  510               // otherwise external_channels has the same length as channels array
  511               if (external_channels == null) {
  512                   external_channels = new SoftChannelProxy[16];
  513                   for (int i = 0; i < external_channels.length; i++)
  514                       external_channels[i] = new SoftChannelProxy();
  515               }
  516               MidiChannel[] ret;
  517               if (isOpen())
  518                   ret = new MidiChannel[channels.length];
  519               else
  520                   ret = new MidiChannel[16];
  521               for (int i = 0; i < ret.length; i++)
  522                   ret[i] = external_channels[i];
  523               return ret;
  524           }
  525       }
  526   
  527       public VoiceStatus[] getVoiceStatus() {
  528           if (!isOpen()) {
  529               VoiceStatus[] tempVoiceStatusArray
  530                       = new VoiceStatus[getMaxPolyphony()];
  531               for (int i = 0; i < tempVoiceStatusArray.length; i++) {
  532                   VoiceStatus b = new VoiceStatus();
  533                   b.active = false;
  534                   b.bank = 0;
  535                   b.channel = 0;
  536                   b.note = 0;
  537                   b.program = 0;
  538                   b.volume = 0;
  539                   tempVoiceStatusArray[i] = b;
  540               }
  541               return tempVoiceStatusArray;
  542           }
  543   
  544           synchronized (control_mutex) {
  545               VoiceStatus[] tempVoiceStatusArray = new VoiceStatus[voices.length];
  546               for (int i = 0; i < voices.length; i++) {
  547                   VoiceStatus a = voices[i];
  548                   VoiceStatus b = new VoiceStatus();
  549                   b.active = a.active;
  550                   b.bank = a.bank;
  551                   b.channel = a.channel;
  552                   b.note = a.note;
  553                   b.program = a.program;
  554                   b.volume = a.volume;
  555                   tempVoiceStatusArray[i] = b;
  556               }
  557               return tempVoiceStatusArray;
  558           }
  559       }
  560   
  561       public boolean isSoundbankSupported(Soundbank soundbank) {
  562           for (Instrument ins: soundbank.getInstruments())
  563               if (!(ins instanceof ModelInstrument))
  564                   return false;
  565           return true;
  566       }
  567   
  568       public boolean loadInstrument(Instrument instrument) {
  569           if (instrument == null || (!(instrument instanceof ModelInstrument))) {
  570               throw new IllegalArgumentException("Unsupported instrument: " +
  571                       instrument);
  572           }
  573           List<ModelInstrument> instruments = new ArrayList<ModelInstrument>();
  574           instruments.add((ModelInstrument)instrument);
  575           return loadInstruments(instruments);
  576       }
  577   
  578       public void unloadInstrument(Instrument instrument) {
  579           if (instrument == null || (!(instrument instanceof ModelInstrument))) {
  580               throw new IllegalArgumentException("Unsupported instrument: " +
  581                       instrument);
  582           }
  583           if (!isOpen())
  584               return;
  585   
  586           String pat = patchToString(instrument.getPatch());
  587           synchronized (control_mutex) {
  588               for (SoftChannel c: channels)
  589                   c.current_instrument = null;
  590               inslist.remove(pat);
  591               loadedlist.remove(pat);
  592               for (int i = 0; i < channels.length; i++) {
  593                   channels[i].allSoundOff();
  594               }
  595           }
  596       }
  597   
  598       public boolean remapInstrument(Instrument from, Instrument to) {
  599   
  600           if (from == null)
  601               throw new NullPointerException();
  602           if (to == null)
  603               throw new NullPointerException();
  604           if (!(from instanceof ModelInstrument)) {
  605               throw new IllegalArgumentException("Unsupported instrument: " +
  606                       from.toString());
  607           }
  608           if (!(to instanceof ModelInstrument)) {
  609               throw new IllegalArgumentException("Unsupported instrument: " +
  610                       to.toString());
  611           }
  612           if (!isOpen())
  613               return false;
  614   
  615           synchronized (control_mutex) {
  616               if (!loadedlist.containsValue(to))
  617                   throw new IllegalArgumentException("Instrument to is not loaded.");
  618               unloadInstrument(from);
  619               ModelMappedInstrument mfrom = new ModelMappedInstrument(
  620                       (ModelInstrument)to, from.getPatch());
  621               return loadInstrument(mfrom);
  622           }
  623       }
  624   
  625       public Soundbank getDefaultSoundbank() {
  626           synchronized (SoftSynthesizer.class) {
  627               if (defaultSoundBank != null)
  628                   return defaultSoundBank;
  629   
  630               List<PrivilegedAction<InputStream>> actions =
  631                   new ArrayList<PrivilegedAction<InputStream>>();
  632   
  633               actions.add(new PrivilegedAction<InputStream>() {
  634                   public InputStream run() {
  635                       File javahome = new File(System.getProperties()
  636                               .getProperty("java.home"));
  637                       File libaudio = new File(new File(javahome, "lib"), "audio");
  638                       if (libaudio.exists()) {
  639                           File foundfile = null;
  640                           File[] files = libaudio.listFiles();
  641                           if (files != null) {
  642                               for (int i = 0; i < files.length; i++) {
  643                                   File file = files[i];
  644                                   if (file.isFile()) {
  645                                       String lname = file.getName().toLowerCase();
  646                                       if (lname.endsWith(".sf2")
  647                                               || lname.endsWith(".dls")) {
  648                                           if (foundfile == null
  649                                                   || (file.length() > foundfile
  650                                                           .length())) {
  651                                               foundfile = file;
  652                                           }
  653                                       }
  654                                   }
  655                               }
  656                           }
  657                           if (foundfile != null) {
  658                               try {
  659                                   return new FileInputStream(foundfile);
  660                               } catch (IOException e) {
  661                               }
  662                           }
  663                       }
  664                       return null;
  665                   }
  666               });
  667   
  668               actions.add(new PrivilegedAction<InputStream>() {
  669                   public InputStream run() {
  670                       if (System.getProperties().getProperty("os.name")
  671                               .startsWith("Windows")) {
  672                           File gm_dls = new File(System.getenv("SystemRoot")
  673                                   + "\\system32\\drivers\\gm.dls");
  674                           if (gm_dls.exists()) {
  675                               try {
  676                                   return new FileInputStream(gm_dls);
  677                               } catch (IOException e) {
  678                               }
  679                           }
  680                       }
  681                       return null;
  682                   }
  683               });
  684   
  685               actions.add(new PrivilegedAction<InputStream>() {
  686                   public InputStream run() {
  687                       /*
  688                        * Try to load saved generated soundbank
  689                        */
  690                       File userhome = new File(System.getProperty("user.home"),
  691                               ".gervill");
  692                       File emg_soundbank_file = new File(userhome,
  693                               "soundbank-emg.sf2");
  694                       if (emg_soundbank_file.exists()) {
  695                           try {
  696                               return new FileInputStream(emg_soundbank_file);
  697                           } catch (IOException e) {
  698                           }
  699                       }
  700                       return null;
  701                   }
  702               });
  703   
  704               for (PrivilegedAction<InputStream> action : actions) {
  705                   try {
  706                       InputStream is = AccessController.doPrivileged(action);
  707                       if(is == null) continue;
  708                       Soundbank sbk;
  709                       try {
  710                           sbk = MidiSystem.getSoundbank(new BufferedInputStream(is));
  711                       } finally {
  712                           is.close();
  713                       }
  714                       if (sbk != null) {
  715                           defaultSoundBank = sbk;
  716                           return defaultSoundBank;
  717                       }
  718                   } catch (Exception e) {
  719                   }
  720               }
  721   
  722               try {
  723                   /*
  724                    * Generate emergency soundbank
  725                    */
  726                   defaultSoundBank = EmergencySoundbank.createSoundbank();
  727               } catch (Exception e) {
  728               }
  729   
  730               if (defaultSoundBank != null) {
  731                   /*
  732                    * Save generated soundbank to disk for faster future use.
  733                    */
  734                   OutputStream out = AccessController
  735                           .doPrivileged(new PrivilegedAction<OutputStream>() {
  736                               public OutputStream run() {
  737                                   try {
  738                                       File userhome = new File(System
  739                                               .getProperty("user.home"),
  740                                               ".gervill");
  741                                       if (!userhome.exists())
  742                                           userhome.mkdirs();
  743                                       File emg_soundbank_file = new File(
  744                                               userhome, "soundbank-emg.sf2");
  745                                       if (emg_soundbank_file.exists())
  746                                           return null;
  747                                       return new FileOutputStream(
  748                                               emg_soundbank_file);
  749                                   } catch (IOException e) {
  750                                   } catch (SecurityException e) {
  751                                   }
  752                                   return null;
  753                               }
  754                           });
  755                   if (out != null) {
  756                       try {
  757                           ((SF2Soundbank) defaultSoundBank).save(out);
  758                           out.close();
  759                       } catch (IOException e) {
  760                       }
  761                   }
  762               }
  763           }
  764           return defaultSoundBank;
  765       }
  766   
  767       public Instrument[] getAvailableInstruments() {
  768           Soundbank defsbk = getDefaultSoundbank();
  769           if (defsbk == null)
  770               return new Instrument[0];
  771           Instrument[] inslist_array = defsbk.getInstruments();
  772           Arrays.sort(inslist_array, new ModelInstrumentComparator());
  773           return inslist_array;
  774       }
  775   
  776       public Instrument[] getLoadedInstruments() {
  777           if (!isOpen())
  778               return new Instrument[0];
  779   
  780           synchronized (control_mutex) {
  781               ModelInstrument[] inslist_array =
  782                       new ModelInstrument[loadedlist.values().size()];
  783               loadedlist.values().toArray(inslist_array);
  784               Arrays.sort(inslist_array, new ModelInstrumentComparator());
  785               return inslist_array;
  786           }
  787       }
  788   
  789       public boolean loadAllInstruments(Soundbank soundbank) {
  790           List<ModelInstrument> instruments = new ArrayList<ModelInstrument>();
  791           for (Instrument ins: soundbank.getInstruments()) {
  792               if (ins == null || !(ins instanceof ModelInstrument)) {
  793                   throw new IllegalArgumentException(
  794                           "Unsupported instrument: " + ins);
  795               }
  796               instruments.add((ModelInstrument)ins);
  797           }
  798           return loadInstruments(instruments);
  799       }
  800   
  801       public void unloadAllInstruments(Soundbank soundbank) {
  802           if (soundbank == null || !isSoundbankSupported(soundbank))
  803               throw new IllegalArgumentException("Unsupported soundbank: " + soundbank);
  804   
  805           if (!isOpen())
  806               return;
  807   
  808           for (Instrument ins: soundbank.getInstruments()) {
  809               if (ins instanceof ModelInstrument) {
  810                   unloadInstrument(ins);
  811               }
  812           }
  813       }
  814   
  815       public boolean loadInstruments(Soundbank soundbank, Patch[] patchList) {
  816           List<ModelInstrument> instruments = new ArrayList<ModelInstrument>();
  817           for (Patch patch: patchList) {
  818               Instrument ins = soundbank.getInstrument(patch);
  819               if (ins == null || !(ins instanceof ModelInstrument)) {
  820                   throw new IllegalArgumentException(
  821                           "Unsupported instrument: " + ins);
  822               }
  823               instruments.add((ModelInstrument)ins);
  824           }
  825           return loadInstruments(instruments);
  826       }
  827   
  828       public void unloadInstruments(Soundbank soundbank, Patch[] patchList) {
  829           if (soundbank == null || !isSoundbankSupported(soundbank))
  830               throw new IllegalArgumentException("Unsupported soundbank: " + soundbank);
  831   
  832           if (!isOpen())
  833               return;
  834   
  835           for (Patch pat: patchList) {
  836               Instrument ins = soundbank.getInstrument(pat);
  837               if (ins instanceof ModelInstrument) {
  838                   unloadInstrument(ins);
  839               }
  840           }
  841       }
  842   
  843       public MidiDevice.Info getDeviceInfo() {
  844           return info;
  845       }
  846   
  847       private Properties getStoredProperties() {
  848           return AccessController
  849                   .doPrivileged(new PrivilegedAction<Properties>() {
  850                       public Properties run() {
  851                           Properties p = new Properties();
  852                           String notePath = "/com/sun/media/sound/softsynthesizer";
  853                           try {
  854                               Preferences prefroot = Preferences.userRoot();
  855                               if (prefroot.nodeExists(notePath)) {
  856                                   Preferences prefs = prefroot.node(notePath);
  857                                   String[] prefs_keys = prefs.keys();
  858                                   for (String prefs_key : prefs_keys) {
  859                                       String val = prefs.get(prefs_key, null);
  860                                       if (val != null)
  861                                           p.setProperty(prefs_key, val);
  862                                   }
  863                               }
  864                           } catch (BackingStoreException e) {
  865                           } catch (SecurityException e) {
  866                           }
  867                           return p;
  868                       }
  869                   });
  870       }
  871   
  872       public AudioSynthesizerPropertyInfo[] getPropertyInfo(Map<String, Object> info) {
  873           List<AudioSynthesizerPropertyInfo> list =
  874                   new ArrayList<AudioSynthesizerPropertyInfo>();
  875   
  876           AudioSynthesizerPropertyInfo item;
  877   
  878           // If info != null or synthesizer is closed
  879           //   we return how the synthesizer will be set on next open
  880           // If info == null and synthesizer is open
  881           //   we return current synthesizer properties.
  882           boolean o = info == null && open;
  883   
  884           item = new AudioSynthesizerPropertyInfo("interpolation", o?resamplerType:"linear");
  885           item.choices = new String[]{"linear", "linear1", "linear2", "cubic",
  886                                       "lanczos", "sinc", "point"};
  887           item.description = "Interpolation method";
  888           list.add(item);
  889   
  890           item = new AudioSynthesizerPropertyInfo("control rate", o?controlrate:147f);
  891           item.description = "Control rate";
  892           list.add(item);
  893   
  894           item = new AudioSynthesizerPropertyInfo("format",
  895                   o?format:new AudioFormat(44100, 16, 2, true, false));
  896           item.description = "Default audio format";
  897           list.add(item);
  898   
  899           item = new AudioSynthesizerPropertyInfo("latency", o?latency:120000L);
  900           item.description = "Default latency";
  901           list.add(item);
  902   
  903           item = new AudioSynthesizerPropertyInfo("device id", o?deviceid:0);
  904           item.description = "Device ID for SysEx Messages";
  905           list.add(item);
  906   
  907           item = new AudioSynthesizerPropertyInfo("max polyphony", o?maxpoly:64);
  908           item.description = "Maximum polyphony";
  909           list.add(item);
  910   
  911           item = new AudioSynthesizerPropertyInfo("reverb", o?reverb_on:true);
  912           item.description = "Turn reverb effect on or off";
  913           list.add(item);
  914   
  915           item = new AudioSynthesizerPropertyInfo("chorus", o?chorus_on:true);
  916           item.description = "Turn chorus effect on or off";
  917           list.add(item);
  918   
  919           item = new AudioSynthesizerPropertyInfo("auto gain control", o?agc_on:true);
  920           item.description = "Turn auto gain control on or off";
  921           list.add(item);
  922   
  923           item = new AudioSynthesizerPropertyInfo("large mode", o?largemode:false);
  924           item.description = "Turn large mode on or off.";
  925           list.add(item);
  926   
  927           item = new AudioSynthesizerPropertyInfo("midi channels", o?channels.length:16);
  928           item.description = "Number of midi channels.";
  929           list.add(item);
  930   
  931           item = new AudioSynthesizerPropertyInfo("jitter correction", o?jitter_correction:true);
  932           item.description = "Turn jitter correction on or off.";
  933           list.add(item);
  934   
  935           item = new AudioSynthesizerPropertyInfo("light reverb", o?reverb_light:true);
  936           item.description = "Turn light reverb mode on or off";
  937           list.add(item);
  938   
  939           item = new AudioSynthesizerPropertyInfo("load default soundbank", o?load_default_soundbank:true);
  940           item.description = "Enabled/disable loading default soundbank";
  941           list.add(item);
  942   
  943           AudioSynthesizerPropertyInfo[] items;
  944           items = list.toArray(new AudioSynthesizerPropertyInfo[list.size()]);
  945   
  946           Properties storedProperties = getStoredProperties();
  947   
  948           for (AudioSynthesizerPropertyInfo item2 : items) {
  949               Object v = (info == null) ? null : info.get(item2.name);
  950               v = (v != null) ? v : storedProperties.getProperty(item2.name);
  951               if (v != null) {
  952                   Class c = (item2.valueClass);
  953                   if (c.isInstance(v))
  954                       item2.value = v;
  955                   else if (v instanceof String) {
  956                       String s = (String) v;
  957                       if (c == Boolean.class) {
  958                           if (s.equalsIgnoreCase("true"))
  959                               item2.value = Boolean.TRUE;
  960                           if (s.equalsIgnoreCase("false"))
  961                               item2.value = Boolean.FALSE;
  962                       } else if (c == AudioFormat.class) {
  963                           int channels = 2;
  964                           boolean signed = true;
  965                           boolean bigendian = false;
  966                           int bits = 16;
  967                           float sampleRate = 44100f;
  968                           try {
  969                               StringTokenizer st = new StringTokenizer(s, ", ");
  970                               String prevToken = "";
  971                               while (st.hasMoreTokens()) {
  972                                   String token = st.nextToken().toLowerCase();
  973                                   if (token.equals("mono"))
  974                                       channels = 1;
  975                                   if (token.startsWith("channel"))
  976                                       channels = Integer.parseInt(prevToken);
  977                                   if (token.contains("unsigned"))
  978                                       signed = false;
  979                                   if (token.equals("big-endian"))
  980                                       bigendian = true;
  981                                   if (token.equals("bit"))
  982                                       bits = Integer.parseInt(prevToken);
  983                                   if (token.equals("hz"))
  984                                       sampleRate = Float.parseFloat(prevToken);
  985                                   prevToken = token;
  986                               }
  987                               item2.value = new AudioFormat(sampleRate, bits,
  988                                       channels, signed, bigendian);
  989                           } catch (NumberFormatException e) {
  990                           }
  991   
  992                       } else
  993                           try {
  994                               if (c == Byte.class)
  995                                   item2.value = Byte.valueOf(s);
  996                               else if (c == Short.class)
  997                                   item2.value = Short.valueOf(s);
  998                               else if (c == Integer.class)
  999                                   item2.value = Integer.valueOf(s);
 1000                               else if (c == Long.class)
 1001                                   item2.value = Long.valueOf(s);
 1002                               else if (c == Float.class)
 1003                                   item2.value = Float.valueOf(s);
 1004                               else if (c == Double.class)
 1005                                   item2.value = Double.valueOf(s);
 1006                           } catch (NumberFormatException e) {
 1007                           }
 1008                   } else if (v instanceof Number) {
 1009                       Number n = (Number) v;
 1010                       if (c == Byte.class)
 1011                           item2.value = Byte.valueOf(n.byteValue());
 1012                       if (c == Short.class)
 1013                           item2.value = Short.valueOf(n.shortValue());
 1014                       if (c == Integer.class)
 1015                           item2.value = Integer.valueOf(n.intValue());
 1016                       if (c == Long.class)
 1017                           item2.value = Long.valueOf(n.longValue());
 1018                       if (c == Float.class)
 1019                           item2.value = Float.valueOf(n.floatValue());
 1020                       if (c == Double.class)
 1021                           item2.value = Double.valueOf(n.doubleValue());
 1022                   }
 1023               }
 1024           }
 1025   
 1026           return items;
 1027       }
 1028   
 1029       public void open() throws MidiUnavailableException {
 1030           if (isOpen()) {
 1031               synchronized (control_mutex) {
 1032                   implicitOpen = false;
 1033               }
 1034               return;
 1035           }
 1036           open(null, null);
 1037       }
 1038   
 1039       public void open(SourceDataLine line, Map<String, Object> info) throws MidiUnavailableException {
 1040           if (isOpen()) {
 1041               synchronized (control_mutex) {
 1042                   implicitOpen = false;
 1043               }
 1044               return;
 1045           }
 1046           synchronized (control_mutex) {
 1047               Throwable causeException = null;
 1048               try {
 1049                   if (line != null) {
 1050                       // can throw IllegalArgumentException
 1051                       setFormat(line.getFormat());
 1052                   }
 1053   
 1054                   AudioInputStream ais = openStream(getFormat(), info);
 1055   
 1056                   weakstream = new WeakAudioStream(ais);
 1057                   ais = weakstream.getAudioInputStream();
 1058   
 1059                   if (line == null)
 1060                   {
 1061                       if (testline != null) {
 1062                           line = testline;
 1063                       } else {
 1064                           // can throw LineUnavailableException,
 1065                           // IllegalArgumentException, SecurityException
 1066                           line = AudioSystem.getSourceDataLine(getFormat());
 1067                       }
 1068                   }
 1069   
 1070                   double latency = this.latency;
 1071   
 1072                   if (!line.isOpen()) {
 1073                       int bufferSize = getFormat().getFrameSize()
 1074                           * (int)(getFormat().getFrameRate() * (latency/1000000f));
 1075                       // can throw LineUnavailableException,
 1076                       // IllegalArgumentException, SecurityException
 1077                       line.open(getFormat(), bufferSize);
 1078   
 1079                       // Remember that we opened that line
 1080                       // so we can close again in SoftSynthesizer.close()
 1081                       sourceDataLine = line;
 1082                   }
 1083                   if (!line.isActive())
 1084                       line.start();
 1085   
 1086                   int controlbuffersize = 512;
 1087                   try {
 1088                       controlbuffersize = ais.available();
 1089                   } catch (IOException e) {
 1090                   }
 1091   
 1092                   // Tell mixer not fill read buffers fully.
 1093                   // This lowers latency, and tells DataPusher
 1094                   // to read in smaller amounts.
 1095                   //mainmixer.readfully = false;
 1096                   //pusher = new DataPusher(line, ais);
 1097   
 1098                   int buffersize = line.getBufferSize();
 1099                   buffersize -= buffersize % controlbuffersize;
 1100   
 1101                   if (buffersize < 3 * controlbuffersize)
 1102                       buffersize = 3 * controlbuffersize;
 1103   
 1104                   if (jitter_correction) {
 1105                       ais = new SoftJitterCorrector(ais, buffersize,
 1106                               controlbuffersize);
 1107                       if(weakstream != null)
 1108                           weakstream.jitter_stream = ais;
 1109                   }
 1110                   pusher = new SoftAudioPusher(line, ais, controlbuffersize);
 1111                   pusher_stream = ais;
 1112                   pusher.start();
 1113   
 1114                   if(weakstream != null)
 1115                   {
 1116                       weakstream.pusher = pusher;
 1117                       weakstream.sourceDataLine = sourceDataLine;
 1118                   }
 1119   
 1120               } catch (LineUnavailableException e) {
 1121                   causeException = e;
 1122               } catch (IllegalArgumentException e) {
 1123                   causeException = e;
 1124               } catch (SecurityException e) {
 1125                   causeException = e;
 1126               }
 1127   
 1128               if (causeException != null) {
 1129                   if (isOpen())
 1130                       close();
 1131                   // am: need MidiUnavailableException(Throwable) ctor!
 1132                   MidiUnavailableException ex = new MidiUnavailableException(
 1133                           "Can not open line");
 1134                   ex.initCause(causeException);
 1135                   throw ex;
 1136               }
 1137   
 1138           }
 1139       }
 1140   
 1141       public AudioInputStream openStream(AudioFormat targetFormat,
 1142               Map<String, Object> info) throws MidiUnavailableException {
 1143   
 1144           if (isOpen())
 1145               throw new MidiUnavailableException("Synthesizer is already open");
 1146   
 1147           synchronized (control_mutex) {
 1148   
 1149               gmmode = 0;
 1150               voice_allocation_mode = 0;
 1151   
 1152               processPropertyInfo(info);
 1153   
 1154               open = true;
 1155               implicitOpen = false;
 1156   
 1157               if (targetFormat != null)
 1158                   setFormat(targetFormat);
 1159   
 1160               if (load_default_soundbank)
 1161               {
 1162                   Soundbank defbank = getDefaultSoundbank();
 1163                   if (defbank != null) {
 1164                       loadAllInstruments(defbank);
 1165                   }
 1166               }
 1167   
 1168               voices = new SoftVoice[maxpoly];
 1169               for (int i = 0; i < maxpoly; i++)
 1170                   voices[i] = new SoftVoice(this);
 1171   
 1172               mainmixer = new SoftMainMixer(this);
 1173   
 1174               channels = new SoftChannel[number_of_midi_channels];
 1175               for (int i = 0; i < channels.length; i++)
 1176                   channels[i] = new SoftChannel(this, i);
 1177   
 1178               if (external_channels == null) {
 1179                   // Always create external_channels array
 1180                   // with 16 or more channels
 1181                   // so getChannels works correctly
 1182                   // when the synhtesizer is closed.
 1183                   if (channels.length < 16)
 1184                       external_channels = new SoftChannelProxy[16];
 1185                   else
 1186                       external_channels = new SoftChannelProxy[channels.length];
 1187                   for (int i = 0; i < external_channels.length; i++)
 1188                       external_channels[i] = new SoftChannelProxy();
 1189               } else {
 1190                   // We must resize external_channels array
 1191                   // but we must also copy the old SoftChannelProxy
 1192                   // into the new one
 1193                   if (channels.length > external_channels.length) {
 1194                       SoftChannelProxy[] new_external_channels
 1195                               = new SoftChannelProxy[channels.length];
 1196                       for (int i = 0; i < external_channels.length; i++)
 1197                           new_external_channels[i] = external_channels[i];
 1198                       for (int i = external_channels.length;
 1199                               i < new_external_channels.length; i++) {
 1200                           new_external_channels[i] = new SoftChannelProxy();
 1201                       }
 1202                   }
 1203               }
 1204   
 1205               for (int i = 0; i < channels.length; i++)
 1206                   external_channels[i].setChannel(channels[i]);
 1207   
 1208               for (SoftVoice voice: getVoices())
 1209                   voice.resampler = resampler.openStreamer();
 1210   
 1211               for (Receiver recv: getReceivers()) {
 1212                   SoftReceiver srecv = ((SoftReceiver)recv);
 1213                   srecv.open = open;
 1214                   srecv.mainmixer = mainmixer;
 1215                   srecv.midimessages = mainmixer.midimessages;
 1216               }
 1217   
 1218               return mainmixer.getInputStream();
 1219           }
 1220       }
 1221   
 1222       public void close() {
 1223   
 1224           if (!isOpen())
 1225               return;
 1226   
 1227           SoftAudioPusher pusher_to_be_closed = null;
 1228           AudioInputStream pusher_stream_to_be_closed = null;
 1229           synchronized (control_mutex) {
 1230               if (pusher != null) {
 1231                   pusher_to_be_closed = pusher;
 1232                   pusher_stream_to_be_closed = pusher_stream;
 1233                   pusher = null;
 1234                   pusher_stream = null;
 1235               }
 1236           }
 1237   
 1238           if (pusher_to_be_closed != null) {
 1239               // Pusher must not be closed synchronized against control_mutex,
 1240               // this may result in synchronized conflict between pusher
 1241               // and current thread.
 1242               pusher_to_be_closed.stop();
 1243   
 1244               try {
 1245                   pusher_stream_to_be_closed.close();
 1246               } catch (IOException e) {
 1247                   //e.printStackTrace();
 1248               }
 1249           }
 1250   
 1251           synchronized (control_mutex) {
 1252   
 1253               if (mainmixer != null)
 1254                   mainmixer.close();
 1255               open = false;
 1256               implicitOpen = false;
 1257               mainmixer = null;
 1258               voices = null;
 1259               channels = null;
 1260   
 1261               if (external_channels != null)
 1262                   for (int i = 0; i < external_channels.length; i++)
 1263                       external_channels[i].setChannel(null);
 1264   
 1265               if (sourceDataLine != null) {
 1266                   sourceDataLine.close();
 1267                   sourceDataLine = null;
 1268               }
 1269   
 1270               inslist.clear();
 1271               loadedlist.clear();
 1272               tunings.clear();
 1273   
 1274               while (recvslist.size() != 0)
 1275                   recvslist.get(recvslist.size() - 1).close();
 1276   
 1277           }
 1278       }
 1279   
 1280       public boolean isOpen() {
 1281           synchronized (control_mutex) {
 1282               return open;
 1283           }
 1284       }
 1285   
 1286       public long getMicrosecondPosition() {
 1287   
 1288           if (!isOpen())
 1289               return 0;
 1290   
 1291           synchronized (control_mutex) {
 1292               return mainmixer.getMicrosecondPosition();
 1293           }
 1294       }
 1295   
 1296       public int getMaxReceivers() {
 1297           return -1;
 1298       }
 1299   
 1300       public int getMaxTransmitters() {
 1301           return 0;
 1302       }
 1303   
 1304       public Receiver getReceiver() throws MidiUnavailableException {
 1305   
 1306           synchronized (control_mutex) {
 1307               SoftReceiver receiver = new SoftReceiver(this);
 1308               receiver.open = open;
 1309               recvslist.add(receiver);
 1310               return receiver;
 1311           }
 1312       }
 1313   
 1314       public List<Receiver> getReceivers() {
 1315   
 1316           synchronized (control_mutex) {
 1317               ArrayList<Receiver> recvs = new ArrayList<Receiver>();
 1318               recvs.addAll(recvslist);
 1319               return recvs;
 1320           }
 1321       }
 1322   
 1323       public Transmitter getTransmitter() throws MidiUnavailableException {
 1324   
 1325           throw new MidiUnavailableException("No transmitter available");
 1326       }
 1327   
 1328       public List<Transmitter> getTransmitters() {
 1329   
 1330           return new ArrayList<Transmitter>();
 1331       }
 1332   
 1333       public Receiver getReceiverReferenceCounting()
 1334               throws MidiUnavailableException {
 1335   
 1336           if (!isOpen()) {
 1337               open();
 1338               synchronized (control_mutex) {
 1339                   implicitOpen = true;
 1340               }
 1341           }
 1342   
 1343           return getReceiver();
 1344       }
 1345   
 1346       public Transmitter getTransmitterReferenceCounting()
 1347               throws MidiUnavailableException {
 1348   
 1349           throw new MidiUnavailableException("No transmitter available");
 1350       }
 1351   }

Save This Page
Home » openjdk-7 » com.sun.media » sound » [javadoc | source]