115 lines
3.9 KiB
Java
115 lines
3.9 KiB
Java
package dk.itu.mario.engine.sonar.sample;
|
|
|
|
import java.io.ByteArrayInputStream;
|
|
import java.io.ByteArrayOutputStream;
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
import java.nio.ByteBuffer;
|
|
import java.nio.ByteOrder;
|
|
|
|
import javax.sound.sampled.AudioFormat;
|
|
import javax.sound.sampled.AudioInputStream;
|
|
import javax.sound.sampled.AudioSystem;
|
|
import javax.sound.sampled.UnsupportedAudioFileException;
|
|
|
|
public class SampleLoader
|
|
{
|
|
/**
|
|
* Loads a sample from an url
|
|
*/
|
|
public static SonarSample loadSample(String resourceName) throws UnsupportedAudioFileException, IOException
|
|
{
|
|
// Hack to prevent "mark/reset not supported" on some systems
|
|
InputStream in=SampleLoader.class.getResourceAsStream(resourceName);
|
|
byte[] d = rip(in);
|
|
AudioInputStream ais = AudioSystem.getAudioInputStream(new ByteArrayInputStream(d));
|
|
return buildSample(rip(ais), ais.getFormat());
|
|
}
|
|
|
|
/**
|
|
* Rips the entire contents of an inputstream into a byte array
|
|
*/
|
|
private static byte[] rip(InputStream in) throws IOException
|
|
{
|
|
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
|
byte[] b = new byte[4096];
|
|
|
|
int read = 0;
|
|
while ((read = in.read(b)) > 0)
|
|
{
|
|
bos.write(b, 0, read);
|
|
}
|
|
|
|
bos.close();
|
|
return bos.toByteArray();
|
|
}
|
|
|
|
/**
|
|
* Reorganizes audio sample data into the intenal sonar format
|
|
*/
|
|
private static SonarSample buildSample(byte[] b, AudioFormat af) throws UnsupportedAudioFileException
|
|
{
|
|
// Rip audioformat data
|
|
int channels = af.getChannels();
|
|
int sampleSize = af.getSampleSizeInBits();
|
|
float rate = af.getFrameRate();
|
|
boolean signed = af.getEncoding() == AudioFormat.Encoding.PCM_SIGNED;
|
|
|
|
// Sanity checking
|
|
if (channels != 1) throw new UnsupportedAudioFileException("Only mono samples are supported");
|
|
if (!(sampleSize == 8 || sampleSize == 16 || sampleSize == 32)) throw new UnsupportedAudioFileException("Unsupported sample size");
|
|
if (!(af.getEncoding() == AudioFormat.Encoding.PCM_UNSIGNED || af.getEncoding() == AudioFormat.Encoding.PCM_SIGNED)) throw new UnsupportedAudioFileException("Unsupported encoding");
|
|
|
|
// Wrap the data into a bytebuffer, and set up the byte order
|
|
ByteBuffer bb = ByteBuffer.wrap(b);
|
|
bb.order(af.isBigEndian() ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN);
|
|
|
|
int s = b.length / (sampleSize / 8);
|
|
float[] buf = new float[s];
|
|
// Six different cases for reordering the data. Can this be improved without slowing it down?
|
|
if (sampleSize == 8)
|
|
{
|
|
if (signed)
|
|
{
|
|
for (int i = 0; i < s; i++)
|
|
buf[i] = bb.get() / (float)0x80;
|
|
}
|
|
else
|
|
{
|
|
for (int i = 0; i < s; i++)
|
|
buf[i] = ((bb.get()&0xFF)-0x80) / (float)0x80;
|
|
}
|
|
}
|
|
else if (sampleSize == 16)
|
|
{
|
|
if (signed)
|
|
{
|
|
for (int i = 0; i < s; i++)
|
|
buf[i] = bb.getShort() / (float)0x8000;
|
|
}
|
|
else
|
|
{
|
|
for (int i = 0; i < s; i++)
|
|
buf[i] = ((bb.getShort()&0xFFFF)-0x8000) / (float)0x8000;
|
|
}
|
|
}
|
|
else if (sampleSize == 32)
|
|
{
|
|
if (signed)
|
|
{
|
|
for (int i = 0; i < s; i++)
|
|
buf[i] = bb.getInt() / (float)0x80000000;
|
|
}
|
|
else
|
|
{
|
|
// Nasty.. check this.
|
|
for (int i = 0; i < s; i++)
|
|
buf[i] = ((bb.getInt()&0xFFFFFFFFl)-0x80000000l) / (float)0x80000000;
|
|
}
|
|
}
|
|
|
|
// Return the completed sample
|
|
return new SonarSample(buf, rate);
|
|
}
|
|
}
|