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.IOException; 28 import java.io.InputStream; 29 import javax.sound.sampled.AudioFormat; 30 import javax.sound.sampled.AudioInputStream; 31 import javax.sound.sampled.AudioSystem; 32 import javax.sound.sampled.AudioFormat.Encoding; 33 34 /** 35 * Wavetable oscillator for pre-loaded data. 36 * 37 * @author Karl Helgason 38 */ 39 public final class ModelByteBufferWavetable implements ModelWavetable { 40 41 private class Buffer8PlusInputStream extends InputStream { 42 43 private final boolean bigendian; 44 private final int framesize_pc; 45 int pos = 0; 46 int pos2 = 0; 47 int markpos = 0; 48 int markpos2 = 0; 49 50 Buffer8PlusInputStream() { 51 framesize_pc = format.getFrameSize() / format.getChannels(); 52 bigendian = format.isBigEndian(); 53 } 54 55 public int read(byte[] b, int off, int len) throws IOException { 56 int avail = available(); 57 if (avail <= 0) 58 return -1; 59 if (len > avail) 60 len = avail; 61 byte[] buff1 = buffer.array(); 62 byte[] buff2 = buffer8.array(); 63 pos += buffer.arrayOffset(); 64 pos2 += buffer8.arrayOffset(); 65 if (bigendian) { 66 for (int i = 0; i < len; i += (framesize_pc + 1)) { 67 System.arraycopy(buff1, pos, b, i, framesize_pc); 68 System.arraycopy(buff2, pos2, b, i + framesize_pc, 1); 69 pos += framesize_pc; 70 pos2 += 1; 71 } 72 } else { 73 for (int i = 0; i < len; i += (framesize_pc + 1)) { 74 System.arraycopy(buff2, pos2, b, i, 1); 75 System.arraycopy(buff1, pos, b, i + 1, framesize_pc); 76 pos += framesize_pc; 77 pos2 += 1; 78 } 79 } 80 pos -= buffer.arrayOffset(); 81 pos2 -= buffer8.arrayOffset(); 82 return len; 83 } 84 85 public long skip(long n) throws IOException { 86 int avail = available(); 87 if (avail <= 0) 88 return -1; 89 if (n > avail) 90 n = avail; 91 pos += (n / (framesize_pc + 1)) * (framesize_pc); 92 pos2 += n / (framesize_pc + 1); 93 return super.skip(n); 94 } 95 96 public int read(byte[] b) throws IOException { 97 return read(b, 0, b.length); 98 } 99 100 public int read() throws IOException { 101 byte[] b = new byte[1]; 102 int ret = read(b, 0, 1); 103 if (ret == -1) 104 return -1; 105 return 0 & 0xFF; 106 } 107 108 public boolean markSupported() { 109 return true; 110 } 111 112 public int available() throws IOException { 113 return (int)buffer.capacity() + (int)buffer8.capacity() - pos - pos2; 114 } 115 116 public synchronized void mark(int readlimit) { 117 markpos = pos; 118 markpos2 = pos2; 119 } 120 121 public synchronized void reset() throws IOException { 122 pos = markpos; 123 pos2 = markpos2; 124 125 } 126 } 127 128 private float loopStart = -1; 129 private float loopLength = -1; 130 private final ModelByteBuffer buffer; 131 private ModelByteBuffer buffer8 = null; 132 private AudioFormat format = null; 133 private float pitchcorrection = 0; 134 private float attenuation = 0; 135 private int loopType = LOOP_TYPE_OFF; 136 137 public ModelByteBufferWavetable(ModelByteBuffer buffer) { 138 this.buffer = buffer; 139 } 140 141 public ModelByteBufferWavetable(ModelByteBuffer buffer, 142 float pitchcorrection) { 143 this.buffer = buffer; 144 this.pitchcorrection = pitchcorrection; 145 } 146 147 public ModelByteBufferWavetable(ModelByteBuffer buffer, AudioFormat format) { 148 this.format = format; 149 this.buffer = buffer; 150 } 151 152 public ModelByteBufferWavetable(ModelByteBuffer buffer, AudioFormat format, 153 float pitchcorrection) { 154 this.format = format; 155 this.buffer = buffer; 156 this.pitchcorrection = pitchcorrection; 157 } 158 159 public void set8BitExtensionBuffer(ModelByteBuffer buffer) { 160 buffer8 = buffer; 161 } 162 163 public ModelByteBuffer get8BitExtensionBuffer() { 164 return buffer8; 165 } 166 167 public ModelByteBuffer getBuffer() { 168 return buffer; 169 } 170 171 public AudioFormat getFormat() { 172 if (format == null) { 173 if (buffer == null) 174 return null; 175 InputStream is = buffer.getInputStream(); 176 AudioFormat format = null; 177 try { 178 format = AudioSystem.getAudioFileFormat(is).getFormat(); 179 } catch (Exception e) { 180 //e.printStackTrace(); 181 } 182 try { 183 is.close(); 184 } catch (IOException e) { 185 //e.printStackTrace(); 186 } 187 return format; 188 } 189 return format; 190 } 191 192 public AudioFloatInputStream openStream() { 193 if (buffer == null) 194 return null; 195 if (format == null) { 196 InputStream is = buffer.getInputStream(); 197 AudioInputStream ais = null; 198 try { 199 ais = AudioSystem.getAudioInputStream(is); 200 } catch (Exception e) { 201 //e.printStackTrace(); 202 return null; 203 } 204 return AudioFloatInputStream.getInputStream(ais); 205 } 206 if (buffer.array() == null) { 207 return AudioFloatInputStream.getInputStream(new AudioInputStream( 208 buffer.getInputStream(), format, 209 buffer.capacity() / format.getFrameSize())); 210 } 211 if (buffer8 != null) { 212 if (format.getEncoding().equals(Encoding.PCM_SIGNED) 213 || format.getEncoding().equals(Encoding.PCM_UNSIGNED)) { 214 InputStream is = new Buffer8PlusInputStream(); 215 AudioFormat format2 = new AudioFormat( 216 format.getEncoding(), 217 format.getSampleRate(), 218 format.getSampleSizeInBits() + 8, 219 format.getChannels(), 220 format.getFrameSize() + (1 * format.getChannels()), 221 format.getFrameRate(), 222 format.isBigEndian()); 223 224 AudioInputStream ais = new AudioInputStream(is, format2, 225 buffer.capacity() / format.getFrameSize()); 226 return AudioFloatInputStream.getInputStream(ais); 227 } 228 } 229 return AudioFloatInputStream.getInputStream(format, buffer.array(), 230 (int)buffer.arrayOffset(), (int)buffer.capacity()); 231 } 232 233 public int getChannels() { 234 return getFormat().getChannels(); 235 } 236 237 public ModelOscillatorStream open(float samplerate) { 238 // ModelWavetableOscillator doesn't support ModelOscillatorStream 239 return null; 240 } 241 242 // attenuation is in cB 243 public float getAttenuation() { 244 return attenuation; 245 } 246 // attenuation is in cB 247 public void setAttenuation(float attenuation) { 248 this.attenuation = attenuation; 249 } 250 251 public float getLoopLength() { 252 return loopLength; 253 } 254 255 public void setLoopLength(float loopLength) { 256 this.loopLength = loopLength; 257 } 258 259 public float getLoopStart() { 260 return loopStart; 261 } 262 263 public void setLoopStart(float loopStart) { 264 this.loopStart = loopStart; 265 } 266 267 public void setLoopType(int loopType) { 268 this.loopType = loopType; 269 } 270 271 public int getLoopType() { 272 return loopType; 273 } 274 275 public float getPitchcorrection() { 276 return pitchcorrection; 277 } 278 279 public void setPitchcorrection(float pitchcorrection) { 280 this.pitchcorrection = pitchcorrection; 281 } 282 }