1 /* 2 * Copyright (c) 2007, 2013, 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 package com.sun.media.sound; 27 28 import java.io.ByteArrayInputStream; 29 import java.io.File; 30 import java.io.IOException; 31 import java.io.InputStream; 32 import java.net.URL; 33 34 import javax.sound.sampled.AudioFormat; 35 import javax.sound.sampled.AudioInputStream; 36 import javax.sound.sampled.AudioSystem; 37 import javax.sound.sampled.UnsupportedAudioFileException; 38 39 /** 40 * This class is used to create AudioFloatInputStream from AudioInputStream and 41 * byte buffers. 42 * 43 * @author Karl Helgason 44 */ 45 public abstract class AudioFloatInputStream { 46 47 private static class BytaArrayAudioFloatInputStream 48 extends AudioFloatInputStream { 49 50 private int pos = 0; 51 private int markpos = 0; 52 private final AudioFloatConverter converter; 53 private final AudioFormat format; 54 private final byte[] buffer; 55 private final int buffer_offset; 56 private final int buffer_len; 57 private final int framesize_pc; 58 59 BytaArrayAudioFloatInputStream(AudioFloatConverter converter, 60 byte[] buffer, int offset, int len) { 61 this.converter = converter; 62 this.format = converter.getFormat(); 63 this.buffer = buffer; 64 this.buffer_offset = offset; 65 framesize_pc = format.getFrameSize() / format.getChannels(); 66 this.buffer_len = len / framesize_pc; 67 68 } 69 70 @Override 71 public AudioFormat getFormat() { 72 return format; 73 } 74 75 @Override 76 public long getFrameLength() { 77 return buffer_len;// / format.getFrameSize(); 78 } 79 80 @Override 81 public int read(float[] b, int off, int len) throws IOException { 82 if (b == null) 83 throw new NullPointerException(); 84 if (off < 0 || len < 0 || len > b.length - off) 85 throw new IndexOutOfBoundsException(); 86 if (pos >= buffer_len) 87 return -1; 88 if (len == 0) 89 return 0; 90 if (pos + len > buffer_len) 91 len = buffer_len - pos; 92 converter.toFloatArray(buffer, buffer_offset + pos * framesize_pc, 93 b, off, len); 94 pos += len; 95 return len; 96 } 97 98 @Override 99 public long skip(long len) throws IOException { 100 if (pos >= buffer_len) 101 return -1; 102 if (len <= 0) 103 return 0; 104 if (pos + len > buffer_len) 105 len = buffer_len - pos; 106 pos += len; 107 return len; 108 } 109 110 @Override 111 public int available() throws IOException { 112 return buffer_len - pos; 113 } 114 115 @Override 116 public void close() throws IOException { 117 } 118 119 @Override 120 public void mark(int readlimit) { 121 markpos = pos; 122 } 123 124 @Override 125 public boolean markSupported() { 126 return true; 127 } 128 129 @Override 130 public void reset() throws IOException { 131 pos = markpos; 132 } 133 } 134 135 private static class DirectAudioFloatInputStream 136 extends AudioFloatInputStream { 137 138 private final AudioInputStream stream; 139 private AudioFloatConverter converter; 140 private final int framesize_pc; // framesize / channels 141 private byte[] buffer; 142 143 DirectAudioFloatInputStream(AudioInputStream stream) { 144 converter = AudioFloatConverter.getConverter(stream.getFormat()); 145 if (converter == null) { 146 AudioFormat format = stream.getFormat(); 147 AudioFormat newformat; 148 149 AudioFormat[] formats = AudioSystem.getTargetFormats( 150 AudioFormat.Encoding.PCM_SIGNED, format); 151 if (formats.length != 0) { 152 newformat = formats[0]; 153 } else { 154 float samplerate = format.getSampleRate(); 155 int samplesizeinbits = format.getSampleSizeInBits(); 156 int framesize = format.getFrameSize(); 157 float framerate = format.getFrameRate(); 158 samplesizeinbits = 16; 159 framesize = format.getChannels() * (samplesizeinbits / 8); 160 framerate = samplerate; 161 162 newformat = new AudioFormat( 163 AudioFormat.Encoding.PCM_SIGNED, samplerate, 164 samplesizeinbits, format.getChannels(), framesize, 165 framerate, false); 166 } 167 168 stream = AudioSystem.getAudioInputStream(newformat, stream); 169 converter = AudioFloatConverter.getConverter(stream.getFormat()); 170 } 171 framesize_pc = stream.getFormat().getFrameSize() 172 / stream.getFormat().getChannels(); 173 this.stream = stream; 174 } 175 176 @Override 177 public AudioFormat getFormat() { 178 return stream.getFormat(); 179 } 180 181 @Override 182 public long getFrameLength() { 183 return stream.getFrameLength(); 184 } 185 186 @Override 187 public int read(float[] b, int off, int len) throws IOException { 188 int b_len = len * framesize_pc; 189 if (buffer == null || buffer.length < b_len) 190 buffer = new byte[b_len]; 191 int ret = stream.read(buffer, 0, b_len); 192 if (ret == -1) 193 return -1; 194 converter.toFloatArray(buffer, b, off, ret / framesize_pc); 195 return ret / framesize_pc; 196 } 197 198 @Override 199 public long skip(long len) throws IOException { 200 long b_len = len * framesize_pc; 201 long ret = stream.skip(b_len); 202 if (ret == -1) 203 return -1; 204 return ret / framesize_pc; 205 } 206 207 @Override 208 public int available() throws IOException { 209 return stream.available() / framesize_pc; 210 } 211 212 @Override 213 public void close() throws IOException { 214 stream.close(); 215 } 216 217 @Override 218 public void mark(int readlimit) { 219 stream.mark(readlimit * framesize_pc); 220 } 221 222 @Override 223 public boolean markSupported() { 224 return stream.markSupported(); 225 } 226 227 @Override 228 public void reset() throws IOException { 229 stream.reset(); 230 } 231 } 232 233 public static AudioFloatInputStream getInputStream(URL url) 234 throws UnsupportedAudioFileException, IOException { 235 return new DirectAudioFloatInputStream(AudioSystem 236 .getAudioInputStream(url)); 237 } 238 239 public static AudioFloatInputStream getInputStream(File file) 240 throws UnsupportedAudioFileException, IOException { 241 return new DirectAudioFloatInputStream(AudioSystem 242 .getAudioInputStream(file)); 243 } 244 245 public static AudioFloatInputStream getInputStream(InputStream stream) 246 throws UnsupportedAudioFileException, IOException { 247 return new DirectAudioFloatInputStream(AudioSystem 248 .getAudioInputStream(stream)); 249 } 250 251 public static AudioFloatInputStream getInputStream( 252 AudioInputStream stream) { 253 return new DirectAudioFloatInputStream(stream); 254 } 255 256 public static AudioFloatInputStream getInputStream(AudioFormat format, 257 byte[] buffer, int offset, int len) { 258 AudioFloatConverter converter = AudioFloatConverter 259 .getConverter(format); 260 if (converter != null) 261 return new BytaArrayAudioFloatInputStream(converter, buffer, 262 offset, len); 263 264 InputStream stream = new ByteArrayInputStream(buffer, offset, len); 265 long aLen = format.getFrameSize() == AudioSystem.NOT_SPECIFIED 266 ? AudioSystem.NOT_SPECIFIED : len / format.getFrameSize(); 267 AudioInputStream astream = new AudioInputStream(stream, format, aLen); 268 return getInputStream(astream); 269 } 270 271 public abstract AudioFormat getFormat(); 272 273 public abstract long getFrameLength(); 274 275 public abstract int read(float[] b, int off, int len) throws IOException; 276 277 public final int read(float[] b) throws IOException { 278 return read(b, 0, b.length); 279 } 280 281 public final float read() throws IOException { 282 float[] b = new float[1]; 283 int ret = read(b, 0, 1); 284 if (ret == -1 || ret == 0) 285 return 0; 286 return b[0]; 287 } 288 289 public abstract long skip(long len) throws IOException; 290 291 public abstract int available() throws IOException; 292 293 public abstract void close() throws IOException; 294 295 public abstract void mark(int readlimit); 296 297 public abstract boolean markSupported(); 298 299 public abstract void reset() throws IOException; 300 }