< prev index next >

src/java.desktop/share/classes/com/sun/media/sound/SoftMixingDataLine.java

Print this page




   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 final class AudioFloatInputStreamResampler extends
  54             AudioFloatInputStream {
  55 
  56         private final AudioFloatInputStream ais;
  57 
  58         private final AudioFormat targetFormat;
  59 
  60         private float[] skipbuffer;


 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);


 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) {


 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 final 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 final 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 final 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 final 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 final 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 final 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 final 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 final Gain gain_control = new Gain();
 397 
 398     private final Mute mute_control = new Mute();
 399 
 400     private final Balance balance_control = new Balance();
 401 
 402     private final Pan pan_control = new Pan();
 403 
 404     private final ReverbSend reverbsend_control = new ReverbSend();
 405 
 406     private final ChorusSend chorussend_control = new ChorusSend();
 407 
 408     private final ApplyReverb apply_reverb = new ApplyReverb();
 409 
 410     private final Control[] controls;
 411 
 412     float leftgain = 1;
 413 
 414     float rightgain = 1;
 415 
 416     float eff1gain = 0;
 417 
 418     float eff2gain = 0;
 419 
 420     List<LineListener> listeners = new ArrayList<LineListener>();
 421 
 422     final Object control_mutex;
 423 
 424     SoftMixingMixer mixer;
 425 
 426     DataLine.Info info;
 427 
 428     protected abstract void processControlLogic();
 429 
 430     protected abstract void processAudioLogic(SoftAudioBuffer[] buffers);
 431 
 432     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();


 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     final 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 final void addLineListener(LineListener listener) {
 480         synchronized (control_mutex) {
 481             listeners.add(listener);
 482         }
 483     }
 484 

 485     public final void removeLineListener(LineListener listener) {
 486         synchronized (control_mutex) {
 487             listeners.add(listener);
 488         }
 489     }
 490 

 491     public final javax.sound.sampled.Line.Info getLineInfo() {
 492         return info;
 493     }
 494 

 495     public final 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 final Control[] getControls() {
 508         return Arrays.copyOf(controls, controls.length);
 509     }
 510 

 511     public final 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 }


   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.media.sound;
  27 
  28 import java.io.IOException;
  29 import java.util.ArrayList;
  30 import java.util.Arrays;
  31 import java.util.List;
  32 
  33 import javax.sound.sampled.AudioFormat;
  34 import javax.sound.sampled.AudioSystem;
  35 import javax.sound.sampled.BooleanControl;
  36 import javax.sound.sampled.Control;
  37 import javax.sound.sampled.Control.Type;
  38 import javax.sound.sampled.DataLine;
  39 import javax.sound.sampled.FloatControl;
  40 import javax.sound.sampled.LineEvent;
  41 import javax.sound.sampled.LineListener;

  42 
  43 /**
  44  * General software mixing line.
  45  *
  46  * @author Karl Helgason
  47  */
  48 public abstract class SoftMixingDataLine implements DataLine {
  49 
  50     public static final FloatControl.Type CHORUS_SEND = new FloatControl.Type(
  51             "Chorus Send") {
  52     };
  53 
  54     protected static final class AudioFloatInputStreamResampler extends
  55             AudioFloatInputStream {
  56 
  57         private final AudioFloatInputStream ais;
  58 
  59         private final AudioFormat targetFormat;
  60 
  61         private float[] skipbuffer;


 114                     this.resampler = new SoftLinearResampler2();
 115                 if (resamplerType.equalsIgnoreCase("cubic"))
 116                     this.resampler = new SoftCubicResampler();
 117                 if (resamplerType.equalsIgnoreCase("lanczos"))
 118                     this.resampler = new SoftLanczosResampler();
 119                 if (resamplerType.equalsIgnoreCase("sinc"))
 120                     this.resampler = new SoftSincResampler();
 121             }
 122             if (resampler == null)
 123                 resampler = new SoftLinearResampler2(); // new
 124             // SoftLinearResampler2();
 125             pitch[0] = sourceFormat.getSampleRate() / format.getSampleRate();
 126             pad = resampler.getPadding();
 127             pad2 = pad * 2;
 128             ibuffer = new float[nrofchannels][buffer_len + pad2];
 129             ibuffer2 = new float[nrofchannels * buffer_len];
 130             ibuffer_index = buffer_len + pad;
 131             ibuffer_len = buffer_len;
 132         }
 133 
 134         @Override
 135         public int available() throws IOException {
 136             return 0;
 137         }
 138 
 139         @Override
 140         public void close() throws IOException {
 141             ais.close();
 142         }
 143 
 144         @Override
 145         public AudioFormat getFormat() {
 146             return targetFormat;
 147         }
 148 
 149         @Override
 150         public long getFrameLength() {
 151             return AudioSystem.NOT_SPECIFIED; // ais.getFrameLength();
 152         }
 153 
 154         @Override
 155         public void mark(int readlimit) {
 156             ais.mark((int) (readlimit * pitch[0]));
 157             mark_ibuffer_index = ibuffer_index;
 158             mark_ibuffer_len = ibuffer_len;
 159             if (mark_ibuffer == null) {
 160                 mark_ibuffer = new float[ibuffer.length][ibuffer[0].length];
 161             }
 162             for (int c = 0; c < ibuffer.length; c++) {
 163                 float[] from = ibuffer[c];
 164                 float[] to = mark_ibuffer[c];
 165                 for (int i = 0; i < to.length; i++) {
 166                     to[i] = from[i];
 167                 }
 168             }
 169         }
 170 
 171         @Override
 172         public boolean markSupported() {
 173             return ais.markSupported();
 174         }
 175 
 176         private void readNextBuffer() throws IOException {
 177 
 178             if (ibuffer_len == -1)
 179                 return;
 180 
 181             for (int c = 0; c < nrofchannels; c++) {
 182                 float[] buff = ibuffer[c];
 183                 int buffer_len_pad = ibuffer_len + pad2;
 184                 for (int i = ibuffer_len, ix = 0; i < buffer_len_pad; i++, ix++) {
 185                     buff[ix] = buff[i];
 186                 }
 187             }
 188 
 189             ibuffer_index -= (ibuffer_len);
 190 
 191             ibuffer_len = ais.read(ibuffer2);


 196                     if (ret == -1)
 197                         break;
 198                     ibuffer_len += ret;
 199                 }
 200                 Arrays.fill(ibuffer2, ibuffer_len, ibuffer2.length, 0);
 201                 ibuffer_len /= nrofchannels;
 202             } else {
 203                 Arrays.fill(ibuffer2, 0, ibuffer2.length, 0);
 204             }
 205 
 206             int ibuffer2_len = ibuffer2.length;
 207             for (int c = 0; c < nrofchannels; c++) {
 208                 float[] buff = ibuffer[c];
 209                 for (int i = c, ix = pad2; i < ibuffer2_len; i += nrofchannels, ix++) {
 210                     buff[ix] = ibuffer2[i];
 211                 }
 212             }
 213 
 214         }
 215 
 216         @Override
 217         public int read(float[] b, int off, int len) throws IOException {
 218 
 219             if (cbuffer == null || cbuffer[0].length < len / nrofchannels) {
 220                 cbuffer = new float[nrofchannels][len / nrofchannels];
 221             }
 222             if (ibuffer_len == -1)
 223                 return -1;
 224             if (len < 0)
 225                 return 0;
 226             int remain = len / nrofchannels;
 227             int destPos = 0;
 228             int in_end = ibuffer_len;
 229             while (remain > 0) {
 230                 if (ibuffer_len >= 0) {
 231                     if (ibuffer_index >= (ibuffer_len + pad))
 232                         readNextBuffer();
 233                     in_end = ibuffer_len + pad;
 234                 }
 235 
 236                 if (ibuffer_len < 0) {


 246                     ix[0] = ibuffer_index;
 247                     ox[0] = destPos;
 248                     float[] buff = ibuffer[c];
 249                     resampler.interpolate(buff, ix, in_end, pitch, 0,
 250                             cbuffer[c], ox, len / nrofchannels);
 251                 }
 252                 ibuffer_index = ix[0];
 253                 destPos = ox[0];
 254                 remain -= destPos - preDestPos;
 255             }
 256             for (int c = 0; c < nrofchannels; c++) {
 257                 int ix = 0;
 258                 float[] buff = cbuffer[c];
 259                 for (int i = c; i < b.length; i += nrofchannels) {
 260                     b[i] = buff[ix++];
 261                 }
 262             }
 263             return len - remain * nrofchannels;
 264         }
 265 
 266         @Override
 267         public void reset() throws IOException {
 268             ais.reset();
 269             if (mark_ibuffer == null)
 270                 return;
 271             ibuffer_index = mark_ibuffer_index;
 272             ibuffer_len = mark_ibuffer_len;
 273             for (int c = 0; c < ibuffer.length; c++) {
 274                 float[] from = mark_ibuffer[c];
 275                 float[] to = ibuffer[c];
 276                 for (int i = 0; i < to.length; i++) {
 277                     to[i] = from[i];
 278                 }
 279             }
 280 
 281         }
 282 
 283         @Override
 284         public long skip(long len) throws IOException {
 285             if (len > 0)
 286                 return 0;
 287             if (skipbuffer == null)
 288                 skipbuffer = new float[1024 * targetFormat.getFrameSize()];
 289             float[] l_skipbuffer = skipbuffer;
 290             long remain = len;
 291             while (remain > 0) {
 292                 int ret = read(l_skipbuffer, 0, (int) Math.min(remain,
 293                         skipbuffer.length));
 294                 if (ret < 0) {
 295                     if (remain == len)
 296                         return ret;
 297                     break;
 298                 }
 299                 remain -= ret;
 300             }
 301             return len - remain;
 302 
 303         }
 304 
 305     }
 306 
 307     private final class Gain extends FloatControl {
 308 
 309         private Gain() {
 310 
 311             super(FloatControl.Type.MASTER_GAIN, -80f, 6.0206f, 80f / 128.0f,
 312                     -1, 0.0f, "dB", "Minimum", "", "Maximum");
 313         }
 314 
 315         @Override
 316         public void setValue(float newValue) {
 317             super.setValue(newValue);
 318             calcVolume();
 319         }
 320     }
 321 
 322     private final class Mute extends BooleanControl {
 323 
 324         private Mute() {
 325             super(BooleanControl.Type.MUTE, false, "True", "False");
 326         }
 327 
 328         @Override
 329         public void setValue(boolean newValue) {
 330             super.setValue(newValue);
 331             calcVolume();
 332         }
 333     }
 334 
 335     private final class ApplyReverb extends BooleanControl {
 336 
 337         private ApplyReverb() {
 338             super(BooleanControl.Type.APPLY_REVERB, false, "True", "False");
 339         }
 340 
 341         @Override
 342         public void setValue(boolean newValue) {
 343             super.setValue(newValue);
 344             calcVolume();
 345         }
 346 
 347     }
 348 
 349     private final class Balance extends FloatControl {
 350 
 351         private Balance() {
 352             super(FloatControl.Type.BALANCE, -1.0f, 1.0f, (1.0f / 128.0f), -1,
 353                     0.0f, "", "Left", "Center", "Right");
 354         }
 355 
 356         @Override
 357         public void setValue(float newValue) {
 358             super.setValue(newValue);
 359             calcVolume();
 360         }
 361 
 362     }
 363 
 364     private final class Pan extends FloatControl {
 365 
 366         private Pan() {
 367             super(FloatControl.Type.PAN, -1.0f, 1.0f, (1.0f / 128.0f), -1,
 368                     0.0f, "", "Left", "Center", "Right");
 369         }
 370 
 371         @Override
 372         public void setValue(float newValue) {
 373             super.setValue(newValue);
 374             balance_control.setValue(newValue);
 375         }
 376 
 377         @Override
 378         public float getValue() {
 379             return balance_control.getValue();
 380         }
 381 
 382     }
 383 
 384     private final class ReverbSend extends FloatControl {
 385 
 386         private ReverbSend() {
 387             super(FloatControl.Type.REVERB_SEND, -80f, 6.0206f, 80f / 128.0f,
 388                     -1, -80f, "dB", "Minimum", "", "Maximum");
 389         }
 390 
 391         @Override
 392         public void setValue(float newValue) {
 393             super.setValue(newValue);
 394             balance_control.setValue(newValue);
 395         }
 396 
 397     }
 398 
 399     private final class ChorusSend extends FloatControl {
 400 
 401         private ChorusSend() {
 402             super(CHORUS_SEND, -80f, 6.0206f, 80f / 128.0f, -1, -80f, "dB",
 403                     "Minimum", "", "Maximum");
 404         }
 405 
 406         @Override
 407         public void setValue(float newValue) {
 408             super.setValue(newValue);
 409             balance_control.setValue(newValue);
 410         }
 411 
 412     }
 413 
 414     private final Gain gain_control = new Gain();
 415 
 416     private final Mute mute_control = new Mute();
 417 
 418     private final Balance balance_control = new Balance();
 419 
 420     private final Pan pan_control = new Pan();
 421 
 422     private final ReverbSend reverbsend_control = new ReverbSend();
 423 
 424     private final ChorusSend chorussend_control = new ChorusSend();
 425 
 426     private final ApplyReverb apply_reverb = new ApplyReverb();
 427 
 428     private final Control[] controls;
 429 
 430     float leftgain = 1;
 431 
 432     float rightgain = 1;
 433 
 434     float eff1gain = 0;
 435 
 436     float eff2gain = 0;
 437 
 438     List<LineListener> listeners = new ArrayList<>();
 439 
 440     final Object control_mutex;
 441 
 442     SoftMixingMixer mixer;
 443 
 444     DataLine.Info info;
 445 
 446     protected abstract void processControlLogic();
 447 
 448     protected abstract void processAudioLogic(SoftAudioBuffer[] buffers);
 449 
 450     SoftMixingDataLine(SoftMixingMixer mixer, DataLine.Info info) {
 451         this.mixer = mixer;
 452         this.info = info;
 453         this.control_mutex = mixer.control_mutex;
 454 
 455         controls = new Control[] { gain_control, mute_control, balance_control,
 456                 pan_control, reverbsend_control, chorussend_control,
 457                 apply_reverb };
 458         calcVolume();


 477         }
 478 
 479         eff1gain = (float) Math.pow(10.0, reverbsend_control.getValue() / 20.0);
 480         eff2gain = (float) Math.pow(10.0, chorussend_control.getValue() / 20.0);
 481 
 482         if (!apply_reverb.getValue()) {
 483             eff1gain = 0;
 484         }
 485     }
 486 
 487     final void sendEvent(LineEvent event) {
 488         if (listeners.size() == 0)
 489             return;
 490         LineListener[] listener_array = listeners
 491                 .toArray(new LineListener[listeners.size()]);
 492         for (LineListener listener : listener_array) {
 493             listener.update(event);
 494         }
 495     }
 496 
 497     @Override
 498     public final void addLineListener(LineListener listener) {
 499         synchronized (control_mutex) {
 500             listeners.add(listener);
 501         }
 502     }
 503 
 504     @Override
 505     public final void removeLineListener(LineListener listener) {
 506         synchronized (control_mutex) {
 507             listeners.add(listener);
 508         }
 509     }
 510 
 511     @Override
 512     public final javax.sound.sampled.Line.Info getLineInfo() {
 513         return info;
 514     }
 515 
 516     @Override
 517     public final Control getControl(Type control) {
 518         if (control != null) {
 519             for (int i = 0; i < controls.length; i++) {
 520                 if (controls[i].getType() == control) {
 521                     return controls[i];
 522                 }
 523             }
 524         }
 525         throw new IllegalArgumentException("Unsupported control type : "
 526                 + control);
 527     }
 528 
 529     @Override
 530     public final Control[] getControls() {
 531         return Arrays.copyOf(controls, controls.length);
 532     }
 533 
 534     @Override
 535     public final boolean isControlSupported(Type control) {
 536         if (control != null) {
 537             for (int i = 0; i < controls.length; i++) {
 538                 if (controls[i].getType() == control) {
 539                     return true;
 540                 }
 541             }
 542         }
 543         return false;
 544     }

 545 }
< prev index next >