mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-03-12 22:56:06 +09:00
added sources for Slick
Former-commit-id: 1647fa32ef6894bd7db44f741f07c2f4dcdf9054 Former-commit-id: 0e5810dcfbe1fd59b13e7cabe9f1e93c5542da2d
This commit is contained in:
@@ -0,0 +1,322 @@
|
||||
package org.newdawn.slick.openal;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
|
||||
import org.lwjgl.BufferUtils;
|
||||
import org.lwjgl.openal.AL10;
|
||||
import org.lwjgl.openal.AL11;
|
||||
import org.lwjgl.openal.OpenALException;
|
||||
import org.newdawn.slick.util.Log;
|
||||
import org.newdawn.slick.util.ResourceLoader;
|
||||
|
||||
/**
|
||||
* A generic tool to work on a supplied stream, pulling out PCM data and buffered it to OpenAL
|
||||
* as required.
|
||||
*
|
||||
* @author Kevin Glass
|
||||
* @author Nathan Sweet <misc@n4te.com>
|
||||
* @author Rockstar play and setPosition cleanup
|
||||
*/
|
||||
public class OpenALStreamPlayer {
|
||||
/** The number of buffers to maintain */
|
||||
public static final int BUFFER_COUNT = 3;
|
||||
/** The size of the sections to stream from the stream */
|
||||
private static final int sectionSize = 4096 * 20;
|
||||
|
||||
/** The buffer read from the data stream */
|
||||
private byte[] buffer = new byte[sectionSize];
|
||||
/** Holds the OpenAL buffer names */
|
||||
private IntBuffer bufferNames;
|
||||
/** The byte buffer passed to OpenAL containing the section */
|
||||
private ByteBuffer bufferData = BufferUtils.createByteBuffer(sectionSize);
|
||||
/** The buffer holding the names of the OpenAL buffer thats been fully played back */
|
||||
private IntBuffer unqueued = BufferUtils.createIntBuffer(1);
|
||||
/** The source we're playing back on */
|
||||
private int source;
|
||||
/** The number of buffers remaining */
|
||||
private int remainingBufferCount;
|
||||
/** True if we should loop the track */
|
||||
private boolean loop;
|
||||
/** True if we've completed play back */
|
||||
private boolean done = true;
|
||||
/** The stream we're currently reading from */
|
||||
private AudioInputStream audio;
|
||||
/** The source of the data */
|
||||
private String ref;
|
||||
/** The source of the data */
|
||||
private URL url;
|
||||
/** The pitch of the music */
|
||||
private float pitch;
|
||||
/** Position in seconds of the previously played buffers */
|
||||
private float positionOffset;
|
||||
|
||||
/**
|
||||
* Create a new player to work on an audio stream
|
||||
*
|
||||
* @param source The source on which we'll play the audio
|
||||
* @param ref A reference to the audio file to stream
|
||||
*/
|
||||
public OpenALStreamPlayer(int source, String ref) {
|
||||
this.source = source;
|
||||
this.ref = ref;
|
||||
|
||||
bufferNames = BufferUtils.createIntBuffer(BUFFER_COUNT);
|
||||
AL10.alGenBuffers(bufferNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new player to work on an audio stream
|
||||
*
|
||||
* @param source The source on which we'll play the audio
|
||||
* @param url A reference to the audio file to stream
|
||||
*/
|
||||
public OpenALStreamPlayer(int source, URL url) {
|
||||
this.source = source;
|
||||
this.url = url;
|
||||
|
||||
bufferNames = BufferUtils.createIntBuffer(BUFFER_COUNT);
|
||||
AL10.alGenBuffers(bufferNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise our connection to the underlying resource
|
||||
*
|
||||
* @throws IOException Indicates a failure to open the underling resource
|
||||
*/
|
||||
private void initStreams() throws IOException {
|
||||
if (audio != null) {
|
||||
audio.close();
|
||||
}
|
||||
|
||||
OggInputStream audio;
|
||||
|
||||
if (url != null) {
|
||||
audio = new OggInputStream(url.openStream());
|
||||
} else {
|
||||
audio = new OggInputStream(ResourceLoader.getResourceAsStream(ref));
|
||||
}
|
||||
|
||||
this.audio = audio;
|
||||
positionOffset = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the source of this stream
|
||||
*
|
||||
* @return The name of the source of string
|
||||
*/
|
||||
public String getSource() {
|
||||
return (url == null) ? ref : url.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up the buffers applied to the sound source
|
||||
*/
|
||||
private void removeBuffers() {
|
||||
IntBuffer buffer = BufferUtils.createIntBuffer(1);
|
||||
int queued = AL10.alGetSourcei(source, AL10.AL_BUFFERS_QUEUED);
|
||||
|
||||
while (queued > 0)
|
||||
{
|
||||
AL10.alSourceUnqueueBuffers(source, buffer);
|
||||
queued--;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start this stream playing
|
||||
*
|
||||
* @param loop True if the stream should loop
|
||||
* @throws IOException Indicates a failure to read from the stream
|
||||
*/
|
||||
public void play(boolean loop) throws IOException {
|
||||
this.loop = loop;
|
||||
initStreams();
|
||||
|
||||
done = false;
|
||||
|
||||
AL10.alSourceStop(source);
|
||||
removeBuffers();
|
||||
|
||||
startPlayback();
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup the playback properties
|
||||
*
|
||||
* @param pitch The pitch to play back at
|
||||
*/
|
||||
public void setup(float pitch) {
|
||||
this.pitch = pitch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the playback is complete. Note this will never
|
||||
* return true if we're looping
|
||||
*
|
||||
* @return True if we're looping
|
||||
*/
|
||||
public boolean done() {
|
||||
return done;
|
||||
}
|
||||
|
||||
/**
|
||||
* Poll the bufferNames - check if we need to fill the bufferNames with another
|
||||
* section.
|
||||
*
|
||||
* Most of the time this should be reasonably quick
|
||||
*/
|
||||
public void update() {
|
||||
if (done) {
|
||||
return;
|
||||
}
|
||||
|
||||
float sampleRate = audio.getRate();
|
||||
float sampleSize;
|
||||
if (audio.getChannels() > 1) {
|
||||
sampleSize = 4; // AL10.AL_FORMAT_STEREO16
|
||||
} else {
|
||||
sampleSize = 2; // AL10.AL_FORMAT_MONO16
|
||||
}
|
||||
|
||||
int processed = AL10.alGetSourcei(source, AL10.AL_BUFFERS_PROCESSED);
|
||||
while (processed > 0) {
|
||||
unqueued.clear();
|
||||
AL10.alSourceUnqueueBuffers(source, unqueued);
|
||||
|
||||
int bufferIndex = unqueued.get(0);
|
||||
|
||||
float bufferLength = (AL10.alGetBufferi(bufferIndex, AL10.AL_SIZE) / sampleSize) / sampleRate;
|
||||
positionOffset += bufferLength;
|
||||
|
||||
if (stream(bufferIndex)) {
|
||||
AL10.alSourceQueueBuffers(source, unqueued);
|
||||
} else {
|
||||
remainingBufferCount--;
|
||||
if (remainingBufferCount == 0) {
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
processed--;
|
||||
}
|
||||
|
||||
int state = AL10.alGetSourcei(source, AL10.AL_SOURCE_STATE);
|
||||
|
||||
if (state != AL10.AL_PLAYING) {
|
||||
AL10.alSourcePlay(source);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stream some data from the audio stream to the buffer indicates by the ID
|
||||
*
|
||||
* @param bufferId The ID of the buffer to fill
|
||||
* @return True if another section was available
|
||||
*/
|
||||
public boolean stream(int bufferId) {
|
||||
try {
|
||||
int count = audio.read(buffer);
|
||||
|
||||
if (count != -1) {
|
||||
bufferData.clear();
|
||||
bufferData.put(buffer,0,count);
|
||||
bufferData.flip();
|
||||
|
||||
int format = audio.getChannels() > 1 ? AL10.AL_FORMAT_STEREO16 : AL10.AL_FORMAT_MONO16;
|
||||
try {
|
||||
AL10.alBufferData(bufferId, format, bufferData, audio.getRate());
|
||||
} catch (OpenALException e) {
|
||||
Log.error("Failed to loop buffer: "+bufferId+" "+format+" "+count+" "+audio.getRate(), e);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (loop) {
|
||||
initStreams();
|
||||
stream(bufferId);
|
||||
} else {
|
||||
done = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
Log.error(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Seeks to a position in the music.
|
||||
*
|
||||
* @param position Position in seconds.
|
||||
* @return True if the setting of the position was successful
|
||||
*/
|
||||
public boolean setPosition(float position) {
|
||||
try {
|
||||
if (getPosition() > position) {
|
||||
initStreams();
|
||||
}
|
||||
|
||||
float sampleRate = audio.getRate();
|
||||
float sampleSize;
|
||||
if (audio.getChannels() > 1) {
|
||||
sampleSize = 4; // AL10.AL_FORMAT_STEREO16
|
||||
} else {
|
||||
sampleSize = 2; // AL10.AL_FORMAT_MONO16
|
||||
}
|
||||
|
||||
while (positionOffset < position) {
|
||||
int count = audio.read(buffer);
|
||||
if (count != -1) {
|
||||
float bufferLength = (count / sampleSize) / sampleRate;
|
||||
positionOffset += bufferLength;
|
||||
} else {
|
||||
if (loop) {
|
||||
initStreams();
|
||||
} else {
|
||||
done = true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
startPlayback();
|
||||
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
Log.error(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the streaming.
|
||||
*/
|
||||
private void startPlayback() {
|
||||
AL10.alSourcei(source, AL10.AL_LOOPING, AL10.AL_FALSE);
|
||||
AL10.alSourcef(source, AL10.AL_PITCH, pitch);
|
||||
|
||||
remainingBufferCount = BUFFER_COUNT;
|
||||
|
||||
for (int i = 0; i < BUFFER_COUNT; i++) {
|
||||
stream(bufferNames.get(i));
|
||||
}
|
||||
|
||||
AL10.alSourceQueueBuffers(source, bufferNames);
|
||||
AL10.alSourcePlay(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current playing position in the sound
|
||||
*
|
||||
* @return The current position in seconds.
|
||||
*/
|
||||
public float getPosition() {
|
||||
return positionOffset + AL10.alGetSourcef(source, AL11.AL_SEC_OFFSET);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user