summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2014-02-21 14:47:36 +0100
committerSven Gothel <[email protected]>2014-02-21 14:47:36 +0100
commitd199e6cdbf1fe1283bad79f68d05a9037a91863b (patch)
treec9b5f489f44e75adb6beeea23f71fc97f98f0f79 /src
parentb49859e5ea464a978812036bef05718e6ea00909 (diff)
WAVLoader: Use Bitstream and support big-endian RIFX; Fix ALutWAVLoaderTest
Diffstat (limited to 'src')
-rw-r--r--src/java/com/jogamp/openal/util/WAVData.java29
-rw-r--r--src/java/com/jogamp/openal/util/WAVLoader.java144
-rw-r--r--src/test/com/jogamp/openal/test/junit/ALutWAVLoaderTest.java45
3 files changed, 96 insertions, 122 deletions
diff --git a/src/java/com/jogamp/openal/util/WAVData.java b/src/java/com/jogamp/openal/util/WAVData.java
index 43c217d..9fab8ba 100644
--- a/src/java/com/jogamp/openal/util/WAVData.java
+++ b/src/java/com/jogamp/openal/util/WAVData.java
@@ -5,17 +5,17 @@
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
-* -Redistribution of source code must retain the above copyright notice,
+* -Redistribution of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
-* -Redistribution in binary form must reproduce the above copyright notice,
+* -Redistribution in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
-* Neither the name of Sun Microsystems, Inc. or the names of contributors may
-* be used to endorse or promote products derived from this software without
+* Neither the name of Sun Microsystems, Inc. or the names of contributors may
+* be used to endorse or promote products derived from this software without
* specific prior written permission.
-*
+*
* This software is provided "AS IS," without a warranty of any kind.
* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
* ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
@@ -39,15 +39,13 @@ import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
-import java.nio.channels.Channels;
-import java.nio.channels.ReadableByteChannel;
import com.jogamp.common.util.IOUtil;
import com.jogamp.openal.ALConstants;
import com.jogamp.openal.UnsupportedAudioFileException;
/**
- * This class is a holder for WAV (.wav ) file Data returned from the WavLoader,
+ * This class is a holder for WAV (.wav ) file Data returned from the WavLoader,
* or directly via {@link #loadFromStream(InputStream, int, int, int)}.
*
* @author Athomas Goldberg, et.al.
@@ -83,23 +81,23 @@ public final class WAVData {
this.freq = freq;
this.loop = loop;
}
-
+
/**
* This method loads a (.wav) file into a WAVData object.
* @param initialCapacity initial buffer capacity in bytes, if &gt; available bytes
* @param numChannels
* @param bits
* @param sampleRate
- * @param byteOrder
+ * @param byteOrder
* @param stream An InputStream for the .WAV stream
*
- * @return a WAVData object containing the audio data
+ * @return a WAVData object containing the audio data
*
* @throws UnsupportedAudioFileException if the format of the audio if not
- * supported.
- * @throws IOException If the file can no be found or some other IO error
+ * supported.
+ * @throws IOException If the file can no be found or some other IO error
* occurs
- */
+ */
public static WAVData loadFromStream(InputStream aIn, int initialCapacity, int numChannels, int bits, int sampleRate, ByteOrder byteOrder, boolean loop)
throws IOException {
if( !(aIn instanceof BufferedInputStream) ) {
@@ -117,7 +115,6 @@ public final class WAVData {
} else if ((bits == 16) && (numChannels == 2)) {
format = ALConstants.AL_FORMAT_STEREO16;
}
-
ByteBuffer buffer = IOUtil.copyStream2ByteBuffer(aIn, initialCapacity);
int size = buffer.limit();
@@ -137,5 +134,5 @@ public final class WAVData {
return result;
}
-
+
}
diff --git a/src/java/com/jogamp/openal/util/WAVLoader.java b/src/java/com/jogamp/openal/util/WAVLoader.java
index 22b4194..5547ed2 100644
--- a/src/java/com/jogamp/openal/util/WAVLoader.java
+++ b/src/java/com/jogamp/openal/util/WAVLoader.java
@@ -1,21 +1,20 @@
/**
-* Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
-* Copyright (c) 2011 JogAmp Community. All rights reserved.
+* Copyright (c) 2013 JogAmp Community. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
-* -Redistribution of source code must retain the above copyright notice,
+* -Redistribution of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
-* -Redistribution in binary form must reproduce the above copyright notice,
+* -Redistribution in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
-* Neither the name of Sun Microsystems, Inc. or the names of contributors may
-* be used to endorse or promote products derived from this software without
+* Neither the name of Sun Microsystems, Inc. or the names of contributors may
+* be used to endorse or promote products derived from this software without
* specific prior written permission.
-*
+*
* This software is provided "AS IS," without a warranty of any kind.
* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
* ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
@@ -30,41 +29,39 @@
*
* You acknowledge that this software is not designed or intended for use in the
* design, construction, operation or maintenance of any nuclear facility.
+*
+* Note: Rewrite started by Julien Goussej 2013-03-27 commit 6292ed9712b17f849f22221aea9d586c3a363c09
*/
package com.jogamp.openal.util;
-import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteOrder;
+import com.jogamp.common.util.Bitstream;
import com.jogamp.openal.ALException;
/**
* A Loader utility for (.wav) files. Creates a WAVData object containing the
* data used by the AL.alBufferData method.
- *
- * @author Athomas Goldberg, et.al
*/
public class WAVLoader {
- // private static final int BUFFER_SIZE = 128000;
/**
* This method loads a (.wav) file into a WAVData object.
*
* @param filename The name of the (.wav) file
*
- * @return a WAVData object containing the audio data
+ * @return a WAVData object containing the audio data
*
- * @throws UnsupportedAudioFileException if the format of the audio if not
- * supported.
- * @throws IOException If the file can no be found or some other IO error
+ * @throws ALException if the format of the audio if not supported.
+ * @throws IOException If the file can no be found or some other IO error
* occurs
*/
- public static WAVData loadFromFile(String filename) throws IOException {
+ public static WAVData loadFromFile(String filename) throws ALException, IOException {
File soundFile = new File(filename);
InputStream is = new FileInputStream(soundFile);
return loadFromStreamImpl(is);
@@ -75,30 +72,24 @@ public class WAVLoader {
*
* @param stream An InputStream for the .WAV stream.
*
- * @return a WAVData object containing the audio data
+ * @return a WAVData object containing the audio data
*
- * @throws UnsupportedAudioFileException if the format of the audio if not
- * supported.
- * @throws IOException If the file can no be found or some other IO error
+ * @throws ALException if the format of the audio if not supported.
+ * @throws IOException If the file can no be found or some other IO error
* occurs
*/
- public static WAVData loadFromStream(InputStream stream) throws IOException {
+ public static WAVData loadFromStream(InputStream stream) throws ALException, IOException {
return loadFromStreamImpl(stream);
}
-
- private static long readUnsignedIntLittleEndian(DataInputStream is) throws IOException {
- byte[] buf = new byte[4];
- is.readFully(buf);
- return (buf[0] & 0xFF | ((buf[1] & 0xFF) << 8) | ((buf[2] & 0xFF) << 16) | ((buf[3] & 0xFF) << 24));
- }
-
- private static short readUnsignedShortLittleEndian(DataInputStream is) throws IOException {
- byte[] buf = new byte[2];
- is.readFully(buf);
- return (short) (buf[0] & 0xFF | ((buf[1] & 0xFF) << 8));
- }
- private static WAVData loadFromStreamImpl(InputStream aIn) throws IOException {
+ private static final int RIFF = 0x52494646;
+ private static final int RIFX = 0x52494658;
+ private static final int WAVE = 0x57415645;
+ private static final int FACT = 0x66616374;
+ private static final int FMT = 0x666D7420;
+ private static final int DATA = 0x64617461;
+
+ private static WAVData loadFromStreamImpl(InputStream aIn) throws ALException, IOException {
/**
* references:
* http://www.sonicspot.com/guide/wavefiles.html
@@ -106,21 +97,25 @@ public class WAVLoader {
* http://stackoverflow.com/questions/1111539/is-the-endianness-of-format-params-guaranteed-in-riff-wav-files
* http://sharkysoft.com/archive/lava/docs/javadocs/lava/riff/wave/doc-files/riffwave-content.htm
*/
- final DataInputStream din;
- if (aIn instanceof DataInputStream) {
- din = (DataInputStream) aIn;
- } else {
- din = new DataInputStream(aIn);
- }
+ final Bitstream.ByteInputStream bis = new Bitstream.ByteInputStream(aIn);
+ final Bitstream<InputStream> bs = new Bitstream<InputStream>(bis, false);
+ bs.setThrowIOExceptionOnEOF(true);
try {
- if (din.readInt() != 0x52494646) {// "RIFF", little endian
- //FIXME "RIFX", big endian, read the data in big endian in this case
- throw new ALException("Invalid WAV header");
+ final boolean bigEndian; // FIXME: for all data incl. signatures ?
+
+ final long riffMarker = bs.readUInt32(true /* msbFirst */, true /* bigEndian */);
+ if ( RIFF == riffMarker ) {
+ bigEndian = false;
+ } else if( RIFX == riffMarker ) {
+ bigEndian = true;
+ } else {
+ throw new ALException("Invalid RIF header: 0x"+Integer.toHexString((int)riffMarker)+", "+bs);
}
- // length of the RIFF, unused
- readUnsignedIntLittleEndian(din);
- if (din.readInt() != 0x57415645) {// "WAVE"
- throw new ALException("Invalid WAV header");
+ final long riffLenL = bs.readUInt32(true /*msbFirst*/, bigEndian);
+ final int riffLenI = Bitstream.uint32LongToInt(riffLenL);
+ final long wavMarker = bs.readUInt32(true /* msbFirst */, true /* bigEndian */);
+ if ( WAVE != wavMarker ) {
+ throw new ALException("Invalid WAV header: 0x"+Integer.toHexString((int)wavMarker)+", "+bs);
}
boolean foundFmt = false;
boolean foundData = false;
@@ -130,49 +125,46 @@ public class WAVLoader {
long chunkLength = 0;
while (!foundData) {
- int chunkId = din.readInt();
- chunkLength = readUnsignedIntLittleEndian(din);
+ int chunkId = (int)bs.readUInt32(true /* msbFirst */, true /* bigEndian */);
+ chunkLength = bs.readUInt32(true /* msbFirst */, bigEndian);
switch (chunkId) {
- case 0x666D7420: // "fmt "
+ case FMT:
foundFmt = true;
- // compression code, unused
- readUnsignedShortLittleEndian(din);
- sChannels = readUnsignedShortLittleEndian(din);
- sampleRate = readUnsignedIntLittleEndian(din);
- // bytes per second, unused
- readUnsignedIntLittleEndian(din);
- // block alignment, unused
- readUnsignedShortLittleEndian(din);
- sSampleSizeInBits = readUnsignedShortLittleEndian(din);
- din.skip(chunkLength - 16);
+ @SuppressWarnings("unused")
+ final int compressionCode = bs.readUInt16(true /* msbFirst */, bigEndian);
+ sChannels = (short)bs.readUInt16(true /* msbFirst */, bigEndian);
+ sampleRate = bs.readUInt32(true /* msbFirst */, bigEndian);
+ @SuppressWarnings("unused")
+ final long bytesPerSeconds = bs.readUInt32(true /* msbFirst */, bigEndian);
+ @SuppressWarnings("unused")
+ final short blockAlignment = (short) bs.readUInt16(true /* msbFirst */, bigEndian);
+ sSampleSizeInBits = (short) bs.readUInt16(true /* msbFirst */, bigEndian);
+ bs.skip( 8 * ( chunkLength - 16 ) );
break;
- case 0x66616374: // "fact"
+ case FACT:
// FIXME: compression format dependent data?
- din.skip(chunkLength);
+ bs.skip( 8 * chunkLength );
break;
- case 0x64617461: // "data"
- if (!foundFmt)
- throw new ALException(
- "WAV fmt chunks must be before data chunks");
+ case DATA:
+ if (!foundFmt) {
+ throw new ALException("WAV fmt chunks must be before data chunks: "+bs);
+ }
foundData = true;
break;
default:
// unrecognized chunk, skips it
- din.skip(chunkLength);
+ bs.skip( 8 * chunkLength );
}
}
- final int channels = (int) sChannels;
+ final int channels = sChannels;
final int sampleSizeInBits = sSampleSizeInBits;
- final float fSampleRate = (float) sampleRate;
- //FIXME big endian not supported yet
- final boolean isBigEndian = false;
- return WAVData.loadFromStream(aIn, -1, channels, sampleSizeInBits,
- Math.round(fSampleRate), isBigEndian ? ByteOrder.BIG_ENDIAN
- : ByteOrder.LITTLE_ENDIAN, false);
+ final float fSampleRate = sampleRate;
+ return WAVData.loadFromStream(bs.getSubStream(), riffLenI, channels, sampleSizeInBits,
+ Math.round(fSampleRate), bigEndian ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN, false);
} finally {
- din.close();
+ bs.close();
}
}
-
+
}
diff --git a/src/test/com/jogamp/openal/test/junit/ALutWAVLoaderTest.java b/src/test/com/jogamp/openal/test/junit/ALutWAVLoaderTest.java
index cda233d..7d8fa05 100644
--- a/src/test/com/jogamp/openal/test/junit/ALutWAVLoaderTest.java
+++ b/src/test/com/jogamp/openal/test/junit/ALutWAVLoaderTest.java
@@ -7,6 +7,7 @@ import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import org.junit.Test;
+import org.junit.Assert;
import com.jogamp.openal.test.resources.ResourceLocation;
import com.jogamp.openal.util.ALut;
@@ -23,39 +24,31 @@ public class ALutWAVLoaderTest {
ByteBuffer[] data = new ByteBuffer[1];
int[] freq = new int[1];
int[] loop = new int[1];
-
+
ALut.alutLoadWAVFile(ResourceLocation.getTestStream0(), format, data, size, freq, loop);
System.out.println("*** ALut.alutLoadWAV Stream0 size "+size[0]);
- assertEquals(size[0], ResourceLocation.getTestStream0Size());
-
- ALut.alutLoadWAVFile(ResourceLocation.getTestStream1(), format, data, size, freq, loop);
- System.out.println("*** ALut.alutLoadWAV Stream1 size "+size[0]);
- assertEquals(size[0], ResourceLocation.getTestStream1Size());
-
- ALut.alutLoadWAVFile(ResourceLocation.getTestStream2(), format, data, size, freq, loop);
- System.out.println("*** ALut.alutLoadWAV Stream2 size "+size[0]);
- assertEquals(size[0], ResourceLocation.getTestStream2Size());
-
+ Assert.assertTrue("Stream0 size "+ResourceLocation.getTestStream0Size()+" < "+size[0], size[0] <= ResourceLocation.getTestStream0Size());
+
ALut.alutLoadWAVFile(ResourceLocation.getTestStream3(), format, data, size, freq, loop);
System.out.println("*** ALut.alutLoadWAV Stream3 size "+size[0]);
- assertEquals(size[0], ResourceLocation.getTestStream3Size());
-
+ Assert.assertTrue("Stream3 size "+ResourceLocation.getTestStream3Size()+" < "+size[0], size[0] <= ResourceLocation.getTestStream3Size());
+
}
-
+
@Test
public void testWAVDataLoadStream() throws IOException {
WAVData wd0 = WAVData.loadFromStream(ResourceLocation.getTestStream0(), ResourceLocation.getTestStream0Size(), 1, 8, 22050, ByteOrder.LITTLE_ENDIAN, true);
System.out.println("*** WAVData.loadFrom Stream0 size "+wd0.data.limit());
assertEquals(wd0.data.limit(), ResourceLocation.getTestStream0Size());
-
+
WAVData wd1 = WAVData.loadFromStream(ResourceLocation.getTestStream1(), ResourceLocation.getTestStream1Size(), 2, 16, 44100, ByteOrder.BIG_ENDIAN, true);
System.out.println("*** WAVData.loadFrom Stream1 size "+wd1.data.limit());
assertEquals(wd1.data.limit(), ResourceLocation.getTestStream1Size());
-
+
WAVData wd2 = WAVData.loadFromStream(ResourceLocation.getTestStream2(), ResourceLocation.getTestStream2Size(), 2, 16, 44100, ByteOrder.LITTLE_ENDIAN, true);
System.out.println("*** WAVData.loadFrom Stream2 size "+wd2.data.limit());
assertEquals(wd2.data.limit(), ResourceLocation.getTestStream2Size());
-
+
WAVData wd3 = WAVData.loadFromStream(ResourceLocation.getTestStream3(), ResourceLocation.getTestStream3Size(), 2, 16, 44100, ByteOrder.LITTLE_ENDIAN, true);
System.out.println("*** WAVData.loadFrom Stream3 size "+wd3.data.limit());
assertEquals(wd3.data.limit(), ResourceLocation.getTestStream3Size());
@@ -66,23 +59,15 @@ public class ALutWAVLoaderTest {
public void testWAVLoaderLoadStream() throws IOException {
WAVData wd0 = WAVLoader.loadFromStream(ResourceLocation.getTestStream0());
System.out.println("*** WAVLoader.loadFrom Stream0 size "+wd0.data.limit());
- assertEquals(wd0.data.limit(), ResourceLocation.getTestStream0Size());
-
- WAVData wd1 = WAVLoader.loadFromStream(ResourceLocation.getTestStream1());
- System.out.println("*** WAVLoader.loadFrom Stream1 size "+wd1.data.limit());
- assertEquals(wd1.data.limit(), ResourceLocation.getTestStream1Size());
-
- WAVData wd2 = WAVLoader.loadFromStream(ResourceLocation.getTestStream2());
- System.out.println("*** WAVLoader.loadFrom Stream2 size "+wd2.data.limit());
- assertEquals(wd2.data.limit(), ResourceLocation.getTestStream2Size());
-
+ Assert.assertTrue("Stream0 size "+ResourceLocation.getTestStream0Size()+" < "+wd0.data.limit(), wd0.data.limit() <= ResourceLocation.getTestStream0Size());
+
WAVData wd3 = WAVLoader.loadFromStream(ResourceLocation.getTestStream3());
System.out.println("*** WAVLoader.loadFrom Stream3 size "+wd3.data.limit());
- assertEquals(wd3.data.limit(), ResourceLocation.getTestStream3Size());
+ Assert.assertTrue("Stream3 size "+ResourceLocation.getTestStream3Size()+" < "+wd3.data.limit()+" .. "+wd3.data, wd3.data.limit() <= ResourceLocation.getTestStream3Size());
}
-
+
// TODO test * LoadFile
-
+
public static void main(String args[]) throws IOException {
org.junit.runner.JUnitCore.main(ALutWAVLoaderTest.class.getName());
}