diff options
Diffstat (limited to 'src/main/java/com/jsyn/util/JavaSoundSampleLoader.java')
-rw-r--r-- | src/main/java/com/jsyn/util/JavaSoundSampleLoader.java | 149 |
1 files changed, 149 insertions, 0 deletions
diff --git a/src/main/java/com/jsyn/util/JavaSoundSampleLoader.java b/src/main/java/com/jsyn/util/JavaSoundSampleLoader.java new file mode 100644 index 0000000..56a654e --- /dev/null +++ b/src/main/java/com/jsyn/util/JavaSoundSampleLoader.java @@ -0,0 +1,149 @@ +/* + * Copyright 2011 Phil Burk, Mobileer Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.jsyn.util; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.UnsupportedAudioFileException; + +import com.jsyn.data.FloatSample; + +/** + * Internal class for loading audio samples. Use SampleLoader instead. + * + * @author Phil Burk (C) 2011 Mobileer Inc + */ +class JavaSoundSampleLoader implements AudioSampleLoader { + /** + * Load a FloatSample from a File object. + */ + @Override + public FloatSample loadFloatSample(File fileIn) throws IOException { + try { + return loadFloatSample(AudioSystem.getAudioInputStream(fileIn)); + } catch (UnsupportedAudioFileException e) { + throw new IOException(e); + } + } + + /** + * Load a FloatSample from an InputStream. This is handy when loading Resources from a JAR file. + */ + @Override + public FloatSample loadFloatSample(InputStream inputStream) throws IOException { + try { + return loadFloatSample(AudioSystem.getAudioInputStream(inputStream)); + } catch (UnsupportedAudioFileException e) { + throw new IOException(e); + } + } + + /** + * Load a FloatSample from a URL.. This is handy when loading Resources from a website. + */ + @Override + public FloatSample loadFloatSample(URL url) throws IOException { + try { + return loadFloatSample(AudioSystem.getAudioInputStream(url)); + } catch (UnsupportedAudioFileException e) { + throw new IOException(e); + } + } + + private FloatSample loadFloatSample(javax.sound.sampled.AudioInputStream audioInputStream) + throws IOException, UnsupportedAudioFileException { + float[] floatData = null; + FloatSample sample = null; + int bytesPerFrame = audioInputStream.getFormat().getFrameSize(); + if (bytesPerFrame == AudioSystem.NOT_SPECIFIED) { + // some audio formats may have unspecified frame size + // in that case we may read any amount of bytes + bytesPerFrame = 1; + } + AudioFormat format = audioInputStream.getFormat(); + if (format.getEncoding() == AudioFormat.Encoding.PCM_SIGNED) { + floatData = loadSignedPCM(audioInputStream); + } + sample = new FloatSample(floatData, format.getChannels()); + sample.setFrameRate(format.getFrameRate()); + return sample; + } + + private float[] loadSignedPCM(AudioInputStream audioInputStream) throws IOException, + UnsupportedAudioFileException { + int totalSamplesRead = 0; + AudioFormat format = audioInputStream.getFormat(); + int numFrames = (int) audioInputStream.getFrameLength(); + int numSamples = format.getChannels() * numFrames; + float[] data = new float[numSamples]; + final int bytesPerFrame = format.getFrameSize(); + // Set an arbitrary buffer size of 1024 frames. + int numBytes = 1024 * bytesPerFrame; + byte[] audioBytes = new byte[numBytes]; + int numBytesRead = 0; + int numFramesRead = 0; + // Try to read numBytes bytes from the file. + while ((numBytesRead = audioInputStream.read(audioBytes)) != -1) { + int bytesRemainder = numBytesRead % bytesPerFrame; + if (bytesRemainder != 0) { + // TODO Read until you get enough data. + throw new IOException("Read partial block of sample data!"); + } + + if (audioInputStream.getFormat().getSampleSizeInBits() == 16) { + if (format.isBigEndian()) { + SampleLoader.decodeBigI16ToF32(audioBytes, 0, numBytesRead, data, + totalSamplesRead); + } else { + SampleLoader.decodeLittleI16ToF32(audioBytes, 0, numBytesRead, data, + totalSamplesRead); + } + } else if (audioInputStream.getFormat().getSampleSizeInBits() == 24) { + if (format.isBigEndian()) { + SampleLoader.decodeBigI24ToF32(audioBytes, 0, numBytesRead, data, + totalSamplesRead); + } else { + SampleLoader.decodeLittleI24ToF32(audioBytes, 0, numBytesRead, data, + totalSamplesRead); + } + } else if (audioInputStream.getFormat().getSampleSizeInBits() == 32) { + if (format.isBigEndian()) { + SampleLoader.decodeBigI32ToF32(audioBytes, 0, numBytesRead, data, + totalSamplesRead); + } else { + SampleLoader.decodeLittleI32ToF32(audioBytes, 0, numBytesRead, data, + totalSamplesRead); + } + } else { + throw new UnsupportedAudioFileException( + "Only 16, 24 or 32 bit PCM samples supported."); + } + + // Calculate the number of frames actually read. + numFramesRead = numBytesRead / bytesPerFrame; + totalSamplesRead += numFramesRead * format.getChannels(); + } + return data; + } + +} |