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

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