Save This Page
Home » openjdk-7 » com.sun.media » sound » [javadoc | source]
    1   /*
    2    * Copyright (c) 2008, 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   package com.sun.media.sound;
   26   
   27   import java.io.ByteArrayOutputStream;
   28   import java.io.IOException;
   29   import java.io.InputStream;
   30   import java.util.Arrays;
   31   
   32   import javax.sound.sampled.AudioFormat;
   33   import javax.sound.sampled.AudioInputStream;
   34   import javax.sound.sampled.AudioSystem;
   35   import javax.sound.sampled.Clip;
   36   import javax.sound.sampled.DataLine;
   37   import javax.sound.sampled.LineEvent;
   38   import javax.sound.sampled.LineUnavailableException;
   39   
   40   /**
   41    * Clip implemention for the SoftMixingMixer.
   42    *
   43    * @author Karl Helgason
   44    */
   45   public class SoftMixingClip extends SoftMixingDataLine implements Clip {
   46   
   47       private AudioFormat format;
   48   
   49       private int framesize;
   50   
   51       private byte[] data;
   52   
   53       private InputStream datastream = new InputStream() {
   54   
   55           public int read() throws IOException {
   56               byte[] b = new byte[1];
   57               int ret = read(b);
   58               if (ret < 0)
   59                   return ret;
   60               return b[0] & 0xFF;
   61           }
   62   
   63           public int read(byte[] b, int off, int len) throws IOException {
   64   
   65               if (_loopcount != 0) {
   66                   int bloopend = _loopend * framesize;
   67                   int bloopstart = _loopstart * framesize;
   68                   int pos = _frameposition * framesize;
   69   
   70                   if (pos + len >= bloopend)
   71                       if (pos < bloopend) {
   72                           int offend = off + len;
   73                           int o = off;
   74                           while (off != offend) {
   75                               if (pos == bloopend) {
   76                                   if (_loopcount == 0)
   77                                       break;
   78                                   pos = bloopstart;
   79                                   if (_loopcount != LOOP_CONTINUOUSLY)
   80                                       _loopcount--;
   81                               }
   82                               len = offend - off;
   83                               int left = bloopend - pos;
   84                               if (len > left)
   85                                   len = left;
   86                               System.arraycopy(data, pos, b, off, len);
   87                               off += len;
   88                           }
   89                           if (_loopcount == 0) {
   90                               len = offend - off;
   91                               int left = bloopend - pos;
   92                               if (len > left)
   93                                   len = left;
   94                               System.arraycopy(data, pos, b, off, len);
   95                               off += len;
   96                           }
   97                           _frameposition = pos / framesize;
   98                           return o - off;
   99                       }
  100               }
  101   
  102               int pos = _frameposition * framesize;
  103               int left = bufferSize - pos;
  104               if (left == 0)
  105                   return -1;
  106               if (len > left)
  107                   len = left;
  108               System.arraycopy(data, pos, b, off, len);
  109               _frameposition += len / framesize;
  110               return len;
  111           }
  112   
  113       };
  114   
  115       private int offset;
  116   
  117       private int bufferSize;
  118   
  119       private float[] readbuffer;
  120   
  121       private boolean open = false;
  122   
  123       private AudioFormat outputformat;
  124   
  125       private int out_nrofchannels;
  126   
  127       private int in_nrofchannels;
  128   
  129       private int frameposition = 0;
  130   
  131       private boolean frameposition_sg = false;
  132   
  133       private boolean active_sg = false;
  134   
  135       private int loopstart = 0;
  136   
  137       private int loopend = -1;
  138   
  139       private boolean active = false;
  140   
  141       private int loopcount = 0;
  142   
  143       private boolean _active = false;
  144   
  145       private int _frameposition = 0;
  146   
  147       private boolean loop_sg = false;
  148   
  149       private int _loopcount = 0;
  150   
  151       private int _loopstart = 0;
  152   
  153       private int _loopend = -1;
  154   
  155       private float _rightgain;
  156   
  157       private float _leftgain;
  158   
  159       private float _eff1gain;
  160   
  161       private float _eff2gain;
  162   
  163       private AudioFloatInputStream afis;
  164   
  165       protected SoftMixingClip(SoftMixingMixer mixer, DataLine.Info info) {
  166           super(mixer, info);
  167       }
  168   
  169       protected void processControlLogic() {
  170   
  171           _rightgain = rightgain;
  172           _leftgain = leftgain;
  173           _eff1gain = eff1gain;
  174           _eff2gain = eff2gain;
  175   
  176           if (active_sg) {
  177               _active = active;
  178               active_sg = false;
  179           } else {
  180               active = _active;
  181           }
  182   
  183           if (frameposition_sg) {
  184               _frameposition = frameposition;
  185               frameposition_sg = false;
  186               afis = null;
  187           } else {
  188               frameposition = _frameposition;
  189           }
  190           if (loop_sg) {
  191               _loopcount = loopcount;
  192               _loopstart = loopstart;
  193               _loopend = loopend;
  194           }
  195   
  196           if (afis == null) {
  197               afis = AudioFloatInputStream.getInputStream(new AudioInputStream(
  198                       datastream, format, AudioSystem.NOT_SPECIFIED));
  199   
  200               if (Math.abs(format.getSampleRate() - outputformat.getSampleRate()) > 0.000001)
  201                   afis = new AudioFloatInputStreamResampler(afis, outputformat);
  202           }
  203   
  204       }
  205   
  206       protected void processAudioLogic(SoftAudioBuffer[] buffers) {
  207           if (_active) {
  208               float[] left = buffers[SoftMixingMainMixer.CHANNEL_LEFT].array();
  209               float[] right = buffers[SoftMixingMainMixer.CHANNEL_RIGHT].array();
  210               int bufferlen = buffers[SoftMixingMainMixer.CHANNEL_LEFT].getSize();
  211   
  212               int readlen = bufferlen * in_nrofchannels;
  213               if (readbuffer == null || readbuffer.length < readlen) {
  214                   readbuffer = new float[readlen];
  215               }
  216               int ret = 0;
  217               try {
  218                   ret = afis.read(readbuffer);
  219                   if (ret == -1) {
  220                       _active = false;
  221                       return;
  222                   }
  223                   if (ret != in_nrofchannels)
  224                       Arrays.fill(readbuffer, ret, readlen, 0);
  225               } catch (IOException e) {
  226               }
  227   
  228               int in_c = in_nrofchannels;
  229               for (int i = 0, ix = 0; i < bufferlen; i++, ix += in_c) {
  230                   left[i] += readbuffer[ix] * _leftgain;
  231               }
  232   
  233               if (out_nrofchannels != 1) {
  234                   if (in_nrofchannels == 1) {
  235                       for (int i = 0, ix = 0; i < bufferlen; i++, ix += in_c) {
  236                           right[i] += readbuffer[ix] * _rightgain;
  237                       }
  238                   } else {
  239                       for (int i = 0, ix = 1; i < bufferlen; i++, ix += in_c) {
  240                           right[i] += readbuffer[ix] * _rightgain;
  241                       }
  242                   }
  243   
  244               }
  245   
  246               if (_eff1gain > 0.0002) {
  247   
  248                   float[] eff1 = buffers[SoftMixingMainMixer.CHANNEL_EFFECT1]
  249                           .array();
  250                   for (int i = 0, ix = 0; i < bufferlen; i++, ix += in_c) {
  251                       eff1[i] += readbuffer[ix] * _eff1gain;
  252                   }
  253                   if (in_nrofchannels == 2) {
  254                       for (int i = 0, ix = 1; i < bufferlen; i++, ix += in_c) {
  255                           eff1[i] += readbuffer[ix] * _eff1gain;
  256                       }
  257                   }
  258               }
  259   
  260               if (_eff2gain > 0.0002) {
  261                   float[] eff2 = buffers[SoftMixingMainMixer.CHANNEL_EFFECT2]
  262                           .array();
  263                   for (int i = 0, ix = 0; i < bufferlen; i++, ix += in_c) {
  264                       eff2[i] += readbuffer[ix] * _eff2gain;
  265                   }
  266                   if (in_nrofchannels == 2) {
  267                       for (int i = 0, ix = 1; i < bufferlen; i++, ix += in_c) {
  268                           eff2[i] += readbuffer[ix] * _eff2gain;
  269                       }
  270                   }
  271               }
  272   
  273           }
  274       }
  275   
  276       public int getFrameLength() {
  277           return bufferSize / format.getFrameSize();
  278       }
  279   
  280       public long getMicrosecondLength() {
  281           return (long) (getFrameLength() * (1000000.0 / (double) getFormat()
  282                   .getSampleRate()));
  283       }
  284   
  285       public void loop(int count) {
  286           LineEvent event = null;
  287   
  288           synchronized (control_mutex) {
  289               if (isOpen()) {
  290                   if (active)
  291                       return;
  292                   active = true;
  293                   active_sg = true;
  294                   loopcount = count;
  295                   event = new LineEvent(this, LineEvent.Type.START,
  296                           getLongFramePosition());
  297               }
  298           }
  299   
  300           if (event != null)
  301               sendEvent(event);
  302   
  303       }
  304   
  305       public void open(AudioInputStream stream) throws LineUnavailableException,
  306               IOException {
  307           if (isOpen()) {
  308               throw new IllegalStateException("Clip is already open with format "
  309                       + getFormat() + " and frame lengh of " + getFrameLength());
  310           }
  311           if (AudioFloatConverter.getConverter(stream.getFormat()) == null)
  312               throw new IllegalArgumentException("Invalid format : "
  313                       + stream.getFormat().toString());
  314   
  315           if (stream.getFrameLength() != AudioSystem.NOT_SPECIFIED) {
  316               byte[] data = new byte[(int) stream.getFrameLength()
  317                       * stream.getFormat().getFrameSize()];
  318               int readsize = 512 * stream.getFormat().getFrameSize();
  319               int len = 0;
  320               while (len != data.length) {
  321                   if (readsize > data.length - len)
  322                       readsize = data.length - len;
  323                   int ret = stream.read(data, len, readsize);
  324                   if (ret == -1)
  325                       break;
  326                   if (ret == 0)
  327                       Thread.yield();
  328                   len += ret;
  329               }
  330               open(stream.getFormat(), data, 0, len);
  331           } else {
  332               ByteArrayOutputStream baos = new ByteArrayOutputStream();
  333               byte[] b = new byte[512 * stream.getFormat().getFrameSize()];
  334               int r = 0;
  335               while ((r = stream.read(b)) != -1) {
  336                   if (r == 0)
  337                       Thread.yield();
  338                   baos.write(b, 0, r);
  339               }
  340               open(stream.getFormat(), baos.toByteArray(), 0, baos.size());
  341           }
  342   
  343       }
  344   
  345       public void open(AudioFormat format, byte[] data, int offset, int bufferSize)
  346               throws LineUnavailableException {
  347           synchronized (control_mutex) {
  348               if (isOpen()) {
  349                   throw new IllegalStateException(
  350                           "Clip is already open with format " + getFormat()
  351                                   + " and frame lengh of " + getFrameLength());
  352               }
  353               if (AudioFloatConverter.getConverter(format) == null)
  354                   throw new IllegalArgumentException("Invalid format : "
  355                           + format.toString());
  356               if (bufferSize % format.getFrameSize() != 0)
  357                   throw new IllegalArgumentException(
  358                           "Buffer size does not represent an integral number of sample frames!");
  359   
  360               this.data = data;
  361               this.offset = offset;
  362               this.bufferSize = bufferSize;
  363               this.format = format;
  364               this.framesize = format.getFrameSize();
  365   
  366               loopstart = 0;
  367               loopend = -1;
  368               loop_sg = true;
  369   
  370               if (!mixer.isOpen()) {
  371                   mixer.open();
  372                   mixer.implicitOpen = true;
  373               }
  374   
  375               outputformat = mixer.getFormat();
  376               out_nrofchannels = outputformat.getChannels();
  377               in_nrofchannels = format.getChannels();
  378   
  379               open = true;
  380   
  381               mixer.getMainMixer().openLine(this);
  382           }
  383   
  384       }
  385   
  386       public void setFramePosition(int frames) {
  387           synchronized (control_mutex) {
  388               frameposition_sg = true;
  389               frameposition = frames;
  390           }
  391       }
  392   
  393       public void setLoopPoints(int start, int end) {
  394           synchronized (control_mutex) {
  395               if (end != -1) {
  396                   if (end < start)
  397                       throw new IllegalArgumentException("Invalid loop points : "
  398                               + start + " - " + end);
  399                   if (end * framesize > bufferSize)
  400                       throw new IllegalArgumentException("Invalid loop points : "
  401                               + start + " - " + end);
  402               }
  403               if (start * framesize > bufferSize)
  404                   throw new IllegalArgumentException("Invalid loop points : "
  405                           + start + " - " + end);
  406               if (0 < start)
  407                   throw new IllegalArgumentException("Invalid loop points : "
  408                           + start + " - " + end);
  409               loopstart = start;
  410               loopend = end;
  411               loop_sg = true;
  412           }
  413       }
  414   
  415       public void setMicrosecondPosition(long microseconds) {
  416           setFramePosition((int) (microseconds * (((double) getFormat()
  417                   .getSampleRate()) / 1000000.0)));
  418       }
  419   
  420       public int available() {
  421           return 0;
  422       }
  423   
  424       public void drain() {
  425       }
  426   
  427       public void flush() {
  428       }
  429   
  430       public int getBufferSize() {
  431           return bufferSize;
  432       }
  433   
  434       public AudioFormat getFormat() {
  435           return format;
  436       }
  437   
  438       public int getFramePosition() {
  439           synchronized (control_mutex) {
  440               return frameposition;
  441           }
  442       }
  443   
  444       public float getLevel() {
  445           return AudioSystem.NOT_SPECIFIED;
  446       }
  447   
  448       public long getLongFramePosition() {
  449           return getFramePosition();
  450       }
  451   
  452       public long getMicrosecondPosition() {
  453           return (long) (getFramePosition() * (1000000.0 / (double) getFormat()
  454                   .getSampleRate()));
  455       }
  456   
  457       public boolean isActive() {
  458           synchronized (control_mutex) {
  459               return active;
  460           }
  461       }
  462   
  463       public boolean isRunning() {
  464           synchronized (control_mutex) {
  465               return active;
  466           }
  467       }
  468   
  469       public void start() {
  470   
  471           LineEvent event = null;
  472   
  473           synchronized (control_mutex) {
  474               if (isOpen()) {
  475                   if (active)
  476                       return;
  477                   active = true;
  478                   active_sg = true;
  479                   loopcount = 0;
  480                   event = new LineEvent(this, LineEvent.Type.START,
  481                           getLongFramePosition());
  482               }
  483           }
  484   
  485           if (event != null)
  486               sendEvent(event);
  487       }
  488   
  489       public void stop() {
  490           LineEvent event = null;
  491   
  492           synchronized (control_mutex) {
  493               if (isOpen()) {
  494                   if (!active)
  495                       return;
  496                   active = false;
  497                   active_sg = true;
  498                   event = new LineEvent(this, LineEvent.Type.STOP,
  499                           getLongFramePosition());
  500               }
  501           }
  502   
  503           if (event != null)
  504               sendEvent(event);
  505       }
  506   
  507       public void close() {
  508           LineEvent event = null;
  509   
  510           synchronized (control_mutex) {
  511               if (!isOpen())
  512                   return;
  513               stop();
  514   
  515               event = new LineEvent(this, LineEvent.Type.CLOSE,
  516                       getLongFramePosition());
  517   
  518               open = false;
  519               mixer.getMainMixer().closeLine(this);
  520           }
  521   
  522           if (event != null)
  523               sendEvent(event);
  524   
  525       }
  526   
  527       public boolean isOpen() {
  528           return open;
  529       }
  530   
  531       public void open() throws LineUnavailableException {
  532           if (data == null) {
  533               throw new IllegalArgumentException(
  534                       "Illegal call to open() in interface Clip");
  535           }
  536           open(format, data, offset, bufferSize);
  537       }
  538   
  539   }

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