com.badlogic.gdx.backends.lwjgl.audio.Mini2DxWav Maven / Gradle / Ivy
/*******************************************************************************
* Copyright 2011 See LIBGDX_AUTHORS file.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package com.badlogic.gdx.backends.lwjgl.audio;
import java.io.EOFException;
import java.io.FilterInputStream;
import java.io.IOException;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.utils.GdxRuntimeException;
import com.badlogic.gdx.utils.StreamUtils;
/**
* Modified version of {@link Wav} to support sound completion events
*/
public class Mini2DxWav extends Wav {
static public class Music extends Mini2DxOpenALMusic {
private WavInputStream input;
public Music (Mini2DxOpenALAudio audio, FileHandle file) {
super(audio, file);
input = new WavInputStream(file);
if (audio.noDevice) return;
setup(input.channels, input.sampleRate);
}
public int read (byte[] buffer) {
if (input == null) {
input = new WavInputStream(file);
setup(input.channels, input.sampleRate);
}
try {
return input.read(buffer);
} catch (IOException ex) {
throw new GdxRuntimeException("Error reading WAV file: " + file, ex);
}
}
public void reset () {
StreamUtils.closeQuietly(input);
input = null;
}
}
static public class Sound extends Mini2DxOpenALSound {
public Sound (Mini2DxOpenALAudio audio, FileHandle file) {
super(audio);
if (audio.noDevice) return;
WavInputStream input = null;
try {
input = new WavInputStream(file);
setup(StreamUtils.copyStreamToByteArray(input, input.dataRemaining), input.channels, input.sampleRate);
} catch (IOException ex) {
throw new GdxRuntimeException("Error reading WAV file: " + file, ex);
} finally {
StreamUtils.closeQuietly(input);
}
}
}
/** @author Nathan Sweet */
static private class WavInputStream extends FilterInputStream {
int channels, sampleRate, dataRemaining;
WavInputStream (FileHandle file) {
super(file.read());
try {
if (read() != 'R' || read() != 'I' || read() != 'F' || read() != 'F')
throw new GdxRuntimeException("RIFF header not found: " + file);
skipFully(4);
if (read() != 'W' || read() != 'A' || read() != 'V' || read() != 'E')
throw new GdxRuntimeException("Invalid wave file header: " + file);
int fmtChunkLength = seekToChunk('f', 'm', 't', ' ');
int type = read() & 0xff | (read() & 0xff) << 8;
if (type != 1) throw new GdxRuntimeException("WAV files must be PCM: " + type);
channels = read() & 0xff | (read() & 0xff) << 8;
if (channels != 1 && channels != 2)
throw new GdxRuntimeException("WAV files must have 1 or 2 channels: " + channels);
sampleRate = read() & 0xff | (read() & 0xff) << 8 | (read() & 0xff) << 16 | (read() & 0xff) << 24;
skipFully(6);
int bitsPerSample = read() & 0xff | (read() & 0xff) << 8;
if (bitsPerSample != 16) throw new GdxRuntimeException("WAV files must have 16 bits per sample: " + bitsPerSample);
skipFully(fmtChunkLength - 16);
dataRemaining = seekToChunk('d', 'a', 't', 'a');
} catch (Throwable ex) {
StreamUtils.closeQuietly(this);
throw new GdxRuntimeException("Error reading WAV file: " + file, ex);
}
}
private int seekToChunk (char c1, char c2, char c3, char c4) throws IOException {
while (true) {
boolean found = read() == c1;
found &= read() == c2;
found &= read() == c3;
found &= read() == c4;
int chunkLength = read() & 0xff | (read() & 0xff) << 8 | (read() & 0xff) << 16 | (read() & 0xff) << 24;
if (chunkLength == -1) throw new IOException("Chunk not found: " + c1 + c2 + c3 + c4);
if (found) return chunkLength;
skipFully(chunkLength);
}
}
private void skipFully (int count) throws IOException {
while (count > 0) {
long skipped = in.skip(count);
if (skipped <= 0) throw new EOFException("Unable to skip.");
count -= skipped;
}
}
public int read (byte[] buffer) throws IOException {
if (dataRemaining == 0) return -1;
int length = Math.min(super.read(buffer), dataRemaining);
if (length == -1) return -1;
dataRemaining -= length;
return length;
}
}
}