Save This Page
Home » openjdk-7 » com.sun.media » sound » [javadoc | source]
    1   /*
    2    * Copyright (c) 1999, 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.util.ArrayList;
   29   import java.util.List;
   30   import java.util.Collections;
   31   
   32   import javax.sound.midi;
   33   
   34   
   35   /**
   36    * Abstract AbstractMidiDevice class representing functionality shared by
   37    * MidiInDevice and MidiOutDevice objects.
   38    *
   39    * @author David Rivas
   40    * @author Kara Kytle
   41    * @author Matthias Pfisterer
   42    * @author Florian Bomers
   43    */
   44   abstract class AbstractMidiDevice implements MidiDevice, ReferenceCountingDevice {
   45   
   46       // STATIC VARIABLES
   47       private static final boolean TRACE_TRANSMITTER = false;
   48   
   49       // INSTANCE VARIABLES
   50   
   51       private ArrayList<Receiver> receiverList;
   52   
   53       private TransmitterList transmitterList;
   54   
   55       // lock to protect receiverList and transmitterList
   56       // from simultaneous creation and destruction
   57       // reduces possibility of deadlock, compared to
   58       // synchronizing to the class instance
   59       private Object traRecLock = new Object();
   60   
   61       // DEVICE ATTRIBUTES
   62   
   63       private MidiDevice.Info info;
   64   
   65   
   66       // DEVICE STATE
   67   
   68       protected /*private*/ boolean open          = false;
   69       private int openRefCount;
   70   
   71       /** List of Receivers and Transmitters that opened the device implicitely.
   72        */
   73       private List openKeepingObjects;
   74   
   75       /**
   76        * This is the device handle returned from native code
   77        */
   78       protected long id                   = 0;
   79   
   80   
   81   
   82       // CONSTRUCTOR
   83   
   84   
   85       /**
   86        * Constructs an AbstractMidiDevice with the specified info object.
   87        * @param info the description of the device
   88        */
   89       /*
   90        * The initial mode and and only supported mode default to OMNI_ON_POLY.
   91        */
   92       protected AbstractMidiDevice(MidiDevice.Info info) {
   93   
   94           if(Printer.trace) Printer.trace(">> AbstractMidiDevice CONSTRUCTOR");
   95   
   96           this.info = info;
   97           openRefCount = 0;
   98   
   99           if(Printer.trace) Printer.trace("<< AbstractMidiDevice CONSTRUCTOR completed");
  100       }
  101   
  102   
  103       // MIDI DEVICE METHODS
  104   
  105       public MidiDevice.Info getDeviceInfo() {
  106           return info;
  107       }
  108   
  109       /** Open the device from an aplication program.
  110        * Setting the open reference count to -1 here prevents Transmitters and Receivers that
  111        * opened the the device implicitly from closing it. The only way to close the device after
  112        * this call is a call to close().
  113        */
  114       public void open() throws MidiUnavailableException {
  115           if (Printer.trace) Printer.trace("> AbstractMidiDevice: open()");
  116           synchronized(this) {
  117               openRefCount = -1;
  118               doOpen();
  119           }
  120           if (Printer.trace) Printer.trace("< AbstractMidiDevice: open() completed");
  121       }
  122   
  123   
  124   
  125       /** Open the device implicitly.
  126        * This method is intended to be used by AbstractReceiver
  127        * and BasicTransmitter. Actually, it is called by getReceiverReferenceCounting() and
  128        * getTransmitterReferenceCounting(). These, in turn, are called by MidiSytem on calls to
  129        * getReceiver() and getTransmitter(). The former methods should pass the Receiver or
  130        * Transmitter just created as the object parameter to this method. Storing references to
  131        * these objects is necessary to be able to decide later (when it comes to closing) if
  132        * R/T's are ones that opened the device implicitly.
  133        *
  134        * @object The Receiver or Transmitter instance that triggered this implicit open.
  135        */
  136       private void openInternal(Object object) throws MidiUnavailableException {
  137           if (Printer.trace) Printer.trace("> AbstractMidiDevice: openInternal()");
  138           synchronized(this) {
  139               if (openRefCount != -1) {
  140                   openRefCount++;
  141                   getOpenKeepingObjects().add(object);
  142               }
  143               // double calls to doOpens() will be catched by the open flag.
  144               doOpen();
  145           }
  146           if (Printer.trace) Printer.trace("< AbstractMidiDevice: openInternal() completed");
  147       }
  148   
  149   
  150       private void doOpen() throws MidiUnavailableException {
  151           if (Printer.trace) Printer.trace("> AbstractMidiDevice: doOpen()");
  152           synchronized(this) {
  153               if (! isOpen()) {
  154                   implOpen();
  155                   open = true;
  156               }
  157           }
  158           if (Printer.trace) Printer.trace("< AbstractMidiDevice: doOpen() completed");
  159       }
  160   
  161   
  162       public void close() {
  163           if (Printer.trace) Printer.trace("> AbstractMidiDevice: close()");
  164           synchronized (this) {
  165               doClose();
  166               openRefCount = 0;
  167           }
  168           if (Printer.trace) Printer.trace("< AbstractMidiDevice: close() completed");
  169       }
  170   
  171   
  172       /** Close the device for an object that implicitely opened it.
  173        * This method is intended to be used by Transmitter.close() and Receiver.close().
  174        * Those methods should pass this for the object parameter. Since Transmitters or Receivers
  175        * do not know if their device has been opened implicitely because of them, they call this
  176        * method in any case. This method now is able to seperate Receivers/Transmitters that opened
  177        * the device implicitely from those that didn't by looking up the R/T in the
  178        * openKeepingObjects list. Only if the R/T is contained there, the reference count is
  179        * reduced.
  180        *
  181        * @param object The object that might have been opening the device implicitely (for now,
  182        * this may be a Transmitter or receiver).
  183        */
  184       public void closeInternal(Object object) {
  185           if (Printer.trace) Printer.trace("> AbstractMidiDevice: closeInternal()");
  186           synchronized(this) {
  187               if (getOpenKeepingObjects().remove(object)) {
  188                   if (openRefCount > 0) {
  189                       openRefCount--;
  190                       if (openRefCount == 0) {
  191                           doClose();
  192                       }
  193                   }
  194               }
  195           }
  196           if (Printer.trace) Printer.trace("< AbstractMidiDevice: closeInternal() completed");
  197       }
  198   
  199   
  200       public void doClose() {
  201           if (Printer.trace) Printer.trace("> AbstractMidiDevice: doClose()");
  202           synchronized(this) {
  203               if (isOpen()) {
  204                   implClose();
  205                   open = false;
  206               }
  207           }
  208           if (Printer.trace) Printer.trace("< AbstractMidiDevice: doClose() completed");
  209       }
  210   
  211   
  212       public boolean isOpen() {
  213           return open;
  214       }
  215   
  216   
  217       protected void implClose() {
  218           synchronized (traRecLock) {
  219               if (receiverList != null) {
  220                   // close all receivers
  221                   for(int i = 0; i < receiverList.size(); i++) {
  222                       receiverList.get(i).close();
  223                   }
  224                   receiverList.clear();
  225               }
  226               if (transmitterList != null) {
  227                   // close all transmitters
  228                   transmitterList.close();
  229               }
  230           }
  231       }
  232   
  233   
  234       /**
  235        * This implementation always returns -1.
  236        * Devices that actually provide this should over-ride
  237        * this method.
  238        */
  239       public long getMicrosecondPosition() {
  240           return -1;
  241       }
  242   
  243   
  244       /** Return the maximum number of Receivers supported by this device.
  245           Depending on the return value of hasReceivers(), this method returns either 0 or -1.
  246           Subclasses should rather override hasReceivers() than override this method.
  247        */
  248       public final int getMaxReceivers() {
  249           if (hasReceivers()) {
  250               return -1;
  251           } else {
  252               return 0;
  253           }
  254       }
  255   
  256   
  257       /** Return the maximum number of Transmitters supported by this device.
  258           Depending on the return value of hasTransmitters(), this method returns either 0 or -1.
  259           Subclasses should override hasTransmitters().
  260        */
  261       public final int getMaxTransmitters() {
  262           if (hasTransmitters()) {
  263               return -1;
  264           } else {
  265               return 0;
  266           }
  267       }
  268   
  269   
  270       /** Retrieve a Receiver for this device.
  271           This method returns the value returned by createReceiver(), if it doesn't throw
  272           an exception. Subclasses should rather override createReceiver() than override
  273           this method.
  274           If createReceiver returns a Receiver, it is added to the internal list
  275           of Receivers (see getReceiversList)
  276        */
  277       public final Receiver getReceiver() throws MidiUnavailableException {
  278           Receiver receiver;
  279           synchronized (traRecLock) {
  280               receiver = createReceiver(); // may throw MidiUnavailableException
  281               getReceiverList().add(receiver);
  282           }
  283           return receiver;
  284       }
  285   
  286   
  287       public final List<Receiver> getReceivers() {
  288           List<Receiver> recs;
  289           synchronized (traRecLock) {
  290               if (receiverList == null) {
  291                   recs = Collections.unmodifiableList(new ArrayList<Receiver>(0));
  292               } else {
  293                   recs = Collections.unmodifiableList
  294                       ((List<Receiver>) (receiverList.clone()));
  295               }
  296           }
  297           return recs;
  298       }
  299   
  300   
  301       /**
  302        * This implementation uses createTransmitter, which may throw an exception.
  303        * If a transmitter is returned in createTransmitter, it is added to the internal
  304        * TransmitterList
  305        */
  306       public final Transmitter getTransmitter() throws MidiUnavailableException {
  307           Transmitter transmitter;
  308           synchronized (traRecLock) {
  309               transmitter = createTransmitter(); // may throw MidiUnavailableException
  310               getTransmitterList().add(transmitter);
  311           }
  312           return transmitter;
  313       }
  314   
  315   
  316       public final List<Transmitter> getTransmitters() {
  317           List<Transmitter> tras;
  318           synchronized (traRecLock) {
  319               if (transmitterList == null
  320                   || transmitterList.transmitters.size() == 0) {
  321                   tras = Collections.unmodifiableList(new ArrayList<Transmitter>(0));
  322               } else {
  323                   tras = Collections.unmodifiableList((List<Transmitter>) (transmitterList.transmitters.clone()));
  324               }
  325           }
  326           return tras;
  327       }
  328   
  329   
  330       // HELPER METHODS
  331   
  332       long getId() {
  333           return id;
  334       }
  335   
  336   
  337       // REFERENCE COUNTING
  338   
  339       /** Retrieve a Receiver and open the device implicitly.
  340           This method is called by MidiSystem.getReceiver().
  341        */
  342       public Receiver getReceiverReferenceCounting() throws MidiUnavailableException {
  343           /* Keep this order of commands! If getReceiver() throws an exception,
  344              openInternal() should not be called!
  345           */
  346           Receiver receiver;
  347           synchronized (traRecLock) {
  348               receiver = getReceiver();
  349               AbstractMidiDevice.this.openInternal(receiver);
  350           }
  351           return receiver;
  352       }
  353   
  354   
  355       /** Retrieve a Transmitter and open the device implicitly.
  356           This method is called by MidiSystem.getTransmitter().
  357        */
  358       public Transmitter getTransmitterReferenceCounting() throws MidiUnavailableException {
  359           /* Keep this order of commands! If getTransmitter() throws an exception,
  360              openInternal() should not be called!
  361           */
  362           Transmitter transmitter;
  363           synchronized (traRecLock) {
  364               transmitter = getTransmitter();
  365               AbstractMidiDevice.this.openInternal(transmitter);
  366           }
  367           return transmitter;
  368       }
  369   
  370   
  371       /** Return the list of objects that have opened the device implicitely.
  372        */
  373       private synchronized List getOpenKeepingObjects() {
  374           if (openKeepingObjects == null) {
  375               openKeepingObjects = new ArrayList();
  376           }
  377           return openKeepingObjects;
  378       }
  379   
  380   
  381   
  382       // RECEIVER HANDLING METHODS
  383   
  384   
  385       /** Return the internal list of Receivers, possibly creating it first.
  386        */
  387       private List<Receiver> getReceiverList() {
  388           synchronized (traRecLock) {
  389               if (receiverList == null) {
  390                   receiverList = new ArrayList<Receiver>();
  391               }
  392           }
  393           return receiverList;
  394       }
  395   
  396   
  397       /** Returns if this device supports Receivers.
  398           Subclasses that use Receivers should override this method to
  399           return true. They also should override createReceiver().
  400   
  401           @return true, if the device supports Receivers, false otherwise.
  402       */
  403       protected boolean hasReceivers() {
  404           return false;
  405       }
  406   
  407   
  408       /** Create a Receiver object.
  409           throwing an exception here means that Receivers aren't enabled.
  410           Subclasses that use Receivers should override this method with
  411           one that returns objects implementing Receiver.
  412           Classes overriding this method should also override hasReceivers()
  413           to return true.
  414       */
  415       protected Receiver createReceiver() throws MidiUnavailableException {
  416           throw new MidiUnavailableException("MIDI IN receiver not available");
  417       }
  418   
  419   
  420   
  421       // TRANSMITTER HANDLING
  422   
  423       /** Return the internal list of Transmitters, possibly creating it first.
  424        */
  425       protected TransmitterList getTransmitterList() {
  426           synchronized (traRecLock) {
  427               if (transmitterList == null) {
  428                   transmitterList = new TransmitterList();
  429               }
  430           }
  431           return transmitterList;
  432       }
  433   
  434   
  435       /** Returns if this device supports Transmitters.
  436           Subclasses that use Transmitters should override this method to
  437           return true. They also should override createTransmitter().
  438   
  439           @return true, if the device supports Transmitters, false otherwise.
  440       */
  441       protected boolean hasTransmitters() {
  442           return false;
  443       }
  444   
  445   
  446       /** Create a Transmitter object.
  447           throwing an exception here means that Transmitters aren't enabled.
  448           Subclasses that use Transmitters should override this method with
  449           one that returns objects implementing Transmitters.
  450           Classes overriding this method should also override hasTransmitters()
  451           to return true.
  452       */
  453       protected Transmitter createTransmitter() throws MidiUnavailableException {
  454           throw new MidiUnavailableException("MIDI OUT transmitter not available");
  455       }
  456   
  457       // ABSTRACT METHODS
  458   
  459       protected abstract void implOpen() throws MidiUnavailableException;
  460   
  461   
  462       /**
  463        * close this device if discarded by the garbage collector
  464        */
  465       protected void finalize() {
  466           close();
  467       }
  468   
  469       // INNER CLASSES
  470   
  471       /** Base class for Receivers.
  472           Subclasses that use Receivers must use this base class, since it
  473           contains magic necessary to manage implicit closing the device.
  474           This is necessary for Receivers retrieved via MidiSystem.getReceiver()
  475           (which opens the device implicitely).
  476        */
  477       protected abstract class AbstractReceiver implements MidiDeviceReceiver {
  478           private boolean open = true;
  479   
  480   
  481           /** Deliver a MidiMessage.
  482               This method contains magic related to the closed state of a
  483               Receiver. Therefore, subclasses should not override this method.
  484               Instead, they should implement implSend().
  485           */
  486           public synchronized void send(MidiMessage message, long timeStamp) {
  487               if (open) {
  488                   implSend(message, timeStamp);
  489               } else {
  490                   throw new IllegalStateException("Receiver is not open");
  491               }
  492           }
  493   
  494   
  495           protected abstract void implSend(MidiMessage message, long timeStamp);
  496   
  497   
  498           /** Close the Receiver.
  499            * Here, the call to the magic method closeInternal() takes place.
  500            * Therefore, subclasses that override this method must call
  501            * 'super.close()'.
  502            */
  503           public void close() {
  504               open = false;
  505               synchronized (AbstractMidiDevice.this.traRecLock) {
  506                   AbstractMidiDevice.this.getReceiverList().remove(this);
  507               }
  508               AbstractMidiDevice.this.closeInternal(this);
  509           }
  510   
  511           public MidiDevice getMidiDevice() {
  512               return AbstractMidiDevice.this;
  513           }
  514   
  515           protected boolean isOpen() {
  516               return open;
  517           }
  518   
  519           //$$fb is that a good idea?
  520           //protected void finalize() {
  521           //    close();
  522           //}
  523   
  524       } // class AbstractReceiver
  525   
  526   
  527       /**
  528        * Transmitter base class.
  529        * This class especially makes sure the device is closed if it
  530        * has been opened implicitly by a call to MidiSystem.getTransmitter().
  531        * The logic of doing so is actually in closeInternal().
  532        *
  533        * Also, it has some optimizations regarding sending to the Receivers,
  534        * for known Receivers, and managing itself in the TransmitterList.
  535        */
  536       protected class BasicTransmitter implements MidiDeviceTransmitter {
  537   
  538           private Receiver receiver = null;
  539           TransmitterList tlist = null;
  540   
  541           protected BasicTransmitter() {
  542           }
  543   
  544           private void setTransmitterList(TransmitterList tlist) {
  545               this.tlist = tlist;
  546           }
  547   
  548           public void setReceiver(Receiver receiver) {
  549               if (tlist != null && this.receiver != receiver) {
  550                   if (Printer.debug) Printer.debug("Transmitter "+toString()+": set receiver "+receiver);
  551                   tlist.receiverChanged(this, this.receiver, receiver);
  552                   this.receiver = receiver;
  553               }
  554           }
  555   
  556           public Receiver getReceiver() {
  557               return receiver;
  558           }
  559   
  560   
  561           /** Close the Transmitter.
  562            * Here, the call to the magic method closeInternal() takes place.
  563            * Therefore, subclasses that override this method must call
  564            * 'super.close()'.
  565            */
  566           public void close() {
  567               AbstractMidiDevice.this.closeInternal(this);
  568               if (tlist != null) {
  569                   tlist.receiverChanged(this, this.receiver, null);
  570                   tlist.remove(this);
  571                   tlist = null;
  572               }
  573           }
  574   
  575           public MidiDevice getMidiDevice() {
  576               return AbstractMidiDevice.this;
  577           }
  578   
  579       } // class BasicTransmitter
  580   
  581   
  582       /**
  583        * a class to manage a list of transmitters
  584        */
  585       class TransmitterList {
  586   
  587           private ArrayList<Transmitter> transmitters = new ArrayList<Transmitter>();
  588           private MidiOutDevice.MidiOutReceiver midiOutReceiver;
  589   
  590           // how many transmitters must be present for optimized
  591           // handling
  592           private int optimizedReceiverCount = 0;
  593   
  594   
  595           private void add(Transmitter t) {
  596               synchronized(transmitters) {
  597                   transmitters.add(t);
  598               }
  599               if (t instanceof BasicTransmitter) {
  600                   ((BasicTransmitter) t).setTransmitterList(this);
  601               }
  602               if (Printer.debug) Printer.debug("--added transmitter "+t);
  603           }
  604   
  605           private void remove(Transmitter t) {
  606               synchronized(transmitters) {
  607                   int index = transmitters.indexOf(t);
  608                   if (index >= 0) {
  609                       transmitters.remove(index);
  610                       if (Printer.debug) Printer.debug("--removed transmitter "+t);
  611                   }
  612               }
  613           }
  614   
  615           private void receiverChanged(BasicTransmitter t,
  616                                        Receiver oldR,
  617                                        Receiver newR) {
  618               synchronized(transmitters) {
  619                   // some optimization
  620                   if (midiOutReceiver == oldR) {
  621                       midiOutReceiver = null;
  622                   }
  623                   if (newR != null) {
  624                       if ((newR instanceof MidiOutDevice.MidiOutReceiver)
  625                           && (midiOutReceiver == null)) {
  626                           midiOutReceiver = ((MidiOutDevice.MidiOutReceiver) newR);
  627                       }
  628                   }
  629                   optimizedReceiverCount =
  630                         ((midiOutReceiver!=null)?1:0);
  631               }
  632               // more potential for optimization here
  633           }
  634   
  635   
  636           /** closes all transmitters and empties the list */
  637           void close() {
  638               synchronized (transmitters) {
  639                   for(int i = 0; i < transmitters.size(); i++) {
  640                       transmitters.get(i).close();
  641                   }
  642                   transmitters.clear();
  643               }
  644               if (Printer.trace) Printer.trace("TransmitterList.close() succeeded");
  645           }
  646   
  647   
  648   
  649           /**
  650           * Send this message to all receivers
  651           * status = packedMessage & 0xFF
  652           * data1 = (packedMessage & 0xFF00) >> 8;
  653           * data1 = (packedMessage & 0xFF0000) >> 16;
  654           */
  655           void sendMessage(int packedMessage, long timeStamp) {
  656               try {
  657                   synchronized(transmitters) {
  658                       int size = transmitters.size();
  659                       if (optimizedReceiverCount == size) {
  660                           if (midiOutReceiver != null) {
  661                               if (TRACE_TRANSMITTER) Printer.println("Sending packed message to MidiOutReceiver");
  662                               midiOutReceiver.sendPackedMidiMessage(packedMessage, timeStamp);
  663                           }
  664                       } else {
  665                           if (TRACE_TRANSMITTER) Printer.println("Sending packed message to "+size+" transmitter's receivers");
  666                           for (int i = 0; i < size; i++) {
  667                               Receiver receiver = ((Transmitter)transmitters.get(i)).getReceiver();
  668                               if (receiver != null) {
  669                                   if (optimizedReceiverCount > 0) {
  670                                       if (receiver instanceof MidiOutDevice.MidiOutReceiver) {
  671                                           ((MidiOutDevice.MidiOutReceiver) receiver).sendPackedMidiMessage(packedMessage, timeStamp);
  672                                       } else {
  673                                           receiver.send(new FastShortMessage(packedMessage), timeStamp);
  674                                       }
  675                                   } else {
  676                                       receiver.send(new FastShortMessage(packedMessage), timeStamp);
  677                                   }
  678                               }
  679                           }
  680                       }
  681                   }
  682               } catch (InvalidMidiDataException e) {
  683                   // this happens when invalid data comes over the wire. Ignore it.
  684               }
  685           }
  686   
  687           void sendMessage(byte[] data, long timeStamp) {
  688               try {
  689                   synchronized(transmitters) {
  690                       int size = transmitters.size();
  691                       if (TRACE_TRANSMITTER) Printer.println("Sending long message to "+size+" transmitter's receivers");
  692                       for (int i = 0; i < size; i++) {
  693                           Receiver receiver = ((Transmitter)transmitters.get(i)).getReceiver();
  694                           if (receiver != null) {
  695                               //$$fb 2002-04-02: SysexMessages are mutable, so
  696                               // an application could change the contents of this object,
  697                               // or try to use the object later. So we can't get around object creation
  698                               // But the array need not be unique for each FastSysexMessage object,
  699                               // because it cannot be modified.
  700                               receiver.send(new FastSysexMessage(data), timeStamp);
  701                           }
  702                       }
  703                   }
  704               } catch (InvalidMidiDataException e) {
  705                   // this happens when invalid data comes over the wire. Ignore it.
  706                   return;
  707               }
  708           }
  709   
  710   
  711           /**
  712           * Send this message to all transmitters
  713           */
  714           void sendMessage(MidiMessage message, long timeStamp) {
  715               if (message instanceof FastShortMessage) {
  716                   sendMessage(((FastShortMessage) message).getPackedMsg(), timeStamp);
  717                   return;
  718               }
  719               synchronized(transmitters) {
  720                   int size = transmitters.size();
  721                   if (optimizedReceiverCount == size) {
  722                       if (midiOutReceiver != null) {
  723                           if (TRACE_TRANSMITTER) Printer.println("Sending MIDI message to MidiOutReceiver");
  724                           midiOutReceiver.send(message, timeStamp);
  725                       }
  726                   } else {
  727                       if (TRACE_TRANSMITTER) Printer.println("Sending MIDI message to "+size+" transmitter's receivers");
  728                       for (int i = 0; i < size; i++) {
  729                           Receiver receiver = ((Transmitter)transmitters.get(i)).getReceiver();
  730                           if (receiver != null) {
  731                               //$$fb 2002-04-02: ShortMessages are mutable, so
  732                               // an application could change the contents of this object,
  733                               // or try to use the object later.
  734                               // We violate this spec here, to avoid costly (and gc-intensive)
  735                               // object creation for potentially hundred of messages per second.
  736                               // The spec should be changed to allow Immutable MidiMessages
  737                               // (i.e. throws InvalidStateException or so in setMessage)
  738                               receiver.send(message, timeStamp);
  739                           }
  740                       }
  741                   }
  742               }
  743           }
  744   
  745   
  746       } // TransmitterList
  747   
  748   }

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