Skip to content

Instantly share code, notes, and snippets.

@alexeygrigorev
Created December 23, 2013 20:26
Show Gist options
  • Save alexeygrigorev/8104025 to your computer and use it in GitHub Desktop.
Save alexeygrigorev/8104025 to your computer and use it in GitHub Desktop.
WAV PCM reader
import java.io.*;
import javax.sound.sampled.*;
import org.apache.commons.lang3.Validate;
import com.google.common.base.Throwables;
/**
* @author Alexey Grigorev
*/
public class AudioFileReader implements Closeable {
private static final int BITS_IN_BYTE = 8;
private AudioInputStream audioInputStream;
private AudioFormat format;
public AudioFileReader(File file) {
Validate.isTrue(file.exists());
Validate.isTrue(!file.isDirectory());
this.audioInputStream = audioFromFile(file);
this.format = audioInputStream.getFormat();
}
public AudioFileReader(InputStream stream) {
Validate.notNull(stream);
this.audioInputStream = audioFromInputStream(stream);
this.format = audioInputStream.getFormat();
}
public long getSampleCountPerChannel() {
long totalSamples = getTotalSampleCount();
return totalSamples / format.getChannels();
}
public long getTotalSampleCount() {
long sizeInBits = audioInputStream.getFrameLength() * format.getFrameSize() * BITS_IN_BYTE;
return sizeInBits / format.getSampleSizeInBits();
}
public double[] readAll() throws IOException {
long sampleCount = getTotalSampleCount();
return readInterval((int) sampleCount);
}
public double[] readInterval(int len) throws IOException {
int sizeInByte = format.getSampleSizeInBits() / BITS_IN_BYTE;
int totalSizeInBytes = len * sizeInByte * format.getChannels();
byte[] bytes = readNext(totalSizeInBytes);
// decode bytes into samples. Supported encodings are:
// PCM-SIGNED, PCM-UNSIGNED, A-LAW, U-LAW
double[] result = decodeBytes(bytes, len);
return result;
}
public double[] readMono() throws IOException {
return readOneChannel(0);
}
public double[] readOneChannel(int channel) throws IOException {
int samplesCount = (int) getSampleCountPerChannel();
double[] allSamples = readAll();
int numberOfChannels = format.getChannels();
double[] result = new double[samplesCount];
for (int i = channel; i < samplesCount; i = i + numberOfChannels) {
result[i] = allSamples[i];
}
return result;
}
private byte[] readNext(int totalSizeInBytes) throws IOException {
byte[] bytes = new byte[totalSizeInBytes];
audioInputStream.read(bytes, 0, totalSizeInBytes);
return bytes;
}
private double[] decodeBytes(byte[] bytes, int numberOfSamples) {
int sampleSizeInBytes = format.getSampleSizeInBits() / BITS_IN_BYTE;
int[] read = AudioIOUtils
.decodeBytes(bytes, numberOfSamples, sampleSizeInBytes, format.isBigEndian());
double[] audioSamples = new double[numberOfSamples];
for (int i = 0; i < numberOfSamples; i++) {
audioSamples[i] = decodeInt(read[i]);
}
return audioSamples;
}
private double decodeInt(int ival) {
double ratio = Math.pow(2.0, format.getSampleSizeInBits() - 1);
return ival / ratio;
}
@Override
public void close() throws IOException {
if (audioInputStream != null) {
audioInputStream.close();
}
}
private static AudioInputStream audioFromInputStream(InputStream inputStream) {
try {
return AudioSystem.getAudioInputStream(inputStream);
} catch (Exception e) {
throw Throwables.propagate(e);
}
}
private static AudioInputStream audioFromFile(File file) {
try {
return AudioSystem.getAudioInputStream(file);
} catch (Exception e) {
throw Throwables.propagate(e);
}
}
}
/**
* @author Alexey Grigorev 1
*/
public class AudioIOUtils {
public static int[] decodeBytes(byte[] bytes, int numberOfSamples, int sampleSizeInBytes, boolean bigEndian) {
int[] audioSamples = new int[numberOfSamples];
byte[] temporaryBuffer = new byte[sampleSizeInBytes];
int k = 0;
for (int i = 0; i < audioSamples.length; i++) {
// collect sample byte in big-endian order
if (bigEndian) {
// bytes start with MSB
for (int j = 0; j < sampleSizeInBytes; j++) {
temporaryBuffer[j] = bytes[k++];
}
} else {
// bytes start with LSB
for (int j = sampleSizeInBytes - 1; j >= 0; j--) {
temporaryBuffer[j] = bytes[k++];
}
}
// get integer value from bytes
int ival = 0;
for (int j = 0; j < sampleSizeInBytes; j++) {
ival += temporaryBuffer[j];
if (j < sampleSizeInBytes - 1) {
ival <<= 8;
}
}
// decode value
audioSamples[i] = ival;
}
return audioSamples;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment