Created
December 23, 2013 20:26
-
-
Save alexeygrigorev/8104025 to your computer and use it in GitHub Desktop.
WAV PCM reader
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @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