package com.talixa.audio.wav;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import com.talixa.audio.riff.RiffFile;
import com.talixa.audio.riff.chunk.AudioDataChunk;
import com.talixa.audio.riff.chunk.ChunkFormatException;
import com.talixa.audio.riff.chunk.FormatChunk;
import com.talixa.audio.riff.exceptions.RiffFormatException;
import com.talixa.audio.utils.endian.EndianConverter;
import com.talixa.audio.wav.exceptions.WaveFormatException;
/**
* @author tgerlach
*/
public class WaveReader {
public static WaveFile readFromFile(String filename) throws IOException, RiffFormatException {
File inputfile = new File(filename);
InputStream is = new FileInputStream(inputfile);
// read & check riff/wave header
byte[] riffHeader = new byte[4];
byte[] dataSize = new byte[4];
byte[] waveHeader = new byte[4];
is.read(riffHeader);
is.read(dataSize);
is.read(waveHeader);
if (!Arrays.equals(riffHeader, RiffFile.RIFF_HEADER)) {
is.close();
throw new RiffFormatException("RIFF header not found");
}
if (!Arrays.equals(waveHeader, WaveFile.WAVE_HEADER)){
is.close();
throw new WaveFormatException("WAVE header missing");
}
// now, read in each chunk
FormatChunk formatChunk = null;
AudioDataChunk audioChunk = null;
byte[] chunkId = new byte[4];
byte[] chunkSize = new byte[4];
byte[] chunkData;
while (is.read(chunkId) == 4) {
is.read(chunkSize);
int size = (int)EndianConverter.littleEndianIntToJavaLong(chunkSize);
if (Arrays.equals(chunkId, FormatChunk.FORMAT_CHUNK_HEADER)) {
chunkData = new byte[size];
is.read(chunkData);
formatChunk = new FormatChunk();
try {
formatChunk.setChunkData(chunkData);
} catch (ChunkFormatException e) {
is.close();
throw new WaveFormatException("Bad Format Header");
}
} else if (Arrays.equals(chunkId,AudioDataChunk.AUDIO_DATA_CHUNK_HEADER)) {
chunkData = new byte[size];
// Reading the entire buffer may not work for large files, and reading one
// byte at a time is horribly slow. So, will read in 512 byte chunks
int readBufferSize = 512;
byte buffer[] = new byte[readBufferSize];
int bytesRead = is.read(buffer);
int fillCount = 0; // number of times buffer filled
while (bytesRead > 0) {
for(int index = 0; index < bytesRead; ++index) {
int fillPosition = (fillCount*readBufferSize)+index;
// for some reason, some files seem to have more bytes than they claim to...
// this will prevent IndexOutOfBounds exceptions
if (fillPosition < size) {
chunkData[(fillCount*readBufferSize)+index] = buffer[index];
}
}
bytesRead = is.read(buffer);
++fillCount;
}
audioChunk = new AudioDataChunk();
audioChunk.setChunkData(chunkData);
} else {
// read past the data, and ignore it
chunkData = new byte[size];
is.read(chunkData);
}
}
// close input stream
is.close();
// make sure the required chunks were found
if (formatChunk == null) {
throw new WaveFormatException("Format chunk not found");
}
if (audioChunk == null) {
throw new WaveFormatException("AudioData chunk not found");
}
WaveFile wave = new WaveFile();
wave.setAudioDataChunk(audioChunk);
wave.setFormatChunk(formatChunk);
return wave;
}
}