1 /*
   2  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 import java.util.ArrayList;
  27 
  28 import javax.sound.sampled.AudioFormat;
  29 import javax.sound.sampled.AudioSystem;
  30 import javax.sound.sampled.Control;
  31 import javax.sound.sampled.DataLine;
  32 import javax.sound.sampled.LineListener;
  33 import javax.sound.sampled.LineUnavailableException;
  34 import javax.sound.sampled.SourceDataLine;
  35 import javax.sound.sampled.AudioFormat.Encoding;
  36 import javax.sound.sampled.Control.Type;
  37 
  38 import com.sun.media.sound.AudioFloatConverter;
  39 
  40 /**
  41  * This is a SourceDataLine simulator used for testing SoftSynthesizer
  42  * without using real SourceDataLine / Audio Device.
  43  *
  44  * @author Karl Helgason
  45  */
  46 
  47 public class DummySourceDataLine implements SourceDataLine {
  48 
  49     private int bufferSize = -1;
  50 
  51     private AudioFormat format = new AudioFormat(44100.0f, 16, 2, true, false);
  52 
  53     private DataLine.Info sourceLineInfo;
  54 
  55     private boolean active = false;
  56 
  57     private long framepos = 0;
  58 
  59     private boolean opened = false;
  60 
  61     private int framesize = 0;
  62 
  63     public DummySourceDataLine()
  64     {
  65         ArrayList<AudioFormat> formats = new ArrayList<AudioFormat>();
  66         for (int channels = 1; channels <= 2; channels++) {
  67             formats.add(new AudioFormat(Encoding.PCM_SIGNED,
  68                     AudioSystem.NOT_SPECIFIED, 8, channels, channels,
  69                     AudioSystem.NOT_SPECIFIED, false));
  70             formats.add(new AudioFormat(Encoding.PCM_UNSIGNED,
  71                     AudioSystem.NOT_SPECIFIED, 8, channels, channels,
  72                     AudioSystem.NOT_SPECIFIED, false));
  73             for (int bits = 16; bits < 32; bits += 8) {
  74                 formats.add(new AudioFormat(Encoding.PCM_SIGNED,
  75                         AudioSystem.NOT_SPECIFIED, bits, channels, channels
  76                                 * bits / 8, AudioSystem.NOT_SPECIFIED, false));
  77                 formats.add(new AudioFormat(Encoding.PCM_UNSIGNED,
  78                         AudioSystem.NOT_SPECIFIED, bits, channels, channels
  79                                 * bits / 8, AudioSystem.NOT_SPECIFIED, false));
  80                 formats.add(new AudioFormat(Encoding.PCM_SIGNED,
  81                         AudioSystem.NOT_SPECIFIED, bits, channels, channels
  82                                 * bits / 8, AudioSystem.NOT_SPECIFIED, true));
  83                 formats.add(new AudioFormat(Encoding.PCM_UNSIGNED,
  84                         AudioSystem.NOT_SPECIFIED, bits, channels, channels
  85                                 * bits / 8, AudioSystem.NOT_SPECIFIED, true));
  86             }
  87             formats.add(new AudioFormat(Encoding.PCM_FLOAT,
  88                     AudioSystem.NOT_SPECIFIED, 32, channels, channels * 4,
  89                     AudioSystem.NOT_SPECIFIED, false));
  90             formats.add(new AudioFormat(Encoding.PCM_FLOAT,
  91                     AudioSystem.NOT_SPECIFIED, 32, channels, channels * 4,
  92                     AudioSystem.NOT_SPECIFIED, true));
  93             formats.add(new AudioFormat(Encoding.PCM_FLOAT,
  94                     AudioSystem.NOT_SPECIFIED, 64, channels, channels * 8,
  95                     AudioSystem.NOT_SPECIFIED, false));
  96             formats.add(new AudioFormat(Encoding.PCM_FLOAT,
  97                     AudioSystem.NOT_SPECIFIED, 64, channels, channels * 8,
  98                     AudioSystem.NOT_SPECIFIED, true));
  99         }
 100         AudioFormat[] formats_array = formats.toArray(new AudioFormat[formats
 101                 .size()]);
 102         sourceLineInfo = new DataLine.Info(SourceDataLine.class,
 103                 formats_array, AudioSystem.NOT_SPECIFIED,
 104                 AudioSystem.NOT_SPECIFIED);
 105 
 106     }
 107 
 108     public void open() throws LineUnavailableException {
 109         open(format);
 110     }
 111 
 112     public void open(AudioFormat format) throws LineUnavailableException {
 113         if (bufferSize == -1)
 114             bufferSize = ((int) (format.getFrameRate() / 2))
 115                     * format.getFrameSize();
 116         open(format, bufferSize);
 117     }
 118 
 119     public void open(AudioFormat format, int bufferSize)
 120             throws LineUnavailableException {
 121         this.format = format;
 122         this.bufferSize = bufferSize;
 123         this.framesize = format.getFrameSize();
 124         opened = true;
 125     }
 126 
 127     public boolean isOpen() {
 128         return opened;
 129     }
 130 
 131     public int write(byte[] b, int off, int len) {
 132         if (!isOpen())
 133             return 0;
 134         if (len % framesize != 0)
 135             throw new IllegalArgumentException(
 136                     "Number of bytes does not represent an integral number of sample frames.");
 137 
 138 
 139         int flen = len / framesize;
 140         framepos += flen;
 141 
 142         long time =  (long) (flen * (1000.0 / (double) getFormat()
 143                 .getSampleRate()));
 144         try {
 145             Thread.sleep(time);
 146         } catch (InterruptedException e) {
 147             e.printStackTrace();
 148             return 0;
 149         }
 150 
 151         return len;
 152     }
 153 
 154     public int available() {
 155         return 0;
 156     }
 157 
 158     public void drain() {
 159     }
 160 
 161     public void flush() {
 162     }
 163 
 164     public int getBufferSize() {
 165         return bufferSize;
 166     }
 167 
 168     public AudioFormat getFormat() {
 169         return format;
 170     }
 171 
 172     public int getFramePosition() {
 173         return (int) getLongFramePosition();
 174     }
 175 
 176     public float getLevel() {
 177         return AudioSystem.NOT_SPECIFIED;
 178     }
 179 
 180     public long getLongFramePosition() {
 181         return framepos;
 182     }
 183 
 184     public long getMicrosecondPosition() {
 185         return (long) (getLongFramePosition() * (1000000.0 / (double) getFormat()
 186                 .getSampleRate()));
 187     }
 188 
 189     public boolean isActive() {
 190         return active;
 191     }
 192 
 193     public boolean isRunning() {
 194         return active;
 195     }
 196 
 197     public void start() {
 198         active = true;
 199     }
 200 
 201     public void stop() {
 202         active = false;
 203     }
 204 
 205     public void close() {
 206         stop();
 207     }
 208 
 209     public Control getControl(Type control) {
 210         throw new IllegalArgumentException("Unsupported control type : "
 211                 + control);
 212     }
 213 
 214     public Control[] getControls() {
 215         return new Control[0];
 216     }
 217 
 218     public javax.sound.sampled.Line.Info getLineInfo() {
 219         return sourceLineInfo;
 220     }
 221 
 222     public boolean isControlSupported(Type control) {
 223         return false;
 224     }
 225 
 226     public void addLineListener(LineListener listener) {
 227     }
 228 
 229     public void removeLineListener(LineListener listener) {
 230     }
 231 
 232 }