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.util.ArrayList;
   29   import java.util.Arrays;
   30   import java.util.List;
   31   
   32   import javax.sound.sampled.AudioFormat;
   33   import javax.sound.sampled.AudioSystem;
   34   import javax.sound.sampled.BooleanControl;
   35   import javax.sound.sampled.Control;
   36   import javax.sound.sampled.DataLine;
   37   import javax.sound.sampled.FloatControl;
   38   import javax.sound.sampled.LineEvent;
   39   import javax.sound.sampled.LineListener;
   40   import javax.sound.sampled.Control.Type;
   41   
   42   /**
   43    * General software mixing line.
   44    *
   45    * @author Karl Helgason
   46    */
   47   public abstract class SoftMixingDataLine implements DataLine {
   48   
   49       public static final FloatControl.Type CHORUS_SEND = new FloatControl.Type(
   50               "Chorus Send") {
   51       };
   52   
   53       protected static class AudioFloatInputStreamResampler extends
   54               AudioFloatInputStream {
   55   
   56           private AudioFloatInputStream ais;
   57   
   58           private AudioFormat targetFormat;
   59   
   60           private float[] skipbuffer;
   61   
   62           private SoftAbstractResampler resampler;
   63   
   64           private float[] pitch = new float[1];
   65   
   66           private float[] ibuffer2;
   67   
   68           private float[][] ibuffer;
   69   
   70           private float ibuffer_index = 0;
   71   
   72           private int ibuffer_len = 0;
   73   
   74           private int nrofchannels = 0;
   75   
   76           private float[][] cbuffer;
   77   
   78           private int buffer_len = 512;
   79   
   80           private int pad;
   81   
   82           private int pad2;
   83   
   84           private float[] ix = new float[1];
   85   
   86           private int[] ox = new int[1];
   87   
   88           private float[][] mark_ibuffer = null;
   89   
   90           private float mark_ibuffer_index = 0;
   91   
   92           private int mark_ibuffer_len = 0;
   93   
   94           public AudioFloatInputStreamResampler(AudioFloatInputStream ais,
   95                   AudioFormat format) {
   96               this.ais = ais;
   97               AudioFormat sourceFormat = ais.getFormat();
   98               targetFormat = new AudioFormat(sourceFormat.getEncoding(), format
   99                       .getSampleRate(), sourceFormat.getSampleSizeInBits(),
  100                       sourceFormat.getChannels(), sourceFormat.getFrameSize(),
  101                       format.getSampleRate(), sourceFormat.isBigEndian());
  102               nrofchannels = targetFormat.getChannels();
  103               Object interpolation = format.getProperty("interpolation");
  104               if (interpolation != null && (interpolation instanceof String)) {
  105                   String resamplerType = (String) interpolation;
  106                   if (resamplerType.equalsIgnoreCase("point"))
  107                       this.resampler = new SoftPointResampler();
  108                   if (resamplerType.equalsIgnoreCase("linear"))
  109                       this.resampler = new SoftLinearResampler2();
  110                   if (resamplerType.equalsIgnoreCase("linear1"))
  111                       this.resampler = new SoftLinearResampler();
  112                   if (resamplerType.equalsIgnoreCase("linear2"))
  113                       this.resampler = new SoftLinearResampler2();
  114                   if (resamplerType.equalsIgnoreCase("cubic"))
  115                       this.resampler = new SoftCubicResampler();
  116                   if (resamplerType.equalsIgnoreCase("lanczos"))
  117                       this.resampler = new SoftLanczosResampler();
  118                   if (resamplerType.equalsIgnoreCase("sinc"))
  119                       this.resampler = new SoftSincResampler();
  120               }
  121               if (resampler == null)
  122                   resampler = new SoftLinearResampler2(); // new
  123               // SoftLinearResampler2();
  124               pitch[0] = sourceFormat.getSampleRate() / format.getSampleRate();
  125               pad = resampler.getPadding();
  126               pad2 = pad * 2;
  127               ibuffer = new float[nrofchannels][buffer_len + pad2];
  128               ibuffer2 = new float[nrofchannels * buffer_len];
  129               ibuffer_index = buffer_len + pad;
  130               ibuffer_len = buffer_len;
  131           }
  132   
  133           public int available() throws IOException {
  134               return 0;
  135           }
  136   
  137           public void close() throws IOException {
  138               ais.close();
  139           }
  140   
  141           public AudioFormat getFormat() {
  142               return targetFormat;
  143           }
  144   
  145           public long getFrameLength() {
  146               return AudioSystem.NOT_SPECIFIED; // ais.getFrameLength();
  147           }
  148   
  149           public void mark(int readlimit) {
  150               ais.mark((int) (readlimit * pitch[0]));
  151               mark_ibuffer_index = ibuffer_index;
  152               mark_ibuffer_len = ibuffer_len;
  153               if (mark_ibuffer == null) {
  154                   mark_ibuffer = new float[ibuffer.length][ibuffer[0].length];
  155               }
  156               for (int c = 0; c < ibuffer.length; c++) {
  157                   float[] from = ibuffer[c];
  158                   float[] to = mark_ibuffer[c];
  159                   for (int i = 0; i < to.length; i++) {
  160                       to[i] = from[i];
  161                   }
  162               }
  163           }
  164   
  165           public boolean markSupported() {
  166               return ais.markSupported();
  167           }
  168   
  169           private void readNextBuffer() throws IOException {
  170   
  171               if (ibuffer_len == -1)
  172                   return;
  173   
  174               for (int c = 0; c < nrofchannels; c++) {
  175                   float[] buff = ibuffer[c];
  176                   int buffer_len_pad = ibuffer_len + pad2;
  177                   for (int i = ibuffer_len, ix = 0; i < buffer_len_pad; i++, ix++) {
  178                       buff[ix] = buff[i];
  179                   }
  180               }
  181   
  182               ibuffer_index -= (ibuffer_len);
  183   
  184               ibuffer_len = ais.read(ibuffer2);
  185               if (ibuffer_len >= 0) {
  186                   while (ibuffer_len < ibuffer2.length) {
  187                       int ret = ais.read(ibuffer2, ibuffer_len, ibuffer2.length
  188                               - ibuffer_len);
  189                       if (ret == -1)
  190                           break;
  191                       ibuffer_len += ret;
  192                   }
  193                   Arrays.fill(ibuffer2, ibuffer_len, ibuffer2.length, 0);
  194                   ibuffer_len /= nrofchannels;
  195               } else {
  196                   Arrays.fill(ibuffer2, 0, ibuffer2.length, 0);
  197               }
  198   
  199               int ibuffer2_len = ibuffer2.length;
  200               for (int c = 0; c < nrofchannels; c++) {
  201                   float[] buff = ibuffer[c];
  202                   for (int i = c, ix = pad2; i < ibuffer2_len; i += nrofchannels, ix++) {
  203                       buff[ix] = ibuffer2[i];
  204                   }
  205               }
  206   
  207           }
  208   
  209           public int read(float[] b, int off, int len) throws IOException {
  210   
  211               if (cbuffer == null || cbuffer[0].length < len / nrofchannels) {
  212                   cbuffer = new float[nrofchannels][len / nrofchannels];
  213               }
  214               if (ibuffer_len == -1)
  215                   return -1;
  216               if (len < 0)
  217                   return 0;
  218               int remain = len / nrofchannels;
  219               int destPos = 0;
  220               int in_end = ibuffer_len;
  221               while (remain > 0) {
  222                   if (ibuffer_len >= 0) {
  223                       if (ibuffer_index >= (ibuffer_len + pad))
  224                           readNextBuffer();
  225                       in_end = ibuffer_len + pad;
  226                   }
  227   
  228                   if (ibuffer_len < 0) {
  229                       in_end = pad2;
  230                       if (ibuffer_index >= in_end)
  231                           break;
  232                   }
  233   
  234                   if (ibuffer_index < 0)
  235                       break;
  236                   int preDestPos = destPos;
  237                   for (int c = 0; c < nrofchannels; c++) {
  238                       ix[0] = ibuffer_index;
  239                       ox[0] = destPos;
  240                       float[] buff = ibuffer[c];
  241                       resampler.interpolate(buff, ix, in_end, pitch, 0,
  242                               cbuffer[c], ox, len / nrofchannels);
  243                   }
  244                   ibuffer_index = ix[0];
  245                   destPos = ox[0];
  246                   remain -= destPos - preDestPos;
  247               }
  248               for (int c = 0; c < nrofchannels; c++) {
  249                   int ix = 0;
  250                   float[] buff = cbuffer[c];
  251                   for (int i = c; i < b.length; i += nrofchannels) {
  252                       b[i] = buff[ix++];
  253                   }
  254               }
  255               return len - remain * nrofchannels;
  256           }
  257   
  258           public void reset() throws IOException {
  259               ais.reset();
  260               if (mark_ibuffer == null)
  261                   return;
  262               ibuffer_index = mark_ibuffer_index;
  263               ibuffer_len = mark_ibuffer_len;
  264               for (int c = 0; c < ibuffer.length; c++) {
  265                   float[] from = mark_ibuffer[c];
  266                   float[] to = ibuffer[c];
  267                   for (int i = 0; i < to.length; i++) {
  268                       to[i] = from[i];
  269                   }
  270               }
  271   
  272           }
  273   
  274           public long skip(long len) throws IOException {
  275               if (len > 0)
  276                   return 0;
  277               if (skipbuffer == null)
  278                   skipbuffer = new float[1024 * targetFormat.getFrameSize()];
  279               float[] l_skipbuffer = skipbuffer;
  280               long remain = len;
  281               while (remain > 0) {
  282                   int ret = read(l_skipbuffer, 0, (int) Math.min(remain,
  283                           skipbuffer.length));
  284                   if (ret < 0) {
  285                       if (remain == len)
  286                           return ret;
  287                       break;
  288                   }
  289                   remain -= ret;
  290               }
  291               return len - remain;
  292   
  293           }
  294   
  295       }
  296   
  297       private class Gain extends FloatControl {
  298   
  299           private Gain() {
  300   
  301               super(FloatControl.Type.MASTER_GAIN, -80f, 6.0206f, 80f / 128.0f,
  302                       -1, 0.0f, "dB", "Minimum", "", "Maximum");
  303           }
  304   
  305           public void setValue(float newValue) {
  306               super.setValue(newValue);
  307               calcVolume();
  308           }
  309       }
  310   
  311       private class Mute extends BooleanControl {
  312   
  313           private Mute() {
  314               super(BooleanControl.Type.MUTE, false, "True", "False");
  315           }
  316   
  317           public void setValue(boolean newValue) {
  318               super.setValue(newValue);
  319               calcVolume();
  320           }
  321       }
  322   
  323       private class ApplyReverb extends BooleanControl {
  324   
  325           private ApplyReverb() {
  326               super(BooleanControl.Type.APPLY_REVERB, false, "True", "False");
  327           }
  328   
  329           public void setValue(boolean newValue) {
  330               super.setValue(newValue);
  331               calcVolume();
  332           }
  333   
  334       }
  335   
  336       private class Balance extends FloatControl {
  337   
  338           private Balance() {
  339               super(FloatControl.Type.BALANCE, -1.0f, 1.0f, (1.0f / 128.0f), -1,
  340                       0.0f, "", "Left", "Center", "Right");
  341           }
  342   
  343           public void setValue(float newValue) {
  344               super.setValue(newValue);
  345               calcVolume();
  346           }
  347   
  348       }
  349   
  350       private class Pan extends FloatControl {
  351   
  352           private Pan() {
  353               super(FloatControl.Type.PAN, -1.0f, 1.0f, (1.0f / 128.0f), -1,
  354                       0.0f, "", "Left", "Center", "Right");
  355           }
  356   
  357           public void setValue(float newValue) {
  358               super.setValue(newValue);
  359               balance_control.setValue(newValue);
  360           }
  361   
  362           public float getValue() {
  363               return balance_control.getValue();
  364           }
  365   
  366       }
  367   
  368       private class ReverbSend extends FloatControl {
  369   
  370           private ReverbSend() {
  371               super(FloatControl.Type.REVERB_SEND, -80f, 6.0206f, 80f / 128.0f,
  372                       -1, -80f, "dB", "Minimum", "", "Maximum");
  373           }
  374   
  375           public void setValue(float newValue) {
  376               super.setValue(newValue);
  377               balance_control.setValue(newValue);
  378           }
  379   
  380       }
  381   
  382       private class ChorusSend extends FloatControl {
  383   
  384           private ChorusSend() {
  385               super(CHORUS_SEND, -80f, 6.0206f, 80f / 128.0f, -1, -80f, "dB",
  386                       "Minimum", "", "Maximum");
  387           }
  388   
  389           public void setValue(float newValue) {
  390               super.setValue(newValue);
  391               balance_control.setValue(newValue);
  392           }
  393   
  394       }
  395   
  396       private Gain gain_control = new Gain();
  397   
  398       private Mute mute_control = new Mute();
  399   
  400       private Balance balance_control = new Balance();
  401   
  402       private Pan pan_control = new Pan();
  403   
  404       private ReverbSend reverbsend_control = new ReverbSend();
  405   
  406       private ChorusSend chorussend_control = new ChorusSend();
  407   
  408       private ApplyReverb apply_reverb = new ApplyReverb();
  409   
  410       private Control[] controls;
  411   
  412       protected float leftgain = 1;
  413   
  414       protected float rightgain = 1;
  415   
  416       protected float eff1gain = 0;
  417   
  418       protected float eff2gain = 0;
  419   
  420       protected List<LineListener> listeners = new ArrayList<LineListener>();
  421   
  422       protected Object control_mutex;
  423   
  424       protected SoftMixingMixer mixer;
  425   
  426       protected DataLine.Info info;
  427   
  428       protected abstract void processControlLogic();
  429   
  430       protected abstract void processAudioLogic(SoftAudioBuffer[] buffers);
  431   
  432       protected SoftMixingDataLine(SoftMixingMixer mixer, DataLine.Info info) {
  433           this.mixer = mixer;
  434           this.info = info;
  435           this.control_mutex = mixer.control_mutex;
  436   
  437           controls = new Control[] { gain_control, mute_control, balance_control,
  438                   pan_control, reverbsend_control, chorussend_control,
  439                   apply_reverb };
  440           calcVolume();
  441       }
  442   
  443       protected void calcVolume() {
  444           synchronized (control_mutex) {
  445               double gain = Math.pow(10.0, gain_control.getValue() / 20.0);
  446               if (mute_control.getValue())
  447                   gain = 0;
  448               leftgain = (float) gain;
  449               rightgain = (float) gain;
  450               if (mixer.getFormat().getChannels() > 1) {
  451                   // -1 = Left, 0 Center, 1 = Right
  452                   double balance = balance_control.getValue();
  453                   if (balance > 0)
  454                       leftgain *= (1 - balance);
  455                   else
  456                       rightgain *= (1 + balance);
  457   
  458               }
  459           }
  460   
  461           eff1gain = (float) Math.pow(10.0, reverbsend_control.getValue() / 20.0);
  462           eff2gain = (float) Math.pow(10.0, chorussend_control.getValue() / 20.0);
  463   
  464           if (!apply_reverb.getValue()) {
  465               eff1gain = 0;
  466           }
  467       }
  468   
  469       protected void sendEvent(LineEvent event) {
  470           if (listeners.size() == 0)
  471               return;
  472           LineListener[] listener_array = listeners
  473                   .toArray(new LineListener[listeners.size()]);
  474           for (LineListener listener : listener_array) {
  475               listener.update(event);
  476           }
  477       }
  478   
  479       public void addLineListener(LineListener listener) {
  480           synchronized (control_mutex) {
  481               listeners.add(listener);
  482           }
  483       }
  484   
  485       public void removeLineListener(LineListener listener) {
  486           synchronized (control_mutex) {
  487               listeners.add(listener);
  488           }
  489       }
  490   
  491       public javax.sound.sampled.Line.Info getLineInfo() {
  492           return info;
  493       }
  494   
  495       public Control getControl(Type control) {
  496           if (control != null) {
  497               for (int i = 0; i < controls.length; i++) {
  498                   if (controls[i].getType() == control) {
  499                       return controls[i];
  500                   }
  501               }
  502           }
  503           throw new IllegalArgumentException("Unsupported control type : "
  504                   + control);
  505       }
  506   
  507       public Control[] getControls() {
  508           return Arrays.copyOf(controls, controls.length);
  509       }
  510   
  511       public boolean isControlSupported(Type control) {
  512           if (control != null) {
  513               for (int i = 0; i < controls.length; i++) {
  514                   if (controls[i].getType() == control) {
  515                       return true;
  516                   }
  517               }
  518           }
  519           return false;
  520       }
  521   
  522   }

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