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